Add compiler source to new directory structure
SVN=121164
diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
new file mode 100644
index 0000000..47adbc8
--- /dev/null
+++ b/src/cmd/6a/a.h
@@ -0,0 +1,206 @@
+// Inferno utils/6a/a.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "../6l/6.out.h"
+#include "compat.h"
+
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Sym Sym;
+typedef struct Ref Ref;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+typedef struct Gen2 Gen2;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 500
+#define BUFSIZ 8192
+#define HISTSZ 20
+#define NINCLUDE 10
+#define NHUNK 10000
+#define EOF (-1)
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ Ref* ref;
+ char* macro;
+ vlong value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+struct Ref
+{
+ int class;
+};
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+EXTERN struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Gen
+{
+ double dval;
+ char sval[8];
+ vlong offset;
+ Sym* sym;
+ short type;
+ short index;
+ short scale;
+};
+struct Gen2
+{
+ Gen from;
+ Gen to;
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ vlong offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC,
+};
+
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char* Dlist[30];
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char* include[NINCLUDE];
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN long lineno;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN int ninclude;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN long pc;
+EXTERN int peekc;
+EXTERN int sym;
+EXTERN char symb[NSYMB];
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN long thunk;
+EXTERN Biobuf obuf;
+
+void* allocn(void*, long, long);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+long yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void checkscale(int);
+void pinit(char*);
+void cclean(void);
+int isreg(Gen*);
+void outcode(int, Gen2*);
+void outhist(void);
+void zaddr(Gen*, int);
+void zname(char*, int, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void macprag(void);
+void maclin(void);
+void macif(int);
+void macend(void);
+void dodefine(char*);
+void prfile(long);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y
new file mode 100644
index 0000000..698e73e
--- /dev/null
+++ b/src/cmd/6a/a.y
@@ -0,0 +1,592 @@
+// Inferno utils/6a/a.y
+// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.y
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+%{
+#include "a.h"
+%}
+%union {
+ Sym *sym;
+ vlong lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+ Gen2 gen2;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
+%token <lval> LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEXC LTYPEX LTYPERT
+%token <lval> LCONST LFP LPC LSB
+%token <lval> LBREG LLREG LSREG LFREG LMREG LXREG
+%token <dval> LFCONST
+%token <sval> LSCONST LSP
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr pointer offset
+%type <gen> mem imm reg nam rel rem rim rom omem nmem
+%type <gen2> nonnon nonrel nonrem rimnon rimrem remrim spec10
+%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
+%%
+prog:
+| prog line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+ LNAME '=' expr
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| LTYPE0 nonnon { outcode($1, &$2); }
+| LTYPE1 nonrem { outcode($1, &$2); }
+| LTYPE2 rimnon { outcode($1, &$2); }
+| LTYPE3 rimrem { outcode($1, &$2); }
+| LTYPE4 remrim { outcode($1, &$2); }
+| LTYPER nonrel { outcode($1, &$2); }
+| LTYPED spec1 { outcode($1, &$2); }
+| LTYPET spec2 { outcode($1, &$2); }
+| LTYPEC spec3 { outcode($1, &$2); }
+| LTYPEN spec4 { outcode($1, &$2); }
+| LTYPES spec5 { outcode($1, &$2); }
+| LTYPEM spec6 { outcode($1, &$2); }
+| LTYPEI spec7 { outcode($1, &$2); }
+| LTYPEXC spec8 { outcode($1, &$2); }
+| LTYPEX spec9 { outcode($1, &$2); }
+| LTYPERT spec10 { outcode($1, &$2); }
+
+nonnon:
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+| ','
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+
+rimrem:
+ rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+remrim:
+ rem ',' rim
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+rimnon:
+ rim ','
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| rim
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+
+nonrem:
+ ',' rem
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+| rem
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+
+nonrel:
+ ',' rel
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+| rel
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+
+spec1: /* DATA */
+ nam '/' con ',' imm
+ {
+ $$.from = $1;
+ $$.from.scale = $3;
+ $$.to = $5;
+ }
+
+spec2: /* TEXT */
+ mem ',' imm
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| mem ',' con ',' imm
+ {
+ $$.from = $1;
+ $$.from.scale = $3;
+ $$.to = $5;
+ }
+
+spec3: /* JMP/CALL */
+ ',' rom
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+| rom
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+
+spec4: /* NOP */
+ nonnon
+| nonrem
+
+spec5: /* SHL/SHR */
+ rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| rim ',' rem ':' LLREG
+ {
+ $$.from = $1;
+ $$.to = $3;
+ if($$.from.index != D_NONE)
+ yyerror("dp shift with lhs index");
+ $$.from.index = $5;
+ }
+
+spec6: /* MOVW/MOVL */
+ rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| rim ',' rem ':' LSREG
+ {
+ $$.from = $1;
+ $$.to = $3;
+ if($$.to.index != D_NONE)
+ yyerror("dp move with lhs index");
+ $$.to.index = $5;
+ }
+
+spec7:
+ rim ','
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| rim
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+spec8: /* CMPPS/CMPPD */
+ reg ',' rem ',' con
+ {
+ $$.from = $1;
+ $$.to = $3;
+ $$.from.offset = $5;
+ }
+
+spec9: /* shufl */
+ imm ',' rem ',' reg
+ {
+ $$.from = $3;
+ $$.to = $5;
+ if($1.type != D_CONST)
+ yyerror("illegal constant");
+ $$.to.offset = $1.offset;
+ }
+
+spec10: /* RET/RETF */
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+| imm
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+
+rem:
+ reg
+| mem
+
+rom:
+ rel
+| nmem
+| '*' reg
+ {
+ $$ = $2;
+ }
+| '*' omem
+ {
+ $$ = $2;
+ }
+| reg
+| omem
+
+rim:
+ rem
+| imm
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $1->value + $2;
+ }
+
+reg:
+ LBREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LFREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LLREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LMREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LSP
+ {
+ $$ = nullgen;
+ $$.type = D_SP;
+ }
+| LSREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LXREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+
+imm:
+ '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+| '$' nam
+ {
+ $$ = $2;
+ $$.index = $2.type;
+ $$.type = D_ADDR;
+ /*
+ if($2.type == D_AUTO || $2.type == D_PARAM)
+ yyerror("constant cannot be automatic: %s",
+ $2.sym->name);
+ */
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+| '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '(' LFCONST ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $3;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+
+mem:
+ omem
+| nmem
+
+omem:
+ con
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_NONE;
+ $$.offset = $1;
+ }
+| con '(' LLREG ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$3;
+ $$.offset = $1;
+ }
+| con '(' LSP ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_SP;
+ $$.offset = $1;
+ }
+| con '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_NONE;
+ $$.offset = $1;
+ $$.index = $3;
+ $$.scale = $5;
+ checkscale($$.scale);
+ }
+| con '(' LLREG ')' '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$3;
+ $$.offset = $1;
+ $$.index = $6;
+ $$.scale = $8;
+ checkscale($$.scale);
+ }
+| '(' LLREG ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$2;
+ }
+| '(' LSP ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_SP;
+ }
+| '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_NONE;
+ $$.index = $2;
+ $$.scale = $4;
+ checkscale($$.scale);
+ }
+| '(' LLREG ')' '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$2;
+ $$.index = $5;
+ $$.scale = $7;
+ checkscale($$.scale);
+ }
+
+nmem:
+ nam
+ {
+ $$ = $1;
+ }
+| nam '(' LLREG '*' con ')'
+ {
+ $$ = $1;
+ $$.index = $3;
+ $$.scale = $5;
+ checkscale($$.scale);
+ }
+
+nam:
+ LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+ {
+ $$ = D_AUTO;
+ }
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
new file mode 100644
index 0000000..ff0a0d5
--- /dev/null
+++ b/src/cmd/6a/lex.c
@@ -0,0 +1,1337 @@
+// Inferno utils/6a/lex.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#define EXTERN
+#include "a.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int nout, nproc, status, i, c;
+
+ thechar = '6';
+ thestring = "amd64";
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ include[ninclude++] = ".";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 || c < sizeof(debug))
+ debug[c] = 1;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p)
+ Dlist[nDlist++] = p;
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't assemble multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0)
+ errorexit();
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ print("%s:\n", *argv);
+ if(assemble(*argv))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char ofile[100], incfile[20], *p;
+ int i, of;
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile){
+ p = utfrrune(outfile, '.');
+ if(p)
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ } else
+ outfile = "/dev/null";
+ }
+ p = getenv("INCLUDE");
+ if(p) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile,"/%s/include", thestring);
+ setinclude(strdup(incfile));
+ }
+ }
+
+ of = mycreate(outfile, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+
+ Bprint(&obuf, "x86-64\n");
+
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ Bprint(&obuf, "\n!\n");
+
+ pass = 2;
+ outhist();
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ return nerrors;
+}
+
+struct
+{
+ char *name;
+ ushort type;
+ ushort value;
+} itab[] =
+{
+ "SP", LSP, D_AUTO,
+ "SB", LSB, D_EXTERN,
+ "FP", LFP, D_PARAM,
+ "PC", LPC, D_BRANCH,
+
+ "AL", LBREG, D_AL,
+ "CL", LBREG, D_CL,
+ "DL", LBREG, D_DL,
+ "BL", LBREG, D_BL,
+/* "SPB", LBREG, D_SPB, */
+ "SIB", LBREG, D_SIB,
+ "DIB", LBREG, D_DIB,
+ "BPB", LBREG, D_BPB,
+ "R8B", LBREG, D_R8B,
+ "R9B", LBREG, D_R9B,
+ "R10B", LBREG, D_R10B,
+ "R11B", LBREG, D_R11B,
+ "R12B", LBREG, D_R12B,
+ "R13B", LBREG, D_R13B,
+ "R14B", LBREG, D_R14B,
+ "R15B", LBREG, D_R15B,
+
+ "AH", LBREG, D_AH,
+ "CH", LBREG, D_CH,
+ "DH", LBREG, D_DH,
+ "BH", LBREG, D_BH,
+
+ "AX", LLREG, D_AX,
+ "CX", LLREG, D_CX,
+ "DX", LLREG, D_DX,
+ "BX", LLREG, D_BX,
+/* "SP", LLREG, D_SP, */
+ "BP", LLREG, D_BP,
+ "SI", LLREG, D_SI,
+ "DI", LLREG, D_DI,
+ "R8", LLREG, D_R8,
+ "R9", LLREG, D_R9,
+ "R10", LLREG, D_R10,
+ "R11", LLREG, D_R11,
+ "R12", LLREG, D_R12,
+ "R13", LLREG, D_R13,
+ "R14", LLREG, D_R14,
+ "R15", LLREG, D_R15,
+
+ "RARG", LLREG, REGARG,
+
+ "F0", LFREG, D_F0+0,
+ "F1", LFREG, D_F0+1,
+ "F2", LFREG, D_F0+2,
+ "F3", LFREG, D_F0+3,
+ "F4", LFREG, D_F0+4,
+ "F5", LFREG, D_F0+5,
+ "F6", LFREG, D_F0+6,
+ "F7", LFREG, D_F0+7,
+
+ "M0", LMREG, D_M0+0,
+ "M1", LMREG, D_M0+1,
+ "M2", LMREG, D_M0+2,
+ "M3", LMREG, D_M0+3,
+ "M4", LMREG, D_M0+4,
+ "M5", LMREG, D_M0+5,
+ "M6", LMREG, D_M0+6,
+ "M7", LMREG, D_M0+7,
+
+ "X0", LXREG, D_X0+0,
+ "X1", LXREG, D_X0+1,
+ "X2", LXREG, D_X0+2,
+ "X3", LXREG, D_X0+3,
+ "X4", LXREG, D_X0+4,
+ "X5", LXREG, D_X0+5,
+ "X6", LXREG, D_X0+6,
+ "X7", LXREG, D_X0+7,
+ "X8", LXREG, D_X0+8,
+ "X9", LXREG, D_X0+9,
+ "X10", LXREG, D_X0+10,
+ "X11", LXREG, D_X0+11,
+ "X12", LXREG, D_X0+12,
+ "X13", LXREG, D_X0+13,
+ "X14", LXREG, D_X0+14,
+ "X15", LXREG, D_X0+15,
+
+ "CS", LSREG, D_CS,
+ "SS", LSREG, D_SS,
+ "DS", LSREG, D_DS,
+ "ES", LSREG, D_ES,
+ "FS", LSREG, D_FS,
+ "GS", LSREG, D_GS,
+
+ "GDTR", LBREG, D_GDTR,
+ "IDTR", LBREG, D_IDTR,
+ "LDTR", LBREG, D_LDTR,
+ "MSW", LBREG, D_MSW,
+ "TASK", LBREG, D_TASK,
+
+ "CR0", LBREG, D_CR+0,
+ "CR1", LBREG, D_CR+1,
+ "CR2", LBREG, D_CR+2,
+ "CR3", LBREG, D_CR+3,
+ "CR4", LBREG, D_CR+4,
+ "CR5", LBREG, D_CR+5,
+ "CR6", LBREG, D_CR+6,
+ "CR7", LBREG, D_CR+7,
+ "CR8", LBREG, D_CR+8,
+ "CR9", LBREG, D_CR+9,
+ "CR10", LBREG, D_CR+10,
+ "CR11", LBREG, D_CR+11,
+ "CR12", LBREG, D_CR+12,
+ "CR13", LBREG, D_CR+13,
+ "CR14", LBREG, D_CR+14,
+ "CR15", LBREG, D_CR+15,
+
+ "DR0", LBREG, D_DR+0,
+ "DR1", LBREG, D_DR+1,
+ "DR2", LBREG, D_DR+2,
+ "DR3", LBREG, D_DR+3,
+ "DR4", LBREG, D_DR+4,
+ "DR5", LBREG, D_DR+5,
+ "DR6", LBREG, D_DR+6,
+ "DR7", LBREG, D_DR+7,
+
+ "TR0", LBREG, D_TR+0,
+ "TR1", LBREG, D_TR+1,
+ "TR2", LBREG, D_TR+2,
+ "TR3", LBREG, D_TR+3,
+ "TR4", LBREG, D_TR+4,
+ "TR5", LBREG, D_TR+5,
+ "TR6", LBREG, D_TR+6,
+ "TR7", LBREG, D_TR+7,
+
+ "AAA", LTYPE0, AAAA,
+ "AAD", LTYPE0, AAAD,
+ "AAM", LTYPE0, AAAM,
+ "AAS", LTYPE0, AAAS,
+ "ADCB", LTYPE3, AADCB,
+ "ADCL", LTYPE3, AADCL,
+ "ADCQ", LTYPE3, AADCQ,
+ "ADCW", LTYPE3, AADCW,
+ "ADDB", LTYPE3, AADDB,
+ "ADDL", LTYPE3, AADDL,
+ "ADDQ", LTYPE3, AADDQ,
+ "ADDW", LTYPE3, AADDW,
+ "ADJSP", LTYPE2, AADJSP,
+ "ANDB", LTYPE3, AANDB,
+ "ANDL", LTYPE3, AANDL,
+ "ANDQ", LTYPE3, AANDQ,
+ "ANDW", LTYPE3, AANDW,
+ "ARPL", LTYPE3, AARPL,
+ "BOUNDL", LTYPE3, ABOUNDL,
+ "BOUNDW", LTYPE3, ABOUNDW,
+ "BSFL", LTYPE3, ABSFL,
+ "BSFQ", LTYPE3, ABSFQ,
+ "BSFW", LTYPE3, ABSFW,
+ "BSRL", LTYPE3, ABSRL,
+ "BSRQ", LTYPE3, ABSRQ,
+ "BSRW", LTYPE3, ABSRW,
+ "BTCL", LTYPE3, ABTCL,
+ "BTCQ", LTYPE3, ABTCQ,
+ "BTCW", LTYPE3, ABTCW,
+ "BTL", LTYPE3, ABTL,
+ "BTQ", LTYPE3, ABTQ,
+ "BTRL", LTYPE3, ABTRL,
+ "BTRQ", LTYPE3, ABTRQ,
+ "BTRW", LTYPE3, ABTRW,
+ "BTSL", LTYPE3, ABTSL,
+ "BTSQ", LTYPE3, ABTSQ,
+ "BTSW", LTYPE3, ABTSW,
+ "BTW", LTYPE3, ABTW,
+ "BYTE", LTYPE2, ABYTE,
+ "CALL", LTYPEC, ACALL,
+ "CLC", LTYPE0, ACLC,
+ "CLD", LTYPE0, ACLD,
+ "CLI", LTYPE0, ACLI,
+ "CLTS", LTYPE0, ACLTS,
+ "CMC", LTYPE0, ACMC,
+ "CMPB", LTYPE4, ACMPB,
+ "CMPL", LTYPE4, ACMPL,
+ "CMPQ", LTYPE4, ACMPQ,
+ "CMPW", LTYPE4, ACMPW,
+ "CMPSB", LTYPE0, ACMPSB,
+ "CMPSL", LTYPE0, ACMPSL,
+ "CMPSQ", LTYPE0, ACMPSQ,
+ "CMPSW", LTYPE0, ACMPSW,
+ "CMPXCHG8B", LTYPE1, ACMPXCHG8B,
+ "CMPXCHGB", LTYPE3, ACMPXCHGB, /* LTYPE3? */
+ "CMPXCHGL", LTYPE3, ACMPXCHGL,
+ "CMPXCHGQ", LTYPE3, ACMPXCHGQ,
+ "CMPXCHGW", LTYPE3, ACMPXCHGW,
+ "CPUID", LTYPE0, ACPUID,
+ "DAA", LTYPE0, ADAA,
+ "DAS", LTYPE0, ADAS,
+ "DATA", LTYPED, ADATA,
+ "DECB", LTYPE1, ADECB,
+ "DECL", LTYPE1, ADECL,
+ "DECQ", LTYPE1, ADECQ,
+ "DECW", LTYPE1, ADECW,
+ "DIVB", LTYPE2, ADIVB,
+ "DIVL", LTYPE2, ADIVL,
+ "DIVQ", LTYPE2, ADIVQ,
+ "DIVW", LTYPE2, ADIVW,
+ "EMMS", LTYPE0, AEMMS,
+ "END", LTYPE0, AEND,
+ "ENTER", LTYPE2, AENTER,
+ "GLOBL", LTYPET, AGLOBL,
+ "HLT", LTYPE0, AHLT,
+ "IDIVB", LTYPE2, AIDIVB,
+ "IDIVL", LTYPE2, AIDIVL,
+ "IDIVQ", LTYPE2, AIDIVQ,
+ "IDIVW", LTYPE2, AIDIVW,
+ "IMULB", LTYPEI, AIMULB,
+ "IMULL", LTYPEI, AIMULL,
+ "IMULQ", LTYPEI, AIMULQ,
+ "IMULW", LTYPEI, AIMULW,
+ "INB", LTYPE0, AINB,
+ "INL", LTYPE0, AINL,
+ "INW", LTYPE0, AINW,
+ "INCB", LTYPE1, AINCB,
+ "INCL", LTYPE1, AINCL,
+ "INCQ", LTYPE1, AINCQ,
+ "INCW", LTYPE1, AINCW,
+ "INSB", LTYPE0, AINSB,
+ "INSL", LTYPE0, AINSL,
+ "INSW", LTYPE0, AINSW,
+ "INT", LTYPE2, AINT,
+ "INTO", LTYPE0, AINTO,
+ "INVD", LTYPE0, AINVD,
+ "INVLPG", LTYPE2, AINVLPG,
+ "IRETL", LTYPE0, AIRETL,
+ "IRETQ", LTYPE0, AIRETQ,
+ "IRETW", LTYPE0, AIRETW,
+
+ "JOS", LTYPER, AJOS,
+ "JO", LTYPER, AJOS, /* alternate */
+ "JOC", LTYPER, AJOC,
+ "JNO", LTYPER, AJOC, /* alternate */
+ "JCS", LTYPER, AJCS,
+ "JB", LTYPER, AJCS, /* alternate */
+ "JC", LTYPER, AJCS, /* alternate */
+ "JNAE", LTYPER, AJCS, /* alternate */
+ "JLO", LTYPER, AJCS, /* alternate */
+ "JCC", LTYPER, AJCC,
+ "JAE", LTYPER, AJCC, /* alternate */
+ "JNB", LTYPER, AJCC, /* alternate */
+ "JNC", LTYPER, AJCC, /* alternate */
+ "JHS", LTYPER, AJCC, /* alternate */
+ "JEQ", LTYPER, AJEQ,
+ "JE", LTYPER, AJEQ, /* alternate */
+ "JZ", LTYPER, AJEQ, /* alternate */
+ "JNE", LTYPER, AJNE,
+ "JNZ", LTYPER, AJNE, /* alternate */
+ "JLS", LTYPER, AJLS,
+ "JBE", LTYPER, AJLS, /* alternate */
+ "JNA", LTYPER, AJLS, /* alternate */
+ "JHI", LTYPER, AJHI,
+ "JA", LTYPER, AJHI, /* alternate */
+ "JNBE", LTYPER, AJHI, /* alternate */
+ "JMI", LTYPER, AJMI,
+ "JS", LTYPER, AJMI, /* alternate */
+ "JPL", LTYPER, AJPL,
+ "JNS", LTYPER, AJPL, /* alternate */
+ "JPS", LTYPER, AJPS,
+ "JP", LTYPER, AJPS, /* alternate */
+ "JPE", LTYPER, AJPS, /* alternate */
+ "JPC", LTYPER, AJPC,
+ "JNP", LTYPER, AJPC, /* alternate */
+ "JPO", LTYPER, AJPC, /* alternate */
+ "JLT", LTYPER, AJLT,
+ "JL", LTYPER, AJLT, /* alternate */
+ "JNGE", LTYPER, AJLT, /* alternate */
+ "JGE", LTYPER, AJGE,
+ "JNL", LTYPER, AJGE, /* alternate */
+ "JLE", LTYPER, AJLE,
+ "JNG", LTYPER, AJLE, /* alternate */
+ "JGT", LTYPER, AJGT,
+ "JG", LTYPER, AJGT, /* alternate */
+ "JNLE", LTYPER, AJGT, /* alternate */
+
+ "JCXZ", LTYPER, AJCXZ,
+ "JMP", LTYPEC, AJMP,
+ "LAHF", LTYPE0, ALAHF,
+ "LARL", LTYPE3, ALARL,
+ "LARW", LTYPE3, ALARW,
+ "LEAL", LTYPE3, ALEAL,
+ "LEAQ", LTYPE3, ALEAQ,
+ "LEAW", LTYPE3, ALEAW,
+ "LEAVEL", LTYPE0, ALEAVEL,
+ "LEAVEQ", LTYPE0, ALEAVEQ,
+ "LEAVEW", LTYPE0, ALEAVEW,
+ "LFENCE", LTYPE0, ALFENCE,
+ "LOCK", LTYPE0, ALOCK,
+ "LODSB", LTYPE0, ALODSB,
+ "LODSL", LTYPE0, ALODSL,
+ "LODSQ", LTYPE0, ALODSQ,
+ "LODSW", LTYPE0, ALODSW,
+ "LONG", LTYPE2, ALONG,
+ "LOOP", LTYPER, ALOOP,
+ "LOOPEQ", LTYPER, ALOOPEQ,
+ "LOOPNE", LTYPER, ALOOPNE,
+ "LSLL", LTYPE3, ALSLL,
+ "LSLW", LTYPE3, ALSLW,
+ "MFENCE", LTYPE0, AMFENCE,
+ "MODE", LTYPE2, AMODE,
+ "MOVB", LTYPE3, AMOVB,
+ "MOVL", LTYPEM, AMOVL,
+ "MOVQ", LTYPEM, AMOVQ,
+ "MOVW", LTYPEM, AMOVW,
+ "MOVBLSX", LTYPE3, AMOVBLSX,
+ "MOVBLZX", LTYPE3, AMOVBLZX,
+ "MOVBQSX", LTYPE3, AMOVBQSX,
+ "MOVBQZX", LTYPE3, AMOVBQZX,
+ "MOVBWSX", LTYPE3, AMOVBWSX,
+ "MOVBWZX", LTYPE3, AMOVBWZX,
+ "MOVLQSX", LTYPE3, AMOVLQSX,
+ "MOVLQZX", LTYPE3, AMOVLQZX,
+ "MOVNTIL", LTYPE3, AMOVNTIL,
+ "MOVNTIQ", LTYPE3, AMOVNTIQ,
+ "MOVWLSX", LTYPE3, AMOVWLSX,
+ "MOVWLZX", LTYPE3, AMOVWLZX,
+ "MOVWQSX", LTYPE3, AMOVWQSX,
+ "MOVWQZX", LTYPE3, AMOVWQZX,
+ "MOVSB", LTYPE0, AMOVSB,
+ "MOVSL", LTYPE0, AMOVSL,
+ "MOVSQ", LTYPE0, AMOVSQ,
+ "MOVSW", LTYPE0, AMOVSW,
+ "MULB", LTYPE2, AMULB,
+ "MULL", LTYPE2, AMULL,
+ "MULQ", LTYPE2, AMULQ,
+ "MULW", LTYPE2, AMULW,
+ "NEGB", LTYPE1, ANEGB,
+ "NEGL", LTYPE1, ANEGL,
+ "NEGQ", LTYPE1, ANEGQ,
+ "NEGW", LTYPE1, ANEGW,
+ "NOP", LTYPEN, ANOP,
+ "NOTB", LTYPE1, ANOTB,
+ "NOTL", LTYPE1, ANOTL,
+ "NOTQ", LTYPE1, ANOTQ,
+ "NOTW", LTYPE1, ANOTW,
+ "ORB", LTYPE3, AORB,
+ "ORL", LTYPE3, AORL,
+ "ORQ", LTYPE3, AORQ,
+ "ORW", LTYPE3, AORW,
+ "OUTB", LTYPE0, AOUTB,
+ "OUTL", LTYPE0, AOUTL,
+ "OUTW", LTYPE0, AOUTW,
+ "OUTSB", LTYPE0, AOUTSB,
+ "OUTSL", LTYPE0, AOUTSL,
+ "OUTSW", LTYPE0, AOUTSW,
+ "POPAL", LTYPE0, APOPAL,
+ "POPAW", LTYPE0, APOPAW,
+ "POPFL", LTYPE0, APOPFL,
+ "POPFQ", LTYPE0, APOPFQ,
+ "POPFW", LTYPE0, APOPFW,
+ "POPL", LTYPE1, APOPL,
+ "POPQ", LTYPE1, APOPQ,
+ "POPW", LTYPE1, APOPW,
+ "PUSHAL", LTYPE0, APUSHAL,
+ "PUSHAW", LTYPE0, APUSHAW,
+ "PUSHFL", LTYPE0, APUSHFL,
+ "PUSHFQ", LTYPE0, APUSHFQ,
+ "PUSHFW", LTYPE0, APUSHFW,
+ "PUSHL", LTYPE2, APUSHL,
+ "PUSHQ", LTYPE2, APUSHQ,
+ "PUSHW", LTYPE2, APUSHW,
+ "RCLB", LTYPE3, ARCLB,
+ "RCLL", LTYPE3, ARCLL,
+ "RCLQ", LTYPE3, ARCLQ,
+ "RCLW", LTYPE3, ARCLW,
+ "RCRB", LTYPE3, ARCRB,
+ "RCRL", LTYPE3, ARCRL,
+ "RCRQ", LTYPE3, ARCRQ,
+ "RCRW", LTYPE3, ARCRW,
+ "RDMSR", LTYPE0, ARDMSR,
+ "RDPMC", LTYPE0, ARDPMC,
+ "RDTSC", LTYPE0, ARDTSC,
+ "REP", LTYPE0, AREP,
+ "REPN", LTYPE0, AREPN,
+ "RET", LTYPE0, ARET,
+ "RETFL", LTYPERT,ARETFL,
+ "RETFW", LTYPERT,ARETFW,
+ "RETFQ", LTYPERT,ARETFQ,
+ "ROLB", LTYPE3, AROLB,
+ "ROLL", LTYPE3, AROLL,
+ "ROLQ", LTYPE3, AROLQ,
+ "ROLW", LTYPE3, AROLW,
+ "RORB", LTYPE3, ARORB,
+ "RORL", LTYPE3, ARORL,
+ "RORQ", LTYPE3, ARORQ,
+ "RORW", LTYPE3, ARORW,
+ "RSM", LTYPE0, ARSM,
+ "SAHF", LTYPE0, ASAHF,
+ "SALB", LTYPE3, ASALB,
+ "SALL", LTYPE3, ASALL,
+ "SALQ", LTYPE3, ASALQ,
+ "SALW", LTYPE3, ASALW,
+ "SARB", LTYPE3, ASARB,
+ "SARL", LTYPE3, ASARL,
+ "SARQ", LTYPE3, ASARQ,
+ "SARW", LTYPE3, ASARW,
+ "SBBB", LTYPE3, ASBBB,
+ "SBBL", LTYPE3, ASBBL,
+ "SBBQ", LTYPE3, ASBBQ,
+ "SBBW", LTYPE3, ASBBW,
+ "SCASB", LTYPE0, ASCASB,
+ "SCASL", LTYPE0, ASCASL,
+ "SCASQ", LTYPE0, ASCASQ,
+ "SCASW", LTYPE0, ASCASW,
+ "SETCC", LTYPE1, ASETCC,
+ "SETCS", LTYPE1, ASETCS,
+ "SETEQ", LTYPE1, ASETEQ,
+ "SETGE", LTYPE1, ASETGE,
+ "SETGT", LTYPE1, ASETGT,
+ "SETHI", LTYPE1, ASETHI,
+ "SETLE", LTYPE1, ASETLE,
+ "SETLS", LTYPE1, ASETLS,
+ "SETLT", LTYPE1, ASETLT,
+ "SETMI", LTYPE1, ASETMI,
+ "SETNE", LTYPE1, ASETNE,
+ "SETOC", LTYPE1, ASETOC,
+ "SETOS", LTYPE1, ASETOS,
+ "SETPC", LTYPE1, ASETPC,
+ "SETPL", LTYPE1, ASETPL,
+ "SETPS", LTYPE1, ASETPS,
+ "SFENCE", LTYPE0, ASFENCE,
+ "CDQ", LTYPE0, ACDQ,
+ "CWD", LTYPE0, ACWD,
+ "CQO", LTYPE0, ACQO,
+ "SHLB", LTYPE3, ASHLB,
+ "SHLL", LTYPES, ASHLL,
+ "SHLQ", LTYPES, ASHLQ,
+ "SHLW", LTYPES, ASHLW,
+ "SHRB", LTYPE3, ASHRB,
+ "SHRL", LTYPES, ASHRL,
+ "SHRQ", LTYPES, ASHRQ,
+ "SHRW", LTYPES, ASHRW,
+ "STC", LTYPE0, ASTC,
+ "STD", LTYPE0, ASTD,
+ "STI", LTYPE0, ASTI,
+ "STOSB", LTYPE0, ASTOSB,
+ "STOSL", LTYPE0, ASTOSL,
+ "STOSQ", LTYPE0, ASTOSQ,
+ "STOSW", LTYPE0, ASTOSW,
+ "SUBB", LTYPE3, ASUBB,
+ "SUBL", LTYPE3, ASUBL,
+ "SUBQ", LTYPE3, ASUBQ,
+ "SUBW", LTYPE3, ASUBW,
+ "SYSCALL", LTYPE0, ASYSCALL,
+ "SYSRET", LTYPE0, ASYSRET,
+ "SWAPGS", LTYPE0, ASWAPGS,
+ "TESTB", LTYPE3, ATESTB,
+ "TESTL", LTYPE3, ATESTL,
+ "TESTQ", LTYPE3, ATESTQ,
+ "TESTW", LTYPE3, ATESTW,
+ "TEXT", LTYPET, ATEXT,
+ "VERR", LTYPE2, AVERR,
+ "VERW", LTYPE2, AVERW,
+ "QUAD", LTYPE2, AQUAD,
+ "WAIT", LTYPE0, AWAIT,
+ "WBINVD", LTYPE0, AWBINVD,
+ "WRMSR", LTYPE0, AWRMSR,
+ "WORD", LTYPE2, AWORD,
+ "XADDB", LTYPE3, AXADDB,
+ "XADDL", LTYPE3, AXADDL,
+ "XADDQ", LTYPE3, AXADDQ,
+ "XADDW", LTYPE3, AXADDW,
+ "XCHGB", LTYPE3, AXCHGB,
+ "XCHGL", LTYPE3, AXCHGL,
+ "XCHGQ", LTYPE3, AXCHGQ,
+ "XCHGW", LTYPE3, AXCHGW,
+ "XLAT", LTYPE2, AXLAT,
+ "XORB", LTYPE3, AXORB,
+ "XORL", LTYPE3, AXORL,
+ "XORQ", LTYPE3, AXORQ,
+ "XORW", LTYPE3, AXORW,
+
+ "CMOVLCC", LTYPE3, ACMOVLCC,
+ "CMOVLCS", LTYPE3, ACMOVLCS,
+ "CMOVLEQ", LTYPE3, ACMOVLEQ,
+ "CMOVLGE", LTYPE3, ACMOVLGE,
+ "CMOVLGT", LTYPE3, ACMOVLGT,
+ "CMOVLHI", LTYPE3, ACMOVLHI,
+ "CMOVLLE", LTYPE3, ACMOVLLE,
+ "CMOVLLS", LTYPE3, ACMOVLLS,
+ "CMOVLLT", LTYPE3, ACMOVLLT,
+ "CMOVLMI", LTYPE3, ACMOVLMI,
+ "CMOVLNE", LTYPE3, ACMOVLNE,
+ "CMOVLOC", LTYPE3, ACMOVLOC,
+ "CMOVLOS", LTYPE3, ACMOVLOS,
+ "CMOVLPC", LTYPE3, ACMOVLPC,
+ "CMOVLPL", LTYPE3, ACMOVLPL,
+ "CMOVLPS", LTYPE3, ACMOVLPS,
+ "CMOVQCC", LTYPE3, ACMOVQCC,
+ "CMOVQCS", LTYPE3, ACMOVQCS,
+ "CMOVQEQ", LTYPE3, ACMOVQEQ,
+ "CMOVQGE", LTYPE3, ACMOVQGE,
+ "CMOVQGT", LTYPE3, ACMOVQGT,
+ "CMOVQHI", LTYPE3, ACMOVQHI,
+ "CMOVQLE", LTYPE3, ACMOVQLE,
+ "CMOVQLS", LTYPE3, ACMOVQLS,
+ "CMOVQLT", LTYPE3, ACMOVQLT,
+ "CMOVQMI", LTYPE3, ACMOVQMI,
+ "CMOVQNE", LTYPE3, ACMOVQNE,
+ "CMOVQOC", LTYPE3, ACMOVQOC,
+ "CMOVQOS", LTYPE3, ACMOVQOS,
+ "CMOVQPC", LTYPE3, ACMOVQPC,
+ "CMOVQPL", LTYPE3, ACMOVQPL,
+ "CMOVQPS", LTYPE3, ACMOVQPS,
+ "CMOVWCC", LTYPE3, ACMOVWCC,
+ "CMOVWCS", LTYPE3, ACMOVWCS,
+ "CMOVWEQ", LTYPE3, ACMOVWEQ,
+ "CMOVWGE", LTYPE3, ACMOVWGE,
+ "CMOVWGT", LTYPE3, ACMOVWGT,
+ "CMOVWHI", LTYPE3, ACMOVWHI,
+ "CMOVWLE", LTYPE3, ACMOVWLE,
+ "CMOVWLS", LTYPE3, ACMOVWLS,
+ "CMOVWLT", LTYPE3, ACMOVWLT,
+ "CMOVWMI", LTYPE3, ACMOVWMI,
+ "CMOVWNE", LTYPE3, ACMOVWNE,
+ "CMOVWOC", LTYPE3, ACMOVWOC,
+ "CMOVWOS", LTYPE3, ACMOVWOS,
+ "CMOVWPC", LTYPE3, ACMOVWPC,
+ "CMOVWPL", LTYPE3, ACMOVWPL,
+ "CMOVWPS", LTYPE3, ACMOVWPS,
+
+ "FMOVB", LTYPE3, AFMOVB,
+ "FMOVBP", LTYPE3, AFMOVBP,
+ "FMOVD", LTYPE3, AFMOVD,
+ "FMOVDP", LTYPE3, AFMOVDP,
+ "FMOVF", LTYPE3, AFMOVF,
+ "FMOVFP", LTYPE3, AFMOVFP,
+ "FMOVL", LTYPE3, AFMOVL,
+ "FMOVLP", LTYPE3, AFMOVLP,
+ "FMOVV", LTYPE3, AFMOVV,
+ "FMOVVP", LTYPE3, AFMOVVP,
+ "FMOVW", LTYPE3, AFMOVW,
+ "FMOVWP", LTYPE3, AFMOVWP,
+ "FMOVX", LTYPE3, AFMOVX,
+ "FMOVXP", LTYPE3, AFMOVXP,
+ "FCOMB", LTYPE3, AFCOMB,
+ "FCOMBP", LTYPE3, AFCOMBP,
+ "FCOMD", LTYPE3, AFCOMD,
+ "FCOMDP", LTYPE3, AFCOMDP,
+ "FCOMDPP", LTYPE3, AFCOMDPP,
+ "FCOMF", LTYPE3, AFCOMF,
+ "FCOMFP", LTYPE3, AFCOMFP,
+ "FCOML", LTYPE3, AFCOML,
+ "FCOMLP", LTYPE3, AFCOMLP,
+ "FCOMW", LTYPE3, AFCOMW,
+ "FCOMWP", LTYPE3, AFCOMWP,
+ "FUCOM", LTYPE3, AFUCOM,
+ "FUCOMP", LTYPE3, AFUCOMP,
+ "FUCOMPP", LTYPE3, AFUCOMPP,
+ "FADDW", LTYPE3, AFADDW,
+ "FADDL", LTYPE3, AFADDL,
+ "FADDF", LTYPE3, AFADDF,
+ "FADDD", LTYPE3, AFADDD,
+ "FADDDP", LTYPE3, AFADDDP,
+ "FSUBDP", LTYPE3, AFSUBDP,
+ "FSUBW", LTYPE3, AFSUBW,
+ "FSUBL", LTYPE3, AFSUBL,
+ "FSUBF", LTYPE3, AFSUBF,
+ "FSUBD", LTYPE3, AFSUBD,
+ "FSUBRDP", LTYPE3, AFSUBRDP,
+ "FSUBRW", LTYPE3, AFSUBRW,
+ "FSUBRL", LTYPE3, AFSUBRL,
+ "FSUBRF", LTYPE3, AFSUBRF,
+ "FSUBRD", LTYPE3, AFSUBRD,
+ "FMULDP", LTYPE3, AFMULDP,
+ "FMULW", LTYPE3, AFMULW,
+ "FMULL", LTYPE3, AFMULL,
+ "FMULF", LTYPE3, AFMULF,
+ "FMULD", LTYPE3, AFMULD,
+ "FDIVDP", LTYPE3, AFDIVDP,
+ "FDIVW", LTYPE3, AFDIVW,
+ "FDIVL", LTYPE3, AFDIVL,
+ "FDIVF", LTYPE3, AFDIVF,
+ "FDIVD", LTYPE3, AFDIVD,
+ "FDIVRDP", LTYPE3, AFDIVRDP,
+ "FDIVRW", LTYPE3, AFDIVRW,
+ "FDIVRL", LTYPE3, AFDIVRL,
+ "FDIVRF", LTYPE3, AFDIVRF,
+ "FDIVRD", LTYPE3, AFDIVRD,
+ "FXCHD", LTYPE3, AFXCHD,
+ "FFREE", LTYPE1, AFFREE,
+ "FLDCW", LTYPE2, AFLDCW,
+ "FLDENV", LTYPE1, AFLDENV,
+ "FRSTOR", LTYPE2, AFRSTOR,
+ "FSAVE", LTYPE1, AFSAVE,
+ "FSTCW", LTYPE1, AFSTCW,
+ "FSTENV", LTYPE1, AFSTENV,
+ "FSTSW", LTYPE1, AFSTSW,
+ "F2XM1", LTYPE0, AF2XM1,
+ "FABS", LTYPE0, AFABS,
+ "FCHS", LTYPE0, AFCHS,
+ "FCLEX", LTYPE0, AFCLEX,
+ "FCOS", LTYPE0, AFCOS,
+ "FDECSTP", LTYPE0, AFDECSTP,
+ "FINCSTP", LTYPE0, AFINCSTP,
+ "FINIT", LTYPE0, AFINIT,
+ "FLD1", LTYPE0, AFLD1,
+ "FLDL2E", LTYPE0, AFLDL2E,
+ "FLDL2T", LTYPE0, AFLDL2T,
+ "FLDLG2", LTYPE0, AFLDLG2,
+ "FLDLN2", LTYPE0, AFLDLN2,
+ "FLDPI", LTYPE0, AFLDPI,
+ "FLDZ", LTYPE0, AFLDZ,
+ "FNOP", LTYPE0, AFNOP,
+ "FPATAN", LTYPE0, AFPATAN,
+ "FPREM", LTYPE0, AFPREM,
+ "FPREM1", LTYPE0, AFPREM1,
+ "FPTAN", LTYPE0, AFPTAN,
+ "FRNDINT", LTYPE0, AFRNDINT,
+ "FSCALE", LTYPE0, AFSCALE,
+ "FSIN", LTYPE0, AFSIN,
+ "FSINCOS", LTYPE0, AFSINCOS,
+ "FSQRT", LTYPE0, AFSQRT,
+ "FTST", LTYPE0, AFTST,
+ "FXAM", LTYPE0, AFXAM,
+ "FXTRACT", LTYPE0, AFXTRACT,
+ "FYL2X", LTYPE0, AFYL2X,
+ "FYL2XP1", LTYPE0, AFYL2XP1,
+
+ "ADDPD", LTYPE3, AADDPD,
+ "ADDPS", LTYPE3, AADDPS,
+ "ADDSD", LTYPE3, AADDSD,
+ "ADDSS", LTYPE3, AADDSS,
+ "ANDNPD", LTYPE3, AANDNPD,
+ "ANDNPS", LTYPE3, AANDNPS,
+ "ANDPD", LTYPE3, AANDPD,
+ "ANDPS", LTYPE3, AANDPS,
+ "CMPPD", LTYPEXC,ACMPPD,
+ "CMPPS", LTYPEXC,ACMPPS,
+ "CMPSD", LTYPEXC,ACMPSD,
+ "CMPSS", LTYPEXC,ACMPSS,
+ "COMISD", LTYPE3, ACOMISD,
+ "COMISS", LTYPE3, ACOMISS,
+ "CVTPL2PD", LTYPE3, ACVTPL2PD,
+ "CVTPL2PS", LTYPE3, ACVTPL2PS,
+ "CVTPD2PL", LTYPE3, ACVTPD2PL,
+ "CVTPD2PS", LTYPE3, ACVTPD2PS,
+ "CVTPS2PL", LTYPE3, ACVTPS2PL,
+ "PF2IW", LTYPE3, APF2IW,
+ "PF2IL", LTYPE3, APF2IL,
+ "PF2ID", LTYPE3, APF2IL, /* syn */
+ "PI2FL", LTYPE3, API2FL,
+ "PI2FD", LTYPE3, API2FL, /* syn */
+ "PI2FW", LTYPE3, API2FW,
+ "CVTPS2PD", LTYPE3, ACVTPS2PD,
+ "CVTSD2SL", LTYPE3, ACVTSD2SL,
+ "CVTSD2SQ", LTYPE3, ACVTSD2SQ,
+ "CVTSD2SS", LTYPE3, ACVTSD2SS,
+ "CVTSL2SD", LTYPE3, ACVTSL2SD,
+ "CVTSQ2SD", LTYPE3, ACVTSQ2SD,
+ "CVTSL2SS", LTYPE3, ACVTSL2SS,
+ "CVTSQ2SS", LTYPE3, ACVTSQ2SS,
+ "CVTSS2SD", LTYPE3, ACVTSS2SD,
+ "CVTSS2SL", LTYPE3, ACVTSS2SL,
+ "CVTSS2SQ", LTYPE3, ACVTSS2SQ,
+ "CVTTPD2PL", LTYPE3, ACVTTPD2PL,
+ "CVTTPS2PL", LTYPE3, ACVTTPS2PL,
+ "CVTTSD2SL", LTYPE3, ACVTTSD2SL,
+ "CVTTSD2SQ", LTYPE3, ACVTTSD2SQ,
+ "CVTTSS2SL", LTYPE3, ACVTTSS2SL,
+ "CVTTSS2SQ", LTYPE3, ACVTTSS2SQ,
+ "DIVPD", LTYPE3, ADIVPD,
+ "DIVPS", LTYPE3, ADIVPS,
+ "DIVSD", LTYPE3, ADIVSD,
+ "DIVSS", LTYPE3, ADIVSS,
+ "FXRSTOR", LTYPE2, AFXRSTOR,
+ "FXRSTOR64", LTYPE2, AFXRSTOR64,
+ "FXSAVE", LTYPE1, AFXSAVE,
+ "FXSAVE64", LTYPE1, AFXSAVE64,
+ "LDMXCSR", LTYPE2, ALDMXCSR,
+ "MASKMOVOU", LTYPE3, AMASKMOVOU,
+ "MASKMOVDQU", LTYPE3, AMASKMOVOU, /* syn */
+ "MASKMOVQ", LTYPE3, AMASKMOVQ,
+ "MAXPD", LTYPE3, AMAXPD,
+ "MAXPS", LTYPE3, AMAXPS,
+ "MAXSD", LTYPE3, AMAXSD,
+ "MAXSS", LTYPE3, AMAXSS,
+ "MINPD", LTYPE3, AMINPD,
+ "MINPS", LTYPE3, AMINPS,
+ "MINSD", LTYPE3, AMINSD,
+ "MINSS", LTYPE3, AMINSS,
+ "MOVAPD", LTYPE3, AMOVAPD,
+ "MOVAPS", LTYPE3, AMOVAPS,
+ "MOVD", LTYPE3, AMOVQ, /* syn */
+ "MOVDQ2Q", LTYPE3, AMOVQ, /* syn */
+ "MOVO", LTYPE3, AMOVO,
+ "MOVOA", LTYPE3, AMOVO, /* syn */
+ "MOVOU", LTYPE3, AMOVOU,
+ "MOVHLPS", LTYPE3, AMOVHLPS,
+ "MOVHPD", LTYPE3, AMOVHPD,
+ "MOVHPS", LTYPE3, AMOVHPS,
+ "MOVLHPS", LTYPE3, AMOVLHPS,
+ "MOVLPD", LTYPE3, AMOVLPD,
+ "MOVLPS", LTYPE3, AMOVLPS,
+ "MOVMSKPD", LTYPE3, AMOVMSKPD,
+ "MOVMSKPS", LTYPE3, AMOVMSKPS,
+ "MOVNTO", LTYPE3, AMOVNTO,
+ "MOVNTDQ", LTYPE3, AMOVNTO, /* syn */
+ "MOVNTPD", LTYPE3, AMOVNTPD,
+ "MOVNTPS", LTYPE3, AMOVNTPS,
+ "MOVNTQ", LTYPE3, AMOVNTQ,
+ "MOVQOZX", LTYPE3, AMOVQOZX,
+ "MOVSD", LTYPE3, AMOVSD,
+ "MOVSS", LTYPE3, AMOVSS,
+ "MOVUPD", LTYPE3, AMOVUPD,
+ "MOVUPS", LTYPE3, AMOVUPS,
+ "MULPD", LTYPE3, AMULPD,
+ "MULPS", LTYPE3, AMULPS,
+ "MULSD", LTYPE3, AMULSD,
+ "MULSS", LTYPE3, AMULSS,
+ "ORPD", LTYPE3, AORPD,
+ "ORPS", LTYPE3, AORPS,
+ "PACKSSLW", LTYPE3, APACKSSLW,
+ "PACKSSWB", LTYPE3, APACKSSWB,
+ "PACKUSWB", LTYPE3, APACKUSWB,
+ "PADDB", LTYPE3, APADDB,
+ "PADDL", LTYPE3, APADDL,
+ "PADDQ", LTYPE3, APADDQ,
+ "PADDSB", LTYPE3, APADDSB,
+ "PADDSW", LTYPE3, APADDSW,
+ "PADDUSB", LTYPE3, APADDUSB,
+ "PADDUSW", LTYPE3, APADDUSW,
+ "PADDW", LTYPE3, APADDW,
+ "PAND", LTYPE3, APAND,
+ "PANDB", LTYPE3, APANDB,
+ "PANDL", LTYPE3, APANDL,
+ "PANDSB", LTYPE3, APANDSB,
+ "PANDSW", LTYPE3, APANDSW,
+ "PANDUSB", LTYPE3, APANDUSB,
+ "PANDUSW", LTYPE3, APANDUSW,
+ "PANDW", LTYPE3, APANDW,
+ "PANDN", LTYPE3, APANDN,
+ "PAVGB", LTYPE3, APAVGB,
+ "PAVGW", LTYPE3, APAVGW,
+ "PCMPEQB", LTYPE3, APCMPEQB,
+ "PCMPEQL", LTYPE3, APCMPEQL,
+ "PCMPEQW", LTYPE3, APCMPEQW,
+ "PCMPGTB", LTYPE3, APCMPGTB,
+ "PCMPGTL", LTYPE3, APCMPGTL,
+ "PCMPGTW", LTYPE3, APCMPGTW,
+ "PEXTRW", LTYPEX, APEXTRW,
+ "PINSRW", LTYPEX, APINSRW,
+ "PMADDWL", LTYPE3, APMADDWL,
+ "PMAXSW", LTYPE3, APMAXSW,
+ "PMAXUB", LTYPE3, APMAXUB,
+ "PMINSW", LTYPE3, APMINSW,
+ "PMINUB", LTYPE3, APMINUB,
+ "PMOVMSKB", LTYPE3, APMOVMSKB,
+ "PMULHRW", LTYPE3, APMULHRW,
+ "PMULHUW", LTYPE3, APMULHUW,
+ "PMULHW", LTYPE3, APMULHW,
+ "PMULLW", LTYPE3, APMULLW,
+ "PMULULQ", LTYPE3, APMULULQ,
+ "POR", LTYPE3, APOR,
+ "PSADBW", LTYPE3, APSADBW,
+ "PSHUFHW", LTYPEX, APSHUFHW,
+ "PSHUFL", LTYPEX, APSHUFL,
+ "PSHUFLW", LTYPEX, APSHUFLW,
+ "PSHUFW", LTYPEX, APSHUFW,
+ "PSLLO", LTYPE3, APSLLO,
+ "PSLLDQ", LTYPE3, APSLLO, /* syn */
+ "PSLLL", LTYPE3, APSLLL,
+ "PSLLQ", LTYPE3, APSLLQ,
+ "PSLLW", LTYPE3, APSLLW,
+ "PSRAL", LTYPE3, APSRAL,
+ "PSRAW", LTYPE3, APSRAW,
+ "PSRLO", LTYPE3, APSRLO,
+ "PSRLDQ", LTYPE3, APSRLO, /* syn */
+ "PSRLL", LTYPE3, APSRLL,
+ "PSRLQ", LTYPE3, APSRLQ,
+ "PSRLW", LTYPE3, APSRLW,
+ "PSUBB", LTYPE3, APSUBB,
+ "PSUBL", LTYPE3, APSUBL,
+ "PSUBQ", LTYPE3, APSUBQ,
+ "PSUBSB", LTYPE3, APSUBSB,
+ "PSUBSW", LTYPE3, APSUBSW,
+ "PSUBUSB", LTYPE3, APSUBUSB,
+ "PSUBUSW", LTYPE3, APSUBUSW,
+ "PSUBW", LTYPE3, APSUBW,
+ "PUNPCKHBW", LTYPE3, APUNPCKHBW,
+ "PUNPCKHLQ", LTYPE3, APUNPCKHLQ,
+ "PUNPCKHQDQ", LTYPE3, APUNPCKHQDQ,
+ "PUNPCKHWL", LTYPE3, APUNPCKHWL,
+ "PUNPCKLBW", LTYPE3, APUNPCKLBW,
+ "PUNPCKLLQ", LTYPE3, APUNPCKLLQ,
+ "PUNPCKLQDQ", LTYPE3, APUNPCKLQDQ,
+ "PUNPCKLWL", LTYPE3, APUNPCKLWL,
+ "PXOR", LTYPE3, APXOR,
+ "RCPPS", LTYPE3, ARCPPS,
+ "RCPSS", LTYPE3, ARCPSS,
+ "RSQRTPS", LTYPE3, ARSQRTPS,
+ "RSQRTSS", LTYPE3, ARSQRTSS,
+ "SHUFPD", LTYPEX, ASHUFPD,
+ "SHUFPS", LTYPEX, ASHUFPS,
+ "SQRTPD", LTYPE3, ASQRTPD,
+ "SQRTPS", LTYPE3, ASQRTPS,
+ "SQRTSD", LTYPE3, ASQRTSD,
+ "SQRTSS", LTYPE3, ASQRTSS,
+ "STMXCSR", LTYPE1, ASTMXCSR,
+ "SUBPD", LTYPE3, ASUBPD,
+ "SUBPS", LTYPE3, ASUBPS,
+ "SUBSD", LTYPE3, ASUBSD,
+ "SUBSS", LTYPE3, ASUBSS,
+ "UCOMISD", LTYPE3, AUCOMISD,
+ "UCOMISS", LTYPE3, AUCOMISS,
+ "UNPCKHPD", LTYPE3, AUNPCKHPD,
+ "UNPCKHPS", LTYPE3, AUNPCKHPS,
+ "UNPCKLPD", LTYPE3, AUNPCKLPD,
+ "UNPCKLPS", LTYPE3, AUNPCKLPS,
+ "XORPD", LTYPE3, AXORPD,
+ "XORPS", LTYPE3, AXORPS,
+
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+
+ nullgen.sym = S;
+ nullgen.offset = 0;
+ if(FPCHIP)
+ nullgen.dval = 0;
+ for(i=0; i<sizeof(nullgen.sval); i++)
+ nullgen.sval[i] = 0;
+ nullgen.type = D_NONE;
+ nullgen.index = D_NONE;
+ nullgen.scale = 0;
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ if(s->type != LNAME)
+ yyerror("double initialization %s", itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+
+ pathname = allocn(pathname, 0, 100);
+ if(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+checkscale(int scale)
+{
+
+ switch(scale) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ return;
+ }
+ yyerror("scale must be 1248: %d", scale);
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+void
+cclean(void)
+{
+ Gen2 g2;
+
+ g2.from = nullgen;
+ g2.to = nullgen;
+ outcode(AEND, &g2);
+ Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+ Bputc(&obuf, ANAME); /* as(2) */
+ Bputc(&obuf, ANAME>>8);
+ Bputc(&obuf, t); /* type */
+ Bputc(&obuf, s); /* sym */
+ while(*n) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+ long l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(a->offset != 0) {
+ t |= T_OFFSET;
+ l = a->offset;
+ if((vlong)l != a->offset)
+ t |= T_64;
+ }
+ if(s != 0)
+ t |= T_SYM;
+
+ switch(a->type) {
+ default:
+ t |= T_TYPE;
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ case D_NONE:
+ break;
+ }
+ Bputc(&obuf, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ Bputc(&obuf, a->index);
+ Bputc(&obuf, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ if(t & T_64) {
+ l = a->offset>>32;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ }
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(&obuf, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ l = e.h;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ Bputc(&obuf, a->type);
+}
+
+void
+outcode(int a, Gen2 *g2)
+{
+ int sf, st, t;
+ Sym *s;
+
+ if(pass == 1)
+ goto out;
+
+jackpot:
+ sf = 0;
+ s = g2->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = g2->from.type;
+ if(t == D_ADDR)
+ t = g2->from.index;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = g2->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = g2->to.type;
+ if(t == D_ADDR)
+ t = g2->to.index;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&obuf, a);
+ Bputc(&obuf, a>>8);
+ Bputc(&obuf, lineno);
+ Bputc(&obuf, lineno>>8);
+ Bputc(&obuf, lineno>>16);
+ Bputc(&obuf, lineno>>24);
+ zaddr(&g2->from, sf);
+ zaddr(&g2->to, st);
+
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+void
+outhist(void)
+{
+ Gen g;
+ Hist *h;
+ char *p, *q, *op, c;
+ int n;
+
+ g = nullgen;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = strchr(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, ANAME>>8);
+ Bputc(&obuf, D_FILE); /* type */
+ Bputc(&obuf, 1); /* sym */
+ Bputc(&obuf, '<');
+ Bwrite(&obuf, p, n);
+ Bputc(&obuf, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ g.offset = h->offset;
+
+ Bputc(&obuf, AHISTORY);
+ Bputc(&obuf, AHISTORY>>8);
+ Bputc(&obuf, h->line);
+ Bputc(&obuf, h->line>>8);
+ Bputc(&obuf, h->line>>16);
+ Bputc(&obuf, h->line>>24);
+ zaddr(&nullgen, 0);
+ zaddr(&g, 0);
+ }
+}
+
+void
+pragbldicks(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+praghjdicks(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c
new file mode 100644
index 0000000..7463aa6
--- /dev/null
+++ b/src/cmd/6c/cgen.c
@@ -0,0 +1,1971 @@
+// Inferno utils/6c/cgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/cgen.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+/* ,x/^(print|prtree)\(/i/\/\/ */
+int castup(Type*, Type*);
+
+void
+cgen(Node *n, Node *nn)
+{
+ Node *l, *r, *t;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o, hardleft;
+ long v, curs;
+ vlong c;
+
+ if(debug['g']) {
+ prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesu[n->type->etype]) {
+ sugen(n, nn, n->type->width);
+ return;
+ }
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ if(n->addable >= INDEXED) {
+ if(nn == Z) {
+ switch(o) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n, nn);
+ return;
+ }
+ curs = cursafe;
+
+ if(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ if(cond(o) && typesu[l->type->etype])
+ break;
+
+ regret(&nod, r);
+ cgen(r, &nod);
+
+ regsalloc(&nod1, r);
+ gmove(&nod, &nod1);
+
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+
+ cgen(&nod, nn);
+ return;
+
+ case OFUNC:
+ case OCOMMA:
+ case OANDAND:
+ case OOROR:
+ case OCOND:
+ case ODOT:
+ break;
+ }
+
+ hardleft = l->addable < INDEXED || l->complex >= FNX;
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case ONEG:
+ case OCOM:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, n->type, Z, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ if(!hardleft) {
+ if(nn != Z || r->addable < INDEXED || hardconst(r)) {
+ if(r->complex >= FNX && nn == Z)
+ regret(&nod, r);
+ else
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gmove(&nod, l);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ gmove(r, l);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ if(l->op == OINDEX && immconst(r)) {
+ gmove(r, l);
+ break;
+ }
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED && !hardconst(r)) {
+ gmove(r, &nod1);
+ if(nn != Z)
+ gmove(r, nn);
+ regfree(&nod1);
+ break;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ reglcgen(&nod1, l, Z);
+ }
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ bitas:
+ n = l->left;
+ regalloc(&nod, r, nn);
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, n, Z);
+ cgen(r, &nod);
+ } else {
+ cgen(r, &nod);
+ reglcgen(&nod1, n, Z);
+ }
+ regalloc(&nod2, n, Z);
+ gmove(&nod1, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(r->op == OCONST) {
+ if(r->vconst == 0) {
+ cgen(l, nn);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(o == OASHL && r->vconst == 1)
+ gopcode(OADD, n->type, &nod, &nod);
+ else
+ gopcode(o, n->type, r, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+
+ /*
+ * get nod to be D_CX
+ */
+ if(nodreg(&nod, nn, D_CX)) {
+ regsalloc(&nod1, n);
+ gmove(&nod, &nod1);
+ cgen(n, &nod); /* probably a bug */
+ gmove(&nod, nn);
+ gmove(&nod1, &nod);
+ break;
+ }
+ reg[D_CX]++;
+ if(nn->op == OREGISTER && nn->reg == D_CX)
+ regalloc(&nod1, l, Z);
+ else
+ regalloc(&nod1, l, nn);
+ if(r->complex >= l->complex) {
+ cgen(r, &nod);
+ cgen(l, &nod1);
+ } else {
+ cgen(l, &nod1);
+ cgen(r, &nod);
+ }
+ gopcode(o, n->type, &nod, &nod1);
+ gmove(&nod1, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OADD:
+ case OSUB:
+ case OOR:
+ case OXOR:
+ case OAND:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(typefd[n->type->etype])
+ goto fop;
+ if(r->op == OCONST) {
+ if(r->vconst == 0 && o != OAND) {
+ cgen(l, nn);
+ break;
+ }
+ }
+ if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
+ && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
+ c = l->right->vconst;
+ if(c > 0 && c <= 3) {
+ if(l->left->complex >= r->complex) {
+ regalloc(&nod, l->left, nn);
+ cgen(l->left, &nod);
+ if(r->addable < INDEXED) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ genmuladd(&nod, &nod, 1 << c, &nod1);
+ regfree(&nod1);
+ }
+ else
+ genmuladd(&nod, &nod, 1 << c, r);
+ }
+ else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l->left, Z);
+ cgen(l->left, &nod1);
+ genmuladd(&nod, &nod1, 1 << c, &nod);
+ regfree(&nod1);
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+ }
+ if(r->addable >= INDEXED && !hardconst(r)) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, n->type, r, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, n->type, &nod1, &nod);
+ } else {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ regalloc(&nod, l, Z);
+ cgen(l, &nod);
+ gopcode(o, n->type, &nod1, &nod);
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OLMOD:
+ case OMOD:
+ case OLMUL:
+ case OLDIV:
+ case OMUL:
+ case ODIV:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(typefd[n->type->etype])
+ goto fop;
+ if(r->op == OCONST && typechl[n->type->etype]) { /* TO DO */
+ SET(v);
+ switch(o) {
+ case ODIV:
+ case OMOD:
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ v = log2(c);
+ if(v < 0)
+ break;
+ /* fall thru */
+ case OMUL:
+ case OLMUL:
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ switch(o) {
+ case OMUL:
+ case OLMUL:
+ mulgen(n->type, r, &nod);
+ break;
+ case ODIV:
+ sdiv2(r->vconst, v, l, &nod);
+ break;
+ case OMOD:
+ smod2(r->vconst, v, l, &nod);
+ break;
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ goto done;
+ case OLDIV:
+ c = r->vconst;
+ if((c & 0x80000000) == 0)
+ break;
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ regalloc(&nod, l, nn);
+ zeroregm(&nod);
+ gins(ACMPL, &nod1, nodconst(c));
+ gins(ASBBL, nodconst(-1), &nod);
+ regfree(&nod1);
+ gmove(&nod, nn);
+ regfree(&nod);
+ goto done;
+ }
+ }
+
+ if(o == OMUL) {
+ if(l->addable >= INDEXED) {
+ t = l;
+ l = r;
+ r = t;
+ }
+ /* should favour AX */
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED || hardconst(r)) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(OMUL, n->type, &nod1, &nod);
+ regfree(&nod1);
+ }else
+ gopcode(OMUL, n->type, r, &nod); /* addressible */
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+
+ /*
+ * get nod to be D_AX
+ * get nod1 to be D_DX
+ */
+ if(nodreg(&nod, nn, D_AX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod, &nod2);
+ v = reg[D_AX];
+ reg[D_AX] = 0;
+
+ if(isreg(l, D_AX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_AX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod);
+ reg[D_AX] = v;
+ break;
+ }
+ if(nodreg(&nod1, nn, D_DX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod1, &nod2);
+ v = reg[D_DX];
+ reg[D_DX] = 0;
+
+ if(isreg(l, D_DX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_DX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod1);
+ reg[D_DX] = v;
+ break;
+ }
+ reg[D_AX]++;
+
+ if(r->op == OCONST && (o == ODIV || o == OLDIV) && immconst(r) && typechl[r->type->etype]) {
+ reg[D_DX]++;
+ if(l->addable < INDEXED) {
+ regalloc(&nod2, l, Z);
+ cgen(l, &nod2);
+ l = &nod2;
+ }
+ if(o == ODIV)
+ sdivgen(l, r, &nod, &nod1);
+ else
+ udivgen(l, r, &nod, &nod1);
+ gmove(&nod1, nn);
+ if(l == &nod2)
+ regfree(l);
+ goto freeaxdx;
+ }
+
+ if(l->complex >= r->complex) {
+ cgen(l, &nod);
+ reg[D_DX]++;
+ if(o == ODIV || o == OMOD)
+ gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+ if(o == OLDIV || o == OLMOD)
+ zeroregm(&nod1);
+ if(r->addable < INDEXED || r->op == OCONST) {
+ regsalloc(&nod3, r);
+ cgen(r, &nod3);
+ gopcode(o, n->type, &nod3, Z);
+ } else
+ gopcode(o, n->type, r, Z);
+ } else {
+ regsalloc(&nod3, r);
+ cgen(r, &nod3);
+ cgen(l, &nod);
+ reg[D_DX]++;
+ if(o == ODIV || o == OMOD)
+ gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+ if(o == OLDIV || o == OLMOD)
+ zeroregm(&nod1);
+ gopcode(o, n->type, &nod3, Z);
+ }
+ if(o == OMOD || o == OLMOD)
+ gmove(&nod1, nn);
+ else
+ gmove(&nod, nn);
+ freeaxdx:
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ if(r->op == OCONST)
+ goto asand;
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype])
+ goto asand; /* can this happen? */
+
+ /*
+ * get nod to be D_CX
+ */
+ if(nodreg(&nod, nn, D_CX)) {
+ regsalloc(&nod1, n);
+ gmove(&nod, &nod1);
+ cgen(n, &nod);
+ if(nn != Z)
+ gmove(&nod, nn);
+ gmove(&nod1, &nod);
+ break;
+ }
+ reg[D_CX]++;
+
+ if(r->complex >= l->complex) {
+ cgen(r, &nod);
+ if(hardleft)
+ reglcgen(&nod1, l, Z);
+ else
+ nod1 = *l;
+ } else {
+ if(hardleft)
+ reglcgen(&nod1, l, Z);
+ else
+ nod1 = *l;
+ cgen(r, &nod);
+ }
+
+ gopcode(o, l->type, &nod, &nod1);
+ regfree(&nod);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ if(hardleft)
+ regfree(&nod1);
+ break;
+
+ case OASAND:
+ case OASADD:
+ case OASSUB:
+ case OASXOR:
+ case OASOR:
+ asand:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[l->type->etype] || typefd[r->type->etype])
+ goto asfop;
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(!immconst(r)) {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, r, &nod);
+ } else {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ }
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ asfop:
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(r->addable < INDEXED){
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ }else
+ nod1 = *r;
+ regalloc(&nod2, r, Z);
+ gmove(&nod, &nod2);
+ gopcode(o, r->type, &nod1, &nod2);
+ gmove(&nod2, &nod);
+ regfree(&nod2);
+ if(r->addable < INDEXED)
+ regfree(&nod1);
+ } else {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(o != OASMUL && o != OASADD) {
+ regalloc(&nod2, r, Z);
+ gmove(&nod, &nod2);
+ gopcode(o, r->type, &nod1, &nod2);
+ regfree(&nod1);
+ gmove(&nod2, &nod);
+ regfree(&nod2);
+ } else {
+ gopcode(o, r->type, &nod, &nod1);
+ gmove(&nod1, &nod);
+ regfree(&nod1);
+ }
+ }
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype] || typefd[r->type->etype])
+ goto asfop;
+ if(r->op == OCONST && typechl[n->type->etype]) {
+ SET(v);
+ switch(o) {
+ case OASDIV:
+ case OASMOD:
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ v = log2(c);
+ if(v < 0)
+ break;
+ /* fall thru */
+ case OASMUL:
+ case OASLMUL:
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, l, nn);
+ cgen(&nod2, &nod);
+ switch(o) {
+ case OASMUL:
+ case OASLMUL:
+ mulgen(n->type, r, &nod);
+ break;
+ case OASDIV:
+ sdiv2(r->vconst, v, l, &nod);
+ break;
+ case OASMOD:
+ smod2(r->vconst, v, l, &nod);
+ break;
+ }
+ havev:
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod2);
+ regfree(&nod);
+ goto done;
+ case OASLDIV:
+ c = r->vconst;
+ if((c & 0x80000000) == 0)
+ break;
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod1, l, nn);
+ cgen(&nod2, &nod1);
+ regalloc(&nod, l, nn);
+ zeroregm(&nod);
+ gins(ACMPL, &nod1, nodconst(c));
+ gins(ASBBL, nodconst(-1), &nod);
+ regfree(&nod1);
+ goto havev;
+ }
+ }
+
+ if(o == OASMUL) {
+ /* should favour AX */
+ regalloc(&nod, l, nn);
+ if(r->complex >= FNX) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ r = &nod1;
+ }
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(r->addable < INDEXED || hardconst(r)) {
+ if(r->complex < FNX) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ }
+ gopcode(OASMUL, n->type, &nod1, &nod);
+ regfree(&nod1);
+ }
+ else
+ gopcode(OASMUL, n->type, r, &nod);
+ if(r == &nod1)
+ regfree(r);
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ if(hardleft)
+ regfree(&nod2);
+ break;
+ }
+
+ /*
+ * get nod to be D_AX
+ * get nod1 to be D_DX
+ */
+ if(nodreg(&nod, nn, D_AX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod, &nod2);
+ v = reg[D_AX];
+ reg[D_AX] = 0;
+
+ if(isreg(l, D_AX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_AX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod);
+ reg[D_AX] = v;
+ break;
+ }
+ if(nodreg(&nod1, nn, D_DX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod1, &nod2);
+ v = reg[D_DX];
+ reg[D_DX] = 0;
+
+ if(isreg(l, D_DX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_DX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod1);
+ reg[D_DX] = v;
+ break;
+ }
+ reg[D_AX]++;
+ reg[D_DX]++;
+
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(r->op == OCONST && typechl[r->type->etype]) {
+ switch(o) {
+ case OASDIV:
+ sdivgen(&nod2, r, &nod, &nod1);
+ goto divdone;
+ case OASLDIV:
+ udivgen(&nod2, r, &nod, &nod1);
+ divdone:
+ gmove(&nod1, &nod2);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ goto freelxaxdx;
+ }
+ }
+ if(o == OASDIV || o == OASMOD)
+ gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+ if(o == OASLDIV || o == OASLMOD)
+ zeroregm(&nod1);
+ if(r->addable < INDEXED || r->op == OCONST ||
+ !typeil[r->type->etype]) {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ gopcode(o, l->type, &nod3, Z);
+ regfree(&nod3);
+ } else
+ gopcode(o, n->type, r, Z);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(o == OASDIV || o == OASMOD)
+ gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+ if(o == OASLDIV || o == OASLMOD)
+ zeroregm(&nod1);
+ gopcode(o, l->type, &nod3, Z);
+ regfree(&nod3);
+ }
+ if(o == OASMOD || o == OASLMOD) {
+ gmove(&nod1, &nod2);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ } else {
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ }
+ freelxaxdx:
+ if(hardleft)
+ regfree(&nod2);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ fop:
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, n->type, &nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, n->type, r, &nod);
+ } else {
+ /* TO DO: could do better with r->addable >= INDEXED */
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, n->type, &nod1, &nod);
+ regfree(&nod1);
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ asbitop:
+ regalloc(&nod4, n, nn);
+ if(l->complex >= r->complex) {
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ }
+ gmove(&nod, &nod4);
+
+ { /* TO DO: check floating point source */
+ Node onod;
+
+ /* incredible grot ... */
+ onod = nod3;
+ onod.op = o;
+ onod.complex = 2;
+ onod.addable = 0;
+ onod.type = tfield;
+ onod.left = &nod4;
+ onod.right = &nod3;
+ cgen(&onod, Z);
+ }
+ regfree(&nod3);
+ gmove(&nod4, &nod);
+ regfree(&nod4);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OADDR:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, nn);
+ break;
+
+ case OFUNC:
+ if(l->complex >= FNX) {
+ if(l->op != OIND)
+ diag(n, "bad function call");
+
+ regret(&nod, l->left);
+ cgen(l->left, &nod);
+ regsalloc(&nod1, l->left);
+ gmove(&nod, &nod1);
+ regfree(&nod);
+
+ nod = *n;
+ nod.left = &nod2;
+ nod2 = *l;
+ nod2.left = &nod1;
+ nod2.complex = 1;
+ cgen(&nod, nn);
+
+ return;
+ }
+ o = reg[REGARG];
+ gargs(r, &nod, &nod1);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, nn);
+ nod.op = OREGISTER;
+ gopcode(OFUNC, n->type, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, n->type, Z, l);
+ if(REGARG)
+ if(o != reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gmove(&nod, nn);
+ regfree(&nod);
+ }
+ break;
+
+ case OIND:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regialloc(&nod, n, nn);
+ r = l;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ cgen(l, &nod);
+ nod.xoffset += v;
+ r->vconst = v;
+ } else
+ cgen(l, &nod);
+ regind(&nod, n);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, nn);
+ if(nn == Z)
+ patch(p, pc);
+ break;
+
+ case ONOT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OCOMMA:
+ cgen(l, Z);
+ cgen(r, nn);
+ break;
+
+ case OCAST:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ /*
+ * convert from types l->n->nn
+ */
+ if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
+ /* both null, gen l->nn */
+ cgen(l, nn);
+ break;
+ }
+ if(ewidth[n->type->etype] < ewidth[l->type->etype]){
+ if(l->type->etype == TIND && typechlp[n->type->etype])
+ warn(n, "conversion of pointer to shorter integer");
+ }else if(0){
+ if(nocast(n->type, nn->type) || castup(n->type, nn->type)){
+ if(typefd[l->type->etype] != typefd[nn->type->etype])
+ regalloc(&nod, l, nn);
+ else
+ regalloc(&nod, nn, nn);
+ cgen(l, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, n, &nod);
+ gmove(&nod, &nod1);
+ gmove(&nod1, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn == Z)
+ break;
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += (long)r->vconst;
+ nod.type = n->type;
+ cgen(&nod, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ cgen(r->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ cgen(r->right, nn);
+ patch(p1, pc);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+
+ gmove(&nod, nn);
+ if(typefd[n->type->etype]) {
+ regalloc(&nod1, l, Z);
+ gmove(&nod, &nod1);
+ if(v < 0)
+ gopcode(OSUB, n->type, nodfconst(-v), &nod1);
+ else
+ gopcode(OADD, n->type, nodfconst(v), &nod1);
+ gmove(&nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(OADD, n->type, nodconst(v), &nod);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(typefd[n->type->etype]) {
+ regalloc(&nod1, l, Z);
+ gmove(&nod, &nod1);
+ if(v < 0)
+ gopcode(OSUB, n->type, nodfconst(-v), &nod1);
+ else
+ gopcode(OADD, n->type, nodfconst(v), &nod1);
+ gmove(&nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(OADD, n->type, nodconst(v), &nod);
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gmove(&nod, nn);
+ gopcode(OADD, tfield, nodconst(v), &nod);
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ gopcode(OADD, tfield, nodconst(v), &nod);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+done:
+ cursafe = curs;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+ Node *r;
+ long v;
+
+ regialloc(t, n, nn);
+ if(n->op == OIND) {
+ r = n->left;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ lcgen(n, t);
+ t->xoffset += v;
+ r->vconst = v;
+ regind(t, n);
+ return;
+ }
+ }
+ lcgen(n, t);
+ regind(t, n);
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+ Prog *p1;
+ Node nod;
+
+ if(debug['g']) {
+ prtree(nn, "lcgen lhs");
+ prtree(n, "lcgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(nn == Z) {
+ nn = &nod;
+ regalloc(&nod, n, Z);
+ }
+ switch(n->op) {
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ gopcode(OADDR, n->type, n, nn);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, n->left);
+ lcgen(n->right, nn);
+ break;
+
+ case OIND:
+ cgen(n->left, nn);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ lcgen(n->right->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ lcgen(n->right->right, nn);
+ patch(p1, pc);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ long curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ o = ONE;
+ if(true)
+ o = OEQ;
+ /* bad, 13 is address of external that becomes constant */
+ if(n->addable >= INDEXED && n->addable != 13) {
+ if(typefd[n->type->etype]) {
+ regalloc(&nod1, n, Z);
+ gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */
+ gopcode(o, n->type, n, &nod1);
+ regfree(&nod1);
+ } else
+ gopcode(o, n->type, n, nodconst(0));
+ goto com;
+ }
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ if(typefd[n->type->etype]) {
+ regalloc(&nod1, n, Z);
+ gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */
+ gopcode(o, n->type, &nod, &nod1);
+ regfree(&nod1);
+ } else
+ gopcode(o, n->type, &nod, nodconst(0));
+ regfree(&nod);
+ goto com;
+
+ case OCONST:
+ o = vconst(n);
+ if(!true)
+ o = !o;
+ gbranch(OGOTO);
+ if(o) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+
+ case OCOMMA:
+ cgen(l, Z);
+ boolgen(r, true, nn);
+ break;
+
+ case ONOT:
+ boolgen(l, !true, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ bcgen(r->left, true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ bcgen(r->right, !true);
+ patch(p2, pc);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ bcgen(l, true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bcgen(l, !true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ o = n->op;
+ if(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r);
+ cgen(r, &nod);
+ regsalloc(&nod1, r);
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(immconst(l)) {
+ o = invrel[relindex(o)];
+ /* bad, 13 is address of external that becomes constant */
+ if(r->addable < INDEXED || r->addable == 13) {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gopcode(o, l->type, &nod, l);
+ regfree(&nod);
+ } else
+ gopcode(o, l->type, r, l);
+ goto com;
+ }
+ if(typefd[l->type->etype])
+ o = invrel[relindex(logrel[relindex(o)])];
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED || hardconst(r) || typefd[l->type->etype]) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, l->type, &nod, &nod1);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, &nod, r);
+ regfree(&nod);
+ goto com;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ if(l->addable < INDEXED || l->addable == 13 || hardconst(l)) {
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ if(typechl[l->type->etype] && ewidth[l->type->etype] <= ewidth[TINT])
+ gopcode(o, types[TINT], &nod1, &nod);
+ else
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, l, &nod);
+ regfree(&nod);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gmove(nodconst(1L), nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gmove(nodconst(0L), nn);
+ patch(p2, pc);
+ }
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, long w)
+{
+ Prog *p1;
+ Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+ Type *t;
+ int c, mt, mo;
+ vlong o0, o1;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ prtree(nn, "sugen lhs");
+ prtree(n, "sugen");
+ }
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ switch(n->op) {
+ case OIND:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ default:
+ goto copy;
+
+ case OCONST:
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn == Z)
+ break;
+ warn(n, "non-interruptable temporary");
+ nod1 = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod1.xoffset += (long)r->vconst;
+ nod1.type = n->type;
+ sugen(&nod1, nn, w);
+ break;
+
+ case OSTRUCT:
+ /*
+ * rewrite so lhs has no fn call
+ */
+ if(nn != Z && side(nn)) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regret(&nod2, &nod1);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ cgen(&nod2, &nod0);
+ regfree(&nod2);
+
+ nod1 = *n;
+ nod1.op = OIND;
+ nod1.left = &nod0;
+ nod1.right = Z;
+ nod1.complex = 1;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ if(nn == Z) {
+ cgen(l, nn);
+ continue;
+ }
+ /*
+ * hand craft *(&nn + o) = l
+ */
+ nod0 = znode;
+ nod0.op = OAS;
+ nod0.type = t;
+ nod0.left = &nod1;
+ nod0.right = nil;
+
+ nod1 = znode;
+ nod1.op = OIND;
+ nod1.type = t;
+ nod1.left = &nod2;
+
+ nod2 = znode;
+ nod2.op = OADD;
+ nod2.type = typ(TIND, t);
+ nod2.left = &nod3;
+ nod2.right = &nod4;
+
+ nod3 = znode;
+ nod3.op = OADDR;
+ nod3.type = nod2.type;
+ nod3.left = nn;
+
+ nod4 = znode;
+ nod4.op = OCONST;
+ nod4.type = nod2.type;
+ nod4.vconst = t->offset;
+
+ ccom(&nod0);
+ acom(&nod0);
+ xcom(&nod0);
+ nod0.addable = 0;
+ nod0.right = l;
+
+ /* prtree(&nod0, "hand craft"); /* */
+ cgen(&nod0, Z);
+ }
+ break;
+
+ case OAS:
+ if(nn == Z) {
+ if(n->addable < INDEXED)
+ sugen(n->right, n->left, w);
+ break;
+ }
+
+ sugen(n->right, nodrat, w);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, n->left, w);
+ sugen(nodrat, nn, w);
+ break;
+
+ case OFUNC:
+ if(nn == Z) {
+ sugen(n, nodrat, w);
+ break;
+ }
+ if(nn->op != OIND) {
+ nn = new1(OADDR, nn, Z);
+ nn->type = types[TIND];
+ nn->addable = 0;
+ } else
+ nn = nn->left;
+ n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ sugen(n->right->left, nn, w);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ sugen(n->right->right, nn, w);
+ patch(p1, pc);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, Z);
+ sugen(n->right, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(nn == Z) {
+ switch(n->op) {
+ case OASADD:
+ case OASSUB:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+
+ case OASMUL:
+ case OASLMUL:
+
+
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ case OPREINC:
+ case OPREDEC:
+ break;
+
+ default:
+ return;
+ }
+ }
+
+ if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gins(AMOVL, &nod1, &nod2);
+ regfree(&nod1);
+
+ nod2.type = typ(TIND, t);
+
+ nod1 = nod2;
+ nod1.op = OIND;
+ nod1.left = &nod2;
+ nod1.right = Z;
+ nod1.complex = 1;
+ nod1.type = t;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ if(w <= 32) {
+ c = cursafe;
+ if(n->left != Z && n->left->complex >= FNX
+ && n->right != Z && n->right->complex >= FNX) {
+ regsalloc(&nod1, n->right);
+ cgen(n->right, &nod1);
+ nod2 = *n;
+ nod2.right = &nod1;
+ cgen(&nod2, nn);
+ cursafe = c;
+ return;
+ }
+ if(w & 7) {
+ mt = TLONG;
+ mo = AMOVL;
+ } else {
+ mt = TVLONG;
+ mo = AMOVQ;
+ }
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[mt];
+ regalloc(&nod0, n, Z);
+ if(!vaddr(n, 0)) {
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ n = &nod1;
+ }
+ else
+ n->type = t;
+
+ t = nn->type;
+ nn->type = types[mt];
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ nn = &nod2;
+ }
+ else
+ nn->type = t;
+ } else {
+ t = nn->type;
+ nn->type = types[mt];
+ regalloc(&nod0, nn, Z);
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ nn = &nod2;
+ }
+ else
+ nn->type = t;
+
+ t = n->type;
+ n->type = types[mt];
+ if(!vaddr(n, 0)) {
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ n = &nod1;
+ }
+ else
+ n->type = t;
+ }
+ o0 = n->xoffset;
+ o1 = nn->xoffset;
+ w /= ewidth[mt];
+ while(--w >= 0) {
+ gins(mo, n, &nod0);
+ gins(mo, &nod0, nn);
+ n->xoffset += ewidth[mt];
+ nn->xoffset += ewidth[mt];
+ }
+ n->xoffset = o0;
+ nn->xoffset = o1;
+ if(nn == &nod2)
+ regfree(&nod2);
+ if(n == &nod1)
+ regfree(&nod1);
+ regfree(&nod0);
+ return;
+ }
+
+ /* botch, need to save in .safe */
+ c = 0;
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[TLONG];
+ nodreg(&nod1, n, D_SI);
+ if(reg[D_SI]) {
+ gins(APUSHQ, &nod1, Z);
+ c |= 1;
+ reg[D_SI]++;
+ }
+ lcgen(n, &nod1);
+ n->type = t;
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ nodreg(&nod2, nn, D_DI);
+ if(reg[D_DI]) {
+warn(Z, "DI botch");
+ gins(APUSHQ, &nod2, Z);
+ c |= 2;
+ reg[D_DI]++;
+ }
+ lcgen(nn, &nod2);
+ nn->type = t;
+ } else {
+ t = nn->type;
+ nn->type = types[TLONG];
+ nodreg(&nod2, nn, D_DI);
+ if(reg[D_DI]) {
+warn(Z, "DI botch");
+ gins(APUSHQ, &nod2, Z);
+ c |= 2;
+ reg[D_DI]++;
+ }
+ lcgen(nn, &nod2);
+ nn->type = t;
+
+ t = n->type;
+ n->type = types[TLONG];
+ nodreg(&nod1, n, D_SI);
+ if(reg[D_SI]) {
+ gins(APUSHQ, &nod1, Z);
+ c |= 1;
+ reg[D_SI]++;
+ }
+ lcgen(n, &nod1);
+ n->type = t;
+ }
+ nodreg(&nod3, n, D_CX);
+ if(reg[D_CX]) {
+ gins(APUSHQ, &nod3, Z);
+ c |= 4;
+ reg[D_CX]++;
+ }
+ gins(AMOVL, nodconst(w/SZ_INT), &nod3);
+ gins(ACLD, Z, Z);
+ gins(AREP, Z, Z);
+ gins(AMOVSL, Z, Z);
+ if(c & 4) {
+ gins(APOPQ, Z, &nod3);
+ reg[D_CX]--;
+ }
+ if(c & 2) {
+ gins(APOPQ, Z, &nod2);
+ reg[nod2.reg]--;
+ }
+ if(c & 1) {
+ gins(APOPQ, Z, &nod1);
+ reg[nod1.reg]--;
+ }
+}
+
+/*
+ * TO DO
+ */
+void
+layout(Node *f, Node *t, int c, int cv, Node *cn)
+{
+ Node t1, t2;
+
+ while(c > 3) {
+ layout(f, t, 2, 0, Z);
+ c -= 2;
+ }
+
+ regalloc(&t1, &lregnode, Z);
+ regalloc(&t2, &lregnode, Z);
+ if(c > 0) {
+ gmove(f, &t1);
+ f->xoffset += SZ_INT;
+ }
+ if(cn != Z)
+ gmove(nodconst(cv), cn);
+ if(c > 1) {
+ gmove(f, &t2);
+ f->xoffset += SZ_INT;
+ }
+ if(c > 0) {
+ gmove(&t1, t);
+ t->xoffset += SZ_INT;
+ }
+ if(c > 2) {
+ gmove(f, &t1);
+ f->xoffset += SZ_INT;
+ }
+ if(c > 1) {
+ gmove(&t2, t);
+ t->xoffset += SZ_INT;
+ }
+ if(c > 2) {
+ gmove(&t1, t);
+ t->xoffset += SZ_INT;
+ }
+ regfree(&t1);
+ regfree(&t2);
+}
+
+/*
+ * constant is not vlong or fits as 32-bit signed immediate
+ */
+int
+immconst(Node *n)
+{
+ long v;
+
+ if(n->op != OCONST || !typechlpv[n->type->etype])
+ return 0;
+ if(typechl[n->type->etype])
+ return 1;
+ v = n->vconst;
+ return n->vconst == (vlong)v;
+}
+
+/*
+ * if a constant and vlong, doesn't fit as 32-bit signed immediate
+ */
+int
+hardconst(Node *n)
+{
+ return n->op == OCONST && !immconst(n);
+}
+
+/*
+ * casting up to t2 covers an intermediate cast to t1
+ */
+int
+castup(Type *t1, Type *t2)
+{
+ int ft;
+
+ if(!nilcast(t1, t2))
+ return 0;
+ /* known to be small to large */
+ ft = t1->etype;
+ switch(t2->etype){
+ case TINT:
+ case TLONG:
+ return ft == TLONG || ft == TINT || ft == TSHORT || ft == TCHAR;
+ case TUINT:
+ case TULONG:
+ return ft == TULONG || ft == TUINT || ft == TUSHORT || ft == TUCHAR;
+ case TVLONG:
+ return ft == TLONG || ft == TINT || ft == TSHORT;
+ case TUVLONG:
+ return ft == TULONG || ft == TUINT || ft == TUSHORT;
+ }
+ return 0;
+}
+
+void
+zeroregm(Node *n)
+{
+ gins(AMOVL, nodconst(0), n);
+}
+
+/* do we need to load the address of a vlong? */
+int
+vaddr(Node *n, int a)
+{
+ switch(n->op) {
+ case ONAME:
+ if(a)
+ return 1;
+ return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
+
+ case OCONST:
+ case OREGISTER:
+ case OINDREG:
+ return 1;
+ }
+ return 0;
+}
+
+long
+hi64v(Node *n)
+{
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ return (long)(n->vconst) & ~0L;
+ else
+ return (long)((uvlong)n->vconst>>32) & ~0L;
+}
+
+long
+lo64v(Node *n)
+{
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ return (long)((uvlong)n->vconst>>32) & ~0L;
+ else
+ return (long)(n->vconst) & ~0L;
+}
+
+Node *
+hi64(Node *n)
+{
+ return nodconst(hi64v(n));
+}
+
+Node *
+lo64(Node *n)
+{
+ return nodconst(lo64v(n));
+}
+
+int
+cond(int op)
+{
+ switch(op) {
+ case OANDAND:
+ case OOROR:
+ case ONOT:
+ return 1;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/cmd/6c/div.c b/src/cmd/6c/div.c
new file mode 100644
index 0000000..4b63ddc
--- /dev/null
+++ b/src/cmd/6c/div.c
@@ -0,0 +1,236 @@
+// Inferno utils/6c/div.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/div.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+/*
+ * Based on: Granlund, T.; Montgomery, P.L.
+ * "Division by Invariant Integers using Multiplication".
+ * SIGPLAN Notices, Vol. 29, June 1994, page 61.
+ */
+
+#define TN(n) ((uvlong)1 << (n))
+#define T31 TN(31)
+#define T32 TN(32)
+
+int
+multiplier(ulong d, int p, uvlong *mp)
+{
+ int l;
+ uvlong mlo, mhi, tlo, thi;
+
+ l = topbit(d - 1) + 1;
+ mlo = (((TN(l) - d) << 32) / d) + T32;
+ if(l + p == 64)
+ mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
+ else
+ mhi = (TN(32 + l) + TN(32 + l - p)) / d;
+ /*assert(mlo < mhi);*/
+ while(l > 0) {
+ tlo = mlo >> 1;
+ thi = mhi >> 1;
+ if(tlo == thi)
+ break;
+ mlo = tlo;
+ mhi = thi;
+ l--;
+ }
+ *mp = mhi;
+ return l;
+}
+
+int
+sdiv(ulong d, ulong *mp, int *sp)
+{
+ int s;
+ uvlong m;
+
+ s = multiplier(d, 32 - 1, &m);
+ *mp = m;
+ *sp = s;
+ if(m >= T31)
+ return 1;
+ else
+ return 0;
+}
+
+int
+udiv(ulong d, ulong *mp, int *sp, int *pp)
+{
+ int p, s;
+ uvlong m;
+
+ s = multiplier(d, 32, &m);
+ p = 0;
+ if(m >= T32) {
+ while((d & 1) == 0) {
+ d >>= 1;
+ p++;
+ }
+ s = multiplier(d, 32 - p, &m);
+ }
+ *mp = m;
+ *pp = p;
+ if(m >= T32) {
+ /*assert(p == 0);*/
+ *sp = s - 1;
+ return 1;
+ }
+ else {
+ *sp = s;
+ return 0;
+ }
+}
+
+void
+sdivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+ int a, s;
+ ulong m;
+ vlong c;
+
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ a = sdiv(c, &m, &s);
+//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m);
+ gins(AMOVL, nodconst(m), ax);
+ gins(AIMULL, l, Z);
+ gins(AMOVL, l, ax);
+ if(a)
+ gins(AADDL, ax, dx);
+ gins(ASHRL, nodconst(31), ax);
+ gins(ASARL, nodconst(s), dx);
+ gins(AADDL, ax, dx);
+ if(r->vconst < 0)
+ gins(ANEGL, Z, dx);
+}
+
+void
+udivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+ int a, s, t;
+ ulong m;
+ Node nod;
+
+ a = udiv(r->vconst, &m, &s, &t);
+//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m);
+ if(t != 0) {
+ gins(AMOVL, l, ax);
+ gins(ASHRL, nodconst(t), ax);
+ gins(AMOVL, nodconst(m), dx);
+ gins(AMULL, dx, Z);
+ }
+ else if(a) {
+ if(l->op != OREGISTER) {
+ regalloc(&nod, l, Z);
+ gins(AMOVL, l, &nod);
+ l = &nod;
+ }
+ gins(AMOVL, nodconst(m), ax);
+ gins(AMULL, l, Z);
+ gins(AADDL, l, dx);
+ gins(ARCRL, nodconst(1), dx);
+ if(l == &nod)
+ regfree(l);
+ }
+ else {
+ gins(AMOVL, nodconst(m), ax);
+ gins(AMULL, l, Z);
+ }
+ if(s != 0)
+ gins(ASHRL, nodconst(s), dx);
+}
+
+void
+sext(Node *d, Node *s, Node *l)
+{
+ if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
+ reg[D_DX]++;
+ gins(ACDQ, Z, Z);
+ }
+ else {
+ regalloc(d, l, Z);
+ gins(AMOVL, s, d);
+ gins(ASARL, nodconst(31), d);
+ }
+}
+
+void
+sdiv2(long c, int v, Node *l, Node *n)
+{
+ Node nod;
+
+ if(v > 0) {
+ if(v > 1) {
+ sext(&nod, n, l);
+ gins(AANDL, nodconst((1 << v) - 1), &nod);
+ gins(AADDL, &nod, n);
+ regfree(&nod);
+ }
+ else {
+ gins(ACMPL, n, nodconst(0x80000000));
+ gins(ASBBL, nodconst(-1), n);
+ }
+ gins(ASARL, nodconst(v), n);
+ }
+ if(c < 0)
+ gins(ANEGL, Z, n);
+}
+
+void
+smod2(long c, int v, Node *l, Node *n)
+{
+ Node nod;
+
+ if(c == 1) {
+ zeroregm(n);
+ return;
+ }
+
+ sext(&nod, n, l);
+ if(v == 0) {
+ zeroregm(n);
+ gins(AXORL, &nod, n);
+ gins(ASUBL, &nod, n);
+ }
+ else if(v > 1) {
+ gins(AANDL, nodconst((1 << v) - 1), &nod);
+ gins(AADDL, &nod, n);
+ gins(AANDL, nodconst((1 << v) - 1), n);
+ gins(ASUBL, &nod, n);
+ }
+ else {
+ gins(AANDL, nodconst(1), n);
+ gins(AXORL, &nod, n);
+ gins(ASUBL, &nod, n);
+ }
+ regfree(&nod);
+}
diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h
new file mode 100644
index 0000000..dee9966
--- /dev/null
+++ b/src/cmd/6c/gc.h
@@ -0,0 +1,411 @@
+// Inferno utils/6c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "../cc/cc.h"
+#include "../6l/6.out.h"
+
+/*
+ * 6c/amd64
+ * Intel 386 with AMD64 extensions
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 8
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+#define FNX 100
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Case Case;
+typedef struct C1 C1;
+typedef struct Var Var;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+typedef struct Renv Renv;
+
+EXTERN struct
+{
+ Node* regtree;
+ Node* basetree;
+ short scale;
+ short reg;
+ short ptr;
+} idx;
+
+struct Adr
+{
+ vlong offset;
+ double dval;
+ char sval[NSNAME];
+
+ Sym* sym;
+ uchar type;
+ uchar index;
+ uchar etype;
+ uchar scale; /* doubles as width in DATA op */
+};
+#define A ((Adr*)0)
+
+#define INDEXED 9
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ long lineno;
+ short as;
+};
+#define P ((Prog*)0)
+
+struct Case
+{
+ Case* link;
+ vlong val;
+ long label;
+ char def;
+ char isv;
+};
+#define C ((Case*)0)
+
+struct C1
+{
+ vlong val;
+ long label;
+};
+
+struct Var
+{
+ vlong offset;
+ Sym* sym;
+ char name;
+ char etype;
+};
+
+struct Reg
+{
+ long pc;
+ long rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ long regu;
+ long loop; /* could be shorter */
+
+ Reg* log5;
+ long active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+struct Renv
+{
+ int safe;
+ Node base;
+ Node* saved;
+ Node* scope;
+};
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN long breakpc;
+EXTERN long nbreak;
+EXTERN Case* cases;
+EXTERN Node constnode;
+EXTERN Node fconstnode;
+EXTERN Node vconstnode;
+EXTERN long continpc;
+EXTERN long curarg;
+EXTERN long cursafe;
+EXTERN Prog* firstp;
+EXTERN Prog* lastp;
+EXTERN long maxargsafe;
+EXTERN int mnstring;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN long nrathole;
+EXTERN long nstring;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Node lregnode;
+EXTERN Node qregnode;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN int reg[D_NONE];
+EXTERN long exregoffset;
+EXTERN long exfregoffset;
+EXTERN uchar typechlpv[NTYPE];
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 5
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+
+EXTERN long regbits;
+EXTERN long exregbits;
+
+EXTERN int change;
+EXTERN int suppress;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Var var[NVAR];
+EXTERN long* idom;
+EXTERN Reg** rpo2r;
+EXTERN long maxnr;
+
+extern char* anames[];
+
+/*
+ * sgen.c
+ */
+void codgen(Node*, Node*);
+void gen(Node*);
+void noretval(int);
+void usedset(Node*, int);
+void xcom(Node*);
+void indx(Node*);
+int bcomplex(Node*, Node*);
+
+/*
+ * cgen.c
+ */
+void zeroregm(Node*);
+void cgen(Node*, Node*);
+void reglcgen(Node*, Node*, Node*);
+void lcgen(Node*, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, Node*);
+void sugen(Node*, Node*, long);
+int needreg(Node*, int);
+int hardconst(Node*);
+int immconst(Node*);
+
+/*
+ * cgen64.c
+ */
+int vaddr(Node*, int);
+void loadpair(Node*, Node*);
+int cgen64(Node*, Node*);
+void testv(Node*, int);
+
+/*
+ * txt.c
+ */
+void ginit(void);
+void gclean(void);
+void nextpc(void);
+void gargs(Node*, Node*, Node*);
+void garg1(Node*, Node*, Node*, int, Node**);
+Node* nodconst(long);
+Node* nodfconst(double);
+Node* nodgconst(vlong, Type*);
+int nodreg(Node*, Node*, int);
+int isreg(Node*, int);
+void regret(Node*, Node*);
+void regalloc(Node*, Node*, Node*);
+void regfree(Node*);
+void regialloc(Node*, Node*, Node*);
+void regsalloc(Node*, Node*);
+void regaalloc1(Node*, Node*);
+void regaalloc(Node*, Node*);
+void regind(Node*, Node*);
+void gprep(Node*, Node*);
+void naddr(Node*, Adr*);
+void gcmp(int, Node*, vlong);
+void gmove(Node*, Node*);
+void gins(int a, Node*, Node*);
+void gopcode(int, Type*, Node*, Node*);
+int samaddr(Node*, Node*);
+void gbranch(int);
+void patch(Prog*, long);
+int sconst(Node*);
+void gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int swcmp(const void*, const void*);
+void doswit(Node*);
+void swit1(C1*, int, long, Node*);
+void cas(void);
+void bitload(Node*, Node*, Node*, Node*, Node*);
+void bitstore(Node*, Node*, Node*, Node*, Node*);
+long outstring(char*, long);
+void nullwarn(Node*, Node*);
+void sextern(Sym*, Node*, long, long);
+void gextern(Sym*, Node*, long, long);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+
+/*
+ * list
+ */
+void listinit(void);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Sconv(Fmt*);
+int Rconv(Fmt*);
+int Xconv(Fmt*);
+int Bconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Reg*, Adr*);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, long);
+void synch(Reg*, Bits);
+ulong allreg(ulong, Rgn*);
+void paint1(Reg*, int);
+ulong paint2(Reg*, int);
+void paint3(Reg*, int, long, int);
+void addreg(Adr*, int);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+long RtoB(int);
+long FtoB(int);
+int BtoR(long);
+int BtoF(long);
+
+#define D_HI D_NONE
+#define D_LO D_NONE
+
+#define isregtype(t) ((t)>= D_AX && (t)<=D_R15)
+
+/*
+ * bound
+ */
+void comtarg(void);
+
+/*
+ * com64
+ */
+int cond(int);
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+long lo64v(Node*);
+long hi64v(Node*);
+Node* lo64(Node*);
+Node* hi64(Node*);
+
+/*
+ * div/mul
+ */
+void sdivgen(Node*, Node*, Node*, Node*);
+void udivgen(Node*, Node*, Node*, Node*);
+void sdiv2(long, int, Node*, Node*);
+void smod2(long, int, Node*, Node*);
+void mulgen(Type*, Node*, Node*);
+void genmuladd(Node*, Node*, int, Node*);
+void shiftit(Type*, Node*, Node*);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "S" char*
+
+#define D_X7 (D_X0+7)
+
+void fgopcode(int, Node*, Node*, int, int);
diff --git a/src/cmd/6c/list.c b/src/cmd/6c/list.c
new file mode 100644
index 0000000..4aae5a3
--- /dev/null
+++ b/src/cmd/6c/list.c
@@ -0,0 +1,372 @@
+// Inferno utils/6c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('B', Bconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('R', Rconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%lld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ if(p->as == ADATA)
+ sprint(str, " %A %D/%d,%D",
+ p->as, &p->from, p->from.scale, &p->to);
+ else if(p->as == ATEXT)
+ sprint(str, " %A %D,%d,%D",
+ p->as, &p->from, p->from.scale, &p->to);
+ else
+ sprint(str, " %A %D,%D",
+ p->as, &p->from, &p->to);
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[i]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[40], s[20];
+ Adr *a;
+ int i;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->type;
+ if(i >= D_INDIR) {
+ if(a->offset)
+ sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
+ else
+ sprint(str, "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ if(a->offset)
+ sprint(str, "$%lld,%R", a->offset, i);
+ else
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%lld(PC)", a->offset-pc);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%lld(SB)", a->sym->name,
+ a->offset);
+ break;
+
+ case D_AUTO:
+ if(a->sym) {
+ sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
+ break;
+ }
+ sprint(str, "%lld(SP)", a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym) {
+ sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
+ break;
+ }
+ sprint(str, "%lld(FP)", a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%lld", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$(%.17e)", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+
+ case D_ADDR:
+ a->type = a->index;
+ a->index = D_NONE;
+ sprint(str, "$%D", a);
+ a->index = a->type;
+ a->type = D_ADDR;
+ goto conv;
+ }
+brk:
+ if(a->index != D_NONE) {
+ sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
+ strcat(str, s);
+ }
+conv:
+ return fmtstrcpy(fp, str);
+}
+
+char* regstr[] =
+{
+ "AL", /* [D_AL] */
+ "CL",
+ "DL",
+ "BL",
+ "SPB",
+ "BPB",
+ "SIB",
+ "DIB",
+ "R8B",
+ "R9B",
+ "R10B",
+ "R11B",
+ "R12B",
+ "R13B",
+ "R14B",
+ "R15B",
+
+ "AX", /* [D_AX] */
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+ "R8",
+ "R9",
+ "R10",
+ "R11",
+ "R12",
+ "R13",
+ "R14",
+ "R15",
+
+ "AH",
+ "CH",
+ "DH",
+ "BH",
+
+ "F0", /* [D_F0] */
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "M0",
+ "M1",
+ "M2",
+ "M3",
+ "M4",
+ "M5",
+ "M6",
+ "M7",
+
+ "X0",
+ "X1",
+ "X2",
+ "X3",
+ "X4",
+ "X5",
+ "X6",
+ "X7",
+ "X8",
+ "X9",
+ "X10",
+ "X11",
+ "X12",
+ "X13",
+ "X14",
+ "X15",
+
+ "CS", /* [D_CS] */
+ "SS",
+ "DS",
+ "ES",
+ "FS",
+ "GS",
+
+ "GDTR", /* [D_GDTR] */
+ "IDTR", /* [D_IDTR] */
+ "LDTR", /* [D_LDTR] */
+ "MSW", /* [D_MSW] */
+ "TASK", /* [D_TASK] */
+
+ "CR0", /* [D_CR] */
+ "CR1",
+ "CR2",
+ "CR3",
+ "CR4",
+ "CR5",
+ "CR6",
+ "CR7",
+ "CR8",
+ "CR9",
+ "CR10",
+ "CR11",
+ "CR12",
+ "CR13",
+ "CR14",
+ "CR15",
+
+ "DR0", /* [D_DR] */
+ "DR1",
+ "DR2",
+ "DR3",
+ "DR4",
+ "DR5",
+ "DR6",
+ "DR7",
+
+ "TR0", /* [D_TR] */
+ "TR1",
+ "TR2",
+ "TR3",
+ "TR4",
+ "TR5",
+ "TR6",
+ "TR7",
+
+ "NONE", /* [D_NONE] */
+};
+
+int
+Rconv(Fmt *fp)
+{
+ char str[20];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_AL && r <= D_NONE)
+ sprint(str, "%s", regstr[r-D_AL]);
+ else
+ sprint(str, "gok(%d)", r);
+
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[30], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
diff --git a/src/cmd/6c/machcap.c b/src/cmd/6c/machcap.c
new file mode 100644
index 0000000..d4f6bfa
--- /dev/null
+++ b/src/cmd/6c/machcap.c
@@ -0,0 +1,108 @@
+// Inferno utils/6c/machcap.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/machcap.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+int
+machcap(Node *n)
+{
+
+ if(n == Z)
+ return 1; /* test */
+
+ switch(n->op) {
+ case OMUL:
+ case OLMUL:
+ case OASMUL:
+ case OASLMUL:
+ if(typechl[n->type->etype])
+ return 1;
+ if(typev[n->type->etype]) {
+ return 1;
+ }
+ break;
+
+ case OCOM:
+ case ONEG:
+ case OADD:
+ case OAND:
+ case OOR:
+ case OSUB:
+ case OXOR:
+ case OASHL:
+ case OLSHR:
+ case OASHR:
+ if(typechlv[n->left->type->etype])
+ return 1;
+ break;
+
+ case OCAST:
+ return 1;
+
+ case OCOND:
+ case OCOMMA:
+ case OLIST:
+ case OANDAND:
+ case OOROR:
+ case ONOT:
+ return 1;
+
+ case OASADD:
+ case OASSUB:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+ return 1;
+
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ return 1;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ case OPREINC:
+ case OPREDEC:
+ return 1;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OGT:
+ case OLT:
+ case OGE:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/cmd/6c/mul.c b/src/cmd/6c/mul.c
new file mode 100644
index 0000000..7fd2012
--- /dev/null
+++ b/src/cmd/6c/mul.c
@@ -0,0 +1,458 @@
+// Inferno utils/6c/mul.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/mul.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+typedef struct Malg Malg;
+typedef struct Mparam Mparam;
+
+struct Malg
+{
+ char vals[10];
+};
+
+struct Mparam
+{
+ ulong value;
+ char alg;
+ char neg;
+ char shift;
+ char arg;
+ char off;
+};
+
+static Mparam multab[32];
+static int mulptr;
+
+static Malg malgs[] =
+{
+ {0, 100},
+ {-1, 1, 100},
+ {-9, -5, -3, 3, 5, 9, 100},
+ {6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
+ {-8, -4, -2, 2, 4, 8, 100},
+};
+
+/*
+ * return position of lowest 1
+ */
+int
+lowbit(ulong v)
+{
+ int s, i;
+ ulong m;
+
+ s = 0;
+ m = 0xFFFFFFFFUL;
+ for(i = 16; i > 0; i >>= 1) {
+ m >>= i;
+ if((v & m) == 0) {
+ v >>= i;
+ s += i;
+ }
+ }
+ return s;
+}
+
+void
+genmuladd(Node *d, Node *s, int m, Node *a)
+{
+ Node nod;
+
+ nod.op = OINDEX;
+ nod.left = a;
+ nod.right = s;
+ nod.scale = m;
+ nod.type = types[TIND];
+ nod.xoffset = 0;
+ xcom(&nod);
+ gopcode(OADDR, d->type, &nod, d);
+}
+
+void
+mulparam(ulong m, Mparam *mp)
+{
+ int c, i, j, n, o, q, s;
+ int bc, bi, bn, bo, bq, bs, bt;
+ char *p;
+ long u;
+ ulong t;
+
+ bc = bq = 10;
+ bi = bn = bo = bs = bt = 0;
+ for(i = 0; i < nelem(malgs); i++) {
+ for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
+ for(s = 0; s < 2; s++) {
+ c = 10;
+ q = 10;
+ u = m - o;
+ if(u == 0)
+ continue;
+ if(s) {
+ o = -o;
+ if(o > 0)
+ continue;
+ u = -u;
+ }
+ n = lowbit(u);
+ t = (ulong)u >> n;
+ switch(i) {
+ case 0:
+ if(t == 1) {
+ c = s + 1;
+ q = 0;
+ break;
+ }
+ switch(t) {
+ case 3:
+ case 5:
+ case 9:
+ c = s + 1;
+ if(n)
+ c++;
+ q = 0;
+ break;
+ }
+ if(s)
+ break;
+ switch(t) {
+ case 15:
+ case 25:
+ case 27:
+ case 45:
+ case 81:
+ c = 2;
+ if(n)
+ c++;
+ q = 1;
+ break;
+ }
+ break;
+ case 1:
+ if(t == 1) {
+ c = 3;
+ q = 3;
+ break;
+ }
+ switch(t) {
+ case 3:
+ case 5:
+ case 9:
+ c = 3;
+ q = 2;
+ break;
+ }
+ break;
+ case 2:
+ if(t == 1) {
+ c = 3;
+ q = 2;
+ break;
+ }
+ break;
+ case 3:
+ if(s)
+ break;
+ if(t == 1) {
+ c = 3;
+ q = 1;
+ break;
+ }
+ break;
+ case 4:
+ if(t == 1) {
+ c = 3;
+ q = 0;
+ break;
+ }
+ break;
+ }
+ if(c < bc || (c == bc && q > bq)) {
+ bc = c;
+ bi = i;
+ bn = n;
+ bo = o;
+ bq = q;
+ bs = s;
+ bt = t;
+ }
+ }
+ }
+ mp->value = m;
+ if(bc <= 3) {
+ mp->alg = bi;
+ mp->shift = bn;
+ mp->off = bo;
+ mp->neg = bs;
+ mp->arg = bt;
+ }
+ else
+ mp->alg = -1;
+}
+
+int
+m0(int a)
+{
+ switch(a) {
+ case -2:
+ case 2:
+ return 2;
+ case -3:
+ case 3:
+ return 2;
+ case -4:
+ case 4:
+ return 4;
+ case -5:
+ case 5:
+ return 4;
+ case 6:
+ return 2;
+ case -8:
+ case 8:
+ return 8;
+ case -9:
+ case 9:
+ return 8;
+ case 10:
+ return 4;
+ case 12:
+ return 2;
+ case 15:
+ return 2;
+ case 18:
+ return 8;
+ case 20:
+ return 4;
+ case 24:
+ return 2;
+ case 25:
+ return 4;
+ case 27:
+ return 2;
+ case 36:
+ return 8;
+ case 40:
+ return 4;
+ case 45:
+ return 4;
+ case 72:
+ return 8;
+ case 81:
+ return 8;
+ }
+ diag(Z, "bad m0");
+ return 0;
+}
+
+int
+m1(int a)
+{
+ switch(a) {
+ case 15:
+ return 4;
+ case 25:
+ return 4;
+ case 27:
+ return 8;
+ case 45:
+ return 8;
+ case 81:
+ return 8;
+ }
+ diag(Z, "bad m1");
+ return 0;
+}
+
+int
+m2(int a)
+{
+ switch(a) {
+ case 6:
+ return 2;
+ case 10:
+ return 2;
+ case 12:
+ return 4;
+ case 18:
+ return 2;
+ case 20:
+ return 4;
+ case 24:
+ return 8;
+ case 36:
+ return 4;
+ case 40:
+ return 8;
+ case 72:
+ return 8;
+ }
+ diag(Z, "bad m2");
+ return 0;
+}
+
+void
+shiftit(Type *t, Node *s, Node *d)
+{
+ long c;
+
+ c = (long)s->vconst & 31;
+ switch(c) {
+ case 0:
+ break;
+ case 1:
+ gopcode(OADD, t, d, d);
+ break;
+ default:
+ gopcode(OASHL, t, s, d);
+ }
+}
+
+static int
+mulgen1(ulong v, Node *n)
+{
+ int i, o;
+ Mparam *p;
+ Node nod, nods;
+
+ for(i = 0; i < nelem(multab); i++) {
+ p = &multab[i];
+ if(p->value == v)
+ goto found;
+ }
+
+ p = &multab[mulptr];
+ if(++mulptr == nelem(multab))
+ mulptr = 0;
+
+ mulparam(v, p);
+
+found:
+// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
+ if(p->alg < 0)
+ return 0;
+
+ nods = *nodconst(p->shift);
+
+ o = OADD;
+ if(p->alg > 0) {
+ regalloc(&nod, n, Z);
+ if(p->off < 0)
+ o = OSUB;
+ }
+
+ switch(p->alg) {
+ case 0:
+ switch(p->arg) {
+ case 1:
+ shiftit(n->type, &nods, n);
+ break;
+ case 15:
+ case 25:
+ case 27:
+ case 45:
+ case 81:
+ genmuladd(n, n, m1(p->arg), n);
+ /* fall thru */
+ case 3:
+ case 5:
+ case 9:
+ genmuladd(n, n, m0(p->arg), n);
+ shiftit(n->type, &nods, n);
+ break;
+ default:
+ goto bad;
+ }
+ if(p->neg == 1)
+ gins(ANEGL, Z, n);
+ break;
+ case 1:
+ switch(p->arg) {
+ case 1:
+ gmove(n, &nod);
+ shiftit(n->type, &nods, &nod);
+ break;
+ case 3:
+ case 5:
+ case 9:
+ genmuladd(&nod, n, m0(p->arg), n);
+ shiftit(n->type, &nods, &nod);
+ break;
+ default:
+ goto bad;
+ }
+ if(p->neg)
+ gopcode(o, n->type, &nod, n);
+ else {
+ gopcode(o, n->type, n, &nod);
+ gmove(&nod, n);
+ }
+ break;
+ case 2:
+ genmuladd(&nod, n, m0(p->off), n);
+ shiftit(n->type, &nods, n);
+ goto comop;
+ case 3:
+ genmuladd(&nod, n, m0(p->off), n);
+ shiftit(n->type, &nods, n);
+ genmuladd(n, &nod, m2(p->off), n);
+ break;
+ case 4:
+ genmuladd(&nod, n, m0(p->off), nodconst(0));
+ shiftit(n->type, &nods, n);
+ goto comop;
+ default:
+ diag(Z, "bad mul alg");
+ break;
+ comop:
+ if(p->neg) {
+ gopcode(o, n->type, n, &nod);
+ gmove(&nod, n);
+ }
+ else
+ gopcode(o, n->type, &nod, n);
+ }
+
+ if(p->alg > 0)
+ regfree(&nod);
+
+ return 1;
+
+bad:
+ diag(Z, "mulgen botch");
+ return 1;
+}
+
+void
+mulgen(Type *t, Node *r, Node *n)
+{
+ if(!mulgen1(r->vconst, n))
+ gopcode(OMUL, t, r, n);
+}
diff --git a/src/cmd/6c/peep.c b/src/cmd/6c/peep.c
new file mode 100644
index 0000000..77c034b
--- /dev/null
+++ b/src/cmd/6c/peep.c
@@ -0,0 +1,876 @@
+// Inferno utils/6c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+static int
+needc(Prog *p)
+{
+ while(p != P) {
+ switch(p->as) {
+ case AADCL:
+ case AADCQ:
+ case ASBBL:
+ case ASBBQ:
+ case ARCRL:
+ case ARCRQ:
+ return 1;
+ case AADDL:
+ case AADDQ:
+ case ASUBL:
+ case ASUBQ:
+ case AJMP:
+ case ARET:
+ case ACALL:
+ return 0;
+ default:
+ if(p->to.type == D_BRANCH)
+ return 0;
+ }
+ p = p->link;
+ }
+ return 0;
+}
+
+static Reg*
+rnops(Reg *r)
+{
+ Prog *p;
+ Reg *r1;
+
+ if(r != R)
+ for(;;){
+ p = r->prog;
+ if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
+ break;
+ r1 = uniqs(r);
+ if(r1 == R)
+ break;
+ r = r1;
+ }
+ return r;
+}
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t;
+
+ /*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+ pc = 0; /* speculating it won't kill */
+
+loop1:
+
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case AMOVL:
+ case AMOVQ:
+ case AMOVSS:
+ case AMOVSD:
+ if(regtyp(&p->to))
+ if(regtyp(&p->from)) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ break;
+
+ case AMOVBLZX:
+ case AMOVWLZX:
+ case AMOVBLSX:
+ case AMOVWLSX:
+ if(regtyp(&p->to)) {
+ r1 = rnops(uniqs(r));
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p->as == p1->as && p->to.type == p1->from.type){
+ p1->as = AMOVL;
+ t++;
+ }
+ }
+ }
+ break;
+
+ case AMOVBQSX:
+ case AMOVBQZX:
+ case AMOVWQSX:
+ case AMOVWQZX:
+ case AMOVLQSX:
+ case AMOVLQZX:
+ if(regtyp(&p->to)) {
+ r1 = rnops(uniqs(r));
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p->as == p1->as && p->to.type == p1->from.type){
+ p1->as = AMOVQ;
+ t++;
+ }
+ }
+ }
+ break;
+
+ case AADDL:
+ case AADDQ:
+ case AADDW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1){
+ if(p->as == AADDQ)
+ p->as = ADECQ;
+ else if(p->as == AADDL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ }
+ else if(p->from.offset == 1){
+ if(p->as == AADDQ)
+ p->as = AINCQ;
+ else if(p->as == AADDL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ }
+ break;
+
+ case ASUBL:
+ case ASUBQ:
+ case ASUBW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1) {
+ if(p->as == ASUBQ)
+ p->as = AINCQ;
+ else if(p->as == ASUBL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ }
+ else if(p->from.offset == 1){
+ if(p->as == ASUBQ)
+ p->as = ADECQ;
+ else if(p->as == ASUBL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ }
+ break;
+ }
+ }
+ if(t)
+ goto loop1;
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+int
+regtyp(Adr *a)
+{
+ int t;
+
+ t = a->type;
+ if(t >= D_AX && t <= D_R15)
+ return 1;
+ if(t >= D_X0 && t <= D_X0+15)
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case ACALL:
+ return 0;
+
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVQ:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVQ:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULQ:
+ case AMULW:
+
+ case AROLB:
+ case AROLL:
+ case AROLQ:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORQ:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALQ:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARQ:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLQ:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRQ:
+ case ASHRW:
+
+ case AREP:
+ case AREPN:
+
+ case ACWD:
+ case ACDQ:
+ case ACQO:
+
+ case AMOVSL:
+ case AMOVSQ:
+ return 0;
+
+ case AMOVL:
+ case AMOVQ:
+ if(p->to.type == v1->type)
+ goto gotit;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, 0) ||
+ copysub(&p->to, v1, v2, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, 1);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->type;
+ v1->type = v2->type;
+ v2->type = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+ Prog *p;
+
+ if(r->active) {
+ if(debug['P'])
+ print("act set; return 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D f=%d\n", v1, v2, f);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(p, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; %D rar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %D set; return 1\n", v2);
+ return 1;
+
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(!debug['P'])
+ return 0;
+ if(t == 4)
+ print("; %D used+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %D used and f=%d; return 0\n", v2, f);
+ return 0;
+ }
+ if(copyu(p, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; sub %D/%D", v2, v1);
+ if(t == 4) {
+ if(debug['P'])
+ print("; %D used+set; return 1\n", v2);
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(p, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ f = 1;
+ if(debug['P'])
+ print("; %D set and !f; f=%d", v1, f);
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print("unknown op %A\n", p->as);
+ /* SBBL; ADCL; FLD1; SAHF */
+ return 2;
+
+
+ case ANEGB:
+ case ANEGW:
+ case ANEGL:
+ case ANEGQ:
+ case ANOTB:
+ case ANOTW:
+ case ANOTL:
+ case ANOTQ:
+ if(copyas(&p->to, v))
+ return 2;
+ break;
+
+ case ALEAL: /* lhs addr, rhs store */
+ case ALEAQ:
+ if(copyas(&p->from, v))
+ return 2;
+
+
+ case ANOP: /* rhs store */
+ case AMOVL:
+ case AMOVQ:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVBQSX:
+ case AMOVBQZX:
+ case AMOVLQSX:
+ case AMOVLQZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ case AMOVWQSX:
+ case AMOVWQZX:
+
+ case AMOVSS:
+ case AMOVSD:
+ case ACVTSD2SL:
+ case ACVTSD2SQ:
+ case ACVTSD2SS:
+ case ACVTSL2SD:
+ case ACVTSL2SS:
+ case ACVTSQ2SD:
+ case ACVTSQ2SS:
+ case ACVTSS2SD:
+ case ACVTSS2SL:
+ case ACVTSS2SQ:
+ case ACVTTSD2SL:
+ case ACVTTSD2SQ:
+ case ACVTTSS2SL:
+ case ACVTTSS2SQ:
+ if(copyas(&p->to, v)) {
+ if(s != A)
+ return copysub(&p->from, v, s, 1);
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ goto caseread;
+
+ case AROLB:
+ case AROLL:
+ case AROLQ:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORQ:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALQ:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARQ:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLQ:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRQ:
+ case ASHRW:
+ if(copyas(&p->to, v))
+ return 2;
+ if(copyas(&p->from, v))
+ if(p->from.type == D_CX)
+ return 2;
+ goto caseread;
+
+ case AADDB: /* rhs rar */
+ case AADDL:
+ case AADDQ:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDQ:
+ case AANDW:
+ case ADECL:
+ case ADECQ:
+ case ADECW:
+ case AINCL:
+ case AINCQ:
+ case AINCW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBQ:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORQ:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORQ:
+ case AXORW:
+ case AMOVB:
+ case AMOVW:
+
+ case AADDSD:
+ case AADDSS:
+ case ACMPSD:
+ case ACMPSS:
+ case ADIVSD:
+ case ADIVSS:
+ case AMAXSD:
+ case AMAXSS:
+ case AMINSD:
+ case AMINSS:
+ case AMULSD:
+ case AMULSS:
+ case ARCPSS:
+ case ARSQRTSS:
+ case ASQRTSD:
+ case ASQRTSS:
+ case ASUBSD:
+ case ASUBSS:
+ case AXORPD:
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ACMPL: /* read only */
+ case ACMPW:
+ case ACMPB:
+ case ACMPQ:
+
+ case ACOMISD:
+ case ACOMISS:
+ case AUCOMISD:
+ case AUCOMISS:
+ caseread:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub(&p->to, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ break;
+
+ case AJGE: /* no reference */
+ case AJNE:
+ case AJLE:
+ case AJEQ:
+ case AJHI:
+ case AJLS:
+ case AJMI:
+ case AJPL:
+ case AJGT:
+ case AJLT:
+ case AJCC:
+ case AJCS:
+
+ case AADJSP:
+ case AWAIT:
+ case ACLD:
+ break;
+
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ if(p->to.type != D_NONE) {
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+ }
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVQ:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVQ:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULQ:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ case ACQO:
+ if(v->type == D_AX || v->type == D_DX)
+ return 2;
+ goto caseread;
+
+ case AMOVSL:
+ case AMOVSQ:
+ case AREP:
+ case AREPN:
+ if(v->type == D_CX || v->type == D_DI || v->type == D_SI)
+ return 2;
+ goto caseread;
+
+ case AJMP: /* funny */
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ARET: /* funny */
+ if(v->type == REGRET || v->type == FREGRET)
+ return 2;
+ if(s != A)
+ return 1;
+ return 3;
+
+ case ACALL: /* funny */
+ if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
+ return 2;
+ if(REGARG && v->type == REGARG)
+ return 2;
+
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 4;
+ return 3;
+
+ case ATEXT: /* funny */
+ if(REGARG && v->type == REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+ if(a->type != v->type)
+ return 0;
+ if(regtyp(v))
+ return 1;
+ if(v->type == D_AUTO || v->type == D_PARAM)
+ if(v->offset == a->offset)
+ return 1;
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(regtyp(v)) {
+ if(a->type-D_INDIR == v->type)
+ return 1;
+ if(a->index == v->type)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+ int t;
+
+ if(copyas(a, v)) {
+ t = s->type;
+ if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
+ if(f)
+ a->type = t;
+ }
+ return 0;
+ }
+ if(regtyp(v)) {
+ t = v->type;
+ if(a->type == t+D_INDIR) {
+ if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
+ return 1; /* can't use BP-base with index */
+ if(f)
+ a->type = s->type+D_INDIR;
+// return 0;
+ }
+ if(a->index == t) {
+ if(f)
+ a->index = s->type;
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
diff --git a/src/cmd/6c/pgen.c b/src/cmd/6c/pgen.c
new file mode 100644
index 0000000..ae0b1b4
--- /dev/null
+++ b/src/cmd/6c/pgen.c
@@ -0,0 +1,550 @@
+// Inferno utils/6c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+ Node *n1, nod, nod1;
+
+ cursafe = 0;
+ curarg = 0;
+ maxargsafe = 0;
+
+ /*
+ * isolate name
+ */
+ for(n1 = nn;; n1 = n1->left) {
+ if(n1 == Z) {
+ diag(nn, "cant find function name");
+ return;
+ }
+ if(n1->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+ gpseudo(ATEXT, n1->sym, nodconst(stkoff));
+ sp = p;
+
+ /*
+ * isolate first argument
+ */
+ if(REGARG) {
+ if(typecmplx[thisfn->link->etype]) {
+ nod1 = *nodret->left;
+ nodreg(&nod, &nod1, REGARG);
+ gmove(&nod, &nod1);
+ } else
+ if(firstarg && typeword[firstargtype->etype]) {
+ nod1 = *nodret->left;
+ nod1.sym = firstarg;
+ nod1.type = firstargtype;
+ nod1.xoffset = align(0, firstargtype, Aarg1);
+ nod1.etype = firstargtype->etype;
+ nodreg(&nod, &nod1, REGARG);
+ gmove(&nod, &nod1);
+ }
+ }
+
+ canreach = 1;
+ warnreach = 1;
+ gen(n);
+ if(canreach && thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", n1->sym->name);
+ noretval(3);
+ gbranch(ORETURN);
+
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+
+ if(thechar=='6' || thechar=='7') /* [sic] */
+ maxargsafe = xround(maxargsafe, 8);
+ sp->to.offset += maxargsafe;
+}
+
+void
+supgen(Node *n)
+{
+ int owarn;
+ long spc;
+ Prog *sp;
+
+ if(n == Z)
+ return;
+ suppress++;
+ owarn = warnreach;
+ warnreach = 0;
+ spc = pc;
+ sp = lastp;
+ gen(n);
+ lastp = sp;
+ pc = spc;
+ sp->link = nil;
+ suppress--;
+ warnreach = owarn;
+}
+
+void
+gen(Node *n)
+{
+ Node *l, nod;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int snbreak, sncontin;
+ int f, o, oldreach;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+
+ if(!canreach) {
+ switch(o) {
+ case OLABEL:
+ case OCASE:
+ case OLIST:
+ case OBREAK:
+ case OFOR:
+ case OWHILE:
+ case ODWHILE:
+ /* all handled specially - see switch body below */
+ break;
+ default:
+ if(warnreach) {
+ warn(n, "unreachable code %O", o);
+ warnreach = 0;
+ }
+ }
+ }
+
+ switch(o) {
+
+ default:
+ complex(n);
+ cgen(n, Z);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ canreach = 0;
+ warnreach = !suppress;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ if(typecmplx[n->type->etype]) {
+ sugen(l, nodret, n->type->width);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ regret(&nod, n);
+ cgen(l, &nod);
+ regfree(&nod);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ break;
+
+ case OLABEL:
+ canreach = 1;
+ l = n->left;
+ if(l) {
+ l->pc = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ canreach = 0;
+ warnreach = !suppress;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ if(suppress)
+ return;
+ gbranch(OGOTO);
+ if(n->pc) {
+ patch(p, n->pc);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ canreach = 1;
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ cas();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ cases->isv = 0;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typeword[l->type->etype] && l->type->etype != TIND) {
+ cas();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ cases->isv = typev[l->type->etype];
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ if(l->type == T)
+ break;
+ if(!typeword[l->type->etype] || l->type->etype == TIND) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ cas();
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right); /* body */
+ if(canreach){
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ nbreak++;
+ }
+
+ patch(sp, pc);
+ regalloc(&nod, l, Z);
+ /* always signed */
+ if(typev[l->type->etype])
+ nod.type = types[TVLONG];
+ else
+ nod.type = types[TLONG];
+ cgen(l, &nod);
+ doswit(&nod);
+ regfree(&nod);
+ patch(spb, pc);
+
+ cases = cn;
+ breakpc = sbc;
+ canreach = nbreak!=0;
+ if(canreach == 0)
+ warnreach = !suppress;
+ nbreak = snbreak;
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l, Z); /* test */
+ patch(p, breakpc);
+ if(l->op != OCONST || vconst(l) == 0)
+ nbreak++;
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ canreach = nbreak!=0;
+ if(canreach == 0)
+ warnreach = !suppress;
+ nbreak = snbreak;
+ break;
+
+ case OFOR:
+ l = n->left;
+ if(!canreach && l->right->left && warnreach) {
+ warn(n, "unreachable code FOR");
+ warnreach = 0;
+ }
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ /*
+ * if there are no incoming labels in the
+ * body and the top's not reachable, warn
+ */
+ if(!canreach && warnreach && deadheads(n)) {
+ warn(n, "unreachable code %O", o);
+ warnreach = 0;
+ }
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ sncontin = ncontin;
+ ncontin = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left, Z);
+ patch(p, breakpc);
+ if(l->left->op != OCONST || vconst(l->left) == 0)
+ nbreak++;
+ }
+ canreach = 1;
+ gen(n->right); /* body */
+ if(canreach){
+ gbranch(OGOTO);
+ patch(p, continpc);
+ ncontin++;
+ }
+ if(!ncontin && l->right->right && warnreach) {
+ warn(l->right->right, "unreachable FOR inc");
+ warnreach = 0;
+ }
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ canreach = nbreak!=0;
+ if(canreach == 0)
+ warnreach = !suppress;
+ nbreak = snbreak;
+ ncontin = sncontin;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ ncontin++;
+ canreach = 0;
+ warnreach = !suppress;
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ /*
+ * Don't complain about unreachable break statements.
+ * There are breaks hidden in yacc's output and some people
+ * write return; break; in their switch statements out of habit.
+ * However, don't confuse the analysis by inserting an
+ * unreachable reference to breakpc either.
+ */
+ if(!canreach)
+ break;
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ nbreak++;
+ canreach = 0;
+ warnreach = !suppress;
+ break;
+
+ case OIF:
+ l = n->left;
+ if(bcomplex(l, n->right)) {
+ if(typefd[l->type->etype])
+ f = !l->fconst;
+ else
+ f = !l->vconst;
+ if(debug['c'])
+ print("%L const if %s\n", nearln, f ? "false" : "true");
+ if(f) {
+ canreach = 1;
+ supgen(n->right->left);
+ oldreach = canreach;
+ canreach = 1;
+ gen(n->right->right);
+ /*
+ * treat constant ifs as regular ifs for
+ * reachability warnings.
+ */
+ if(!canreach && oldreach && debug['w'] < 2)
+ warnreach = 0;
+ }
+ else {
+ canreach = 1;
+ gen(n->right->left);
+ oldreach = canreach;
+ canreach = 1;
+ supgen(n->right->right);
+ /*
+ * treat constant ifs as regular ifs for
+ * reachability warnings.
+ */
+ if(!oldreach && canreach && debug['w'] < 2)
+ warnreach = 0;
+ canreach = oldreach;
+ }
+ }
+ else {
+ sp = p;
+ canreach = 1;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ oldreach = canreach;
+ canreach = 1;
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ canreach = canreach || oldreach;
+ if(canreach == 0)
+ warnreach = !suppress;
+ }
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gins(ANOP, n, Z);
+ break;
+ case ONAME:
+ if(o == OSET)
+ gins(ANOP, Z, n);
+ else
+ gins(ANOP, n, Z);
+ break;
+ }
+}
+
+int
+bcomplex(Node *n, Node *c)
+{
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type == T) {
+ gbranch(OGOTO);
+ return 0;
+ }
+ if(c != Z && n->op == OCONST && deadheads(c))
+ return 1;
+ bool64(n);
+ boolgen(n, 1, Z);
+ return 0;
+}
diff --git a/src/cmd/6c/pswt.c b/src/cmd/6c/pswt.c
new file mode 100644
index 0000000..f4149f1
--- /dev/null
+++ b/src/cmd/6c/pswt.c
@@ -0,0 +1,168 @@
+// Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = (C1*)a1;
+ p2 = (C1*)a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ long def, nc, i, isv;
+
+ def = 0;
+ nc = 0;
+ isv = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ isv |= c->isv;
+ nc++;
+ }
+ if(isv && !typev[n->type->etype])
+ warn(n, "32-bit switch expression with 64-bit case constant");
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ if(isv)
+ q->val = c->val;
+ else
+ q->val = (long)c->val; /* cast ensures correct value for 32-bit switch on 64-bit architecture */
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(debug['W'])
+ for(i=0; i<nc; i++)
+ print("case %2ld: = %.8llux\n", i, (vlong)iq[i].val);
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val)
+ diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val);
+ if(def == 0) {
+ def = breakpc;
+ nbreak++;
+ }
+ swit1(iq, nc, def, n);
+}
+
+void
+cas(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+ char buf[2];
+ int c;
+ long r;
+
+ if(suppress)
+ return nstring;
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, Z);
+ if(r != Z)
+ cgen(r, Z);
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c
new file mode 100644
index 0000000..a03d1ca
--- /dev/null
+++ b/src/cmd/6c/reg.c
@@ -0,0 +1,1386 @@
+// Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->cost;
+ c2 = p1->cost;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ long initpc, val, npc;
+ ulong vreg;
+ Bits bit;
+ struct
+ {
+ long m;
+ long c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = RtoB(D_SP) | RtoB(D_AX) | RtoB(D_X0);
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ARET:
+ case AJMP:
+ case AIRETL:
+ case AIRETQ:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ bit = mkvar(r, &p->from);
+ if(bany(&bit))
+ switch(p->as) {
+ /*
+ * funny
+ */
+ case ALEAL:
+ case ALEAQ:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * left side read
+ */
+ default:
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+ break;
+ }
+
+ bit = mkvar(r, &p->to);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ diag(Z, "reg: unknown op: %A", p->as);
+ break;
+
+ /*
+ * right side read
+ */
+ case ACMPB:
+ case ACMPL:
+ case ACMPQ:
+ case ACMPW:
+ case ACOMISS:
+ case ACOMISD:
+ case AUCOMISS:
+ case AUCOMISD:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVL:
+ case AMOVQ:
+ case AMOVB:
+ case AMOVW:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVBQSX:
+ case AMOVBQZX:
+ case AMOVLQSX:
+ case AMOVLQZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ case AMOVWQSX:
+ case AMOVWQZX:
+
+ case AMOVSS:
+ case AMOVSD:
+ case ACVTSD2SL:
+ case ACVTSD2SQ:
+ case ACVTSD2SS:
+ case ACVTSL2SD:
+ case ACVTSL2SS:
+ case ACVTSQ2SD:
+ case ACVTSQ2SS:
+ case ACVTSS2SD:
+ case ACVTSS2SL:
+ case ACVTSS2SQ:
+ case ACVTTSD2SL:
+ case ACVTTSD2SQ:
+ case ACVTTSS2SL:
+ case ACVTTSS2SQ:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side read+write
+ */
+ case AADDB:
+ case AADDL:
+ case AADDQ:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDQ:
+ case AANDW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBQ:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORQ:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORQ:
+ case AXORW:
+ case ASALB:
+ case ASALL:
+ case ASALQ:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARQ:
+ case ASARW:
+ case AROLB:
+ case AROLL:
+ case AROLQ:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORQ:
+ case ARORW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLQ:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRQ:
+ case ASHRW:
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ case ANEGL:
+ case ANEGQ:
+ case ANOTL:
+ case ANOTQ:
+ case AADCL:
+ case AADCQ:
+ case ASBBL:
+ case ASBBQ:
+
+ case AADDSD:
+ case AADDSS:
+ case ACMPSD:
+ case ACMPSS:
+ case ADIVSD:
+ case ADIVSS:
+ case AMAXSD:
+ case AMAXSS:
+ case AMINSD:
+ case AMINSS:
+ case AMULSD:
+ case AMULSS:
+ case ARCPSS:
+ case ARSQRTSS:
+ case ASQRTSD:
+ case ASQRTSS:
+ case ASUBSD:
+ case ASUBSS:
+ case AXORPD:
+ for(z=0; z<BITS; z++) {
+ r->set.b[z] |= bit.b[z];
+ r->use2.b[z] |= bit.b[z];
+ }
+ break;
+
+ /*
+ * funny
+ */
+ case ACALL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+
+ switch(p->as) {
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVQ:
+ case AIDIVW:
+ case AIMULB:
+ case ADIVB:
+ case ADIVL:
+ case ADIVQ:
+ case ADIVW:
+ case AMULB:
+ case AMULL:
+ case AMULQ:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ case ACQO:
+ r->regu |= RtoB(D_AX) | RtoB(D_DX);
+ break;
+
+ case AREP:
+ case AREPN:
+ case ALOOP:
+ case ALOOPEQ:
+ case ALOOPNE:
+ r->regu |= RtoB(D_CX);
+ break;
+
+ case AMOVSB:
+ case AMOVSL:
+ case AMOVSQ:
+ case AMOVSW:
+ case ACMPSB:
+ case ACMPSL:
+ case ACMPSQ:
+ case ACMPSW:
+ r->regu |= RtoB(D_SI) | RtoB(D_DI);
+ break;
+
+ case ASTOSB:
+ case ASTOSL:
+ case ASTOSQ:
+ case ASTOSW:
+ case ASCASB:
+ case ASCASL:
+ case ASCASQ:
+ case ASCASW:
+ r->regu |= RtoB(D_AX) | RtoB(D_DI);
+ break;
+
+ case AINSB:
+ case AINSL:
+ case AINSW:
+ case AOUTSB:
+ case AOUTSL:
+ case AOUTSW:
+ r->regu |= RtoB(D_DI) | RtoB(D_DX);
+ break;
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ nearln = p->lineno;
+ diag(Z, "ref not found\n%P", p);
+ continue;
+ }
+ if(r1 == r) {
+ nearln = p->lineno;
+ diag(Z, "ref to self\n%P", p);
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R']) {
+ p = firstr->prog;
+ print("\n%L %D\n", p->lineno, &p->from);
+ }
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, npc);
+ if(debug['R'] && debug['v']) {
+ print("\nlooping structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%ld:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->use1.b[z] |
+ r->use2.b[z] |
+ r->set.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARET)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(change)
+ goto loop1;
+
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(change)
+ goto loop2;
+
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+ }
+ }
+ if(debug['R'] && debug['v'])
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ if(debug['R'] && debug['v']) {
+ print("%P\t", r->prog);
+ if(bany(&r->set))
+ print("s:%B ", r->set);
+ if(bany(&r->refahead))
+ print("ra:%B ", r->refahead);
+ if(bany(&r->calahead))
+ print("ca:%B ", r->calahead);
+ print("\n");
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set and not used: %B\n", bit);
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ change = 0;
+ if(debug['R'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L$%d: %B\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R']) {
+ print("%L$%d %R: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno,
+ bit);
+ }
+ if(rgp->regno != 0)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ peep();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Adr *a;
+ Var *v;
+
+ p1 = alloc(sizeof(*p1));
+ *p1 = zprog;
+ p = r->prog;
+
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+
+ a = &p1->to;
+ a->sym = v->sym;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = v->name;
+
+ p1->as = AMOVL;
+ if(v->etype == TCHAR || v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TSHORT || v->etype == TUSHORT)
+ p1->as = AMOVW;
+ if(v->etype == TVLONG || v->etype == TUVLONG || v->etype == TIND)
+ p1->as = AMOVQ;
+ if(v->etype == TFLOAT)
+ p1->as = AMOVSS;
+ if(v->etype == TDOUBLE)
+ p1->as = AMOVSD;
+
+ p1->from.type = rn;
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = rn;
+ if(v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TUSHORT)
+ p1->as = AMOVW;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+ulong
+doregbits(int r)
+{
+ ulong b;
+
+ b = 0;
+ if(r >= D_INDIR)
+ r -= D_INDIR;
+ if(r >= D_AX && r <= D_R15)
+ b |= RtoB(r);
+ else
+ if(r >= D_AL && r <= D_R15B)
+ b |= RtoB(r-D_AL+D_AX);
+ else
+ if(r >= D_AH && r <= D_BH)
+ b |= RtoB(r-D_AH+D_AX);
+ else
+ if(r >= D_X0 && r <= D_X0+15)
+ b |= FtoB(r);
+ return b;
+}
+
+Bits
+mkvar(Reg *r, Adr *a)
+{
+ Var *v;
+ int i, t, n, et, z;
+ long o;
+ Bits bit;
+ Sym *s;
+
+ /*
+ * mark registers used
+ */
+ t = a->type;
+ r->regu |= doregbits(t);
+ r->regu |= doregbits(a->index);
+
+ switch(t) {
+ default:
+ goto none;
+ case D_ADDR:
+ a->type = a->index;
+ bit = mkvar(r, a);
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ a->type = t;
+ goto none;
+ case D_EXTERN:
+ case D_STATIC:
+ case D_PARAM:
+ case D_AUTO:
+ n = t;
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ goto none;
+ if(s->name[0] == '.')
+ goto none;
+ et = a->etype;
+ o = a->offset;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(n == v->name)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->name = n;
+ v->etype = et;
+ if(debug['R'])
+ print("bit=%2d et=%2d %D\n", i, et, a);
+
+out:
+ bit = blsh(i);
+ if(n == D_EXTERN || n == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(n == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ if(v->etype != et || !(typechlpfd[et] || typev[et])) /* funny punning */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ change++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ change++;
+ }
+ }
+ switch(r1->prog->as) {
+ case ACALL:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARET:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z];
+ ref.b[z] = 0;
+ }
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+long
+postorder(Reg *r, Reg **rpo2r, long n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+long
+rpolca(long *idom, long rpo1, long rpo2)
+{
+ long t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal(Z, "bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(long *idom, long r, long s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(long *idom, Reg *r)
+{
+ long src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, long head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, long nr)
+{
+ Reg *r1;
+ long i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(long));
+ maxnr = nr;
+ }
+
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ change++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+ulong
+allreg(ulong b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ case TARRAY:
+ i = BtoR(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TDOUBLE:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tld %B $%d\n", r->loop,
+ r->prog, blsh(bn), change);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu1 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu2 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tst %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+ulong
+regset(Reg *r, ulong bb)
+{
+ ulong b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = b & 0xFFFF? BtoR(b): BtoF(b);
+ if(v.type == 0)
+ diag(Z, "zero v.type for %#lux", b);
+ c = copyu(r->prog, &v, A);
+ if(c == 3)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+ulong
+reguse(Reg *r, ulong bb)
+{
+ ulong b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = b & 0xFFFF? BtoR(b): BtoF(b);
+ c = copyu(r->prog, &v, A);
+ if(c == 1 || c == 2 || c == 4)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ ulong bb, vreg, x;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+
+ bb = vreg;
+ for(; r; r=r->s1) {
+ x = r->regu & ~bb;
+ if(x) {
+ vreg |= reguse(r, x);
+ bb |= regset(r, x);
+ }
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, long rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+
+ a->sym = 0;
+ a->offset = 0;
+ a->type = rn;
+}
+
+long
+RtoB(int r)
+{
+
+ if(r < D_AX || r > D_R15)
+ return 0;
+ return 1L << (r-D_AX);
+}
+
+int
+BtoR(long b)
+{
+
+ b &= 0xffffL;
+ if(b == 0)
+ return 0;
+ return bitno(b) + D_AX;
+}
+
+/*
+ * bit reg
+ * 16 X5
+ * 17 X6
+ * 18 X7
+ */
+long
+FtoB(int f)
+{
+ if(f < FREGMIN || f > FREGEXT)
+ return 0;
+ return 1L << (f - FREGMIN + 16);
+}
+
+int
+BtoF(long b)
+{
+
+ b &= 0x70000L;
+ if(b == 0)
+ return 0;
+ return bitno(b) - 16 + FREGMIN;
+}
diff --git a/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c
new file mode 100644
index 0000000..63a86ba
--- /dev/null
+++ b/src/cmd/6c/sgen.c
@@ -0,0 +1,465 @@
+// Inferno utils/6c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gins(ANOP, Z, Z);
+ p->to.type = REGRET;
+ }
+ if(n & 2) {
+ gins(ANOP, Z, Z);
+ p->to.type = FREGRET;
+ }
+}
+
+/* welcome to commute */
+static void
+commute(Node *n)
+{
+ Node *l, *r;
+
+ l = n->left;
+ r = n->right;
+ if(r->complex > l->complex) {
+ n->left = r;
+ n->right = l;
+ }
+}
+
+void
+indexshift(Node *n)
+{
+ int g;
+
+ if(!typechlpv[n->type->etype])
+ return;
+ simplifyshift(n);
+ if(n->op == OASHL && n->right->op == OCONST){
+ g = vconst(n->right);
+ if(g >= 0 && g <= 3)
+ n->addable = 7;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * NAME ==> 10/11 name+value(SB/SP)
+ * REGISTER ==> 12 register
+ * CONST ==> 20 $value
+ * *(20) ==> 21 value
+ * &(10) ==> 13 $name+value(SB)
+ * &(11) ==> 1 $name+value(SP)
+ * (13) + (20) ==> 13 fold constants
+ * (1) + (20) ==> 1 fold constants
+ * *(13) ==> 10 back to name
+ * *(1) ==> 11 back to name
+ *
+ * (20) * (X) ==> 7 multiplier in indexing
+ * (X,7) + (13,1) ==> 8 adder in indexing (addresses)
+ * (8) ==> &9(OINDEX) index, almost addressable
+ *
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int g;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->complex = 0;
+ n->addable = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ break;
+
+ case ONAME:
+ n->addable = 10;
+ if(n->class == CPARAM || n->class == CAUTO)
+ n->addable = 11;
+ break;
+
+ case OREGISTER:
+ n->addable = 12;
+ break;
+
+ case OINDREG:
+ n->addable = 12;
+ break;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 13;
+ else
+ if(l->addable == 11)
+ n->addable = 1;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(n->type->etype != TIND)
+ break;
+
+ switch(r->addable) {
+ case 20:
+ switch(l->addable) {
+ case 1:
+ case 13:
+ commadd:
+ l->type = n->type;
+ *n = *l;
+ l = new(0, Z, Z);
+ *l = *(n->left);
+ l->xoffset += r->vconst;
+ n->left = l;
+ r = n->right;
+ goto brk;
+ }
+ break;
+
+ case 1:
+ case 13:
+ case 10:
+ case 11:
+ /* l is the base, r is the index */
+ if(l->addable != 20)
+ n->addable = 8;
+ break;
+ }
+ switch(l->addable) {
+ case 20:
+ switch(r->addable) {
+ case 13:
+ case 1:
+ r = n->left;
+ l = n->right;
+ n->left = l;
+ n->right = r;
+ goto commadd;
+ }
+ break;
+
+ case 13:
+ case 1:
+ case 10:
+ case 11:
+ /* r is the base, l is the index */
+ if(r->addable != 20)
+ n->addable = 8;
+ break;
+ }
+ if(n->addable == 8 && !side(n)) {
+ indx(n);
+ l = new1(OINDEX, idx.basetree, idx.regtree);
+ l->scale = idx.scale;
+ l->addable = 9;
+ l->complex = l->right->complex;
+ l->type = l->left->type;
+ n->op = OADDR;
+ n->left = l;
+ n->right = Z;
+ n->addable = 8;
+ break;
+ }
+ break;
+
+ case OINDEX:
+ xcom(l);
+ xcom(r);
+ n->addable = 9;
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->op == OADDR) {
+ l = l->left;
+ l->type = n->type;
+ *n = *l;
+ return;
+ }
+ switch(l->addable) {
+ case 20:
+ n->addable = 21;
+ break;
+ case 1:
+ n->addable = 11;
+ break;
+ case 13:
+ n->addable = 10;
+ break;
+ }
+ break;
+
+ case OASHL:
+ xcom(l);
+ xcom(r);
+ indexshift(n);
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ g = vlog(l);
+ if(g >= 0) {
+ n->left = r;
+ n->right = l;
+ l = r;
+ r = n->right;
+ }
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASHL;
+ r->vconst = g;
+ r->type = types[TINT];
+ indexshift(n);
+ break;
+ }
+ commute(n);
+ break;
+
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASLSHR;
+ r->vconst = g;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OLSHR;
+ r->vconst = g;
+ r->type = types[TINT];
+ indexshift(n);
+ break;
+ }
+ break;
+
+ case OASLMOD:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLMOD:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OAND;
+ r->vconst--;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASASHL;
+ r->vconst = g;
+ }
+ break;
+
+ case OLSHR:
+ case OASHR:
+ xcom(l);
+ xcom(r);
+ indexshift(n);
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+brk:
+ if(n->addable >= 10)
+ return;
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ switch(n->op) {
+
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OCAST:
+ if(l->type->etype == TUVLONG && typefd[n->type->etype])
+ n->complex += 2;
+ break;
+
+ case OLMOD:
+ case OMOD:
+ case OLMUL:
+ case OLDIV:
+ case OMUL:
+ case ODIV:
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(r->complex >= l->complex) {
+ n->complex = l->complex + 3;
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ } else {
+ n->complex = r->complex + 3;
+ if(l->complex > n->complex)
+ n->complex = l->complex;
+ }
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ if(r->complex >= l->complex) {
+ n->complex = l->complex + 2;
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ } else {
+ n->complex = r->complex + 2;
+ if(l->complex > n->complex)
+ n->complex = l->complex;
+ }
+ break;
+
+ case OADD:
+ case OXOR:
+ case OAND:
+ case OOR:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ /*
+ * compare operators, make const on left
+ */
+ if(r->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ n->op = invrel[relindex(n->op)];
+ }
+ break;
+ }
+}
+
+void
+indx(Node *n)
+{
+ Node *l, *r;
+
+ if(debug['x'])
+ prtree(n, "indx");
+
+ l = n->left;
+ r = n->right;
+ if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
+ n->right = l;
+ n->left = r;
+ l = r;
+ r = n->right;
+ }
+ if(l->addable != 7) {
+ idx.regtree = l;
+ idx.scale = 1;
+ } else
+ if(l->right->addable == 20) {
+ idx.regtree = l->left;
+ idx.scale = 1 << l->right->vconst;
+ } else
+ if(l->left->addable == 20) {
+ idx.regtree = l->right;
+ idx.scale = 1 << l->left->vconst;
+ } else
+ diag(n, "bad index");
+
+ idx.basetree = r;
+ if(debug['x']) {
+ print("scale = %d\n", idx.scale);
+ prtree(idx.regtree, "index");
+ prtree(idx.basetree, "base");
+ }
+}
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
new file mode 100644
index 0000000..5b2a6ca
--- /dev/null
+++ b/src/cmd/6c/swt.c
@@ -0,0 +1,566 @@
+// Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+void
+swit1(C1 *q, int nc, long def, Node *n)
+{
+ C1 *r;
+ int i;
+ Prog *sp;
+
+ if(nc < 5) {
+ for(i=0; i<nc; i++) {
+ if(debug['W'])
+ print("case = %.8llux\n", q->val);
+ gcmp(OEQ, n, q->val);
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+ i = nc / 2;
+ r = q+i;
+ if(debug['W'])
+ print("case > %.8llux\n", r->val);
+ gcmp(OGT, n, r->val);
+ sp = p;
+ gbranch(OGOTO);
+ p->as = AJEQ;
+ patch(p, r->label);
+ swit1(q, i, def, n);
+
+ if(debug['W'])
+ print("case < %.8llux\n", r->val);
+ patch(sp, pc);
+ swit1(r+1, nc-i-1, def, n);
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int sh;
+ long v;
+ Node *l;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ l = b->left;
+ if(n2 != Z) {
+ regalloc(n1, l, nn);
+ reglcgen(n2, l, Z);
+ regalloc(n3, l, Z);
+ gmove(n2, n3);
+ gmove(n3, n1);
+ } else {
+ regalloc(n1, l, nn);
+ cgen(l, n1);
+ }
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, tfield, nodconst(v), n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, tfield, nodconst(sh), n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, tfield, nodconst(sh), n1);
+ else
+ gopcode(OASHR, tfield, nodconst(sh), n1);
+ }
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ long v;
+ Node nod;
+ int sh;
+
+ regalloc(&nod, b->left, Z);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, types[TLONG], nodconst(v), n1);
+ gmove(n1, &nod);
+ if(nn != Z)
+ gmove(n1, nn);
+ sh = b->type->shift;
+ if(sh > 0)
+ gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
+ v <<= sh;
+ gopcode(OAND, types[TLONG], nodconst(~v), n3);
+ gopcode(OOR, types[TLONG], n3, &nod);
+ gmove(&nod, n2);
+
+ regfree(&nod);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+long
+outstring(char *s, long n)
+{
+ long r;
+
+ if(suppress)
+ return nstring;
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, nodconst(0L));
+ p->from.offset += nstring - NSNAME;
+ p->from.scale = NSNAME;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, string, NSNAME);
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+void
+sextern(Sym *s, Node *a, long o, long w)
+{
+ long e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, nodconst(0L));
+ p->from.offset += o+e;
+ p->from.scale = lw;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, long o, long w)
+{
+ if(0 && a->op == OCONST && typev[a->type->etype]) {
+ gpseudo(ADATA, s, lo64(a));
+ p->from.offset += o;
+ p->from.scale = 4;
+ gpseudo(ADATA, s, hi64(a));
+ p->from.offset += o + 4;
+ p->from.scale = 4;
+ return;
+ }
+ gpseudo(ADATA, s, a);
+ p->from.offset += o;
+ p->from.scale = w;
+ switch(p->to.type) {
+ default:
+ p->to.index = p->to.type;
+ p->to.type = D_ADDR;
+ case D_CONST:
+ case D_FCONST:
+ case D_ADDR:
+ break;
+ }
+}
+
+void zname(Biobuf*, Sym*, int);
+void zaddr(Biobuf*, Adr*, int);
+void outhist(Biobuf*);
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int f, sf, st, t, sym;
+ Biobuf b;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+
+ f = open(outfile, OWRITE);
+ if(f < 0) {
+ diag(Z, "cannot open %s", outfile);
+ return;
+ }
+ Binit(&b, f, OWRITE);
+
+ Bprint(&b, "x86-64\n");
+ Bprint(&b, "!\n");
+
+ outhist(&b);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.type;
+ if(t == D_ADDR)
+ t = p->from.index;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.type;
+ if(t == D_ADDR)
+ t = p->to.index;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&b, p->as);
+ Bputc(&b, p->as>>8);
+ Bputc(&b, p->lineno);
+ Bputc(&b, p->lineno>>8);
+ Bputc(&b, p->lineno>>16);
+ Bputc(&b, p->lineno>>24);
+ zaddr(&b, &p->from, sf);
+ zaddr(&b, &p->to, st);
+ }
+ Bflush(&b);
+ close(f);
+ firstp = P;
+ lastp = P;
+}
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, ANAME>>8);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ Bputc(b, pg.as);
+ Bputc(b, pg.as>>8);
+ Bputc(b, pg.lineno);
+ Bputc(b, pg.lineno>>8);
+ Bputc(b, pg.lineno>>16);
+ Bputc(b, pg.lineno>>24);
+ zaddr(b, &pg.from, 0);
+ zaddr(b, &pg.to, 0);
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n;
+ ulong sig;
+
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ Bputc(b, ASIGNAME);
+ Bputc(b, ASIGNAME>>8);
+ Bputc(b, sig);
+ Bputc(b, sig>>8);
+ Bputc(b, sig>>16);
+ Bputc(b, sig>>24);
+ s->sig = SIGDONE;
+ }
+ else{
+ Bputc(b, ANAME); /* as */
+ Bputc(b, ANAME>>8); /* as */
+ }
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+ n = s->name;
+ while(*n) {
+ Bputc(b, *n);
+ n++;
+ }
+ Bputc(b, 0);
+}
+
+void
+zaddr(Biobuf *b, Adr *a, int s)
+{
+ long l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(s != 0)
+ t |= T_SYM;
+
+ switch(a->type) {
+ default:
+ t |= T_TYPE;
+ case D_NONE:
+ if(a->offset != 0) {
+ t |= T_OFFSET;
+ l = a->offset;
+ if((vlong)l != a->offset)
+ t |= T_64;
+ }
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ }
+ Bputc(b, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ Bputc(b, a->index);
+ Bputc(b, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ if(t & T_64) {
+ l = a->offset>>32;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(b, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ l = e.h;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(b, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ Bputc(b, a->type);
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_VLONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial align of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_VLONG)
+ w = SZ_VLONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesu[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial align of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_VLONG) {
+ w = SZ_VLONG;
+ break;
+ }
+ w = 1; /* little endian no adjustment */
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = t->width;
+ if(w > SZ_VLONG)
+ w = SZ_VLONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael1);
+ o = align(o, t, Ael2);
+ break;
+ }
+ o = xround(o, w);
+ if(debug['A'])
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v += SZ_VLONG-1;
+ if(v > max)
+ max = xround(v, SZ_VLONG);
+ return max;
+}
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
new file mode 100644
index 0000000..eb560f5
--- /dev/null
+++ b/src/cmd/6c/txt.c
@@ -0,0 +1,1546 @@
+// Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+void
+ginit(void)
+{
+ int i;
+ Type *t;
+
+ thechar = '6';
+ thestring = "amd64";
+ exregoffset = REGEXT;
+ exfregoffset = FREGEXT;
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TINT];
+
+ typeword = typechlvp;
+ typecmplx = typesu;
+
+ /* TO DO */
+ memmove(typechlpv, typechlp, sizeof(typechlpv));
+ typechlpv[TVLONG] = 1;
+ typechlpv[TUVLONG] = 1;
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.from.type = D_NONE;
+ zprog.from.index = D_NONE;
+ zprog.from.scale = 0;
+ zprog.to = zprog.from;
+
+ lregnode.op = OREGISTER;
+ lregnode.class = CEXREG;
+ lregnode.reg = REGTMP;
+ lregnode.complex = 0;
+ lregnode.addable = 11;
+ lregnode.type = types[TLONG];
+
+ qregnode = lregnode;
+ qregnode.type = types[TVLONG];
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ vconstnode = constnode;
+ vconstnode.type = types[TVLONG];
+
+ fconstnode.op = OCONST;
+ fconstnode.class = CXXX;
+ fconstnode.complex = 0;
+ fconstnode.addable = 20;
+ fconstnode.type = types[TDOUBLE];
+
+ nodsafe = new(ONAME, Z, Z);
+ nodsafe->sym = slookup(".safe");
+ nodsafe->type = types[TINT];
+ nodsafe->etype = types[TINT]->etype;
+ nodsafe->class = CAUTO;
+ complex(nodsafe);
+
+ t = typ(TARRAY, types[TCHAR]);
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = t;
+
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = t;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = TIND;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ if(0)
+ com64init();
+
+ for(i=0; i<nelem(reg); i++) {
+ reg[i] = 1;
+ if(i >= D_AX && i <= D_R15 && i != D_SP)
+ reg[i] = 0;
+ if(i >= D_X0 && i <= D_X7)
+ reg[i] = 0;
+ }
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ reg[D_SP]--;
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i])
+ diag(Z, "reg %R left allocated", i);
+ for(i=D_X0; i<=D_X7; i++)
+ if(reg[i])
+ diag(Z, "reg %R left allocated", i);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, nodconst(s->type->width));
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+nextpc(void)
+{
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ p->lineno = nearln;
+ pc++;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+ long regs;
+ Node fnxargs[20], *fnxp;
+
+ regs = cursafe;
+
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
+
+ curarg = 0;
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
+
+ cursafe = regs;
+}
+
+int
+nareg(void)
+{
+ int i, n;
+
+ n = 0;
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i] == 0)
+ n++;
+ return n;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+ Node nod;
+
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ garg1(n->left, tn1, tn2, f, fnxp);
+ garg1(n->right, tn1, tn2, f, fnxp);
+ return;
+ }
+ if(f == 0) {
+ if(n->complex >= FNX) {
+ regsalloc(*fnxp, n);
+ nod = znode;
+ nod.op = OAS;
+ nod.left = *fnxp;
+ nod.right = n;
+ nod.type = n->type;
+ cgen(&nod, Z);
+ (*fnxp)++;
+ }
+ return;
+ }
+ if(typesu[n->type->etype]) {
+ regaalloc(tn2, n);
+ if(n->complex >= FNX) {
+ sugen(*fnxp, tn2, n->type->width);
+ (*fnxp)++;
+ } else
+ sugen(n, tn2, n->type->width);
+ return;
+ }
+ if(REGARG && curarg == 0 && typechlpv[n->type->etype]) {
+ regaalloc1(tn1, n);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ return;
+ }
+ if(vconst(n) == 0) {
+ regaalloc(tn2, n);
+ gmove(n, tn2);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ regaalloc(tn2, n);
+ gmove(tn1, tn2);
+ regfree(tn1);
+}
+
+Node*
+nodgconst(vlong v, Type *t)
+{
+ if(!typev[t->etype])
+ return nodconst((long)v);
+ vconstnode.vconst = v;
+ return &vconstnode;
+}
+
+Node*
+nodconst(long v)
+{
+ constnode.vconst = v;
+ return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+int
+isreg(Node *n, int r)
+{
+
+ if(n->op == OREGISTER)
+ if(n->reg == r)
+ return 1;
+ return 0;
+}
+
+int
+nodreg(Node *n, Node *nn, int r)
+{
+ int et;
+
+ *n = qregnode;
+ n->reg = r;
+ if(nn != Z){
+ et = nn->type->etype;
+ if(!typefd[et] && nn->type->width <= SZ_LONG && 0)
+ n->type = typeu[et]? types[TUINT]: types[TINT];
+ else
+ n->type = nn->type;
+//print("nodreg %s [%s]\n", tnames[et], tnames[n->type->etype]);
+ n->lineno = nn->lineno;
+ }
+ if(reg[r] == 0)
+ return 0;
+ if(nn != Z) {
+ if(nn->op == OREGISTER)
+ if(nn->reg == r)
+ return 0;
+ }
+ return 1;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i;
+
+ switch(tn->type->etype) {
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= D_AX && i <= D_R15)
+ goto out;
+ }
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i] == 0)
+ goto out;
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= D_X0 && i <= D_X7)
+ goto out;
+ }
+ for(i=D_X0; i<=D_X7; i++)
+ if(reg[i] == 0)
+ goto out;
+ diag(tn, "out of float registers");
+ goto out;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ i = 0;
+out:
+ if(i)
+ reg[i]++;
+ nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+ Node nod;
+
+ nod = *tn;
+ nod.type = types[TIND];
+ regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ i = 0;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ goto err;
+ i = n->reg;
+ if(i < 0 || i >= sizeof(reg))
+ goto err;
+ if(reg[i] <= 0)
+ goto err;
+ reg[i]--;
+ return;
+err:
+ diag(n, "error in regfree: %R", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+ *n = *nodsafe;
+ n->xoffset = -(stkoff + cursafe);
+ n->type = nn->type;
+ n->etype = nn->type->etype;
+ n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+ if(REGARG == 0)
+ diag(n, "regaalloc1 and REGARG==0");
+ nodreg(n, nn, REGARG);
+ reg[REGARG]++;
+ curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+ curarg = align(curarg, nn->type, Aarg1);
+ *n = *nn;
+ n->op = OINDREG;
+ n->reg = REGSP;
+ n->xoffset = curarg;
+ n->complex = 0;
+ n->addable = 20;
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+ if(n->op != OREGISTER) {
+ diag(n, "regind not OREGISTER");
+ return;
+ }
+ n->op = OINDREG;
+ n->type = nn->type;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+ long v;
+
+ a->type = D_NONE;
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O %D", n->op, a);
+ break;
+
+ case OREGISTER:
+ a->type = n->reg;
+ a->sym = S;
+ break;
+
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type >= D_AX && a->type <= D_R15)
+ a->type += D_INDIR;
+ else
+ if(a->type == D_CONST)
+ a->type = D_NONE+D_INDIR;
+ else
+ if(a->type == D_ADDR) {
+ a->type = a->index;
+ a->index = D_NONE;
+ } else
+ goto bad;
+ break;
+
+ case OINDEX:
+ a->type = idx.ptr;
+ if(n->left->op == OADDR || n->left->op == OCONST)
+ naddr(n->left, a);
+ if(a->type >= D_AX && a->type <= D_R15)
+ a->type += D_INDIR;
+ else
+ if(a->type == D_CONST)
+ a->type = D_NONE+D_INDIR;
+ else
+ if(a->type == D_ADDR) {
+ a->type = a->index;
+ a->index = D_NONE;
+ } else
+ goto bad;
+ a->index = idx.reg;
+ a->scale = n->scale;
+ a->offset += n->xoffset;
+ break;
+
+ case OINDREG:
+ a->type = n->reg+D_INDIR;
+ a->sym = S;
+ a->offset = n->xoffset;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->type = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->type = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->type = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ break;
+ }
+ a->sym = S;
+ a->type = D_CONST;
+ if(typev[n->type->etype] || n->type->etype == TIND)
+ a->offset = n->vconst;
+ else
+ a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG);
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type >= D_INDIR) {
+ a->type -= D_INDIR;
+ break;
+ }
+ if(a->type == D_EXTERN || a->type == D_STATIC ||
+ a->type == D_AUTO || a->type == D_PARAM)
+ if(a->index == D_NONE) {
+ a->index = a->type;
+ a->type = D_ADDR;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->right->op == OCONST) {
+ v = n->right->vconst;
+ naddr(n->left, a);
+ } else
+ if(n->left->op == OCONST) {
+ v = n->left->vconst;
+ naddr(n->right, a);
+ } else
+ goto bad;
+ a->offset += v;
+ break;
+
+ }
+}
+
+void
+gcmp(int op, Node *n, vlong val)
+{
+ Node *cn, nod;
+
+ cn = nodgconst(val, n->type);
+ if(!immconst(cn)){
+ regalloc(&nod, n, Z);
+ gmove(cn, &nod);
+ gopcode(op, n->type, n, &nod);
+ regfree(&nod);
+ }else
+ gopcode(op, n->type, n, cn);
+}
+
+#define CASE(a,b) ((a<<8)|(b<<0))
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, t64, a;
+ Node nod, nod1, nod2, nod3;
+ Prog *p1, *p2;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+ t64 = tt == TVLONG || tt == TUVLONG || tt == TIND;
+ if(debug['M'])
+ print("gop: %O %O[%s],%O[%s]\n", OAS,
+ f->op, tnames[ft], t->op, tnames[tt]);
+ if(typefd[ft] && f->op == OCONST) {
+ /* TO DO: pick up special constants, possibly preloaded */
+ if(f->fconst == 0.0){
+ regalloc(&nod, t, t);
+ gins(AXORPD, &nod, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ }
+/*
+ * load
+ */
+ if(f->op == ONAME || f->op == OINDREG ||
+ f->op == OIND || f->op == OINDEX)
+ switch(ft) {
+ case TCHAR:
+ a = AMOVBLSX;
+ if(t64)
+ a = AMOVBQSX;
+ goto ld;
+ case TUCHAR:
+ a = AMOVBLZX;
+ if(t64)
+ a = AMOVBQZX;
+ goto ld;
+ case TSHORT:
+ a = AMOVWLSX;
+ if(t64)
+ a = AMOVWQSX;
+ goto ld;
+ case TUSHORT:
+ a = AMOVWLZX;
+ if(t64)
+ a = AMOVWQZX;
+ goto ld;
+ case TINT:
+ case TLONG:
+ if(typefd[tt]) {
+ regalloc(&nod, t, t);
+ if(tt == TDOUBLE)
+ a = ACVTSL2SD;
+ else
+ a = ACVTSL2SS;
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ a = AMOVL;
+ if(t64)
+ a = AMOVLQSX;
+ goto ld;
+ case TUINT:
+ case TULONG:
+ a = AMOVL;
+ if(t64)
+ a = AMOVLQZX; /* could probably use plain MOVL */
+ goto ld;
+ case TVLONG:
+ if(typefd[tt]) {
+ regalloc(&nod, t, t);
+ if(tt == TDOUBLE)
+ a = ACVTSQ2SD;
+ else
+ a = ACVTSQ2SS;
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ case TUVLONG:
+ a = AMOVQ;
+ goto ld;
+ case TIND:
+ a = AMOVQ;
+
+ ld:
+ regalloc(&nod, f, t);
+ nod.type = t64? types[TVLONG]: types[TINT];
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ a = AMOVSS;
+ goto fld;
+ case TDOUBLE:
+ a = AMOVSD;
+ fld:
+ regalloc(&nod, f, t);
+ if(tt != TDOUBLE && tt != TFLOAT){ /* TO DO: why is this here */
+ prtree(f, "odd tree");
+ nod.type = t64? types[TVLONG]: types[TINT];
+ }
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+/*
+ * store
+ */
+ if(t->op == ONAME || t->op == OINDREG ||
+ t->op == OIND || t->op == OINDEX)
+ switch(tt) {
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVB; goto st;
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVW; goto st;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ a = AMOVL; goto st;
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ a = AMOVQ; goto st;
+
+ st:
+ if(f->op == OCONST) {
+ gins(a, f, t);
+ return;
+ }
+ fst:
+ regalloc(&nod, t, f);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ a = AMOVSS;
+ goto fst;
+ case TDOUBLE:
+ a = AMOVSD;
+ goto fst;
+ }
+
+/*
+ * convert
+ */
+ switch(CASE(ft,tt)) {
+ default:
+/*
+ * integer to integer
+ ********
+ a = AGOK; break;
+
+ case CASE( TCHAR, TCHAR):
+ case CASE( TUCHAR, TCHAR):
+ case CASE( TSHORT, TCHAR):
+ case CASE( TUSHORT,TCHAR):
+ case CASE( TINT, TCHAR):
+ case CASE( TUINT, TCHAR):
+ case CASE( TLONG, TCHAR):
+ case CASE( TULONG, TCHAR):
+ case CASE( TIND, TCHAR):
+
+ case CASE( TCHAR, TUCHAR):
+ case CASE( TUCHAR, TUCHAR):
+ case CASE( TSHORT, TUCHAR):
+ case CASE( TUSHORT,TUCHAR):
+ case CASE( TINT, TUCHAR):
+ case CASE( TUINT, TUCHAR):
+ case CASE( TLONG, TUCHAR):
+ case CASE( TULONG, TUCHAR):
+ case CASE( TIND, TUCHAR):
+
+ case CASE( TSHORT, TSHORT):
+ case CASE( TUSHORT,TSHORT):
+ case CASE( TINT, TSHORT):
+ case CASE( TUINT, TSHORT):
+ case CASE( TLONG, TSHORT):
+ case CASE( TULONG, TSHORT):
+ case CASE( TIND, TSHORT):
+
+ case CASE( TSHORT, TUSHORT):
+ case CASE( TUSHORT,TUSHORT):
+ case CASE( TINT, TUSHORT):
+ case CASE( TUINT, TUSHORT):
+ case CASE( TLONG, TUSHORT):
+ case CASE( TULONG, TUSHORT):
+ case CASE( TIND, TUSHORT):
+
+ case CASE( TINT, TINT):
+ case CASE( TUINT, TINT):
+ case CASE( TLONG, TINT):
+ case CASE( TULONG, TINT):
+ case CASE( TIND, TINT):
+
+ case CASE( TINT, TUINT):
+ case CASE( TUINT, TUINT):
+ case CASE( TLONG, TUINT):
+ case CASE( TULONG, TUINT):
+ case CASE( TIND, TUINT):
+
+ case CASE( TUINT, TIND):
+ case CASE( TVLONG, TUINT):
+ case CASE( TVLONG, TULONG):
+ case CASE( TUVLONG, TUINT):
+ case CASE( TUVLONG, TULONG):
+ *****/
+ a = AMOVL;
+ break;
+
+ case CASE( TVLONG, TCHAR):
+ case CASE( TVLONG, TSHORT):
+ case CASE( TVLONG, TINT):
+ case CASE( TVLONG, TLONG):
+ case CASE( TUVLONG, TCHAR):
+ case CASE( TUVLONG, TSHORT):
+ case CASE( TUVLONG, TINT):
+ case CASE( TUVLONG, TLONG):
+ case CASE( TINT, TVLONG):
+ case CASE( TINT, TUVLONG):
+ case CASE( TLONG, TVLONG):
+ case CASE( TINT, TIND):
+ case CASE( TLONG, TIND):
+ a = AMOVLQSX;
+ if(f->op == OCONST) {
+ f->vconst &= (uvlong)0xffffffffU;
+ if(f->vconst & 0x80000000)
+ f->vconst |= (vlong)0xffffffff << 32;
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE( TUINT, TIND):
+ case CASE( TUINT, TVLONG):
+ case CASE( TUINT, TUVLONG):
+ case CASE( TULONG, TVLONG):
+ case CASE( TULONG, TUVLONG):
+ case CASE( TULONG, TIND):
+ a = AMOVL; /* same effect as AMOVLQZX */
+ if(f->op == OCONST) {
+ f->vconst &= (uvlong)0xffffffffU;
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE( TIND, TVLONG):
+ case CASE( TVLONG, TVLONG):
+ case CASE( TUVLONG, TVLONG):
+ case CASE( TVLONG, TUVLONG):
+ case CASE( TUVLONG, TUVLONG):
+ case CASE( TIND, TUVLONG):
+ case CASE( TVLONG, TIND):
+ case CASE( TUVLONG, TIND):
+ case CASE( TIND, TIND):
+ a = AMOVQ;
+ break;
+
+ case CASE( TSHORT, TINT):
+ case CASE( TSHORT, TUINT):
+ case CASE( TSHORT, TLONG):
+ case CASE( TSHORT, TULONG):
+ a = AMOVWLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ if(f->vconst & 0x8000)
+ f->vconst |= 0xffff0000;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TSHORT, TVLONG):
+ case CASE( TSHORT, TUVLONG):
+ case CASE( TSHORT, TIND):
+ a = AMOVWQSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ if(f->vconst & 0x8000){
+ f->vconst |= 0xffff0000;
+ f->vconst |= (vlong)~0 << 32;
+ }
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUSHORT,TINT):
+ case CASE( TUSHORT,TUINT):
+ case CASE( TUSHORT,TLONG):
+ case CASE( TUSHORT,TULONG):
+ a = AMOVWLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUSHORT,TVLONG):
+ case CASE( TUSHORT,TUVLONG):
+ case CASE( TUSHORT,TIND):
+ a = AMOVWQZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ a = AMOVL; /* MOVL also zero-extends to 64 bits */
+ }
+ break;
+
+ case CASE( TCHAR, TSHORT):
+ case CASE( TCHAR, TUSHORT):
+ case CASE( TCHAR, TINT):
+ case CASE( TCHAR, TUINT):
+ case CASE( TCHAR, TLONG):
+ case CASE( TCHAR, TULONG):
+ a = AMOVBLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ if(f->vconst & 0x80)
+ f->vconst |= 0xffffff00;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TCHAR, TVLONG):
+ case CASE( TCHAR, TUVLONG):
+ case CASE( TCHAR, TIND):
+ a = AMOVBQSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ if(f->vconst & 0x80){
+ f->vconst |= 0xffffff00;
+ f->vconst |= (vlong)~0 << 32;
+ }
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE( TUCHAR, TSHORT):
+ case CASE( TUCHAR, TUSHORT):
+ case CASE( TUCHAR, TINT):
+ case CASE( TUCHAR, TUINT):
+ case CASE( TUCHAR, TLONG):
+ case CASE( TUCHAR, TULONG):
+ a = AMOVBLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUCHAR, TVLONG):
+ case CASE( TUCHAR, TUVLONG):
+ case CASE( TUCHAR, TIND):
+ a = AMOVBQZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ a = AMOVL; /* zero-extends to 64-bits */
+ }
+ break;
+
+/*
+ * float to fix
+ */
+ case CASE( TFLOAT, TCHAR):
+ case CASE( TFLOAT, TUCHAR):
+ case CASE( TFLOAT, TSHORT):
+ case CASE( TFLOAT, TUSHORT):
+ case CASE( TFLOAT, TINT):
+ case CASE( TFLOAT, TUINT):
+ case CASE( TFLOAT, TLONG):
+ case CASE( TFLOAT, TULONG):
+ case CASE( TFLOAT, TVLONG):
+ case CASE( TFLOAT, TUVLONG):
+ case CASE( TFLOAT, TIND):
+
+ case CASE( TDOUBLE,TCHAR):
+ case CASE( TDOUBLE,TUCHAR):
+ case CASE( TDOUBLE,TSHORT):
+ case CASE( TDOUBLE,TUSHORT):
+ case CASE( TDOUBLE,TINT):
+ case CASE( TDOUBLE,TUINT):
+ case CASE( TDOUBLE,TLONG):
+ case CASE( TDOUBLE,TULONG):
+ case CASE( TDOUBLE,TVLONG):
+ case CASE( TDOUBLE,TUVLONG):
+ case CASE( TDOUBLE,TIND):
+ regalloc(&nod, t, Z);
+ if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){
+ if(ft == TFLOAT)
+ a = ACVTTSS2SQ;
+ else
+ a = ACVTTSD2SQ;
+ }else{
+ if(ft == TFLOAT)
+ a = ACVTTSS2SL;
+ else
+ a = ACVTTSD2SL;
+ }
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+/*
+ * ulong to float
+ */
+ case CASE( TUVLONG, TDOUBLE):
+ case CASE( TUVLONG, TFLOAT):
+ a = ACVTSQ2SS;
+ if(tt == TDOUBLE)
+ a = ACVTSQ2SD;
+ regalloc(&nod, f, f);
+ gmove(f, &nod);
+ regalloc(&nod1, t, t);
+ gins(ACMPQ, &nod, nodconst(0));
+ gins(AJLT, Z, Z);
+ p1 = p;
+ gins(a, &nod, &nod1);
+ gins(AJMP, Z, Z);
+ p2 = p;
+ patch(p1, pc);
+ regalloc(&nod2, f, Z);
+ regalloc(&nod3, f, Z);
+ gmove(&nod, &nod2);
+ gins(ASHRQ, nodconst(1), &nod2);
+ gmove(&nod, &nod3);
+ gins(AANDL, nodconst(1), &nod3);
+ gins(AORQ, &nod3, &nod2);
+ gins(a, &nod2, &nod1);
+ gins(tt == TDOUBLE? AADDSD: AADDSS, &nod1, &nod1);
+ regfree(&nod2);
+ regfree(&nod3);
+ patch(p2, pc);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+ case CASE( TULONG, TDOUBLE):
+ case CASE( TUINT, TDOUBLE):
+ case CASE( TULONG, TFLOAT):
+ case CASE( TUINT, TFLOAT):
+ a = ACVTSQ2SS;
+ if(tt == TDOUBLE)
+ a = ACVTSQ2SD;
+ regalloc(&nod, f, f);
+ gins(AMOVLQZX, f, &nod);
+ regalloc(&nod1, t, t);
+ gins(a, &nod, &nod1);
+ gmove(&nod1, t);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+/*
+ * fix to float
+ */
+ case CASE( TCHAR, TFLOAT):
+ case CASE( TUCHAR, TFLOAT):
+ case CASE( TSHORT, TFLOAT):
+ case CASE( TUSHORT,TFLOAT):
+ case CASE( TINT, TFLOAT):
+ case CASE( TLONG, TFLOAT):
+ case CASE( TVLONG, TFLOAT):
+ case CASE( TIND, TFLOAT):
+
+ case CASE( TCHAR, TDOUBLE):
+ case CASE( TUCHAR, TDOUBLE):
+ case CASE( TSHORT, TDOUBLE):
+ case CASE( TUSHORT,TDOUBLE):
+ case CASE( TINT, TDOUBLE):
+ case CASE( TLONG, TDOUBLE):
+ case CASE( TVLONG, TDOUBLE):
+ case CASE( TIND, TDOUBLE):
+ regalloc(&nod, t, t);
+ if(ewidth[ft] == SZ_VLONG){
+ if(tt == TFLOAT)
+ a = ACVTSQ2SS;
+ else
+ a = ACVTSQ2SD;
+ }else{
+ if(tt == TFLOAT)
+ a = ACVTSL2SS;
+ else
+ a = ACVTSL2SD;
+ }
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+/*
+ * float to float
+ */
+ case CASE( TFLOAT, TFLOAT):
+ a = AMOVSS;
+ break;
+ case CASE( TDOUBLE,TFLOAT):
+ a = ACVTSD2SS;
+ break;
+ case CASE( TFLOAT, TDOUBLE):
+ a = ACVTSS2SD;
+ break;
+ case CASE( TDOUBLE,TDOUBLE):
+ a = AMOVSD;
+ break;
+ }
+ if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt]) /* TO DO: check AMOVL */
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+doindex(Node *n)
+{
+ Node nod, nod1;
+ long v;
+
+if(debug['Y'])
+prtree(n, "index");
+
+if(n->left->complex >= FNX)
+print("botch in doindex\n");
+
+ regalloc(&nod, &qregnode, Z);
+ v = constnode.vconst;
+ cgen(n->right, &nod);
+ idx.ptr = D_NONE;
+ if(n->left->op == OCONST)
+ idx.ptr = D_CONST;
+ else if(n->left->op == OREGISTER)
+ idx.ptr = n->left->reg;
+ else if(n->left->op != OADDR) {
+ reg[D_BP]++; // cant be used as a base
+ regalloc(&nod1, &qregnode, Z);
+ cgen(n->left, &nod1);
+ idx.ptr = nod1.reg;
+ regfree(&nod1);
+ reg[D_BP]--;
+ }
+ idx.reg = nod.reg;
+ regfree(&nod);
+ constnode.vconst = v;
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ if(f != Z && f->op == OINDEX)
+ doindex(f);
+ if(t != Z && t->op == OINDEX)
+ doindex(t);
+ nextpc();
+ p->as = a;
+ if(f != Z)
+ naddr(f, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+gopcode(int o, Type *ty, Node *f, Node *t)
+{
+ int a, et;
+
+ et = TLONG;
+ if(ty != T)
+ et = ty->etype;
+ if(debug['M']) {
+ if(f != Z && f->type != T)
+ print("gop: %O %O[%s],", o, f->op, tnames[et]);
+ else
+ print("gop: %O Z,", o);
+ if(t != Z && t->type != T)
+ print("%O[%s]\n", t->op, tnames[t->type->etype]);
+ else
+ print("Z\n");
+ }
+ a = AGOK;
+ switch(o) {
+ case OCOM:
+ a = ANOTL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ANOTB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ANOTW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ANOTQ;
+ break;
+
+ case ONEG:
+ a = ANEGL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ANEGB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ANEGW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ANEGQ;
+ break;
+
+ case OADDR:
+ a = ALEAQ;
+ break;
+
+ case OASADD:
+ case OADD:
+ a = AADDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AADDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AADDW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AADDQ;
+ if(et == TFLOAT)
+ a = AADDSS;
+ if(et == TDOUBLE)
+ a = AADDSD;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a = ASUBL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASUBB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASUBW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASUBQ;
+ if(et == TFLOAT)
+ a = ASUBSS;
+ if(et == TDOUBLE)
+ a = ASUBSD;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AORW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AORQ;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AANDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AANDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AANDW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AANDQ;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AXORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AXORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AXORW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AXORQ;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASHRL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASHRB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASHRW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASHRQ;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASARL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASARB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASARW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASARQ;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASALL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASALB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASALW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASALQ;
+ break;
+
+ case OFUNC:
+ a = ACALL;
+ break;
+
+ case OASMUL:
+ case OMUL:
+ if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
+ t = Z;
+ a = AIMULL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AIMULQ;
+ if(et == TFLOAT)
+ a = AMULSS;
+ if(et == TDOUBLE)
+ a = AMULSD;
+ break;
+
+ case OASMOD:
+ case OMOD:
+ case OASDIV:
+ case ODIV:
+ a = AIDIVL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AIDIVQ;
+ if(et == TFLOAT)
+ a = ADIVSS;
+ if(et == TDOUBLE)
+ a = ADIVSD;
+ break;
+
+ case OASLMUL:
+ case OLMUL:
+ a = AMULL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AMULQ;
+ break;
+
+ case OASLMOD:
+ case OLMOD:
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ADIVQ;
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHS:
+ case OHI:
+ a = ACMPL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ACMPB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ACMPW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ACMPQ;
+ if(et == TFLOAT)
+ a = AUCOMISS;
+ if(et == TDOUBLE)
+ a = AUCOMISD;
+ gins(a, f, t);
+ switch(o) {
+ case OEQ: a = AJEQ; break;
+ case ONE: a = AJNE; break;
+ case OLT: a = AJLT; break;
+ case OLE: a = AJLE; break;
+ case OGE: a = AJGE; break;
+ case OGT: a = AJGT; break;
+ case OLO: a = AJCS; break;
+ case OLS: a = AJLS; break;
+ case OHS: a = AJCC; break;
+ case OHI: a = AJHI; break;
+ }
+ gins(a, Z, Z);
+ return;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ gins(a, f, t);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+ return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg;
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = AGOK;
+ switch(o) {
+ case ORETURN:
+ a = ARET;
+ break;
+ case OGOTO:
+ a = AJMP;
+ break;
+ }
+ nextpc();
+ if(a == AGOK) {
+ diag(Z, "bad in gbranch %O", o);
+ nextpc();
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, long pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ p->as = a;
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.scale = (profileflg ? 0 : NOPROF);
+ if(s->class == CSTATIC)
+ p->from.type = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sconst(Node *n)
+{
+ long v;
+
+ if(n->op == OCONST && !typefd[n->type->etype]) {
+ v = n->vconst;
+ if(v >= -32766L && v < 32766L)
+ return 1;
+ }
+ return 0;
+}
+
+long
+exreg(Type *t)
+{
+ long o;
+
+ if(typechlpv[t->etype]) {
+ if(exregoffset <= REGEXT-4)
+ return 0;
+ o = exregoffset;
+ exregoffset--;
+ return o;
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /*[TXXX]*/
+ SZ_CHAR, /*[TCHAR]*/
+ SZ_CHAR, /*[TUCHAR]*/
+ SZ_SHORT, /*[TSHORT]*/
+ SZ_SHORT, /*[TUSHORT]*/
+ SZ_INT, /*[TINT]*/
+ SZ_INT, /*[TUINT]*/
+ SZ_LONG, /*[TLONG]*/
+ SZ_LONG, /*[TULONG]*/
+ SZ_VLONG, /*[TVLONG]*/
+ SZ_VLONG, /*[TUVLONG]*/
+ SZ_FLOAT, /*[TFLOAT]*/
+ SZ_DOUBLE, /*[TDOUBLE]*/
+ SZ_IND, /*[TIND]*/
+ 0, /*[TFUNC]*/
+ -1, /*[TARRAY]*/
+ 0, /*[TVOID]*/
+ -1, /*[TSTRUCT]*/
+ -1, /*[TUNION]*/
+ SZ_INT, /*[TENUM]*/
+};
+long ncast[NTYPE] =
+{
+ 0, /*[TXXX]*/
+ BCHAR|BUCHAR, /*[TCHAR]*/
+ BCHAR|BUCHAR, /*[TUCHAR]*/
+ BSHORT|BUSHORT, /*[TSHORT]*/
+ BSHORT|BUSHORT, /*[TUSHORT]*/
+ BINT|BUINT|BLONG|BULONG, /*[TINT]*/
+ BINT|BUINT|BLONG|BULONG, /*[TUINT]*/
+ BINT|BUINT|BLONG|BULONG, /*[TLONG]*/
+ BINT|BUINT|BLONG|BULONG, /*[TULONG]*/
+ BVLONG|BUVLONG|BIND, /*[TVLONG]*/
+ BVLONG|BUVLONG|BIND, /*[TUVLONG]*/
+ BFLOAT, /*[TFLOAT]*/
+ BDOUBLE, /*[TDOUBLE]*/
+ BVLONG|BUVLONG|BIND, /*[TIND]*/
+ 0, /*[TFUNC]*/
+ 0, /*[TARRAY]*/
+ 0, /*[TVOID]*/
+ BSTRUCT, /*[TSTRUCT]*/
+ BUNION, /*[TUNION]*/
+ 0, /*[TENUM]*/
+};
diff --git a/src/cmd/6g/align.c b/src/cmd/6g/align.c
new file mode 100644
index 0000000..6538d3c
--- /dev/null
+++ b/src/cmd/6g/align.c
@@ -0,0 +1,210 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "gg.h"
+
+/*
+ * machine size and rounding
+ * alignment is dictated around
+ * the size of a pointer.
+ * the size of the generic types
+ * are pulled from the typedef table.
+ */
+
+static int wptr = 8; // width of a pointer
+static int wmax = 8; // max rounding
+
+static char*
+typedefs[] =
+{
+ "short", "int16", // shorts
+ "ushort", "uint16",
+
+ "int", "int32", // ints
+ "uint", "uint32",
+ "rune", "uint32",
+
+ "long", "int64", // longs
+ "ulong", "uint64",
+
+ "vlong", "int64", // vlongs
+ "uvlong", "uint64",
+
+ "float", "float32", // floats
+ "double", "float64",
+
+};
+
+ulong
+rnd(ulong o, ulong r)
+{
+ if(r > wmax)
+ r = wmax;
+ if(r != 0)
+ while(o%r != 0)
+ o++;
+ return o;
+}
+
+void
+offmod(Type *t)
+{
+ Type *f;
+ long o;
+
+ o = 0;
+ for(f=t->type; f!=T; f=f->down) {
+ if(f->etype != TFIELD)
+ fatal("widstruct: not TFIELD: %lT", f);
+ if(f->type->etype != TFUNC)
+ continue;
+ f->width = o;
+ o += wptr;
+ }
+}
+
+ulong
+widstruct(Type *t, ulong o, int flag)
+{
+ Type *f;
+ long w;
+
+ for(f=t->type; f!=T; f=f->down) {
+ if(f->etype != TFIELD)
+ fatal("widstruct: not TFIELD: %lT", f);
+ dowidth(f->type);
+ w = f->type->width;
+ o = rnd(o, w);
+ f->width = o; // really offset for TFIELD
+ o += w;
+ }
+ // final width is rounded
+ if(flag)
+ o = rnd(o, maxround);
+ t->width = o;
+ return o;
+}
+
+void
+dowidth(Type *t)
+{
+ ulong w;
+
+ w = 0;
+ if(t == T)
+ return;
+
+ switch(t->etype) {
+ default:
+ fatal("dowidth: unknown type: %E", t->etype);
+ break;
+
+ case TINT8:
+ case TUINT8:
+ case TBOOL: // bool is int8
+ w = 1;
+ break;
+ case TINT16:
+ case TUINT16:
+ w = 2;
+ break;
+ case TINT32:
+ case TUINT32:
+ case TFLOAT32:
+ case TPTR32:
+ w = 4;
+ break;
+ case TINT64:
+ case TUINT64:
+ case TFLOAT64:
+ case TPTR64:
+ w = 8;
+ break;
+ case TFLOAT80:
+ w = 10;
+ break;
+ case TINTER: // implemented as 2 pointers
+ offmod(t);
+ w = 2*wptr;
+ break;
+ case TCHAN: // implemented as pointer
+ dowidth(t->type);
+ dowidth(t->down);
+ w = wptr;
+ break;
+ case TMAP: // implemented as pointer
+ dowidth(t->type);
+ w = wptr;
+ break;
+ case TFORW: // implemented as pointer
+ w = wptr;
+ break;
+ case TANY: // implemented as pointer
+ w = wptr;
+ break;
+ case TSTRING: // implemented as pointer
+ w = wptr;
+ break;
+ case TARRAY:
+ case TDARRAY:
+ if(t->type == T)
+ break;
+ dowidth(t->type);
+ w = t->bound * t->type->width;
+ break;
+
+ case TSTRUCT:
+ w = widstruct(t, 0, 1);
+ offmod(t);
+ break;
+
+ case TFUNC:
+ // function is 3 cated structures
+ w = widstruct(*getthis(t), 0, 0);
+ w = widstruct(*getinarg(t), w, 0);
+ w = widstruct(*getoutarg(t), w, 1);
+ w = 0;
+ break;
+ }
+ t->width = w;
+}
+
+void
+besetptr(void)
+{
+ maxround = wmax;
+ widthptr = wptr;
+
+ types[TPTR32] = typ(TPTR32);
+ dowidth(types[TPTR32]);
+
+ types[TPTR64] = typ(TPTR64);
+ dowidth(types[TPTR64]);
+
+ tptr = TPTR32;
+ if(wptr == 8)
+ tptr = TPTR64;
+}
+
+void
+belexinit(int lextype)
+{
+ int i;
+ Sym *s0, *s1;
+
+ for(i=0; i<nelem(typedefs); i+=2) {
+ s1 = lookup(typedefs[i+1]);
+ if(s1->lexical != lextype)
+ yyerror("need %s to define %s",
+ typedefs[i+1], typedefs[i+0]);
+ s0 = lookup(typedefs[i+0]);
+ s0->lexical = s1->lexical;
+ s0->otype = s1->otype;
+ }
+
+ symstringo = lookup(".stringo"); // strings
+
+ listinit();
+ buildtxt();
+}
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
new file mode 100644
index 0000000..7a00688
--- /dev/null
+++ b/src/cmd/6g/cgen.c
@@ -0,0 +1,638 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "gg.h"
+
+void
+cgen(Node *n, Node *res)
+{
+ long lno;
+ Node *nl, *nr, *r;
+ Node n1, tmp;
+ int a;
+ Prog *p1, *p2, *p3;
+
+ if(debug['g']) {
+ dump("\ncgen-l", res);
+ dump("cgen-r", n);
+ }
+ if(n == N || n->type == T)
+ return;
+ if(res == N || res->type == T)
+ fatal("cgen: res nil");
+
+ lno = dynlineno;
+ if(n->op != ONAME)
+ dynlineno = n->lineno; // for diagnostics
+
+ if(isfat(n->type)) {
+ sgen(n, res, n->type->width);
+ goto ret;
+ }
+
+ if(!res->addable) {
+ igen(res, &n1, N);
+ cgen(n, &n1);
+ regfree(&n1);
+ goto ret;
+ }
+
+ if(n->addable) {
+ gmove(n, res);
+ goto ret;
+ }
+
+ nl = n->left;
+ nr = n->right;
+ if(nl != N && nl->ullman >= UINF)
+ if(nr != N && nr->ullman >= UINF) {
+ fatal("cgen: both sides functions");
+ goto ret;
+ }
+
+ switch(n->op) {
+ default:
+ dump("cgen", n);
+ fatal("cgen: unknown op %N", n);
+ break;
+
+ // these call bgen to get a bool value
+ case OOROR:
+ case OANDAND:
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case ONOT:
+ p1 = gbranch(AJMP, T);
+ p2 = pc;
+ gmove(booltrue, res);
+ p3 = gbranch(AJMP, T);
+ patch(p1, pc);
+ bgen(n, 1, p2);
+ gmove(boolfalse, res);
+ patch(p3, pc);
+ goto ret;
+
+ case OPLUS:
+ cgen(nl, res);
+ goto ret;
+
+ // unary
+ case OMINUS:
+ case OCOM:
+ a = optoas(n->op, nl->type);
+ goto uop;
+
+ // symmetric binary
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OADD:
+ case OMUL:
+ a = optoas(n->op, nl->type);
+ goto sbop;
+
+ // asymmetric binary
+ case OMOD:
+ case OSUB:
+ case ODIV:
+ case OLSH:
+ case ORSH:
+ a = optoas(n->op, nl->type);
+ goto abop;
+
+ case OCONV:
+ if(eqtype(n->type, nl->type, 0)) {
+ cgen(nl, res);
+ break;
+ }
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+
+// case OINDEXPTRSTR:
+// nl = n->left;
+// nr = n->right;
+// if(nl->addable) {
+// cgen(nr);
+// cgen(nl);
+// gopcode(P_LOADI, T_ADDR, N);
+// gopcodet(P_INDEXZ, nr->type, N);
+// break;
+// }
+// break;
+
+// case OINDEXSTR:
+// nl = n->left;
+// nr = n->right;
+// if(nl->addable) {
+// cgen(nr);
+// gopcodet(P_INDEXZ, nr->type, nl);
+// break;
+// }
+// cgen(nl);
+// r = tempname(nl->type);
+// gopcodet(P_STORE, nl->type, r);
+// cgen(nr);
+// gopcodet(P_INDEXZ, nr->type, r);
+// break;
+
+// case OSLICESTR:
+// case OSLICEPTRSTR:
+// nl = n->left; // name
+// nr = n->right;
+//
+// r = nr->right; // index2
+// if(!r->addable) {
+// cgen(r);
+// r = tempname(r->type);
+// gopcodet(P_STORE, r->type, r);
+// }
+//
+// // string into T_ADDR
+// if(!nl->addable) {
+// cgen(nl);
+// gconv(T_ADDR, nl->type->etype);
+// } else
+// gopcode(P_LOAD, T_ADDR, nl);
+//
+// if(n->op == OSLICEPTRSTR)
+// gopcode(P_LOADI, T_ADDR, N);
+//
+// // offset in int reg
+// cgen(nr->left);
+//
+// // index 2 addressed
+// gopcodet(P_SLICE, r->type, r);
+// break;
+
+ case OS2I:
+ case OI2I:
+ case OI2S:
+
+ case OINDEXPTR:
+ case OINDEX:
+ case ODOT:
+ case ODOTPTR:
+ case OIND:
+ igen(n, &n1, res);
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+
+ case OLEN:
+ if(isptrto(nl->type, TSTRING)) {
+ regalloc(&n1, types[tptr], res);
+ cgen(nl, res);
+ n1.op = OINDREG;
+ n1.type = types[TINT32];
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ fatal("cgen: OLEN: unknown type %lT", nl->type);
+ break;
+
+// case ODOTMETH:
+// case ODOTINTER:
+// cgen(n->left);
+// break;
+
+ case OADDR:
+ agen(nl, res);
+ break;
+
+ case OCALLMETH:
+ cgen_callmeth(n);
+ cgen_callret(n, res);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n, res);
+ cgen_callret(n, res);
+ break;
+
+ case OCALL:
+ cgen_call(n);
+ cgen_callret(n, res);
+ break;
+ }
+ goto ret;
+
+sbop: // symmetric binary
+ if(nl->ullman < nr->ullman) {
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+
+abop: // asymmetric binary
+ if(nr->addable) {
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ gins(a, nr, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ goto ret;
+ }
+
+ tempname(&tmp, nr->type);
+ regalloc(&n1, nr->type, res);
+ cgen(nr, &n1);
+ gmove(&n1, &tmp);
+ regfree(&n1);
+
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ gins(a, &tmp, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ goto ret;
+
+uop: // unary
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ gins(a, N, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ goto ret;
+
+ret:
+ dynlineno = lno;
+}
+
+void
+agen(Node *n, Node *res)
+{
+ Node *nl, *nr;
+ Node n1, n2, n3, tmp;
+ ulong w;
+ Type *t;
+
+ if(n == N || n->type == T)
+ return;
+
+ if(!isptr[res->type->etype])
+ fatal("agen: not tptr: %T", res->type);
+
+ if(n->addable) {
+ regalloc(&n1, types[tptr], res);
+ gins(ALEAQ, n, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ return;
+ }
+
+ switch(n->op) {
+ default:
+ fatal("agen: unknown op %N", n);
+ break;
+
+// case ONAME:
+// regalloc(&n1, types[tptr], res);
+// gins(optoas(OADDR, types[tptr]), n, &n1);
+// gmove(&n1, res);
+// regfree(&n1);
+// break;
+
+ case OINDEXPTR:
+ nl = n->left;
+ nr = n->right;
+ w = n->type->width;
+ if(nr->addable)
+ goto iprad;
+ if(nl->addable) {
+ regalloc(&n1, nr->type, N);
+ cgen(nr, &n1);
+ cgen(nl, res);
+ goto index;
+ }
+ cgen(nr, res);
+ tempname(&tmp, nr->type);
+ gmove(res, &tmp);
+
+ iprad:
+ cgen(nl, res);
+ regalloc(&n1, nr->type, N);
+ cgen(nr, &n1);
+ goto index;
+
+ case OS2I:
+ case OI2I:
+ case OI2S:
+ agen_inter(n, res);
+ break;
+
+// case OINDREG:
+
+ case OINDEX:
+ nl = n->left;
+ nr = n->right;
+ w = n->type->width;
+ if(nr->addable)
+ goto irad;
+ if(nl->addable) {
+ regalloc(&n1, nr->type, N);
+ cgen(nr, &n1);
+ agen(nl, res);
+ goto index;
+ }
+ cgen(nr, res);
+ tempname(&tmp, nr->type);
+ gmove(res, &tmp);
+
+ irad:
+ agen(nl, res);
+ regalloc(&n1, nr->type, N);
+ cgen(nr, &n1);
+ goto index;
+
+ index:
+ // &a is in res
+ // i is in &n1
+ // w is width
+ if(issigned[n1.type->etype]) {
+ nodconst(&n3, types[TINT64], w); // w/tint64
+ regalloc(&n2, types[TINT64], &n1); // i/int64
+ gmove(&n1, &n2);
+ gins(optoas(OMUL, types[TINT64]), &n3, &n2);
+ gins(optoas(OADD, types[tptr]), &n2, res);
+ regfree(&n1);
+ regfree(&n2);
+ break;
+ }
+ // unsigned multiply is a pain in the ass
+ fatal("agen: unsigned index");
+ break;
+
+// case OIND:
+// nl = n->left;
+// if(nl->addable) {
+// gopcode(P_LOAD, T_ADDR, nl);
+// break;
+// }
+// cgen(nl);
+// gconv(T_ADDR, nl->type->etype);
+// break;
+
+ case ODOT:
+ nl = n->left;
+ t = nl->type;
+ agen(nl, res);
+ if(n->xoffset != 0) {
+ nodconst(&n1, types[TINT64], n->xoffset);
+ gins(optoas(OADD, types[tptr]), &n1, res);
+ }
+ break;
+
+ case ODOTPTR:
+ nl = n->left;
+ t = nl->type;
+ if(!isptr[t->etype])
+ fatal("agen: not ptr %N", n);
+ cgen(nl, res);
+ if(n->xoffset != 0) {
+ nodconst(&n1, types[TINT64], n->xoffset);
+ gins(optoas(OADD, types[tptr]), &n1, res);
+ }
+ break;
+ }
+}
+
+vlong
+fieldoffset(Type *t, Node *n)
+{
+ if(t->etype != TSTRUCT)
+ fatal("fieldoffset: not struct %lT", t);
+ if(n->op != ONAME)
+ fatal("fieldoffset: not field name %N", n);
+ return 0;
+}
+
+void
+igen(Node *n, Node *a, Node *res)
+{
+ regalloc(a, types[tptr], res);
+ agen(n, a);
+ a->op = OINDREG;
+ a->type = n->type;
+}
+
+void
+bgen(Node *n, int true, Prog *to)
+{
+ long lno;
+ int et, a, b;
+ Node *nl, *nr, *r;
+ Node n1, n2, tmp;
+ Prog *p1, *p2;
+
+ if(n == N)
+ n = booltrue;
+
+ lno = dynlineno;
+ if(n->op != ONAME)
+ dynlineno = n->lineno; // for diagnostics
+
+ if(n->type == T) {
+ convlit(n, types[TBOOL]);
+ if(n->type == T)
+ goto ret;
+ }
+
+ et = n->type->etype;
+ if(et != TBOOL) {
+ yyerror("cgen: bad type %T for %O", n->type, n->op);
+ patch(gins(AEND, N, N), to);
+ goto ret;
+ }
+ nl = N;
+ nr = N;
+
+ switch(n->op) {
+ default:
+ regalloc(&n1, n->type, N);
+ cgen(n, &n1);
+ nodconst(&n2, n->type, 0);
+ gins(optoas(OCMP, n->type), &n1, &n2);
+ a = AJNE;
+ if(!true)
+ a = AJEQ;
+ patch(gbranch(a, n->type), to);
+ regfree(&n1);
+ goto ret;
+
+ case OLITERAL:
+ if(!true == !n->val.vval)
+ patch(gbranch(AJMP, T), to);
+ goto ret;
+
+ case ONAME:
+ nodconst(&n1, n->type, 0);
+ gins(optoas(OCMP, n->type), n, &n1);
+ a = AJNE;
+ if(!true)
+ a = AJEQ;
+ patch(gbranch(a, n->type), to);
+ goto ret;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ p1 = gbranch(AJMP, T);
+ p2 = gbranch(AJMP, T);
+ patch(p1, pc);
+ bgen(n->left, !true, p2);
+ bgen(n->right, !true, p2);
+ p1 = gbranch(AJMP, T);
+ patch(p1, to);
+ patch(p2, pc);
+ goto ret;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bgen(n->left, true, to);
+ bgen(n->right, true, to);
+ goto ret;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGT:
+ case OLE:
+ case OGE:
+ nr = n->right;
+ if(nr == N || nr->type == T)
+ goto ret;
+
+ case ONOT: // unary
+ nl = n->left;
+ if(nl == N || nl->type == T)
+ goto ret;
+ }
+
+ switch(n->op) {
+
+ case ONOT:
+ bgen(nl, !true, to);
+ goto ret;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGT:
+ case OLE:
+ case OGE:
+ a = n->op;
+ if(!true)
+ a = brcom(a);
+
+ // make simplest on right
+ if(nl->ullman < nr->ullman) {
+ a = brrev(a);
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+ a = optoas(a, nr->type);
+
+ if(nr->addable) {
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1);
+ b = optoas(OCMP, nr->type);
+
+ switch(b) {
+ case ACMPQ:
+ if(nr->op == OLITERAL)
+ if(nr->val.vval >= (1LL<<32))
+ goto dolit;
+
+ case AUCOMISS:
+ if(nr->op == OLITERAL)
+ goto dolit;
+ if(nr->op == ONAME)
+ goto dolit;
+ }
+
+ gins(b, &n1, nr);
+ patch(gbranch(a, nr->type), to);
+ regfree(&n1);
+ break;
+
+ dolit:
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ gins(b, &n1, &n2);
+ patch(gbranch(a, nr->type), to);
+ regfree(&n2);
+ regfree(&n1);
+ break;
+ }
+
+ tempname(&tmp, nr->type);
+ cgen(nr, &tmp);
+
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1);
+
+ gins(optoas(OCMP, nr->type), &n1, &tmp);
+ patch(gbranch(a, nr->type), to);
+ regfree(&n1);
+ break;
+ }
+ goto ret;
+
+ret:
+ dynlineno = lno;
+}
+
+void
+sgen(Node *n, Node *ns, ulong w)
+{
+ Node nodl, nodr;
+ long c;
+
+ if(w == 0)
+ return;
+ if(n->ullman >= UINF && ns->ullman >= UINF) {
+ fatal("sgen UINF");
+ }
+
+ nodreg(&nodl, types[tptr], D_DI);
+ nodreg(&nodr, types[tptr], D_SI);
+
+ if(n->ullman >= ns->ullman) {
+ agen(n, &nodr);
+ agen(ns, &nodl);
+ } else {
+ agen(ns, &nodl);
+ agen(n, &nodr);
+ }
+
+ gins(ACLD, N, N); // clear direction flag
+
+ c = w / 8;
+ if(c > 0) {
+ gconreg(AMOVQ, c, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
+ }
+
+ c = w % 8;
+ if(c > 0) {
+ gconreg(AMOVQ, c, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
+ }
+}
diff --git a/src/cmd/6g/gen.c b/src/cmd/6g/gen.c
new file mode 100644
index 0000000..7000574
--- /dev/null
+++ b/src/cmd/6g/gen.c
@@ -0,0 +1,820 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+#undef EXTERN
+#define EXTERN
+#include "gg.h"
+
+enum
+{
+ // random unused opcode
+ AJMPX = AADDPD,
+};
+
+static Node* curfn;
+
+void
+compile(Node *fn)
+{
+ Plist *pl;
+ Node nod1;
+ Prog *ptxt;
+
+ if(fn->nbody == N)
+ return;
+
+ curfn = fn;
+ dowidth(curfn->type);
+
+ if(nerrors != 0) {
+ walk(curfn);
+ return;
+ }
+
+ if(debug['w'])
+ dump("--- pre walk ---", curfn->nbody);
+
+ maxarg = 0;
+ stksize = 0;
+
+ walk(curfn);
+ if(nerrors != 0)
+ return;
+
+ if(debug['w'])
+ dump("--- post walk ---", curfn->nbody);
+
+ allocparams();
+
+ continpc = P;
+ breakpc = P;
+
+ pl = newplist();
+ pl->name = curfn->nname;
+ pl->locals = autodcl;
+
+ nodconst(&nod1, types[TINT32], 0);
+ ptxt = gins(ATEXT, curfn->nname, &nod1);
+
+// inarggen();
+
+ ginit();
+ gen(curfn->nbody);
+ gclean();
+
+// if(curfn->type->outtuple != 0)
+// gins(AGOK, N, N);
+
+ pc->as = ARET; // overwrite AEND
+
+ // fill in final stack size
+ ptxt->to.offset = rnd(stksize+maxarg, maxround);
+
+ if(debug['f'])
+ frame(0);
+}
+
+void
+allocparams(void)
+{
+ Dcl *d;
+ Iter list;
+ Type *t;
+ Node *n;
+ ulong w;
+
+ /*
+ * allocate (set xoffset) the stack
+ * slots for this, inargs, outargs
+ * these are allocated positavely
+ * from 0 up.
+ * note that this uses the 'width'
+ * field, which, in the OFIELD of the
+ * parameters, is the offset in the
+ * parameter list.
+ */
+ d = autodcl;
+ t = funcfirst(&list, curfn->type);
+ while(t != T) {
+ if(d == D)
+ fatal("allocparams: this nil");
+ if(d->op != ONAME) {
+ d = d->forw;
+ continue;
+ }
+
+ n = d->dnode;
+ if(n->class != PPARAM)
+ fatal("allocparams: this class");
+
+ n->xoffset = t->width;
+ d = d->forw;
+ t = funcnext(&list);
+ }
+
+ /*
+ * allocate (set xoffset) the stack
+ * slots for all automatics.
+ * allocated starting at -w down.
+ */
+ for(d=autodcl; d!=D; d=d->forw) {
+ if(d->op != ONAME)
+ continue;
+
+ n = d->dnode;
+ if(n->class != PAUTO)
+ continue;
+
+ dowidth(n->type);
+ w = n->type->width;
+ stksize += w;
+ stksize = rnd(stksize, w);
+
+ n->xoffset = -stksize;
+ }
+}
+
+/*
+ * compile statements
+ */
+void
+gen(Node *n)
+{
+ long lno;
+ Prog *scontin, *sbreak;
+ Prog *p1, *p2, *p3;
+ Sym *s;
+
+ lno = dynlineno;
+
+loop:
+ if(n == N)
+ goto ret;
+ dynlineno = n->lineno; // for diagnostics
+
+ switch(n->op) {
+ default:
+ fatal("gen: unknown op %N", n);
+ break;
+
+ case OLIST:
+ gen(n->left);
+ n = n->right;
+ goto loop;
+
+ case OPANIC:
+ genpanic();
+ break;
+
+ case OCASE:
+ case OFALL:
+ case OXCASE:
+ case OXFALL:
+ case OEMPTY:
+ break;
+
+ case OLABEL:
+ // before declaration, s->label points at
+ // a link list of PXGOTO instructions.
+ // after declaration, s->label points
+ // at a AJMP to .+1
+
+ s = n->left->sym;
+ p1 = (Prog*)s->label;
+
+ if(p1 != P) {
+ if(p1->as == AJMP) {
+ yyerror("label redeclared: %S", s);
+ break;
+ }
+ while(p1 != P) {
+ if(p1->as != AJMPX)
+ fatal("bad label pointer: %S", s);
+ p1->as = AJMP;
+ p2 = p1->to.branch;
+ patch(p1, pc);
+ p1 = p2;
+ }
+ }
+
+ s->label = pc;
+ p1 = gbranch(AJMP, T);
+ patch(p1, pc);
+ break;
+
+ case OGOTO:
+ s = n->left->sym;
+ p1 = (Prog*)s->label;
+ if(p1 != P && p1->as == AJMP) {
+ // already declared
+ p2 = gbranch(AJMP, T);
+ patch(p2, p1->to.branch);
+ break;
+ }
+
+ // link thru to.branch
+ p2 = gbranch(AJMPX, T);
+ p2->to.branch = p1;
+ s->label = p2;
+ break;
+
+ case OBREAK:
+ if(breakpc == P) {
+ yyerror("gen: break is not in a loop");
+ break;
+ }
+ patch(gbranch(AJMP, T), breakpc);
+ break;
+
+ case OCONTINUE:
+ if(continpc == P) {
+ yyerror("gen: continue is not in a loop");
+ break;
+ }
+ patch(gbranch(AJMP, T), continpc);
+ break;
+
+ case OFOR:
+ gen(n->ninit); // init
+ p1 = gbranch(AJMP, T); // goto test
+ sbreak = breakpc;
+ breakpc = gbranch(AJMP, T); // break: goto done
+ scontin = continpc;
+ continpc = pc;
+ gen(n->nincr); // contin: incr
+ patch(p1, pc); // test:
+ bgen(n->ntest, 0, breakpc); // if(!test) goto break
+ gen(n->nbody); // body
+ patch(gbranch(AJMP, T), continpc); // goto contin
+ patch(breakpc, pc); // done:
+ continpc = scontin;
+ breakpc = sbreak;
+ break;
+
+ case OIF:
+ gen(n->ninit); // init
+ p1 = gbranch(AJMP, T); // goto test
+ p2 = gbranch(AJMP, T); // p2: goto else
+ patch(p1, pc); // test:
+ bgen(n->ntest, 0, p2); // if(!test) goto p2
+ gen(n->nbody); // then
+ p3 = gbranch(AJMP, T); // goto done
+ patch(p2, pc); // else:
+ gen(n->nelse); // else
+ patch(p3, pc); // done:
+ break;
+
+ case OSWITCH:
+ gen(n->ninit); // init
+ p1 = gbranch(AJMP, T); // goto test
+ sbreak = breakpc;
+ breakpc = gbranch(AJMP, T); // break: goto done
+ patch(p1, pc); // test:
+ swgen(n); // switch(test) body
+ patch(breakpc, pc); // done:
+ breakpc = sbreak;
+ break;
+
+ case OASOP:
+ cgen_asop(n->left, n->right, n->etype);
+ break;
+
+ case OAS:
+ cgen_as(n->left, n->right, n->op);
+ break;
+
+ case OCALLMETH:
+ cgen_callmeth(n);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n, N);
+ break;
+
+ case OCALL:
+ cgen_call(n);
+ break;
+
+ case ORETURN:
+ cgen_ret(n);
+ break;
+ }
+
+ret:
+ dynlineno = lno;
+}
+
+void
+agen_inter(Node *n, Node *res)
+{
+ Node nodo, nodr, nodt;
+ Sym *s;
+ char *e;
+ long o;
+
+ // stack offset
+ memset(&nodo, 0, sizeof(nodo));
+ nodo.op = OINDREG;
+ nodo.val.vval = D_SP;
+ nodo.addable = 1;
+ nodo.type = types[tptr];
+
+ // pointer register
+ regalloc(&nodr, types[tptr], res);
+
+ switch(n->op) {
+ default:
+ fatal("agen_inter %O\n", n->op);
+
+ case OS2I:
+ // ifaces2i(*sigi, *sigs, i.map, i.s)
+ // i.s is input
+ // (i.map, i.s) is output
+
+ cgen(n->left, &nodr);
+ nodo.xoffset = 3*widthptr;
+ cgen_as(&nodo, &nodr, 0);
+
+ nodtypesig(&nodt, n->type);
+ agen(&nodt, &nodr);
+ nodo.xoffset = 0*widthptr;
+ cgen_as(&nodo, &nodr, 0);
+
+ nodtypesig(&nodt, n->left->type);
+ agen(&nodt, &nodr);
+ nodo.xoffset = 1*widthptr;
+ cgen_as(&nodo, &nodr, 0);
+
+ e = "ifaces2i";
+ if(maxarg < 4*widthptr)
+ maxarg = 4*widthptr;
+ o = 2*widthptr;
+ break;
+
+ case OI2I:
+ // ifacei2i(*sigi, i.map, i.s)
+ // (i.map, i.s) is input
+ // (i.map, i.s) is output
+
+ nodo.xoffset = 1*widthptr;
+ if(!n->left->addable) {
+ agen(n->left, &nodr);
+ gmove(&nodr, &nodo);
+ fatal("agen_inter i2i");
+ } else {
+ cgen(n->left, &nodo);
+ }
+
+ nodtypesig(&nodt, n->type);
+ agen(&nodt, &nodr);
+ nodo.xoffset = 0*widthptr;
+ cgen_as(&nodo, &nodr, 0);
+
+ e = "ifacei2i";
+ if(maxarg < 3*widthptr)
+ maxarg = 3*widthptr;
+ o = 1*widthptr;
+ break;
+
+ case OI2S:
+ // ifacei2s(*sigs, i.map, i.s)
+ // (i.map, i.s) is input
+ // i.s is output
+
+ nodo.xoffset = 1*widthptr;
+ if(!n->left->addable) {
+ agen(n->left, &nodr);
+ gmove(&nodr, &nodo);
+ fatal("agen_inter i2s");
+ } else
+ gmove(n->left, &nodo);
+
+ nodtypesig(&nodt, n->type);
+ agen(&nodt, &nodr);
+ nodo.xoffset = 0*widthptr;
+ cgen_as(&nodo, &nodr, 0);
+
+ e = "ifacei2s";
+ if(maxarg < 3*widthptr)
+ maxarg = 3*widthptr;
+ o = 2*widthptr;
+ break;
+ }
+
+ s = pkglookup(e, "sys");
+ if(s->oname == N) {
+ s->oname = newname(s);
+ s->oname->class = PEXTERN;
+ }
+ gins(ACALL, N, s->oname);
+
+ nodo.xoffset = o;
+ gins(ALEAQ, &nodo, res);
+
+ regfree(&nodr);
+}
+
+void
+swgen(Node *n)
+{
+ Node *c1, *c2;
+ Node n1, tmp;
+ Case *s0, *se, *s;
+ Prog *p1, *dflt;
+ long lno;
+ int any;
+ Iter save1, save2;
+
+// botch - put most of this code in
+// walk. gen binary search for
+// sequence of constant cases
+
+ lno = dynlineno;
+
+ p1 = gbranch(AJMP, T);
+ s0 = C;
+ se = C;
+
+ // walk thru the body placing breaks
+ // and labels into the case statements
+
+ any = 0;
+ dflt = P;
+ c1 = listfirst(&save1, &n->nbody);
+ while(c1 != N) {
+ dynlineno = c1->lineno; // for diagnostics
+ if(c1->op != OCASE) {
+ if(s0 == C)
+ yyerror("unreachable statements in a switch");
+ gen(c1);
+
+ any = 1;
+ if(c1->op == OFALL)
+ any = 0;
+ c1 = listnext(&save1);
+ continue;
+ }
+
+ // put in the break between cases
+ if(any) {
+ patch(gbranch(AJMP, T), breakpc);
+ any = 0;
+ }
+
+ // over case expressions
+ c2 = listfirst(&save2, &c1->left);
+ if(c2 == N)
+ dflt = pc;
+
+ while(c2 != N) {
+
+ s = mal(sizeof(*s));
+ if(s0 == C)
+ s0 = s;
+ else
+ se->slink = s;
+ se = s;
+
+ s->scase = c2; // case expression
+ s->sprog = pc; // where to go
+
+ c2 = listnext(&save2);
+ }
+
+ c1 = listnext(&save1);
+ }
+
+ if(any)
+ patch(gbranch(AJMP, T), breakpc);
+
+ patch(p1, pc);
+
+ tempname(&tmp, n->ntest->type);
+ cgen(n->ntest, &tmp);
+
+ for(s=s0; s!=C; s=s->slink) {
+ memset(&n1, 0, sizeof(n1));
+ n1.op = OEQ;
+ n1.left = &tmp;
+ n1.right = s->scase;
+ walktype(&n1, 0);
+ bgen(&n1, 1, s->sprog);
+ }
+ if(dflt != P) {
+ patch(gbranch(AJMP, T), dflt);
+ goto ret;
+ }
+ patch(gbranch(AJMP, T), breakpc);
+
+ret:
+ dynlineno = lno;
+}
+
+void
+inarggen(void)
+{
+ fatal("inarggen");
+}
+
+void
+genpanic(void)
+{
+ Node n1, n2;
+ Prog *p;
+
+ nodconst(&n1, types[TINT64], 0xf0);
+ nodreg(&n2, types[TINT64], D_AX);
+ gins(AMOVL, &n1, &n2);
+ p = pc;
+ gins(AMOVQ, &n2, N);
+ p->to.type = D_INDIR+D_AX;
+}
+
+void
+cgen_callinter(Node *n, Node *res)
+{
+ Node *i, *f;
+ Node tmpi, nodo, nodr, nodsp;
+
+ i = n->left;
+ if(i->op != ODOTINTER)
+ fatal("cgen_callinter: not ODOTINTER %O", i->op);
+
+ f = i->right; // field
+ if(f->op != ONAME)
+ fatal("cgen_callinter: not ONAME %O", f->op);
+
+ i = i->left; // interface
+
+ if(!i->addable) {
+ tempname(&tmpi, i->type);
+ cgen(i, &tmpi);
+ i = &tmpi;
+ }
+
+ gen(n->right); // args
+
+ regalloc(&nodr, types[tptr], res);
+ regalloc(&nodo, types[tptr], &nodr);
+ nodo.op = OINDREG;
+
+ agen(i, &nodr); // REG = &inter
+
+ nodindreg(&nodsp, types[tptr], D_SP);
+ nodo.xoffset += widthptr;
+ cgen(&nodo, &nodsp); // 0(SP) = 8(REG) -- i.s
+
+ nodo.xoffset -= widthptr;
+ cgen(&nodo, &nodr); // REG = 0(REG) -- i.m
+
+//print("field = %N\n", f);
+//print("offset = %ld\n", n->left->xoffset);
+
+ nodo.xoffset = n->left->xoffset + 4*widthptr;
+ cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.m->fun[f]
+
+ gins(ACALL, N, &nodr);
+ regfree(&nodr);
+ regfree(&nodr);
+
+ setmaxarg(n->left->type);
+}
+
+void
+cgen_callmeth(Node *n)
+{
+ Node *l;
+
+ // generate a rewrite for method call
+ // (p.f)(...) goes to (f)(p,...)
+
+ l = n->left;
+
+ n->op = OCALL;
+ n->left = n->left->right;
+ n->left->type = l->type;
+
+ if(n->left->op == ONAME)
+ n->left->class = PEXTERN;
+ cgen_call(n);
+}
+
+void
+cgen_call(Node *n)
+{
+ Type *t;
+ Node nod, afun;
+
+ if(n == N)
+ return;
+
+ if(n->left->ullman >= UINF) {
+ // if name involves a fn call
+ // precompute the address of the fn
+ tempname(&afun, types[tptr]);
+ if(isptr[n->left->type->etype])
+ cgen(n->left, &afun);
+ else
+ agen(n->left, &afun);
+ }
+
+ gen(n->right); // assign the args
+ t = n->left->type;
+ if(isptr[t->etype])
+ t = t->type;
+
+ setmaxarg(t);
+
+ // call tempname pointer
+ if(n->left->ullman >= UINF) {
+ regalloc(&nod, types[tptr], N);
+ cgen_as(&nod, &afun, 0);
+ gins(ACALL, N, &nod);
+ regfree(&nod);
+ return;
+ }
+
+ // call pointer
+ if(isptr[n->left->type->etype]) {
+ regalloc(&nod, types[tptr], N);
+ cgen_as(&nod, n->left, 0);
+ gins(ACALL, N, &nod);
+ regfree(&nod);
+ return;
+ }
+
+ // call direct
+ gins(ACALL, N, n->left);
+}
+
+void
+cgen_callret(Node *n, Node *res)
+{
+ Node nod;
+ Type *fp, *t;
+ Iter flist;
+
+ t = n->left->type;
+ if(t->etype == TPTR32 || t->etype == TPTR64)
+ t = t->type;
+
+ fp = structfirst(&flist, getoutarg(t));
+ if(fp == T)
+ fatal("cgen_callret: nil");
+
+ memset(&nod, 0, sizeof(nod));
+ nod.op = OINDREG;
+ nod.val.vval = D_SP;
+ nod.addable = 1;
+
+ nod.xoffset = fp->width;
+ nod.type = fp->type;
+ cgen_as(res, &nod, 0);
+}
+
+void
+cgen_ret(Node *n)
+{
+ gen(n->left); // copy out args
+ gins(ARET, N, N);
+}
+
+void
+cgen_asop(Node *nl, Node *nr, int op)
+{
+ Node n1, n2;
+ int a;
+
+ // botch compare ullman numbers
+ // and use temp for functions
+
+ a = optoas(op, nl->type);
+ regalloc(&n1, nl->type, N);
+ if(nl->addable) {
+ cgen(nr, &n1);
+ gins(a, nl, &n1);
+ gmove(&n1, nl);
+ regfree(&n1);
+ return;
+ }
+
+ igen(nl, &n2, N);
+ cgen(nr, &n1);
+ gins(a, &n2, &n1);
+ gmove(&n1, &n2);
+ regfree(&n1);
+ regfree(&n2);
+}
+
+void
+cgen_as(Node *nl, Node *nr, int op)
+{
+ Node nc, n1;
+ Type *tl;
+ ulong w, c;
+
+ if(nl == N)
+ return;
+
+ tl = nl->type;
+ if(tl == T)
+ return;
+
+ if(nr == N) {
+ if(isfat(tl)) {
+ /* clear a fat object */
+ if(debug['g'])
+ dump("\nclearfat", nl);
+
+ w = nl->type->width;
+ if(w > 0)
+ gconreg(AMOVQ, 0, D_AX);
+
+ if(w > 0) {
+ nodreg(&n1, types[tptr], D_DI);
+ agen(nl, &n1);
+ gins(ACLD, N, N); // clear direction flag
+ }
+
+ c = w / 8;
+ if(c > 0) {
+ gconreg(AMOVQ, c, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
+ }
+
+ c = w % 8;
+ if(c > 0) {
+ gconreg(AMOVQ, c, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(ASTOSB, N, N); // STOB AL,*(DI)+
+ }
+ return;
+ }
+
+ /* invent a "zero" for the rhs */
+ nr = &nc;
+ memset(nr, 0, sizeof(*nr));
+ switch(tl->etype) {
+ default:
+ fatal("cgen_as: tl %T", tl);
+ break;
+
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ nr->val.ctype = CTINT;
+ nr->val.vval = 0;
+ break;
+
+ case TFLOAT32:
+ case TFLOAT64:
+ case TFLOAT80:
+ nr->val.ctype = CTFLT;
+ nr->val.dval = 0.0;
+ break;
+
+ case TBOOL:
+ nr->val.ctype = CTBOOL;
+ nr->val.vval = 0;
+ break;
+
+ case TPTR32:
+ case TPTR64:
+ if(isptrto(nl->type, TSTRING)) {
+ nr->val.ctype = CTSTR;
+ nr->val.sval = &emptystring;
+ break;
+ }
+ nr->val.ctype = CTNIL;
+ nr->val.vval = 0;
+ break;
+
+// case TINTER:
+// nodreg(&n1, types[tptr], D_DI);
+// agen(nl, &n1);
+// n1.op = OINDREG;
+//
+// nodreg(&nc, types[tptr], D_AX);
+// gconreg(AMOVQ, 0, D_AX);
+//
+// gins(AMOVQ, &nc, &n1);
+// n1.xoffset += widthptr;
+// gins(AMOVQ, &nc, &n1);
+// return;
+
+ }
+ nr->op = OLITERAL;
+ nr->type = tl;
+ nr->addable = 1;
+ ullmancalc(nr);
+ }
+ cgen(nr, nl);
+}
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
new file mode 100644
index 0000000..5cd31b4
--- /dev/null
+++ b/src/cmd/6g/gg.h
@@ -0,0 +1,203 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+#include <u.h>
+#include <libc.h>
+
+#include "../gc/go.h"
+#include "../6l/6.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Prog Prog;
+typedef struct Addr Addr;
+
+struct Addr
+{
+ vlong offset;
+ double dval;
+ Prog* branch;
+ char sval[NSNAME];
+
+ Sym* sym;
+ uchar type;
+ uchar index;
+ uchar etype;
+ uchar scale; /* doubles as width in DATA op */
+};
+#define A ((Addr*)0)
+
+struct Prog
+{
+ short as; // opcode
+ ulong loc; // pc offset in this func
+ ulong lineno; // source line that generated this
+ Addr from; // src address
+ Addr to; // dst address
+ Prog* link; // next instruction in this func
+};
+#define P ((Prog*)0)
+
+typedef struct Plist Plist;
+struct Plist
+{
+ Node* name;
+ Dcl* locals;
+ Prog* firstpc;
+ int recur;
+ Plist* link;
+};
+
+typedef struct Sig Sig;
+struct Sig
+{
+ char* name;
+ Sym* sym;
+ ulong hash;
+ long offset;
+ Sig* link;
+};
+
+typedef struct Case Case;
+struct Case
+{
+ Prog* sprog;
+ Node* scase;
+ Case* slink;
+};
+#define C ((Case*)0)
+
+typedef struct Pool Pool;
+struct Pool
+{
+ String* sval;
+ Pool* link;
+};
+
+EXTERN Prog* continpc;
+EXTERN Prog* breakpc;
+EXTERN Prog* pc;
+EXTERN Prog* firstpc;
+EXTERN Plist* plist;
+EXTERN Plist* plast;
+EXTERN Pool* poolist;
+EXTERN Pool* poolast;
+EXTERN Biobuf* bout;
+EXTERN long dynloc;
+EXTERN uchar reg[D_NONE];
+EXTERN ushort txt[NTYPE*NTYPE];
+EXTERN long maxround;
+EXTERN long widthptr;
+EXTERN long maxarg;
+EXTERN long stksize;
+EXTERN Sym* symstringo; // string objects
+EXTERN long stringo; // size of string objects
+EXTERN long pcloc; // instruction counter
+EXTERN String emptystring;
+extern char* anames[];
+
+/*
+ * gen.c
+ */
+void compile(Node*);
+void proglist(void);
+void gen(Node*);
+void swgen(Node*);
+Node* lookdot(Node*, Node*, int);
+void inarggen(void);
+void agen_inter(Node*, Node*);
+void cgen_as(Node*, Node*, int);
+void cgen_asop(Node*, Node*, int);
+void cgen_ret(Node*);
+void cgen_call(Node*);
+void cgen_callmeth(Node*);
+void cgen_callinter(Node*, Node*);
+void cgen_callret(Node*, Node*);
+void genpanic(void);
+int needconvert(Type*, Type*);
+void genconv(Type*, Type*);
+void allocparams(void);
+
+/*
+ * cgen
+ */
+void cgen(Node*, Node*);
+void agen(Node*, Node*);
+void igen(Node*, Node*, Node*);
+vlong fieldoffset(Type*, Node*);
+void bgen(Node*, int, Prog*);
+void sgen(Node*, Node*, ulong);
+void gmove(Node*, Node*);
+Prog* gins(int, Node*, Node*);
+int samaddr(Node*, Node*);
+void naddr(Node*, Addr*);
+
+/*
+ * gsubr.c
+ */
+void clearp(Prog*);
+void proglist(void);
+Prog* gbranch(int, Type*);
+void patch(Prog*, Prog*);
+Prog* prog(int);
+void gaddoffset(Node*);
+void gconv(int, int);
+int conv2pt(Type*);
+void belexinit(int);
+vlong convvtox(vlong, int);
+int brcom(int);
+int brrev(int);
+void fnparam(Type*, int, int);
+Sig* lsort(Sig*, int(*)(Sig*, Sig*));
+Prog* gop(int, Node*, Node*, Node*);
+void setconst(Addr*, vlong);
+void setaddr(Addr*, Node*);
+int optoas(int, Type*);
+void ginit(void);
+void gclean(void);
+void regalloc(Node*, Type*, Node*);
+void regfree(Node*);
+void regsalloc(Node*, Type*); // replace w tmpvar
+void regret(Node*, Type*);
+Node* nodarg(Type*, int);
+void nodreg(Node*, Type*, int);
+void nodindreg(Node*, Type*, int);
+void nodconst(Node*, Type*, vlong);
+Sym* signame(Type*);
+void nodtypesig(Node*, Type*);
+void gconreg(int, vlong, int);
+void buildtxt(void);
+void stringpool(Node*);
+void tempname(Node*, Type*);
+Plist* newplist(void);
+int isfat(Type*);
+void setmaxarg(Type*);
+
+/*
+ * list.c
+ */
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Pconv(Fmt*);
+int Rconv(Fmt*);
+int Yconv(Fmt*);
+void listinit(void);
+
+/*
+ * obj
+ */
+void zname(Biobuf*, Sym*, int);
+void zaddr(Biobuf*, Addr*, int);
+void ieeedtod(Ieee*, double);
+void dumpstrings(void);
+void dumpsignatures(void);
+
+/*
+ * align
+ */
+void dowidth(Type*);
+ulong rnd(ulong, ulong);
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
new file mode 100644
index 0000000..9ced8fe
--- /dev/null
+++ b/src/cmd/6g/gsubr.c
@@ -0,0 +1,1649 @@
+// Derived from Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gg.h"
+
+void
+clearp(Prog *p)
+{
+ p->as = AEND;
+ p->from.type = D_NONE;
+ p->from.index = D_NONE;
+ p->to.type = D_NONE;
+ p->to.index = D_NONE;
+ p->loc = pcloc;
+ pcloc++;
+}
+
+Prog*
+prog(int as)
+{
+ Prog *p;
+
+ p = pc;
+ pc = mal(sizeof(*pc));
+
+ clearp(pc);
+
+ p->as = as;
+ p->lineno = dynlineno;
+ p->link = pc;
+ return p;
+}
+
+Prog*
+gbranch(int as, Type *t)
+{
+ Prog *p;
+
+ p = prog(as);
+ p->to.type = D_BRANCH;
+ p->to.branch = P;
+ return p;
+}
+
+void
+patch(Prog *p, Prog *to)
+{
+ if(p->to.type != D_BRANCH)
+ fatal("patch: not a branch");
+ p->to.branch = to;
+ p->to.offset = to->loc;
+}
+
+Plist*
+newplist(void)
+{
+ Plist *pl;
+
+ pl = mal(sizeof(*pl));
+ if(plist == nil)
+ plist = pl;
+ else
+ plast->link = pl;
+ plast = pl;
+
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ pl->firstpc = pc;
+
+ return pl;
+}
+
+void
+ginit(void)
+{
+ int i;
+
+ for(i=0; i<nelem(reg); i++)
+ reg[i] = 1;
+ for(i=D_AX; i<=D_R15; i++)
+ reg[i] = 0;
+ for(i=D_X0; i<=D_X7; i++)
+ reg[i] = 0;
+ reg[D_SP]++;
+}
+
+void
+gclean(void)
+{
+ int i;
+
+ reg[D_SP]--;
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i])
+ yyerror("reg %R left allocated\n", i);
+ for(i=D_X0; i<=D_X7; i++)
+ if(reg[i])
+ yyerror("reg %R left allocated\n", i);
+}
+
+void
+regalloc(Node *n, Type *t, Node *o)
+{
+ int i;
+
+ if(t == T)
+ fatal("regalloc: t nil");
+
+ switch(t->etype) {
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TPTR32:
+ case TPTR64:
+ case TBOOL:
+ if(o != N && o->op == OREGISTER) {
+ i = o->val.vval;
+ if(i >= D_AX && i <= D_R15)
+ goto out;
+ }
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i] == 0)
+ goto out;
+
+ yyerror("out of fixed registers");
+ goto err;
+
+ case TFLOAT32:
+ case TFLOAT64:
+ case TFLOAT80:
+ if(o != N && o->op == OREGISTER) {
+ i = o->val.vval;
+ if(i >= D_X0 && i <= D_X7)
+ goto out;
+ }
+ for(i=D_X0; i<=D_X7; i++)
+ if(reg[i] == 0)
+ goto out;
+ yyerror("out of floating registers");
+ goto err;
+ }
+ yyerror("regalloc: unknown type %T", t);
+
+err:
+ nodreg(n, t, 0);
+ return;
+
+out:
+ reg[i]++;
+ nodreg(n, t, i);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ if(n->op != OREGISTER && n->op != OINDREG)
+ fatal("regfree: not a register");
+ i = n->val.vval;
+ if(i < 0 || i >= sizeof(reg))
+ fatal("regfree: reg out of range");
+ if(reg[i] <= 0)
+ fatal("regfree: reg not allocated");
+ reg[i]--;
+}
+
+void
+regret(Node *n, Type *t)
+{
+ if(t == T)
+ fatal("regret: t nil");
+ fatal("regret");
+}
+
+void
+nodreg(Node *n, Type *t, int r)
+{
+ if(t == T)
+ fatal("nodreg: t nil");
+
+ memset(n, 0, sizeof(*n));
+ n->op = OREGISTER;
+ n->addable = 1;
+ ullmancalc(n);
+ n->val.vval = r;
+ n->type = t;
+}
+
+void
+nodindreg(Node *n, Type *t, int r)
+{
+ nodreg(n, t, r);
+ n->op = OINDREG;
+}
+
+Node*
+nodarg(Type *t, int fp)
+{
+ Node *n;
+
+ if(t->etype != TFIELD)
+ fatal("nodarg: not field %T", t);
+
+ n = nod(ONAME, N, N);
+ n->type = t->type;
+ n->sym = t->sym;
+ n->xoffset = t->width;
+ n->addable = 1;
+
+ switch(fp) {
+ case 0: // output arg
+ n->op = OINDREG;
+ n->val.vval = D_SP;
+ break;
+
+ case 1: // input arg
+ n->class = PPARAM;
+ break;
+
+ case 2: // offset output arg
+fatal("shpuldnt be used");
+ n->op = OINDREG;
+ n->val.vval = D_SP;
+ n->xoffset += types[tptr]->width;
+ break;
+ }
+ return n;
+}
+
+void
+nodconst(Node *n, Type *t, vlong v)
+{
+ memset(n, 0, sizeof(*n));
+ n->op = OLITERAL;
+ n->addable = 1;
+ ullmancalc(n);
+ n->val.vval = v;
+ n->val.ctype = CTINT;
+ n->type = t;
+
+ switch(t->etype) {
+ case TFLOAT32:
+ case TFLOAT64:
+ case TFLOAT80:
+ fatal("nodconst: bad type %T", t);
+
+ case TPTR32:
+ case TPTR64:
+ case TUINT8:
+ case TUINT16:
+ case TUINT32:
+ case TUINT64:
+ n->val.ctype = CTUINT;
+ break;
+ }
+}
+
+Sym*
+signame(Type *t)
+{
+ Sym *s;
+ char *e;
+
+loop:
+ if(t == T)
+ fatal("signame: nil type");
+
+ switch(t->etype) {
+ default:
+ fatal("signame: unknown type %T", t);
+
+ case TPTR32:
+ case TPTR64:
+ t = t->type;
+ goto loop;
+ case TSTRUCT:
+ e = "sigs";
+ break;
+ case TINTER:
+ e = "sigi";
+ break;
+ }
+
+ s = t->sym;
+ if(s == S)
+ fatal("nodtypesig: no sym for type");
+
+ snprint(namebuf, sizeof(namebuf), "%s_%s", e, s->name);
+ s = pkglookup(namebuf, s->package);
+ return s;
+}
+
+void
+nodtypesig(Node *n, Type *t)
+{
+ memset(n, 0, sizeof(*n));
+ n->op = ONAME;
+ n->type = types[TUINT8];
+ n->etype = TUINT8;
+ n->xoffset = 0;
+ n->sym = signame(t);
+ n->class = PEXTERN;
+ n->addable = 1;
+ n->ullman = 0;
+}
+
+void
+gconreg(int as, vlong c, int reg)
+{
+ Node n1, n2;
+
+ nodconst(&n1, types[TINT64], c);
+ nodreg(&n2, types[TINT64], reg);
+ gins(as, &n1, &n2);
+}
+
+#define CASE(a,b) (((a)<<16)|((b)<<0))
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, t64, a;
+ Node nod, nod1, nod2, nod3, nodc;
+ Prog *p1, *p2;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+
+ t64 = 0;
+ if(tt == TINT64 || tt == TUINT64 || tt == TPTR64)
+ t64 = 1;
+
+ if(debug['M'])
+ print("gop: %O %O[%E],%O[%E]\n", OAS,
+ f->op, ft, t->op, tt);
+ if(isfloat[ft] && f->op == OCONST) {
+ /* TO DO: pick up special constants, possibly preloaded */
+ if(f->val.dval == 0.0){
+ regalloc(&nod, t->type, t);
+ gins(AXORPD, &nod, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ }
+/*
+ * load
+ */
+ if(f->op == ONAME || f->op == OINDREG ||
+ f->op == OIND || f->op == OINDEX)
+ switch(ft) {
+ case TINT8:
+ a = AMOVBLSX;
+ if(t64)
+ a = AMOVBQSX;
+ goto ld;
+ case TBOOL:
+ case TUINT8:
+ a = AMOVBLZX;
+ if(t64)
+ a = AMOVBQZX;
+ goto ld;
+ case TINT16:
+ a = AMOVWLSX;
+ if(t64)
+ a = AMOVWQSX;
+ goto ld;
+ case TUINT16:
+ a = AMOVWLZX;
+ if(t64)
+ a = AMOVWQZX;
+ goto ld;
+ case TINT32:
+ if(isfloat[tt]) {
+ regalloc(&nod, t->type, t);
+ if(tt == TFLOAT64)
+ a = ACVTSL2SD;
+ else
+ a = ACVTSL2SS;
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ a = AMOVL;
+ if(t64)
+ a = AMOVLQSX;
+ goto ld;
+ case TUINT32:
+ case TPTR32:
+ a = AMOVL;
+ if(t64)
+ a = AMOVLQZX; /* could probably use plain MOVL */
+ goto ld;
+ case TINT64:
+ if(isfloat[tt]) {
+ regalloc(&nod, t->type, t);
+ if(tt == TFLOAT64)
+ a = ACVTSQ2SD;
+ else
+ a = ACVTSQ2SS;
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ case TUINT64:
+ case TPTR64:
+ a = AMOVQ;
+
+ ld:
+ regalloc(&nod, f->type, t);
+ nod.type = t64? types[TINT64]: types[TINT32];
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT32:
+ a = AMOVSS;
+ goto fld;
+ case TFLOAT64:
+ a = AMOVSD;
+ fld:
+ regalloc(&nod, f->type, t);
+ if(tt != TFLOAT64 && tt != TFLOAT32){ /* TO DO: why is this here */
+ dump("odd tree", f);
+ nod.type = t64? types[TINT64]: types[TINT32];
+ }
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+/*
+ * store
+ */
+ if(t->op == ONAME || t->op == OINDREG ||
+ t->op == OIND || t->op == OINDEX)
+ switch(tt) {
+ case TBOOL:
+ case TINT8:
+ case TUINT8:
+ a = AMOVB;
+ goto st;
+ case TINT16:
+ case TUINT16:
+ a = AMOVW;
+ goto st;
+ case TINT32:
+ case TUINT32:
+ case TPTR32:
+ a = AMOVL;
+ goto st;
+ case TINT64:
+ case TUINT64:
+ case TPTR64:
+ a = AMOVQ;
+ goto st;
+
+ st:
+ if(f->op == OCONST) {
+ gins(a, f, t);
+ return;
+ }
+ fst:
+ regalloc(&nod, t->type, f);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT32:
+ a = AMOVSS;
+ goto fst;
+ case TFLOAT64:
+ a = AMOVSD;
+ goto fst;
+ }
+
+/*
+ * convert
+ */
+ switch(CASE(ft, tt)) {
+ default:
+/*
+ * integer to integer
+ ********
+ a = AGOK; break;
+
+ case CASE(TBOOL, TBOOL):
+ case CASE(TINT8, TBOOL):
+ case CASE(TUINT8, TBOOL):
+ case CASE(TINT16, TBOOL):
+ case CASE(TUINT16, TBOOL):
+ case CASE(TINT32, TBOOL):
+ case CASE(TUINT32, TBOOL):
+ case CASE(TPTR64, TBOOL):
+
+ case CASE(TBOOL, TINT8):
+ case CASE(TINT8, TINT8):
+ case CASE(TUINT8, TINT8):
+ case CASE(TINT16, TINT8):
+ case CASE(TUINT16, TINT8):
+ case CASE(TINT32, TINT8):
+ case CASE(TUINT32, TINT8):
+ case CASE(TPTR64, TINT8):
+
+ case CASE(TBOOL, TUINT8):
+ case CASE(TINT8, TUINT8):
+ case CASE(TUINT8, TUINT8):
+ case CASE(TINT16, TUINT8):
+ case CASE(TUINT16, TUINT8):
+ case CASE(TINT32, TUINT8):
+ case CASE(TUINT32, TUINT8):
+ case CASE(TPTR64, TUINT8):
+
+ case CASE(TINT16, TINT16):
+ case CASE(TUINT16, TINT16):
+ case CASE(TINT32, TINT16):
+ case CASE(TUINT32, TINT16):
+ case CASE(TPTR64, TINT16):
+
+ case CASE(TINT16, TUINT16):
+ case CASE(TUINT16, TUINT16):
+ case CASE(TINT32, TUINT16):
+ case CASE(TUINT32, TUINT16):
+ case CASE(TPTR64, TUINT16):
+
+ case CASE(TINT64, TUINT):
+ case CASE(TINT64, TUINT32):
+ case CASE(TUINT64, TUINT32):
+ *****/
+ a = AMOVL;
+ break;
+
+ case CASE(TINT64, TINT8):
+ case CASE(TINT64, TINT16):
+ case CASE(TINT64, TINT32):
+ case CASE(TUINT64, TINT8):
+ case CASE(TUINT64, TINT16):
+ case CASE(TUINT64, TINT32):
+ case CASE(TINT32, TINT64):
+ case CASE(TINT32, TPTR64):
+ a = AMOVLQSX;
+ if(f->op == OCONST) {
+ f->val.vval &= (uvlong)0xffffffffU;
+ if(f->val.vval & 0x80000000)
+ f->val.vval |= (vlong)0xffffffff << 32;
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE(TUINT32, TINT64):
+ case CASE(TUINT32, TUINT64):
+ case CASE(TUINT32, TPTR64):
+ a = AMOVL; /* same effect as AMOVLQZX */
+ if(f->op == OCONST) {
+ f->val.vval &= (uvlong)0xffffffffU;
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE(TPTR64, TINT64):
+ case CASE(TINT64, TINT64):
+ case CASE(TUINT64, TINT64):
+ case CASE(TINT64, TUINT64):
+ case CASE(TUINT64, TUINT64):
+ case CASE(TPTR64, TUINT64):
+ case CASE(TINT64, TPTR64):
+ case CASE(TUINT64, TPTR64):
+ case CASE(TPTR64, TPTR64):
+ a = AMOVQ;
+ break;
+
+ case CASE(TINT16, TINT32):
+ case CASE(TINT16, TUINT32):
+ a = AMOVWLSX;
+ if(f->op == OCONST) {
+ f->val.vval &= 0xffff;
+ if(f->val.vval & 0x8000)
+ f->val.vval |= 0xffff0000;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE(TINT16, TINT64):
+ case CASE(TINT16, TUINT64):
+ case CASE(TINT16, TPTR64):
+ a = AMOVWQSX;
+ if(f->op == OCONST) {
+ f->val.vval &= 0xffff;
+ if(f->val.vval & 0x8000){
+ f->val.vval |= 0xffff0000;
+ f->val.vval |= (vlong)~0 << 32;
+ }
+ a = AMOVL;
+ }
+ break;
+
+ case CASE(TUINT16, TINT32):
+ case CASE(TUINT16, TUINT32):
+ a = AMOVWLZX;
+ if(f->op == OCONST) {
+ f->val.vval &= 0xffff;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE(TUINT16, TINT64):
+ case CASE(TUINT16, TUINT64):
+ case CASE(TUINT16, TPTR64):
+ a = AMOVWQZX;
+ if(f->op == OCONST) {
+ f->val.vval &= 0xffff;
+ a = AMOVL; /* MOVL also zero-extends to 64 bits */
+ }
+ break;
+
+ case CASE(TINT8, TINT16):
+ case CASE(TINT8, TUINT16):
+ case CASE(TINT8, TINT32):
+ case CASE(TINT8, TUINT32):
+ a = AMOVBLSX;
+ if(f->op == OCONST) {
+ f->val.vval &= 0xff;
+ if(f->val.vval & 0x80)
+ f->val.vval |= 0xffffff00;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE(TINT8, TINT64):
+ case CASE(TINT8, TUINT64):
+ case CASE(TINT8, TPTR64):
+ a = AMOVBQSX;
+ if(f->op == OCONST) {
+ f->val.vval &= 0xff;
+ if(f->val.vval & 0x80){
+ f->val.vval |= 0xffffff00;
+ f->val.vval |= (vlong)~0 << 32;
+ }
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE(TBOOL, TINT16):
+ case CASE(TBOOL, TUINT16):
+ case CASE(TBOOL, TINT32):
+ case CASE(TBOOL, TUINT32):
+ case CASE(TUINT8, TINT16):
+ case CASE(TUINT8, TUINT16):
+ case CASE(TUINT8, TINT32):
+ case CASE(TUINT8, TUINT32):
+ a = AMOVBLZX;
+ if(f->op == OCONST) {
+ f->val.vval &= 0xff;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE(TBOOL, TINT64):
+ case CASE(TBOOL, TUINT64):
+ case CASE(TBOOL, TPTR64):
+ case CASE(TUINT8, TINT64):
+ case CASE(TUINT8, TUINT64):
+ case CASE(TUINT8, TPTR64):
+ a = AMOVBQZX;
+ if(f->op == OCONST) {
+ f->val.vval &= 0xff;
+ a = AMOVL; /* zero-extends to 64-bits */
+ }
+ break;
+
+/*
+ * float to fix
+ */
+ case CASE(TFLOAT32, TINT8):
+ case CASE(TFLOAT32, TINT16):
+ case CASE(TFLOAT32, TINT32):
+ regalloc(&nod, t->type, N);
+ gins(ACVTTSS2SL, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case CASE(TFLOAT32, TBOOL):
+ case CASE(TFLOAT32, TUINT8):
+ case CASE(TFLOAT32, TUINT16):
+ case CASE(TFLOAT32, TUINT32):
+ case CASE(TFLOAT32, TINT64):
+ case CASE(TFLOAT32, TUINT64):
+ case CASE(TFLOAT32, TPTR64):
+ regalloc(&nod, t->type, N);
+ gins(ACVTTSS2SQ, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case CASE(TFLOAT64, TINT8):
+ case CASE(TFLOAT64, TINT16):
+ case CASE(TFLOAT64, TINT32):
+ regalloc(&nod, t->type, N);
+ gins(ACVTTSD2SL, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case CASE(TFLOAT64, TBOOL):
+ case CASE(TFLOAT64, TUINT8):
+ case CASE(TFLOAT64, TUINT16):
+ case CASE(TFLOAT64, TUINT32):
+ case CASE(TFLOAT64, TINT64):
+ case CASE(TFLOAT64, TUINT64):
+ case CASE(TFLOAT64, TPTR64):
+ regalloc(&nod, t->type, N);
+ gins(ACVTTSD2SQ, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+/*
+ * ulong to float
+ */
+ case CASE(TUINT64, TFLOAT64):
+ case CASE(TUINT64, TFLOAT32):
+ a = ACVTSQ2SS;
+ if(tt == TFLOAT64)
+ a = ACVTSQ2SD;
+ regalloc(&nod, f->type, f);
+ gmove(f, &nod);
+ regalloc(&nod1, t->type, t);
+nodconst(&nodc, types[TUINT64], 0);
+ gins(ACMPQ, &nod, &nodc);
+ p1 = pc;
+ gins(AJLT, N, N);
+ gins(a, &nod, &nod1);
+ p2 = pc;
+ gins(AJMP, N, N);
+ patch(p1, pc);
+ regalloc(&nod2, f->type, N);
+ regalloc(&nod3, f->type, N);
+ gmove(&nod, &nod2);
+nodconst(&nodc, types[TUINT64], 1);
+ gins(ASHRQ, &nodc, &nod2);
+ gmove(&nod, &nod3);
+ gins(AANDL, &nodc, &nod3);
+ gins(AORQ, &nod3, &nod2);
+ gins(a, &nod2, &nod1);
+ gins(tt == TFLOAT64? AADDSD: AADDSS, &nod1, &nod1);
+ regfree(&nod2);
+ regfree(&nod3);
+ patch(p2, pc);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+ case CASE(TUINT32, TFLOAT64):
+ case CASE(TUINT32, TFLOAT32):
+ a = ACVTSQ2SS;
+ if(tt == TFLOAT64)
+ a = ACVTSQ2SD;
+ regalloc(&nod, f->type, f);
+ gins(AMOVLQZX, f, &nod);
+ regalloc(&nod1, t->type, t);
+ gins(a, &nod, &nod1);
+ gmove(&nod1, t);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+/*
+ * fix to float
+ */
+ case CASE(TINT64, TFLOAT32):
+ case CASE(TPTR64, TFLOAT32):
+ regalloc(&nod, t->type, t);
+ gins(ACVTSQ2SS, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case CASE(TINT64, TFLOAT64):
+ case CASE(TPTR64, TFLOAT64):
+ regalloc(&nod, t->type, t);
+ gins(ACVTSQ2SD, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case CASE(TBOOL, TFLOAT32):
+ case CASE(TINT8, TFLOAT32):
+ case CASE(TUINT8, TFLOAT32):
+ case CASE(TINT16, TFLOAT32):
+ case CASE(TUINT16, TFLOAT32):
+ case CASE(TINT32, TFLOAT32):
+ regalloc(&nod, t->type, t);
+ gins(ACVTSL2SS, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case CASE(TBOOL, TFLOAT64):
+ case CASE(TINT8, TFLOAT64):
+ case CASE(TUINT8, TFLOAT64):
+ case CASE(TINT16, TFLOAT64):
+ case CASE(TUINT16, TFLOAT64):
+ case CASE(TINT32, TFLOAT64):
+ regalloc(&nod, t->type, t);
+ gins(ACVTSL2SD, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+/*
+ * float to float
+ */
+ case CASE(TFLOAT32, TFLOAT32):
+ a = AMOVSS;
+ break;
+ case CASE(TFLOAT64, TFLOAT32):
+ a = ACVTSD2SS;
+ break;
+ case CASE(TFLOAT32, TFLOAT64):
+ a = ACVTSS2SD;
+ break;
+ case CASE(TFLOAT64, TFLOAT64):
+ a = AMOVSD;
+ break;
+ }
+ if(a == AMOVQ ||
+ a == AMOVSD ||
+ a == AMOVSS ||
+ a == AMOVL && f->type->width == t->type->width) /* TO DO: check AMOVL */
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+buildtxt(void)
+{
+ Type t1, t2;
+ int i, j, a;
+
+ memset(&t1, 0, sizeof(t1));
+ memset(&t2, 0, sizeof(t2));
+
+ for(i=0; i<NTYPE; i++)
+ for(j=0; j<NTYPE; j++) {
+ a = AGOK;
+ txt[i*NTYPE+j] = a;
+ t1.etype = i;
+ t2.etype = j;
+
+ if(isint[i] || isptr[i] || i==TBOOL) {
+ if(isint[j] || isptr[j] || j==TBOOL) {
+ dowidth(&t1);
+ dowidth(&t2);
+ if(t1.width >= t2.width) {
+ a = AMOVL;
+ if(t1.width >= 8)
+ a = AMOVQ;
+ txt[i*NTYPE+j] = a;
+ continue;
+ }
+ switch(i) {
+ case TINT8:
+ a = AMOVBLSX;
+ if(t1.width >= 8)
+ a = AMOVBQSX;
+ break;
+ case TINT16:
+ a = AMOVWLSX;
+ if(t1.width >= 8)
+ a = AMOVWQSX;
+ break;
+ case TINT32:
+ a = AMOVLQSX;
+ break;
+ case TBOOL:
+ case TUINT8:
+ a = AMOVBLZX;
+ if(t1.width >= 8)
+ a = AMOVBQZX;
+ break;
+ case TUINT16:
+ a = AMOVWLZX;
+ if(t1.width >= 8)
+ a = AMOVLQZX;
+ break;
+ case TPTR32:
+ case TUINT32:
+ a = AMOVWQZX;
+ break;
+ }
+ txt[i*NTYPE+j] = a;
+ continue;
+ }
+ if(isfloat[j]) {
+ }
+ }
+ if(isint[j] || isptr[j] || j==TBOOL) {
+ if(isfloat[i]) {
+ }
+ }
+ }
+}
+
+void
+regsalloc(Node *f, Type *t)
+{
+ fatal("regsalloc");
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+
+ switch(f->op) {
+ case OREGISTER:
+ if(f->val.vval != t->val.vval)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+Prog*
+gins(int as, Node *f, Node *t)
+{
+// Node nod;
+// long v;
+ Prog *p;
+
+// if(f != N && f->op == OINDEX) {
+// regalloc(&nod, ®node, 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, ®node, Z);
+// v = constnode.vconst;
+// cgen(t->right, &nod);
+// constnode.vconst = v;
+// idx.reg = nod.reg;
+// regfree(&nod);
+// }
+
+ p = prog(as);
+ if(f != N)
+ naddr(f, &p->from);
+ if(t != N)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+ return p;
+}
+
+void
+naddr(Node *n, Addr *a)
+{
+
+ a->type = D_NONE;
+ if(n == N)
+ return;
+
+ switch(n->op) {
+ default:
+ fatal("naddr: bad %O %D", n->op, a);
+ break;
+
+ case OREGISTER:
+ a->type = n->val.vval;
+ a->sym = S;
+ break;
+
+// case OINDEX:
+// case OIND:
+// naddr(n->left, a);
+// if(a->type >= D_AX && a->type <= D_DI)
+// a->type += D_INDIR;
+// else
+// if(a->type == D_CONST)
+// a->type = D_NONE+D_INDIR;
+// else
+// if(a->type == D_ADDR) {
+// a->type = a->index;
+// a->index = D_NONE;
+// } else
+// goto bad;
+// if(n->op == OINDEX) {
+// a->index = idx.reg;
+// a->scale = n->scale;
+// }
+// break;
+
+ case OINDREG:
+ a->type = n->val.vval+D_INDIR;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->offset = n->xoffset;
+ a->sym = n->sym;
+ if(a->sym == S)
+ a->sym = lookup(".noname");
+
+ switch(n->class) {
+ default:
+ fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
+ case PEXTERN:
+ a->type = D_EXTERN;
+ break;
+ case PAUTO:
+ a->type = D_AUTO;
+ break;
+ case PPARAM:
+ a->type = D_PARAM;
+ break;
+ case PSTATIC:
+ a->type = D_STATIC;
+ break;
+ }
+ break;
+
+ case OLITERAL:
+ if(isfloat[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->val.dval;
+ break;
+ }
+ if(isptrto(n->type, TSTRING)) {
+ a->etype = n->etype;
+ a->sym = symstringo;
+ a->type = D_ADDR;
+ a->index = D_STATIC;
+ a->offset = symstringo->offset;
+ stringpool(n);
+ break;
+ }
+ if(isint[n->type->etype] ||
+ isptr[n->type->etype] ||
+ n->type->etype == TBOOL) {
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = n->val.vval;
+ break;
+ }
+ fatal("naddr: const %lT", n->type);
+ break;
+
+// case OADDR:
+// naddr(n->left, a);
+// if(a->type >= D_INDIR) {
+// a->type -= D_INDIR;
+// break;
+// }
+// if(a->type == D_EXTERN || a->type == D_STATIC ||
+// a->type == D_AUTO || a->type == D_PARAM)
+// if(a->index == D_NONE) {
+// a->index = a->type;
+// a->type = D_ADDR;
+// break;
+// }
+// goto bad;
+
+// case OADD:
+// if(n->right->op == OLITERAL) {
+// v = n->right->vconst;
+// naddr(n->left, a);
+// } else
+// if(n->left->op == OLITERAL) {
+// v = n->left->vconst;
+// naddr(n->right, a);
+// } else
+// goto bad;
+// a->offset += v;
+// break;
+
+ }
+}
+
+int
+optoas(int op, Type *t)
+{
+ int a;
+
+ if(t == T)
+ fatal("optoas: t is nil");
+
+ a = AGOK;
+ switch(CASE(op, t->etype)) {
+ default:
+ fatal("optoas: no entry %O-%T", op, t);
+ break;
+
+ case CASE(OADDR, TPTR32):
+ a = ALEAL;
+ break;
+
+ case CASE(OADDR, TPTR64):
+ a = ALEAQ;
+ break;
+
+ case CASE(OEQ, TBOOL):
+ case CASE(OEQ, TINT8):
+ case CASE(OEQ, TUINT8):
+ case CASE(OEQ, TINT16):
+ case CASE(OEQ, TUINT16):
+ case CASE(OEQ, TINT32):
+ case CASE(OEQ, TUINT32):
+ case CASE(OEQ, TINT64):
+ case CASE(OEQ, TUINT64):
+ case CASE(OEQ, TFLOAT32):
+ case CASE(OEQ, TFLOAT64):
+ case CASE(OEQ, TPTR32):
+ case CASE(OEQ, TPTR64):
+ a = AJEQ;
+ break;
+
+ case CASE(ONE, TBOOL):
+ case CASE(ONE, TINT8):
+ case CASE(ONE, TUINT8):
+ case CASE(ONE, TINT16):
+ case CASE(ONE, TUINT16):
+ case CASE(ONE, TINT32):
+ case CASE(ONE, TUINT32):
+ case CASE(ONE, TINT64):
+ case CASE(ONE, TUINT64):
+ case CASE(ONE, TFLOAT32):
+ case CASE(ONE, TFLOAT64):
+ case CASE(ONE, TPTR32):
+ case CASE(ONE, TPTR64):
+ a = AJNE;
+ break;
+
+ case CASE(OLT, TINT8):
+ case CASE(OLT, TINT16):
+ case CASE(OLT, TINT32):
+ case CASE(OLT, TINT64):
+ case CASE(OLT, TFLOAT32):
+ case CASE(OLT, TFLOAT64):
+ a = AJLT;
+ break;
+
+ case CASE(OLT, TUINT8):
+ case CASE(OLT, TUINT16):
+ case CASE(OLT, TUINT32):
+ case CASE(OLT, TUINT64):
+ a = AJCS;
+ break;
+
+ case CASE(OLE, TINT8):
+ case CASE(OLE, TINT16):
+ case CASE(OLE, TINT32):
+ case CASE(OLE, TINT64):
+ case CASE(OLE, TFLOAT32):
+ case CASE(OLE, TFLOAT64):
+ a = AJLE;
+ break;
+
+ case CASE(OLE, TUINT8):
+ case CASE(OLE, TUINT16):
+ case CASE(OLE, TUINT32):
+ case CASE(OLE, TUINT64):
+ a = AJLS;
+ break;
+
+ case CASE(OGT, TINT8):
+ case CASE(OGT, TINT16):
+ case CASE(OGT, TINT32):
+ case CASE(OGT, TINT64):
+ case CASE(OGT, TFLOAT32):
+ case CASE(OGT, TFLOAT64):
+ a = AJGT;
+ break;
+
+ case CASE(OGT, TUINT8):
+ case CASE(OGT, TUINT16):
+ case CASE(OGT, TUINT32):
+ case CASE(OGT, TUINT64):
+ a = AJHI;
+ break;
+
+ case CASE(OGE, TINT8):
+ case CASE(OGE, TINT16):
+ case CASE(OGE, TINT32):
+ case CASE(OGE, TINT64):
+ case CASE(OGE, TFLOAT32):
+ case CASE(OGE, TFLOAT64):
+ a = AJGE;
+ break;
+
+ case CASE(OGE, TUINT8):
+ case CASE(OGE, TUINT16):
+ case CASE(OGE, TUINT32):
+ case CASE(OGE, TUINT64):
+ a = AJCC;
+ break;
+
+ case CASE(OCMP, TBOOL):
+ case CASE(OCMP, TINT8):
+ case CASE(OCMP, TUINT8):
+ a = ACMPB;
+ break;
+
+ case CASE(OCMP, TINT16):
+ case CASE(OCMP, TUINT16):
+ a = ACMPW;
+ break;
+
+ case CASE(OCMP, TINT32):
+ case CASE(OCMP, TUINT32):
+ case CASE(OCMP, TPTR32):
+ a = ACMPL;
+ break;
+
+ case CASE(OCMP, TINT64):
+ case CASE(OCMP, TUINT64):
+ case CASE(OCMP, TPTR64):
+ a = ACMPQ;
+ break;
+
+ case CASE(OCMP, TFLOAT32):
+ a = AUCOMISS;
+ break;
+
+ case CASE(OCMP, TFLOAT64):
+ a = AUCOMISD;
+ break;
+
+ case CASE(OADD, TINT8):
+ case CASE(OADD, TUINT8):
+ a = AADDB;
+ break;
+
+ case CASE(OADD, TINT16):
+ case CASE(OADD, TUINT16):
+ a = AADDW;
+ break;
+
+ case CASE(OADD, TINT32):
+ case CASE(OADD, TUINT32):
+ case CASE(OADD, TPTR32):
+ a = AADDL;
+ break;
+
+ case CASE(OADD, TINT64):
+ case CASE(OADD, TUINT64):
+ case CASE(OADD, TPTR64):
+ a = AADDQ;
+ break;
+
+ case CASE(OADD, TFLOAT32):
+ a = AADDSS;
+ break;
+
+ case CASE(OADD, TFLOAT64):
+ a = AADDSD;
+ break;
+
+ case CASE(OSUB, TINT8):
+ case CASE(OSUB, TUINT8):
+ a = ASUBB;
+ break;
+
+ case CASE(OSUB, TINT16):
+ case CASE(OSUB, TUINT16):
+ a = ASUBW;
+ break;
+
+ case CASE(OSUB, TINT32):
+ case CASE(OSUB, TUINT32):
+ case CASE(OSUB, TPTR32):
+ a = ASUBL;
+ break;
+
+ case CASE(OSUB, TINT64):
+ case CASE(OSUB, TUINT64):
+ case CASE(OSUB, TPTR64):
+ a = ASUBQ;
+ break;
+
+ case CASE(OSUB, TFLOAT32):
+ a = ASUBSS;
+ break;
+
+ case CASE(OSUB, TFLOAT64):
+ a = ASUBSD;
+ break;
+
+ case CASE(OMINUS, TINT8):
+ case CASE(OMINUS, TUINT8):
+ a = ANEGB;
+ break;
+
+ case CASE(OMINUS, TINT16):
+ case CASE(OMINUS, TUINT16):
+ a = ANEGW;
+ break;
+
+ case CASE(OMINUS, TINT32):
+ case CASE(OMINUS, TUINT32):
+ case CASE(OMINUS, TPTR32):
+ a = ANEGL;
+ break;
+
+ case CASE(OMINUS, TINT64):
+ case CASE(OMINUS, TUINT64):
+ case CASE(OMINUS, TPTR64):
+ a = ANEGQ;
+ break;
+
+ case CASE(OMUL, TINT8):
+ a = AIMULB;
+ break;
+
+ case CASE(OMUL, TUINT8):
+ a = AMULB;
+ break;
+
+ case CASE(OMUL, TINT16):
+ a = AIMULW;
+ break;
+
+ case CASE(OMUL, TUINT16):
+ a = AMULW;
+ break;
+
+ case CASE(OMUL, TINT32):
+ a = AIMULL;
+ break;
+
+ case CASE(OMUL, TUINT32):
+ case CASE(OMUL, TPTR32):
+ a = AMULL;
+ break;
+
+ case CASE(OMUL, TINT64):
+ a = AIMULQ;
+ break;
+
+ case CASE(OMUL, TUINT64):
+ case CASE(OMUL, TPTR64):
+ a = AMULQ;
+ break;
+
+ case CASE(OMUL, TFLOAT32):
+ a = AMULSS;
+ break;
+
+ case CASE(OMUL, TFLOAT64):
+ a = AMULSD;
+ break;
+
+ case CASE(ODIV, TINT8):
+ a = AIDIVB;
+ break;
+
+ case CASE(ODIV, TUINT8):
+ a = ADIVB;
+ break;
+
+ case CASE(ODIV, TINT16):
+ a = AIDIVW;
+ break;
+
+ case CASE(ODIV, TUINT16):
+ a = ADIVW;
+ break;
+
+ case CASE(ODIV, TINT32):
+ a = AIDIVL;
+ break;
+
+ case CASE(ODIV, TUINT32):
+ case CASE(ODIV, TPTR32):
+ a = ADIVL;
+ break;
+
+ case CASE(ODIV, TINT64):
+ a = AIDIVQ;
+ break;
+
+ case CASE(ODIV, TUINT64):
+ case CASE(ODIV, TPTR64):
+ a = ADIVQ;
+ break;
+
+ case CASE(ODIV, TFLOAT32):
+ a = ADIVSS;
+ break;
+
+ case CASE(ODIV, TFLOAT64):
+ a = ADIVSD;
+ break;
+
+ }
+ return a;
+}
+
+int
+isfat(Type *t)
+{
+ if(t != T)
+ switch(t->etype) {
+ case TSTRUCT:
+ case TARRAY:
+ case TDARRAY:
+ case TINTER: // maybe remove later
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * return unsigned(op)
+ * eg GT -> HS
+ */
+int
+brunsigned(int a)
+{
+ switch(a) {
+ case AJLT: return AJGE;
+ case AJGT: return AJLE;
+ case AJLE: return AJGT;
+ case AJGE: return AJLT;
+ }
+ return a;
+}
+
+/*
+ * return !(op)
+ * eg == <=> !=
+ */
+int
+brcom(int a)
+{
+ switch(a) {
+ case OEQ: return ONE;
+ case ONE: return OEQ;
+ case OLT: return OGE;
+ case OGT: return OLE;
+ case OLE: return OGT;
+ case OGE: return OLT;
+ }
+ fatal("brcom: no com for %A\n", a);
+ return a;
+}
+
+/*
+ * return reverse(op)
+ * eg a op b <=> b r(op) a
+ */
+int
+brrev(int a)
+{
+ switch(a) {
+ case OEQ: return OEQ;
+ case ONE: return ONE;
+ case OLT: return OGT;
+ case OGT: return OLT;
+ case OLE: return OGE;
+ case OGE: return OLE;
+ }
+ fatal("brcom: no rev for %A\n", a);
+ return a;
+}
+
+/*
+ * make a new off the books
+ */
+void
+tempname(Node *n, Type *t)
+{
+ Sym *s;
+ ulong w;
+
+ if(t == T) {
+ yyerror("tempname called with nil type");
+ t = types[TINT32];
+ }
+
+ s = lookup("!tmpname!");
+
+ memset(n, 0, sizeof(*n));
+ n->op = ONAME;
+ n->sym = s;
+ n->type = t;
+ n->sym = s;
+ n->etype = t->etype;
+ n->class = PAUTO;
+ n->addable = 1;
+ n->ullman = 0;
+
+ dowidth(t);
+ w = t->width;
+ stksize += w;
+ stksize = rnd(stksize, w);
+ n->xoffset = -stksize;
+}
+
+void
+stringpool(Node *n)
+{
+ Pool *p;
+ int w;
+
+ if(n->op != OLITERAL || n->val.ctype != CTSTR)
+ fatal("stringpool: not string");
+
+ p = mal(sizeof(*p));
+
+ p->sval = n->val.sval;
+ p->link = nil;
+
+ if(poolist == nil)
+ poolist = p;
+ else
+ poolast->link = p;
+ poolast = p;
+
+ w = types[TINT32]->width;
+ symstringo->offset += w; // len
+ symstringo->offset += p->sval->len; // str[len]
+ symstringo->offset = rnd(symstringo->offset, w);
+}
+
+Sig*
+lsort(Sig *l, int(*f)(Sig*, Sig*))
+{
+ Sig *l1, *l2, *le;
+
+ if(l == 0 || l->link == 0)
+ return l;
+
+ l1 = l;
+ l2 = l;
+ for(;;) {
+ l2 = l2->link;
+ if(l2 == 0)
+ break;
+ l2 = l2->link;
+ if(l2 == 0)
+ break;
+ l1 = l1->link;
+ }
+
+ l2 = l1->link;
+ l1->link = 0;
+ l1 = lsort(l, f);
+ l2 = lsort(l2, f);
+
+ /* set up lead element */
+ if((*f)(l1, l2) < 0) {
+ l = l1;
+ l1 = l1->link;
+ } else {
+ l = l2;
+ l2 = l2->link;
+ }
+ le = l;
+
+ for(;;) {
+ if(l1 == 0) {
+ while(l2) {
+ le->link = l2;
+ le = l2;
+ l2 = l2->link;
+ }
+ le->link = 0;
+ break;
+ }
+ if(l2 == 0) {
+ while(l1) {
+ le->link = l1;
+ le = l1;
+ l1 = l1->link;
+ }
+ break;
+ }
+ if((*f)(l1, l2) < 0) {
+ le->link = l1;
+ le = l1;
+ l1 = l1->link;
+ } else {
+ le->link = l2;
+ le = l2;
+ l2 = l2->link;
+ }
+ }
+ le->link = 0;
+ return l;
+}
+
+void
+setmaxarg(Type *t)
+{
+ Type *to;
+ long w;
+
+ to = *getoutarg(t);
+ w = to->width;
+ if(w > maxarg)
+ maxarg = w;
+}
diff --git a/src/cmd/6g/list.c b/src/cmd/6g/list.c
new file mode 100644
index 0000000..361eb3c
--- /dev/null
+++ b/src/cmd/6g/list.c
@@ -0,0 +1,336 @@
+// Derived from Inferno utils/6c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gg.h"
+
+static int sconsize;
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv); // as
+ fmtinstall('P', Pconv); // Prog*
+ fmtinstall('D', Dconv); // Addr*
+ fmtinstall('R', Rconv); // reg
+ fmtinstall('Y', Yconv); // sconst
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ sconsize = 8;
+ if(p->as == ADATA) {
+ sconsize = p->from.scale;
+ snprint(str, sizeof(str), "%.4ld %-7A %D/%d,%D",
+ p->loc, p->as, &p->from, sconsize, &p->to);
+ return fmtstrcpy(fp, str);
+ }
+ snprint(str, sizeof(str), "%.4ld %-7A %D,%D",
+ p->loc, p->as, &p->from, &p->to);
+ return fmtstrcpy(fp, str);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[40], s[20];
+ Addr *a;
+ int i;
+
+ a = va_arg(fp->args, Addr*);
+ i = a->type;
+ if(i >= D_INDIR) {
+ if(a->offset)
+ sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
+ else
+ sprint(str, "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ if(a->offset)
+ sprint(str, "$%lld,%R", a->offset, i);
+ else
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ snprint(str, sizeof(str), "%ld", a->branch->loc);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%S+%lld(SB)", a->sym, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%S<>+%lld(SB)", a->sym, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%S+%lld(SP)", a->sym, a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%S+%lld(FP)", a->sym, a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%lld", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$(%.17e)", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%Y\"", a->sval);
+ break;
+
+ case D_ADDR:
+ a->type = a->index;
+ a->index = D_NONE;
+ sprint(str, "$%D", a);
+ a->index = a->type;
+ a->type = D_ADDR;
+ goto conv;
+ }
+brk:
+ if(a->index != D_NONE) {
+ sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
+ strcat(str, s);
+ }
+conv:
+ return fmtstrcpy(fp, str);
+}
+
+static char* regstr[] =
+{
+ "AL", /* [D_AL] */
+ "CL",
+ "DL",
+ "BL",
+ "SPB",
+ "BPB",
+ "SIB",
+ "DIB",
+ "R8B",
+ "R9B",
+ "R10B",
+ "R11B",
+ "R12B",
+ "R13B",
+ "R14B",
+ "R15B",
+
+ "AX", /* [D_AX] */
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+ "R8",
+ "R9",
+ "R10",
+ "R11",
+ "R12",
+ "R13",
+ "R14",
+ "R15",
+
+ "AH",
+ "CH",
+ "DH",
+ "BH",
+
+ "F0", /* [D_F0] */
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "M0",
+ "M1",
+ "M2",
+ "M3",
+ "M4",
+ "M5",
+ "M6",
+ "M7",
+
+ "X0",
+ "X1",
+ "X2",
+ "X3",
+ "X4",
+ "X5",
+ "X6",
+ "X7",
+ "X8",
+ "X9",
+ "X10",
+ "X11",
+ "X12",
+ "X13",
+ "X14",
+ "X15",
+
+ "CS", /* [D_CS] */
+ "SS",
+ "DS",
+ "ES",
+ "FS",
+ "GS",
+
+ "GDTR", /* [D_GDTR] */
+ "IDTR", /* [D_IDTR] */
+ "LDTR", /* [D_LDTR] */
+ "MSW", /* [D_MSW] */
+ "TASK", /* [D_TASK] */
+
+ "CR0", /* [D_CR] */
+ "CR1",
+ "CR2",
+ "CR3",
+ "CR4",
+ "CR5",
+ "CR6",
+ "CR7",
+ "CR8",
+ "CR9",
+ "CR10",
+ "CR11",
+ "CR12",
+ "CR13",
+ "CR14",
+ "CR15",
+
+ "DR0", /* [D_DR] */
+ "DR1",
+ "DR2",
+ "DR3",
+ "DR4",
+ "DR5",
+ "DR6",
+ "DR7",
+
+ "TR0", /* [D_TR] */
+ "TR1",
+ "TR2",
+ "TR3",
+ "TR4",
+ "TR5",
+ "TR6",
+ "TR7",
+
+ "NONE", /* [D_NONE] */
+};
+
+int
+Rconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r < 0 || r >= nelem(regstr) || regstr[r] == nil) {
+ snprint(str, sizeof(str), "BAD_R(%d)", r);
+ return fmtstrcpy(fp, str);
+ }
+ return fmtstrcpy(fp, regstr[r]);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[i]);
+}
+
+
+int
+Yconv(Fmt *fp)
+{
+ int i, c;
+ char str[30], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sconsize; i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
diff --git a/src/cmd/6g/obj.c b/src/cmd/6g/obj.c
new file mode 100644
index 0000000..47ae0ab
--- /dev/null
+++ b/src/cmd/6g/obj.c
@@ -0,0 +1,604 @@
+// Derived from Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gg.h"
+
+void
+dumpobj(void)
+{
+ Plist *pl;
+ Prog *p;
+ Dcl *d;
+ Sym *s;
+ Node *n;
+ struct { Sym *sym; short type; } h[NSYM];
+ int sf, st, t, sym;
+ Node n1;
+
+ // add nil plist w AEND
+ newplist();
+
+ bout = Bopen(outfile, OWRITE);
+ if(bout == nil)
+ fatal("cant open %s", outfile);
+
+ Bprint(bout, "x86-64\n");
+ Bprint(bout, " exports automatically generated from\n");
+ Bprint(bout, " %s in package \"%s\"\n", curio.infile, package);
+ dumpexport();
+ Bprint(bout, "\n!\n");
+
+ // add globals
+ nodconst(&n1, types[TINT32], 0);
+ for(d=externdcl; d!=D; d=d->forw) {
+ if(d->op != ONAME)
+ continue;
+
+ s = d->dsym;
+ if(s == S)
+ fatal("external nil");
+ n = d->dnode;
+ if(n == N || n->type == T)
+ fatal("external %S nil\n", s);
+
+ if(n->type->etype == TFUNC)
+ continue;
+
+ dowidth(n->type);
+ n1.val.vval = n->type->width;
+
+ p = pc;
+ gins(AGLOBL, s->oname, &n1);
+ p->lineno = s->oname->lineno;
+ }
+
+ dumpstrings();
+ dumpsignatures();
+
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+
+ // put out functions
+ for(pl=plist; pl!=nil; pl=pl->link) {
+
+ if(debug['S']) {
+ s = S;
+ if(pl->name != N)
+ s = pl->name->sym;
+ print("\n--- prog list \"%S\" ---\n", s);
+ for(p=pl->firstpc; p!=P; p=p->link)
+ print("%P\n", p);
+ }
+
+ for(p=pl->firstpc; p!=P; p=p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.type;
+ if(t == D_ADDR)
+ t = p->from.index;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(bout, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.type;
+ if(t == D_ADDR)
+ t = p->to.index;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(bout, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(bout, p->as);
+ Bputc(bout, p->as>>8);
+ Bputc(bout, p->lineno);
+ Bputc(bout, p->lineno>>8);
+ Bputc(bout, p->lineno>>16);
+ Bputc(bout, p->lineno>>24);
+ zaddr(bout, &p->from, sf);
+ zaddr(bout, &p->to, st);
+ }
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n;
+
+ Bputc(b, ANAME); /* as */
+ Bputc(b, ANAME>>8); /* as */
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+
+ for(n=s->opackage; *n; n++)
+ Bputc(b, *n);
+ Bputc(b, '_');
+ for(n=s->name; *n; n++)
+ Bputc(b, *n);
+ Bputc(b, 0);
+}
+
+void
+zaddr(Biobuf *b, Addr *a, int s)
+{
+ long l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(s != 0)
+ t |= T_SYM;
+
+ switch(a->type) {
+ default:
+ t |= T_TYPE;
+ case D_NONE:
+ if(a->offset != 0) {
+ t |= T_OFFSET;
+ l = a->offset;
+ if((vlong)l != a->offset)
+ t |= T_64;
+ }
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ }
+ Bputc(b, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ Bputc(b, a->index);
+ Bputc(b, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ if(t & T_64) {
+ l = a->offset>>32;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(b, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ l = e.h;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(b, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ Bputc(b, a->type);
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
+
+void
+datastring(char *s, int len)
+{
+ int w;
+ Prog *p;
+ Addr ac, ao;
+
+ // string
+ memset(&ao, 0, sizeof(ao));
+ ao.type = D_STATIC;
+ ao.index = D_NONE;
+ ao.etype = TINT32;
+ ao.sym = symstringo;
+ ao.offset = 0; // fill in
+
+ // constant
+ memset(&ac, 0, sizeof(ac));
+ ac.type = D_CONST;
+ ac.index = D_NONE;
+ ac.offset = 0; // fill in
+
+ for(w=0; w<len; w+=8) {
+ p = pc;
+ gins(ADATA, N, N);
+
+ // .stringo<>+oo, [NSNAME], $"xxx"
+ p->from = ao;
+ p->from.offset = stringo;
+
+ p->from.scale = NSNAME;
+ if(w+8 > len)
+ p->from.scale = len-w;
+
+ p->to = ac;
+ p->to.type = D_SCONST;
+ p->to.offset = len;
+ memmove(p->to.sval, s+w, p->from.scale);
+ stringo += p->from.scale;
+ }
+}
+
+void
+dumpstrings(void)
+{
+ Pool *l;
+ Prog *p;
+ Addr ac, ao;
+ long wi;
+
+ if(poolist == nil)
+ return;
+
+ memset(&ac, 0, sizeof(ac));
+ memset(&ao, 0, sizeof(ao));
+
+ // constant
+ ac.type = D_CONST;
+ ac.index = D_NONE;
+ ac.offset = 0; // fill in
+
+ // string len+ptr
+ ao.type = D_STATIC;
+ ao.index = D_NONE;
+ ao.etype = TINT32;
+ ao.sym = symstringo;
+ ao.offset = 0; // fill in
+
+ wi = types[TINT32]->width;
+
+ // lay out (count+string)
+ for(l=poolist; l!=nil; l=l->link) {
+
+ p = pc;
+ gins(ADATA, N, N);
+
+ // .stringo<>+xx, wi, $len
+ stringo = rnd(stringo, wi);
+ p->from = ao;
+ p->from.offset = stringo;
+ p->from.scale = wi;
+ p->to = ac;
+ p->to.offset = l->sval->len;
+ stringo += wi;
+
+ datastring(l->sval->s, l->sval->len);
+ }
+}
+
+static int
+sigcmp(Sig *a, Sig *b)
+{
+ return strcmp(a->name, b->name);
+}
+
+void
+dumpsignatures(void)
+{
+ Dcl *d;
+ Type *t, *f;
+ Sym *s1, *s;
+ int et, o, wi, ot;
+ Sig *a, *b;
+ Addr at, ao, ac, ad;
+ Prog *p;
+ char *sp;
+
+ /*
+ * put all the names into a linked
+ * list so that it may be generated in sorted order.
+ * the runtime will be linear rather than quadradic
+ */
+
+ memset(&at, 0, sizeof(at));
+ memset(&ao, 0, sizeof(ao));
+ memset(&ac, 0, sizeof(ac));
+ memset(&ad, 0, sizeof(ad));
+
+ // sig structure
+ at.type = D_EXTERN;
+ at.index = D_NONE;
+ at.sym = S; // fill in
+ at.offset = 0; // fill in
+
+ // $string
+ ao.type = D_ADDR;
+ ao.index = D_STATIC;
+ ao.etype = TINT32;
+ ao.sym = symstringo;
+ ao.offset = 0; // fill in
+
+ // constant
+ ac.type = D_CONST;
+ ac.index = D_NONE;
+ ac.offset = 0; // fill in
+
+ // $method
+ ad.type = D_ADDR;
+ ad.index = D_EXTERN;
+ ad.sym = S; // fill in
+ ad.offset = 0;
+
+ wi = types[TINT32]->width;
+
+ for(d=externdcl; d!=D; d=d->forw) {
+ if(d->op != OTYPE)
+ continue;
+
+ t = d->dtype;
+ et = t->etype;
+ if(et != TSTRUCT && et != TINTER)
+ continue;
+
+ s = d->dsym;
+ if(s == S)
+ continue;
+
+ if(s->name[0] == '_')
+ continue;
+
+ if(strcmp(s->opackage, package) != 0)
+ continue;
+
+ at.sym = signame(t);
+
+ a = nil;
+ o = 0;
+ for(f=t->type; f!=T; f=f->down) {
+ if(f->type->etype != TFUNC)
+ continue;
+
+ if(f->etype != TFIELD)
+ fatal("dumpsignatures: not field");
+
+ s1 = f->sym;
+ if(s1 == nil)
+ continue;
+ if(s1->name[0] == '_')
+ continue;
+
+ b = mal(sizeof(*b));
+ b->link = a;
+ a = b;
+
+ a->name = s1->name;
+ sp = strchr(s1->name, '_');
+ if(sp != nil)
+ a->name = sp+1;
+
+ a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0);
+ a->sym = f->sym;
+ a->offset = o;
+ o++;
+ }
+
+ a = lsort(a, sigcmp);
+ ot = 0;
+
+ if(et == TINTER) {
+ o = 0;
+ for(b=a; b!=nil; b=b->link)
+ o++;
+
+ // sigi[0].name = ""
+ ot = rnd(ot, maxround);
+ p = pc;
+ gins(ADATA, N, N);
+ p->from = at;
+ p->from.offset = ot;
+ p->from.scale = widthptr;
+ p->to = ao;
+ p->to.offset = stringo;
+ ot += widthptr;
+
+ // sigi[0].hash = 0
+ ot = rnd(ot, wi);
+ p = pc;
+ gins(ADATA, N, N);
+ p->from = at;
+ p->from.offset = ot;
+ p->from.scale = wi;
+ p->to = ac;
+ p->to.offset = 0;
+ ot += wi;
+
+ // sigi[0].offset = count
+ ot = rnd(ot, wi);
+ p = pc;
+ gins(ADATA, N, N);
+ p->from = at;
+ p->from.offset = ot;
+ p->from.scale = wi;
+ p->to = ac;
+ p->to.offset = o;
+ ot += wi;
+
+ datastring("", 1);
+
+ }
+
+ for(b=a; b!=nil; b=b->link) {
+
+ // sigx[++].name = "fieldname"
+ ot = rnd(ot, maxround);
+ p = pc;
+ gins(ADATA, N, N);
+ p->from = at;
+ p->from.offset = ot;
+ p->from.scale = widthptr;
+ p->to = ao;
+ p->to.offset = stringo;
+ ot += widthptr;
+
+ // sigx[++].hash = hashcode
+ ot = rnd(ot, wi);
+ p = pc;
+ gins(ADATA, N, N);
+ p->from = at;
+ p->from.offset = ot;
+ p->from.scale = wi;
+ p->to = ac;
+ p->to.offset = b->hash;
+ ot += wi;
+
+ if(et == TINTER) {
+ // sigi[++].offset = offset of method
+ ot = rnd(ot, wi);
+ p = pc;
+ gins(ADATA, N, N);
+ p->from = at;
+ p->from.offset = ot;
+ p->from.scale = wi;
+ p->to = ac;
+ p->to.offset = b->offset;
+ ot += wi;
+ } else {
+ // sigs[++].fun = &method
+ ot = rnd(ot, widthptr);
+ p = pc;
+ gins(ADATA, N, N);
+ p->from = at;
+ p->from.offset = ot;
+ p->from.scale = widthptr;
+ p->to = ad;
+ p->to.sym = b->sym;
+ ot += widthptr;
+ }
+ datastring(b->name, strlen(b->name)+1);
+ }
+
+ // nil field name at end
+ ot = rnd(ot, maxround);
+ p = pc;
+ gins(ADATA, N, N);
+ p->from = at;
+ p->from.offset = ot;
+ p->from.scale = widthptr;
+ p->to = ac;
+ p->to.offset = 0;
+ ot += widthptr;
+
+ p = pc;
+ gins(AGLOBL, N, N);
+ p->from = at;
+ p->to = ac;
+ p->to.offset = ot;
+ }
+
+ if(stringo > 0) {
+ p = pc;
+ gins(AGLOBL, N, N);
+ p->from = ao;
+ p->to = ac;
+ p->to.offset = stringo;
+ }
+}
diff --git a/src/cmd/6g/runtime.c b/src/cmd/6g/runtime.c
new file mode 100644
index 0000000..482e013
--- /dev/null
+++ b/src/cmd/6g/runtime.c
@@ -0,0 +1,595 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+
+int32 debug = 0;
+
+void
+sys_printbool(bool v)
+{
+ if(v) {
+ sys_write(1, (byte*)"true", 4);
+ return;
+ }
+ sys_write(1, (byte*)"false", 5);
+}
+
+void
+sys_printfloat(float64 v)
+{
+ sys_write(1, "printfloat", 10);
+}
+
+void
+sys_printint(int64 v)
+{
+ byte buf[100];
+ int32 i, s;
+
+ s = 0;
+ if(v < 0) {
+ v = -v;
+ s = 1;
+ if(v < 0) {
+ sys_write(1, (byte*)"-oo", 3);
+ return;
+ }
+ }
+
+ for(i=nelem(buf)-1; i>0; i--) {
+ buf[i] = v%10 + '0';
+ if(v < 10)
+ break;
+ v = v/10;
+ }
+ if(s) {
+ i--;
+ buf[i] = '-';
+ }
+ sys_write(1, buf+i, nelem(buf)-i);
+}
+
+void
+sys_printpointer(void *p)
+{
+ uint64 v;
+ byte buf[100];
+ int32 i;
+
+ v = (int64)p;
+ for(i=nelem(buf)-1; i>0; i--) {
+ buf[i] = v%16 + '0';
+ if(buf[i] > '9')
+ buf[i] += 'a'-'0'-10;
+ if(v < 16)
+ break;
+ v = v/16;
+ }
+ sys_write(1, buf+i, nelem(buf)-i);
+}
+
+void
+sys_panicl(int32 lno)
+{
+ prints("\npanic on line ");
+ sys_printint(lno);
+ prints("\n");
+ *(int32*)0 = 0;
+}
+
+void
+sys_printstring(string v)
+{
+ sys_write(1, v->str, v->len);
+}
+
+int32
+strlen(int8 *s)
+{
+ int32 l;
+
+ for(l=0; s[l]!=0; l++)
+ ;
+ return l;
+}
+
+void
+prints(int8 *s)
+{
+ sys_write(1, s, strlen(s));
+}
+
+dump(byte *p, int32 n)
+{
+ uint32 v;
+ int32 i;
+
+ for(i=0; i<n; i++) {
+ sys_printpointer((byte*)(p[i]>>4));
+ sys_printpointer((byte*)(p[i]&0xf));
+ if((i&15) == 15)
+ prints("\n");
+ else
+ prints(" ");
+ }
+ if(n & 15)
+ prints("\n");
+}
+
+static uint8* hunk;
+static uint32 nhunk;
+static uint64 nmmap;
+static uint64 nmal;
+enum
+{
+ NHUNK = 20<<20,
+
+ PROT_NONE = 0x00,
+ PROT_READ = 0x01,
+ PROT_WRITE = 0x02,
+ PROT_EXEC = 0x04,
+
+ MAP_FILE = 0x0000,
+ MAP_SHARED = 0x0001,
+ MAP_PRIVATE = 0x0002,
+ MAP_FIXED = 0x0010,
+ MAP_ANON = 0x1000,
+};
+
+static void
+throw(int8 *s)
+{
+ prints("throw: ");
+ prints(s);
+ prints("\n");
+ sys_exit(1);
+}
+
+static void
+mcpy(byte *t, byte *f, uint32 n)
+{
+ while(n > 0) {
+ *t = *f;
+ t++;
+ f++;
+ n--;
+ }
+}
+
+static byte*
+brk(uint32 n)
+{
+ byte* v;
+
+ v = sys_mmap(nil, NHUNK, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0);
+ sys_memclr(v, n);
+ nmmap += n;
+ return v;
+}
+
+static void*
+mal(uint32 n)
+{
+ byte* v;
+
+ // round to keep everything 64-bit alligned
+ while(n & 7)
+ n++;
+
+ nmal += n;
+
+ // do we have enough in contiguous hunk
+ if(n > nhunk) {
+
+ // if it is big allocate it separately
+ if(n > NHUNK)
+ return brk(n);
+
+ // allocate a new contiguous hunk
+ hunk = brk(NHUNK);
+ nhunk = NHUNK;
+ }
+
+ // allocate from the contiguous hunk
+ v = hunk;
+ hunk += n;
+ nhunk -= n;
+ return v;
+}
+
+void
+sys_mal(uint32 n, uint8 *ret)
+{
+ ret = mal(n);
+ FLUSH(&ret);
+}
+
+void
+sys_catstring(string s1, string s2, string s3)
+{
+ uint32 l;
+
+ if(s1->len == 0) {
+ s3 = s2;
+ goto out;
+ }
+ if(s2->len == 0) {
+ s3 = s1;
+ goto out;
+ }
+
+ l = s1->len + s2->len;
+
+ s3 = mal(sizeof(s3->len)+l);
+ s3->len = l;
+ mcpy(s3->str, s1->str, s1->len);
+ mcpy(s3->str+s1->len, s2->str, s2->len);
+
+out:
+ FLUSH(&s3);
+}
+
+void
+sys_cmpstring(string s1, string s2, int32 v)
+{
+ uint32 i, l;
+ byte c1, c2;
+
+ l = s1->len;
+ if(s2->len < l)
+ l = s2->len;
+ for(i=0; i<l; i++) {
+ c1 = s1->str[i];
+ c2 = s2->str[i];
+ if(c1 < c2) {
+ v = -1;
+ goto out;
+ }
+ if(c1 > c2) {
+ v = +1;
+ goto out;
+ }
+ }
+ if(s1->len < s2->len) {
+ v = -1;
+ goto out;
+ }
+ if(s1->len > s2->len) {
+ v = +1;
+ goto out;
+ }
+ v = 0;
+
+out:
+ FLUSH(&v);
+}
+
+static int32
+strcmp(byte *s1, byte *s2)
+{
+ uint32 i;
+ byte c1, c2;
+
+ for(i=0;; i++) {
+ c1 = s1[i];
+ c2 = s2[i];
+ if(c1 < c2)
+ return -1;
+ if(c1 > c2)
+ return +1;
+ if(c1 == 0)
+ return 0;
+ }
+}
+
+static void
+prbounds(int8* s, int32 a, int32 b, int32 c)
+{
+ int32 i;
+
+ prints(s);
+ prints(" ");
+ sys_printint(a);
+ prints("<");
+ sys_printint(b);
+ prints(">");
+ sys_printint(c);
+ prints("\n");
+ throw("bounds");
+}
+
+void
+sys_slicestring(string si, int32 lindex, int32 hindex, string so)
+{
+ string s, str;
+ int32 l;
+
+ if(lindex < 0 || lindex > si->len ||
+ hindex < lindex || hindex > si->len)
+ prbounds("slice", lindex, si->len, hindex);
+
+ l = hindex-lindex;
+ so = mal(sizeof(so->len)+l);
+ so->len = l;
+ mcpy(so->str, si->str+lindex, l);
+ FLUSH(&so);
+}
+
+void
+sys_indexstring(string s, int32 i, byte b)
+{
+ if(i < 0 || i >= s->len)
+ prbounds("index", 0, i, s->len);
+
+ b = s->str[i];
+ FLUSH(&b);
+}
+
+/*
+ * this is the plan9 runetochar
+ * extended for 36 bits in 7 bytes
+ * note that it truncates to 32 bits
+ * through the argument passing.
+ */
+static int32
+runetochar(byte *str, uint32 c)
+{
+ int32 i, n;
+ uint32 mask, mark;
+
+ /*
+ * one character in 7 bits
+ */
+ if(c <= 0x07FUL) {
+ str[0] = c;
+ return 1;
+ }
+
+ /*
+ * every new character picks up 5 bits
+ * one less in the first byte and
+ * six more in an extension byte
+ */
+ mask = 0x7ffUL;
+ mark = 0xC0UL;
+ for(n=1;; n++) {
+ if(c <= mask)
+ break;
+ mask = (mask<<5) | 0x1fUL;
+ mark = (mark>>1) | 0x80UL;
+ }
+
+ /*
+ * lay down the bytes backwards
+ * n is the number of extension bytes
+ * mask is the max codepoint
+ * mark is the zeroth byte indicator
+ */
+ for(i=n; i>0; i--) {
+ str[i] = 0x80UL | (c&0x3fUL);
+ c >>= 6;
+ }
+
+ str[0] = mark|c;
+ return n+1;
+}
+
+void
+sys_intstring(int64 v, string s)
+{
+ int32 l;
+
+ s = mal(sizeof(s->len)+8);
+ s->len = runetochar(s->str, v);
+ FLUSH(&s);
+}
+
+void
+sys_byteastring(byte *a, int32 l, string s)
+{
+ s = mal(sizeof(s->len)+l);
+ s->len = l;
+ mcpy(s->str, a, l);
+ FLUSH(&s);
+}
+
+static Map* hash[1009];
+
+static Map*
+hashmap(Sigi *si, Sigs *ss)
+{
+ int32 ns, ni;
+ uint32 ihash, h;
+ byte *sname, *iname;
+ Map *m;
+
+ h = ((uint32)si + (uint32)ss) % nelem(hash);
+ for(m=hash[h]; m!=nil; m=m->link) {
+ if(m->si == si && m->ss == ss) {
+ if(m->bad) {
+ throw("bad hashmap");
+ m = nil;
+ }
+ // prints("old hashmap\n");
+ return m;
+ }
+ }
+
+ ni = si[0].offset; // first word has size
+ m = mal(sizeof(*m) + ni*sizeof(m->fun[0]));
+ m->si = si;
+ m->ss = ss;
+
+ ni = 1; // skip first word
+ ns = 0;
+
+loop1:
+ // pick up next name from
+ // interface signature
+ iname = si[ni].name;
+ if(iname == nil) {
+ m->link = hash[h];
+ hash[h] = m;
+ // prints("new hashmap\n");
+ return m;
+ }
+ ihash = si[ni].hash;
+
+loop2:
+ // pick up and comapre next name
+ // from structure signature
+ sname = ss[ns].name;
+ if(sname == nil) {
+ prints((int8*)iname);
+ prints(": ");
+ throw("hashmap: failed to find method");
+ m->bad = 1;
+ m->link = hash[h];
+ hash[h] = m;
+ return nil;
+ }
+ if(ihash != ss[ns].hash ||
+ strcmp(sname, iname) != 0) {
+ ns++;
+ goto loop2;
+ }
+
+ m->fun[si[ni].offset] = ss[ns].fun;
+ ni++;
+ goto loop1;
+}
+
+void
+sys_ifaces2i(Sigi *si, Sigs *ss, Map *m, void *s)
+{
+
+ if(debug) {
+ prints("s2i sigi=");
+ sys_printpointer(si);
+ prints(" sigs=");
+ sys_printpointer(ss);
+ prints(" s=");
+ sys_printpointer(s);
+ }
+
+ if(s == nil) {
+ throw("ifaces2i: nil pointer");
+ m = nil;
+ FLUSH(&m);
+ return;
+ }
+
+ m = hashmap(si, ss);
+
+ if(debug) {
+ prints(" returning m=");
+ sys_printpointer(m);
+ prints(" s=");
+ sys_printpointer(s);
+ prints("\n");
+ dump((byte*)m, 64);
+ }
+
+ FLUSH(&m);
+}
+
+void
+sys_ifacei2i(Sigi *si, Map *m, void *s)
+{
+
+ if(debug) {
+ prints("i2i sigi=");
+ sys_printpointer(si);
+ prints(" m=");
+ sys_printpointer(m);
+ prints(" s=");
+ sys_printpointer(s);
+ }
+
+ if(m == nil) {
+ throw("ifacei2i: nil map");
+ s = nil;
+ FLUSH(&s);
+ return;
+ }
+
+ if(m->si == nil) {
+ throw("ifacei2i: nil pointer");
+ return;
+ }
+
+ if(m->si != si) {
+ m = hashmap(si, m->ss);
+ FLUSH(&m);
+ }
+
+ if(debug) {
+ prints(" returning m=");
+ sys_printpointer(m);
+ prints(" s=");
+ sys_printpointer(s);
+ prints("\n");
+ dump((byte*)m, 64);
+ }
+}
+
+void
+sys_ifacei2s(Sigs *ss, Map *m, void *s)
+{
+
+ if(debug) {
+ prints("i2s m=");
+ sys_printpointer(m);
+ prints(" s=");
+ sys_printpointer(s);
+ prints("\n");
+ }
+
+ if(m == nil) {
+ throw("ifacei2s: nil map");
+ s = nil;
+ FLUSH(&s);
+ return;
+ }
+
+ if(m->ss != ss) {
+ dump((byte*)m, 64);
+ throw("ifacei2s: wrong pointer");
+ s = nil;
+ FLUSH(&s);
+ return;
+ }
+}
+
+void
+check(void)
+{
+ int8 a;
+ uint8 b;
+ int16 c;
+ uint16 d;
+ int32 e;
+ uint32 f;
+ int64 g;
+ uint64 h;
+ float32 i;
+ float64 j;
+ void* k;
+ uint16* l;
+
+ if(sizeof(a) != 1) throw("bad a");
+ if(sizeof(b) != 1) throw("bad b");
+ if(sizeof(c) != 2) throw("bad c");
+ if(sizeof(d) != 2) throw("bad d");
+ if(sizeof(e) != 4) throw("bad e");
+ if(sizeof(f) != 4) throw("bad f");
+ if(sizeof(g) != 8) throw("bad g");
+ if(sizeof(h) != 8) throw("bad h");
+ if(sizeof(i) != 4) throw("bad i");
+ if(sizeof(j) != 8) throw("bad j");
+ if(sizeof(k) != 8) throw("bad k");
+ if(sizeof(l) != 8) throw("bad l");
+// prints(1"check ok\n");
+}
diff --git a/src/cmd/6g/runtime.h b/src/cmd/6g/runtime.h
new file mode 100644
index 0000000..6220a03
--- /dev/null
+++ b/src/cmd/6g/runtime.h
@@ -0,0 +1,107 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+/*
+ * basic types
+ */
+typedef signed char int8;
+typedef unsigned char uint8;
+typedef signed short int16;
+typedef unsigned short uint16;
+typedef signed int int32;
+typedef unsigned int uint32;
+typedef signed long long int int64;
+typedef unsigned long long int uint64;
+typedef float float32;
+typedef double float64;
+
+/*
+ * get rid of C types
+ */
+#define unsigned XXunsigned
+#define signed XXsigned
+#define char XXchar
+#define short XXshort
+#define int XXint
+#define long XXlong
+#define float XXfloat
+#define double XXdouble
+
+/*
+ * defined types
+ */
+typedef uint8 bool;
+typedef uint8 byte;
+typedef struct
+{
+ int32 len;
+ byte str[1];
+} *string;
+typedef struct
+{
+ byte* name;
+ uint32 hash;
+ void (*fun)(void);
+} Sigs;
+typedef struct
+{
+ byte* name;
+ uint32 hash;
+ uint32 offset;
+} Sigi;
+typedef struct Map Map;
+struct Map
+{
+ Sigi* si;
+ Sigs* ss;
+ Map* link;
+ int32 bad;
+ int32 unused;
+ void (*fun[])(void);
+};
+
+/*
+ * defined constants
+ */
+enum
+{
+ true = 1,
+ false = 0,
+};
+
+/*
+ * defined macros
+ * you need super-goru privilege
+ * to add this list.
+ */
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+#define nil ((void*)0)
+
+/*
+ * very low level
+ */
+void FLUSH(void*);
+void prints(int8*);
+void sys_exit(int32);
+void sys_write(int32, void*, int32);
+void sys_breakpoint(void);
+uint8* sys_mmap(byte*, uint32, int32, int32, int32, uint32);
+void sys_memclr(byte*, uint32);
+
+/*
+ * runtime
+ */
+void sys_printbool(bool);
+void sys_printfloat(float64);
+void sys_printint(int64);
+void sys_printstring(string);
+void sys_catstring(string, string, string);
+void sys_cmpstring(string, string, int32);
+void sys_slicestring(string, int32, int32, string);
+void sys_indexstring(string, int32, byte);
+void sys_intstring(int64, string);
+void sys_ifaces2i(Sigi*, Sigs*, Map*, void*);
+void sys_ifacei2i(Sigi*, Map*, void*);
+void sys_ifacei2s(Sigs*, Map*, void*);
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
new file mode 100644
index 0000000..8006826
--- /dev/null
+++ b/src/cmd/6l/6.out.h
@@ -0,0 +1,857 @@
+// Inferno utils/6c/6.out.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/6.out.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#define NSYM 50
+#define NSNAME 8
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+
+/*
+ * amd64
+ */
+
+enum as
+{
+ AXXX,
+ AAAA,
+ AAAD,
+ AAAM,
+ AAAS,
+ AADCB,
+ AADCL,
+ AADCW,
+ AADDB,
+ AADDL,
+ AADDW,
+ AADJSP,
+ AANDB,
+ AANDL,
+ AANDW,
+ AARPL,
+ ABOUNDL,
+ ABOUNDW,
+ ABSFL,
+ ABSFW,
+ ABSRL,
+ ABSRW,
+ ABTL,
+ ABTW,
+ ABTCL,
+ ABTCW,
+ ABTRL,
+ ABTRW,
+ ABTSL,
+ ABTSW,
+ ABYTE,
+ ACALL,
+ ACLC,
+ ACLD,
+ ACLI,
+ ACLTS,
+ ACMC,
+ ACMPB,
+ ACMPL,
+ ACMPW,
+ ACMPSB,
+ ACMPSL,
+ ACMPSW,
+ ADAA,
+ ADAS,
+ ADATA,
+ ADECB,
+ ADECL,
+ ADECQ,
+ ADECW,
+ ADIVB,
+ ADIVL,
+ ADIVW,
+ AENTER,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ AHLT,
+ AIDIVB,
+ AIDIVL,
+ AIDIVW,
+ AIMULB,
+ AIMULL,
+ AIMULW,
+ AINB,
+ AINL,
+ AINW,
+ AINCB,
+ AINCL,
+ AINCQ,
+ AINCW,
+ AINSB,
+ AINSL,
+ AINSW,
+ AINT,
+ AINTO,
+ AIRETL,
+ AIRETW,
+ AJCC,
+ AJCS,
+ AJCXZ,
+ AJEQ,
+ AJGE,
+ AJGT,
+ AJHI,
+ AJLE,
+ AJLS,
+ AJLT,
+ AJMI,
+ AJMP,
+ AJNE,
+ AJOC,
+ AJOS,
+ AJPC,
+ AJPL,
+ AJPS,
+ ALAHF,
+ ALARL,
+ ALARW,
+ ALEAL,
+ ALEAW,
+ ALEAVEL,
+ ALEAVEW,
+ ALOCK,
+ ALODSB,
+ ALODSL,
+ ALODSW,
+ ALONG,
+ ALOOP,
+ ALOOPEQ,
+ ALOOPNE,
+ ALSLL,
+ ALSLW,
+ AMOVB,
+ AMOVL,
+ AMOVW,
+ AMOVBLSX,
+ AMOVBLZX,
+ AMOVBQSX,
+ AMOVBQZX,
+ AMOVBWSX,
+ AMOVBWZX,
+ AMOVWLSX,
+ AMOVWLZX,
+ AMOVWQSX,
+ AMOVWQZX,
+ AMOVSB,
+ AMOVSL,
+ AMOVSW,
+ AMULB,
+ AMULL,
+ AMULW,
+ ANAME,
+ ANEGB,
+ ANEGL,
+ ANEGW,
+ ANOP,
+ ANOTB,
+ ANOTL,
+ ANOTW,
+ AORB,
+ AORL,
+ AORW,
+ AOUTB,
+ AOUTL,
+ AOUTW,
+ AOUTSB,
+ AOUTSL,
+ AOUTSW,
+ APOPAL,
+ APOPAW,
+ APOPFL,
+ APOPFW,
+ APOPL,
+ APOPW,
+ APUSHAL,
+ APUSHAW,
+ APUSHFL,
+ APUSHFW,
+ APUSHL,
+ APUSHW,
+ ARCLB,
+ ARCLL,
+ ARCLW,
+ ARCRB,
+ ARCRL,
+ ARCRW,
+ AREP,
+ AREPN,
+ ARET,
+ AROLB,
+ AROLL,
+ AROLW,
+ ARORB,
+ ARORL,
+ ARORW,
+ ASAHF,
+ ASALB,
+ ASALL,
+ ASALW,
+ ASARB,
+ ASARL,
+ ASARW,
+ ASBBB,
+ ASBBL,
+ ASBBW,
+ ASCASB,
+ ASCASL,
+ ASCASW,
+ ASETCC,
+ ASETCS,
+ ASETEQ,
+ ASETGE,
+ ASETGT,
+ ASETHI,
+ ASETLE,
+ ASETLS,
+ ASETLT,
+ ASETMI,
+ ASETNE,
+ ASETOC,
+ ASETOS,
+ ASETPC,
+ ASETPL,
+ ASETPS,
+ ACDQ,
+ ACWD,
+ ASHLB,
+ ASHLL,
+ ASHLW,
+ ASHRB,
+ ASHRL,
+ ASHRW,
+ ASTC,
+ ASTD,
+ ASTI,
+ ASTOSB,
+ ASTOSL,
+ ASTOSW,
+ ASUBB,
+ ASUBL,
+ ASUBW,
+ ASYSCALL,
+ ATESTB,
+ ATESTL,
+ ATESTW,
+ ATEXT,
+ AVERR,
+ AVERW,
+ AWAIT,
+ AWORD,
+ AXCHGB,
+ AXCHGL,
+ AXCHGW,
+ AXLAT,
+ AXORB,
+ AXORL,
+ AXORW,
+
+ AFMOVB,
+ AFMOVBP,
+ AFMOVD,
+ AFMOVDP,
+ AFMOVF,
+ AFMOVFP,
+ AFMOVL,
+ AFMOVLP,
+ AFMOVV,
+ AFMOVVP,
+ AFMOVW,
+ AFMOVWP,
+ AFMOVX,
+ AFMOVXP,
+
+ AFCOMB,
+ AFCOMBP,
+ AFCOMD,
+ AFCOMDP,
+ AFCOMDPP,
+ AFCOMF,
+ AFCOMFP,
+ AFCOML,
+ AFCOMLP,
+ AFCOMW,
+ AFCOMWP,
+ AFUCOM,
+ AFUCOMP,
+ AFUCOMPP,
+
+ AFADDDP,
+ AFADDW,
+ AFADDL,
+ AFADDF,
+ AFADDD,
+
+ AFMULDP,
+ AFMULW,
+ AFMULL,
+ AFMULF,
+ AFMULD,
+
+ AFSUBDP,
+ AFSUBW,
+ AFSUBL,
+ AFSUBF,
+ AFSUBD,
+
+ AFSUBRDP,
+ AFSUBRW,
+ AFSUBRL,
+ AFSUBRF,
+ AFSUBRD,
+
+ AFDIVDP,
+ AFDIVW,
+ AFDIVL,
+ AFDIVF,
+ AFDIVD,
+
+ AFDIVRDP,
+ AFDIVRW,
+ AFDIVRL,
+ AFDIVRF,
+ AFDIVRD,
+
+ AFXCHD,
+ AFFREE,
+
+ AFLDCW,
+ AFLDENV,
+ AFRSTOR,
+ AFSAVE,
+ AFSTCW,
+ AFSTENV,
+ AFSTSW,
+
+ AF2XM1,
+ AFABS,
+ AFCHS,
+ AFCLEX,
+ AFCOS,
+ AFDECSTP,
+ AFINCSTP,
+ AFINIT,
+ AFLD1,
+ AFLDL2E,
+ AFLDL2T,
+ AFLDLG2,
+ AFLDLN2,
+ AFLDPI,
+ AFLDZ,
+ AFNOP,
+ AFPATAN,
+ AFPREM,
+ AFPREM1,
+ AFPTAN,
+ AFRNDINT,
+ AFSCALE,
+ AFSIN,
+ AFSINCOS,
+ AFSQRT,
+ AFTST,
+ AFXAM,
+ AFXTRACT,
+ AFYL2X,
+ AFYL2XP1,
+
+ AEND,
+
+ ADYNT,
+ AINIT,
+
+ ASIGNAME,
+
+ /* extra 32-bit operations */
+ ACMPXCHGB,
+ ACMPXCHGL,
+ ACMPXCHGW,
+ ACMPXCHG8B,
+ ACPUID,
+ AINVD,
+ AINVLPG,
+ ALFENCE,
+ AMFENCE,
+ AMOVNTIL,
+ ARDMSR,
+ ARDPMC,
+ ARDTSC,
+ ARSM,
+ ASFENCE,
+ ASYSRET,
+ AWBINVD,
+ AWRMSR,
+ AXADDB,
+ AXADDL,
+ AXADDW,
+
+ /* conditional move */
+ ACMOVLCC,
+ ACMOVLCS,
+ ACMOVLEQ,
+ ACMOVLGE,
+ ACMOVLGT,
+ ACMOVLHI,
+ ACMOVLLE,
+ ACMOVLLS,
+ ACMOVLLT,
+ ACMOVLMI,
+ ACMOVLNE,
+ ACMOVLOC,
+ ACMOVLOS,
+ ACMOVLPC,
+ ACMOVLPL,
+ ACMOVLPS,
+ ACMOVQCC,
+ ACMOVQCS,
+ ACMOVQEQ,
+ ACMOVQGE,
+ ACMOVQGT,
+ ACMOVQHI,
+ ACMOVQLE,
+ ACMOVQLS,
+ ACMOVQLT,
+ ACMOVQMI,
+ ACMOVQNE,
+ ACMOVQOC,
+ ACMOVQOS,
+ ACMOVQPC,
+ ACMOVQPL,
+ ACMOVQPS,
+ ACMOVWCC,
+ ACMOVWCS,
+ ACMOVWEQ,
+ ACMOVWGE,
+ ACMOVWGT,
+ ACMOVWHI,
+ ACMOVWLE,
+ ACMOVWLS,
+ ACMOVWLT,
+ ACMOVWMI,
+ ACMOVWNE,
+ ACMOVWOC,
+ ACMOVWOS,
+ ACMOVWPC,
+ ACMOVWPL,
+ ACMOVWPS,
+
+ /* 64-bit */
+ AADCQ,
+ AADDQ,
+ AANDQ,
+ ABSFQ,
+ ABSRQ,
+ ABTCQ,
+ ABTQ,
+ ABTRQ,
+ ABTSQ,
+ ACMPQ,
+ ACMPSQ,
+ ACMPXCHGQ,
+ ACQO,
+ ADIVQ,
+ AIDIVQ,
+ AIMULQ,
+ AIRETQ,
+ ALEAQ,
+ ALEAVEQ,
+ ALODSQ,
+ AMOVQ,
+ AMOVLQSX,
+ AMOVLQZX,
+ AMOVNTIQ,
+ AMOVSQ,
+ AMULQ,
+ ANEGQ,
+ ANOTQ,
+ AORQ,
+ APOPFQ,
+ APOPQ,
+ APUSHFQ,
+ APUSHQ,
+ ARCLQ,
+ ARCRQ,
+ AROLQ,
+ ARORQ,
+ AQUAD,
+ ASALQ,
+ ASARQ,
+ ASBBQ,
+ ASCASQ,
+ ASHLQ,
+ ASHRQ,
+ ASTOSQ,
+ ASUBQ,
+ ATESTQ,
+ AXADDQ,
+ AXCHGQ,
+ AXORQ,
+
+ /* media */
+ AADDPD,
+ AADDPS,
+ AADDSD,
+ AADDSS,
+ AANDNPD,
+ AANDNPS,
+ AANDPD,
+ AANDPS,
+ ACMPPD,
+ ACMPPS,
+ ACMPSD,
+ ACMPSS,
+ ACOMISD,
+ ACOMISS,
+ ACVTPD2PL,
+ ACVTPD2PS,
+ ACVTPL2PD,
+ ACVTPL2PS,
+ ACVTPS2PD,
+ ACVTPS2PL,
+ ACVTSD2SL,
+ ACVTSD2SQ,
+ ACVTSD2SS,
+ ACVTSL2SD,
+ ACVTSL2SS,
+ ACVTSQ2SD,
+ ACVTSQ2SS,
+ ACVTSS2SD,
+ ACVTSS2SL,
+ ACVTSS2SQ,
+ ACVTTPD2PL,
+ ACVTTPS2PL,
+ ACVTTSD2SL,
+ ACVTTSD2SQ,
+ ACVTTSS2SL,
+ ACVTTSS2SQ,
+ ADIVPD,
+ ADIVPS,
+ ADIVSD,
+ ADIVSS,
+ AEMMS,
+ AFXRSTOR,
+ AFXRSTOR64,
+ AFXSAVE,
+ AFXSAVE64,
+ ALDMXCSR,
+ AMASKMOVOU,
+ AMASKMOVQ,
+ AMAXPD,
+ AMAXPS,
+ AMAXSD,
+ AMAXSS,
+ AMINPD,
+ AMINPS,
+ AMINSD,
+ AMINSS,
+ AMOVAPD,
+ AMOVAPS,
+ AMOVOU,
+ AMOVHLPS,
+ AMOVHPD,
+ AMOVHPS,
+ AMOVLHPS,
+ AMOVLPD,
+ AMOVLPS,
+ AMOVMSKPD,
+ AMOVMSKPS,
+ AMOVNTO,
+ AMOVNTPD,
+ AMOVNTPS,
+ AMOVNTQ,
+ AMOVO,
+ AMOVQOZX,
+ AMOVSD,
+ AMOVSS,
+ AMOVUPD,
+ AMOVUPS,
+ AMULPD,
+ AMULPS,
+ AMULSD,
+ AMULSS,
+ AORPD,
+ AORPS,
+ APACKSSLW,
+ APACKSSWB,
+ APACKUSWB,
+ APADDB,
+ APADDL,
+ APADDQ,
+ APADDSB,
+ APADDSW,
+ APADDUSB,
+ APADDUSW,
+ APADDW,
+ APANDB,
+ APANDL,
+ APANDSB,
+ APANDSW,
+ APANDUSB,
+ APANDUSW,
+ APANDW,
+ APAND,
+ APANDN,
+ APAVGB,
+ APAVGW,
+ APCMPEQB,
+ APCMPEQL,
+ APCMPEQW,
+ APCMPGTB,
+ APCMPGTL,
+ APCMPGTW,
+ APEXTRW,
+ APFACC,
+ APFADD,
+ APFCMPEQ,
+ APFCMPGE,
+ APFCMPGT,
+ APFMAX,
+ APFMIN,
+ APFMUL,
+ APFNACC,
+ APFPNACC,
+ APFRCP,
+ APFRCPIT1,
+ APFRCPI2T,
+ APFRSQIT1,
+ APFRSQRT,
+ APFSUB,
+ APFSUBR,
+ APINSRW,
+ APMADDWL,
+ APMAXSW,
+ APMAXUB,
+ APMINSW,
+ APMINUB,
+ APMOVMSKB,
+ APMULHRW,
+ APMULHUW,
+ APMULHW,
+ APMULLW,
+ APMULULQ,
+ APOR,
+ APSADBW,
+ APSHUFHW,
+ APSHUFL,
+ APSHUFLW,
+ APSHUFW,
+ APSLLO,
+ APSLLL,
+ APSLLQ,
+ APSLLW,
+ APSRAL,
+ APSRAW,
+ APSRLO,
+ APSRLL,
+ APSRLQ,
+ APSRLW,
+ APSUBB,
+ APSUBL,
+ APSUBQ,
+ APSUBSB,
+ APSUBSW,
+ APSUBUSB,
+ APSUBUSW,
+ APSUBW,
+ APSWAPL,
+ APUNPCKHBW,
+ APUNPCKHLQ,
+ APUNPCKHQDQ,
+ APUNPCKHWL,
+ APUNPCKLBW,
+ APUNPCKLLQ,
+ APUNPCKLQDQ,
+ APUNPCKLWL,
+ APXOR,
+ ARCPPS,
+ ARCPSS,
+ ARSQRTPS,
+ ARSQRTSS,
+ ASHUFPD,
+ ASHUFPS,
+ ASQRTPD,
+ ASQRTPS,
+ ASQRTSD,
+ ASQRTSS,
+ ASTMXCSR,
+ ASUBPD,
+ ASUBPS,
+ ASUBSD,
+ ASUBSS,
+ AUCOMISD,
+ AUCOMISS,
+ AUNPCKHPD,
+ AUNPCKHPS,
+ AUNPCKLPD,
+ AUNPCKLPS,
+ AXORPD,
+ AXORPS,
+
+ APF2IW,
+ APF2IL,
+ API2FW,
+ API2FL,
+ ARETFW,
+ ARETFL,
+ ARETFQ,
+ ASWAPGS,
+
+ AMODE,
+
+ ALAST
+};
+
+enum
+{
+
+ D_AL = 0,
+ D_CL,
+ D_DL,
+ D_BL,
+ D_SPB,
+ D_BPB,
+ D_SIB,
+ D_DIB,
+ D_R8B,
+ D_R9B,
+ D_R10B,
+ D_R11B,
+ D_R12B,
+ D_R13B,
+ D_R14B,
+ D_R15B,
+
+ D_AX = 16,
+ D_CX,
+ D_DX,
+ D_BX,
+ D_SP,
+ D_BP,
+ D_SI,
+ D_DI,
+ D_R8,
+ D_R9,
+ D_R10,
+ D_R11,
+ D_R12,
+ D_R13,
+ D_R14,
+ D_R15,
+
+ D_AH = 32,
+ D_CH,
+ D_DH,
+ D_BH,
+
+ D_F0 = 36,
+
+ D_M0 = 44,
+
+ D_X0 = 52,
+ D_X1,
+ D_X2,
+ D_X3,
+ D_X4,
+ D_X5,
+ D_X6,
+ D_X7,
+
+ D_CS = 68,
+ D_SS,
+ D_DS,
+ D_ES,
+ D_FS,
+ D_GS,
+
+ D_GDTR, /* global descriptor table register */
+ D_IDTR, /* interrupt descriptor table register */
+ D_LDTR, /* local descriptor table register */
+ D_MSW, /* machine status word */
+ D_TASK, /* task register */
+
+ D_CR = 79,
+ D_DR = 95,
+ D_TR = 103,
+
+ D_NONE = 111,
+
+ D_BRANCH = 112,
+ D_EXTERN = 113,
+ D_STATIC = 114,
+ D_AUTO = 115,
+ D_PARAM = 116,
+ D_CONST = 117,
+ D_FCONST = 118,
+ D_SCONST = 119,
+ D_ADDR = 120,
+
+ D_FILE,
+ D_FILE1,
+
+ D_INDIR, /* additive */
+
+ T_TYPE = 1<<0,
+ T_INDEX = 1<<1,
+ T_OFFSET = 1<<2,
+ T_FCONST = 1<<3,
+ T_SYM = 1<<4,
+ T_SCONST = 1<<5,
+ T_64 = 1<<6,
+
+ REGARG = 0,
+ REGRET = D_AX,
+ FREGRET = D_X0,
+ REGSP = D_SP,
+ REGTMP = D_DI,
+ REGEXT = D_R15, /* compiler allocates external registers R15 down */
+ FREGMIN = D_X0+5, /* first register variable */
+ FREGEXT = D_X0+7 /* first external register */
+};
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ long l; /* contains ls-man 0xffffffff */
+ long h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
new file mode 100644
index 0000000..4d1e9d9
--- /dev/null
+++ b/src/cmd/6l/asm.c
@@ -0,0 +1,617 @@
+// Inferno utils/6l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "l.h"
+
+#define Dbufslop 100
+
+#define PADDR(a) ((ulong)(a) & ~0x80000000)
+
+vlong
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ switch(s->type) {
+ case STEXT:
+ break;
+ case SDATA:
+ if(dlm)
+ return s->value+INITDAT;
+ default:
+ diag("entry not text: %s", s->name);
+ }
+ return s->value;
+}
+
+void
+wputl(ushort w)
+{
+ cput(w);
+ cput(w>>8);
+}
+
+void
+wput(ushort w)
+{
+ cput(w>>8);
+ cput(w);
+}
+
+void
+lput(long l)
+{
+ cput(l>>24);
+ cput(l>>16);
+ cput(l>>8);
+ cput(l);
+}
+
+void
+llput(vlong v)
+{
+ lput(v>>32);
+ lput(v);
+}
+
+void
+lputl(long l)
+{
+ cput(l);
+ cput(l>>8);
+ cput(l>>16);
+ cput(l>>24);
+}
+
+void
+strnput(char *s, int n)
+{
+ int i;
+
+ for(i=0; i<n; i++) {
+ cput(*s);
+ if(*s != 0)
+ s++;
+ }
+}
+
+void
+asmb(void)
+{
+ Prog *p;
+ long v, magic, w;
+ int a;
+ uchar *op1;
+ vlong vl, va;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asmb\n", cputime());
+ Bflush(&bso);
+
+ seek(cout, HEADR, 0);
+ pc = INITTEXT;
+ curp = firstp;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->pc != pc) {
+ if(!debug['a'])
+ print("%P\n", curp);
+ diag("phase error %llux sb %llux in %s", p->pc, pc, TNAME);
+ pc = p->pc;
+ }
+ curp = p;
+ asmins(p);
+ a = (andptr - and);
+ if(cbc < a)
+ cflush();
+ if(debug['a']) {
+ Bprint(&bso, pcstr, pc);
+ for(op1 = and; op1 < andptr; op1++)
+ Bprint(&bso, "%.2ux", *op1);
+ for(; op1 < and+Maxand; op1++)
+ Bprint(&bso, " ");
+ Bprint(&bso, "%P\n", curp);
+ }
+ if(dlm) {
+ if(p->as == ATEXT)
+ reloca = nil;
+ else if(reloca != nil)
+ diag("reloc failure: %P", curp);
+ }
+ memmove(cbp, and, a);
+ cbp += a;
+ pc += a;
+ cbc -= a;
+ }
+ cflush();
+ switch(HEADTYPE) {
+ default:
+ diag("unknown header type %ld", HEADTYPE);
+ case 2:
+ case 5:
+ seek(cout, HEADR+textsize, 0);
+ break;
+ case 6:
+ v = HEADR+textsize;
+ myseek(cout, v);
+ v = rnd(v, 4096) - v;
+ while(v > 0) {
+ cput(0);
+ v--;
+ }
+ cflush();
+ break;
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f datblk\n", cputime());
+ Bflush(&bso);
+
+ if(dlm){
+ char buf[8];
+
+ write(cout, buf, INITDAT-textsize);
+ textsize = INITDAT;
+ }
+
+ for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) {
+ if(datsize-v > sizeof(buf)-Dbufslop)
+ datblk(v, sizeof(buf)-Dbufslop);
+ else
+ datblk(v, datsize-v);
+ }
+
+ symsize = 0;
+ spsize = 0;
+ lcsize = 0;
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ Bflush(&bso);
+ switch(HEADTYPE) {
+ default:
+ case 2:
+ case 5:
+ seek(cout, HEADR+textsize+datsize, 0);
+ break;
+ case 6:
+ debug['s'] = 1;
+ break;
+ }
+ if(!debug['s'])
+ asmsym();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sp\n", cputime());
+ Bflush(&bso);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f pc\n", cputime());
+ Bflush(&bso);
+ if(!debug['s'])
+ asmlc();
+ if(dlm)
+ asmdyn();
+ cflush();
+ }
+ else if(dlm){
+ seek(cout, HEADR+textsize+datsize, 0);
+ asmdyn();
+ cflush();
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f headr\n", cputime());
+ Bflush(&bso);
+ seek(cout, 0L, 0);
+ switch(HEADTYPE) {
+ default:
+ case 2: /* plan9 */
+ magic = 4*26*26+7;
+ magic |= 0x00008000; /* fat header */
+ if(dlm)
+ magic |= 0x80000000; /* dlm */
+ lput(magic); /* magic */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ vl = entryvalue();
+ lput(PADDR(vl)); /* va of entry */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ llput(vl); /* va of entry */
+ break;
+ case 3: /* plan9 */
+ magic = 4*26*26+7;
+ if(dlm)
+ magic |= 0x80000000;
+ lput(magic); /* magic */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ break;
+ case 5:
+ strnput("\177ELF", 4); /* e_ident */
+ cput(1); /* class = 32 bit */
+ cput(1); /* data = LSB */
+ cput(1); /* version = CURRENT */
+ strnput("", 9);
+ wputl(2); /* type = EXEC */
+ wputl(62); /* machine = AMD64 */
+ lputl(1L); /* version = CURRENT */
+ lputl(PADDR(entryvalue())); /* entry vaddr */
+ lputl(52L); /* offset to first phdr */
+ lputl(0L); /* offset to first shdr */
+ lputl(0L); /* processor specific flags */
+ wputl(52); /* Ehdr size */
+ wputl(32); /* Phdr size */
+ wputl(3); /* # of Phdrs */
+ wputl(0); /* Shdr size */
+ wputl(0); /* # of Shdrs */
+ wputl(0); /* Shdr string size */
+
+ lputl(1L); /* text - type = PT_LOAD */
+ lputl(HEADR); /* file offset */
+ lputl(INITTEXT); /* vaddr */
+ lputl(PADDR(INITTEXT)); /* paddr */
+ lputl(textsize); /* file size */
+ lputl(textsize); /* memory size */
+ lputl(0x05L); /* protections = RX */
+ lputl(INITRND); /* alignment */
+
+ lputl(1L); /* data - type = PT_LOAD */
+ lputl(HEADR+textsize); /* file offset */
+ lputl(INITDAT); /* vaddr */
+ lputl(PADDR(INITDAT)); /* paddr */
+ lputl(datsize); /* file size */
+ lputl(datsize+bsssize); /* memory size */
+ lputl(0x06L); /* protections = RW */
+ lputl(INITRND); /* alignment */
+
+ lputl(0L); /* data - type = PT_NULL */
+ lputl(HEADR+textsize+datsize); /* file offset */
+ lputl(0L);
+ lputl(0L);
+ lputl(symsize); /* symbol table size */
+ lputl(lcsize); /* line number size */
+ lputl(0x04L); /* protections = R */
+ lputl(0x04L); /* alignment */
+ break;
+ case 6:
+ /* apple MACH */
+ va = 4096;
+
+ lputl(0xfeedfacf); /* 64-bit */
+ lputl((1<<24)|7); /* cputype - x86/ABI64 */
+ lputl(3); /* subtype - x86 */
+ lputl(2); /* file type - mach executable */
+ lputl(4); /* number of loads */
+ lputl(machheadr()-32); /* size of loads */
+ lputl(1); /* flags - no undefines */
+ lputl(0); /* reserved */
+
+ machseg("__PAGEZERO",
+ 0,va, /* vaddr vsize */
+ 0,0, /* fileoffset filesize */
+ 0,0, /* protects */
+ 0,0); /* sections flags */
+
+ v = rnd(HEADR+textsize, INITRND);
+ machseg("__TEXT",
+ va, /* vaddr */
+ v, /* vsize */
+ 0,v, /* fileoffset filesize */
+ 7,5, /* protects */
+ 1,0); /* sections flags */
+ machsect("__text", "__TEXT",
+ va+HEADR,v-HEADR, /* addr size */
+ HEADR,0,0,0, /* offset align reloc nreloc */
+ 0|0x400); /* flag - some instructions */
+
+ w = datsize+bsssize;
+ machseg("__DATA",
+ va+v, /* vaddr */
+ w, /* vsize */
+ v,datsize, /* fileoffset filesize */
+ 7,3, /* protects */
+ 2,0); /* sections flags */
+ machsect("__data", "__DATA",
+ va+v,datsize, /* addr size */
+ v,0,0,0, /* offset align reloc nreloc */
+ 0); /* flag */
+ machsect("__bss", "__DATA",
+ va+v+datsize,bsssize, /* addr size */
+ 0,0,0,0, /* offset align reloc nreloc */
+ 1); /* flag - zero fill */
+ machstack(va+HEADR);
+ break;
+ }
+ cflush();
+}
+
+void
+cflush(void)
+{
+ int n;
+
+ n = sizeof(buf.cbuf) - cbc;
+ if(n)
+ write(cout, buf.cbuf, n);
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+}
+
+void
+outa(int n, uchar *cast, uchar *map, vlong l)
+{
+ int i, j;
+
+ Bprint(&bso, pcstr, l);
+ for(i=0; i<n; i++) {
+ j = i;
+ if(map != nil)
+ j = map[j];
+ Bprint(&bso, "%.2ux", cast[j]);
+ }
+ for(; i<Maxand; i++)
+ Bprint(&bso, " ");
+ Bprint(&bso, "%P\n", curp);
+}
+
+void
+datblk(long s, long n)
+{
+ Prog *p;
+ uchar *cast;
+ long l, fl, j;
+ vlong o;
+ int i, c;
+
+ memset(buf.dbuf, 0, n+Dbufslop);
+ for(p = datap; p != P; p = p->link) {
+ curp = p;
+ l = p->from.sym->value + p->from.offset - s;
+ c = p->from.scale;
+ i = 0;
+ if(l < 0) {
+ if(l+c <= 0)
+ continue;
+ while(l < 0) {
+ l++;
+ i++;
+ }
+ }
+ if(l >= n)
+ continue;
+ if(p->as != AINIT && p->as != ADYNT) {
+ for(j=l+(c-i)-1; j>=l; j--)
+ if(buf.dbuf[j]) {
+ print("%P\n", p);
+ diag("multiple initialization");
+ break;
+ }
+ }
+
+ switch(p->to.type) {
+ case D_FCONST:
+ switch(c) {
+ default:
+ case 4:
+ fl = ieeedtof(&p->to.ieee);
+ cast = (uchar*)&fl;
+ if(debug['a'] && i == 0)
+ outa(c, cast, fnuxi4, l+s+INITDAT);
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi4[i]];
+ l++;
+ }
+ break;
+ case 8:
+ cast = (uchar*)&p->to.ieee;
+ if(debug['a'] && i == 0)
+ outa(c, cast, fnuxi8, l+s+INITDAT);
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ if(debug['a'] && i == 0)
+ outa(c, (uchar*)p->to.scon, nil, l+s+INITDAT);
+ for(; i<c; i++) {
+ buf.dbuf[l] = p->to.scon[i];
+ l++;
+ }
+ break;
+ default:
+ o = p->to.offset;
+ if(p->to.type == D_ADDR) {
+ if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
+ diag("DADDR type%P", p);
+ if(p->to.sym) {
+ if(p->to.sym->type == SUNDEF)
+ ckoff(p->to.sym, o);
+ o += p->to.sym->value;
+ if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
+ o += INITDAT;
+ if(dlm)
+ dynreloc(p->to.sym, l+s+INITDAT, 1);
+ }
+ }
+ fl = o;
+ cast = (uchar*)&fl;
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P", c, i, curp);
+ break;
+ case 1:
+ if(debug['a'] && i == 0)
+ outa(c, cast, inuxi1, l+s+INITDAT);
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi1[i]];
+ l++;
+ }
+ break;
+ case 2:
+ if(debug['a'] && i == 0)
+ outa(c, cast, inuxi2, l+s+INITDAT);
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi2[i]];
+ l++;
+ }
+ break;
+ case 4:
+ if(debug['a'] && i == 0)
+ outa(c, cast, inuxi4, l+s+INITDAT);
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi4[i]];
+ l++;
+ }
+ break;
+ case 8:
+ cast = (uchar*)&o;
+ if(debug['a'] && i == 0)
+ outa(c, cast, inuxi8, l+s+INITDAT);
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ write(cout, buf.dbuf, n);
+}
+
+vlong
+rnd(vlong v, vlong r)
+{
+ vlong c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
+
+void
+vputl(vlong v)
+{
+ lputl(v);
+ lputl(v>>32);
+}
+
+void
+machseg(char *name, vlong vaddr, vlong vsize, vlong foff, vlong fsize,
+ ulong prot1, ulong prot2, ulong nsect, ulong flag)
+{
+ lputl(25); // section
+ lputl(72 + 80*nsect);
+ strnput(name, 16);
+ vputl(vaddr);
+ vputl(vsize);
+ vputl(foff);
+ vputl(fsize);
+ lputl(prot1);
+ lputl(prot2);
+ lputl(nsect);
+ lputl(flag);
+}
+
+void
+machsect(char *name, char *seg, vlong addr, vlong size, ulong off,
+ ulong align, ulong reloc, ulong nreloc, ulong flag)
+{
+ strnput(name, 16);
+ strnput(seg, 16);
+ vputl(addr);
+ vputl(size);
+ lputl(off);
+ lputl(align);
+ lputl(reloc);
+ lputl(nreloc);
+ lputl(flag);
+ lputl(0); /* reserved */
+ lputl(0); /* reserved */
+ lputl(0); /* reserved */
+}
+
+void
+machstack(vlong e)
+{
+ int i;
+
+ lputl(5); /* unix thread */
+ lputl((42+4)*4); /* total byte count */
+
+ lputl(4); /* thread type */
+ lputl(42); /* word count */
+
+ for(i=0; i<32; i++)
+ lputl(0);
+ vputl(e);
+ for(i=0; i<8; i++)
+ lputl(0);
+}
+
+ulong
+machheadr(void)
+{
+ ulong a;
+
+ a = 8; /* a.out header */
+ a += 18; /* page zero seg */
+ a += 18; /* text seg */
+ a += 20; /* text sect */
+ a += 18; /* data seg */
+ a += 20; /* data sect */
+ a += 20; /* bss sect */
+ a += 46; /* stack sect */
+
+ return a*4;
+}
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
new file mode 100644
index 0000000..137474b
--- /dev/null
+++ b/src/cmd/6l/l.h
@@ -0,0 +1,430 @@
+// Inferno utils/6l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "../6l/6.out.h"
+#include "compat.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define TNAME (curtext?curtext->from.sym->name:noname)
+#define cput(c)\
+ { *cbp++ = c;\
+ if(--cbc <= 0)\
+ cflush(); }
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Sym Sym;
+typedef struct Auto Auto;
+typedef struct Optab Optab;
+typedef struct Movtab Movtab;
+
+struct Adr
+{
+ union
+ {
+ vlong u0offset;
+ char u0scon[8];
+ Prog *u0cond; /* not used, but should be D_BRANCH */
+ Ieee u0ieee;
+ } u0;
+ union
+ {
+ Auto* u1autom;
+ Sym* u1sym;
+ } u1;
+ short type;
+ char index;
+ char scale;
+};
+
+#define offset u0.u0offset
+#define scon u0.u0scon
+#define cond u0.u0cond
+#define ieee u0.u0ieee
+
+#define autom u1.u1autom
+#define sym u1.u1sym
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog *forwd;
+ Prog* link;
+ Prog* pcond; /* work on this */
+ vlong pc;
+ long line;
+ uchar mark; /* work on these */
+ uchar back;
+
+ short as;
+ char width; /* fake for DATA */
+ char mode; /* 16, 32, or 64 */
+};
+struct Auto
+{
+ Sym* asym;
+ Auto* link;
+ long aoffset;
+ short type;
+};
+struct Sym
+{
+ char *name;
+ short type;
+ short version;
+ short become;
+ short frame;
+ uchar subtype;
+ ushort file;
+ vlong value;
+ long sig;
+ Sym* link;
+};
+struct Optab
+{
+ short as;
+ uchar* ytab;
+ uchar prefix;
+ uchar op[20];
+};
+struct Movtab
+{
+ short as;
+ uchar ft;
+ uchar tt;
+ uchar code;
+ uchar op[4];
+};
+
+enum
+{
+ STEXT = 1,
+ SDATA,
+ SBSS,
+ SDATA1,
+ SXREF,
+ SFILE,
+ SCONST,
+ SUNDEF,
+
+ SIMPORT,
+ SEXPORT,
+
+ NHASH = 10007,
+ NHUNK = 100000,
+ MINSIZ = 8,
+ STRINGSZ = 200,
+ MINLC = 1,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+
+ Yxxx = 0,
+ Ynone,
+ Yi0,
+ Yi1,
+ Yi8,
+ Ys32,
+ Yi32,
+ Yi64,
+ Yiauto,
+ Yal,
+ Ycl,
+ Yax,
+ Ycx,
+ Yrb,
+ Yrl,
+ Yrf,
+ Yf0,
+ Yrx,
+ Ymb,
+ Yml,
+ Ym,
+ Ybr,
+ Ycol,
+
+ Ycs, Yss, Yds, Yes, Yfs, Ygs,
+ Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
+ Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ycr8,
+ Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
+ Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64,
+ Ymr, Ymm,
+ Yxr, Yxm,
+ Ymax,
+
+ Zxxx = 0,
+
+ Zlit,
+ Z_rp,
+ Zbr,
+ Zcall,
+ Zib_,
+ Zib_rp,
+ Zibo_m,
+ Zibo_m_xm,
+ Zil_,
+ Zil_rp,
+ Ziq_rp,
+ Zilo_m,
+ Ziqo_m,
+ Zjmp,
+ Zloop,
+ Zo_iw,
+ Zm_o,
+ Zm_r,
+ Zm_r_xm,
+ Zm_r_i_xm,
+ Zm_r_3d,
+ Zm_r_xm_nr,
+ Zr_m_xm_nr,
+ Zibm_r, /* mmx1,mmx2/mem64,imm8 */
+ Zmb_r,
+ Zaut_r,
+ Zo_m,
+ Zo_m64,
+ Zpseudo,
+ Zr_m,
+ Zr_m_xm,
+ Zr_m_i_xm,
+ Zrp_,
+ Z_ib,
+ Z_il,
+ Zm_ibo,
+ Zm_ilo,
+ Zib_rr,
+ Zil_rr,
+ Zclr,
+ Zbyte,
+ Zmax,
+
+ Px = 0,
+ P32 = 0x32, /* 32-bit only */
+ Pe = 0x66, /* operand escape */
+ Pm = 0x0f, /* 2byte opcode escape */
+ Pq = 0xff, /* both escape */
+ Pb = 0xfe, /* byte operands */
+ Pf2 = 0xf2, /* xmm escape 1 */
+ Pf3 = 0xf3, /* xmm escape 2 */
+ Pw = 0x48, /* Rex.w */
+ Py = 0x80, /* defaults to 64-bit mode */
+
+ Rxf = 1<<9, /* internal flag for Rxr on from */
+ Rxt = 1<<8, /* internal flag for Rxr on to */
+ Rxw = 1<<3, /* =1, 64-bit operand size */
+ Rxr = 1<<2, /* extend modrm reg */
+ Rxx = 1<<1, /* extend sib index */
+ Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */
+
+ Roffset = 22, /* no. bits for offset in relocation address */
+ Rindex = 10, /* no. bits for index in relocation address */
+ Maxand = 10, /* in -a output width of the byte codes */
+};
+
+EXTERN union
+{
+ struct
+ {
+ char obuf[MAXIO]; /* output buffer */
+ uchar ibuf[MAXIO]; /* input buffer */
+ } u;
+ char dbuf[1];
+} buf;
+
+#define cbuf u.obuf
+#define xbuf u.ibuf
+
+#pragma varargck type "A" uint
+#pragma varargck type "D" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "S" char*
+
+EXTERN long HEADR;
+EXTERN long HEADTYPE;
+EXTERN vlong INITDAT;
+EXTERN long INITRND;
+EXTERN vlong INITTEXT;
+EXTERN char* INITENTRY; /* entry point */
+EXTERN Biobuf bso;
+EXTERN long bsssize;
+EXTERN int cbc;
+EXTERN char* cbp;
+EXTERN char* pcstr;
+EXTERN int cout;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Prog* curtext;
+EXTERN Prog* datap;
+EXTERN Prog* edatap;
+EXTERN vlong datsize;
+EXTERN char debug[128];
+EXTERN char literal[32];
+EXTERN Prog* etextp;
+EXTERN Prog* firstp;
+EXTERN uchar fnuxi8[8];
+EXTERN uchar fnuxi4[4];
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* histfrog[MAXHIST];
+EXTERN int histfrogp;
+EXTERN int histgen;
+EXTERN char* library[50];
+EXTERN char* libraryobj[50];
+EXTERN int libraryp;
+EXTERN int xrefresolv;
+EXTERN char* hunk;
+EXTERN uchar inuxi1[1];
+EXTERN uchar inuxi2[2];
+EXTERN uchar inuxi4[4];
+EXTERN uchar inuxi8[8];
+EXTERN char ycover[Ymax*Ymax];
+EXTERN uchar* andptr;
+EXTERN uchar* rexptr;
+EXTERN uchar and[30];
+EXTERN int reg[D_NONE];
+EXTERN int regrex[D_NONE+1];
+EXTERN Prog* lastp;
+EXTERN long lcsize;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN long nsymbol;
+EXTERN char* noname;
+EXTERN char* outfile;
+EXTERN vlong pc;
+EXTERN long spsize;
+EXTERN Sym* symlist;
+EXTERN long symsize;
+EXTERN Prog* textp;
+EXTERN vlong textsize;
+EXTERN long thunk;
+EXTERN int version;
+EXTERN Prog zprg;
+EXTERN int dtype;
+EXTERN char* paramspace;
+
+EXTERN Adr* reloca;
+EXTERN int doexp, dlm;
+EXTERN int imports, nimports;
+EXTERN int exports, nexports;
+EXTERN char* EXPTAB;
+EXTERN Prog undefp;
+
+#define UP (&undefp)
+
+extern Optab optab[];
+extern Optab* opindex[];
+extern char* anames[];
+
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Pconv(Fmt*);
+int Rconv(Fmt*);
+int Sconv(Fmt*);
+void addhist(long, int);
+Prog* appendp(Prog*);
+void asmb(void);
+void asmdyn(void);
+void asmins(Prog*);
+void asmlc(void);
+void asmsp(void);
+void asmsym(void);
+vlong atolwhex(char*);
+Prog* brchain(Prog*);
+Prog* brloop(Prog*);
+void buildop(void);
+void cflush(void);
+void ckoff(Sym*, long);
+Prog* copyp(Prog*);
+double cputime(void);
+void datblk(long, long);
+void diag(char*, ...);
+void dodata(void);
+void doinit(void);
+void doprof1(void);
+void doprof2(void);
+void dostkoff(void);
+void dynreloc(Sym*, ulong, int);
+vlong entryvalue(void);
+void errorexit(void);
+void export(void);
+int find1(long, int);
+int find2(long, int);
+void follow(void);
+void gethunk(void);
+void histtoauto(void);
+double ieeedtod(Ieee*);
+long ieeedtof(Ieee*);
+void import(void);
+void ldobj(int, long, char*);
+void loadlib(void);
+void listinit(void);
+Sym* lookup(char*, int);
+void lput(long);
+void lputl(long);
+void main(int, char*[]);
+void mkfwd(void);
+void* mysbrk(ulong);
+void nuxiinit(void);
+void objfile(char*);
+int opsize(Prog*);
+void patch(void);
+Prog* prg(void);
+void readundefs(char*, int);
+int relinv(int);
+long reuse(Prog*, Sym*);
+vlong rnd(vlong, vlong);
+void span(void);
+void undef(void);
+void undefsym(Sym*);
+vlong vaddr(Adr*);
+void wput(ushort);
+void xdefine(char*, int, vlong);
+void xfol(Prog*);
+int zaddr(uchar*, Adr*, Sym*[]);
+void zerosig(char*);
+
+void machseg(char*, vlong, vlong, vlong, vlong, ulong, ulong, ulong, ulong);
+void machsect(char*, char*, vlong, vlong, ulong, ulong, ulong, ulong, ulong);
+void machstack(vlong);
+ulong machheadr(void);
+
+#pragma varargck type "D" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "A" int
+#pragma varargck argpos diag 1
diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c
new file mode 100644
index 0000000..3af0192
--- /dev/null
+++ b/src/cmd/6l/list.c
@@ -0,0 +1,397 @@
+// Inferno utils/6l/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/list.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "l.h"
+
+static Prog* bigP;
+
+void
+listinit(void)
+{
+
+ fmtinstall('R', Rconv);
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('P', Pconv);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], str1[STRINGSZ];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ bigP = p;
+
+ sprint(str1, "(%ld)", p->line);
+ switch(p->as) {
+ case ATEXT:
+ if(p->from.scale) {
+ sprint(str, "%-7s %-7A %D,%d,%D",
+ str1, p->as, &p->from, p->from.scale, &p->to);
+ break;
+ }
+
+ default:
+ sprint(str, "%-7s %-7A %D,%D",
+ str1, p->as, &p->from, &p->to);
+ break;
+
+ case ADATA:
+ case AINIT:
+ case ADYNT:
+ sprint(str, "%-7s %-7A %D/%d,%D",
+ str1, p->as, &p->from, p->from.scale, &p->to);
+ break;
+ }
+ bigP = P;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[i]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[40], s[20];
+ Adr *a;
+ int i;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->type;
+ if(i >= D_INDIR) {
+ if(a->offset)
+ sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
+ else
+ sprint(str, "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ if(a->offset)
+ sprint(str, "$%lld,%R", a->offset, i);
+ else
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ if(bigP != P && bigP->pcond != P)
+ if(a->sym != S)
+ sprint(str, "%llux+%s", bigP->pcond->pc,
+ a->sym->name);
+ else
+ sprint(str, "%llux", bigP->pcond->pc);
+ else
+ sprint(str, "%lld(PC)", a->offset);
+ break;
+
+ case D_EXTERN:
+ if(a->sym) {
+ sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
+ break;
+ }
+ sprint(str, "!!noname!!+%lld(SB)", a->offset);
+ break;
+
+ case D_STATIC:
+ if(a->sym) {
+ sprint(str, "%s<%d>+%lld(SB)", a->sym->name,
+ a->sym->version, a->offset);
+ break;
+ }
+ sprint(str, "!!noname!!<999>+%lld(SB)", a->offset);
+ break;
+
+ case D_AUTO:
+ if(a->sym) {
+ sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
+ break;
+ }
+ sprint(str, "!!noname!!+%lld(SP)", a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym) {
+ sprint(str, "%s+%lld(%s)", a->sym->name, a->offset, paramspace);
+ break;
+ }
+ sprint(str, "!!noname!!+%lld(%s)", a->offset, paramspace);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%lld", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->scon);
+ break;
+
+ case D_ADDR:
+ a->type = a->index;
+ a->index = D_NONE;
+ sprint(str, "$%D", a);
+ a->index = a->type;
+ a->type = D_ADDR;
+ goto conv;
+ }
+brk:
+ if(a->index != D_NONE) {
+ sprint(s, "(%R*%d)", a->index, a->scale);
+ strcat(str, s);
+ }
+conv:
+ return fmtstrcpy(fp, str);
+}
+
+char* regstr[] =
+{
+ "AL", /* [D_AL] */
+ "CL",
+ "DL",
+ "BL",
+ "SPB",
+ "BPB",
+ "SIB",
+ "DIB",
+ "R8B",
+ "R9B",
+ "R10B",
+ "R11B",
+ "R12B",
+ "R13B",
+ "R14B",
+ "R15B",
+
+ "AX", /* [D_AX] */
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+ "R8",
+ "R9",
+ "R10",
+ "R11",
+ "R12",
+ "R13",
+ "R14",
+ "R15",
+
+ "AH",
+ "CH",
+ "DH",
+ "BH",
+
+ "F0", /* [D_F0] */
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "M0",
+ "M1",
+ "M2",
+ "M3",
+ "M4",
+ "M5",
+ "M6",
+ "M7",
+
+ "X0",
+ "X1",
+ "X2",
+ "X3",
+ "X4",
+ "X5",
+ "X6",
+ "X7",
+ "X8",
+ "X9",
+ "X10",
+ "X11",
+ "X12",
+ "X13",
+ "X14",
+ "X15",
+
+ "CS", /* [D_CS] */
+ "SS",
+ "DS",
+ "ES",
+ "FS",
+ "GS",
+
+ "GDTR", /* [D_GDTR] */
+ "IDTR", /* [D_IDTR] */
+ "LDTR", /* [D_LDTR] */
+ "MSW", /* [D_MSW] */
+ "TASK", /* [D_TASK] */
+
+ "CR0", /* [D_CR] */
+ "CR1",
+ "CR2",
+ "CR3",
+ "CR4",
+ "CR5",
+ "CR6",
+ "CR7",
+ "CR8",
+ "CR9",
+ "CR10",
+ "CR11",
+ "CR12",
+ "CR13",
+ "CR14",
+ "CR15",
+
+ "DR0", /* [D_DR] */
+ "DR1",
+ "DR2",
+ "DR3",
+ "DR4",
+ "DR5",
+ "DR6",
+ "DR7",
+
+ "TR0", /* [D_TR] */
+ "TR1",
+ "TR2",
+ "TR3",
+ "TR4",
+ "TR5",
+ "TR6",
+ "TR7",
+
+ "NONE", /* [D_NONE] */
+};
+
+int
+Rconv(Fmt *fp)
+{
+ char str[20];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_AL && r <= D_NONE)
+ sprint(str, "%s", regstr[r-D_AL]);
+ else
+ sprint(str, "gok(%d)", r);
+
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[30], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+void
+diag(char *fmt, ...)
+{
+ char buf[STRINGSZ], *tn;
+ va_list arg;
+
+ tn = "??none??";
+ if(curtext != P && curtext->from.sym != S)
+ tn = curtext->from.sym->name;
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%s: %s\n", tn, buf);
+
+ nerrors++;
+ if(nerrors > 20) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
diff --git a/src/cmd/6l/mkenam b/src/cmd/6l/mkenam
new file mode 100644
index 0000000..fc91828
--- /dev/null
+++ b/src/cmd/6l/mkenam
@@ -0,0 +1,45 @@
+# Inferno utils/6c/mkenam
+# http://code.google.com/p/inferno-os/source/browse/utils/6c/mkenam
+#
+# Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+# Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+# Portions Copyright © 1997-1999 Vita Nuova Limited
+# Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+# Portions Copyright © 2004,2006 Bruce Ellis
+# Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+# Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+# Portions Copyright © 2009 The Go Authors. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+ed - ../6l/6.out.h <<'!'
+v/^ A/d
+,s/^ A/ "/
+g/ .*$/s///
+,s/,*$/",/
+1i
+char* anames[] =
+{
+.
+$a
+};
+.
+w enam.c
+Q
+!
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
new file mode 100644
index 0000000..55dcaac
--- /dev/null
+++ b/src/cmd/6l/obj.c
@@ -0,0 +1,1595 @@
+// Inferno utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#define EXTERN
+#include "l.h"
+#include <ar.h>
+
+#ifndef DEFAULT
+#define DEFAULT '9'
+#endif
+
+char *noname = "<none>";
+char symname[] = SYMDEF;
+char thechar = '6';
+char *thestring = "amd64";
+char *paramspace = "FP";
+
+/*
+ * -H2 -T4136 -R4096 is plan9 64-bit format
+ * -H3 -T4128 -R4096 is plan9 32-bit format
+ * -H5 -T0x80110000 -R4096 is ELF32
+ * -H6 -Tx -Rx is apple MH-exec
+ *
+ * options used: 189BLQSWabcjlnpsvz
+ */
+
+static int
+isobjfile(char *f)
+{
+ int n, v;
+ Biobuf *b;
+ char buf1[5], buf2[SARMAG];
+
+ b = Bopen(f, OREAD);
+ if(b == nil)
+ return 0;
+ n = Bread(b, buf1, 5);
+ if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
+ v = 1; /* good enough for our purposes */
+ else{
+ Bseek(b, 0, 0);
+ n = Bread(b, buf2, SARMAG);
+ v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
+ }
+ Bterm(b);
+ return v;
+}
+
+void
+main(int argc, char *argv[])
+{
+ int i, c;
+ char *a;
+
+ Binit(&bso, 1, OWRITE);
+ cout = -1;
+ listinit();
+ memset(debug, 0, sizeof(debug));
+ nerrors = 0;
+ outfile = "6.out";
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+HEADTYPE = 6; // botch
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o': /* output to (next arg) */
+ outfile = ARGF();
+ break;
+ case 'E':
+ a = ARGF();
+ if(a)
+ INITENTRY = a;
+ break;
+ case 'H':
+ a = ARGF();
+ if(a)
+ HEADTYPE = atolwhex(a);
+ break;
+ case 'T':
+ a = ARGF();
+ if(a)
+ INITTEXT = atolwhex(a);
+ break;
+ case 'D':
+ a = ARGF();
+ if(a)
+ INITDAT = atolwhex(a);
+ break;
+ case 'R':
+ a = ARGF();
+ if(a)
+ INITRND = atolwhex(a);
+ break;
+ case 'x': /* produce export table */
+ doexp = 1;
+ if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
+ readundefs(ARGF(), SEXPORT);
+ break;
+ case 'u': /* produce dynamically loadable module */
+ dlm = 1;
+ debug['l']++;
+ if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
+ readundefs(ARGF(), SIMPORT);
+ break;
+ } ARGEND
+ USED(argc);
+ if(*argv == 0) {
+ diag("usage: 6l [-options] objects");
+ errorexit();
+ }
+ if(!debug['9'] && !debug['U'] && !debug['B'])
+ debug[DEFAULT] = 1;
+ if(HEADTYPE == -1) {
+ if(debug['B'])
+ HEADTYPE = 2;
+ if(debug['9'])
+ HEADTYPE = 2;
+ }
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option");
+ errorexit();
+ case 2: /* plan 9 */
+ HEADR = 32L+8L;
+ if(INITTEXT == -1)
+ INITTEXT = 4096+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case 3: /* plan 9 */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 4096+32;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case 5: /* elf32 executable */
+ HEADR = rnd(52L+3*32L, 16);
+ if(INITTEXT == -1)
+ INITTEXT = 0x80110000L;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case 6: /* apple MACH */
+ HEADR = machheadr();
+ if(INITTEXT == -1)
+ INITTEXT = 4096+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%llux is ignored because of -R0x%lux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H%ld -T0x%llux -D0x%llux -R0x%lux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ for(i=1; optab[i].as; i++) {
+ c = optab[i].as;
+ if(opindex[c] != nil) {
+ diag("phase error in optab: %d (%A)", i, c);
+ errorexit();
+ }
+ opindex[c] = &optab[i];
+ }
+
+ for(i=0; i<Ymax; i++)
+ ycover[i*Ymax + i] = 1;
+
+ ycover[Yi0*Ymax + Yi8] = 1;
+ ycover[Yi1*Ymax + Yi8] = 1;
+
+ ycover[Yi0*Ymax + Ys32] = 1;
+ ycover[Yi1*Ymax + Ys32] = 1;
+ ycover[Yi8*Ymax + Ys32] = 1;
+
+ ycover[Yi0*Ymax + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 1;
+ ycover[Ys32*Ymax + Yi32] = 1;
+
+ ycover[Yi0*Ymax + Yi64] = 1;
+ ycover[Yi1*Ymax + Yi64] = 1;
+ ycover[Yi8*Ymax + Yi64] = 1;
+ ycover[Ys32*Ymax + Yi64] = 1;
+ ycover[Yi32*Ymax + Yi64] = 1;
+
+ ycover[Yal*Ymax + Yrb] = 1;
+ ycover[Ycl*Ymax + Yrb] = 1;
+ ycover[Yax*Ymax + Yrb] = 1;
+ ycover[Ycx*Ymax + Yrb] = 1;
+ ycover[Yrx*Ymax + Yrb] = 1;
+ ycover[Yrl*Ymax + Yrb] = 1;
+
+ ycover[Ycl*Ymax + Ycx] = 1;
+
+ ycover[Yax*Ymax + Yrx] = 1;
+ ycover[Ycx*Ymax + Yrx] = 1;
+
+ ycover[Yax*Ymax + Yrl] = 1;
+ ycover[Ycx*Ymax + Yrl] = 1;
+ ycover[Yrx*Ymax + Yrl] = 1;
+
+ ycover[Yf0*Ymax + Yrf] = 1;
+
+ ycover[Yal*Ymax + Ymb] = 1;
+ ycover[Ycl*Ymax + Ymb] = 1;
+ ycover[Yax*Ymax + Ymb] = 1;
+ ycover[Ycx*Ymax + Ymb] = 1;
+ ycover[Yrx*Ymax + Ymb] = 1;
+ ycover[Yrb*Ymax + Ymb] = 1;
+ ycover[Yrl*Ymax + Ymb] = 1;
+ ycover[Ym*Ymax + Ymb] = 1;
+
+ ycover[Yax*Ymax + Yml] = 1;
+ ycover[Ycx*Ymax + Yml] = 1;
+ ycover[Yrx*Ymax + Yml] = 1;
+ ycover[Yrl*Ymax + Yml] = 1;
+ ycover[Ym*Ymax + Yml] = 1;
+
+ ycover[Yax*Ymax + Ymm] = 1;
+ ycover[Ycx*Ymax + Ymm] = 1;
+ ycover[Yrx*Ymax + Ymm] = 1;
+ ycover[Yrl*Ymax + Ymm] = 1;
+ ycover[Ym*Ymax + Ymm] = 1;
+ ycover[Ymr*Ymax + Ymm] = 1;
+
+ ycover[Yax*Ymax + Yxm] = 1;
+ ycover[Ycx*Ymax + Yxm] = 1;
+ ycover[Yrx*Ymax + Yxm] = 1;
+ ycover[Yrl*Ymax + Yxm] = 1;
+ ycover[Ym*Ymax + Yxm] = 1;
+ ycover[Yxr*Ymax + Yxm] = 1;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_R15B) {
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_SPB && i <= D_DIB)
+ regrex[i] = 0x40;
+ if(i >= D_R8B && i <= D_R15B)
+ regrex[i] = Rxr | Rxx | Rxb;
+ }
+ if(i >= D_AH && i<= D_BH)
+ reg[i] = 4 + ((i-D_AH) & 7);
+ if(i >= D_AX && i <= D_R15) {
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_R8)
+ regrex[i] = Rxr | Rxx | Rxb;
+ }
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
+ if(i >= D_M0 && i <= D_M0+7)
+ reg[i] = (i-D_M0) & 7;
+ if(i >= D_X0 && i <= D_X0+15) {
+ reg[i] = (i-D_X0) & 7;
+ if(i >= D_X0+8)
+ regrex[i] = Rxr | Rxx | Rxb;
+ }
+ if(i >= D_CR+8 && i <= D_CR+15)
+ regrex[i] = Rxr;
+ }
+
+ zprg.link = P;
+ zprg.pcond = P;
+ zprg.back = 2;
+ zprg.as = AGOK;
+ zprg.from.type = D_NONE;
+ zprg.from.index = D_NONE;
+ zprg.from.scale = 1;
+ zprg.to = zprg.from;
+ zprg.mode = 64;
+
+ pcstr = "%.6llux ";
+ nuxiinit();
+ histgen = 0;
+ textp = P;
+ datap = P;
+ edatap = P;
+ pc = 0;
+ dtype = 4;
+ cout = create(outfile, 1, 0775);
+ if(cout < 0) {
+ diag("cannot create %s", outfile);
+ errorexit();
+ }
+ version = 0;
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+ firstp = prg();
+ lastp = firstp;
+
+ if(INITENTRY == 0) {
+ INITENTRY = "_main";
+ if(debug['p'])
+ INITENTRY = "_mainp";
+ if(!debug['l'])
+ lookup(INITENTRY, 0)->type = SXREF;
+ } else if(!(*INITENTRY >= '0' && *INITENTRY <= '9'))
+ lookup(INITENTRY, 0)->type = SXREF;
+
+ while(*argv)
+ objfile(*argv++);
+ if(!debug['l'])
+ loadlib();
+ firstp = firstp->link;
+ if(firstp == P)
+ errorexit();
+ if(doexp || dlm){
+ EXPTAB = "_exporttab";
+ zerosig(EXPTAB);
+ zerosig("etext");
+ zerosig("edata");
+ zerosig("end");
+ if(dlm){
+ import();
+ HEADTYPE = 2;
+ INITTEXT = 0;
+ INITDAT = 0;
+ INITRND = 8;
+ INITENTRY = EXPTAB;
+ }
+ export();
+ }
+ patch();
+ follow();
+ dodata();
+ dostkoff();
+ paramspace = "SP"; /* (FP) now (SP) on output */
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ span();
+ doinit();
+ asmb();
+ undef();
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%ld symbols\n", nsymbol);
+ Bprint(&bso, "%ld memory used\n", thunk);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ Bflush(&bso);
+
+ errorexit();
+}
+
+void
+loadlib(void)
+{
+ int i;
+ long h;
+ Sym *s;
+
+loop:
+ xrefresolv = 0;
+ for(i=0; i<libraryp; i++) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
+ objfile(library[i]);
+ }
+ if(xrefresolv)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == SXREF)
+ goto loop;
+}
+
+void
+errorexit(void)
+{
+
+ if(nerrors) {
+ if(cout >= 0)
+ remove(outfile);
+ exits("error");
+ }
+ exits(0);
+}
+
+void
+objfile(char *file)
+{
+ long off, esym, cnt, l;
+ int f, work;
+ Sym *s;
+ char magbuf[SARMAG];
+ char name[100], pname[150];
+ struct ar_hdr arhdr;
+ char *e, *start, *stop;
+
+ if(file[0] == '-' && file[1] == 'l') {
+ if(debug['9'])
+ sprint(name, "/%s/lib/lib", thestring);
+ else
+ sprint(name, "/usr/%clib/lib", thechar);
+ strcat(name, file+2);
+ strcat(name, ".a");
+ file = name;
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
+ Bflush(&bso);
+ f = open(file, 0);
+ if(f < 0) {
+ diag("cannot open file: %s", file);
+ errorexit();
+ }
+ l = read(f, magbuf, SARMAG);
+ if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+ /* load it as a regular file */
+ l = seek(f, 0L, 2);
+ seek(f, 0L, 0);
+ ldobj(f, l, file);
+ close(f);
+ return;
+ }
+
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR) {
+ diag("%s: short read on archive file symbol header", file);
+ goto out;
+ }
+ if(strncmp(arhdr.name, symname, strlen(symname))) {
+ diag("%s: first entry not symbol header", file);
+ goto out;
+ }
+
+ esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
+ off = SARMAG + SAR_HDR;
+
+ /*
+ * just bang the whole symbol file into memory
+ */
+ seek(f, off, 0);
+ cnt = esym - off;
+ start = malloc(cnt + 10);
+ cnt = read(f, start, cnt);
+ if(cnt <= 0){
+ close(f);
+ return;
+ }
+ stop = &start[cnt];
+ memset(stop, 0, 10);
+
+ work = 1;
+ while(work) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
+ Bflush(&bso);
+ work = 0;
+ for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
+ s = lookup(e+5, 0);
+ if(s->type != SXREF)
+ continue;
+ sprint(pname, "%s(%s)", file, s->name);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
+ Bflush(&bso);
+ l = e[1] & 0xff;
+ l |= (e[2] & 0xff) << 8;
+ l |= (e[3] & 0xff) << 16;
+ l |= (e[4] & 0xff) << 24;
+ seek(f, l, 0);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR)
+ goto bad;
+ if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
+ goto bad;
+ l = atolwhex(arhdr.size);
+ ldobj(f, l, pname);
+ if(s->type == SXREF) {
+ diag("%s: failed to load: %s", file, s->name);
+ errorexit();
+ }
+ work = 1;
+ xrefresolv = 1;
+ }
+ }
+ return;
+
+bad:
+ diag("%s: bad or out of date archive", file);
+out:
+ close(f);
+}
+
+int
+zaddr(uchar *p, Adr *a, Sym *h[])
+{
+ int c, t, i;
+ long l;
+ Sym *s;
+ Auto *u;
+
+ t = p[0];
+ c = 1;
+ if(t & T_INDEX) {
+ a->index = p[c];
+ a->scale = p[c+1];
+ c += 2;
+ } else {
+ a->index = D_NONE;
+ a->scale = 0;
+ }
+ a->offset = 0;
+ if(t & T_OFFSET) {
+ /*
+ * Hack until Charles fixes the compiler.
+ a->offset = (long)(p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24));
+ */
+ l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+ a->offset = l;
+ c += 4;
+ if(t & T_64) {
+ l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+ a->offset = ((vlong)l<<32) | (a->offset & 0xFFFFFFFFUL);
+ c += 4;
+ }
+ }
+ a->sym = S;
+ if(t & T_SYM) {
+ a->sym = h[p[c]];
+ c++;
+ }
+ a->type = D_NONE;
+ if(t & T_FCONST) {
+ a->ieee.l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+ a->ieee.h = p[c+4] | (p[c+5]<<8) | (p[c+6]<<16) | (p[c+7]<<24);
+ c += 8;
+ a->type = D_FCONST;
+ } else
+ if(t & T_SCONST) {
+ for(i=0; i<NSNAME; i++)
+ a->scon[i] = p[c+i];
+ c += NSNAME;
+ a->type = D_SCONST;
+ }
+ if(t & T_TYPE) {
+ a->type = p[c];
+ c++;
+ }
+ s = a->sym;
+ if(s == S)
+ return c;
+
+ t = a->type;
+ if(t != D_AUTO && t != D_PARAM)
+ return c;
+ l = a->offset;
+ for(u=curauto; u; u=u->link) {
+ if(u->asym == s)
+ if(u->type == t) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ return c;
+ }
+ }
+
+ u = mal(sizeof(*u));
+ u->link = curauto;
+ curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = t;
+ return c;
+}
+
+void
+addlib(char *obj)
+{
+ char name[1024], comp[256], *p;
+ int i;
+
+ if(histfrogp <= 0)
+ return;
+
+ if(histfrog[0]->name[1] == '/') {
+ sprint(name, "");
+ i = 1;
+ } else
+ if(histfrog[0]->name[1] == '.') {
+ sprint(name, ".");
+ i = 0;
+ } else {
+ if(debug['9'])
+ sprint(name, "/%s/lib", thestring);
+ else
+ sprint(name, "/usr/%clib", thechar);
+ i = 0;
+ }
+
+ for(; i<histfrogp; i++) {
+ snprint(comp, sizeof comp, histfrog[i]->name+1);
+ for(;;) {
+ p = strstr(comp, "$O");
+ if(p == 0)
+ break;
+ memmove(p+1, p+2, strlen(p+2)+1);
+ p[0] = thechar;
+ }
+ for(;;) {
+ p = strstr(comp, "$M");
+ if(p == 0)
+ break;
+ if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
+ diag("library component too long");
+ return;
+ }
+ memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
+ memmove(p, thestring, strlen(thestring));
+ }
+ if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
+ diag("library component too long");
+ return;
+ }
+ strcat(name, "/");
+ strcat(name, comp);
+ }
+ for(i=0; i<libraryp; i++)
+ if(strcmp(name, library[i]) == 0)
+ return;
+ if(libraryp == nelem(library)){
+ diag("too many autolibs; skipping %s", name);
+ return;
+ }
+
+ p = malloc(strlen(name) + 1);
+ strcpy(p, name);
+ library[libraryp] = p;
+ p = malloc(strlen(obj) + 1);
+ strcpy(p, obj);
+ libraryobj[libraryp] = p;
+ libraryp++;
+}
+
+void
+addhist(long line, int type)
+{
+ Auto *u;
+ Sym *s;
+ int i, j, k;
+
+ u = malloc(sizeof(Auto));
+ s = malloc(sizeof(Sym));
+ s->name = malloc(2*(histfrogp+1) + 1);
+
+ u->asym = s;
+ u->type = type;
+ u->aoffset = line;
+ u->link = curhist;
+ curhist = u;
+
+ j = 1;
+ for(i=0; i<histfrogp; i++) {
+ k = histfrog[i]->value;
+ s->name[j+0] = k>>8;
+ s->name[j+1] = k;
+ j += 2;
+ }
+}
+
+void
+histtoauto(void)
+{
+ Auto *l;
+
+ while(l = curhist) {
+ curhist = l->link;
+ l->link = curauto;
+ curauto = l;
+ }
+}
+
+void
+collapsefrog(Sym *s)
+{
+ int i;
+
+ /*
+ * bad encoding of path components only allows
+ * MAXHIST components. if there is an overflow,
+ * first try to collapse xxx/..
+ */
+ for(i=1; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, "..") == 0) {
+ memmove(histfrog+i-1, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ histfrogp--;
+ goto out;
+ }
+
+ /*
+ * next try to collapse .
+ */
+ for(i=0; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, ".") == 0) {
+ memmove(histfrog+i, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ goto out;
+ }
+
+ /*
+ * last chance, just truncate from front
+ */
+ memmove(histfrog+0, histfrog+1,
+ (histfrogp-1)*sizeof(histfrog[0]));
+
+out:
+ histfrog[histfrogp-1] = s;
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+uchar*
+readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
+{
+ int n;
+
+ n = stop - good;
+ memmove(buf, good, stop - good);
+ stop = buf + n;
+ n = MAXIO - n;
+ if(n > max)
+ n = max;
+ n = read(f, stop, n);
+ if(n <= 0)
+ return 0;
+ return stop + n;
+}
+
+void
+ldobj(int f, long c, char *pn)
+{
+ vlong ipc;
+ Prog *p, *t;
+ uchar *bloc, *bsize, *stop;
+ int v, o, r, skip, mode;
+ Sym *h[NSYM], *s, *di;
+ ulong sig;
+ static int files;
+ static char **filen;
+ char **nfilen;
+
+ if((files&15) == 0){
+ nfilen = malloc((files+16)*sizeof(char*));
+ memmove(nfilen, filen, files*sizeof(char*));
+ free(filen);
+ filen = nfilen;
+ }
+ filen[files++] = strdup(pn);
+
+ di = S;
+
+ /* check the header */
+ bsize = readsome(f, buf.xbuf, buf.xbuf, buf.xbuf, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ r = bsize - bloc;
+ if(r < 7)
+ goto eof;
+ if(memcmp(bloc, "x86-64\n", 7) != 0) {
+ diag("file not x86-64: %s\n", pn);
+ return;
+ }
+
+hloop:
+ /* skip over exports */
+ while(bloc+3 <= bsize) {
+ if(bloc[0] == '\n' && bloc[1] == '!' && bloc[2] == '\n') {
+ bloc += 3;
+ c -= 3;
+ goto newloop;
+ }
+ bloc++;
+ c--;
+ }
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ r = bsize - bloc;
+ if(r < 3)
+ goto eof;
+ goto hloop;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ version++;
+ histfrogp = 0;
+ ipc = pc;
+ skip = 0;
+ mode = 64;
+
+loop:
+ if(c <= 0)
+ goto eof;
+ r = bsize - bloc;
+ if(r < 100 && r < c) { /* enough for largest prog */
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ goto loop;
+ }
+ o = bloc[0] | (bloc[1] << 8);
+ if(o <= AXXX || o >= ALAST) {
+ if(o < 0)
+ goto eof;
+ diag("%s: opcode out of range %d", pn, o);
+ print(" probably not a .6 file\n");
+ errorexit();
+ }
+
+ if(o == ANAME || o == ASIGNAME) {
+ sig = 0;
+ if(o == ASIGNAME) {
+ sig = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24);
+ bloc += 4;
+ c -= 4;
+ }
+ stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
+ if(stop == 0){
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
+ if(stop == 0){
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ }
+ v = bloc[2]; /* type */
+ o = bloc[3]; /* sym */
+ bloc += 4;
+ c -= 4;
+
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ s = lookup((char*)bloc, r);
+ c -= &stop[1] - bloc;
+ bloc = stop + 1;
+
+ if(debug['S'] && r == 0)
+ sig = 1729;
+ if(sig != 0){
+ if(s->sig != 0 && s->sig != sig)
+ diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name);
+ s->sig = sig;
+ s->file = files-1;
+ }
+
+ if(debug['W'])
+ print(" ANAME %s\n", s->name);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ }
+ goto loop;
+ }
+
+ p = mal(sizeof(*p));
+ p->as = o;
+ p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24);
+ p->back = 2;
+ p->mode = mode;
+ r = zaddr(bloc+6, &p->from, h) + 6;
+ r += zaddr(bloc+r, &p->to, h);
+ bloc += r;
+ c -= r;
+
+ if(debug['W'])
+ print("%P\n", p);
+
+ switch(p->as) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(curtext != P)
+ curtext->to.autom = curauto;
+ curauto = 0;
+ curtext = P;
+ if(c)
+ goto newloop;
+ return;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(s->type != SBSS) {
+ diag("%s: redefinition: %s in %s",
+ pn, s->name, TNAME);
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(p->to.offset > s->value)
+ s->value = p->to.offset;
+ goto loop;
+
+ case ADYNT:
+ if(p->to.sym == S) {
+ diag("DYNT without a sym\n%P", p);
+ break;
+ }
+ di = p->to.sym;
+ p->from.scale = 4;
+ if(di->type == SXREF) {
+ if(debug['z'])
+ Bprint(&bso, "%P set to %d\n", p, dtype);
+ di->type = SCONST;
+ di->value = dtype;
+ dtype += 4;
+ }
+ if(p->from.sym == S)
+ break;
+
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ if(curtext == P) {
+ diag("DYNT not in text: %P", p);
+ break;
+ }
+ p->to.sym = curtext->from.sym;
+ p->to.type = D_ADDR;
+ p->to.index = D_EXTERN;
+ goto data;
+
+ case AINIT:
+ if(p->from.sym == S) {
+ diag("INIT without a sym\n%P", p);
+ break;
+ }
+ if(di == S) {
+ diag("INIT without previous DYNT\n%P", p);
+ break;
+ }
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ goto data;
+
+ case ADATA:
+ data:
+ if(edatap == P)
+ datap = p;
+ else
+ edatap->link = p;
+ edatap = p;
+ p->link = P;
+ goto loop;
+
+ case AGOK:
+ diag("%s: GOK opcode in %s", pn, TNAME);
+ pc++;
+ goto loop;
+
+ case ATEXT:
+ if(curtext != P) {
+ histtoauto();
+ curtext->to.autom = curauto;
+ curauto = 0;
+ }
+ skip = 0;
+ curtext = p;
+ s = p->from.sym;
+ if(s == S) {
+ diag("%s: no TEXT symbol: %P", pn, p);
+ errorexit();
+ }
+ if(s->type != 0 && s->type != SXREF) {
+ if(p->from.scale & DUPOK) {
+ skip = 1;
+ goto casdef;
+ }
+ diag("%s: redefinition: %s\n%P", pn, s->name, p);
+ }
+ s->type = STEXT;
+ s->value = pc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ if(textp == P) {
+ textp = p;
+ etextp = p;
+ goto loop;
+ }
+ etextp->pcond = p;
+ etextp = p;
+ goto loop;
+
+ case AMODE:
+ if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){
+ switch((int)p->from.offset){
+ case 16: case 32: case 64:
+ mode = p->from.offset;
+ break;
+ }
+ }
+ goto loop;
+
+ case AFMOVF:
+ case AFADDF:
+ case AFSUBF:
+ case AFSUBRF:
+ case AFMULF:
+ case AFDIVF:
+ case AFDIVRF:
+ case AFCOMF:
+ case AFCOMFP:
+ case AMOVSS:
+ case AADDSS:
+ case ASUBSS:
+ case AMULSS:
+ case ADIVSS:
+ case ACOMISS:
+ case AUCOMISS:
+ if(skip)
+ goto casdef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 9 max */
+ sprint(literal, "$%lux", ieeedtof(&p->from.ieee));
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 4;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_EXTERN;
+ t->from.sym = s;
+ t->from.scale = 4;
+ t->to = p->from;
+ if(edatap == P)
+ datap = t;
+ else
+ edatap->link = t;
+ edatap = t;
+ t->link = P;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ case AFMOVD:
+ case AFADDD:
+ case AFSUBD:
+ case AFSUBRD:
+ case AFMULD:
+ case AFDIVD:
+ case AFDIVRD:
+ case AFCOMD:
+ case AFCOMDP:
+ case AMOVSD:
+ case AADDSD:
+ case ASUBSD:
+ case AMULSD:
+ case ADIVSD:
+ case ACOMISD:
+ case AUCOMISD:
+ if(skip)
+ goto casdef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 18 max */
+ sprint(literal, "$%lux.%lux",
+ p->from.ieee.l, p->from.ieee.h);
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 8;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_EXTERN;
+ t->from.sym = s;
+ t->from.scale = 8;
+ t->to = p->from;
+ if(edatap == P)
+ datap = t;
+ else
+ edatap->link = t;
+ edatap = t;
+ t->link = P;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ casdef:
+ default:
+ if(skip)
+ nopout(p);
+
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ goto loop;
+ }
+ goto loop;
+
+eof:
+ diag("truncated object file: %s", pn);
+}
+
+Sym*
+lookup(char *symb, int v)
+{
+ Sym *s;
+ char *p;
+ long h;
+ int l, c;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->version == v)
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+
+ s = mal(sizeof(*s));
+
+ s->name = malloc(l + 1);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ s->sig = 0;
+ hash[h] = s;
+ nsymbol++;
+ return s;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = mal(sizeof(*p));
+
+ *p = zprg;
+ return p;
+}
+
+Prog*
+copyp(Prog *q)
+{
+ Prog *p;
+
+ p = prg();
+ *p = *q;
+ return p;
+}
+
+Prog*
+appendp(Prog *q)
+{
+ Prog *p;
+
+ p = prg();
+ p->link = q->link;
+ q->link = p;
+ p->line = q->line;
+ p->mode = q->mode;
+ return p;
+}
+
+void
+doprof1(void)
+{
+ Sym *s;
+ long n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADDL;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->value = n*4;
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->from.sym == s2) {
+ p->from.scale = 1;
+ ps2 = p;
+ }
+ if(p->from.sym == s4) {
+ p->from.scale = 1;
+ ps4 = p;
+ }
+ }
+ }
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+
+ if(p->from.scale & NOPROF) { /* dont profile */
+ for(;;) {
+ q = p->link;
+ if(q == P)
+ break;
+ if(q->as == ATEXT)
+ break;
+ p = q;
+ }
+ continue;
+ }
+
+ /*
+ * JMPL profin
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = ps2;
+ p->to.sym = s2;
+
+ continue;
+ }
+ if(p->as == ARET) {
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * JAL profout
+ */
+ p->as = ACALL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->pcond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+
+ continue;
+ }
+ }
+}
+
+void
+nuxiinit(void)
+{
+ int i, c;
+
+ for(i=0; i<4; i++) {
+ c = find1(0x04030201L, i+1);
+ if(i < 2)
+ inuxi2[i] = c;
+ if(i < 1)
+ inuxi1[i] = c;
+ inuxi4[i] = c;
+ inuxi8[i] = c;
+ inuxi8[i+4] = c+4;
+ fnuxi4[i] = c;
+ fnuxi8[i] = c;
+ fnuxi8[i+4] = c+4;
+ }
+ if(debug['v']) {
+ Bprint(&bso, "inuxi = ");
+ for(i=0; i<1; i++)
+ Bprint(&bso, "%d", inuxi1[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<2; i++)
+ Bprint(&bso, "%d", inuxi2[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", inuxi4[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", inuxi8[i]);
+ Bprint(&bso, "\nfnuxi = ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", fnuxi4[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", fnuxi8[i]);
+ Bprint(&bso, "\n");
+ }
+ Bflush(&bso);
+}
+
+int
+find1(long l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+int
+find2(long l, int c)
+{
+ short *p;
+ int i;
+
+ p = (short*)&l;
+ for(i=0; i<4; i+=2) {
+ if(((*p >> 8) & 0xff) == c)
+ return i;
+ if((*p++ & 0xff) == c)
+ return i+1;
+ }
+ return 0;
+}
+
+long
+ieeedtof(Ieee *e)
+{
+ int exp;
+ long v;
+
+ if(e->h == 0)
+ return 0;
+ exp = (e->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ v = (e->h & 0xfffffL) << 3;
+ v |= (e->l >> 29) & 0x7L;
+ if((e->l >> 28) & 1) {
+ v++;
+ if(v & 0x800000L) {
+ v = (v & 0x7fffffL) >> 1;
+ exp++;
+ }
+ }
+ if(exp <= -126 || exp >= 130)
+ diag("double fp to single fp overflow");
+ v |= ((exp + 126) & 0xffL) << 23;
+ v |= e->h & 0x80000000L;
+ return v;
+}
+
+double
+ieeedtod(Ieee *ieeep)
+{
+ Ieee e;
+ double fr;
+ int exp;
+
+ if(ieeep->h & (1L<<31)) {
+ e.h = ieeep->h & ~(1L<<31);
+ e.l = ieeep->l;
+ return -ieeedtod(&e);
+ }
+ if(ieeep->l == 0 && ieeep->h == 0)
+ return 0;
+ fr = ieeep->l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ return ldexp(fr, exp);
+}
+
+void
+undefsym(Sym *s)
+{
+ int n;
+
+ n = imports;
+ if(s->value != 0)
+ diag("value != 0 on SXREF");
+ if(n >= 1<<Rindex)
+ diag("import index %d out of range", n);
+ s->value = n<<Roffset;
+ s->type = SUNDEF;
+ imports++;
+}
+
+void
+zerosig(char *sp)
+{
+ Sym *s;
+
+ s = lookup(sp, 0);
+ s->sig = 0;
+}
+
+void
+readundefs(char *f, int t)
+{
+ int i, n;
+ Sym *s;
+ Biobuf *b;
+ char *l, buf[256], *fields[64];
+
+ if(f == nil)
+ return;
+ b = Bopen(f, OREAD);
+ if(b == nil){
+ diag("could not open %s: %r", f);
+ errorexit();
+ }
+ while((l = Brdline(b, '\n')) != nil){
+ n = Blinelen(b);
+ if(n >= sizeof(buf)){
+ diag("%s: line too long", f);
+ errorexit();
+ }
+ memmove(buf, l, n);
+ buf[n-1] = '\0';
+ n = getfields(buf, fields, nelem(fields), 1, " \t\r\n");
+ if(n == nelem(fields)){
+ diag("%s: bad format", f);
+ errorexit();
+ }
+ for(i = 0; i < n; i++){
+ s = lookup(fields[i], 0);
+ s->type = SXREF;
+ s->subtype = t;
+ if(t == SIMPORT)
+ nimports++;
+ else
+ nexports++;
+ }
+ }
+ Bterm(b);
+}
diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c
new file mode 100644
index 0000000..d997971
--- /dev/null
+++ b/src/cmd/6l/optab.c
@@ -0,0 +1,1213 @@
+// Inferno utils/6l/optab.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/optab.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "l.h"
+
+uchar ynone[] =
+{
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+uchar ytext[] =
+{
+ Ymb, Yi32, Zpseudo,1,
+ 0
+};
+uchar ynop[] =
+{
+ Ynone, Ynone, Zpseudo,1,
+ Ynone, Yml, Zpseudo,1,
+ Ynone, Yrf, Zpseudo,1,
+ Yml, Ynone, Zpseudo,1,
+ Yrf, Ynone, Zpseudo,1,
+ 0
+};
+uchar yxorb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+uchar yxorl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar yaddl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar yincb[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+uchar yincw[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ 0
+};
+uchar yincl[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ 0
+};
+uchar ycmpb[] =
+{
+ Yal, Yi32, Z_ib, 1,
+ Ymb, Yi32, Zm_ibo, 2,
+ Ymb, Yrb, Zm_r, 1,
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+uchar ycmpl[] =
+{
+ Yml, Yi8, Zm_ibo, 2,
+ Yax, Yi32, Z_il, 1,
+ Yml, Yi32, Zm_ilo, 2,
+ Yml, Yrl, Zm_r, 1,
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+uchar yshb[] =
+{
+ Yi1, Ymb, Zo_m, 2,
+ Yi32, Ymb, Zibo_m, 2,
+ Ycx, Ymb, Zo_m, 2,
+ 0
+};
+uchar yshl[] =
+{
+ Yi1, Yml, Zo_m, 2,
+ Yi32, Yml, Zibo_m, 2,
+ Ycl, Yml, Zo_m, 2,
+ Ycx, Yml, Zo_m, 2,
+ 0
+};
+uchar ytestb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+uchar ytestl[] =
+{
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar ymovb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ Yi32, Yrb, Zib_rp, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ 0
+};
+uchar ymbs[] =
+{
+ Ymb, Ynone, Zm_o, 2,
+ 0
+};
+uchar ybtl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+uchar ymovw[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1,
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yiauto, Yrl, Zaut_r, 2,
+ 0
+};
+uchar ymovl[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1,
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yml, Ymr, Zm_r_xm, 1, // MMX MOVD
+ Ymr, Yml, Zr_m_xm, 1, // MMX MOVD
+ Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit)
+ Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit)
+ Yiauto, Yrl, Zaut_r, 2,
+ 0
+};
+uchar yret[] =
+{
+ Ynone, Ynone, Zo_iw, 1,
+ Yi32, Ynone, Zo_iw, 1,
+ 0
+};
+uchar ymovq[] =
+{
+ Yrl, Yml, Zr_m, 1, // 0x89
+ Yml, Yrl, Zm_r, 1, // 0x8b
+ Yi0, Yrl, Zclr, 1, // 0x31
+ Ys32, Yrl, Zilo_m, 2, // 32 bit signed 0xc7,(0)
+ Yi64, Yrl, Ziq_rp, 1, // 0xb8 -- 32/64 bit immediate
+ Yi32, Yml, Zilo_m, 2, // 0xc7,(0)
+ Ym, Ymr, Zm_r_xm_nr, 1, // MMX MOVQ (shorter encoding)
+ Ymr, Ym, Zr_m_xm_nr, 1, // MMX MOVQ
+ Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD
+ Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD
+ Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q
+ Yxr, Ym, Zr_m_xm_nr, 2, // MOVQ xmm store
+ Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load
+ Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store
+ Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ
+ 0
+};
+uchar ym_rl[] =
+{
+ Ym, Yrl, Zm_r, 1,
+ 0
+};
+uchar yrl_m[] =
+{
+ Yrl, Ym, Zr_m, 1,
+ 0
+};
+uchar ymb_rl[] =
+{
+ Ymb, Yrl, Zmb_r, 1,
+ 0
+};
+uchar yml_rl[] =
+{
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar yrl_ml[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+uchar yml_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+uchar yrb_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+uchar yml_ml[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar ydivl[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ 0
+};
+uchar ydivb[] =
+{
+ Ymb, Ynone, Zm_o, 2,
+ 0
+};
+uchar yimul[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ Yi8, Yrl, Zib_rr, 1,
+ Yi32, Yrl, Zil_rr, 1,
+ Yml, Yrl, Zm_r, 2,
+ 0
+};
+uchar ybyte[] =
+{
+ Yi64, Ynone, Zbyte, 1,
+ 0
+};
+uchar yin[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+uchar yint[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ 0
+};
+uchar ypushl[] =
+{
+ Yrl, Ynone, Zrp_, 1,
+ Ym, Ynone, Zm_o, 2,
+ Yi8, Ynone, Zib_, 1,
+ Yi32, Ynone, Zil_, 1,
+ 0
+};
+uchar ypopl[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ Ynone, Ym, Zo_m, 2,
+ 0
+};
+uchar yscond[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+uchar yjcond[] =
+{
+ Ynone, Ybr, Zbr, 1,
+ 0
+};
+uchar yloop[] =
+{
+ Ynone, Ybr, Zloop, 1,
+ 0
+};
+uchar ycall[] =
+{
+ Ynone, Yml, Zo_m64, 2,
+ Ynone, Ybr, Zcall, 1,
+ 0
+};
+uchar yjmp[] =
+{
+ Ynone, Yml, Zo_m64, 2,
+ Ynone, Ybr, Zjmp, 1,
+ 0
+};
+
+uchar yfmvd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfmvdp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfmvf[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+uchar yfmvx[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ 0
+};
+uchar yfmvp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+uchar yfadd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfaddp[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfxch[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ 0
+};
+uchar ycompp[] =
+{
+ Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
+ 0
+};
+uchar ystsw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ynone, Yax, Zlit, 1,
+ 0
+};
+uchar ystcw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+uchar ysvrs[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+uchar ymm[] =
+{
+ Ymm, Ymr, Zm_r_xm, 1,
+ Yxm, Yxr, Zm_r_xm, 2,
+ 0
+};
+uchar yxm[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+uchar yxcvm1[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ Yxm, Ymr, Zm_r_xm, 2,
+ 0
+};
+uchar yxcvm2[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ Ymm, Yxr, Zm_r_xm, 2,
+ 0
+};
+uchar yxmq[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ 0
+};
+uchar yxr[] =
+{
+ Yxr, Yxr, Zm_r_xm, 1,
+ 0
+};
+uchar yxr_ml[] =
+{
+ Yxr, Yml, Zr_m_xm, 1,
+ 0
+};
+uchar ymr[] =
+{
+ Ymr, Ymr, Zm_r, 1,
+ 0
+};
+uchar ymr_ml[] =
+{
+ Ymr, Yml, Zr_m_xm, 1,
+ 0
+};
+uchar yxcmp[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+uchar yxcmpi[] =
+{
+ Yxm, Yxr, Zm_r_i_xm, 2,
+ 0
+};
+uchar yxmov[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ Yxr, Yxm, Zr_m_xm, 1,
+ 0
+};
+uchar yxcvfl[] =
+{
+ Yxm, Yrl, Zm_r_xm, 1,
+ 0
+};
+uchar yxcvlf[] =
+{
+ Yml, Yxr, Zm_r_xm, 1,
+ 0
+};
+uchar yxcvfq[] =
+{
+ Yxm, Yrl, Zm_r_xm, 2,
+ 0
+};
+uchar yxcvqf[] =
+{
+ Yml, Yxr, Zm_r_xm, 2,
+ 0
+};
+uchar yps[] =
+{
+ Ymm, Ymr, Zm_r_xm, 1,
+ Yi8, Ymr, Zibo_m_xm, 2,
+ Yxm, Yxr, Zm_r_xm, 2,
+ Yi8, Yxr, Zibo_m_xm, 3,
+ 0
+};
+uchar yxrrl[] =
+{
+ Yxr, Yrl, Zm_r, 1,
+ 0
+};
+uchar ymfp[] =
+{
+ Ymm, Ymr, Zm_r_3d, 1,
+ 0,
+};
+uchar ymrxr[] =
+{
+ Ymr, Yxr, Zm_r, 1,
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+uchar ymshuf[] =
+{
+ Ymm, Ymr, Zibm_r, 1,
+ 0
+};
+uchar yxshuf[] =
+{
+ Yxm, Yxr, Zibm_r, 1,
+ 0
+};
+uchar yextrw[] =
+{
+ Yxr, Yrl, Zibm_r, 1,
+ 0
+};
+uchar ypsdq[] =
+{
+ Yi8, Yxr, Zibo_m, 2,
+ 0
+};
+uchar ymskb[] =
+{
+ Yxr, Yrl, Zm_r_xm, 2,
+ Ymr, Yrl, Zm_r_xm, 1,
+ 0
+};
+
+Optab optab[] =
+/* as, ytab, andproto, opcode */
+{
+ { AXXX },
+ { AAAA, ynone, P32, 0x37 },
+ { AAAD, ynone, P32, 0xd5,0x0a },
+ { AAAM, ynone, P32, 0xd4,0x0a },
+ { AAAS, ynone, P32, 0x3f },
+ { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
+ { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADCQ, yxorl, Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADDB, yxorb, Pb, 0x04,0x80,(00),0x00,0x02 },
+ { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADDPD, yxm, Pq, 0x58 },
+ { AADDPS, yxm, Pm, 0x58 },
+ { AADDQ, yaddl, Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADDSD, yxm, Pf2, 0x58 },
+ { AADDSS, yxm, Pf3, 0x58 },
+ { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADJSP },
+ { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
+ { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AANDNPD, yxm, Pq, 0x55 },
+ { AANDNPS, yxm, Pm, 0x55 },
+ { AANDPD, yxm, Pq, 0x54 },
+ { AANDPS, yxm, Pq, 0x54 },
+ { AANDQ, yxorl, Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AARPL, yrl_ml, P32, 0x63 },
+ { ABOUNDL, yrl_m, P32, 0x62 },
+ { ABOUNDW, yrl_m, Pe, 0x62 },
+ { ABSFL, yml_rl, Pm, 0xbc },
+ { ABSFQ, yml_rl, Pw, 0x0f,0xbc },
+ { ABSFW, yml_rl, Pq, 0xbc },
+ { ABSRL, yml_rl, Pm, 0xbd },
+ { ABSRQ, yml_rl, Pw, 0x0f,0xbd },
+ { ABSRW, yml_rl, Pq, 0xbd },
+ { ABTCL, ybtl, Pm, 0xba,(07),0xbb },
+ { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb },
+ { ABTCW, ybtl, Pq, 0xba,(07),0xbb },
+ { ABTL, ybtl, Pm, 0xba,(04),0xa3 },
+ { ABTQ, ybtl, Pw, 0x0f,0xba,(04),0x0f,0xa3},
+ { ABTRL, ybtl, Pm, 0xba,(06),0xb3 },
+ { ABTRQ, ybtl, Pw, 0x0f,0xba,(06),0x0f,0xb3 },
+ { ABTRW, ybtl, Pq, 0xba,(06),0xb3 },
+ { ABTSL, ybtl, Pm, 0xba,(05),0xab },
+ { ABTSQ, ybtl, Pw, 0x0f,0xba,(05),0x0f,0xab },
+ { ABTSW, ybtl, Pq, 0xba,(05),0xab },
+ { ABTW, ybtl, Pq, 0xba,(04),0xa3 },
+ { ABYTE, ybyte, Px, 1 },
+ { ACALL, ycall, Px, 0xff,(02),0xe8 },
+ { ACDQ, ynone, Px, 0x99 },
+ { ACLC, ynone, Px, 0xf8 },
+ { ACLD, ynone, Px, 0xfc },
+ { ACLI, ynone, Px, 0xfa },
+ { ACLTS, ynone, Pm, 0x06 },
+ { ACMC, ynone, Px, 0xf5 },
+ { ACMOVLCC, yml_rl, Pm, 0x43 },
+ { ACMOVLCS, yml_rl, Pm, 0x42 },
+ { ACMOVLEQ, yml_rl, Pm, 0x44 },
+ { ACMOVLGE, yml_rl, Pm, 0x4d },
+ { ACMOVLGT, yml_rl, Pm, 0x4f },
+ { ACMOVLHI, yml_rl, Pm, 0x47 },
+ { ACMOVLLE, yml_rl, Pm, 0x4e },
+ { ACMOVLLS, yml_rl, Pm, 0x46 },
+ { ACMOVLLT, yml_rl, Pm, 0x4c },
+ { ACMOVLMI, yml_rl, Pm, 0x48 },
+ { ACMOVLNE, yml_rl, Pm, 0x45 },
+ { ACMOVLOC, yml_rl, Pm, 0x41 },
+ { ACMOVLOS, yml_rl, Pm, 0x40 },
+ { ACMOVLPC, yml_rl, Pm, 0x4b },
+ { ACMOVLPL, yml_rl, Pm, 0x49 },
+ { ACMOVLPS, yml_rl, Pm, 0x4a },
+ { ACMOVQCC, yml_rl, Pw, 0x0f,0x43 },
+ { ACMOVQCS, yml_rl, Pw, 0x0f,0x42 },
+ { ACMOVQEQ, yml_rl, Pw, 0x0f,0x44 },
+ { ACMOVQGE, yml_rl, Pw, 0x0f,0x4d },
+ { ACMOVQGT, yml_rl, Pw, 0x0f,0x4f },
+ { ACMOVQHI, yml_rl, Pw, 0x0f,0x47 },
+ { ACMOVQLE, yml_rl, Pw, 0x0f,0x4e },
+ { ACMOVQLS, yml_rl, Pw, 0x0f,0x46 },
+ { ACMOVQLT, yml_rl, Pw, 0x0f,0x4c },
+ { ACMOVQMI, yml_rl, Pw, 0x0f,0x48 },
+ { ACMOVQNE, yml_rl, Pw, 0x0f,0x45 },
+ { ACMOVQOC, yml_rl, Pw, 0x0f,0x41 },
+ { ACMOVQOS, yml_rl, Pw, 0x0f,0x40 },
+ { ACMOVQPC, yml_rl, Pw, 0x0f,0x4b },
+ { ACMOVQPL, yml_rl, Pw, 0x0f,0x49 },
+ { ACMOVQPS, yml_rl, Pw, 0x0f,0x4a },
+ { ACMOVWCC, yml_rl, Pq, 0x43 },
+ { ACMOVWCS, yml_rl, Pq, 0x42 },
+ { ACMOVWEQ, yml_rl, Pq, 0x44 },
+ { ACMOVWGE, yml_rl, Pq, 0x4d },
+ { ACMOVWGT, yml_rl, Pq, 0x4f },
+ { ACMOVWHI, yml_rl, Pq, 0x47 },
+ { ACMOVWLE, yml_rl, Pq, 0x4e },
+ { ACMOVWLS, yml_rl, Pq, 0x46 },
+ { ACMOVWLT, yml_rl, Pq, 0x4c },
+ { ACMOVWMI, yml_rl, Pq, 0x48 },
+ { ACMOVWNE, yml_rl, Pq, 0x45 },
+ { ACMOVWOC, yml_rl, Pq, 0x41 },
+ { ACMOVWOS, yml_rl, Pq, 0x40 },
+ { ACMOVWPC, yml_rl, Pq, 0x4b },
+ { ACMOVWPL, yml_rl, Pq, 0x49 },
+ { ACMOVWPS, yml_rl, Pq, 0x4a },
+ { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
+ { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPPD, yxcmpi, Px, Pe,0xc2 },
+ { ACMPPS, yxcmpi, Pm, 0xc2,0 },
+ { ACMPQ, ycmpl, Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPSB, ynone, Pb, 0xa6 },
+ { ACMPSD, yxcmpi, Px, Pf2,0xc2 },
+ { ACMPSL, ynone, Px, 0xa7 },
+ { ACMPSQ, ynone, Pw, 0xa7 },
+ { ACMPSS, yxcmpi, Px, Pf3,0xc2 },
+ { ACMPSW, ynone, Pe, 0xa7 },
+ { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACOMISD, yxcmp, Pe, 0x2f },
+ { ACOMISS, yxcmp, Pm, 0x2f },
+ { ACPUID, ynone, Pm, 0xa2 },
+ { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a },
+ { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, },
+ { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d },
+ { ACVTPD2PS, yxm, Pe, 0x5a },
+ { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d },
+ { ACVTPS2PD, yxm, Pm, 0x5a },
+ { API2FW, ymfp, Px, 0x0c },
+ { ACVTSD2SL, yxcvfl, Pf2, 0x2d },
+ { ACVTSD2SQ, yxcvfq, Pw, Pf2,0x2d },
+ { ACVTSD2SS, yxm, Pf2, 0x5a },
+ { ACVTSL2SD, yxcvlf, Pf2, 0x2a },
+ { ACVTSQ2SD, yxcvqf, Pw, Pf2,0x2a },
+ { ACVTSL2SS, yxcvlf, Pf3, 0x2a },
+ { ACVTSQ2SS, yxcvqf, Pw, Pf3,0x2a },
+ { ACVTSS2SD, yxm, Pf3, 0x5a },
+ { ACVTSS2SL, yxcvfl, Pf3, 0x2d },
+ { ACVTSS2SQ, yxcvfq, Pw, Pf3,0x2d },
+ { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c },
+ { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c },
+ { ACVTTSD2SL, yxcvfl, Pf2, 0x2c },
+ { ACVTTSD2SQ, yxcvfq, Pw, Pf2,0x2c },
+ { ACVTTSS2SL, yxcvfl, Pf3, 0x2c },
+ { ACVTTSS2SQ, yxcvfq, Pw, Pf3,0x2c },
+ { ACWD, ynone, Pe, 0x99 },
+ { ACQO, ynone, Pw, 0x99 },
+ { ADAA, ynone, P32, 0x27 },
+ { ADAS, ynone, P32, 0x2f },
+ { ADATA },
+ { ADECB, yincb, Pb, 0xfe,(01) },
+ { ADECL, yincl, Px, 0xff,(01) },
+ { ADECQ, yincl, Pw, 0xff,(01) },
+ { ADECW, yincw, Pe, 0xff,(01) },
+ { ADIVB, ydivb, Pb, 0xf6,(06) },
+ { ADIVL, ydivl, Px, 0xf7,(06) },
+ { ADIVPD, yxm, Pe, 0x5e },
+ { ADIVPS, yxm, Pm, 0x5e },
+ { ADIVQ, ydivl, Pw, 0xf7,(06) },
+ { ADIVSD, yxm, Pf2, 0x5e },
+ { ADIVSS, yxm, Pf3, 0x5e },
+ { ADIVW, ydivl, Pe, 0xf7,(06) },
+ { AEMMS, ynone, Pm, 0x77 },
+ { AENTER }, /* botch */
+ { AFXRSTOR, ysvrs, Pm, 0xae,(01),0xae,(01) },
+ { AFXSAVE, ysvrs, Pm, 0xae,(00),0xae,(00) },
+ { AFXRSTOR64, ysvrs, Pw, 0x0f,0xae,(01),0x0f,0xae,(01) },
+ { AFXSAVE64, ysvrs, Pw, 0x0f,0xae,(00),0x0f,0xae,(00) },
+ { AGLOBL },
+ { AGOK },
+ { AHISTORY },
+ { AHLT, ynone, Px, 0xf4 },
+ { AIDIVB, ydivb, Pb, 0xf6,(07) },
+ { AIDIVL, ydivl, Px, 0xf7,(07) },
+ { AIDIVQ, ydivl, Pw, 0xf7,(07) },
+ { AIDIVW, ydivl, Pe, 0xf7,(07) },
+ { AIMULB, ydivb, Pb, 0xf6,(05) },
+ { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+ { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+ { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+ { AINB, yin, Pb, 0xe4,0xec },
+ { AINCB, yincb, Pb, 0xfe,(00) },
+ { AINCL, yincl, Px, 0xff,(00) },
+ { AINCQ, yincl, Pw, 0xff,(00) },
+ { AINCW, yincw, Pe, 0xff,(00) },
+ { AINL, yin, Px, 0xe5,0xed },
+ { AINSB, ynone, Pb, 0x6c },
+ { AINSL, ynone, Px, 0x6d },
+ { AINSW, ynone, Pe, 0x6d },
+ { AINT, yint, Px, 0xcd },
+ { AINTO, ynone, P32, 0xce },
+ { AINW, yin, Pe, 0xe5,0xed },
+ { AIRETL, ynone, Px, 0xcf },
+ { AIRETQ, ynone, Pw, 0xcf },
+ { AIRETW, ynone, Pe, 0xcf },
+ { AJCC, yjcond, Px, 0x73,0x83,(00) },
+ { AJCS, yjcond, Px, 0x72,0x82 },
+ { AJCXZ, yloop, Px, 0xe3 },
+ { AJEQ, yjcond, Px, 0x74,0x84 },
+ { AJGE, yjcond, Px, 0x7d,0x8d },
+ { AJGT, yjcond, Px, 0x7f,0x8f },
+ { AJHI, yjcond, Px, 0x77,0x87 },
+ { AJLE, yjcond, Px, 0x7e,0x8e },
+ { AJLS, yjcond, Px, 0x76,0x86 },
+ { AJLT, yjcond, Px, 0x7c,0x8c },
+ { AJMI, yjcond, Px, 0x78,0x88 },
+ { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
+ { AJNE, yjcond, Px, 0x75,0x85 },
+ { AJOC, yjcond, Px, 0x71,0x81,(00) },
+ { AJOS, yjcond, Px, 0x70,0x80,(00) },
+ { AJPC, yjcond, Px, 0x7b,0x8b },
+ { AJPL, yjcond, Px, 0x79,0x89 },
+ { AJPS, yjcond, Px, 0x7a,0x8a },
+ { ALAHF, ynone, Px, 0x9f },
+ { ALARL, yml_rl, Pm, 0x02 },
+ { ALARW, yml_rl, Pq, 0x02 },
+ { ALDMXCSR, ysvrs, Pm, 0xae,(02),0xae,(02) },
+ { ALEAL, ym_rl, Px, 0x8d },
+ { ALEAQ, ym_rl, Pw, 0x8d },
+ { ALEAVEL, ynone, P32, 0xc9 },
+ { ALEAVEQ, ynone, Py, 0xc9 },
+ { ALEAVEW, ynone, Pe, 0xc9 },
+ { ALEAW, ym_rl, Pe, 0x8d },
+ { ALOCK, ynone, Px, 0xf0 },
+ { ALODSB, ynone, Pb, 0xac },
+ { ALODSL, ynone, Px, 0xad },
+ { ALODSQ, ynone, Pw, 0xad },
+ { ALODSW, ynone, Pe, 0xad },
+ { ALONG, ybyte, Px, 4 },
+ { ALOOP, yloop, Px, 0xe2 },
+ { ALOOPEQ, yloop, Px, 0xe1 },
+ { ALOOPNE, yloop, Px, 0xe0 },
+ { ALSLL, yml_rl, Pm, 0x03 },
+ { ALSLW, yml_rl, Pq, 0x03 },
+ { AMASKMOVOU, yxr, Pe, 0xf7 },
+ { AMASKMOVQ, ymr, Pm, 0xf7 },
+ { AMAXPD, yxm, Pe, 0x5f },
+ { AMAXPS, yxm, Pm, 0x5f },
+ { AMAXSD, yxm, Pf2, 0x5f },
+ { AMAXSS, yxm, Pf3, 0x5f },
+ { AMINPD, yxm, Pe, 0x5d },
+ { AMINPS, yxm, Pm, 0x5d },
+ { AMINSD, yxm, Pf2, 0x5d },
+ { AMINSS, yxm, Pf3, 0x5d },
+ { AMOVAPD, yxmov, Pe, 0x28,0x29 },
+ { AMOVAPS, yxmov, Pm, 0x28,0x29 },
+ { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
+ { AMOVBLSX, ymb_rl, Pm, 0xbe },
+ { AMOVBLZX, ymb_rl, Pm, 0xb6 },
+ { AMOVBQSX, ymb_rl, Pw, 0x0f,0xbe },
+ { AMOVBQZX, ymb_rl, Pw, 0x0f,0xb6 },
+ { AMOVBWSX, ymb_rl, Pq, 0xbe },
+ { AMOVBWZX, ymb_rl, Pq, 0xb6 },
+ { AMOVO, yxmov, Pe, 0x6f,0x7f },
+ { AMOVOU, yxmov, Pf2, 0x6f,0x7f },
+ { AMOVHLPS, yxr, Pm, 0x12 },
+ { AMOVHPD, yxmov, Pe, 0x16,0x17 },
+ { AMOVHPS, yxmov, Pm, 0x16,0x17 },
+ { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e },
+ { AMOVLHPS, yxr, Pm, 0x16 },
+ { AMOVLPD, yxmov, Pe, 0x12,0x13 },
+ { AMOVLPS, yxmov, Pm, 0x12,0x13 },
+ { AMOVLQSX, yml_rl, Pw, 0x63 },
+ { AMOVLQZX, yml_rl, Px, 0x63 },
+ { AMOVMSKPD, yxrrl, Pq, 0x50 },
+ { AMOVMSKPS, yxrrl, Pm, 0x50 },
+ { AMOVNTO, yxr_ml, Pe, 0xe7 },
+ { AMOVNTPD, yxr_ml, Pe, 0x2b },
+ { AMOVNTPS, yxr_ml, Pm, 0x2b },
+ { AMOVNTQ, ymr_ml, Pm, 0xe7 },
+ { AMOVQ, ymovq, Pw, 0x89,0x8b,0x31,0xc7,(00),0xb8,0xc7,(00),0x6f,0x7f,0x6e,0x7e,Pf2,0xd6,Pe,0xd6,Pe,0x6e,Pe,0x7e },
+ { AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e },
+ { AMOVSB, ynone, Pb, 0xa4 },
+ { AMOVSD, yxmov, Pf2, 0x10,0x11 },
+ { AMOVSL, ynone, Px, 0xa5 },
+ { AMOVSQ, ynone, Pw, 0xa5 },
+ { AMOVSS, yxmov, Pf3, 0x10,0x11 },
+ { AMOVSW, ynone, Pe, 0xa5 },
+ { AMOVUPD, yxmov, Pe, 0x10,0x11 },
+ { AMOVUPS, yxmov, Pm, 0x10,0x11 },
+ { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0xb8,0xc7,(00) },
+ { AMOVWLSX, yml_rl, Pm, 0xbf },
+ { AMOVWLZX, yml_rl, Pm, 0xb7 },
+ { AMOVWQSX, yml_rl, Pw, 0x0f,0xbf },
+ { AMOVWQZX, yml_rl, Pw, 0x0f,0xb7 },
+ { AMULB, ydivb, Pb, 0xf6,(04) },
+ { AMULL, ydivl, Px, 0xf7,(04) },
+ { AMULPD, yxm, Pe, 0x59 },
+ { AMULPS, yxm, Ym, 0x59 },
+ { AMULQ, ydivl, Pw, 0xf7,(04) },
+ { AMULSD, yxm, Pf2, 0x59 },
+ { AMULSS, yxm, Pf3, 0x59 },
+ { AMULW, ydivl, Pe, 0xf7,(04) },
+ { ANAME },
+ { ANEGB, yscond, Pb, 0xf6,(03) },
+ { ANEGL, yscond, Px, 0xf7,(03) },
+ { ANEGQ, yscond, Pw, 0xf7,(03) },
+ { ANEGW, yscond, Pe, 0xf7,(03) },
+ { ANOP, ynop, Px, 0,0 },
+ { ANOTB, yscond, Pb, 0xf6,(02) },
+ { ANOTL, yscond, Px, 0xf7,(02) },
+ { ANOTQ, yscond, Pw, 0xf7,(02) },
+ { ANOTW, yscond, Pe, 0xf7,(02) },
+ { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
+ { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AORPD, yxm, Pq, 0x56 },
+ { AORPS, yxm, Pm, 0x56 },
+ { AORQ, yxorl, Pw, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AOUTB, yin, Pb, 0xe6,0xee },
+ { AOUTL, yin, Px, 0xe7,0xef },
+ { AOUTSB, ynone, Pb, 0x6e },
+ { AOUTSL, ynone, Px, 0x6f },
+ { AOUTSW, ynone, Pe, 0x6f },
+ { AOUTW, yin, Pe, 0xe7,0xef },
+ { APACKSSLW, ymm, Py, 0x6b,Pe,0x6b },
+ { APACKSSWB, ymm, Py, 0x63,Pe,0x63 },
+ { APACKUSWB, ymm, Py, 0x67,Pe,0x67 },
+ { APADDB, ymm, Py, 0xfc,Pe,0xfc },
+ { APADDL, ymm, Py, 0xfe,Pe,0xfe },
+ { APADDQ, yxm, Pe, 0xd4 },
+ { APADDSB, ymm, Py, 0xec,Pe,0xec },
+ { APADDSW, ymm, Py, 0xed,Pe,0xed },
+ { APADDUSB, ymm, Py, 0xdc,Pe,0xdc },
+ { APADDUSW, ymm, Py, 0xdd,Pe,0xdd },
+ { APADDW, ymm, Py, 0xfd,Pe,0xfd },
+ { APAND, ymm, Py, 0xdb,Pe,0xdb },
+ { APANDN, ymm, Py, 0xdf,Pe,0xdf },
+ { APAVGB, ymm, Py, 0xe0,Pe,0xe0 },
+ { APAVGW, ymm, Py, 0xe3,Pe,0xe3 },
+ { APCMPEQB, ymm, Py, 0x74,Pe,0x74 },
+ { APCMPEQL, ymm, Py, 0x76,Pe,0x76 },
+ { APCMPEQW, ymm, Py, 0x75,Pe,0x75 },
+ { APCMPGTB, ymm, Py, 0x64,Pe,0x64 },
+ { APCMPGTL, ymm, Py, 0x66,Pe,0x66 },
+ { APCMPGTW, ymm, Py, 0x65,Pe,0x65 },
+ { APEXTRW, yextrw, Pq, 0xc5 },
+ { APF2IL, ymfp, Px, 0x1d },
+ { APF2IW, ymfp, Px, 0x1c },
+ { API2FL, ymfp, Px, 0x0d },
+ { APFACC, ymfp, Px, 0xae },
+ { APFADD, ymfp, Px, 0x9e },
+ { APFCMPEQ, ymfp, Px, 0xb0 },
+ { APFCMPGE, ymfp, Px, 0x90 },
+ { APFCMPGT, ymfp, Px, 0xa0 },
+ { APFMAX, ymfp, Px, 0xa4 },
+ { APFMIN, ymfp, Px, 0x94 },
+ { APFMUL, ymfp, Px, 0xb4 },
+ { APFNACC, ymfp, Px, 0x8a },
+ { APFPNACC, ymfp, Px, 0x8e },
+ { APFRCP, ymfp, Px, 0x96 },
+ { APFRCPIT1, ymfp, Px, 0xa6 },
+ { APFRCPI2T, ymfp, Px, 0xb6 },
+ { APFRSQIT1, ymfp, Px, 0xa7 },
+ { APFRSQRT, ymfp, Px, 0x97 },
+ { APFSUB, ymfp, Px, 0x9a },
+ { APFSUBR, ymfp, Px, 0xaa },
+ { APINSRW, yextrw, Pq, 0xc4 },
+ { APMADDWL, ymm, Py, 0xf5,Pe,0xf5 },
+ { APMAXSW, yxm, Pe, 0xee },
+ { APMAXUB, yxm, Pe, 0xde },
+ { APMINSW, yxm, Pe, 0xea },
+ { APMINUB, yxm, Pe, 0xda },
+ { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 },
+ { APMULHRW, ymfp, Px, 0xb7 },
+ { APMULHUW, ymm, Py, 0xe4,Pe,0xe4 },
+ { APMULHW, ymm, Py, 0xe5,Pe,0xe5 },
+ { APMULLW, ymm, Py, 0xd5,Pe,0xd5 },
+ { APMULULQ, ymm, Py, 0xf4,Pe,0xf4 },
+ { APOPAL, ynone, P32, 0x61 },
+ { APOPAW, ynone, Pe, 0x61 },
+ { APOPFL, ynone, P32, 0x9d },
+ { APOPFQ, ynone, Py, 0x9d },
+ { APOPFW, ynone, Pe, 0x9d },
+ { APOPL, ypopl, P32, 0x58,0x8f,(00) },
+ { APOPQ, ypopl, Py, 0x58,0x8f,(00) },
+ { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
+ { APOR, ymm, Py, 0xeb,Pe,0xeb },
+ { APSADBW, yxm, Pw, Pe,0xf6 },
+ { APSHUFHW, yxshuf, Pf3, 0x70 },
+ { APSHUFL, yxm, Pw, Pe,0x70 },
+ { APSHUFLW, yxshuf, Pf2, 0x70 },
+ { APSHUFW, ymshuf, Pm, 0x70 },
+ { APSLLO, ypsdq, Pq, 0x73,(07) },
+ { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) },
+ { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x7e,(06) },
+ { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) },
+ { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) },
+ { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) },
+ { APSRLO, ypsdq, Pq, 0x73,(03) },
+ { APSRLL, yps, Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) },
+ { APSRLQ, yps, Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) },
+ { APSRLW, yps, Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) },
+ { APSUBB, yxm, Pe, 0xf8 },
+ { APSUBL, yxm, Pe, 0xfa },
+ { APSUBQ, yxm, Pe, 0xfb },
+ { APSUBSB, yxm, Pe, 0xe8 },
+ { APSUBSW, yxm, Pe, 0xe9 },
+ { APSUBUSB, yxm, Pe, 0xd8 },
+ { APSUBUSW, yxm, Pe, 0xd9 },
+ { APSUBW, yxm, Pe, 0xf9 },
+ { APSWAPL, ymfp, Px, 0xbb },
+ { APUNPCKHBW, ymm, Py, 0x68,Pe,0x68 },
+ { APUNPCKHLQ, ymm, Py, 0x6a,Pe,0x6a },
+ { APUNPCKHQDQ, yxm, Pe, 0x6d },
+ { APUNPCKHWL, ymm, Py, 0x69,Pe,0x69 },
+ { APUNPCKLBW, ymm, Py, 0x60,Pe,0x60 },
+ { APUNPCKLLQ, ymm, Py, 0x62,Pe,0x62 },
+ { APUNPCKLQDQ, yxm, Pe, 0x6c },
+ { APUNPCKLWL, ymm, Py, 0x61,Pe,0x61 },
+ { APUSHAL, ynone, P32, 0x60 },
+ { APUSHAW, ynone, Pe, 0x60 },
+ { APUSHFL, ynone, P32, 0x9c },
+ { APUSHFQ, ynone, Py, 0x9c },
+ { APUSHFW, ynone, Pe, 0x9c },
+ { APUSHL, ypushl, P32, 0x50,0xff,(06),0x6a,0x68 },
+ { APUSHQ, ypushl, Py, 0x50,0xff,(06),0x6a,0x68 },
+ { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
+ { APXOR, ymm, Py, 0xef,Pe,0xef },
+ { AQUAD, ybyte, Px, 8 },
+ { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
+ { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCLQ, yshl, Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCPPS, yxm, Pm, 0x53 },
+ { ARCPSS, yxm, Pf3, 0x53 },
+ { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
+ { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { ARCRQ, yshl, Pw, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { AREP, ynone, Px, 0xf3 },
+ { AREPN, ynone, Px, 0xf2 },
+ { ARET, ynone, Px, 0xc3 },
+ { ARETFW, yret, Pe, 0xcb,0xca },
+ { ARETFL, yret, Px, 0xcb,0xca },
+ { ARETFQ, yret, Pw, 0xcb,0xca },
+ { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
+ { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { AROLQ, yshl, Pw, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
+ { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARORQ, yshl, Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARSQRTPS, yxm, Pm, 0x52 },
+ { ARSQRTSS, yxm, Pf3, 0x52 },
+ { ASAHF, ynone, Px, 0x86,0xe0,0x50,0x9d }, /* XCHGB AH,AL; PUSH AX; POPFL */
+ { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASALQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
+ { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASARQ, yshl, Pw, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
+ { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASBBQ, yxorl, Pw, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASCASB, ynone, Pb, 0xae },
+ { ASCASL, ynone, Px, 0xaf },
+ { ASCASQ, ynone, Pw, 0xaf },
+ { ASCASW, ynone, Pe, 0xaf },
+ { ASETCC, yscond, Pm, 0x93,(00) },
+ { ASETCS, yscond, Pm, 0x92,(00) },
+ { ASETEQ, yscond, Pm, 0x94,(00) },
+ { ASETGE, yscond, Pm, 0x9d,(00) },
+ { ASETGT, yscond, Pm, 0x9f,(00) },
+ { ASETHI, yscond, Pm, 0x97,(00) },
+ { ASETLE, yscond, Pm, 0x9e,(00) },
+ { ASETLS, yscond, Pm, 0x96,(00) },
+ { ASETLT, yscond, Pm, 0x9c,(00) },
+ { ASETMI, yscond, Pm, 0x98,(00) },
+ { ASETNE, yscond, Pm, 0x95,(00) },
+ { ASETOC, yscond, Pm, 0x91,(00) },
+ { ASETOS, yscond, Pm, 0x90,(00) },
+ { ASETPC, yscond, Pm, 0x96,(00) },
+ { ASETPL, yscond, Pm, 0x99,(00) },
+ { ASETPS, yscond, Pm, 0x9a,(00) },
+ { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHLQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
+ { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHUFPD, yxshuf, Pq, 0xc6 },
+ { ASHUFPS, yxshuf, Pm, 0xc6 },
+ { ASQRTPD, yxm, Pe, 0x51 },
+ { ASQRTPS, yxm, Pm, 0x51 },
+ { ASQRTSD, yxm, Pf2, 0x51 },
+ { ASQRTSS, yxm, Pf3, 0x51 },
+ { ASTC, ynone, Px, 0xf9 },
+ { ASTD, ynone, Px, 0xfd },
+ { ASTI, ynone, Px, 0xfb },
+ { ASTMXCSR, ysvrs, Pm, 0xae,(03),0xae,(03) },
+ { ASTOSB, ynone, Pb, 0xaa },
+ { ASTOSL, ynone, Px, 0xab },
+ { ASTOSQ, ynone, Pw, 0xab },
+ { ASTOSW, ynone, Pe, 0xab },
+ { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
+ { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASUBPD, yxm, Pe, 0x5c },
+ { ASUBPS, yxm, Pm, 0x5c },
+ { ASUBQ, yaddl, Pw, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASUBSD, yxm, Pf2, 0x5c },
+ { ASUBSS, yxm, Pf3, 0x5c },
+ { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASWAPGS, ynone, Pm, 0x01,0xf8 },
+ { ASYSCALL, ynone, Px, 0x0f,0x05 }, /* fast syscall */
+ { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
+ { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATESTQ, ytestl, Pw, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATEXT, ytext, Px },
+ { AUCOMISD, yxcmp, Pe, 0x2e },
+ { AUCOMISS, yxcmp, Pm, 0x2e },
+ { AUNPCKHPD, yxm, Pe, 0x15 },
+ { AUNPCKHPS, yxm, Pm, 0x15 },
+ { AUNPCKLPD, yxm, Pe, 0x14 },
+ { AUNPCKLPS, yxm, Pm, 0x14 },
+ { AVERR, ydivl, Pm, 0x00,(04) },
+ { AVERW, ydivl, Pm, 0x00,(05) },
+ { AWAIT, ynone, Px, 0x9b },
+ { AWORD, ybyte, Px, 2 },
+ { AXCHGB, yml_mb, Pb, 0x86,0x86 },
+ { AXCHGL, yml_ml, Px, 0x87,0x87 },
+ { AXCHGQ, yml_ml, Pw, 0x87,0x87 },
+ { AXCHGW, yml_ml, Pe, 0x87,0x87 },
+ { AXLAT, ynone, Px, 0xd7 },
+ { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
+ { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+ { AXORPD, yxm, Pe, 0x57 },
+ { AXORPS, yxm, Pm, 0x57 },
+ { AXORQ, yxorl, Pw, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+ { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+
+ { AFMOVB, yfmvx, Px, 0xdf,(04) },
+ { AFMOVBP, yfmvp, Px, 0xdf,(06) },
+ { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
+ { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
+ { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
+ { AFMOVFP, yfmvp, Px, 0xd9,(03) },
+ { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
+ { AFMOVLP, yfmvp, Px, 0xdb,(03) },
+ { AFMOVV, yfmvx, Px, 0xdf,(05) },
+ { AFMOVVP, yfmvp, Px, 0xdf,(07) },
+ { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
+ { AFMOVWP, yfmvp, Px, 0xdf,(03) },
+ { AFMOVX, yfmvx, Px, 0xdb,(05) },
+ { AFMOVXP, yfmvp, Px, 0xdb,(07) },
+
+ { AFCOMB },
+ { AFCOMBP },
+ { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
+ { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
+ { AFCOMDPP, ycompp, Px, 0xde,(03) },
+ { AFCOMF, yfmvx, Px, 0xd8,(02) },
+ { AFCOMFP, yfmvx, Px, 0xd8,(03) },
+ { AFCOML, yfmvx, Px, 0xda,(02) },
+ { AFCOMLP, yfmvx, Px, 0xda,(03) },
+ { AFCOMW, yfmvx, Px, 0xde,(02) },
+ { AFCOMWP, yfmvx, Px, 0xde,(03) },
+
+ { AFUCOM, ycompp, Px, 0xdd,(04) },
+ { AFUCOMP, ycompp, Px, 0xdd,(05) },
+ { AFUCOMPP, ycompp, Px, 0xda,(13) },
+
+ { AFADDDP, yfaddp, Px, 0xde,(00) },
+ { AFADDW, yfmvx, Px, 0xde,(00) },
+ { AFADDL, yfmvx, Px, 0xda,(00) },
+ { AFADDF, yfmvx, Px, 0xd8,(00) },
+ { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
+
+ { AFMULDP, yfaddp, Px, 0xde,(01) },
+ { AFMULW, yfmvx, Px, 0xde,(01) },
+ { AFMULL, yfmvx, Px, 0xda,(01) },
+ { AFMULF, yfmvx, Px, 0xd8,(01) },
+ { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
+
+ { AFSUBDP, yfaddp, Px, 0xde,(05) },
+ { AFSUBW, yfmvx, Px, 0xde,(04) },
+ { AFSUBL, yfmvx, Px, 0xda,(04) },
+ { AFSUBF, yfmvx, Px, 0xd8,(04) },
+ { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
+
+ { AFSUBRDP, yfaddp, Px, 0xde,(04) },
+ { AFSUBRW, yfmvx, Px, 0xde,(05) },
+ { AFSUBRL, yfmvx, Px, 0xda,(05) },
+ { AFSUBRF, yfmvx, Px, 0xd8,(05) },
+ { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
+
+ { AFDIVDP, yfaddp, Px, 0xde,(07) },
+ { AFDIVW, yfmvx, Px, 0xde,(06) },
+ { AFDIVL, yfmvx, Px, 0xda,(06) },
+ { AFDIVF, yfmvx, Px, 0xd8,(06) },
+ { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
+
+ { AFDIVRDP, yfaddp, Px, 0xde,(06) },
+ { AFDIVRW, yfmvx, Px, 0xde,(07) },
+ { AFDIVRL, yfmvx, Px, 0xda,(07) },
+ { AFDIVRF, yfmvx, Px, 0xd8,(07) },
+ { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
+
+ { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
+ { AFFREE },
+ { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
+ { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
+ { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
+ { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
+ { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
+ { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
+ { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
+ { AF2XM1, ynone, Px, 0xd9, 0xf0 },
+ { AFABS, ynone, Px, 0xd9, 0xe1 },
+ { AFCHS, ynone, Px, 0xd9, 0xe0 },
+ { AFCLEX, ynone, Px, 0xdb, 0xe2 },
+ { AFCOS, ynone, Px, 0xd9, 0xff },
+ { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
+ { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
+ { AFINIT, ynone, Px, 0xdb, 0xe3 },
+ { AFLD1, ynone, Px, 0xd9, 0xe8 },
+ { AFLDL2E, ynone, Px, 0xd9, 0xea },
+ { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
+ { AFLDLG2, ynone, Px, 0xd9, 0xec },
+ { AFLDLN2, ynone, Px, 0xd9, 0xed },
+ { AFLDPI, ynone, Px, 0xd9, 0xeb },
+ { AFLDZ, ynone, Px, 0xd9, 0xee },
+ { AFNOP, ynone, Px, 0xd9, 0xd0 },
+ { AFPATAN, ynone, Px, 0xd9, 0xf3 },
+ { AFPREM, ynone, Px, 0xd9, 0xf8 },
+ { AFPREM1, ynone, Px, 0xd9, 0xf5 },
+ { AFPTAN, ynone, Px, 0xd9, 0xf2 },
+ { AFRNDINT, ynone, Px, 0xd9, 0xfc },
+ { AFSCALE, ynone, Px, 0xd9, 0xfd },
+ { AFSIN, ynone, Px, 0xd9, 0xfe },
+ { AFSINCOS, ynone, Px, 0xd9, 0xfb },
+ { AFSQRT, ynone, Px, 0xd9, 0xfa },
+ { AFTST, ynone, Px, 0xd9, 0xe4 },
+ { AFXAM, ynone, Px, 0xd9, 0xe5 },
+ { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
+ { AFYL2X, ynone, Px, 0xd9, 0xf1 },
+ { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
+
+ { ACMPXCHGB, yrb_mb, Pb, 0x0f,0xb0 },
+ { ACMPXCHGL, yrl_ml, Px, 0x0f,0xb1 },
+ { ACMPXCHGW, yrl_ml, Pe, 0x0f,0xb1 },
+ { ACMPXCHGQ, yrl_ml, Pw, 0x0f,0xb1 },
+ { ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
+ { AINVD, ynone, Pm, 0x08 },
+ { AINVLPG, ymbs, Pm, 0x01,(07) },
+ { ALFENCE, ynone, Pm, 0xae,0xe8 },
+ { AMFENCE, ynone, Pm, 0xae,0xf0 },
+ { AMOVNTIL, yrl_ml, Pm, 0xc3 },
+ { AMOVNTIQ, yrl_ml, Pw, 0x0f,0xc3 },
+ { ARDMSR, ynone, Pm, 0x32 },
+ { ARDPMC, ynone, Pm, 0x33 },
+ { ARDTSC, ynone, Pm, 0x31 },
+ { ARSM, ynone, Pm, 0xaa },
+ { ASFENCE, ynone, Pm, 0xae,0xf8 },
+ { ASYSRET, ynone, Pm, 0x07 },
+ { AWBINVD, ynone, Pm, 0x09 },
+ { AWRMSR, ynone, Pm, 0x30 },
+
+ { AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
+ { AXADDL, yrl_ml, Px, 0x0f,0xc1 },
+ { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 },
+ { AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
+
+ { AEND },
+ 0
+};
+
+Optab* opindex[ALAST+1];
+
+/*
+AMOVD 0f 6e/r mmx,reg/mem32[mem64-rex?]
+AMOVD 0f 7e/r reg/mem32[64],mmx STORE
+AMOVQ 0f 6f/r mmx1,mmx2/mem64
+AMOVQ 0f 7f/r mmx1/mem64,mmx2
+*/
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
new file mode 100644
index 0000000..5884022
--- /dev/null
+++ b/src/cmd/6l/pass.c
@@ -0,0 +1,820 @@
+// Inferno utils/6l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "l.h"
+
+void
+dodata(void)
+{
+ int i;
+ Sym *s;
+ Prog *p;
+ long t, u;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dodata\n", cputime());
+ Bflush(&bso);
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(p->as == ADYNT || p->as == AINIT)
+ s->value = dtype;
+ if(s->type == SBSS)
+ s->type = SDATA;
+ if(s->type != SDATA)
+ diag("initialize non-data (%d): %s\n%P",
+ s->type, s->name, p);
+ t = p->from.offset + p->width;
+ if(t > s->value)
+ diag("initialize bounds (%lld): %s\n%P",
+ s->value, s->name, p);
+ }
+ /* allocate small guys */
+ datsize = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SDATA)
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ if(t == 0) {
+ diag("%s: no size", s->name);
+ t = 1;
+ }
+ t = rnd(t, 4);
+ s->value = t;
+ if(t > MINSIZ)
+ continue;
+ if(t >= 8)
+ datsize = rnd(datsize, 8);
+ s->value = datsize;
+ datsize += t;
+ s->type = SDATA1;
+ }
+
+ /* allocate the rest of the data */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SDATA) {
+ if(s->type == SDATA1)
+ s->type = SDATA;
+ continue;
+ }
+ t = s->value;
+ if(t >= 8)
+ datsize = rnd(datsize, 8);
+ s->value = datsize;
+ datsize += t;
+ }
+ if(datsize)
+ datsize = rnd(datsize, 8);
+
+ if(debug['j']) {
+ /*
+ * pad data with bss that fits up to next
+ * 8k boundary, then push data to 8k
+ */
+ u = rnd(datsize, 8192);
+ u -= datsize;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ if(t > u)
+ continue;
+ u -= t;
+ s->value = datsize;
+ s->type = SDATA;
+ datsize += t;
+ }
+ datsize += u;
+ }
+
+ /* now the bss */
+ bsssize = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ if(t >= 8)
+ bsssize = rnd(bsssize, 8);
+ s->value = bsssize + datsize;
+ bsssize += t;
+ }
+ xdefine("edata", SBSS, datsize);
+ xdefine("end", SBSS, bsssize + datsize);
+}
+
+Prog*
+brchain(Prog *p)
+{
+ int i;
+
+ for(i=0; i<20; i++) {
+ if(p == P || p->as != AJMP)
+ return p;
+ p = p->pcond;
+ }
+ return P;
+}
+
+void
+follow(void)
+{
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+ firstp = prg();
+ lastp = firstp;
+ xfol(textp);
+ lastp->link = P;
+ firstp = firstp->link;
+}
+
+void
+xfol(Prog *p)
+{
+ Prog *q;
+ int i;
+ enum as a;
+
+loop:
+ if(p == P)
+ return;
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->as == AJMP)
+ if((q = p->pcond) != P) {
+ p->mark = 1;
+ p = q;
+ if(p->mark == 0)
+ goto loop;
+ }
+ if(p->mark) {
+ /* copy up to 4 instructions to avoid branch */
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == P)
+ break;
+ if(q == lastp)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ switch(a) {
+ case AJMP:
+ case ARET:
+ case AIRETL:
+ case AIRETQ:
+ case AIRETW:
+ case ARETFL:
+ case ARETFQ:
+ case ARETFW:
+
+ case APUSHL:
+ case APUSHFL:
+ case APUSHQ:
+ case APUSHFQ:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ case APOPQ:
+ case APOPFQ:
+ case APOPW:
+ case APOPFW:
+ goto brk;
+ }
+ if(q->pcond == P || q->pcond->mark)
+ continue;
+ if(a == ACALL || a == ALOOP)
+ continue;
+ for(;;) {
+ if(p->as == ANOP) {
+ p = p->link;
+ continue;
+ }
+ q = copyp(p);
+ p = p->link;
+ q->mark = 1;
+ lastp->link = q;
+ lastp = q;
+ if(q->as != a || q->pcond == P || q->pcond->mark)
+ continue;
+
+ q->as = relinv(q->as);
+ p = q->pcond;
+ q->pcond = q->link;
+ q->link = p;
+ xfol(q->link);
+ p = q->link;
+ if(p->mark)
+ return;
+ goto loop;
+ }
+ } /* */
+ brk:;
+ q = prg();
+ q->as = AJMP;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+ p->mark = 1;
+ lastp->link = p;
+ lastp = p;
+ a = p->as;
+ if(a == AJMP || a == ARET || a == AIRETL || a == AIRETQ || a == AIRETW ||
+ a == ARETFL || a == ARETFQ || a == ARETFW)
+ return;
+ if(p->pcond != P)
+ if(a != ACALL) {
+ q = brchain(p->link);
+ if(q != P && q->mark)
+ if(a != ALOOP) {
+ p->as = relinv(a);
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ xfol(p->link);
+ q = brchain(p->pcond);
+ if(q->mark) {
+ p->pcond = q;
+ return;
+ }
+ p = q;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+int
+relinv(int a)
+{
+
+ switch(a) {
+ case AJEQ: return AJNE;
+ case AJNE: return AJEQ;
+ case AJLE: return AJGT;
+ case AJLS: return AJHI;
+ case AJLT: return AJGE;
+ case AJMI: return AJPL;
+ case AJGE: return AJLT;
+ case AJPL: return AJMI;
+ case AJGT: return AJLE;
+ case AJHI: return AJLS;
+ case AJCS: return AJCC;
+ case AJCC: return AJCS;
+ case AJPS: return AJPC;
+ case AJPC: return AJPS;
+ case AJOS: return AJOC;
+ case AJOC: return AJOS;
+ }
+ diag("unknown relation: %s in %s", anames[a], TNAME);
+ return a;
+}
+
+void
+doinit(void)
+{
+ Sym *s;
+ Prog *p;
+ int x;
+
+ for(p = datap; p != P; p = p->link) {
+ x = p->to.type;
+ if(x != D_EXTERN && x != D_STATIC)
+ continue;
+ s = p->to.sym;
+ if(s->type == 0 || s->type == SXREF)
+ diag("undefined %s initializer of %s",
+ s->name, p->from.sym->name);
+ p->to.offset += s->value;
+ p->to.type = D_CONST;
+ if(s->type == SDATA || s->type == SBSS)
+ p->to.offset += INITDAT;
+ }
+}
+
+void
+patch(void)
+{
+ long c;
+ Prog *p, *q;
+ Sym *s;
+ long vexit;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f mkfwd\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+ s = lookup("exit", 0);
+ vexit = s->value;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->as == ACALL || p->as == ARET) {
+ s = p->to.sym;
+ if(s) {
+ if(debug['c'])
+ Bprint(&bso, "%s calls %s\n", TNAME, s->name);
+ switch(s->type) {
+ default:
+ diag("undefined: %s in %s", s->name, TNAME);
+ s->type = STEXT;
+ s->value = vexit;
+ break; /* or fall through to set offset? */
+ case STEXT:
+ p->to.offset = s->value;
+ break;
+ case SUNDEF:
+ p->pcond = UP;
+ p->to.offset = 0;
+ break;
+ }
+ p->to.type = D_BRANCH;
+ }
+ }
+ if(p->to.type != D_BRANCH || p->pcond == UP)
+ continue;
+ c = p->to.offset;
+ for(q = firstp; q != P;) {
+ if(q->forwd != P)
+ if(c >= q->forwd->pc) {
+ q = q->forwd;
+ continue;
+ }
+ if(c == q->pc)
+ break;
+ q = q->link;
+ }
+ if(q == P) {
+ diag("branch out of range in %s\n%P", TNAME, p);
+ p->to.type = D_NONE;
+ }
+ p->pcond = q;
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ p->mark = 0; /* initialization for follow */
+ if(p->pcond != P && p->pcond != UP) {
+ p->pcond = brloop(p->pcond);
+ if(p->pcond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->pcond->pc;
+ }
+ }
+}
+
+#define LOG 5
+void
+mkfwd(void)
+{
+ Prog *p;
+ int i;
+ long dwn[LOG], cnt[LOG];
+ Prog *lst[LOG];
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1; else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = P;
+ }
+ i = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = P;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != P)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ int c;
+ Prog *q;
+
+ c = 0;
+ for(q = p; q != P; q = q->pcond) {
+ if(q->as != AJMP)
+ break;
+ c++;
+ if(c >= 5000)
+ return P;
+ }
+ return q;
+}
+
+void
+dostkoff(void)
+{
+ Prog *p, *q;
+ long autoffset, deltasp;
+ int a, f, curframe, curbecome, maxbecome, pcsize;
+
+ curframe = 0;
+ curbecome = 0;
+ maxbecome = 0;
+ curtext = 0;
+ for(p = firstp; p != P; p = p->link) {
+
+ /* find out how much arg space is used in this TEXT */
+ if(p->to.type == (D_INDIR+D_SP))
+ if(p->to.offset > curframe)
+ curframe = p->to.offset;
+
+ switch(p->as) {
+ case ATEXT:
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+ curframe = 0;
+ curbecome = 0;
+
+ curtext = p;
+ break;
+
+ case ARET:
+ /* special form of RET is BECOME */
+ if(p->from.type == D_CONST)
+ if(p->from.offset > curbecome)
+ curbecome = p->from.offset;
+ break;
+ }
+ }
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+
+ if(debug['b'])
+ print("max become = %d\n", maxbecome);
+ xdefine("ALEFbecome", STEXT, maxbecome);
+
+ curtext = 0;
+ for(p = firstp; p != P; p = p->link) {
+ switch(p->as) {
+ case ATEXT:
+ curtext = p;
+ break;
+ case ACALL:
+ if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
+ f = maxbecome - curtext->from.sym->frame;
+ if(f <= 0)
+ break;
+ /* calling a become or calling a variable */
+ if(p->to.sym == S || p->to.sym->become) {
+ curtext->to.offset += f;
+ if(debug['b']) {
+ curp = p;
+ print("%D calling %D increase %d\n",
+ &curtext->from, &p->to, f);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ autoffset = 0;
+ deltasp = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autoffset = p->to.offset;
+ if(autoffset < 0)
+ autoffset = 0;
+ if(autoffset) {
+ p = appendp(p);
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset;
+ }
+ deltasp = autoffset;
+ }
+ pcsize = p->mode/8;
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + pcsize;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + pcsize;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ continue;
+ case APUSHQ:
+ case APUSHFQ:
+ deltasp += 8;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ continue;
+ case APOPQ:
+ case APOPFQ:
+ deltasp -= 8;
+ continue;
+ case APOPW:
+ case APOPFW:
+ deltasp -= 2;
+ continue;
+ case ARET:
+ break;
+ }
+
+ if(autoffset != deltasp)
+ diag("unbalanced PUSH/POP");
+ if(p->from.type == D_CONST)
+ goto become;
+
+ if(autoffset) {
+ q = p;
+ p = appendp(p);
+ p->as = ARET;
+
+ q->as = AADJSP;
+ q->from.type = D_CONST;
+ q->from.offset = -autoffset;
+ }
+ continue;
+
+ become:
+ q = p;
+ p = appendp(p);
+ p->as = AJMP;
+ p->to = q->to;
+ p->pcond = q->pcond;
+
+ q->as = AADJSP;
+ q->from = zprg.from;
+ q->from.type = D_CONST;
+ q->from.offset = -autoffset;
+ q->to = zprg.to;
+ continue;
+ }
+}
+
+vlong
+atolwhex(char *s)
+{
+ vlong n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+void
+undef(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SXREF)
+ diag("%s: not defined", s->name);
+}
+
+void
+import(void)
+{
+ int i;
+ Sym *s;
+
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
+ if(s->value != 0)
+ diag("value != 0 on SXREF");
+ undefsym(s);
+ Bprint(&bso, "IMPORT: %s sig=%lux v=%lld\n", s->name, s->sig, s->value);
+ if(debug['S'])
+ s->sig = 0;
+ }
+}
+
+void
+ckoff(Sym *s, long v)
+{
+ if(v < 0 || v >= 1<<Roffset)
+ diag("relocation offset %ld for %s out of range", v, s->name);
+}
+
+static Prog*
+newdata(Sym *s, int o, int w, int t)
+{
+ Prog *p;
+
+ p = prg();
+ if(edatap == P)
+ datap = p;
+ else
+ edatap->link = p;
+ edatap = p;
+ p->as = ADATA;
+ p->width = w;
+ p->from.scale = w;
+ p->from.type = t;
+ p->from.sym = s;
+ p->from.offset = o;
+ p->to.type = D_CONST;
+ return p;
+}
+
+void
+export(void)
+{
+ int i, j, n, off, nb, sv, ne;
+ Sym *s, *et, *str, **esyms;
+ Prog *p;
+ char buf[NSNAME], *t;
+
+ n = 0;
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
+ n++;
+ esyms = malloc(n*sizeof(Sym*));
+ ne = n;
+ n = 0;
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
+ esyms[n++] = s;
+ for(i = 0; i < ne-1; i++)
+ for(j = i+1; j < ne; j++)
+ if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
+ s = esyms[i];
+ esyms[i] = esyms[j];
+ esyms[j] = s;
+ }
+
+ nb = 0;
+ off = 0;
+ et = lookup(EXPTAB, 0);
+ if(et->type != 0 && et->type != SXREF)
+ diag("%s already defined", EXPTAB);
+ et->type = SDATA;
+ str = lookup(".string", 0);
+ if(str->type == 0)
+ str->type = SDATA;
+ sv = str->value;
+ for(i = 0; i < ne; i++){
+ s = esyms[i];
+ if(debug['S'])
+ s->sig = 0;
+ /* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */
+
+ /* signature */
+ p = newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ p->to.offset = s->sig;
+
+ /* address */
+ p = newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ p->to.type = D_ADDR;
+ p->to.index = D_EXTERN;
+ p->to.sym = s;
+
+ /* string */
+ t = s->name;
+ n = strlen(t)+1;
+ for(;;){
+ buf[nb++] = *t;
+ sv++;
+ if(nb >= NSNAME){
+ p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
+ p->to.type = D_SCONST;
+ memmove(p->to.scon, buf, NSNAME);
+ nb = 0;
+ }
+ if(*t++ == 0)
+ break;
+ }
+
+ /* name */
+ p = newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ p->to.type = D_ADDR;
+ p->to.index = D_STATIC;
+ p->to.sym = str;
+ p->to.offset = sv-n;
+ }
+
+ if(nb > 0){
+ p = newdata(str, sv-nb, nb, D_STATIC);
+ p->to.type = D_SCONST;
+ memmove(p->to.scon, buf, nb);
+ }
+
+ for(i = 0; i < 3; i++){
+ newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ }
+ et->value = off;
+ if(sv == 0)
+ sv = 1;
+ str->value = sv;
+ exports = ne;
+ free(esyms);
+}
diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c
new file mode 100644
index 0000000..4b225da
--- /dev/null
+++ b/src/cmd/6l/span.c
@@ -0,0 +1,1776 @@
+// Inferno utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "l.h"
+
+static int rexflag;
+static int asmode;
+
+void
+span(void)
+{
+ Prog *p, *q;
+ long v;
+ vlong c, idat;
+ int m, n, again;
+
+ xdefine("etext", STEXT, 0L);
+ idat = INITDAT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ n = 0;
+ if(p->to.type == D_BRANCH)
+ if(p->pcond == P)
+ p->pcond = p;
+ if((q = p->pcond) != P)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = p->mode != 64? AADDL: AADDQ;
+ if(v < 0) {
+ p->as = p->mode != 64? ASUBL: ASUBQ;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
+ }
+ }
+ n = 0;
+
+start:
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+ Bflush(&bso);
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->to.type == D_BRANCH)
+ if(p->back)
+ p->pc = c;
+ asmins(p);
+ p->pc = c;
+ m = andptr-and;
+ p->mark = m;
+ c += m;
+ }
+
+loop:
+ n++;
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span %d\n", cputime(), n);
+ Bflush(&bso);
+ if(n > 50) {
+ print("span must be looping\n");
+ errorexit();
+ }
+ again = 0;
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->to.type == D_BRANCH || p->back & 0100) {
+ if(p->back)
+ p->pc = c;
+ asmins(p);
+ m = andptr-and;
+ if(m != p->mark) {
+ p->mark = m;
+ again++;
+ }
+ }
+ p->pc = c;
+ c += p->mark;
+ }
+ if(again) {
+ textsize = c;
+ goto loop;
+ }
+ if(INITRND) {
+ INITDAT = rnd(c, INITRND);
+ if(INITDAT != idat) {
+ idat = INITDAT;
+ goto start;
+ }
+ }
+ xdefine("etext", STEXT, c);
+ if(debug['v'])
+ Bprint(&bso, "etext = %llux\n", c);
+ Bflush(&bso);
+ for(p = textp; p != P; p = p->pcond)
+ p->from.sym->value = p->pc;
+ textsize = c - INITTEXT;
+}
+
+void
+xdefine(char *p, int t, vlong v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = t;
+ s->value = v;
+ }
+ if(s->type == STEXT && s->value == 0)
+ s->value = v;
+}
+
+void
+putsymb(char *s, int t, vlong v, int ver)
+{
+ int i, f, l;
+
+ if(t == 'f')
+ s++;
+ l = 4;
+ if(!debug['8']){
+ lput(v>>32);
+ l = 8;
+ }
+ lput(v);
+ if(ver)
+ t += 'a' - 'A';
+ cput(t+0x80); /* 0x80 is variable length */
+
+ if(t == 'Z' || t == 'z') {
+ cput(s[0]);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
+ cput(s[i]);
+ cput(s[i+1]);
+ }
+ cput(0);
+ cput(0);
+ i++;
+ }
+ else {
+ for(i=0; s[i]; i++)
+ cput(s[i]);
+ cput(0);
+ }
+ symsize += l + 1 + i + 1;
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8llux ", t, v);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
+ f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
+ Bprint(&bso, "/%x", f);
+ }
+ Bprint(&bso, "\n");
+ return;
+ }
+ if(ver)
+ Bprint(&bso, "%c %.8llux %s<%d>\n", t, v, s, ver);
+ else
+ Bprint(&bso, "%c %.8llux %s\n", t, v, s);
+ }
+}
+
+void
+asmsym(void)
+{
+ Prog *p;
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+
+ for(h=0; h<NHASH; h++)
+ for(s=hash[h]; s!=S; s=s->link)
+ switch(s->type) {
+ case SCONST:
+ putsymb(s->name, 'D', s->value, s->version);
+ continue;
+
+ case SDATA:
+ putsymb(s->name, 'D', s->value+INITDAT, s->version);
+ continue;
+
+ case SBSS:
+ putsymb(s->name, 'B', s->value+INITDAT, s->version);
+ continue;
+
+ case SFILE:
+ putsymb(s->name, 'f', s->value, s->version);
+ continue;
+ }
+
+ for(p=textp; p!=P; p=p->pcond) {
+ s = p->from.sym;
+ if(s->type != STEXT)
+ continue;
+
+ /* filenames first */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_FILE)
+ putsymb(a->asym->name, 'z', a->aoffset, 0);
+ else
+ if(a->type == D_FILE1)
+ putsymb(a->asym->name, 'Z', a->aoffset, 0);
+
+ putsymb(s->name, 'T', s->value, s->version);
+
+ /* frame, auto and param after */
+ putsymb(".frame", 'm', p->to.offset+8, 0);
+
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ putsymb(a->asym->name, 'a', -a->aoffset, 0);
+ else
+ if(a->type == D_PARAM)
+ putsymb(a->asym->name, 'p', a->aoffset, 0);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %lud\n", symsize);
+ Bflush(&bso);
+}
+
+void
+asmlc(void)
+{
+ vlong oldpc;
+ Prog *p;
+ long oldlc, v, s;
+
+ oldpc = INITTEXT;
+ oldlc = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['L'])
+ Bprint(&bso, "%6llux %P\n",
+ p->pc, p);
+ continue;
+ }
+ if(debug['L'])
+ Bprint(&bso, "\t\t%6ld", lcsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ cput(s+128); /* 129-255 +pc */
+ if(debug['L'])
+ Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
+ v -= s;
+ lcsize++;
+ }
+ s = p->line - oldlc;
+ oldlc = p->line;
+ oldpc = p->pc + MINLC;
+ if(s > 64 || s < -64) {
+ cput(0); /* 0 vv +lc */
+ cput(s>>24);
+ cput(s>>16);
+ cput(s>>8);
+ cput(s);
+ if(debug['L']) {
+ if(s > 0)
+ Bprint(&bso, " lc+%ld(%d,%ld)\n",
+ s, 0, s);
+ else
+ Bprint(&bso, " lc%ld(%d,%ld)\n",
+ s, 0, s);
+ Bprint(&bso, "%6llux %P\n",
+ p->pc, p);
+ }
+ lcsize += 5;
+ continue;
+ }
+ if(s > 0) {
+ cput(0+s); /* 1-64 +lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
+ Bprint(&bso, "%6llux %P\n",
+ p->pc, p);
+ }
+ } else {
+ cput(64-s); /* 65-128 -lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
+ Bprint(&bso, "%6llux %P\n",
+ p->pc, p);
+ }
+ }
+ lcsize++;
+ }
+ while(lcsize & 1) {
+ s = 129;
+ cput(s);
+ lcsize++;
+ }
+ if(debug['v'] || debug['L'])
+ Bprint(&bso, "lcsize = %ld\n", lcsize);
+ Bflush(&bso);
+}
+
+int
+oclass(Adr *a)
+{
+ vlong v;
+ long l;
+
+ if(a->type >= D_INDIR || a->index != D_NONE) {
+ if(a->index != D_NONE && a->scale == 0) {
+ if(a->type == D_ADDR) {
+ switch(a->index) {
+ case D_EXTERN:
+ case D_STATIC:
+ return Yi32; /* TO DO: Yi64 */
+ case D_AUTO:
+ case D_PARAM:
+ return Yiauto;
+ }
+ return Yxxx;
+ }
+ return Ycol;
+ }
+ return Ym;
+ }
+ switch(a->type)
+ {
+ case D_AL:
+ return Yal;
+
+ case D_AX:
+ return Yax;
+
+/*
+ case D_SPB:
+*/
+ case D_BPB:
+ case D_SIB:
+ case D_DIB:
+ case D_R8B:
+ case D_R9B:
+ case D_R10B:
+ case D_R11B:
+ case D_R12B:
+ case D_R13B:
+ case D_R14B:
+ case D_R15B:
+ if(asmode != 64)
+ return Yxxx;
+ case D_DL:
+ case D_BL:
+ case D_AH:
+ case D_CH:
+ case D_DH:
+ case D_BH:
+ return Yrb;
+
+ case D_CL:
+ return Ycl;
+
+ case D_CX:
+ return Ycx;
+
+ case D_DX:
+ case D_BX:
+ return Yrx;
+
+ case D_R8: /* not really Yrl */
+ case D_R9:
+ case D_R10:
+ case D_R11:
+ case D_R12:
+ case D_R13:
+ case D_R14:
+ case D_R15:
+ if(asmode != 64)
+ return Yxxx;
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ return Yrl;
+
+ case D_F0+0:
+ return Yf0;
+
+ case D_F0+1:
+ case D_F0+2:
+ case D_F0+3:
+ case D_F0+4:
+ case D_F0+5:
+ case D_F0+6:
+ case D_F0+7:
+ return Yrf;
+
+ case D_M0+0:
+ case D_M0+1:
+ case D_M0+2:
+ case D_M0+3:
+ case D_M0+4:
+ case D_M0+5:
+ case D_M0+6:
+ case D_M0+7:
+ return Ymr;
+
+ case D_X0+0:
+ case D_X0+1:
+ case D_X0+2:
+ case D_X0+3:
+ case D_X0+4:
+ case D_X0+5:
+ case D_X0+6:
+ case D_X0+7:
+ case D_X0+8:
+ case D_X0+9:
+ case D_X0+10:
+ case D_X0+11:
+ case D_X0+12:
+ case D_X0+13:
+ case D_X0+14:
+ case D_X0+15:
+ return Yxr;
+
+ case D_NONE:
+ return Ynone;
+
+ case D_CS: return Ycs;
+ case D_SS: return Yss;
+ case D_DS: return Yds;
+ case D_ES: return Yes;
+ case D_FS: return Yfs;
+ case D_GS: return Ygs;
+
+ case D_GDTR: return Ygdtr;
+ case D_IDTR: return Yidtr;
+ case D_LDTR: return Yldtr;
+ case D_MSW: return Ymsw;
+ case D_TASK: return Ytask;
+
+ case D_CR+0: return Ycr0;
+ case D_CR+1: return Ycr1;
+ case D_CR+2: return Ycr2;
+ case D_CR+3: return Ycr3;
+ case D_CR+4: return Ycr4;
+ case D_CR+5: return Ycr5;
+ case D_CR+6: return Ycr6;
+ case D_CR+7: return Ycr7;
+ case D_CR+8: return Ycr8;
+
+ case D_DR+0: return Ydr0;
+ case D_DR+1: return Ydr1;
+ case D_DR+2: return Ydr2;
+ case D_DR+3: return Ydr3;
+ case D_DR+4: return Ydr4;
+ case D_DR+5: return Ydr5;
+ case D_DR+6: return Ydr6;
+ case D_DR+7: return Ydr7;
+
+ case D_TR+0: return Ytr0;
+ case D_TR+1: return Ytr1;
+ case D_TR+2: return Ytr2;
+ case D_TR+3: return Ytr3;
+ case D_TR+4: return Ytr4;
+ case D_TR+5: return Ytr5;
+ case D_TR+6: return Ytr6;
+ case D_TR+7: return Ytr7;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ return Ym;
+
+ case D_CONST:
+ case D_ADDR:
+ if(a->sym == S) {
+ v = a->offset;
+ if(v == 0)
+ return Yi0;
+ if(v == 1)
+ return Yi1;
+ if(v >= -128 && v <= 127)
+ return Yi8;
+ l = v;
+ if((vlong)l == v)
+ return Ys32; /* can sign extend */
+ if((v>>32) == 0)
+ return Yi32; /* unsigned */
+ return Yi64;
+ }
+ return Yi32; /* TO DO: D_ADDR as Yi64 */
+
+ case D_BRANCH:
+ return Ybr;
+ }
+ return Yxxx;
+}
+
+void
+asmidx(Adr *a, int base)
+{
+ int i;
+
+ switch(a->index) {
+ default:
+ goto bad;
+
+ case D_NONE:
+ i = 4 << 3;
+ goto bas;
+
+ case D_R8:
+ case D_R9:
+ case D_R10:
+ case D_R11:
+ case D_R12:
+ case D_R13:
+ case D_R14:
+ case D_R15:
+ if(asmode != 64)
+ goto bad;
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i = reg[(int)a->index] << 3;
+ break;
+ }
+ switch(a->scale) {
+ default:
+ goto bad;
+ case 1:
+ break;
+ case 2:
+ i |= (1<<6);
+ break;
+ case 4:
+ i |= (2<<6);
+ break;
+ case 8:
+ i |= (3<<6);
+ break;
+ }
+bas:
+ switch(base) {
+ default:
+ goto bad;
+ case D_NONE: /* must be mod=00 */
+ i |= 5;
+ break;
+ case D_R8:
+ case D_R9:
+ case D_R10:
+ case D_R11:
+ case D_R12:
+ case D_R13:
+ case D_R14:
+ case D_R15:
+ if(asmode != 64)
+ goto bad;
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i |= reg[base];
+ break;
+ }
+ *andptr++ = i;
+ return;
+bad:
+ diag("asmidx: bad address %D", a);
+ *andptr++ = 0;
+ return;
+}
+
+static void
+put4(long v)
+{
+ if(dlm && curp != P && reloca != nil){
+ dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1);
+ reloca = nil;
+ }
+ andptr[0] = v;
+ andptr[1] = v>>8;
+ andptr[2] = v>>16;
+ andptr[3] = v>>24;
+ andptr += 4;
+}
+
+static void
+put8(vlong v)
+{
+ if(dlm && curp != P && reloca != nil){
+ dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1); /* TO DO */
+ reloca = nil;
+ }
+ andptr[0] = v;
+ andptr[1] = v>>8;
+ andptr[2] = v>>16;
+ andptr[3] = v>>24;
+ andptr[4] = v>>32;
+ andptr[5] = v>>40;
+ andptr[6] = v>>48;
+ andptr[7] = v>>56;
+ andptr += 8;
+}
+
+vlong
+vaddr(Adr *a)
+{
+ int t;
+ vlong v;
+ Sym *s;
+
+ t = a->type;
+ v = a->offset;
+ if(t == D_ADDR)
+ t = a->index;
+ switch(t) {
+ case D_STATIC:
+ case D_EXTERN:
+ s = a->sym;
+ if(s != nil) {
+ if(dlm && curp != P)
+ reloca = a;
+ switch(s->type) {
+ case SUNDEF:
+ ckoff(s, v);
+ case STEXT:
+ case SCONST:
+ if((uvlong)s->value < (uvlong)INITTEXT)
+ v += INITTEXT; /* TO DO */
+ v += s->value;
+ break;
+ default:
+ v += INITDAT + s->value;
+ }
+ }
+ }
+ return v;
+}
+
+static void
+asmandsz(Adr *a, int r, int rex, int m64)
+{
+ long v;
+ int t;
+ Adr aa;
+
+ rex &= (0x40 | Rxr);
+ v = a->offset;
+ t = a->type;
+ if(a->index != D_NONE) {
+ if(t >= D_INDIR) {
+ t -= D_INDIR;
+ rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
+ if(t == D_NONE) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, t);
+ put4(v);
+ return;
+ }
+ if(v == 0 && t != D_BP && t != D_R13) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, t);
+ return;
+ }
+ if(v >= -128 && v < 128) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, t);
+ *andptr++ = v;
+ return;
+ }
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, t);
+ put4(v);
+ return;
+ }
+ switch(t) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ aa.type = D_NONE+D_INDIR;
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ aa.type = D_SP+D_INDIR;
+ break;
+ }
+ aa.offset = vaddr(a);
+ aa.index = a->index;
+ aa.scale = a->scale;
+ asmandsz(&aa, r, rex, m64);
+ return;
+ }
+ if(t >= D_AL && t <= D_X0+15) {
+ if(v)
+ goto bad;
+ *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
+ rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
+ return;
+ }
+ if(t >= D_INDIR) {
+ t -= D_INDIR;
+ rexflag |= (regrex[t] & Rxb) | rex;
+ if(t == D_NONE) {
+ if(asmode != 64){
+ *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ put4(v);
+ return;
+ }
+ /* temporary */
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
+ *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
+ put4(v);
+ return;
+ }
+ if(t == D_SP || t == D_R12) {
+ if(v == 0) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(a, t);
+ return;
+ }
+ if(v >= -128 && v < 128) {
+ *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(a, t);
+ *andptr++ = v;
+ return;
+ }
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(a, t);
+ put4(v);
+ return;
+ }
+ if(t >= D_AX && t <= D_R15) {
+ if(v == 0 && t != D_BP && t != D_R13) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+ return;
+ }
+ if(v >= -128 && v < 128) {
+ andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+ andptr[1] = v;
+ andptr += 2;
+ return;
+ }
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ put4(v);
+ return;
+ }
+ goto bad;
+ }
+ switch(a->type) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ aa.type = D_NONE+D_INDIR;
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ aa.type = D_SP+D_INDIR;
+ break;
+ }
+ aa.index = D_NONE;
+ aa.scale = 1;
+ aa.offset = vaddr(a);
+ asmandsz(&aa, r, rex, m64);
+ return;
+bad:
+ diag("asmand: bad address %D", a);
+ return;
+}
+
+void
+asmand(Adr *a, Adr *ra)
+{
+ asmandsz(a, reg[ra->type], regrex[ra->type], 0);
+}
+
+void
+asmando(Adr *a, int o)
+{
+ asmandsz(a, o, 0, 0);
+}
+
+static void
+bytereg(Adr *a)
+{
+ if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15))
+ a->type = D_AL + (a->type-D_AX);
+}
+
+#define E 0xff
+Movtab ymovtab[] =
+{
+/* push */
+ {APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0},
+ {APUSHL, Yss, Ynone, 0, 0x16,E,0,0},
+ {APUSHL, Yds, Ynone, 0, 0x1e,E,0,0},
+ {APUSHL, Yes, Ynone, 0, 0x06,E,0,0},
+ {APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
+ {APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
+ {APUSHQ, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
+ {APUSHQ, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
+
+ {APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0},
+ {APUSHW, Yss, Ynone, 0, Pe,0x16,E,0},
+ {APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0},
+ {APUSHW, Yes, Ynone, 0, Pe,0x06,E,0},
+ {APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E},
+ {APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E},
+
+/* pop */
+ {APOPL, Ynone, Yds, 0, 0x1f,E,0,0},
+ {APOPL, Ynone, Yes, 0, 0x07,E,0,0},
+ {APOPL, Ynone, Yss, 0, 0x17,E,0,0},
+ {APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
+ {APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
+ {APOPQ, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
+ {APOPQ, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
+
+ {APOPW, Ynone, Yds, 0, Pe,0x1f,E,0},
+ {APOPW, Ynone, Yes, 0, Pe,0x07,E,0},
+ {APOPW, Ynone, Yss, 0, Pe,0x17,E,0},
+ {APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E},
+ {APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E},
+
+/* mov seg */
+ {AMOVW, Yes, Yml, 1, 0x8c,0,0,0},
+ {AMOVW, Ycs, Yml, 1, 0x8c,1,0,0},
+ {AMOVW, Yss, Yml, 1, 0x8c,2,0,0},
+ {AMOVW, Yds, Yml, 1, 0x8c,3,0,0},
+ {AMOVW, Yfs, Yml, 1, 0x8c,4,0,0},
+ {AMOVW, Ygs, Yml, 1, 0x8c,5,0,0},
+
+ {AMOVW, Yml, Yes, 2, 0x8e,0,0,0},
+ {AMOVW, Yml, Ycs, 2, 0x8e,1,0,0},
+ {AMOVW, Yml, Yss, 2, 0x8e,2,0,0},
+ {AMOVW, Yml, Yds, 2, 0x8e,3,0,0},
+ {AMOVW, Yml, Yfs, 2, 0x8e,4,0,0},
+ {AMOVW, Yml, Ygs, 2, 0x8e,5,0,0},
+
+/* mov cr */
+ {AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0},
+ {AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0},
+ {AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0},
+ {AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0},
+ {AMOVL, Ycr8, Yml, 3, 0x0f,0x20,8,0},
+ {AMOVQ, Ycr0, Yml, 3, 0x0f,0x20,0,0},
+ {AMOVQ, Ycr2, Yml, 3, 0x0f,0x20,2,0},
+ {AMOVQ, Ycr3, Yml, 3, 0x0f,0x20,3,0},
+ {AMOVQ, Ycr4, Yml, 3, 0x0f,0x20,4,0},
+ {AMOVQ, Ycr8, Yml, 3, 0x0f,0x20,8,0},
+
+ {AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0},
+ {AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0},
+ {AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0},
+ {AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0},
+ {AMOVL, Yml, Ycr8, 4, 0x0f,0x22,8,0},
+ {AMOVQ, Yml, Ycr0, 4, 0x0f,0x22,0,0},
+ {AMOVQ, Yml, Ycr2, 4, 0x0f,0x22,2,0},
+ {AMOVQ, Yml, Ycr3, 4, 0x0f,0x22,3,0},
+ {AMOVQ, Yml, Ycr4, 4, 0x0f,0x22,4,0},
+ {AMOVQ, Yml, Ycr8, 4, 0x0f,0x22,8,0},
+
+/* mov dr */
+ {AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0},
+ {AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0},
+ {AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0},
+ {AMOVQ, Ydr0, Yml, 3, 0x0f,0x21,0,0},
+ {AMOVQ, Ydr6, Yml, 3, 0x0f,0x21,6,0},
+ {AMOVQ, Ydr7, Yml, 3, 0x0f,0x21,7,0},
+
+ {AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0},
+ {AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0},
+ {AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0},
+ {AMOVQ, Yml, Ydr0, 4, 0x0f,0x23,0,0},
+ {AMOVQ, Yml, Ydr6, 4, 0x0f,0x23,6,0},
+ {AMOVQ, Yml, Ydr7, 4, 0x0f,0x23,7,0},
+
+/* mov tr */
+ {AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0},
+ {AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0},
+
+ {AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E},
+ {AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E},
+
+/* lgdt, sgdt, lidt, sidt */
+ {AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
+ {AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
+ {AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0},
+ {AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0},
+ {AMOVQ, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
+ {AMOVQ, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
+ {AMOVQ, Ym, Yidtr, 4, 0x0f,0x01,3,0},
+ {AMOVQ, Yidtr, Ym, 3, 0x0f,0x01,1,0},
+
+/* lldt, sldt */
+ {AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0},
+ {AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0},
+
+/* lmsw, smsw */
+ {AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0},
+ {AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0},
+
+/* ltr, str */
+ {AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0},
+ {AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0},
+
+/* load full pointer */
+ {AMOVL, Yml, Ycol, 5, 0,0,0,0},
+ {AMOVW, Yml, Ycol, 5, Pe,0,0,0},
+
+/* double shift */
+ {ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0},
+ {ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0},
+ {ASHLQ, Ycol, Yml, 6, Pw,0xa4,0xa5,0},
+ {ASHRQ, Ycol, Yml, 6, Pw,0xac,0xad,0},
+ {ASHLW, Ycol, Yml, 6, Pe,0xa4,0xa5,0},
+ {ASHRW, Ycol, Yml, 6, Pe,0xac,0xad,0},
+ 0
+};
+
+int
+isax(Adr *a)
+{
+
+ switch(a->type) {
+ case D_AX:
+ case D_AL:
+ case D_AH:
+ case D_INDIR+D_AX:
+ return 1;
+ }
+ if(a->index == D_AX)
+ return 1;
+ return 0;
+}
+
+void
+subreg(Prog *p, int from, int to)
+{
+
+ if(debug['Q'])
+ print("\n%P s/%R/%R/\n", p, from, to);
+
+ if(p->from.type == from)
+ p->from.type = to;
+ if(p->to.type == from)
+ p->to.type = to;
+
+ if(p->from.index == from)
+ p->from.index = to;
+ if(p->to.index == from)
+ p->to.index = to;
+
+ from += D_INDIR;
+ if(p->from.type == from)
+ p->from.type = to+D_INDIR;
+ if(p->to.type == from)
+ p->to.type = to+D_INDIR;
+
+ if(debug['Q'])
+ print("%P\n", p);
+}
+
+static int
+mediaop(Optab *o, int op, int osize, int z)
+{
+ switch(op){
+ case Pm:
+ case Pe:
+ case Pf2:
+ case Pf3:
+ if(osize != 1){
+ if(op != Pm)
+ *andptr++ = op;
+ *andptr++ = Pm;
+ op = o->op[++z];
+ break;
+ }
+ default:
+ if(andptr == and || andptr[-1] != Pm)
+ *andptr++ = Pm;
+ break;
+ }
+ *andptr++ = op;
+ return z;
+}
+
+void
+doasm(Prog *p)
+{
+ Optab *o;
+ Prog *q, pp;
+ uchar *t;
+ Movtab *mo;
+ int z, op, ft, tt, xo, l;
+ vlong v;
+
+ o = opindex[p->as];
+ if(o == nil) {
+ diag("asmins: missing op %P", p);
+ return;
+ }
+ ft = oclass(&p->from) * Ymax;
+ tt = oclass(&p->to) * Ymax;
+ t = o->ytab;
+ if(t == 0) {
+ diag("asmins: noproto %P", p);
+ return;
+ }
+ xo = o->op[0] == 0x0f;
+ for(z=0; *t; z+=t[3]+xo,t+=4)
+ if(ycover[ft+t[0]])
+ if(ycover[tt+t[1]])
+ goto found;
+ goto domov;
+
+found:
+ switch(o->prefix) {
+ case Pq: /* 16 bit escape and opcode escape */
+ *andptr++ = Pe;
+ *andptr++ = Pm;
+ break;
+
+ case Pf2: /* xmm opcode escape */
+ case Pf3:
+ *andptr++ = o->prefix;
+ *andptr++ = Pm;
+ break;
+
+ case Pm: /* opcode escape */
+ *andptr++ = Pm;
+ break;
+
+ case Pe: /* 16 bit escape */
+ *andptr++ = Pe;
+ break;
+
+ case Pw: /* 64-bit escape */
+ if(p->mode != 64)
+ diag("asmins: illegal 64: %P", p);
+ rexflag |= Pw;
+ break;
+
+ case Pb: /* botch */
+ bytereg(&p->from);
+ bytereg(&p->to);
+ break;
+
+ case P32: /* 32 bit but illegal if 64-bit mode */
+ if(p->mode == 64)
+ diag("asmins: illegal in 64-bit mode: %P", p);
+ break;
+
+ case Py: /* 64-bit only, no prefix */
+ if(p->mode != 64)
+ diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
+ break;
+ }
+ v = vaddr(&p->from);
+ op = o->op[z];
+ if(op == 0x0f) {
+ *andptr++ = op;
+ op = o->op[++z];
+ }
+ switch(t[2]) {
+ default:
+ diag("asmins: unknown z %d %P", t[2], p);
+ return;
+
+ case Zpseudo:
+ break;
+
+ case Zlit:
+ for(; op = o->op[z]; z++)
+ *andptr++ = op;
+ break;
+
+ case Zmb_r:
+ bytereg(&p->from);
+ /* fall through */
+ case Zm_r:
+ *andptr++ = op;
+ asmand(&p->from, &p->to);
+ break;
+
+ case Zm_r_xm:
+ mediaop(o, op, t[3], z);
+ asmand(&p->from, &p->to);
+ break;
+
+ case Zm_r_xm_nr:
+ rexflag = 0;
+ mediaop(o, op, t[3], z);
+ asmand(&p->from, &p->to);
+ break;
+
+ case Zm_r_i_xm:
+ mediaop(o, op, t[3], z);
+ asmand(&p->from, &p->to);
+ *andptr++ = p->to.offset;
+ break;
+
+ case Zm_r_3d:
+ *andptr++ = 0x0f;
+ *andptr++ = 0x0f;
+ asmand(&p->from, &p->to);
+ *andptr++ = op;
+ break;
+
+ case Zibm_r:
+ *andptr++ = op;
+ asmand(&p->from, &p->to);
+ *andptr++ = p->to.offset;
+ break;
+
+ case Zaut_r:
+ *andptr++ = 0x8d; /* leal */
+ if(p->from.type != D_ADDR)
+ diag("asmins: Zaut sb type ADDR");
+ p->from.type = p->from.index;
+ p->from.index = D_NONE;
+ asmand(&p->from, &p->to);
+ p->from.index = p->from.type;
+ p->from.type = D_ADDR;
+ break;
+
+ case Zm_o:
+ *andptr++ = op;
+ asmando(&p->from, o->op[z+1]);
+ break;
+
+ case Zr_m:
+ *andptr++ = op;
+ asmand(&p->to, &p->from);
+ break;
+
+ case Zr_m_xm:
+ mediaop(o, op, t[3], z);
+ asmand(&p->to, &p->from);
+ break;
+
+ case Zr_m_xm_nr:
+ rexflag = 0;
+ mediaop(o, op, t[3], z);
+ asmand(&p->to, &p->from);
+ break;
+
+ case Zr_m_i_xm:
+ mediaop(o, op, t[3], z);
+ asmand(&p->to, &p->from);
+ *andptr++ = p->from.offset;
+ break;
+
+ case Zo_m:
+ *andptr++ = op;
+ asmando(&p->to, o->op[z+1]);
+ break;
+
+ case Zo_m64:
+ *andptr++ = op;
+ asmandsz(&p->to, o->op[z+1], 0, 1);
+ break;
+
+ case Zm_ibo:
+ v = vaddr(&p->to);
+ *andptr++ = op;
+ asmando(&p->from, o->op[z+1]);
+ *andptr++ = v;
+ break;
+
+ case Zibo_m:
+ *andptr++ = op;
+ asmando(&p->to, o->op[z+1]);
+ *andptr++ = v;
+ break;
+
+ case Zibo_m_xm:
+ z = mediaop(o, op, t[3], z);
+ asmando(&p->to, o->op[z+1]);
+ *andptr++ = v;
+ break;
+
+ case Z_ib:
+ v = vaddr(&p->to);
+ case Zib_:
+ *andptr++ = op;
+ *andptr++ = v;
+ break;
+
+ case Zib_rp:
+ rexflag |= regrex[p->to.type] & (Rxb|0x40);
+ *andptr++ = op + reg[p->to.type];
+ *andptr++ = v;
+ break;
+
+ case Zil_rp:
+ rexflag |= regrex[p->to.type] & Rxb;
+ *andptr++ = op + reg[p->to.type];
+ if(o->prefix == Pe) {
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ put4(v);
+ break;
+
+ case Zo_iw:
+ *andptr++ = op;
+ if(p->from.type != D_NONE){
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ break;
+
+ case Ziq_rp:
+ l = v>>32;
+ if(l == 0){
+ //p->mark |= 0100;
+ //print("zero: %llux %P\n", v, p);
+ rexflag &= ~(0x40|Rxw);
+ rexflag |= regrex[p->to.type] & Rxb;
+ *andptr++ = 0xb8 + reg[p->to.type];
+ put4(v);
+ }else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */
+ //p->mark |= 0100;
+ //print("sign: %llux %P\n", v, p);
+ *andptr ++ = 0xc7;
+ asmando(&p->to, 0);
+ put4(v);
+ }else{ /* need all 8 */
+ //print("all: %llux %P\n", v, p);
+ rexflag |= regrex[p->to.type] & Rxb;
+ *andptr++ = op + reg[p->to.type];
+ put8(v);
+ }
+ break;
+
+ case Zib_rr:
+ *andptr++ = op;
+ asmand(&p->to, &p->to);
+ *andptr++ = v;
+ break;
+
+ case Z_il:
+ v = vaddr(&p->to);
+ case Zil_:
+ *andptr++ = op;
+ if(o->prefix == Pe) {
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ put4(v);
+ break;
+
+ case Zm_ilo:
+ v = vaddr(&p->to);
+ *andptr++ = op;
+ asmando(&p->from, o->op[z+1]);
+ if(o->prefix == Pe) {
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ put4(v);
+ break;
+
+ case Zilo_m:
+ *andptr++ = op;
+ asmando(&p->to, o->op[z+1]);
+ if(o->prefix == Pe) {
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ put4(v);
+ break;
+
+ case Zil_rr:
+ *andptr++ = op;
+ asmand(&p->to, &p->to);
+ if(o->prefix == Pe) {
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ put4(v);
+ break;
+
+ case Z_rp:
+ rexflag |= regrex[p->to.type] & (Rxb|0x40);
+ *andptr++ = op + reg[p->to.type];
+ break;
+
+ case Zrp_:
+ rexflag |= regrex[p->from.type] & (Rxb|0x40);
+ *andptr++ = op + reg[p->from.type];
+ break;
+
+ case Zclr:
+ *andptr++ = op;
+ asmand(&p->to, &p->to);
+ break;
+
+ case Zbr:
+ q = p->pcond;
+ if(q) {
+ v = q->pc - p->pc - 2;
+ if(v >= -128 && v <= 127) {
+ *andptr++ = op;
+ *andptr++ = v;
+ } else {
+ v -= 6-2;
+ *andptr++ = 0x0f;
+ *andptr++ = o->op[z+1];
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ }
+ }
+ break;
+
+ case Zcall:
+ q = p->pcond;
+ if(q) {
+ v = q->pc - p->pc - 5;
+ if(dlm && curp != P && p->to.sym->type == SUNDEF){
+ /* v = 0 - p->pc - 5; */
+ v = 0;
+ ckoff(p->to.sym, v);
+ v += p->to.sym->value;
+ dynreloc(p->to.sym, p->pc+1, 0);
+ }
+ *andptr++ = op;
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ }
+ break;
+
+ case Zjmp:
+ q = p->pcond;
+ if(q) {
+ v = q->pc - p->pc - 2;
+ if(v >= -128 && v <= 127) {
+ *andptr++ = op;
+ *andptr++ = v;
+ } else {
+ v -= 5-2;
+ *andptr++ = o->op[z+1];
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ }
+ }
+ break;
+
+ case Zloop:
+ q = p->pcond;
+ if(q) {
+ v = q->pc - p->pc - 2;
+ if(v < -128 && v > 127)
+ diag("loop too far: %P", p);
+ *andptr++ = op;
+ *andptr++ = v;
+ }
+ break;
+
+ case Zbyte:
+ *andptr++ = v;
+ if(op > 1) {
+ *andptr++ = v>>8;
+ if(op > 2) {
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ if(op > 4) {
+ *andptr++ = v>>32;
+ *andptr++ = v>>40;
+ *andptr++ = v>>48;
+ *andptr++ = v>>56;
+ }
+ }
+ }
+ break;
+ }
+ return;
+
+domov:
+ for(mo=ymovtab; mo->as; mo++)
+ if(p->as == mo->as)
+ if(ycover[ft+mo->ft])
+ if(ycover[tt+mo->tt]){
+ t = mo->op;
+ goto mfound;
+ }
+bad:
+ if(p->mode != 64){
+ /*
+ * here, the assembly has failed.
+ * if its a byte instruction that has
+ * unaddressable registers, try to
+ * exchange registers and reissue the
+ * instruction with the operands renamed.
+ */
+ pp = *p;
+ z = p->from.type;
+ if(z >= D_BP && z <= D_DI) {
+ if(isax(&p->to)) {
+ *andptr++ = 0x87; /* xchg lhs,bx */
+ asmando(&p->from, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(&pp);
+ *andptr++ = 0x87; /* xchg lhs,bx */
+ asmando(&p->from, reg[D_BX]);
+ } else {
+ *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(&pp);
+ *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ }
+ return;
+ }
+ z = p->to.type;
+ if(z >= D_BP && z <= D_DI) {
+ if(isax(&p->from)) {
+ *andptr++ = 0x87; /* xchg rhs,bx */
+ asmando(&p->to, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(&pp);
+ *andptr++ = 0x87; /* xchg rhs,bx */
+ asmando(&p->to, reg[D_BX]);
+ } else {
+ *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(&pp);
+ *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ }
+ return;
+ }
+ }
+ diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p);
+ return;
+
+mfound:
+ switch(mo->code) {
+ default:
+ diag("asmins: unknown mov %d %P", mo->code, p);
+ break;
+
+ case 0: /* lit */
+ for(z=0; t[z]!=E; z++)
+ *andptr++ = t[z];
+ break;
+
+ case 1: /* r,m */
+ *andptr++ = t[0];
+ asmando(&p->to, t[1]);
+ break;
+
+ case 2: /* m,r */
+ *andptr++ = t[0];
+ asmando(&p->from, t[1]);
+ break;
+
+ case 3: /* r,m - 2op */
+ *andptr++ = t[0];
+ *andptr++ = t[1];
+ asmando(&p->to, t[2]);
+ rexflag |= regrex[p->from.type] & (Rxr|0x40);
+ break;
+
+ case 4: /* m,r - 2op */
+ *andptr++ = t[0];
+ *andptr++ = t[1];
+ asmando(&p->from, t[2]);
+ rexflag |= regrex[p->to.type] & (Rxr|0x40);
+ break;
+
+ case 5: /* load full pointer, trash heap */
+ if(t[0])
+ *andptr++ = t[0];
+ switch(p->to.index) {
+ default:
+ goto bad;
+ case D_DS:
+ *andptr++ = 0xc5;
+ break;
+ case D_SS:
+ *andptr++ = 0x0f;
+ *andptr++ = 0xb2;
+ break;
+ case D_ES:
+ *andptr++ = 0xc4;
+ break;
+ case D_FS:
+ *andptr++ = 0x0f;
+ *andptr++ = 0xb4;
+ break;
+ case D_GS:
+ *andptr++ = 0x0f;
+ *andptr++ = 0xb5;
+ break;
+ }
+ asmand(&p->from, &p->to);
+ break;
+
+ case 6: /* double shift */
+ if(t[0] == Pw){
+ if(p->mode != 64)
+ diag("asmins: illegal 64: %P", p);
+ rexflag |= Pw;
+ t++;
+ }else if(t[0] == Pe){
+ *andptr++ = Pe;
+ t++;
+ }
+ z = p->from.type;
+ switch(z) {
+ default:
+ goto bad;
+ case D_CONST:
+ *andptr++ = 0x0f;
+ *andptr++ = t[0];
+ asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
+ *andptr++ = p->from.offset;
+ break;
+ case D_CL:
+ case D_CX:
+ *andptr++ = 0x0f;
+ *andptr++ = t[1];
+ asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
+ break;
+ }
+ break;
+ }
+}
+
+void
+asmins(Prog *p)
+{
+ int n, np, c;
+
+ rexflag = 0;
+ andptr = and;
+ asmode = p->mode;
+ doasm(p);
+ if(rexflag){
+ /*
+ * as befits the whole approach of the architecture,
+ * the rex prefix must appear before the first opcode byte
+ * (and thus after any 66/67/f2/f3 prefix bytes, but
+ * before the 0f opcode escape!), or it might be ignored.
+ * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
+ */
+ if(p->mode != 64)
+ diag("asmins: illegal in mode %d: %P", p->mode, p);
+ n = andptr - and;
+ for(np = 0; np < n; np++) {
+ c = and[np];
+ if(c != 0x66 && c != 0xf2 && c != 0xf3 && c != 0x67)
+ break;
+ }
+ memmove(and+np+1, and+np, n-np);
+ and[np] = 0x40 | rexflag;
+ andptr++;
+ }
+}
+
+enum{
+ ABSD = 0,
+ ABSU = 1,
+ RELD = 2,
+ RELU = 3,
+};
+
+int modemap[4] = { 0, 1, -1, 2, };
+
+typedef struct Reloc Reloc;
+
+struct Reloc
+{
+ int n;
+ int t;
+ uchar *m;
+ ulong *a;
+};
+
+Reloc rels;
+
+static void
+grow(Reloc *r)
+{
+ int t;
+ uchar *m, *nm;
+ ulong *a, *na;
+
+ t = r->t;
+ r->t += 64;
+ m = r->m;
+ a = r->a;
+ r->m = nm = malloc(r->t*sizeof(uchar));
+ r->a = na = malloc(r->t*sizeof(ulong));
+ memmove(nm, m, t*sizeof(uchar));
+ memmove(na, a, t*sizeof(ulong));
+ free(m);
+ free(a);
+}
+
+void
+dynreloc(Sym *s, ulong v, int abs)
+{
+ int i, k, n;
+ uchar *m;
+ ulong *a;
+ Reloc *r;
+
+ if(s->type == SUNDEF)
+ k = abs ? ABSU : RELU;
+ else
+ k = abs ? ABSD : RELD;
+ /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */
+ k = modemap[k];
+ r = &rels;
+ n = r->n;
+ if(n >= r->t)
+ grow(r);
+ m = r->m;
+ a = r->a;
+ for(i = n; i > 0; i--){
+ if(v < a[i-1]){ /* happens occasionally for data */
+ m[i] = m[i-1];
+ a[i] = a[i-1];
+ }
+ else
+ break;
+ }
+ m[i] = k;
+ a[i] = v;
+ r->n++;
+}
+
+static int
+sput(char *s)
+{
+ char *p;
+
+ p = s;
+ while(*s)
+ cput(*s++);
+ cput(0);
+ return s-p+1;
+}
+
+void
+asmdyn()
+{
+ int i, n, t, c;
+ Sym *s;
+ ulong la, ra, *a;
+ vlong off;
+ uchar *m;
+ Reloc *r;
+
+ cflush();
+ off = seek(cout, 0, 1);
+ lput(0);
+ t = 0;
+ lput(imports);
+ t += 4;
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SUNDEF){
+ lput(s->sig);
+ t += 4;
+ t += sput(s->name);
+ }
+
+ la = 0;
+ r = &rels;
+ n = r->n;
+ m = r->m;
+ a = r->a;
+ lput(n);
+ t += 4;
+ for(i = 0; i < n; i++){
+ ra = *a-la;
+ if(*a < la)
+ diag("bad relocation order");
+ if(ra < 256)
+ c = 0;
+ else if(ra < 65536)
+ c = 1;
+ else
+ c = 2;
+ cput((c<<6)|*m++);
+ t++;
+ if(c == 0){
+ cput(ra);
+ t++;
+ }
+ else if(c == 1){
+ wput(ra);
+ t += 2;
+ }
+ else{
+ lput(ra);
+ t += 4;
+ }
+ la = *a++;
+ }
+
+ cflush();
+ seek(cout, off, 0);
+ lput(t);
+
+ if(debug['v']){
+ Bprint(&bso, "import table entries = %d\n", imports);
+ Bprint(&bso, "export table entries = %d\n", exports);
+ }
+}
diff --git a/src/cmd/cc/acid.c b/src/cmd/cc/acid.c
new file mode 100644
index 0000000..62be5e8
--- /dev/null
+++ b/src/cmd/cc/acid.c
@@ -0,0 +1,331 @@
+// Inferno utils/cc/acid.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/acid.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+static char *kwd[] =
+{
+ "$adt", "$aggr", "$append", "$complex", "$defn",
+ "$delete", "$do", "$else", "$eval", "$head", "$if",
+ "$local", "$loop", "$return", "$tail", "$then",
+ "$union", "$whatis", "$while",
+};
+
+char*
+amap(char *s)
+{
+ int i, bot, top, new;
+
+ bot = 0;
+ top = bot + nelem(kwd) - 1;
+ while(bot <= top){
+ new = bot + (top - bot)/2;
+ i = strcmp(kwd[new]+1, s);
+ if(i == 0)
+ return kwd[new];
+
+ if(i < 0)
+ bot = new + 1;
+ else
+ top = new - 1;
+ }
+ return s;
+}
+
+Sym*
+acidsue(Type *t)
+{
+ int h;
+ Sym *s;
+
+ if(t != T)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->suetag && s->suetag->link == t)
+ return s;
+ return 0;
+}
+
+Sym*
+acidfun(Type *t)
+{
+ int h;
+ Sym *s;
+
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == t)
+ return s;
+ return 0;
+}
+
+char acidchar[NTYPE];
+Init acidcinit[] =
+{
+ TCHAR, 'C', 0,
+ TUCHAR, 'b', 0,
+ TSHORT, 'd', 0,
+ TUSHORT, 'u', 0,
+ TLONG, 'D', 0,
+ TULONG, 'U', 0,
+ TVLONG, 'V', 0,
+ TUVLONG, 'W', 0,
+ TFLOAT, 'f', 0,
+ TDOUBLE, 'F', 0,
+ TARRAY, 'a', 0,
+ TIND, 'X', 0,
+ -1, 0, 0,
+};
+
+static void
+acidinit(void)
+{
+ Init *p;
+
+ for(p=acidcinit; p->code >= 0; p++)
+ acidchar[p->code] = p->value;
+
+ acidchar[TINT] = acidchar[TLONG];
+ acidchar[TUINT] = acidchar[TULONG];
+ if(types[TINT]->width != types[TLONG]->width) {
+ acidchar[TINT] = acidchar[TSHORT];
+ acidchar[TUINT] = acidchar[TUSHORT];
+ if(types[TINT]->width != types[TSHORT]->width)
+ warn(Z, "acidmember int not long or short");
+ }
+
+}
+
+void
+acidmember(Type *t, long off, int flag)
+{
+ Sym *s, *s1;
+ Type *l;
+ static int acidcharinit = 0;
+
+ if(acidcharinit == 0) {
+ acidinit();
+ acidcharinit = 1;
+ }
+ s = t->sym;
+ switch(t->etype) {
+ default:
+ Bprint(&outbuf, " T%d\n", t->etype);
+ break;
+
+ case TIND:
+ if(s == S)
+ break;
+ if(flag) {
+ for(l=t; l->etype==TIND; l=l->link)
+ ;
+ if(typesu[l->etype]) {
+ s1 = acidsue(l->link);
+ if(s1 != S) {
+ Bprint(&outbuf, " 'A' %s %ld %s;\n",
+ amap(s1->name),
+ t->offset+off, amap(s->name));
+ break;
+ }
+ }
+ } else {
+ Bprint(&outbuf,
+ "\tprint(\"\t%s\t\", addr.%s\\X, \"\\n\");\n",
+ amap(s->name), amap(s->name));
+ break;
+ }
+
+ case TINT:
+ case TUINT:
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TFLOAT:
+ case TDOUBLE:
+ case TARRAY:
+ if(s == S)
+ break;
+ if(flag) {
+ Bprint(&outbuf, " '%c' %ld %s;\n",
+ acidchar[t->etype], t->offset+off, amap(s->name));
+ } else {
+ Bprint(&outbuf, "\tprint(\"\t%s\t\", addr.%s, \"\\n\");\n",
+ amap(s->name), amap(s->name));
+ }
+ break;
+
+ case TSTRUCT:
+ case TUNION:
+ s1 = acidsue(t->link);
+ if(s1 == S)
+ break;
+ if(flag) {
+ if(s == S) {
+ Bprint(&outbuf, " {\n");
+ for(l = t->link; l != T; l = l->down)
+ acidmember(l, t->offset+off, flag);
+ Bprint(&outbuf, " };\n");
+ } else {
+ Bprint(&outbuf, " %s %ld %s;\n",
+ amap(s1->name),
+ t->offset+off, amap(s->name));
+ }
+ } else {
+ if(s != S) {
+ Bprint(&outbuf, "\tprint(\"%s %s {\\n\");\n",
+ amap(s1->name), amap(s->name));
+ Bprint(&outbuf, "\t%s(addr.%s);\n",
+ amap(s1->name), amap(s->name));
+ Bprint(&outbuf, "\tprint(\"}\\n\");\n");
+ } else {
+ Bprint(&outbuf, "\tprint(\"%s {\\n\");\n",
+ amap(s1->name));
+ Bprint(&outbuf, "\t\t%s(addr+%ld);\n",
+ amap(s1->name), t->offset+off);
+ Bprint(&outbuf, "\tprint(\"}\\n\");\n");
+ }
+ }
+ break;
+ }
+}
+
+void
+acidtype(Type *t)
+{
+ Sym *s;
+ Type *l;
+ Io *i;
+ int n;
+ char *an;
+
+ if(!debug['a'])
+ return;
+ if(debug['a'] > 1) {
+ n = 0;
+ for(i=iostack; i; i=i->link)
+ n++;
+ if(n > 1)
+ return;
+ }
+ s = acidsue(t->link);
+ if(s == S)
+ return;
+ switch(t->etype) {
+ default:
+ Bprint(&outbuf, "T%d\n", t->etype);
+ return;
+
+ case TUNION:
+ case TSTRUCT:
+ if(debug['s'])
+ goto asmstr;
+ an = amap(s->name);
+ Bprint(&outbuf, "sizeof%s = %ld;\n", an, t->width);
+ Bprint(&outbuf, "aggr %s\n{\n", an);
+ for(l = t->link; l != T; l = l->down)
+ acidmember(l, 0, 1);
+ Bprint(&outbuf, "};\n\n");
+
+ Bprint(&outbuf, "defn\n%s(addr) {\n\tcomplex %s addr;\n", an, an);
+ for(l = t->link; l != T; l = l->down)
+ acidmember(l, 0, 0);
+ Bprint(&outbuf, "};\n\n");
+ break;
+ asmstr:
+ if(s == S)
+ break;
+ for(l = t->link; l != T; l = l->down)
+ if(l->sym != S)
+ Bprint(&outbuf, "#define\t%s.%s\t%ld\n",
+ s->name,
+ l->sym->name,
+ l->offset);
+ break;
+ }
+}
+
+void
+acidvar(Sym *s)
+{
+ int n;
+ Io *i;
+ Type *t;
+ Sym *s1, *s2;
+
+ if(!debug['a'] || debug['s'])
+ return;
+ if(debug['a'] > 1) {
+ n = 0;
+ for(i=iostack; i; i=i->link)
+ n++;
+ if(n > 1)
+ return;
+ }
+ t = s->type;
+ while(t && t->etype == TIND)
+ t = t->link;
+ if(t == T)
+ return;
+ if(t->etype == TENUM) {
+ Bprint(&outbuf, "%s = ", amap(s->name));
+ if(!typefd[t->etype])
+ Bprint(&outbuf, "%lld;\n", s->vconst);
+ else
+ Bprint(&outbuf, "%f\n;", s->fconst);
+ return;
+ }
+ if(!typesu[t->etype])
+ return;
+ s1 = acidsue(t->link);
+ if(s1 == S)
+ return;
+ switch(s->class) {
+ case CAUTO:
+ case CPARAM:
+ s2 = acidfun(thisfn);
+ if(s2)
+ Bprint(&outbuf, "complex %s %s:%s;\n",
+ amap(s1->name), amap(s2->name), amap(s->name));
+ break;
+
+ case CSTATIC:
+ case CEXTERN:
+ case CGLOBL:
+ case CLOCAL:
+ Bprint(&outbuf, "complex %s %s;\n",
+ amap(s1->name), amap(s->name));
+ break;
+ }
+}
diff --git a/src/cmd/cc/bits.c b/src/cmd/cc/bits.c
new file mode 100644
index 0000000..31e788c
--- /dev/null
+++ b/src/cmd/cc/bits.c
@@ -0,0 +1,119 @@
+// Inferno utils/cc/bits.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+Bits
+bor(Bits a, Bits b)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = a.b[i] | b.b[i];
+ return c;
+}
+
+Bits
+band(Bits a, Bits b)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = a.b[i] & b.b[i];
+ return c;
+}
+
+/*
+Bits
+bnot(Bits a)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = ~a.b[i];
+ return c;
+}
+*/
+
+int
+bany(Bits *a)
+{
+ int i;
+
+ for(i=0; i<BITS; i++)
+ if(a->b[i])
+ return 1;
+ return 0;
+}
+
+int
+beq(Bits a, Bits b)
+{
+ int i;
+
+ for(i=0; i<BITS; i++)
+ if(a.b[i] != b.b[i])
+ return 0;
+ return 1;
+}
+
+int
+bnum(Bits a)
+{
+ int i;
+ long b;
+
+ for(i=0; i<BITS; i++)
+ if(b = a.b[i])
+ return 32*i + bitno(b);
+ diag(Z, "bad in bnum");
+ return 0;
+}
+
+Bits
+blsh(uint n)
+{
+ Bits c;
+
+ c = zbits;
+ c.b[n/32] = 1L << (n%32);
+ return c;
+}
+
+int
+bset(Bits a, uint n)
+{
+ if(a.b[n/32] & (1L << (n%32)))
+ return 1;
+ return 0;
+}
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
new file mode 100644
index 0000000..db1cf94
--- /dev/null
+++ b/src/cmd/cc/cc.h
@@ -0,0 +1,795 @@
+// Inferno utils/cc/cc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include "compat.h"
+
+#pragma lib "../cc/cc.a$O"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Node Node;
+typedef struct Sym Sym;
+typedef struct Type Type;
+typedef struct Funct Funct;
+typedef struct Decl Decl;
+typedef struct Io Io;
+typedef struct Hist Hist;
+typedef struct Term Term;
+typedef struct Init Init;
+typedef struct Bits Bits;
+
+#define NHUNK 50000L
+#define BUFSIZ 8192
+#define NSYMB 500
+#define NHASH 1024
+#define STRINGSZ 200
+#define HISTSZ 20
+#define YYMAXDEPTH 500
+#define NTERM 10
+#define MAXALIGN 7
+
+#define SIGN(n) ((vlong)1<<(n-1))
+#define MASK(n) (SIGN(n)|(SIGN(n)-1))
+
+#define BITS 5
+#define NVAR (BITS*sizeof(ulong)*8)
+struct Bits
+{
+ ulong b[BITS];
+};
+
+struct Node
+{
+ Node* left;
+ Node* right;
+ void* label;
+ long pc;
+ int reg;
+ long xoffset;
+ double fconst; /* fp constant */
+ vlong vconst; /* non fp const */
+ char* cstring; /* character string */
+ ushort* rstring; /* rune string */
+
+ Sym* sym;
+ Type* type;
+ long lineno;
+ uchar op;
+ uchar oldop;
+ uchar xcast;
+ uchar class;
+ uchar etype;
+ uchar complex;
+ uchar addable;
+ uchar scale;
+ uchar garb;
+};
+#define Z ((Node*)0)
+
+struct Sym
+{
+ Sym* link;
+ Type* type;
+ Type* suetag;
+ Type* tenum;
+ char* macro;
+ long varlineno;
+ long offset;
+ vlong vconst;
+ double fconst;
+ Node* label;
+ ushort lexical;
+ char *name;
+ ushort block;
+ ushort sueblock;
+ uchar class;
+ uchar sym;
+ uchar aused;
+ uchar sig;
+};
+#define S ((Sym*)0)
+
+enum{
+ SIGNONE = 0,
+ SIGDONE = 1,
+ SIGINTERN = 2,
+
+ SIGNINTERN = 1729*325*1729,
+};
+
+struct Decl
+{
+ Decl* link;
+ Sym* sym;
+ Type* type;
+ long varlineno;
+ long offset;
+ short val;
+ ushort block;
+ uchar class;
+ uchar aused;
+};
+#define D ((Decl*)0)
+
+struct Type
+{
+ Sym* sym;
+ Sym* tag;
+ Funct* funct;
+ Type* link;
+ Type* down;
+ long width;
+ long offset;
+ long lineno;
+ uchar shift;
+ uchar nbits;
+ uchar etype;
+ uchar garb;
+};
+
+#define T ((Type*)0)
+#define NODECL ((void(*)(int, Type*, Sym*))0)
+
+struct Init /* general purpose initialization */
+{
+ int code;
+ ulong value;
+ char* s;
+};
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char* p;
+ char b[BUFSIZ];
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ long offset;
+};
+#define H ((Hist*)0)
+EXTERN Hist* hist;
+
+struct Term
+{
+ vlong mult;
+ Node *node;
+};
+
+enum
+{
+ Axxx,
+ Ael1,
+ Ael2,
+ Asu2,
+ Aarg0,
+ Aarg1,
+ Aarg2,
+ Aaut3,
+ NALIGN,
+};
+
+enum
+{
+ DMARK,
+ DAUTO,
+ DSUE,
+ DLABEL,
+};
+enum
+{
+ OXXX,
+ OADD,
+ OADDR,
+ OAND,
+ OANDAND,
+ OARRAY,
+ OAS,
+ OASI,
+ OASADD,
+ OASAND,
+ OASASHL,
+ OASASHR,
+ OASDIV,
+ OASHL,
+ OASHR,
+ OASLDIV,
+ OASLMOD,
+ OASLMUL,
+ OASLSHR,
+ OASMOD,
+ OASMUL,
+ OASOR,
+ OASSUB,
+ OASXOR,
+ OBIT,
+ OBREAK,
+ OCASE,
+ OCAST,
+ OCOMMA,
+ OCOND,
+ OCONST,
+ OCONTINUE,
+ ODIV,
+ ODOT,
+ ODOTDOT,
+ ODWHILE,
+ OENUM,
+ OEQ,
+ OFOR,
+ OFUNC,
+ OGE,
+ OGOTO,
+ OGT,
+ OHI,
+ OHS,
+ OIF,
+ OIND,
+ OINDREG,
+ OINIT,
+ OLABEL,
+ OLDIV,
+ OLE,
+ OLIST,
+ OLMOD,
+ OLMUL,
+ OLO,
+ OLS,
+ OLSHR,
+ OLT,
+ OMOD,
+ OMUL,
+ ONAME,
+ ONE,
+ ONOT,
+ OOR,
+ OOROR,
+ OPOSTDEC,
+ OPOSTINC,
+ OPREDEC,
+ OPREINC,
+ OPROTO,
+ OREGISTER,
+ ORETURN,
+ OSET,
+ OSIGN,
+ OSIZE,
+ OSTRING,
+ OLSTRING,
+ OSTRUCT,
+ OSUB,
+ OSWITCH,
+ OUNION,
+ OUSED,
+ OWHILE,
+ OXOR,
+ ONEG,
+ OCOM,
+ OPOS,
+ OELEM,
+
+ OTST, /* used in some compilers */
+ OINDEX,
+ OFAS,
+ OREGPAIR,
+
+ OEND
+};
+enum
+{
+ TXXX,
+ TCHAR,
+ TUCHAR,
+ TSHORT,
+ TUSHORT,
+ TINT,
+ TUINT,
+ TLONG,
+ TULONG,
+ TVLONG,
+ TUVLONG,
+ TFLOAT,
+ TDOUBLE,
+ TIND,
+ TFUNC,
+ TARRAY,
+ TVOID,
+ TSTRUCT,
+ TUNION,
+ TENUM,
+ NTYPE,
+
+ TAUTO = NTYPE,
+ TEXTERN,
+ TSTATIC,
+ TTYPEDEF,
+ TTYPESTR,
+ TREGISTER,
+ TCONSTNT,
+ TVOLATILE,
+ TUNSIGNED,
+ TSIGNED,
+ TDOT,
+ TFILE,
+ TOLD,
+ NALLTYPES,
+};
+enum
+{
+ CXXX,
+ CAUTO,
+ CEXTERN,
+ CGLOBL,
+ CSTATIC,
+ CLOCAL,
+ CTYPEDEF,
+ CTYPESTR,
+ CPARAM,
+ CSELEM,
+ CLABEL,
+ CEXREG,
+ NCTYPES,
+};
+enum
+{
+ GXXX = 0,
+ GCONSTNT = 1<<0,
+ GVOLATILE = 1<<1,
+ NGTYPES = 1<<2,
+
+ GINCOMPLETE = 1<<2,
+};
+enum
+{
+ BCHAR = 1L<<TCHAR,
+ BUCHAR = 1L<<TUCHAR,
+ BSHORT = 1L<<TSHORT,
+ BUSHORT = 1L<<TUSHORT,
+ BINT = 1L<<TINT,
+ BUINT = 1L<<TUINT,
+ BLONG = 1L<<TLONG,
+ BULONG = 1L<<TULONG,
+ BVLONG = 1L<<TVLONG,
+ BUVLONG = 1L<<TUVLONG,
+ BFLOAT = 1L<<TFLOAT,
+ BDOUBLE = 1L<<TDOUBLE,
+ BIND = 1L<<TIND,
+ BFUNC = 1L<<TFUNC,
+ BARRAY = 1L<<TARRAY,
+ BVOID = 1L<<TVOID,
+ BSTRUCT = 1L<<TSTRUCT,
+ BUNION = 1L<<TUNION,
+ BENUM = 1L<<TENUM,
+ BFILE = 1L<<TFILE,
+ BDOT = 1L<<TDOT,
+ BCONSTNT = 1L<<TCONSTNT,
+ BVOLATILE = 1L<<TVOLATILE,
+ BUNSIGNED = 1L<<TUNSIGNED,
+ BSIGNED = 1L<<TSIGNED,
+ BAUTO = 1L<<TAUTO,
+ BEXTERN = 1L<<TEXTERN,
+ BSTATIC = 1L<<TSTATIC,
+ BTYPEDEF = 1L<<TTYPEDEF,
+ BTYPESTR = 1L<<TTYPESTR,
+ BREGISTER = 1L<<TREGISTER,
+
+ BINTEGER = BCHAR|BUCHAR|BSHORT|BUSHORT|BINT|BUINT|
+ BLONG|BULONG|BVLONG|BUVLONG,
+ BNUMBER = BINTEGER|BFLOAT|BDOUBLE,
+
+/* these can be overloaded with complex types */
+
+ BCLASS = BAUTO|BEXTERN|BSTATIC|BTYPEDEF|BTYPESTR|BREGISTER,
+ BGARB = BCONSTNT|BVOLATILE,
+};
+
+struct Funct
+{
+ Sym* sym[OEND];
+ Sym* castto[NTYPE];
+ Sym* castfr[NTYPE];
+};
+
+EXTERN struct
+{
+ Type* tenum; /* type of entire enum */
+ Type* cenum; /* type of current enum run */
+ vlong lastenum; /* value of current enum */
+ double floatenum; /* value of current enum */
+} en;
+
+EXTERN int autobn;
+EXTERN long autoffset;
+EXTERN int blockno;
+EXTERN Decl* dclstack;
+EXTERN char debug[256];
+EXTERN Hist* ehist;
+EXTERN long firstbit;
+EXTERN Sym* firstarg;
+EXTERN Type* firstargtype;
+EXTERN Decl* firstdcl;
+EXTERN int fperror;
+EXTERN Sym* hash[NHASH];
+EXTERN char* hunk;
+EXTERN char* include[20];
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN long lastbit;
+EXTERN char lastclass;
+EXTERN Type* lastdcl;
+EXTERN long lastfield;
+EXTERN Type* lasttype;
+EXTERN long lineno;
+EXTERN long nearln;
+EXTERN int nerrors;
+EXTERN int newflag;
+EXTERN long nhunk;
+EXTERN int ninclude;
+EXTERN Node* nodproto;
+EXTERN Node* nodcast;
+EXTERN Biobuf outbuf;
+EXTERN Biobuf diagbuf;
+EXTERN char* outfile;
+EXTERN char* pathname;
+EXTERN int peekc;
+EXTERN long stkoff;
+EXTERN Type* strf;
+EXTERN Type* strl;
+EXTERN char symb[NSYMB];
+EXTERN Sym* symstring;
+EXTERN int taggen;
+EXTERN Type* tfield;
+EXTERN Type* tufield;
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN Type* thisfn;
+EXTERN long thunk;
+EXTERN Type* types[NTYPE];
+EXTERN Type* fntypes[NTYPE];
+EXTERN Node* initlist;
+EXTERN Term term[NTERM];
+EXTERN int nterm;
+EXTERN int packflg;
+EXTERN int fproundflg;
+EXTERN int profileflg;
+EXTERN int ncontin;
+EXTERN int canreach;
+EXTERN int warnreach;
+EXTERN Bits zbits;
+
+extern char *onames[], *tnames[], *gnames[];
+extern char *cnames[], *qnames[], *bnames[];
+extern uchar tab[NTYPE][NTYPE];
+extern uchar comrel[], invrel[], logrel[];
+extern long ncast[], tadd[], tand[];
+extern long targ[], tasadd[], tasign[], tcast[];
+extern long tdot[], tfunct[], tindir[], tmul[];
+extern long tnot[], trel[], tsub[];
+
+extern uchar typeaf[];
+extern uchar typefd[];
+extern uchar typei[];
+extern uchar typesu[];
+extern uchar typesuv[];
+extern uchar typeu[];
+extern uchar typev[];
+extern uchar typec[];
+extern uchar typeh[];
+extern uchar typeil[];
+extern uchar typeilp[];
+extern uchar typechl[];
+extern uchar typechlv[];
+extern uchar typechlvp[];
+extern uchar typechlp[];
+extern uchar typechlpfd[];
+
+EXTERN uchar* typeword;
+EXTERN uchar* typecmplx;
+
+extern ulong thash1;
+extern ulong thash2;
+extern ulong thash3;
+extern ulong thash[];
+
+/*
+ * compat.c/unix.c/windows.c
+ */
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+int myaccess(char*);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
+
+/*
+ * parser
+ */
+int yyparse(void);
+int mpatov(char*, vlong*);
+
+/*
+ * lex.c
+ */
+void* allocn(void*, long, long);
+void* alloc(long);
+void cinit(void);
+int compile(char*, char**, int);
+void errorexit(void);
+int filbuf(void);
+int getc(void);
+long getr(void);
+int getnsc(void);
+Sym* lookup(void);
+void main(int, char*[]);
+void newfile(char*, int);
+void newio(void);
+void pushio(void);
+long escchar(long, int, int);
+Sym* slookup(char*);
+void syminit(Sym*);
+void unget(int);
+long yylex(void);
+int Lconv(Fmt*);
+int Tconv(Fmt*);
+int FNconv(Fmt*);
+int Oconv(Fmt*);
+int Qconv(Fmt*);
+int VBconv(Fmt*);
+void setinclude(char*);
+
+/*
+ * mac.c
+ */
+void dodefine(char*);
+void domacro(void);
+Sym* getsym(void);
+long getnsn(void);
+void linehist(char*, int);
+void macdef(void);
+void macprag(void);
+void macend(void);
+void macexpand(Sym*, char*);
+void macif(int);
+void macinc(void);
+void maclin(void);
+void macund(void);
+
+/*
+ * dcl.c
+ */
+Node* doinit(Sym*, Type*, long, Node*);
+Type* tcopy(Type*);
+Node* init1(Sym*, Type*, long, int);
+Node* newlist(Node*, Node*);
+void adecl(int, Type*, Sym*);
+int anyproto(Node*);
+void argmark(Node*, int);
+void dbgdecl(Sym*);
+Node* dcllabel(Sym*, int);
+Node* dodecl(void(*)(int, Type*, Sym*), int, Type*, Node*);
+Sym* mkstatic(Sym*);
+void doenum(Sym*, Node*);
+void snap(Type*);
+Type* dotag(Sym*, int, int);
+void edecl(int, Type*, Sym*);
+Type* fnproto(Node*);
+Type* fnproto1(Node*);
+void markdcl(void);
+Type* paramconv(Type*, int);
+void pdecl(int, Type*, Sym*);
+Decl* push(void);
+Decl* push1(Sym*);
+Node* revertdcl(void);
+long xround(long, int);
+int rsametype(Type*, Type*, int, int);
+int sametype(Type*, Type*);
+ulong sign(Sym*);
+ulong signature(Type*);
+void suallign(Type*);
+void tmerge(Type*, Sym*);
+void walkparam(Node*, int);
+void xdecl(int, Type*, Sym*);
+Node* contig(Sym*, Node*, long);
+
+/*
+ * com.c
+ */
+void ccom(Node*);
+void complex(Node*);
+int tcom(Node*);
+int tcoma(Node*, Node*, Type*, int);
+int tcomd(Node*);
+int tcomo(Node*, int);
+int tcomx(Node*);
+int tlvalue(Node*);
+void constas(Node*, Type*, Type*);
+
+/*
+ * con.c
+ */
+void acom(Node*);
+void acom1(vlong, Node*);
+void acom2(Node*, Type*);
+int acomcmp1(const void*, const void*);
+int acomcmp2(const void*, const void*);
+int addo(Node*);
+void evconst(Node*);
+
+/*
+ * funct.c
+ */
+int isfunct(Node*);
+void dclfunct(Type*, Sym*);
+
+/*
+ * sub.c
+ */
+void arith(Node*, int);
+int deadheads(Node*);
+Type* dotsearch(Sym*, Type*, Node*, long*);
+long dotoffset(Type*, Type*, Node*);
+void gethunk(void);
+Node* invert(Node*);
+int bitno(long);
+void makedot(Node*, Type*, long);
+int mixedasop(Type*, Type*);
+Node* new(int, Node*, Node*);
+Node* new1(int, Node*, Node*);
+int nilcast(Type*, Type*);
+int nocast(Type*, Type*);
+void prtree(Node*, char*);
+void prtree1(Node*, int, int);
+void relcon(Node*, Node*);
+int relindex(int);
+int simpleg(long);
+Type* garbt(Type*, long);
+int simplec(long);
+Type* simplet(long);
+int stcompat(Node*, Type*, Type*, long[]);
+int tcompat(Node*, Type*, Type*, long[]);
+void tinit(void);
+Type* typ(int, Type*);
+Type* copytyp(Type*);
+void typeext(Type*, Node*);
+void typeext1(Type*, Node*);
+int side(Node*);
+int vconst(Node*);
+int xlog2(uvlong);
+int vlog(Node*);
+int topbit(ulong);
+void simplifyshift(Node*);
+long typebitor(long, long);
+void diag(Node*, char*, ...);
+void warn(Node*, char*, ...);
+void yyerror(char*, ...);
+void fatal(Node*, char*, ...);
+
+/*
+ * acid.c
+ */
+void acidtype(Type*);
+void acidvar(Sym*);
+
+/*
+ * pickle.c
+ */
+void pickletype(Type*);
+
+/*
+ * bits.c
+ */
+Bits bor(Bits, Bits);
+Bits band(Bits, Bits);
+Bits bnot(Bits);
+int bany(Bits*);
+int bnum(Bits);
+Bits blsh(uint);
+int beq(Bits, Bits);
+int bset(Bits, uint);
+
+/*
+ * dpchk.c
+ */
+void dpcheck(Node*);
+void arginit(void);
+void pragvararg(void);
+void pragpack(void);
+void pragfpround(void);
+void pragprofile(void);
+void pragincomplete(void);
+
+/*
+ * calls to machine depend part
+ */
+void codgen(Node*, Node*);
+void gclean(void);
+void gextern(Sym*, Node*, long, long);
+void ginit(void);
+long outstring(char*, long);
+long outlstring(ushort*, long);
+void sextern(Sym*, Node*, long, long);
+void xcom(Node*);
+long exreg(Type*);
+long align(long, Type*, int);
+long maxround(long, long);
+
+extern schar ewidth[];
+
+/*
+ * com64
+ */
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+double convvtof(vlong);
+vlong convftov(double);
+double convftox(double, int);
+vlong convvtox(vlong, int);
+
+/*
+ * machcap
+ */
+int machcap(Node*);
+
+#pragma varargck argpos warn 2
+#pragma varargck argpos diag 2
+#pragma varargck argpos yyerror 1
+
+#pragma varargck type "F" Node*
+#pragma varargck type "L" long
+#pragma varargck type "Q" long
+#pragma varargck type "O" int
+#pragma varargck type "T" Type*
+#pragma varargck type "|" int
diff --git a/src/cmd/cc/cc.y b/src/cmd/cc/cc.y
new file mode 100644
index 0000000..1abcddd
--- /dev/null
+++ b/src/cmd/cc/cc.y
@@ -0,0 +1,1205 @@
+// Inferno utils/cc/cc.y
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.y
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+%{
+#include "cc.h"
+%}
+%union {
+ Node* node;
+ Sym* sym;
+ Type* type;
+ struct
+ {
+ Type* t;
+ uchar c;
+ } tycl;
+ struct
+ {
+ Type* t1;
+ Type* t2;
+ } tyty;
+ struct
+ {
+ char* s;
+ long l;
+ } sval;
+ long lval;
+ double dval;
+ vlong vval;
+}
+%type <sym> ltag
+%type <lval> gctname gcname cname gname tname
+%type <lval> gctnlist gcnlist zgnlist
+%type <type> tlist sbody complex
+%type <tycl> types
+%type <node> zarglist arglist zcexpr
+%type <node> name block stmnt cexpr expr xuexpr pexpr
+%type <node> zelist elist adecl slist uexpr string lstring
+%type <node> xdecor xdecor2 labels label ulstmnt
+%type <node> adlist edecor tag qual qlist
+%type <node> abdecor abdecor1 abdecor2 abdecor3
+%type <node> zexpr lexpr init ilist forexpr
+
+%left ';'
+%left ','
+%right '=' LPE LME LMLE LDVE LMDE LRSHE LLSHE LANDE LXORE LORE
+%right '?' ':'
+%left LOROR
+%left LANDAND
+%left '|'
+%left '^'
+%left '&'
+%left LEQ LNE
+%left '<' '>' LLE LGE
+%left LLSH LRSH
+%left '+' '-'
+%left '*' '/' '%'
+%right LMM LPP LMG '.' '[' '('
+
+%token <sym> LNAME LTYPE
+%token <dval> LFCONST LDCONST
+%token <vval> LCONST LLCONST LUCONST LULCONST LVLCONST LUVLCONST
+%token <sval> LSTRING LLSTRING
+%token LAUTO LBREAK LCASE LCHAR LCONTINUE LDEFAULT LDO
+%token LDOUBLE LELSE LEXTERN LFLOAT LFOR LGOTO
+%token LIF LINT LLONG LREGISTER LRETURN LSHORT LSIZEOF LUSED
+%token LSTATIC LSTRUCT LSWITCH LTYPEDEF LTYPESTR LUNION LUNSIGNED
+%token LWHILE LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF
+%token LRESTRICT LINLINE
+%%
+prog:
+| prog xdecl
+
+/*
+ * external declarator
+ */
+xdecl:
+ zctlist ';'
+ {
+ dodecl(xdecl, lastclass, lasttype, Z);
+ }
+| zctlist xdlist ';'
+| zctlist xdecor
+ {
+ lastdcl = T;
+ firstarg = S;
+ dodecl(xdecl, lastclass, lasttype, $2);
+ if(lastdcl == T || lastdcl->etype != TFUNC) {
+ diag($2, "not a function");
+ lastdcl = types[TFUNC];
+ }
+ thisfn = lastdcl;
+ markdcl();
+ firstdcl = dclstack;
+ argmark($2, 0);
+ }
+ pdecl
+ {
+ argmark($2, 1);
+ }
+ block
+ {
+ Node *n;
+
+ n = revertdcl();
+ if(n)
+ $6 = new(OLIST, n, $6);
+ if(!debug['a'] && !debug['Z'])
+ codgen($6, $2);
+ }
+
+xdlist:
+ xdecor
+ {
+ dodecl(xdecl, lastclass, lasttype, $1);
+ }
+| xdecor
+ {
+ $1 = dodecl(xdecl, lastclass, lasttype, $1);
+ }
+ '=' init
+ {
+ doinit($1->sym, $1->type, 0L, $4);
+ }
+| xdlist ',' xdlist
+
+xdecor:
+ xdecor2
+| '*' zgnlist xdecor
+ {
+ $$ = new(OIND, $3, Z);
+ $$->garb = simpleg($2);
+ }
+
+xdecor2:
+ tag
+| '(' xdecor ')'
+ {
+ $$ = $2;
+ }
+| xdecor2 '(' zarglist ')'
+ {
+ $$ = new(OFUNC, $1, $3);
+ }
+| xdecor2 '[' zexpr ']'
+ {
+ $$ = new(OARRAY, $1, $3);
+ }
+
+/*
+ * automatic declarator
+ */
+adecl:
+ ctlist ';'
+ {
+ $$ = dodecl(adecl, lastclass, lasttype, Z);
+ }
+| ctlist adlist ';'
+ {
+ $$ = $2;
+ }
+
+adlist:
+ xdecor
+ {
+ dodecl(adecl, lastclass, lasttype, $1);
+ $$ = Z;
+ }
+| xdecor
+ {
+ $1 = dodecl(adecl, lastclass, lasttype, $1);
+ }
+ '=' init
+ {
+ long w;
+
+ w = $1->sym->type->width;
+ $$ = doinit($1->sym, $1->type, 0L, $4);
+ $$ = contig($1->sym, $$, w);
+ }
+| adlist ',' adlist
+ {
+ $$ = $1;
+ if($3 != Z) {
+ $$ = $3;
+ if($1 != Z)
+ $$ = new(OLIST, $1, $3);
+ }
+ }
+
+/*
+ * parameter declarator
+ */
+pdecl:
+| pdecl ctlist pdlist ';'
+
+pdlist:
+ xdecor
+ {
+ dodecl(pdecl, lastclass, lasttype, $1);
+ }
+| pdlist ',' pdlist
+
+/*
+ * structure element declarator
+ */
+edecl:
+ tlist
+ {
+ lasttype = $1;
+ }
+ zedlist ';'
+| edecl tlist
+ {
+ lasttype = $2;
+ }
+ zedlist ';'
+
+zedlist: /* extension */
+ {
+ lastfield = 0;
+ edecl(CXXX, lasttype, S);
+ }
+| edlist
+
+edlist:
+ edecor
+ {
+ dodecl(edecl, CXXX, lasttype, $1);
+ }
+| edlist ',' edlist
+
+edecor:
+ xdecor
+ {
+ lastbit = 0;
+ firstbit = 1;
+ }
+| tag ':' lexpr
+ {
+ $$ = new(OBIT, $1, $3);
+ }
+| ':' lexpr
+ {
+ $$ = new(OBIT, Z, $2);
+ }
+
+/*
+ * abstract declarator
+ */
+abdecor:
+ {
+ $$ = (Z);
+ }
+| abdecor1
+
+abdecor1:
+ '*' zgnlist
+ {
+ $$ = new(OIND, (Z), Z);
+ $$->garb = simpleg($2);
+ }
+| '*' zgnlist abdecor1
+ {
+ $$ = new(OIND, $3, Z);
+ $$->garb = simpleg($2);
+ }
+| abdecor2
+
+abdecor2:
+ abdecor3
+| abdecor2 '(' zarglist ')'
+ {
+ $$ = new(OFUNC, $1, $3);
+ }
+| abdecor2 '[' zexpr ']'
+ {
+ $$ = new(OARRAY, $1, $3);
+ }
+
+abdecor3:
+ '(' ')'
+ {
+ $$ = new(OFUNC, (Z), Z);
+ }
+| '[' zexpr ']'
+ {
+ $$ = new(OARRAY, (Z), $2);
+ }
+| '(' abdecor1 ')'
+ {
+ $$ = $2;
+ }
+
+init:
+ expr
+| '{' ilist '}'
+ {
+ $$ = new(OINIT, invert($2), Z);
+ }
+
+qual:
+ '[' lexpr ']'
+ {
+ $$ = new(OARRAY, $2, Z);
+ }
+| '.' ltag
+ {
+ $$ = new(OELEM, Z, Z);
+ $$->sym = $2;
+ }
+| qual '='
+
+qlist:
+ init ','
+| qlist init ','
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+| qual
+| qlist qual
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+ilist:
+ qlist
+| init
+| qlist init
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+zarglist:
+ {
+ $$ = Z;
+ }
+| arglist
+ {
+ $$ = invert($1);
+ }
+
+
+arglist:
+ name
+| tlist abdecor
+ {
+ $$ = new(OPROTO, $2, Z);
+ $$->type = $1;
+ }
+| tlist xdecor
+ {
+ $$ = new(OPROTO, $2, Z);
+ $$->type = $1;
+ }
+| '.' '.' '.'
+ {
+ $$ = new(ODOTDOT, Z, Z);
+ }
+| arglist ',' arglist
+ {
+ $$ = new(OLIST, $1, $3);
+ }
+
+block:
+ '{' slist '}'
+ {
+ $$ = invert($2);
+ // if($2 != Z)
+ // $$ = new(OLIST, $2, $$);
+ if($$ == Z)
+ $$ = new(OLIST, Z, Z);
+ }
+
+slist:
+ {
+ $$ = Z;
+ }
+| slist adecl
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+| slist stmnt
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+labels:
+ label
+| labels label
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+label:
+ LCASE expr ':'
+ {
+ $$ = new(OCASE, $2, Z);
+ }
+| LDEFAULT ':'
+ {
+ $$ = new(OCASE, Z, Z);
+ }
+| LNAME ':'
+ {
+ $$ = new(OLABEL, dcllabel($1, 1), Z);
+ }
+
+stmnt:
+ error ';'
+ {
+ $$ = Z;
+ }
+| ulstmnt
+| labels ulstmnt
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+forexpr:
+ zcexpr
+| ctlist adlist
+ {
+ $$ = $2;
+ }
+
+ulstmnt:
+ zcexpr ';'
+| {
+ markdcl();
+ }
+ block
+ {
+ $$ = revertdcl();
+ if($$)
+ $$ = new(OLIST, $$, $2);
+ else
+ $$ = $2;
+ }
+| LIF '(' cexpr ')' stmnt
+ {
+ $$ = new(OIF, $3, new(OLIST, $5, Z));
+ if($5 == Z)
+ warn($3, "empty if body");
+ }
+| LIF '(' cexpr ')' stmnt LELSE stmnt
+ {
+ $$ = new(OIF, $3, new(OLIST, $5, $7));
+ if($5 == Z)
+ warn($3, "empty if body");
+ if($7 == Z)
+ warn($3, "empty else body");
+ }
+| { markdcl(); } LFOR '(' forexpr ';' zcexpr ';' zcexpr ')' stmnt
+ {
+ $$ = revertdcl();
+ if($$){
+ if($4)
+ $4 = new(OLIST, $$, $4);
+ else
+ $4 = $$;
+ }
+ $$ = new(OFOR, new(OLIST, $6, new(OLIST, $4, $8)), $10);
+ }
+| LWHILE '(' cexpr ')' stmnt
+ {
+ $$ = new(OWHILE, $3, $5);
+ }
+| LDO stmnt LWHILE '(' cexpr ')' ';'
+ {
+ $$ = new(ODWHILE, $5, $2);
+ }
+| LRETURN zcexpr ';'
+ {
+ $$ = new(ORETURN, $2, Z);
+ $$->type = thisfn->link;
+ }
+| LSWITCH '(' cexpr ')' stmnt
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->vconst = 0;
+ $$->type = types[TINT];
+ $3 = new(OSUB, $$, $3);
+
+ $$ = new(OCONST, Z, Z);
+ $$->vconst = 0;
+ $$->type = types[TINT];
+ $3 = new(OSUB, $$, $3);
+
+ $$ = new(OSWITCH, $3, $5);
+ }
+| LBREAK ';'
+ {
+ $$ = new(OBREAK, Z, Z);
+ }
+| LCONTINUE ';'
+ {
+ $$ = new(OCONTINUE, Z, Z);
+ }
+| LGOTO ltag ';'
+ {
+ $$ = new(OGOTO, dcllabel($2, 0), Z);
+ }
+| LUSED '(' zelist ')' ';'
+ {
+ $$ = new(OUSED, $3, Z);
+ }
+| LSET '(' zelist ')' ';'
+ {
+ $$ = new(OSET, $3, Z);
+ }
+
+zcexpr:
+ {
+ $$ = Z;
+ }
+| cexpr
+
+zexpr:
+ {
+ $$ = Z;
+ }
+| lexpr
+
+lexpr:
+ expr
+ {
+ $$ = new(OCAST, $1, Z);
+ $$->type = types[TLONG];
+ }
+
+cexpr:
+ expr
+| cexpr ',' cexpr
+ {
+ $$ = new(OCOMMA, $1, $3);
+ }
+
+expr:
+ xuexpr
+| expr '*' expr
+ {
+ $$ = new(OMUL, $1, $3);
+ }
+| expr '/' expr
+ {
+ $$ = new(ODIV, $1, $3);
+ }
+| expr '%' expr
+ {
+ $$ = new(OMOD, $1, $3);
+ }
+| expr '+' expr
+ {
+ $$ = new(OADD, $1, $3);
+ }
+| expr '-' expr
+ {
+ $$ = new(OSUB, $1, $3);
+ }
+| expr LRSH expr
+ {
+ $$ = new(OASHR, $1, $3);
+ }
+| expr LLSH expr
+ {
+ $$ = new(OASHL, $1, $3);
+ }
+| expr '<' expr
+ {
+ $$ = new(OLT, $1, $3);
+ }
+| expr '>' expr
+ {
+ $$ = new(OGT, $1, $3);
+ }
+| expr LLE expr
+ {
+ $$ = new(OLE, $1, $3);
+ }
+| expr LGE expr
+ {
+ $$ = new(OGE, $1, $3);
+ }
+| expr LEQ expr
+ {
+ $$ = new(OEQ, $1, $3);
+ }
+| expr LNE expr
+ {
+ $$ = new(ONE, $1, $3);
+ }
+| expr '&' expr
+ {
+ $$ = new(OAND, $1, $3);
+ }
+| expr '^' expr
+ {
+ $$ = new(OXOR, $1, $3);
+ }
+| expr '|' expr
+ {
+ $$ = new(OOR, $1, $3);
+ }
+| expr LANDAND expr
+ {
+ $$ = new(OANDAND, $1, $3);
+ }
+| expr LOROR expr
+ {
+ $$ = new(OOROR, $1, $3);
+ }
+| expr '?' cexpr ':' expr
+ {
+ $$ = new(OCOND, $1, new(OLIST, $3, $5));
+ }
+| expr '=' expr
+ {
+ $$ = new(OAS, $1, $3);
+ }
+| expr LPE expr
+ {
+ $$ = new(OASADD, $1, $3);
+ }
+| expr LME expr
+ {
+ $$ = new(OASSUB, $1, $3);
+ }
+| expr LMLE expr
+ {
+ $$ = new(OASMUL, $1, $3);
+ }
+| expr LDVE expr
+ {
+ $$ = new(OASDIV, $1, $3);
+ }
+| expr LMDE expr
+ {
+ $$ = new(OASMOD, $1, $3);
+ }
+| expr LLSHE expr
+ {
+ $$ = new(OASASHL, $1, $3);
+ }
+| expr LRSHE expr
+ {
+ $$ = new(OASASHR, $1, $3);
+ }
+| expr LANDE expr
+ {
+ $$ = new(OASAND, $1, $3);
+ }
+| expr LXORE expr
+ {
+ $$ = new(OASXOR, $1, $3);
+ }
+| expr LORE expr
+ {
+ $$ = new(OASOR, $1, $3);
+ }
+
+xuexpr:
+ uexpr
+| '(' tlist abdecor ')' xuexpr
+ {
+ $$ = new(OCAST, $5, Z);
+ dodecl(NODECL, CXXX, $2, $3);
+ $$->type = lastdcl;
+ $$->xcast = 1;
+ }
+| '(' tlist abdecor ')' '{' ilist '}' /* extension */
+ {
+ $$ = new(OSTRUCT, $6, Z);
+ dodecl(NODECL, CXXX, $2, $3);
+ $$->type = lastdcl;
+ }
+
+uexpr:
+ pexpr
+| '*' xuexpr
+ {
+ $$ = new(OIND, $2, Z);
+ }
+| '&' xuexpr
+ {
+ $$ = new(OADDR, $2, Z);
+ }
+| '+' xuexpr
+ {
+ $$ = new(OPOS, $2, Z);
+ }
+| '-' xuexpr
+ {
+ $$ = new(ONEG, $2, Z);
+ }
+| '!' xuexpr
+ {
+ $$ = new(ONOT, $2, Z);
+ }
+| '~' xuexpr
+ {
+ $$ = new(OCOM, $2, Z);
+ }
+| LPP xuexpr
+ {
+ $$ = new(OPREINC, $2, Z);
+ }
+| LMM xuexpr
+ {
+ $$ = new(OPREDEC, $2, Z);
+ }
+| LSIZEOF uexpr
+ {
+ $$ = new(OSIZE, $2, Z);
+ }
+| LSIGNOF uexpr
+ {
+ $$ = new(OSIGN, $2, Z);
+ }
+
+pexpr:
+ '(' cexpr ')'
+ {
+ $$ = $2;
+ }
+| LSIZEOF '(' tlist abdecor ')'
+ {
+ $$ = new(OSIZE, Z, Z);
+ dodecl(NODECL, CXXX, $3, $4);
+ $$->type = lastdcl;
+ }
+| LSIGNOF '(' tlist abdecor ')'
+ {
+ $$ = new(OSIGN, Z, Z);
+ dodecl(NODECL, CXXX, $3, $4);
+ $$->type = lastdcl;
+ }
+| pexpr '(' zelist ')'
+ {
+ $$ = new(OFUNC, $1, Z);
+ if($1->op == ONAME)
+ if($1->type == T)
+ dodecl(xdecl, CXXX, types[TINT], $$);
+ $$->right = invert($3);
+ }
+| pexpr '[' cexpr ']'
+ {
+ $$ = new(OIND, new(OADD, $1, $3), Z);
+ }
+| pexpr LMG ltag
+ {
+ $$ = new(ODOT, new(OIND, $1, Z), Z);
+ $$->sym = $3;
+ }
+| pexpr '.' ltag
+ {
+ $$ = new(ODOT, $1, Z);
+ $$->sym = $3;
+ }
+| pexpr LPP
+ {
+ $$ = new(OPOSTINC, $1, Z);
+ }
+| pexpr LMM
+ {
+ $$ = new(OPOSTDEC, $1, Z);
+ }
+| name
+| LCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TINT];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TLONG];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LUCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TUINT];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LULCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TULONG];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LDCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TDOUBLE];
+ $$->fconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LFCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TFLOAT];
+ $$->fconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LVLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TVLONG];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LUVLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TUVLONG];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| string
+| lstring
+
+string:
+ LSTRING
+ {
+ $$ = new(OSTRING, Z, Z);
+ $$->type = typ(TARRAY, types[TCHAR]);
+ $$->type->width = $1.l + 1;
+ $$->cstring = $1.s;
+ $$->sym = symstring;
+ $$->etype = TARRAY;
+ $$->class = CSTATIC;
+ }
+| string LSTRING
+ {
+ char *s;
+ int n;
+
+ n = $1->type->width - 1;
+ s = alloc(n+$2.l+MAXALIGN);
+
+ memcpy(s, $1->cstring, n);
+ memcpy(s+n, $2.s, $2.l);
+ s[n+$2.l] = 0;
+
+ $$ = $1;
+ $$->type->width += $2.l;
+ $$->cstring = s;
+ }
+
+lstring:
+ LLSTRING
+ {
+ $$ = new(OLSTRING, Z, Z);
+ $$->type = typ(TARRAY, types[TUSHORT]);
+ $$->type->width = $1.l + sizeof(ushort);
+ $$->rstring = (ushort*)$1.s;
+ $$->sym = symstring;
+ $$->etype = TARRAY;
+ $$->class = CSTATIC;
+ }
+| lstring LLSTRING
+ {
+ char *s;
+ int n;
+
+ n = $1->type->width - sizeof(ushort);
+ s = alloc(n+$2.l+MAXALIGN);
+
+ memcpy(s, $1->rstring, n);
+ memcpy(s+n, $2.s, $2.l);
+ *(ushort*)(s+n+$2.l) = 0;
+
+ $$ = $1;
+ $$->type->width += $2.l;
+ $$->rstring = (ushort*)s;
+ }
+
+zelist:
+ {
+ $$ = Z;
+ }
+| elist
+
+elist:
+ expr
+| elist ',' elist
+ {
+ $$ = new(OLIST, $1, $3);
+ }
+
+sbody:
+ '{'
+ {
+ $<tyty>$.t1 = strf;
+ $<tyty>$.t2 = strl;
+ strf = T;
+ strl = T;
+ lastbit = 0;
+ firstbit = 1;
+ }
+ edecl '}'
+ {
+ $$ = strf;
+ strf = $<tyty>2.t1;
+ strl = $<tyty>2.t2;
+ }
+
+zctlist:
+ {
+ lastclass = CXXX;
+ lasttype = types[TINT];
+ }
+| ctlist
+
+types:
+ complex
+ {
+ $$.t = $1;
+ $$.c = CXXX;
+ }
+| tname
+ {
+ $$.t = simplet($1);
+ $$.c = CXXX;
+ }
+| gcnlist
+ {
+ $$.t = simplet($1);
+ $$.c = simplec($1);
+ $$.t = garbt($$.t, $1);
+ }
+| complex gctnlist
+ {
+ $$.t = $1;
+ $$.c = simplec($2);
+ $$.t = garbt($$.t, $2);
+ if($2 & ~BCLASS & ~BGARB)
+ diag(Z, "duplicate types given: %T and %Q", $1, $2);
+ }
+| tname gctnlist
+ {
+ $$.t = simplet(typebitor($1, $2));
+ $$.c = simplec($2);
+ $$.t = garbt($$.t, $2);
+ }
+| gcnlist complex zgnlist
+ {
+ $$.t = $2;
+ $$.c = simplec($1);
+ $$.t = garbt($$.t, $1|$3);
+ }
+| gcnlist tname
+ {
+ $$.t = simplet($2);
+ $$.c = simplec($1);
+ $$.t = garbt($$.t, $1);
+ }
+| gcnlist tname gctnlist
+ {
+ $$.t = simplet(typebitor($2, $3));
+ $$.c = simplec($1|$3);
+ $$.t = garbt($$.t, $1|$3);
+ }
+
+tlist:
+ types
+ {
+ $$ = $1.t;
+ if($1.c != CXXX)
+ diag(Z, "illegal combination of class 4: %s", cnames[$1.c]);
+ }
+
+ctlist:
+ types
+ {
+ lasttype = $1.t;
+ lastclass = $1.c;
+ }
+
+complex:
+ LSTRUCT ltag
+ {
+ dotag($2, TSTRUCT, 0);
+ $$ = $2->suetag;
+ }
+| LSTRUCT ltag
+ {
+ dotag($2, TSTRUCT, autobn);
+ }
+ sbody
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ $$->link = $4;
+ suallign($$);
+ }
+| LSTRUCT sbody
+ {
+ taggen++;
+ sprint(symb, "_%d_", taggen);
+ $$ = dotag(lookup(), TSTRUCT, autobn);
+ $$->link = $2;
+ suallign($$);
+ }
+| LUNION ltag
+ {
+ dotag($2, TUNION, 0);
+ $$ = $2->suetag;
+ }
+| LUNION ltag
+ {
+ dotag($2, TUNION, autobn);
+ }
+ sbody
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ $$->link = $4;
+ suallign($$);
+ }
+| LUNION sbody
+ {
+ taggen++;
+ sprint(symb, "_%d_", taggen);
+ $$ = dotag(lookup(), TUNION, autobn);
+ $$->link = $2;
+ suallign($$);
+ }
+| LENUM ltag
+ {
+ dotag($2, TENUM, 0);
+ $$ = $2->suetag;
+ if($$->link == T)
+ $$->link = types[TINT];
+ $$ = $$->link;
+ }
+| LENUM ltag
+ {
+ dotag($2, TENUM, autobn);
+ }
+ '{'
+ {
+ en.tenum = T;
+ en.cenum = T;
+ }
+ enum '}'
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ if(en.tenum == T) {
+ diag(Z, "enum type ambiguous: %s", $2->name);
+ en.tenum = types[TINT];
+ }
+ $$->link = en.tenum;
+ $$ = en.tenum;
+ }
+| LENUM '{'
+ {
+ en.tenum = T;
+ en.cenum = T;
+ }
+ enum '}'
+ {
+ $$ = en.tenum;
+ }
+| LTYPE
+ {
+ $$ = tcopy($1->type);
+ }
+
+gctnlist:
+ gctname
+| gctnlist gctname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+zgnlist:
+ {
+ $$ = 0;
+ }
+| zgnlist gname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+gctname:
+ tname
+| gname
+| cname
+
+gcnlist:
+ gcname
+| gcnlist gcname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+gcname:
+ gname
+| cname
+
+enum:
+ LNAME
+ {
+ doenum($1, Z);
+ }
+| LNAME '=' expr
+ {
+ doenum($1, $3);
+ }
+| enum ','
+| enum ',' enum
+
+tname: /* type words */
+ LCHAR { $$ = BCHAR; }
+| LSHORT { $$ = BSHORT; }
+| LINT { $$ = BINT; }
+| LLONG { $$ = BLONG; }
+| LSIGNED { $$ = BSIGNED; }
+| LUNSIGNED { $$ = BUNSIGNED; }
+| LFLOAT { $$ = BFLOAT; }
+| LDOUBLE { $$ = BDOUBLE; }
+| LVOID { $$ = BVOID; }
+
+cname: /* class words */
+ LAUTO { $$ = BAUTO; }
+| LSTATIC { $$ = BSTATIC; }
+| LEXTERN { $$ = BEXTERN; }
+| LTYPEDEF { $$ = BTYPEDEF; }
+| LTYPESTR { $$ = BTYPESTR; }
+| LREGISTER { $$ = BREGISTER; }
+| LINLINE { $$ = 0; }
+
+gname: /* garbage words */
+ LCONSTNT { $$ = BCONSTNT; }
+| LVOLATILE { $$ = BVOLATILE; }
+| LRESTRICT { $$ = 0; }
+
+name:
+ LNAME
+ {
+ $$ = new(ONAME, Z, Z);
+ if($1->class == CLOCAL)
+ $1 = mkstatic($1);
+ $$->sym = $1;
+ $$->type = $1->type;
+ $$->etype = TVOID;
+ if($$->type != T)
+ $$->etype = $$->type->etype;
+ $$->xoffset = $1->offset;
+ $$->class = $1->class;
+ $1->aused = 1;
+ }
+tag:
+ ltag
+ {
+ $$ = new(ONAME, Z, Z);
+ $$->sym = $1;
+ $$->type = $1->type;
+ $$->etype = TVOID;
+ if($$->type != T)
+ $$->etype = $$->type->etype;
+ $$->xoffset = $1->offset;
+ $$->class = $1->class;
+ }
+ltag:
+ LNAME
+| LTYPE
+%%
diff --git a/src/cmd/cc/com.c b/src/cmd/cc/com.c
new file mode 100644
index 0000000..b0b1620
--- /dev/null
+++ b/src/cmd/cc/com.c
@@ -0,0 +1,1378 @@
+// Inferno utils/cc/com.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/com.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+int compar(Node*, int);
+
+void
+complex(Node *n)
+{
+
+ if(n == Z)
+ return;
+
+ nearln = n->lineno;
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "pre complex");
+ if(tcom(n))
+ return;
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "t complex");
+ ccom(n);
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "c complex");
+ acom(n);
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "a complex");
+ xcom(n);
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "x complex");
+}
+
+/*
+ * evaluate types
+ * evaluate lvalues (addable == 1)
+ */
+enum
+{
+ ADDROF = 1<<0,
+ CASTOF = 1<<1,
+ ADDROP = 1<<2,
+};
+
+int
+tcom(Node *n)
+{
+
+ return tcomo(n, ADDROF);
+}
+
+int
+tcomo(Node *n, int f)
+{
+ Node *l, *r;
+ Type *t;
+ int o;
+
+ if(n == Z) {
+ diag(Z, "Z in tcom");
+ errorexit();
+ }
+ n->addable = 0;
+ l = n->left;
+ r = n->right;
+
+ switch(n->op) {
+ default:
+ diag(n, "unknown op in type complex: %O", n->op);
+ goto bad;
+
+ case ODOTDOT:
+ /*
+ * tcom has already been called on this subtree
+ */
+ *n = *n->left;
+ if(n->type == T)
+ goto bad;
+ break;
+
+ case OCAST:
+ if(n->type == T)
+ break;
+ if(n->type->width == types[TLONG]->width) {
+ if(tcomo(l, ADDROF|CASTOF))
+ goto bad;
+ } else
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, n->type, tcast))
+ goto bad;
+ break;
+
+ case ORETURN:
+ if(l == Z) {
+ if(n->type->etype != TVOID)
+ warn(n, "null return of a typed function");
+ break;
+ }
+ if(tcom(l))
+ goto bad;
+ typeext(n->type, l);
+ if(tcompat(n, n->type, l->type, tasign))
+ break;
+ constas(n, n->type, l->type);
+ if(!sametype(n->type, l->type)) {
+ l = new1(OCAST, l, Z);
+ l->type = n->type;
+ n->left = l;
+ }
+ break;
+
+ case OASI: /* same as as, but no test for const */
+ n->op = OAS;
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+
+ typeext(l->type, r);
+ if(tlvalue(l) || tcompat(n, l->type, r->type, tasign))
+ goto bad;
+ if(!sametype(l->type, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = l->type;
+ n->right = r;
+ }
+ n->type = l->type;
+ break;
+
+ case OAS:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext(l->type, r);
+ if(tcompat(n, l->type, r->type, tasign))
+ goto bad;
+ constas(n, l->type, r->type);
+ if(!sametype(l->type, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = l->type;
+ n->right = r;
+ }
+ n->type = l->type;
+ break;
+
+ case OASADD:
+ case OASSUB:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext1(l->type, r);
+ if(tcompat(n, l->type, r->type, tasadd))
+ goto bad;
+ constas(n, l->type, r->type);
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ case OASDIV:
+ case OASLDIV:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext1(l->type, r);
+ if(tcompat(n, l->type, r->type, tmul))
+ goto bad;
+ constas(n, l->type, r->type);
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ if(typeu[n->type->etype]) {
+ if(n->op == OASDIV)
+ n->op = OASLDIV;
+ if(n->op == OASMUL)
+ n->op = OASLMUL;
+ }
+ break;
+
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ n->type = l->type;
+ if(typeu[n->type->etype]) {
+ if(n->op == OASASHR)
+ n->op = OASLSHR;
+ }
+ break;
+
+ case OASMOD:
+ case OASLMOD:
+ case OASOR:
+ case OASAND:
+ case OASXOR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ if(typeu[n->type->etype]) {
+ if(n->op == OASMOD)
+ n->op = OASLMOD;
+ }
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ case OPOSTINC:
+ case OPOSTDEC:
+ if(tcom(l))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, types[TINT], tadd))
+ goto bad;
+ n->type = l->type;
+ if(n->type->etype == TIND)
+ if(n->type->link->width < 1)
+ diag(n, "inc/dec of a void pointer");
+ break;
+
+ case OEQ:
+ case ONE:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext(l->type, r);
+ typeext(r->type, l);
+ if(tcompat(n, l->type, r->type, trel))
+ goto bad;
+ arith(n, 0);
+ n->type = types[TINT];
+ break;
+
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLE:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext1(l->type, r);
+ typeext1(r->type, l);
+ if(tcompat(n, l->type, r->type, trel))
+ goto bad;
+ arith(n, 0);
+ if(typeu[n->type->etype])
+ n->op = logrel[relindex(n->op)];
+ n->type = types[TINT];
+ break;
+
+ case OCOND:
+ o = tcom(l);
+ o |= tcom(r->left);
+ if(o | tcom(r->right))
+ goto bad;
+ if(r->right->type->etype == TIND && vconst(r->left) == 0) {
+ r->left->type = r->right->type;
+ r->left->vconst = 0;
+ }
+ if(r->left->type->etype == TIND && vconst(r->right) == 0) {
+ r->right->type = r->left->type;
+ r->right->vconst = 0;
+ }
+ if(sametype(r->right->type, r->left->type)) {
+ r->type = r->right->type;
+ n->type = r->type;
+ break;
+ }
+ if(tcompat(r, r->left->type, r->right->type, trel))
+ goto bad;
+ arith(r, 0);
+ n->type = r->type;
+ break;
+
+ case OADD:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tadd))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OSUB:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tsub))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OMUL:
+ case OLMUL:
+ case ODIV:
+ case OLDIV:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tmul))
+ goto bad;
+ arith(n, 1);
+ if(typeu[n->type->etype]) {
+ if(n->op == ODIV)
+ n->op = OLDIV;
+ if(n->op == OMUL)
+ n->op = OLMUL;
+ }
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ n->right = Z;
+ arith(n, 1);
+ n->right = new1(OCAST, r, Z);
+ n->right->type = types[TINT];
+ if(typeu[n->type->etype])
+ if(n->op == OASHR)
+ n->op = OLSHR;
+ break;
+
+ case OAND:
+ case OOR:
+ case OXOR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OMOD:
+ case OLMOD:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ arith(n, 1);
+ if(typeu[n->type->etype])
+ n->op = OLMOD;
+ break;
+
+ case OPOS:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+
+ r = l;
+ l = new(OCONST, Z, Z);
+ l->vconst = 0;
+ l->type = types[TINT];
+ n->op = OADD;
+ n->right = r;
+ n->left = l;
+
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tsub))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case ONEG:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+
+ if(!machcap(n)) {
+ r = l;
+ l = new(OCONST, Z, Z);
+ l->vconst = 0;
+ l->type = types[TINT];
+ n->op = OSUB;
+ n->right = r;
+ n->left = l;
+
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tsub))
+ goto bad;
+ }
+ arith(n, 1);
+ break;
+
+ case OCOM:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+
+ if(!machcap(n)) {
+ r = l;
+ l = new(OCONST, Z, Z);
+ l->vconst = -1;
+ l->type = types[TINT];
+ n->op = OXOR;
+ n->right = r;
+ n->left = l;
+
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ }
+ arith(n, 1);
+ break;
+
+ case ONOT:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, T, l->type, tnot))
+ goto bad;
+ n->type = types[TINT];
+ break;
+
+ case OANDAND:
+ case OOROR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tcompat(n, T, l->type, tnot) |
+ tcompat(n, T, r->type, tnot))
+ goto bad;
+ n->type = types[TINT];
+ break;
+
+ case OCOMMA:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ n->type = r->type;
+ break;
+
+
+ case OSIGN: /* extension signof(type) returns a hash */
+ if(l != Z) {
+ if(l->op != OSTRING && l->op != OLSTRING)
+ if(tcomo(l, 0))
+ goto bad;
+ if(l->op == OBIT) {
+ diag(n, "signof bitfield");
+ goto bad;
+ }
+ n->type = l->type;
+ }
+ if(n->type == T)
+ goto bad;
+ if(n->type->width < 0) {
+ diag(n, "signof undefined type");
+ goto bad;
+ }
+ n->op = OCONST;
+ n->left = Z;
+ n->right = Z;
+ n->vconst = convvtox(signature(n->type), TULONG);
+ n->type = types[TULONG];
+ break;
+
+ case OSIZE:
+ if(l != Z) {
+ if(l->op != OSTRING && l->op != OLSTRING)
+ if(tcomo(l, 0))
+ goto bad;
+ if(l->op == OBIT) {
+ diag(n, "sizeof bitfield");
+ goto bad;
+ }
+ n->type = l->type;
+ }
+ if(n->type == T)
+ goto bad;
+ if(n->type->width <= 0) {
+ diag(n, "sizeof undefined type");
+ goto bad;
+ }
+ if(n->type->etype == TFUNC) {
+ diag(n, "sizeof function");
+ goto bad;
+ }
+ n->op = OCONST;
+ n->left = Z;
+ n->right = Z;
+ n->vconst = convvtox(n->type->width, TINT);
+ n->type = types[TINT];
+ break;
+
+ case OFUNC:
+ o = tcomo(l, 0);
+ if(o)
+ goto bad;
+ if(l->type->etype == TIND && l->type->link->etype == TFUNC) {
+ l = new1(OIND, l, Z);
+ l->type = l->left->type->link;
+ n->left = l;
+ }
+ if(tcompat(n, T, l->type, tfunct))
+ goto bad;
+ if(o | tcoma(l, r, l->type->down, 1))
+ goto bad;
+ n->type = l->type->link;
+ if(!debug['B'])
+ if(l->type->down == T || l->type->down->etype == TOLD) {
+ nerrors--;
+ diag(n, "function args not checked: %F", l);
+ }
+ dpcheck(n);
+ break;
+
+ case ONAME:
+ if(n->type == T) {
+ diag(n, "name not declared: %F", n);
+ goto bad;
+ }
+ if(n->type->etype == TENUM) {
+ n->op = OCONST;
+ n->type = n->sym->tenum;
+ if(!typefd[n->type->etype])
+ n->vconst = n->sym->vconst;
+ else
+ n->fconst = n->sym->fconst;
+ break;
+ }
+ n->addable = 1;
+ if(n->class == CEXREG) {
+ n->op = OREGISTER;
+ n->reg = n->sym->offset;
+ n->xoffset = 0;
+ break;
+ }
+ break;
+
+ case OLSTRING:
+ if(n->type->link != types[TUSHORT]) {
+ o = outstring(0, 0);
+ while(o & 3) {
+ ushort a[1];
+ a[0] = 0;
+ outlstring(a, sizeof(ushort));
+ o = outlstring(0, 0);
+ }
+ }
+ n->op = ONAME;
+ n->xoffset = outlstring(n->rstring, n->type->width);
+ n->addable = 1;
+ break;
+
+ case OSTRING:
+ if(n->type->link != types[TCHAR]) {
+ o = outstring(0, 0);
+ while(o & 3) {
+ outstring("", 1);
+ o = outstring(0, 0);
+ }
+ }
+ n->op = ONAME;
+ n->xoffset = outstring(n->cstring, n->type->width);
+ n->addable = 1;
+ break;
+
+ case OCONST:
+ break;
+
+ case ODOT:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tdot))
+ goto bad;
+ if(tcomd(n))
+ goto bad;
+ break;
+
+ case OADDR:
+ if(tcomo(l, ADDROP))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(l->type->nbits) {
+ diag(n, "address of a bit field");
+ goto bad;
+ }
+ if(l->op == OREGISTER) {
+ diag(n, "address of a register");
+ goto bad;
+ }
+ n->type = typ(TIND, l->type);
+ n->type->width = types[TIND]->width;
+ break;
+
+ case OIND:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tindir))
+ goto bad;
+ n->type = l->type->link;
+ n->addable = 1;
+ break;
+
+ case OSTRUCT:
+ if(tcomx(n))
+ goto bad;
+ break;
+ }
+ t = n->type;
+ if(t == T)
+ goto bad;
+ if(t->width < 0) {
+ snap(t);
+ if(t->width < 0) {
+ if(typesu[t->etype] && t->tag)
+ diag(n, "structure not fully declared %s", t->tag->name);
+ else
+ diag(n, "structure not fully declared");
+ goto bad;
+ }
+ }
+ if(typeaf[t->etype]) {
+ if(f & ADDROF)
+ goto addaddr;
+ if(f & ADDROP)
+ warn(n, "address of array/func ignored");
+ }
+ return 0;
+
+addaddr:
+ if(tlvalue(n))
+ goto bad;
+ l = new1(OXXX, Z, Z);
+ *l = *n;
+ n->op = OADDR;
+ if(l->type->etype == TARRAY)
+ l->type = l->type->link;
+ n->left = l;
+ n->right = Z;
+ n->addable = 0;
+ n->type = typ(TIND, l->type);
+ n->type->width = types[TIND]->width;
+ return 0;
+
+bad:
+ n->type = T;
+ return 1;
+}
+
+int
+tcoma(Node *l, Node *n, Type *t, int f)
+{
+ Node *n1;
+ int o;
+
+ if(t != T)
+ if(t->etype == TOLD || t->etype == TDOT) /* .../old in prototype */
+ t = T;
+ if(n == Z) {
+ if(t != T && !sametype(t, types[TVOID])) {
+ diag(n, "not enough function arguments: %F", l);
+ return 1;
+ }
+ return 0;
+ }
+ if(n->op == OLIST) {
+ o = tcoma(l, n->left, t, 0);
+ if(t != T) {
+ t = t->down;
+ if(t == T)
+ t = types[TVOID];
+ }
+ return o | tcoma(l, n->right, t, 1);
+ }
+ if(f && t != T)
+ tcoma(l, Z, t->down, 0);
+ if(tcom(n) || tcompat(n, T, n->type, targ))
+ return 1;
+ if(sametype(t, types[TVOID])) {
+ diag(n, "too many function arguments: %F", l);
+ return 1;
+ }
+ if(t != T) {
+ typeext(t, n);
+ if(stcompat(nodproto, t, n->type, tasign)) {
+ diag(l, "argument prototype mismatch \"%T\" for \"%T\": %F",
+ n->type, t, l);
+ return 1;
+ }
+ switch(t->etype) {
+ case TCHAR:
+ case TSHORT:
+ t = types[TINT];
+ break;
+
+ case TUCHAR:
+ case TUSHORT:
+ t = types[TUINT];
+ break;
+ }
+ } else
+ switch(n->type->etype)
+ {
+ case TCHAR:
+ case TSHORT:
+ t = types[TINT];
+ break;
+
+ case TUCHAR:
+ case TUSHORT:
+ t = types[TUINT];
+ break;
+
+ case TFLOAT:
+ t = types[TDOUBLE];
+ }
+ if(t != T && !sametype(t, n->type)) {
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = OCAST;
+ n->left = n1;
+ n->right = Z;
+ n->type = t;
+ n->addable = 0;
+ }
+ return 0;
+}
+
+int
+tcomd(Node *n)
+{
+ Type *t;
+ long o;
+
+ o = 0;
+ t = dotsearch(n->sym, n->left->type->link, n, &o);
+ if(t == T) {
+ diag(n, "not a member of struct/union: %F", n);
+ return 1;
+ }
+ makedot(n, t, o);
+ return 0;
+}
+
+int
+tcomx(Node *n)
+{
+ Type *t;
+ Node *l, *r, **ar, **al;
+ int e;
+
+ e = 0;
+ if(n->type->etype != TSTRUCT) {
+ diag(n, "constructor must be a structure");
+ return 1;
+ }
+ l = invert(n->left);
+ n->left = l;
+ al = &n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ if(l == Z) {
+ diag(n, "constructor list too short");
+ return 1;
+ }
+ if(l->op == OLIST) {
+ r = l->left;
+ ar = &l->left;
+ al = &l->right;
+ l = l->right;
+ } else {
+ r = l;
+ ar = al;
+ l = Z;
+ }
+ if(tcom(r))
+ e++;
+ typeext(t, r);
+ if(tcompat(n, t, r->type, tasign))
+ e++;
+ constas(n, t, r->type);
+ if(!e && !sametype(t, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = t;
+ *ar = r;
+ }
+ }
+ if(l != Z) {
+ diag(n, "constructor list too long");
+ return 1;
+ }
+ return e;
+}
+
+int
+tlvalue(Node *n)
+{
+
+ if(!n->addable) {
+ diag(n, "not an l-value");
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * general rewrite
+ * (IND(ADDR x)) ==> x
+ * (ADDR(IND x)) ==> x
+ * remove some zero operands
+ * remove no op casts
+ * evaluate constants
+ */
+void
+ccom(Node *n)
+{
+ Node *l, *r;
+ int t;
+
+loop:
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ case OAS:
+ case OASXOR:
+ case OASAND:
+ case OASOR:
+ case OASMOD:
+ case OASLMOD:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASDIV:
+ case OASLDIV:
+ case OASMUL:
+ case OASLMUL:
+ case OASSUB:
+ case OASADD:
+ ccom(l);
+ ccom(r);
+ if(n->op == OASLSHR || n->op == OASASHR || n->op == OASASHL)
+ if(r->op == OCONST) {
+ t = n->type->width * 8; /* bits per byte */
+ if(r->vconst >= t || r->vconst < 0)
+ warn(n, "stupid shift: %lld", r->vconst);
+ }
+ break;
+
+ case OCAST:
+ ccom(l);
+ if(l->op == OCONST) {
+ evconst(n);
+ if(n->op == OCONST)
+ break;
+ }
+ if(nocast(l->type, n->type)) {
+ l->type = n->type;
+ *n = *l;
+ }
+ break;
+
+ case OCOND:
+ ccom(l);
+ ccom(r);
+ if(l->op == OCONST)
+ if(vconst(l) == 0)
+ *n = *r->right;
+ else
+ *n = *r->left;
+ break;
+
+ case OREGISTER:
+ case OINDREG:
+ case OCONST:
+ case ONAME:
+ break;
+
+ case OADDR:
+ ccom(l);
+ l->etype = TVOID;
+ if(l->op == OIND) {
+ l->left->type = n->type;
+ *n = *l->left;
+ break;
+ }
+ goto common;
+
+ case OIND:
+ ccom(l);
+ if(l->op == OADDR) {
+ l->left->type = n->type;
+ *n = *l->left;
+ break;
+ }
+ goto common;
+
+ case OEQ:
+ case ONE:
+
+ case OLE:
+ case OGE:
+ case OLT:
+ case OGT:
+
+ case OLS:
+ case OHS:
+ case OLO:
+ case OHI:
+ ccom(l);
+ ccom(r);
+ if(compar(n, 0) || compar(n, 1))
+ break;
+ relcon(l, r);
+ relcon(r, l);
+ goto common;
+
+ case OASHR:
+ case OASHL:
+ case OLSHR:
+ ccom(l);
+ if(vconst(l) == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ ccom(r);
+ if(vconst(r) == 0) {
+ *n = *l;
+ break;
+ }
+ if(r->op == OCONST) {
+ t = n->type->width * 8; /* bits per byte */
+ if(r->vconst >= t || r->vconst <= -t)
+ warn(n, "stupid shift: %lld", r->vconst);
+ }
+ goto common;
+
+ case OMUL:
+ case OLMUL:
+ ccom(l);
+ t = vconst(l);
+ if(t == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ if(t == 1) {
+ *n = *r;
+ goto loop;
+ }
+ ccom(r);
+ t = vconst(r);
+ if(t == 0 && !side(l)) {
+ *n = *r;
+ break;
+ }
+ if(t == 1) {
+ *n = *l;
+ break;
+ }
+ goto common;
+
+ case ODIV:
+ case OLDIV:
+ ccom(l);
+ if(vconst(l) == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ ccom(r);
+ t = vconst(r);
+ if(t == 0) {
+ diag(n, "divide check");
+ *n = *r;
+ break;
+ }
+ if(t == 1) {
+ *n = *l;
+ break;
+ }
+ goto common;
+
+ case OSUB:
+ ccom(r);
+ if(r->op == OCONST) {
+ if(typefd[r->type->etype]) {
+ n->op = OADD;
+ r->fconst = -r->fconst;
+ goto loop;
+ } else {
+ n->op = OADD;
+ r->vconst = -r->vconst;
+ goto loop;
+ }
+ }
+ ccom(l);
+ goto common;
+
+ case OXOR:
+ case OOR:
+ case OADD:
+ ccom(l);
+ if(vconst(l) == 0) {
+ *n = *r;
+ goto loop;
+ }
+ ccom(r);
+ if(vconst(r) == 0) {
+ *n = *l;
+ break;
+ }
+ goto commute;
+
+ case OAND:
+ ccom(l);
+ ccom(r);
+ if(vconst(l) == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ if(vconst(r) == 0 && !side(l)) {
+ *n = *r;
+ break;
+ }
+
+ commute:
+ /* look for commutative constant */
+ if(r->op == OCONST) {
+ if(l->op == n->op) {
+ if(l->left->op == OCONST) {
+ n->right = l->right;
+ l->right = r;
+ goto loop;
+ }
+ if(l->right->op == OCONST) {
+ n->right = l->left;
+ l->left = r;
+ goto loop;
+ }
+ }
+ }
+ if(l->op == OCONST) {
+ if(r->op == n->op) {
+ if(r->left->op == OCONST) {
+ n->left = r->right;
+ r->right = l;
+ goto loop;
+ }
+ if(r->right->op == OCONST) {
+ n->left = r->left;
+ r->left = l;
+ goto loop;
+ }
+ }
+ }
+ goto common;
+
+ case OANDAND:
+ ccom(l);
+ if(vconst(l) == 0) {
+ *n = *l;
+ break;
+ }
+ ccom(r);
+ goto common;
+
+ case OOROR:
+ ccom(l);
+ if(l->op == OCONST && l->vconst != 0) {
+ *n = *l;
+ n->vconst = 1;
+ break;
+ }
+ ccom(r);
+ goto common;
+
+ default:
+ if(l != Z)
+ ccom(l);
+ if(r != Z)
+ ccom(r);
+ common:
+ if(l != Z)
+ if(l->op != OCONST)
+ break;
+ if(r != Z)
+ if(r->op != OCONST)
+ break;
+ evconst(n);
+ }
+}
+
+/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
+static char *cmps[12] =
+{
+ "==", "!=", "<=", "<=", "<", "<", ">=", ">=", ">", ">",
+};
+
+/* 128-bit numbers */
+typedef struct Big Big;
+struct Big
+{
+ vlong a;
+ uvlong b;
+};
+static int
+cmp(Big x, Big y)
+{
+ if(x.a != y.a){
+ if(x.a < y.a)
+ return -1;
+ return 1;
+ }
+ if(x.b != y.b){
+ if(x.b < y.b)
+ return -1;
+ return 1;
+ }
+ return 0;
+}
+static Big
+add(Big x, int y)
+{
+ uvlong ob;
+
+ ob = x.b;
+ x.b += y;
+ if(y > 0 && x.b < ob)
+ x.a++;
+ if(y < 0 && x.b > ob)
+ x.a--;
+ return x;
+}
+
+Big
+big(vlong a, uvlong b)
+{
+ Big x;
+
+ x.a = a;
+ x.b = b;
+ return x;
+}
+
+int
+compar(Node *n, int reverse)
+{
+ Big lo, hi, x;
+ int op;
+ char xbuf[40], cmpbuf[50];
+ Node *l, *r;
+ Type *lt, *rt;
+
+ /*
+ * The point of this function is to diagnose comparisons
+ * that can never be true or that look misleading because
+ * of the `usual arithmetic conversions'. As an example
+ * of the latter, if x is a ulong, then if(x <= -1) really means
+ * if(x <= 0xFFFFFFFF), while if(x <= -1LL) really means
+ * what it says (but 8c compiles it wrong anyway).
+ */
+
+ if(reverse){
+ r = n->left;
+ l = n->right;
+ op = comrel[relindex(n->op)];
+ }else{
+ l = n->left;
+ r = n->right;
+ op = n->op;
+ }
+
+ /*
+ * Skip over left casts to find out the original expression range.
+ */
+ while(l->op == OCAST)
+ l = l->left;
+ if(l->op == OCONST)
+ return 0;
+ lt = l->type;
+ if(l->op == ONAME && l->sym->type){
+ lt = l->sym->type;
+ if(lt->etype == TARRAY)
+ lt = lt->link;
+ }
+ if(lt == T)
+ return 0;
+ if(lt->etype == TXXX || lt->etype > TUVLONG)
+ return 0;
+
+ /*
+ * Skip over the right casts to find the on-screen value.
+ */
+ if(r->op != OCONST)
+ return 0;
+ while(r->oldop == OCAST && !r->xcast)
+ r = r->left;
+ rt = r->type;
+ if(rt == T)
+ return 0;
+
+ x.b = r->vconst;
+ x.a = 0;
+ if((rt->etype&1) && r->vconst < 0) /* signed negative */
+ x.a = ~0ULL;
+
+ if((lt->etype&1)==0){
+ /* unsigned */
+ lo = big(0, 0);
+ if(lt->width == 8)
+ hi = big(0, ~0ULL);
+ else
+ hi = big(0, (1LL<<(l->type->width*8))-1);
+ }else{
+ lo = big(~0ULL, -(1LL<<(l->type->width*8-1)));
+ hi = big(0, (1LL<<(l->type->width*8-1))-1);
+ }
+
+ switch(op){
+ case OLT:
+ case OLO:
+ case OGE:
+ case OHS:
+ if(cmp(x, lo) <= 0)
+ goto useless;
+ if(cmp(x, add(hi, 1)) >= 0)
+ goto useless;
+ break;
+ case OLE:
+ case OLS:
+ case OGT:
+ case OHI:
+ if(cmp(x, add(lo, -1)) <= 0)
+ goto useless;
+ if(cmp(x, hi) >= 0)
+ goto useless;
+ break;
+ case OEQ:
+ case ONE:
+ /*
+ * Don't warn about comparisons if the expression
+ * is as wide as the value: the compiler-supplied casts
+ * will make both outcomes possible.
+ */
+ if(lt->width >= rt->width && debug['w'] < 2)
+ return 0;
+ if(cmp(x, lo) < 0 || cmp(x, hi) > 0)
+ goto useless;
+ break;
+ }
+ return 0;
+
+useless:
+ if((x.a==0 && x.b<=9) || (x.a==~0LL && x.b >= -9ULL))
+ snprint(xbuf, sizeof xbuf, "%lld", x.b);
+ else if(x.a == 0)
+ snprint(xbuf, sizeof xbuf, "%#llux", x.b);
+ else
+ snprint(xbuf, sizeof xbuf, "%#llx", x.b);
+ if(reverse)
+ snprint(cmpbuf, sizeof cmpbuf, "%s %s %T",
+ xbuf, cmps[relindex(n->op)], lt);
+ else
+ snprint(cmpbuf, sizeof cmpbuf, "%T %s %s",
+ lt, cmps[relindex(n->op)], xbuf);
+ warn(n, "useless or misleading comparison: %s", cmpbuf);
+ return 0;
+}
+
diff --git a/src/cmd/cc/com64.c b/src/cmd/cc/com64.c
new file mode 100644
index 0000000..8d6e07d
--- /dev/null
+++ b/src/cmd/cc/com64.c
@@ -0,0 +1,643 @@
+// Inferno utils/cc/com64.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/com64.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+/*
+ * this is machine depend, but it is totally
+ * common on all of the 64-bit symulating machines.
+ */
+
+#define FNX 100 /* botch -- redefinition */
+
+Node* nodaddv;
+Node* nodsubv;
+Node* nodmulv;
+Node* noddivv;
+Node* noddivvu;
+Node* nodmodv;
+Node* nodmodvu;
+Node* nodlshv;
+Node* nodrshav;
+Node* nodrshlv;
+Node* nodandv;
+Node* nodorv;
+Node* nodxorv;
+Node* nodnegv;
+Node* nodcomv;
+
+Node* nodtestv;
+Node* nodeqv;
+Node* nodnev;
+Node* nodlev;
+Node* nodltv;
+Node* nodgev;
+Node* nodgtv;
+Node* nodhiv;
+Node* nodhsv;
+Node* nodlov;
+Node* nodlsv;
+
+Node* nodf2v;
+Node* nodd2v;
+Node* nodp2v;
+Node* nodsi2v;
+Node* nodui2v;
+Node* nodsl2v;
+Node* nodul2v;
+Node* nodsh2v;
+Node* noduh2v;
+Node* nodsc2v;
+Node* noduc2v;
+
+Node* nodv2f;
+Node* nodv2d;
+Node* nodv2ui;
+Node* nodv2si;
+Node* nodv2ul;
+Node* nodv2sl;
+Node* nodv2uh;
+Node* nodv2sh;
+Node* nodv2uc;
+Node* nodv2sc;
+
+Node* nodvpp;
+Node* nodppv;
+Node* nodvmm;
+Node* nodmmv;
+
+Node* nodvasop;
+
+char etconv[NTYPE]; /* for _vasop */
+Init initetconv[] =
+{
+ TCHAR, 1, 0,
+ TUCHAR, 2, 0,
+ TSHORT, 3, 0,
+ TUSHORT, 4, 0,
+ TLONG, 5, 0,
+ TULONG, 6, 0,
+ TVLONG, 7, 0,
+ TUVLONG, 8, 0,
+ TINT, 9, 0,
+ TUINT, 10, 0,
+ -1, 0, 0,
+};
+
+Node*
+fvn(char *name, int type)
+{
+ Node *n;
+
+ n = new(ONAME, Z, Z);
+ n->sym = slookup(name);
+ n->sym->sig = SIGINTERN;
+ if(fntypes[type] == 0)
+ fntypes[type] = typ(TFUNC, types[type]);
+ n->type = fntypes[type];
+ n->etype = type;
+ n->class = CGLOBL;
+ n->addable = 10;
+ n->complex = 0;
+ return n;
+}
+
+void
+com64init(void)
+{
+ Init *p;
+
+ nodaddv = fvn("_addv", TVLONG);
+ nodsubv = fvn("_subv", TVLONG);
+ nodmulv = fvn("_mulv", TVLONG);
+ noddivv = fvn("_divv", TVLONG);
+ noddivvu = fvn("_divvu", TVLONG);
+ nodmodv = fvn("_modv", TVLONG);
+ nodmodvu = fvn("_modvu", TVLONG);
+ nodlshv = fvn("_lshv", TVLONG);
+ nodrshav = fvn("_rshav", TVLONG);
+ nodrshlv = fvn("_rshlv", TVLONG);
+ nodandv = fvn("_andv", TVLONG);
+ nodorv = fvn("_orv", TVLONG);
+ nodxorv = fvn("_xorv", TVLONG);
+ nodnegv = fvn("_negv", TVLONG);
+ nodcomv = fvn("_comv", TVLONG);
+
+ nodtestv = fvn("_testv", TLONG);
+ nodeqv = fvn("_eqv", TLONG);
+ nodnev = fvn("_nev", TLONG);
+ nodlev = fvn("_lev", TLONG);
+ nodltv = fvn("_ltv", TLONG);
+ nodgev = fvn("_gev", TLONG);
+ nodgtv = fvn("_gtv", TLONG);
+ nodhiv = fvn("_hiv", TLONG);
+ nodhsv = fvn("_hsv", TLONG);
+ nodlov = fvn("_lov", TLONG);
+ nodlsv = fvn("_lsv", TLONG);
+
+ nodf2v = fvn("_f2v", TVLONG);
+ nodd2v = fvn("_d2v", TVLONG);
+ nodp2v = fvn("_p2v", TVLONG);
+ nodsi2v = fvn("_si2v", TVLONG);
+ nodui2v = fvn("_ui2v", TVLONG);
+ nodsl2v = fvn("_sl2v", TVLONG);
+ nodul2v = fvn("_ul2v", TVLONG);
+ nodsh2v = fvn("_sh2v", TVLONG);
+ noduh2v = fvn("_uh2v", TVLONG);
+ nodsc2v = fvn("_sc2v", TVLONG);
+ noduc2v = fvn("_uc2v", TVLONG);
+
+ nodv2f = fvn("_v2f", TFLOAT);
+ nodv2d = fvn("_v2d", TDOUBLE);
+ nodv2sl = fvn("_v2sl", TLONG);
+ nodv2ul = fvn("_v2ul", TULONG);
+ nodv2si = fvn("_v2si", TINT);
+ nodv2ui = fvn("_v2ui", TUINT);
+ nodv2sh = fvn("_v2sh", TSHORT);
+ nodv2uh = fvn("_v2ul", TUSHORT);
+ nodv2sc = fvn("_v2sc", TCHAR);
+ nodv2uc = fvn("_v2uc", TUCHAR);
+
+ nodvpp = fvn("_vpp", TVLONG);
+ nodppv = fvn("_ppv", TVLONG);
+ nodvmm = fvn("_vmm", TVLONG);
+ nodmmv = fvn("_mmv", TVLONG);
+
+ nodvasop = fvn("_vasop", TVLONG);
+
+ for(p = initetconv; p->code >= 0; p++)
+ etconv[p->code] = p->value;
+}
+
+int
+com64(Node *n)
+{
+ Node *l, *r, *a, *t;
+ int lv, rv;
+
+ if(n->type == 0)
+ return 0;
+
+ l = n->left;
+ r = n->right;
+
+ lv = 0;
+ if(l && l->type && typev[l->type->etype])
+ lv = 1;
+ rv = 0;
+ if(r && r->type && typev[r->type->etype])
+ rv = 1;
+
+ if(lv) {
+ switch(n->op) {
+ case OEQ:
+ a = nodeqv;
+ goto setbool;
+ case ONE:
+ a = nodnev;
+ goto setbool;
+ case OLE:
+ a = nodlev;
+ goto setbool;
+ case OLT:
+ a = nodltv;
+ goto setbool;
+ case OGE:
+ a = nodgev;
+ goto setbool;
+ case OGT:
+ a = nodgtv;
+ goto setbool;
+ case OHI:
+ a = nodhiv;
+ goto setbool;
+ case OHS:
+ a = nodhsv;
+ goto setbool;
+ case OLO:
+ a = nodlov;
+ goto setbool;
+ case OLS:
+ a = nodlsv;
+ goto setbool;
+
+ case OANDAND:
+ case OOROR:
+ if(machcap(n))
+ return 1;
+
+ if(rv) {
+ r = new(OFUNC, nodtestv, r);
+ n->right = r;
+ r->complex = FNX;
+ r->op = OFUNC;
+ r->type = types[TLONG];
+ }
+
+ case OCOND:
+ case ONOT:
+ if(machcap(n))
+ return 1;
+
+ l = new(OFUNC, nodtestv, l);
+ n->left = l;
+ l->complex = FNX;
+ l->op = OFUNC;
+ l->type = types[TLONG];
+ n->complex = FNX;
+ return 1;
+ }
+ }
+
+ if(rv) {
+ if(machcap(n))
+ return 1;
+ switch(n->op) {
+ case OANDAND:
+ case OOROR:
+ r = new(OFUNC, nodtestv, r);
+ n->right = r;
+ r->complex = FNX;
+ r->op = OFUNC;
+ r->type = types[TLONG];
+ return 1;
+ }
+ }
+
+ if(typev[n->type->etype]) {
+ if(machcap(n))
+ return 1;
+ switch(n->op) {
+ default:
+ diag(n, "unknown vlong %O", n->op);
+ case OFUNC:
+ n->complex = FNX;
+ case ORETURN:
+ case OAS:
+ case OIND:
+ return 1;
+ case OADD:
+ a = nodaddv;
+ goto setbop;
+ case OSUB:
+ a = nodsubv;
+ goto setbop;
+ case OMUL:
+ case OLMUL:
+ a = nodmulv;
+ goto setbop;
+ case ODIV:
+ a = noddivv;
+ goto setbop;
+ case OLDIV:
+ a = noddivvu;
+ goto setbop;
+ case OMOD:
+ a = nodmodv;
+ goto setbop;
+ case OLMOD:
+ a = nodmodvu;
+ goto setbop;
+ case OASHL:
+ a = nodlshv;
+ goto setbop;
+ case OASHR:
+ a = nodrshav;
+ goto setbop;
+ case OLSHR:
+ a = nodrshlv;
+ goto setbop;
+ case OAND:
+ a = nodandv;
+ goto setbop;
+ case OOR:
+ a = nodorv;
+ goto setbop;
+ case OXOR:
+ a = nodxorv;
+ goto setbop;
+ case OPOSTINC:
+ a = nodvpp;
+ goto setvinc;
+ case OPOSTDEC:
+ a = nodvmm;
+ goto setvinc;
+ case OPREINC:
+ a = nodppv;
+ goto setvinc;
+ case OPREDEC:
+ a = nodmmv;
+ goto setvinc;
+ case ONEG:
+ a = nodnegv;
+ goto setfnx;
+ case OCOM:
+ a = nodcomv;
+ goto setfnx;
+ case OCAST:
+ switch(l->type->etype) {
+ case TCHAR:
+ a = nodsc2v;
+ goto setfnxl;
+ case TUCHAR:
+ a = noduc2v;
+ goto setfnxl;
+ case TSHORT:
+ a = nodsh2v;
+ goto setfnxl;
+ case TUSHORT:
+ a = noduh2v;
+ goto setfnxl;
+ case TINT:
+ a = nodsi2v;
+ goto setfnx;
+ case TUINT:
+ a = nodui2v;
+ goto setfnx;
+ case TLONG:
+ a = nodsl2v;
+ goto setfnx;
+ case TULONG:
+ a = nodul2v;
+ goto setfnx;
+ case TFLOAT:
+ a = nodf2v;
+ goto setfnx;
+ case TDOUBLE:
+ a = nodd2v;
+ goto setfnx;
+ case TIND:
+ a = nodp2v;
+ goto setfnx;
+ }
+ diag(n, "unknown %T->vlong cast", l->type);
+ return 1;
+ case OASADD:
+ a = nodaddv;
+ goto setasop;
+ case OASSUB:
+ a = nodsubv;
+ goto setasop;
+ case OASMUL:
+ case OASLMUL:
+ a = nodmulv;
+ goto setasop;
+ case OASDIV:
+ a = noddivv;
+ goto setasop;
+ case OASLDIV:
+ a = noddivvu;
+ goto setasop;
+ case OASMOD:
+ a = nodmodv;
+ goto setasop;
+ case OASLMOD:
+ a = nodmodvu;
+ goto setasop;
+ case OASASHL:
+ a = nodlshv;
+ goto setasop;
+ case OASASHR:
+ a = nodrshav;
+ goto setasop;
+ case OASLSHR:
+ a = nodrshlv;
+ goto setasop;
+ case OASAND:
+ a = nodandv;
+ goto setasop;
+ case OASOR:
+ a = nodorv;
+ goto setasop;
+ case OASXOR:
+ a = nodxorv;
+ goto setasop;
+ }
+ }
+
+ if(typefd[n->type->etype] && l && l->op == OFUNC) {
+ switch(n->op) {
+ case OASADD:
+ case OASSUB:
+ case OASMUL:
+ case OASLMUL:
+ case OASDIV:
+ case OASLDIV:
+ case OASMOD:
+ case OASLMOD:
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+ if(l->right && typev[l->right->etype]) {
+ diag(n, "sorry float <asop> vlong not implemented\n");
+ }
+ }
+ }
+
+ if(n->op == OCAST) {
+ if(l->type && typev[l->type->etype]) {
+ if(machcap(n))
+ return 1;
+ switch(n->type->etype) {
+ case TDOUBLE:
+ a = nodv2d;
+ goto setfnx;
+ case TFLOAT:
+ a = nodv2f;
+ goto setfnx;
+ case TLONG:
+ a = nodv2sl;
+ goto setfnx;
+ case TULONG:
+ a = nodv2ul;
+ goto setfnx;
+ case TINT:
+ a = nodv2si;
+ goto setfnx;
+ case TUINT:
+ a = nodv2ui;
+ goto setfnx;
+ case TSHORT:
+ a = nodv2sh;
+ goto setfnx;
+ case TUSHORT:
+ a = nodv2uh;
+ goto setfnx;
+ case TCHAR:
+ a = nodv2sc;
+ goto setfnx;
+ case TUCHAR:
+ a = nodv2uc;
+ goto setfnx;
+ case TIND: // small pun here
+ a = nodv2ul;
+ goto setfnx;
+ }
+ diag(n, "unknown vlong->%T cast", n->type);
+ return 1;
+ }
+ }
+
+ return 0;
+
+setbop:
+ n->left = a;
+ n->right = new(OLIST, l, r);
+ n->complex = FNX;
+ n->op = OFUNC;
+ return 1;
+
+setfnxl:
+ l = new(OCAST, l, 0);
+ l->type = types[TLONG];
+ l->complex = l->left->complex;
+
+setfnx:
+ n->left = a;
+ n->right = l;
+ n->complex = FNX;
+ n->op = OFUNC;
+ return 1;
+
+setvinc:
+ n->left = a;
+ l = new(OADDR, l, Z);
+ l->type = typ(TIND, l->left->type);
+ n->right = new(OLIST, l, r);
+ n->complex = FNX;
+ n->op = OFUNC;
+ return 1;
+
+setbool:
+ if(machcap(n))
+ return 1;
+ n->left = a;
+ n->right = new(OLIST, l, r);
+ n->complex = FNX;
+ n->op = OFUNC;
+ n->type = types[TLONG];
+ return 1;
+
+setasop:
+ if(l->op == OFUNC) {
+ l = l->right;
+ goto setasop;
+ }
+
+ t = new(OCONST, 0, 0);
+ t->vconst = etconv[l->type->etype];
+ t->type = types[TLONG];
+ t->addable = 20;
+ r = new(OLIST, t, r);
+
+ t = new(OADDR, a, 0);
+ t->type = typ(TIND, a->type);
+ r = new(OLIST, t, r);
+
+ t = new(OADDR, l, 0);
+ t->type = typ(TIND, l->type);
+ r = new(OLIST, t, r);
+
+ n->left = nodvasop;
+ n->right = r;
+ n->complex = FNX;
+ n->op = OFUNC;
+
+ return 1;
+}
+
+void
+bool64(Node *n)
+{
+ Node *n1;
+
+ if(machcap(Z))
+ return;
+ if(typev[n->type->etype]) {
+ n1 = new(OXXX, 0, 0);
+ *n1 = *n;
+
+ n->right = n1;
+ n->left = nodtestv;
+ n->complex = FNX;
+ n->addable = 0;
+ n->op = OFUNC;
+ n->type = types[TLONG];
+ }
+}
+
+/*
+ * more machine depend stuff.
+ * this is common for 8,16,32,64 bit machines.
+ * this is common for ieee machines.
+ */
+double
+convvtof(vlong v)
+{
+ double d;
+
+ d = v; /* BOTCH */
+ return d;
+}
+
+vlong
+convftov(double d)
+{
+ vlong v;
+
+
+ v = d; /* BOTCH */
+ return v;
+}
+
+double
+convftox(double d, int et)
+{
+
+ if(!typefd[et])
+ diag(Z, "bad type in castftox %s", tnames[et]);
+ return d;
+}
+
+vlong
+convvtox(vlong c, int et)
+{
+ int n;
+
+ n = 8 * ewidth[et];
+ c &= MASK(n);
+ if(!typeu[et])
+ if(c & SIGN(n))
+ c |= ~MASK(n);
+ return c;
+}
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
new file mode 100644
index 0000000..f44c340
--- /dev/null
+++ b/src/cmd/cc/dcl.c
@@ -0,0 +1,1664 @@
+// Inferno utils/cc/dcl.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/dcl.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+Node*
+dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n)
+{
+ Sym *s;
+ Node *n1;
+ long v;
+
+ nearln = lineno;
+ lastfield = 0;
+
+loop:
+ if(n != Z)
+ switch(n->op) {
+ default:
+ diag(n, "unknown declarator: %O", n->op);
+ break;
+
+ case OARRAY:
+ t = typ(TARRAY, t);
+ t->width = 0;
+ n1 = n->right;
+ n = n->left;
+ if(n1 != Z) {
+ complex(n1);
+ v = -1;
+ if(n1->op == OCONST)
+ v = n1->vconst;
+ if(v <= 0) {
+ diag(n, "array size must be a positive constant");
+ v = 1;
+ }
+ t->width = v * t->link->width;
+ }
+ goto loop;
+
+ case OIND:
+ t = typ(TIND, t);
+ t->garb = n->garb;
+ n = n->left;
+ goto loop;
+
+ case OFUNC:
+ t = typ(TFUNC, t);
+ t->down = fnproto(n);
+ n = n->left;
+ goto loop;
+
+ case OBIT:
+ n1 = n->right;
+ complex(n1);
+ lastfield = -1;
+ if(n1->op == OCONST)
+ lastfield = n1->vconst;
+ if(lastfield < 0) {
+ diag(n, "field width must be non-negative constant");
+ lastfield = 1;
+ }
+ if(lastfield == 0) {
+ lastbit = 0;
+ firstbit = 1;
+ if(n->left != Z) {
+ diag(n, "zero width named field");
+ lastfield = 1;
+ }
+ }
+ if(!typei[t->etype]) {
+ diag(n, "field type must be int-like");
+ t = types[TINT];
+ lastfield = 1;
+ }
+ if(lastfield > tfield->width*8) {
+ diag(n, "field width larger than field unit");
+ lastfield = 1;
+ }
+ lastbit += lastfield;
+ if(lastbit > tfield->width*8) {
+ lastbit = lastfield;
+ firstbit = 1;
+ }
+ n = n->left;
+ goto loop;
+
+ case ONAME:
+ if(f == NODECL)
+ break;
+ s = n->sym;
+ (*f)(c, t, s);
+ if(s->class == CLOCAL)
+ s = mkstatic(s);
+ firstbit = 0;
+ n->sym = s;
+ n->type = s->type;
+ n->xoffset = s->offset;
+ n->class = s->class;
+ n->etype = TVOID;
+ if(n->type != T)
+ n->etype = n->type->etype;
+ if(debug['d'])
+ dbgdecl(s);
+ acidvar(s);
+ s->varlineno = lineno;
+ break;
+ }
+ lastdcl = t;
+ return n;
+}
+
+Sym*
+mkstatic(Sym *s)
+{
+ Sym *s1;
+
+ if(s->class != CLOCAL)
+ return s;
+ snprint(symb, NSYMB, "%s$%d", s->name, s->block);
+ s1 = lookup();
+ if(s1->class != CSTATIC) {
+ s1->type = s->type;
+ s1->offset = s->offset;
+ s1->block = s->block;
+ s1->class = CSTATIC;
+ }
+ return s1;
+}
+
+/*
+ * make a copy of a typedef
+ * the problem is to split out incomplete
+ * arrays so that it is in the variable
+ * rather than the typedef.
+ */
+Type*
+tcopy(Type *t)
+{
+ Type *tl, *tx;
+ int et;
+
+ if(t == T)
+ return t;
+ et = t->etype;
+ if(typesu[et])
+ return t;
+ tl = tcopy(t->link);
+ if(tl != t->link ||
+ (et == TARRAY && t->width == 0)) {
+ tx = copytyp(t);
+ tx->link = tl;
+ return tx;
+ }
+ return t;
+}
+
+Node*
+doinit(Sym *s, Type *t, long o, Node *a)
+{
+ Node *n;
+
+ if(t == T)
+ return Z;
+ if(s->class == CEXTERN) {
+ s->class = CGLOBL;
+ if(debug['d'])
+ dbgdecl(s);
+ }
+ if(debug['i']) {
+ print("t = %T; o = %ld; n = %s\n", t, o, s->name);
+ prtree(a, "doinit value");
+ }
+
+
+ n = initlist;
+ if(a->op == OINIT)
+ a = a->left;
+ initlist = a;
+
+ a = init1(s, t, o, 0);
+ if(initlist != Z)
+ diag(initlist, "more initializers than structure: %s",
+ s->name);
+ initlist = n;
+
+ return a;
+}
+
+/*
+ * get next major operator,
+ * dont advance initlist.
+ */
+Node*
+peekinit(void)
+{
+ Node *a;
+
+ a = initlist;
+
+loop:
+ if(a == Z)
+ return a;
+ if(a->op == OLIST) {
+ a = a->left;
+ goto loop;
+ }
+ return a;
+}
+
+/*
+ * consume and return next element on
+ * initlist. expand strings.
+ */
+Node*
+nextinit(void)
+{
+ Node *a, *b, *n;
+
+ a = initlist;
+ n = Z;
+
+ if(a == Z)
+ return a;
+ if(a->op == OLIST) {
+ n = a->right;
+ a = a->left;
+ }
+ if(a->op == OUSED) {
+ a = a->left;
+ b = new(OCONST, Z, Z);
+ b->type = a->type->link;
+ if(a->op == OSTRING) {
+ b->vconst = convvtox(*a->cstring, TCHAR);
+ a->cstring++;
+ }
+ if(a->op == OLSTRING) {
+ b->vconst = convvtox(*a->rstring, TUSHORT);
+ a->rstring++;
+ }
+ a->type->width -= b->type->width;
+ if(a->type->width <= 0)
+ initlist = n;
+ return b;
+ }
+ initlist = n;
+ return a;
+}
+
+int
+isstruct(Node *a, Type *t)
+{
+ Node *n;
+
+ switch(a->op) {
+ case ODOTDOT:
+ n = a->left;
+ if(n && n->type && sametype(n->type, t))
+ return 1;
+ case OSTRING:
+ case OLSTRING:
+ case OCONST:
+ case OINIT:
+ case OELEM:
+ return 0;
+ }
+
+ n = new(ODOTDOT, Z, Z);
+ *n = *a;
+
+ /*
+ * ODOTDOT is a flag for tcom
+ * a second tcom will not be performed
+ */
+ a->op = ODOTDOT;
+ a->left = n;
+ a->right = Z;
+
+ if(tcom(n))
+ return 0;
+
+ if(sametype(n->type, t))
+ return 1;
+ return 0;
+}
+
+Node*
+init1(Sym *s, Type *t, long o, int exflag)
+{
+ Node *a, *l, *r, nod;
+ Type *t1;
+ long e, w, so, mw;
+
+ a = peekinit();
+ if(a == Z)
+ return Z;
+
+ if(debug['i']) {
+ print("t = %T; o = %ld; n = %s\n", t, o, s->name);
+ prtree(a, "init1 value");
+ }
+
+ if(exflag && a->op == OINIT)
+ return doinit(s, t, o, nextinit());
+
+ switch(t->etype) {
+ default:
+ diag(Z, "unknown type in initialization: %T to: %s", t, s->name);
+ return Z;
+
+ case TCHAR:
+ case TUCHAR:
+ case TINT:
+ case TUINT:
+ case TSHORT:
+ case TUSHORT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TFLOAT:
+ case TDOUBLE:
+ case TIND:
+ single:
+ if(a->op == OARRAY || a->op == OELEM)
+ return Z;
+
+ a = nextinit();
+ if(a == Z)
+ return Z;
+
+ if(t->nbits)
+ diag(Z, "cannot initialize bitfields");
+ if(s->class == CAUTO) {
+ l = new(ONAME, Z, Z);
+ l->sym = s;
+ l->type = t;
+ l->etype = TVOID;
+ if(s->type)
+ l->etype = s->type->etype;
+ l->xoffset = s->offset + o;
+ l->class = s->class;
+
+ l = new(OASI, l, a);
+ return l;
+ }
+
+ complex(a);
+ if(a->type == T)
+ return Z;
+
+ if(a->op == OCONST) {
+ if(vconst(a) && t->etype == TIND && a->type && a->type->etype != TIND){
+ diag(a, "initialize pointer to an integer: %s", s->name);
+ return Z;
+ }
+ if(!sametype(a->type, t)) {
+ /* hoop jumping to save malloc */
+ if(nodcast == Z)
+ nodcast = new(OCAST, Z, Z);
+ nod = *nodcast;
+ nod.left = a;
+ nod.type = t;
+ nod.lineno = a->lineno;
+ complex(&nod);
+ if(nod.type)
+ *a = nod;
+ }
+ if(a->op != OCONST) {
+ diag(a, "initializer is not a constant: %s",
+ s->name);
+ return Z;
+ }
+ if(vconst(a) == 0)
+ return Z;
+ goto gext;
+ }
+ if(t->etype == TIND) {
+ while(a->op == OCAST) {
+ warn(a, "CAST in initialization ignored");
+ a = a->left;
+ }
+ if(!sametype(t, a->type)) {
+ diag(a, "initialization of incompatible pointers: %s\n%T and %T",
+ s->name, t, a->type);
+ }
+ if(a->op == OADDR)
+ a = a->left;
+ goto gext;
+ }
+
+ while(a->op == OCAST)
+ a = a->left;
+ if(a->op == OADDR) {
+ warn(a, "initialize pointer to an integer: %s", s->name);
+ a = a->left;
+ goto gext;
+ }
+ diag(a, "initializer is not a constant: %s", s->name);
+ return Z;
+
+ gext:
+ gextern(s, a, o, t->width);
+
+ return Z;
+
+ case TARRAY:
+ w = t->link->width;
+ if(a->op == OSTRING || a->op == OLSTRING)
+ if(typei[t->link->etype]) {
+ /*
+ * get rid of null if sizes match exactly
+ */
+ a = nextinit();
+ mw = t->width/w;
+ so = a->type->width/a->type->link->width;
+ if(mw && so > mw) {
+ if(so != mw+1)
+ diag(a, "string initialization larger than array");
+ a->type->width -= a->type->link->width;
+ }
+
+ /*
+ * arrange strings to be expanded
+ * inside OINIT braces.
+ */
+ a = new(OUSED, a, Z);
+ return doinit(s, t, o, a);
+ }
+
+ mw = -w;
+ l = Z;
+ for(e=0;;) {
+ /*
+ * peek ahead for element initializer
+ */
+ a = peekinit();
+ if(a == Z)
+ break;
+ if(a->op == OELEM && t->link->etype != TSTRUCT)
+ break;
+ if(a->op == OARRAY) {
+ if(e && exflag)
+ break;
+ a = nextinit();
+ r = a->left;
+ complex(r);
+ if(r->op != OCONST) {
+ diag(r, "initializer subscript must be constant");
+ return Z;
+ }
+ e = r->vconst;
+ if(t->width != 0)
+ if(e < 0 || e*w >= t->width) {
+ diag(a, "initialization index out of range: %ld", e);
+ continue;
+ }
+ }
+
+ so = e*w;
+ if(so > mw)
+ mw = so;
+ if(t->width != 0)
+ if(mw >= t->width)
+ break;
+ r = init1(s, t->link, o+so, 1);
+ l = newlist(l, r);
+ e++;
+ }
+ if(t->width == 0)
+ t->width = mw+w;
+ return l;
+
+ case TUNION:
+ case TSTRUCT:
+ /*
+ * peek ahead to find type of rhs.
+ * if its a structure, then treat
+ * this element as a variable
+ * rather than an aggregate.
+ */
+ if(isstruct(a, t))
+ goto single;
+
+ if(t->width <= 0) {
+ diag(Z, "incomplete structure: %s", s->name);
+ return Z;
+ }
+ l = Z;
+
+ again:
+ for(t1 = t->link; t1 != T; t1 = t1->down) {
+ if(a->op == OARRAY && t1->etype != TARRAY)
+ break;
+ if(a->op == OELEM) {
+ if(t1->sym != a->sym)
+ continue;
+ nextinit();
+ }
+ r = init1(s, t1, o+t1->offset, 1);
+ l = newlist(l, r);
+ a = peekinit();
+ if(a == Z)
+ break;
+ if(a->op == OELEM)
+ goto again;
+ }
+ if(a && a->op == OELEM)
+ diag(a, "structure element not found %F", a);
+ return l;
+ }
+}
+
+Node*
+newlist(Node *l, Node *r)
+{
+ if(r == Z)
+ return l;
+ if(l == Z)
+ return r;
+ return new(OLIST, l, r);
+}
+
+void
+suallign(Type *t)
+{
+ Type *l;
+ long o, w;
+
+ o = 0;
+ switch(t->etype) {
+
+ case TSTRUCT:
+ t->offset = 0;
+ w = 0;
+ for(l = t->link; l != T; l = l->down) {
+ if(l->nbits) {
+ if(l->shift <= 0) {
+ l->shift = -l->shift;
+ w = xround(w, tfield->width);
+ o = w;
+ w += tfield->width;
+ }
+ l->offset = o;
+ } else {
+ if(l->width <= 0)
+ if(l->down != T)
+ if(l->sym)
+ diag(Z, "incomplete structure element: %s",
+ l->sym->name);
+ else
+ diag(Z, "incomplete structure element");
+ w = align(w, l, Ael1);
+ l->offset = w;
+ w = align(w, l, Ael2);
+ }
+ }
+ w = align(w, t, Asu2);
+ t->width = w;
+ acidtype(t);
+ pickletype(t);
+ return;
+
+ case TUNION:
+ t->offset = 0;
+ w = 0;
+ for(l = t->link; l != T; l = l->down) {
+ if(l->width <= 0)
+ if(l->sym)
+ diag(Z, "incomplete union element: %s",
+ l->sym->name);
+ else
+ diag(Z, "incomplete union element");
+ l->offset = 0;
+ l->shift = 0;
+ o = align(align(0, l, Ael1), l, Ael2);
+ if(o > w)
+ w = o;
+ }
+ w = align(w, t, Asu2);
+ t->width = w;
+ acidtype(t);
+ pickletype(t);
+ return;
+
+ default:
+ diag(Z, "unknown type in suallign: %T", t);
+ break;
+ }
+}
+
+long
+xround(long v, int w)
+{
+ int r;
+
+ if(w <= 0 || w > 8) {
+ diag(Z, "rounding by %d", w);
+ w = 1;
+ }
+ r = v%w;
+ if(r)
+ v += w-r;
+ return v;
+}
+
+Type*
+ofnproto(Node *n)
+{
+ Type *tl, *tr, *t;
+
+ if(n == Z)
+ return T;
+ switch(n->op) {
+ case OLIST:
+ tl = ofnproto(n->left);
+ tr = ofnproto(n->right);
+ if(tl == T)
+ return tr;
+ tl->down = tr;
+ return tl;
+
+ case ONAME:
+ t = copytyp(n->sym->type);
+ t->down = T;
+ return t;
+ }
+ return T;
+}
+
+#define ANSIPROTO 1
+#define OLDPROTO 2
+
+void
+argmark(Node *n, int pass)
+{
+ Type *t;
+
+ autoffset = align(0, thisfn->link, Aarg0);
+ stkoff = 0;
+ for(; n->left != Z; n = n->left) {
+ if(n->op != OFUNC || n->left->op != ONAME)
+ continue;
+ walkparam(n->right, pass);
+ if(pass != 0 && anyproto(n->right) == OLDPROTO) {
+ t = typ(TFUNC, n->left->sym->type->link);
+ t->down = typ(TOLD, T);
+ t->down->down = ofnproto(n->right);
+ tmerge(t, n->left->sym);
+ n->left->sym->type = t;
+ }
+ break;
+ }
+ autoffset = 0;
+ stkoff = 0;
+}
+
+void
+walkparam(Node *n, int pass)
+{
+ Sym *s;
+ Node *n1;
+
+ if(n != Z && n->op == OPROTO && n->left == Z && n->type == types[TVOID])
+ return;
+
+loop:
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ diag(n, "argument not a name/prototype: %O", n->op);
+ break;
+
+ case OLIST:
+ walkparam(n->left, pass);
+ n = n->right;
+ goto loop;
+
+ case OPROTO:
+ for(n1 = n; n1 != Z; n1=n1->left)
+ if(n1->op == ONAME) {
+ if(pass == 0) {
+ s = n1->sym;
+ push1(s);
+ s->offset = -1;
+ break;
+ }
+ dodecl(pdecl, CPARAM, n->type, n->left);
+ break;
+ }
+ if(n1)
+ break;
+ if(pass == 0) {
+ /*
+ * extension:
+ * allow no name in argument declaration
+ diag(Z, "no name in argument declaration");
+ */
+ break;
+ }
+ dodecl(NODECL, CPARAM, n->type, n->left);
+ pdecl(CPARAM, lastdcl, S);
+ break;
+
+ case ODOTDOT:
+ break;
+
+ case ONAME:
+ s = n->sym;
+ if(pass == 0) {
+ push1(s);
+ s->offset = -1;
+ break;
+ }
+ if(s->offset != -1) {
+ if(autoffset == 0) {
+ firstarg = s;
+ firstargtype = s->type;
+ }
+ autoffset = align(autoffset, s->type, Aarg1);
+ s->offset = autoffset;
+ autoffset = align(autoffset, s->type, Aarg2);
+ } else
+ dodecl(pdecl, CXXX, types[TINT], n);
+ break;
+ }
+}
+
+void
+markdcl(void)
+{
+ Decl *d;
+
+ blockno++;
+ d = push();
+ d->val = DMARK;
+ d->offset = autoffset;
+ d->block = autobn;
+ autobn = blockno;
+}
+
+Node*
+revertdcl(void)
+{
+ Decl *d;
+ Sym *s;
+ Node *n, *n1;
+
+ n = Z;
+ for(;;) {
+ d = dclstack;
+ if(d == D) {
+ diag(Z, "pop off dcl stack");
+ break;
+ }
+ dclstack = d->link;
+ s = d->sym;
+ switch(d->val) {
+ case DMARK:
+ autoffset = d->offset;
+ autobn = d->block;
+ return n;
+
+ case DAUTO:
+ if(debug['d'])
+ print("revert1 \"%s\"\n", s->name);
+ if(s->aused == 0) {
+ nearln = s->varlineno;
+ if(s->class == CAUTO)
+ warn(Z, "auto declared and not used: %s", s->name);
+ if(s->class == CPARAM)
+ warn(Z, "param declared and not used: %s", s->name);
+ }
+ if(s->type && (s->type->garb & GVOLATILE)) {
+ n1 = new(ONAME, Z, Z);
+ n1->sym = s;
+ n1->type = s->type;
+ n1->etype = TVOID;
+ if(n1->type != T)
+ n1->etype = n1->type->etype;
+ n1->xoffset = s->offset;
+ n1->class = s->class;
+
+ n1 = new(OADDR, n1, Z);
+ n1 = new(OUSED, n1, Z);
+ if(n == Z)
+ n = n1;
+ else
+ n = new(OLIST, n1, n);
+ }
+ s->type = d->type;
+ s->class = d->class;
+ s->offset = d->offset;
+ s->block = d->block;
+ s->varlineno = d->varlineno;
+ s->aused = d->aused;
+ break;
+
+ case DSUE:
+ if(debug['d'])
+ print("revert2 \"%s\"\n", s->name);
+ s->suetag = d->type;
+ s->sueblock = d->block;
+ break;
+
+ case DLABEL:
+ if(debug['d'])
+ print("revert3 \"%s\"\n", s->name);
+ if(s->label && s->label->addable == 0)
+ warn(s->label, "label declared and not used \"%s\"", s->name);
+ s->label = Z;
+ break;
+ }
+ }
+ return n;
+}
+
+Type*
+fnproto(Node *n)
+{
+ int r;
+
+ r = anyproto(n->right);
+ if(r == 0 || (r & OLDPROTO)) {
+ if(r & ANSIPROTO)
+ diag(n, "mixed ansi/old function declaration: %F", n->left);
+ return T;
+ }
+ return fnproto1(n->right);
+}
+
+int
+anyproto(Node *n)
+{
+ int r;
+
+ r = 0;
+
+loop:
+ if(n == Z)
+ return r;
+ switch(n->op) {
+ case OLIST:
+ r |= anyproto(n->left);
+ n = n->right;
+ goto loop;
+
+ case ODOTDOT:
+ case OPROTO:
+ return r | ANSIPROTO;
+ }
+ return r | OLDPROTO;
+}
+
+Type*
+fnproto1(Node *n)
+{
+ Type *t;
+
+ if(n == Z)
+ return T;
+ switch(n->op) {
+ case OLIST:
+ t = fnproto1(n->left);
+ if(t != T)
+ t->down = fnproto1(n->right);
+ return t;
+
+ case OPROTO:
+ lastdcl = T;
+ dodecl(NODECL, CXXX, n->type, n->left);
+ t = typ(TXXX, T);
+ if(lastdcl != T)
+ *t = *paramconv(lastdcl, 1);
+ return t;
+
+ case ONAME:
+ diag(n, "incomplete argument prototype");
+ return typ(TINT, T);
+
+ case ODOTDOT:
+ return typ(TDOT, T);
+ }
+ diag(n, "unknown op in fnproto");
+ return T;
+}
+
+void
+dbgdecl(Sym *s)
+{
+ print("decl \"%s\": C=%s [B=%d:O=%ld] T=%T\n",
+ s->name, cnames[s->class], s->block, s->offset, s->type);
+}
+
+Decl*
+push(void)
+{
+ Decl *d;
+
+ d = alloc(sizeof(*d));
+ d->link = dclstack;
+ dclstack = d;
+ return d;
+}
+
+Decl*
+push1(Sym *s)
+{
+ Decl *d;
+
+ d = push();
+ d->sym = s;
+ d->val = DAUTO;
+ d->type = s->type;
+ d->class = s->class;
+ d->offset = s->offset;
+ d->block = s->block;
+ d->varlineno = s->varlineno;
+ d->aused = s->aused;
+ return d;
+}
+
+int
+sametype(Type *t1, Type *t2)
+{
+
+ if(t1 == t2)
+ return 1;
+ return rsametype(t1, t2, 5, 1);
+}
+
+int
+rsametype(Type *t1, Type *t2, int n, int f)
+{
+ int et;
+
+ n--;
+ for(;;) {
+ if(t1 == t2)
+ return 1;
+ if(t1 == T || t2 == T)
+ return 0;
+ if(n <= 0)
+ return 1;
+ et = t1->etype;
+ if(et != t2->etype)
+ return 0;
+ if(et == TFUNC) {
+ if(!rsametype(t1->link, t2->link, n, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ while(t1 != T && t2 != T) {
+ if(t1->etype == TOLD) {
+ t1 = t1->down;
+ continue;
+ }
+ if(t2->etype == TOLD) {
+ t2 = t2->down;
+ continue;
+ }
+ while(t1 != T || t2 != T) {
+ if(!rsametype(t1, t2, n, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ break;
+ }
+ return 1;
+ }
+ if(et == TARRAY)
+ if(t1->width != t2->width && t1->width != 0 && t2->width != 0)
+ return 0;
+ if(typesu[et]) {
+ if(t1->link == T)
+ snap(t1);
+ if(t2->link == T)
+ snap(t2);
+ t1 = t1->link;
+ t2 = t2->link;
+ for(;;) {
+ if(t1 == t2)
+ return 1;
+ if(!rsametype(t1, t2, n, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ }
+ t1 = t1->link;
+ t2 = t2->link;
+ if((f || !debug['V']) && et == TIND) {
+ if(t1 != T && t1->etype == TVOID)
+ return 1;
+ if(t2 != T && t2->etype == TVOID)
+ return 1;
+ }
+ }
+}
+
+typedef struct Typetab Typetab;
+
+struct Typetab{
+ int n;
+ Type **a;
+};
+
+static int
+sigind(Type *t, Typetab *tt)
+{
+ int n;
+ Type **a, **na, **p, **e;
+
+ n = tt->n;
+ a = tt->a;
+ e = a+n;
+ /* linear search seems ok */
+ for(p = a ; p < e; p++)
+ if(sametype(*p, t))
+ return p-a;
+ if((n&15) == 0){
+ na = malloc((n+16)*sizeof(Type*));
+ memmove(na, a, n*sizeof(Type*));
+ free(a);
+ a = tt->a = na;
+ }
+ a[tt->n++] = t;
+ return -1;
+}
+
+static ulong
+signat(Type *t, Typetab *tt)
+{
+ int i;
+ Type *t1;
+ long s;
+
+ s = 0;
+ for(; t; t=t->link) {
+ s = s*thash1 + thash[t->etype];
+ if(t->garb&GINCOMPLETE)
+ return s;
+ switch(t->etype) {
+ default:
+ return s;
+ case TARRAY:
+ s = s*thash2 + 0; /* was t->width */
+ break;
+ case TFUNC:
+ for(t1=t->down; t1; t1=t1->down)
+ s = s*thash3 + signat(t1, tt);
+ break;
+ case TSTRUCT:
+ case TUNION:
+ if((i = sigind(t, tt)) >= 0){
+ s = s*thash2 + i;
+ return s;
+ }
+ for(t1=t->link; t1; t1=t1->down)
+ s = s*thash3 + signat(t1, tt);
+ return s;
+ case TIND:
+ break;
+ }
+ }
+ return s;
+}
+
+ulong
+signature(Type *t)
+{
+ ulong s;
+ Typetab tt;
+
+ tt.n = 0;
+ tt.a = nil;
+ s = signat(t, &tt);
+ free(tt.a);
+ return s;
+}
+
+ulong
+sign(Sym *s)
+{
+ ulong v;
+ Type *t;
+
+ if(s->sig == SIGINTERN)
+ return SIGNINTERN;
+ if((t = s->type) == T)
+ return 0;
+ v = signature(t);
+ if(v == 0)
+ v = SIGNINTERN;
+ return v;
+}
+
+void
+snap(Type *t)
+{
+ if(typesu[t->etype])
+ if(t->link == T && t->tag && t->tag->suetag) {
+ t->link = t->tag->suetag->link;
+ t->width = t->tag->suetag->width;
+ }
+}
+
+Type*
+dotag(Sym *s, int et, int bn)
+{
+ Decl *d;
+
+ if(bn != 0 && bn != s->sueblock) {
+ d = push();
+ d->sym = s;
+ d->val = DSUE;
+ d->type = s->suetag;
+ d->block = s->sueblock;
+ s->suetag = T;
+ }
+ if(s->suetag == T) {
+ s->suetag = typ(et, T);
+ s->sueblock = autobn;
+ }
+ if(s->suetag->etype != et)
+ diag(Z, "tag used for more than one type: %s",
+ s->name);
+ if(s->suetag->tag == S)
+ s->suetag->tag = s;
+ return s->suetag;
+}
+
+Node*
+dcllabel(Sym *s, int f)
+{
+ Decl *d, d1;
+ Node *n;
+
+ n = s->label;
+ if(n != Z) {
+ if(f) {
+ if(n->complex)
+ diag(Z, "label reused: %s", s->name);
+ n->complex = 1; // declared
+ } else
+ n->addable = 1; // used
+ return n;
+ }
+
+ d = push();
+ d->sym = s;
+ d->val = DLABEL;
+ dclstack = d->link;
+
+ d1 = *firstdcl;
+ *firstdcl = *d;
+ *d = d1;
+
+ firstdcl->link = d;
+ firstdcl = d;
+
+ n = new(OXXX, Z, Z);
+ n->sym = s;
+ n->complex = f;
+ n->addable = !f;
+ s->label = n;
+
+ if(debug['d'])
+ dbgdecl(s);
+ return n;
+}
+
+Type*
+paramconv(Type *t, int f)
+{
+
+ switch(t->etype) {
+ case TUNION:
+ case TSTRUCT:
+ if(t->width <= 0)
+ diag(Z, "incomplete structure: %s", t->tag->name);
+ break;
+
+ case TARRAY:
+ t = typ(TIND, t->link);
+ t->width = types[TIND]->width;
+ break;
+
+ case TFUNC:
+ t = typ(TIND, t);
+ t->width = types[TIND]->width;
+ break;
+
+ case TFLOAT:
+ if(!f)
+ t = types[TDOUBLE];
+ break;
+
+ case TCHAR:
+ case TSHORT:
+ if(!f)
+ t = types[TINT];
+ break;
+
+ case TUCHAR:
+ case TUSHORT:
+ if(!f)
+ t = types[TUINT];
+ break;
+ }
+ return t;
+}
+
+void
+adecl(int c, Type *t, Sym *s)
+{
+
+ if(c == CSTATIC)
+ c = CLOCAL;
+ if(t->etype == TFUNC) {
+ if(c == CXXX)
+ c = CEXTERN;
+ if(c == CLOCAL)
+ c = CSTATIC;
+ if(c == CAUTO || c == CEXREG)
+ diag(Z, "function cannot be %s %s", cnames[c], s->name);
+ }
+ if(c == CXXX)
+ c = CAUTO;
+ if(s) {
+ if(s->class == CSTATIC)
+ if(c == CEXTERN || c == CGLOBL) {
+ warn(Z, "just say static: %s", s->name);
+ c = CSTATIC;
+ }
+ if(s->class == CAUTO || s->class == CPARAM || s->class == CLOCAL)
+ if(s->block == autobn)
+ diag(Z, "auto redeclaration of: %s", s->name);
+ if(c != CPARAM)
+ push1(s);
+ s->block = autobn;
+ s->offset = 0;
+ s->type = t;
+ s->class = c;
+ s->aused = 0;
+ }
+ switch(c) {
+ case CAUTO:
+ autoffset = align(autoffset, t, Aaut3);
+ stkoff = maxround(stkoff, autoffset);
+ s->offset = -autoffset;
+ break;
+
+ case CPARAM:
+ if(autoffset == 0) {
+ firstarg = s;
+ firstargtype = t;
+ }
+ autoffset = align(autoffset, t, Aarg1);
+ if(s)
+ s->offset = autoffset;
+ autoffset = align(autoffset, t, Aarg2);
+ break;
+ }
+}
+
+void
+pdecl(int c, Type *t, Sym *s)
+{
+ if(s && s->offset != -1) {
+ diag(Z, "not a parameter: %s", s->name);
+ return;
+ }
+ t = paramconv(t, c==CPARAM);
+ if(c == CXXX)
+ c = CPARAM;
+ if(c != CPARAM) {
+ diag(Z, "parameter cannot have class: %s", s->name);
+ c = CPARAM;
+ }
+ adecl(c, t, s);
+}
+
+void
+xdecl(int c, Type *t, Sym *s)
+{
+ long o;
+
+ o = 0;
+ switch(c) {
+ case CEXREG:
+ o = exreg(t);
+ if(o == 0)
+ c = CEXTERN;
+ if(s->class == CGLOBL)
+ c = CGLOBL;
+ break;
+
+ case CEXTERN:
+ if(s->class == CGLOBL)
+ c = CGLOBL;
+ break;
+
+ case CXXX:
+ c = CGLOBL;
+ if(s->class == CEXTERN)
+ s->class = CGLOBL;
+ break;
+
+ case CAUTO:
+ diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
+ c = CEXTERN;
+ break;
+
+ case CTYPESTR:
+ if(!typesuv[t->etype]) {
+ diag(Z, "typestr must be struct/union: %s", s->name);
+ break;
+ }
+ dclfunct(t, s);
+ break;
+ }
+
+ if(s->class == CSTATIC)
+ if(c == CEXTERN || c == CGLOBL) {
+ warn(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
+ c = CSTATIC;
+ }
+ if(s->type != T)
+ if(s->class != c || !sametype(t, s->type) || t->etype == TENUM) {
+ diag(Z, "external redeclaration of: %s", s->name);
+ Bprint(&diagbuf, " %s %T %L\n", cnames[c], t, nearln);
+ Bprint(&diagbuf, " %s %T %L\n", cnames[s->class], s->type, s->varlineno);
+ }
+ tmerge(t, s);
+ s->type = t;
+ s->class = c;
+ s->block = 0;
+ s->offset = o;
+}
+
+void
+tmerge(Type *t1, Sym *s)
+{
+ Type *ta, *tb, *t2;
+
+ t2 = s->type;
+/*print("merge %T; %T\n", t1, t2);/**/
+ for(;;) {
+ if(t1 == T || t2 == T || t1 == t2)
+ break;
+ if(t1->etype != t2->etype)
+ break;
+ switch(t1->etype) {
+ case TFUNC:
+ ta = t1->down;
+ tb = t2->down;
+ if(ta == T) {
+ t1->down = tb;
+ break;
+ }
+ if(tb == T)
+ break;
+ while(ta != T && tb != T) {
+ if(ta == tb)
+ break;
+ /* ignore old-style flag */
+ if(ta->etype == TOLD) {
+ ta = ta->down;
+ continue;
+ }
+ if(tb->etype == TOLD) {
+ tb = tb->down;
+ continue;
+ }
+ /* checking terminated by ... */
+ if(ta->etype == TDOT && tb->etype == TDOT) {
+ ta = T;
+ tb = T;
+ break;
+ }
+ if(!sametype(ta, tb))
+ break;
+ ta = ta->down;
+ tb = tb->down;
+ }
+ if(ta != tb)
+ diag(Z, "function inconsistently declared: %s", s->name);
+
+ /* take new-style over old-style */
+ ta = t1->down;
+ tb = t2->down;
+ if(ta != T && ta->etype == TOLD)
+ if(tb != T && tb->etype != TOLD)
+ t1->down = tb;
+ break;
+
+ case TARRAY:
+ /* should we check array size change? */
+ if(t2->width > t1->width)
+ t1->width = t2->width;
+ break;
+
+ case TUNION:
+ case TSTRUCT:
+ return;
+ }
+ t1 = t1->link;
+ t2 = t2->link;
+ }
+}
+
+void
+edecl(int c, Type *t, Sym *s)
+{
+ Type *t1;
+
+ if(s == S) {
+ if(!typesu[t->etype])
+ diag(Z, "unnamed structure element must be struct/union");
+ if(c != CXXX)
+ diag(Z, "unnamed structure element cannot have class");
+ } else
+ if(c != CXXX)
+ diag(Z, "structure element cannot have class: %s", s->name);
+ t1 = t;
+ t = copytyp(t1);
+ t->sym = s;
+ t->down = T;
+ if(lastfield) {
+ t->shift = lastbit - lastfield;
+ t->nbits = lastfield;
+ if(firstbit)
+ t->shift = -t->shift;
+ if(typeu[t->etype])
+ t->etype = tufield->etype;
+ else
+ t->etype = tfield->etype;
+ }
+ if(strf == T)
+ strf = t;
+ else
+ strl->down = t;
+ strl = t;
+}
+
+/*
+ * this routine is very suspect.
+ * ansi requires the enum type to
+ * be represented as an 'int'
+ * this means that 0x81234567
+ * would be illegal. this routine
+ * makes signed and unsigned go
+ * to unsigned.
+ */
+Type*
+maxtype(Type *t1, Type *t2)
+{
+
+ if(t1 == T)
+ return t2;
+ if(t2 == T)
+ return t1;
+ if(t1->etype > t2->etype)
+ return t1;
+ return t2;
+}
+
+void
+doenum(Sym *s, Node *n)
+{
+
+ if(n) {
+ complex(n);
+ if(n->op != OCONST) {
+ diag(n, "enum not a constant: %s", s->name);
+ return;
+ }
+ en.cenum = n->type;
+ en.tenum = maxtype(en.cenum, en.tenum);
+
+ if(!typefd[en.cenum->etype])
+ en.lastenum = n->vconst;
+ else
+ en.floatenum = n->fconst;
+ }
+ if(dclstack)
+ push1(s);
+ xdecl(CXXX, types[TENUM], s);
+
+ if(en.cenum == T) {
+ en.tenum = types[TINT];
+ en.cenum = types[TINT];
+ en.lastenum = 0;
+ }
+ s->tenum = en.cenum;
+
+ if(!typefd[s->tenum->etype]) {
+ s->vconst = convvtox(en.lastenum, s->tenum->etype);
+ en.lastenum++;
+ } else {
+ s->fconst = en.floatenum;
+ en.floatenum++;
+ }
+
+ if(debug['d'])
+ dbgdecl(s);
+ acidvar(s);
+}
+
+void
+symadjust(Sym *s, Node *n, long del)
+{
+
+ switch(n->op) {
+ default:
+ if(n->left)
+ symadjust(s, n->left, del);
+ if(n->right)
+ symadjust(s, n->right, del);
+ return;
+
+ case ONAME:
+ if(n->sym == s)
+ n->xoffset -= del;
+ return;
+
+ case OCONST:
+ case OSTRING:
+ case OLSTRING:
+ case OINDREG:
+ case OREGISTER:
+ return;
+ }
+}
+
+Node*
+contig(Sym *s, Node *n, long v)
+{
+ Node *p, *r, *q, *m;
+ long w;
+ Type *zt;
+
+ if(debug['i']) {
+ print("contig v = %ld; s = %s\n", v, s->name);
+ prtree(n, "doinit value");
+ }
+
+ if(n == Z)
+ goto no;
+ w = s->type->width;
+
+ /*
+ * nightmare: an automatic array whose size
+ * increases when it is initialized
+ */
+ if(v != w) {
+ if(v != 0)
+ diag(n, "automatic adjustable array: %s", s->name);
+ v = s->offset;
+ autoffset = align(autoffset, s->type, Aaut3);
+ s->offset = -autoffset;
+ stkoff = maxround(stkoff, autoffset);
+ symadjust(s, n, v - s->offset);
+ }
+ if(w <= ewidth[TIND])
+ goto no;
+ if(n->op == OAS)
+ diag(Z, "oops in contig");
+/*ZZZ this appears incorrect
+need to check if the list completely covers the data.
+if not, bail
+ */
+ if(n->op == OLIST)
+ goto no;
+ if(n->op == OASI)
+ if(n->left->type)
+ if(n->left->type->width == w)
+ goto no;
+ while(w & (ewidth[TIND]-1))
+ w++;
+/*
+ * insert the following code, where long becomes vlong if pointers are fat
+ *
+ *(long**)&X = (long*)((char*)X + sizeof(X));
+ do {
+ *(long**)&X -= 1;
+ **(long**)&X = 0;
+ } while(*(long**)&X);
+ */
+
+ for(q=n; q->op != ONAME; q=q->left)
+ ;
+
+ zt = ewidth[TIND] > ewidth[TLONG]? types[TVLONG]: types[TLONG];
+
+ p = new(ONAME, Z, Z);
+ *p = *q;
+ p->type = typ(TIND, zt);
+ p->xoffset = s->offset;
+
+ r = new(ONAME, Z, Z);
+ *r = *p;
+ r = new(OPOSTDEC, r, Z);
+
+ q = new(ONAME, Z, Z);
+ *q = *p;
+ q = new(OIND, q, Z);
+
+ m = new(OCONST, Z, Z);
+ m->vconst = 0;
+ m->type = zt;
+
+ q = new(OAS, q, m);
+
+ r = new(OLIST, r, q);
+
+ q = new(ONAME, Z, Z);
+ *q = *p;
+ r = new(ODWHILE, q, r);
+
+ q = new(ONAME, Z, Z);
+ *q = *p;
+ q->type = q->type->link;
+ q->xoffset += w;
+ q = new(OADDR, q, 0);
+
+ q = new(OASI, p, q);
+ r = new(OLIST, q, r);
+
+ n = new(OLIST, r, n);
+
+no:
+ return n;
+}
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
new file mode 100644
index 0000000..6a81934
--- /dev/null
+++ b/src/cmd/cc/dpchk.c
@@ -0,0 +1,524 @@
+// Inferno utils/cc/dpchk.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/dpchk.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+#include "y.tab.h"
+
+enum
+{
+ Fnone = 0,
+ Fl,
+ Fvl,
+ Fignor,
+ Fstar,
+ Fadj,
+
+ Fverb = 10,
+};
+
+typedef struct Tprot Tprot;
+struct Tprot
+{
+ Type* type;
+ Bits flag;
+ Tprot* link;
+};
+
+typedef struct Tname Tname;
+struct Tname
+{
+ char* name;
+ int param;
+ Tname* link;
+};
+
+static Type* indchar;
+static uchar flagbits[512];
+static char fmtbuf[100];
+static int lastadj;
+static int lastverb;
+static int nstar;
+static Tprot* tprot;
+static Tname* tname;
+
+void
+argflag(int c, int v)
+{
+
+ switch(v) {
+ case Fignor:
+ case Fstar:
+ case Fl:
+ case Fvl:
+ flagbits[c] = v;
+ break;
+ case Fverb:
+ flagbits[c] = lastverb;
+/*print("flag-v %c %d\n", c, lastadj);*/
+ lastverb++;
+ break;
+ case Fadj:
+ flagbits[c] = lastadj;
+/*print("flag-l %c %d\n", c, lastadj);*/
+ lastadj++;
+ break;
+ }
+}
+
+Bits
+getflag(char *s)
+{
+ Bits flag;
+ int f;
+ char *fmt;
+ Rune c;
+
+ fmt = fmtbuf;
+ flag = zbits;
+ nstar = 0;
+ for(;;) {
+ s += chartorune(&c, s);
+ if(c == 0 || c >= nelem(flagbits))
+ break;
+ fmt += runetochar(fmt, &c);
+ f = flagbits[c];
+ switch(f) {
+ case Fnone:
+ argflag(c, Fverb);
+ f = flagbits[c];
+ break;
+ case Fstar:
+ nstar++;
+ case Fignor:
+ continue;
+ case Fl:
+ if(bset(flag, Fl))
+ flag = bor(flag, blsh(Fvl));
+ }
+ flag = bor(flag, blsh(f));
+ if(f >= Fverb)
+ break;
+ }
+ *fmt = 0;
+ return flag;
+}
+
+void
+newprot(Sym *m, Type *t, char *s)
+{
+ Bits flag;
+ Tprot *l;
+
+ if(t == T) {
+ warn(Z, "%s: newprot: type not defined", m->name);
+ return;
+ }
+ flag = getflag(s);
+ for(l=tprot; l; l=l->link)
+ if(beq(flag, l->flag) && sametype(t, l->type))
+ return;
+ l = alloc(sizeof(*l));
+ l->type = t;
+ l->flag = flag;
+ l->link = tprot;
+ tprot = l;
+}
+
+void
+newname(char *s, int p)
+{
+ Tname *l;
+
+ for(l=tname; l; l=l->link)
+ if(strcmp(l->name, s) == 0) {
+ if(l->param != p)
+ yyerror("vargck %s already defined\n", s);
+ return;
+ }
+ l = alloc(sizeof(*l));
+ l->name = s;
+ l->param = p;
+ l->link = tname;
+ tname = l;
+}
+
+void
+arginit(void)
+{
+ int i;
+
+/* debug['F'] = 1;*/
+/* debug['w'] = 1;*/
+
+ lastadj = Fadj;
+ lastverb = Fverb;
+ indchar = typ(TIND, types[TCHAR]);
+
+ memset(flagbits, Fnone, sizeof(flagbits));
+
+ for(i='0'; i<='9'; i++)
+ argflag(i, Fignor);
+ argflag('.', Fignor);
+ argflag('#', Fignor);
+ argflag('u', Fignor);
+ argflag('h', Fignor);
+ argflag('+', Fignor);
+ argflag('-', Fignor);
+
+ argflag('*', Fstar);
+ argflag('l', Fl);
+
+ argflag('o', Fverb);
+ flagbits['x'] = flagbits['o'];
+ flagbits['X'] = flagbits['o'];
+}
+
+void
+pragvararg(void)
+{
+ Sym *s;
+ int n, c;
+ char *t;
+ Rune r;
+ Type *ty;
+
+ if(!debug['F'])
+ goto out;
+ s = getsym();
+ if(s && strcmp(s->name, "argpos") == 0)
+ goto ckpos;
+ if(s && strcmp(s->name, "type") == 0)
+ goto cktype;
+ if(s && strcmp(s->name, "flag") == 0)
+ goto ckflag;
+ yyerror("syntax in #pragma varargck");
+ goto out;
+
+ckpos:
+/*#pragma varargck argpos warn 2*/
+ s = getsym();
+ if(s == S)
+ goto bad;
+ n = getnsn();
+ if(n < 0)
+ goto bad;
+ newname(s->name, n);
+ goto out;
+
+ckflag:
+/*#pragma varargck flag 'c'*/
+ c = getnsc();
+ if(c != '\'')
+ goto bad;
+ c = getr();
+ if(c == '\\')
+ c = getr();
+ else if(c == '\'')
+ goto bad;
+ if(c == '\n')
+ goto bad;
+ if(getc() != '\'')
+ goto bad;
+ argflag(c, Fignor);
+ goto out;
+
+cktype:
+/*#pragma varargck type O int*/
+ c = getnsc();
+ if(c != '"')
+ goto bad;
+ t = fmtbuf;
+ for(;;) {
+ r = getr();
+ if(r == ' ' || r == '\n')
+ goto bad;
+ if(r == '"')
+ break;
+ t += runetochar(t, &r);
+ }
+ *t = 0;
+ t = strdup(fmtbuf);
+ s = getsym();
+ if(s == S)
+ goto bad;
+ ty = s->type;
+ while((c = getnsc()) == '*')
+ ty = typ(TIND, ty);
+ unget(c);
+ newprot(s, ty, t);
+ goto out;
+
+bad:
+ yyerror("syntax in #pragma varargck");
+
+out:
+ while(getnsc() != '\n')
+ ;
+}
+
+Node*
+nextarg(Node *n, Node **a)
+{
+ if(n == Z) {
+ *a = Z;
+ return Z;
+ }
+ if(n->op == OLIST) {
+ *a = n->left;
+ return n->right;
+ }
+ *a = n;
+ return Z;
+}
+
+void
+checkargs(Node *nn, char *s, int pos)
+{
+ Node *a, *n;
+ Bits flag;
+ Tprot *l;
+
+ if(!debug['F'])
+ return;
+ n = nn;
+ for(;;) {
+ s = strchr(s, '%');
+ if(s == 0) {
+ nextarg(n, &a);
+ if(a != Z)
+ warn(nn, "more arguments than format %T",
+ a->type);
+ return;
+ }
+ s++;
+ flag = getflag(s);
+ while(nstar > 0) {
+ n = nextarg(n, &a);
+ pos++;
+ nstar--;
+ if(a == Z) {
+ warn(nn, "more format than arguments %s",
+ fmtbuf);
+ return;
+ }
+ if(a->type == T)
+ continue;
+ if(!sametype(types[TINT], a->type) &&
+ !sametype(types[TUINT], a->type))
+ warn(nn, "format mismatch '*' in %s %T, arg %d",
+ fmtbuf, a->type, pos);
+ }
+ for(l=tprot; l; l=l->link)
+ if(sametype(types[TVOID], l->type)) {
+ if(beq(flag, l->flag)) {
+ s++;
+ goto loop;
+ }
+ }
+
+ n = nextarg(n, &a);
+ pos++;
+ if(a == Z) {
+ warn(nn, "more format than arguments %s",
+ fmtbuf);
+ return;
+ }
+ if(a->type == 0)
+ continue;
+ for(l=tprot; l; l=l->link)
+ if(sametype(a->type, l->type)) {
+/*print("checking %T/%ulx %T/%ulx\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/
+ if(beq(flag, l->flag))
+ goto loop;
+ }
+ warn(nn, "format mismatch %s %T, arg %d", fmtbuf, a->type, pos);
+ loop:;
+ }
+}
+
+void
+dpcheck(Node *n)
+{
+ char *s;
+ Node *a, *b;
+ Tname *l;
+ int i;
+
+ if(n == Z)
+ return;
+ b = n->left;
+ if(b == Z || b->op != ONAME)
+ return;
+ s = b->sym->name;
+ for(l=tname; l; l=l->link)
+ if(strcmp(s, l->name) == 0)
+ break;
+ if(l == 0)
+ return;
+
+ i = l->param;
+ b = n->right;
+ while(i > 0) {
+ b = nextarg(b, &a);
+ i--;
+ }
+ if(a == Z) {
+ warn(n, "cant find format arg");
+ return;
+ }
+ if(!sametype(indchar, a->type)) {
+ warn(n, "format arg type %T", a->type);
+ return;
+ }
+ if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) {
+/* warn(n, "format arg not constant string");*/
+ return;
+ }
+ s = a->left->cstring;
+ checkargs(b, s, l->param);
+}
+
+void
+pragpack(void)
+{
+ Sym *s;
+
+ packflg = 0;
+ s = getsym();
+ if(s) {
+ packflg = atoi(s->name+1);
+ if(strcmp(s->name, "on") == 0 ||
+ strcmp(s->name, "yes") == 0)
+ packflg = 1;
+ }
+ while(getnsc() != '\n')
+ ;
+ if(debug['f'])
+ if(packflg)
+ print("%4ld: pack %d\n", lineno, packflg);
+ else
+ print("%4ld: pack off\n", lineno);
+}
+
+void
+pragfpround(void)
+{
+ Sym *s;
+
+ fproundflg = 0;
+ s = getsym();
+ if(s) {
+ fproundflg = atoi(s->name+1);
+ if(strcmp(s->name, "on") == 0 ||
+ strcmp(s->name, "yes") == 0)
+ fproundflg = 1;
+ }
+ while(getnsc() != '\n')
+ ;
+ if(debug['f'])
+ if(fproundflg)
+ print("%4ld: fproundflg %d\n", lineno, fproundflg);
+ else
+ print("%4ld: fproundflg off\n", lineno);
+}
+
+void
+pragprofile(void)
+{
+ Sym *s;
+
+ profileflg = 0;
+ s = getsym();
+ if(s) {
+ profileflg = atoi(s->name+1);
+ if(strcmp(s->name, "on") == 0 ||
+ strcmp(s->name, "yes") == 0)
+ profileflg = 1;
+ }
+ while(getnsc() != '\n')
+ ;
+ if(debug['f'])
+ if(profileflg)
+ print("%4ld: profileflg %d\n", lineno, profileflg);
+ else
+ print("%4ld: profileflg off\n", lineno);
+}
+
+void
+pragincomplete(void)
+{
+ Sym *s;
+ Type *t;
+ int istag, w, et;
+
+ istag = 0;
+ s = getsym();
+ if(s == nil)
+ goto out;
+ et = 0;
+ w = s->lexical;
+ if(w == LSTRUCT)
+ et = TSTRUCT;
+ else if(w == LUNION)
+ et = TUNION;
+ if(et != 0){
+ s = getsym();
+ if(s == nil){
+ yyerror("missing struct/union tag in pragma incomplete");
+ goto out;
+ }
+ if(s->lexical != LNAME && s->lexical != LTYPE){
+ yyerror("invalid struct/union tag: %s", s->name);
+ goto out;
+ }
+ dotag(s, et, 0);
+ istag = 1;
+ }else if(strcmp(s->name, "_off_") == 0){
+ debug['T'] = 0;
+ goto out;
+ }else if(strcmp(s->name, "_on_") == 0){
+ debug['T'] = 1;
+ goto out;
+ }
+ t = s->type;
+ if(istag)
+ t = s->suetag;
+ if(t == T)
+ yyerror("unknown type %s in pragma incomplete", s->name);
+ else if(!typesu[t->etype])
+ yyerror("not struct/union type in pragma incomplete: %s", s->name);
+ else
+ t->garb |= GINCOMPLETE;
+out:
+ while(getnsc() != '\n')
+ ;
+ if(debug['f'])
+ print("%s incomplete\n", s->name);
+}
diff --git a/src/cmd/cc/funct.c b/src/cmd/cc/funct.c
new file mode 100644
index 0000000..21d8625
--- /dev/null
+++ b/src/cmd/cc/funct.c
@@ -0,0 +1,430 @@
+// Inferno utils/cc/funct.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/funct.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+typedef struct Ftab Ftab;
+struct Ftab
+{
+ char op;
+ char* name;
+ char typ;
+};
+typedef struct Gtab Gtab;
+struct Gtab
+{
+ char etype;
+ char* name;
+};
+
+Ftab ftabinit[OEND];
+Gtab gtabinit[NTYPE];
+
+int
+isfunct(Node *n)
+{
+ Type *t, *t1;
+ Funct *f;
+ Node *l;
+ Sym *s;
+ int o;
+
+ o = n->op;
+ if(n->left == Z)
+ goto no;
+ t = n->left->type;
+ if(t == T)
+ goto no;
+ f = t->funct;
+
+ switch(o) {
+ case OAS: // put cast on rhs
+ case OASI:
+ case OASADD:
+ case OASAND:
+ case OASASHL:
+ case OASASHR:
+ case OASDIV:
+ case OASLDIV:
+ case OASLMOD:
+ case OASLMUL:
+ case OASLSHR:
+ case OASMOD:
+ case OASMUL:
+ case OASOR:
+ case OASSUB:
+ case OASXOR:
+ if(n->right == Z)
+ goto no;
+ t1 = n->right->type;
+ if(t1 == T)
+ goto no;
+ if(t1->funct == f)
+ break;
+
+ l = new(OXXX, Z, Z);
+ *l = *n->right;
+
+ n->right->left = l;
+ n->right->right = Z;
+ n->right->type = t;
+ n->right->op = OCAST;
+
+ if(!isfunct(n->right))
+ prtree(n, "isfunc !");
+ break;
+
+ case OCAST: // t f(T) or T f(t)
+ t1 = n->type;
+ if(t1 == T)
+ goto no;
+ if(f != nil) {
+ s = f->castfr[t1->etype];
+ if(s == S)
+ goto no;
+ n->right = n->left;
+ goto build;
+ }
+ f = t1->funct;
+ if(f != nil) {
+ s = f->castto[t->etype];
+ if(s == S)
+ goto no;
+ n->right = n->left;
+ goto build;
+ }
+ goto no;
+ }
+
+ if(f == nil)
+ goto no;
+ s = f->sym[o];
+ if(s == S)
+ goto no;
+
+ /*
+ * the answer is yes,
+ * now we rewrite the node
+ * and give diagnostics
+ */
+ switch(o) {
+ default:
+ diag(n, "isfunct op missing %O\n", o);
+ goto bad;
+
+ case OADD: // T f(T, T)
+ case OAND:
+ case OASHL:
+ case OASHR:
+ case ODIV:
+ case OLDIV:
+ case OLMOD:
+ case OLMUL:
+ case OLSHR:
+ case OMOD:
+ case OMUL:
+ case OOR:
+ case OSUB:
+ case OXOR:
+
+ case OEQ: // int f(T, T)
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLE:
+ case OLO:
+ case OLS:
+ case OLT:
+ case ONE:
+ if(n->right == Z)
+ goto bad;
+ t1 = n->right->type;
+ if(t1 == T)
+ goto bad;
+ if(t1->funct != f)
+ goto bad;
+ n->right = new(OLIST, n->left, n->right);
+ break;
+
+ case OAS: // structure copies done by the compiler
+ case OASI:
+ goto no;
+
+ case OASADD: // T f(T*, T)
+ case OASAND:
+ case OASASHL:
+ case OASASHR:
+ case OASDIV:
+ case OASLDIV:
+ case OASLMOD:
+ case OASLMUL:
+ case OASLSHR:
+ case OASMOD:
+ case OASMUL:
+ case OASOR:
+ case OASSUB:
+ case OASXOR:
+ if(n->right == Z)
+ goto bad;
+ t1 = n->right->type;
+ if(t1 == T)
+ goto bad;
+ if(t1->funct != f)
+ goto bad;
+ n->right = new(OLIST, new(OADDR, n->left, Z), n->right);
+ break;
+
+ case OPOS: // T f(T)
+ case ONEG:
+ case ONOT:
+ case OCOM:
+ n->right = n->left;
+ break;
+
+
+ }
+
+build:
+ l = new(ONAME, Z, Z);
+ l->sym = s;
+ l->type = s->type;
+ l->etype = s->type->etype;
+ l->xoffset = s->offset;
+ l->class = s->class;
+ tcomo(l, 0);
+
+ n->op = OFUNC;
+ n->left = l;
+ n->type = l->type->link;
+ if(tcompat(n, T, l->type, tfunct))
+ goto bad;
+ if(tcoma(n->left, n->right, l->type->down, 1))
+ goto bad;
+ return 1;
+
+no:
+ return 0;
+
+bad:
+ diag(n, "cant rewrite typestr for op %O\n", o);
+ prtree(n, "isfunct");
+ n->type = T;
+ return 1;
+}
+
+void
+dclfunct(Type *t, Sym *s)
+{
+ Funct *f;
+ Node *n;
+ Type *f1, *f2, *f3, *f4;
+ int o, i, c;
+ char str[100];
+
+ if(t->funct)
+ return;
+
+ // recognize generated tag of dorm _%d_
+ if(t->tag == S)
+ goto bad;
+ for(i=0; c = t->tag->name[i]; i++) {
+ if(c == '_') {
+ if(i == 0 || t->tag->name[i+1] == 0)
+ continue;
+ break;
+ }
+ if(c < '0' || c > '9')
+ break;
+ }
+ if(c == 0)
+ goto bad;
+
+ f = alloc(sizeof(*f));
+ for(o=0; o<sizeof(f->sym); o++)
+ f->sym[o] = S;
+
+ t->funct = f;
+
+ f1 = typ(TFUNC, t);
+ f1->down = copytyp(t);
+ f1->down->down = t;
+
+ f2 = typ(TFUNC, types[TINT]);
+ f2->down = copytyp(t);
+ f2->down->down = t;
+
+ f3 = typ(TFUNC, t);
+ f3->down = typ(TIND, t);
+ f3->down->down = t;
+
+ f4 = typ(TFUNC, t);
+ f4->down = t;
+
+ for(i=0;; i++) {
+ o = ftabinit[i].op;
+ if(o == OXXX)
+ break;
+ sprint(str, "%s_%s_", t->tag->name, ftabinit[i].name);
+ n = new(ONAME, Z, Z);
+ n->sym = slookup(str);
+ f->sym[o] = n->sym;
+ switch(ftabinit[i].typ) {
+ default:
+ diag(Z, "dclfunct op missing %d\n", ftabinit[i].typ);
+ break;
+
+ case 1: // T f(T,T) +
+ dodecl(xdecl, CEXTERN, f1, n);
+ break;
+
+ case 2: // int f(T,T) ==
+ dodecl(xdecl, CEXTERN, f2, n);
+ break;
+
+ case 3: // void f(T*,T) +=
+ dodecl(xdecl, CEXTERN, f3, n);
+ break;
+
+ case 4: // T f(T) ~
+ dodecl(xdecl, CEXTERN, f4, n);
+ break;
+ }
+ }
+ for(i=0;; i++) {
+ o = gtabinit[i].etype;
+ if(o == TXXX)
+ break;
+
+ /*
+ * OCAST types T1 _T2_T1_(T2)
+ */
+ sprint(str, "_%s%s_", gtabinit[i].name, t->tag->name);
+ n = new(ONAME, Z, Z);
+ n->sym = slookup(str);
+ f->castto[o] = n->sym;
+
+ f1 = typ(TFUNC, t);
+ f1->down = types[o];
+ dodecl(xdecl, CEXTERN, f1, n);
+
+ sprint(str, "%s_%s_", t->tag->name, gtabinit[i].name);
+ n = new(ONAME, Z, Z);
+ n->sym = slookup(str);
+ f->castfr[o] = n->sym;
+
+ f1 = typ(TFUNC, types[o]);
+ f1->down = t;
+ dodecl(xdecl, CEXTERN, f1, n);
+ }
+ return;
+bad:
+ diag(Z, "dclfunct bad %T %s\n", t, s->name);
+}
+
+Gtab gtabinit[NTYPE] =
+{
+ TCHAR, "c",
+ TUCHAR, "uc",
+ TSHORT, "h",
+ TUSHORT, "uh",
+ TINT, "i",
+ TUINT, "ui",
+ TLONG, "l",
+ TULONG, "ul",
+ TVLONG, "v",
+ TUVLONG, "uv",
+ TFLOAT, "f",
+ TDOUBLE, "d",
+ TXXX
+};
+
+Ftab ftabinit[OEND] =
+{
+ OADD, "add", 1,
+ OAND, "and", 1,
+ OASHL, "ashl", 1,
+ OASHR, "ashr", 1,
+ ODIV, "div", 1,
+ OLDIV, "ldiv", 1,
+ OLMOD, "lmod", 1,
+ OLMUL, "lmul", 1,
+ OLSHR, "lshr", 1,
+ OMOD, "mod", 1,
+ OMUL, "mul", 1,
+ OOR, "or", 1,
+ OSUB, "sub", 1,
+ OXOR, "xor", 1,
+
+ OEQ, "eq", 2,
+ OGE, "ge", 2,
+ OGT, "gt", 2,
+ OHI, "hi", 2,
+ OHS, "hs", 2,
+ OLE, "le", 2,
+ OLO, "lo", 2,
+ OLS, "ls", 2,
+ OLT, "lt", 2,
+ ONE, "ne", 2,
+
+ OASADD, "asadd", 3,
+ OASAND, "asand", 3,
+ OASASHL, "asashl", 3,
+ OASASHR, "asashr", 3,
+ OASDIV, "asdiv", 3,
+ OASLDIV, "asldiv", 3,
+ OASLMOD, "aslmod", 3,
+ OASLMUL, "aslmul", 3,
+ OASLSHR, "aslshr", 3,
+ OASMOD, "asmod", 3,
+ OASMUL, "asmul", 3,
+ OASOR, "asor", 3,
+ OASSUB, "assub", 3,
+ OASXOR, "asxor", 3,
+
+ OPOS, "pos", 4,
+ ONEG, "neg", 4,
+ OCOM, "com", 4,
+ ONOT, "not", 4,
+
+// OPOSTDEC,
+// OPOSTINC,
+// OPREDEC,
+// OPREINC,
+
+ OXXX,
+};
+
+// Node* nodtestv;
+
+// Node* nodvpp;
+// Node* nodppv;
+// Node* nodvmm;
+// Node* nodmmv;
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
new file mode 100644
index 0000000..e3a8e44
--- /dev/null
+++ b/src/cmd/cc/lex.c
@@ -0,0 +1,1542 @@
+// Inferno utils/cc/lex.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/lex.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+#include "y.tab.h"
+
+#ifndef CPP
+#define CPP "/bin/cpp"
+#endif
+
+/*
+ * known debug flags
+ * -a acid declaration output
+ * -A !B
+ * -B non ANSI
+ * -d print declarations
+ * -D name define
+ * -F format specification check
+ * -i print initialization
+ * -I path include
+ * -l generate little-endian code
+ * -L print every NAME symbol
+ * -M constant multiplication
+ * -m print add/sub/mul trees
+ * -n print acid to file (%.c=%.acid) (with -a or -aa)
+ * -o file output file
+ * -p use standard cpp ANSI preprocessor (not on windows)
+ * -r print registerization
+ * -s print structure offsets (with -a or -aa)
+ * -S print assembly
+ * -t print type trees
+ * -V enable void* conversion warnings
+ * -v verbose printing
+ * -w print warnings
+ * -X abort on error
+ * -. Inhibit search for includes in source directory
+ */
+
+void
+main(int argc, char *argv[])
+{
+ char *defs[50], *p;
+ int nproc, nout, status, i, c, ndef;
+
+ memset(debug, 0, sizeof(debug));
+ tinit();
+ cinit();
+ ginit();
+ arginit();
+
+ profileflg = 1; /* #pragma can turn it off */
+ tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
+ ndef = 0;
+ outfile = 0;
+ include[ninclude++] = ".";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+
+ case 'l': /* for little-endian mips */
+ if(thechar != 'v'){
+ print("can only use -l with vc");
+ errorexit();
+ }
+ thechar = '0';
+ thestring = "spim";
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p) {
+ defs[ndef++] = p;
+ dodefine(p);
+ }
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(argc < 1 && outfile == 0) {
+ print("usage: %cc [-options] files\n", thechar);
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't compile multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ /*
+ * if we're writing acid to standard output, don't compile
+ * concurrently, to avoid interleaving output.
+ */
+ if(((!debug['a'] && !debug['Z']) || debug['n']) &&
+ (p = getenv("NPROC")) != nil)
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0) {
+ print("cannot create a process\n");
+ errorexit();
+ }
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ fprint(2, "%s:\n", *argv);
+ if (compile(*argv, defs, ndef))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+
+ if(argc == 0)
+ c = compile("stdin", defs, ndef);
+ else
+ c = compile(argv[0], defs, ndef);
+
+ if(c)
+ errorexit();
+ exits(0);
+}
+
+int
+compile(char *file, char **defs, int ndef)
+{
+ char ofile[400], incfile[20];
+ char *p, *av[100], opt[256];
+ int i, c, fd[2];
+ static int first = 1;
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ *p++ = 0;
+ if(!debug['.'])
+ include[0] = strdup(ofile);
+ } else
+ p = ofile;
+
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile) {
+ if(p = utfrrune(outfile, '.'))
+ if(p[1] == 'c' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ if(debug['a'] && debug['n'])
+ strcat(p, ".acid");
+ else if(debug['Z'] && debug['n'])
+ strcat(p, "_pickle.c");
+ else {
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ }
+ } else
+ outfile = "/dev/null";
+ }
+
+ if(p = getenv("INCLUDE")) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile, "/%s/include", thestring);
+ setinclude(strdup(incfile));
+ setinclude("/sys/include");
+ }
+ }
+ if (first)
+ Binit(&diagbuf, 1, OWRITE);
+ /*
+ * if we're writing acid to standard output, don't keep scratching
+ * outbuf.
+ */
+ if((debug['a'] || debug['Z']) && !debug['n']) {
+ if (first) {
+ outfile = 0;
+ Binit(&outbuf, dup(1, -1), OWRITE);
+ dup(2, 1);
+ }
+ } else {
+ c = mycreate(outfile, 0664);
+ if(c < 0) {
+ diag(Z, "cannot open %s - %r", outfile);
+ outfile = 0;
+ errorexit();
+ }
+ Binit(&outbuf, c, OWRITE);
+ }
+ newio();
+ first = 0;
+
+ /* Use an ANSI preprocessor */
+ if(debug['p']) {
+ if(systemtype(Windows)) {
+ diag(Z, "-p option not supported on windows");
+ errorexit();
+ }
+ if(myaccess(file) < 0) {
+ diag(Z, "%s does not exist", file);
+ errorexit();
+ }
+ if(mypipe(fd) < 0) {
+ diag(Z, "pipe failed");
+ errorexit();
+ }
+ switch(myfork()) {
+ case -1:
+ diag(Z, "fork failed");
+ errorexit();
+ case 0:
+ close(fd[0]);
+ mydup(fd[1], 1);
+ close(fd[1]);
+ av[0] = CPP;
+ i = 1;
+ if(debug['.']){
+ sprint(opt, "-.");
+ av[i++] = strdup(opt);
+ }
+ if(debug['+']) {
+ sprint(opt, "-+");
+ av[i++] = strdup(opt);
+ }
+ for(c = 0; c < ndef; c++) {
+ sprint(opt, "-D%s", defs[c]);
+ av[i++] = strdup(opt);
+ }
+ for(c = 0; c < ninclude; c++) {
+ sprint(opt, "-I%s", include[c]);
+ av[i++] = strdup(opt);
+ }
+ if(strcmp(file, "stdin") != 0)
+ av[i++] = file;
+ av[i] = 0;
+ if(debug['p'] > 1) {
+ for(c = 0; c < i; c++)
+ fprint(2, "%s ", av[c]);
+ fprint(2, "\n");
+ }
+ myexec(av[0], av);
+ fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
+ errorexit();
+ default:
+ close(fd[1]);
+ newfile(file, fd[0]);
+ break;
+ }
+ } else {
+ if(strcmp(file, "stdin") == 0)
+ newfile(file, 0);
+ else
+ newfile(file, -1);
+ }
+ yyparse();
+ if(!debug['a'] && !debug['Z'])
+ gclean();
+ return nerrors;
+}
+
+void
+errorexit(void)
+{
+ if(outfile)
+ remove(outfile);
+ exits("error");
+}
+
+void
+pushio(void)
+{
+ Io *i;
+
+ i = iostack;
+ if(i == I) {
+ yyerror("botch in pushio");
+ errorexit();
+ }
+ i->p = fi.p;
+ i->c = fi.c;
+}
+
+void
+newio(void)
+{
+ Io *i;
+ static int pushdepth = 0;
+
+ i = iofree;
+ if(i == I) {
+ pushdepth++;
+ if(pushdepth > 1000) {
+ yyerror("macro/io expansion too deep");
+ errorexit();
+ }
+ i = alloc(sizeof(*i));
+ } else
+ iofree = i->link;
+ i->c = 0;
+ i->f = -1;
+ ionext = i;
+}
+
+void
+newfile(char *s, int f)
+{
+ Io *i;
+
+ if(debug['e'])
+ print("%L: %s\n", lineno, s);
+
+ i = ionext;
+ i->link = iostack;
+ iostack = i;
+ i->f = f;
+ if(f < 0)
+ i->f = open(s, 0);
+ if(i->f < 0) {
+ yyerror("%cc: %r: %s", thechar, s);
+ errorexit();
+ }
+ fi.c = 0;
+ linehist(s, 0);
+}
+
+Sym*
+slookup(char *s)
+{
+
+ strcpy(symb, s);
+ return lookup();
+}
+
+Sym*
+lookup(void)
+{
+ Sym *s;
+ ulong h;
+ char *p;
+ int c, n;
+
+ h = 0;
+ for(p=symb; *p;) {
+ h = h * 3;
+ h += *p++;
+ }
+ n = (p - symb) + 1;
+ if((long)h < 0)
+ h = ~h;
+ h %= NHASH;
+ c = symb[0];
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c)
+ continue;
+ if(strcmp(s->name, symb) == 0)
+ return s;
+ }
+ s = alloc(sizeof(*s));
+ s->name = alloc(n);
+ memmove(s->name, symb, n);
+
+ strcpy(s->name, symb);
+ s->link = hash[h];
+ hash[h] = s;
+ syminit(s);
+
+ return s;
+}
+
+void
+syminit(Sym *s)
+{
+ s->lexical = LNAME;
+ s->block = 0;
+ s->offset = 0;
+ s->type = T;
+ s->suetag = T;
+ s->class = CXXX;
+ s->aused = 0;
+ s->sig = SIGNONE;
+}
+
+#define EOF (-1)
+#define IGN (-2)
+#define ESC (1<<20)
+#define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
+
+enum
+{
+ Numdec = 1<<0,
+ Numlong = 1<<1,
+ Numuns = 1<<2,
+ Numvlong = 1<<3,
+ Numflt = 1<<4,
+};
+
+long
+yylex(void)
+{
+ vlong vv;
+ long c, c1, t;
+ char *cp;
+ Rune rune;
+ Sym *s;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ goto l1;
+ }
+l0:
+ c = GETC();
+
+l1:
+ if(c >= Runeself) {
+ /*
+ * extension --
+ * all multibyte runes are alpha
+ */
+ cp = symb;
+ goto talph;
+ }
+ if(isspace(c)) {
+ if(c == '\n')
+ lineno++;
+ goto l0;
+ }
+ if(isalpha(c)) {
+ cp = symb;
+ if(c != 'L')
+ goto talph;
+ *cp++ = c;
+ c = GETC();
+ if(c == '\'') {
+ /* L'x' */
+ c = escchar('\'', 1, 0);
+ if(c == EOF)
+ c = '\'';
+ c1 = escchar('\'', 1, 0);
+ if(c1 != EOF) {
+ yyerror("missing '");
+ peekc = c1;
+ }
+ yylval.vval = convvtox(c, TUSHORT);
+ return LUCONST;
+ }
+ if(c == '"') {
+ goto caselq;
+ }
+ goto talph;
+ }
+ if(isdigit(c))
+ goto tnum;
+ switch(c)
+ {
+
+ case EOF:
+ peekc = EOF;
+ return -1;
+
+ case '_':
+ cp = symb;
+ goto talph;
+
+ case '#':
+ domacro();
+ goto l0;
+
+ case '.':
+ c1 = GETC();
+ if(isdigit(c1)) {
+ cp = symb;
+ *cp++ = c;
+ c = c1;
+ c1 = 0;
+ goto casedot;
+ }
+ break;
+
+ case '"':
+ strcpy(symb, "\"<string>\"");
+ cp = alloc(0);
+ c1 = 0;
+
+ /* "..." */
+ for(;;) {
+ c = escchar('"', 0, 1);
+ if(c == EOF)
+ break;
+ if(c & ESC) {
+ cp = allocn(cp, c1, 1);
+ cp[c1++] = c;
+ } else {
+ rune = c;
+ c = runelen(rune);
+ cp = allocn(cp, c1, c);
+ runetochar(cp+c1, &rune);
+ c1 += c;
+ }
+ }
+ yylval.sval.l = c1;
+ do {
+ cp = allocn(cp, c1, 1);
+ cp[c1++] = 0;
+ } while(c1 & MAXALIGN);
+ yylval.sval.s = cp;
+ return LSTRING;
+
+ caselq:
+ /* L"..." */
+ strcpy(symb, "\"L<string>\"");
+ cp = alloc(0);
+ c1 = 0;
+ for(;;) {
+ c = escchar('"', 1, 0);
+ if(c == EOF)
+ break;
+ cp = allocn(cp, c1, sizeof(ushort));
+ *(ushort*)(cp + c1) = c;
+ c1 += sizeof(ushort);
+ }
+ yylval.sval.l = c1;
+ do {
+ cp = allocn(cp, c1, sizeof(ushort));
+ *(ushort*)(cp + c1) = 0;
+ c1 += sizeof(ushort);
+ } while(c1 & MAXALIGN);
+ yylval.sval.s = cp;
+ return LLSTRING;
+
+ case '\'':
+ /* '.' */
+ c = escchar('\'', 0, 0);
+ if(c == EOF)
+ c = '\'';
+ c1 = escchar('\'', 0, 0);
+ if(c1 != EOF) {
+ yyerror("missing '");
+ peekc = c1;
+ }
+ vv = c;
+ yylval.vval = convvtox(vv, TUCHAR);
+ if(yylval.vval != vv)
+ yyerror("overflow in character constant: 0x%lx", c);
+ else
+ if(c & 0x80){
+ nearln = lineno;
+ warn(Z, "sign-extended character constant");
+ }
+ yylval.vval = convvtox(vv, TCHAR);
+ return LCONST;
+
+ case '/':
+ c1 = GETC();
+ if(c1 == '*') {
+ for(;;) {
+ c = getr();
+ while(c == '*') {
+ c = getr();
+ if(c == '/')
+ goto l0;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '/') {
+ for(;;) {
+ c = getr();
+ if(c == '\n')
+ goto l0;
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '=')
+ return LDVE;
+ break;
+
+ case '*':
+ c1 = GETC();
+ if(c1 == '=')
+ return LMLE;
+ break;
+
+ case '%':
+ c1 = GETC();
+ if(c1 == '=')
+ return LMDE;
+ break;
+
+ case '+':
+ c1 = GETC();
+ if(c1 == '+')
+ return LPP;
+ if(c1 == '=')
+ return LPE;
+ break;
+
+ case '-':
+ c1 = GETC();
+ if(c1 == '-')
+ return LMM;
+ if(c1 == '=')
+ return LME;
+ if(c1 == '>')
+ return LMG;
+ break;
+
+ case '>':
+ c1 = GETC();
+ if(c1 == '>') {
+ c = LRSH;
+ c1 = GETC();
+ if(c1 == '=')
+ return LRSHE;
+ break;
+ }
+ if(c1 == '=')
+ return LGE;
+ break;
+
+ case '<':
+ c1 = GETC();
+ if(c1 == '<') {
+ c = LLSH;
+ c1 = GETC();
+ if(c1 == '=')
+ return LLSHE;
+ break;
+ }
+ if(c1 == '=')
+ return LLE;
+ break;
+
+ case '=':
+ c1 = GETC();
+ if(c1 == '=')
+ return LEQ;
+ break;
+
+ case '!':
+ c1 = GETC();
+ if(c1 == '=')
+ return LNE;
+ break;
+
+ case '&':
+ c1 = GETC();
+ if(c1 == '&')
+ return LANDAND;
+ if(c1 == '=')
+ return LANDE;
+ break;
+
+ case '|':
+ c1 = GETC();
+ if(c1 == '|')
+ return LOROR;
+ if(c1 == '=')
+ return LORE;
+ break;
+
+ case '^':
+ c1 = GETC();
+ if(c1 == '=')
+ return LXORE;
+ break;
+
+ default:
+ return c;
+ }
+ peekc = c1;
+ return c;
+
+talph:
+ /*
+ * cp is set to symb and some
+ * prefix has been stored
+ */
+ for(;;) {
+ if(c >= Runeself) {
+ for(c1=0;;) {
+ cp[c1++] = c;
+ if(fullrune(cp, c1))
+ break;
+ c = GETC();
+ }
+ cp += c1;
+ c = GETC();
+ continue;
+ }
+ if(!isalnum(c) && c != '_')
+ break;
+ *cp++ = c;
+ c = GETC();
+ }
+ *cp = 0;
+ if(debug['L'])
+ print("%L: %s\n", lineno, symb);
+ peekc = c;
+ s = lookup();
+ if(s->macro) {
+ newio();
+ cp = ionext->b;
+ macexpand(s, cp);
+ pushio();
+ ionext->link = iostack;
+ iostack = ionext;
+ fi.p = cp;
+ fi.c = strlen(cp);
+ if(peekc != IGN) {
+ cp[fi.c++] = peekc;
+ cp[fi.c] = 0;
+ peekc = IGN;
+ }
+ goto l0;
+ }
+ yylval.sym = s;
+ if(s->class == CTYPEDEF || s->class == CTYPESTR)
+ return LTYPE;
+ return s->lexical;
+
+tnum:
+ c1 = 0;
+ cp = symb;
+ if(c != '0') {
+ c1 |= Numdec;
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(isdigit(c))
+ continue;
+ goto dc;
+ }
+ }
+ *cp++ = c;
+ c = GETC();
+ if(c == 'x' || c == 'X')
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(isdigit(c))
+ continue;
+ if(c >= 'a' && c <= 'f')
+ continue;
+ if(c >= 'A' && c <= 'F')
+ continue;
+ if(cp == symb+2)
+ yyerror("malformed hex constant");
+ goto ncu;
+ }
+ if(c < '0' || c > '7')
+ goto dc;
+ for(;;) {
+ if(c >= '0' && c <= '7') {
+ *cp++ = c;
+ c = GETC();
+ continue;
+ }
+ goto ncu;
+ }
+
+dc:
+ if(c == '.')
+ goto casedot;
+ if(c == 'e' || c == 'E')
+ goto casee;
+
+ncu:
+ if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
+ c = GETC();
+ c1 |= Numuns;
+ goto ncu;
+ }
+ if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
+ c = GETC();
+ if(c1 & Numlong)
+ c1 |= Numvlong;
+ c1 |= Numlong;
+ goto ncu;
+ }
+ *cp = 0;
+ peekc = c;
+ if(mpatov(symb, &yylval.vval))
+ yyerror("overflow in constant");
+
+ vv = yylval.vval;
+ if(c1 & Numvlong) {
+ if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
+ c = LUVLCONST;
+ t = TUVLONG;
+ goto nret;
+ }
+ c = LVLCONST;
+ t = TVLONG;
+ goto nret;
+ }
+ if(c1 & Numlong) {
+ if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
+ c = LULCONST;
+ t = TULONG;
+ goto nret;
+ }
+ c = LLCONST;
+ t = TLONG;
+ goto nret;
+ }
+ if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
+ c = LUCONST;
+ t = TUINT;
+ goto nret;
+ }
+ c = LCONST;
+ t = TINT;
+ goto nret;
+
+nret:
+ yylval.vval = convvtox(vv, t);
+ if(yylval.vval != vv){
+ nearln = lineno;
+ warn(Z, "truncated constant: %T %s", types[t], symb);
+ }
+ return c;
+
+casedot:
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(!isdigit(c))
+ break;
+ }
+ if(c != 'e' && c != 'E')
+ goto caseout;
+
+casee:
+ *cp++ = 'e';
+ c = GETC();
+ if(c == '+' || c == '-') {
+ *cp++ = c;
+ c = GETC();
+ }
+ if(!isdigit(c))
+ yyerror("malformed fp constant exponent");
+ while(isdigit(c)) {
+ *cp++ = c;
+ c = GETC();
+ }
+
+caseout:
+ if(c == 'L' || c == 'l') {
+ c = GETC();
+ c1 |= Numlong;
+ } else
+ if(c == 'F' || c == 'f') {
+ c = GETC();
+ c1 |= Numflt;
+ }
+ *cp = 0;
+ peekc = c;
+ yylval.dval = strtod(symb, nil);
+ if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) {
+ yyerror("overflow in float constant");
+ yylval.dval = 0;
+ }
+ if(c1 & Numflt)
+ return LFCONST;
+ return LDCONST;
+}
+
+/*
+ * convert a string, s, to vlong in *v
+ * return conversion overflow.
+ * required syntax is [0[x]]d*
+ */
+int
+mpatov(char *s, vlong *v)
+{
+ vlong n, nn;
+ int c;
+
+ n = 0;
+ c = *s;
+ if(c == '0')
+ goto oct;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ nn = n*10 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+
+oct:
+ s++;
+ c = *s;
+ if(c == 'x' || c == 'X')
+ goto hex;
+ while(c = *s++) {
+ if(c >= '0' || c <= '7')
+ nn = n*8 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+
+hex:
+ s++;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ c += 0-'0';
+ else
+ if(c >= 'a' && c <= 'f')
+ c += 10-'a';
+ else
+ if(c >= 'A' && c <= 'F')
+ c += 10-'A';
+ else
+ goto bad;
+ nn = n*16 + c;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+out:
+ *v = n;
+ return 0;
+
+bad:
+ *v = ~0;
+ return 1;
+}
+
+int
+getc(void)
+{
+ int c;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ } else
+ c = GETC();
+ if(c == '\n')
+ lineno++;
+ if(c == EOF) {
+ yyerror("End of file");
+ errorexit();
+ }
+ return c;
+}
+
+long
+getr(void)
+{
+ int c, i;
+ char str[UTFmax+1];
+ Rune rune;
+
+
+ c = getc();
+ if(c < Runeself)
+ return c;
+ i = 0;
+ str[i++] = c;
+
+loop:
+ c = getc();
+ str[i++] = c;
+ if(!fullrune(str, i))
+ goto loop;
+ c = chartorune(&rune, str);
+ if(rune == Runeerror && c == 1) {
+ nearln = lineno;
+ diag(Z, "illegal rune in string");
+ for(c=0; c<i; c++)
+ print(" %.2x", *(uchar*)(str+c));
+ print("\n");
+ }
+ return rune;
+}
+
+int
+getnsc(void)
+{
+ int c;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ } else
+ c = GETC();
+ for(;;) {
+ if(!isspace(c))
+ return c;
+ if(c == '\n') {
+ lineno++;
+ return c;
+ }
+ c = GETC();
+ }
+}
+
+void
+unget(int c)
+{
+
+ peekc = c;
+ if(c == '\n')
+ lineno--;
+}
+
+long
+escchar(long e, int longflg, int escflg)
+{
+ long c, l;
+ int i;
+
+loop:
+ c = getr();
+ if(c == '\n') {
+ yyerror("newline in string");
+ return EOF;
+ }
+ if(c != '\\') {
+ if(c == e)
+ c = EOF;
+ return c;
+ }
+ c = getr();
+ if(c == 'x') {
+ /*
+ * note this is not ansi,
+ * supposed to only accept 2 hex
+ */
+ i = 2;
+ if(longflg)
+ i = 4;
+ l = 0;
+ for(; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '9') {
+ l = l*16 + c-'0';
+ continue;
+ }
+ if(c >= 'a' && c <= 'f') {
+ l = l*16 + c-'a' + 10;
+ continue;
+ }
+ if(c >= 'A' && c <= 'F') {
+ l = l*16 + c-'A' + 10;
+ continue;
+ }
+ unget(c);
+ break;
+ }
+ if(escflg)
+ l |= ESC;
+ return l;
+ }
+ if(c >= '0' && c <= '7') {
+ /*
+ * note this is not ansi,
+ * supposed to only accept 3 oct
+ */
+ i = 2;
+ if(longflg)
+ i = 5;
+ l = c - '0';
+ for(; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ continue;
+ }
+ unget(c);
+ }
+ if(escflg)
+ l |= ESC;
+ return l;
+ }
+ switch(c)
+ {
+ case '\n': goto loop;
+ case 'n': return '\n';
+ case 't': return '\t';
+ case 'b': return '\b';
+ case 'r': return '\r';
+ case 'f': return '\f';
+ case 'a': return '\a';
+ case 'v': return '\v';
+ }
+ return c;
+}
+
+struct
+{
+ char *name;
+ ushort lexical;
+ ushort type;
+} itab[] =
+{
+ "auto", LAUTO, 0,
+ "break", LBREAK, 0,
+ "case", LCASE, 0,
+ "char", LCHAR, TCHAR,
+ "const", LCONSTNT, 0,
+ "continue", LCONTINUE, 0,
+ "default", LDEFAULT, 0,
+ "do", LDO, 0,
+ "double", LDOUBLE, TDOUBLE,
+ "else", LELSE, 0,
+ "enum", LENUM, 0,
+ "extern", LEXTERN, 0,
+ "float", LFLOAT, TFLOAT,
+ "for", LFOR, 0,
+ "goto", LGOTO, 0,
+ "if", LIF, 0,
+ "inline", LINLINE, 0,
+ "int", LINT, TINT,
+ "long", LLONG, TLONG,
+ "register", LREGISTER, 0,
+ "restrict", LRESTRICT, 0,
+ "return", LRETURN, 0,
+ "SET", LSET, 0,
+ "short", LSHORT, TSHORT,
+ "signed", LSIGNED, 0,
+ "signof", LSIGNOF, 0,
+ "sizeof", LSIZEOF, 0,
+ "static", LSTATIC, 0,
+ "struct", LSTRUCT, 0,
+ "switch", LSWITCH, 0,
+ "typedef", LTYPEDEF, 0,
+ "typestr", LTYPESTR, 0,
+ "union", LUNION, 0,
+ "unsigned", LUNSIGNED, 0,
+ "USED", LUSED, 0,
+ "void", LVOID, TVOID,
+ "volatile", LVOLATILE, 0,
+ "while", LWHILE, 0,
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+ Type *t;
+
+ nerrors = 0;
+ lineno = 1;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+
+ types[TXXX] = T;
+ types[TCHAR] = typ(TCHAR, T);
+ types[TUCHAR] = typ(TUCHAR, T);
+ types[TSHORT] = typ(TSHORT, T);
+ types[TUSHORT] = typ(TUSHORT, T);
+ types[TINT] = typ(TINT, T);
+ types[TUINT] = typ(TUINT, T);
+ types[TLONG] = typ(TLONG, T);
+ types[TULONG] = typ(TULONG, T);
+ types[TVLONG] = typ(TVLONG, T);
+ types[TUVLONG] = typ(TUVLONG, T);
+ types[TFLOAT] = typ(TFLOAT, T);
+ types[TDOUBLE] = typ(TDOUBLE, T);
+ types[TVOID] = typ(TVOID, T);
+ types[TENUM] = typ(TENUM, T);
+ types[TFUNC] = typ(TFUNC, types[TINT]);
+ types[TIND] = typ(TIND, types[TVOID]);
+
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->lexical = itab[i].lexical;
+ if(itab[i].type != 0)
+ s->type = types[itab[i].type];
+ }
+ blockno = 0;
+ autobn = 0;
+ autoffset = 0;
+
+ t = typ(TARRAY, types[TCHAR]);
+ t->width = 0;
+ symstring = slookup(".string");
+ symstring->class = CSTATIC;
+ symstring->type = t;
+
+ t = typ(TARRAY, types[TCHAR]);
+ t->width = 0;
+
+ nodproto = new(OPROTO, Z, Z);
+ dclstack = D;
+
+ pathname = allocn(pathname, 0, 100);
+ if(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+
+ fmtinstall('O', Oconv);
+ fmtinstall('T', Tconv);
+ fmtinstall('F', FNconv);
+ fmtinstall('L', Lconv);
+ fmtinstall('Q', Qconv);
+ fmtinstall('|', VBconv);
+}
+
+int
+filbuf(void)
+{
+ Io *i;
+
+loop:
+ i = iostack;
+ if(i == I)
+ return EOF;
+ if(i->f < 0)
+ goto pop;
+ fi.c = read(i->f, i->b, BUFSIZ) - 1;
+ if(fi.c < 0) {
+ close(i->f);
+ linehist(0, 0);
+ goto pop;
+ }
+ fi.p = i->b + 1;
+ return i->b[0] & 0xff;
+
+pop:
+ iostack = i->link;
+ i->link = iofree;
+ iofree = i;
+ i = iostack;
+ if(i == I)
+ return EOF;
+ fi.p = i->p;
+ fi.c = i->c;
+ if(--fi.c < 0)
+ goto loop;
+ return *fi.p++ & 0xff;
+}
+
+int
+Oconv(Fmt *fp)
+{
+ int a;
+
+ a = va_arg(fp->args, int);
+ if(a < OXXX || a > OEND)
+ return fmtprint(fp, "***badO %d***", a);
+
+ return fmtstrcpy(fp, onames[a]);
+}
+
+int
+Lconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[STRINGSZ];
+ Hist *h;
+ struct
+ {
+ Hist* incl; /* start of this include file */
+ long idel; /* delta line number to apply to include */
+ Hist* line; /* start of this #line directive */
+ long ldel; /* delta line number to apply to #line */
+ } a[HISTSZ];
+ long l, d;
+ int i, n;
+
+ l = va_arg(fp->args, long);
+ n = 0;
+ for(h = hist; h != H; h = h->link) {
+ if(l < h->line)
+ break;
+ if(h->name) {
+ if(h->offset != 0) { /* #line directive, not #pragma */
+ if(n > 0 && n < HISTSZ && h->offset >= 0) {
+ a[n-1].line = h;
+ a[n-1].ldel = h->line - h->offset + 1;
+ }
+ } else {
+ if(n < HISTSZ) { /* beginning of file */
+ a[n].incl = h;
+ a[n].idel = h->line;
+ a[n].line = 0;
+ }
+ n++;
+ }
+ continue;
+ }
+ n--;
+ if(n > 0 && n < HISTSZ) {
+ d = h->line - a[n].incl->line;
+ a[n-1].ldel += d;
+ a[n-1].idel += d;
+ }
+ }
+ if(n > HISTSZ)
+ n = HISTSZ;
+ str[0] = 0;
+ for(i=n-1; i>=0; i--) {
+ if(i != n-1) {
+ if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */
+ break;
+ strcat(str, " ");
+ }
+ if(a[i].line)
+ snprint(s, STRINGSZ, "%s:%ld[%s:%ld]",
+ a[i].line->name, l-a[i].ldel+1,
+ a[i].incl->name, l-a[i].idel+1);
+ else
+ snprint(s, STRINGSZ, "%s:%ld",
+ a[i].incl->name, l-a[i].idel+1);
+ if(strlen(s)+strlen(str) >= STRINGSZ-10)
+ break;
+ strcat(str, s);
+ l = a[i].incl->line - 1; /* now print out start of this file */
+ }
+ if(n == 0)
+ strcat(str, "<eof>");
+ return fmtstrcpy(fp, str);
+}
+
+int
+Tconv(Fmt *fp)
+{
+ char str[STRINGSZ+20], s[STRINGSZ+20];
+ Type *t, *t1;
+ int et;
+ long n;
+
+ str[0] = 0;
+ for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
+ et = t->etype;
+ if(str[0])
+ strcat(str, " ");
+ if(t->garb&~GINCOMPLETE) {
+ sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ sprint(s, "%s", tnames[et]);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ if(et == TFUNC && (t1 = t->down)) {
+ sprint(s, "(%T", t1);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ while(t1 = t1->down) {
+ sprint(s, ", %T", t1);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, ")");
+ }
+ if(et == TARRAY) {
+ n = t->width;
+ if(t->link && t->link->width)
+ n /= t->link->width;
+ sprint(s, "[%ld]", n);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(t->nbits) {
+ sprint(s, " %d:%d", t->shift, t->nbits);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(typesu[et]) {
+ if(t->tag) {
+ strcat(str, " ");
+ if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
+ strcat(str, t->tag->name);
+ } else
+ strcat(str, " {}");
+ break;
+ }
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+FNconv(Fmt *fp)
+{
+ char *str;
+ Node *n;
+
+ n = va_arg(fp->args, Node*);
+ str = "<indirect>";
+ if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
+ str = n->sym->name;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Qconv(Fmt *fp)
+{
+ char str[STRINGSZ+20], *s;
+ long b;
+ int i;
+
+ str[0] = 0;
+ for(b = va_arg(fp->args, long); b;) {
+ i = bitno(b);
+ if(str[0])
+ strcat(str, " ");
+ s = qnames[i];
+ if(strlen(str) + strlen(s) >= STRINGSZ)
+ break;
+ strcat(str, s);
+ b &= ~(1L << i);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+VBconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ int i, n, t, pc;
+
+ n = va_arg(fp->args, int);
+ pc = 0; /* BUG: was printcol */
+ i = 0;
+ while(pc < n) {
+ t = (pc+4) & ~3;
+ if(t <= n) {
+ str[i++] = '\t';
+ pc = t;
+ continue;
+ }
+ str[i++] = ' ';
+ pc++;
+ }
+ str[i] = 0;
+
+ return fmtstrcpy(fp, str);
+}
+
+void
+setinclude(char *p)
+{
+ int i;
+ char *e;
+
+ while(*p != 0) {
+ e = strchr(p, ' ');
+ if(e != 0)
+ *e = '\0';
+
+ for(i=1; i < ninclude; i++)
+ if(strcmp(p, include[i]) == 0)
+ break;
+
+ if(i >= ninclude)
+ include[ninclude++] = p;
+
+ if(ninclude > nelem(include)) {
+ diag(Z, "ninclude too small %d", nelem(include));
+ exits("ninclude");
+ }
+
+ if(e == 0)
+ break;
+ p = e+1;
+ }
+}
diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody
new file mode 100644
index 0000000..f7ba6d0
--- /dev/null
+++ b/src/cmd/cc/lexbody
@@ -0,0 +1,723 @@
+// Inferno utils/cc/lexbody
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/lexbody
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * common code for all the assemblers
+ */
+
+void
+pragpack(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragvararg(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragfpround(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragprofile(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragincomplete(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+gethunk(void)
+{
+ hunk = malloc(NHUNK);
+ memset(hunk, 0, NHUNK);
+ nhunk = NHUNK;
+}
+
+void*
+alloc(long n)
+{
+ void *p;
+
+ while((uintptr)hunk & MAXALIGN) {
+ hunk++;
+ nhunk--;
+ }
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void*
+allocn(void *p, long on, long n)
+{
+ void *q;
+
+ q = (uchar*)p + on;
+ if(q != hunk || nhunk < n) {
+ while(nhunk < on+n)
+ gethunk();
+ memmove(hunk, p, on);
+ p = hunk;
+ hunk += on;
+ nhunk -= on;
+ }
+ hunk += n;
+ nhunk -= n;
+ return p;
+}
+
+void
+setinclude(char *p)
+{
+ int i;
+
+ if(p == 0)
+ return;
+ for(i=1; i < ninclude; i++)
+ if(strcmp(p, include[i]) == 0)
+ return;
+
+ if(ninclude >= nelem(include)) {
+ yyerror("ninclude too small %d", nelem(include));
+ exits("ninclude");
+ }
+ include[ninclude++] = p;
+}
+
+void
+errorexit(void)
+{
+
+ if(outfile)
+ remove(outfile);
+ exits("error");
+}
+
+void
+pushio(void)
+{
+ Io *i;
+
+ i = iostack;
+ if(i == I) {
+ yyerror("botch in pushio");
+ errorexit();
+ }
+ i->p = fi.p;
+ i->c = fi.c;
+}
+
+void
+newio(void)
+{
+ Io *i;
+ static int pushdepth = 0;
+
+ i = iofree;
+ if(i == I) {
+ pushdepth++;
+ if(pushdepth > 1000) {
+ yyerror("macro/io expansion too deep");
+ errorexit();
+ }
+ i = alloc(sizeof(*i));
+ } else
+ iofree = i->link;
+ i->c = 0;
+ i->f = -1;
+ ionext = i;
+}
+
+void
+newfile(char *s, int f)
+{
+ Io *i;
+
+ i = ionext;
+ i->link = iostack;
+ iostack = i;
+ i->f = f;
+ if(f < 0)
+ i->f = open(s, 0);
+ if(i->f < 0) {
+ yyerror("%ca: %r: %s", thechar, s);
+ errorexit();
+ }
+ fi.c = 0;
+ linehist(s, 0);
+}
+
+Sym*
+slookup(char *s)
+{
+
+ strcpy(symb, s);
+ return lookup();
+}
+
+Sym*
+lookup(void)
+{
+ Sym *s;
+ long h;
+ char *p;
+ int c, l;
+
+ h = 0;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ c = symb[0];
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c)
+ continue;
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+ }
+ s = alloc(sizeof(*s));
+ s->name = alloc(l);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ hash[h] = s;
+ syminit(s);
+ return s;
+}
+
+long
+yylex(void)
+{
+ int c, c1;
+ char *cp;
+ Sym *s;
+
+ c = peekc;
+ if(c != IGN) {
+ peekc = IGN;
+ goto l1;
+ }
+l0:
+ c = GETC();
+
+l1:
+ if(c == EOF) {
+ peekc = EOF;
+ return -1;
+ }
+ if(isspace(c)) {
+ if(c == '\n') {
+ lineno++;
+ return ';';
+ }
+ goto l0;
+ }
+ if(isalpha(c))
+ goto talph;
+ if(isdigit(c))
+ goto tnum;
+ switch(c)
+ {
+ case '\n':
+ lineno++;
+ return ';';
+
+ case '#':
+ domacro();
+ goto l0;
+
+ case '.':
+ c = GETC();
+ if(isalpha(c)) {
+ cp = symb;
+ *cp++ = '.';
+ goto aloop;
+ }
+ if(isdigit(c)) {
+ cp = symb;
+ *cp++ = '.';
+ goto casedot;
+ }
+ peekc = c;
+ return '.';
+
+ talph:
+ case '_':
+ case '@':
+ cp = symb;
+
+ aloop:
+ *cp++ = c;
+ c = GETC();
+ if(isalpha(c) || isdigit(c) || c == '_' || c == '$')
+ goto aloop;
+ *cp = 0;
+ peekc = c;
+ s = lookup();
+ if(s->macro) {
+ newio();
+ cp = ionext->b;
+ macexpand(s, cp);
+ pushio();
+ ionext->link = iostack;
+ iostack = ionext;
+ fi.p = cp;
+ fi.c = strlen(cp);
+ if(peekc != IGN) {
+ cp[fi.c++] = peekc;
+ cp[fi.c] = 0;
+ peekc = IGN;
+ }
+ goto l0;
+ }
+ if(s->type == 0)
+ s->type = LNAME;
+ if(s->type == LNAME ||
+ s->type == LVAR ||
+ s->type == LLAB) {
+ yylval.sym = s;
+ return s->type;
+ }
+ yylval.lval = s->value;
+ return s->type;
+
+ tnum:
+ cp = symb;
+ if(c != '0')
+ goto dc;
+ *cp++ = c;
+ c = GETC();
+ c1 = 3;
+ if(c == 'x' || c == 'X') {
+ c1 = 4;
+ c = GETC();
+ } else
+ if(c < '0' || c > '7')
+ goto dc;
+ yylval.lval = 0;
+ for(;;) {
+ if(c >= '0' && c <= '9') {
+ if(c > '7' && c1 == 3)
+ break;
+ yylval.lval <<= c1;
+ yylval.lval += c - '0';
+ c = GETC();
+ continue;
+ }
+ if(c1 == 3)
+ break;
+ if(c >= 'A' && c <= 'F')
+ c += 'a' - 'A';
+ if(c >= 'a' && c <= 'f') {
+ yylval.lval <<= c1;
+ yylval.lval += c - 'a' + 10;
+ c = GETC();
+ continue;
+ }
+ break;
+ }
+ goto ncu;
+
+ dc:
+ for(;;) {
+ if(!isdigit(c))
+ break;
+ *cp++ = c;
+ c = GETC();
+ }
+ if(c == '.')
+ goto casedot;
+ if(c == 'e' || c == 'E')
+ goto casee;
+ *cp = 0;
+ if(sizeof(yylval.lval) == sizeof(vlong))
+ yylval.lval = strtoll(symb, nil, 10);
+ else
+ yylval.lval = strtol(symb, nil, 10);
+
+ ncu:
+ while(c == 'U' || c == 'u' || c == 'l' || c == 'L')
+ c = GETC();
+ peekc = c;
+ return LCONST;
+
+ casedot:
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(!isdigit(c))
+ break;
+ }
+ if(c == 'e' || c == 'E')
+ goto casee;
+ goto caseout;
+
+ casee:
+ *cp++ = 'e';
+ c = GETC();
+ if(c == '+' || c == '-') {
+ *cp++ = c;
+ c = GETC();
+ }
+ while(isdigit(c)) {
+ *cp++ = c;
+ c = GETC();
+ }
+
+ caseout:
+ *cp = 0;
+ peekc = c;
+ if(FPCHIP) {
+ yylval.dval = atof(symb);
+ return LFCONST;
+ }
+ yyerror("assembler cannot interpret fp constants");
+ yylval.lval = 1L;
+ return LCONST;
+
+ case '"':
+ memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval));
+ cp = yylval.sval;
+ c1 = 0;
+ for(;;) {
+ c = escchar('"');
+ if(c == EOF)
+ break;
+ if(c1 < sizeof(yylval.sval))
+ *cp++ = c;
+ c1++;
+ }
+ if(c1 > sizeof(yylval.sval))
+ yyerror("string constant too long");
+ return LSCONST;
+
+ case '\'':
+ c = escchar('\'');
+ if(c == EOF)
+ c = '\'';
+ if(escchar('\'') != EOF)
+ yyerror("missing '");
+ yylval.lval = c;
+ return LCONST;
+
+ case '/':
+ c1 = GETC();
+ if(c1 == '/') {
+ for(;;) {
+ c = GETC();
+ if(c == '\n') {
+ lineno++;
+ goto l1;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '*') {
+ for(;;) {
+ c = GETC();
+ while(c == '*') {
+ c = GETC();
+ if(c == '/')
+ goto l0;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ if(c == '\n')
+ lineno++;
+ }
+ }
+ break;
+
+ default:
+ return c;
+ }
+ peekc = c1;
+ return c;
+}
+
+int
+getc(void)
+{
+ int c;
+
+ c = peekc;
+ if(c != IGN) {
+ peekc = IGN;
+ return c;
+ }
+ c = GETC();
+ if(c == '\n')
+ lineno++;
+ if(c == EOF) {
+ yyerror("End of file");
+ errorexit();
+ }
+ return c;
+}
+
+int
+getnsc(void)
+{
+ int c;
+
+ for(;;) {
+ c = getc();
+ if(!isspace(c) || c == '\n')
+ return c;
+ }
+}
+
+void
+unget(int c)
+{
+
+ peekc = c;
+ if(c == '\n')
+ lineno--;
+}
+
+int
+escchar(int e)
+{
+ int c, l;
+
+loop:
+ c = getc();
+ if(c == '\n') {
+ yyerror("newline in string");
+ return EOF;
+ }
+ if(c != '\\') {
+ if(c == e)
+ return EOF;
+ return c;
+ }
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = c - '0';
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ return l;
+ }
+ }
+ peekc = c;
+ return l;
+ }
+ switch(c)
+ {
+ case '\n': goto loop;
+ case 'n': return '\n';
+ case 't': return '\t';
+ case 'b': return '\b';
+ case 'r': return '\r';
+ case 'f': return '\f';
+ case 'a': return 0x07;
+ case 'v': return 0x0b;
+ case 'z': return 0x00;
+ }
+ return c;
+}
+
+void
+pinit(char *f)
+{
+ int i;
+ Sym *s;
+
+ lineno = 1;
+ newio();
+ newfile(f, -1);
+ pc = 0;
+ peekc = IGN;
+ sym = 1;
+ for(i=0; i<NSYM; i++) {
+ h[i].type = 0;
+ h[i].sym = S;
+ }
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ s->macro = 0;
+}
+
+int
+filbuf(void)
+{
+ Io *i;
+
+loop:
+ i = iostack;
+ if(i == I)
+ return EOF;
+ if(i->f < 0)
+ goto pop;
+ fi.c = read(i->f, i->b, BUFSIZ) - 1;
+ if(fi.c < 0) {
+ close(i->f);
+ linehist(0, 0);
+ goto pop;
+ }
+ fi.p = i->b + 1;
+ return i->b[0];
+
+pop:
+ iostack = i->link;
+ i->link = iofree;
+ iofree = i;
+ i = iostack;
+ if(i == I)
+ return EOF;
+ fi.p = i->p;
+ fi.c = i->c;
+ if(--fi.c < 0)
+ goto loop;
+ return *fi.p++;
+}
+
+void
+yyerror(char *a, ...)
+{
+ char buf[200];
+ va_list arg;
+
+ /*
+ * hack to intercept message from yaccpar
+ */
+ if(strcmp(a, "syntax error") == 0) {
+ yyerror("syntax error, last name: %s", symb);
+ return;
+ }
+ prfile(lineno);
+ va_start(arg, a);
+ vseprint(buf, buf+sizeof(buf), a, arg);
+ va_end(arg);
+ print("%s\n", buf);
+ nerrors++;
+ if(nerrors > 10) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
+
+void
+prfile(long l)
+{
+ int i, n;
+ Hist a[HISTSZ], *h;
+ long d;
+
+ n = 0;
+ for(h = hist; h != H; h = h->link) {
+ if(l < h->line)
+ break;
+ if(h->name) {
+ if(h->offset == 0) {
+ if(n >= 0 && n < HISTSZ)
+ a[n] = *h;
+ n++;
+ continue;
+ }
+ if(n > 0 && n < HISTSZ)
+ if(a[n-1].offset == 0) {
+ a[n] = *h;
+ n++;
+ } else
+ a[n-1] = *h;
+ continue;
+ }
+ n--;
+ if(n >= 0 && n < HISTSZ) {
+ d = h->line - a[n].line;
+ for(i=0; i<n; i++)
+ a[i].line += d;
+ }
+ }
+ if(n > HISTSZ)
+ n = HISTSZ;
+ for(i=0; i<n; i++)
+ print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
diff --git a/src/cmd/cc/mac.c b/src/cmd/cc/mac.c
new file mode 100644
index 0000000..c08cd9c
--- /dev/null
+++ b/src/cmd/cc/mac.c
@@ -0,0 +1,33 @@
+// Inferno utils/cc/mac.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/mac.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+#include "macbody"
diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody
new file mode 100644
index 0000000..9d309c1
--- /dev/null
+++ b/src/cmd/cc/macbody
@@ -0,0 +1,842 @@
+// Inferno utils/cc/macbody
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#define VARMAC 0x80
+
+long
+getnsn(void)
+{
+ long n;
+ int c;
+
+ c = getnsc();
+ if(c < '0' || c > '9')
+ return -1;
+ n = 0;
+ while(c >= '0' && c <= '9') {
+ n = n*10 + c-'0';
+ c = getc();
+ }
+ unget(c);
+ return n;
+}
+
+Sym*
+getsym(void)
+{
+ int c;
+ char *cp;
+
+ c = getnsc();
+ if(!isalpha(c) && c != '_') {
+ unget(c);
+ return S;
+ }
+ for(cp = symb;;) {
+ if(cp <= symb+NSYMB-4)
+ *cp++ = c;
+ c = getc();
+ if(isalnum(c) || c == '_')
+ continue;
+ unget(c);
+ break;
+ }
+ *cp = 0;
+ if(cp > symb+NSYMB-4)
+ yyerror("symbol too large: %s", symb);
+ return lookup();
+}
+
+Sym*
+getsymdots(int *dots)
+{
+ int c;
+ Sym *s;
+
+ s = getsym();
+ if(s != S)
+ return s;
+
+ c = getnsc();
+ if(c != '.'){
+ unget(c);
+ return S;
+ }
+ if(getc() != '.' || getc() != '.')
+ yyerror("bad dots in macro");
+ *dots = 1;
+ return slookup("__VA_ARGS__");
+}
+
+int
+getcom(void)
+{
+ int c;
+
+ for(;;) {
+ c = getnsc();
+ if(c != '/')
+ break;
+ c = getc();
+ if(c == '/') {
+ while(c != '\n')
+ c = getc();
+ break;
+ }
+ if(c != '*')
+ break;
+ c = getc();
+ for(;;) {
+ if(c == '*') {
+ c = getc();
+ if(c != '/')
+ continue;
+ c = getc();
+ break;
+ }
+ if(c == '\n') {
+ yyerror("comment across newline");
+ break;
+ }
+ c = getc();
+ }
+ if(c == '\n')
+ break;
+ }
+ return c;
+}
+
+void
+dodefine(char *cp)
+{
+ Sym *s;
+ char *p;
+ long l;
+
+ strcpy(symb, cp);
+ p = strchr(symb, '=');
+ if(p) {
+ *p++ = 0;
+ s = lookup();
+ l = strlen(p) + 2; /* +1 null, +1 nargs */
+ s->macro = alloc(l);
+ strcpy(s->macro+1, p);
+ } else {
+ s = lookup();
+ s->macro = "\0001"; /* \000 is nargs */
+ }
+ if(debug['m'])
+ print("#define (-D) %s %s\n", s->name, s->macro+1);
+}
+
+struct
+{
+ char *macname;
+ void (*macf)(void);
+} mactab[] =
+{
+ "ifdef", 0, /* macif(0) */
+ "ifndef", 0, /* macif(1) */
+ "else", 0, /* macif(2) */
+
+ "line", maclin,
+ "define", macdef,
+ "include", macinc,
+ "undef", macund,
+
+ "pragma", macprag,
+ "endif", macend,
+ 0
+};
+
+void
+domacro(void)
+{
+ int i;
+ Sym *s;
+
+ s = getsym();
+ if(s == S)
+ s = slookup("endif");
+ for(i=0; mactab[i].macname; i++)
+ if(strcmp(s->name, mactab[i].macname) == 0) {
+ if(mactab[i].macf)
+ (*mactab[i].macf)();
+ else
+ macif(i);
+ return;
+ }
+ yyerror("unknown #: %s", s->name);
+ macend();
+}
+
+void
+macund(void)
+{
+ Sym *s;
+
+ s = getsym();
+ macend();
+ if(s == S) {
+ yyerror("syntax in #undef");
+ return;
+ }
+ s->macro = 0;
+}
+
+#define NARG 25
+void
+macdef(void)
+{
+ Sym *s, *a;
+ char *args[NARG], *np, *base;
+ int n, i, c, len, dots;
+ int ischr;
+
+ s = getsym();
+ if(s == S)
+ goto bad;
+ if(s->macro)
+ yyerror("macro redefined: %s", s->name);
+ c = getc();
+ n = -1;
+ dots = 0;
+ if(c == '(') {
+ n++;
+ c = getnsc();
+ if(c != ')') {
+ unget(c);
+ for(;;) {
+ a = getsymdots(&dots);
+ if(a == S)
+ goto bad;
+ if(n >= NARG) {
+ yyerror("too many arguments in #define: %s", s->name);
+ goto bad;
+ }
+ args[n++] = a->name;
+ c = getnsc();
+ if(c == ')')
+ break;
+ if(c != ',' || dots)
+ goto bad;
+ }
+ }
+ c = getc();
+ }
+ if(isspace(c))
+ if(c != '\n')
+ c = getnsc();
+ base = hunk;
+ len = 1;
+ ischr = 0;
+ for(;;) {
+ if(isalpha(c) || c == '_') {
+ np = symb;
+ *np++ = c;
+ c = getc();
+ while(isalnum(c) || c == '_') {
+ *np++ = c;
+ c = getc();
+ }
+ *np = 0;
+ for(i=0; i<n; i++)
+ if(strcmp(symb, args[i]) == 0)
+ break;
+ if(i >= n) {
+ i = strlen(symb);
+ base = allocn(base, len, i);
+ memcpy(base+len, symb, i);
+ len += i;
+ continue;
+ }
+ base = allocn(base, len, 2);
+ base[len++] = '#';
+ base[len++] = 'a' + i;
+ continue;
+ }
+ if(ischr){
+ if(c == '\\'){
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ c = getc();
+ }else if(c == ischr)
+ ischr = 0;
+ }else{
+ if(c == '"' || c == '\''){
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ ischr = c;
+ c = getc();
+ continue;
+ }
+ if(c == '/') {
+ c = getc();
+ if(c == '/'){
+ c = getc();
+ for(;;) {
+ if(c == '\n')
+ break;
+ c = getc();
+ }
+ continue;
+ }
+ if(c == '*'){
+ c = getc();
+ for(;;) {
+ if(c == '*') {
+ c = getc();
+ if(c != '/')
+ continue;
+ c = getc();
+ break;
+ }
+ if(c == '\n') {
+ yyerror("comment and newline in define: %s", s->name);
+ break;
+ }
+ c = getc();
+ }
+ continue;
+ }
+ base = allocn(base, len, 1);
+ base[len++] = '/';
+ continue;
+ }
+ }
+ if(c == '\\') {
+ c = getc();
+ if(c == '\n') {
+ c = getc();
+ continue;
+ }
+ else if(c == '\r') {
+ c = getc();
+ if(c == '\n') {
+ c = getc();
+ continue;
+ }
+ }
+ base = allocn(base, len, 1);
+ base[len++] = '\\';
+ continue;
+ }
+ if(c == '\n')
+ break;
+ if(c == '#')
+ if(n > 0) {
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ }
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
+ if(c == '\n')
+ lineno++;
+ if(c == -1) {
+ yyerror("eof in a macro: %s", s->name);
+ break;
+ }
+ }
+ do {
+ base = allocn(base, len, 1);
+ base[len++] = 0;
+ } while(len & 3);
+
+ *base = n+1;
+ if(dots)
+ *base |= VARMAC;
+ s->macro = base;
+ if(debug['m'])
+ print("#define %s %s\n", s->name, s->macro+1);
+ return;
+
+bad:
+ if(s == S)
+ yyerror("syntax in #define");
+ else
+ yyerror("syntax in #define: %s", s->name);
+ macend();
+}
+
+void
+macexpand(Sym *s, char *b)
+{
+ char buf[2000];
+ int n, l, c, nargs;
+ char *arg[NARG], *cp, *ob, *ecp, dots;
+
+ ob = b;
+ if(*s->macro == 0) {
+ strcpy(b, s->macro+1);
+ if(debug['m'])
+ print("#expand %s %s\n", s->name, ob);
+ return;
+ }
+
+ nargs = (char)(*s->macro & ~VARMAC) - 1;
+ dots = *s->macro & VARMAC;
+
+ c = getnsc();
+ if(c != '(')
+ goto bad;
+ n = 0;
+ c = getc();
+ if(c != ')') {
+ unget(c);
+ l = 0;
+ cp = buf;
+ ecp = cp + sizeof(buf)-4;
+ arg[n++] = cp;
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ c = getc();
+ if(c == '"')
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ *cp++ = c;
+ c = getc();
+ if(c == '\\') {
+ *cp++ = c;
+ c = getc();
+ continue;
+ }
+ if(c == '\n')
+ goto bad;
+ if(c == '"')
+ break;
+ }
+ if(c == '\'')
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ *cp++ = c;
+ c = getc();
+ if(c == '\\') {
+ *cp++ = c;
+ c = getc();
+ continue;
+ }
+ if(c == '\n')
+ goto bad;
+ if(c == '\'')
+ break;
+ }
+ if(c == '/') {
+ c = getc();
+ switch(c) {
+ case '*':
+ for(;;) {
+ c = getc();
+ if(c == '*') {
+ c = getc();
+ if(c == '/')
+ break;
+ }
+ }
+ *cp++ = ' ';
+ continue;
+ case '/':
+ while((c = getc()) != '\n')
+ ;
+ break;
+ default:
+ unget(c);
+ c = '/';
+ }
+ }
+ if(l == 0) {
+ if(c == ',') {
+ if(n == nargs && dots) {
+ *cp++ = ',';
+ continue;
+ }
+ *cp++ = 0;
+ arg[n++] = cp;
+ if(n > nargs)
+ break;
+ continue;
+ }
+ if(c == ')')
+ break;
+ }
+ if(c == '\n')
+ c = ' ';
+ *cp++ = c;
+ if(c == '(')
+ l++;
+ if(c == ')')
+ l--;
+ }
+ *cp = 0;
+ }
+ if(n != nargs) {
+ yyerror("argument mismatch expanding: %s", s->name);
+ *b = 0;
+ return;
+ }
+ cp = s->macro+1;
+ for(;;) {
+ c = *cp++;
+ if(c == '\n')
+ c = ' ';
+ if(c != '#') {
+ *b++ = c;
+ if(c == 0)
+ break;
+ continue;
+ }
+ c = *cp++;
+ if(c == 0)
+ goto bad;
+ if(c == '#') {
+ *b++ = c;
+ continue;
+ }
+ c -= 'a';
+ if(c < 0 || c >= n)
+ continue;
+ strcpy(b, arg[c]);
+ b += strlen(arg[c]);
+ }
+ *b = 0;
+ if(debug['m'])
+ print("#expand %s %s\n", s->name, ob);
+ return;
+
+bad:
+ yyerror("syntax in macro expansion: %s", s->name);
+ *b = 0;
+ return;
+
+toobig:
+ yyerror("too much text in macro expansion: %s", s->name);
+ *b = 0;
+}
+
+void
+macinc(void)
+{
+ int c0, c, i, f;
+ char str[STRINGSZ], *hp;
+
+ c0 = getnsc();
+ if(c0 != '"') {
+ c = c0;
+ if(c0 != '<')
+ goto bad;
+ c0 = '>';
+ }
+ for(hp = str;;) {
+ c = getc();
+ if(c == c0)
+ break;
+ if(c == '\n')
+ goto bad;
+ *hp++ = c;
+ }
+ *hp = 0;
+
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+ f = -1;
+ for(i=0; i<ninclude; i++) {
+ if(i == 0 && c0 == '>')
+ continue;
+ strcpy(symb, include[i]);
+ strcat(symb, "/");
+ if(strcmp(symb, "./") == 0)
+ symb[0] = 0;
+ strcat(symb, str);
+ f = myopen(symb);
+ if(f >= 0)
+ break;
+ }
+ if(f < 0)
+ strcpy(symb, str);
+ c = strlen(symb) + 1;
+ hp = alloc(c);
+ memcpy(hp, symb, c);
+ newio();
+ pushio();
+ newfile(hp, f);
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #include");
+ macend();
+}
+
+void
+maclin(void)
+{
+ char *cp;
+ int c;
+ long n;
+
+ n = getnsn();
+ c = getc();
+ if(n < 0)
+ goto bad;
+
+ for(;;) {
+ if(c == ' ' || c == '\t') {
+ c = getc();
+ continue;
+ }
+ if(c == '"')
+ break;
+ if(c == '\n') {
+ strcpy(symb, "<noname>");
+ goto nn;
+ }
+ goto bad;
+ }
+ cp = symb;
+ for(;;) {
+ c = getc();
+ if(c == '"')
+ break;
+ *cp++ = c;
+ }
+ *cp = 0;
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+nn:
+ c = strlen(symb) + 1;
+ cp = alloc(c);
+ memcpy(cp, symb, c);
+ linehist(cp, n);
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #line");
+ macend();
+}
+
+void
+macif(int f)
+{
+ int c, l, bol;
+ Sym *s;
+
+ if(f == 2)
+ goto skip;
+ s = getsym();
+ if(s == S)
+ goto bad;
+ if(getcom() != '\n')
+ goto bad;
+ if((s->macro != 0) ^ f)
+ return;
+
+skip:
+ bol = 1;
+ l = 0;
+ for(;;) {
+ c = getc();
+ if(c != '#') {
+ if(!isspace(c))
+ bol = 0;
+ if(c == '\n')
+ bol = 1;
+ continue;
+ }
+ if(!bol)
+ continue;
+ s = getsym();
+ if(s == S)
+ continue;
+ if(strcmp(s->name, "endif") == 0) {
+ if(l) {
+ l--;
+ continue;
+ }
+ macend();
+ return;
+ }
+ if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
+ l++;
+ continue;
+ }
+ if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
+ macend();
+ return;
+ }
+ }
+
+bad:
+ yyerror("syntax in #if(n)def");
+ macend();
+}
+
+void
+macprag(void)
+{
+ Sym *s;
+ int c0, c;
+ char *hp;
+ Hist *h;
+
+ s = getsym();
+
+ if(s && strcmp(s->name, "lib") == 0)
+ goto praglib;
+ if(s && strcmp(s->name, "pack") == 0) {
+ pragpack();
+ return;
+ }
+ if(s && strcmp(s->name, "fpround") == 0) {
+ pragfpround();
+ return;
+ }
+ if(s && strcmp(s->name, "profile") == 0) {
+ pragprofile();
+ return;
+ }
+ if(s && strcmp(s->name, "varargck") == 0) {
+ pragvararg();
+ return;
+ }
+ if(s && strcmp(s->name, "incomplete") == 0) {
+ pragincomplete();
+ return;
+ }
+ while(getnsc() != '\n')
+ ;
+ return;
+
+praglib:
+ c0 = getnsc();
+ if(c0 != '"') {
+ c = c0;
+ if(c0 != '<')
+ goto bad;
+ c0 = '>';
+ }
+ for(hp = symb;;) {
+ c = getc();
+ if(c == c0)
+ break;
+ if(c == '\n')
+ goto bad;
+ *hp++ = c;
+ }
+ *hp = 0;
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+ /*
+ * put pragma-line in as a funny history
+ */
+ c = strlen(symb) + 1;
+ hp = alloc(c);
+ memcpy(hp, symb, c);
+
+ h = alloc(sizeof(Hist));
+ h->name = hp;
+ h->line = lineno;
+ h->offset = -1;
+ h->link = H;
+ if(ehist == H) {
+ hist = h;
+ ehist = h;
+ return;
+ }
+ ehist->link = h;
+ ehist = h;
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #pragma lib");
+ macend();
+}
+
+void
+macend(void)
+{
+ int c;
+
+ for(;;) {
+ c = getnsc();
+ if(c < 0 || c == '\n')
+ return;
+ }
+}
+
+void
+linehist(char *f, int offset)
+{
+ Hist *h;
+
+ /*
+ * overwrite the last #line directive if
+ * no alloc has happened since the last one
+ */
+ if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0)
+ if(f && ehist->name && strcmp(f, ehist->name) == 0) {
+ ehist->line = lineno;
+ ehist->offset = offset;
+ return;
+ }
+
+ if(debug['f'])
+ if(f) {
+ if(offset)
+ print("%4ld: %s (#line %d)\n", lineno, f, offset);
+ else
+ print("%4ld: %s\n", lineno, f);
+ } else
+ print("%4ld: <pop>\n", lineno);
+ newflag = 0;
+
+ h = alloc(sizeof(Hist));
+ h->name = f;
+ h->line = lineno;
+ h->offset = offset;
+ h->link = H;
+ if(ehist == H) {
+ hist = h;
+ ehist = h;
+ return;
+ }
+ ehist->link = h;
+ ehist = h;
+}
diff --git a/src/cmd/cc/omachcap.c b/src/cmd/cc/omachcap.c
new file mode 100644
index 0000000..ec5aa86
--- /dev/null
+++ b/src/cmd/cc/omachcap.c
@@ -0,0 +1,38 @@
+// Inferno utils/cc/machcap.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/machcap.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+/* default, like old cc */
+int
+machcap(Node *n)
+{
+ return 0;
+}
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c
new file mode 100644
index 0000000..ae0b1b4
--- /dev/null
+++ b/src/cmd/cc/pgen.c
@@ -0,0 +1,550 @@
+// Inferno utils/6c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+ Node *n1, nod, nod1;
+
+ cursafe = 0;
+ curarg = 0;
+ maxargsafe = 0;
+
+ /*
+ * isolate name
+ */
+ for(n1 = nn;; n1 = n1->left) {
+ if(n1 == Z) {
+ diag(nn, "cant find function name");
+ return;
+ }
+ if(n1->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+ gpseudo(ATEXT, n1->sym, nodconst(stkoff));
+ sp = p;
+
+ /*
+ * isolate first argument
+ */
+ if(REGARG) {
+ if(typecmplx[thisfn->link->etype]) {
+ nod1 = *nodret->left;
+ nodreg(&nod, &nod1, REGARG);
+ gmove(&nod, &nod1);
+ } else
+ if(firstarg && typeword[firstargtype->etype]) {
+ nod1 = *nodret->left;
+ nod1.sym = firstarg;
+ nod1.type = firstargtype;
+ nod1.xoffset = align(0, firstargtype, Aarg1);
+ nod1.etype = firstargtype->etype;
+ nodreg(&nod, &nod1, REGARG);
+ gmove(&nod, &nod1);
+ }
+ }
+
+ canreach = 1;
+ warnreach = 1;
+ gen(n);
+ if(canreach && thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", n1->sym->name);
+ noretval(3);
+ gbranch(ORETURN);
+
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+
+ if(thechar=='6' || thechar=='7') /* [sic] */
+ maxargsafe = xround(maxargsafe, 8);
+ sp->to.offset += maxargsafe;
+}
+
+void
+supgen(Node *n)
+{
+ int owarn;
+ long spc;
+ Prog *sp;
+
+ if(n == Z)
+ return;
+ suppress++;
+ owarn = warnreach;
+ warnreach = 0;
+ spc = pc;
+ sp = lastp;
+ gen(n);
+ lastp = sp;
+ pc = spc;
+ sp->link = nil;
+ suppress--;
+ warnreach = owarn;
+}
+
+void
+gen(Node *n)
+{
+ Node *l, nod;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int snbreak, sncontin;
+ int f, o, oldreach;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+
+ if(!canreach) {
+ switch(o) {
+ case OLABEL:
+ case OCASE:
+ case OLIST:
+ case OBREAK:
+ case OFOR:
+ case OWHILE:
+ case ODWHILE:
+ /* all handled specially - see switch body below */
+ break;
+ default:
+ if(warnreach) {
+ warn(n, "unreachable code %O", o);
+ warnreach = 0;
+ }
+ }
+ }
+
+ switch(o) {
+
+ default:
+ complex(n);
+ cgen(n, Z);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ canreach = 0;
+ warnreach = !suppress;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ if(typecmplx[n->type->etype]) {
+ sugen(l, nodret, n->type->width);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ regret(&nod, n);
+ cgen(l, &nod);
+ regfree(&nod);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ break;
+
+ case OLABEL:
+ canreach = 1;
+ l = n->left;
+ if(l) {
+ l->pc = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ canreach = 0;
+ warnreach = !suppress;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ if(suppress)
+ return;
+ gbranch(OGOTO);
+ if(n->pc) {
+ patch(p, n->pc);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ canreach = 1;
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ cas();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ cases->isv = 0;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typeword[l->type->etype] && l->type->etype != TIND) {
+ cas();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ cases->isv = typev[l->type->etype];
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ if(l->type == T)
+ break;
+ if(!typeword[l->type->etype] || l->type->etype == TIND) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ cas();
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right); /* body */
+ if(canreach){
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ nbreak++;
+ }
+
+ patch(sp, pc);
+ regalloc(&nod, l, Z);
+ /* always signed */
+ if(typev[l->type->etype])
+ nod.type = types[TVLONG];
+ else
+ nod.type = types[TLONG];
+ cgen(l, &nod);
+ doswit(&nod);
+ regfree(&nod);
+ patch(spb, pc);
+
+ cases = cn;
+ breakpc = sbc;
+ canreach = nbreak!=0;
+ if(canreach == 0)
+ warnreach = !suppress;
+ nbreak = snbreak;
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l, Z); /* test */
+ patch(p, breakpc);
+ if(l->op != OCONST || vconst(l) == 0)
+ nbreak++;
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ canreach = nbreak!=0;
+ if(canreach == 0)
+ warnreach = !suppress;
+ nbreak = snbreak;
+ break;
+
+ case OFOR:
+ l = n->left;
+ if(!canreach && l->right->left && warnreach) {
+ warn(n, "unreachable code FOR");
+ warnreach = 0;
+ }
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ /*
+ * if there are no incoming labels in the
+ * body and the top's not reachable, warn
+ */
+ if(!canreach && warnreach && deadheads(n)) {
+ warn(n, "unreachable code %O", o);
+ warnreach = 0;
+ }
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ sncontin = ncontin;
+ ncontin = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left, Z);
+ patch(p, breakpc);
+ if(l->left->op != OCONST || vconst(l->left) == 0)
+ nbreak++;
+ }
+ canreach = 1;
+ gen(n->right); /* body */
+ if(canreach){
+ gbranch(OGOTO);
+ patch(p, continpc);
+ ncontin++;
+ }
+ if(!ncontin && l->right->right && warnreach) {
+ warn(l->right->right, "unreachable FOR inc");
+ warnreach = 0;
+ }
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ canreach = nbreak!=0;
+ if(canreach == 0)
+ warnreach = !suppress;
+ nbreak = snbreak;
+ ncontin = sncontin;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ ncontin++;
+ canreach = 0;
+ warnreach = !suppress;
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ /*
+ * Don't complain about unreachable break statements.
+ * There are breaks hidden in yacc's output and some people
+ * write return; break; in their switch statements out of habit.
+ * However, don't confuse the analysis by inserting an
+ * unreachable reference to breakpc either.
+ */
+ if(!canreach)
+ break;
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ nbreak++;
+ canreach = 0;
+ warnreach = !suppress;
+ break;
+
+ case OIF:
+ l = n->left;
+ if(bcomplex(l, n->right)) {
+ if(typefd[l->type->etype])
+ f = !l->fconst;
+ else
+ f = !l->vconst;
+ if(debug['c'])
+ print("%L const if %s\n", nearln, f ? "false" : "true");
+ if(f) {
+ canreach = 1;
+ supgen(n->right->left);
+ oldreach = canreach;
+ canreach = 1;
+ gen(n->right->right);
+ /*
+ * treat constant ifs as regular ifs for
+ * reachability warnings.
+ */
+ if(!canreach && oldreach && debug['w'] < 2)
+ warnreach = 0;
+ }
+ else {
+ canreach = 1;
+ gen(n->right->left);
+ oldreach = canreach;
+ canreach = 1;
+ supgen(n->right->right);
+ /*
+ * treat constant ifs as regular ifs for
+ * reachability warnings.
+ */
+ if(!oldreach && canreach && debug['w'] < 2)
+ warnreach = 0;
+ canreach = oldreach;
+ }
+ }
+ else {
+ sp = p;
+ canreach = 1;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ oldreach = canreach;
+ canreach = 1;
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ canreach = canreach || oldreach;
+ if(canreach == 0)
+ warnreach = !suppress;
+ }
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gins(ANOP, n, Z);
+ break;
+ case ONAME:
+ if(o == OSET)
+ gins(ANOP, Z, n);
+ else
+ gins(ANOP, n, Z);
+ break;
+ }
+}
+
+int
+bcomplex(Node *n, Node *c)
+{
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type == T) {
+ gbranch(OGOTO);
+ return 0;
+ }
+ if(c != Z && n->op == OCONST && deadheads(c))
+ return 1;
+ bool64(n);
+ boolgen(n, 1, Z);
+ return 0;
+}
diff --git a/src/cmd/cc/pickle.c b/src/cmd/cc/pickle.c
new file mode 100644
index 0000000..3626e4a
--- /dev/null
+++ b/src/cmd/cc/pickle.c
@@ -0,0 +1,298 @@
+// Inferno utils/cc/pickle.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/pickle.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+static char *kwd[] =
+{
+ "$adt", "$aggr", "$append", "$complex", "$defn",
+ "$delete", "$do", "$else", "$eval", "$head", "$if",
+ "$local", "$loop", "$return", "$tail", "$then",
+ "$union", "$whatis", "$while",
+};
+static char picklestr[] = "\tbp = pickle(bp, ep, un, ";
+
+static char*
+pmap(char *s)
+{
+ int i, bot, top, new;
+
+ bot = 0;
+ top = bot + nelem(kwd) - 1;
+ while(bot <= top){
+ new = bot + (top - bot)/2;
+ i = strcmp(kwd[new]+1, s);
+ if(i == 0)
+ return kwd[new];
+
+ if(i < 0)
+ bot = new + 1;
+ else
+ top = new - 1;
+ }
+ return s;
+}
+
+Sym*
+picklesue(Type *t)
+{
+ int h;
+ Sym *s;
+
+ if(t != T)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->suetag && s->suetag->link == t)
+ return s;
+ return 0;
+}
+
+Sym*
+picklefun(Type *t)
+{
+ int h;
+ Sym *s;
+
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == t)
+ return s;
+ return 0;
+}
+
+char picklechar[NTYPE];
+Init picklecinit[] =
+{
+ TCHAR, 'C', 0,
+ TUCHAR, 'b', 0,
+ TSHORT, 'd', 0,
+ TUSHORT, 'u', 0,
+ TLONG, 'D', 0,
+ TULONG, 'U', 0,
+ TVLONG, 'V', 0,
+ TUVLONG, 'W', 0,
+ TFLOAT, 'f', 0,
+ TDOUBLE, 'F', 0,
+ TARRAY, 'a', 0,
+ TIND, 'X', 0,
+ -1, 0, 0,
+};
+
+static void
+pickleinit(void)
+{
+ Init *p;
+
+ for(p=picklecinit; p->code >= 0; p++)
+ picklechar[p->code] = p->value;
+
+ picklechar[TINT] = picklechar[TLONG];
+ picklechar[TUINT] = picklechar[TULONG];
+ if(types[TINT]->width != types[TLONG]->width) {
+ picklechar[TINT] = picklechar[TSHORT];
+ picklechar[TUINT] = picklechar[TUSHORT];
+ if(types[TINT]->width != types[TSHORT]->width)
+ warn(Z, "picklemember int not long or short");
+ }
+
+}
+
+void
+picklemember(Type *t, long off)
+{
+ Sym *s, *s1;
+ static int picklecharinit = 0;
+
+ if(picklecharinit == 0) {
+ pickleinit();
+ picklecharinit = 1;
+ }
+ s = t->sym;
+ switch(t->etype) {
+ default:
+ Bprint(&outbuf, " T%d\n", t->etype);
+ break;
+
+ case TIND:
+ if(s == S)
+ Bprint(&outbuf,
+ "%s\"p\", (char*)addr+%ld+_i*%ld);\n",
+ picklestr, t->offset+off, t->width);
+ else
+ Bprint(&outbuf,
+ "%s\"p\", &addr->%s);\n",
+ picklestr, pmap(s->name));
+ break;
+
+ case TINT:
+ case TUINT:
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TFLOAT:
+ case TDOUBLE:
+ if(s == S)
+ Bprint(&outbuf, "%s\"%c\", (char*)addr+%ld+_i*%ld);\n",
+ picklestr, picklechar[t->etype], t->offset+off, t->width);
+ else
+ Bprint(&outbuf, "%s\"%c\", &addr->%s);\n",
+ picklestr, picklechar[t->etype], pmap(s->name));
+ break;
+ case TARRAY:
+ Bprint(&outbuf, "\tfor(_i = 0; _i < %ld; _i++) {\n\t",
+ t->width/t->link->width);
+ picklemember(t->link, t->offset+off);
+ Bprint(&outbuf, "\t}\n\t_i = 0;\n\tUSED(_i);\n");
+ break;
+
+ case TSTRUCT:
+ case TUNION:
+ s1 = picklesue(t->link);
+ if(s1 == S)
+ break;
+ if(s == S) {
+ Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%ld+_i*%ld));\n",
+ pmap(s1->name), pmap(s1->name), t->offset+off, t->width);
+ } else {
+ Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, &addr->%s);\n",
+ pmap(s1->name), pmap(s->name));
+ }
+ break;
+ }
+}
+
+void
+pickletype(Type *t)
+{
+ Sym *s;
+ Type *l;
+ Io *i;
+ int n;
+ char *an;
+
+ if(!debug['P'])
+ return;
+ if(debug['P'] > 1) {
+ n = 0;
+ for(i=iostack; i; i=i->link)
+ n++;
+ if(n > 1)
+ return;
+ }
+ s = picklesue(t->link);
+ if(s == S)
+ return;
+ switch(t->etype) {
+ default:
+ Bprint(&outbuf, "T%d\n", t->etype);
+ return;
+
+ case TUNION:
+ case TSTRUCT:
+ if(debug['s'])
+ goto asmstr;
+ an = pmap(s->name);
+
+ Bprint(&outbuf, "char *\npickle_%s(char *bp, char *ep, int un, %s *addr)\n{\n\tint _i = 0;\n\n\tUSED(_i);\n", an, an);
+ for(l = t->link; l != T; l = l->down)
+ picklemember(l, 0);
+ Bprint(&outbuf, "\treturn bp;\n}\n\n");
+ break;
+ asmstr:
+ if(s == S)
+ break;
+ for(l = t->link; l != T; l = l->down)
+ if(l->sym != S)
+ Bprint(&outbuf, "#define\t%s.%s\t%ld\n",
+ s->name,
+ l->sym->name,
+ l->offset);
+ break;
+ }
+}
+
+void
+picklevar(Sym *s)
+{
+ int n;
+ Io *i;
+ Type *t;
+ Sym *s1, *s2;
+
+ if(!debug['P'] || debug['s'])
+ return;
+ if(debug['P'] > 1) {
+ n = 0;
+ for(i=iostack; i; i=i->link)
+ n++;
+ if(n > 1)
+ return;
+ }
+ t = s->type;
+ while(t && t->etype == TIND)
+ t = t->link;
+ if(t == T)
+ return;
+ if(t->etype == TENUM) {
+ Bprint(&outbuf, "%s = ", pmap(s->name));
+ if(!typefd[t->etype])
+ Bprint(&outbuf, "%lld;\n", s->vconst);
+ else
+ Bprint(&outbuf, "%f\n;", s->fconst);
+ return;
+ }
+ if(!typesu[t->etype])
+ return;
+ s1 = picklesue(t->link);
+ if(s1 == S)
+ return;
+ switch(s->class) {
+ case CAUTO:
+ case CPARAM:
+ s2 = picklefun(thisfn);
+ if(s2)
+ Bprint(&outbuf, "complex %s %s:%s;\n",
+ pmap(s1->name), pmap(s2->name), pmap(s->name));
+ break;
+
+ case CSTATIC:
+ case CEXTERN:
+ case CGLOBL:
+ case CLOCAL:
+ Bprint(&outbuf, "complex %s %s;\n",
+ pmap(s1->name), pmap(s->name));
+ break;
+ }
+}
diff --git a/src/cmd/cc/pswt.c b/src/cmd/cc/pswt.c
new file mode 100644
index 0000000..f4149f1
--- /dev/null
+++ b/src/cmd/cc/pswt.c
@@ -0,0 +1,168 @@
+// Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = (C1*)a1;
+ p2 = (C1*)a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ long def, nc, i, isv;
+
+ def = 0;
+ nc = 0;
+ isv = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ isv |= c->isv;
+ nc++;
+ }
+ if(isv && !typev[n->type->etype])
+ warn(n, "32-bit switch expression with 64-bit case constant");
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ if(isv)
+ q->val = c->val;
+ else
+ q->val = (long)c->val; /* cast ensures correct value for 32-bit switch on 64-bit architecture */
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(debug['W'])
+ for(i=0; i<nc; i++)
+ print("case %2ld: = %.8llux\n", i, (vlong)iq[i].val);
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val)
+ diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val);
+ if(def == 0) {
+ def = breakpc;
+ nbreak++;
+ }
+ swit1(iq, nc, def, n);
+}
+
+void
+cas(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+ char buf[2];
+ int c;
+ long r;
+
+ if(suppress)
+ return nstring;
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, Z);
+ if(r != Z)
+ cgen(r, Z);
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
diff --git a/src/cmd/cc/scon.c b/src/cmd/cc/scon.c
new file mode 100644
index 0000000..3047ca4
--- /dev/null
+++ b/src/cmd/cc/scon.c
@@ -0,0 +1,636 @@
+// Inferno utils/cc/scon.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/scon.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+static Node*
+acast(Type *t, Node *n)
+{
+ if(n->type->etype != t->etype || n->op == OBIT) {
+ n = new1(OCAST, n, Z);
+ if(nocast(n->left->type, t))
+ *n = *n->left;
+ n->type = t;
+ }
+ return n;
+}
+
+
+void
+evconst(Node *n)
+{
+ Node *l, *r;
+ int et, isf;
+ vlong v;
+ double d;
+
+ if(n == Z || n->type == T)
+ return;
+
+ et = n->type->etype;
+ isf = typefd[et];
+
+ l = n->left;
+ r = n->right;
+
+ d = 0;
+ v = 0;
+
+ switch(n->op) {
+ default:
+ return;
+
+ case ONEG:
+ if(isf)
+ d = -l->fconst;
+ else
+ v = -l->vconst;
+ break;
+
+ case OCOM:
+ v = ~l->vconst;
+ break;
+
+ case OCAST:
+ if(et == TVOID)
+ return;
+ et = l->type->etype;
+ if(isf) {
+ if(typefd[et])
+ d = l->fconst;
+ else
+ d = l->vconst;
+ } else {
+ if(typefd[et])
+ v = l->fconst;
+ else
+ v = convvtox(l->vconst, n->type->etype);
+ }
+ break;
+
+ case OCONST:
+ break;
+
+ case OADD:
+ if(isf)
+ d = l->fconst + r->fconst;
+ else {
+ v = l->vconst + r->vconst;
+ }
+ break;
+
+ case OSUB:
+ if(isf)
+ d = l->fconst - r->fconst;
+ else
+ v = l->vconst - r->vconst;
+ break;
+
+ case OMUL:
+ if(isf)
+ d = l->fconst * r->fconst;
+ else {
+ v = l->vconst * r->vconst;
+ }
+ break;
+
+ case OLMUL:
+ v = (uvlong)l->vconst * (uvlong)r->vconst;
+ break;
+
+
+ case ODIV:
+ if(vconst(r) == 0) {
+ warn(n, "divide by zero");
+ return;
+ }
+ if(isf)
+ d = l->fconst / r->fconst;
+ else
+ v = l->vconst / r->vconst;
+ break;
+
+ case OLDIV:
+ if(vconst(r) == 0) {
+ warn(n, "divide by zero");
+ return;
+ }
+ v = (uvlong)l->vconst / (uvlong)r->vconst;
+ break;
+
+ case OMOD:
+ if(vconst(r) == 0) {
+ warn(n, "modulo by zero");
+ return;
+ }
+ v = l->vconst % r->vconst;
+ break;
+
+ case OLMOD:
+ if(vconst(r) == 0) {
+ warn(n, "modulo by zero");
+ return;
+ }
+ v = (uvlong)l->vconst % (uvlong)r->vconst;
+ break;
+
+ case OAND:
+ v = l->vconst & r->vconst;
+ break;
+
+ case OOR:
+ v = l->vconst | r->vconst;
+ break;
+
+ case OXOR:
+ v = l->vconst ^ r->vconst;
+ break;
+
+ case OLSHR:
+ v = (uvlong)l->vconst >> r->vconst;
+ break;
+
+ case OASHR:
+ v = l->vconst >> r->vconst;
+ break;
+
+ case OASHL:
+ v = l->vconst << r->vconst;
+ break;
+
+ case OLO:
+ v = (uvlong)l->vconst < (uvlong)r->vconst;
+ break;
+
+ case OLT:
+ if(typefd[l->type->etype])
+ v = l->fconst < r->fconst;
+ else
+ v = l->vconst < r->vconst;
+ break;
+
+ case OHI:
+ v = (uvlong)l->vconst > (uvlong)r->vconst;
+ break;
+
+ case OGT:
+ if(typefd[l->type->etype])
+ v = l->fconst > r->fconst;
+ else
+ v = l->vconst > r->vconst;
+ break;
+
+ case OLS:
+ v = (uvlong)l->vconst <= (uvlong)r->vconst;
+ break;
+
+ case OLE:
+ if(typefd[l->type->etype])
+ v = l->fconst <= r->fconst;
+ else
+ v = l->vconst <= r->vconst;
+ break;
+
+ case OHS:
+ v = (uvlong)l->vconst >= (uvlong)r->vconst;
+ break;
+
+ case OGE:
+ if(typefd[l->type->etype])
+ v = l->fconst >= r->fconst;
+ else
+ v = l->vconst >= r->vconst;
+ break;
+
+ case OEQ:
+ if(typefd[l->type->etype])
+ v = l->fconst == r->fconst;
+ else
+ v = l->vconst == r->vconst;
+ break;
+
+ case ONE:
+ if(typefd[l->type->etype])
+ v = l->fconst != r->fconst;
+ else
+ v = l->vconst != r->vconst;
+ break;
+
+ case ONOT:
+ if(typefd[l->type->etype])
+ v = !l->fconst;
+ else
+ v = !l->vconst;
+ break;
+
+ case OANDAND:
+ if(typefd[l->type->etype])
+ v = l->fconst && r->fconst;
+ else
+ v = l->vconst && r->vconst;
+ break;
+
+ case OOROR:
+ if(typefd[l->type->etype])
+ v = l->fconst || r->fconst;
+ else
+ v = l->vconst || r->vconst;
+ break;
+ }
+ if(isf) {
+ n->fconst = d;
+ } else {
+ n->vconst = convvtox(v, n->type->etype);
+ }
+ n->oldop = n->op;
+ n->op = OCONST;
+}
+
+void
+acom(Node *n)
+{
+ Type *t;
+ Node *l, *r;
+ int i;
+
+ switch(n->op)
+ {
+
+ case ONAME:
+ case OCONST:
+ case OSTRING:
+ case OINDREG:
+ case OREGISTER:
+ return;
+
+ case ONEG:
+ l = n->left;
+ if(addo(n) && addo(l))
+ break;
+ acom(l);
+ return;
+
+ case OADD:
+ case OSUB:
+ case OMUL:
+ l = n->left;
+ r = n->right;
+ if(addo(n)) {
+ if(addo(r))
+ break;
+ if(addo(l))
+ break;
+ }
+ acom(l);
+ acom(r);
+ return;
+
+ default:
+ l = n->left;
+ r = n->right;
+ if(l != Z)
+ acom(l);
+ if(r != Z)
+ acom(r);
+ return;
+ }
+
+ /* bust terms out */
+ t = n->type;
+ term[0].mult = 0;
+ term[0].node = Z;
+ nterm = 1;
+ acom1(1, n);
+ if(debug['m'])
+ for(i=0; i<nterm; i++) {
+ print("%d %3lld ", i, term[i].mult);
+ prtree1(term[i].node, 1, 0);
+ }
+ if(nterm < NTERM)
+ acom2(n, t);
+ n->type = t;
+}
+
+int
+acomcmp1(const void *a1, const void *a2)
+{
+ vlong c1, c2;
+ Term *t1, *t2;
+
+ t1 = (Term*)a1;
+ t2 = (Term*)a2;
+ c1 = t1->mult;
+ if(c1 < 0)
+ c1 = -c1;
+ c2 = t2->mult;
+ if(c2 < 0)
+ c2 = -c2;
+ if(c1 > c2)
+ return 1;
+ if(c1 < c2)
+ return -1;
+ c1 = 1;
+ if(t1->mult < 0)
+ c1 = 0;
+ c2 = 1;
+ if(t2->mult < 0)
+ c2 = 0;
+ if(c2 -= c1)
+ return c2;
+ if(t2 > t1)
+ return 1;
+ return -1;
+}
+
+int
+acomcmp2(const void *a1, const void *a2)
+{
+ vlong c1, c2;
+ Term *t1, *t2;
+
+ t1 = (Term*)a1;
+ t2 = (Term*)a2;
+ c1 = t1->mult;
+ c2 = t2->mult;
+ if(c1 > c2)
+ return 1;
+ if(c1 < c2)
+ return -1;
+ if(t2 > t1)
+ return 1;
+ return -1;
+}
+
+void
+acom2(Node *n, Type *t)
+{
+ Node *l, *r;
+ Term trm[NTERM];
+ int et, nt, i, j;
+ vlong c1, c2;
+
+ /*
+ * copy into automatic
+ */
+ c2 = 0;
+ nt = nterm;
+ for(i=0; i<nt; i++)
+ trm[i] = term[i];
+ /*
+ * recur on subtrees
+ */
+ j = 0;
+ for(i=1; i<nt; i++) {
+ c1 = trm[i].mult;
+ if(c1 == 0)
+ continue;
+ l = trm[i].node;
+ if(l != Z) {
+ j = 1;
+ acom(l);
+ }
+ }
+ c1 = trm[0].mult;
+ if(j == 0) {
+ n->oldop = n->op;
+ n->op = OCONST;
+ n->vconst = c1;
+ return;
+ }
+ et = t->etype;
+
+ /*
+ * prepare constant term,
+ * combine it with an addressing term
+ */
+ if(c1 != 0) {
+ l = new1(OCONST, Z, Z);
+ l->type = t;
+ l->vconst = c1;
+ trm[0].mult = 1;
+ for(i=1; i<nt; i++) {
+ if(trm[i].mult != 1)
+ continue;
+ r = trm[i].node;
+ if(r->op != OADDR)
+ continue;
+ r->type = t;
+ l = new1(OADD, r, l);
+ l->type = t;
+ trm[i].mult = 0;
+ break;
+ }
+ trm[0].node = l;
+ }
+ /*
+ * look for factorable terms
+ * c1*i + c1*c2*j -> c1*(i + c2*j)
+ */
+ qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp1);
+ for(i=nt-1; i>=0; i--) {
+ c1 = trm[i].mult;
+ if(c1 < 0)
+ c1 = -c1;
+ if(c1 <= 1)
+ continue;
+ for(j=i+1; j<nt; j++) {
+ c2 = trm[j].mult;
+ if(c2 < 0)
+ c2 = -c2;
+ if(c2 <= 1)
+ continue;
+ if(c2 % c1)
+ continue;
+ r = trm[j].node;
+ if(r->type->etype != et)
+ r = acast(t, r);
+ c2 = trm[j].mult/trm[i].mult;
+ if(c2 != 1 && c2 != -1) {
+ r = new1(OMUL, r, new(OCONST, Z, Z));
+ r->type = t;
+ r->right->type = t;
+ r->right->vconst = c2;
+ }
+ l = trm[i].node;
+ if(l->type->etype != et)
+ l = acast(t, l);
+ r = new1(OADD, l, r);
+ r->type = t;
+ if(c2 == -1)
+ r->op = OSUB;
+ trm[i].node = r;
+ trm[j].mult = 0;
+ }
+ }
+ if(debug['m']) {
+ print("\n");
+ for(i=0; i<nt; i++) {
+ print("%d %3lld ", i, trm[i].mult);
+ prtree1(trm[i].node, 1, 0);
+ }
+ }
+
+ /*
+ * put it all back together
+ */
+ qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp2);
+ l = Z;
+ for(i=nt-1; i>=0; i--) {
+ c1 = trm[i].mult;
+ if(c1 == 0)
+ continue;
+ r = trm[i].node;
+ if(r->type->etype != et || r->op == OBIT)
+ r = acast(t, r);
+ if(c1 != 1 && c1 != -1) {
+ r = new1(OMUL, r, new(OCONST, Z, Z));
+ r->type = t;
+ r->right->type = t;
+ if(c1 < 0) {
+ r->right->vconst = -c1;
+ c1 = -1;
+ } else {
+ r->right->vconst = c1;
+ c1 = 1;
+ }
+ }
+ if(l == Z) {
+ l = r;
+ c2 = c1;
+ continue;
+ }
+ if(c1 < 0)
+ if(c2 < 0)
+ l = new1(OADD, l, r);
+ else
+ l = new1(OSUB, l, r);
+ else
+ if(c2 < 0) {
+ l = new1(OSUB, r, l);
+ c2 = 1;
+ } else
+ l = new1(OADD, l, r);
+ l->type = t;
+ }
+ if(c2 < 0) {
+ r = new1(OCONST, 0, 0);
+ r->vconst = 0;
+ r->type = t;
+ l = new1(OSUB, r, l);
+ l->type = t;
+ }
+ *n = *l;
+}
+
+void
+acom1(vlong v, Node *n)
+{
+ Node *l, *r;
+
+ if(v == 0 || nterm >= NTERM)
+ return;
+ if(!addo(n)) {
+ if(n->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ term[0].mult += v*n->vconst;
+ return;
+ }
+ term[nterm].mult = v;
+ term[nterm].node = n;
+ nterm++;
+ return;
+ }
+ switch(n->op) {
+
+ case OCAST:
+ acom1(v, n->left);
+ break;
+
+ case ONEG:
+ acom1(-v, n->left);
+ break;
+
+ case OADD:
+ acom1(v, n->left);
+ acom1(v, n->right);
+ break;
+
+ case OSUB:
+ acom1(v, n->left);
+ acom1(-v, n->right);
+ break;
+
+ case OMUL:
+ l = n->left;
+ r = n->right;
+ if(l->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ acom1(v*l->vconst, r);
+ break;
+ }
+ if(r->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ acom1(v*r->vconst, l);
+ break;
+ }
+ break;
+
+ default:
+ diag(n, "not addo");
+ }
+}
+
+int
+addo(Node *n)
+{
+
+ if(n != Z)
+ if(!typefd[n->type->etype])
+ if(!typev[n->type->etype] || ewidth[TVLONG] == ewidth[TIND])
+ switch(n->op) {
+
+ case OCAST:
+ if(nilcast(n->left->type, n->type))
+ return 1;
+ break;
+
+ case ONEG:
+ case OADD:
+ case OSUB:
+ return 1;
+
+ case OMUL:
+ if(n->left->op == OCONST)
+ return 1;
+ if(n->right->op == OCONST)
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c
new file mode 100644
index 0000000..fcf915c
--- /dev/null
+++ b/src/cmd/cc/sub.c
@@ -0,0 +1,2054 @@
+// Inferno utils/cc/sub.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/sub.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+Node*
+new(int t, Node *l, Node *r)
+{
+ Node *n;
+
+ n = alloc(sizeof(*n));
+ n->op = t;
+ n->left = l;
+ n->right = r;
+ if(l && t != OGOTO)
+ n->lineno = l->lineno;
+ else if(r)
+ n->lineno = r->lineno;
+ else
+ n->lineno = lineno;
+ newflag = 1;
+ return n;
+}
+
+Node*
+new1(int o, Node *l, Node *r)
+{
+ Node *n;
+
+ n = new(o, l, r);
+ n->lineno = nearln;
+ return n;
+}
+
+void
+prtree(Node *n, char *s)
+{
+
+ print(" == %s ==\n", s);
+ prtree1(n, 0, 0);
+ print("\n");
+}
+
+void
+prtree1(Node *n, int d, int f)
+{
+ int i;
+
+ if(f)
+ for(i=0; i<d; i++)
+ print(" ");
+ if(n == Z) {
+ print("Z\n");
+ return;
+ }
+ if(n->op == OLIST) {
+ prtree1(n->left, d, 0);
+ prtree1(n->right, d, 1);
+ return;
+ }
+ d++;
+ print("%O", n->op);
+ i = 3;
+ switch(n->op)
+ {
+ case ONAME:
+ print(" \"%F\"", n);
+ print(" %ld", n->xoffset);
+ i = 0;
+ break;
+
+ case OINDREG:
+ print(" %ld(R%d)", n->xoffset, n->reg);
+ i = 0;
+ break;
+
+ case OREGISTER:
+ if(n->xoffset)
+ print(" %ld+R%d", n->xoffset, n->reg);
+ else
+ print(" R%d", n->reg);
+ i = 0;
+ break;
+
+ case OSTRING:
+ print(" \"%s\"", n->cstring);
+ i = 0;
+ break;
+
+ case OLSTRING:
+ print(" \"%S\"", n->rstring);
+ i = 0;
+ break;
+
+ case ODOT:
+ case OELEM:
+ print(" \"%F\"", n);
+ break;
+
+ case OCONST:
+ if(typefd[n->type->etype])
+ print(" \"%.8e\"", n->fconst);
+ else
+ print(" \"%lld\"", n->vconst);
+ i = 0;
+ break;
+ }
+ if(n->addable != 0)
+ print(" <%d>", n->addable);
+ if(n->type != T)
+ print(" %T", n->type);
+ if(n->complex != 0)
+ print(" (%d)", n->complex);
+ print(" %L\n", n->lineno);
+ if(i & 2)
+ prtree1(n->left, d, 1);
+ if(i & 1)
+ prtree1(n->right, d, 1);
+}
+
+Type*
+typ(int et, Type *d)
+{
+ Type *t;
+
+ t = alloc(sizeof(*t));
+ t->etype = et;
+ t->link = d;
+ t->down = T;
+ t->sym = S;
+ t->width = ewidth[et];
+ t->offset = 0;
+ t->shift = 0;
+ t->nbits = 0;
+ t->garb = 0;
+ return t;
+}
+
+Type*
+copytyp(Type *t)
+{
+ Type *nt;
+
+ nt = typ(TXXX, T);
+ *nt = *t;
+ return nt;
+}
+
+Type*
+garbt(Type *t, long b)
+{
+ Type *t1;
+
+ if(b & BGARB) {
+ t1 = copytyp(t);
+ t1->garb = simpleg(b);
+ return t1;
+ }
+ return t;
+}
+
+int
+simpleg(long b)
+{
+
+ b &= BGARB;
+ switch(b) {
+ case BCONSTNT:
+ return GCONSTNT;
+ case BVOLATILE:
+ return GVOLATILE;
+ case BVOLATILE|BCONSTNT:
+ return GCONSTNT|GVOLATILE;
+ }
+ return GXXX;
+}
+
+int
+simplec(long b)
+{
+
+ b &= BCLASS;
+ switch(b) {
+ case 0:
+ case BREGISTER:
+ return CXXX;
+ case BAUTO:
+ case BAUTO|BREGISTER:
+ return CAUTO;
+ case BEXTERN:
+ return CEXTERN;
+ case BEXTERN|BREGISTER:
+ return CEXREG;
+ case BSTATIC:
+ return CSTATIC;
+ case BTYPEDEF:
+ return CTYPEDEF;
+ case BTYPESTR:
+ return CTYPESTR;
+ }
+ diag(Z, "illegal combination of classes %Q", b);
+ return CXXX;
+}
+
+Type*
+simplet(long b)
+{
+
+ b &= ~BCLASS & ~BGARB;
+ switch(b) {
+ case BCHAR:
+ case BCHAR|BSIGNED:
+ return types[TCHAR];
+
+ case BCHAR|BUNSIGNED:
+ return types[TUCHAR];
+
+ case BSHORT:
+ case BSHORT|BINT:
+ case BSHORT|BSIGNED:
+ case BSHORT|BINT|BSIGNED:
+ return types[TSHORT];
+
+ case BUNSIGNED|BSHORT:
+ case BUNSIGNED|BSHORT|BINT:
+ return types[TUSHORT];
+
+ case 0:
+ case BINT:
+ case BINT|BSIGNED:
+ case BSIGNED:
+ return types[TINT];
+
+ case BUNSIGNED:
+ case BUNSIGNED|BINT:
+ return types[TUINT];
+
+ case BLONG:
+ case BLONG|BINT:
+ case BLONG|BSIGNED:
+ case BLONG|BINT|BSIGNED:
+ return types[TLONG];
+
+ case BUNSIGNED|BLONG:
+ case BUNSIGNED|BLONG|BINT:
+ return types[TULONG];
+
+ case BVLONG|BLONG:
+ case BVLONG|BLONG|BINT:
+ case BVLONG|BLONG|BSIGNED:
+ case BVLONG|BLONG|BINT|BSIGNED:
+ return types[TVLONG];
+
+ case BVLONG|BLONG|BUNSIGNED:
+ case BVLONG|BLONG|BINT|BUNSIGNED:
+ return types[TUVLONG];
+
+ case BFLOAT:
+ return types[TFLOAT];
+
+ case BDOUBLE:
+ case BDOUBLE|BLONG:
+ case BFLOAT|BLONG:
+ return types[TDOUBLE];
+
+ case BVOID:
+ return types[TVOID];
+ }
+
+ diag(Z, "illegal combination of types %Q", b);
+ return types[TINT];
+}
+
+int
+stcompat(Node *n, Type *t1, Type *t2, long ttab[])
+{
+ int i;
+ ulong b;
+
+ i = 0;
+ if(t2 != T)
+ i = t2->etype;
+ b = 1L << i;
+ i = 0;
+ if(t1 != T)
+ i = t1->etype;
+ if(b & ttab[i]) {
+ if(ttab == tasign)
+ if(b == BSTRUCT || b == BUNION)
+ if(!sametype(t1, t2))
+ return 1;
+ if(n->op != OCAST)
+ if(b == BIND && i == TIND)
+ if(!sametype(t1, t2))
+ return 1;
+ return 0;
+ }
+ return 1;
+}
+
+int
+tcompat(Node *n, Type *t1, Type *t2, long ttab[])
+{
+
+ if(stcompat(n, t1, t2, ttab)) {
+ if(t1 == T)
+ diag(n, "incompatible type: \"%T\" for op \"%O\"",
+ t2, n->op);
+ else
+ diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"",
+ t1, t2, n->op);
+ return 1;
+ }
+ return 0;
+}
+
+void
+makedot(Node *n, Type *t, long o)
+{
+ Node *n1, *n2;
+
+ if(t->nbits) {
+ n1 = new(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = OBIT;
+ n->left = n1;
+ n->right = Z;
+ n->type = t;
+ n->addable = n1->left->addable;
+ n = n1;
+ }
+ n->addable = n->left->addable;
+ if(n->addable == 0) {
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = o;
+ n1->type = types[TLONG];
+ n->right = n1;
+ n->type = t;
+ return;
+ }
+ n->left->type = t;
+ if(o == 0) {
+ *n = *n->left;
+ return;
+ }
+ n->type = t;
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = o;
+ t = typ(TIND, t);
+ t->width = types[TIND]->width;
+ n1->type = t;
+
+ n2 = new1(OADDR, n->left, Z);
+ n2->type = t;
+
+ n1 = new1(OADD, n1, n2);
+ n1->type = t;
+
+ n->op = OIND;
+ n->left = n1;
+ n->right = Z;
+}
+
+Type*
+dotsearch(Sym *s, Type *t, Node *n, long *off)
+{
+ Type *t1, *xt, *rt;
+
+ xt = T;
+
+ /*
+ * look it up by name
+ */
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == s) {
+ if(xt != T)
+ goto ambig;
+ xt = t1;
+ }
+
+ /*
+ * look it up by type
+ */
+ if(s->class == CTYPEDEF || s->class == CTYPESTR)
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == S && typesu[t1->etype])
+ if(sametype(s->type, t1)) {
+ if(xt != T)
+ goto ambig;
+ xt = t1;
+ }
+ if(xt != T) {
+ *off = xt->offset;
+ return xt;
+ }
+
+ /*
+ * look it up in unnamed substructures
+ */
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == S && typesu[t1->etype]){
+ rt = dotsearch(s, t1->link, n, off);
+ if(rt != T) {
+ if(xt != T)
+ goto ambig;
+ xt = rt;
+ *off += t1->offset;
+ }
+ }
+ return xt;
+
+ambig:
+ diag(n, "ambiguous structure element: %s", s->name);
+ return xt;
+}
+
+long
+dotoffset(Type *st, Type *lt, Node *n)
+{
+ Type *t;
+ Sym *g;
+ long o, o1;
+
+ o = -1;
+ /*
+ * first try matching at the top level
+ * for matching tag names
+ */
+ g = st->tag;
+ if(g != S)
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(g == t->tag) {
+ if(o >= 0)
+ goto ambig;
+ o = t->offset;
+ }
+ if(o >= 0)
+ return o;
+
+ /*
+ * second try matching at the top level
+ * for similar types
+ */
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(sametype(st, t)) {
+ if(o >= 0)
+ goto ambig;
+ o = t->offset;
+ }
+ if(o >= 0)
+ return o;
+
+ /*
+ * last try matching sub-levels
+ */
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(typesu[t->etype]) {
+ o1 = dotoffset(st, t, n);
+ if(o1 >= 0) {
+ if(o >= 0)
+ goto ambig;
+ o = o1 + t->offset;
+ }
+ }
+ return o;
+
+ambig:
+ diag(n, "ambiguous unnamed structure element");
+ return o;
+}
+
+/*
+ * look into tree for floating point constant expressions
+ */
+int
+allfloat(Node *n, int flag)
+{
+
+ if(n != Z) {
+ if(n->type->etype != TDOUBLE)
+ return 1;
+ switch(n->op) {
+ case OCONST:
+ if(flag)
+ n->type = types[TFLOAT];
+ return 1;
+ case OADD: /* no need to get more exotic than this */
+ case OSUB:
+ case OMUL:
+ case ODIV:
+ if(!allfloat(n->right, flag))
+ break;
+ case OCAST:
+ if(!allfloat(n->left, flag))
+ break;
+ if(flag)
+ n->type = types[TFLOAT];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+constas(Node *n, Type *il, Type *ir)
+{
+ Type *l, *r;
+
+ l = il;
+ r = ir;
+
+ if(l == T)
+ return;
+ if(l->garb & GCONSTNT) {
+ warn(n, "assignment to a constant type (%T)", il);
+ return;
+ }
+ if(r == T)
+ return;
+ for(;;) {
+ if(l->etype != TIND || r->etype != TIND)
+ break;
+ l = l->link;
+ r = r->link;
+ if(l == T || r == T)
+ break;
+ if(r->garb & GCONSTNT)
+ if(!(l->garb & GCONSTNT)) {
+ warn(n, "assignment of a constant pointer type (%T)", ir);
+ break;
+ }
+ }
+}
+
+void
+typeext1(Type *st, Node *l)
+{
+ if(st->etype == TFLOAT && allfloat(l, 0))
+ allfloat(l, 1);
+}
+
+void
+typeext(Type *st, Node *l)
+{
+ Type *lt;
+ Node *n1, *n2;
+ long o;
+
+ lt = l->type;
+ if(lt == T)
+ return;
+ if(st->etype == TIND && vconst(l) == 0) {
+ l->type = st;
+ l->vconst = 0;
+ return;
+ }
+ typeext1(st, l);
+
+ /*
+ * extension of C
+ * if assign of struct containing unnamed sub-struct
+ * to type of sub-struct, insert the DOT.
+ * if assign of *struct containing unnamed substruct
+ * to type of *sub-struct, insert the add-offset
+ */
+ if(typesu[st->etype] && typesu[lt->etype]) {
+ o = dotoffset(st, lt, l);
+ if(o >= 0) {
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *l;
+ l->op = ODOT;
+ l->left = n1;
+ l->right = Z;
+ makedot(l, st, o);
+ }
+ return;
+ }
+ if(st->etype == TIND && typesu[st->link->etype])
+ if(lt->etype == TIND && typesu[lt->link->etype]) {
+ o = dotoffset(st->link, lt->link, l);
+ if(o >= 0) {
+ l->type = st;
+ if(o == 0)
+ return;
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *l;
+ n2 = new1(OCONST, Z, Z);
+ n2->vconst = o;
+ n2->type = st;
+ l->op = OADD;
+ l->left = n1;
+ l->right = n2;
+ }
+ return;
+ }
+}
+
+/*
+ * a cast that generates no code
+ * (same size move)
+ */
+int
+nocast(Type *t1, Type *t2)
+{
+ int i, b;
+
+ if(t1->nbits)
+ return 0;
+ i = 0;
+ if(t2 != T)
+ i = t2->etype;
+ b = 1<<i;
+ i = 0;
+ if(t1 != T)
+ i = t1->etype;
+ if(b & ncast[i])
+ return 1;
+ return 0;
+}
+
+/*
+ * a cast that has a noop semantic
+ * (small to large, convert)
+ */
+int
+nilcast(Type *t1, Type *t2)
+{
+ int et1, et2;
+
+ if(t1 == T)
+ return 0;
+ if(t1->nbits)
+ return 0;
+ if(t2 == T)
+ return 0;
+ et1 = t1->etype;
+ et2 = t2->etype;
+ if(et1 == et2)
+ return 1;
+ if(typefd[et1] && typefd[et2]) {
+ if(ewidth[et1] < ewidth[et2])
+ return 1;
+ return 0;
+ }
+ if(typechlp[et1] && typechlp[et2]) {
+ if(ewidth[et1] < ewidth[et2])
+ return 1;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * "the usual arithmetic conversions are performed"
+ */
+void
+arith(Node *n, int f)
+{
+ Type *t1, *t2;
+ int i, j, k;
+ Node *n1;
+ long w;
+
+ t1 = n->left->type;
+ if(n->right == Z)
+ t2 = t1;
+ else
+ t2 = n->right->type;
+ i = TXXX;
+ if(t1 != T)
+ i = t1->etype;
+ j = TXXX;
+ if(t2 != T)
+ j = t2->etype;
+ k = tab[i][j];
+ if(k == TIND) {
+ if(i == TIND)
+ n->type = t1;
+ else
+ if(j == TIND)
+ n->type = t2;
+ } else {
+ /* convert up to at least int */
+ if(f == 1)
+ while(k < TINT)
+ k += 2;
+ n->type = types[k];
+ }
+ if(n->op == OSUB)
+ if(i == TIND && j == TIND) {
+ w = n->right->type->link->width;
+ if(w < 1 || n->left->type->link == T || n->left->type->link->width < 1)
+ goto bad;
+ n->type = types[ewidth[TIND] <= ewidth[TLONG]? TLONG: TVLONG];
+ if(1 && ewidth[TIND] > ewidth[TLONG]){
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = OCAST;
+ n->left = n1;
+ n->right = Z;
+ n->type = types[TLONG];
+ }
+ if(w > 1) {
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = ODIV;
+ n->left = n1;
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = w;
+ n1->type = n->type;
+ n->right = n1;
+ w = vlog(n1);
+ if(w >= 0) {
+ n->op = OASHR;
+ n1->vconst = w;
+ }
+ }
+ return;
+ }
+ if(!sametype(n->type, n->left->type)) {
+ n->left = new1(OCAST, n->left, Z);
+ n->left->type = n->type;
+ if(n->type->etype == TIND) {
+ w = n->type->link->width;
+ if(w < 1) {
+ snap(n->type->link);
+ w = n->type->link->width;
+ if(w < 1)
+ goto bad;
+ }
+ if(w > 1) {
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = w;
+ n1->type = n->type;
+ n->left = new1(OMUL, n->left, n1);
+ n->left->type = n->type;
+ }
+ }
+ }
+ if(n->right != Z)
+ if(!sametype(n->type, n->right->type)) {
+ n->right = new1(OCAST, n->right, Z);
+ n->right->type = n->type;
+ if(n->type->etype == TIND) {
+ w = n->type->link->width;
+ if(w < 1) {
+ snap(n->type->link);
+ w = n->type->link->width;
+ if(w < 1)
+ goto bad;
+ }
+ if(w != 1) {
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = w;
+ n1->type = n->type;
+ n->right = new1(OMUL, n->right, n1);
+ n->right->type = n->type;
+ }
+ }
+ }
+ return;
+bad:
+ diag(n, "pointer addition not fully declared: %T", n->type->link);
+}
+
+/*
+ * try to rewrite shift & mask
+ */
+void
+simplifyshift(Node *n)
+{
+ ulong c3;
+ int o, s1, s2, c1, c2;
+
+ if(!typechlp[n->type->etype])
+ return;
+ switch(n->op) {
+ default:
+ return;
+ case OASHL:
+ s1 = 0;
+ break;
+ case OLSHR:
+ s1 = 1;
+ break;
+ case OASHR:
+ s1 = 2;
+ break;
+ }
+ if(n->right->op != OCONST)
+ return;
+ if(n->left->op != OAND)
+ return;
+ if(n->left->right->op != OCONST)
+ return;
+ switch(n->left->left->op) {
+ default:
+ return;
+ case OASHL:
+ s2 = 0;
+ break;
+ case OLSHR:
+ s2 = 1;
+ break;
+ case OASHR:
+ s2 = 2;
+ break;
+ }
+ if(n->left->left->right->op != OCONST)
+ return;
+
+ c1 = n->right->vconst;
+ c2 = n->left->left->right->vconst;
+ c3 = n->left->right->vconst;
+
+/*
+ if(debug['h'])
+ print("%.3o %ld %ld %d #%.lux\n",
+ (s1<<3)|s2, c1, c2, topbit(c3), c3);
+*/
+
+ o = n->op;
+ switch((s1<<3)|s2) {
+ case 000: /* (((e <<u c2) & c3) <<u c1) */
+ c3 >>= c2;
+ c1 += c2;
+ if(c1 >= 32)
+ break;
+ goto rewrite1;
+
+ case 002: /* (((e >>s c2) & c3) <<u c1) */
+ if(topbit(c3) >= (32-c2))
+ break;
+ case 001: /* (((e >>u c2) & c3) <<u c1) */
+ if(c1 > c2) {
+ c3 <<= c2;
+ c1 -= c2;
+ o = OASHL;
+ goto rewrite1;
+ }
+ c3 <<= c1;
+ if(c1 == c2)
+ goto rewrite0;
+ c1 = c2-c1;
+ o = OLSHR;
+ goto rewrite2;
+
+ case 022: /* (((e >>s c2) & c3) >>s c1) */
+ if(c2 <= 0)
+ break;
+ case 012: /* (((e >>s c2) & c3) >>u c1) */
+ if(topbit(c3) >= (32-c2))
+ break;
+ goto s11;
+ case 021: /* (((e >>u c2) & c3) >>s c1) */
+ if(topbit(c3) >= 31 && c2 <= 0)
+ break;
+ goto s11;
+ case 011: /* (((e >>u c2) & c3) >>u c1) */
+ s11:
+ c3 <<= c2;
+ c1 += c2;
+ if(c1 >= 32)
+ break;
+ o = OLSHR;
+ goto rewrite1;
+
+ case 020: /* (((e <<u c2) & c3) >>s c1) */
+ if(topbit(c3) >= 31)
+ break;
+ case 010: /* (((e <<u c2) & c3) >>u c1) */
+ c3 >>= c1;
+ if(c1 == c2)
+ goto rewrite0;
+ if(c1 > c2) {
+ c1 -= c2;
+ goto rewrite2;
+ }
+ c1 = c2 - c1;
+ o = OASHL;
+ goto rewrite2;
+ }
+ return;
+
+rewrite0: /* get rid of both shifts */
+if(debug['<'])prtree(n, "rewrite0");
+ *n = *n->left;
+ n->left = n->left->left;
+ n->right->vconst = c3;
+ return;
+rewrite1: /* get rid of lower shift */
+if(debug['<'])prtree(n, "rewrite1");
+ n->left->left = n->left->left->left;
+ n->left->right->vconst = c3;
+ n->right->vconst = c1;
+ n->op = o;
+ return;
+rewrite2: /* get rid of upper shift */
+if(debug['<'])prtree(n, "rewrite2");
+ *n = *n->left;
+ n->right->vconst = c3;
+ n->left->right->vconst = c1;
+ n->left->op = o;
+}
+
+int
+side(Node *n)
+{
+
+loop:
+ if(n != Z)
+ switch(n->op) {
+ case OCAST:
+ case ONOT:
+ case OADDR:
+ case OIND:
+ n = n->left;
+ goto loop;
+
+ case OCOND:
+ if(side(n->left))
+ break;
+ n = n->right;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLE:
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case OLMUL:
+ case ODIV:
+ case OLDIV:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OMOD:
+ case OLMOD:
+ case OANDAND:
+ case OOROR:
+ case OCOMMA:
+ case ODOT:
+ if(side(n->left))
+ break;
+ n = n->right;
+ goto loop;
+
+ case OSIGN:
+ case OSIZE:
+ case OCONST:
+ case OSTRING:
+ case OLSTRING:
+ case ONAME:
+ return 0;
+ }
+ return 1;
+}
+
+int
+vconst(Node *n)
+{
+ int i;
+
+ if(n == Z)
+ goto no;
+ if(n->op != OCONST)
+ goto no;
+ if(n->type == T)
+ goto no;
+ switch(n->type->etype)
+ {
+ case TFLOAT:
+ case TDOUBLE:
+ i = 100;
+ if(n->fconst > i || n->fconst < -i)
+ goto no;
+ i = n->fconst;
+ if(i != n->fconst)
+ goto no;
+ return i;
+
+ case TVLONG:
+ case TUVLONG:
+ i = n->vconst;
+ if(i != n->vconst)
+ goto no;
+ return i;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ i = n->vconst;
+ if(i != n->vconst)
+ goto no;
+ return i;
+ }
+no:
+ return -159; /* first uninteresting constant */
+}
+
+/*
+ * return log(n) if n is a power of 2 constant
+ */
+int
+xlog2(uvlong v)
+{
+ int s, i;
+ uvlong m;
+
+ s = 0;
+ m = MASK(8*sizeof(uvlong));
+ for(i=32; i; i>>=1) {
+ m >>= i;
+ if(!(v & m)) {
+ v >>= i;
+ s += i;
+ }
+ }
+ if(v == 1)
+ return s;
+ return -1;
+}
+
+int
+vlog(Node *n)
+{
+ if(n->op != OCONST)
+ goto bad;
+ if(typefd[n->type->etype])
+ goto bad;
+
+ return xlog2(n->vconst);
+
+bad:
+ return -1;
+}
+
+int
+topbit(ulong v)
+{
+ int i;
+
+ for(i = -1; v; i++)
+ v >>= 1;
+ return i;
+}
+
+/*
+ * try to cast a constant down
+ * rather than cast a variable up
+ * example:
+ * if(c == 'a')
+ */
+void
+relcon(Node *l, Node *r)
+{
+ vlong v;
+
+ if(l->op != OCONST)
+ return;
+ if(r->op != OCAST)
+ return;
+ if(!nilcast(r->left->type, r->type))
+ return;
+ switch(r->type->etype) {
+ default:
+ return;
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ v = convvtox(l->vconst, r->type->etype);
+ if(v != l->vconst)
+ return;
+ break;
+ }
+ l->type = r->left->type;
+ *r = *r->left;
+}
+
+int
+relindex(int o)
+{
+
+ switch(o) {
+ default:
+ diag(Z, "bad in relindex: %O", o);
+ case OEQ: return 0;
+ case ONE: return 1;
+ case OLE: return 2;
+ case OLS: return 3;
+ case OLT: return 4;
+ case OLO: return 5;
+ case OGE: return 6;
+ case OHS: return 7;
+ case OGT: return 8;
+ case OHI: return 9;
+ }
+}
+
+Node*
+invert(Node *n)
+{
+ Node *i;
+
+ if(n == Z || n->op != OLIST)
+ return n;
+ i = n;
+ for(n = n->left; n != Z; n = n->left) {
+ if(n->op != OLIST)
+ break;
+ i->left = n->right;
+ n->right = i;
+ i = n;
+ }
+ i->left = n;
+ return i;
+}
+
+int
+bitno(long b)
+{
+ int i;
+
+ for(i=0; i<32; i++)
+ if(b & (1L<<i))
+ return i;
+ diag(Z, "bad in bitno");
+ return 0;
+}
+
+long
+typebitor(long a, long b)
+{
+ long c;
+
+ c = a | b;
+ if(a & b)
+ if((a & b) == BLONG)
+ c |= BVLONG; /* long long => vlong */
+ else
+ warn(Z, "once is enough: %Q", a & b);
+ return c;
+}
+
+void
+diag(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(debug['X']){
+ Bflush(&diagbuf);
+ abort();
+ }
+ if(n != Z)
+ if(debug['v'])
+ prtree(n, "diagnostic");
+
+ nerrors++;
+ if(nerrors > 10) {
+ Bprint(&diagbuf, "too many errors\n");
+ errorexit();
+ }
+}
+
+void
+warn(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ if(debug['w']) {
+ Bprint(&diagbuf, "warning: ");
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(n != Z)
+ if(debug['v'])
+ prtree(n, "warning");
+ }
+}
+
+void
+yyerror(char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ /*
+ * hack to intercept message from yaccpar
+ */
+ if(strcmp(fmt, "syntax error") == 0) {
+ yyerror("syntax error, last name: %s", symb);
+ return;
+ }
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", lineno, buf);
+ nerrors++;
+ if(nerrors > 10) {
+ Bprint(&diagbuf, "too many errors\n");
+ errorexit();
+ }
+}
+
+void
+fatal(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(debug['X']){
+ Bflush(&diagbuf);
+ abort();
+ }
+ if(n != Z)
+ if(debug['v'])
+ prtree(n, "diagnostic");
+
+ nerrors++;
+ errorexit();
+}
+
+ulong thash1 = 0x2edab8c9;
+ulong thash2 = 0x1dc74fb8;
+ulong thash3 = 0x1f241331;
+ulong thash[NALLTYPES];
+Init thashinit[] =
+{
+ TXXX, 0x17527bbd, 0,
+ TCHAR, 0x5cedd32b, 0,
+ TUCHAR, 0x552c4454, 0,
+ TSHORT, 0x63040b4b, 0,
+ TUSHORT, 0x32a45878, 0,
+ TINT, 0x4151d5bd, 0,
+ TUINT, 0x5ae707d6, 0,
+ TLONG, 0x5ef20f47, 0,
+ TULONG, 0x36d8eb8f, 0,
+ TVLONG, 0x6e5e9590, 0,
+ TUVLONG, 0x75910105, 0,
+ TFLOAT, 0x25fd7af1, 0,
+ TDOUBLE, 0x7c40a1b2, 0,
+ TIND, 0x1b832357, 0,
+ TFUNC, 0x6babc9cb, 0,
+ TARRAY, 0x7c50986d, 0,
+ TVOID, 0x44112eff, 0,
+ TSTRUCT, 0x7c2da3bf, 0,
+ TUNION, 0x3eb25e98, 0,
+ TENUM, 0x44b54f61, 0,
+ TFILE, 0x19242ac3, 0,
+ TOLD, 0x22b15988, 0,
+ TDOT, 0x0204f6b3, 0,
+ -1, 0, 0,
+};
+
+char* bnames[NALIGN];
+Init bnamesinit[] =
+{
+ Axxx, 0, "Axxx",
+ Ael1, 0, "el1",
+ Ael2, 0, "el2",
+ Asu2, 0, "su2",
+ Aarg0, 0, "arg0",
+ Aarg1, 0, "arg1",
+ Aarg2, 0, "arg2",
+ Aaut3, 0, "aut3",
+ -1, 0, 0,
+};
+
+char* tnames[NALLTYPES];
+Init tnamesinit[] =
+{
+ TXXX, 0, "TXXX",
+ TCHAR, 0, "CHAR",
+ TUCHAR, 0, "UCHAR",
+ TSHORT, 0, "SHORT",
+ TUSHORT, 0, "USHORT",
+ TINT, 0, "INT",
+ TUINT, 0, "UINT",
+ TLONG, 0, "LONG",
+ TULONG, 0, "ULONG",
+ TVLONG, 0, "VLONG",
+ TUVLONG, 0, "UVLONG",
+ TFLOAT, 0, "FLOAT",
+ TDOUBLE, 0, "DOUBLE",
+ TIND, 0, "IND",
+ TFUNC, 0, "FUNC",
+ TARRAY, 0, "ARRAY",
+ TVOID, 0, "VOID",
+ TSTRUCT, 0, "STRUCT",
+ TUNION, 0, "UNION",
+ TENUM, 0, "ENUM",
+ TFILE, 0, "FILE",
+ TOLD, 0, "OLD",
+ TDOT, 0, "DOT",
+ -1, 0, 0,
+};
+
+char* gnames[NGTYPES];
+Init gnamesinit[] =
+{
+ GXXX, 0, "GXXX",
+ GCONSTNT, 0, "CONST",
+ GVOLATILE, 0, "VOLATILE",
+ GVOLATILE|GCONSTNT, 0, "CONST-VOLATILE",
+ -1, 0, 0,
+};
+
+char* qnames[NALLTYPES];
+Init qnamesinit[] =
+{
+ TXXX, 0, "TXXX",
+ TCHAR, 0, "CHAR",
+ TUCHAR, 0, "UCHAR",
+ TSHORT, 0, "SHORT",
+ TUSHORT, 0, "USHORT",
+ TINT, 0, "INT",
+ TUINT, 0, "UINT",
+ TLONG, 0, "LONG",
+ TULONG, 0, "ULONG",
+ TVLONG, 0, "VLONG",
+ TUVLONG, 0, "UVLONG",
+ TFLOAT, 0, "FLOAT",
+ TDOUBLE, 0, "DOUBLE",
+ TIND, 0, "IND",
+ TFUNC, 0, "FUNC",
+ TARRAY, 0, "ARRAY",
+ TVOID, 0, "VOID",
+ TSTRUCT, 0, "STRUCT",
+ TUNION, 0, "UNION",
+ TENUM, 0, "ENUM",
+
+ TAUTO, 0, "AUTO",
+ TEXTERN, 0, "EXTERN",
+ TSTATIC, 0, "STATIC",
+ TTYPEDEF, 0, "TYPEDEF",
+ TTYPESTR, 0, "TYPESTR",
+ TREGISTER, 0, "REGISTER",
+ TCONSTNT, 0, "CONSTNT",
+ TVOLATILE, 0, "VOLATILE",
+ TUNSIGNED, 0, "UNSIGNED",
+ TSIGNED, 0, "SIGNED",
+ TDOT, 0, "DOT",
+ TFILE, 0, "FILE",
+ TOLD, 0, "OLD",
+ -1, 0, 0,
+};
+char* cnames[NCTYPES];
+Init cnamesinit[] =
+{
+ CXXX, 0, "CXXX",
+ CAUTO, 0, "AUTO",
+ CEXTERN, 0, "EXTERN",
+ CGLOBL, 0, "GLOBL",
+ CSTATIC, 0, "STATIC",
+ CLOCAL, 0, "LOCAL",
+ CTYPEDEF, 0, "TYPEDEF",
+ CTYPESTR, 0, "TYPESTR",
+ CPARAM, 0, "PARAM",
+ CSELEM, 0, "SELEM",
+ CLABEL, 0, "LABEL",
+ CEXREG, 0, "EXREG",
+ -1, 0, 0,
+};
+
+char* onames[OEND+1];
+Init onamesinit[] =
+{
+ OXXX, 0, "OXXX",
+ OADD, 0, "ADD",
+ OADDR, 0, "ADDR",
+ OAND, 0, "AND",
+ OANDAND, 0, "ANDAND",
+ OARRAY, 0, "ARRAY",
+ OAS, 0, "AS",
+ OASI, 0, "ASI",
+ OASADD, 0, "ASADD",
+ OASAND, 0, "ASAND",
+ OASASHL, 0, "ASASHL",
+ OASASHR, 0, "ASASHR",
+ OASDIV, 0, "ASDIV",
+ OASHL, 0, "ASHL",
+ OASHR, 0, "ASHR",
+ OASLDIV, 0, "ASLDIV",
+ OASLMOD, 0, "ASLMOD",
+ OASLMUL, 0, "ASLMUL",
+ OASLSHR, 0, "ASLSHR",
+ OASMOD, 0, "ASMOD",
+ OASMUL, 0, "ASMUL",
+ OASOR, 0, "ASOR",
+ OASSUB, 0, "ASSUB",
+ OASXOR, 0, "ASXOR",
+ OBIT, 0, "BIT",
+ OBREAK, 0, "BREAK",
+ OCASE, 0, "CASE",
+ OCAST, 0, "CAST",
+ OCOMMA, 0, "COMMA",
+ OCOND, 0, "COND",
+ OCONST, 0, "CONST",
+ OCONTINUE, 0, "CONTINUE",
+ ODIV, 0, "DIV",
+ ODOT, 0, "DOT",
+ ODOTDOT, 0, "DOTDOT",
+ ODWHILE, 0, "DWHILE",
+ OENUM, 0, "ENUM",
+ OEQ, 0, "EQ",
+ OFOR, 0, "FOR",
+ OFUNC, 0, "FUNC",
+ OGE, 0, "GE",
+ OGOTO, 0, "GOTO",
+ OGT, 0, "GT",
+ OHI, 0, "HI",
+ OHS, 0, "HS",
+ OIF, 0, "IF",
+ OIND, 0, "IND",
+ OINDREG, 0, "INDREG",
+ OINIT, 0, "INIT",
+ OLABEL, 0, "LABEL",
+ OLDIV, 0, "LDIV",
+ OLE, 0, "LE",
+ OLIST, 0, "LIST",
+ OLMOD, 0, "LMOD",
+ OLMUL, 0, "LMUL",
+ OLO, 0, "LO",
+ OLS, 0, "LS",
+ OLSHR, 0, "LSHR",
+ OLT, 0, "LT",
+ OMOD, 0, "MOD",
+ OMUL, 0, "MUL",
+ ONAME, 0, "NAME",
+ ONE, 0, "NE",
+ ONOT, 0, "NOT",
+ OOR, 0, "OR",
+ OOROR, 0, "OROR",
+ OPOSTDEC, 0, "POSTDEC",
+ OPOSTINC, 0, "POSTINC",
+ OPREDEC, 0, "PREDEC",
+ OPREINC, 0, "PREINC",
+ OPROTO, 0, "PROTO",
+ OREGISTER, 0, "REGISTER",
+ ORETURN, 0, "RETURN",
+ OSET, 0, "SET",
+ OSIGN, 0, "SIGN",
+ OSIZE, 0, "SIZE",
+ OSTRING, 0, "STRING",
+ OLSTRING, 0, "LSTRING",
+ OSTRUCT, 0, "STRUCT",
+ OSUB, 0, "SUB",
+ OSWITCH, 0, "SWITCH",
+ OUNION, 0, "UNION",
+ OUSED, 0, "USED",
+ OWHILE, 0, "WHILE",
+ OXOR, 0, "XOR",
+ OPOS, 0, "POS",
+ ONEG, 0, "NEG",
+ OCOM, 0, "COM",
+ OELEM, 0, "ELEM",
+ OTST, 0, "TST",
+ OINDEX, 0, "INDEX",
+ OFAS, 0, "FAS",
+ OREGPAIR, 0, "REGPAIR",
+ OEND, 0, "END",
+ -1, 0, 0,
+};
+
+/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
+uchar comrel[12] =
+{
+ ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS,
+};
+uchar invrel[12] =
+{
+ OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO,
+};
+uchar logrel[12] =
+{
+ OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI,
+};
+
+uchar typei[NTYPE];
+int typeiinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1,
+};
+uchar typeu[NTYPE];
+int typeuinit[] =
+{
+ TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1,
+};
+
+uchar typesuv[NTYPE];
+int typesuvinit[] =
+{
+ TVLONG, TUVLONG, TSTRUCT, TUNION, -1,
+};
+
+uchar typeilp[NTYPE];
+int typeilpinit[] =
+{
+ TINT, TUINT, TLONG, TULONG, TIND, -1
+};
+
+uchar typechl[NTYPE];
+uchar typechlv[NTYPE];
+uchar typechlvp[NTYPE];
+int typechlinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1,
+};
+
+uchar typechlp[NTYPE];
+int typechlpinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1,
+};
+
+uchar typechlpfd[NTYPE];
+int typechlpfdinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1,
+};
+
+uchar typec[NTYPE];
+int typecinit[] =
+{
+ TCHAR, TUCHAR, -1
+};
+
+uchar typeh[NTYPE];
+int typehinit[] =
+{
+ TSHORT, TUSHORT, -1,
+};
+
+uchar typeil[NTYPE];
+int typeilinit[] =
+{
+ TINT, TUINT, TLONG, TULONG, -1,
+};
+
+uchar typev[NTYPE];
+int typevinit[] =
+{
+ TVLONG, TUVLONG, -1,
+};
+
+uchar typefd[NTYPE];
+int typefdinit[] =
+{
+ TFLOAT, TDOUBLE, -1,
+};
+
+uchar typeaf[NTYPE];
+int typeafinit[] =
+{
+ TFUNC, TARRAY, -1,
+};
+
+uchar typesu[NTYPE];
+int typesuinit[] =
+{
+ TSTRUCT, TUNION, -1,
+};
+
+long tasign[NTYPE];
+Init tasigninit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BIND, 0,
+ TSTRUCT, BSTRUCT, 0,
+ TUNION, BUNION, 0,
+ -1, 0, 0,
+};
+
+long tasadd[NTYPE];
+Init tasaddinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+long tcast[NTYPE];
+Init tcastinit[] =
+{
+ TCHAR, BNUMBER|BIND|BVOID, 0,
+ TUCHAR, BNUMBER|BIND|BVOID, 0,
+ TSHORT, BNUMBER|BIND|BVOID, 0,
+ TUSHORT, BNUMBER|BIND|BVOID, 0,
+ TINT, BNUMBER|BIND|BVOID, 0,
+ TUINT, BNUMBER|BIND|BVOID, 0,
+ TLONG, BNUMBER|BIND|BVOID, 0,
+ TULONG, BNUMBER|BIND|BVOID, 0,
+ TVLONG, BNUMBER|BIND|BVOID, 0,
+ TUVLONG, BNUMBER|BIND|BVOID, 0,
+ TFLOAT, BNUMBER|BVOID, 0,
+ TDOUBLE, BNUMBER|BVOID, 0,
+ TIND, BINTEGER|BIND|BVOID, 0,
+ TVOID, BVOID, 0,
+ TSTRUCT, BSTRUCT|BVOID, 0,
+ TUNION, BUNION|BVOID, 0,
+ -1, 0, 0,
+};
+
+long tadd[NTYPE];
+Init taddinit[] =
+{
+ TCHAR, BNUMBER|BIND, 0,
+ TUCHAR, BNUMBER|BIND, 0,
+ TSHORT, BNUMBER|BIND, 0,
+ TUSHORT, BNUMBER|BIND, 0,
+ TINT, BNUMBER|BIND, 0,
+ TUINT, BNUMBER|BIND, 0,
+ TLONG, BNUMBER|BIND, 0,
+ TULONG, BNUMBER|BIND, 0,
+ TVLONG, BNUMBER|BIND, 0,
+ TUVLONG, BNUMBER|BIND, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+long tsub[NTYPE];
+Init tsubinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER|BIND, 0,
+ -1, 0, 0,
+};
+
+long tmul[NTYPE];
+Init tmulinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ -1, 0, 0,
+};
+
+long tand[NTYPE];
+Init tandinit[] =
+{
+ TCHAR, BINTEGER, 0,
+ TUCHAR, BINTEGER, 0,
+ TSHORT, BINTEGER, 0,
+ TUSHORT, BINTEGER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BINTEGER, 0,
+ TULONG, BINTEGER, 0,
+ TVLONG, BINTEGER, 0,
+ TUVLONG, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+long trel[NTYPE];
+Init trelinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BIND, 0,
+ -1, 0, 0,
+};
+
+long tfunct[1] =
+{
+ BFUNC,
+};
+
+long tindir[1] =
+{
+ BIND,
+};
+
+long tdot[1] =
+{
+ BSTRUCT|BUNION,
+};
+
+long tnot[1] =
+{
+ BNUMBER|BIND,
+};
+
+long targ[1] =
+{
+ BNUMBER|BIND|BSTRUCT|BUNION,
+};
+
+uchar tab[NTYPE][NTYPE] =
+{
+/*TXXX*/ { 0,
+ },
+
+/*TCHAR*/ { 0, TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUCHAR*/ { 0, TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TSHORT*/ { 0, TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUSHORT*/ { 0, TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TINT*/ { 0, TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUINT*/ { 0, TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TLONG*/ { 0, TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TULONG*/ { 0, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TVLONG*/ { 0, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG,
+ TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUVLONG*/ { 0, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG,
+ TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TFLOAT*/ { 0, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT,
+ TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND,
+ },
+/*TDOUBLE*/ { 0, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE,
+ TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND,
+ },
+/*TIND*/ { 0, TIND, TIND, TIND, TIND, TIND, TIND, TIND,
+ TIND, TIND, TIND, TIND, TIND, TIND,
+ },
+};
+
+void
+urk(char *name, int max, int i)
+{
+ if(i >= max) {
+ fprint(2, "bad tinit: %s %d>=%d\n", name, i, max);
+ exits("init");
+ }
+}
+
+void
+tinit(void)
+{
+ int *ip;
+ Init *p;
+
+ for(p=thashinit; p->code >= 0; p++) {
+ urk("thash", nelem(thash), p->code);
+ thash[p->code] = p->value;
+ }
+ for(p=bnamesinit; p->code >= 0; p++) {
+ urk("bnames", nelem(bnames), p->code);
+ bnames[p->code] = p->s;
+ }
+ for(p=tnamesinit; p->code >= 0; p++) {
+ urk("tnames", nelem(tnames), p->code);
+ tnames[p->code] = p->s;
+ }
+ for(p=gnamesinit; p->code >= 0; p++) {
+ urk("gnames", nelem(gnames), p->code);
+ gnames[p->code] = p->s;
+ }
+ for(p=qnamesinit; p->code >= 0; p++) {
+ urk("qnames", nelem(qnames), p->code);
+ qnames[p->code] = p->s;
+ }
+ for(p=cnamesinit; p->code >= 0; p++) {
+ urk("cnames", nelem(cnames), p->code);
+ cnames[p->code] = p->s;
+ }
+ for(p=onamesinit; p->code >= 0; p++) {
+ urk("onames", nelem(onames), p->code);
+ onames[p->code] = p->s;
+ }
+ for(ip=typeiinit; *ip>=0; ip++) {
+ urk("typei", nelem(typei), *ip);
+ typei[*ip] = 1;
+ }
+ for(ip=typeuinit; *ip>=0; ip++) {
+ urk("typeu", nelem(typeu), *ip);
+ typeu[*ip] = 1;
+ }
+ for(ip=typesuvinit; *ip>=0; ip++) {
+ urk("typesuv", nelem(typesuv), *ip);
+ typesuv[*ip] = 1;
+ }
+ for(ip=typeilpinit; *ip>=0; ip++) {
+ urk("typeilp", nelem(typeilp), *ip);
+ typeilp[*ip] = 1;
+ }
+ for(ip=typechlinit; *ip>=0; ip++) {
+ urk("typechl", nelem(typechl), *ip);
+ typechl[*ip] = 1;
+ typechlv[*ip] = 1;
+ typechlvp[*ip] = 1;
+ }
+ for(ip=typechlpinit; *ip>=0; ip++) {
+ urk("typechlp", nelem(typechlp), *ip);
+ typechlp[*ip] = 1;
+ typechlvp[*ip] = 1;
+ }
+ for(ip=typechlpfdinit; *ip>=0; ip++) {
+ urk("typechlpfd", nelem(typechlpfd), *ip);
+ typechlpfd[*ip] = 1;
+ }
+ for(ip=typecinit; *ip>=0; ip++) {
+ urk("typec", nelem(typec), *ip);
+ typec[*ip] = 1;
+ }
+ for(ip=typehinit; *ip>=0; ip++) {
+ urk("typeh", nelem(typeh), *ip);
+ typeh[*ip] = 1;
+ }
+ for(ip=typeilinit; *ip>=0; ip++) {
+ urk("typeil", nelem(typeil), *ip);
+ typeil[*ip] = 1;
+ }
+ for(ip=typevinit; *ip>=0; ip++) {
+ urk("typev", nelem(typev), *ip);
+ typev[*ip] = 1;
+ typechlv[*ip] = 1;
+ typechlvp[*ip] = 1;
+ }
+ for(ip=typefdinit; *ip>=0; ip++) {
+ urk("typefd", nelem(typefd), *ip);
+ typefd[*ip] = 1;
+ }
+ for(ip=typeafinit; *ip>=0; ip++) {
+ urk("typeaf", nelem(typeaf), *ip);
+ typeaf[*ip] = 1;
+ }
+ for(ip=typesuinit; *ip >= 0; ip++) {
+ urk("typesu", nelem(typesu), *ip);
+ typesu[*ip] = 1;
+ }
+ for(p=tasigninit; p->code >= 0; p++) {
+ urk("tasign", nelem(tasign), p->code);
+ tasign[p->code] = p->value;
+ }
+ for(p=tasaddinit; p->code >= 0; p++) {
+ urk("tasadd", nelem(tasadd), p->code);
+ tasadd[p->code] = p->value;
+ }
+ for(p=tcastinit; p->code >= 0; p++) {
+ urk("tcast", nelem(tcast), p->code);
+ tcast[p->code] = p->value;
+ }
+ for(p=taddinit; p->code >= 0; p++) {
+ urk("tadd", nelem(tadd), p->code);
+ tadd[p->code] = p->value;
+ }
+ for(p=tsubinit; p->code >= 0; p++) {
+ urk("tsub", nelem(tsub), p->code);
+ tsub[p->code] = p->value;
+ }
+ for(p=tmulinit; p->code >= 0; p++) {
+ urk("tmul", nelem(tmul), p->code);
+ tmul[p->code] = p->value;
+ }
+ for(p=tandinit; p->code >= 0; p++) {
+ urk("tand", nelem(tand), p->code);
+ tand[p->code] = p->value;
+ }
+ for(p=trelinit; p->code >= 0; p++) {
+ urk("trel", nelem(trel), p->code);
+ trel[p->code] = p->value;
+ }
+
+ /* 32-bit defaults */
+ typeword = typechlp;
+ typecmplx = typesuv;
+}
+
+/*
+ * return 1 if it is impossible to jump into the middle of n.
+ */
+static int
+deadhead(Node *n, int caseok)
+{
+loop:
+ if(n == Z)
+ return 1;
+ switch(n->op) {
+ case OLIST:
+ if(!deadhead(n->left, caseok))
+ return 0;
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ break;
+
+ case OLABEL:
+ return 0;
+
+ case OGOTO:
+ break;
+
+ case OCASE:
+ if(!caseok)
+ return 0;
+ goto rloop;
+
+ case OSWITCH:
+ return deadhead(n->right, 1);
+
+ case OWHILE:
+ case ODWHILE:
+ goto rloop;
+
+ case OFOR:
+ goto rloop;
+
+ case OCONTINUE:
+ break;
+
+ case OBREAK:
+ break;
+
+ case OIF:
+ return deadhead(n->right->left, caseok) && deadhead(n->right->right, caseok);
+
+ case OSET:
+ case OUSED:
+ break;
+ }
+ return 1;
+}
+
+int
+deadheads(Node *c)
+{
+ return deadhead(c->left, 0) && deadhead(c->right, 0);
+}
+
+int
+mixedasop(Type *l, Type *r)
+{
+ return !typefd[l->etype] && typefd[r->etype];
+}
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
new file mode 100644
index 0000000..cc8e732
--- /dev/null
+++ b/src/cmd/gc/const.c
@@ -0,0 +1,370 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+#define TUP(x,y) (((x)<<16)|(y))
+
+void
+convlit(Node *n, Type *t)
+{
+ int et;
+
+ if(n->op != OLITERAL)
+ return;
+ if(t == T)
+ return;
+
+ n->type = t;
+ et = t->etype;
+
+ switch(whatis(n)) {
+ case Wlitint:
+ if(isptrto(t, TSTRING)) {
+ Rune rune;
+ int l;
+ String *s;
+
+ rune = n->val.vval;
+ l = runelen(rune);
+ s = mal(sizeof(*s)+l);
+ s->len = l;
+ runetochar((char*)(s->s), &rune);
+
+ n->val.sval = s;
+ n->val.ctype = CTSTR;
+ break;
+ }
+ if(isint[et]) {
+ if(n->val.vval < minintval[et])
+ goto bad2;
+ if(n->val.vval > maxintval[et])
+ goto bad2;
+ break;
+ }
+ if(isfloat[et]) {
+ if(n->val.vval < minfloatval[et])
+ goto bad2;
+ if(n->val.vval > maxfloatval[et])
+ goto bad2;
+ n->val.dval = n->val.vval;
+ n->val.ctype = CTFLT;
+ break;
+ }
+ goto bad1;
+
+ case Wlitfloat:
+ if(isint[et]) {
+ if(n->val.dval < minintval[et])
+ goto bad2;
+ if(n->val.dval > maxintval[et])
+ goto bad2;
+ n->val.vval = n->val.dval;
+ n->val.ctype = CTINT;
+ break;
+ }
+ if(isfloat[et]) {
+ if(n->val.dval < minfloatval[et])
+ goto bad2;
+ if(n->val.dval > maxfloatval[et])
+ goto bad2;
+ break;
+ }
+ goto bad1;
+ }
+ return;
+
+bad1:
+ yyerror("illegal conversion of constant to %T", t);
+ return;
+
+bad2:
+ yyerror("overflow converting constant to %T", t);
+ return;
+}
+
+void
+evconst(Node *n)
+{
+ Node *nl, *nr;
+ long len;
+ String *str;
+ int wl, wr;
+
+ nl = n->left;
+ if(nl == N)
+ return;
+
+ wl = whatis(nl);
+ switch(wl) {
+ default:
+ return;
+
+ case Wlitint:
+ case Wlitfloat:
+ case Wlitbool:
+ case Wlitstr:
+ break;
+ }
+
+ nr = n->right;
+ if(nr == N)
+ goto unary;
+
+ wr = whatis(nr);
+ switch(wr) {
+ default:
+ return;
+
+ case Wlitint:
+ case Wlitfloat:
+ case Wlitbool:
+ case Wlitstr:
+ break;
+ }
+ if(wl != wr) {
+ yyerror("illegal combination of literals %d %d", nl->etype, nr->etype);
+ return;
+ }
+
+ switch(TUP(n->op, wl)) {
+ default:
+ yyerror("illegal combination of literals %O %d", n->op, wl);
+ return;
+
+ case TUP(OADD, Wlitint):
+ nl->val.vval += nr->val.vval;
+ break;
+ case TUP(OSUB, Wlitint):
+ nl->val.vval -= nr->val.vval;
+ break;
+ case TUP(OMUL, Wlitint):
+ nl->val.vval *= nr->val.vval;
+ break;
+ case TUP(ODIV, Wlitint):
+ nl->val.vval /= nr->val.vval;
+ break;
+ case TUP(OMOD, Wlitint):
+ nl->val.vval %= nr->val.vval;
+ break;
+ case TUP(OLSH, Wlitint):
+ nl->val.vval <<= nr->val.vval;
+ break;
+ case TUP(ORSH, Wlitint):
+ nl->val.vval >>= nr->val.vval;
+ break;
+ case TUP(OOR, Wlitint):
+ nl->val.vval |= nr->val.vval;
+ break;
+ case TUP(OAND, Wlitint):
+ nl->val.vval &= nr->val.vval;
+ break;
+
+ case TUP(OADD, Wlitfloat):
+ nl->val.dval += nr->val.dval;
+ break;
+ case TUP(OSUB, Wlitfloat):
+ nl->val.dval -= nr->val.dval;
+ break;
+ case TUP(OMUL, Wlitfloat):
+ nl->val.dval *= nr->val.dval;
+ break;
+ case TUP(ODIV, Wlitfloat):
+ nl->val.dval /= nr->val.dval;
+ break;
+
+ case TUP(OEQ, Wlitint):
+ if(nl->val.vval == nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ case TUP(ONE, Wlitint):
+ if(nl->val.vval != nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLT, Wlitint):
+ if(nl->val.vval < nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLE, Wlitint):
+ if(nl->val.vval <= nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGE, Wlitint):
+ if(nl->val.vval >= nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGT, Wlitint):
+ if(nl->val.vval > nr->val.vval)
+ goto settrue;
+ goto setfalse;
+
+ case TUP(OEQ, Wlitfloat):
+ if(nl->val.dval == nr->val.dval)
+ goto settrue;
+ goto setfalse;
+ case TUP(ONE, Wlitfloat):
+ if(nl->val.dval != nr->val.dval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLT, Wlitfloat):
+ if(nl->val.dval < nr->val.dval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLE, Wlitfloat):
+ if(nl->val.dval <= nr->val.dval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGE, Wlitfloat):
+ if(nl->val.dval >= nr->val.dval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGT, Wlitfloat):
+ if(nl->val.dval > nr->val.dval)
+ goto settrue;
+ goto setfalse;
+
+
+ case TUP(OEQ, Wlitstr):
+ if(cmpslit(nl, nr) == 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(ONE, Wlitstr):
+ if(cmpslit(nl, nr) != 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLT, Wlitstr):
+ if(cmpslit(nl, nr) < 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLE, Wlitstr):
+ if(cmpslit(nl, nr) <= 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGE, Wlitstr):
+ if(cmpslit(nl, nr) >= 0l)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGT, Wlitstr):
+ if(cmpslit(nl, nr) > 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OADD, Wlitstr):
+ len = nl->val.sval->len + nr->val.sval->len;
+ str = mal(sizeof(*str) + len);
+ str->len = len;
+ memcpy(str->s, nl->val.sval->s, nl->val.sval->len);
+ memcpy(str->s+nl->val.sval->len, nr->val.sval->s, nr->val.sval->len);
+ str->len = len;
+ nl->val.sval = str;
+ break;
+
+ case TUP(OOROR, Wlitbool):
+ if(nl->val.vval || nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OANDAND, Wlitbool):
+ if(nl->val.vval && nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ }
+ *n = *nl;
+ return;
+
+settrue:
+ *n = *booltrue;
+ return;
+
+setfalse:
+ *n = *boolfalse;
+ return;
+
+unary:
+ switch(TUP(n->op, wl)) {
+ default:
+ yyerror("illegal combination of literals %O %d", n->op, wl);
+ return;
+
+ case TUP(OPLUS, Wlitint):
+ nl->val.vval = +nl->val.vval;
+ break;
+ case TUP(OMINUS, Wlitint):
+ nl->val.vval = -nl->val.vval;
+ break;
+ case TUP(OCOM, Wlitint):
+ nl->val.vval = ~nl->val.vval;
+ break;
+
+ case TUP(OPLUS, Wlitfloat):
+ nl->val.dval = +nl->val.dval;
+ break;
+ case TUP(OMINUS, Wlitfloat):
+ nl->val.dval = -nl->val.dval;
+ break;
+
+ case TUP(ONOT, Wlitbool):
+ if(nl->val.vval)
+ goto settrue;
+ goto setfalse;
+ }
+ *n = *nl;
+}
+
+void
+defaultlit(Node *n)
+{
+ if(n == N)
+ return;
+ if(n->type != T)
+ return;
+ if(n->op != OLITERAL)
+ return;
+
+ switch(n->val.ctype) {
+ default:
+ yyerror("defaultlit: unknown literal: %N", n);
+ break;
+ case CTINT:
+ case CTSINT:
+ case CTUINT:
+ n->type = types[TINT32];
+ break;
+ case CTFLT:
+ n->type = types[TFLOAT64];
+ break;
+ case CTBOOL:
+ n->type = types[TBOOL];
+ break;
+ case CTSTR:
+ n->type = types[TSTRING];
+ break;
+ }
+}
+
+int
+cmpslit(Node *l, Node *r)
+{
+ long l1, l2, i, m;
+ char *s1, *s2;
+
+ l1 = l->val.sval->len;
+ l2 = r->val.sval->len;
+ s1 = l->val.sval->s;
+ s2 = r->val.sval->s;
+
+ m = l1;
+ if(l2 < m)
+ m = l2;
+
+ for(i=0; i<m; i++) {
+ if(s1[i] == s2[i])
+ continue;
+ if(s1[i] > s2[i])
+ return +1;
+ return -1;
+ }
+ if(l1 == l2)
+ return 0;
+ if(l1 > l2)
+ return +1;
+ return -1;
+}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
new file mode 100644
index 0000000..3eae5f3
--- /dev/null
+++ b/src/cmd/gc/dcl.c
@@ -0,0 +1,814 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+#include "y.tab.h"
+
+void
+dodclvar(Node *n, Type *t)
+{
+
+loop:
+ if(n == N)
+ return;
+
+ if(n->op == OLIST) {
+ dodclvar(n->left, t);
+ n = n->right;
+ goto loop;
+ }
+
+ addvar(n, t, dclcontext);
+}
+
+void
+dodcltype(Type *n, Type *t)
+{
+
+ if(n == T)
+ return;
+ addtyp(n, t, dclcontext);
+}
+
+void
+dodclconst(Node *n, Node *e)
+{
+ Sym *s;
+ Dcl *r, *d;
+
+loop:
+ if(n == N)
+ return;
+ if(n->op == OLIST) {
+ dodclconst(n->left, e);
+ n = n->right;
+ goto loop;
+ }
+
+ if(n->op != ONAME)
+ fatal("dodclconst: not a name");
+
+ if(e->op != OLITERAL) {
+ yyerror("expression must be a constant");
+ goto loop;
+ }
+ s = n->sym;
+
+ s->oconst = e;
+ s->lexical = LACONST;
+
+ r = autodcl;
+ if(dclcontext == PEXTERN)
+ r = externdcl;
+
+ d = dcl();
+ d->dsym = s;
+ d->dnode = e;
+ d->op = OCONST;
+
+ r->back->forw = d;
+ r->back = d;
+
+ if(debug['d'])
+ print("const-dcl %S %N\n", n->sym, n->sym->oconst);
+}
+
+/*
+ * return nelem of list
+ */
+int
+listcount(Node *n)
+{
+ int v;
+
+ v = 0;
+ while(n != N) {
+ v++;
+ if(n->op != OLIST)
+ break;
+ n = n->right;
+ }
+ return v;
+}
+
+/*
+ * turn a parsed function declaration
+ * into a type
+ */
+Type*
+functype(Node *this, Node *in, Node *out)
+{
+ Type *t;
+
+ t = typ(TFUNC);
+
+ t->type = dostruct(this, TSTRUCT);
+ t->type->down = dostruct(out, TSTRUCT);
+ t->type->down->down = dostruct(in, TSTRUCT);
+
+ t->thistuple = listcount(this);
+ t->outtuple = listcount(out);
+ t->intuple = listcount(in);
+
+ dowidth(t);
+ return t;
+}
+
+void
+funcnam(Type *t, char *nam)
+{
+ Node *n;
+ Sym *s;
+ char buf[100];
+
+ if(nam == nil) {
+ vargen++;
+ snprint(buf, sizeof(buf), "_f%.3ld", vargen);
+ nam = buf;
+ }
+
+ if(t->etype != TFUNC)
+ fatal("funcnam: not func %T\n", t);
+
+ if(t->thistuple > 0) {
+ vargen++;
+ snprint(namebuf, sizeof(namebuf), "_t%.3ld", vargen);
+ s = lookup(namebuf);
+ addtyp(newtype(s), t->type, PEXTERN);
+ n = newname(s);
+ n->vargen = vargen;
+ t->type->nname = n;
+ }
+ if(t->outtuple > 0) {
+ vargen++;
+ snprint(namebuf, sizeof(namebuf), "_o%.3ld", vargen);
+ s = lookup(namebuf);
+ addtyp(newtype(s), t->type->down, PEXTERN);
+ n = newname(s);
+ n->vargen = vargen;
+ t->type->down->nname = n;
+ }
+ if(t->intuple > 0) {
+ vargen++;
+ snprint(namebuf, sizeof(namebuf), "_i%.3ld", vargen);
+ s = lookup(namebuf);
+ addtyp(newtype(s), t->type->down->down, PEXTERN);
+ n = newname(s);
+ n->vargen = vargen;
+ t->type->down->down->nname = n;
+ }
+}
+
+int
+methcmp(Type *t1, Type *t2)
+{
+ if(t1->etype != TFUNC)
+ return 0;
+ if(t2->etype != TFUNC)
+ return 0;
+
+ t1 = t1->type->down; // skip this arg
+ t2 = t2->type->down; // skip this arg
+ for(;;) {
+ if(t1 == t2)
+ break;
+ if(t1 == T || t2 == T)
+ return 0;
+ if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
+ return 0;
+
+ if(!eqtype(t1->type, t2->type, 0))
+ return 0;
+
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ return 1;
+}
+
+Node*
+methodname(Node *n, Type *t)
+{
+ if(isptr[t->etype])
+ t = t->type;
+ if(t->etype != TSTRUCT)
+ goto bad;
+ if(t->sym == S)
+ goto bad;
+
+ snprint(namebuf, sizeof(namebuf), "%s_%s", t->sym->name, n->sym->name);
+ return newname(lookup(namebuf));
+
+bad:
+ yyerror("illegal <this> pointer");
+ return n;
+}
+
+/*
+ * add a method, declared as a function,
+ * into the structure
+ */
+void
+addmethod(Node *n, Type *pa, Type *t)
+{
+ Type *f, *d, *p;
+ Sym *s;
+
+ if(n->op != ONAME)
+ goto bad;
+ s = n->sym;
+ if(s == S)
+ goto bad;
+ if(pa == T)
+ goto bad;
+ if(!isptr[pa->etype])
+ goto bad;
+ p = pa->type;
+ if(p == T)
+ goto bad;
+ if(p->etype != TSTRUCT)
+ goto bad;
+ if(p->sym == S)
+ goto bad;
+
+ if(p->type == T) {
+ n = nod(ODCLFIELD, newname(s), N);
+ n->type = t;
+
+ stotype(n, &p->type);
+ return;
+ }
+
+ d = T; // last found
+ for(f=p->type; f!=T; f=f->down) {
+ if(f->etype != TFIELD)
+ fatal("addmethod: not TFIELD: %N", f);
+
+ if(strcmp(s->name, f->sym->name) != 0) {
+ d = f;
+ continue;
+ }
+
+ // if a field matches a non-this function
+ // then delete it and let it be redeclared
+ if(methcmp(t, f->type)) {
+ if(d == T) {
+ p->type = f->down;
+ continue;
+ }
+ d->down = f->down;
+ continue;
+ }
+ if(!eqtype(t, f->type, 0))
+ yyerror("field redeclared as method: %S", s);
+ return;
+ }
+
+ n = nod(ODCLFIELD, newname(s), N);
+ n->type = t;
+
+ if(d == T)
+ stotype(n, &p->type);
+ else
+ stotype(n, &d->down);
+ return;
+
+bad:
+ yyerror("unknown method pointer: %T", pa);
+}
+
+/*
+ * declare the function proper.
+ * and declare the arguments
+ * called in extern-declaration context
+ * returns in auto-declaration context.
+ */
+void
+funchdr(Node *n)
+{
+ Node *on;
+ Sym *s;
+
+ s = n->nname->sym;
+ on = s->oname;
+
+ // check for same types
+ if(on != N) {
+ if(eqtype(n->type, on->type, 0)) {
+ if(!eqargs(n->type, on->type))
+ yyerror("foreward declarations not the same: %S", s);
+ } else {
+ yyerror("redeclare of function: %S", s);
+ on = N;
+ }
+ }
+
+ // check for foreward declaration
+ if(on == N) {
+ // initial declaration or redeclaration
+ // declare fun name, argument types and argument names
+ funcnam(n->type, s->name);
+ n->nname->type = n->type;
+ if(n->type->thistuple == 0)
+ addvar(n->nname, n->type, PEXTERN);
+ else
+ n->nname->class = PEXTERN;
+ } else {
+ // identical redeclaration
+ // steal previous names
+ n->nname = on;
+ n->type = on->type;
+ n->class = on->class;
+ n->sym = s;
+ if(debug['d'])
+ print("forew var-dcl %S %T\n", n->sym, n->type);
+ }
+
+ // change the declaration context from extern to auto
+ autodcl = dcl();
+ autodcl->back = autodcl;
+
+ if(dclcontext != PEXTERN)
+ fatal("funchdr: dclcontext");
+
+ dclcontext = PAUTO;
+ markdcl("func");
+ funcargs(n->type);
+
+ if(n->type->thistuple > 0) {
+ Type *t;
+ t = *getthis(n->type);
+ addmethod(n->nname, t->type->type, n->type);
+ }
+}
+
+void
+funcargs(Type *t)
+{
+ Type *n1;
+ Iter save;
+
+ // declare the this argument
+ n1 = funcfirst(&save, t);
+ while(n1 != T) {
+ if(n1->nname != N)
+ addvar(n1->nname, n1->type, PPARAM);
+ n1 = funcnext(&save);
+ }
+
+ // declare the outgoing arguments
+// n1 = structfirst(&save, getoutarg(t));
+// while(n1 != T) {
+// n1->left = newname(n1->sym);
+// if(n1->nname != N)
+// addvar(n1->nname, n1->type, PPARAM);
+// n1 = structnext(&save);
+// }
+}
+
+/*
+ * compile the function.
+ * called in auto-declaration context.
+ * returns in extern-declaration context.
+ */
+void
+funcbody(Node *n)
+{
+
+ compile(n);
+
+ // change the declaration context from auto to extern
+ if(dclcontext != PAUTO)
+ fatal("funcbody: dclcontext");
+ popdcl("func");
+ dclcontext = PEXTERN;
+}
+
+/*
+ * turn a parsed struct into a type
+ */
+Type**
+stotype(Node *n, Type **t)
+{
+ Type *f;
+ Iter save;
+
+ n = listfirst(&save, &n);
+
+loop:
+ if(n == N) {
+ *t = T;
+ return t;
+ }
+
+ if(n->op == OLIST) {
+ // recursive because it can be lists of lists
+ t = stotype(n, t);
+ goto next;
+ }
+
+ if(n->op != ODCLFIELD || n->type == T)
+ fatal("stotype: oops %N\n", n);
+
+ if(n->type->etype == TDARRAY)
+ yyerror("type of a structure field cannot be an open array");
+
+ f = typ(TFIELD);
+ f->type = n->type;
+
+ if(n->left != N && n->left->op == ONAME) {
+ f->nname = n->left;
+ } else {
+ vargen++;
+ snprint(namebuf, sizeof(namebuf), "_e%.3ld", vargen);
+ f->nname = newname(lookup(namebuf));
+ }
+ f->sym = f->nname->sym;
+
+ *t = f;
+ t = &f->down;
+
+next:
+ n = listnext(&save);
+ goto loop;
+}
+
+Type*
+dostruct(Node *n, int et)
+{
+ Type *t;
+
+ /*
+ * convert a parsed id/type list into
+ * a type for struct/interface/arglist
+ */
+
+ t = typ(et);
+ stotype(n, &t->type);
+ dowidth(t);
+ return t;
+}
+
+Type*
+sortinter(Type *t)
+{
+ return t;
+}
+
+void
+dcopy(Sym *a, Sym *b)
+{
+ a->name = b->name;
+ a->oname = b->oname;
+ a->otype = b->otype;
+ a->oconst = b->oconst;
+ a->package = b->package;
+ a->opackage = b->opackage;
+ a->forwtype = b->forwtype;
+ a->lexical = b->lexical;
+ a->undef = b->undef;
+ a->vargen = b->vargen;
+}
+
+Sym*
+push(void)
+{
+ Sym *d;
+
+ d = mal(sizeof(*d));
+ d->link = dclstack;
+ dclstack = d;
+ return d;
+}
+
+Sym*
+pushdcl(Sym *s)
+{
+ Sym *d;
+
+ d = push();
+ dcopy(d, s);
+ return d;
+}
+
+void
+popdcl(char *why)
+{
+ Sym *d, *s;
+
+// if(debug['d'])
+// print("revert\n");
+ for(d=dclstack; d!=S; d=d->link) {
+ if(d->name == nil)
+ break;
+ s = pkglookup(d->name, d->package);
+ dcopy(s, d);
+ if(debug['d'])
+ print("\t%ld pop %S\n", curio.lineno, s);
+ }
+ if(d == S)
+ fatal("popdcl: no mark");
+ if(strcmp(why, d->package) != 0)
+ fatal("popdcl: pushed as %s poped as %s", d->package, why);
+ dclstack = d->link;
+}
+
+void
+poptodcl(void)
+{
+ Sym *d, *s;
+
+ for(d=dclstack; d!=S; d=d->link) {
+ if(d->name == nil)
+ break;
+ s = pkglookup(d->name, d->package);
+ dcopy(s, d);
+ if(debug['d'])
+ print("\t%ld pop %S\n", curio.lineno, s);
+ }
+ if(d == S)
+ fatal("poptodcl: no mark");
+}
+
+void
+markdcl(char *why)
+{
+ Sym *d;
+
+ d = push();
+ d->name = nil; // used as a mark in fifo
+ d->package = why; // diagnostic for unmatched
+// if(debug['d'])
+// print("markdcl\n");
+}
+
+void
+markdclstack(void)
+{
+ Sym *d, *s;
+
+ markdcl("fnlit");
+
+ // copy the entire pop of the stack
+ // all the way back to block0.
+ // after this the symbol table is at
+ // block0 and popdcl will restore it.
+ for(d=dclstack; d!=S; d=d->link) {
+ if(d == b0stack)
+ break;
+ if(d->name != nil) {
+ s = pkglookup(d->name, d->package);
+ pushdcl(s);
+ dcopy(s, d);
+ }
+ }
+}
+
+void
+testdclstack(void)
+{
+ Sym *d;
+
+ for(d=dclstack; d!=S; d=d->link) {
+ if(d->name == nil) {
+ yyerror("mark left on the stack");
+ continue;
+ }
+ }
+}
+
+void
+addvar(Node *n, Type *t, int ctxt)
+{
+ Dcl *r, *d;
+ Sym *s;
+ Type *ot;
+ Node *on;
+ int gen;
+
+ if(n==N || n->sym == S || n->op != ONAME || t == T)
+ fatal("addvar: n=%N t=%T nil", n, t);
+
+ ot = t;
+ if(isptr[ot->etype])
+ ot = ot->type;
+
+ if(ot->etype == TSTRUCT && ot->vargen == 0) {
+ vargen++;
+ snprint(namebuf, sizeof(namebuf), "_s%.3ld", vargen);
+ s = lookup(namebuf);
+ addtyp(newtype(s), ot, PEXTERN);
+ }
+
+ s = n->sym;
+ vargen++;
+ gen = vargen;
+
+ r = autodcl;
+ if(ctxt == PEXTERN) {
+ on = s->oname;
+ if(on != N) {
+ if(eqtype(t, on->type, 0)) {
+ warn("%S redeclared", s);
+ return;
+ }
+ yyerror("%S redeclared (%T %T)", s,
+ on->type, t);
+ }
+ r = externdcl;
+ gen = 0;
+ }
+
+ if(ctxt != PEXTERN)
+ pushdcl(s);
+
+ s->vargen = gen;
+ s->oname = n;
+ s->offset = 0;
+
+ n->type = t;
+ n->vargen = gen;
+ n->class = ctxt;
+
+ d = dcl();
+ d->dsym = s;
+ d->dnode = n;
+ d->op = ONAME;
+
+ r->back->forw = d;
+ r->back = d;
+
+ if(debug['d']) {
+ if(ctxt == PEXTERN)
+ print("extern var-dcl %S G%ld %T\n", s, s->vargen, t);
+ else
+ print("auto var-dcl %S G%ld %T\n", s, s->vargen, t);
+ }
+}
+
+void
+addtyp(Type *n, Type *t, int ctxt)
+{
+ Dcl *r, *d;
+ Sym *s;
+ Type *f, *ot;
+
+ if(n==T || n->sym == S || t == T)
+ fatal("addtyp: n=%T t=%T nil", n, t);
+
+ s = n->sym;
+
+ r = autodcl;
+ if(ctxt == PEXTERN) {
+ ot = s->otype;
+ if(ot != T) {
+ // allow nil interface to be
+ // redeclared as an interface
+ if(ot->etype == TINTER && ot->type == T && t->etype == TINTER) {
+ if(debug['d'])
+ print("forew typ-dcl %S G%ld %T\n", s, s->vargen, t);
+ s->otype = t;
+ return;
+ }
+ if(eqtype(t, ot, 0)) {
+ warn("%S redeclared", s);
+ return;
+ }
+ yyerror("%S redeclared (%T %T)", s,
+ ot, t);
+ }
+ r = externdcl;
+ }
+
+ if(ctxt != PEXTERN)
+ pushdcl(s);
+
+ if(t->sym != S)
+ warn("addtyp: renaming %S/%lT to %S/%lT", t->sym, t->sym->otype, s, n);
+
+ vargen++;
+ s->vargen = vargen;
+ s->otype = t;
+ s->lexical = LATYPE;
+
+ t->sym = s;
+ t->vargen = vargen;
+
+ for(f=s->forwtype; f!=T; f=f->nforw) {
+ if(!isptr[f->etype])
+ fatal("addtyp: foreward");
+ f->type = t;
+ }
+ s->forwtype = T;
+
+ d = dcl();
+ d->dsym = s;
+ d->dtype = t;
+ d->op = OTYPE;
+
+ r->back->forw = d;
+ r->back = d;
+
+ if(debug['d']) {
+ if(ctxt == PEXTERN)
+ print("extern typ-dcl %S G%ld %T\n", s, s->vargen, t);
+ else
+ print("auto typ-dcl %S G%ld %T\n", s, s->vargen, t);
+ }
+}
+
+Node*
+fakethis(void)
+{
+ Node *n;
+ Type *t;
+
+ n = nod(ODCLFIELD, N, N);
+ t = dostruct(N, TSTRUCT);
+ t = ptrto(t);
+ n->type = t;
+ return n;
+}
+
+/*
+ * this generates a new name that is
+ * pushed down on the declaration list.
+ * no diagnostics are produced as this
+ * name will soon be declared.
+ */
+Node*
+newname(Sym *s)
+{
+ Node *n;
+
+ n = nod(ONAME, N, N);
+ n->sym = s;
+ n->type = T;
+ n->addable = 1;
+ n->ullman = 0;
+ return n;
+}
+
+/*
+ * this will return an old name
+ * that has already been pushed on the
+ * declaration list. a diagnostic is
+ * generated if no name has been defined.
+ */
+Node*
+oldname(Sym *s)
+{
+ Node *n;
+
+ n = s->oname;
+ if(n == N) {
+ yyerror("%S undefined", s);
+ n = newname(s);
+ dodclvar(n, types[TINT32]);
+ }
+ return n;
+}
+
+/*
+ * same for types
+ */
+Type*
+newtype(Sym *s)
+{
+ Type *t;
+
+ t = typ(TFORW);
+ t->sym = s;
+ t->type = T;
+ return t;
+}
+
+Type*
+oldtype(Sym *s)
+{
+ Type *t;
+
+ t = s->otype;
+ if(t == T)
+ fatal("%S not a type", s); // cant happen
+ return t;
+}
+
+Type*
+forwdcl(Sym *s)
+{
+ Type *t;
+
+ // this type has no meaning and
+ // will cause an error if referenced.
+ // it will be patched when/if the
+ // type is ever assigned.
+
+ t = typ(TFORW);
+ t = ptrto(t);
+
+ t->nforw = s->forwtype;
+ s->forwtype = t;
+ return t;
+}
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
new file mode 100644
index 0000000..336ad63
--- /dev/null
+++ b/src/cmd/gc/export.c
@@ -0,0 +1,578 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+#include "y.tab.h"
+
+void
+markexport(Node *n)
+{
+ Sym *s;
+ Dcl *d, *r;
+
+loop:
+ if(n == N)
+ return;
+ if(n->op == OLIST) {
+ markexport(n->left);
+ n = n->right;
+ goto loop;
+ }
+ if(n->op != OEXPORT)
+ fatal("markexport: op no OEXPORT: %O", n->op);
+
+ s = n->sym;
+ if(n->psym != S)
+ s = pkglookup(n->sym->name, n->psym->name);
+
+ if(s->export != 0)
+ return;
+ s->export = 1;
+
+ d = mal(sizeof(*d));
+ d->dsym = s;
+ d->dnode = N;
+ d->lineno = curio.lineno;
+
+ r = exportlist;
+ d->back = r->back;
+ r->back->forw = d;
+ r->back = d;
+}
+
+void
+reexport(Type *t)
+{
+ Sym *s;
+
+ if(t == T)
+ fatal("reexport: type nil\n");
+
+ s = t->sym;
+ if(s == S/* || s->name[0] == '_'*/) {
+ exportgen++;
+ snprint(namebuf, sizeof(namebuf), "_e%.3ld", exportgen);
+ s = lookup(namebuf);
+ s->lexical = LATYPE;
+ s->otype = t;
+ t->sym = s;
+ }
+ dumpexporttype(s);
+}
+
+void
+dumpexportconst(Sym *s)
+{
+ Node *n;
+ Type *t;
+
+ if(s->exported != 0)
+ return;
+ s->exported = 1;
+
+ n = s->oconst;
+ if(n == N || n->op != OLITERAL)
+ fatal("dumpexportconst: oconst nil: %S\n", s);
+
+ t = n->type; // may or may not be specified
+ if(t != T)
+ reexport(t);
+
+ Bprint(bout, "\tconst ");
+ if(s->export != 0)
+ Bprint(bout, "!");
+ Bprint(bout, "%lS ", s);
+ if(t != T)
+ Bprint(bout, "%lS ", t->sym);
+
+ switch(n->val.ctype) {
+ default:
+ fatal("dumpexportconst: unknown ctype: %S\n", s);
+ case CTINT:
+ case CTSINT:
+ case CTUINT:
+ case CTBOOL:
+ Bprint(bout, "0x%llux\n", n->val.vval);
+ break;
+ case CTFLT:
+ Bprint(bout, "%.17e\n", n->val.dval);
+ break;
+ case CTSTR:
+ Bprint(bout, "\"%Z\"\n", n->val.sval);
+ break;
+ }
+}
+
+void
+dumpexportvar(Sym *s)
+{
+ Node *n;
+ Type *t;
+
+ if(s->exported != 0)
+ return;
+ s->exported = 1;
+
+ n = s->oname;
+ if(n == N || n->type == T)
+ fatal("dumpexportvar: oname nil: %S\n", s);
+
+ t = n->type;
+ reexport(t);
+
+ Bprint(bout, "\tvar ");
+ if(s->export != 0)
+ Bprint(bout, "!");
+ Bprint(bout, "%lS %lS\n", s, t->sym);
+}
+
+void
+dumpexporttype(Sym *s)
+{
+ Type *t, *f;
+ Sym *ts;
+ int et;
+
+ if(s->exported != 0)
+ return;
+ s->exported = 1;
+
+ t = s->otype;
+ if(t == T)
+ fatal("dumpexporttype: otype nil: %S\n", s);
+ if(t->sym != s)
+ fatal("dumpexporttype: cross reference: %S\n", s);
+
+ et = t->etype;
+ switch(et) {
+ default:
+ if(et < 0 || et >= nelem(types) || types[et] == T)
+ fatal("dumpexporttype: basic type: %S %E\n", s, et);
+ /* type 5 */
+ Bprint(bout, "\ttype %lS %d\n", s, et);
+ break;
+
+ case TARRAY:
+ reexport(t->type);
+
+ /* type 2 */
+ Bprint(bout, "\ttype ");
+ if(s->export != 0)
+ Bprint(bout, "!");
+ Bprint(bout, "%lS [%lud] %lS\n", s, t->bound, t->type->sym);
+ break;
+
+ case TPTR32:
+ case TPTR64:
+ reexport(t->type);
+
+ /* type 6 */
+ Bprint(bout, "\ttype ");
+ if(s->export != 0)
+ Bprint(bout, "!");
+ Bprint(bout, "%lS *%lS\n", s, t->type->sym);
+ break;
+
+ case TFUNC:
+ for(f=t->type; f!=T; f=f->down) {
+ if(f->etype != TSTRUCT)
+ fatal("dumpexporttype: funct not field: %T\n", f);
+ reexport(f);
+ }
+
+ /* type 3 */
+ Bprint(bout, "\ttype ");
+ if(s->export != 0)
+ Bprint(bout, "!");
+ Bprint(bout, "%lS (", s);
+ for(f=t->type; f!=T; f=f->down) {
+ if(f != t->type)
+ Bprint(bout, " ");
+ Bprint(bout, "%lS", f->sym);
+ }
+ Bprint(bout, ")\n");
+ break;
+
+ case TSTRUCT:
+ case TINTER:
+ for(f=t->type; f!=T; f=f->down) {
+ if(f->etype != TFIELD)
+ fatal("dumpexporttype: funct not field: %lT\n", f);
+ reexport(f->type);
+ }
+
+ /* type 4 */
+ Bprint(bout, "\ttype ");
+ if(s->export)
+ Bprint(bout, "!");
+ Bprint(bout, "%lS %c", s, (et==TSTRUCT)? '{': '<');
+ for(f=t->type; f!=T; f=f->down) {
+ ts = f->type->sym;
+ if(f != t->type)
+ Bprint(bout, " ");
+ Bprint(bout, "%s %lS", f->sym->name, ts);
+ }
+ Bprint(bout, "%c\n", (et==TSTRUCT)? '}': '>');
+ break;
+ }
+}
+
+void
+dumpe(Sym *s)
+{
+ switch(s->lexical) {
+ default:
+ yyerror("unknown export symbol: %S\n", s, s->lexical);
+ break;
+ case LPACK:
+ yyerror("package export symbol: %S\n", s);
+ break;
+ case LATYPE:
+ case LBASETYPE:
+ dumpexporttype(s);
+ break;
+ case LNAME:
+ dumpexportvar(s);
+ break;
+ case LACONST:
+ dumpexportconst(s);
+ break;
+ }
+}
+
+void
+dumpexport(void)
+{
+ Dcl *d;
+ long lno;
+
+ lno = dynlineno;
+
+ Bprint(bout, " import\n");
+ Bprint(bout, " ((\n");
+
+ // print it depth first
+ for(d=exportlist->forw; d!=D; d=d->forw) {
+ dynlineno = d->lineno;
+ dumpe(d->dsym);
+ }
+
+ Bprint(bout, " ))\n");
+
+ dynlineno = lno;
+}
+
+/*
+ * ******* import *******
+ */
+Type*
+importlooktype(Node *n)
+{
+ Sym *s;
+
+ if(n->op != OIMPORT)
+ fatal("importlooktype: oops1 %N\n", n);
+
+ s = pkglookup(n->sym->name, n->psym->name);
+ if(s->otype == T)
+ fatal("importlooktype: oops2 %S\n", s);
+
+ return s->otype;
+}
+
+Type**
+importstotype(Node *fl, Type **t, Type *uber)
+{
+ Type *f;
+ Iter save;
+ Node *n;
+
+ n = listfirst(&save, &fl);
+
+loop:
+ if(n == N) {
+ *t = T;
+ return t;
+ }
+ f = typ(TFIELD);
+ f->type = importlooktype(n);
+
+ if(n->fsym != S) {
+ f->nname = newname(n->fsym);
+ } else {
+ vargen++;
+ snprint(namebuf, sizeof(namebuf), "_m%.3ld", vargen);
+ f->nname = newname(lookup(namebuf));
+ }
+ f->sym = f->nname->sym;
+
+ *t = f;
+ t = &f->down;
+
+ n = listnext(&save);
+ goto loop;
+}
+
+int
+importcount(Type *t)
+{
+ int i;
+ Type *f;
+
+ if(t == T || t->etype != TSTRUCT)
+ fatal("importcount: not a struct: %N", t);
+
+ i = 0;
+ for(f=t->type; f!=T; f=f->down)
+ i = i+1;
+ return i;
+}
+
+void
+importfuncnam(Type *t)
+{
+ Node *n;
+ Type *t1;
+
+ if(t->etype != TFUNC)
+ fatal("importfuncnam: not func %T\n", t);
+
+ if(t->thistuple > 0) {
+ t1 = t->type;
+ if(t1->sym == S)
+ fatal("importfuncnam: no this");
+ n = newname(t1->sym);
+ vargen++;
+ n->vargen = vargen;
+ t1->nname = n;
+ }
+ if(t->outtuple > 0) {
+ t1 = t->type->down;
+ if(t1->sym == S)
+ fatal("importfuncnam: no output");
+ n = newname(t1->sym);
+ vargen++;
+ n->vargen = vargen;
+ t1->nname = n;
+ }
+ if(t->intuple > 0) {
+ t1 = t->type->down->down;
+ if(t1->sym == S)
+ fatal("importfuncnam: no input");
+ n = newname(t1->sym);
+ vargen++;
+ n->vargen = vargen;
+ t1->nname = n;
+ }
+}
+
+Sym*
+getimportsym(Node *ss)
+{
+ char *pkg;
+ Sym *s;
+
+ pkg = ss->psym->name;
+ if(pkgmyname != S)
+ pkg = pkgmyname->name;
+
+ s = pkglookup(ss->sym->name, pkg);
+ /* botch - need some diagnostic checking for the following assignment */
+ s->opackage = ss->osym->name;
+ return s;
+}
+
+void
+importaddtyp(Node *ss, Type *t)
+{
+ Sym *s;
+
+ s = getimportsym(ss);
+ if(s->otype == T || !eqtype(t, s->otype, 0)) {
+ addtyp(newtype(s), t, PEXTERN);
+ }
+}
+
+/*
+ * LCONST importsym LITERAL
+ * untyped constant
+ */
+void
+doimportc1(Node *ss, Val *v)
+{
+ Node *n;
+ Sym *s;
+
+ n = nod(OLITERAL, N, N);
+ n->val = *v;
+
+ s = getimportsym(ss);
+ if(s->oconst == N) {
+ // botch sould ask if already declared the same
+ dodclconst(newname(s), n);
+ }
+}
+
+/*
+ * LCONST importsym importsym LITERAL
+ * typed constant
+ */
+void
+doimportc2(Node *ss, Node *st, Val *v)
+{
+ Node *n;
+ Type *t;
+ Sym *s;
+
+ n = nod(OLITERAL, N, N);
+ n->val = *v;
+
+ t = importlooktype(st);
+ n->type = t;
+
+ s = getimportsym(ss);
+ if(s->oconst == N) {
+ // botch sould ask if already declared the same
+ dodclconst(newname(s), n);
+ }
+}
+
+/*
+ * LVAR importsym importsym
+ * variable
+ */
+void
+doimportv1(Node *ss, Node *st)
+{
+ Type *t;
+ Sym *s;
+
+ t = importlooktype(st);
+ s = getimportsym(ss);
+ if(s->oname == N || !eqtype(t, s->oname->type, 0)) {
+ addvar(newname(s), t, dclcontext);
+ }
+}
+
+/*
+ * LTYPE importsym [ importsym ] importsym
+ * array type
+ */
+void
+doimport1(Node *ss, Node *ss1, Node *s)
+{
+ fatal("doimport1");
+}
+
+/*
+ * LTYPE importsym [ LLITERAL ] importsym
+ * array type
+ */
+void
+doimport2(Node *ss, Val *b, Node *st)
+{
+ Type *t;
+ Sym *s;
+
+ t = typ(TARRAY);
+ t->bound = b->vval;
+ s = pkglookup(st->sym->name, st->psym->name);
+ t->type = s->otype;
+
+ importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym '(' importsym_list ')'
+ * function/method type
+ */
+void
+doimport3(Node *ss, Node *n)
+{
+ Type *t;
+
+ t = typ(TFUNC);
+
+ t->type = importlooktype(n->left);
+ t->type->down = importlooktype(n->right->left);
+ t->type->down->down = importlooktype(n->right->right);
+
+ t->thistuple = importcount(t->type);
+ t->outtuple = importcount(t->type->down);
+ t->intuple = importcount(t->type->down->down);
+
+ importfuncnam(t);
+
+ importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym '{' importsym_list '}'
+ * structure type
+ */
+void
+doimport4(Node *ss, Node *n)
+{
+ Type *t;
+
+ t = typ(TSTRUCT);
+ importstotype(n, &t->type, t);
+
+ importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym LLITERAL
+ * basic type
+ */
+void
+doimport5(Node *ss, Val *v)
+{
+ int et;
+ Type *t;
+
+ et = v->vval;
+ if(et <= 0 || et >= nelem(types) || types[et] == T)
+ fatal("doimport5: bad type index: %E\n", et);
+
+ t = typ(et);
+ t->sym = S;
+
+ importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym * importsym
+ * pointer type
+ */
+void
+doimport6(Node *ss, Node *st)
+{
+ Type *t;
+ Sym *s;
+
+ s = pkglookup(st->sym->name, st->psym->name);
+ t = s->otype;
+ if(t == T)
+ t = forwdcl(s);
+ else
+ t = ptrto(t);
+
+ importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym '<' importsym '>'
+ * interface type
+ */
+void
+doimport7(Node *ss, Node *n)
+{
+ Type *t;
+
+ t = typ(TINTER);
+ importstotype(n, &t->type, t);
+
+ importaddtyp(ss, t);
+}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
new file mode 100644
index 0000000..ecd33a8
--- /dev/null
+++ b/src/cmd/gc/go.h
@@ -0,0 +1,553 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+todo:
+ 1. dyn arrays
+ 2. multi
+ 3. block 0
+tothinkabout:
+ 2. argument in import
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+enum
+{
+ NHUNK = 50000,
+ BUFSIZ = 8192,
+ NSYMB = 500,
+ NHASH = 1024,
+ STRINGSZ = 200,
+ YYMAXDEPTH = 500,
+ MAXALIGN = 7,
+ UINF = 100,
+
+ PRIME1 = 3,
+ PRIME2 = 10007,
+ PRIME3 = 10009,
+ PRIME4 = 10037,
+ PRIME5 = 10039,
+ PRIME6 = 10061,
+ PRIME7 = 10067,
+ PRIME8 = 10079,
+ PRIME9 = 10091,
+};
+
+/*
+ * note this is the representation
+ * of the compilers string literals,
+ * it happens to also be the runtime
+ * representation, ignoring sizes and
+ * alignment, but that may change.
+ */
+typedef struct String String;
+struct String
+{
+ long len;
+ char s[3]; // variable
+};
+
+typedef struct Val Val;
+struct Val
+{
+ int ctype;
+ double dval;
+ vlong vval;
+ String* sval;
+};
+
+typedef struct Sym Sym;
+typedef struct Node Node;
+typedef struct Type Type;
+
+struct Type
+{
+ int etype;
+ int chan;
+ uchar recur; // to detect loops
+ uchar trecur; // to detect loops
+ Sym* sym;
+ long vargen; // unique name for OTYPE/ONAME
+
+ // most nodes
+ Type* type;
+ vlong width; // offset in TFIELD, width in all others
+
+ // TFIELD
+ Type* down; // also used in TMAP
+
+ // TPTR
+ Type* nforw;
+
+ // TFUNCT
+ Type* this;
+ Type* argout;
+ Type* argin;
+ Node* nname;
+
+ uchar thistuple;
+ uchar outtuple;
+ uchar intuple;
+
+ // TARRAY
+ long bound;
+};
+#define T ((Type*)0)
+
+struct Node
+{
+ int op;
+
+ // most nodes
+ Node* left;
+ Node* right;
+ Type* type;
+
+ // for-body
+ Node* ninit;
+ Node* ntest;
+ Node* nincr;
+ Node* nbody;
+
+ // if-body
+ Node* nelse;
+
+ // cases
+ Node* ncase;
+
+ // func
+ Node* nname;
+
+ // OLITERAL
+ Val val;
+
+ Sym* osym; // import
+ Sym* fsym; // import
+ Sym* psym; // import
+ Sym* sym; // various
+ uchar ullman; // sethi/ullman number
+ uchar addable; // type of addressability - 0 is not addressable
+ uchar trecur; // to detect loops
+ uchar etype; // op for OASOP, etype for OTYPE, exclam for export
+ uchar class; // PPARAM, PAUTO, PEXTERN, PSTATIC
+ long vargen; // unique name for OTYPE/ONAME
+ ulong lineno;
+ vlong xoffset;
+};
+#define N ((Node*)0)
+
+struct Sym
+{
+ char* opackage; // original package name
+ char* package; // package name
+ char* name; // variable name
+ Node* oname; // ONAME node if a var
+ Type* otype; // TYPE node if a type
+ Node* oconst; // OLITERAL node if a const
+ Type* forwtype; // TPTR iff foreward declared
+ void* label; // pointer to Prog* of label
+ vlong offset; // stack location if automatic
+ long lexical;
+ long vargen; // unique variable number
+ uchar undef; // a diagnostic has been generated
+ uchar export; // marked as export
+ uchar exported; // has been exported
+ uchar sym; // huffman encoding in object file
+ Sym* link;
+};
+#define S ((Sym*)0)
+
+typedef struct Dcl Dcl;
+struct Dcl
+{
+ int op;
+ Sym* dsym; // for printing only
+ Node* dnode; // oname
+ Type* dtype; // otype
+ long lineno;
+
+ Dcl* forw;
+ Dcl* back; // sentinel has pointer to last
+};
+#define D ((Dcl*)0)
+
+typedef struct Iter Iter;
+struct Iter
+{
+ int done;
+ Type* tfunc;
+ Type* t;
+ Node** an;
+ Node* n;
+};
+
+enum
+{
+ OXXX,
+
+ OTYPE, OCONST, OVAR, OEXPORT, OIMPORT,
+
+ ONAME,
+ ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
+ ODCLFUNC, ODCLFIELD, ODCLARG,
+ OLIST, OCMP,
+ OPTR, OARRAY,
+ ORETURN, OFOR, OIF, OSWITCH, OI2S, OS2I, OI2I,
+ OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL,
+ OGOTO, OPROC, ONEW, OPANIC, OPRINT, OEMPTY,
+
+ OOROR,
+ OANDAND,
+ OEQ, ONE, OLT, OLE, OGE, OGT,
+ OADD, OSUB, OOR, OXOR,
+ OMUL, ODIV, OMOD, OLSH, ORSH, OAND,
+ ODEC, OINC,
+ OLEN,
+ OFUNC,
+ OLABEL,
+ OBREAK,
+ OCONTINUE,
+ OADDR,
+ OIND,
+ OCALL, OCALLMETH, OCALLINTER,
+ OINDEX, OINDEXPTR, OSLICE,
+ ONOT, OCOM, OPLUS, OMINUS, OSEND, ORECV,
+ OLITERAL, OREGISTER, OINDREG,
+ OCONV,
+ OBAD,
+
+ OEND,
+};
+enum
+{
+ Txxx, // 0
+
+ TINT8, TUINT8, // 1
+ TINT16, TUINT16,
+ TINT32, TUINT32,
+ TINT64, TUINT64,
+
+ TFLOAT32, // 9
+ TFLOAT64,
+ TFLOAT80,
+
+ TBOOL, // 12
+
+ TPTR32, TPTR64, // 13
+
+ TFUNC,
+ TARRAY,
+ TDARRAY,
+ TSTRUCT,
+ TCHAN,
+ TMAP,
+ TINTER,
+ TFORW,
+ TFIELD,
+ TANY,
+ TSTRING,
+
+ NTYPE, // 26
+};
+enum
+{
+ CTxxx,
+
+ CTINT,
+ CTSINT,
+ CTUINT,
+ CTFLT,
+
+ CTSTR,
+ CTBOOL,
+ CTNIL,
+};
+
+enum
+{
+ /* indications for whatis() */
+ Wnil = 0,
+ Wtnil,
+
+ Wtfloat,
+ Wtint,
+ Wtbool,
+ Wtstr,
+
+ Wlitfloat,
+ Wlitint,
+ Wlitbool,
+ Wlitstr,
+
+ Wtunkn,
+};
+
+enum
+{
+ /* types of channel */
+ Cxxx,
+ Cboth,
+ Crecv,
+ Csend,
+};
+
+enum
+{
+ Pxxx,
+
+ PEXTERN, // declaration context
+ PAUTO,
+ PPARAM,
+ PSTATIC,
+};
+
+typedef struct Io Io;
+struct Io
+{
+ char* infile;
+ Biobuf* bin;
+ long lineno;
+ int peekc;
+ char* cp; // used for content when bin==nil
+};
+
+EXTERN Io curio;
+EXTERN Io pushedio;
+
+EXTERN char* outfile;
+EXTERN char* package;
+EXTERN Biobuf* bout;
+EXTERN int nerrors;
+EXTERN char namebuf[NSYMB];
+EXTERN char debug[256];
+EXTERN long dynlineno;
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* dclstack;
+EXTERN Sym* b0stack;
+EXTERN Sym* pkgmyname; // my name for package
+EXTERN int tptr; // either TPTR32 or TPTR64
+extern char* sysimport;
+
+EXTERN Type* types[NTYPE];
+EXTERN uchar isptr[NTYPE];
+EXTERN uchar isint[NTYPE];
+EXTERN uchar isfloat[NTYPE];
+EXTERN uchar issigned[NTYPE];
+EXTERN uchar okforeq[NTYPE];
+EXTERN uchar okforadd[NTYPE];
+EXTERN uchar okforand[NTYPE];
+EXTERN double minfloatval[NTYPE];
+EXTERN double maxfloatval[NTYPE];
+EXTERN vlong minintval[NTYPE];
+EXTERN vlong maxintval[NTYPE];
+
+EXTERN Dcl* autodcl;
+EXTERN Dcl* externdcl;
+EXTERN Dcl* exportlist;
+EXTERN int dclcontext; // PEXTERN/PAUTO
+EXTERN int importflag;
+
+EXTERN Node* booltrue;
+EXTERN Node* boolfalse;
+EXTERN ulong iota;
+EXTERN long vargen;
+EXTERN long exportgen;
+
+EXTERN Node* retnil;
+EXTERN Node* fskel;
+
+EXTERN char* context;
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN char* hunk;
+EXTERN long nhunk;
+EXTERN long thunk;
+
+/*
+ * y.tab.c
+ */
+int yyparse(void);
+
+/*
+ * lex.c
+ */
+int main(int, char*[]);
+void importfile(Val*);
+void cannedimports(void);
+void unimportfile();
+long yylex(void);
+void lexinit(void);
+char* lexname(int);
+long getr(void);
+int getnsc(void);
+long escchar(long, int*);
+int getc(void);
+void ungetc(int);
+void mkpackage(char*);
+
+/*
+ * mpatof.c
+ */
+int mpatof(char*, double*);
+int mpatov(char*, vlong*);
+
+/*
+ * subr.c
+ */
+void myexit(int);
+void* mal(long);
+void* remal(void*, long, long);
+void errorexit(void);
+ulong stringhash(char*);
+Sym* lookup(char*);
+Sym* pkglookup(char*, char*);
+void yyerror(char*, ...);
+void warn(char*, ...);
+void fatal(char*, ...);
+Node* nod(int, Node*, Node*);
+Type* typ(int);
+Dcl* dcl(void);
+Node* rev(Node*);
+Node* unrev(Node*);
+void dodump(Node*, int);
+void dump(char*, Node*);
+Type* aindex(Node*, Type*);
+int isnil(Node*);
+int isptrto(Type*, int);
+int isinter(Type*);
+int isbytearray(Type*);
+int eqtype(Type*, Type*, int);
+int eqargs(Type*, Type*);
+ulong typehash(Type*, int);
+void frame(int);
+Node* literal(long);
+Node* dobad(void);
+Node* nodintconst(long);
+void ullmancalc(Node*);
+void badtype(int, Type*, Type*);
+Type* ptrto(Type*);
+Node* cleanidlist(Node*);
+
+Type** getthis(Type*);
+Type** getoutarg(Type*);
+Type** getinarg(Type*);
+
+Type* getthisx(Type*);
+Type* getoutargx(Type*);
+Type* getinargx(Type*);
+
+Node* listfirst(Iter*, Node**);
+Node* listnext(Iter*);
+Type* structfirst(Iter*, Type**);
+Type* structnext(Iter*);
+Type* funcfirst(Iter*, Type*);
+Type* funcnext(Iter*);
+
+int Econv(Fmt*);
+int Jconv(Fmt*);
+int Oconv(Fmt*);
+int Sconv(Fmt*);
+int Tconv(Fmt*);
+int Nconv(Fmt*);
+int Zconv(Fmt*);
+
+/*
+ * dcl.c
+ */
+void dodclvar(Node*, Type*);
+void dodcltype(Type*, Type*);
+void dodclconst(Node*, Node*);
+void defaultlit(Node*);
+int listcount(Node*);
+Node* methodname(Node*, Type*);
+Type* functype(Node*, Node*, Node*);
+char* thistypenam(Node*);
+void funcnam(Type*, char*);
+void funchdr(Node*);
+void funcargs(Type*);
+void funcbody(Node*);
+Type* dostruct(Node*, int);
+Type** stotype(Node*, Type**);
+Type* sortinter(Type*);
+void markdcl(char*);
+void popdcl(char*);
+void poptodcl(void);
+void markdclstack(void);
+void testdclstack(void);
+Sym* pushdcl(Sym*);
+void addvar(Node*, Type*, int);
+void addtyp(Type*, Type*, int);
+Node* fakethis(void);
+Node* newname(Sym*);
+Node* oldname(Sym*);
+Type* newtype(Sym*);
+Type* oldtype(Sym*);
+Type* forwdcl(Sym*);
+
+/*
+ * export.c
+ */
+void markexport(Node*);
+void dumpe(Sym*);
+void dumpexport(void);
+void dumpexporttype(Sym*);
+void dumpexportvar(Sym*);
+void dumpexportconst(Sym*);
+void doimportv1(Node*, Node*);
+void doimportc1(Node*, Val*);
+void doimportc2(Node*, Node*, Val*);
+void doimport1(Node*, Node*, Node*);
+void doimport2(Node*, Val*, Node*);
+void doimport3(Node*, Node*);
+void doimport4(Node*, Node*);
+void doimport5(Node*, Val*);
+void doimport6(Node*, Node*);
+void doimport7(Node*, Node*);
+
+/*
+ * walk.c
+ */
+void walk(Node*);
+void walktype(Node*, int);
+Type* walkswitch(Node*, Node*, Type*(*)(Node*, Type*));
+int casebody(Node*);
+int whatis(Node*);
+void walkdot(Node*);
+Node* ascompatee(int, Node**, Node**);
+Node* ascompatet(int, Node**, Type**, int);
+Node* ascompatte(int, Type**, Node**, int);
+int ascompat(Type*, Type*);
+Node* prcompat(Node*);
+Node* nodpanic(long);
+Node* newcompat(Node*);
+Node* stringop(Node*);
+Node* convas(Node*);
+Node* reorder(Node*);
+
+/*
+ * const.c
+ */
+void convlit(Node*, Type*);
+void evconst(Node*);
+int cmpslit(Node *l, Node *r);
+
+/*
+ * gen.c/gsubr.c/obj.c
+ */
+void belexinit(int);
+void besetptr(void);
+vlong convvtox(vlong, int);
+void compile(Node*);
+void proglist(void);
+int optopop(int);
+void dumpobj(void);
+void dowidth(Type*);
+void argspace(long);
+Node* nodarg(Type*, int);
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
new file mode 100644
index 0000000..a3f8e98
--- /dev/null
+++ b/src/cmd/gc/go.y
@@ -0,0 +1,1292 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+%{
+#include "go.h"
+%}
+%union {
+ Node* node;
+ Type* type;
+ Sym* sym;
+ struct Val val;
+ int lint;
+}
+%token <sym> LNAME LBASETYPE LATYPE LANY LPACK LACONST
+%token <val> LLITERAL LASOP
+%token LPACKAGE LIMPORT LEXPORT
+%token LMAP LCHAN LINTERFACE LFUNC LSTRUCT
+%token LCOLAS LFALL LRETURN
+%token LNEW LLEN
+%token LVAR LTYPE LCONST LCONVERT
+%token LFOR LIF LELSE LSWITCH LCASE LDEFAULT
+%token LBREAK LCONTINUE LGO LGOTO LRANGE
+%token LOROR LANDAND LEQ LNE LLE LLT LGE LGT
+%token LLSH LRSH LINC LDEC
+%token LNIL LTRUE LFALSE LIOTA
+%token LPANIC LPRINT LIGNORE
+
+%type <sym> sym laconst lname latype
+%type <lint> chandir
+%type <node> xdcl xdcl_list_r oxdcl_list common_dcl
+%type <node> oarg_type_list arg_type_list_r arg_type
+%type <node> stmt empty_stmt else_stmt
+%type <node> complex_stmt compound_stmt stmt_list_r ostmt_list
+%type <node> for_stmt for_body for_header
+%type <node> if_stmt if_body if_header
+%type <node> range_header range_body range_stmt
+%type <node> simple_stmt osimple_stmt
+%type <node> expr uexpr pexpr expr_list oexpr oexpr_list expr_list_r
+%type <node> name name_name new_name new_name_list_r
+%type <node> vardcl_list_r vardcl
+%type <node> interfacedcl_list_r interfacedcl
+%type <node> structdcl_list_r structdcl
+%type <node> export_list_r export
+%type <node> hidden_importsym_list_r ohidden_importsym_list hidden_importsym isym
+%type <node> hidden_importfield_list_r ohidden_importfield_list hidden_importfield
+%type <node> fnbody
+%type <node> fnres fnliteral xfndcl fndcl
+%type <node> keyval_list_r keyval
+
+%type <type> type fntypeh fntype fnlitdcl intype new_type
+
+%left LOROR
+%left LANDAND
+%left LEQ LNE LLE LGE LLT LGT
+%left '+' '-' '|' '^'
+%left '*' '/' '%' '&' LLSH LRSH
+%%
+file:
+ package import_there imports oxdcl_list
+ {
+ if(debug['f'])
+ frame(1);
+ testdclstack();
+ }
+
+package:
+ {
+ yyerror("package statement must be first");
+ mkpackage("main");
+ cannedimports();
+ }
+| LPACKAGE sym
+ {
+ mkpackage($2->name);
+ cannedimports();
+ }
+
+imports:
+| imports import
+
+import:
+ LIMPORT import_stmt
+| LIMPORT '(' import_stmt_list_r osemi ')'
+
+import_stmt:
+ import_here import_there
+
+import_here:
+ LLITERAL
+ {
+ // import with original name
+ pkgmyname = S;
+ importfile(&$1);
+ }
+| sym LLITERAL
+ {
+ // import with given name
+ pkgmyname = $1;
+ pkgmyname->lexical = LPACK;
+ importfile(&$2);
+ }
+| '.' LLITERAL
+ {
+ // import with my name
+ pkgmyname = lookup(package);
+ importfile(&$2);
+ }
+
+import_there:
+ hidden_import_list_r ')' ')'
+ {
+ unimportfile();
+ }
+| LIMPORT '(' '(' hidden_import_list_r ')' ')'
+
+/*
+ * declarations
+ */
+xdcl:
+ common_dcl
+| LEXPORT export_list_r
+ {
+ markexport(rev($2));
+ }
+| LEXPORT '(' export_list_r ')'
+ {
+ markexport(rev($3));
+ }
+| xfndcl
+| ';'
+ {
+ $$ = N;
+ }
+
+common_dcl:
+ LVAR vardcl
+ {
+ $$ = $2;
+ }
+| LVAR '(' vardcl_list_r osemi ')'
+ {
+ $$ = rev($3);
+ }
+| LCONST constdcl
+ {
+ $$ = N;
+ iota = 0;
+ }
+| LCONST '(' constdcl_list_r osemi ')'
+ {
+ $$ = N;
+ iota = 0;
+ }
+| LTYPE typedcl
+ {
+ $$ = N;
+ }
+| LTYPE '(' typedcl_list_r osemi ')'
+ {
+ $$ = N;
+ }
+
+vardcl:
+ new_name_list_r type
+ {
+ $$ = rev($1);
+ dodclvar($$, $2);
+
+ $$ = nod(OAS, $$, N);
+ }
+| new_name_list_r type '=' oexpr_list
+ {
+ $$ = rev($1);
+ dodclvar($$, $2);
+
+ $$ = nod(OAS, $$, $4);
+ }
+| new_name '=' expr
+ {
+ walktype($3, 0); // this is a little harry
+ defaultlit($3);
+ dodclvar($1, $3->type);
+
+ $$ = nod(OAS, $1, $3);
+ }
+
+constdcl:
+ new_name '=' expr
+ {
+ walktype($3, 0);
+ dodclconst($1, $3);
+ iota += 1;
+ }
+| new_name type '=' expr
+ {
+ walktype($4, 0);
+ convlit($4, $2);
+ dodclconst($1, $4);
+ iota += 1;
+ }
+
+typedcl:
+ new_type type
+ {
+ dodcltype($1, $2);
+ }
+
+/*
+ * statements
+ */
+stmt:
+ error ';'
+ {
+ $$ = N;
+ context = nil;
+ }
+| common_dcl ';'
+ {
+ $$ = $1;
+ }
+| simple_stmt ';'
+| complex_stmt
+| compound_stmt
+| empty_stmt
+
+empty_stmt:
+ ';'
+ {
+ $$ = nod(OEMPTY, N, N);
+ }
+
+else_stmt:
+ stmt
+ {
+ $$ = $1;
+ switch($$->op) {
+ case OLABEL:
+ case OXCASE:
+ case OXFALL:
+ yyerror("statement cannot be labeled");
+ }
+ }
+
+simple_stmt:
+ expr
+ {
+ $$ = $1;
+ }
+| expr LINC
+ {
+ $$ = nod(OASOP, $1, literal(1));
+ $$->etype = OADD;
+ }
+| expr LDEC
+ {
+ $$ = nod(OASOP, $1, literal(1));
+ $$->etype = OSUB;
+ }
+| expr LASOP expr
+ {
+ $$ = nod(OASOP, $1, $3);
+ $$->etype = $2.vval; // rathole to pass opcode
+ }
+| expr_list '=' expr_list
+ {
+ $$ = nod(OAS, $1, $3);
+ }
+| new_name LCOLAS expr
+ {
+ walktype($3, 0); // this is a little harry
+ defaultlit($3);
+ dodclvar($1, $3->type);
+
+ $$ = nod(OAS, $1, $3);
+ }
+
+complex_stmt:
+ LFOR for_stmt
+ {
+ /* FOR and WHILE are the same keyword */
+ popdcl("for/while");
+ $$ = $2;
+ }
+| LSWITCH if_stmt
+ {
+ popdcl("if/switch");
+ if(!casebody($2->nbody))
+ yyerror("switch statement must have case labels");
+ $$ = $2;
+ $$->op = OSWITCH;
+ }
+| LIF if_stmt
+ {
+ popdcl("if/switch");
+ $$ = $2;
+ }
+| LIF if_stmt LELSE else_stmt
+ {
+ popdcl("if/switch");
+ $$ = $2;
+ $$->nelse = $4;
+ }
+| LRANGE range_stmt
+ {
+ popdcl("range");
+ $$ = $2;
+ }
+| LRETURN oexpr_list ';'
+ {
+ $$ = nod(ORETURN, $2, N);
+ }
+| LCASE expr_list ':'
+ {
+ // will be converted to OCASE
+ // right will point to next case
+ // done in casebody()
+ poptodcl();
+ $$ = nod(OXCASE, $2, N);
+ }
+| LDEFAULT ':'
+ {
+ poptodcl();
+ $$ = nod(OXCASE, N, N);
+ }
+| LFALL ';'
+ {
+ // will be converted to OFALL
+ $$ = nod(OXFALL, N, N);
+ }
+| LBREAK oexpr ';'
+ {
+ $$ = nod(OBREAK, $2, N);
+ }
+| LCONTINUE oexpr ';'
+ {
+ $$ = nod(OCONTINUE, $2, N);
+ }
+| LGO pexpr '(' oexpr_list ')' ';'
+ {
+ $$ = nod(OPROC, $2, $4);
+ }
+| LPRINT expr_list ';'
+ {
+ $$ = nod(OPRINT, $2, N);
+ }
+| LPANIC oexpr_list ';'
+ {
+ $$ = nod(OPANIC, $2, N);
+ }
+| LGOTO new_name ';'
+ {
+ $$ = nod(OGOTO, $2, N);
+ }
+| new_name ':'
+ {
+ $$ = nod(OLABEL, $1, N);
+ }
+
+compound_stmt:
+ '{'
+ {
+ markdcl("compound");
+ } ostmt_list '}'
+ {
+ $$ = $3;
+ if($$ == N)
+ $$ = nod(OEMPTY, N, N);
+ popdcl("compound");
+ }
+
+for_header:
+ osimple_stmt ';' osimple_stmt ';' osimple_stmt
+ {
+ // init ; test ; incr
+ $$ = nod(OFOR, N, N);
+ $$->ninit = $1;
+ $$->ntest = $3;
+ $$->nincr = $5;
+ }
+| osimple_stmt
+ {
+ // test
+ $$ = nod(OFOR, N, N);
+ $$->ninit = N;
+ $$->ntest = $1;
+ $$->nincr = N;
+ }
+
+for_body:
+ for_header compound_stmt
+ {
+ $$ = $1;
+ $$->nbody = $2;
+ }
+
+for_stmt:
+ {
+ markdcl("for/while");
+ } for_body
+ {
+ $$ = $2;
+ }
+
+if_header:
+ osimple_stmt
+ {
+ // test
+ $$ = nod(OIF, N, N);
+ $$->ninit = N;
+ $$->ntest = $1;
+ }
+| osimple_stmt ';' osimple_stmt
+ {
+ // init ; test
+ $$ = nod(OIF, N, N);
+ $$->ninit = $1;
+ $$->ntest = $3;
+ }
+
+if_body:
+ if_header compound_stmt
+ {
+ $$ = $1;
+ $$->nbody = $2;
+ }
+
+if_stmt:
+ {
+ markdcl("if/switch");
+ } if_body
+ {
+ $$ = $2;
+ }
+
+range_header:
+ new_name LCOLAS expr
+ {
+ $$ = N;
+ }
+| new_name ',' new_name LCOLAS expr
+ {
+ $$ = N;
+ }
+| new_name ',' new_name '=' expr
+ {
+ yyerror("range statement only allows := assignment");
+ $$ = N;
+ }
+
+range_body:
+ range_header compound_stmt
+ {
+ $$ = $1;
+ $$->nbody = $2;
+ }
+
+range_stmt:
+ {
+ markdcl("range");
+ } range_body
+ {
+ $$ = $2;
+ }
+
+/*
+ * expressions
+ */
+expr:
+ uexpr
+| expr LOROR expr
+ {
+ $$ = nod(OOROR, $1, $3);
+ }
+| expr LANDAND expr
+ {
+ $$ = nod(OANDAND, $1, $3);
+ }
+| expr LEQ expr
+ {
+ $$ = nod(OEQ, $1, $3);
+ }
+| expr LNE expr
+ {
+ $$ = nod(ONE, $1, $3);
+ }
+| expr LLT expr
+ {
+ $$ = nod(OLT, $1, $3);
+ }
+| expr LLE expr
+ {
+ $$ = nod(OLE, $1, $3);
+ }
+| expr LGE expr
+ {
+ $$ = nod(OGE, $1, $3);
+ }
+| expr LGT expr
+ {
+ $$ = nod(OGT, $1, $3);
+ }
+| expr '+' expr
+ {
+ $$ = nod(OADD, $1, $3);
+ }
+| expr '-' expr
+ {
+ $$ = nod(OSUB, $1, $3);
+ }
+| expr '|' expr
+ {
+ $$ = nod(OOR, $1, $3);
+ }
+| expr '^' expr
+ {
+ $$ = nod(OXOR, $1, $3);
+ }
+| expr '*' expr
+ {
+ $$ = nod(OMUL, $1, $3);
+ }
+| expr '/' expr
+ {
+ $$ = nod(ODIV, $1, $3);
+ }
+| expr '%' expr
+ {
+ $$ = nod(OMOD, $1, $3);
+ }
+| expr '&' expr
+ {
+ $$ = nod(OAND, $1, $3);
+ }
+| expr LLSH expr
+ {
+ $$ = nod(OLSH, $1, $3);
+ }
+| expr LRSH expr
+ {
+ $$ = nod(ORSH, $1, $3);
+ }
+
+uexpr:
+ pexpr
+| '*' uexpr
+ {
+ $$ = nod(OIND, $2, N);
+ }
+| '&' uexpr
+ {
+ $$ = nod(OADDR, $2, N);
+ }
+| '+' uexpr
+ {
+ $$ = nod(OPLUS, $2, N);
+ }
+| '-' uexpr
+ {
+ $$ = nod(OMINUS, $2, N);
+ }
+| '!' uexpr
+ {
+ $$ = nod(ONOT, $2, N);
+ }
+| '~' uexpr
+ {
+ yyerror("the OCOM operator is ^");
+ $$ = nod(OCOM, $2, N);
+ }
+| '^' uexpr
+ {
+ $$ = nod(OCOM, $2, N);
+ }
+| LLT uexpr
+ {
+ $$ = nod(ORECV, $2, N);
+ }
+| LGT uexpr
+ {
+ $$ = nod(OSEND, $2, N);
+ }
+
+pexpr:
+ LLITERAL
+ {
+ $$ = nod(OLITERAL, N, N);
+ $$->val = $1;
+ }
+| laconst
+ {
+ $$ = nod(OLITERAL, N, N);
+ $$->val = $1->oconst->val;
+ $$->type = $1->oconst->type;
+ }
+| LNIL
+ {
+ $$ = nod(OLITERAL, N, N);
+ $$->val.ctype = CTNIL;
+ $$->val.vval = 0;
+ }
+| LTRUE
+ {
+ $$ = booltrue;
+ }
+| LFALSE
+ {
+ $$ = boolfalse;
+ }
+| LIOTA
+ {
+ $$ = literal(iota);
+ }
+| name
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+| pexpr '.' sym
+ {
+ $$ = nod(ODOT, $1, newname($3));
+ }
+| pexpr '.' '(' type ')'
+ {
+ $$ = nod(OCONV, $1, N);
+ $$->type = $4;
+ }
+| pexpr '[' expr ']'
+ {
+ $$ = nod(OINDEX, $1, $3);
+ }
+| pexpr '[' keyval ']'
+ {
+ $$ = nod(OSLICE, $1, $3);
+ }
+| pexpr '(' oexpr_list ')'
+ {
+ $$ = nod(OCALL, $1, $3);
+ }
+| LLEN '(' name ')'
+ {
+ $$ = nod(OLEN, $3, N);
+ }
+| LNEW '(' type ')'
+ {
+ $$ = nod(ONEW, N, N);
+ $$->type = ptrto($3);
+ }
+| fnliteral
+| '[' expr_list ']'
+ {
+ // array literal
+ $$ = N;
+ }
+| '[' keyval_list_r ']'
+ {
+ // map literal
+ $$ = N;
+ }
+| latype '(' oexpr_list ')'
+ {
+ // struct literal and conversions
+ $$ = nod(OCONV, $3, N);
+ $$->type = $1->otype;
+ }
+| LCONVERT '(' type ',' expr ')'
+ {
+ $$ = nod(OCONV, $5, N);
+ $$->type = $3;
+ }
+
+/*
+ * lexical symbols that can be
+ * from other packages
+ */
+lpack:
+ LPACK
+ {
+ context = $1->name;
+ }
+
+laconst:
+ LACONST
+| lpack '.' LACONST
+ {
+ $$ = $3;
+ context = nil;
+ }
+
+lname:
+ LNAME
+| lpack '.' LNAME
+ {
+ $$ = $3;
+ context = nil;
+ }
+
+latype:
+ LATYPE
+| lpack '.' LATYPE
+ {
+ $$ = $3;
+ context = nil;
+ }
+
+/*
+ * names and types
+ * newname is used before declared
+ * oldname is used after declared
+ */
+name_name:
+ LNAME
+ {
+ $$ = newname($1);
+ }
+
+new_name:
+ sym
+ {
+ $$ = newname($1);
+ }
+
+new_type:
+ sym
+ {
+ $$ = newtype($1);
+ }
+
+sym:
+ LATYPE
+| LNAME
+| LACONST
+| LPACK
+
+name:
+ lname
+ {
+ $$ = oldname($1);
+ }
+
+type:
+ latype
+ {
+ $$ = oldtype($1);
+ }
+| '[' oexpr ']' type
+ {
+ $$ = aindex($2, $4);
+ }
+| LCHAN chandir type
+ {
+ $$ = typ(TCHAN);
+ $$->type = $3;
+ $$->chan = $2;
+ }
+| LMAP '[' type ']' type
+ {
+ $$ = typ(TMAP);
+ $$->down = $3;
+ $$->type = $5;
+ }
+| LSTRUCT '{' structdcl_list_r osemi '}'
+ {
+ $$ = dostruct(rev($3), TSTRUCT);
+ }
+| LSTRUCT '{' '}'
+ {
+ $$ = dostruct(N, TSTRUCT);
+ }
+| LINTERFACE '{' interfacedcl_list_r osemi '}'
+ {
+ $$ = dostruct(rev($3), TINTER);
+ $$ = sortinter($$);
+ }
+| LINTERFACE '{' '}'
+ {
+ $$ = dostruct(N, TINTER);
+ }
+| LANY
+ {
+ $$ = typ(TANY);
+ }
+| fntypeh
+| '*' type
+ {
+ $$ = ptrto($2);
+ }
+| '*' lname
+ {
+ // dont know if this is an error or not
+ if(dclcontext != PEXTERN)
+ yyerror("foreward type in function body %s", $2->name);
+ $$ = forwdcl($2);
+ }
+
+chandir:
+ {
+ $$ = Cboth;
+ }
+| LLT
+ {
+ $$ = Crecv;
+ }
+| LGT
+ {
+ $$ = Csend;
+ }
+
+keyval:
+ expr ':' expr
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+/*
+ * function stuff
+ * all in one place to show how crappy it all is
+ */
+xfndcl:
+ LFUNC fndcl fnbody
+ {
+ $$ = $2;
+ $$->nbody = $3;
+ funcbody($$);
+ }
+
+fndcl:
+ new_name '(' oarg_type_list ')' fnres
+ {
+ b0stack = dclstack; // mark base for fn literals
+ $$ = nod(ODCLFUNC, N, N);
+ $$->nname = $1;
+ $$->type = functype(N, $3, $5);
+ funchdr($$);
+ }
+| '(' oarg_type_list ')' new_name '(' oarg_type_list ')' fnres
+ {
+ b0stack = dclstack; // mark base for fn literals
+ if($2 == N || $2->op == OLIST)
+ yyerror("syntax error in method receiver");
+ $$ = nod(ODCLFUNC, N, N);
+ $$->nname = methodname($4, $2->type);
+ $$->type = functype($2, $6, $8);
+ funchdr($$);
+ }
+
+fntypeh:
+ LFUNC '(' oarg_type_list ')' fnres
+ {
+ $$ = functype(N, $3, $5);
+ funcnam($$, nil);
+ }
+| LFUNC '(' oarg_type_list ')' '.' '(' oarg_type_list ')' fnres
+ /* i dont believe that this form is useful for anything */
+ {
+ if($3 == N || $3->op == OLIST)
+ yyerror("syntax error in method receiver");
+ $$ = functype($3, $7, $9);
+ funcnam($$, nil);
+ }
+
+fntype:
+ fntypeh
+| latype
+ {
+ $$ = oldtype($1);
+ if($$ == T || $$->etype != TFUNC)
+ yyerror("illegal type for function literal");
+ }
+
+fnlitdcl:
+ fntype
+ {
+ markdclstack(); // save dcl stack and revert to block0
+ $$ = $1;
+ funcargs($$);
+ }
+
+fnliteral:
+ fnlitdcl '{' ostmt_list '}'
+ {
+ popdcl("fnlit");
+
+ vargen++;
+ snprint(namebuf, sizeof(namebuf), "_f%.3ld", vargen);
+
+ $$ = newname(lookup(namebuf));
+ addvar($$, $1, PEXTERN);
+
+ {
+ Node *n;
+
+ n = nod(ODCLFUNC, N, N);
+ n->nname = $$;
+ n->type = $1;
+ n->nbody = $3;
+ if(n->nbody == N)
+ n->nbody = nod(ORETURN, N, N);
+ compile(n);
+ }
+
+ $$ = nod(OADDR, $$, N);
+ }
+
+fnbody:
+ compound_stmt
+ {
+ $$ = $1;
+ if($$->op == OEMPTY)
+ $$ = nod(ORETURN, N, N);
+ }
+| ';'
+ {
+ $$ = N;
+ }
+
+fnres:
+ {
+ $$ = N;
+ }
+| type
+ {
+ $$ = nod(ODCLFIELD, N, N);
+ $$->type = $1;
+ $$ = cleanidlist($$);
+ }
+| '(' oarg_type_list ')'
+ {
+ $$ = $2;
+ }
+
+/*
+ * lists of things
+ * note that they are left recursive
+ * to conserve yacc stack. they need to
+ * be reversed to interpret correctly
+ */
+xdcl_list_r:
+ xdcl
+| xdcl_list_r xdcl
+ {
+ $$ = nod(OLIST, $1, $2);
+ }
+
+vardcl_list_r:
+ vardcl
+| vardcl_list_r ';' vardcl
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+constdcl_list_r:
+ constdcl
+| constdcl_list_r ';' constdcl
+
+typedcl_list_r:
+ typedcl
+| typedcl_list_r ';' typedcl
+
+structdcl_list_r:
+ structdcl
+ {
+ $$ = cleanidlist($1);
+ }
+| structdcl_list_r ';' structdcl
+ {
+ $$ = cleanidlist($3);
+ $$ = nod(OLIST, $1, $$);
+ }
+
+interfacedcl_list_r:
+ interfacedcl
+ {
+ $$ = cleanidlist($1);
+ }
+| interfacedcl_list_r ';' interfacedcl
+ {
+ $$ = cleanidlist($3);
+ $$ = nod(OLIST, $1, $$);
+ }
+
+structdcl:
+ new_name ',' structdcl
+ {
+ $$ = nod(ODCLFIELD, $1, N);
+ $$ = nod(OLIST, $$, $3);
+ }
+| new_name type
+ {
+ $$ = nod(ODCLFIELD, $1, N);
+ $$->type = $2;
+ }
+
+interfacedcl:
+ new_name ',' interfacedcl
+ {
+ $$ = nod(ODCLFIELD, $1, N);
+ $$ = nod(OLIST, $$, $3);
+ }
+| new_name intype
+ {
+ $$ = nod(ODCLFIELD, $1, N);
+ $$->type = $2;
+ }
+
+intype:
+ '(' oarg_type_list ')' fnres
+ {
+ // without func keyword
+ $$ = functype(fakethis(), $2, $4);
+ funcnam($$, nil);
+ }
+| LFUNC '(' oarg_type_list ')' fnres
+ {
+ // with func keyword
+ $$ = functype(fakethis(), $3, $5);
+ funcnam($$, nil);
+ }
+| latype
+ {
+ $$ = oldtype($1);
+ if($$ == T || $$->etype != TFUNC)
+ yyerror("illegal type for function literal");
+ }
+
+arg_type:
+ name_name
+ {
+ $$ = nod(ODCLFIELD, $1, N);
+ }
+| type
+ {
+ $$ = nod(ODCLFIELD, N, N);
+ $$->type = $1;
+ }
+| new_name type
+ {
+ $$ = nod(ODCLFIELD, $1, N);
+ $$->type = $2;
+ }
+
+arg_type_list_r:
+ arg_type
+| arg_type_list_r ',' arg_type
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+stmt_list_r:
+ stmt
+ {
+ $$ = $1;
+ }
+| stmt_list_r stmt
+ {
+ $$ = nod(OLIST, $1, $2);
+ }
+
+expr_list_r:
+ expr
+| expr_list_r ',' expr
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+new_name_list_r:
+ new_name
+| new_name_list_r ',' new_name
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+export_list_r:
+ export
+| export_list_r ocomma export
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+export:
+ sym
+ {
+ $$ = nod(OEXPORT, N, N);
+ $$->sym = $1;
+ }
+| sym '.' sym
+ {
+ $$ = nod(OEXPORT, N, N);
+ $$->psym = $1;
+ $$->sym = $3;
+ }
+
+import_stmt_list_r:
+ import_stmt
+| import_stmt_list_r osemi import_stmt
+
+hidden_import_list_r:
+ hidden_import
+| hidden_import_list_r hidden_import
+
+hidden_importsym_list_r:
+ hidden_importsym
+| hidden_importsym_list_r hidden_importsym
+ {
+ $$ = nod(OLIST, $1, $2);
+ }
+
+hidden_importfield_list_r:
+ hidden_importfield
+| hidden_importfield_list_r hidden_importfield
+ {
+ $$ = nod(OLIST, $1, $2);
+ }
+
+keyval_list_r:
+ keyval
+| keyval_list_r ',' keyval
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+/*
+ * the one compromise of a
+ * non-reversed list
+ */
+expr_list:
+ expr_list_r
+ {
+ $$ = rev($1);
+ }
+
+/*
+ * optional things
+ */
+osemi:
+| ';'
+
+ocomma:
+| ','
+
+oexpr:
+ {
+ $$ = N;
+ }
+| expr
+
+oexpr_list:
+ {
+ $$ = N;
+ }
+| expr_list
+
+osimple_stmt:
+ {
+ $$ = N;
+ }
+| simple_stmt
+
+ostmt_list:
+ {
+ $$ = N;
+ }
+| stmt_list_r
+ {
+ $$ = rev($1);
+ }
+
+oxdcl_list:
+ {
+ $$ = N;
+ }
+| xdcl_list_r
+ {
+ $$ = rev($1);
+ }
+
+ohidden_importsym_list:
+ {
+ $$ = N;
+ }
+| hidden_importsym_list_r
+ {
+ $$ = rev($1);
+ }
+
+ohidden_importfield_list:
+ {
+ $$ = N;
+ }
+| hidden_importfield_list_r
+ {
+ $$ = rev($1);
+ }
+
+oarg_type_list:
+ {
+ $$ = N;
+ }
+| arg_type_list_r
+ {
+ $$ = cleanidlist(rev($1));
+ }
+
+/*
+ * import syntax from header of
+ * an output package
+ */
+hidden_import:
+ /* variables */
+ LVAR hidden_importsym hidden_importsym
+ {
+ // var
+ doimportv1($2, $3);
+ }
+
+ /* constants */
+| LCONST hidden_importsym LLITERAL
+ {
+ doimportc1($2, &$3);
+ }
+| LCONST hidden_importsym hidden_importsym LLITERAL
+ {
+ doimportc2($2, $3, &$4);
+ }
+
+ /* types */
+| LTYPE hidden_importsym '[' hidden_importsym ']' hidden_importsym
+ {
+ // type map
+ doimport1($2, $4, $6);
+ }
+| LTYPE hidden_importsym '[' LLITERAL ']' hidden_importsym
+ {
+ // type array
+ doimport2($2, &$4, $6);
+ }
+| LTYPE hidden_importsym '(' ohidden_importsym_list ')'
+ {
+ // type function
+ doimport3($2, $4);
+ }
+| LTYPE hidden_importsym '{' ohidden_importfield_list '}'
+ {
+ // type structure
+ doimport4($2, $4);
+ }
+| LTYPE hidden_importsym LLITERAL
+ {
+ // type basic
+ doimport5($2, &$3);
+ }
+| LTYPE hidden_importsym '*' hidden_importsym
+ {
+ // type pointer
+ doimport6($2, $4);
+ }
+| LTYPE hidden_importsym LLT ohidden_importfield_list LGT
+ {
+ // type interface
+ doimport7($2, $4);
+ }
+
+isym:
+ sym '.' sym
+ {
+ $1->lexical = LPACK;
+ $$ = nod(OIMPORT, N, N);
+ $$->osym = $1;
+ $$->psym = $1;
+ $$->sym = $3;
+ }
+| '(' sym ')' sym '.' sym
+ {
+ $$ = nod(OIMPORT, N, N);
+ $$->osym = $2;
+ $$->psym = $4;
+ $$->sym = $6;
+ }
+
+hidden_importsym:
+ isym
+| '!' isym
+ {
+ $$ = $2;
+ }
+
+hidden_importfield:
+ sym isym
+ {
+ $$ = $2;
+ $$->fsym = $1;
+ }
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
new file mode 100644
index 0000000..b44540c
--- /dev/null
+++ b/src/cmd/gc/lex.c
@@ -0,0 +1,1088 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+#define EXTERN
+#include "go.h"
+#include "y.tab.h"
+
+#define DBG if(!debug['x']);else print
+enum
+{
+ EOF = -1,
+};
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+
+ outfile = nil;
+ package = "____";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'k':
+ package = ARGF();
+ break;
+ } ARGEND
+
+ if(argc != 1)
+ goto usage;
+
+ fmtinstall('O', Oconv); // node opcodes
+ fmtinstall('E', Econv); // etype opcodes
+ fmtinstall('J', Jconv); // all the node flags
+ fmtinstall('S', Sconv); // sym pointer
+ fmtinstall('T', Tconv); // type pointer
+ fmtinstall('N', Nconv); // node pointer
+ fmtinstall('Z', Zconv); // escaped string
+
+ lexinit();
+
+ curio.infile = argv[0];
+
+ curio.bin = Bopen(curio.infile, OREAD);
+ if(curio.bin == nil)
+ fatal("cant open: %s", curio.infile);
+
+ externdcl = mal(sizeof(*externdcl));
+ externdcl->back = externdcl;
+ dclcontext = PEXTERN;
+
+ exportlist = mal(sizeof(*exportlist));
+ exportlist->back = exportlist;
+
+ // function field skeleton
+ fskel = nod(OLIST, N, nod(OLIST, N, N));
+ fskel->left = nod(ODCLFIELD, N, N);
+ fskel->right->left = nod(ODCLFIELD, N, N);
+ fskel->right->right = nod(ODCLFIELD, N, N);
+
+ curio.peekc = 0;
+ curio.lineno = 1;
+ nerrors = 0;
+ yyparse();
+
+ Bterm(curio.bin);
+ if(bout != nil)
+ Bterm(bout);
+
+ if(nerrors)
+ errorexit();
+
+ dumpobj();
+
+ myexit(0);
+ return 0;
+
+usage:
+ print("flags:\n");
+ print(" -d print declarations\n");
+ print(" -f print stack frame structure\n");
+ print(" -k name specify package name\n");
+ print(" -o file specify output file\n");
+ print(" -p print the assembly language\n");
+ print(" -w print the parse tree after typing\n");
+ print(" -x print lex tokens\n");
+ print(" -h panic on an error\n");
+ myexit(0);
+ return 0;
+}
+
+void
+importfile(Val *f)
+{
+ Biobuf *imp;
+ long c;
+
+ if(f->ctype != CTSTR) {
+ yyerror("import statement not a string");
+ return;
+ }
+ // BOTCH need to get .8 from backend
+ snprint(namebuf, sizeof(namebuf), "%Z.8", f->sval);
+
+ imp = Bopen(namebuf, OREAD);
+ if(imp == nil) {
+ yyerror("cant open import: %s", namebuf);
+ return;
+ }
+
+ /*
+ * position the input right
+ * after (( and return
+ */
+ pushedio = curio;
+ curio.bin = imp;
+ curio.lineno = 1;
+ curio.peekc = 0;
+ curio.infile = strdup(namebuf);
+ for(;;) {
+ c = getc();
+ if(c == EOF)
+ break;
+ if(c != '(')
+ continue;
+ c = getc();
+ if(c == EOF)
+ break;
+ if(c != '(')
+ continue;
+ return;
+ }
+ yyerror("no import in: %Z", f->sval);
+ unimportfile();
+}
+
+void
+unimportfile(void)
+{
+ if(curio.bin != nil) {
+ Bterm(curio.bin);
+ curio.bin = nil;
+ }
+ curio = pushedio;
+ pushedio.bin = nil;
+}
+
+void
+cannedimports(void)
+{
+ pushedio = curio;
+ curio.bin = nil;
+ curio.lineno = 1;
+ curio.peekc = 0;
+ curio.infile = "internal sys.go";
+ curio.cp = sysimport;
+ pkgmyname = S;
+}
+
+long
+yylex(void)
+{
+ long c, c1;
+ char *cp;
+ Rune rune;
+ int escflag;
+ Sym *s;
+
+l0:
+ c = getc();
+ if(isspace(c))
+ goto l0;
+
+ if(c >= Runeself) {
+ /* all multibyte runes are alpha */
+ cp = namebuf;
+ goto talph;
+ }
+
+ if(isalpha(c)) {
+ cp = namebuf;
+ goto talph;
+ }
+
+ if(isdigit(c))
+ goto tnum;
+
+ switch(c) {
+ case EOF:
+ ungetc(EOF);
+ return -1;
+
+ case '_':
+ cp = namebuf;
+ goto talph;
+
+ case '.':
+ c1 = getc();
+ if(isdigit(c1)) {
+ cp = namebuf;
+ *cp++ = c;
+ c = c1;
+ c1 = 0;
+ goto casedot;
+ }
+ break;
+
+ case '"':
+ /* "..." */
+ strcpy(namebuf, "\"<string>\"");
+ cp = mal(sizeof(long));
+ c1 = 4;
+
+ caseq:
+ for(;;) {
+ c = escchar('"', &escflag);
+ if(c == EOF)
+ break;
+ if(escflag) {
+ cp = remal(cp, c1, 1);
+ cp[c1++] = c;
+ } else {
+ rune = c;
+ c = runelen(rune);
+ cp = remal(cp, c1, c);
+ runetochar(cp+c1, &rune);
+ c1 += c;
+ }
+ }
+ goto catem;
+
+ case '`':
+ /* `...` */
+ strcpy(namebuf, "`<string>`");
+ cp = mal(sizeof(long));
+ c1 = 4;
+
+ casebq:
+ for(;;) {
+ c = getc();
+ if(c == EOF || c == '`')
+ break;
+ cp = remal(cp, c1, 1);
+ cp[c1++] = c;
+ }
+
+ catem:
+ for(;;) {
+ /* it takes 2 peekc's to skip comments */
+ c = getc();
+ if(isspace(c))
+ continue;
+ if(c == '"')
+ goto caseq;
+ if(c == '`')
+ goto casebq;
+ ungetc(c);
+ break;
+ }
+
+ *(long*)cp = c1-4; // length
+ do {
+ cp = remal(cp, c1, 1);
+ cp[c1++] = 0;
+ } while(c1 & MAXALIGN);
+ yylval.val.sval = (String*)cp;
+ yylval.val.ctype = CTSTR;
+ DBG("lex: string literal\n");
+ return LLITERAL;
+
+ case '\'':
+ /* '.' */
+ c = escchar('\'', &escflag);
+ if(c == EOF)
+ c = '\'';
+ c1 = escchar('\'', &escflag);
+ if(c1 != EOF) {
+ yyerror("missing '");
+ ungetc(c1);
+ }
+ yylval.val.vval = c;
+ yylval.val.ctype = CTINT;
+ DBG("lex: codepoint literal\n");
+ return LLITERAL;
+
+ case '/':
+ c1 = getc();
+ if(c1 == '*') {
+ for(;;) {
+ c = getr();
+ while(c == '*') {
+ c = getr();
+ if(c == '/')
+ goto l0;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '/') {
+ for(;;) {
+ c = getr();
+ if(c == '\n')
+ goto l0;
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '=') {
+ c = ODIV;
+ goto asop;
+ }
+ break;
+
+ case ':':
+ c1 = getc();
+ if(c1 == '=') {
+ c = LCOLAS;
+ goto lx;
+ }
+ break;
+
+ case '*':
+ c1 = getc();
+ if(c1 == '=') {
+ c = OMUL;
+ goto asop;
+ }
+ break;
+
+ case '%':
+ c1 = getc();
+ if(c1 == '=') {
+ c = OMOD;
+ goto asop;
+ }
+ break;
+
+ case '+':
+ c1 = getc();
+ if(c1 == '+') {
+ c = LINC;
+ goto lx;
+ }
+ if(c1 == '=') {
+ c = OADD;
+ goto asop;
+ }
+ break;
+
+ case '-':
+ c1 = getc();
+ if(c1 == '-') {
+ c = LDEC;
+ goto lx;
+ }
+ if(c1 == '=') {
+ c = OSUB;
+ goto asop;
+ }
+ break;
+
+ case '>':
+ c1 = getc();
+ if(c1 == '>') {
+ c = LRSH;
+ c1 = getc();
+ if(c1 == '=') {
+ c = ORSH;
+ goto asop;
+ }
+ break;
+ }
+ if(c1 == '=') {
+ c = LGE;
+ goto lx;
+ }
+ c = LGT;
+ break;
+
+ case '<':
+ c1 = getc();
+ if(c1 == '<') {
+ c = LLSH;
+ c1 = getc();
+ if(c1 == '=') {
+ c = OLSH;
+ goto asop;
+ }
+ break;
+ }
+ if(c1 == '=') {
+ c = LLE;
+ goto lx;
+ }
+ c = LLT;
+ break;
+
+ case '=':
+ c1 = getc();
+ if(c1 == '=') {
+ c = LEQ;
+ goto lx;
+ }
+ break;
+
+ case '!':
+ c1 = getc();
+ if(c1 == '=') {
+ c = LNE;
+ goto lx;
+ }
+ break;
+
+ case '&':
+ c1 = getc();
+ if(c1 == '&') {
+ c = LANDAND;
+ goto lx;
+ }
+ if(c1 == '=') {
+ c = OAND;
+ goto asop;
+ }
+ break;
+
+ case '|':
+ c1 = getc();
+ if(c1 == '|') {
+ c = LOROR;
+ goto lx;
+ }
+ if(c1 == '=') {
+ c = OOR;
+ goto asop;
+ }
+ break;
+
+ case '^':
+ c1 = getc();
+ if(c1 == '=') {
+ c = OXOR;
+ goto asop;
+ }
+ break;
+
+ default:
+ goto lx;
+ }
+ ungetc(c1);
+
+lx:
+ if(c > 0xff)
+ DBG("lex: TOKEN %s\n", lexname(c));
+ else
+ DBG("lex: TOKEN '%c'\n", c);
+ return c;
+
+asop:
+ yylval.val.vval = c; // rathole to hold which asop
+ DBG("lex: TOKEN ASOP %c\n", c);
+ return LASOP;
+
+talph:
+ /*
+ * cp is set to namebuf and some
+ * prefix has been stored
+ */
+ for(;;) {
+ if(c >= Runeself) {
+ for(c1=0;;) {
+ cp[c1++] = c;
+ if(fullrune(cp, c1))
+ break;
+ c = getc();
+ }
+ cp += c1;
+ c = getc();
+ continue;
+ }
+ if(!isalnum(c) && c != '_')
+ break;
+ *cp++ = c;
+ c = getc();
+ }
+ *cp = 0;
+ ungetc(c);
+
+ s = lookup(namebuf);
+ if(s->lexical == LIGNORE)
+ goto l0;
+
+ if(context != nil) {
+ s = pkglookup(s->name, context);
+ if(s->lexical == LIGNORE)
+ goto l0;
+ }
+
+ DBG("lex: %S %s\n", s, lexname(s->lexical));
+ yylval.sym = s;
+ if(s->lexical == LBASETYPE)
+ return LATYPE;
+ return s->lexical;
+
+tnum:
+ c1 = 0;
+ cp = namebuf;
+ if(c != '0') {
+ for(;;) {
+ *cp++ = c;
+ c = getc();
+ if(isdigit(c))
+ continue;
+ goto dc;
+ }
+ }
+ *cp++ = c;
+ c = getc();
+ if(c == 'x' || c == 'X')
+ for(;;) {
+ *cp++ = c;
+ c = getc();
+ if(isdigit(c))
+ continue;
+ if(c >= 'a' && c <= 'f')
+ continue;
+ if(c >= 'A' && c <= 'F')
+ continue;
+ if(cp == namebuf+2)
+ yyerror("malformed hex constant");
+ goto ncu;
+ }
+ if(c < '0' || c > '7')
+ goto dc;
+ for(;;) {
+ if(c >= '0' && c <= '7') {
+ *cp++ = c;
+ c = getc();
+ continue;
+ }
+ goto ncu;
+ }
+
+dc:
+ if(c == '.')
+ goto casedot;
+ if(c == 'e' || c == 'E')
+ goto casee;
+
+ncu:
+ *cp = 0;
+ ungetc(c);
+ if(mpatov(namebuf, &yylval.val.vval)) {
+ yyerror("overflow in constant");
+ yylval.val.vval = 0;
+ }
+ yylval.val.ctype = CTINT;
+ DBG("lex: integer literal\n");
+ return LLITERAL;
+
+casedot:
+ for(;;) {
+ *cp++ = c;
+ c = getc();
+ if(!isdigit(c))
+ break;
+ }
+ if(c != 'e' && c != 'E')
+ goto caseout;
+
+casee:
+ *cp++ = 'e';
+ c = getc();
+ if(c == '+' || c == '-') {
+ *cp++ = c;
+ c = getc();
+ }
+ if(!isdigit(c))
+ yyerror("malformed fp constant exponent");
+ while(isdigit(c)) {
+ *cp++ = c;
+ c = getc();
+ }
+
+caseout:
+ *cp = 0;
+ ungetc(c);
+ if(mpatof(namebuf, &yylval.val.dval)) {
+ yyerror("overflow in float constant");
+ yylval.val.dval = 0;
+ }
+ yylval.val.ctype = CTFLT;
+ DBG("lex: floating literal\n");
+ return LLITERAL;
+}
+
+int
+getc(void)
+{
+ int c;
+
+ c = curio.peekc;
+ if(c != 0) {
+ curio.peekc = 0;
+ if(c == '\n')
+ curio.lineno++;
+ return c;
+ }
+
+ if(curio.bin == nil) {
+ c = *curio.cp & 0xff;
+ if(c != 0)
+ curio.cp++;
+ } else
+ c = Bgetc(curio.bin);
+
+ switch(c) {
+ case 0:
+ case EOF:
+ return EOF;
+
+ case '\n':
+ curio.lineno++;
+ break;
+ }
+ return c;
+}
+
+void
+ungetc(int c)
+{
+ curio.peekc = c;
+ if(c == '\n')
+ curio.lineno--;
+}
+
+long
+getr(void)
+{
+ int c, i;
+ char str[UTFmax+1];
+ Rune rune;
+
+ c = getc();
+ if(c < Runeself)
+ return c;
+ i = 0;
+ str[i++] = c;
+
+loop:
+ c = getc();
+ str[i++] = c;
+ if(!fullrune(str, i))
+ goto loop;
+ c = chartorune(&rune, str);
+ if(rune == Runeerror && c == 1) {
+ yyerror("illegal rune in string");
+ for(c=0; c<i; c++)
+ print(" %.2x", *(uchar*)(str+c));
+ print("\n");
+ }
+ return rune;
+}
+
+int
+getnsc(void)
+{
+ int c;
+
+ c = getc();
+ for(;;) {
+ if(!isspace(c))
+ return c;
+ if(c == '\n') {
+ curio.lineno++;
+ return c;
+ }
+ c = getc();
+ }
+ return 0;
+}
+
+
+long
+escchar(long e, int *escflg)
+{
+ long c, l;
+ int i;
+
+ *escflg = 0;
+
+loop:
+ c = getr();
+ if(c == '\n') {
+ yyerror("newline in string");
+ return EOF;
+ }
+ if(c != '\\') {
+ if(c == e)
+ c = EOF;
+ return c;
+ }
+ c = getr();
+ switch(c) {
+ case '\n':
+ goto loop;
+
+ case 'x':
+ i = 2;
+ goto hex;
+
+ case 'u':
+ i = 4;
+ goto hex;
+
+ case 'U':
+ i = 8;
+ goto hex;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ goto oct;
+
+ case 'a': return '\a';
+ case 'b': return '\b';
+ case 'f': return '\f';
+ case 'n': return '\n';
+ case 'r': return '\r';
+ case 't': return '\t';
+ case 'v': return '\v';
+
+ default:
+ if(c != e)
+ warn("unknown escape sequence: %c", c);
+ }
+ return c;
+
+hex:
+ l = 0;
+ for(; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '9') {
+ l = l*16 + c-'0';
+ continue;
+ }
+ if(c >= 'a' && c <= 'f') {
+ l = l*16 + c-'a' + 10;
+ continue;
+ }
+ if(c >= 'A' && c <= 'F') {
+ l = l*16 + c-'A' + 10;
+ continue;
+ }
+ warn("non-hex character in escape sequence: %c", c);
+ ungetc(c);
+ break;
+ }
+ *escflg = 1;
+ return l;
+
+oct:
+ l = c - '0';
+ for(i=2; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ continue;
+ }
+ warn("non-oct character in escape sequence: %c", c);
+ ungetc(c);
+ }
+ if(l > 255)
+ warn("oct escape value > 255: %d", l);
+ *escflg = 1;
+ return l;
+}
+
+static struct
+{
+ char* name;
+ int lexical;
+ int etype;
+} syms[] =
+{
+/* name lexical etype
+ */
+/* basic types */
+ "int8", LBASETYPE, TINT8,
+ "int16", LBASETYPE, TINT16,
+ "int32", LBASETYPE, TINT32,
+ "int64", LBASETYPE, TINT64,
+
+ "uint8", LBASETYPE, TUINT8,
+ "uint16", LBASETYPE, TUINT16,
+ "uint32", LBASETYPE, TUINT32,
+ "uint64", LBASETYPE, TUINT64,
+
+ "float32", LBASETYPE, TFLOAT32,
+ "float64", LBASETYPE, TFLOAT64,
+ "float80", LBASETYPE, TFLOAT80,
+
+ "bool", LBASETYPE, TBOOL,
+ "byte", LBASETYPE, TUINT8,
+ "char", LBASETYPE, TUINT8, // temp??
+ "string", LBASETYPE, TSTRING,
+
+/* keywords */
+ "any", LANY, Txxx,
+ "break", LBREAK, Txxx,
+ "case", LCASE, Txxx,
+ "chan", LCHAN, Txxx,
+ "const", LCONST, Txxx,
+ "continue", LCONTINUE, Txxx,
+ "convert", LCONVERT, Txxx,
+ "default", LDEFAULT, Txxx,
+ "else", LELSE, Txxx,
+ "export", LEXPORT, Txxx,
+ "fallthrough", LFALL, Txxx,
+ "false", LFALSE, Txxx,
+ "for", LFOR, Txxx,
+ "func", LFUNC, Txxx,
+ "go", LGO, Txxx,
+ "goto", LGOTO, Txxx,
+ "if", LIF, Txxx,
+ "import", LIMPORT, Txxx,
+ "interface", LINTERFACE, Txxx,
+ "iota", LIOTA, Txxx,
+ "map", LMAP, Txxx,
+ "new", LNEW, Txxx,
+ "len", LLEN, Txxx,
+ "nil", LNIL, Txxx,
+ "package", LPACKAGE, Txxx,
+ "panic", LPANIC, Txxx,
+ "print", LPRINT, Txxx,
+ "range", LRANGE, Txxx,
+ "return", LRETURN, Txxx,
+ "struct", LSTRUCT, Txxx,
+ "switch", LSWITCH, Txxx,
+ "true", LTRUE, Txxx,
+ "type", LTYPE, Txxx,
+ "var", LVAR, Txxx,
+
+ "notwithstanding", LIGNORE, Txxx,
+ "thetruthofthematter", LIGNORE, Txxx,
+ "despiteallobjections", LIGNORE, Txxx,
+ "whereas", LIGNORE, Txxx,
+ "insofaras", LIGNORE, Txxx,
+};
+
+void
+lexinit(void)
+{
+ int i, etype, lex;
+ Sym *s;
+ Type *t;
+
+ besetptr();
+
+ for(i=TINT8; i<=TUINT64; i++)
+ isint[i] = 1;
+ for(i=TFLOAT32; i<=TFLOAT80; i++)
+ isfloat[i] = 1;
+ isptr[TPTR32] = 1;
+ isptr[TPTR64] = 1;
+
+ issigned[TINT8] = 1;
+ issigned[TINT16] = 1;
+ issigned[TINT32] = 1;
+ issigned[TINT64] = 1;
+
+ /*
+ * initialize okfor
+ */
+ for(i=0; i<NTYPE; i++) {
+ if(isint[i]) {
+ okforeq[i] = 1;
+ okforadd[i] = 1;
+ okforand[i] = 1;
+ }
+ if(isfloat[i]) {
+ okforeq[i] = 1;
+ okforadd[i] = 1;
+ }
+ switch(i) {
+ case TBOOL:
+ case TPTR32:
+ case TPTR64:
+ okforeq[i] = 1;
+ break;
+ }
+ minfloatval[i] = 0.0;
+ maxfloatval[i] = 0.0;
+ minintval[i] = 0;
+ maxintval[i] = 0;
+ }
+
+// this stuff smells - really need to do constants
+// in multi precision arithmetic
+
+ maxintval[TINT8] = 0x7f;
+ minintval[TINT8] = -maxintval[TINT8]-1;
+ maxintval[TINT16] = 0x7fff;
+ minintval[TINT16] = -maxintval[TINT16]-1;
+ maxintval[TINT32] = 0x7fffffffL;
+ minintval[TINT32] = -maxintval[TINT32]-1;
+ maxintval[TINT64] = 0x7fffffffffffffffLL;
+ minintval[TINT64] = -maxintval[TINT64]-1;
+ maxintval[TUINT8] = 0xff;
+ maxintval[TUINT16] = 0xffff;
+ maxintval[TUINT32] = 0xffffffffL;
+
+ /* special case until we got to multiple precision */
+ maxintval[TUINT64] = 0x7fffffffffffffffLL;
+ minintval[TUINT64] = -maxintval[TUINT64]-1;
+
+ maxfloatval[TFLOAT32] = 3.40282347e+38;
+ minfloatval[TFLOAT32] = -maxfloatval[TFLOAT32];
+ maxfloatval[TFLOAT64] = 1.7976931348623157e+308;
+ minfloatval[TFLOAT64] = -maxfloatval[TFLOAT64]-1;
+
+ /*
+ * initialize basic types array
+ * initialize known symbols
+ */
+ for(i=0; i<nelem(syms); i++) {
+ lex = syms[i].lexical;
+ s = lookup(syms[i].name);
+ s->lexical = lex;
+
+ if(lex != LBASETYPE)
+ continue;
+
+ etype = syms[i].etype;
+ if(etype < 0 || etype >= nelem(types))
+ fatal("lexinit: %s bad etype", s->name);
+
+ t = types[etype];
+ if(t != T) {
+ s->otype = t;
+ continue;
+ }
+ t = typ(etype);
+ switch(etype) {
+ case TSTRING:
+ case TCHAN:
+ case TMAP:
+ t = ptrto(t);
+ }
+
+ t->sym = s;
+ t->recur = 1; // supresses printing beyond name
+
+ dowidth(t);
+ types[etype] = t;
+ s->otype = t;
+ }
+
+ /* pick up the backend typedefs */
+ belexinit(LBASETYPE);
+
+ booltrue = nod(OLITERAL, N, N);
+ booltrue->val.ctype = CTBOOL;
+ booltrue->val.vval = 1;
+ booltrue->type = types[TBOOL];
+ booltrue->addable = 1;
+
+ boolfalse = nod(OLITERAL, N, N);
+ boolfalse->val.ctype = CTBOOL;
+ boolfalse->val.vval = 0;
+ boolfalse->type = types[TBOOL];
+ boolfalse->addable = 1;
+}
+
+struct
+{
+ int lex;
+ char* name;
+} lexn[] =
+{
+ LANDAND, "ANDAND",
+ LASOP, "ASOP",
+ LACONST, "ACONST",
+ LATYPE, "ATYPE",
+ LBASETYPE, "BASETYPE",
+ LBREAK, "BREAK",
+ LCASE, "CASE",
+ LCHAN, "CHAN",
+ LCOLAS, "COLAS",
+ LCONST, "CONST",
+ LCONTINUE, "CONTINUE",
+ LDEC, "DEC",
+ LELSE, "ELSE",
+ LEQ, "EQ",
+ LFUNC, "FUNC",
+ LGE, "GE",
+ LGO, "GO",
+ LGOTO, "GOTO",
+ LGT, "GT",
+ LIF, "IF",
+ LINC, "INC",
+ LINTERFACE, "INTERFACE",
+ LLE, "LE",
+ LLITERAL, "LITERAL",
+ LLSH, "LSH",
+ LLT, "LT",
+ LMAP, "MAP",
+ LNAME, "NAME",
+ LNE, "NE",
+ LOROR, "OROR",
+ LPACK, "PACK",
+ LRANGE, "RANGE",
+ LRETURN, "RETURN",
+ LRSH, "RSH",
+ LSTRUCT, "STRUCT",
+ LSWITCH, "SWITCH",
+ LTYPE, "TYPE",
+ LVAR, "VAR",
+ LFOR, "FOR",
+ LNEW, "NEW",
+ LLEN, "LEN",
+ LFALL, "FALL",
+ LCONVERT, "CONVERT",
+ LIOTA, "IOTA",
+ LPRINT, "PRINT",
+ LPACKAGE, "PACKAGE",
+ LIMPORT, "IMPORT",
+ LEXPORT, "EXPORT",
+ LPANIC, "PANIC",
+};
+
+char*
+lexname(int lex)
+{
+ int i;
+ static char buf[100];
+
+ for(i=0; i<nelem(lexn); i++)
+ if(lexn[i].lex == lex)
+ return lexn[i].name;
+ snprint(buf, sizeof(buf), "LEX-%d", lex);
+ return buf;
+}
+
+void
+mkpackage(char* pkg)
+{
+ Sym *s;
+ long h;
+
+ if(bout != nil) {
+ yyerror("mkpackage: called again %s %s", pkg, package);
+ return;
+ }
+
+ // redefine all names to be this package
+ package = pkg;
+ for(h=0; h<NHASH; h++)
+ for(s = hash[h]; s != S; s = s->link) {
+ s->package = package;
+ s->opackage = package;
+ }
+
+ if(outfile == nil) {
+ // BOTCH need to get .6 from backend
+ snprint(namebuf, sizeof(namebuf), "%s.6", package);
+ outfile = strdup(namebuf);
+ }
+}
diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
new file mode 100644
index 0000000..edd1c9d
--- /dev/null
+++ b/src/cmd/gc/mksys.bash
@@ -0,0 +1,19 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+6g sys.go
+echo '1,/((/d
+/))/+1,$d
+1,$s/foop/sys/g
+1,$s/^[ ]*/ "/g
+1,$s/$/\\n"/g
+1i
+char* sysimport =
+.
+$a
+;
+
+.
+w sysimport.c
+q' | ed foop.6
diff --git a/src/cmd/gc/mpatof.c b/src/cmd/gc/mpatof.c
new file mode 100644
index 0000000..07bcf4a
--- /dev/null
+++ b/src/cmd/gc/mpatof.c
@@ -0,0 +1,342 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+
+int mpatof(char*, double*);
+int mpatov(char *s, vlong *v);
+
+enum
+{
+ Mpscale = 29, /* safely smaller than bits in a long */
+ Mpprec = 36, /* Mpscale*Mpprec sb > largest fp exp */
+ Mpbase = 1L<<Mpscale,
+};
+
+typedef
+struct
+{
+ long a[Mpprec];
+ char ovf;
+} Mp;
+
+static void mpint(Mp*, int);
+static void mppow(Mp*, int, int);
+static void mpmul(Mp*, int);
+static void mpadd(Mp*, Mp*);
+static int mptof(Mp*, double*);
+
+/*
+ * convert a string, s, to floating in *d
+ * return conversion overflow.
+ * required syntax is [+-]d*[.]d*[e[+-]d*]
+ */
+int
+mpatof(char *s, double *d)
+{
+ Mp a, b;
+ int dp, c, f, ef, ex, zer;
+ double d1, d2;
+
+ dp = 0; /* digits after decimal point */
+ f = 0; /* sign */
+ ex = 0; /* exponent */
+ zer = 1; /* zero */
+ memset(&a, 0, sizeof(a));
+ for(;;) {
+ switch(c = *s++) {
+ default:
+ goto bad;
+ case '-':
+ f = 1;
+ case ' ':
+ case '\t':
+ case '+':
+ continue;
+ case '.':
+ dp = 1;
+ continue;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ zer = 0;
+ case '0':
+ mpint(&b, c-'0');
+ mpmul(&a, 10);
+ mpadd(&a, &b);
+ if(dp)
+ dp++;
+ continue;
+ case 'E':
+ case 'e':
+ ex = 0;
+ ef = 0;
+ for(;;) {
+ c = *s++;
+ if(c == '+' || c == ' ' || c == '\t')
+ continue;
+ if(c == '-') {
+ ef = 1;
+ continue;
+ }
+ if(c >= '0' && c <= '9') {
+ ex = ex*10 + (c-'0');
+ continue;
+ }
+ break;
+ }
+ if(ef)
+ ex = -ex;
+ case 0:
+ break;
+ }
+ break;
+ }
+ if(a.ovf)
+ goto bad;
+ if(zer) {
+ *d = 0;
+ return 0;
+ }
+ if(dp)
+ dp--;
+ dp -= ex;
+ if(dp > 0) {
+ /*
+ * must divide by 10**dp
+ */
+ if(mptof(&a, &d1))
+ goto bad;
+
+ /*
+ * trial exponent of 8**dp
+ * 8 (being between 5 and 10)
+ * should pick up all underflows
+ * in the division of 5**dp.
+ */
+ d2 = frexp(d1, &ex);
+ d2 = ldexp(d2, ex-3*dp);
+ if(d2 == 0)
+ goto bad;
+
+ /*
+ * decompose each 10 into 5*2.
+ * create 5**dp in fixed point
+ * and then play with the exponent
+ * for the remaining 2**dp.
+ * note that 5**dp will overflow
+ * with as few as 134 input digits.
+ */
+ mpint(&a, 1);
+ mppow(&a, 5, dp);
+ if(mptof(&a, &d2))
+ goto bad;
+ d1 = frexp(d1/d2, &ex);
+ d1 = ldexp(d1, ex-dp);
+ if(d1 == 0)
+ goto bad;
+ } else {
+ /*
+ * must multiply by 10**|dp| --
+ * just do it in fixed point.
+ */
+ mppow(&a, 10, -dp);
+ if(mptof(&a, &d1))
+ goto bad;
+ }
+ if(f)
+ d1 = -d1;
+ *d = d1;
+ return 0;
+
+bad:
+ return 1;
+}
+
+/*
+ * convert a to floating in *d
+ * return conversion overflow
+ */
+static int
+mptof(Mp *a, double *d)
+{
+ double f, g;
+ long x, *a1;
+ int i;
+
+ if(a->ovf)
+ return 1;
+ a1 = a->a;
+ f = ldexp(*a1++, 0);
+ for(i=Mpscale; i<Mpprec*Mpscale; i+=Mpscale)
+ if(x = *a1++) {
+ g = ldexp(x, i);
+ /*
+ * NOTE: the test (g==0) is plan9
+ * specific. ansi compliant overflow
+ * is signaled by HUGE and errno==ERANGE.
+ * change this for your particular ldexp.
+ */
+ if(g == 0)
+ return 1;
+ f += g; /* this could bomb! */
+ }
+ *d = f;
+ return 0;
+}
+
+/*
+ * return a += b
+ */
+static void
+mpadd(Mp *a, Mp *b)
+{
+ int i, c;
+ long x, *a1, *b1;
+
+ if(b->ovf)
+ a->ovf = 1;
+ if(a->ovf)
+ return;
+ c = 0;
+ a1 = a->a;
+ b1 = b->a;
+ for(i=0; i<Mpprec; i++) {
+ x = *a1 + *b1++ + c;
+ c = 0;
+ if(x >= Mpbase) {
+ x -= Mpbase;
+ c = 1;
+ }
+ *a1++ = x;
+ }
+ a->ovf = c;
+}
+
+/*
+ * return a = c
+ */
+static void
+mpint(Mp *a, int c)
+{
+
+ memset(a, 0, sizeof(*a));
+ a->a[0] = c;
+}
+
+/*
+ * return a *= c
+ */
+static void
+mpmul(Mp *a, int c)
+{
+ Mp p;
+ int b;
+ memmove(&p, a, sizeof(p));
+ if(!(c & 1))
+ memset(a, 0, sizeof(*a));
+ c &= ~1;
+ for(b=2; c; b<<=1) {
+ mpadd(&p, &p);
+ if(c & b) {
+ mpadd(a, &p);
+ c &= ~b;
+ }
+ }
+}
+
+/*
+ * return a *= b**e
+ */
+static void
+mppow(Mp *a, int b, int e)
+{
+ int b1;
+
+ b1 = b*b;
+ b1 = b1*b1;
+ while(e >= 4) {
+ mpmul(a, b1);
+ e -= 4;
+ if(a->ovf)
+ return;
+ }
+ while(e > 0) {
+ mpmul(a, b);
+ e--;
+ }
+}
+
+/*
+ * convert a string, s, to vlong in *v
+ * return conversion overflow.
+ * required syntax is [0[x]]d*
+ */
+int
+mpatov(char *s, vlong *v)
+{
+ vlong n, nn;
+ int c;
+ n = 0;
+ c = *s;
+ if(c == '0')
+ goto oct;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ nn = n*10 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+oct:
+ s++;
+ c = *s;
+ if(c == 'x' || c == 'X')
+ goto hex;
+ while(c = *s++) {
+ if(c >= '0' || c <= '7')
+ nn = n*8 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+hex:
+ s++;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ c += 0-'0';
+ else
+ if(c >= 'a' && c <= 'f')
+ c += 10-'a';
+ else
+ if(c >= 'A' && c <= 'F')
+ c += 10-'A';
+ else
+ goto bad;
+ nn = n*16 + c;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+out:
+ *v = n;
+ return 0;
+
+bad:
+ *v = ~0;
+ return 1;
+}
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
new file mode 100644
index 0000000..6f1ad12
--- /dev/null
+++ b/src/cmd/gc/subr.c
@@ -0,0 +1,1591 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+#include "y.tab.h"
+
+void
+errorexit(void)
+{
+ if(outfile)
+ remove(outfile);
+ myexit(1);
+}
+
+void
+myexit(int x)
+{
+ if(x)
+ exits("error");
+ exits(nil);
+}
+
+void
+yyerror(char *fmt, ...)
+{
+ va_list arg;
+ long lno;
+
+ lno = dynlineno;
+ if(lno == 0)
+ lno = curio.lineno;
+
+ print("%s:%ld: ", curio.infile, lno);
+ va_start(arg, fmt);
+ vfprint(1, fmt, arg);
+ va_end(arg);
+ print("\n");
+ if(debug['h'])
+ *(int*)0 = 0;
+
+ nerrors++;
+ if(nerrors >= 10)
+ fatal("too many errors");
+}
+
+void
+warn(char *fmt, ...)
+{
+ va_list arg;
+ long lno;
+
+ lno = dynlineno;
+ if(lno == 0)
+ lno = curio.lineno;
+
+ print("%s:%ld: ", curio.infile, lno);
+ va_start(arg, fmt);
+ vfprint(1, fmt, arg);
+ va_end(arg);
+ print("\n");
+ if(debug['h'])
+ *(int*)0 = 0;
+}
+
+void
+fatal(char *fmt, ...)
+{
+ va_list arg;
+ long lno;
+
+ lno = dynlineno;
+ if(lno == 0)
+ lno = curio.lineno;
+
+ print("%s:%ld: fatal error: ", curio.infile, lno);
+ va_start(arg, fmt);
+ vfprint(1, fmt, arg);
+ va_end(arg);
+ print("\n");
+ if(debug['h'])
+ *(int*)0 = 0;
+ myexit(1);
+}
+
+ulong
+stringhash(char *p)
+{
+ long h;
+ int c;
+
+ h = 0;
+ for(;;) {
+ c = *p++;
+ if(c == 0)
+ break;
+ h = h*PRIME1 + c;
+ }
+
+ if(h < 0) {
+ h = -h;
+ if(h < 0)
+ h = 0;
+ }
+ return h;
+}
+
+Sym*
+lookup(char *p)
+{
+ Sym *s;
+ ulong h;
+ int c;
+
+ h = stringhash(p) % NHASH;
+ c = p[0];
+
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c)
+ continue;
+ if(strcmp(s->name, p) == 0)
+ if(strcmp(s->package, package) == 0)
+ return s;
+ }
+
+ s = mal(sizeof(*s));
+ s->lexical = LNAME;
+ s->name = mal(strlen(p)+1);
+ s->opackage = package;
+ s->package = package;
+
+ strcpy(s->name, p);
+
+ s->link = hash[h];
+ hash[h] = s;
+
+ return s;
+}
+
+Sym*
+pkglookup(char *p, char *k)
+{
+ Sym *s;
+ ulong h;
+ int c;
+
+ h = stringhash(p) % NHASH;
+ c = p[0];
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c)
+ continue;
+ if(strcmp(s->name, p) == 0)
+ if(strcmp(s->package, k) == 0)
+ return s;
+ }
+
+ s = mal(sizeof(*s));
+ s->lexical = LNAME;
+ s->name = mal(strlen(p)+1);
+ strcpy(s->name, p);
+
+ // botch - should probably try to reuse the pkg string
+ s->package = mal(strlen(k)+1);
+ s->opackage = s->package;
+ strcpy(s->package, k);
+
+ s->link = hash[h];
+ hash[h] = s;
+
+ return s;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(thunk >= 10L*NHUNK)
+ nh = 10L*NHUNK;
+ h = (char*)malloc(nh);
+ if(h == (char*)-1) {
+ yyerror("out of memory");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
+
+void*
+mal(long n)
+{
+ void *p;
+
+ while((ulong)hunk & MAXALIGN) {
+ hunk++;
+ nhunk--;
+ }
+ while(nhunk < n)
+ gethunk();
+
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+remal(void *p, long on, long n)
+{
+ void *q;
+
+ q = (uchar*)p + on;
+ if(q != hunk || nhunk < n) {
+ while(nhunk < on+n)
+ gethunk();
+ memmove(hunk, p, on);
+ p = hunk;
+ hunk += on;
+ nhunk -= on;
+ }
+ hunk += n;
+ nhunk -= n;
+ return p;
+}
+
+Dcl*
+dcl(void)
+{
+ Dcl *d;
+
+ d = mal(sizeof(*d));
+ d->lineno = dynlineno;
+ return d;
+}
+
+Node*
+nod(int op, Node *nleft, Node *nright)
+{
+ Node *n;
+
+ n = mal(sizeof(*n));
+ n->op = op;
+ n->left = nleft;
+ n->right = nright;
+ n->lineno = dynlineno;
+ if(dynlineno == 0)
+ n->lineno = curio.lineno;
+ return n;
+}
+
+Type*
+typ(int et)
+{
+ Type *t;
+
+ t = mal(sizeof(*t));
+ t->etype = et;
+ return t;
+}
+
+Node*
+dobad(void)
+{
+ return nod(OBAD, N, N);
+}
+
+Node*
+nodintconst(long v)
+{
+ Node *c;
+
+ c = nod(OLITERAL, N, N);
+ c->addable = 1;
+ c->val.vval = v;
+ c->val.ctype = CTINT;
+ c->type = types[TINT32];
+ ullmancalc(c);
+ return c;
+}
+
+Node*
+rev(Node *na)
+{
+ Node *i, *n;
+
+ /*
+ * since yacc wants to build lists
+ * stacked down on the left -
+ * this routine converts them to
+ * stack down on the right -
+ * in memory without recursion
+ */
+
+ if(na == N || na->op != OLIST)
+ return na;
+ i = na;
+ for(n = na->left; n != N; n = n->left) {
+ if(n->op != OLIST)
+ break;
+ i->left = n->right;
+ n->right = i;
+ i = n;
+ }
+ i->left = n;
+ return i;
+}
+
+Node*
+unrev(Node *na)
+{
+ Node *i, *n;
+
+ /*
+ * this restores a reverse list
+ */
+ if(na == N || na->op != OLIST)
+ return na;
+ i = na;
+ for(n = na->right; n != N; n = n->right) {
+ if(n->op != OLIST)
+ break;
+ i->right = n->left;
+ n->left = i;
+ i = n;
+ }
+ i->right = n;
+ return i;
+}
+
+Type*
+aindex(Node *b, Type *t)
+{
+ Type *r;
+
+ r = typ(TARRAY);
+ r->type = t;
+
+ if(t->etype == TDARRAY)
+ yyerror("dynamic array type cannot be a dynamic array");
+
+ walktype(b, 0);
+ switch(whatis(b)) {
+ default:
+ yyerror("array bound must be a constant integer expression");
+ break;
+
+ case Wnil: // default zero lb
+ r->bound = 0;
+ break;
+
+ case Wlitint: // fixed lb
+ r->bound = b->val.vval;
+ break;
+ }
+ return r;
+}
+
+void
+indent(int dep)
+{
+ int i;
+
+ for(i=0; i<dep; i++)
+ print(". ");
+}
+
+void
+dodump(Node *n, int dep)
+{
+
+loop:
+ if(n == N)
+ return;
+
+ switch(n->op) {
+ case OLIST:
+ if(n->left != N && n->left->op == OLIST)
+ dodump(n->left, dep+1);
+ else
+ dodump(n->left, dep);
+ n = n->right;
+ goto loop;
+
+// case ODCLFUNC:
+// dodump(n->nname, dep);
+// if(n->this) {
+// indent(dep);
+// print("%O-this\n", n->op);
+// dodump(n->this, dep+1);
+// }
+// if(n->argout) {
+// indent(dep);
+// print("%O-outarg\n", n->op);
+// dodump(n->argout, dep+1);
+// }
+// if(n->argin) {
+// indent(dep);
+// print("%O-inarg\n", n->op);
+// dodump(n->argin, dep+1);
+// }
+// n = n->nbody;
+// goto loop;
+
+ case OIF:
+ case OSWITCH:
+ case OFOR:
+ dodump(n->ninit, dep);
+ break;
+ }
+
+ indent(dep);
+ if(dep > 10) {
+ print("...\n");
+ return;
+ }
+
+ switch(n->op) {
+ default:
+ print("%N\n", n);
+ break;
+
+ case OTYPE:
+ print("%O-%E %lT\n", n->op, n->etype, n);
+ break;
+
+ case OIF:
+ print("%O%J\n", n->op, n);
+ dodump(n->ntest, dep+1);
+ if(n->nbody != N) {
+ indent(dep);
+ print("%O-then\n", n->op);
+ dodump(n->nbody, dep+1);
+ }
+ if(n->nelse != N) {
+ indent(dep);
+ print("%O-else\n", n->op);
+ dodump(n->nelse, dep+1);
+ }
+ return;
+
+ case OSWITCH:
+ case OFOR:
+ print("%O%J\n", n->op, n);
+ dodump(n->ntest, dep+1);
+
+ if(n->nbody != N) {
+ indent(dep);
+ print("%O-body\n", n->op);
+ dodump(n->nbody, dep+1);
+ }
+
+ if(n->nincr != N) {
+ indent(dep);
+ print("%O-incr\n", n->op);
+ dodump(n->nincr, dep+1);
+ }
+ return;
+
+ case OCASE:
+ // the right side points to the next case
+ print("%O%J\n", n->op, n);
+ dodump(n->left, dep+1);
+ return;
+ }
+
+ dodump(n->left, dep+1);
+ n = n->right;
+ dep++;
+ goto loop;
+}
+
+void
+dump(char *s, Node *n)
+{
+ print("%s\n", s);
+ dodump(n, 1);
+}
+
+int
+whatis(Node *n)
+{
+ Type *t;
+
+ if(n == N)
+ return Wnil;
+
+ if(n->op == OLITERAL) {
+ switch(n->val.ctype) {
+ default:
+ break;
+ case CTINT:
+ case CTSINT:
+ case CTUINT:
+ return Wlitint;
+ case CTFLT:
+ return Wlitfloat;
+ case CTBOOL:
+ return Wlitbool;
+ case CTSTR:
+ return Wlitstr;
+ }
+ return Wtunkn;
+ }
+
+ t = n->type;
+ if(t == T)
+ return Wtnil;
+
+ switch(t->etype) {
+ case TINT8:
+ case TINT16:
+ case TINT32:
+ case TINT64:
+ case TUINT8:
+ case TUINT16:
+ case TUINT32:
+ case TUINT64:
+ return Wtint;
+ case TFLOAT32:
+ case TFLOAT64:
+ case TFLOAT80:
+ return Wtfloat;
+ case TBOOL:
+ return Wtbool;
+
+ case TPTR32:
+ case TPTR64:
+ if(isptrto(t, TSTRING))
+ return Wtstr;
+ break;
+ }
+ return Wtunkn;
+}
+
+/*
+s%,%,\n%g
+s%\n+%\n%g
+s%^[ ]*O%%g
+s%,.*%%g
+s%.+% [O&] = "&",%g
+s%^ ........*\]%&~%g
+s%~ %%g
+*/
+
+static char*
+opnames[] =
+{
+ [OADDR] = "ADDR",
+ [OADD] = "ADD",
+ [OANDAND] = "ANDAND",
+ [OAND] = "AND",
+ [OARRAY] = "ARRAY",
+ [OASOP] = "ASOP",
+ [OAS] = "AS",
+ [OBAD] = "BAD",
+ [OBREAK] = "BREAK",
+ [OCALL] = "CALL",
+ [OCALLMETH] = "CALLMETH",
+ [OCALLINTER] = "CALLINTER",
+ [OCASE] = "CASE",
+ [OXCASE] = "XCASE",
+ [OCMP] = "CMP",
+ [OFALL] = "FALL",
+ [OCONV] = "CONV",
+ [OCOM] = "COM",
+ [OCONST] = "CONST",
+ [OCONTINUE] = "CONTINUE",
+ [ODCLARG] = "DCLARG",
+ [ODCLFIELD] = "DCLFIELD",
+ [ODCLFUNC] = "DCLFUNC",
+ [ODIV] = "DIV",
+ [ODOT] = "DOT",
+ [ODOTPTR] = "DOTPTR",
+ [ODOTMETH] = "DOTMETH",
+ [ODOTINTER] = "DOTINTER",
+ [OEMPTY] = "EMPTY",
+ [OEND] = "END",
+ [OEQ] = "EQ",
+ [OFOR] = "FOR",
+ [OFUNC] = "FUNC",
+ [OGE] = "GE",
+ [OPROC] = "PROC",
+ [OGOTO] = "GOTO",
+ [OGT] = "GT",
+ [OIF] = "IF",
+ [OINDEX] = "INDEX",
+ [OINDEXPTR] = "INDEXPTR",
+ [OIND] = "IND",
+ [OLABEL] = "LABEL",
+ [OLE] = "LE",
+ [OLEN] = "LEN",
+ [OLIST] = "LIST",
+ [OLITERAL] = "LITERAL",
+ [OLSH] = "LSH",
+ [OLT] = "LT",
+ [OMINUS] = "MINUS",
+ [OMOD] = "MOD",
+ [OMUL] = "MUL",
+ [ONAME] = "NAME",
+ [ONE] = "NE",
+ [ONOT] = "NOT",
+ [OOROR] = "OROR",
+ [OOR] = "OR",
+ [OPLUS] = "PLUS",
+ [ODEC] = "DEC",
+ [OINC] = "INC",
+ [OREGISTER] = "REGISTER",
+ [OINDREG] = "INDREG",
+ [OSEND] = "SEND",
+ [ORECV] = "RECV",
+ [OPTR] = "PTR",
+ [ORETURN] = "RETURN",
+ [ORSH] = "RSH",
+ [OI2S] = "I2S",
+ [OS2I] = "S2I",
+ [OI2I] = "I2I",
+ [OSLICE] = "SLICE",
+ [OSUB] = "SUB",
+ [OSWITCH] = "SWITCH",
+ [OTYPE] = "TYPE",
+ [OVAR] = "VAR",
+ [OEXPORT] = "EXPORT",
+ [OIMPORT] = "IMPORT",
+ [OXOR] = "XOR",
+ [ONEW] = "NEW",
+ [OFALL] = "FALL",
+ [OXFALL] = "XFALL",
+ [OPANIC] = "PANIC",
+ [OPRINT] = "PRINT",
+ [OXXX] = "XXX",
+};
+
+int
+Oconv(Fmt *fp)
+{
+ char buf[500];
+ int o;
+
+ o = va_arg(fp->args, int);
+ if(o < 0 || o >= nelem(opnames) || opnames[o] == nil) {
+ snprint(buf, sizeof(buf), "O-%d", o);
+ return fmtstrcpy(fp, buf);
+ }
+ return fmtstrcpy(fp, opnames[o]);
+}
+
+/*
+s%,%,\n%g
+s%\n+%\n%g
+s%^[ ]*T%%g
+s%,.*%%g
+s%.+% [T&] = "&",%g
+s%^ ........*\]%&~%g
+s%~ %%g
+*/
+
+static char*
+etnames[] =
+{
+ [TINT8] = "INT8",
+ [TUINT8] = "UINT8",
+ [TINT16] = "INT16",
+ [TUINT16] = "UINT16",
+ [TINT32] = "INT32",
+ [TUINT32] = "UINT32",
+ [TINT64] = "INT64",
+ [TUINT64] = "UINT64",
+ [TFLOAT32] = "FLOAT32",
+ [TFLOAT64] = "FLOAT64",
+ [TFLOAT80] = "FLOAT80",
+ [TBOOL] = "BOOL",
+ [TPTR32] = "PTR32",
+ [TPTR64] = "PTR64",
+ [TFUNC] = "FUNC",
+ [TARRAY] = "ARRAY",
+ [TDARRAY] = "DARRAY",
+ [TSTRUCT] = "STRUCT",
+ [TCHAN] = "CHAN",
+ [TMAP] = "MAP",
+ [TINTER] = "INTER",
+ [TFORW] = "FORW",
+ [TFIELD] = "FIELD",
+ [TSTRING] = "STRING",
+ [TCHAN] = "CHAN",
+};
+
+int
+Econv(Fmt *fp)
+{
+ char buf[500];
+ int et;
+
+ et = va_arg(fp->args, int);
+ if(et < 0 || et >= nelem(etnames) || etnames[et] == nil) {
+ snprint(buf, sizeof(buf), "E-%d", et);
+ return fmtstrcpy(fp, buf);
+ }
+ return fmtstrcpy(fp, etnames[et]);
+}
+
+int
+Jconv(Fmt *fp)
+{
+ char buf[500], buf1[100];
+ Node *n;
+
+ n = va_arg(fp->args, Node*);
+ strcpy(buf, "");
+
+ if(n->ullman != 0) {
+ snprint(buf1, sizeof(buf1), " u(%d)", n->ullman);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+ if(n->addable != 0) {
+ snprint(buf1, sizeof(buf1), " a(%d)", n->addable);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+ if(n->vargen != 0) {
+ snprint(buf1, sizeof(buf1), " g(%ld)", n->vargen);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+ if(n->lineno != 0) {
+ snprint(buf1, sizeof(buf1), " l(%ld)", n->lineno);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+ return fmtstrcpy(fp, buf);
+}
+
+int
+Gconv(Fmt *fp)
+{
+ char buf[100];
+ Type *t;
+
+ t = va_arg(fp->args, Type*);
+
+ if(t->etype == TFUNC) {
+ if(t->vargen != 0) {
+ snprint(buf, sizeof(buf), "-%d%d%d g(%ld)",
+ t->thistuple, t->outtuple, t->intuple, t->vargen);
+ goto out;
+ }
+ snprint(buf, sizeof(buf), "-%d%d%d",
+ t->thistuple, t->outtuple, t->intuple);
+ goto out;
+ }
+ if(t->vargen != 0) {
+ snprint(buf, sizeof(buf), " g(%ld)", t->vargen);
+ goto out;
+ }
+ strcpy(buf, "");
+
+out:
+ return fmtstrcpy(fp, buf);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ char buf[500];
+ Sym *s;
+ char *opk, *pkg, *nam;
+
+ s = va_arg(fp->args, Sym*);
+ if(s == S) {
+ snprint(buf, sizeof(buf), "<S>");
+ goto out;
+ }
+
+ pkg = "<nil>";
+ nam = pkg;
+ opk = pkg;
+
+ if(s->opackage != nil)
+ opk = s->opackage;
+ if(s->package != nil)
+ pkg = s->package;
+ if(s->name != nil)
+ nam = s->name;
+
+ if(strcmp(pkg, package) || strcmp(opk, package) || (fp->flags & FmtLong)) {
+ if(strcmp(opk, pkg) == 0) {
+ snprint(buf, sizeof(buf), "%s.%s", pkg, nam);
+ goto out;
+ }
+ snprint(buf, sizeof(buf), "(%s)%s.%s", opk, pkg, nam);
+ goto out;
+ }
+ snprint(buf, sizeof(buf), "%s", nam);
+
+out:
+ return fmtstrcpy(fp, buf);
+}
+
+int
+Tconv(Fmt *fp)
+{
+ char buf[500], buf1[500];
+ Type *t, *t1;
+ int et;
+
+ t = va_arg(fp->args, Type*);
+ if(t == T)
+ return fmtstrcpy(fp, "<T>");
+
+ t->trecur++;
+ et = t->etype;
+
+ strcpy(buf, "");
+ if(t->sym != S) {
+ snprint(buf, sizeof(buf), "<%S>", t->sym);
+ }
+ if(t->trecur > 5) {
+ strncat(buf, "...", sizeof(buf));
+ goto out;
+ }
+
+ switch(et) {
+ default:
+ snprint(buf1, sizeof(buf1), "%E", et);
+ strncat(buf, buf1, sizeof(buf));
+ if(t->type != T) {
+ snprint(buf1, sizeof(buf1), " %T", t->type);
+ strncat(buf, buf1, sizeof(buf));
+ }
+ break;
+
+ case TFIELD:
+ snprint(buf1, sizeof(buf1), "%T", t->type);
+ strncat(buf, buf1, sizeof(buf));
+ break;
+
+ case TFUNC:
+ if(fp->flags & FmtLong)
+ snprint(buf1, sizeof(buf1), "%d%d%d(%lT,%lT,%lT)",
+ t->thistuple, t->outtuple, t->intuple,
+ t->type, t->type->down, t->type->down->down);
+ else
+ snprint(buf1, sizeof(buf1), "%d%d%d(%T,%T,%T)",
+ t->thistuple, t->outtuple, t->intuple,
+ t->type, t->type->down, t->type->down->down);
+ strncat(buf, buf1, sizeof(buf));
+ break;
+
+ case TINTER:
+ strncat(buf, "I{", sizeof(buf));
+ if(fp->flags & FmtLong) {
+ for(t1=t->type; t1!=T; t1=t1->down) {
+ snprint(buf1, sizeof(buf1), "%lT;", t1);
+ strncat(buf, buf1, sizeof(buf));
+ }
+ }
+ strncat(buf, "}", sizeof(buf));
+ break;
+
+ case TSTRUCT:
+ strncat(buf, "{", sizeof(buf));
+ if(fp->flags & FmtLong) {
+ for(t1=t->type; t1!=T; t1=t1->down) {
+ snprint(buf1, sizeof(buf1), "%lT;", t1);
+ strncat(buf, buf1, sizeof(buf));
+ }
+ }
+ strncat(buf, "}", sizeof(buf));
+ break;
+
+ case TMAP:
+ snprint(buf, sizeof(buf), "[%T]%T", t->down, t->type);
+ break;
+
+ case TARRAY:
+ snprint(buf1, sizeof(buf1), "[%ld]%T", t->bound, t->type);
+ strncat(buf, buf1, sizeof(buf));
+ break;
+
+ case TDARRAY:
+ snprint(buf1, sizeof(buf1), "[]%T", t->type);
+ strncat(buf, buf1, sizeof(buf));
+ break;
+
+ case TPTR32:
+ case TPTR64:
+ snprint(buf1, sizeof(buf1), "*%T", t->type);
+ strncat(buf, buf1, sizeof(buf));
+ break;
+ }
+
+out:
+ t->trecur--;
+ return fmtstrcpy(fp, buf);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char buf[500], buf1[500];
+ Node *n;
+
+ n = va_arg(fp->args, Node*);
+ if(n == N) {
+ snprint(buf, sizeof(buf), "<N>");
+ goto out;
+ }
+
+ switch(n->op) {
+ default:
+ snprint(buf, sizeof(buf), "%O%J", n->op, n);
+ break;
+
+ case ONAME:
+ if(n->sym == S) {
+ snprint(buf, sizeof(buf), "%O%J", n->op, n);
+ break;
+ }
+ snprint(buf, sizeof(buf), "%O-%S G%ld%J", n->op,
+ n->sym, n->sym->vargen, n);
+ goto ptyp;
+
+ case OREGISTER:
+ snprint(buf, sizeof(buf), "%O-%R%J", n->op, (int)n->val.vval, n);
+ break;
+
+ case OLITERAL:
+ switch(n->val.ctype) {
+ default:
+ snprint(buf1, sizeof(buf1), "LITERAL-ctype=%d%lld", n->val.ctype, n->val.vval);
+ break;
+ case CTINT:
+ snprint(buf1, sizeof(buf1), "I%lld", n->val.vval);
+ break;
+ case CTSINT:
+ snprint(buf1, sizeof(buf1), "S%lld", n->val.vval);
+ break;
+ case CTUINT:
+ snprint(buf1, sizeof(buf1), "U%lld", n->val.vval);
+ break;
+ case CTFLT:
+ snprint(buf1, sizeof(buf1), "F%g", n->val.dval);
+ break;
+ case CTSTR:
+ snprint(buf1, sizeof(buf1), "S\"%Z\"", n->val.sval);
+ break;
+ case CTBOOL:
+ snprint(buf1, sizeof(buf1), "B%lld", n->val.vval);
+ break;
+ case CTNIL:
+ snprint(buf1, sizeof(buf1), "N");
+ break;
+ }
+ snprint(buf, sizeof(buf), "%O-%s%J", n->op, buf1, n);
+ break;
+
+ case OASOP:
+ snprint(buf, sizeof(buf), "%O-%O%J", n->op, n->etype, n);
+ break;
+
+ case OTYPE:
+ snprint(buf, sizeof(buf), "%O-%E%J", n->op, n->etype, n);
+ break;
+ }
+ if(n->sym != S) {
+ snprint(buf1, sizeof(buf1), " %S G%ld", n->sym, n->sym->vargen);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+ptyp:
+ if(n->type != T) {
+ snprint(buf1, sizeof(buf1), " %T", n->type);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+out:
+ return fmtstrcpy(fp, buf);
+}
+
+int
+Zconv(Fmt *fp)
+{
+ char *s, *se;
+ char *p;
+ char buf[500];
+ int c;
+ String *sp;
+
+ sp = va_arg(fp->args, String*);
+ if(sp == nil) {
+ snprint(buf, sizeof(buf), "<nil>");
+ goto out;
+ }
+ s = sp->s;
+ se = s + sp->len;
+
+ p = buf;
+
+loop:
+ c = *s++;
+ if(s > se)
+ c = 0;
+ switch(c) {
+ default:
+ *p++ = c;
+ break;
+ case 0:
+ *p = 0;
+ goto out;
+ case '\t':
+ *p++ = '\\';
+ *p++ = 't';
+ break;
+ case '\n':
+ *p++ = '\\';
+ *p++ = 'n';
+ break;
+ }
+ goto loop;
+
+out:
+ return fmtstrcpy(fp, buf);
+}
+
+int
+isnil(Node *n)
+{
+ if(n == N)
+ return 0;
+ if(n->op != OLITERAL)
+ return 0;
+ if(n->val.ctype != CTNIL)
+ return 0;
+ return 1;
+}
+
+int
+isptrto(Type *t, int et)
+{
+ if(t == T)
+ return 0;
+ if(!isptr[t->etype])
+ return 0;
+ t = t->type;
+ if(t == T)
+ return 0;
+ if(t->etype != et)
+ return 0;
+ return 1;
+}
+
+int
+isinter(Type *t)
+{
+ if(t != T && t->etype == TINTER)
+ return 1;
+ return 0;
+}
+
+int
+isbytearray(Type *t)
+{
+ if(t == T)
+ return 0;
+ if(isptr[t->etype]) {
+ t = t->type;
+ if(t == T)
+ return 0;
+ }
+ if(t->etype != TARRAY)
+ return 0;
+ return t->bound+1;
+}
+
+int
+eqtype(Type *t1, Type *t2, int d)
+{
+ if(d >= 10)
+ return 1;
+
+ if(t1 == t2)
+ return 1;
+ if(t1 == T || t2 == T)
+ return 0;
+
+ if(t1->etype != t2->etype)
+ return 0;
+
+ switch(t1->etype) {
+ case TINTER:
+ case TSTRUCT:
+ t1 = t1->type;
+ t2 = t2->type;
+ for(;;) {
+ if(!eqtype(t1, t2, 0))
+ return 0;
+ if(t1 == T)
+ return 1;
+ if(t1->nname != N && t1->nname->sym != S) {
+ if(t2->nname == N || t2->nname->sym == S)
+ return 0;
+ if(strcmp(t1->nname->sym->name, t2->nname->sym->name) != 0) {
+ // assigned names dont count
+ if(t1->nname->sym->name[0] != '_' ||
+ t2->nname->sym->name[0] != '_')
+ return 0;
+ }
+ }
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ return 1;
+
+ case TFUNC:
+ t1 = t1->type;
+ t2 = t2->type;
+ for(;;) {
+ if(t1 == t2)
+ break;
+ if(t1 == T || t2 == T)
+ return 0;
+ if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
+ return 0;
+
+ if(!eqtype(t1->type, t2->type, 0))
+ return 0;
+
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ return 1;
+ }
+ return eqtype(t1->type, t2->type, d+1);
+}
+
+/*
+ * are the arg names of two
+ * functions the same. we know
+ * that eqtype has been called
+ * and has returned true.
+ */
+int
+eqargs(Type *t1, Type *t2)
+{
+ if(t1 == t2)
+ return 1;
+ if(t1 == T || t2 == T)
+ return 0;
+
+ if(t1->etype != t2->etype)
+ return 0;
+
+ if(t1->etype != TFUNC)
+ fatal("eqargs: oops %E", t1->etype);
+
+ t1 = t1->type;
+ t2 = t2->type;
+ for(;;) {
+ if(t1 == t2)
+ break;
+ if(!eqtype(t1, t2, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ return 1;
+}
+
+ulong
+typehash(Type *at, int d)
+{
+ ulong h;
+ Type *t;
+
+ if(at == T)
+ return PRIME2;
+ if(d >= 5)
+ return PRIME3;
+
+ if(at->recur)
+ return 0;
+ at->recur = 1;
+
+ h = at->etype*PRIME4;
+
+ switch(at->etype) {
+ default:
+ h += PRIME5 * typehash(at->type, d+1);
+ break;
+
+ case TINTER:
+ // botch -- should be sorted?
+ for(t=at->type; t!=T; t=t->down)
+ h += PRIME6 * typehash(t, d+1);
+ break;
+
+ case TSTRUCT:
+ for(t=at->type; t!=T; t=t->down)
+ h += PRIME7 * typehash(t, d+1);
+ break;
+
+ case TFUNC:
+ t = at->type;
+ // skip this argument
+ if(t != T)
+ t = t->down;
+ for(; t!=T; t=t->down)
+ h += PRIME7 * typehash(t, d+1);
+ break;
+ }
+
+ at->recur = 0;
+ return h;
+}
+
+Type*
+ptrto(Type *t)
+{
+ Type *t1;
+
+ if(tptr == 0)
+ fatal("ptrto: nil");
+ t1 = typ(tptr);
+ t1->type = t;
+ return t1;
+}
+
+Node*
+literal(long v)
+{
+ Node *n;
+
+ n = nod(OLITERAL, N, N);
+ n->val.ctype = CTINT;
+ n->val.vval = v;
+ return n;
+}
+
+void
+frame(int context)
+{
+ char *p;
+ Dcl *d;
+ int flag;
+
+ p = "stack";
+ d = autodcl;
+ if(context) {
+ p = "external";
+ d = externdcl;
+ }
+
+ flag = 1;
+ for(; d!=D; d=d->forw) {
+ switch(d->op) {
+ case ONAME:
+ if(flag)
+ print("--- %s frame ---\n", p);
+ print("%O %S G%ld T\n", d->op, d->dsym, d->dnode->vargen, d->dnode->type);
+ flag = 0;
+ break;
+
+ case OTYPE:
+ if(flag)
+ print("--- %s frame ---\n", p);
+ print("%O %lT\n", d->op, d->dnode);
+ flag = 0;
+ break;
+ }
+ }
+}
+
+/*
+ * calculate sethi/ullman number
+ * roughly how many registers needed to
+ * compile a node. used to compile the
+ * hardest side first to minimize registers.
+ */
+void
+ullmancalc(Node *n)
+{
+ int ul, ur;
+
+ if(n == N)
+ return;
+
+ switch(n->op) {
+ case OLITERAL:
+ case ONAME:
+ ul = 0;
+ goto out;
+ case OS2I:
+ case OI2S:
+ case OI2I:
+ case OCALL:
+ ul = UINF;
+ goto out;
+ }
+ ul = 0;
+ if(n->left != N)
+ ul = n->left->ullman;
+ ur = 0;
+ if(n->right != N)
+ ur = n->right->ullman;
+ if(ul == ur)
+ ul += 1;
+ if(ur > ul)
+ ul = ur;
+
+out:
+ n->ullman = ul;
+}
+
+void
+badtype(int o, Type *tl, Type *tr)
+{
+ yyerror("illegal types for operand");
+ if(tl != T)
+ print(" (%T)", tl);
+ print(" %O ", o);
+ if(tr != T)
+ print("(%T)", tr);
+ print("\n");
+}
+
+/*
+ * this routine gets the parsing of
+ * a parameter list that can have
+ * name, type and name-type.
+ * it must distribute lone names
+ * with trailing types to give every
+ * name a type. (a,b,c int) comes out
+ * (a int, b int, c int).
+ */
+Node*
+cleanidlist(Node *r)
+{
+ Node *t, *n, *nn, *l;
+ Type *dt;
+
+ t = N; // untyped name
+ nn = r; // next node to take
+
+loop:
+ n = nn;
+ if(n == N) {
+ if(t != N) {
+ yyerror("syntax error in parameter list");
+ dt = types[TINT32];
+ goto distrib;
+ }
+ return r;
+ }
+
+ l = n;
+ nn = N;
+ if(l->op == OLIST) {
+ nn = l->right;
+ l = l->left;
+ }
+
+ if(l->op != ODCLFIELD)
+ fatal("cleanformal: %O", n->op);
+
+ if(l->type == T) {
+ if(t == N)
+ t = n;
+ goto loop;
+ }
+
+ if(t == N)
+ goto loop;
+
+ dt = l->type; // type to be distributed
+
+distrib:
+ while(t != n) {
+ if(t->op != OLIST) {
+ if(t->type == T)
+ t->type = dt;
+ break;
+ }
+ if(t->left->type == T)
+ t->left->type = dt;
+ t = t->right;
+ }
+
+ t = N;
+ goto loop;
+}
+
+/*
+ * iterator to walk a structure declaration
+ */
+Type*
+structfirst(Iter *s, Type **nn)
+{
+ Type *n, *t;
+
+ n = *nn;
+ if(n == T)
+ goto bad;
+
+ switch(n->etype) {
+ default:
+ goto bad;
+
+ case TSTRUCT:
+ case TINTER:
+ case TFUNC:
+ break;
+ }
+
+ t = n->type;
+ if(t == T)
+ goto rnil;
+
+ if(t->etype != TFIELD)
+ fatal("structfirst: not field %T", t);
+
+ s->t = t;
+ return t;
+
+bad:
+ fatal("structfirst: not struct %T", n);
+
+rnil:
+ return T;
+}
+
+Type*
+structnext(Iter *s)
+{
+ Type *n, *t;
+
+ n = s->t;
+ t = n->down;
+ if(t == T)
+ goto rnil;
+
+ if(t->etype != TFIELD)
+ goto bad;
+
+ s->t = t;
+ return t;
+
+bad:
+ fatal("structnext: not struct %T", n);
+
+rnil:
+ return T;
+}
+
+/*
+ * iterator to this and inargs in a function
+ */
+Type*
+funcfirst(Iter *s, Type *t)
+{
+ Type *fp;
+
+ if(t == T)
+ goto bad;
+
+ if(t->etype != TFUNC)
+ goto bad;
+
+ s->tfunc = t;
+ s->done = 0;
+ fp = structfirst(s, getthis(t));
+ if(fp == T) {
+ s->done = 1;
+ fp = structfirst(s, getinarg(t));
+ }
+ return fp;
+
+bad:
+ fatal("funcfirst: not func %T", t);
+ return T;
+}
+
+Type*
+funcnext(Iter *s)
+{
+ Type *fp;
+
+ fp = structnext(s);
+ if(fp == T && !s->done) {
+ s->done = 1;
+ fp = structfirst(s, getinarg(s->tfunc));
+ }
+ return fp;
+}
+
+/*
+ * iterator to walk a list
+ */
+Node*
+listfirst(Iter *s, Node **nn)
+{
+ Node *n;
+
+ n = *nn;
+ if(n == N) {
+ s->done = 1;
+ s->an = &s->n;
+ s->n = N;
+ return N;
+ }
+
+ if(n->op == OLIST) {
+ s->done = 0;
+ s->n = n;
+ s->an = &n->left;
+ return n->left;
+ }
+
+ s->done = 1;
+ s->an = nn;
+ return n;
+}
+
+Node*
+listnext(Iter *s)
+{
+ Node *n, *r;
+
+ if(s->done) {
+ s->an = &s->n;
+ s->n = N;
+ return N;
+ }
+
+ n = s->n;
+ r = n->right;
+ if(r->op == OLIST) {
+ s->n = r;
+ s->an = &r->left;
+ return r->left;
+ }
+
+ s->done = 1;
+ s->an = &n->right;
+ return n->right;
+}
+
+Type**
+getthis(Type *t)
+{
+ if(t->etype != TFUNC)
+ fatal("getthis: not a func %N", t);
+ return &t->type;
+}
+
+Type**
+getoutarg(Type *t)
+{
+ if(t->etype != TFUNC)
+ fatal("getoutarg: not a func %N", t);
+ return &t->type->down;
+}
+
+Type**
+getinarg(Type *t)
+{
+ if(t->etype != TFUNC)
+ fatal("getinarg: not a func %N", t);
+ return &t->type->down->down;
+}
+
+Type*
+getthisx(Type *t)
+{
+ return *getthis(t);
+}
+
+Type*
+getoutargx(Type *t)
+{
+ return *getoutarg(t);
+}
+
+Type*
+getinargx(Type *t)
+{
+ return *getinarg(t);
+}
diff --git a/src/cmd/gc/sys.go b/src/cmd/gc/sys.go
new file mode 100644
index 0000000..19b5c2e
--- /dev/null
+++ b/src/cmd/gc/sys.go
@@ -0,0 +1,44 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package foop // rename to avoid redeclaration
+
+func mal(uint32) *byte;
+func breakpoint();
+func panicl(int32);
+
+func printbool(bool);
+func printfloat(double);
+func printint(int64);
+func printstring(string);
+func printpointer(*byte);
+
+func catstring(string, string) string;
+func cmpstring(string, string) int32;
+func slicestring(string, int32, int32) string;
+func indexstring(string, int32) byte;
+func intstring(int64) string;
+func byteastring(*byte, int32) string;
+func mkiface(*byte, *byte, *struct{}) interface{};
+
+export
+ mal
+ breakpoint
+ panicl
+
+ printbool
+ printfloat
+ printint
+ printstring
+ printpointer
+
+ catstring
+ cmpstring
+ slicestring
+ indexstring
+ intstring
+ byteastring
+ mkiface
+ ;
diff --git a/src/cmd/gc/sysimport.c b/src/cmd/gc/sysimport.c
new file mode 100644
index 0000000..f6ff105
--- /dev/null
+++ b/src/cmd/gc/sysimport.c
@@ -0,0 +1,2 @@
+;
+
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
new file mode 100644
index 0000000..995c641
--- /dev/null
+++ b/src/cmd/gc/walk.c
@@ -0,0 +1,1278 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+static Type* sw1(Node*, Type*);
+static Type* sw2(Node*, Type*);
+static Type* sw3(Node*, Type*);
+static Node* curfn;
+
+void
+walk(Node *fn)
+{
+ curfn = fn;
+ walktype(fn->nbody, 1);
+}
+
+void
+walktype(Node *n, int top)
+{
+ Node *r, *l;
+ Type *t;
+ Sym *s;
+ long lno;
+ int et;
+
+ /*
+ * walk the whole tree of the body of a function.
+ * the types expressions are calculated.
+ * compile-time constants are evaluated.
+ */
+
+ lno = dynlineno;
+
+loop:
+ if(n == N)
+ goto ret;
+ if(n->op != ONAME)
+ dynlineno = n->lineno; // for diagnostics
+
+ t = T;
+ et = Txxx;
+
+ switch(n->op) {
+ default:
+ fatal("walktype: switch 1 unknown op %N", n);
+ goto ret;
+
+ case OPRINT:
+ walktype(n->left, 0);
+ *n = *prcompat(n->left);
+ goto ret;
+
+ case OPANIC:
+ walktype(n->left, 0);
+ *n = *nod(OLIST, prcompat(n->left), nodpanic(n->lineno));
+ goto ret;
+
+ case OLITERAL:
+ n->addable = 1;
+ ullmancalc(n);
+ goto ret;
+
+ case ONAME:
+ n->addable = 1;
+ ullmancalc(n);
+ if(n->type == T) {
+ s = n->sym;
+ if(s->undef == 0) {
+ yyerror("walktype: %N undeclared", n);
+ s->undef = 1;
+ }
+ }
+ goto ret;
+
+ case OLIST:
+ walktype(n->left, top);
+ n = n->right;
+ goto loop;
+
+ case OFOR:
+ if(!top)
+ goto nottop;
+ walktype(n->ninit, 1);
+ walktype(n->ntest, 1);
+ walktype(n->nincr, 1);
+ n = n->nbody;
+ goto loop;
+
+ case OSWITCH:
+ if(!top)
+ goto nottop;
+
+ if(n->ntest == N)
+ n->ntest = booltrue;
+ walktype(n->ninit, 1);
+ walktype(n->ntest, 1);
+ walktype(n->nbody, 1);
+
+ // find common type
+ if(n->ntest->type == T)
+ n->ntest->type = walkswitch(n->ntest, n->nbody, sw1);
+
+ // if that fails pick a type
+ if(n->ntest->type == T)
+ n->ntest->type = walkswitch(n->ntest, n->nbody, sw2);
+
+ // set the type on all literals
+ if(n->ntest->type != T)
+ walkswitch(n->ntest, n->nbody, sw3);
+
+ walktype(n->ntest, 1);
+
+ n = n->nincr;
+ goto loop;
+
+ case OEMPTY:
+ if(!top)
+ goto nottop;
+ goto ret;
+
+ case OIF:
+ if(!top)
+ goto nottop;
+ walktype(n->ninit, 1);
+ walktype(n->ntest, 1);
+ walktype(n->nelse, 1);
+ n = n->nbody;
+ goto loop;
+
+ case OCALLMETH:
+ case OCALLINTER:
+ case OCALL:
+ n->ullman = UINF;
+ if(n->type != T)
+ goto ret;
+
+ walktype(n->left, 0);
+ if(n->left == N)
+ goto ret;
+
+ t = n->left->type;
+ if(t == T)
+ goto ret;
+
+ dowidth(t);
+ if(n->left->op == ODOTMETH)
+ n->op = OCALLMETH;
+ if(n->left->op == ODOTINTER)
+ n->op = OCALLINTER;
+
+ if(isptr[t->etype])
+ t = t->type;
+
+ if(t->etype != TFUNC) {
+ yyerror("call of a non-function %T", t);
+ goto ret;
+ }
+
+ n->type = *getoutarg(t);
+ if(t->outtuple == 1)
+ n->type = n->type->type->type;
+ else
+ if(!top)
+ yyerror("function call must be single valued (%d)", t->outtuple);
+
+ walktype(n->right, 0);
+
+ switch(n->op) {
+ default:
+ fatal("walk: op: %O", n->op);
+
+ case OCALLINTER:
+ l = ascompatte(n->op, getinarg(t), &n->right, 0);
+ n->right = reorder(l);
+ break;
+
+ case OCALL:
+ l = ascompatte(n->op, getinarg(t), &n->right, 0);
+ n->right = reorder(l);
+ break;
+
+ case OCALLMETH:
+ // add this-pointer to the arg list
+ l = ascompatte(n->op, getinarg(t), &n->right, 0);
+ r = ascompatte(n->op, getthis(t), &n->left->left, 0);
+ if(l != N)
+ r = nod(OLIST, r, l);
+ n->right = reorder(r);
+ break;
+ }
+ goto ret;
+
+ case OAS:
+ if(!top)
+ goto nottop;
+
+ r = n->right;
+ if(r == N)
+ goto ret;
+ l = n->left;
+ if(l == N)
+ goto ret;
+
+ if(r->op == OCALL && l->op == OLIST) {
+ // botch callmulti - need to do more
+ walktype(l, 0);
+ walktype(r, 0);
+ l = ascompatet(n->op, &n->left, &r->type, 0);
+ if(l != N && l->op == OAS)
+ *n = *reorder(l);
+ goto ret;
+ }
+
+ walktype(l, 0);
+ walktype(r, 0);
+ l = ascompatee(n->op, &n->left, &n->right);
+ if(l != N)
+ *n = *reorder(l);
+ goto ret;
+
+ case OBREAK:
+ case OCONTINUE:
+ case OGOTO:
+ case OLABEL:
+ goto ret;
+
+ case OXCASE:
+ yyerror("case statement out of place");
+ n->op = OCASE;
+
+ case OCASE:
+ n = n->left;
+ goto loop;
+
+ case OXFALL:
+ yyerror("fallthrough statement out of place");
+ n->op = OFALL;
+
+ case OFALL:
+ case OINDREG:
+ goto ret;
+
+ case OS2I:
+ case OI2S:
+ case OI2I:
+ n->addable = 0;
+ walktype(n->left, 0);
+ goto ret;
+
+ case OCONV:
+ walktype(n->left, 0);
+ if(n->left == N)
+ goto ret;
+
+ convlit(n->left, n->type);
+
+ // nil conversion
+ if(eqtype(n->type, n->left->type, 0)) {
+ if(n->left->op != ONAME)
+ *n = *n->left;
+ goto ret;
+ }
+
+ // simple fix-float
+ if(isint[n->left->type->etype] || isfloat[n->left->type->etype])
+ if(isint[n->type->etype] || isfloat[n->type->etype]) {
+ evconst(n);
+ goto ret;
+ }
+
+ // to string
+ if(isptrto(n->type, TSTRING)) {
+ if(isint[n->left->type->etype]) {
+ *n = *stringop(n);
+ goto ret;
+ }
+ if(isbytearray(n->left->type) != 0) {
+ n->op = OARRAY;
+ *n = *stringop(n);
+ goto ret;
+ }
+ }
+
+ badtype(n->op, n->left->type, n->type);
+ goto ret;
+
+ case ORETURN:
+ walktype(n->left, 0);
+ l = ascompatte(n->op, getoutarg(curfn->type), &n->left, 1);
+ if(l != N)
+ n->left = reorder(l);
+ goto ret;
+
+ case ONOT:
+ walktype(n->left, 0);
+ if(n->left == N || n->left->type == T)
+ goto ret;
+ et = n->left->type->etype;
+ break;
+
+ case OASOP:
+ if(!top)
+ goto nottop;
+
+ case OLSH:
+ case ORSH:
+ case OMOD:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OANDAND:
+ case OOROR:
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case ODIV:
+ walktype(n->left, 0);
+ walktype(n->right, 0);
+ if(n->left == N || n->right == N)
+ goto ret;
+ convlit(n->left, n->right->type);
+ convlit(n->right, n->left->type);
+ evconst(n);
+ if(n->op == OLITERAL)
+ goto ret;
+ if(n->left->type == T || n->right->type == T)
+ goto ret;
+ if(!ascompat(n->left->type, n->right->type))
+ goto badt;
+
+ switch(n->op) {
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case OADD:
+ case OASOP:
+ if(isptrto(n->left->type, TSTRING)) {
+ *n = *stringop(n);
+ goto ret;
+ }
+ }
+ break;
+
+ case OMINUS:
+ case OPLUS:
+ case OCOM:
+ walktype(n->left, 0);
+ if(n->left == N)
+ goto ret;
+ evconst(n);
+ ullmancalc(n);
+ if(n->op == OLITERAL)
+ goto ret;
+ break;
+
+ case OLEN:
+ walktype(n->left, 0);
+ evconst(n);
+ ullmancalc(n);
+ t = n->left->type;
+ if(t != T && isptr[t->etype])
+ t = t->type;
+ if(t == T)
+ goto ret;
+ switch(t->etype) {
+ default:
+ goto badt;
+ case TSTRING:
+ break;
+ }
+ n->type = types[TINT32];
+ goto ret;
+
+ case OINDEX:
+ case OINDEXPTR:
+ walktype(n->left, 0);
+ walktype(n->right, 0);
+ ullmancalc(n);
+ if(n->left == N || n->right == N)
+ goto ret;
+ t = n->left->type;
+ if(t == T)
+ goto ret;
+
+ // map
+ if(isptrto(t, TMAP)) {
+ fatal("index map");
+ goto ret;
+ }
+
+ // right side must be an int
+ if(n->right->type == T)
+ convlit(n->right, types[TINT32]);
+ if(n->left->type == T || n->right->type == T)
+ goto ret;
+ if(!isint[n->right->type->etype])
+ goto badt;
+
+ // left side is string
+ if(isptrto(t, TSTRING)) {
+ *n = *stringop(n);
+ goto ret;
+ }
+
+ // left side is array
+ if(isptr[t->etype]) {
+ t = t->type;
+ n->op = OINDEXPTR;
+ }
+ if(t->etype != TARRAY && t->etype != TDARRAY)
+ goto badt;
+ n->type = t->type;
+ goto ret;
+
+ case OSLICE:
+ walktype(n->left, 0);
+ walktype(n->right, 0);
+ if(n->left == N || n->right == N)
+ goto ret;
+ if(isptrto(n->left->type, TSTRING)) {
+ *n = *stringop(n);
+ goto ret;
+ }
+ badtype(OSLICE, n->left->type, T);
+ goto ret;
+
+ case ODOT:
+ case ODOTPTR:
+ case ODOTMETH:
+ case ODOTINTER:
+ walkdot(n);
+ goto ret;
+
+ case OADDR:
+ walktype(n->left, 0);
+ if(n->left == N)
+ goto ret;
+ t = n->left->type;
+ if(t == T)
+ goto ret;
+ n->type = ptrto(t);
+ goto ret;
+
+ case OIND:
+ walktype(n->left, 0);
+ if(n->left == N)
+ goto ret;
+ t = n->left->type;
+ if(t == T)
+ goto ret;
+ if(!isptr[t->etype])
+ goto badt;
+ n->type = t->type;
+ goto ret;
+
+ case ONEW:
+ *n = *newcompat(n);
+ goto ret;
+ }
+
+/*
+ * ======== second switch ========
+ */
+
+ switch(n->op) {
+ default:
+ fatal("walktype: switch 2 unknown op %N", n);
+ goto ret;
+
+ case OASOP:
+ break;
+
+ case ONOT:
+ case OANDAND:
+ case OOROR:
+ et = n->left->type->etype;
+ if(et != TBOOL)
+ goto badt;
+ t = types[TBOOL];
+ break;
+
+ case OEQ:
+ case ONE:
+ et = n->left->type->etype;
+ if(!okforeq[et])
+ goto badt;
+ t = types[TBOOL];
+ break;
+
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ et = n->left->type->etype;
+ if(!okforadd[et])
+ if(!isptrto(n->left->type, TSTRING))
+ goto badt;
+ t = types[TBOOL];
+ break;
+
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case ODIV:
+ case OPLUS:
+ et = n->left->type->etype;
+ if(!okforadd[et])
+ goto badt;
+ break;
+
+ case OMINUS:
+ et = n->left->type->etype;
+ if(!okforadd[et])
+ goto badt;
+ if(!isfloat[et])
+ break;
+
+ l = nod(OLITERAL, N, N);
+ l->val.ctype = CTFLT;
+ l->val.dval = 0;
+
+ l = nod(OSUB, l, n->left);
+ *n = *l;
+ walktype(n, 0);
+ goto ret;
+
+ case OLSH:
+ case ORSH:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OMOD:
+ case OCOM:
+ et = n->left->type->etype;
+ if(!okforand[et])
+ goto badt;
+ break;
+ }
+
+ if(t == T)
+ t = n->left->type;
+ n->type = t;
+ goto ret;
+
+nottop:
+ fatal("walktype: not top %O", n->op);
+
+badt:
+ if(n->right == N) {
+ if(n->left == N) {
+ badtype(n->op, T, T);
+ goto ret;
+ }
+ badtype(n->op, n->left->type, T);
+ goto ret;
+ }
+ badtype(n->op, n->left->type, n->right->type);
+ goto ret;
+
+ret:
+ ullmancalc(n);
+ dynlineno = lno;
+}
+
+/*
+ * return the first type
+ */
+Type*
+sw1(Node *c, Type *place)
+{
+ if(place == T)
+ return c->type;
+ return place;
+}
+
+/*
+ * return a suitable type
+ */
+Type*
+sw2(Node *c, Type *place)
+{
+ return types[TINT32]; // botch
+}
+
+/*
+ * check that selected type
+ * is compat with all the cases
+ */
+Type*
+sw3(Node *c, Type *place)
+{
+ if(place == T)
+ return c->type;
+ if(c->type == T)
+ c->type = place;
+ convlit(c, place);
+ if(!ascompat(place, c->type))
+ badtype(OSWITCH, place, c->type);
+ return place;
+}
+
+Type*
+walkswitch(Node *test, Node *body, Type*(*call)(Node*, Type*))
+{
+ Node *n, *c;
+ Type *place;
+
+ place = call(test, T);
+
+ n = body;
+ if(n->op == OLIST)
+ n = n->left;
+
+ for(; n!=N; n=n->right) {
+ if(n->op != OCASE)
+ fatal("walkswitch: not case %O\n", n->op);
+ for(c=n->left; c!=N; c=c->right) {
+ if(c->op != OLIST) {
+ place = call(c, place);
+ break;
+ }
+ place = call(c->left, place);
+ }
+ }
+ return place;
+}
+
+int
+casebody(Node *n)
+{
+ Node *oc, *ot, *t;
+ Iter save;
+
+
+ /*
+ * look to see if statements at top level have
+ * case labels attached to them. convert the illegal
+ * ops XFALL and XCASE into legal ops FALL and CASE.
+ * all unconverted ops will thus be caught as illegal
+ */
+
+ oc = N; // last case statement
+ ot = N; // last statement (look for XFALL)
+
+ t = listfirst(&save, &n);
+
+ if(t->op != OXCASE)
+ return 0;
+
+loop:
+ if(t == N) {
+ if(oc == N)
+ return 0;
+ return 1;
+ }
+ if(t->op == OXCASE) {
+ /* rewrite and link top level cases */
+ t->op = OCASE;
+ if(oc != N)
+ oc->right = t;
+ oc = t;
+
+ /* rewrite top fall that preceed case */
+ if(ot != N && ot->op == OXFALL)
+ ot->op = OFALL;
+ }
+
+ /* if first statement is not case then return 0 */
+ if(oc == N)
+ return 0;
+
+ ot = t;
+ t = listnext(&save);
+ goto loop;
+}
+
+/*
+ * allowable type combinations for
+ * normal binary operations.
+ */
+Type*
+lookdot(Node *n, Type *t, int d)
+{
+ Type *f, *r, *c;
+ Sym *s;
+
+//dowidth(t);
+//print("\nlookdot %T\n", t);
+//for(f=t->type; f!=T; f=f->down) {
+//print(" %3ld", f->width);
+//print(" %S\n", f->sym);
+//}
+
+ r = T;
+ s = n->sym;
+ if(d > 0)
+ goto deep;
+
+ for(f=t->type; f!=T; f=f->down) {
+ if(f->sym == S)
+ continue;
+ if(f->sym != s)
+ continue;
+ if(r != T) {
+ yyerror("ambiguous DOT reference %s", s->name);
+ break;
+ }
+ r = f;
+ }
+ return r;
+
+deep:
+ /* deeper look after shallow failed */
+ for(f=t->type; f!=T; f=f->down) {
+ // only look at unnamed sub-structures
+ // BOTCH no such thing -- all are assigned temp names
+ if(f->sym != S)
+ continue;
+ c = f->type;
+ if(c->etype != TSTRUCT)
+ continue;
+ c = lookdot(n, c, d-1);
+ if(c == T)
+ continue;
+ if(r != T) {
+ yyerror("ambiguous unnamed DOT reference %s", s->name);
+ break;
+ }
+ r = c;
+ }
+ return r;
+}
+
+void
+walkdot(Node *n)
+{
+ Node *mn;
+ Type *t, *f;
+ int i;
+
+ if(n->left == N || n->right == N)
+ return;
+
+ walktype(n->left, 0);
+ if(n->right->op != ONAME) {
+ yyerror("rhs of . must be a name");
+ return;
+ }
+
+ t = n->left->type;
+ if(t == T)
+ return;
+
+ if(isptr[t->etype]) {
+ t = t->type;
+ if(t == T)
+ return;
+ n->op = ODOTPTR;
+ }
+
+ if(n->right->op != ONAME)
+ fatal("walkdot: not name %O", n->right->op);
+
+ switch(t->etype) {
+ default:
+ badtype(ODOT, t, T);
+ return;
+
+ case TSTRUCT:
+ case TINTER:
+ for(i=0; i<5; i++) {
+ f = lookdot(n->right, t, i);
+ if(f != T)
+ break;
+ }
+
+ // look up the field as TYPE_name
+ // for a mothod. botch this should
+ // be done better.
+ if(f == T && t->etype == TSTRUCT) {
+ mn = methodname(n->right, t);
+ for(i=0; i<5; i++) {
+ f = lookdot(mn, t, i);
+ if(f != T)
+ break;
+ }
+ }
+
+ if(f == T) {
+ yyerror("undefined DOT reference %N", n->right);
+ break;
+ }
+
+ n->xoffset = f->width;
+ n->right = f->nname; // substitute real name
+ n->type = f->type;
+ if(n->type->etype == TFUNC) {
+ n->op = ODOTMETH;
+ if(t->etype == TINTER) {
+ n->op = ODOTINTER;
+ }
+ }
+ break;
+ }
+}
+
+
+/*
+ * check assign expression list to
+ * a expression list. called in
+ * expr-list = expr-list
+ */
+Node*
+ascompatee(int op, Node **nl, Node **nr)
+{
+ Node *l, *r, *nn, *a;
+ Iter savel, saver;
+
+ l = listfirst(&savel, nl);
+ r = listfirst(&saver, nr);
+ nn = N;
+
+
+loop:
+ if(l == N || r == N) {
+ if(l != r)
+ yyerror("error in shape across assignment");
+ return nn;
+ }
+
+ convlit(r, l->type);
+ if(!ascompat(l->type, r->type)) {
+ badtype(op, l->type, r->type);
+ return N;
+ }
+
+ a = nod(OAS, l, r);
+ a = convas(a);
+ if(nn == N)
+ nn = a;
+ else
+ nn = nod(OLIST, nn, a);
+
+ l = listnext(&savel);
+ r = listnext(&saver);
+ goto loop;
+}
+
+/*
+ * check assign type list to
+ * a expression list. called in
+ * expr-list = func()
+ */
+Node*
+ascompatet(int op, Node **nl, Type **nr, int fp)
+{
+ Node *l, *nn, *a;
+ Type *r;
+ Iter savel, saver;
+
+ l = listfirst(&savel, nl);
+ r = structfirst(&saver, nr);
+ nn = N;
+
+loop:
+ if(l == N || r == T) {
+ if(l != N || r != T)
+ yyerror("error in shape across assignment");
+ return nn;
+ }
+
+ if(!ascompat(l->type, r->type)) {
+ badtype(op, l->type, r->type);
+ return N;
+ }
+
+ a = nod(OAS, l, nodarg(r, fp));
+ a = convas(a);
+ if(nn == N)
+ nn = a;
+ else
+ nn = nod(OLIST, nn, a);
+
+ l = listnext(&savel);
+ r = structnext(&saver);
+
+ goto loop;
+}
+
+/*
+ * check assign expression list to
+ * a type list. called in
+ * return expr-list
+ * func(expr-list)
+ */
+Node*
+ascompatte(int op, Type **nl, Node **nr, int fp)
+{
+ Type *l;
+ Node *r, *nn, *a;
+ Iter savel, saver;
+
+ l = structfirst(&savel, nl);
+ r = listfirst(&saver, nr);
+ nn = N;
+
+loop:
+ if(l == T || r == N) {
+ if(l != T || r != N)
+ yyerror("error in shape across assignment");
+ return nn;
+ }
+
+ convlit(r, l->type);
+ if(!ascompat(l->type, r->type)) {
+ badtype(op, l->type, r->type);
+ return N;
+ }
+
+ a = nod(OAS, nodarg(l, fp), r);
+ a = convas(a);
+ if(nn == N)
+ nn = a;
+ else
+ nn = nod(OLIST, nn, a);
+
+ l = structnext(&savel);
+ r = listnext(&saver);
+
+ goto loop;
+}
+
+/*
+ * can we assign var of type t2 to var of type t1
+ */
+int
+ascompat(Type *t1, Type *t2)
+{
+ if(eqtype(t1, t2, 0))
+ return 1;
+
+// if(eqtype(t1, nilptr, 0))
+// return 1;
+// if(eqtype(t2, nilptr, 0))
+// return 1;
+
+ if(isinter(t1))
+ if(isptrto(t2, TSTRUCT) || isinter(t2))
+ return 1;
+
+ if(isinter(t2))
+ if(isptrto(t1, TSTRUCT))
+ return 1;
+
+ return 0;
+}
+
+Node*
+prcompat(Node *n)
+{
+ Node *l, *r;
+ Type *t;
+ Iter save;
+ int w;
+ char *name;
+ Sym *s;
+
+ r = N;
+ l = listfirst(&save, &n);
+
+loop:
+ if(l == N) {
+ walktype(r, 1);
+ return r;
+ }
+
+ w = whatis(l);
+ switch(w) {
+ default:
+ badtype(n->op, l->type, T);
+ l = listnext(&save);
+ goto loop;
+ case Wlitint:
+ case Wtint:
+ name = "printint";
+ break;
+ case Wlitfloat:
+ case Wtfloat:
+ name = "printfloat";
+ break;
+ case Wlitbool:
+ case Wtbool:
+ name = "printbool";
+ break;
+ case Wlitstr:
+ case Wtstr:
+ name = "printstring";
+ break;
+ }
+
+ s = pkglookup(name, "sys");
+ if(s == S || s->oname == N)
+ fatal("prcompat: cant find sys_%s", name);
+
+ t = *getinarg(s->oname->type);
+ if(t != nil)
+ t = t->type;
+ if(t != nil)
+ t = t->type;
+
+ if(!eqtype(t, l->type, 0)) {
+ l = nod(OCONV, l, N);
+ l->type = t;
+ }
+
+ if(r == N)
+ r = nod(OCALL, s->oname, l);
+ else
+ r = nod(OLIST, r, nod(OCALL, s->oname, l));
+
+ l = listnext(&save);
+ goto loop;
+}
+
+Node*
+nodpanic(long lineno)
+{
+ Sym *s;
+ char *name;
+ Node *n;
+
+ name = "panicl";
+ s = pkglookup(name, "sys");
+ if(s == S || s->oname == N)
+ fatal("prcompat: cant find sys_%s", name);
+
+ n = nodintconst(lineno);
+ n = nod(OCALL, s->oname, n);
+ walktype(n, 1);
+ return n;
+}
+
+Node*
+newcompat(Node *n)
+{
+ Node *r;
+ Type *t;
+ Sym *s;
+
+ if(n->left != N)
+ yyerror("dont know what new(,e) means");
+ t = n->type;
+ if(t == T || !isptr[t->etype])
+ fatal("NEW sb pointer %lT", t);
+
+ dowidth(t->type);
+
+ s = pkglookup("mal", "sys");
+ if(s == S || s->oname == N)
+ fatal("newcompat: cant find sys_mal");
+
+ r = nodintconst(t->type->width);
+ r = nod(OCALL, s->oname, r);
+ walktype(r, 0);
+
+// r = nod(OCONV, r, N);
+ r->type = t;
+
+ return r;
+}
+
+Node*
+stringop(Node *n)
+{
+ Node *r, *c;
+ Sym *s;
+ long lno;
+ long l;
+
+ lno = dynlineno;
+ dynlineno = n->lineno;
+
+ switch(n->op) {
+ default:
+ fatal("stringop: unknown op %E", n->op);
+
+ case OEQ:
+ case ONE:
+ case OGE:
+ case OGT:
+ case OLE:
+ case OLT:
+ // sys_cmpstring(s1, s2) :: 0
+ s = pkglookup("cmpstring", "sys");
+ if(s == S || s->oname == N)
+ fatal("stringop: cant find sys_cmpstring");
+
+ r = nod(OLIST, n->left, n->right);
+ r = nod(OCALL, s->oname, r);
+ c = nodintconst(0);
+ r = nod(n->op, r, c);
+ break;
+
+ case OADD:
+ // sys_catstring(s1, s2)
+ s = pkglookup("catstring", "sys");
+ if(s == S || s->oname == N)
+ fatal("stringop: cant find sys_catstring");
+ r = nod(OLIST, n->left, n->right);
+ r = nod(OCALL, s->oname, r);
+ break;
+
+ case OASOP:
+ // sys_catstring(s1, s2)
+ switch(n->etype) {
+ default:
+ fatal("stringop: unknown op %E-%E", n->op, n->etype);
+
+ case OADD:
+ // s1 = sys_catstring(s1, s2)
+ s = pkglookup("catstring", "sys");
+ if(s == S || s->oname == N || n->etype != OADD)
+ fatal("stringop: cant find sys_catstring");
+ r = nod(OLIST, n->left, n->right);
+ r = nod(OCALL, s->oname, r);
+ r = nod(OAS, n->left, r);
+ break;
+ }
+ break;
+
+ case OSLICE:
+ // sys_slicestring(s, lb, hb)
+ s = pkglookup("slicestring", "sys");
+ if(s == S || s->oname == N)
+ fatal("stringop: cant find sys_slicestring");
+
+ r = nod(OCONV, n->right->left, N);
+ r->type = types[TINT32];
+
+ c = nod(OCONV, n->right->right, N);
+ c->type = types[TINT32];
+
+ r = nod(OLIST, r, c);
+
+ r = nod(OLIST, n->left, r);
+
+ r = nod(OCALL, s->oname, r);
+ break;
+
+ case OINDEX:
+ // sys_indexstring(s, i)
+ s = pkglookup("indexstring", "sys");
+ if(s == S || s->oname == N)
+ fatal("stringop: cant find sys_indexstring");
+
+ r = nod(OCONV, n->right, N);
+ r->type = types[TINT32];
+
+ r = nod(OLIST, n->left, r);
+ r = nod(OCALL, s->oname, r);
+ break;
+
+ case OCONV:
+ // sys_intstring(v)
+ s = pkglookup("intstring", "sys");
+ if(s == S || s->oname == N)
+ fatal("stringop: cant find sys_intstring");
+
+ r = nod(OCONV, n->left, N);
+ r->type = types[TINT64];
+
+ r = nod(OCALL, s->oname, r);
+ break;
+
+ case OARRAY:
+ // byteastring(a, l)
+ s = pkglookup("byteastring", "sys");
+ if(s == S || s->oname == N)
+ fatal("stringop: cant find sys_byteastring");
+
+ c = nodintconst(0);
+ r = nod(OINDEX, n->left, c);
+ r = nod(OADDR, r, N);
+
+ l = isbytearray(n->left->type);
+ c = nodintconst(l-1);
+
+ r = nod(OLIST, r, c);
+ r = nod(OCALL, s->oname, r);
+ break;
+ }
+
+ walktype(r, 1);
+ dynlineno = lno;
+ return r;
+}
+
+void
+diagnamed(Type *t)
+{
+ if(isinter(t))
+ if(t->sym == S)
+ yyerror("interface type must be named");
+ if(isptrto(t, TSTRUCT))
+ if(t->type == T || t->type->sym == S)
+ yyerror("structure type must be named");
+}
+
+Node*
+convas(Node *n)
+{
+ int o;
+ Node *l, *r;
+ Type *lt, *rt;
+
+ if(n->op != OAS)
+ fatal("convas: not as %O", n->op);
+
+ l = n->left;
+ r = n->right;
+ if(l == N || r == N)
+ return n;
+
+ lt = l->type;
+ rt = r->type;
+ if(lt == T || rt == T)
+ return n;
+
+ if(eqtype(lt, rt, 0))
+ return n;
+
+ if(isinter(lt)) {
+ if(isptrto(rt, TSTRUCT)) {
+ o = OS2I;
+ goto ret;
+ }
+ if(isinter(rt)) {
+ o = OI2I;
+ goto ret;
+ }
+ }
+
+ if(isptrto(lt, TSTRUCT)) {
+ if(isinter(rt)) {
+ o = OI2S;
+ goto ret;
+ }
+ }
+
+ badtype(n->op, lt, rt);
+ return n;
+
+ret:
+ diagnamed(lt);
+ diagnamed(rt);
+
+ n->right = nod(o, r, N);
+ n->right->type = l->type;
+ walktype(n, 1);
+ return n;
+}
+
+Node*
+reorder(Node *n)
+{
+ return n;
+}