--- /dev/null
+// Inferno utils/8a/a.h
+// http://code.google.com/p/inferno-os/source/browse/utils/8a/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 <lib9.h>
+#include <bio.h>
+#include "../8c/8.out.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;
+ long 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];
+ long offset;
+ Sym* sym;
+ short type;
+ short index;
+ short scale;
+};
+struct Gen2
+{
+ Gen from;
+ Gen to;
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ long 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*);
+
+/*
+ * Posix.c/Inferno.c/Nt.c
+ */
+enum /* keep in synch with ../cc/cc.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2
+};
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
--- /dev/null
+// Inferno utils/8a/a.y
+// http://code.google.com/p/inferno-os/source/browse/utils/8a/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;
+ long 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
+%token <lval> LCONST LFP LPC LSB
+%token <lval> LBREG LLREG LSREG LFREG
+%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
+%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7
+%%
+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); }
+
+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;
+ }
+
+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;
+ }
+| LSP
+ {
+ $$ = nullgen;
+ $$.type = D_SP;
+ }
+| LSREG
+ {
+ $$ = 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;
+ }
--- /dev/null
+// Inferno utils/8a/l.s
+// http://code.google.com/p/inferno-os/source/browse/utils/8a/l.s
+//
+// 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.
+
+/*
+ * Memory and machine-specific definitions. Used in C and assembler.
+ */
+
+/*
+ * Sizes
+ */
+#define BI2BY 8 /* bits per byte */
+#define BI2WD 32 /* bits per word */
+#define BY2WD 4 /* bytes per word */
+#define BY2PG 4096 /* bytes per page */
+#define WD2PG (BY2PG/BY2WD) /* words per page */
+#define PGSHIFT 12 /* log(BY2PG) */
+#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1))
+
+#define MAXMACH 1 /* max # cpus system can run */
+
+/*
+ * Time
+ */
+#define HZ (20) /* clock frequency */
+#define MS2HZ (1000/HZ) /* millisec per clock tick */
+#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
+#define TK2MS(t) ((((ulong)(t))*1000)/HZ) /* ticks to milliseconds */
+#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */
+
+/*
+ * Fundamental addresses
+ */
+
+/*
+ * Address spaces
+ *
+ * User is at 0-2GB
+ * Kernel is at 2GB-4GB
+ *
+ * To avoid an extra page map, both the user stack (USTKTOP) and
+ * the temporary user stack (TSTKTOP) should be in the the same
+ * 4 meg.
+ */
+#define UZERO 0 /* base of user address space */
+#define UTZERO (UZERO+BY2PG) /* first address in user text */
+#define KZERO 0x80000000 /* base of kernel address space */
+#define KTZERO KZERO /* first address in kernel text */
+#define USERADDR 0xC0000000 /* struct User */
+#define UREGADDR (USERADDR+BY2PG-4*19)
+#define TSTKTOP USERADDR /* end of new stack in sysexec */
+#define TSTKSIZ 10
+#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */
+#define USTKSIZE (16*1024*1024 - TSTKSIZ*BY2PG) /* size of user stack */
+#define ROMBIOS (KZERO|0xF0000)
+
+#define MACHSIZE 4096
+
+#define isphys(x) (((ulong)x)&KZERO)
+
+/*
+ * known 80386 segments (in GDT) and their selectors
+ */
+#define NULLSEG 0 /* null segment */
+#define KDSEG 1 /* kernel data/stack */
+#define KESEG 2 /* kernel executable */
+#define UDSEG 3 /* user data/stack */
+#define UESEG 4 /* user executable */
+#define TSSSEG 5 /* task segment */
+
+#define SELGDT (0<<3) /* selector is in gdt */
+#define SELLDT (1<<3) /* selector is in ldt */
+
+#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p))
+
+#define NULLSEL SELECTOR(NULLSEG, SELGDT, 0)
+#define KESEL SELECTOR(KESEG, SELGDT, 0)
+#define KDSEL SELECTOR(KDSEG, SELGDT, 0)
+#define UESEL SELECTOR(UESEG, SELGDT, 3)
+#define UDSEL SELECTOR(UDSEG, SELGDT, 3)
+#define TSSSEL SELECTOR(TSSSEG, SELGDT, 0)
+
+/*
+ * fields in segment descriptors
+ */
+#define SEGDATA (0x10<<8) /* data/stack segment */
+#define SEGEXEC (0x18<<8) /* executable segment */
+#define SEGTSS (0x9<<8) /* TSS segment */
+#define SEGCG (0x0C<<8) /* call gate */
+#define SEGIG (0x0E<<8) /* interrupt gate */
+#define SEGTG (0x0F<<8) /* task gate */
+#define SEGTYPE (0x1F<<8)
+
+#define SEGP (1<<15) /* segment present */
+#define SEGPL(x) ((x)<<13) /* priority level */
+#define SEGB (1<<22) /* granularity 1==4k (for expand-down) */
+#define SEGG (1<<23) /* granularity 1==4k (for other) */
+#define SEGE (1<<10) /* expand down */
+#define SEGW (1<<9) /* writable (for data/stack) */
+#define SEGR (1<<9) /* readable (for code) */
+#define SEGD (1<<22) /* default 1==32bit (for code) */
+
+/*
+ * virtual MMU
+ */
+#define PTEMAPMEM (1024*1024) /* ??? */
+#define SEGMAPSIZE 16 /* ??? */
+#define PTEPERTAB (PTEMAPMEM/BY2PG) /* ??? */
+#define PPN(x) ((x)&~(BY2PG-1))
+
+/*
+ * physical MMU
+ */
+#define PTEVALID (1<<0)
+#define PTEUNCACHED 0 /* everything is uncached */
+#define PTEWRITE (1<<1)
+#define PTERONLY (0<<1)
+#define PTEKERNEL (0<<2)
+#define PTEUSER (1<<2)
+
+/*
+ * flag register bits that we care about
+ */
+#define IFLAG 0x200
+
+#define OP16 BYTE $0x66
+
+/*
+ * about to walk all over ms/dos - turn off interrupts
+ */
+TEXT origin(SB),$0
+
+ CLI
+
+#ifdef BOOT
+/*
+ * This part of l.s is used only in the boot kernel.
+ * It assumes that we are in real address mode, i.e.,
+ * that we look like an 8086.
+ */
+/*
+ * relocate everything to a half meg and jump there
+ * - looks wierd because it is being assembled by a 32 bit
+ * assembler for a 16 bit world
+ */
+ MOVL $0,BX
+ INCL BX
+ SHLL $15,BX
+ MOVL BX,CX
+ MOVW BX,ES
+ MOVL $0,SI
+ MOVL SI,DI
+ CLD; REP; MOVSL
+/* JMPFAR 0X8000:$lowcore(SB) /**/
+ BYTE $0xEA
+ WORD $lowcore(SB)
+ WORD $0X8000
+
+TEXT lowcore(SB),$0
+
+/*
+ * now that we're in low core, update the DS
+ */
+
+ MOVW BX,DS
+
+/*
+ * goto protected mode
+ */
+/* MOVL tgdtptr(SB),GDTR /**/
+ BYTE $0x0f
+ BYTE $0x01
+ BYTE $0x16
+ WORD $tgdtptr(SB)
+ MOVL CR0,AX
+ ORL $1,AX
+ MOVL AX,CR0
+
+/*
+ * clear prefetch queue (wierd code to avoid optimizations)
+ */
+ CLC
+ JCC flush
+ MOVL AX,AX
+flush:
+
+/*
+ * set all segs
+ */
+/* MOVW $SELECTOR(1, SELGDT, 0),AX /**/
+ BYTE $0xc7
+ BYTE $0xc0
+ WORD $SELECTOR(1, SELGDT, 0)
+ MOVW AX,DS
+ MOVW AX,SS
+ MOVW AX,ES
+ MOVW AX,FS
+ MOVW AX,GS
+
+/* JMPFAR SELECTOR(2, SELGDT, 0):$mode32bit(SB) /**/
+ BYTE $0x66
+ BYTE $0xEA
+ LONG $mode32bit-KZERO(SB)
+ WORD $SELECTOR(2, SELGDT, 0)
+
+TEXT mode32bit(SB),$0
+
+#endif BOOT
+
+ /*
+ * Clear BSS
+ */
+ LEAL edata-KZERO(SB),SI
+ MOVL SI,DI
+ ADDL $4,DI
+ MOVL $0,AX
+ MOVL AX,(SI)
+ LEAL end-KZERO(SB),CX
+ SUBL DI,CX
+ SHRL $2,CX
+ CLD; REP; MOVSL
+
+ /*
+ * make a bottom level page table page that maps the first
+ * 16 meg of physical memory
+ */
+ LEAL tpt-KZERO(SB),AX /* get phys addr of temporary page table */
+ ADDL $(BY2PG-1),AX /* must be page alligned */
+ ANDL $(~(BY2PG-1)),AX /* ... */
+ MOVL $(4*1024),CX /* pte's per page */
+ MOVL $((((4*1024)-1)<<PGSHIFT)|PTEVALID|PTEKERNEL|PTEWRITE),BX
+setpte:
+ MOVL BX,-4(AX)(CX*4)
+ SUBL $(1<<PGSHIFT),BX
+ LOOP setpte
+
+ /*
+ * make a top level page table page that maps the first
+ * 16 meg of memory to 0 thru 16meg and to KZERO thru KZERO+16meg
+ */
+ MOVL AX,BX
+ ADDL $(4*BY2PG),AX
+ ADDL $(PTEVALID|PTEKERNEL|PTEWRITE),BX
+ MOVL BX,0(AX)
+ MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+0)(AX)
+ ADDL $BY2PG,BX
+ MOVL BX,4(AX)
+ MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+4)(AX)
+ ADDL $BY2PG,BX
+ MOVL BX,8(AX)
+ MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+8)(AX)
+ ADDL $BY2PG,BX
+ MOVL BX,12(AX)
+ MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+12)(AX)
+
+ /*
+ * point processor to top level page & turn on paging
+ */
+ MOVL AX,CR3
+ MOVL CR0,AX
+ ORL $0X80000000,AX
+ ANDL $~(0x8|0x2),AX /* TS=0, MP=0 */
+ MOVL AX,CR0
+
+ /*
+ * use a jump to an absolute location to get the PC into
+ * KZERO.
+ */
+ LEAL tokzero(SB),AX
+ JMP* AX
+
+TEXT tokzero(SB),$0
+
+ /*
+ * stack and mach
+ */
+ MOVL $mach0(SB),SP
+ MOVL SP,m(SB)
+ MOVL $0,0(SP)
+ ADDL $(MACHSIZE-4),SP /* start stack under machine struct */
+ MOVL $0, u(SB)
+
+ /*
+ * clear flags
+ */
+ MOVL $0,AX
+ PUSHL AX
+ POPFL
+
+ CALL main(SB)
+
+loop:
+ JMP loop
+
+GLOBL mach0+0(SB), $MACHSIZE
+GLOBL u(SB), $4
+GLOBL m(SB), $4
+GLOBL tpt(SB), $(BY2PG*6)
+
+/*
+ * gdt to get us to 32-bit/segmented/unpaged mode
+ */
+TEXT tgdt(SB),$0
+
+ /* null descriptor */
+ LONG $0
+ LONG $0
+
+ /* data segment descriptor for 4 gigabytes (PL 0) */
+ LONG $(0xFFFF)
+ LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
+
+ /* exec segment descriptor for 4 gigabytes (PL 0) */
+ LONG $(0xFFFF)
+ LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
+
+/*
+ * pointer to initial gdt
+ */
+TEXT tgdtptr(SB),$0
+
+ WORD $(3*8)
+ LONG $tgdt-KZERO(SB)
+
+/*
+ * input a byte
+ */
+TEXT inb(SB),$0
+
+ MOVL p+0(FP),DX
+ XORL AX,AX
+ INB
+ RET
+
+/*
+ * output a byte
+ */
+TEXT outb(SB),$0
+
+ MOVL p+0(FP),DX
+ MOVL b+4(FP),AX
+ OUTB
+ RET
+
+/*
+ * input a string of shorts from a port
+ */
+TEXT inss(SB),$0
+ MOVL p+0(FP),DX
+ MOVL a+4(FP),DI
+ MOVL c+8(FP),CX
+ CLD; REP; OP16; INSL
+ RET
+
+/*
+ * output a string of shorts to a port
+ */
+TEXT outss(SB),$0
+ MOVL p+0(FP),DX
+ MOVL a+4(FP),SI
+ MOVL c+8(FP),CX
+ CLD; REP; OP16; OUTSL
+ RET
+
+/*
+ * test and set
+ */
+TEXT tas(SB),$0
+ MOVL $0xdeadead,AX
+ MOVL l+0(FP),BX
+ XCHGL AX,(BX)
+ RET
+
+/*
+ * routines to load/read various system registers
+ */
+GLOBL idtptr(SB),$6
+TEXT putidt(SB),$0 /* interrupt descriptor table */
+ MOVL t+0(FP),AX
+ MOVL AX,idtptr+2(SB)
+ MOVL l+4(FP),AX
+ MOVW AX,idtptr(SB)
+ MOVL idtptr(SB),IDTR
+ RET
+
+GLOBL gdtptr(SB),$6
+TEXT putgdt(SB),$0 /* global descriptor table */
+ MOVL t+0(FP),AX
+ MOVL AX,gdtptr+2(SB)
+ MOVL l+4(FP),AX
+ MOVW AX,gdtptr(SB)
+ MOVL gdtptr(SB),GDTR
+ RET
+
+TEXT putcr3(SB),$0 /* top level page table pointer */
+ MOVL t+0(FP),AX
+ MOVL AX,CR3
+ RET
+
+TEXT puttr(SB),$0 /* task register */
+ MOVL t+0(FP),AX
+ MOVW AX,TASK
+ RET
+
+TEXT getcr0(SB),$0 /* coprocessor bits */
+ MOVL CR0,AX
+ RET
+
+TEXT getcr2(SB),$0 /* fault address */
+ MOVL CR2,AX
+ RET
+
+#define FPOFF\
+ WAIT;\
+ MOVL CR0,AX;\
+ ORL $0x4,AX /* EM=1 */;\
+ MOVL AX,CR0
+
+#define FPON\
+ MOVL CR0,AX;\
+ ANDL $~0x4,AX /* EM=0 */;\
+ MOVL AX,CR0
+
+TEXT fpoff(SB),$0 /* turn off floating point */
+ FPOFF
+ RET
+
+TEXT fpinit(SB),$0 /* turn on & init the floating point */
+ FPON
+ FINIT
+ WAIT
+ PUSHW $0x0330
+ FLDCW 0(SP) /* ignore underflow/precision, signal others */
+ POPW AX
+ WAIT
+ RET
+
+TEXT fpsave(SB),$0 /* save floating point state and turn off */
+ MOVL p+0(FP),AX
+ WAIT
+ FSAVE 0(AX)
+ FPOFF
+ RET
+
+TEXT fprestore(SB),$0 /* turn on floating point and restore regs */
+ FPON
+ MOVL p+0(FP),AX
+ FRSTOR 0(AX)
+ WAIT
+ RET
+
+TEXT fpstatus(SB),$0 /* get floating point status */
+ FSTSW AX
+ RET
+
+/*
+ * special traps
+ */
+TEXT intr0(SB),$0
+ PUSHL $0
+ PUSHL $0
+ JMP intrcommon
+TEXT intr1(SB),$0
+ PUSHL $0
+ PUSHL $1
+ JMP intrcommon
+TEXT intr2(SB),$0
+ PUSHL $0
+ PUSHL $2
+ JMP intrcommon
+TEXT intr3(SB),$0
+ PUSHL $0
+ PUSHL $3
+ JMP intrcommon
+TEXT intr4(SB),$0
+ PUSHL $0
+ PUSHL $4
+ JMP intrcommon
+TEXT intr5(SB),$0
+ PUSHL $0
+ PUSHL $5
+ JMP intrcommon
+TEXT intr6(SB),$0
+ PUSHL $0
+ PUSHL $6
+ JMP intrcommon
+TEXT intr7(SB),$0
+ PUSHL $0
+ PUSHL $7
+ JMP intrcommon
+TEXT intr8(SB),$0
+ PUSHL $8
+ JMP intrscommon
+TEXT intr9(SB),$0
+ PUSHL $0
+ PUSHL $9
+ JMP intrcommon
+TEXT intr10(SB),$0
+ PUSHL $10
+ JMP intrscommon
+TEXT intr11(SB),$0
+ PUSHL $11
+ JMP intrscommon
+TEXT intr12(SB),$0
+ PUSHL $12
+ JMP intrscommon
+TEXT intr13(SB),$0
+ PUSHL $13
+ JMP intrscommon
+TEXT intr14(SB),$0
+ PUSHL $14
+ JMP intrscommon
+TEXT intr15(SB),$0
+ PUSHL $0
+ PUSHL $15
+ JMP intrcommon
+TEXT intr16(SB),$0
+ PUSHL $0
+ PUSHL $16
+ JMP intrcommon
+TEXT intr24(SB),$0
+ PUSHL $0
+ PUSHL $24
+ JMP intrcommon
+TEXT intr25(SB),$0
+ PUSHL $0
+ PUSHL $25
+ JMP intrcommon
+TEXT intr26(SB),$0
+ PUSHL $0
+ PUSHL $26
+ JMP intrcommon
+TEXT intr27(SB),$0
+ PUSHL $0
+ PUSHL $27
+ JMP intrcommon
+TEXT intr28(SB),$0
+ PUSHL $0
+ PUSHL $28
+ JMP intrcommon
+TEXT intr29(SB),$0
+ PUSHL $0
+ PUSHL $29
+ JMP intrcommon
+TEXT intr30(SB),$0
+ PUSHL $0
+ PUSHL $30
+ JMP intrcommon
+TEXT intr31(SB),$0
+ PUSHL $0
+ PUSHL $31
+ JMP intrcommon
+TEXT intr32(SB),$0
+ PUSHL $0
+ PUSHL $16
+ JMP intrcommon
+TEXT intr33(SB),$0
+ PUSHL $0
+ PUSHL $33
+ JMP intrcommon
+TEXT intr34(SB),$0
+ PUSHL $0
+ PUSHL $34
+ JMP intrcommon
+TEXT intr35(SB),$0
+ PUSHL $0
+ PUSHL $35
+ JMP intrcommon
+TEXT intr36(SB),$0
+ PUSHL $0
+ PUSHL $36
+ JMP intrcommon
+TEXT intr37(SB),$0
+ PUSHL $0
+ PUSHL $37
+ JMP intrcommon
+TEXT intr38(SB),$0
+ PUSHL $0
+ PUSHL $38
+ JMP intrcommon
+TEXT intr39(SB),$0
+ PUSHL $0
+ PUSHL $39
+ JMP intrcommon
+TEXT intr64(SB),$0
+ PUSHL $0
+ PUSHL $64
+ JMP intrcommon
+TEXT intrbad(SB),$0
+ PUSHL $0
+ PUSHL $0x1ff
+ JMP intrcommon
+
+intrcommon:
+ PUSHL DS
+ PUSHL ES
+ PUSHL FS
+ PUSHL GS
+ PUSHAL
+ MOVL $(KDSEL),AX
+ MOVW AX,DS
+ MOVW AX,ES
+ LEAL 0(SP),AX
+ PUSHL AX
+ CALL trap(SB)
+ POPL AX
+ POPAL
+ POPL GS
+ POPL FS
+ POPL ES
+ POPL DS
+ ADDL $8,SP /* error code and trap type */
+ IRETL
+
+intrscommon:
+ PUSHL DS
+ PUSHL ES
+ PUSHL FS
+ PUSHL GS
+ PUSHAL
+ MOVL $(KDSEL),AX
+ MOVW AX,DS
+ MOVW AX,ES
+ LEAL 0(SP),AX
+ PUSHL AX
+ CALL trap(SB)
+ POPL AX
+ POPAL
+ POPL GS
+ POPL FS
+ POPL ES
+ POPL DS
+ ADDL $8,SP /* error code and trap type */
+ IRETL
+
+/*
+ * interrupt level is interrupts on or off
+ */
+TEXT spllo(SB),$0
+ PUSHFL
+ POPL AX
+ STI
+ RET
+
+TEXT splhi(SB),$0
+ PUSHFL
+ POPL AX
+ CLI
+ RET
+
+TEXT splx(SB),$0
+ MOVL s+0(FP),AX
+ PUSHL AX
+ POPFL
+ RET
+
+/*
+ * do nothing whatsoever till interrupt happens
+ */
+TEXT idle(SB),$0
+ HLT
+ RET
+
+/*
+ * label consists of a stack pointer and a PC
+ */
+TEXT gotolabel(SB),$0
+ MOVL l+0(FP),AX
+ MOVL 0(AX),SP /* restore sp */
+ MOVL 4(AX),AX /* put return pc on the stack */
+ MOVL AX,0(SP)
+ MOVL $1,AX /* return 1 */
+ RET
+
+TEXT setlabel(SB),$0
+ MOVL l+0(FP),AX
+ MOVL SP,0(AX) /* store sp */
+ MOVL 0(SP),BX /* store return pc */
+ MOVL BX,4(AX)
+ MOVL $0,AX /* return 0 */
+ RET
+
+/*
+ * Used to get to the first process.
+ * Set up an interrupt return frame and IRET to user level.
+ */
+TEXT touser(SB),$0
+ PUSHL $(UDSEL) /* old ss */
+ PUSHL $(USTKTOP) /* old sp */
+ PUSHFL /* old flags */
+ PUSHL $(UESEL) /* old cs */
+ PUSHL $(UTZERO+32) /* old pc */
+ MOVL $(UDSEL),AX
+ MOVW AX,DS
+ MOVW AX,ES
+ MOVW AX,GS
+ MOVW AX,FS
+ IRETL
+
+/*
+ * set configuration register
+ */
+TEXT config(SB),$0
+ MOVL l+0(FP),AX
+ MOVL $0x3F3,DX
+ OUTB
+ OUTB
+ RET
--- /dev/null
+// Inferno utils/8a/lex.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8a/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 = '8';
+ thestring = "386";
+ 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 = mycreat(outfile, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ 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,
+ "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,
+
+ "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,
+
+ "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,
+
+ "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,
+ "ADCW", LTYPE3, AADCW,
+ "ADDB", LTYPE3, AADDB,
+ "ADDL", LTYPE3, AADDL,
+ "ADDW", LTYPE3, AADDW,
+ "ADJSP", LTYPE2, AADJSP,
+ "ANDB", LTYPE3, AANDB,
+ "ANDL", LTYPE3, AANDL,
+ "ANDW", LTYPE3, AANDW,
+ "ARPL", LTYPE3, AARPL,
+ "BOUNDL", LTYPE3, ABOUNDL,
+ "BOUNDW", LTYPE3, ABOUNDW,
+ "BSFL", LTYPE3, ABSFL,
+ "BSFW", LTYPE3, ABSFW,
+ "BSRL", LTYPE3, ABSRL,
+ "BSRW", LTYPE3, ABSRW,
+ "BTCL", LTYPE3, ABTCL,
+ "BTCW", LTYPE3, ABTCW,
+ "BTL", LTYPE3, ABTL,
+ "BTRL", LTYPE3, ABTRL,
+ "BTRW", LTYPE3, ABTRW,
+ "BTSL", LTYPE3, ABTSL,
+ "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,
+ "CMPW", LTYPE4, ACMPW,
+ "CMPSB", LTYPE0, ACMPSB,
+ "CMPSL", LTYPE0, ACMPSL,
+ "CMPSW", LTYPE0, ACMPSW,
+ "DAA", LTYPE0, ADAA,
+ "DAS", LTYPE0, ADAS,
+ "DATA", LTYPED, ADATA,
+ "DECB", LTYPE1, ADECB,
+ "DECL", LTYPE1, ADECL,
+ "DECW", LTYPE1, ADECW,
+ "DIVB", LTYPE2, ADIVB,
+ "DIVL", LTYPE2, ADIVL,
+ "DIVW", LTYPE2, ADIVW,
+ "END", LTYPE0, AEND,
+ "ENTER", LTYPE2, AENTER,
+ "GLOBL", LTYPET, AGLOBL,
+ "HLT", LTYPE0, AHLT,
+ "IDIVB", LTYPE2, AIDIVB,
+ "IDIVL", LTYPE2, AIDIVL,
+ "IDIVW", LTYPE2, AIDIVW,
+ "IMULB", LTYPE2, AIMULB,
+ "IMULL", LTYPE2, AIMULL,
+ "IMULW", LTYPE2, AIMULW,
+ "INB", LTYPE0, AINB,
+ "INL", LTYPE0, AINL,
+ "INW", LTYPE0, AINW,
+ "INCB", LTYPE1, AINCB,
+ "INCL", LTYPE1, AINCL,
+ "INCW", LTYPE1, AINCW,
+ "INSB", LTYPE0, AINSB,
+ "INSL", LTYPE0, AINSL,
+ "INSW", LTYPE0, AINSW,
+ "INT", LTYPE2, AINT,
+ "INTO", LTYPE0, AINTO,
+ "IRETL", LTYPE0, AIRETL,
+ "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,
+ "LEAW", LTYPE3, ALEAW,
+ "LEAVEL", LTYPE0, ALEAVEL,
+ "LEAVEW", LTYPE0, ALEAVEW,
+ "LOCK", LTYPE0, ALOCK,
+ "LODSB", LTYPE0, ALODSB,
+ "LODSL", LTYPE0, ALODSL,
+ "LODSW", LTYPE0, ALODSW,
+ "LONG", LTYPE2, ALONG,
+ "LOOP", LTYPER, ALOOP,
+ "LOOPEQ", LTYPER, ALOOPEQ,
+ "LOOPNE", LTYPER, ALOOPNE,
+ "LSLL", LTYPE3, ALSLL,
+ "LSLW", LTYPE3, ALSLW,
+ "MOVB", LTYPE3, AMOVB,
+ "MOVL", LTYPEM, AMOVL,
+ "MOVW", LTYPEM, AMOVW,
+ "MOVBLSX", LTYPE3, AMOVBLSX,
+ "MOVBLZX", LTYPE3, AMOVBLZX,
+ "MOVBWSX", LTYPE3, AMOVBWSX,
+ "MOVBWZX", LTYPE3, AMOVBWZX,
+ "MOVWLSX", LTYPE3, AMOVWLSX,
+ "MOVWLZX", LTYPE3, AMOVWLZX,
+ "MOVSB", LTYPE0, AMOVSB,
+ "MOVSL", LTYPE0, AMOVSL,
+ "MOVSW", LTYPE0, AMOVSW,
+ "MULB", LTYPE2, AMULB,
+ "MULL", LTYPE2, AMULL,
+ "MULW", LTYPE2, AMULW,
+ "NEGB", LTYPE1, ANEGB,
+ "NEGL", LTYPE1, ANEGL,
+ "NEGW", LTYPE1, ANEGW,
+ "NOP", LTYPEN, ANOP,
+ "NOTB", LTYPE1, ANOTB,
+ "NOTL", LTYPE1, ANOTL,
+ "NOTW", LTYPE1, ANOTW,
+ "ORB", LTYPE3, AORB,
+ "ORL", LTYPE3, AORL,
+ "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,
+ "POPFW", LTYPE0, APOPFW,
+ "POPL", LTYPE1, APOPL,
+ "POPW", LTYPE1, APOPW,
+ "PUSHAL", LTYPE0, APUSHAL,
+ "PUSHAW", LTYPE0, APUSHAW,
+ "PUSHFL", LTYPE0, APUSHFL,
+ "PUSHFW", LTYPE0, APUSHFW,
+ "PUSHL", LTYPE2, APUSHL,
+ "PUSHW", LTYPE2, APUSHW,
+ "RCLB", LTYPE3, ARCLB,
+ "RCLL", LTYPE3, ARCLL,
+ "RCLW", LTYPE3, ARCLW,
+ "RCRB", LTYPE3, ARCRB,
+ "RCRL", LTYPE3, ARCRL,
+ "RCRW", LTYPE3, ARCRW,
+ "REP", LTYPE0, AREP,
+ "REPN", LTYPE0, AREPN,
+ "RET", LTYPE0, ARET,
+ "ROLB", LTYPE3, AROLB,
+ "ROLL", LTYPE3, AROLL,
+ "ROLW", LTYPE3, AROLW,
+ "RORB", LTYPE3, ARORB,
+ "RORL", LTYPE3, ARORL,
+ "RORW", LTYPE3, ARORW,
+ "SAHF", LTYPE0, ASAHF,
+ "SALB", LTYPE3, ASALB,
+ "SALL", LTYPE3, ASALL,
+ "SALW", LTYPE3, ASALW,
+ "SARB", LTYPE3, ASARB,
+ "SARL", LTYPE3, ASARL,
+ "SARW", LTYPE3, ASARW,
+ "SBBB", LTYPE3, ASBBB,
+ "SBBL", LTYPE3, ASBBL,
+ "SBBW", LTYPE3, ASBBW,
+ "SCASB", LTYPE0, ASCASB,
+ "SCASL", LTYPE0, ASCASL,
+ "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,
+ "CDQ", LTYPE0, ACDQ,
+ "CWD", LTYPE0, ACWD,
+ "SHLB", LTYPE3, ASHLB,
+ "SHLL", LTYPES, ASHLL,
+ "SHLW", LTYPES, ASHLW,
+ "SHRB", LTYPE3, ASHRB,
+ "SHRL", LTYPES, ASHRL,
+ "SHRW", LTYPES, ASHRW,
+ "STC", LTYPE0, ASTC,
+ "STD", LTYPE0, ASTD,
+ "STI", LTYPE0, ASTI,
+ "STOSB", LTYPE0, ASTOSB,
+ "STOSL", LTYPE0, ASTOSL,
+ "STOSW", LTYPE0, ASTOSW,
+ "SUBB", LTYPE3, ASUBB,
+ "SUBL", LTYPE3, ASUBL,
+ "SUBW", LTYPE3, ASUBW,
+ "SYSCALL", LTYPE0, ASYSCALL,
+ "TESTB", LTYPE3, ATESTB,
+ "TESTL", LTYPE3, ATESTL,
+ "TESTW", LTYPE3, ATESTW,
+ "TEXT", LTYPET, ATEXT,
+ "VERR", LTYPE2, AVERR,
+ "VERW", LTYPE2, AVERW,
+ "WAIT", LTYPE0, AWAIT,
+ "WORD", LTYPE2, AWORD,
+ "XCHGB", LTYPE3, AXCHGB,
+ "XCHGL", LTYPE3, AXCHGL,
+ "XCHGW", LTYPE3, AXCHGW,
+ "XLAT", LTYPE2, AXLAT,
+ "XORB", LTYPE3, AXORB,
+ "XORL", LTYPE3, AXORL,
+ "XORW", LTYPE3, AXORW,
+
+ "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,
+
+ 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;
+ 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_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);
+ }
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
--- /dev/null
+// Inferno utils/8c/8.out.h
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/8.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)
+
+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,
+ ADECW,
+ ADIVB,
+ ADIVL,
+ ADIVW,
+ AENTER,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ AHLT,
+ AIDIVB,
+ AIDIVL,
+ AIDIVW,
+ AIMULB,
+ AIMULL,
+ AIMULW,
+ AINB,
+ AINL,
+ AINW,
+ AINCB,
+ AINCL,
+ 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,
+ AMOVBWSX,
+ AMOVBWZX,
+ AMOVWLSX,
+ AMOVWLZX,
+ 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,
+
+ ALAST
+};
+
+enum
+{
+ D_AL = 0,
+ D_CL,
+ D_DL,
+ D_BL,
+
+ D_AH = 4,
+ D_CH,
+ D_DH,
+ D_BH,
+
+ D_AX = 8,
+ D_CX,
+ D_DX,
+ D_BX,
+ D_SP,
+ D_BP,
+ D_SI,
+ D_DI,
+
+ D_F0 = 16,
+
+ D_CS = 24,
+ 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 = 35,
+ D_DR = 43,
+ D_TR = 51,
+
+ D_NONE = 59,
+
+ D_BRANCH = 60,
+ D_EXTERN = 61,
+ D_STATIC = 62,
+ D_AUTO = 63,
+ D_PARAM = 64,
+ D_CONST = 65,
+ D_FCONST = 66,
+ D_SCONST = 67,
+ D_ADDR = 68,
+
+ 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,
+
+ REGARG = 0,
+ REGRET = D_AX,
+ FREGRET = D_F0,
+ REGSP = D_SP,
+ REGTMP = D_DI,
+};
+
+/*
+ * 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 */
+};
--- /dev/null
+// Inferno utils/8c/cgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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/\/\/ */
+
+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(typesuv[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) && typesuv[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(typefd[n->type->etype]) {
+ cgen(r, &fregnode0);
+ if(nn != Z)
+ gins(AFMOVD, &fregnode0, &fregnode0);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, Z);
+ gmove(&fregnode0, &nod);
+ regfree(&nod);
+ } else
+ gmove(&fregnode0, l);
+ if(nn != Z)
+ gmove(&fregnode0, nn);
+ return;
+ }
+ if(l->op == OBIT)
+ goto bitas;
+ if(!hardleft) {
+ if(nn != Z || r->addable < INDEXED) {
+ 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 && r->op == OCONST) {
+ gmove(r, l);
+ break;
+ }
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED) {
+ 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) {
+ 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) {
+ 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) {
+ 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)) {
+ 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(ACDQ, 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(ACDQ, 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 asfop;
+
+ /*
+ * 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[n->type->etype]||typefd[r->type->etype])
+ goto asfop;
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(r->op != OCONST) {
+ 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;
+
+ 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) {
+ 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) {
+ 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) {
+ 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(ACDQ, 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(ACDQ, 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) {
+ cgen(l, &fregnode0);
+ if(r->addable < INDEXED) {
+ cgen(r, &fregnode0);
+ fgopcode(o, &fregnode0, &fregnode1, 1, 0);
+ } else
+ fgopcode(o, r, &fregnode0, 0, 0);
+ } else {
+ cgen(r, &fregnode0);
+ if(l->addable < INDEXED) {
+ cgen(l, &fregnode0);
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else
+ fgopcode(o, l, &fregnode0, 0, 1);
+ }
+ gmove(&fregnode0, nn);
+ break;
+
+ asfop:
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ cgen(r, &fregnode0);
+ } else {
+ cgen(r, &fregnode0);
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ }
+ if(!typefd[l->type->etype]) {
+ gmove(&nod, &fregnode0);
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else
+ fgopcode(o, &nod, &fregnode0, 0, 1);
+ if(nn != Z)
+ gins(AFMOVD, &fregnode0, &fregnode0);
+ gmove(&fregnode0, &nod);
+ if(nn != Z)
+ gmove(&fregnode0, nn);
+ if(hardleft)
+ 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);
+
+ if(typefd[nod3.type->etype])
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ else {
+ 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;
+ }
+ 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 && reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ if(typefd[n->type->etype])
+ gins(AFMOVDP, &fregnode0, &fregnode0);
+ 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(typev[l->type->etype]) {
+ cgen64(n, nn);
+ 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;
+
+ if(typefd[n->type->etype])
+ goto fltinc;
+ gmove(&nod, nn);
+ 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])
+ goto fltinc;
+ gopcode(OADD, n->type, nodconst(v), &nod);
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ fltinc:
+ gmove(&nod, &fregnode0);
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC))
+ gins(AFMOVD, &fregnode0, &fregnode0);
+ gins(AFLD1, Z, Z);
+ if(v < 0)
+ fgopcode(OSUB, &fregnode0, &fregnode1, 1, 0);
+ else
+ fgopcode(OADD, &fregnode0, &fregnode1, 1, 0);
+ if(nn != Z && (o == OPREINC || o == OPREDEC))
+ gins(AFMOVD, &fregnode0, &fregnode0);
+ gmove(&fregnode0, &nod);
+ 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:
+ if(typev[n->type->etype]) {
+ testv(n, true);
+ goto com;
+ }
+ o = ONE;
+ if(true)
+ o = OEQ;
+ if(typefd[n->type->etype]) {
+ if(n->addable < INDEXED) {
+ cgen(n, &fregnode0);
+ gins(AFLDZ, Z, Z);
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else {
+ gins(AFLDZ, Z, Z);
+ fgopcode(o, n, &fregnode0, 0, 1);
+ }
+ goto com;
+ }
+ /* bad, 13 is address of external that becomes constant */
+ if(n->addable >= INDEXED && n->addable != 13) {
+ gopcode(o, n->type, n, nodconst(0));
+ goto com;
+ }
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ 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(typev[l->type->etype]) {
+ if(!true)
+ n->op = comrel[relindex(o)];
+ cgen64(n, Z);
+ goto com;
+ }
+ 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(typefd[l->type->etype]) {
+ if(l->complex >= r->complex) {
+ cgen(l, &fregnode0);
+ if(r->addable < INDEXED) {
+ cgen(r, &fregnode0);
+ o = invrel[relindex(o)];
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else
+ fgopcode(o, r, &fregnode0, 0, 1);
+ } else {
+ o = invrel[relindex(o)];
+ cgen(r, &fregnode0);
+ if(l->addable < INDEXED) {
+ cgen(l, &fregnode0);
+ o = invrel[relindex(o)];
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else
+ fgopcode(o, l, &fregnode0, 0, 1);
+ }
+ goto com;
+ }
+ if(l->op == OCONST) {
+ 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(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED) {
+ 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) {
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ if(typechlp[l->type->etype])
+ 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, *h, *l, *r;
+ Type *t;
+ int c, v, x;
+
+ 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:
+ if(n->type && typev[n->type->etype]) {
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ if(nn->op == OREGPAIR) {
+ loadpair(n, nn);
+ break;
+ }
+ else if(!vaddr(nn, 0)) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod1, nn, Z);
+ nn->type = t;
+
+ gmove(lo64(n), &nod1);
+ nod1.xoffset += SZ_LONG;
+ gmove(hi64(n), &nod1);
+ regfree(&nod1);
+ }
+ else {
+ gins(AMOVL, lo64(n), nn);
+ nn->xoffset += SZ_LONG;
+ gins(AMOVL, hi64(n), nn);
+ nn->xoffset -= SZ_LONG;
+ break;
+ }
+ break;
+ }
+ 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;
+ }
+ h = nn;
+ if(nn->op == OREGPAIR) {
+ regsalloc(&nod1, nn);
+ nn = &nod1;
+ }
+ 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);
+ if(h->op == OREGPAIR)
+ loadpair(nn->left, h);
+ 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;
+ }
+
+ x = 0;
+ v = w == 8;
+ if(v) {
+ c = cursafe;
+ if(n->left != Z && n->left->complex >= FNX
+ && n->right != Z && n->right->complex >= FNX) {
+// warn(n, "toughie");
+ regsalloc(&nod1, n->right);
+ cgen(n->right, &nod1);
+ nod2 = *n;
+ nod2.right = &nod1;
+ cgen(&nod2, nn);
+ cursafe = c;
+ return;
+ }
+ if(cgen64(n, nn)) {
+ cursafe = c;
+ return;
+ }
+ if(n->op == OCOM) {
+ n = n->left;
+ x = 1;
+ }
+ }
+
+ /* botch, need to save in .safe */
+ c = 0;
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[TLONG];
+ if(v) {
+ regalloc(&nod0, n, Z);
+ if(!vaddr(n, 0)) {
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ n = &nod1;
+ }
+ else
+ n->type = t;
+ }
+ else {
+ nodreg(&nod1, n, D_SI);
+ if(reg[D_SI]) {
+ gins(APUSHL, &nod1, Z);
+ c |= 1;
+ reg[D_SI]++;
+ }
+ lcgen(n, &nod1);
+ n->type = t;
+ }
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ if(v) {
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ nn = &nod2;
+ }
+ else
+ nn->type = t;
+ }
+ else {
+ nodreg(&nod2, nn, D_DI);
+ if(reg[D_DI]) {
+ gins(APUSHL, &nod2, Z);
+ c |= 2;
+ reg[D_DI]++;
+ }
+ lcgen(nn, &nod2);
+ nn->type = t;
+ }
+ } else {
+ t = nn->type;
+ nn->type = types[TLONG];
+ if(v) {
+ regalloc(&nod0, nn, Z);
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ nn = &nod2;
+ }
+ else
+ nn->type = t;
+ }
+ else {
+ nodreg(&nod2, nn, D_DI);
+ if(reg[D_DI]) {
+ gins(APUSHL, &nod2, Z);
+ c |= 2;
+ reg[D_DI]++;
+ }
+ lcgen(nn, &nod2);
+ nn->type = t;
+ }
+
+ t = n->type;
+ n->type = types[TLONG];
+ if(v) {
+ if(!vaddr(n, 0)) {
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ n = &nod1;
+ }
+ else
+ n->type = t;
+ }
+ else {
+ nodreg(&nod1, n, D_SI);
+ if(reg[D_SI]) {
+ gins(APUSHL, &nod1, Z);
+ c |= 1;
+ reg[D_SI]++;
+ }
+ lcgen(n, &nod1);
+ n->type = t;
+ }
+ }
+ if(v) {
+ gins(AMOVL, n, &nod0);
+ if(x)
+ gins(ANOTL, Z, &nod0);
+ gins(AMOVL, &nod0, nn);
+ n->xoffset += SZ_LONG;
+ nn->xoffset += SZ_LONG;
+ gins(AMOVL, n, &nod0);
+ if(x)
+ gins(ANOTL, Z, &nod0);
+ gins(AMOVL, &nod0, nn);
+ n->xoffset -= SZ_LONG;
+ nn->xoffset -= SZ_LONG;
+ if(nn == &nod2)
+ regfree(&nod2);
+ if(n == &nod1)
+ regfree(&nod1);
+ regfree(&nod0);
+ return;
+ }
+ nodreg(&nod3, n, D_CX);
+ if(reg[D_CX]) {
+ gins(APUSHL, &nod3, Z);
+ c |= 4;
+ reg[D_CX]++;
+ }
+ gins(AMOVL, nodconst(w/SZ_LONG), &nod3);
+ gins(ACLD, Z, Z);
+ gins(AREP, Z, Z);
+ gins(AMOVSL, Z, Z);
+ if(c & 4) {
+ gins(APOPL, Z, &nod3);
+ reg[D_CX]--;
+ }
+ if(c & 2) {
+ gins(APOPL, Z, &nod2);
+ reg[nod2.reg]--;
+ }
+ if(c & 1) {
+ gins(APOPL, Z, &nod1);
+ reg[nod1.reg]--;
+ }
+}
--- /dev/null
+// Inferno utils/8c/cgen64.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen64.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
+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));
+}
+
+static Node *
+anonreg(void)
+{
+ Node *n;
+
+ n = new(OREGISTER, Z, Z);
+ n->reg = D_NONE;
+ n->type = types[TLONG];
+ return n;
+}
+
+static Node *
+regpair(Node *n, Node *t)
+{
+ Node *r;
+
+ if(n != Z && n->op == OREGPAIR)
+ return n;
+ r = new(OREGPAIR, anonreg(), anonreg());
+ if(n != Z)
+ r->type = n->type;
+ else
+ r->type = t->type;
+ return r;
+}
+
+static void
+evacaxdx(Node *r)
+{
+ Node nod1, nod2;
+
+ if(r->reg == D_AX || r->reg == D_DX) {
+ reg[D_AX]++;
+ reg[D_DX]++;
+ /*
+ * this is just an optim that should
+ * check for spill
+ */
+ r->type = types[TULONG];
+ regalloc(&nod1, r, Z);
+ nodreg(&nod2, Z, r->reg);
+ gins(AMOVL, &nod2, &nod1);
+ regfree(r);
+ r->reg = nod1.reg;
+ reg[D_AX]--;
+ reg[D_DX]--;
+ }
+}
+
+/* lazy instantiation of register pair */
+static int
+instpair(Node *n, Node *l)
+{
+ int r;
+
+ r = 0;
+ if(n->left->reg == D_NONE) {
+ if(l != Z) {
+ n->left->reg = l->reg;
+ r = 1;
+ }
+ else
+ regalloc(n->left, n->left, Z);
+ }
+ if(n->right->reg == D_NONE)
+ regalloc(n->right, n->right, Z);
+ return r;
+}
+
+static void
+zapreg(Node *n)
+{
+ if(n->reg != D_NONE) {
+ regfree(n);
+ n->reg = D_NONE;
+ }
+}
+
+static void
+freepair(Node *n)
+{
+ regfree(n->left);
+ regfree(n->right);
+}
+
+/* n is not OREGPAIR, nn is */
+void
+loadpair(Node *n, Node *nn)
+{
+ Node nod;
+
+ instpair(nn, Z);
+ if(n->op == OCONST) {
+ gins(AMOVL, lo64(n), nn->left);
+ n->xoffset += SZ_LONG;
+ gins(AMOVL, hi64(n), nn->right);
+ n->xoffset -= SZ_LONG;
+ return;
+ }
+ if(!vaddr(n, 0)) {
+ /* steal the right register for the laddr */
+ nod = regnode;
+ nod.reg = nn->right->reg;
+ lcgen(n, &nod);
+ n = &nod;
+ regind(n, n);
+ n->xoffset = 0;
+ }
+ gins(AMOVL, n, nn->left);
+ n->xoffset += SZ_LONG;
+ gins(AMOVL, n, nn->right);
+ n->xoffset -= SZ_LONG;
+}
+
+/* n is OREGPAIR, nn is not */
+static void
+storepair(Node *n, Node *nn, int f)
+{
+ Node nod;
+
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod, nn, Z);
+ nn = &nod;
+ }
+ gins(AMOVL, n->left, nn);
+ nn->xoffset += SZ_LONG;
+ gins(AMOVL, n->right, nn);
+ nn->xoffset -= SZ_LONG;
+ if(nn == &nod)
+ regfree(&nod);
+ if(f)
+ freepair(n);
+}
+
+/* generate a cast t from n to tt */
+static void
+cast(Node *n, Type *t, Node *nn)
+{
+ Node *r;
+
+ r = new(OCAST, n, Z);
+ r->type = t;
+ sugen(r, nn, 8);
+}
+
+static void
+swapregs(Node *a, Node *b)
+{
+ int t;
+
+ t = a->reg;
+ a->reg = b->reg;
+ b->reg = t;
+}
+
+static void
+swappairs(Node *a, Node *b)
+{
+ swapregs(a->left, b->left);
+ swapregs(a->right, b->right);
+}
+
+static int
+saveme(Node *n)
+{
+ int r;
+
+ r = n->reg;
+ return r >= D_AX && r <= D_DI;
+}
+
+static void
+saveit(Node *n, Node *t, Node *r)
+{
+ Node nod;
+
+ if(saveme(n)) {
+ t->reg = n->reg;
+ gins(AMOVL, t, r);
+ r->xoffset += SZ_LONG;
+ if(n->reg == D_AX) {
+ regalloc(&nod, n, Z);
+ regfree(n);
+ n->reg = nod.reg;
+ }
+ }
+}
+
+static void
+restoreit(Node *n, Node *t, Node *r)
+{
+ if(saveme(n)) {
+ t->reg = n->reg;
+ gins(AMOVL, r, t);
+ r->xoffset += SZ_LONG;
+ }
+}
+
+enum
+{
+/* 4 only, see WW */
+ WNONE = 0,
+ WCONST,
+ WADDR,
+ WHARD,
+};
+
+static int
+whatof(Node *n, int a)
+{
+ if(n->op == OCONST)
+ return WCONST;
+ return !vaddr(n, a) ? WHARD : WADDR;
+}
+
+/* can upgrade an extern to addr for AND */
+static int
+reduxv(Node *n)
+{
+ return lo64v(n) == 0 || hi64v(n) == 0;
+}
+
+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;
+}
+
+/*
+ * for a func operand call it and then return
+ * the safe node
+ */
+static Node *
+vfunc(Node *n, Node *nn)
+{
+ Node *t;
+
+ if(n->op != OFUNC)
+ return n;
+ t = new(0, Z, Z);
+ if(nn == Z || nn == nodret)
+ nn = n;
+ regsalloc(t, nn);
+ sugen(n, t, 8);
+ return t;
+}
+
+static int
+forcereg(Node *d, int r, int o, Node *t)
+{
+ int a;
+
+ if(d->reg != D_NONE)
+ diag(Z, "force alloc");
+ d->reg = r;
+ a = 0;
+ if(reg[r]) {
+ reg[o]++;
+ regalloc(t, d, Z);
+ a = 1;
+ gins(AMOVL, d, t);
+ reg[o]--;
+ }
+ reg[r]++;
+ return a;
+}
+
+/* try to steal a reg */
+static int
+getreg(Node **np, Node *t, int r)
+{
+ Node *n, *p;
+
+ n = *np;
+ if(n->reg == r) {
+ p = new(0, Z, Z);
+ regalloc(p, n, Z);
+ gins(AMOVL, n, p);
+ *t = *n;
+ *np = p;
+ return 1;
+ }
+ return 0;
+}
+
+static Node *
+snarfreg(Node *n, Node *t, int r, Node *d, Node *c)
+{
+ if(n == Z || n->op != OREGPAIR || (!getreg(&n->left, t, r) && !getreg(&n->right, t, r))) {
+ if(nodreg(t, Z, r)) {
+ regalloc(c, d, Z);
+ gins(AMOVL, t, c);
+ reg[r]++;
+ return c;
+ }
+ reg[r]++;
+ }
+ return Z;
+}
+
+enum
+{
+ Vstart = OEND,
+
+ Vgo,
+ Vamv,
+ Vmv,
+ Vzero,
+ Vop,
+ Vopx,
+ Vins,
+ Vins0,
+ Vinsl,
+ Vinsr,
+ Vinsla,
+ Vinsra,
+ Vinsx,
+ Vmul,
+ Vshll,
+ VT,
+ VF,
+ V_l_lo_f,
+ V_l_hi_f,
+ V_l_lo_t,
+ V_l_hi_t,
+ V_l_lo_u,
+ V_l_hi_u,
+ V_r_lo_f,
+ V_r_hi_f,
+ V_r_lo_t,
+ V_r_hi_t,
+ V_r_lo_u,
+ V_r_hi_u,
+ Vspazz,
+ Vend,
+
+ V_T0,
+ V_T1,
+ V_F0,
+ V_F1,
+
+ V_a0,
+ V_a1,
+ V_f0,
+ V_f1,
+
+ V_p0,
+ V_p1,
+ V_p2,
+ V_p3,
+ V_p4,
+
+ V_s0,
+ V_s1,
+ V_s2,
+ V_s3,
+ V_s4,
+
+ C00,
+ C01,
+ C31,
+ C32,
+
+ O_l_lo,
+ O_l_hi,
+ O_r_lo,
+ O_r_hi,
+ O_t_lo,
+ O_t_hi,
+ O_l,
+ O_r,
+ O_l_rp,
+ O_r_rp,
+ O_t_rp,
+ O_r0,
+ O_r1,
+ O_Zop,
+
+ O_a0,
+ O_a1,
+
+ V_C0,
+ V_C1,
+
+ V_S0,
+ V_S1,
+
+ VOPS = 5,
+ VLEN = 5,
+ VARGS = 2,
+
+ S00 = 0,
+ Sc0,
+ Sc1,
+ Sc2,
+ Sac3,
+ Sac4,
+ S10,
+
+ SAgen = 0,
+ SAclo,
+ SAc32,
+ SAchi,
+ SAdgen,
+ SAdclo,
+ SAdc32,
+ SAdchi,
+
+ B0c = 0,
+ Bca,
+ Bac,
+
+ T0i = 0,
+ Tii,
+
+ Bop0 = 0,
+ Bop1,
+};
+
+/*
+ * _testv:
+ * CMPL lo,$0
+ * JNE true
+ * CMPL hi,$0
+ * JNE true
+ * GOTO false
+ * false:
+ * GOTO code
+ * true:
+ * GOTO patchme
+ * code:
+ */
+
+static uchar testi[][VLEN] =
+{
+ {Vop, ONE, O_l_lo, C00},
+ {V_s0, Vop, ONE, O_l_hi, C00},
+ {V_s1, Vgo, V_s2, Vgo, V_s3},
+ {VF, V_p0, V_p1, VT, V_p2},
+ {Vgo, V_p3},
+ {VT, V_p0, V_p1, VF, V_p2},
+ {Vend},
+};
+
+/* shift left general case */
+static uchar shll00[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vinsl, ASHLL, O_r, O_l_rp},
+ {Vins, ASHLL, O_r, O_l_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, ASHLL, O_r, O_l_lo},
+ {Vins, AMOVL, O_l_lo, O_l_hi},
+ {Vzero, O_l_lo, V_p0, Vend},
+};
+
+/* shift left rp, const < 32 */
+static uchar shllc0[][VLEN] =
+{
+ {Vinsl, ASHLL, O_r, O_l_rp},
+ {Vshll, O_r, O_l_lo, Vend},
+};
+
+/* shift left rp, const == 32 */
+static uchar shllc1[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_l_hi},
+ {Vzero, O_l_lo, Vend},
+};
+
+/* shift left rp, const > 32 */
+static uchar shllc2[][VLEN] =
+{
+ {Vshll, O_r, O_l_lo},
+ {Vins, AMOVL, O_l_lo, O_l_hi},
+ {Vzero, O_l_lo, Vend},
+};
+
+/* shift left addr, const == 32 */
+static uchar shllac3[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_t_lo, Vend},
+};
+
+/* shift left addr, const > 32 */
+static uchar shllac4[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vshll, O_r, O_t_hi},
+ {Vzero, O_t_lo, Vend},
+};
+
+/* shift left of constant */
+static uchar shll10[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsl, ASHLL, O_r, O_t_rp},
+ {Vins, ASHLL, O_r, O_t_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {V_l_lo_t, Vins, ASHLL, O_r, O_t_hi},
+ {Vzero, O_t_lo, V_p0, Vend},
+};
+
+static uchar (*shlltab[])[VLEN] =
+{
+ shll00,
+ shllc0,
+ shllc1,
+ shllc2,
+ shllac3,
+ shllac4,
+ shll10,
+};
+
+/* shift right general case */
+static uchar shrl00[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vinsr, ASHRL, O_r, O_l_rp},
+ {Vins, O_a0, O_r, O_l_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, O_a0, O_r, O_l_hi},
+ {Vins, AMOVL, O_l_hi, O_l_lo},
+ {V_T1, Vzero, O_l_hi},
+ {V_F1, Vins, ASARL, C31, O_l_hi},
+ {V_p0, Vend},
+};
+
+/* shift right rp, const < 32 */
+static uchar shrlc0[][VLEN] =
+{
+ {Vinsr, ASHRL, O_r, O_l_rp},
+ {Vins, O_a0, O_r, O_l_hi, Vend},
+};
+
+/* shift right rp, const == 32 */
+static uchar shrlc1[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_l_lo},
+ {V_T1, Vzero, O_l_hi},
+ {V_F1, Vins, ASARL, C31, O_l_hi},
+ {Vend},
+};
+
+/* shift right rp, const > 32 */
+static uchar shrlc2[][VLEN] =
+{
+ {Vins, O_a0, O_r, O_l_hi},
+ {Vins, AMOVL, O_l_hi, O_l_lo},
+ {V_T1, Vzero, O_l_hi},
+ {V_F1, Vins, ASARL, C31, O_l_hi},
+ {Vend},
+};
+
+/* shift right addr, const == 32 */
+static uchar shrlac3[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vend},
+};
+
+/* shift right addr, const > 32 */
+static uchar shrlac4[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {Vins, O_a0, O_r, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vend},
+};
+
+/* shift right of constant */
+static uchar shrl10[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsr, ASHRL, O_r, O_t_rp},
+ {Vins, O_a0, O_r, O_t_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_l_hi_t, Vins, O_a0, O_r, O_t_lo},
+ {V_l_hi_u, V_S1},
+ {V_T1, Vzero, O_t_hi, V_p0},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vend},
+};
+
+static uchar (*shrltab[])[VLEN] =
+{
+ shrl00,
+ shrlc0,
+ shrlc1,
+ shrlc2,
+ shrlac3,
+ shrlac4,
+ shrl10,
+};
+
+/* shift asop left general case */
+static uchar asshllgen[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsla, ASHLL, O_r, O_r0},
+ {Vins, ASHLL, O_r, O_r0},
+ {Vins, AMOVL, O_r1, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vzero, O_l_lo},
+ {Vins, ASHLL, O_r, O_r0},
+ {Vins, AMOVL, O_r0, O_l_hi, V_p0},
+ {V_f0, V_f1, Vend},
+};
+
+/* shift asop left, const < 32 */
+static uchar asshllclo[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsla, ASHLL, O_r, O_r0},
+ {Vshll, O_r, O_r0},
+ {Vins, AMOVL, O_r1, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_f0, V_f1, Vend},
+};
+
+/* shift asop left, const == 32 */
+static uchar asshllc32[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vzero, O_l_lo},
+ {Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop left, const > 32 */
+static uchar asshllchi[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vzero, O_l_lo},
+ {Vshll, O_r, O_r0},
+ {Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop dest left general case */
+static uchar asdshllgen[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsl, ASHLL, O_r, O_t_rp},
+ {Vins, ASHLL, O_r, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_l_lo},
+ {Vins, ASHLL, O_r, O_t_hi},
+ {Vzero, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
+ {Vend},
+};
+
+/* shift asop dest left, const < 32 */
+static uchar asdshllclo[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsl, ASHLL, O_r, O_t_rp},
+ {Vshll, O_r, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vend},
+};
+
+/* shift asop dest left, const == 32 */
+static uchar asdshllc32[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vend},
+};
+
+/* shift asop dest, const > 32 */
+static uchar asdshllchi[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_t_lo},
+ {Vshll, O_r, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+static uchar (*asshlltab[])[VLEN] =
+{
+ asshllgen,
+ asshllclo,
+ asshllc32,
+ asshllchi,
+ asdshllgen,
+ asdshllclo,
+ asdshllc32,
+ asdshllchi,
+};
+
+/* shift asop right general case */
+static uchar asshrlgen[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsra, ASHRL, O_r, O_r0},
+ {Vinsx, Bop0, O_r, O_r1},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {Vins, AMOVL, O_r1, O_l_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {Vinsx, Bop0, O_r, O_r0},
+ {V_T1, Vzero, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_F1, Vins, ASARL, C31, O_r0},
+ {V_F1, Vins, AMOVL, O_r0, O_l_hi},
+ {V_p0, V_f0, V_f1, Vend},
+};
+
+/* shift asop right, const < 32 */
+static uchar asshrlclo[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsra, ASHRL, O_r, O_r0},
+ {Vinsx, Bop0, O_r, O_r1},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {Vins, AMOVL, O_r1, O_l_hi},
+ {V_f0, V_f1, Vend},
+};
+
+/* shift asop right, const == 32 */
+static uchar asshrlc32[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {V_T1, Vzero, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_F1, Vins, ASARL, C31, O_r0},
+ {V_F1, Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop right, const > 32 */
+static uchar asshrlchi[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {V_T1, Vzero, O_l_hi},
+ {Vinsx, Bop0, O_r, O_r0},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_F1, Vins, ASARL, C31, O_r0},
+ {V_F1, Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop dest right general case */
+static uchar asdshrlgen[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsr, ASHRL, O_r, O_t_rp},
+ {Vinsx, Bop0, O_r, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {Vinsx, Bop0, O_r, O_t_lo},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
+ {Vend},
+};
+
+/* shift asop dest right, const < 32 */
+static uchar asdshrlclo[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsr, ASHRL, O_r, O_t_rp},
+ {Vinsx, Bop0, O_r, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+/* shift asop dest right, const == 32 */
+static uchar asdshrlc32[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+/* shift asop dest, const > 32 */
+static uchar asdshrlchi[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {Vinsx, Bop0, O_r, O_t_lo},
+ {V_T1, Vins, AMOVL, O_t_hi, O_l_hi},
+ {V_T1, Vins, AMOVL, O_t_lo, O_l_lo},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_l_lo},
+ {V_F1, Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+static uchar (*asshrltab[])[VLEN] =
+{
+ asshrlgen,
+ asshrlclo,
+ asshrlc32,
+ asshrlchi,
+ asdshrlgen,
+ asdshrlclo,
+ asdshrlc32,
+ asdshrlchi,
+};
+
+static uchar shrlargs[] = { ASHRL, 1 };
+static uchar sarlargs[] = { ASARL, 0 };
+
+/* ++ -- */
+static uchar incdec[][VLEN] =
+{
+ {Vinsx, Bop0, C01, O_l_lo},
+ {Vinsx, Bop1, C00, O_l_hi, Vend},
+};
+
+/* ++ -- *p */
+static uchar incdecpre[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop0, C01, O_t_lo},
+ {Vinsx, Bop1, C00, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi, Vend},
+};
+
+/* *p ++ -- */
+static uchar incdecpost[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop0, C01, O_l_lo},
+ {Vinsx, Bop1, C00, O_l_hi, Vend},
+};
+
+/* binop rp, rp */
+static uchar binop00[][VLEN] =
+{
+ {Vinsx, Bop0, O_r_lo, O_l_lo},
+ {Vinsx, Bop1, O_r_hi, O_l_hi, Vend},
+ {Vend},
+};
+
+/* binop rp, addr */
+static uchar binoptmp[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vinsx, Bop0, O_r0, O_l_lo},
+ {Vins, AMOVL, O_r_hi, O_r0},
+ {Vinsx, Bop1, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* binop t = *a op *b */
+static uchar binop11[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vinsx, Bop0, O_r_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop1, O_r_hi, O_t_hi, Vend},
+};
+
+/* binop t = rp +- c */
+static uchar add0c[][VLEN] =
+{
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+ {V_r_lo_f, Vamv, Bop0, Bop1},
+ {Vinsx, Bop1, O_r_hi, O_l_hi},
+ {Vend},
+};
+
+/* binop t = rp & c */
+static uchar and0c[][VLEN] =
+{
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+ {V_r_lo_f, Vins, AMOVL, C00, O_l_lo},
+ {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
+ {V_r_hi_f, Vins, AMOVL, C00, O_l_hi},
+ {Vend},
+};
+
+/* binop t = rp | c */
+static uchar or0c[][VLEN] =
+{
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+ {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
+ {Vend},
+};
+
+/* binop t = c - rp */
+static uchar sub10[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vinsx, Bop0, O_r_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r_lo},
+ {Vinsx, Bop1, O_r_hi, O_r_lo},
+ {Vspazz, V_f0, Vend},
+};
+
+/* binop t = c + *b */
+static uchar addca[][VLEN] =
+{
+ {Vins, AMOVL, O_r_lo, O_t_lo},
+ {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+ {V_l_lo_f, Vamv, Bop0, Bop1},
+ {Vins, AMOVL, O_r_hi, O_t_hi},
+ {Vinsx, Bop1, O_l_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = c & *b */
+static uchar andca[][VLEN] =
+{
+ {V_l_lo_t, Vins, AMOVL, O_r_lo, O_t_lo},
+ {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+ {V_l_lo_f, Vzero, O_t_lo},
+ {V_l_hi_t, Vins, AMOVL, O_r_hi, O_t_hi},
+ {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
+ {V_l_hi_f, Vzero, O_t_hi},
+ {Vend},
+};
+
+/* binop t = c | *b */
+static uchar orca[][VLEN] =
+{
+ {Vins, AMOVL, O_r_lo, O_t_lo},
+ {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_r_hi, O_t_hi},
+ {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = c - *b */
+static uchar subca[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop0, O_r_lo, O_t_lo},
+ {Vinsx, Bop1, O_r_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = *a +- c */
+static uchar addac[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+ {V_r_lo_f, Vamv, Bop0, Bop1},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop1, O_r_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = *a | c */
+static uchar orac[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = *a & c */
+static uchar andac[][VLEN] =
+{
+ {V_r_lo_t, Vins, AMOVL, O_l_lo, O_t_lo},
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+ {V_r_lo_f, Vzero, O_t_lo},
+ {V_r_hi_t, Vins, AMOVL, O_l_hi, O_t_hi},
+ {V_r_hi_t, Vinsx, Bop0, O_r_hi, O_t_hi},
+ {V_r_hi_f, Vzero, O_t_hi},
+ {Vend},
+};
+
+static uchar ADDargs[] = { AADDL, AADCL };
+static uchar ANDargs[] = { AANDL, AANDL };
+static uchar ORargs[] = { AORL, AORL };
+static uchar SUBargs[] = { ASUBL, ASBBL };
+static uchar XORargs[] = { AXORL, AXORL };
+
+static uchar (*ADDtab[])[VLEN] =
+{
+ add0c, addca, addac,
+};
+
+static uchar (*ANDtab[])[VLEN] =
+{
+ and0c, andca, andac,
+};
+
+static uchar (*ORtab[])[VLEN] =
+{
+ or0c, orca, orac,
+};
+
+static uchar (*SUBtab[])[VLEN] =
+{
+ add0c, subca, addac,
+};
+
+/* mul of const32 */
+static uchar mulc32[][VLEN] =
+{
+ {V_a0, Vop, ONE, O_l_hi, C00},
+ {V_s0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vins, AMULL, O_r0, O_Zop},
+ {Vgo, V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {Vmul, O_r_lo, O_r0},
+ {Vins, AMOVL, O_r_lo, O_l_hi},
+ {Vins, AMULL, O_l_hi, O_Zop},
+ {Vins, AADDL, O_r0, O_l_hi},
+ {V_f0, V_p0, Vend},
+};
+
+/* mul of const64 */
+static uchar mulc64[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_r_hi, O_r0},
+ {Vop, OOR, O_l_hi, O_r0},
+ {Vop, ONE, O_r0, C00},
+ {V_s0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vins, AMULL, O_r0, O_Zop},
+ {Vgo, V_p0, V_s0},
+ {Vmul, O_r_lo, O_l_hi},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vmul, O_r_hi, O_r0},
+ {Vins, AADDL, O_l_hi, O_r0},
+ {Vins, AMOVL, O_r_lo, O_l_hi},
+ {Vins, AMULL, O_l_hi, O_Zop},
+ {Vins, AADDL, O_r0, O_l_hi},
+ {V_f0, V_p0, Vend},
+};
+
+/* mul general */
+static uchar mull[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_r_hi, O_r0},
+ {Vop, OOR, O_l_hi, O_r0},
+ {Vop, ONE, O_r0, C00},
+ {V_s0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vins, AMULL, O_r0, O_Zop},
+ {Vgo, V_p0, V_s0},
+ {Vins, AIMULL, O_r_lo, O_l_hi},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AIMULL, O_r_hi, O_r0},
+ {Vins, AADDL, O_l_hi, O_r0},
+ {Vins, AMOVL, O_r_lo, O_l_hi},
+ {Vins, AMULL, O_l_hi, O_Zop},
+ {Vins, AADDL, O_r0, O_l_hi},
+ {V_f0, V_p0, Vend},
+};
+
+/* cast rp l to rp t */
+static uchar castrp[][VLEN] =
+{
+ {Vmv, O_l, O_t_lo},
+ {VT, Vins, AMOVL, O_t_lo, O_t_hi},
+ {VT, Vins, ASARL, C31, O_t_hi},
+ {VF, Vzero, O_t_hi},
+ {Vend},
+};
+
+/* cast rp l to addr t */
+static uchar castrpa[][VLEN] =
+{
+ {VT, V_a0, Vmv, O_l, O_r0},
+ {VT, Vins, AMOVL, O_r0, O_t_lo},
+ {VT, Vins, ASARL, C31, O_r0},
+ {VT, Vins, AMOVL, O_r0, O_t_hi},
+ {VT, V_f0},
+ {VF, Vmv, O_l, O_t_lo},
+ {VF, Vzero, O_t_hi},
+ {Vend},
+};
+
+static uchar netab0i[][VLEN] =
+{
+ {Vop, ONE, O_l_lo, O_r_lo},
+ {V_s0, Vop, ONE, O_l_hi, O_r_hi},
+ {V_s1, Vgo, V_s2, Vgo, V_s3},
+ {VF, V_p0, V_p1, VT, V_p2},
+ {Vgo, V_p3},
+ {VT, V_p0, V_p1, VF, V_p2},
+ {Vend},
+};
+
+static uchar netabii[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vop, ONE, O_r0, O_r_lo},
+ {V_s0, Vins, AMOVL, O_l_hi, O_r0},
+ {Vop, ONE, O_r0, O_r_hi},
+ {V_s1, Vgo, V_s2, Vgo, V_s3},
+ {VF, V_p0, V_p1, VT, V_p2},
+ {Vgo, V_p3},
+ {VT, V_p0, V_p1, VF, V_p2},
+ {V_f0, Vend},
+};
+
+static uchar cmptab0i[][VLEN] =
+{
+ {Vopx, Bop0, O_l_hi, O_r_hi},
+ {V_s0, Vins0, AJNE},
+ {V_s1, Vopx, Bop1, O_l_lo, O_r_lo},
+ {V_s2, Vgo, V_s3, Vgo, V_s4},
+ {VT, V_p1, V_p3},
+ {VF, V_p0, V_p2},
+ {Vgo, V_p4},
+ {VT, V_p0, V_p2},
+ {VF, V_p1, V_p3},
+ {Vend},
+};
+
+static uchar cmptabii[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_l_hi, O_r0},
+ {Vopx, Bop0, O_r0, O_r_hi},
+ {V_s0, Vins0, AJNE},
+ {V_s1, Vins, AMOVL, O_l_lo, O_r0},
+ {Vopx, Bop1, O_r0, O_r_lo},
+ {V_s2, Vgo, V_s3, Vgo, V_s4},
+ {VT, V_p1, V_p3},
+ {VF, V_p0, V_p2},
+ {Vgo, V_p4},
+ {VT, V_p0, V_p2},
+ {VF, V_p1, V_p3},
+ {V_f0, Vend},
+};
+
+static uchar (*NEtab[])[VLEN] =
+{
+ netab0i, netabii,
+};
+
+static uchar (*cmptab[])[VLEN] =
+{
+ cmptab0i, cmptabii,
+};
+
+static uchar GEargs[] = { OGT, OHS };
+static uchar GTargs[] = { OGT, OHI };
+static uchar HIargs[] = { OHI, OHI };
+static uchar HSargs[] = { OHI, OHS };
+
+/* Big Generator */
+static void
+biggen(Node *l, Node *r, Node *t, int true, uchar code[][VLEN], uchar *a)
+{
+ int i, j, g, oc, op, lo, ro, to, xo, *xp;
+ Type *lt;
+ Prog *pr[VOPS];
+ Node *ot, *tl, *tr, tmps[2];
+ uchar *c, (*cp)[VLEN], args[VARGS];
+
+ if(a != nil)
+ memmove(args, a, VARGS);
+//print("biggen %d %d %d\n", args[0], args[1], args[2]);
+//if(l) prtree(l, "l");
+//if(r) prtree(r, "r");
+//if(t) prtree(t, "t");
+ lo = ro = to = 0;
+ cp = code;
+
+ for (;;) {
+ c = *cp++;
+ g = 1;
+ i = 0;
+//print("code %d %d %d %d %d\n", c[0], c[1], c[2], c[3], c[4]);
+ for(;;) {
+ switch(op = c[i]) {
+ case Vgo:
+ if(g)
+ gbranch(OGOTO);
+ i++;
+ break;
+
+ case Vamv:
+ i += 3;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ if(g)
+ args[c[i - 1]] = args[c[i - 2]];
+ break;
+
+ case Vzero:
+ i += 2;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ j = i - 1;
+ goto op;
+
+ case Vspazz: // nasty hack to save a reg in SUB
+//print("spazz\n");
+ if(g) {
+//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
+ ot = r->right;
+ r->right = r->left;
+ tl = new(0, Z, Z);
+ *tl = tmps[0];
+ r->left = tl;
+ tmps[0] = *ot;
+//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
+ }
+ i++;
+ break;
+
+ case Vmv:
+ case Vmul:
+ case Vshll:
+ i += 3;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ j = i - 2;
+ goto op;
+
+ case Vins0:
+ i += 2;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ gins(c[i - 1], Z, Z);
+ break;
+
+ case Vop:
+ case Vopx:
+ case Vins:
+ case Vinsl:
+ case Vinsr:
+ case Vinsla:
+ case Vinsra:
+ case Vinsx:
+ i += 4;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ j = i - 2;
+ goto op;
+
+ op:
+ if(!g)
+ break;
+ tl = Z;
+ tr = Z;
+ for(; j < i; j++) {
+ switch(c[j]) {
+ case C00:
+ ot = nodconst(0);
+ break;
+ case C01:
+ ot = nodconst(1);
+ break;
+ case C31:
+ ot = nodconst(31);
+ break;
+ case C32:
+ ot = nodconst(32);
+ break;
+
+ case O_l:
+ case O_l_lo:
+ ot = l; xp = &lo; xo = 0;
+ goto op0;
+ case O_l_hi:
+ ot = l; xp = &lo; xo = SZ_LONG;
+ goto op0;
+ case O_r:
+ case O_r_lo:
+ ot = r; xp = &ro; xo = 0;
+ goto op0;
+ case O_r_hi:
+ ot = r; xp = &ro; xo = SZ_LONG;
+ goto op0;
+ case O_t_lo:
+ ot = t; xp = &to; xo = 0;
+ goto op0;
+ case O_t_hi:
+ ot = t; xp = &to; xo = SZ_LONG;
+ goto op0;
+ case O_l_rp:
+ ot = l;
+ break;
+ case O_r_rp:
+ ot = r;
+ break;
+ case O_t_rp:
+ ot = t;
+ break;
+ case O_r0:
+ case O_r1:
+ ot = &tmps[c[j] - O_r0];
+ break;
+ case O_Zop:
+ ot = Z;
+ break;
+
+ op0:
+ switch(ot->op) {
+ case OCONST:
+ if(xo)
+ ot = hi64(ot);
+ else
+ ot = lo64(ot);
+ break;
+ case OREGPAIR:
+ if(xo)
+ ot = ot->right;
+ else
+ ot = ot->left;
+ break;
+ case OREGISTER:
+ break;
+ default:
+ if(xo != *xp) {
+ ot->xoffset += xo - *xp;
+ *xp = xo;
+ }
+ }
+ break;
+
+ default:
+ diag(l, "bad V_lop");
+ return;
+ }
+ if(tl == nil)
+ tl = ot;
+ else
+ tr = ot;
+ }
+ if(op == Vzero) {
+ zeroregm(tl);
+ break;
+ }
+ oc = c[i - 3];
+ if(op == Vinsx || op == Vopx) {
+//print("%d -> %d\n", oc, args[oc]);
+ oc = args[oc];
+ }
+ else {
+ switch(oc) {
+ case O_a0:
+ case O_a1:
+ oc = args[oc - O_a0];
+ break;
+ }
+ }
+ switch(op) {
+ case Vmul:
+ mulgen(tr->type, tl, tr);
+ break;
+ case Vmv:
+ gmove(tl, tr);
+ break;
+ case Vshll:
+ shiftit(tr->type, tl, tr);
+ break;
+ case Vop:
+ case Vopx:
+ gopcode(oc, types[TULONG], tl, tr);
+ break;
+ case Vins:
+ case Vinsx:
+ gins(oc, tl, tr);
+ break;
+ case Vinsl:
+ gins(oc, tl, tr->right);
+ p->from.index = tr->left->reg;
+ break;
+ case Vinsr:
+ gins(oc, tl, tr->left);
+ p->from.index = tr->right->reg;
+ break;
+ case Vinsla:
+ gins(oc, tl, tr + 1);
+ p->from.index = tr->reg;
+ break;
+ case Vinsra:
+ gins(oc, tl, tr);
+ p->from.index = (tr + 1)->reg;
+ break;
+ }
+ break;
+
+ case VT:
+ g = true;
+ i++;
+ break;
+ case VF:
+ g = !true;
+ i++;
+ break;
+
+ case V_T0: case V_T1:
+ g = args[op - V_T0];
+ i++;
+ break;
+
+ case V_F0: case V_F1:
+ g = !args[op - V_F0];
+ i++;
+ break;
+
+ case V_C0: case V_C1:
+ if(g)
+ args[op - V_C0] = 0;
+ i++;
+ break;
+
+ case V_S0: case V_S1:
+ if(g)
+ args[op - V_S0] = 1;
+ i++;
+ break;
+
+ case V_l_lo_f:
+ g = lo64v(l) == 0;
+ i++;
+ break;
+ case V_l_hi_f:
+ g = hi64v(l) == 0;
+ i++;
+ break;
+ case V_l_lo_t:
+ g = lo64v(l) != 0;
+ i++;
+ break;
+ case V_l_hi_t:
+ g = hi64v(l) != 0;
+ i++;
+ break;
+ case V_l_lo_u:
+ g = lo64v(l) >= 0;
+ i++;
+ break;
+ case V_l_hi_u:
+ g = hi64v(l) >= 0;
+ i++;
+ break;
+ case V_r_lo_f:
+ g = lo64v(r) == 0;
+ i++;
+ break;
+ case V_r_hi_f:
+ g = hi64v(r) == 0;
+ i++;
+ break;
+ case V_r_lo_t:
+ g = lo64v(r) != 0;
+ i++;
+ break;
+ case V_r_hi_t:
+ g = hi64v(r) != 0;
+ i++;
+ break;
+ case V_r_lo_u:
+ g = lo64v(r) >= 0;
+ i++;
+ break;
+ case V_r_hi_u:
+ g = hi64v(r) >= 0;
+ i++;
+ break;
+
+ case Vend:
+ goto out;
+
+ case V_a0: case V_a1:
+ if(g) {
+ lt = l->type;
+ l->type = types[TULONG];
+ regalloc(&tmps[op - V_a0], l, Z);
+ l->type = lt;
+ }
+ i++;
+ break;
+
+ case V_f0: case V_f1:
+ if(g)
+ regfree(&tmps[op - V_f0]);
+ i++;
+ break;
+
+ case V_p0: case V_p1: case V_p2: case V_p3: case V_p4:
+ if(g)
+ patch(pr[op - V_p0], pc);
+ i++;
+ break;
+
+ case V_s0: case V_s1: case V_s2: case V_s3: case V_s4:
+ if(g)
+ pr[op - V_s0] = p;
+ i++;
+ break;
+
+ default:
+ diag(l, "bad biggen: %d", op);
+ return;
+ }
+ if(i == VLEN || c[i] == 0)
+ break;
+ }
+ }
+out:
+ if(lo)
+ l->xoffset -= lo;
+ if(ro)
+ r->xoffset -= ro;
+ if(to)
+ t->xoffset -= to;
+}
+
+int
+cgen64(Node *n, Node *nn)
+{
+ Type *dt;
+ uchar *args, (*cp)[VLEN], (**optab)[VLEN];
+ int li, ri, lri, dr, si, m, op, sh, cmp, true;
+ Node *c, *d, *l, *r, *t, *s, nod1, nod2, nod3, nod4, nod5;
+
+ if(debug['g']) {
+ prtree(nn, "cgen64 lhs");
+ prtree(n, "cgen64");
+ print("AX = %d\n", reg[D_AX]);
+ }
+ cmp = 0;
+ sh = 0;
+
+ switch(n->op) {
+ case ONEG:
+ d = regpair(nn, n);
+ sugen(n->left, d, 8);
+ gins(ANOTL, Z, d->right);
+ gins(ANEGL, Z, d->left);
+ gins(ASBBL, nodconst(-1), d->right);
+ break;
+
+ case OCOM:
+ if(!vaddr(n->left, 0) || !vaddr(nn, 0))
+ d = regpair(nn, n);
+ else
+ return 0;
+ sugen(n->left, d, 8);
+ gins(ANOTL, Z, d->left);
+ gins(ANOTL, Z, d->right);
+ break;
+
+ case OADD:
+ optab = ADDtab;
+ args = ADDargs;
+ goto twoop;
+ case OAND:
+ optab = ANDtab;
+ args = ANDargs;
+ goto twoop;
+ case OOR:
+ optab = ORtab;
+ args = ORargs;
+ goto twoop;
+ case OSUB:
+ optab = SUBtab;
+ args = SUBargs;
+ goto twoop;
+ case OXOR:
+ optab = ORtab;
+ args = XORargs;
+ goto twoop;
+ case OASHL:
+ sh = 1;
+ args = nil;
+ optab = shlltab;
+ goto twoop;
+ case OLSHR:
+ sh = 1;
+ args = shrlargs;
+ optab = shrltab;
+ goto twoop;
+ case OASHR:
+ sh = 1;
+ args = sarlargs;
+ optab = shrltab;
+ goto twoop;
+ case OEQ:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case ONE:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLE:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLT:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OGE:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OGT:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OHI:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OHS:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLO:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLS:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+
+twoop:
+ dr = nn != Z && nn->op == OREGPAIR;
+ l = vfunc(n->left, nn);
+ if(sh)
+ r = n->right;
+ else
+ r = vfunc(n->right, nn);
+
+ li = l->op == ONAME || l->op == OINDREG || l->op == OCONST;
+ ri = r->op == ONAME || r->op == OINDREG || r->op == OCONST;
+
+#define IMM(l, r) ((l) | ((r) << 1))
+
+ lri = IMM(li, ri);
+
+ /* find out what is so easy about some operands */
+ if(li)
+ li = whatof(l, sh | cmp);
+ if(ri)
+ ri = whatof(r, cmp);
+
+ if(sh)
+ goto shift;
+
+ if(cmp)
+ goto cmp;
+
+ /* evaluate hard subexps, stealing nn if possible. */
+ switch(lri) {
+ case IMM(0, 0):
+ bin00:
+ if(l->complex > r->complex) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ }
+ else {
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ }
+ break;
+ case IMM(0, 1):
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ break;
+ case IMM(1, 0):
+ if(n->op == OSUB && l->op == OCONST && hi64v(l) == 0) {
+ lri = IMM(0, 0);
+ goto bin00;
+ }
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ break;
+ case IMM(1, 1):
+ break;
+ }
+
+#define WW(l, r) ((l) | ((r) << 2))
+ d = Z;
+ dt = nn->type;
+ nn->type = types[TLONG];
+
+ switch(lri) {
+ case IMM(0, 0):
+ biggen(l, r, Z, 0, binop00, args);
+ break;
+ case IMM(0, 1):
+ switch(ri) {
+ case WNONE:
+ diag(r, "bad whatof\n");
+ break;
+ case WCONST:
+ biggen(l, r, Z, 0, optab[B0c], args);
+ break;
+ case WHARD:
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ /* fall thru */
+ case WADDR:
+ biggen(l, r, Z, 0, binoptmp, args);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+ break;
+ case IMM(1, 0):
+ if(n->op == OSUB) {
+ switch(li) {
+ case WNONE:
+ diag(l, "bad whatof\n");
+ break;
+ case WHARD:
+ reglcgen(&nod2, l, Z);
+ l = &nod2;
+ /* fall thru */
+ case WADDR:
+ case WCONST:
+ biggen(l, r, Z, 0, sub10, args);
+ break;
+ }
+ if(li == WHARD)
+ regfree(l);
+ }
+ else {
+ switch(li) {
+ case WNONE:
+ diag(l, "bad whatof\n");
+ break;
+ case WCONST:
+ biggen(r, l, Z, 0, optab[B0c], args);
+ break;
+ case WHARD:
+ reglcgen(&nod2, l, Z);
+ l = &nod2;
+ /* fall thru */
+ case WADDR:
+ biggen(r, l, Z, 0, binoptmp, args);
+ if(li == WHARD)
+ regfree(l);
+ break;
+ }
+ }
+ break;
+ case IMM(1, 1):
+ switch(WW(li, ri)) {
+ case WW(WCONST, WHARD):
+ if(r->op == ONAME && n->op == OAND && reduxv(l))
+ ri = WADDR;
+ break;
+ case WW(WHARD, WCONST):
+ if(l->op == ONAME && n->op == OAND && reduxv(r))
+ li = WADDR;
+ break;
+ }
+ if(li == WHARD) {
+ reglcgen(&nod3, l, Z);
+ l = &nod3;
+ }
+ if(ri == WHARD) {
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ }
+ d = regpair(nn, n);
+ instpair(d, Z);
+ switch(WW(li, ri)) {
+ case WW(WCONST, WADDR):
+ case WW(WCONST, WHARD):
+ biggen(l, r, d, 0, optab[Bca], args);
+ break;
+
+ case WW(WADDR, WCONST):
+ case WW(WHARD, WCONST):
+ biggen(l, r, d, 0, optab[Bac], args);
+ break;
+
+ case WW(WADDR, WADDR):
+ case WW(WADDR, WHARD):
+ case WW(WHARD, WADDR):
+ case WW(WHARD, WHARD):
+ biggen(l, r, d, 0, binop11, args);
+ break;
+
+ default:
+ diag(r, "bad whatof pair %d %d\n", li, ri);
+ break;
+ }
+ if(li == WHARD)
+ regfree(l);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+
+ nn->type = dt;
+
+ if(d != Z)
+ goto finished;
+
+ switch(lri) {
+ case IMM(0, 0):
+ freepair(r);
+ /* fall thru */;
+ case IMM(0, 1):
+ if(!dr)
+ storepair(l, nn, 1);
+ break;
+ case IMM(1, 0):
+ if(!dr)
+ storepair(r, nn, 1);
+ break;
+ case IMM(1, 1):
+ break;
+ }
+ return 1;
+
+ shift:
+ c = Z;
+
+ /* evaluate hard subexps, stealing nn if possible. */
+ /* must also secure CX. not as many optims as binop. */
+ switch(lri) {
+ case IMM(0, 0):
+ imm00:
+ if(l->complex + 1 > r->complex) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ t = &nod1;
+ c = snarfreg(l, t, D_CX, r, &nod2);
+ cgen(r, t);
+ r = t;
+ }
+ else {
+ t = &nod1;
+ c = snarfreg(nn, t, D_CX, r, &nod2);
+ cgen(r, t);
+ r = t;
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ }
+ break;
+ case IMM(0, 1):
+ imm01:
+ if(ri != WCONST) {
+ lri = IMM(0, 0);
+ goto imm00;
+ }
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ break;
+ case IMM(1, 0):
+ imm10:
+ if(li != WCONST) {
+ lri = IMM(0, 0);
+ goto imm00;
+ }
+ t = &nod1;
+ c = snarfreg(nn, t, D_CX, r, &nod2);
+ cgen(r, t);
+ r = t;
+ break;
+ case IMM(1, 1):
+ if(ri != WCONST) {
+ lri = IMM(1, 0);
+ goto imm10;
+ }
+ if(li == WHARD) {
+ lri = IMM(0, 1);
+ goto imm01;
+ }
+ break;
+ }
+
+ d = Z;
+
+ switch(lri) {
+ case IMM(0, 0):
+ biggen(l, r, Z, 0, optab[S00], args);
+ break;
+ case IMM(0, 1):
+ switch(ri) {
+ case WNONE:
+ case WADDR:
+ case WHARD:
+ diag(r, "bad whatof\n");
+ break;
+ case WCONST:
+ m = r->vconst & 63;
+ s = nodconst(m);
+ if(m < 32)
+ cp = optab[Sc0];
+ else if(m == 32)
+ cp = optab[Sc1];
+ else
+ cp = optab[Sc2];
+ biggen(l, s, Z, 0, cp, args);
+ break;
+ }
+ break;
+ case IMM(1, 0):
+ /* left is const */
+ d = regpair(nn, n);
+ instpair(d, Z);
+ biggen(l, r, d, 0, optab[S10], args);
+ regfree(r);
+ break;
+ case IMM(1, 1):
+ d = regpair(nn, n);
+ instpair(d, Z);
+ switch(WW(li, ri)) {
+ case WW(WADDR, WCONST):
+ m = r->vconst & 63;
+ s = nodconst(m);
+ if(m < 32) {
+ loadpair(l, d);
+ l = d;
+ cp = optab[Sc0];
+ }
+ else if(m == 32)
+ cp = optab[Sac3];
+ else
+ cp = optab[Sac4];
+ biggen(l, s, d, 0, cp, args);
+ break;
+
+ default:
+ diag(r, "bad whatof pair %d %d\n", li, ri);
+ break;
+ }
+ break;
+ }
+
+ if(c != Z) {
+ gins(AMOVL, c, r);
+ regfree(c);
+ }
+
+ if(d != Z)
+ goto finished;
+
+ switch(lri) {
+ case IMM(0, 0):
+ regfree(r);
+ /* fall thru */
+ case IMM(0, 1):
+ if(!dr)
+ storepair(l, nn, 1);
+ break;
+ case IMM(1, 0):
+ regfree(r);
+ break;
+ case IMM(1, 1):
+ break;
+ }
+ return 1;
+
+ cmp:
+ op = n->op;
+ /* evaluate hard subexps */
+ switch(lri) {
+ case IMM(0, 0):
+ if(l->complex > r->complex) {
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ }
+ else {
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ }
+ break;
+ case IMM(1, 0):
+ t = r;
+ r = l;
+ l = t;
+ ri = li;
+ op = invrel[relindex(op)];
+ /* fall thru */
+ case IMM(0, 1):
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ break;
+ case IMM(1, 1):
+ break;
+ }
+
+ true = 1;
+ optab = cmptab;
+ switch(op) {
+ case OEQ:
+ optab = NEtab;
+ true = 0;
+ break;
+ case ONE:
+ optab = NEtab;
+ break;
+ case OLE:
+ args = GTargs;
+ true = 0;
+ break;
+ case OGT:
+ args = GTargs;
+ break;
+ case OLS:
+ args = HIargs;
+ true = 0;
+ break;
+ case OHI:
+ args = HIargs;
+ break;
+ case OLT:
+ args = GEargs;
+ true = 0;
+ break;
+ case OGE:
+ args = GEargs;
+ break;
+ case OLO:
+ args = HSargs;
+ true = 0;
+ break;
+ case OHS:
+ args = HSargs;
+ break;
+ default:
+ diag(n, "bad cmp\n");
+ SET(optab);
+ }
+
+ switch(lri) {
+ case IMM(0, 0):
+ biggen(l, r, Z, true, optab[T0i], args);
+ break;
+ case IMM(0, 1):
+ case IMM(1, 0):
+ switch(ri) {
+ case WNONE:
+ diag(l, "bad whatof\n");
+ break;
+ case WCONST:
+ biggen(l, r, Z, true, optab[T0i], args);
+ break;
+ case WHARD:
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ /* fall thru */
+ case WADDR:
+ biggen(l, r, Z, true, optab[T0i], args);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+ break;
+ case IMM(1, 1):
+ if(li == WHARD) {
+ reglcgen(&nod3, l, Z);
+ l = &nod3;
+ }
+ if(ri == WHARD) {
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ }
+ biggen(l, r, Z, true, optab[Tii], args);
+ if(li == WHARD)
+ regfree(l);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+
+ switch(lri) {
+ case IMM(0, 0):
+ freepair(r);
+ /* fall thru */;
+ case IMM(0, 1):
+ case IMM(1, 0):
+ freepair(l);
+ break;
+ case IMM(1, 1):
+ break;
+ }
+ return 1;
+
+ case OASMUL:
+ case OASLMUL:
+ m = 0;
+ goto mulop;
+
+ case OMUL:
+ case OLMUL:
+ m = 1;
+ goto mulop;
+
+ mulop:
+ dr = nn != Z && nn->op == OREGPAIR;
+ l = vfunc(n->left, nn);
+ r = vfunc(n->right, nn);
+ if(r->op != OCONST) {
+ if(l->complex > r->complex) {
+ if(m) {
+ t = l;
+ l = r;
+ r = t;
+ }
+ else if(!vaddr(l, 1)) {
+ reglcgen(&nod5, l, Z);
+ l = &nod5;
+ evacaxdx(l);
+ }
+ }
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ evacaxdx(r->left);
+ evacaxdx(r->right);
+ if(l->complex <= r->complex && !m && !vaddr(l, 1)) {
+ reglcgen(&nod5, l, Z);
+ l = &nod5;
+ evacaxdx(l);
+ }
+ }
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ c = Z;
+ d = Z;
+ if(!nodreg(&nod1, t->left, D_AX)) {
+ if(t->left->reg != D_AX){
+ t->left->reg = D_AX;
+ reg[D_AX]++;
+ }else if(reg[D_AX] == 0)
+ fatal(Z, "vlong mul AX botch");
+ }
+ if(!nodreg(&nod2, t->right, D_DX)) {
+ if(t->right->reg != D_DX){
+ t->right->reg = D_DX;
+ reg[D_DX]++;
+ }else if(reg[D_DX] == 0)
+ fatal(Z, "vlong mul DX botch");
+ }
+ if(m)
+ sugen(l, t, 8);
+ else
+ loadpair(l, t);
+ if(t->left->reg != D_AX) {
+ c = &nod3;
+ regsalloc(c, t->left);
+ gmove(&nod1, c);
+ gmove(t->left, &nod1);
+ zapreg(t->left);
+ }
+ if(t->right->reg != D_DX) {
+ d = &nod4;
+ regsalloc(d, t->right);
+ gmove(&nod2, d);
+ gmove(t->right, &nod2);
+ zapreg(t->right);
+ }
+ if(c != Z || d != Z) {
+ s = regpair(Z, n);
+ s->left = &nod1;
+ s->right = &nod2;
+ }
+ else
+ s = t;
+ if(r->op == OCONST) {
+ if(hi64v(r) == 0)
+ biggen(s, r, Z, 0, mulc32, nil);
+ else
+ biggen(s, r, Z, 0, mulc64, nil);
+ }
+ else
+ biggen(s, r, Z, 0, mull, nil);
+ instpair(t, Z);
+ if(c != Z) {
+ gmove(&nod1, t->left);
+ gmove(&nod3, &nod1);
+ }
+ if(d != Z) {
+ gmove(&nod2, t->right);
+ gmove(&nod4, &nod2);
+ }
+ if(r->op == OREGPAIR)
+ freepair(r);
+ if(!m)
+ storepair(t, l, 0);
+ if(l == &nod5)
+ regfree(l);
+ if(!dr) {
+ if(nn != Z)
+ storepair(t, nn, 1);
+ else
+ freepair(t);
+ }
+ return 1;
+
+ case OASADD:
+ args = ADDargs;
+ goto vasop;
+ case OASAND:
+ args = ANDargs;
+ goto vasop;
+ case OASOR:
+ args = ORargs;
+ goto vasop;
+ case OASSUB:
+ args = SUBargs;
+ goto vasop;
+ case OASXOR:
+ args = XORargs;
+ goto vasop;
+
+ vasop:
+ l = n->left;
+ r = n->right;
+ dr = nn != Z && nn->op == OREGPAIR;
+ m = 0;
+ if(l->complex > r->complex) {
+ if(!vaddr(l, 1)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ m = 1;
+ }
+ }
+ else {
+ if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ m = 1;
+ }
+ if(!vaddr(l, 1)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ }
+ if(nn != Z) {
+ if(n->op == OASSUB)
+ biggen(l, r, Z, 0, sub10, args);
+ else
+ biggen(r, l, Z, 0, binoptmp, args);
+ storepair(r, l, 0);
+ }
+ else {
+ if(m)
+ biggen(l, r, Z, 0, binop00, args);
+ else
+ biggen(l, r, Z, 0, binoptmp, args);
+ }
+ if(l == &nod1)
+ regfree(&nod1);
+ if(m) {
+ if(nn == Z)
+ freepair(r);
+ else if(!dr)
+ storepair(r, nn, 1);
+ }
+ return 1;
+
+ case OASASHL:
+ args = nil;
+ optab = asshlltab;
+ goto assh;
+ case OASLSHR:
+ args = shrlargs;
+ optab = asshrltab;
+ goto assh;
+ case OASASHR:
+ args = sarlargs;
+ optab = asshrltab;
+ goto assh;
+
+ assh:
+ c = Z;
+ l = n->left;
+ r = n->right;
+ if(r->op == OCONST) {
+ m = r->vconst & 63;
+ if(m < 32)
+ m = SAclo;
+ else if(m == 32)
+ m = SAc32;
+ else
+ m = SAchi;
+ }
+ else
+ m = SAgen;
+ if(l->complex > r->complex) {
+ if(!vaddr(l, 0)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ if(m == SAgen) {
+ t = &nod2;
+ if(l->reg == D_CX) {
+ regalloc(t, r, Z);
+ gmove(l, t);
+ l->reg = t->reg;
+ t->reg = D_CX;
+ }
+ else
+ c = snarfreg(nn, t, D_CX, r, &nod3);
+ cgen(r, t);
+ r = t;
+ }
+ }
+ else {
+ if(m == SAgen) {
+ t = &nod2;
+ c = snarfreg(nn, t, D_CX, r, &nod3);
+ cgen(r, t);
+ r = t;
+ }
+ if(!vaddr(l, 0)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ }
+
+ if(nn != Z) {
+ m += SAdgen - SAgen;
+ d = regpair(nn, n);
+ instpair(d, Z);
+ biggen(l, r, d, 0, optab[m], args);
+ if(l == &nod1) {
+ regfree(&nod1);
+ l = Z;
+ }
+ if(r == &nod2 && c == Z) {
+ regfree(&nod2);
+ r = Z;
+ }
+ if(d != nn)
+ storepair(d, nn, 1);
+ }
+ else
+ biggen(l, r, Z, 0, optab[m], args);
+
+ if(c != Z) {
+ gins(AMOVL, c, r);
+ regfree(c);
+ }
+ if(l == &nod1)
+ regfree(&nod1);
+ if(r == &nod2)
+ regfree(&nod2);
+ return 1;
+
+ case OPOSTINC:
+ args = ADDargs;
+ cp = incdecpost;
+ goto vinc;
+ case OPOSTDEC:
+ args = SUBargs;
+ cp = incdecpost;
+ goto vinc;
+ case OPREINC:
+ args = ADDargs;
+ cp = incdecpre;
+ goto vinc;
+ case OPREDEC:
+ args = SUBargs;
+ cp = incdecpre;
+ goto vinc;
+
+ vinc:
+ l = n->left;
+ if(!vaddr(l, 1)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+
+ if(nn != Z) {
+ d = regpair(nn, n);
+ instpair(d, Z);
+ biggen(l, Z, d, 0, cp, args);
+ if(l == &nod1) {
+ regfree(&nod1);
+ l = Z;
+ }
+ if(d != nn)
+ storepair(d, nn, 1);
+ }
+ else
+ biggen(l, Z, Z, 0, incdec, args);
+
+ if(l == &nod1)
+ regfree(&nod1);
+ return 1;
+
+ case OCAST:
+ l = n->left;
+ if(typev[l->type->etype]) {
+ if(!vaddr(l, 1)) {
+ if(l->complex + 1 > nn->complex) {
+ d = regpair(Z, l);
+ sugen(l, d, 8);
+ if(!vaddr(nn, 1)) {
+ reglcgen(&nod1, nn, Z);
+ r = &nod1;
+ }
+ else
+ r = nn;
+ }
+ else {
+ if(!vaddr(nn, 1)) {
+ reglcgen(&nod1, nn, Z);
+ r = &nod1;
+ }
+ else
+ r = nn;
+ d = regpair(Z, l);
+ sugen(l, d, 8);
+ }
+// d->left->type = r->type;
+ d->left->type = types[TLONG];
+ gmove(d->left, r);
+ freepair(d);
+ }
+ else {
+ if(nn->op != OREGISTER && !vaddr(nn, 1)) {
+ reglcgen(&nod1, nn, Z);
+ r = &nod1;
+ }
+ else
+ r = nn;
+// l->type = r->type;
+ l->type = types[TLONG];
+ gmove(l, r);
+ }
+ if(r != nn)
+ regfree(r);
+ }
+ else {
+ if(typeu[l->type->etype] || cond(l->op))
+ si = TUNSIGNED;
+ else
+ si = TSIGNED;
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ if(nn->op == OREGPAIR) {
+ m = instpair(nn, &nod1);
+ biggen(&nod1, Z, nn, si == TSIGNED, castrp, nil);
+ }
+ else {
+ m = 0;
+ if(!vaddr(nn, si != TSIGNED)) {
+ dt = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = dt;
+ nn = &nod2;
+ }
+ dt = nn->type;
+ nn->type = types[TLONG];
+ biggen(&nod1, Z, nn, si == TSIGNED, castrpa, nil);
+ nn->type = dt;
+ if(nn == &nod2)
+ regfree(&nod2);
+ }
+ if(!m)
+ regfree(&nod1);
+ }
+ return 1;
+
+ default:
+ if(n->op == OREGPAIR) {
+ storepair(n, nn, 1);
+ return 1;
+ }
+ if(nn->op == OREGPAIR) {
+ loadpair(n, nn);
+ return 1;
+ }
+ return 0;
+ }
+finished:
+ if(d != nn)
+ storepair(d, nn, 1);
+ return 1;
+}
+
+void
+testv(Node *n, int true)
+{
+ Type *t;
+ Node *nn, nod;
+
+ switch(n->op) {
+ case OINDREG:
+ case ONAME:
+ biggen(n, Z, Z, true, testi, nil);
+ break;
+
+ default:
+ n = vfunc(n, n);
+ if(n->addable >= INDEXED) {
+ t = n->type;
+ n->type = types[TLONG];
+ reglcgen(&nod, n, Z);
+ n->type = t;
+ n = &nod;
+ biggen(n, Z, Z, true, testi, nil);
+ if(n == &nod)
+ regfree(n);
+ }
+ else {
+ nn = regpair(Z, n);
+ sugen(n, nn, 8);
+ biggen(nn, Z, Z, true, testi, nil);
+ freepair(nn);
+ }
+ }
+}
--- /dev/null
+// Inferno utils/8c/div.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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);
+}
--- /dev/null
+// Inferno utils/8c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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 "../8c/8.out.h"
+
+/*
+ * 8c/386
+ * Intel 386
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 4
+#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
+{
+ long 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;
+ long val;
+ long label;
+ char def;
+};
+#define C ((Case*)0)
+
+struct C1
+{
+ long val;
+ long label;
+};
+
+struct Var
+{
+ long 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 Case* cases;
+EXTERN Node constnode;
+EXTERN Node fconstnode;
+EXTERN long continpc;
+EXTERN long curarg;
+EXTERN long cursafe;
+EXTERN Prog* firstp;
+EXTERN Prog* lastp;
+EXTERN long maxargsafe;
+EXTERN int mnstring;
+EXTERN int retok;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN long nrathole;
+EXTERN long nstring;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Node regnode;
+EXTERN Node fregnode0;
+EXTERN Node fregnode1;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN int reg[D_NONE];
+EXTERN long exregoffset;
+EXTERN long exfregoffset;
+
+#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);
+
+/*
+ * 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);
+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 gmove(Node*, Node*);
+void gins(int a, Node*, Node*);
+void fgopcode(int, Node*, Node*, int, int);
+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
+
+/*
+ * 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*
+
+/* wrecklessly steal a field */
+
+#define rplink label
--- /dev/null
+// Inferno utils/8c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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, "$%ld", 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, "%ld(%R)", a->offset, i-D_INDIR);
+ else
+ sprint(str, "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ if(a->offset)
+ sprint(str, "$%ld,%R", a->offset, i);
+ else
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%ld(PC)", a->offset-pc);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%ld(SB)", a->sym->name,
+ a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s+%ld(SP)", a->sym->name, a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym)
+ sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
+ else
+ sprint(str, "%ld(FP)", a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%ld", 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",
+ "AH",
+ "CH",
+ "DH",
+ "BH",
+
+ "AX", /*[D_AX]*/
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+
+ "F0", /*[D_F0]*/
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "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",
+
+ "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);
+}
--- /dev/null
+// Inferno utils/8c/machcap.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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:
+ if(typev[n->type->etype]) {
+ if(typechlp[n->left->type->etype])
+ return 1;
+ }
+ else if(!typefd[n->type->etype]) {
+ if(typev[n->left->type->etype])
+ return 1;
+ }
+ break;
+
+ 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;
+}
--- /dev/null
+# Inferno utils/8c/mkenam
+# http://code.google.com/p/inferno-os/source/browse/utils/8c/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 - ../8c/8.out.h <<'!'
+v/^ A/d
+,s/^ A/ "/
+g/ .*$/s///
+,s/,*$/",/
+1i
+char* anames[] =
+{
+.
+$a
+};
+.
+w enam.c
+Q
+!
--- /dev/null
+// Inferno utils/8c/mul.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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);
+}
--- /dev/null
+// Inferno utils/8c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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 ASBBL:
+ case ARCRL:
+ return 1;
+ case AADDL:
+ case ASUBL:
+ case AJMP:
+ case ARET:
+ case ACALL:
+ return 0;
+ default:
+ if(p->to.type == D_BRANCH)
+ return 0;
+ }
+ p = p->link;
+ }
+ return 0;
+}
+
+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:
+ if(regtyp(&p->to))
+ if(regtyp(&p->from)) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ break;
+
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ if(regtyp(&p->to)) {
+ r1 = uniqs(r);
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p->as == p1->as && p->to.type == p1->from.type)
+ p1->as = AMOVL;
+ }
+ }
+ break;
+ case AADDL:
+ case AADDW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1){
+ if(p->as == AADDL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ }
+ else if(p->from.offset == 1){
+ if(p->as == AADDL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ }
+ break;
+ case ASUBL:
+ case ASUBW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1) {
+ if(p->as == ASUBL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ }
+ else if(p->from.offset == 1){
+ 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_DI)
+ 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 AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULW:
+
+ case AROLB:
+ case AROLL:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRW:
+
+ case AREP:
+ case AREPN:
+
+ case ACWD:
+ case ACDQ:
+
+ case AMOVSL:
+ case AFSTSW:
+ return 0;
+
+ case AMOVL:
+ 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);
+ return 2;
+
+ case ANEGB:
+ case ANEGW:
+ case ANEGL:
+ case ANOTB:
+ case ANOTW:
+ case ANOTL:
+ if(copyas(&p->to, v))
+ return 2;
+ break;
+
+ case ALEAL: /* lhs addr, rhs store */
+ if(copyas(&p->from, v))
+ return 2;
+
+
+ case ANOP: /* rhs store */
+ case AMOVL:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ 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 AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ 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 AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDW:
+ case ADECL:
+ case ADECW:
+ case AINCL:
+ case AINCW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORW:
+ case AMOVB:
+ case AMOVW:
+
+ case AFMOVB:
+ case AFMOVBP:
+ case AFMOVD:
+ case AFMOVDP:
+ case AFMOVF:
+ case AFMOVFP:
+ case AFMOVL:
+ case AFMOVLP:
+ case AFMOVV:
+ case AFMOVVP:
+ case AFMOVW:
+ case AFMOVWP:
+ case AFMOVX:
+ case AFMOVXP:
+ case AFADDDP:
+ case AFADDW:
+ case AFADDL:
+ case AFADDF:
+ case AFADDD:
+ case AFMULDP:
+ case AFMULW:
+ case AFMULL:
+ case AFMULF:
+ case AFMULD:
+ case AFSUBDP:
+ case AFSUBW:
+ case AFSUBL:
+ case AFSUBF:
+ case AFSUBD:
+ case AFSUBRDP:
+ case AFSUBRW:
+ case AFSUBRL:
+ case AFSUBRF:
+ case AFSUBRD:
+ case AFDIVDP:
+ case AFDIVW:
+ case AFDIVL:
+ case AFDIVF:
+ case AFDIVD:
+ case AFDIVRDP:
+ case AFDIVRW:
+ case AFDIVRL:
+ case AFDIVRF:
+ case AFDIVRD:
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ACMPL: /* read only */
+ case ACMPW:
+ case ACMPB:
+
+ case AFCOMB:
+ case AFCOMBP:
+ case AFCOMD:
+ case AFCOMDP:
+ case AFCOMDPP:
+ case AFCOMF:
+ case AFCOMFP:
+ case AFCOML:
+ case AFCOMLP:
+ case AFCOMW:
+ case AFCOMWP:
+ case AFUCOM:
+ case AFUCOMP:
+ case AFUCOMPP:
+ 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 AFLDZ:
+ case AWAIT:
+ break;
+
+ case AIMULL:
+ case AIMULW:
+ if(p->to.type != D_NONE) {
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+ }
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ if(v->type == D_AX || v->type == D_DX)
+ return 2;
+ goto caseread;
+
+ case AMOVSL:
+ case AREP:
+ case AREPN:
+ if(v->type == D_CX || v->type == D_DI || v->type == D_SI)
+ return 2;
+ goto caseread;
+
+ case AFSTSW:
+ if(v->type == D_AX)
+ 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)
+ return 2;
+ if(s != A)
+ return 1;
+ return 3;
+
+ case ACALL: /* funny */
+ 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;
+ }
+ 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_DI) {
+ if(f)
+ a->type = t;
+ }
+ return 0;
+ }
+ if(regtyp(v)) {
+ t = v->type;
+ if(a->type == t+D_INDIR) {
+ if(s->type == D_BP && 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;
+}
--- /dev/null
+// Inferno utils/8c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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);
+ 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:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ bit = mkvar(r, &p->from);
+ if(bany(&bit))
+ switch(p->as) {
+ /*
+ * funny
+ */
+ case ALEAL:
+ 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 ACMPW:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVL:
+ case AMOVB:
+ case AMOVW:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side read+write
+ */
+ case AADDB:
+ case AADDL:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORW:
+ case ASALB:
+ case ASALL:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARW:
+ case AROLB:
+ case AROLL:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRW:
+ case AIMULL:
+ case AIMULW:
+ case ANEGL:
+ case ANOTL:
+ case AADCL:
+ case ASBBL:
+ for(z=0; z<BITS; z++) {
+ r->set.b[z] |= bit.b[z];
+ r->use2.b[z] |= bit.b[z];
+ }
+ break;
+
+ /*
+ * funny
+ */
+ case AFMOVDP:
+ case AFMOVFP:
+ case AFMOVVP:
+ case ACALL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+
+ switch(p->as) {
+ case AIMULL:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVW:
+ case AIMULB:
+ case ADIVB:
+ case ADIVL:
+ case ADIVW:
+ case AMULB:
+ case AMULL:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ 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 AMOVSW:
+ case ACMPSB:
+ case ACMPSL:
+ case ACMPSW:
+ r->regu |= RtoB(D_SI) | RtoB(D_DI);
+ break;
+
+ case ASTOSB:
+ case ASTOSL:
+ case ASTOSW:
+ case ASCASB:
+ case ASCASL:
+ 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;
+
+ case AFSTSW:
+ case ASAHF:
+ r->regu |= RtoB(D_AX);
+ 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;
+
+ 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_DI)
+ b |= RtoB(r);
+ else
+ if(r >= D_AL && r <= D_BL)
+ b |= RtoB(r-D_AL+D_AX);
+ else
+ if(r >= D_AH && r <= D_BH)
+ b |= RtoB(r-D_AH+D_AX);
+ 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]) /* 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 TIND:
+ case TARRAY:
+ i = BtoR(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TDOUBLE:
+ case TFLOAT:
+ 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(p->as == AFMOVL)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ 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(p->as == AFMOVL)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ 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(p->as == AFMOVL)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ 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 = BtoR(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 = BtoR(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_DI)
+ return 0;
+ return 1L << (r-D_AX);
+}
+
+int
+BtoR(long b)
+{
+
+ b &= 0xffL;
+ if(b == 0)
+ return 0;
+ return bitno(b) + D_AX;
+}
--- /dev/null
+// Inferno utils/8c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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));
+
+ /*
+ * isolate first argument
+ */
+ if(REGARG) {
+ if(typesuv[thisfn->link->etype]) {
+ nod1 = *nodret->left;
+ nodreg(&nod, &nod1, REGARG);
+ gmove(&nod, &nod1);
+ } else
+ if(firstarg && typechlp[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);
+ }
+ }
+
+ sp = p;
+ retok = 0;
+ gen(n);
+ if(!retok)
+ if(thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", n1->sym->name);
+ noretval(3);
+ if(thisfn && thisfn->link && typefd[thisfn->link->etype])
+ gins(AFLDZ, Z, Z);
+ gbranch(ORETURN);
+
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+ sp->to.offset += maxargsafe;
+}
+
+void
+supgen(Node *n)
+{
+ long spc;
+ Prog *sp;
+
+ if(n == Z)
+ return;
+ suppress++;
+ spc = pc;
+ sp = lastp;
+ gen(n);
+ lastp = sp;
+ pc = spc;
+ sp->link = nil;
+ suppress--;
+}
+
+void
+gen(Node *n)
+{
+ Node *l, nod;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int f, o;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+
+ retok = 0;
+ switch(o) {
+
+ default:
+ complex(n);
+ cgen(n, Z);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ retok = 1;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ if(typefd[n->type->etype])
+ gins(AFLDZ, Z, Z);
+ gbranch(ORETURN);
+ break;
+ }
+ if(typesuv[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:
+ l = n->left;
+ if(l) {
+ l->xoffset = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ retok = 1;
+ 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->xoffset) {
+ patch(p, n->xoffset);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ 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;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typechl[l->type->etype]) {
+ cas();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ 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(!typechl[l->type->etype]) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ cas();
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right);
+ gbranch(OGOTO);
+ patch(p, breakpc);
+
+ patch(sp, pc);
+ regalloc(&nod, l, Z);
+ nod.type = types[TLONG];
+ cgen(l, &nod);
+ doswit(&nod);
+ regfree(&nod);
+ patch(spb, pc);
+
+ cases = cn;
+ breakpc = sbc;
+ 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;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l, Z); /* test */
+ patch(p, breakpc);
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OFOR:
+ l = n->left;
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ 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);
+ }
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ 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) {
+ supgen(n->right->left);
+ gen(n->right->right);
+ }
+ else {
+ gen(n->right->left);
+ supgen(n->right->right);
+ }
+ }
+ else {
+ sp = p;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ }
+ 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;
+ }
+}
+
+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(!typechlp[n->type->etype])
+ return;
+ simplifyshift(n);
+ if(n->op == OASHL && n->right->op == OCONST){
+ g = vconst(n->right);
+ if(g >= 0 && g < 4)
+ 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++;
+
+ if(com64(n))
+ return;
+
+ switch(n->op) {
+
+ case OFUNC:
+ n->complex = FNX;
+ 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");
+ }
+}
+
+int
+bcomplex(Node *n, Node *c)
+{
+ Node *b, nod;
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type != T) {
+ if(c != Z && n->op == OCONST && deadheads(c))
+ return 1;
+ if(typev[n->type->etype] && machcap(Z)) {
+ b = &nod;
+ b->op = ONE;
+ b->left = n;
+ b->right = new(0, Z, Z);
+ *b->right = *nodconst(0);
+ b->right->type = n->type;
+ b->type = types[TLONG];
+ cgen64(b, Z);
+ return 0;
+ }
+ bool64(n);
+ boolgen(n, 1, Z);
+ } else
+ gbranch(OGOTO);
+ return 0;
+}
--- /dev/null
+// Inferno utils/8c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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;
+
+ def = 0;
+ nc = 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;
+ }
+ nc++;
+ }
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ q->val = c->val;
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(debug['W'])
+ for(i=0; i<nc; i++)
+ print("case %2ld: = %.8lux\n", i, iq[i].val);
+ if(def == 0)
+ def = breakpc;
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val)
+ diag(n, "duplicate cases in switch %ld", iq[i].val);
+ swit1(iq, nc, def, n);
+}
+
+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 = %.8lux\n", q->val);
+ gopcode(OEQ, n->type, n, nodconst(q->val));
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+ i = nc / 2;
+ r = q+i;
+ if(debug['W'])
+ print("case > %.8lux\n", r->val);
+ gopcode(OGT, n->type, n, nodconst(r->val));
+ sp = p;
+ gbranch(OGOTO);
+ p->as = AJEQ;
+ patch(p, r->label);
+ swit1(q, i, def, n);
+
+ if(debug['W'])
+ print("case < %.8lux\n", r->val);
+ patch(sp, pc);
+ swit1(r+1, nc-i-1, def, n);
+}
+
+void
+cas(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+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, types[TLONG], nodconst(v), n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, types[TLONG], nodconst(sh), n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, types[TLONG], nodconst(sh), n1);
+ else
+ gopcode(OASHR, types[TLONG], 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;
+}
+
+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
+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(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);
+ Bseek(&b, 0L, 2);
+ 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;
+ 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_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);
+}
+
+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_LONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_LONG)
+ w = SZ_LONG;
+ 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(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ w = 1; /* little endian no adjustment */
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael1);
+ o = align(o, t, Ael2);
+ break;
+ }
+ o = round(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_LONG-1;
+ if(v > max)
+ max = round(v, SZ_LONG);
+ return max;
+}
--- /dev/null
+// Inferno utils/8c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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 = '8';
+ thestring = "386";
+ exregoffset = 0;
+ exfregoffset = 0;
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.from.type = D_NONE;
+ zprog.from.index = D_NONE;
+ zprog.from.scale = 0;
+ zprog.to = zprog.from;
+
+ regnode.op = OREGISTER;
+ regnode.class = CEXREG;
+ regnode.reg = REGTMP;
+ regnode.complex = 0;
+ regnode.addable = 11;
+ regnode.type = types[TLONG];
+
+ fregnode0 = regnode;
+ fregnode0.reg = D_F0;
+ fregnode0.type = types[TDOUBLE];
+
+ fregnode1 = fregnode0;
+ fregnode1.reg = D_F0+1;
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ 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);
+
+ com64init();
+
+ for(i=0; i<nelem(reg); i++) {
+ reg[i] = 1;
+ if(i >= D_AX && i <= D_DI && i != D_SP)
+ reg[i] = 0;
+ }
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ reg[D_SP]--;
+ for(i=D_AX; i<=D_DI; 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_DI; 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] || typev[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 && typeilp[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*
+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)
+{
+
+ *n = regnode;
+ n->reg = r;
+ if(reg[r] == 0)
+ return 0;
+ if(nn != Z) {
+ n->type = nn->type;
+ n->lineno = nn->lineno;
+ 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 TIND:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= D_AX && i <= D_DI)
+ goto out;
+ }
+ for(i=D_AX; i<=D_DI; i++)
+ if(reg[i] == 0)
+ goto out;
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ case TVLONG:
+ i = D_F0;
+ 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)
+{
+ 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_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;
+ 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_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;
+ 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;
+ a->offset = n->vconst;
+ 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;
+
+ }
+}
+
+#define CASE(a,b) ((a<<8)|(b<<0))
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, a;
+ Node nod, nod1;
+ Prog *p1;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+ 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) {
+ if(f->fconst == 0)
+ gins(AFLDZ, Z, Z);
+ else
+ if(f->fconst == 1)
+ gins(AFLD1, Z, Z);
+ else
+ gins(AFMOVD, f, &fregnode0);
+ gmove(&fregnode0, t);
+ return;
+ }
+/*
+ * load
+ */
+ if(f->op == ONAME || f->op == OINDREG ||
+ f->op == OIND || f->op == OINDEX)
+ switch(ft) {
+ case TCHAR:
+ a = AMOVBLSX;
+ goto ld;
+ case TUCHAR:
+ a = AMOVBLZX;
+ goto ld;
+ case TSHORT:
+ if(typefd[tt]) {
+ gins(AFMOVW, f, &fregnode0);
+ gmove(&fregnode0, t);
+ return;
+ }
+ a = AMOVWLSX;
+ goto ld;
+ case TUSHORT:
+ a = AMOVWLZX;
+ goto ld;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ if(typefd[tt]) {
+ gins(AFMOVL, f, &fregnode0);
+ gmove(&fregnode0, t);
+ return;
+ }
+ a = AMOVL;
+
+ ld:
+ regalloc(&nod, f, t);
+ nod.type = types[TLONG];
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ gins(AFMOVF, f, t);
+ return;
+ case TDOUBLE:
+ gins(AFMOVD, f, t);
+ return;
+ case TVLONG:
+ gins(AFMOVV, f, t);
+ 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:
+ case TIND:
+ a = AMOVL; goto st;
+
+ st:
+ if(f->op == OCONST) {
+ gins(a, f, t);
+ return;
+ }
+ regalloc(&nod, t, f);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ gins(AFMOVFP, f, t);
+ return;
+ case TDOUBLE:
+ gins(AFMOVDP, f, t);
+ return;
+ case TVLONG:
+ gins(AFMOVVP, f, t);
+ return;
+ }
+
+/*
+ * 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( TINT, TLONG):
+ case CASE( TUINT, TLONG):
+ case CASE( TLONG, TLONG):
+ case CASE( TULONG, TLONG):
+ case CASE( TIND, TLONG):
+
+ case CASE( TINT, TULONG):
+ case CASE( TUINT, TULONG):
+ case CASE( TLONG, TULONG):
+ case CASE( TULONG, TULONG):
+ case CASE( TIND, TULONG):
+
+ case CASE( TINT, TIND):
+ case CASE( TUINT, TIND):
+ case CASE( TLONG, TIND):
+ case CASE( TULONG, TIND):
+ case CASE( TIND, TIND):
+ *****/
+ a = AMOVL;
+ break;
+
+ case CASE( TSHORT, TINT):
+ case CASE( TSHORT, TUINT):
+ case CASE( TSHORT, TLONG):
+ case CASE( TSHORT, TULONG):
+ case CASE( TSHORT, TIND):
+ a = AMOVWLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ if(f->vconst & 0x8000)
+ f->vconst |= 0xffff0000;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUSHORT,TINT):
+ case CASE( TUSHORT,TUINT):
+ case CASE( TUSHORT,TLONG):
+ case CASE( TUSHORT,TULONG):
+ case CASE( TUSHORT,TIND):
+ a = AMOVWLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ a = AMOVL;
+ }
+ 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):
+ case CASE( TCHAR, TIND):
+ a = AMOVBLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ if(f->vconst & 0x80)
+ f->vconst |= 0xffffff00;
+ a = AMOVL;
+ }
+ 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):
+ case CASE( TUCHAR, TIND):
+ a = AMOVBLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ a = AMOVL;
+ }
+ 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, 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,TIND):
+
+ case CASE( TVLONG, TCHAR):
+ case CASE( TVLONG, TUCHAR):
+ case CASE( TVLONG, TSHORT):
+ case CASE( TVLONG, TUSHORT):
+ case CASE( TVLONG, TINT):
+ case CASE( TVLONG, TUINT):
+ case CASE( TVLONG, TLONG):
+ case CASE( TVLONG, TULONG):
+ case CASE( TVLONG, TIND):
+ if(fproundflg) {
+ regsalloc(&nod, ®node);
+ gins(AFMOVLP, f, &nod);
+ gmove(&nod, t);
+ return;
+ }
+ regsalloc(&nod, ®node);
+ regsalloc(&nod1, ®node);
+ gins(AFSTCW, Z, &nod1);
+ nod1.xoffset += 2;
+ gins(AMOVW, nodconst(0xf7f), &nod1);
+ gins(AFLDCW, &nod1, Z);
+ gins(AFMOVLP, f, &nod);
+ nod1.xoffset -= 2;
+ gins(AFLDCW, &nod1, Z);
+ gmove(&nod, t);
+ return;
+
+/*
+ * ulong to float
+ */
+ case CASE( TULONG, TDOUBLE):
+ case CASE( TULONG, TVLONG):
+ case CASE( TULONG, TFLOAT):
+ case CASE( TUINT, TDOUBLE):
+ case CASE( TUINT, TVLONG):
+ case CASE( TUINT, TFLOAT):
+ regalloc(&nod, f, f);
+ gmove(f, &nod);
+ regsalloc(&nod1, ®node);
+ gmove(&nod, &nod1);
+ gins(AFMOVL, &nod1, &fregnode0);
+ gins(ACMPL, &nod, nodconst(0));
+ gins(AJGE, Z, Z);
+ p1 = p;
+ gins(AFADDD, nodfconst(4294967296.), &fregnode0);
+ patch(p1, pc);
+ regfree(&nod);
+ 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( 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( TIND, TDOUBLE):
+
+ case CASE( TCHAR, TVLONG):
+ case CASE( TUCHAR, TVLONG):
+ case CASE( TSHORT, TVLONG):
+ case CASE( TUSHORT,TVLONG):
+ case CASE( TINT, TVLONG):
+ case CASE( TLONG, TVLONG):
+ case CASE( TIND, TVLONG):
+ regsalloc(&nod, ®node);
+ gmove(f, &nod);
+ gins(AFMOVL, &nod, &fregnode0);
+ return;
+
+/*
+ * float to float
+ */
+ case CASE( TFLOAT, TFLOAT):
+ case CASE( TDOUBLE,TFLOAT):
+ case CASE( TVLONG, TFLOAT):
+
+ case CASE( TFLOAT, TDOUBLE):
+ case CASE( TDOUBLE,TDOUBLE):
+ case CASE( TVLONG, TDOUBLE):
+
+ case CASE( TFLOAT, TVLONG):
+ case CASE( TDOUBLE,TVLONG):
+ case CASE( TVLONG, TVLONG):
+ a = AFMOVD; break;
+ }
+ if(a == AMOVL || a == AFMOVD)
+ 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, ®node, 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, ®node, 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
+fgopcode(int o, Node *f, Node *t, int pop, int rev)
+{
+ int a, et;
+ Node nod;
+
+ et = TLONG;
+ if(f != Z && f->type != T)
+ et = f->type->etype;
+ if(!typefd[et]) {
+ diag(f, "fop: integer %O", o);
+ return;
+ }
+ if(debug['M']) {
+ if(t != Z && t->type != T)
+ print("gop: %O %O-%s Z\n", o, f->op, tnames[et]);
+ else
+ print("gop: %O %O-%s %O-%s\n", o,
+ f->op, tnames[et], t->op, tnames[t->type->etype]);
+ }
+ a = AGOK;
+ switch(o) {
+
+ case OASADD:
+ case OADD:
+ if(et == TFLOAT)
+ a = AFADDF;
+ else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFADDD;
+ if(pop)
+ a = AFADDDP;
+ }
+ break;
+
+ case OASSUB:
+ case OSUB:
+ if(et == TFLOAT) {
+ a = AFSUBF;
+ if(rev)
+ a = AFSUBRF;
+ } else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFSUBD;
+ if(pop)
+ a = AFSUBDP;
+ if(rev) {
+ a = AFSUBRD;
+ if(pop)
+ a = AFSUBRDP;
+ }
+ }
+ break;
+
+ case OASMUL:
+ case OMUL:
+ if(et == TFLOAT)
+ a = AFMULF;
+ else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFMULD;
+ if(pop)
+ a = AFMULDP;
+ }
+ break;
+
+ case OASMOD:
+ case OMOD:
+ case OASDIV:
+ case ODIV:
+ if(et == TFLOAT) {
+ a = AFDIVF;
+ if(rev)
+ a = AFDIVRF;
+ } else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFDIVD;
+ if(pop)
+ a = AFDIVDP;
+ if(rev) {
+ a = AFDIVRD;
+ if(pop)
+ a = AFDIVRDP;
+ }
+ }
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ pop += rev;
+ if(et == TFLOAT) {
+ a = AFCOMF;
+ if(pop) {
+ a = AFCOMFP;
+ if(pop > 1)
+ a = AGOK;
+ }
+ } else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFCOMF;
+ if(pop) {
+ a = AFCOMDP;
+ if(pop > 1)
+ a = AFCOMDPP;
+ }
+ }
+ gins(a, f, t);
+ regalloc(&nod, ®node, Z);
+ if(nod.reg != D_AX) {
+ regfree(&nod);
+ nod.reg = D_AX;
+ gins(APUSHL, &nod, Z);
+ gins(AWAIT, Z, Z);
+ gins(AFSTSW, Z, &nod);
+ gins(ASAHF, Z, Z);
+ gins(APOPL, Z, &nod);
+ } else {
+ gins(AWAIT, Z, Z);
+ gins(AFSTSW, Z, &nod);
+ gins(ASAHF, Z, Z);
+ regfree(&nod);
+ }
+ switch(o) {
+ case OEQ: a = AJEQ; break;
+ case ONE: a = AJNE; break;
+ case OLT: a = AJCS; break;
+ case OLE: a = AJLS; break;
+ case OGE: a = AJCC; break;
+ case OGT: a = AJHI; break;
+ }
+ gins(a, Z, Z);
+ return;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ gins(a, f, t);
+}
+
+void
+gopcode(int o, Type *ty, Node *f, Node *t)
+{
+ int a, et;
+
+ et = TLONG;
+ if(ty != T)
+ et = ty->etype;
+ if(typefd[et] && o != OADDR && o != OFUNC) {
+ diag(f, "gop: float %O", o);
+ return;
+ }
+ 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;
+ break;
+
+ case ONEG:
+ a = ANEGL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ANEGB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ANEGW;
+ break;
+
+ case OADDR:
+ a = ALEAL;
+ break;
+
+ case OASADD:
+ case OADD:
+ a = AADDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AADDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AADDW;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a = ASUBL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASUBB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASUBW;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AORW;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AANDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AANDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AANDW;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AXORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AXORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AXORW;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASHRL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASHRB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASHRW;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASARL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASARB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASARW;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASALL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASALB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASALW;
+ 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;
+ break;
+
+ case OASMOD:
+ case OMOD:
+ case OASDIV:
+ case ODIV:
+ a = AIDIVL;
+ break;
+
+ case OASLMUL:
+ case OLMUL:
+ a = AMULL;
+ break;
+
+ case OASLMOD:
+ case OLMOD:
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVL;
+ 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;
+ 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)
+{
+
+ if(f->op != t->op)
+ return 0;
+ switch(f->op) {
+
+ case OREGISTER:
+ if(f->reg != t->reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+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)
+{
+
+ USED(t);
+ 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|BIND, /*[TINT]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TUINT]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TLONG]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TULONG]*/
+ BVLONG|BUVLONG, /*[TVLONG]*/
+ BVLONG|BUVLONG, /*[TUVLONG]*/
+ BFLOAT, /*[TFLOAT]*/
+ BDOUBLE, /*[TDOUBLE]*/
+ BLONG|BULONG|BIND, /*[TIND]*/
+ 0, /*[TFUNC]*/
+ 0, /*[TARRAY]*/
+ 0, /*[TVOID]*/
+ BSTRUCT, /*[TSTRUCT]*/
+ BUNION, /*[TUNION]*/
+ 0, /*[TENUM]*/
+};
--- /dev/null
+// Inferno utils/8l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/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
+
+long
+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
+wput(ushort w)
+{
+ cput(w);
+ cput(w>>8);
+}
+
+void
+wputb(ushort w)
+{
+ cput(w>>8);
+ cput(w);
+}
+
+void
+asmb(void)
+{
+ Prog *p;
+ long v, magic;
+ int a;
+ uchar *op1;
+
+ 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 %lux sb %lux in %s", p->pc, pc, TNAME);
+ pc = p->pc;
+ }
+ curp = p;
+ asmins(p);
+ if(cbc < sizeof(and))
+ cflush();
+ a = (andptr - and);
+ if(debug['a']) {
+ Bprint(&bso, pcstr, pc);
+ for(op1 = and; op1 < andptr; op1++)
+ Bprint(&bso, "%.2ux", *op1 & 0xff);
+ Bprint(&bso, "\t%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 %d", HEADTYPE);
+ case 0:
+ seek(cout, rnd(HEADR+textsize, 8192), 0);
+ break;
+ case 1:
+ textsize = rnd(HEADR+textsize, 4096)-HEADR;
+ seek(cout, textsize+HEADR, 0);
+ break;
+ case 2:
+ seek(cout, HEADR+textsize, 0);
+ break;
+ case 3:
+ case 4:
+ seek(cout, HEADR+rnd(textsize, INITRND), 0);
+ 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 0:
+ seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0);
+ break;
+ case 1:
+ seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0);
+ break;
+ case 2:
+ seek(cout, HEADR+textsize+datsize, 0);
+ break;
+ case 3:
+ case 4:
+ 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 0: /* garbage */
+ lput(0x160L<<16); /* magic and sections */
+ lput(0L); /* time and date */
+ lput(rnd(HEADR+textsize, 4096)+datsize);
+ lput(symsize); /* nsyms */
+ lput((0x38L<<16)|7L); /* size of optional hdr and flags */
+ lput((0413<<16)|0437L); /* magic and version */
+ lput(rnd(HEADR+textsize, 4096)); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(entryvalue()); /* va of entry */
+ lput(INITTEXT-HEADR); /* va of base of text */
+ lput(INITDAT); /* va of base of data */
+ lput(INITDAT+datsize); /* va of base of bss */
+ lput(~0L); /* gp reg mask */
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(~0L); /* gp value ?? */
+ break;
+ lputl(0); /* x */
+ case 1: /* unix coff */
+ /*
+ * file header
+ */
+ lputl(0x0004014c); /* 4 sections, magic */
+ lputl(0); /* unix time stamp */
+ lputl(0); /* symbol table */
+ lputl(0); /* nsyms */
+ lputl(0x0003001c); /* flags, sizeof a.out header */
+ /*
+ * a.out header
+ */
+ lputl(0x10b); /* magic, version stamp */
+ lputl(rnd(textsize, INITRND)); /* text sizes */
+ lputl(datsize); /* data sizes */
+ lputl(bsssize); /* bss sizes */
+ lput(entryvalue()); /* va of entry */
+ lputl(INITTEXT); /* text start */
+ lputl(INITDAT); /* data start */
+ /*
+ * text section header
+ */
+ s8put(".text");
+ lputl(HEADR); /* pa */
+ lputl(HEADR); /* va */
+ lputl(textsize); /* text size */
+ lputl(HEADR); /* file offset */
+ lputl(0); /* relocation */
+ lputl(0); /* line numbers */
+ lputl(0); /* relocation, line numbers */
+ lputl(0x20); /* flags text only */
+ /*
+ * data section header
+ */
+ s8put(".data");
+ lputl(INITDAT); /* pa */
+ lputl(INITDAT); /* va */
+ lputl(datsize); /* data size */
+ lputl(HEADR+textsize); /* file offset */
+ lputl(0); /* relocation */
+ lputl(0); /* line numbers */
+ lputl(0); /* relocation, line numbers */
+ lputl(0x40); /* flags data only */
+ /*
+ * bss section header
+ */
+ s8put(".bss");
+ lputl(INITDAT+datsize); /* pa */
+ lputl(INITDAT+datsize); /* va */
+ lputl(bsssize); /* bss size */
+ lputl(0); /* file offset */
+ lputl(0); /* relocation */
+ lputl(0); /* line numbers */
+ lputl(0); /* relocation, line numbers */
+ lputl(0x80); /* flags bss only */
+ /*
+ * comment section header
+ */
+ s8put(".comment");
+ lputl(0); /* pa */
+ lputl(0); /* va */
+ lputl(symsize+lcsize); /* comment size */
+ lputl(HEADR+textsize+datsize); /* file offset */
+ lputl(HEADR+textsize+datsize); /* offset of syms */
+ lputl(HEADR+textsize+datsize+symsize);/* offset of line numbers */
+ lputl(0); /* relocation, line numbers */
+ lputl(0x200); /* flags comment only */
+ break;
+ case 2: /* plan9 */
+ magic = 4*11*11+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 3:
+ /* MS-DOS .COM */
+ break;
+ case 4:
+ /* fake MS-DOS .EXE */
+ v = rnd(HEADR+textsize, INITRND)+datsize;
+ wput(0x5A4D); /* 'MZ' */
+ wput(v % 512); /* bytes in last page */
+ wput(rnd(v, 512)/512); /* total number of pages */
+ wput(0x0000); /* number of reloc items */
+ v = rnd(HEADR-(INITTEXT & 0xFFFF), 16);
+ wput(v/16); /* size of header */
+ wput(0x0000); /* minimum allocation */
+ wput(0xFFFF); /* maximum allocation */
+ wput(0x0000); /* initial ss value */
+ wput(0x0100); /* initial sp value */
+ wput(0x0000); /* complemented checksum */
+ v = entryvalue();
+ wput(v); /* initial ip value (!) */
+ wput(0x0000); /* initial cs value */
+ wput(0x0000);
+ wput(0x0000);
+ wput(0x003E); /* reloc table offset */
+ wput(0x0000); /* overlay number */
+ break;
+ }
+ cflush();
+}
+
+void
+lput(long l)
+{
+ cput(l>>24);
+ cput(l>>16);
+ cput(l>>8);
+ cput(l);
+}
+
+void
+lputl(long l)
+{
+ cput(l);
+ cput(l>>8);
+ cput(l>>16);
+ cput(l>>24);
+}
+
+void
+s8put(char *n)
+{
+ char name[8];
+ int i;
+
+ strncpy(name, n, sizeof(name));
+ for(i=0; i<sizeof(name); i++)
+ cput(name[i]);
+}
+
+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
+datblk(long s, long n)
+{
+ Prog *p;
+ char *cast;
+ long l, fl, j;
+ 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 = (char*)&fl;
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, pcstr, l+s+INITDAT);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[fnuxi4[j]] & 0xff);
+ Bprint(&bso, "\t%P\n", curp);
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi4[i]];
+ l++;
+ }
+ break;
+ case 8:
+ cast = (char*)&p->to.ieee;
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, pcstr, l+s+INITDAT);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff);
+ Bprint(&bso, "\t%P\n", curp);
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, pcstr, l+s+INITDAT);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff);
+ Bprint(&bso, "\t%P\n", curp);
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = p->to.scon[i];
+ l++;
+ }
+ break;
+ default:
+ fl = 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, fl);
+ fl += p->to.sym->value;
+ if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
+ fl += INITDAT;
+ if(dlm)
+ dynreloc(p->to.sym, l+s+INITDAT, 1);
+ }
+ }
+ cast = (char*)&fl;
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P", c, i, curp);
+ break;
+ case 1:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, pcstr, l+s+INITDAT);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[inuxi1[j]] & 0xff);
+ Bprint(&bso, "\t%P\n", curp);
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi1[i]];
+ l++;
+ }
+ break;
+ case 2:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, pcstr, l+s+INITDAT);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[inuxi2[j]] & 0xff);
+ Bprint(&bso, "\t%P\n", curp);
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi2[i]];
+ l++;
+ }
+ break;
+ case 4:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, pcstr, l+s+INITDAT);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[inuxi4[j]] & 0xff);
+ Bprint(&bso, "\t%P\n", curp);
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi4[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ write(cout, buf.dbuf, n);
+}
+
+long
+rnd(long v, long r)
+{
+ long c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
--- /dev/null
+// Inferno utils/8l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/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 <lib9.h>
+#include <bio.h>
+#include "../8c/8.out.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;
+
+struct Adr
+{
+ union
+ {
+ long 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 */
+ long pc;
+ long line;
+ uchar mark; /* work on these */
+ uchar back;
+
+ short as;
+ char width; /* fake for DATA */
+};
+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;
+ long value;
+ long sig;
+ Sym* link;
+};
+struct Optab
+{
+ short as;
+ uchar* ytab;
+ uchar prefix;
+ uchar op[10];
+};
+
+enum
+{
+ STEXT = 1,
+ SDATA,
+ SBSS,
+ SDATA1,
+ SXREF,
+ SFILE,
+ SCONST,
+ SUNDEF,
+
+ SIMPORT,
+ SEXPORT,
+
+ NHASH = 10007,
+ NHUNK = 100000,
+ MINSIZ = 4,
+ STRINGSZ = 200,
+ MINLC = 1,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+
+ Yxxx = 0,
+ Ynone,
+ Yi0,
+ Yi1,
+ Yi8,
+ Yi32,
+ 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,
+ Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
+ Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7,
+ Ymax,
+
+ Zxxx = 0,
+
+ Zlit,
+ Z_rp,
+ Zbr,
+ Zcall,
+ Zib_,
+ Zib_rp,
+ Zibo_m,
+ Zil_,
+ Zil_rp,
+ Zilo_m,
+ Zjmp,
+ Zloop,
+ Zm_o,
+ Zm_r,
+ Zaut_r,
+ Zo_m,
+ Zpseudo,
+ Zr_m,
+ Zrp_,
+ Z_ib,
+ Z_il,
+ Zm_ibo,
+ Zm_ilo,
+ Zib_rr,
+ Zil_rr,
+ Zclr,
+ Zbyte,
+ Zmov,
+ Zmax,
+
+ Px = 0,
+ Pe = 0x66, /* operand escape */
+ Pm = 0x0f, /* 2byte opcode escape */
+ Pq = 0xff, /* both escape */
+ Pb = 0xfe, /* byte operands */
+
+ Roffset = 22, /* no. bits for offset in relocation address */
+ Rindex = 10, /* no. bits for index in relocation address */
+};
+
+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 long INITDAT;
+EXTERN long INITRND;
+EXTERN long INITTEXT;
+EXTERN char* INITENTRY; /* entry point */
+EXTERN Biobuf bso;
+EXTERN long bsssize;
+EXTERN long casepc;
+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 long datsize;
+EXTERN char debug[128];
+EXTERN char literal[32];
+EXTERN Prog* etextp;
+EXTERN Prog* firstp;
+EXTERN char fnuxi8[8];
+EXTERN char 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 char inuxi1[1];
+EXTERN char inuxi2[2];
+EXTERN char inuxi4[4];
+EXTERN char ycover[Ymax*Ymax];
+EXTERN uchar* andptr;
+EXTERN uchar and[30];
+EXTERN char reg[D_NONE];
+EXTERN Prog* lastp;
+EXTERN long lcsize;
+EXTERN int maxop;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN long nsymbol;
+EXTERN char* noname;
+EXTERN char* outfile;
+EXTERN long pc;
+EXTERN long spsize;
+EXTERN Sym* symlist;
+EXTERN long symsize;
+EXTERN Prog* textp;
+EXTERN long textsize;
+EXTERN long thunk;
+EXTERN int version;
+EXTERN Prog zprg;
+EXTERN int dtype;
+
+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 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);
+long atolwhex(char*);
+Prog* brchain(Prog*);
+Prog* brloop(Prog*);
+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);
+long 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*);
+long rnd(long, long);
+void s8put(char*);
+void span(void);
+void undef(void);
+void undefsym(Sym*);
+long vaddr(Adr*);
+void wputb(ushort);
+void xdefine(char*, int, long);
+void xfol(Prog*);
+int zaddr(uchar*, Adr*, Sym*[]);
+void zerosig(char*);
+
+#pragma varargck type "D" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "A" int
--- /dev/null
+// Inferno utils/8l/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/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"
+
+void
+listinit(void)
+{
+
+ fmtinstall('R', Rconv);
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('P', Pconv);
+}
+
+static Prog *bigP;
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ bigP = p;
+ switch(p->as) {
+ case ATEXT:
+ if(p->from.scale) {
+ sprint(str, "(%ld) %A %D,%d,%D",
+ p->line, p->as, &p->from, p->from.scale, &p->to);
+ break;
+ }
+ default:
+ sprint(str, "(%ld) %A %D,%D",
+ p->line, p->as, &p->from, &p->to);
+ break;
+ case ADATA:
+ case AINIT:
+ case ADYNT:
+ sprint(str, "(%ld) %A %D/%d,%D",
+ p->line, 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, "%ld(%R)", a->offset, i-D_INDIR);
+ else
+ sprint(str, "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ 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, "%lux+%s", bigP->pcond->pc,
+ a->sym->name);
+ else
+ sprint(str, "%lux", bigP->pcond->pc);
+ else
+ sprint(str, "%ld(PC)", a->offset);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<%d>+%ld(SB)", a->sym->name,
+ a->sym->version, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s+%ld(SP)", a->sym->name, a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym)
+ sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
+ else
+ sprint(str, "%ld(FP)", a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%ld", 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",
+ "AH",
+ "CH",
+ "DH",
+ "BH",
+
+ "AX", /* [D_AX] */
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+
+ "F0", /* [D_F0] */
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "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",
+
+ "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();
+ }
+}
--- /dev/null
+// Inferno utils/8l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/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 = '8';
+char *thestring = "386";
+
+/*
+ * -H0 -T0x40004C -D0x10000000 is garbage unix
+ * -H1 -T0xd0 -R4 is unix coff
+ * -H2 -T4128 -R4096 is plan9 format
+ * -H3 -Tx -Rx is MS-DOS .COM
+ * -H4 -Tx -Rx is fake MS-DOS .EXE
+ */
+
+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 = "8.out";
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+ 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: 8l [-options] objects");
+ errorexit();
+ }
+ if(!debug['9'] && !debug['U'] && !debug['B'])
+ debug[DEFAULT] = 1;
+ if(HEADTYPE == -1) {
+ if(debug['U'])
+ HEADTYPE = 1;
+ if(debug['B'])
+ HEADTYPE = 2;
+ if(debug['9'])
+ HEADTYPE = 2;
+ }
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option");
+ errorexit();
+
+ case 0: /* this is garbage */
+ HEADR = 20L+56L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x40004CL;
+ if(INITDAT == -1)
+ INITDAT = 0x10000000L;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 1: /* is unix coff */
+ HEADR = 0xd0L;
+ if(INITTEXT == -1)
+ INITTEXT = 0xd0;
+ if(INITDAT == -1)
+ INITDAT = 0x400000;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 2: /* plan 9 */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 4096+32;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case 3: /* MS-DOS .COM */
+ HEADR = 0;
+ if(INITTEXT == -1)
+ INITTEXT = 0x0100;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case 4: /* fake MS-DOS .EXE */
+ HEADR = 0x200;
+ if(INITTEXT == -1)
+ INITTEXT = 0x0100;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ HEADR += (INITTEXT & 0xFFFF);
+ if(debug['v'])
+ Bprint(&bso, "HEADR = 0x%ld\n", HEADR);
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ for(i=1; optab[i].as; i++)
+ if(i != optab[i].as) {
+ diag("phase error in optab: %d", i);
+ errorexit();
+ }
+ maxop = 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 + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 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[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[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;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_BH)
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_AX && i <= D_DI)
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
+ }
+
+ 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;
+
+ pcstr = "%.6lux ";
+ 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
+ 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 = INITDAT = 0;
+ INITRND = 8;
+ INITENTRY = EXPTAB;
+ }
+ export();
+ }
+ patch();
+ follow();
+ dodata();
+ dostkoff();
+ 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) {
+ a->offset = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+ 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;
+ }
+ }
+
+ while(nhunk < sizeof(Auto))
+ gethunk();
+ u = (Auto*)hunk;
+ nhunk -= sizeof(Auto);
+ hunk += sizeof(Auto);
+
+ 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)
+{
+ long ipc;
+ Prog *p, *t;
+ uchar *bloc, *bsize, *stop;
+ int v, o, r, skip;
+ 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);
+
+ bsize = buf.xbuf;
+ bloc = buf.xbuf;
+ di = S;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ version++;
+ histfrogp = 0;
+ ipc = pc;
+ skip = 0;
+
+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 .8 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;
+ }
+
+ while(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ p->as = o;
+ p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24);
+ p->back = 2;
+ 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 AFMOVF:
+ case AFADDF:
+ case AFSUBF:
+ case AFSUBRF:
+ case AFMULF:
+ case AFDIVF:
+ case AFDIVRF:
+ case AFCOMF:
+ case AFCOMFP:
+ 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:
+ 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;
+
+ while(nhunk < sizeof(Sym))
+ gethunk();
+ s = (Sym*)hunk;
+ nhunk -= sizeof(Sym);
+ hunk += sizeof(Sym);
+
+ 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;
+
+ while(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ *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;
+ return p;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(thunk >= 5L*NHUNK) {
+ nh = 5L*NHUNK;
+ if(thunk >= 25L*NHUNK)
+ nh = 25L*NHUNK;
+ }
+ h = mysbrk(nh);
+ if(h == (char*)-1) {
+ diag("out of memory");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
+
+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;
+ 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, "\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);
+}
--- /dev/null
+// Inferno utils/8l/optab.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/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 yincl[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ 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 ymovl[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1+2,
+// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yiauto, Yrl, Zaut_r, 2,
+ 0
+};
+uchar ym_rl[] =
+{
+ Ym, Yrl, Zm_r, 1,
+ 0
+};
+uchar yrl_m[] =
+{
+ Yrl, Ym, Zr_m, 1,
+ 0
+};
+uchar ymb_rl[] =
+{
+ Ymb, Yrl, Zm_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 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,
+ 0
+};
+uchar ybyte[] =
+{
+ Yi32, 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_m, 2,
+ Ynone, Ybr, Zcall, 1,
+ 0
+};
+uchar yjmp[] =
+{
+ Ynone, Yml, Zo_m, 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
+};
+
+Optab optab[] =
+/* as, ytab, andproto, opcode */
+{
+ { AXXX },
+ { AAAA, ynone, Px, 0x37 },
+ { AAAD, ynone, Px, 0xd5,0x0a },
+ { AAAM, ynone, Px, 0xd4,0x0a },
+ { AAAS, ynone, Px, 0x3f },
+ { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
+ { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADDB, yxorb, Px, 0x04,0x80,(00),0x00,0x02 },
+ { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { 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 },
+ { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AARPL, yrl_ml, Px, 0x63 },
+ { ABOUNDL, yrl_m, Px, 0x62 },
+ { ABOUNDW, yrl_m, Pe, 0x62 },
+ { ABSFL, yml_rl, Pm, 0xbc },
+ { ABSFW, yml_rl, Pq, 0xbc },
+ { ABSRL, yml_rl, Pm, 0xbd },
+ { ABSRW, yml_rl, Pq, 0xbd },
+ { ABTL, yml_rl, Pm, 0xa3 },
+ { ABTW, yml_rl, Pq, 0xa3 },
+ { ABTCL, yml_rl, Pm, 0xbb },
+ { ABTCW, yml_rl, Pq, 0xbb },
+ { ABTRL, yml_rl, Pm, 0xb3 },
+ { ABTRW, yml_rl, Pq, 0xb3 },
+ { ABTSL, yml_rl, Pm, 0xab },
+ { ABTSW, yml_rl, Pq, 0xab },
+ { ABYTE, ybyte, Px, 1 },
+ { ACALL, ycall, Px, 0xff,(02),0xe8 },
+ { ACLC, ynone, Px, 0xf8 },
+ { ACLD, ynone, Px, 0xfc },
+ { ACLI, ynone, Px, 0xfa },
+ { ACLTS, ynone, Pm, 0x06 },
+ { ACMC, ynone, Px, 0xf5 },
+ { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
+ { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPSB, ynone, Pb, 0xa6 },
+ { ACMPSL, ynone, Px, 0xa7 },
+ { ACMPSW, ynone, Pe, 0xa7 },
+ { ADAA, ynone, Px, 0x27 },
+ { ADAS, ynone, Px, 0x2f },
+ { ADATA },
+ { ADECB, yincb, Pb, 0xfe,(01) },
+ { ADECL, yincl, Px, 0x48,0xff,(01) },
+ { ADECW, yincl, Pe, 0x48,0xff,(01) },
+ { ADIVB, ydivb, Pb, 0xf6,(06) },
+ { ADIVL, ydivl, Px, 0xf7,(06) },
+ { ADIVW, ydivl, Pe, 0xf7,(06) },
+ { AENTER }, /* botch */
+ { AGLOBL },
+ { AGOK },
+ { AHISTORY },
+ { AHLT, ynone, Px, 0xf4 },
+ { AIDIVB, ydivb, Pb, 0xf6,(07) },
+ { AIDIVL, ydivl, Px, 0xf7,(07) },
+ { AIDIVW, ydivl, Pe, 0xf7,(07) },
+ { AIMULB, ydivb, Pb, 0xf6,(05) },
+ { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69 },
+ { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69 },
+ { AINB, yin, Pb, 0xe4,0xec },
+ { AINL, yin, Px, 0xe5,0xed },
+ { AINW, yin, Pe, 0xe5,0xed },
+ { AINCB, yincb, Pb, 0xfe,(00) },
+ { AINCL, yincl, Px, 0x40,0xff,(00) },
+ { AINCW, yincl, Pe, 0x40,0xff,(00) },
+ { AINSB, ynone, Pb, 0x6c },
+ { AINSL, ynone, Px, 0x6d },
+ { AINSW, ynone, Pe, 0x6d },
+ { AINT, yint, Px, 0xcd },
+ { AINTO, ynone, Px, 0xce },
+ { AIRETL, ynone, Px, 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 },
+ { ALEAL, ym_rl, Px, 0x8d },
+ { ALEAW, ym_rl, Pe, 0x8d },
+ { ALEAVEL, ynone, Px, 0xc9 },
+ { ALEAVEW, ynone, Pe, 0xc9 },
+ { ALOCK, ynone, Px, 0xf0 },
+ { ALODSB, ynone, Pb, 0xac },
+ { ALODSL, ynone, Px, 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 },
+ { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
+ { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) },
+ { AMOVW, ymovl, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) },
+ { AMOVBLSX, ymb_rl, Pm, 0xbe },
+ { AMOVBLZX, ymb_rl, Pm, 0xb6 },
+ { AMOVBWSX, ymb_rl, Pq, 0xbe },
+ { AMOVBWZX, ymb_rl, Pq, 0xb6 },
+ { AMOVWLSX, yml_rl, Pm, 0xbf },
+ { AMOVWLZX, yml_rl, Pm, 0xb7 },
+ { AMOVSB, ynone, Pb, 0xa4 },
+ { AMOVSL, ynone, Px, 0xa5 },
+ { AMOVSW, ynone, Pe, 0xa5 },
+ { AMULB, ydivb, Pb, 0xf6,(04) },
+ { AMULL, ydivl, Px, 0xf7,(04) },
+ { AMULW, ydivl, Pe, 0xf7,(04) },
+ { ANAME },
+ { ANEGB, yscond, Px, 0xf6,(03) },
+ { ANEGL, yscond, Px, 0xf7,(03) },
+ { ANEGW, yscond, Pe, 0xf7,(03) },
+ { ANOP, ynop, Px,0,0 },
+ { ANOTB, yscond, Px, 0xf6,(02) },
+ { ANOTL, yscond, Px, 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 },
+ { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AOUTB, yin, Pb, 0xe6,0xee },
+ { AOUTL, yin, Px, 0xe7,0xef },
+ { AOUTW, yin, Pe, 0xe7,0xef },
+ { AOUTSB, ynone, Pb, 0x6e },
+ { AOUTSL, ynone, Px, 0x6f },
+ { AOUTSW, ynone, Pe, 0x6f },
+ { APOPAL, ynone, Px, 0x61 },
+ { APOPAW, ynone, Pe, 0x61 },
+ { APOPFL, ynone, Px, 0x9d },
+ { APOPFW, ynone, Pe, 0x9d },
+ { APOPL, ypopl, Px, 0x58,0x8f,(00) },
+ { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
+ { APUSHAL, ynone, Px, 0x60 },
+ { APUSHAW, ynone, Pe, 0x60 },
+ { APUSHFL, ynone, Px, 0x9c },
+ { APUSHFW, ynone, Pe, 0x9c },
+ { APUSHL, ypushl, Px, 0x50,0xff,(06),0x6a,0x68 },
+ { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
+ { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
+ { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
+ { ARCRL, yshl, Px, 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 },
+ { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
+ { AROLL, yshl, Px, 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) },
+ { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ASAHF, ynone, Px, 0x9e },
+ { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASALL, yshl, Px, 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) },
+ { 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 },
+ { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASCASB, ynone, Pb, 0xae },
+ { ASCASL, ynone, Px, 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) },
+ { ACDQ, ynone, Px, 0x99 },
+ { ACWD, ynone, Pe, 0x99 },
+ { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASHLL, yshl, Px, 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) },
+ { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASTC, ynone, Px, 0xf9 },
+ { ASTD, ynone, Px, 0xfd },
+ { ASTI, ynone, Px, 0xfb },
+ { ASTOSB, ynone, Pb, 0xaa },
+ { ASTOSL, ynone, Px, 0xab },
+ { ASTOSW, ynone, Pe, 0xab },
+ { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
+ { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASYSCALL, ynone, Px, 0xcd,100 },
+ { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
+ { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATEXT, ytext, Px },
+ { 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 },
+ { 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 },
+ { 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 },
+ { AEND },
+ 0
+};
--- /dev/null
+// Inferno utils/8l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/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 (%ld): %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;
+ 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;
+ s->value = datsize;
+ datsize += t;
+ }
+
+ 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;
+ 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 APUSHL:
+ case APUSHFL:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ 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)
+ 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;
+
+ 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;
+ }
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + 4;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + 4;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ 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;
+ }
+}
+
+long
+atolwhex(char *s)
+{
+ long 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=%ld\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);
+}
--- /dev/null
+// Inferno utils/8l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/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"
+
+void
+span(void)
+{
+ Prog *p, *q;
+ long v, 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 = AADDL;
+ if(v < 0) {
+ p->as = ASUBL;
+ 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) {
+ 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 = %lux\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, long 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, long v, int ver)
+{
+ int i, f;
+
+ if(t == 'f')
+ s++;
+ 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 += 4 + 1 + i + 1;
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8lux ", 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 %.8lux %s<%d>\n", t, v, s, ver);
+ else
+ Bprint(&bso, "%c %.8lux %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+4, 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)
+{
+ long oldpc, oldlc;
+ Prog *p;
+ long 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, "%6lux %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, "%6lux %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, "%6lux %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, "%6lux %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)
+{
+ long v;
+
+ 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;
+ 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_CL:
+ case D_DL:
+ case D_BL:
+ case D_AH:
+ case D_CH:
+ case D_DH:
+ case D_BH:
+ return Yrb;
+
+ case D_CX:
+ return Ycx;
+
+ case D_DX:
+ case D_BX:
+ return Yrx;
+
+ 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_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_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;
+ }
+ return Yi32;
+
+ 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_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i = reg[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_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;
+}
+
+long
+vaddr(Adr *a)
+{
+ int t;
+ long 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:
+ v += s->value;
+ break;
+ default:
+ v += INITDAT + s->value;
+ }
+ }
+ }
+ return v;
+}
+
+void
+asmand(Adr *a, int r)
+{
+ long v;
+ int t;
+ Adr aa;
+
+ v = a->offset;
+ t = a->type;
+ if(a->index != D_NONE) {
+ if(t >= D_INDIR) {
+ t -= D_INDIR;
+ if(t == D_NONE) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, t);
+ put4(v);
+ return;
+ }
+ if(v == 0 && t != D_BP) {
+ *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;
+ asmand(&aa, r);
+ return;
+ }
+ if(t >= D_AL && t <= D_F0+7) {
+ if(v)
+ goto bad;
+ *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
+ return;
+ }
+ if(t >= D_INDIR) {
+ t -= D_INDIR;
+ if(t == D_NONE) {
+ *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ put4(v);
+ return;
+ }
+ if(t == D_SP) {
+ if(v == 0) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, D_SP);
+ return;
+ }
+ if(v >= -128 && v < 128) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, D_SP);
+ *andptr++ = v;
+ return;
+ }
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, D_SP);
+ put4(v);
+ return;
+ }
+ if(t >= D_AX && t <= D_DI) {
+ if(v == 0 && t != D_BP) {
+ *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);
+ asmand(&aa, r);
+ return;
+bad:
+ diag("asmand: bad address %D", a);
+ return;
+}
+
+#define E 0xff
+uchar 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,
+
+ 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,
+
+ 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, 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,
+
+/* 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,
+
+ AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0,
+ AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0,
+ AMOVL, 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,
+
+/* 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,
+
+/* extra imul */
+ AIMULL, Yml, Yrl, 7, Pm,0xaf,0,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);
+}
+
+void
+doasm(Prog *p)
+{
+ Optab *o;
+ Prog *q, pp;
+ uchar *t;
+ int z, op, ft, tt;
+ long v;
+
+ o = &optab[p->as];
+ ft = oclass(&p->from) * Ymax;
+ tt = oclass(&p->to) * Ymax;
+ t = o->ytab;
+ if(t == 0) {
+ diag("asmins: noproto %P", p);
+ return;
+ }
+ for(z=0; *t; z+=t[3],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 Pm: /* opcode escape */
+ *andptr++ = Pm;
+ break;
+
+ case Pe: /* 16 bit escape */
+ *andptr++ = Pe;
+ break;
+
+ case Pb: /* botch */
+ break;
+ }
+ v = vaddr(&p->from);
+ 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 Zm_r:
+ *andptr++ = op;
+ asmand(&p->from, reg[p->to.type]);
+ 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, reg[p->to.type]);
+ p->from.index = p->from.type;
+ p->from.type = D_ADDR;
+ break;
+
+ case Zm_o:
+ *andptr++ = op;
+ asmand(&p->from, o->op[z+1]);
+ break;
+
+ case Zr_m:
+ *andptr++ = op;
+ asmand(&p->to, reg[p->from.type]);
+ break;
+
+ case Zo_m:
+ *andptr++ = op;
+ asmand(&p->to, o->op[z+1]);
+ break;
+
+ case Zm_ibo:
+ v = vaddr(&p->to);
+ *andptr++ = op;
+ asmand(&p->from, o->op[z+1]);
+ *andptr++ = v;
+ break;
+
+ case Zibo_m:
+ *andptr++ = op;
+ asmand(&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:
+ *andptr++ = op + reg[p->to.type];
+ *andptr++ = v;
+ break;
+
+ case Zil_rp:
+ *andptr++ = op + reg[p->to.type];
+ if(o->prefix == Pe) {
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ put4(v);
+ break;
+
+ case Zib_rr:
+ *andptr++ = op;
+ asmand(&p->to, reg[p->to.type]);
+ *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;
+ asmand(&p->from, o->op[z+1]);
+ if(o->prefix == Pe) {
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ put4(v);
+ break;
+
+ case Zilo_m:
+ *andptr++ = op;
+ asmand(&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, reg[p->to.type]);
+ if(o->prefix == Pe) {
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ put4(v);
+ break;
+
+ case Z_rp:
+ *andptr++ = op + reg[p->to.type];
+ break;
+
+ case Zrp_:
+ *andptr++ = op + reg[p->from.type];
+ break;
+
+ case Zclr:
+ *andptr++ = op;
+ asmand(&p->to, reg[p->to.type]);
+ 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;
+ }
+ }
+ break;
+
+ case Zmov:
+ goto domov;
+ }
+ return;
+
+domov:
+ for(t=ymovtab; *t; t+=8)
+ if(p->as == t[0])
+ if(ycover[ft+t[1]])
+ if(ycover[tt+t[2]])
+ goto mfound;
+bad:
+ /*
+ * 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 */
+ asmand(&p->from, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(&pp);
+ *andptr++ = 0x87; /* xchg lhs,bx */
+ asmand(&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 */
+ asmand(&p->to, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(&pp);
+ *andptr++ = 0x87; /* xchg rhs,bx */
+ asmand(&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 t2=%lux from=%lux to=%lux %P", t[2], p->from.type, p->to.type, p);
+ return;
+
+mfound:
+ switch(t[3]) {
+ default:
+ diag("asmins: unknown mov %d %P", t[3], p);
+ break;
+
+ case 0: /* lit */
+ for(z=4; t[z]!=E; z++)
+ *andptr++ = t[z];
+ break;
+
+ case 1: /* r,m */
+ *andptr++ = t[4];
+ asmand(&p->to, t[5]);
+ break;
+
+ case 2: /* m,r */
+ *andptr++ = t[4];
+ asmand(&p->from, t[5]);
+ break;
+
+ case 3: /* r,m - 2op */
+ *andptr++ = t[4];
+ *andptr++ = t[5];
+ asmand(&p->to, t[6]);
+ break;
+
+ case 4: /* m,r - 2op */
+ *andptr++ = t[4];
+ *andptr++ = t[5];
+ asmand(&p->from, t[6]);
+ break;
+
+ case 5: /* load full pointer, trash heap */
+ if(t[4])
+ *andptr++ = t[4];
+ 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, reg[p->to.type]);
+ break;
+
+ case 6: /* double shift */
+ z = p->from.type;
+ switch(z) {
+ default:
+ goto bad;
+ case D_CONST:
+ *andptr++ = 0x0f;
+ *andptr++ = t[4];
+ asmand(&p->to, reg[p->from.index]);
+ *andptr++ = p->from.offset;
+ break;
+ case D_CL:
+ case D_CX:
+ *andptr++ = 0x0f;
+ *andptr++ = t[5];
+ asmand(&p->to, reg[p->from.index]);
+ break;
+ }
+ break;
+
+ case 7: /* imul rm,r */
+ *andptr++ = t[4];
+ *andptr++ = t[5];
+ asmand(&p->from, reg[p->to.type]);
+ break;
+ }
+}
+
+void
+asmins(Prog *p)
+{
+
+ andptr = and;
+ doasm(p);
+}
+
+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){
+ wputb(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);
+ }
+}