From 4f33c88a51587681b7be1ae57cfbc43b627c6bc4 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Mon, 30 Jul 2012 19:11:16 +0200 Subject: [PATCH] import updated compilers from sources --- sys/src/ape/cmd/basename.c | 1 + sys/src/ape/cmd/make/dosys.c | 2 +- sys/src/ape/cmd/make/gram.y | 1 + sys/src/ape/cmd/make/misc.c | 2 +- sys/src/ape/cmd/pdksh/c_sh.c | 2 +- sys/src/ape/cmd/sed/sed0.c | 1 + sys/src/ape/cmd/uname.c | 1 + sys/src/ape/lib/ap/math/j0.c | 2 +- sys/src/ape/lib/ap/math/j1.c | 2 +- sys/src/ape/lib/ap/plan9/_buf.c | 1 + sys/src/ape/lib/ap/plan9/signal.c | 1 + sys/src/ape/lib/ap/plan9/tcgetattr.c | 1 + sys/src/ape/lib/ap/posix/getgrent.c | 2 + sys/src/ape/lib/ap/stdio/strerror.c | 1 + sys/src/ape/lib/bsd/listen.c | 1 + sys/src/ape/lib/openssl/apps/openssl.c | 3 +- sys/src/ape/lib/openssl/apps/speed.c | 1 + sys/src/ape/lib/v/nap.c | 1 + sys/src/cmd/1c/gc.h | 4 +- sys/src/cmd/1c/swt.c | 2 +- sys/src/cmd/2c/gc.h | 4 +- sys/src/cmd/2c/swt.c | 2 +- sys/src/cmd/5a/a.h | 4 - sys/src/cmd/5a/lex.c | 11 +- sys/src/cmd/5a/mkfile | 2 +- sys/src/cmd/5c/5.out.h | 16 +- sys/src/cmd/5c/enam.c | 6 + sys/src/cmd/5c/gc.h | 6 +- sys/src/cmd/5c/mkfile | 3 + sys/src/cmd/5c/peep.c | 4 +- sys/src/cmd/5c/reg.c | 2 +- sys/src/cmd/5c/swt.c | 14 +- sys/src/cmd/5i/5i.c | 11 +- sys/src/cmd/5l/asm.c | 8 +- sys/src/cmd/5l/mkfile | 3 + sys/src/cmd/5l/obj.c | 53 +- sys/src/cmd/6a/a.h | 195 ++ sys/src/cmd/6a/a.y | 562 +++++ sys/src/cmd/6a/lex.c | 1289 ++++++++++++ sys/src/cmd/6a/mkfile | 26 + sys/src/cmd/6c/6.out.h | 820 ++++++++ sys/src/cmd/6c/cgen.c | 1942 ++++++++++++++++++ sys/src/cmd/6c/div.c | 206 ++ sys/src/cmd/6c/enam.c | 669 ++++++ sys/src/cmd/6c/gc.h | 381 ++++ sys/src/cmd/6c/list.c | 337 +++ sys/src/cmd/6c/machcap.c | 78 + sys/src/cmd/6c/mkenam | 15 + sys/src/cmd/6c/mkfile | 38 + sys/src/cmd/6c/mul.c | 428 ++++ sys/src/cmd/6c/peep.c | 846 ++++++++ sys/src/cmd/6c/reg.c | 1356 ++++++++++++ sys/src/cmd/6c/sgen.c | 435 ++++ sys/src/cmd/6c/swt.c | 530 +++++ sys/src/cmd/6c/sys.c | 106 + sys/src/cmd/6c/txt.c | 1515 ++++++++++++++ sys/src/cmd/6c/vlrt.c | 746 +++++++ sys/src/cmd/6l/asm.c | 461 +++++ sys/src/cmd/6l/compat.c | 55 + sys/src/cmd/6l/l.h | 390 ++++ sys/src/cmd/6l/list.c | 350 ++++ sys/src/cmd/6l/mkfile | 31 + sys/src/cmd/6l/obj.c | 1595 ++++++++++++++ sys/src/cmd/6l/optab.c | 1183 +++++++++++ sys/src/cmd/6l/pass.c | 790 +++++++ sys/src/cmd/6l/span.c | 1746 ++++++++++++++++ sys/src/cmd/7c/gc.h | 4 +- sys/src/cmd/7c/swt.c | 6 +- sys/src/cmd/8a/a.h | 1 + sys/src/cmd/8a/a.y | 63 +- sys/src/cmd/8a/l.s | 2 +- sys/src/cmd/8a/lex.c | 66 +- sys/src/cmd/8c/8.out.h | 60 + sys/src/cmd/8c/cgen.c | 15 +- sys/src/cmd/8c/cgen64.c | 84 - sys/src/cmd/8c/div.c | 2 +- sys/src/cmd/8c/enam.c | 47 + sys/src/cmd/8c/gc.h | 12 +- sys/src/cmd/8c/list.c | 45 +- sys/src/cmd/8c/machcap.c | 1 + sys/src/cmd/8c/mkfile | 2 - sys/src/cmd/8c/peep.c | 20 +- sys/src/cmd/8c/reg.c | 25 +- sys/src/cmd/8c/sgen.c | 4 + sys/src/cmd/8c/swt.c | 7 +- sys/src/cmd/8c/txt.c | 67 +- sys/src/cmd/8l/l.h | 17 +- sys/src/cmd/8l/list.c | 44 +- sys/src/cmd/8l/obj.c | 9 +- sys/src/cmd/8l/pass.c | 6 +- sys/src/cmd/8l/span.c | 34 +- sys/src/cmd/audio/mp3enc/main.c | 2 +- sys/src/cmd/bzfs/unbzip.c | 1 - sys/src/cmd/cc/acid.c | 2 + sys/src/cmd/cc/cc.h | 13 +- sys/src/cmd/cc/cc.y | 18 +- sys/src/cmd/cc/com.c | 119 +- sys/src/cmd/cc/com64.c | 2 +- sys/src/cmd/cc/dcl.c | 12 +- sys/src/cmd/cc/lex.c | 4 +- sys/src/cmd/cc/macbody | 4 +- sys/src/cmd/cc/pgen.c | 69 +- sys/src/cmd/cc/pswt.c | 62 +- sys/src/cmd/cc/sub.c | 2 + sys/src/cmd/disk/prep/fdisk.c | 1 - sys/src/cmd/grap/main.c | 1 + sys/src/cmd/kc/gc.h | 4 +- sys/src/cmd/ki/ki.c | 17 +- sys/src/cmd/lp/lpdaemon.c | 1 + sys/src/cmd/lp/lpdsend.c | 1 + sys/src/cmd/postscript/text2post/text2post.c | 1 + sys/src/cmd/postscript/tr2post/ps_include.c | 2 +- sys/src/cmd/postscript/tr2post/readDESC.c | 3 +- sys/src/cmd/postscript/tr2post/tr2post.c | 1 + sys/src/cmd/qc/gc.h | 4 +- sys/src/cmd/qc/txt.c | 3 + sys/src/cmd/qi/qi.c | 29 +- sys/src/cmd/vc/gc.h | 4 +- sys/src/cmd/vc/swt.c | 6 +- sys/src/cmd/vi/vi.c | 17 +- sys/src/libmach/5db.c | 73 +- sys/src/libmach/6.c | 8 +- sys/src/libmach/9.c | 34 +- sys/src/libmach/elf.h | 47 +- sys/src/libmach/executable.c | 174 +- sys/src/libmach/map.c | 8 +- sys/src/libmach/mkfile | 12 + sys/src/libmach/sym.c | 8 +- sys/src/mkfile.proto | 2 +- 129 files changed, 20341 insertions(+), 375 deletions(-) create mode 100644 sys/src/cmd/6a/a.h create mode 100644 sys/src/cmd/6a/a.y create mode 100644 sys/src/cmd/6a/lex.c create mode 100644 sys/src/cmd/6a/mkfile create mode 100644 sys/src/cmd/6c/6.out.h create mode 100644 sys/src/cmd/6c/cgen.c create mode 100644 sys/src/cmd/6c/div.c create mode 100644 sys/src/cmd/6c/enam.c create mode 100644 sys/src/cmd/6c/gc.h create mode 100644 sys/src/cmd/6c/list.c create mode 100644 sys/src/cmd/6c/machcap.c create mode 100644 sys/src/cmd/6c/mkenam create mode 100644 sys/src/cmd/6c/mkfile create mode 100644 sys/src/cmd/6c/mul.c create mode 100644 sys/src/cmd/6c/peep.c create mode 100644 sys/src/cmd/6c/reg.c create mode 100644 sys/src/cmd/6c/sgen.c create mode 100644 sys/src/cmd/6c/swt.c create mode 100644 sys/src/cmd/6c/sys.c create mode 100644 sys/src/cmd/6c/txt.c create mode 100644 sys/src/cmd/6c/vlrt.c create mode 100644 sys/src/cmd/6l/asm.c create mode 100644 sys/src/cmd/6l/compat.c create mode 100644 sys/src/cmd/6l/l.h create mode 100644 sys/src/cmd/6l/list.c create mode 100644 sys/src/cmd/6l/mkfile create mode 100644 sys/src/cmd/6l/obj.c create mode 100644 sys/src/cmd/6l/optab.c create mode 100644 sys/src/cmd/6l/pass.c create mode 100644 sys/src/cmd/6l/span.c diff --git a/sys/src/ape/cmd/basename.c b/sys/src/ape/cmd/basename.c index 429a9afb6..63e261ec6 100644 --- a/sys/src/ape/cmd/basename.c +++ b/sys/src/ape/cmd/basename.c @@ -2,6 +2,7 @@ #include #include +void main(int argc, char **argv) { char *f, *b, *s; diff --git a/sys/src/ape/cmd/make/dosys.c b/sys/src/ape/cmd/make/dosys.c index 7d28eaa4d..dfa417b84 100644 --- a/sys/src/ape/cmd/make/dosys.c +++ b/sys/src/ape/cmd/make/dosys.c @@ -164,7 +164,7 @@ for(i=0, procp=procstack; itype == D_REG) { if(v->reg <= REGEXT && v->reg > exregoffset) return 2; - if(v->reg == REGARG) + if(v->reg == (uchar)REGARG) return 2; } if(v->type == D_FREG) @@ -1087,7 +1087,7 @@ copyu(Prog *p, Adr *v, Adr *s) case ATEXT: /* funny */ if(v->type == D_REG) - if(v->reg == REGARG) + if(v->reg == (uchar)REGARG) return 3; return 0; } diff --git a/sys/src/cmd/5c/reg.c b/sys/src/cmd/5c/reg.c index 43c78712e..a27b7148a 100644 --- a/sys/src/cmd/5c/reg.c +++ b/sys/src/cmd/5c/reg.c @@ -1125,7 +1125,7 @@ RtoB(int r) int BtoR(long b) { - b &= 0x01fcL; + b &= 0x01fcL; // excluded R9 and R10 for m and g if(b == 0) return 0; return bitno(b); diff --git a/sys/src/cmd/5c/swt.c b/sys/src/cmd/5c/swt.c index ccc63ee79..185d97237 100644 --- a/sys/src/cmd/5c/swt.c +++ b/sys/src/cmd/5c/swt.c @@ -26,7 +26,7 @@ swit2(C1 *q, int nc, long def, Node *n, Node *tn) if(nc < 5) { for(i=0; ival); + print("case = %.8llux\n", q->val); gopcode(OEQ, nodconst(q->val), n, Z); patch(p, q->label); q++; @@ -39,7 +39,7 @@ swit2(C1 *q, int nc, long def, Node *n, Node *tn) i = nc / 2; r = q+i; if(debug['W']) - print("case > %.8lux\n", r->val); + print("case > %.8llux\n", r->val); gopcode(OGT, nodconst(r->val), n, Z); sp = p; gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */ @@ -47,7 +47,7 @@ swit2(C1 *q, int nc, long def, Node *n, Node *tn) swit2(q, i, def, n, tn); if(debug['W']) - print("case < %.8lux\n", r->val); + print("case < %.8llux\n", r->val); patch(sp, pc); swit2(r+1, nc-i-1, def, n, tn); return; @@ -60,7 +60,7 @@ direct: patch(p, def); for(i=0; ival); + print("case = %.8llux\n", q->val); while(q->val != v) { nextpc(); p->as = ABCASE; @@ -579,7 +579,7 @@ align(long i, Type *t, int op) w = packflg; break; - case Ael1: /* initial allign of struct element */ + case Ael1: /* initial align of struct element */ for(v=t; v->etype==TARRAY; v=v->link) ; w = ewidth[v->etype]; @@ -600,7 +600,7 @@ align(long i, Type *t, int op) } break; - case Aarg1: /* initial allign of parameter */ + case Aarg1: /* initial align of parameter */ w = ewidth[t->etype]; if(w <= 0 || w >= SZ_LONG) { w = SZ_LONG; @@ -614,7 +614,7 @@ align(long i, Type *t, int op) w = SZ_LONG; break; - case Aaut3: /* total allign of automatic */ + case Aaut3: /* total align of automatic */ o = align(o, t, Ael2); o = align(o, t, Ael1); w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */ diff --git a/sys/src/cmd/5i/5i.c b/sys/src/cmd/5i/5i.c index 554a9f2cc..73e51219d 100644 --- a/sys/src/cmd/5i/5i.c +++ b/sys/src/cmd/5i/5i.c @@ -147,6 +147,15 @@ initstk(int argc, char *argv[]) initmap(); tos = STACKTOP - sizeof(Tos)*2; /* we'll assume twice the host's is big enough */ sp = tos; + for (i = 0; i < sizeof(Tos)*2; i++) + putmem_b(tos + i, 0); + + /* + * pid is second word from end of tos and needs to be set for nsec(). + * we know arm is a 32-bit cpu, so we'll assume knowledge of the Tos + * struct for now, and use our pid. + */ + putmem_w(tos + 4*4 + 2*sizeof(ulong) + 3*sizeof(uvlong), getpid()); /* Build exec stack */ size = strlen(file)+1+BY2WD+BY2WD+BY2WD; @@ -157,7 +166,7 @@ initstk(int argc, char *argv[]) sp &= ~7; reg.r[0] = tos; reg.r[13] = sp; - reg.r[1] = STACKTOP-4; /* Plan 9 profiling clock */ + reg.r[1] = STACKTOP-4; /* Plan 9 profiling clock (why & why in R1?) */ /* Push argc */ putmem_w(sp, argc+1); diff --git a/sys/src/cmd/5l/asm.c b/sys/src/cmd/5l/asm.c index 5aa051a80..1316dd909 100644 --- a/sys/src/cmd/5l/asm.c +++ b/sys/src/cmd/5l/asm.c @@ -77,11 +77,6 @@ asmb(void) curtext = P; switch(HEADTYPE) { case 0: - if(debug['P']){ - OFFSET = rnd(textsize, INITRND); - seek(cout, OFFSET, 0); - break; - } case 1: case 2: case 5: @@ -89,6 +84,7 @@ asmb(void) seek(cout, OFFSET, 0); break; case 3: + case 6: /* no header, padded segments */ OFFSET = rnd(HEADR+textsize, 4096); seek(cout, OFFSET, 0); break; @@ -124,6 +120,7 @@ asmb(void) seek(cout, OFFSET, 0); break; case 3: + case 6: /* no header, padded segments */ OFFSET += rnd(datsize, 4096); seek(cout, OFFSET, 0); break; @@ -152,6 +149,7 @@ asmb(void) seek(cout, OFFSET, 0); switch(HEADTYPE) { case 0: /* no header */ + case 6: /* no header, padded segments */ break; case 1: /* aif for risc os */ lputl(0xe1a00000); /* NOP - decompress code */ diff --git a/sys/src/cmd/5l/mkfile b/sys/src/cmd/5l/mkfile index 507e52a4a..829dd12a2 100644 --- a/sys/src/cmd/5l/mkfile +++ b/sys/src/cmd/5l/mkfile @@ -19,6 +19,9 @@ HFILES=\ BIN=/$objtype/bin value = n*4; } +static int brcond[] = {ABEQ, ABNE, ABCS, ABCC, ABMI, ABPL, ABVS, ABVC, ABHI, ABLS, ABGE, ABLT, ABGT, ABLE}; + void doprof2(void) { @@ -1280,7 +1285,7 @@ doprof2(void) } /* - * BL profin, R2 + * BL profin */ q = prg(); q->line = p->line; @@ -1320,6 +1325,7 @@ doprof2(void) p->link = q; p = q; } + /* * RET */ @@ -1327,21 +1333,46 @@ doprof2(void) q->as = ARET; q->from = p->from; q->to = p->to; + q->cond = p->cond; q->link = p->link; + q->reg = p->reg; p->link = q; - /* - * BL profout - */ - p->as = ABL; - p->from = zprg.from; - p->to = zprg.to; - p->to.type = D_BRANCH; - p->cond = ps4; - p->to.sym = s4; + if(p->scond != 14) { + q = prg(); + q->as = ABL; + q->from = zprg.from; + q->to = zprg.to; + q->to.type = D_BRANCH; + q->cond = ps4; + q->to.sym = s4; + q->link = p->link; + p->link = q; - p = q; + p->as = brcond[p->scond^1]; /* complement */ + p->scond = 14; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->cond = q->link->link; /* successor of RET */ + p->to.offset = q->link->link->pc; + p = q->link->link; + } else { + + /* + * BL profout + */ + p->as = ABL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->cond = ps4; + p->to.sym = s4; + p->scond = 14; + + p = q; + } continue; } } diff --git a/sys/src/cmd/6a/a.h b/sys/src/cmd/6a/a.h new file mode 100644 index 000000000..84be2f007 --- /dev/null +++ b/sys/src/cmd/6a/a.h @@ -0,0 +1,195 @@ +#include +#include +#include +#include "../6c/6.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; + vlong value; + ushort type; + char *name; + char sym; +}; +#define S ((Sym*)0) + +struct Ref +{ + int class; +}; + +EXTERN struct +{ + char* p; + int c; +} fi; + +struct Io +{ + Io* link; + char b[BUFSIZ]; + char* p; + short c; + short f; +}; +#define I ((Io*)0) + +EXTERN struct +{ + Sym* sym; + short type; +} h[NSYM]; + +struct Gen +{ + double dval; + char sval[8]; + vlong offset; + Sym* sym; + short type; + short index; + short scale; +}; +struct Gen2 +{ + Gen from; + Gen to; +}; + +struct Hist +{ + Hist* link; + char* name; + long line; + vlong offset; +}; +#define H ((Hist*)0) + +enum +{ + CLAST, + CMACARG, + CMACRO, + CPREPROC, +}; + + +EXTERN char debug[256]; +EXTERN Sym* hash[NHASH]; +EXTERN char* Dlist[30]; +EXTERN int nDlist; +EXTERN Hist* ehist; +EXTERN int newflag; +EXTERN Hist* hist; +EXTERN char* hunk; +EXTERN char* include[NINCLUDE]; +EXTERN Io* iofree; +EXTERN Io* ionext; +EXTERN Io* iostack; +EXTERN long lineno; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN int ninclude; +EXTERN Gen nullgen; +EXTERN char* outfile; +EXTERN int pass; +EXTERN char* pathname; +EXTERN long pc; +EXTERN int peekc; +EXTERN int sym; +EXTERN char symb[NSYMB]; +EXTERN int thechar; +EXTERN char* thestring; +EXTERN long thunk; +EXTERN Biobuf obuf; + +void* allocn(void*, long, long); +void errorexit(void); +void pushio(void); +void newio(void); +void newfile(char*, int); +Sym* slookup(char*); +Sym* lookup(void); +void syminit(Sym*); +long yylex(void); +int getc(void); +int getnsc(void); +void unget(int); +int escchar(int); +void cinit(void); +void checkscale(int); +void pinit(char*); +void cclean(void); +int isreg(Gen*); +void outcode(int, Gen2*); +void outhist(void); +void zaddr(Gen*, int); +void zname(char*, int, int); +void ieeedtod(Ieee*, double); +int filbuf(void); +Sym* getsym(void); +void domacro(void); +void macund(void); +void macdef(void); +void macexpand(Sym*, char*); +void macinc(void); +void macprag(void); +void maclin(void); +void macif(int); +void macend(void); +void dodefine(char*); +void prfile(long); +void linehist(char*, int); +void gethunk(void); +void yyerror(char*, ...); +int yyparse(void); +void setinclude(char*); +int assemble(char*); + +/* + * 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); diff --git a/sys/src/cmd/6a/a.y b/sys/src/cmd/6a/a.y new file mode 100644 index 000000000..1b4cf2ec2 --- /dev/null +++ b/sys/src/cmd/6a/a.y @@ -0,0 +1,562 @@ +%{ +#include "a.h" +%} +%union { + Sym *sym; + vlong lval; + double dval; + char sval[8]; + Gen gen; + Gen2 gen2; +} +%left '|' +%left '^' +%left '&' +%left '<' '>' +%left '+' '-' +%left '*' '/' '%' +%token LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4 +%token LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEXC LTYPEX LTYPERT +%token LCONST LFP LPC LSB +%token LBREG LLREG LSREG LFREG LMREG LXREG +%token LFCONST +%token LSCONST LSP +%token LNAME LLAB LVAR +%type con expr pointer offset +%type mem imm reg nam rel rem rim rom omem nmem +%type nonnon nonrel nonrem rimnon rimrem remrim spec10 +%type spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 +%% +prog: +| prog line + +line: + LLAB ':' + { + if($1->value != pc) + yyerror("redeclaration of %s", $1->name); + $1->value = pc; + } + line +| LNAME ':' + { + $1->type = LLAB; + $1->value = pc; + } + line +| ';' +| inst ';' +| error ';' + +inst: + LNAME '=' expr + { + $1->type = LVAR; + $1->value = $3; + } +| LVAR '=' expr + { + if($1->value != $3) + yyerror("redeclaration of %s", $1->name); + $1->value = $3; + } +| LTYPE0 nonnon { outcode($1, &$2); } +| LTYPE1 nonrem { outcode($1, &$2); } +| LTYPE2 rimnon { outcode($1, &$2); } +| LTYPE3 rimrem { outcode($1, &$2); } +| LTYPE4 remrim { outcode($1, &$2); } +| LTYPER nonrel { outcode($1, &$2); } +| LTYPED spec1 { outcode($1, &$2); } +| LTYPET spec2 { outcode($1, &$2); } +| LTYPEC spec3 { outcode($1, &$2); } +| LTYPEN spec4 { outcode($1, &$2); } +| LTYPES spec5 { outcode($1, &$2); } +| LTYPEM spec6 { outcode($1, &$2); } +| LTYPEI spec7 { outcode($1, &$2); } +| LTYPEXC spec8 { outcode($1, &$2); } +| LTYPEX spec9 { outcode($1, &$2); } +| LTYPERT spec10 { outcode($1, &$2); } + +nonnon: + { + $$.from = nullgen; + $$.to = nullgen; + } +| ',' + { + $$.from = nullgen; + $$.to = nullgen; + } + +rimrem: + rim ',' rem + { + $$.from = $1; + $$.to = $3; + } + +remrim: + rem ',' rim + { + $$.from = $1; + $$.to = $3; + } + +rimnon: + rim ',' + { + $$.from = $1; + $$.to = nullgen; + } +| rim + { + $$.from = $1; + $$.to = nullgen; + } + +nonrem: + ',' rem + { + $$.from = nullgen; + $$.to = $2; + } +| rem + { + $$.from = nullgen; + $$.to = $1; + } + +nonrel: + ',' rel + { + $$.from = nullgen; + $$.to = $2; + } +| rel + { + $$.from = nullgen; + $$.to = $1; + } + +spec1: /* DATA */ + nam '/' con ',' imm + { + $$.from = $1; + $$.from.scale = $3; + $$.to = $5; + } + +spec2: /* TEXT */ + mem ',' imm + { + $$.from = $1; + $$.to = $3; + } +| mem ',' con ',' imm + { + $$.from = $1; + $$.from.scale = $3; + $$.to = $5; + } + +spec3: /* JMP/CALL */ + ',' rom + { + $$.from = nullgen; + $$.to = $2; + } +| rom + { + $$.from = nullgen; + $$.to = $1; + } + +spec4: /* NOP */ + nonnon +| nonrem + +spec5: /* SHL/SHR */ + rim ',' rem + { + $$.from = $1; + $$.to = $3; + } +| rim ',' rem ':' LLREG + { + $$.from = $1; + $$.to = $3; + if($$.from.index != D_NONE) + yyerror("dp shift with lhs index"); + $$.from.index = $5; + } + +spec6: /* MOVW/MOVL */ + rim ',' rem + { + $$.from = $1; + $$.to = $3; + } +| rim ',' rem ':' LSREG + { + $$.from = $1; + $$.to = $3; + if($$.to.index != D_NONE) + yyerror("dp move with lhs index"); + $$.to.index = $5; + } + +spec7: + rim ',' + { + $$.from = $1; + $$.to = nullgen; + } +| rim + { + $$.from = $1; + $$.to = nullgen; + } +| rim ',' rem + { + $$.from = $1; + $$.to = $3; + } + +spec8: /* CMPPS/CMPPD */ + reg ',' rem ',' con + { + $$.from = $1; + $$.to = $3; + $$.from.offset = $5; + } + +spec9: /* shufl */ + imm ',' rem ',' reg + { + $$.from = $3; + $$.to = $5; + if($1.type != D_CONST) + yyerror("illegal constant"); + $$.to.offset = $1.offset; + } + +spec10: /* RET/RETF */ + { + $$.from = nullgen; + $$.to = nullgen; + } +| imm + { + $$.from = $1; + $$.to = nullgen; + } + +rem: + reg +| mem + +rom: + rel +| nmem +| '*' reg + { + $$ = $2; + } +| '*' omem + { + $$ = $2; + } +| reg +| omem + +rim: + rem +| imm + +rel: + con '(' LPC ')' + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.offset = $1 + pc; + } +| LNAME offset + { + $$ = nullgen; + if(pass == 2) + yyerror("undefined label: %s", $1->name); + $$.type = D_BRANCH; + $$.sym = $1; + $$.offset = $2; + } +| LLAB offset + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.sym = $1; + $$.offset = $1->value + $2; + } + +reg: + LBREG + { + $$ = nullgen; + $$.type = $1; + } +| LFREG + { + $$ = nullgen; + $$.type = $1; + } +| LLREG + { + $$ = nullgen; + $$.type = $1; + } +| LMREG + { + $$ = nullgen; + $$.type = $1; + } +| LSP + { + $$ = nullgen; + $$.type = D_SP; + } +| LSREG + { + $$ = nullgen; + $$.type = $1; + } +| LXREG + { + $$ = nullgen; + $$.type = $1; + } + +imm: + '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.offset = $2; + } +| '$' nam + { + $$ = $2; + $$.index = $2.type; + $$.type = D_ADDR; + /* + if($2.type == D_AUTO || $2.type == D_PARAM) + yyerror("constant cannot be automatic: %s", + $2.sym->name); + */ + } +| '$' LSCONST + { + $$ = nullgen; + $$.type = D_SCONST; + memcpy($$.sval, $2, sizeof($$.sval)); + } +| '$' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = $2; + } +| '$' '(' LFCONST ')' + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = $3; + } +| '$' '-' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = -$3; + } + +mem: + omem +| nmem + +omem: + con + { + $$ = nullgen; + $$.type = D_INDIR+D_NONE; + $$.offset = $1; + } +| con '(' LLREG ')' + { + $$ = nullgen; + $$.type = D_INDIR+$3; + $$.offset = $1; + } +| con '(' LSP ')' + { + $$ = nullgen; + $$.type = D_INDIR+D_SP; + $$.offset = $1; + } +| con '(' LLREG '*' con ')' + { + $$ = nullgen; + $$.type = D_INDIR+D_NONE; + $$.offset = $1; + $$.index = $3; + $$.scale = $5; + checkscale($$.scale); + } +| con '(' LLREG ')' '(' LLREG '*' con ')' + { + $$ = nullgen; + $$.type = D_INDIR+$3; + $$.offset = $1; + $$.index = $6; + $$.scale = $8; + checkscale($$.scale); + } +| '(' LLREG ')' + { + $$ = nullgen; + $$.type = D_INDIR+$2; + } +| '(' LSP ')' + { + $$ = nullgen; + $$.type = D_INDIR+D_SP; + } +| '(' LLREG '*' con ')' + { + $$ = nullgen; + $$.type = D_INDIR+D_NONE; + $$.index = $2; + $$.scale = $4; + checkscale($$.scale); + } +| '(' LLREG ')' '(' LLREG '*' con ')' + { + $$ = nullgen; + $$.type = D_INDIR+$2; + $$.index = $5; + $$.scale = $7; + checkscale($$.scale); + } + +nmem: + nam + { + $$ = $1; + } +| nam '(' LLREG '*' con ')' + { + $$ = $1; + $$.index = $3; + $$.scale = $5; + checkscale($$.scale); + } + +nam: + LNAME offset '(' pointer ')' + { + $$ = nullgen; + $$.type = $4; + $$.sym = $1; + $$.offset = $2; + } +| LNAME '<' '>' offset '(' LSB ')' + { + $$ = nullgen; + $$.type = D_STATIC; + $$.sym = $1; + $$.offset = $4; + } + +offset: + { + $$ = 0; + } +| '+' con + { + $$ = $2; + } +| '-' con + { + $$ = -$2; + } + +pointer: + LSB +| LSP + { + $$ = D_AUTO; + } +| LFP + +con: + LCONST +| LVAR + { + $$ = $1->value; + } +| '-' con + { + $$ = -$2; + } +| '+' con + { + $$ = $2; + } +| '~' con + { + $$ = ~$2; + } +| '(' expr ')' + { + $$ = $2; + } + +expr: + con +| expr '+' expr + { + $$ = $1 + $3; + } +| expr '-' expr + { + $$ = $1 - $3; + } +| expr '*' expr + { + $$ = $1 * $3; + } +| expr '/' expr + { + $$ = $1 / $3; + } +| expr '%' expr + { + $$ = $1 % $3; + } +| expr '<' '<' expr + { + $$ = $1 << $4; + } +| expr '>' '>' expr + { + $$ = $1 >> $4; + } +| expr '&' expr + { + $$ = $1 & $3; + } +| expr '^' expr + { + $$ = $1 ^ $3; + } +| expr '|' expr + { + $$ = $1 | $3; + } diff --git a/sys/src/cmd/6a/lex.c b/sys/src/cmd/6a/lex.c new file mode 100644 index 000000000..f7c4abcd6 --- /dev/null +++ b/sys/src/cmd/6a/lex.c @@ -0,0 +1,1289 @@ +#define EXTERN +#include "a.h" +#include "y.tab.h" +#include + +void +main(int argc, char *argv[]) +{ + char *p; + int nout, nproc, status, i, c; + + thechar = '6'; + thestring = "amd64"; + memset(debug, 0, sizeof(debug)); + cinit(); + outfile = 0; + include[ninclude++] = "."; + ARGBEGIN { + default: + c = ARGC(); + if(c >= 0 || c < sizeof(debug)) + debug[c] = 1; + break; + + case 'o': + outfile = ARGF(); + break; + + case 'D': + p = ARGF(); + if(p) + Dlist[nDlist++] = p; + break; + + case 'I': + p = ARGF(); + setinclude(p); + break; + } ARGEND + if(*argv == 0) { + print("usage: %ca [-options] file.s\n", thechar); + errorexit(); + } + if(argc > 1 && systemtype(Windows)){ + print("can't assemble multiple files on windows\n"); + errorexit(); + } + if(argc > 1 && !systemtype(Windows)) { + nproc = 1; + if(p = getenv("NPROC")) + nproc = atol(p); /* */ + c = 0; + nout = 0; + for(;;) { + while(nout < nproc && argc > 0) { + i = myfork(); + if(i < 0) { + i = mywait(&status); + if(i < 0) + errorexit(); + if(status) + c++; + nout--; + continue; + } + if(i == 0) { + print("%s:\n", *argv); + if(assemble(*argv)) + errorexit(); + exits(0); + } + nout++; + argc--; + argv++; + } + i = mywait(&status); + if(i < 0) { + if(c) + errorexit(); + exits(0); + } + if(status) + c++; + nout--; + } + } + if(assemble(argv[0])) + errorexit(); + exits(0); +} + +int +assemble(char *file) +{ + char ofile[100], incfile[20], *p; + int i, of; + + strcpy(ofile, file); + p = utfrrune(ofile, pathchar()); + if(p) { + include[0] = ofile; + *p++ = 0; + } else + p = ofile; + if(outfile == 0) { + outfile = p; + if(outfile){ + p = utfrrune(outfile, '.'); + if(p) + if(p[1] == 's' && p[2] == 0) + p[0] = 0; + p = utfrune(outfile, 0); + p[0] = '.'; + p[1] = thechar; + p[2] = 0; + } else + outfile = "/dev/null"; + } + p = getenv("INCLUDE"); + if(p) { + setinclude(p); + } else { + if(systemtype(Plan9)) { + sprint(incfile,"/%s/include", thestring); + setinclude(strdup(incfile)); + } + } + + of = 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; itype != LNAME) + yyerror("double initialization %s", itab[i].name); + s->type = itab[i].type; + s->value = itab[i].value; + } + + pathname = allocn(pathname, 0, 100); + if(mygetwd(pathname, 99) == 0) { + pathname = allocn(pathname, 100, 900); + if(mygetwd(pathname, 999) == 0) + strcpy(pathname, "/???"); + } +} + +void +checkscale(int scale) +{ + + switch(scale) { + case 1: + case 2: + case 4: + case 8: + return; + } + yyerror("scale must be 1248: %d", scale); +} + +void +syminit(Sym *s) +{ + + s->type = LNAME; + s->value = 0; +} + +void +cclean(void) +{ + Gen2 g2; + + g2.from = nullgen; + g2.to = nullgen; + outcode(AEND, &g2); + Bflush(&obuf); +} + +void +zname(char *n, int t, int s) +{ + + Bputc(&obuf, ANAME); /* as(2) */ + Bputc(&obuf, ANAME>>8); + Bputc(&obuf, t); /* type */ + Bputc(&obuf, s); /* sym */ + while(*n) { + Bputc(&obuf, *n); + n++; + } + Bputc(&obuf, 0); +} + +void +zaddr(Gen *a, int s) +{ + long l; + int i, t; + char *n; + Ieee e; + + t = 0; + if(a->index != D_NONE || a->scale != 0) + t |= T_INDEX; + if(a->offset != 0) { + t |= T_OFFSET; + l = a->offset; + if((vlong)l != a->offset) + t |= T_64; + } + if(s != 0) + t |= T_SYM; + + switch(a->type) { + default: + t |= T_TYPE; + break; + case D_FCONST: + t |= T_FCONST; + break; + case D_SCONST: + t |= T_SCONST; + break; + case D_NONE: + break; + } + Bputc(&obuf, t); + + if(t & T_INDEX) { /* implies index, scale */ + Bputc(&obuf, a->index); + Bputc(&obuf, a->scale); + } + if(t & T_OFFSET) { /* implies offset */ + l = a->offset; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + if(t & T_64) { + l = a->offset>>32; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + } + } + if(t & T_SYM) /* implies sym */ + Bputc(&obuf, s); + if(t & T_FCONST) { + ieeedtod(&e, a->dval); + l = e.l; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + l = e.h; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + return; + } + if(t & T_SCONST) { + n = a->sval; + for(i=0; itype); +} + +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 && a != AMODE) + 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" +#include "../cc/compat" diff --git a/sys/src/cmd/6a/mkfile b/sys/src/cmd/6a/mkfile new file mode 100644 index 000000000..77b215cdb --- /dev/null +++ b/sys/src/cmd/6a/mkfile @@ -0,0 +1,26 @@ +type == T) + return; + if(typesu[n->type->etype]) { + sugen(n, nn, n->type->width); + return; + } + l = n->left; + r = n->right; + o = n->op; + if(n->addable >= INDEXED) { + if(nn == Z) { + switch(o) { + default: + nullwarn(Z, Z); + break; + case OINDEX: + nullwarn(l, r); + break; + } + return; + } + gmove(n, nn); + return; + } + curs = cursafe; + + if(l->complex >= FNX) + if(r != Z && r->complex >= FNX) + switch(o) { + default: + if(cond(o) && typesu[l->type->etype]) + break; + + regret(&nod, r); + cgen(r, &nod); + + regsalloc(&nod1, r); + gmove(&nod, &nod1); + + regfree(&nod); + nod = *n; + nod.right = &nod1; + + cgen(&nod, nn); + return; + + case OFUNC: + case OCOMMA: + case OANDAND: + case OOROR: + case OCOND: + case ODOT: + break; + } + + hardleft = l->addable < INDEXED || l->complex >= FNX; + switch(o) { + default: + diag(n, "unknown op in cgen: %O", o); + break; + + case ONEG: + case OCOM: + if(nn == Z) { + nullwarn(l, Z); + break; + } + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, n->type, Z, &nod); + gmove(&nod, nn); + regfree(&nod); + break; + + case OAS: + if(l->op == OBIT) + goto bitas; + if(!hardleft) { + if(nn != Z || r->addable < INDEXED || hardconst(r)) { + if(r->complex >= FNX && nn == Z) + regret(&nod, r); + else + regalloc(&nod, r, nn); + cgen(r, &nod); + gmove(&nod, l); + if(nn != Z) + gmove(&nod, nn); + regfree(&nod); + } else + gmove(r, l); + break; + } + if(l->complex >= r->complex) { + if(l->op == OINDEX && immconst(r)) { + gmove(r, l); + break; + } + reglcgen(&nod1, l, Z); + if(r->addable >= INDEXED && !hardconst(r)) { + gmove(r, &nod1); + if(nn != Z) + gmove(r, nn); + regfree(&nod1); + break; + } + regalloc(&nod, r, nn); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + reglcgen(&nod1, l, Z); + } + gmove(&nod, &nod1); + regfree(&nod); + regfree(&nod1); + break; + + bitas: + n = l->left; + regalloc(&nod, r, nn); + if(l->complex >= r->complex) { + reglcgen(&nod1, n, Z); + cgen(r, &nod); + } else { + cgen(r, &nod); + reglcgen(&nod1, n, Z); + } + regalloc(&nod2, n, Z); + gmove(&nod1, &nod2); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OBIT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + bitload(n, &nod, Z, Z, nn); + gmove(&nod, nn); + regfree(&nod); + break; + + case OLSHR: + case OASHL: + case OASHR: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(r->op == OCONST) { + if(r->vconst == 0) { + cgen(l, nn); + break; + } + regalloc(&nod, l, nn); + cgen(l, &nod); + if(o == OASHL && r->vconst == 1) + gopcode(OADD, n->type, &nod, &nod); + else + gopcode(o, n->type, r, &nod); + gmove(&nod, nn); + regfree(&nod); + break; + } + + /* + * get nod to be D_CX + */ + if(nodreg(&nod, nn, D_CX)) { + regsalloc(&nod1, n); + gmove(&nod, &nod1); + cgen(n, &nod); /* probably a bug */ + gmove(&nod, nn); + gmove(&nod1, &nod); + break; + } + reg[D_CX]++; + if(nn->op == OREGISTER && nn->reg == D_CX) + regalloc(&nod1, l, Z); + else + regalloc(&nod1, l, nn); + if(r->complex >= l->complex) { + cgen(r, &nod); + cgen(l, &nod1); + } else { + cgen(l, &nod1); + cgen(r, &nod); + } + gopcode(o, n->type, &nod, &nod1); + gmove(&nod1, nn); + regfree(&nod); + regfree(&nod1); + break; + + case OADD: + case OSUB: + case OOR: + case OXOR: + case OAND: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(typefd[n->type->etype]) + goto fop; + if(r->op == OCONST) { + if(r->vconst == 0 && o != OAND) { + cgen(l, nn); + break; + } + } + if(n->op == OADD && l->op == OASHL && l->right->op == OCONST + && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) { + c = l->right->vconst; + if(c > 0 && c <= 3) { + if(l->left->complex >= r->complex) { + regalloc(&nod, l->left, nn); + cgen(l->left, &nod); + if(r->addable < INDEXED) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + genmuladd(&nod, &nod, 1 << c, &nod1); + regfree(&nod1); + } + else + genmuladd(&nod, &nod, 1 << c, r); + } + else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l->left, Z); + cgen(l->left, &nod1); + genmuladd(&nod, &nod1, 1 << c, &nod); + regfree(&nod1); + } + gmove(&nod, nn); + regfree(&nod); + break; + } + } + if(r->addable >= INDEXED && !hardconst(r)) { + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, n->type, r, &nod); + gmove(&nod, nn); + regfree(&nod); + break; + } + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, n->type, &nod1, &nod); + } else { + regalloc(&nod1, r, nn); + cgen(r, &nod1); + regalloc(&nod, l, Z); + cgen(l, &nod); + gopcode(o, n->type, &nod1, &nod); + } + gmove(&nod, nn); + regfree(&nod); + regfree(&nod1); + break; + + case OLMOD: + case OMOD: + case OLMUL: + case OLDIV: + case OMUL: + case ODIV: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(typefd[n->type->etype]) + goto fop; + if(r->op == OCONST && typechl[n->type->etype]) { /* TO DO */ + SET(v); + switch(o) { + case ODIV: + case OMOD: + c = r->vconst; + if(c < 0) + c = -c; + v = log2(c); + if(v < 0) + break; + /* fall thru */ + case OMUL: + case OLMUL: + regalloc(&nod, l, nn); + cgen(l, &nod); + switch(o) { + case OMUL: + case OLMUL: + mulgen(n->type, r, &nod); + break; + case ODIV: + sdiv2(r->vconst, v, l, &nod); + break; + case OMOD: + smod2(r->vconst, v, l, &nod); + break; + } + gmove(&nod, nn); + regfree(&nod); + goto done; + case OLDIV: + c = r->vconst; + if((c & 0x80000000) == 0) + break; + regalloc(&nod1, l, Z); + cgen(l, &nod1); + regalloc(&nod, l, nn); + zeroregm(&nod); + gins(ACMPL, &nod1, nodconst(c)); + gins(ASBBL, nodconst(-1), &nod); + regfree(&nod1); + gmove(&nod, nn); + regfree(&nod); + goto done; + } + } + + if(o == OMUL) { + if(l->addable >= INDEXED) { + t = l; + l = r; + r = t; + } + /* should favour AX */ + regalloc(&nod, l, nn); + cgen(l, &nod); + if(r->addable < INDEXED || hardconst(r)) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(OMUL, n->type, &nod1, &nod); + regfree(&nod1); + }else + gopcode(OMUL, n->type, r, &nod); /* addressible */ + gmove(&nod, nn); + regfree(&nod); + break; + } + + /* + * get nod to be D_AX + * get nod1 to be D_DX + */ + if(nodreg(&nod, nn, D_AX)) { + regsalloc(&nod2, n); + gmove(&nod, &nod2); + v = reg[D_AX]; + reg[D_AX] = 0; + + if(isreg(l, D_AX)) { + nod3 = *n; + nod3.left = &nod2; + cgen(&nod3, nn); + } else + if(isreg(r, D_AX)) { + nod3 = *n; + nod3.right = &nod2; + cgen(&nod3, nn); + } else + cgen(n, nn); + + gmove(&nod2, &nod); + reg[D_AX] = v; + break; + } + if(nodreg(&nod1, nn, D_DX)) { + regsalloc(&nod2, n); + gmove(&nod1, &nod2); + v = reg[D_DX]; + reg[D_DX] = 0; + + if(isreg(l, D_DX)) { + nod3 = *n; + nod3.left = &nod2; + cgen(&nod3, nn); + } else + if(isreg(r, D_DX)) { + nod3 = *n; + nod3.right = &nod2; + cgen(&nod3, nn); + } else + cgen(n, nn); + + gmove(&nod2, &nod1); + reg[D_DX] = v; + break; + } + reg[D_AX]++; + + if(r->op == OCONST && (o == ODIV || o == OLDIV) && immconst(r) && typechl[r->type->etype]) { + reg[D_DX]++; + if(l->addable < INDEXED) { + regalloc(&nod2, l, Z); + cgen(l, &nod2); + l = &nod2; + } + if(o == ODIV) + sdivgen(l, r, &nod, &nod1); + else + udivgen(l, r, &nod, &nod1); + gmove(&nod1, nn); + if(l == &nod2) + regfree(l); + goto freeaxdx; + } + + if(l->complex >= r->complex) { + cgen(l, &nod); + reg[D_DX]++; + if(o == ODIV || o == OMOD) + gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); + if(o == OLDIV || o == OLMOD) + zeroregm(&nod1); + if(r->addable < INDEXED || r->op == OCONST) { + regalloc(&nod3, r, Z); + cgen(r, &nod3); + gopcode(o, n->type, &nod3, Z); + regfree(&nod3); + } else + gopcode(o, n->type, r, Z); + } else { + regsalloc(&nod3, r); + cgen(r, &nod3); + cgen(l, &nod); + reg[D_DX]++; + if(o == ODIV || o == OMOD) + gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); + if(o == OLDIV || o == OLMOD) + zeroregm(&nod1); + gopcode(o, n->type, &nod3, Z); + } + if(o == OMOD || o == OLMOD) + gmove(&nod1, nn); + else + gmove(&nod, nn); + freeaxdx: + regfree(&nod); + regfree(&nod1); + break; + + case OASLSHR: + case OASASHL: + case OASASHR: + if(r->op == OCONST) + goto asand; + if(l->op == OBIT) + goto asbitop; + if(typefd[n->type->etype]) + goto asand; /* can this happen? */ + + /* + * get nod to be D_CX + */ + if(nodreg(&nod, nn, D_CX)) { + regsalloc(&nod1, n); + gmove(&nod, &nod1); + cgen(n, &nod); + if(nn != Z) + gmove(&nod, nn); + gmove(&nod1, &nod); + break; + } + reg[D_CX]++; + + if(r->complex >= l->complex) { + cgen(r, &nod); + if(hardleft) + reglcgen(&nod1, l, Z); + else + nod1 = *l; + } else { + if(hardleft) + reglcgen(&nod1, l, Z); + else + nod1 = *l; + cgen(r, &nod); + } + + gopcode(o, l->type, &nod, &nod1); + regfree(&nod); + if(nn != Z) + gmove(&nod1, nn); + if(hardleft) + regfree(&nod1); + break; + + case OASAND: + case OASADD: + case OASSUB: + case OASXOR: + case OASOR: + asand: + if(l->op == OBIT) + goto asbitop; + if(typefd[l->type->etype] || typefd[r->type->etype]) + goto asfop; + if(l->complex >= r->complex) { + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + if(!immconst(r)) { + regalloc(&nod1, r, nn); + cgen(r, &nod1); + gopcode(o, l->type, &nod1, &nod); + regfree(&nod1); + } else + gopcode(o, l->type, r, &nod); + } else { + regalloc(&nod1, r, nn); + cgen(r, &nod1); + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + gopcode(o, l->type, &nod1, &nod); + regfree(&nod1); + } + if(nn != Z) + gmove(&nod, nn); + if(hardleft) + regfree(&nod); + break; + + asfop: + if(l->complex >= r->complex) { + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + if(r->addable < INDEXED){ + regalloc(&nod1, r, nn); + cgen(r, &nod1); + }else + nod1 = *r; + regalloc(&nod2, r, Z); + gmove(&nod, &nod2); + gopcode(o, r->type, &nod1, &nod2); + gmove(&nod2, &nod); + regfree(&nod2); + if(r->addable < INDEXED) + regfree(&nod1); + } else { + regalloc(&nod1, r, nn); + cgen(r, &nod1); + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + if(o != OASMUL && o != OASADD || !typefd[l->type->etype]) { + regalloc(&nod2, r, Z); + gmove(&nod, &nod2); + gopcode(o, r->type, &nod1, &nod2); + regfree(&nod1); + gmove(&nod2, &nod); + regfree(&nod2); + } else { + gopcode(o, r->type, &nod, &nod1); + gmove(&nod1, &nod); + regfree(&nod1); + } + } + if(nn != Z) + gmove(&nod, nn); + if(hardleft) + regfree(&nod); + break; + + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + if(l->op == OBIT) + goto asbitop; + if(typefd[n->type->etype] || typefd[r->type->etype]) + goto asfop; + if(r->op == OCONST && typechl[n->type->etype]) { + SET(v); + switch(o) { + case OASDIV: + case OASMOD: + c = r->vconst; + if(c < 0) + c = -c; + v = log2(c); + if(v < 0) + break; + /* fall thru */ + case OASMUL: + case OASLMUL: + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod, l, nn); + cgen(&nod2, &nod); + switch(o) { + case OASMUL: + case OASLMUL: + mulgen(n->type, r, &nod); + break; + case OASDIV: + sdiv2(r->vconst, v, l, &nod); + break; + case OASMOD: + smod2(r->vconst, v, l, &nod); + break; + } + havev: + gmove(&nod, &nod2); + if(nn != Z) + gmove(&nod, nn); + if(hardleft) + regfree(&nod2); + regfree(&nod); + goto done; + case OASLDIV: + c = r->vconst; + if((c & 0x80000000) == 0) + break; + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod1, l, nn); + cgen(&nod2, &nod1); + regalloc(&nod, l, nn); + zeroregm(&nod); + gins(ACMPL, &nod1, nodconst(c)); + gins(ASBBL, nodconst(-1), &nod); + regfree(&nod1); + goto havev; + } + } + + if(o == OASMUL) { + /* should favour AX */ + regalloc(&nod, l, nn); + if(r->complex >= FNX) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + r = &nod1; + } + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + cgen(&nod2, &nod); + if(r->addable < INDEXED || hardconst(r)) { + if(r->complex < FNX) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + } + gopcode(OASMUL, n->type, &nod1, &nod); + regfree(&nod1); + } + else + gopcode(OASMUL, n->type, r, &nod); + if(r == &nod1) + regfree(r); + gmove(&nod, &nod2); + if(nn != Z) + gmove(&nod, nn); + regfree(&nod); + if(hardleft) + regfree(&nod2); + break; + } + + /* + * get nod to be D_AX + * get nod1 to be D_DX + */ + if(nodreg(&nod, nn, D_AX)) { + regsalloc(&nod2, n); + gmove(&nod, &nod2); + v = reg[D_AX]; + reg[D_AX] = 0; + + if(isreg(l, D_AX)) { + nod3 = *n; + nod3.left = &nod2; + cgen(&nod3, nn); + } else + if(isreg(r, D_AX)) { + nod3 = *n; + nod3.right = &nod2; + cgen(&nod3, nn); + } else + cgen(n, nn); + + gmove(&nod2, &nod); + reg[D_AX] = v; + break; + } + if(nodreg(&nod1, nn, D_DX)) { + regsalloc(&nod2, n); + gmove(&nod1, &nod2); + v = reg[D_DX]; + reg[D_DX] = 0; + + if(isreg(l, D_DX)) { + nod3 = *n; + nod3.left = &nod2; + cgen(&nod3, nn); + } else + if(isreg(r, D_DX)) { + nod3 = *n; + nod3.right = &nod2; + cgen(&nod3, nn); + } else + cgen(n, nn); + + gmove(&nod2, &nod1); + reg[D_DX] = v; + break; + } + reg[D_AX]++; + reg[D_DX]++; + + if(l->complex >= r->complex) { + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + cgen(&nod2, &nod); + if(r->op == OCONST && typechl[r->type->etype]) { + switch(o) { + case OASDIV: + sdivgen(&nod2, r, &nod, &nod1); + goto divdone; + case OASLDIV: + udivgen(&nod2, r, &nod, &nod1); + divdone: + gmove(&nod1, &nod2); + if(nn != Z) + gmove(&nod1, nn); + goto freelxaxdx; + } + } + if(o == OASDIV || o == OASMOD) + gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); + if(o == OASLDIV || o == OASLMOD) + zeroregm(&nod1); + if(r->addable < INDEXED || r->op == OCONST || + !typeil[r->type->etype]) { + regalloc(&nod3, r, Z); + cgen(r, &nod3); + gopcode(o, l->type, &nod3, Z); + regfree(&nod3); + } else + gopcode(o, n->type, r, Z); + } else { + regalloc(&nod3, r, Z); + cgen(r, &nod3); + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + cgen(&nod2, &nod); + if(o == OASDIV || o == OASMOD) + gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); + if(o == OASLDIV || o == OASLMOD) + zeroregm(&nod1); + gopcode(o, l->type, &nod3, Z); + regfree(&nod3); + } + if(o == OASMOD || o == OASLMOD) { + gmove(&nod1, &nod2); + if(nn != Z) + gmove(&nod1, nn); + } else { + gmove(&nod, &nod2); + if(nn != Z) + gmove(&nod, nn); + } + freelxaxdx: + if(hardleft) + regfree(&nod2); + regfree(&nod); + regfree(&nod1); + break; + + fop: + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + if(r->addable < INDEXED) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, n->type, &nod1, &nod); + regfree(&nod1); + } else + gopcode(o, n->type, r, &nod); + } else { + /* TO DO: could do better with r->addable >= INDEXED */ + regalloc(&nod1, r, Z); + cgen(r, &nod1); + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, n->type, &nod1, &nod); + regfree(&nod1); + } + gmove(&nod, nn); + regfree(&nod); + break; + + asbitop: + regalloc(&nod4, n, nn); + if(l->complex >= r->complex) { + bitload(l, &nod, &nod1, &nod2, &nod4); + regalloc(&nod3, r, Z); + cgen(r, &nod3); + } else { + regalloc(&nod3, r, Z); + cgen(r, &nod3); + bitload(l, &nod, &nod1, &nod2, &nod4); + } + gmove(&nod, &nod4); + + { /* TO DO: check floating point source */ + Node onod; + + /* incredible grot ... */ + onod = nod3; + onod.op = o; + onod.complex = 2; + onod.addable = 0; + onod.type = tfield; + onod.left = &nod4; + onod.right = &nod3; + cgen(&onod, Z); + } + regfree(&nod3); + gmove(&nod4, &nod); + regfree(&nod4); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OADDR: + if(nn == Z) { + nullwarn(l, Z); + break; + } + lcgen(l, nn); + break; + + case OFUNC: + if(l->complex >= FNX) { + if(l->op != OIND) + diag(n, "bad function call"); + + regret(&nod, l->left); + cgen(l->left, &nod); + regsalloc(&nod1, l->left); + gmove(&nod, &nod1); + regfree(&nod); + + nod = *n; + nod.left = &nod2; + nod2 = *l; + nod2.left = &nod1; + nod2.complex = 1; + cgen(&nod, nn); + + return; + } + o = reg[REGARG]; + gargs(r, &nod, &nod1); + if(l->addable < INDEXED) { + reglcgen(&nod, l, nn); + nod.op = OREGISTER; + gopcode(OFUNC, n->type, Z, &nod); + regfree(&nod); + } else + gopcode(OFUNC, n->type, Z, l); + if(REGARG) + if(o != reg[REGARG]) + reg[REGARG]--; + if(nn != Z) { + regret(&nod, n); + gmove(&nod, nn); + regfree(&nod); + } + break; + + case OIND: + if(nn == Z) { + nullwarn(l, Z); + break; + } + regialloc(&nod, n, nn); + r = l; + while(r->op == OADD) + r = r->right; + if(sconst(r)) { + v = r->vconst; + r->vconst = 0; + cgen(l, &nod); + nod.xoffset += v; + r->vconst = v; + } else + cgen(l, &nod); + regind(&nod, n); + gmove(&nod, nn); + regfree(&nod); + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OLO: + case OLS: + case OHI: + case OHS: + if(nn == Z) { + nullwarn(l, r); + break; + } + boolgen(n, 1, nn); + break; + + case OANDAND: + case OOROR: + boolgen(n, 1, nn); + if(nn == Z) + patch(p, pc); + break; + + case ONOT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + boolgen(n, 1, nn); + break; + + case OCOMMA: + cgen(l, Z); + cgen(r, nn); + break; + + case OCAST: + if(nn == Z) { + nullwarn(l, Z); + break; + } + /* + * convert from types l->n->nn + */ + if(nocast(l->type, n->type) && nocast(n->type, nn->type)) { + /* both null, gen l->nn */ + cgen(l, nn); + break; + } + if(ewidth[n->type->etype] < ewidth[l->type->etype]){ + if(l->type->etype == TIND && typechlp[n->type->etype]) + warn(n, "conversion of pointer to shorter integer"); + }else if(0){ + if(nocast(n->type, nn->type) || castup(n->type, nn->type)){ + if(typefd[l->type->etype] != typefd[nn->type->etype]) + regalloc(&nod, l, nn); + else + regalloc(&nod, nn, nn); + cgen(l, &nod); + gmove(&nod, nn); + regfree(&nod); + break; + } + } + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, n, &nod); + gmove(&nod, &nod1); + gmove(&nod1, nn); + regfree(&nod1); + regfree(&nod); + break; + + case ODOT: + sugen(l, nodrat, l->type->width); + if(nn == Z) + break; + warn(n, "non-interruptable temporary"); + nod = *nodrat; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += (long)r->vconst; + nod.type = n->type; + cgen(&nod, nn); + break; + + case OCOND: + bcgen(l, 1); + p1 = p; + cgen(r->left, nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + cgen(r->right, nn); + patch(p1, pc); + break; + + case OPOSTINC: + case OPOSTDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPOSTDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + if(nn == Z) + goto pre; + + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + + gmove(&nod, nn); + if(typefd[n->type->etype]) { + regalloc(&nod1, l, Z); + gmove(&nod, &nod1); + if(v < 0) + gopcode(OSUB, n->type, nodfconst(-v), &nod1); + else + gopcode(OADD, n->type, nodfconst(v), &nod1); + gmove(&nod1, &nod); + regfree(&nod1); + } else + gopcode(OADD, n->type, nodconst(v), &nod); + if(hardleft) + regfree(&nod); + break; + + case OPREINC: + case OPREDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPREDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + + pre: + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + if(typefd[n->type->etype]) { + regalloc(&nod1, l, Z); + gmove(&nod, &nod1); + if(v < 0) + gopcode(OSUB, n->type, nodfconst(-v), &nod1); + else + gopcode(OADD, n->type, nodfconst(v), &nod1); + gmove(&nod1, &nod); + regfree(&nod1); + } else + gopcode(OADD, n->type, nodconst(v), &nod); + if(nn != Z) + gmove(&nod, nn); + if(hardleft) + regfree(&nod); + break; + + bitinc: + if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { + bitload(l, &nod, &nod1, &nod2, Z); + gmove(&nod, nn); + gopcode(OADD, tfield, nodconst(v), &nod); + bitstore(l, &nod, &nod1, &nod2, Z); + break; + } + bitload(l, &nod, &nod1, &nod2, nn); + gopcode(OADD, tfield, nodconst(v), &nod); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + } +done: + cursafe = curs; +} + +void +reglcgen(Node *t, Node *n, Node *nn) +{ + Node *r; + long v; + + regialloc(t, n, nn); + if(n->op == OIND) { + r = n->left; + while(r->op == OADD) + r = r->right; + if(sconst(r)) { + v = r->vconst; + r->vconst = 0; + lcgen(n, t); + t->xoffset += v; + r->vconst = v; + regind(t, n); + return; + } + } + lcgen(n, t); + regind(t, n); +} + +void +lcgen(Node *n, Node *nn) +{ + Prog *p1; + Node nod; + + if(debug['g']) { + prtree(nn, "lcgen lhs"); + prtree(n, "lcgen"); + } + if(n == Z || n->type == T) + return; + if(nn == Z) { + nn = &nod; + regalloc(&nod, n, Z); + } + switch(n->op) { + default: + if(n->addable < INDEXED) { + diag(n, "unknown op in lcgen: %O", n->op); + break; + } + gopcode(OADDR, n->type, n, nn); + break; + + case OCOMMA: + cgen(n->left, n->left); + lcgen(n->right, nn); + break; + + case OIND: + cgen(n->left, nn); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + lcgen(n->right->left, nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + lcgen(n->right->right, nn); + patch(p1, pc); + break; + } +} + +void +bcgen(Node *n, int true) +{ + + if(n->type == T) + gbranch(OGOTO); + else + boolgen(n, true, Z); +} + +void +boolgen(Node *n, int true, Node *nn) +{ + int o; + Prog *p1, *p2; + Node *l, *r, nod, nod1; + long curs; + + if(debug['g']) { + prtree(nn, "boolgen lhs"); + prtree(n, "boolgen"); + } + curs = cursafe; + l = n->left; + r = n->right; + switch(n->op) { + + default: + o = ONE; + if(true) + o = OEQ; + /* bad, 13 is address of external that becomes constant */ + if(n->addable >= INDEXED && n->addable != 13) { + if(typefd[n->type->etype]) { + regalloc(&nod1, n, Z); + gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */ + gopcode(o, n->type, n, &nod1); + regfree(&nod1); + } else + gopcode(o, n->type, n, nodconst(0)); + goto com; + } + regalloc(&nod, n, nn); + cgen(n, &nod); + if(typefd[n->type->etype]) { + regalloc(&nod1, n, Z); + gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */ + gopcode(o, n->type, &nod, &nod1); + regfree(&nod1); + } else + gopcode(o, n->type, &nod, nodconst(0)); + regfree(&nod); + goto com; + + case OCONST: + o = vconst(n); + if(!true) + o = !o; + gbranch(OGOTO); + if(o) { + p1 = p; + gbranch(OGOTO); + patch(p1, pc); + } + goto com; + + case OCOMMA: + cgen(l, Z); + boolgen(r, true, nn); + break; + + case ONOT: + boolgen(l, !true, nn); + break; + + case OCOND: + bcgen(l, 1); + p1 = p; + bcgen(r->left, true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + bcgen(r->right, !true); + patch(p2, pc); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OANDAND: + if(!true) + goto caseor; + + caseand: + bcgen(l, true); + p1 = p; + bcgen(r, !true); + p2 = p; + patch(p1, pc); + gbranch(OGOTO); + patch(p2, pc); + goto com; + + case OOROR: + if(!true) + goto caseand; + + caseor: + bcgen(l, !true); + p1 = p; + bcgen(r, !true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + o = n->op; + if(true) + o = comrel[relindex(o)]; + if(l->complex >= FNX && r->complex >= FNX) { + regret(&nod, r); + cgen(r, &nod); + regsalloc(&nod1, r); + gmove(&nod, &nod1); + regfree(&nod); + nod = *n; + nod.right = &nod1; + boolgen(&nod, true, nn); + break; + } + if(immconst(l)) { + o = invrel[relindex(o)]; + /* bad, 13 is address of external that becomes constant */ + if(r->addable < INDEXED || r->addable == 13) { + regalloc(&nod, r, nn); + cgen(r, &nod); + gopcode(o, l->type, &nod, l); + regfree(&nod); + } else + gopcode(o, l->type, r, l); + goto com; + } + if(typefd[l->type->etype]) + o = invrel[relindex(logrel[relindex(o)])]; + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + if(r->addable < INDEXED || hardconst(r) || typefd[l->type->etype]) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, l->type, &nod, &nod1); + regfree(&nod1); + } else + gopcode(o, l->type, &nod, r); + regfree(&nod); + goto com; + } + regalloc(&nod, r, nn); + cgen(r, &nod); + if(l->addable < INDEXED || l->addable == 13 || hardconst(l)) { + regalloc(&nod1, l, Z); + cgen(l, &nod1); + if(typechl[l->type->etype] && ewidth[l->type->etype] <= ewidth[TINT]) + gopcode(o, types[TINT], &nod1, &nod); + else + gopcode(o, l->type, &nod1, &nod); + regfree(&nod1); + } else + gopcode(o, l->type, l, &nod); + regfree(&nod); + + com: + if(nn != Z) { + p1 = p; + gmove(nodconst(1L), nn); + gbranch(OGOTO); + p2 = p; + patch(p1, pc); + gmove(nodconst(0L), nn); + patch(p2, pc); + } + break; + } + cursafe = curs; +} + +void +sugen(Node *n, Node *nn, long w) +{ + Prog *p1; + Node nod0, nod1, nod2, nod3, nod4, *l, *r; + Type *t; + int c, mt, mo; + vlong o0, o1; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + prtree(nn, "sugen lhs"); + prtree(n, "sugen"); + } + if(nn == nodrat) + if(w > nrathole) + nrathole = w; + switch(n->op) { + case OIND: + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + default: + goto copy; + + case OCONST: + goto copy; + + case ODOT: + l = n->left; + sugen(l, nodrat, l->type->width); + if(nn == Z) + break; + warn(n, "non-interruptable temporary"); + nod1 = *nodrat; + r = n->right; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod1.xoffset += (long)r->vconst; + nod1.type = n->type; + sugen(&nod1, nn, w); + break; + + case OSTRUCT: + /* + * rewrite so lhs has no fn call + */ + if(nn != Z && side(nn)) { + nod1 = *n; + nod1.type = typ(TIND, n->type); + regret(&nod2, &nod1); + lcgen(nn, &nod2); + regsalloc(&nod0, &nod1); + cgen(&nod2, &nod0); + regfree(&nod2); + + nod1 = *n; + nod1.op = OIND; + nod1.left = &nod0; + nod1.right = Z; + nod1.complex = 1; + + sugen(n, &nod1, w); + return; + } + + r = n->left; + for(t = n->type->link; t != T; t = t->down) { + l = r; + if(r->op == OLIST) { + l = r->left; + r = r->right; + } + if(nn == Z) { + cgen(l, nn); + continue; + } + /* + * hand craft *(&nn + o) = l + */ + nod0 = znode; + nod0.op = OAS; + nod0.type = t; + nod0.left = &nod1; + nod0.right = nil; + + nod1 = znode; + nod1.op = OIND; + nod1.type = t; + nod1.left = &nod2; + + nod2 = znode; + nod2.op = OADD; + nod2.type = typ(TIND, t); + nod2.left = &nod3; + nod2.right = &nod4; + + nod3 = znode; + nod3.op = OADDR; + nod3.type = nod2.type; + nod3.left = nn; + + nod4 = znode; + nod4.op = OCONST; + nod4.type = nod2.type; + nod4.vconst = t->offset; + + ccom(&nod0); + acom(&nod0); + xcom(&nod0); + nod0.addable = 0; + nod0.right = l; + + /* prtree(&nod0, "hand craft"); /* */ + cgen(&nod0, Z); + } + break; + + case OAS: + if(nn == Z) { + if(n->addable < INDEXED) + sugen(n->right, n->left, w); + break; + } + + sugen(n->right, nodrat, w); + warn(n, "non-interruptable temporary"); + sugen(nodrat, n->left, w); + sugen(nodrat, nn, w); + break; + + case OFUNC: + if(nn == Z) { + sugen(n, nodrat, w); + break; + } + if(nn->op != OIND) { + nn = new1(OADDR, nn, Z); + nn->type = types[TIND]; + nn->addable = 0; + } else + nn = nn->left; + n = new(OFUNC, n->left, new(OLIST, nn, n->right)); + n->type = types[TVOID]; + n->left->type = types[TVOID]; + cgen(n, Z); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + sugen(n->right->left, nn, w); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + sugen(n->right->right, nn, w); + patch(p1, pc); + break; + + case OCOMMA: + cgen(n->left, Z); + sugen(n->right, nn, w); + break; + } + return; + +copy: + if(nn == Z) { + switch(n->op) { + case OASADD: + case OASSUB: + case OASAND: + case OASOR: + case OASXOR: + + case OASMUL: + case OASLMUL: + + + case OASASHL: + case OASASHR: + case OASLSHR: + break; + + case OPOSTINC: + case OPOSTDEC: + case OPREINC: + case OPREDEC: + break; + + default: + return; + } + } + + if(n->complex >= FNX && nn != nil && nn->complex >= FNX) { + t = nn->type; + nn->type = types[TLONG]; + regialloc(&nod1, nn, Z); + lcgen(nn, &nod1); + regsalloc(&nod2, nn); + nn->type = t; + + gins(AMOVL, &nod1, &nod2); + regfree(&nod1); + + nod2.type = typ(TIND, t); + + nod1 = nod2; + nod1.op = OIND; + nod1.left = &nod2; + nod1.right = Z; + nod1.complex = 1; + nod1.type = t; + + sugen(n, &nod1, w); + return; + } + + if(w <= 32) { + c = cursafe; + if(n->left != Z && n->left->complex >= FNX + && n->right != Z && n->right->complex >= FNX) { + regsalloc(&nod1, n->right); + cgen(n->right, &nod1); + nod2 = *n; + nod2.right = &nod1; + cgen(&nod2, nn); + cursafe = c; + return; + } + if(w & 7) { + mt = TLONG; + mo = AMOVL; + } else { + mt = TVLONG; + mo = AMOVQ; + } + if(n->complex > nn->complex) { + t = n->type; + n->type = types[mt]; + regalloc(&nod0, n, Z); + if(!vaddr(n, 0)) { + reglcgen(&nod1, n, Z); + n->type = t; + n = &nod1; + } + else + n->type = t; + + t = nn->type; + nn->type = types[mt]; + if(!vaddr(nn, 0)) { + reglcgen(&nod2, nn, Z); + nn->type = t; + nn = &nod2; + } + else + nn->type = t; + } else { + t = nn->type; + nn->type = types[mt]; + regalloc(&nod0, nn, Z); + if(!vaddr(nn, 0)) { + reglcgen(&nod2, nn, Z); + nn->type = t; + nn = &nod2; + } + else + nn->type = t; + + t = n->type; + n->type = types[mt]; + if(!vaddr(n, 0)) { + reglcgen(&nod1, n, Z); + n->type = t; + n = &nod1; + } + else + n->type = t; + } + o0 = n->xoffset; + o1 = nn->xoffset; + w /= ewidth[mt]; + while(--w >= 0) { + gins(mo, n, &nod0); + gins(mo, &nod0, nn); + n->xoffset += ewidth[mt]; + nn->xoffset += ewidth[mt]; + } + n->xoffset = o0; + nn->xoffset = o1; + if(nn == &nod2) + regfree(&nod2); + if(n == &nod1) + regfree(&nod1); + regfree(&nod0); + return; + } + + /* botch, need to save in .safe */ + c = 0; + if(n->complex > nn->complex) { + t = n->type; + n->type = types[TLONG]; + nodreg(&nod1, n, D_SI); + if(reg[D_SI]) { + gins(APUSHQ, &nod1, Z); + c |= 1; + reg[D_SI]++; + } + lcgen(n, &nod1); + n->type = t; + + t = nn->type; + nn->type = types[TLONG]; + nodreg(&nod2, nn, D_DI); + if(reg[D_DI]) { +warn(Z, "DI botch"); + gins(APUSHQ, &nod2, Z); + c |= 2; + reg[D_DI]++; + } + lcgen(nn, &nod2); + nn->type = t; + } else { + t = nn->type; + nn->type = types[TLONG]; + nodreg(&nod2, nn, D_DI); + if(reg[D_DI]) { +warn(Z, "DI botch"); + gins(APUSHQ, &nod2, Z); + c |= 2; + reg[D_DI]++; + } + lcgen(nn, &nod2); + nn->type = t; + + t = n->type; + n->type = types[TLONG]; + nodreg(&nod1, n, D_SI); + if(reg[D_SI]) { + gins(APUSHQ, &nod1, Z); + c |= 1; + reg[D_SI]++; + } + lcgen(n, &nod1); + n->type = t; + } + nodreg(&nod3, n, D_CX); + if(reg[D_CX]) { + gins(APUSHQ, &nod3, Z); + c |= 4; + reg[D_CX]++; + } + gins(AMOVL, nodconst(w/SZ_INT), &nod3); + gins(ACLD, Z, Z); + gins(AREP, Z, Z); + gins(AMOVSL, Z, Z); + if(c & 4) { + gins(APOPQ, Z, &nod3); + reg[D_CX]--; + } + if(c & 2) { + gins(APOPQ, Z, &nod2); + reg[nod2.reg]--; + } + if(c & 1) { + gins(APOPQ, Z, &nod1); + reg[nod1.reg]--; + } +} + +/* + * TO DO + */ +void +layout(Node *f, Node *t, int c, int cv, Node *cn) +{ + Node t1, t2; + + while(c > 3) { + layout(f, t, 2, 0, Z); + c -= 2; + } + + regalloc(&t1, &lregnode, Z); + regalloc(&t2, &lregnode, Z); + if(c > 0) { + gmove(f, &t1); + f->xoffset += SZ_INT; + } + if(cn != Z) + gmove(nodconst(cv), cn); + if(c > 1) { + gmove(f, &t2); + f->xoffset += SZ_INT; + } + if(c > 0) { + gmove(&t1, t); + t->xoffset += SZ_INT; + } + if(c > 2) { + gmove(f, &t1); + f->xoffset += SZ_INT; + } + if(c > 1) { + gmove(&t2, t); + t->xoffset += SZ_INT; + } + if(c > 2) { + gmove(&t1, t); + t->xoffset += SZ_INT; + } + regfree(&t1); + regfree(&t2); +} + +/* + * constant is not vlong or fits as 32-bit signed immediate + */ +int +immconst(Node *n) +{ + long v; + + if(n->op != OCONST || !typechlpv[n->type->etype]) + return 0; + if(typechl[n->type->etype]) + return 1; + v = n->vconst; + return n->vconst == (vlong)v; +} + +/* + * if a constant and vlong, doesn't fit as 32-bit signed immediate + */ +int +hardconst(Node *n) +{ + return n->op == OCONST && !immconst(n); +} + +/* + * casting up to t2 covers an intermediate cast to t1 + */ +int +castup(Type *t1, Type *t2) +{ + int ft; + + if(!nilcast(t1, t2)) + return 0; + /* known to be small to large */ + ft = t1->etype; + switch(t2->etype){ + case TINT: + case TLONG: + return ft == TLONG || ft == TINT || ft == TSHORT || ft == TCHAR; + case TUINT: + case TULONG: + return ft == TULONG || ft == TUINT || ft == TUSHORT || ft == TUCHAR; + case TVLONG: + return ft == TLONG || ft == TINT || ft == TSHORT; + case TUVLONG: + return ft == TULONG || ft == TUINT || ft == TUSHORT; + } + return 0; +} + +void +zeroregm(Node *n) +{ + gins(AMOVL, nodconst(0), n); +} + +/* do we need to load the address of a vlong? */ +int +vaddr(Node *n, int a) +{ + switch(n->op) { + case ONAME: + if(a) + return 1; + return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC); + + case OCONST: + case OREGISTER: + case OINDREG: + return 1; + } + return 0; +} + +long +hi64v(Node *n) +{ + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + return (long)(n->vconst) & ~0L; + else + return (long)((uvlong)n->vconst>>32) & ~0L; +} + +long +lo64v(Node *n) +{ + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + return (long)((uvlong)n->vconst>>32) & ~0L; + else + return (long)(n->vconst) & ~0L; +} + +Node * +hi64(Node *n) +{ + return nodconst(hi64v(n)); +} + +Node * +lo64(Node *n) +{ + return nodconst(lo64v(n)); +} + +int +cond(int op) +{ + switch(op) { + case OANDAND: + case OOROR: + case ONOT: + return 1; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + return 1; + } + return 0; +} diff --git a/sys/src/cmd/6c/div.c b/sys/src/cmd/6c/div.c new file mode 100644 index 000000000..cb5886789 --- /dev/null +++ b/sys/src/cmd/6c/div.c @@ -0,0 +1,206 @@ +#include "gc.h" + +/* + * Based on: Granlund, T.; Montgomery, P.L. + * "Division by Invariant Integers using Multiplication". + * SIGPLAN Notices, Vol. 29, June 1994, page 61. + */ + +#define TN(n) ((uvlong)1 << (n)) +#define T31 TN(31) +#define T32 TN(32) + +int +multiplier(ulong d, int p, uvlong *mp) +{ + int l; + uvlong mlo, mhi, tlo, thi; + + l = topbit(d - 1) + 1; + mlo = (((TN(l) - d) << 32) / d) + T32; + if(l + p == 64) + mhi = (((TN(l) + 1 - d) << 32) / d) + T32; + else + mhi = (TN(32 + l) + TN(32 + l - p)) / d; + /*assert(mlo < mhi);*/ + while(l > 0) { + tlo = mlo >> 1; + thi = mhi >> 1; + if(tlo == thi) + break; + mlo = tlo; + mhi = thi; + l--; + } + *mp = mhi; + return l; +} + +int +sdiv(ulong d, ulong *mp, int *sp) +{ + int s; + uvlong m; + + s = multiplier(d, 32 - 1, &m); + *mp = m; + *sp = s; + if(m >= T31) + return 1; + else + return 0; +} + +int +udiv(ulong d, ulong *mp, int *sp, int *pp) +{ + int p, s; + uvlong m; + + s = multiplier(d, 32, &m); + p = 0; + if(m >= T32) { + while((d & 1) == 0) { + d >>= 1; + p++; + } + s = multiplier(d, 32 - p, &m); + } + *mp = m; + *pp = p; + if(m >= T32) { + /*assert(p == 0);*/ + *sp = s - 1; + return 1; + } + else { + *sp = s; + return 0; + } +} + +void +sdivgen(Node *l, Node *r, Node *ax, Node *dx) +{ + int a, s; + ulong m; + vlong c; + + c = r->vconst; + if(c < 0) + c = -c; + a = sdiv(c, &m, &s); +//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m); + gins(AMOVL, nodconst(m), ax); + gins(AIMULL, l, Z); + gins(AMOVL, l, ax); + if(a) + gins(AADDL, ax, dx); + gins(ASHRL, nodconst(31), ax); + gins(ASARL, nodconst(s), dx); + gins(AADDL, ax, dx); + if(r->vconst < 0) + gins(ANEGL, Z, dx); +} + +void +udivgen(Node *l, Node *r, Node *ax, Node *dx) +{ + int a, s, t; + ulong m; + Node nod; + + a = udiv(r->vconst, &m, &s, &t); +//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m); + if(t != 0) { + gins(AMOVL, l, ax); + gins(ASHRL, nodconst(t), ax); + gins(AMOVL, nodconst(m), dx); + gins(AMULL, dx, Z); + } + else if(a) { + if(l->op != OREGISTER) { + regalloc(&nod, l, Z); + gins(AMOVL, l, &nod); + l = &nod; + } + gins(AMOVL, nodconst(m), ax); + gins(AMULL, l, Z); + gins(AADDL, l, dx); + gins(ARCRL, nodconst(1), dx); + if(l == &nod) + regfree(l); + } + else { + gins(AMOVL, nodconst(m), ax); + gins(AMULL, l, Z); + } + if(s != 0) + gins(ASHRL, nodconst(s), dx); +} + +void +sext(Node *d, Node *s, Node *l) +{ + if(s->reg == D_AX && !nodreg(d, Z, D_DX)) { + reg[D_DX]++; + gins(ACDQ, Z, Z); + } + else { + regalloc(d, l, Z); + gins(AMOVL, s, d); + gins(ASARL, nodconst(31), d); + } +} + +void +sdiv2(long c, int v, Node *l, Node *n) +{ + Node nod; + + if(v > 0) { + if(v > 1) { + sext(&nod, n, l); + gins(AANDL, nodconst((1 << v) - 1), &nod); + gins(AADDL, &nod, n); + regfree(&nod); + } + else { + gins(ACMPL, n, nodconst(0x80000000)); + gins(ASBBL, nodconst(-1), n); + } + gins(ASARL, nodconst(v), n); + } + if(c < 0) + gins(ANEGL, Z, n); +} + +void +smod2(long c, int v, Node *l, Node *n) +{ + Node nod; + + if(c == 1) { + zeroregm(n); + return; + } + + sext(&nod, n, l); + if(v == 0) { + zeroregm(n); + gins(AXORL, &nod, n); + gins(ASUBL, &nod, n); + } + else if(v > 1) { + gins(AANDL, nodconst((1 << v) - 1), &nod); + gins(AADDL, &nod, n); + gins(AANDL, nodconst((1 << v) - 1), n); + gins(ASUBL, &nod, n); + } + else { + gins(AANDL, nodconst(1), n); + gins(AXORL, &nod, n); + gins(ASUBL, &nod, n); + } + regfree(&nod); +} diff --git a/sys/src/cmd/6c/enam.c b/sys/src/cmd/6c/enam.c new file mode 100644 index 000000000..ab8068f54 --- /dev/null +++ b/sys/src/cmd/6c/enam.c @@ -0,0 +1,669 @@ +char* anames[] = +{ + "XXX", + "AAA", + "AAD", + "AAM", + "AAS", + "ADCB", + "ADCL", + "ADCW", + "ADDB", + "ADDL", + "ADDW", + "ADJSP", + "ANDB", + "ANDL", + "ANDW", + "ARPL", + "BOUNDL", + "BOUNDW", + "BSFL", + "BSFW", + "BSRL", + "BSRW", + "BTL", + "BTW", + "BTCL", + "BTCW", + "BTRL", + "BTRW", + "BTSL", + "BTSW", + "BYTE", + "CALL", + "CLC", + "CLD", + "CLI", + "CLTS", + "CMC", + "CMPB", + "CMPL", + "CMPW", + "CMPSB", + "CMPSL", + "CMPSW", + "DAA", + "DAS", + "DATA", + "DECB", + "DECL", + "DECQ", + "DECW", + "DIVB", + "DIVL", + "DIVW", + "ENTER", + "GLOBL", + "GOK", + "HISTORY", + "HLT", + "IDIVB", + "IDIVL", + "IDIVW", + "IMULB", + "IMULL", + "IMULW", + "INB", + "INL", + "INW", + "INCB", + "INCL", + "INCQ", + "INCW", + "INSB", + "INSL", + "INSW", + "INT", + "INTO", + "IRETL", + "IRETW", + "JCC", + "JCS", + "JCXZ", + "JEQ", + "JGE", + "JGT", + "JHI", + "JLE", + "JLS", + "JLT", + "JMI", + "JMP", + "JNE", + "JOC", + "JOS", + "JPC", + "JPL", + "JPS", + "LAHF", + "LARL", + "LARW", + "LEAL", + "LEAW", + "LEAVEL", + "LEAVEW", + "LOCK", + "LODSB", + "LODSL", + "LODSW", + "LONG", + "LOOP", + "LOOPEQ", + "LOOPNE", + "LSLL", + "LSLW", + "MOVB", + "MOVL", + "MOVW", + "MOVBLSX", + "MOVBLZX", + "MOVBQSX", + "MOVBQZX", + "MOVBWSX", + "MOVBWZX", + "MOVWLSX", + "MOVWLZX", + "MOVWQSX", + "MOVWQZX", + "MOVSB", + "MOVSL", + "MOVSW", + "MULB", + "MULL", + "MULW", + "NAME", + "NEGB", + "NEGL", + "NEGW", + "NOP", + "NOTB", + "NOTL", + "NOTW", + "ORB", + "ORL", + "ORW", + "OUTB", + "OUTL", + "OUTW", + "OUTSB", + "OUTSL", + "OUTSW", + "POPAL", + "POPAW", + "POPFL", + "POPFW", + "POPL", + "POPW", + "PUSHAL", + "PUSHAW", + "PUSHFL", + "PUSHFW", + "PUSHL", + "PUSHW", + "RCLB", + "RCLL", + "RCLW", + "RCRB", + "RCRL", + "RCRW", + "REP", + "REPN", + "RET", + "ROLB", + "ROLL", + "ROLW", + "RORB", + "RORL", + "RORW", + "SAHF", + "SALB", + "SALL", + "SALW", + "SARB", + "SARL", + "SARW", + "SBBB", + "SBBL", + "SBBW", + "SCASB", + "SCASL", + "SCASW", + "SETCC", + "SETCS", + "SETEQ", + "SETGE", + "SETGT", + "SETHI", + "SETLE", + "SETLS", + "SETLT", + "SETMI", + "SETNE", + "SETOC", + "SETOS", + "SETPC", + "SETPL", + "SETPS", + "CDQ", + "CWD", + "SHLB", + "SHLL", + "SHLW", + "SHRB", + "SHRL", + "SHRW", + "STC", + "STD", + "STI", + "STOSB", + "STOSL", + "STOSW", + "SUBB", + "SUBL", + "SUBW", + "SYSCALL", + "TESTB", + "TESTL", + "TESTW", + "TEXT", + "VERR", + "VERW", + "WAIT", + "WORD", + "XCHGB", + "XCHGL", + "XCHGW", + "XLAT", + "XORB", + "XORL", + "XORW", + "FMOVB", + "FMOVBP", + "FMOVD", + "FMOVDP", + "FMOVF", + "FMOVFP", + "FMOVL", + "FMOVLP", + "FMOVV", + "FMOVVP", + "FMOVW", + "FMOVWP", + "FMOVX", + "FMOVXP", + "FCOMB", + "FCOMBP", + "FCOMD", + "FCOMDP", + "FCOMDPP", + "FCOMF", + "FCOMFP", + "FCOML", + "FCOMLP", + "FCOMW", + "FCOMWP", + "FUCOM", + "FUCOMP", + "FUCOMPP", + "FADDDP", + "FADDW", + "FADDL", + "FADDF", + "FADDD", + "FMULDP", + "FMULW", + "FMULL", + "FMULF", + "FMULD", + "FSUBDP", + "FSUBW", + "FSUBL", + "FSUBF", + "FSUBD", + "FSUBRDP", + "FSUBRW", + "FSUBRL", + "FSUBRF", + "FSUBRD", + "FDIVDP", + "FDIVW", + "FDIVL", + "FDIVF", + "FDIVD", + "FDIVRDP", + "FDIVRW", + "FDIVRL", + "FDIVRF", + "FDIVRD", + "FXCHD", + "FFREE", + "FLDCW", + "FLDENV", + "FRSTOR", + "FSAVE", + "FSTCW", + "FSTENV", + "FSTSW", + "F2XM1", + "FABS", + "FCHS", + "FCLEX", + "FCOS", + "FDECSTP", + "FINCSTP", + "FINIT", + "FLD1", + "FLDL2E", + "FLDL2T", + "FLDLG2", + "FLDLN2", + "FLDPI", + "FLDZ", + "FNOP", + "FPATAN", + "FPREM", + "FPREM1", + "FPTAN", + "FRNDINT", + "FSCALE", + "FSIN", + "FSINCOS", + "FSQRT", + "FTST", + "FXAM", + "FXTRACT", + "FYL2X", + "FYL2XP1", + "END", + "DYNT", + "INIT", + "SIGNAME", + "CMPXCHGB", + "CMPXCHGL", + "CMPXCHGW", + "CMPXCHG8B", + "CPUID", + "INVD", + "INVLPG", + "LFENCE", + "MFENCE", + "MOVNTIL", + "RDMSR", + "RDPMC", + "RDTSC", + "RSM", + "SFENCE", + "SYSRET", + "WBINVD", + "WRMSR", + "XADDB", + "XADDL", + "XADDW", + "CMOVLCC", + "CMOVLCS", + "CMOVLEQ", + "CMOVLGE", + "CMOVLGT", + "CMOVLHI", + "CMOVLLE", + "CMOVLLS", + "CMOVLLT", + "CMOVLMI", + "CMOVLNE", + "CMOVLOC", + "CMOVLOS", + "CMOVLPC", + "CMOVLPL", + "CMOVLPS", + "CMOVQCC", + "CMOVQCS", + "CMOVQEQ", + "CMOVQGE", + "CMOVQGT", + "CMOVQHI", + "CMOVQLE", + "CMOVQLS", + "CMOVQLT", + "CMOVQMI", + "CMOVQNE", + "CMOVQOC", + "CMOVQOS", + "CMOVQPC", + "CMOVQPL", + "CMOVQPS", + "CMOVWCC", + "CMOVWCS", + "CMOVWEQ", + "CMOVWGE", + "CMOVWGT", + "CMOVWHI", + "CMOVWLE", + "CMOVWLS", + "CMOVWLT", + "CMOVWMI", + "CMOVWNE", + "CMOVWOC", + "CMOVWOS", + "CMOVWPC", + "CMOVWPL", + "CMOVWPS", + "ADCQ", + "ADDQ", + "ANDQ", + "BSFQ", + "BSRQ", + "BTCQ", + "BTQ", + "BTRQ", + "BTSQ", + "CMPQ", + "CMPSQ", + "CMPXCHGQ", + "CQO", + "DIVQ", + "IDIVQ", + "IMULQ", + "IRETQ", + "LEAQ", + "LEAVEQ", + "LODSQ", + "MOVQ", + "MOVLQSX", + "MOVLQZX", + "MOVNTIQ", + "MOVSQ", + "MULQ", + "NEGQ", + "NOTQ", + "ORQ", + "POPFQ", + "POPQ", + "PUSHFQ", + "PUSHQ", + "RCLQ", + "RCRQ", + "ROLQ", + "RORQ", + "QUAD", + "SALQ", + "SARQ", + "SBBQ", + "SCASQ", + "SHLQ", + "SHRQ", + "STOSQ", + "SUBQ", + "TESTQ", + "XADDQ", + "XCHGQ", + "XORQ", + "ADDPD", + "ADDPS", + "ADDSD", + "ADDSS", + "ANDNPD", + "ANDNPS", + "ANDPD", + "ANDPS", + "CMPPD", + "CMPPS", + "CMPSD", + "CMPSS", + "COMISD", + "COMISS", + "CVTPD2PL", + "CVTPD2PS", + "CVTPL2PD", + "CVTPL2PS", + "CVTPS2PD", + "CVTPS2PL", + "CVTSD2SL", + "CVTSD2SQ", + "CVTSD2SS", + "CVTSL2SD", + "CVTSL2SS", + "CVTSQ2SD", + "CVTSQ2SS", + "CVTSS2SD", + "CVTSS2SL", + "CVTSS2SQ", + "CVTTPD2PL", + "CVTTPS2PL", + "CVTTSD2SL", + "CVTTSD2SQ", + "CVTTSS2SL", + "CVTTSS2SQ", + "DIVPD", + "DIVPS", + "DIVSD", + "DIVSS", + "EMMS", + "FXRSTOR", + "FXRSTOR64", + "FXSAVE", + "FXSAVE64", + "LDMXCSR", + "MASKMOVOU", + "MASKMOVQ", + "MAXPD", + "MAXPS", + "MAXSD", + "MAXSS", + "MINPD", + "MINPS", + "MINSD", + "MINSS", + "MOVAPD", + "MOVAPS", + "MOVOU", + "MOVHLPS", + "MOVHPD", + "MOVHPS", + "MOVLHPS", + "MOVLPD", + "MOVLPS", + "MOVMSKPD", + "MOVMSKPS", + "MOVNTO", + "MOVNTPD", + "MOVNTPS", + "MOVNTQ", + "MOVO", + "MOVQOZX", + "MOVSD", + "MOVSS", + "MOVUPD", + "MOVUPS", + "MULPD", + "MULPS", + "MULSD", + "MULSS", + "ORPD", + "ORPS", + "PACKSSLW", + "PACKSSWB", + "PACKUSWB", + "PADDB", + "PADDL", + "PADDQ", + "PADDSB", + "PADDSW", + "PADDUSB", + "PADDUSW", + "PADDW", + "PANDB", + "PANDL", + "PANDSB", + "PANDSW", + "PANDUSB", + "PANDUSW", + "PANDW", + "PAND", + "PANDN", + "PAVGB", + "PAVGW", + "PCMPEQB", + "PCMPEQL", + "PCMPEQW", + "PCMPGTB", + "PCMPGTL", + "PCMPGTW", + "PEXTRW", + "PFACC", + "PFADD", + "PFCMPEQ", + "PFCMPGE", + "PFCMPGT", + "PFMAX", + "PFMIN", + "PFMUL", + "PFNACC", + "PFPNACC", + "PFRCP", + "PFRCPIT1", + "PFRCPI2T", + "PFRSQIT1", + "PFRSQRT", + "PFSUB", + "PFSUBR", + "PINSRW", + "PMADDWL", + "PMAXSW", + "PMAXUB", + "PMINSW", + "PMINUB", + "PMOVMSKB", + "PMULHRW", + "PMULHUW", + "PMULHW", + "PMULLW", + "PMULULQ", + "POR", + "PSADBW", + "PSHUFHW", + "PSHUFL", + "PSHUFLW", + "PSHUFW", + "PSLLO", + "PSLLL", + "PSLLQ", + "PSLLW", + "PSRAL", + "PSRAW", + "PSRLO", + "PSRLL", + "PSRLQ", + "PSRLW", + "PSUBB", + "PSUBL", + "PSUBQ", + "PSUBSB", + "PSUBSW", + "PSUBUSB", + "PSUBUSW", + "PSUBW", + "PSWAPL", + "PUNPCKHBW", + "PUNPCKHLQ", + "PUNPCKHQDQ", + "PUNPCKHWL", + "PUNPCKLBW", + "PUNPCKLLQ", + "PUNPCKLQDQ", + "PUNPCKLWL", + "PXOR", + "RCPPS", + "RCPSS", + "RSQRTPS", + "RSQRTSS", + "SHUFPD", + "SHUFPS", + "SQRTPD", + "SQRTPS", + "SQRTSD", + "SQRTSS", + "STMXCSR", + "SUBPD", + "SUBPS", + "SUBSD", + "SUBSS", + "UCOMISD", + "UCOMISS", + "UNPCKHPD", + "UNPCKHPS", + "UNPCKLPD", + "UNPCKLPS", + "XORPD", + "XORPS", + "PF2IW", + "PF2IL", + "PI2FW", + "PI2FL", + "RETFW", + "RETFL", + "RETFQ", + "SWAPGS", + "MODE", + "LAST", +}; diff --git a/sys/src/cmd/6c/gc.h b/sys/src/cmd/6c/gc.h new file mode 100644 index 000000000..57d3a9994 --- /dev/null +++ b/sys/src/cmd/6c/gc.h @@ -0,0 +1,381 @@ +#include "../cc/cc.h" +#include "../6c/6.out.h" + +/* + * 6c/amd64 + * Intel 386 with AMD64 extensions + */ +#define SZ_CHAR 1 +#define SZ_SHORT 2 +#define SZ_INT 4 +#define SZ_LONG 4 +#define SZ_IND 8 +#define SZ_FLOAT 4 +#define SZ_VLONG 8 +#define SZ_DOUBLE 8 +#define FNX 100 + +typedef struct Adr Adr; +typedef struct Prog Prog; +typedef struct Case Case; +typedef struct C1 C1; +typedef struct Var Var; +typedef struct Reg Reg; +typedef struct Rgn Rgn; +typedef struct Renv Renv; + +EXTERN struct +{ + Node* regtree; + Node* basetree; + short scale; + short reg; + short ptr; +} idx; + +struct Adr +{ + vlong offset; + double dval; + char sval[NSNAME]; + + Sym* sym; + uchar type; + uchar index; + uchar etype; + uchar scale; /* doubles as width in DATA op */ +}; +#define A ((Adr*)0) + +#define INDEXED 9 +struct Prog +{ + Adr from; + Adr to; + Prog* link; + long lineno; + short as; +}; +#define P ((Prog*)0) + +struct Case +{ + Case* link; + vlong val; + long label; + char def; + char isv; +}; +#define C ((Case*)0) + +struct C1 +{ + vlong val; + long label; +}; + +struct Var +{ + vlong offset; + Sym* sym; + char name; + char etype; +}; + +struct Reg +{ + long pc; + long rpo; /* reverse post ordering */ + + Bits set; + Bits use1; + Bits use2; + + Bits refbehind; + Bits refahead; + Bits calbehind; + Bits calahead; + Bits regdiff; + Bits act; + + long regu; + long loop; /* could be shorter */ + + Reg* log5; + long active; + + Reg* p1; + Reg* p2; + Reg* p2link; + Reg* s1; + Reg* s2; + Reg* link; + Prog* prog; +}; +#define R ((Reg*)0) + +struct Renv +{ + int safe; + Node base; + Node* saved; + Node* scope; +}; + +#define NRGN 600 +struct Rgn +{ + Reg* enter; + short cost; + short varno; + short regno; +}; + +EXTERN long breakpc; +EXTERN long nbreak; +EXTERN Case* cases; +EXTERN Node constnode; +EXTERN Node fconstnode; +EXTERN Node vconstnode; +EXTERN long continpc; +EXTERN long curarg; +EXTERN long cursafe; +EXTERN Prog* firstp; +EXTERN Prog* lastp; +EXTERN long maxargsafe; +EXTERN int mnstring; +EXTERN Node* nodrat; +EXTERN Node* nodret; +EXTERN Node* nodsafe; +EXTERN long nrathole; +EXTERN long nstring; +EXTERN Prog* p; +EXTERN long pc; +EXTERN Node lregnode; +EXTERN Node qregnode; +EXTERN char string[NSNAME]; +EXTERN Sym* symrathole; +EXTERN Node znode; +EXTERN Prog zprog; +EXTERN int reg[D_NONE]; +EXTERN long exregoffset; +EXTERN long exfregoffset; +EXTERN uchar typechlpv[NTYPE]; + +#define BLOAD(r) band(bnot(r->refbehind), r->refahead) +#define BSTORE(r) band(bnot(r->calbehind), r->calahead) +#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z]) +#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z]) + +#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32)) + +#define CLOAD 5 +#define CREF 5 +#define CINF 1000 +#define LOOP 3 + +EXTERN Rgn region[NRGN]; +EXTERN Rgn* rgp; +EXTERN int nregion; +EXTERN int nvar; + +EXTERN Bits externs; +EXTERN Bits params; +EXTERN Bits consts; +EXTERN Bits addrs; + +EXTERN long regbits; +EXTERN long exregbits; + +EXTERN int change; +EXTERN int suppress; + +EXTERN Reg* firstr; +EXTERN Reg* lastr; +EXTERN Reg zreg; +EXTERN Reg* freer; +EXTERN Var var[NVAR]; +EXTERN long* idom; +EXTERN Reg** rpo2r; +EXTERN long maxnr; + +extern char* anames[]; + +/* + * sgen.c + */ +void codgen(Node*, Node*); +void gen(Node*); +void noretval(int); +void usedset(Node*, int); +void xcom(Node*); +void indx(Node*); +int bcomplex(Node*, Node*); + +/* + * cgen.c + */ +void zeroregm(Node*); +void cgen(Node*, Node*); +void reglcgen(Node*, Node*, Node*); +void lcgen(Node*, Node*); +void bcgen(Node*, int); +void boolgen(Node*, int, Node*); +void sugen(Node*, Node*, long); +int needreg(Node*, int); +int hardconst(Node*); +int immconst(Node*); + +/* + * cgen64.c + */ +int vaddr(Node*, int); +void loadpair(Node*, Node*); +int cgen64(Node*, Node*); +void testv(Node*, int); + +/* + * txt.c + */ +void ginit(void); +void gclean(void); +void nextpc(void); +void gargs(Node*, Node*, Node*); +void garg1(Node*, Node*, Node*, int, Node**); +Node* nodconst(long); +Node* nodfconst(double); +Node* nodgconst(vlong, Type*); +int nodreg(Node*, Node*, int); +int isreg(Node*, int); +void regret(Node*, Node*); +void regalloc(Node*, Node*, Node*); +void regfree(Node*); +void regialloc(Node*, Node*, Node*); +void regsalloc(Node*, Node*); +void regaalloc1(Node*, Node*); +void regaalloc(Node*, Node*); +void regind(Node*, Node*); +void gprep(Node*, Node*); +void naddr(Node*, Adr*); +void gcmp(int, Node*, vlong); +void gmove(Node*, Node*); +void gins(int a, Node*, Node*); +void gopcode(int, Type*, Node*, Node*); +int samaddr(Node*, Node*); +void gbranch(int); +void patch(Prog*, long); +int sconst(Node*); +void gpseudo(int, Sym*, Node*); + +/* + * swt.c + */ +int swcmp(const void*, const void*); +void doswit(Node*); +void swit1(C1*, int, long, Node*); +void casf(void); +void bitload(Node*, Node*, Node*, Node*, Node*); +void bitstore(Node*, Node*, Node*, Node*, Node*); +long outstring(char*, long); +void nullwarn(Node*, Node*); +void sextern(Sym*, Node*, long, long); +void gextern(Sym*, Node*, long, long); +void outcode(void); +void ieeedtod(Ieee*, double); + +/* + * list + */ +void listinit(void); +int Pconv(Fmt*); +int Aconv(Fmt*); +int Dconv(Fmt*); +int Sconv(Fmt*); +int Rconv(Fmt*); +int Xconv(Fmt*); +int Bconv(Fmt*); + +/* + * reg.c + */ +Reg* rega(void); +int rcmp(const void*, const void*); +void regopt(Prog*); +void addmove(Reg*, int, int, int); +Bits mkvar(Reg*, Adr*); +void prop(Reg*, Bits, Bits); +void loopit(Reg*, long); +void synch(Reg*, Bits); +ulong allreg(ulong, Rgn*); +void paint1(Reg*, int); +ulong paint2(Reg*, int); +void paint3(Reg*, int, long, int); +void addreg(Adr*, int); + +/* + * peep.c + */ +void peep(void); +void excise(Reg*); +Reg* uniqp(Reg*); +Reg* uniqs(Reg*); +int regtyp(Adr*); +int anyvar(Adr*); +int subprop(Reg*); +int copyprop(Reg*); +int copy1(Adr*, Adr*, Reg*, int); +int copyu(Prog*, Adr*, Adr*); + +int copyas(Adr*, Adr*); +int copyau(Adr*, Adr*); +int copysub(Adr*, Adr*, Adr*, int); +int copysub1(Prog*, Adr*, Adr*, int); + +long RtoB(int); +long FtoB(int); +int BtoR(long); +int BtoF(long); + +#define D_HI D_NONE +#define D_LO D_NONE + +#define isregtype(t) ((t)>= D_AX && (t)<=D_R15) + +/* + * bound + */ +void comtarg(void); + +/* + * com64 + */ +int cond(int); +int com64(Node*); +void com64init(void); +void bool64(Node*); +long lo64v(Node*); +long hi64v(Node*); +Node* lo64(Node*); +Node* hi64(Node*); + +/* + * div/mul + */ +void sdivgen(Node*, Node*, Node*, Node*); +void udivgen(Node*, Node*, Node*, Node*); +void sdiv2(long, int, Node*, Node*); +void smod2(long, int, Node*, Node*); +void mulgen(Type*, Node*, Node*); +void genmuladd(Node*, Node*, int, Node*); +void shiftit(Type*, Node*, Node*); + +#pragma varargck type "A" int +#pragma varargck type "B" Bits +#pragma varargck type "D" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "R" int +#pragma varargck type "S" char* + +#define D_X7 (D_X0+7) + +void fgopcode(int, Node*, Node*, int, int); diff --git a/sys/src/cmd/6c/list.c b/sys/src/cmd/6c/list.c new file mode 100644 index 000000000..73efdf139 --- /dev/null +++ b/sys/src/cmd/6c/list.c @@ -0,0 +1,337 @@ +#define EXTERN +#include "gc.h" + +void +listinit(void) +{ + + fmtinstall('A', Aconv); + fmtinstall('B', Bconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('D', Dconv); + fmtinstall('R', Rconv); +} + +int +Bconv(Fmt *fp) +{ + char str[STRINGSZ], ss[STRINGSZ], *s; + Bits bits; + int i; + + str[0] = 0; + bits = va_arg(fp->args, Bits); + while(bany(&bits)) { + i = bnum(bits); + if(str[0]) + strcat(str, " "); + if(var[i].sym == S) { + sprint(ss, "$%lld", var[i].offset); + s = ss; + } else + s = var[i].sym->name; + if(strlen(str) + strlen(s) + 1 >= STRINGSZ) + break; + strcat(str, s); + bits.b[i/32] &= ~(1L << (i%32)); + } + return fmtstrcpy(fp, str); +} + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ]; + Prog *p; + + p = va_arg(fp->args, Prog*); + if(p->as == ADATA) + sprint(str, " %A %D/%d,%D", + p->as, &p->from, p->from.scale, &p->to); + else if(p->as == ATEXT) + sprint(str, " %A %D,%d,%D", + p->as, &p->from, p->from.scale, &p->to); + else + sprint(str, " %A %D,%D", + p->as, &p->from, &p->to); + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + int i; + + i = va_arg(fp->args, int); + return fmtstrcpy(fp, anames[i]); +} + +int +Dconv(Fmt *fp) +{ + char str[40], s[20]; + Adr *a; + int i; + + a = va_arg(fp->args, Adr*); + i = a->type; + if(i >= D_INDIR) { + if(a->offset) + sprint(str, "%lld(%R)", a->offset, i-D_INDIR); + else + sprint(str, "(%R)", i-D_INDIR); + goto brk; + } + switch(i) { + + default: + if(a->offset) + sprint(str, "$%lld,%R", a->offset, i); + else + sprint(str, "%R", i); + break; + + case D_NONE: + str[0] = 0; + break; + + case D_BRANCH: + sprint(str, "%lld(PC)", a->offset-pc); + break; + + case D_EXTERN: + sprint(str, "%s+%lld(SB)", a->sym->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<>+%lld(SB)", a->sym->name, + a->offset); + break; + + case D_AUTO: + sprint(str, "%s+%lld(SP)", a->sym->name, a->offset); + break; + + case D_PARAM: + if(a->sym) + sprint(str, "%s+%lld(FP)", a->sym->name, a->offset); + else + sprint(str, "%lld(FP)", a->offset); + break; + + case D_CONST: + sprint(str, "$%lld", a->offset); + break; + + case D_FCONST: + sprint(str, "$(%.17e)", a->dval); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + + case D_ADDR: + a->type = a->index; + a->index = D_NONE; + sprint(str, "$%D", a); + a->index = a->type; + a->type = D_ADDR; + goto conv; + } +brk: + if(a->index != D_NONE) { + sprint(s, "(%R*%d)", (int)a->index, (int)a->scale); + strcat(str, s); + } +conv: + return fmtstrcpy(fp, str); +} + +char* regstr[] = +{ + "AL", /* [D_AL] */ + "CL", + "DL", + "BL", + "SPB", + "BPB", + "SIB", + "DIB", + "R8B", + "R9B", + "R10B", + "R11B", + "R12B", + "R13B", + "R14B", + "R15B", + + "AX", /* [D_AX] */ + "CX", + "DX", + "BX", + "SP", + "BP", + "SI", + "DI", + "R8", + "R9", + "R10", + "R11", + "R12", + "R13", + "R14", + "R15", + + "AH", + "CH", + "DH", + "BH", + + "F0", /* [D_F0] */ + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + + "M0", + "M1", + "M2", + "M3", + "M4", + "M5", + "M6", + "M7", + + "X0", + "X1", + "X2", + "X3", + "X4", + "X5", + "X6", + "X7", + "X8", + "X9", + "X10", + "X11", + "X12", + "X13", + "X14", + "X15", + + "CS", /* [D_CS] */ + "SS", + "DS", + "ES", + "FS", + "GS", + + "GDTR", /* [D_GDTR] */ + "IDTR", /* [D_IDTR] */ + "LDTR", /* [D_LDTR] */ + "MSW", /* [D_MSW] */ + "TASK", /* [D_TASK] */ + + "CR0", /* [D_CR] */ + "CR1", + "CR2", + "CR3", + "CR4", + "CR5", + "CR6", + "CR7", + "CR8", + "CR9", + "CR10", + "CR11", + "CR12", + "CR13", + "CR14", + "CR15", + + "DR0", /* [D_DR] */ + "DR1", + "DR2", + "DR3", + "DR4", + "DR5", + "DR6", + "DR7", + + "TR0", /* [D_TR] */ + "TR1", + "TR2", + "TR3", + "TR4", + "TR5", + "TR6", + "TR7", + + "NONE", /* [D_NONE] */ +}; + +int +Rconv(Fmt *fp) +{ + char str[20]; + int r; + + r = va_arg(fp->args, int); + if(r >= D_AL && r <= D_NONE) + sprint(str, "%s", regstr[r-D_AL]); + else + sprint(str, "gok(%d)", r); + + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[30], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + default: + if(c < 040 || c >= 0177) + break; /* not portable */ + p[-1] = c; + continue; + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} diff --git a/sys/src/cmd/6c/machcap.c b/sys/src/cmd/6c/machcap.c new file mode 100644 index 000000000..68c7fa8d2 --- /dev/null +++ b/sys/src/cmd/6c/machcap.c @@ -0,0 +1,78 @@ +#include "gc.h" + +int +machcap(Node *n) +{ + + if(n == Z) + return 1; /* test */ + + switch(n->op) { + case OMUL: + case OLMUL: + case OASMUL: + case OASLMUL: + if(typechl[n->type->etype]) + return 1; + if(typev[n->type->etype]) { + return 1; + } + break; + + case OCOM: + case ONEG: + case OADD: + case OAND: + case OOR: + case OSUB: + case OXOR: + case OASHL: + case OLSHR: + case OASHR: + if(typechlv[n->left->type->etype]) + return 1; + break; + + case OCAST: + return 1; + + case OCOND: + case OCOMMA: + case OLIST: + case OANDAND: + case OOROR: + case ONOT: + return 1; + + case OASADD: + case OASSUB: + case OASAND: + case OASOR: + case OASXOR: + return 1; + + case OASASHL: + case OASASHR: + case OASLSHR: + return 1; + + case OPOSTINC: + case OPOSTDEC: + case OPREINC: + case OPREDEC: + return 1; + + case OEQ: + case ONE: + case OLE: + case OGT: + case OLT: + case OGE: + case OHI: + case OHS: + case OLO: + case OLS: + return 1; + } + return 0; +} diff --git a/sys/src/cmd/6c/mkenam b/sys/src/cmd/6c/mkenam new file mode 100644 index 000000000..32cb1d958 --- /dev/null +++ b/sys/src/cmd/6c/mkenam @@ -0,0 +1,15 @@ +ed - ../6c/6.out.h <<'!' +v/^ A/d +,s/^ A/ "/ +g/ .*$/s/// +,s/,*$/",/ +1i +char* anames[] = +{ +. +$a +}; +. +w enam.c +Q +! diff --git a/sys/src/cmd/6c/mkfile b/sys/src/cmd/6c/mkfile new file mode 100644 index 000000000..18dea3867 --- /dev/null +++ b/sys/src/cmd/6c/mkfile @@ -0,0 +1,38 @@ + 0; i >>= 1) { + m >>= i; + if((v & m) == 0) { + v >>= i; + s += i; + } + } + return s; +} + +void +genmuladd(Node *d, Node *s, int m, Node *a) +{ + Node nod; + + nod.op = OINDEX; + nod.left = a; + nod.right = s; + nod.scale = m; + nod.type = types[TIND]; + nod.xoffset = 0; + xcom(&nod); + gopcode(OADDR, d->type, &nod, d); +} + +void +mulparam(ulong m, Mparam *mp) +{ + int c, i, j, n, o, q, s; + int bc, bi, bn, bo, bq, bs, bt; + char *p; + long u; + ulong t; + + bc = bq = 10; + bi = bn = bo = bs = bt = 0; + for(i = 0; i < nelem(malgs); i++) { + for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++) + for(s = 0; s < 2; s++) { + c = 10; + q = 10; + u = m - o; + if(u == 0) + continue; + if(s) { + o = -o; + if(o > 0) + continue; + u = -u; + } + n = lowbit(u); + t = (ulong)u >> n; + switch(i) { + case 0: + if(t == 1) { + c = s + 1; + q = 0; + break; + } + switch(t) { + case 3: + case 5: + case 9: + c = s + 1; + if(n) + c++; + q = 0; + break; + } + if(s) + break; + switch(t) { + case 15: + case 25: + case 27: + case 45: + case 81: + c = 2; + if(n) + c++; + q = 1; + break; + } + break; + case 1: + if(t == 1) { + c = 3; + q = 3; + break; + } + switch(t) { + case 3: + case 5: + case 9: + c = 3; + q = 2; + break; + } + break; + case 2: + if(t == 1) { + c = 3; + q = 2; + break; + } + break; + case 3: + if(s) + break; + if(t == 1) { + c = 3; + q = 1; + break; + } + break; + case 4: + if(t == 1) { + c = 3; + q = 0; + break; + } + break; + } + if(c < bc || (c == bc && q > bq)) { + bc = c; + bi = i; + bn = n; + bo = o; + bq = q; + bs = s; + bt = t; + } + } + } + mp->value = m; + if(bc <= 3) { + mp->alg = bi; + mp->shift = bn; + mp->off = bo; + mp->neg = bs; + mp->arg = bt; + } + else + mp->alg = -1; +} + +int +m0(int a) +{ + switch(a) { + case -2: + case 2: + return 2; + case -3: + case 3: + return 2; + case -4: + case 4: + return 4; + case -5: + case 5: + return 4; + case 6: + return 2; + case -8: + case 8: + return 8; + case -9: + case 9: + return 8; + case 10: + return 4; + case 12: + return 2; + case 15: + return 2; + case 18: + return 8; + case 20: + return 4; + case 24: + return 2; + case 25: + return 4; + case 27: + return 2; + case 36: + return 8; + case 40: + return 4; + case 45: + return 4; + case 72: + return 8; + case 81: + return 8; + } + diag(Z, "bad m0"); + return 0; +} + +int +m1(int a) +{ + switch(a) { + case 15: + return 4; + case 25: + return 4; + case 27: + return 8; + case 45: + return 8; + case 81: + return 8; + } + diag(Z, "bad m1"); + return 0; +} + +int +m2(int a) +{ + switch(a) { + case 6: + return 2; + case 10: + return 2; + case 12: + return 4; + case 18: + return 2; + case 20: + return 4; + case 24: + return 8; + case 36: + return 4; + case 40: + return 8; + case 72: + return 8; + } + diag(Z, "bad m2"); + return 0; +} + +void +shiftit(Type *t, Node *s, Node *d) +{ + long c; + + c = (long)s->vconst & 31; + switch(c) { + case 0: + break; + case 1: + gopcode(OADD, t, d, d); + break; + default: + gopcode(OASHL, t, s, d); + } +} + +static int +mulgen1(ulong v, Node *n) +{ + int i, o; + Mparam *p; + Node nod, nods; + + for(i = 0; i < nelem(multab); i++) { + p = &multab[i]; + if(p->value == v) + goto found; + } + + p = &multab[mulptr]; + if(++mulptr == nelem(multab)) + mulptr = 0; + + mulparam(v, p); + +found: +// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off); + if(p->alg < 0) + return 0; + + nods = *nodconst(p->shift); + + o = OADD; + if(p->alg > 0) { + regalloc(&nod, n, Z); + if(p->off < 0) + o = OSUB; + } + + switch(p->alg) { + case 0: + switch(p->arg) { + case 1: + shiftit(n->type, &nods, n); + break; + case 15: + case 25: + case 27: + case 45: + case 81: + genmuladd(n, n, m1(p->arg), n); + /* fall thru */ + case 3: + case 5: + case 9: + genmuladd(n, n, m0(p->arg), n); + shiftit(n->type, &nods, n); + break; + default: + goto bad; + } + if(p->neg == 1) + gins(ANEGL, Z, n); + break; + case 1: + switch(p->arg) { + case 1: + gmove(n, &nod); + shiftit(n->type, &nods, &nod); + break; + case 3: + case 5: + case 9: + genmuladd(&nod, n, m0(p->arg), n); + shiftit(n->type, &nods, &nod); + break; + default: + goto bad; + } + if(p->neg) + gopcode(o, n->type, &nod, n); + else { + gopcode(o, n->type, n, &nod); + gmove(&nod, n); + } + break; + case 2: + genmuladd(&nod, n, m0(p->off), n); + shiftit(n->type, &nods, n); + goto comop; + case 3: + genmuladd(&nod, n, m0(p->off), n); + shiftit(n->type, &nods, n); + genmuladd(n, &nod, m2(p->off), n); + break; + case 4: + genmuladd(&nod, n, m0(p->off), nodconst(0)); + shiftit(n->type, &nods, n); + goto comop; + default: + diag(Z, "bad mul alg"); + break; + comop: + if(p->neg) { + gopcode(o, n->type, n, &nod); + gmove(&nod, n); + } + else + gopcode(o, n->type, &nod, n); + } + + if(p->alg > 0) + regfree(&nod); + + return 1; + +bad: + diag(Z, "mulgen botch"); + return 1; +} + +void +mulgen(Type *t, Node *r, Node *n) +{ + if(!mulgen1(r->vconst, n)) + gopcode(OMUL, t, r, n); +} diff --git a/sys/src/cmd/6c/peep.c b/sys/src/cmd/6c/peep.c new file mode 100644 index 000000000..2511b6c7e --- /dev/null +++ b/sys/src/cmd/6c/peep.c @@ -0,0 +1,846 @@ +#include "gc.h" + +static int +needc(Prog *p) +{ + while(p != P) { + switch(p->as) { + case AADCL: + case AADCQ: + case ASBBL: + case ASBBQ: + case ARCRL: + case ARCRQ: + return 1; + case AADDL: + case AADDQ: + case ASUBL: + case ASUBQ: + case AJMP: + case ARET: + case ACALL: + return 0; + default: + if(p->to.type == D_BRANCH) + return 0; + } + p = p->link; + } + return 0; +} + +static Reg* +rnops(Reg *r) +{ + Prog *p; + Reg *r1; + + if(r != R) + for(;;){ + p = r->prog; + if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE) + break; + r1 = uniqs(r); + if(r1 == R) + break; + r = r1; + } + return r; +} + +void +peep(void) +{ + Reg *r, *r1, *r2; + Prog *p, *p1; + int t; + + /* + * complete R structure + */ + t = 0; + for(r=firstr; r!=R; r=r1) { + r1 = r->link; + if(r1 == R) + break; + p = r->prog->link; + while(p != r1->prog) + switch(p->as) { + default: + r2 = rega(); + r->link = r2; + r2->link = r1; + + r2->prog = p; + r2->p1 = r; + r->s1 = r2; + r2->s1 = r1; + r1->p1 = r2; + + r = r2; + t++; + + case ADATA: + case AGLOBL: + case ANAME: + case ASIGNAME: + p = p->link; + } + } + + pc = 0; /* speculating it won't kill */ + +loop1: + + t = 0; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + case AMOVL: + case AMOVQ: + case AMOVSS: + case AMOVSD: + if(regtyp(&p->to)) + if(regtyp(&p->from)) { + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + break; + + case AMOVBLZX: + case AMOVWLZX: + case AMOVBLSX: + case AMOVWLSX: + if(regtyp(&p->to)) { + r1 = rnops(uniqs(r)); + if(r1 != R) { + p1 = r1->prog; + if(p->as == p1->as && p->to.type == p1->from.type){ + p1->as = AMOVL; + t++; + } + } + } + break; + + case AMOVBQSX: + case AMOVBQZX: + case AMOVWQSX: + case AMOVWQZX: + case AMOVLQSX: + case AMOVLQZX: + if(regtyp(&p->to)) { + r1 = rnops(uniqs(r)); + if(r1 != R) { + p1 = r1->prog; + if(p->as == p1->as && p->to.type == p1->from.type){ + p1->as = AMOVQ; + t++; + } + } + } + break; + + case AADDL: + case AADDQ: + case AADDW: + if(p->from.type != D_CONST || needc(p->link)) + break; + if(p->from.offset == -1){ + if(p->as == AADDQ) + p->as = ADECQ; + else if(p->as == AADDL) + p->as = ADECL; + else + p->as = ADECW; + p->from = zprog.from; + } + else if(p->from.offset == 1){ + if(p->as == AADDQ) + p->as = AINCQ; + else if(p->as == AADDL) + p->as = AINCL; + else + p->as = AINCW; + p->from = zprog.from; + } + break; + + case ASUBL: + case ASUBQ: + case ASUBW: + if(p->from.type != D_CONST || needc(p->link)) + break; + if(p->from.offset == -1) { + if(p->as == ASUBQ) + p->as = AINCQ; + else if(p->as == ASUBL) + p->as = AINCL; + else + p->as = AINCW; + p->from = zprog.from; + } + else if(p->from.offset == 1){ + if(p->as == ASUBQ) + p->as = ADECQ; + else if(p->as == ASUBL) + p->as = ADECL; + else + p->as = ADECW; + p->from = zprog.from; + } + break; + } + } + if(t) + goto loop1; +} + +void +excise(Reg *r) +{ + Prog *p; + + p = r->prog; + p->as = ANOP; + p->from = zprog.from; + p->to = zprog.to; +} + +Reg* +uniqp(Reg *r) +{ + Reg *r1; + + r1 = r->p1; + if(r1 == R) { + r1 = r->p2; + if(r1 == R || r1->p2link != R) + return R; + } else + if(r->p2 != R) + return R; + return r1; +} + +Reg* +uniqs(Reg *r) +{ + Reg *r1; + + r1 = r->s1; + if(r1 == R) { + r1 = r->s2; + if(r1 == R) + return R; + } else + if(r->s2 != R) + return R; + return r1; +} + +int +regtyp(Adr *a) +{ + int t; + + t = a->type; + if(t >= D_AX && t <= D_R15) + return 1; + if(t >= D_X0 && t <= D_X0+15) + return 1; + return 0; +} + +/* + * the idea is to substitute + * one register for another + * from one MOV to another + * MOV a, R0 + * ADD b, R0 / no use of R1 + * MOV R0, R1 + * would be converted to + * MOV a, R1 + * ADD b, R1 + * MOV R1, R0 + * hopefully, then the former or latter MOV + * will be eliminated by copy propagation. + */ +int +subprop(Reg *r0) +{ + Prog *p; + Adr *v1, *v2; + Reg *r; + int t; + + p = r0->prog; + v1 = &p->from; + if(!regtyp(v1)) + return 0; + v2 = &p->to; + if(!regtyp(v2)) + return 0; + for(r=uniqp(r0); r!=R; r=uniqp(r)) { + if(uniqs(r) == R) + break; + p = r->prog; + switch(p->as) { + case ACALL: + return 0; + + case AIMULL: + case AIMULQ: + case AIMULW: + if(p->to.type != D_NONE) + break; + + case ADIVB: + case ADIVL: + case ADIVQ: + case ADIVW: + case AIDIVB: + case AIDIVL: + case AIDIVQ: + case AIDIVW: + case AIMULB: + case AMULB: + case AMULL: + case AMULQ: + case AMULW: + + case AROLB: + case AROLL: + case AROLQ: + case AROLW: + case ARORB: + case ARORL: + case ARORQ: + case ARORW: + case ASALB: + case ASALL: + case ASALQ: + case ASALW: + case ASARB: + case ASARL: + case ASARQ: + case ASARW: + case ASHLB: + case ASHLL: + case ASHLQ: + case ASHLW: + case ASHRB: + case ASHRL: + case ASHRQ: + case ASHRW: + + case AREP: + case AREPN: + + case ACWD: + case ACDQ: + case ACQO: + + case AMOVSL: + case AMOVSQ: + return 0; + + case AMOVL: + case AMOVQ: + if(p->to.type == v1->type) + goto gotit; + break; + } + if(copyau(&p->from, v2) || + copyau(&p->to, v2)) + break; + if(copysub(&p->from, v1, v2, 0) || + copysub(&p->to, v1, v2, 0)) + break; + } + return 0; + +gotit: + copysub(&p->to, v1, v2, 1); + if(debug['P']) { + print("gotit: %D->%D\n%P", v1, v2, r->prog); + if(p->from.type == v2->type) + print(" excise"); + print("\n"); + } + for(r=uniqs(r); r!=r0; r=uniqs(r)) { + p = r->prog; + copysub(&p->from, v1, v2, 1); + copysub(&p->to, v1, v2, 1); + if(debug['P']) + print("%P\n", r->prog); + } + t = v1->type; + v1->type = v2->type; + v2->type = t; + if(debug['P']) + print("%P last\n", r->prog); + return 1; +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success + */ +int +copyprop(Reg *r0) +{ + Prog *p; + Adr *v1, *v2; + Reg *r; + + p = r0->prog; + v1 = &p->from; + v2 = &p->to; + if(copyas(v1, v2)) + return 1; + for(r=firstr; r!=R; r=r->link) + r->active = 0; + return copy1(v1, v2, r0->s1, 0); +} + +int +copy1(Adr *v1, Adr *v2, Reg *r, int f) +{ + int t; + Prog *p; + + if(r->active) { + if(debug['P']) + print("act set; return 1\n"); + return 1; + } + r->active = 1; + if(debug['P']) + print("copy %D->%D f=%d\n", v1, v2, f); + for(; r != R; r = r->s1) { + p = r->prog; + if(debug['P']) + print("%P", p); + if(!f && uniqp(r) == R) { + f = 1; + if(debug['P']) + print("; merge; f=%d", f); + } + t = copyu(p, v2, A); + switch(t) { + case 2: /* rar, cant split */ + if(debug['P']) + print("; %D rar; return 0\n", v2); + return 0; + + case 3: /* set */ + if(debug['P']) + print("; %D set; return 1\n", v2); + return 1; + + case 1: /* used, substitute */ + case 4: /* use and set */ + if(f) { + if(!debug['P']) + return 0; + if(t == 4) + print("; %D used+set and f=%d; return 0\n", v2, f); + else + print("; %D used and f=%d; return 0\n", v2, f); + return 0; + } + if(copyu(p, v2, v1)) { + if(debug['P']) + print("; sub fail; return 0\n"); + return 0; + } + if(debug['P']) + print("; sub %D/%D", v2, v1); + if(t == 4) { + if(debug['P']) + print("; %D used+set; return 1\n", v2); + return 1; + } + break; + } + if(!f) { + t = copyu(p, v1, A); + if(!f && (t == 2 || t == 3 || t == 4)) { + f = 1; + if(debug['P']) + print("; %D set and !f; f=%d", v1, f); + } + } + if(debug['P']) + print("\n"); + if(r->s2) + if(!copy1(v1, v2, r->s2, f)) + return 0; + } + return 1; +} + +/* + * return + * 1 if v only used (and substitute), + * 2 if read-alter-rewrite + * 3 if set + * 4 if set and used + * 0 otherwise (not touched) + */ +int +copyu(Prog *p, Adr *v, Adr *s) +{ + + switch(p->as) { + + default: + if(debug['P']) + print("unknown op %A\n", p->as); + /* SBBL; ADCL; FLD1; SAHF */ + return 2; + + + case ANEGB: + case ANEGW: + case ANEGL: + case ANEGQ: + case ANOTB: + case ANOTW: + case ANOTL: + case ANOTQ: + if(copyas(&p->to, v)) + return 2; + break; + + case ALEAL: /* lhs addr, rhs store */ + case ALEAQ: + if(copyas(&p->from, v)) + return 2; + + + case ANOP: /* rhs store */ + case AMOVL: + case AMOVQ: + case AMOVBLSX: + case AMOVBLZX: + case AMOVBQSX: + case AMOVBQZX: + case AMOVLQSX: + case AMOVLQZX: + case AMOVWLSX: + case AMOVWLZX: + case AMOVWQSX: + case AMOVWQZX: + + case AMOVSS: + case AMOVSD: + case ACVTSD2SL: + case ACVTSD2SQ: + case ACVTSD2SS: + case ACVTSL2SD: + case ACVTSL2SS: + case ACVTSQ2SD: + case ACVTSQ2SS: + case ACVTSS2SD: + case ACVTSS2SL: + case ACVTSS2SQ: + case ACVTTSD2SL: + case ACVTTSD2SQ: + case ACVTTSS2SL: + case ACVTTSS2SQ: + if(copyas(&p->to, v)) { + if(s != A) + return copysub(&p->from, v, s, 1); + if(copyau(&p->from, v)) + return 4; + return 3; + } + goto caseread; + + case AROLB: + case AROLL: + case AROLQ: + case AROLW: + case ARORB: + case ARORL: + case ARORQ: + case ARORW: + case ASALB: + case ASALL: + case ASALQ: + case ASALW: + case ASARB: + case ASARL: + case ASARQ: + case ASARW: + case ASHLB: + case ASHLL: + case ASHLQ: + case ASHLW: + case ASHRB: + case ASHRL: + case ASHRQ: + case ASHRW: + if(copyas(&p->to, v)) + return 2; + if(copyas(&p->from, v)) + if(p->from.type == D_CX) + return 2; + goto caseread; + + case AADDB: /* rhs rar */ + case AADDL: + case AADDQ: + case AADDW: + case AANDB: + case AANDL: + case AANDQ: + case AANDW: + case ADECL: + case ADECQ: + case ADECW: + case AINCL: + case AINCQ: + case AINCW: + case ASUBB: + case ASUBL: + case ASUBQ: + case ASUBW: + case AORB: + case AORL: + case AORQ: + case AORW: + case AXORB: + case AXORL: + case AXORQ: + case AXORW: + case AMOVB: + case AMOVW: + + case AADDSD: + case AADDSS: + case ACMPSD: + case ACMPSS: + case ADIVSD: + case ADIVSS: + case AMAXSD: + case AMAXSS: + case AMINSD: + case AMINSS: + case AMULSD: + case AMULSS: + case ARCPSS: + case ARSQRTSS: + case ASQRTSD: + case ASQRTSS: + case ASUBSD: + case ASUBSS: + case AXORPD: + if(copyas(&p->to, v)) + return 2; + goto caseread; + + case ACMPL: /* read only */ + case ACMPW: + case ACMPB: + case ACMPQ: + + case ACOMISD: + case ACOMISS: + case AUCOMISD: + case AUCOMISS: + caseread: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + return copysub(&p->to, v, s, 1); + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + break; + + case AJGE: /* no reference */ + case AJNE: + case AJLE: + case AJEQ: + case AJHI: + case AJLS: + case AJMI: + case AJPL: + case AJGT: + case AJLT: + case AJCC: + case AJCS: + + case AADJSP: + case AWAIT: + case ACLD: + break; + + case AIMULL: + case AIMULQ: + case AIMULW: + if(p->to.type != D_NONE) { + if(copyas(&p->to, v)) + return 2; + goto caseread; + } + + case ADIVB: + case ADIVL: + case ADIVQ: + case ADIVW: + case AIDIVB: + case AIDIVL: + case AIDIVQ: + case AIDIVW: + case AIMULB: + case AMULB: + case AMULL: + case AMULQ: + case AMULW: + + case ACWD: + case ACDQ: + case ACQO: + if(v->type == D_AX || v->type == D_DX) + return 2; + goto caseread; + + case AMOVSL: + case AMOVSQ: + case AREP: + case AREPN: + if(v->type == D_CX || v->type == D_DI || v->type == D_SI) + return 2; + goto caseread; + + case AJMP: /* funny */ + if(s != A) { + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->to, v)) + return 1; + return 0; + + case ARET: /* funny */ + if(v->type == REGRET || v->type == FREGRET) + return 2; + if(s != A) + return 1; + return 3; + + case ACALL: /* funny */ + if(REGEXT && v->type <= REGEXT && v->type > exregoffset) + return 2; + if(REGARG && v->type == REGARG) + return 2; + + if(s != A) { + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->to, v)) + return 4; + return 3; + + case ATEXT: /* funny */ + if(REGARG && v->type == REGARG) + return 3; + return 0; + } + return 0; +} + +/* + * direct reference, + * could be set/use depending on + * semantics + */ +int +copyas(Adr *a, Adr *v) +{ + if(a->type != v->type) + return 0; + if(regtyp(v)) + return 1; + if(v->type == D_AUTO || v->type == D_PARAM) + if(v->offset == a->offset) + return 1; + return 0; +} + +/* + * either direct or indirect + */ +int +copyau(Adr *a, Adr *v) +{ + + if(copyas(a, v)) + return 1; + if(regtyp(v)) { + if(a->type-D_INDIR == v->type) + return 1; + if(a->index == v->type) + return 1; + } + return 0; +} + +/* + * substitute s for v in a + * return failure to substitute + */ +int +copysub(Adr *a, Adr *v, Adr *s, int f) +{ + int t; + + if(copyas(a, v)) { + t = s->type; + if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) { + if(f) + a->type = t; + } + return 0; + } + if(regtyp(v)) { + t = v->type; + if(a->type == t+D_INDIR) { + if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE) + return 1; /* can't use BP-base with index */ + if(f) + a->type = s->type+D_INDIR; +// return 0; + } + if(a->index == t) { + if(f) + a->index = s->type; + return 0; + } + return 0; + } + return 0; +} diff --git a/sys/src/cmd/6c/reg.c b/sys/src/cmd/6c/reg.c new file mode 100644 index 000000000..32b9abf5d --- /dev/null +++ b/sys/src/cmd/6c/reg.c @@ -0,0 +1,1356 @@ +#include "gc.h" + +Reg* +rega(void) +{ + Reg *r; + + r = freer; + if(r == R) { + r = alloc(sizeof(*r)); + } else + freer = r->link; + + *r = zreg; + return r; +} + +int +rcmp(const void *a1, const void *a2) +{ + Rgn *p1, *p2; + int c1, c2; + + p1 = (Rgn*)a1; + p2 = (Rgn*)a2; + c1 = p2->cost; + c2 = p1->cost; + if(c1 -= c2) + return c1; + return p2->varno - p1->varno; +} + +void +regopt(Prog *p) +{ + Reg *r, *r1, *r2; + Prog *p1; + int i, z; + long initpc, val, npc; + ulong vreg; + Bits bit; + struct + { + long m; + long c; + Reg* p; + } log5[6], *lp; + + firstr = R; + lastr = R; + nvar = 0; + regbits = RtoB(D_SP) | RtoB(D_AX) | RtoB(D_X0); + for(z=0; zm = val; + lp->c = 0; + lp->p = R; + val /= 5L; + lp++; + } + val = 0; + for(; p != P; p = p->link) { + switch(p->as) { + case ADATA: + case AGLOBL: + case ANAME: + case ASIGNAME: + continue; + } + r = rega(); + if(firstr == R) { + firstr = r; + lastr = r; + } else { + lastr->link = r; + r->p1 = lastr; + lastr->s1 = r; + lastr = r; + } + r->prog = p; + r->pc = val; + val++; + + lp = log5; + for(i=0; i<5; i++) { + lp->c--; + if(lp->c <= 0) { + lp->c = lp->m; + if(lp->p != R) + lp->p->log5 = r; + lp->p = r; + (lp+1)->c = 0; + break; + } + lp++; + } + + r1 = r->p1; + if(r1 != R) + switch(r1->prog->as) { + case ARET: + case AJMP: + case AIRETL: + case AIRETQ: + r->p1 = R; + r1->s1 = R; + } + + bit = mkvar(r, &p->from); + if(bany(&bit)) + switch(p->as) { + /* + * funny + */ + case ALEAL: + case ALEAQ: + for(z=0; zuse1.b[z] |= bit.b[z]; + break; + } + + bit = mkvar(r, &p->to); + if(bany(&bit)) + switch(p->as) { + default: + diag(Z, "reg: unknown op: %A", p->as); + break; + + /* + * right side read + */ + case ACMPB: + case ACMPL: + case ACMPQ: + case ACMPW: + case ACOMISS: + case ACOMISD: + case AUCOMISS: + case AUCOMISD: + for(z=0; zuse2.b[z] |= bit.b[z]; + break; + + /* + * right side write + */ + case ANOP: + case AMOVL: + case AMOVQ: + case AMOVB: + case AMOVW: + case AMOVBLSX: + case AMOVBLZX: + case AMOVBQSX: + case AMOVBQZX: + case AMOVLQSX: + case AMOVLQZX: + case AMOVWLSX: + case AMOVWLZX: + case AMOVWQSX: + case AMOVWQZX: + + case AMOVSS: + case AMOVSD: + case ACVTSD2SL: + case ACVTSD2SQ: + case ACVTSD2SS: + case ACVTSL2SD: + case ACVTSL2SS: + case ACVTSQ2SD: + case ACVTSQ2SS: + case ACVTSS2SD: + case ACVTSS2SL: + case ACVTSS2SQ: + case ACVTTSD2SL: + case ACVTTSD2SQ: + case ACVTTSS2SL: + case ACVTTSS2SQ: + for(z=0; zset.b[z] |= bit.b[z]; + break; + + /* + * right side read+write + */ + case AADDB: + case AADDL: + case AADDQ: + case AADDW: + case AANDB: + case AANDL: + case AANDQ: + case AANDW: + case ASUBB: + case ASUBL: + case ASUBQ: + case ASUBW: + case AORB: + case AORL: + case AORQ: + case AORW: + case AXORB: + case AXORL: + case AXORQ: + case AXORW: + case ASALB: + case ASALL: + case ASALQ: + case ASALW: + case ASARB: + case ASARL: + case ASARQ: + case ASARW: + case AROLB: + case AROLL: + case AROLQ: + case AROLW: + case ARORB: + case ARORL: + case ARORQ: + case ARORW: + case ASHLB: + case ASHLL: + case ASHLQ: + case ASHLW: + case ASHRB: + case ASHRL: + case ASHRQ: + case ASHRW: + case AIMULL: + case AIMULQ: + case AIMULW: + case ANEGL: + case ANEGQ: + case ANOTL: + case ANOTQ: + case AADCL: + case AADCQ: + case ASBBL: + case ASBBQ: + + case AADDSD: + case AADDSS: + case ACMPSD: + case ACMPSS: + case ADIVSD: + case ADIVSS: + case AMAXSD: + case AMAXSS: + case AMINSD: + case AMINSS: + case AMULSD: + case AMULSS: + case ARCPSS: + case ARSQRTSS: + case ASQRTSD: + case ASQRTSS: + case ASUBSD: + case ASUBSS: + case AXORPD: + for(z=0; zset.b[z] |= bit.b[z]; + r->use2.b[z] |= bit.b[z]; + } + break; + + /* + * funny + */ + case ACALL: + for(z=0; zas) { + case AIMULL: + case AIMULQ: + case AIMULW: + if(p->to.type != D_NONE) + break; + + case AIDIVB: + case AIDIVL: + case AIDIVQ: + case AIDIVW: + case AIMULB: + case ADIVB: + case ADIVL: + case ADIVQ: + case ADIVW: + case AMULB: + case AMULL: + case AMULQ: + case AMULW: + + case ACWD: + case ACDQ: + case ACQO: + r->regu |= RtoB(D_AX) | RtoB(D_DX); + break; + + case AREP: + case AREPN: + case ALOOP: + case ALOOPEQ: + case ALOOPNE: + r->regu |= RtoB(D_CX); + break; + + case AMOVSB: + case AMOVSL: + case AMOVSQ: + case AMOVSW: + case ACMPSB: + case ACMPSL: + case ACMPSQ: + case ACMPSW: + r->regu |= RtoB(D_SI) | RtoB(D_DI); + break; + + case ASTOSB: + case ASTOSL: + case ASTOSQ: + case ASTOSW: + case ASCASB: + case ASCASL: + case ASCASQ: + case ASCASW: + r->regu |= RtoB(D_AX) | RtoB(D_DI); + break; + + case AINSB: + case AINSL: + case AINSW: + case AOUTSB: + case AOUTSL: + case AOUTSW: + r->regu |= RtoB(D_DI) | RtoB(D_DX); + break; + } + } + if(firstr == R) + return; + initpc = pc - val; + npc = val; + + /* + * pass 2 + * turn branch references to pointers + * build back pointers + */ + for(r = firstr; r != R; r = r->link) { + p = r->prog; + if(p->to.type == D_BRANCH) { + val = p->to.offset - initpc; + r1 = firstr; + while(r1 != R) { + r2 = r1->log5; + if(r2 != R && val >= r2->pc) { + r1 = r2; + continue; + } + if(r1->pc == val) + break; + r1 = r1->link; + } + if(r1 == R) { + nearln = p->lineno; + diag(Z, "ref not found\n%P", p); + continue; + } + if(r1 == r) { + nearln = p->lineno; + diag(Z, "ref to self\n%P", p); + continue; + } + r->s2 = r1; + r->p2link = r1->p2; + r1->p2 = r; + } + } + if(debug['R']) { + p = firstr->prog; + print("\n%L %D\n", p->lineno, &p->from); + } + + /* + * pass 2.5 + * find looping structure + */ + for(r = firstr; r != R; r = r->link) + r->active = 0; + change = 0; + loopit(firstr, npc); + if(debug['R'] && debug['v']) { + print("\nlooping structure:\n"); + for(r = firstr; r != R; r = r->link) { + print("%ld:%P", r->loop, r->prog); + for(z=0; zuse1.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; zrefahead.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; zset.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; zact.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; ivarno); + vreg = paint2(rgp->enter, rgp->varno); + vreg = allreg(vreg, rgp); + if(debug['R']) { + print("%L$%d %R: %B\n", + rgp->enter->prog->lineno, + rgp->cost, + rgp->regno, + bit); + } + if(rgp->regno != 0) + paint3(rgp->enter, rgp->varno, vreg, rgp->regno); + rgp++; + } + /* + * pass 7 + * peep-hole on basic block + */ + if(!debug['R'] || debug['P']) + peep(); + + /* + * pass 8 + * recalculate pc + */ + val = initpc; + for(r = firstr; r != R; r = r1) { + r->pc = val; + p = r->prog; + p1 = P; + r1 = r->link; + if(r1 != R) + p1 = r1->prog; + for(; p != p1; p = p->link) { + switch(p->as) { + default: + val++; + break; + + case ANOP: + case ADATA: + case AGLOBL: + case ANAME: + case ASIGNAME: + break; + } + } + } + pc = val; + + /* + * fix up branches + */ + if(debug['R']) + if(bany(&addrs)) + print("addrs: %B\n", addrs); + + r1 = 0; /* set */ + for(r = firstr; r != R; r = r->link) { + p = r->prog; + if(p->to.type == D_BRANCH) + p->to.offset = r->s2->pc; + r1 = r; + } + + /* + * last pass + * eliminate nops + * free aux structures + */ + for(p = firstr->prog; p != P; p = p->link){ + while(p->link && p->link->as == ANOP) + p->link = p->link->link; + } + if(r1 != R) { + r1->link = freer; + freer = firstr; + } +} + +/* + * add mov b,rn + * just after r + */ +void +addmove(Reg *r, int bn, int rn, int f) +{ + Prog *p, *p1; + Adr *a; + Var *v; + + p1 = alloc(sizeof(*p1)); + *p1 = zprog; + p = r->prog; + + p1->link = p->link; + p->link = p1; + p1->lineno = p->lineno; + + v = var + bn; + + a = &p1->to; + a->sym = v->sym; + a->offset = v->offset; + a->etype = v->etype; + a->type = v->name; + + p1->as = AMOVL; + if(v->etype == TCHAR || v->etype == TUCHAR) + p1->as = AMOVB; + if(v->etype == TSHORT || v->etype == TUSHORT) + p1->as = AMOVW; + if(v->etype == TVLONG || v->etype == TUVLONG || v->etype == TIND) + p1->as = AMOVQ; + if(v->etype == TFLOAT) + p1->as = AMOVSS; + if(v->etype == TDOUBLE) + p1->as = AMOVSD; + + p1->from.type = rn; + if(!f) { + p1->from = *a; + *a = zprog.from; + a->type = rn; + if(v->etype == TUCHAR) + p1->as = AMOVB; + if(v->etype == TUSHORT) + p1->as = AMOVW; + } + if(debug['R']) + print("%P\t.a%P\n", p, p1); +} + +ulong +doregbits(int r) +{ + ulong b; + + b = 0; + if(r >= D_INDIR) + r -= D_INDIR; + if(r >= D_AX && r <= D_R15) + b |= RtoB(r); + else + if(r >= D_AL && r <= D_R15B) + b |= RtoB(r-D_AL+D_AX); + else + if(r >= D_AH && r <= D_BH) + b |= RtoB(r-D_AH+D_AX); + else + if(r >= D_X0 && r <= D_X0+15) + b |= FtoB(r); + return b; +} + +Bits +mkvar(Reg *r, Adr *a) +{ + Var *v; + int i, t, n, et, z; + long o; + Bits bit; + Sym *s; + + /* + * mark registers used + */ + t = a->type; + r->regu |= doregbits(t); + r->regu |= doregbits(a->index); + + switch(t) { + default: + goto none; + case D_ADDR: + a->type = a->index; + bit = mkvar(r, a); + for(z=0; ztype = 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; isym) + 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; zetype != et || !(typechlpfd[et] || typev[et])) /* funny punning */ + for(z=0; zp1) { + for(z=0; zrefahead.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; zset.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; zrefbehind.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; zcalbehind.b[z] & r1->calahead.b[z]); + if(r1->s2 != R) + synch(r1->s2, dif); + } +} + +ulong +allreg(ulong b, Rgn *r) +{ + Var *v; + int i; + + v = var + r->varno; + r->regno = 0; + switch(v->etype) { + + default: + diag(Z, "unknown etype %d/%d", bitno(b), v->etype); + break; + + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TIND: + case TARRAY: + i = BtoR(~b); + if(i && r->cost > 0) { + r->regno = i; + return RtoB(i); + } + break; + + case TDOUBLE: + case TFLOAT: + i = BtoF(~b); + if(i && r->cost > 0) { + r->regno = i; + return FtoB(i); + } + break; + } + return 0; +} + +void +paint1(Reg *r, int bn) +{ + Reg *r1; + Prog *p; + int z; + ulong bb; + + z = bn/32; + bb = 1L<<(bn%32); + if(r->act.b[z] & bb) + return; + for(;;) { + if(!(r->refbehind.b[z] & bb)) + break; + r1 = r->p1; + if(r1 == R) + break; + if(!(r1->refahead.b[z] & bb)) + break; + if(r1->act.b[z] & bb) + break; + r = r1; + } + + if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) { + change -= CLOAD * r->loop; + if(debug['R'] && debug['v']) + print("%ld%P\tld %B $%d\n", r->loop, + r->prog, blsh(bn), change); + } + for(;;) { + r->act.b[z] |= bb; + p = r->prog; + + if(r->use1.b[z] & bb) { + change += CREF * r->loop; + if(debug['R'] && debug['v']) + print("%ld%P\tu1 %B $%d\n", r->loop, + p, blsh(bn), change); + } + + if((r->use2.b[z]|r->set.b[z]) & bb) { + change += CREF * r->loop; + if(debug['R'] && debug['v']) + print("%ld%P\tu2 %B $%d\n", r->loop, + p, blsh(bn), change); + } + + if(STORE(r) & r->regdiff.b[z] & bb) { + change -= CLOAD * r->loop; + if(debug['R'] && debug['v']) + print("%ld%P\tst %B $%d\n", r->loop, + p, blsh(bn), change); + } + + if(r->refbehind.b[z] & bb) + for(r1 = r->p2; r1 != R; r1 = r1->p2link) + if(r1->refahead.b[z] & bb) + paint1(r1, bn); + + if(!(r->refahead.b[z] & bb)) + break; + r1 = r->s2; + if(r1 != R) + if(r1->refbehind.b[z] & bb) + paint1(r1, bn); + r = r->s1; + if(r == R) + break; + if(r->act.b[z] & bb) + break; + if(!(r->refbehind.b[z] & bb)) + break; + } +} + +ulong +regset(Reg *r, ulong bb) +{ + ulong b, set; + Adr v; + int c; + + set = 0; + v = zprog.from; + while(b = bb & ~(bb-1)) { + v.type = b & 0xFFFF? BtoR(b): BtoF(b); + if(v.type == 0) + diag(Z, "zero v.type for %#lux", b); + c = copyu(r->prog, &v, A); + if(c == 3) + set |= b; + bb &= ~b; + } + return set; +} + +ulong +reguse(Reg *r, ulong bb) +{ + ulong b, set; + Adr v; + int c; + + set = 0; + v = zprog.from; + while(b = bb & ~(bb-1)) { + v.type = b & 0xFFFF? BtoR(b): BtoF(b); + c = copyu(r->prog, &v, A); + if(c == 1 || c == 2 || c == 4) + set |= b; + bb &= ~b; + } + return set; +} + +ulong +paint2(Reg *r, int bn) +{ + Reg *r1; + int z; + ulong bb, vreg, x; + + z = bn/32; + bb = 1L << (bn%32); + vreg = regbits; + if(!(r->act.b[z] & bb)) + return vreg; + for(;;) { + if(!(r->refbehind.b[z] & bb)) + break; + r1 = r->p1; + if(r1 == R) + break; + if(!(r1->refahead.b[z] & bb)) + break; + if(!(r1->act.b[z] & bb)) + break; + r = r1; + } + for(;;) { + r->act.b[z] &= ~bb; + + vreg |= r->regu; + + if(r->refbehind.b[z] & bb) + for(r1 = r->p2; r1 != R; r1 = r1->p2link) + if(r1->refahead.b[z] & bb) + vreg |= paint2(r1, bn); + + if(!(r->refahead.b[z] & bb)) + break; + r1 = r->s2; + if(r1 != R) + if(r1->refbehind.b[z] & bb) + vreg |= paint2(r1, bn); + r = r->s1; + if(r == R) + break; + if(!(r->act.b[z] & bb)) + break; + if(!(r->refbehind.b[z] & bb)) + break; + } + + bb = vreg; + for(; r; r=r->s1) { + x = r->regu & ~bb; + if(x) { + vreg |= reguse(r, x); + bb |= regset(r, x); + } + } + return vreg; +} + +void +paint3(Reg *r, int bn, long rb, int rn) +{ + Reg *r1; + Prog *p; + int z; + ulong bb; + + z = bn/32; + bb = 1L << (bn%32); + if(r->act.b[z] & bb) + return; + for(;;) { + if(!(r->refbehind.b[z] & bb)) + break; + r1 = r->p1; + if(r1 == R) + break; + if(!(r1->refahead.b[z] & bb)) + break; + if(r1->act.b[z] & bb) + break; + r = r1; + } + + if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) + addmove(r, bn, rn, 0); + for(;;) { + r->act.b[z] |= bb; + p = r->prog; + + if(r->use1.b[z] & bb) { + if(debug['R']) + print("%P", p); + addreg(&p->from, rn); + if(debug['R']) + print("\t.c%P\n", p); + } + if((r->use2.b[z]|r->set.b[z]) & bb) { + if(debug['R']) + print("%P", p); + addreg(&p->to, rn); + if(debug['R']) + print("\t.c%P\n", p); + } + + if(STORE(r) & r->regdiff.b[z] & bb) + addmove(r, bn, rn, 1); + r->regu |= rb; + + if(r->refbehind.b[z] & bb) + for(r1 = r->p2; r1 != R; r1 = r1->p2link) + if(r1->refahead.b[z] & bb) + paint3(r1, bn, rb, rn); + + if(!(r->refahead.b[z] & bb)) + break; + r1 = r->s2; + if(r1 != R) + if(r1->refbehind.b[z] & bb) + paint3(r1, bn, rb, rn); + r = r->s1; + if(r == R) + break; + if(r->act.b[z] & bb) + break; + if(!(r->refbehind.b[z] & bb)) + break; + } +} + +void +addreg(Adr *a, int rn) +{ + + a->sym = 0; + a->offset = 0; + a->type = rn; +} + +long +RtoB(int r) +{ + + if(r < D_AX || r > D_R15) + return 0; + return 1L << (r-D_AX); +} + +int +BtoR(long b) +{ + + b &= 0xffffL; + if(b == 0) + return 0; + return bitno(b) + D_AX; +} + +/* + * bit reg + * 16 X5 + * 17 X6 + * 18 X7 + */ +long +FtoB(int f) +{ + if(f < FREGMIN || f > FREGEXT) + return 0; + return 1L << (f - FREGMIN + 16); +} + +int +BtoF(long b) +{ + + b &= 0x70000L; + if(b == 0) + return 0; + return bitno(b) - 16 + FREGMIN; +} diff --git a/sys/src/cmd/6c/sgen.c b/sys/src/cmd/6c/sgen.c new file mode 100644 index 000000000..a7d751c0f --- /dev/null +++ b/sys/src/cmd/6c/sgen.c @@ -0,0 +1,435 @@ +#include "gc.h" + +void +noretval(int n) +{ + + if(n & 1) { + gins(ANOP, Z, Z); + p->to.type = REGRET; + } + if(n & 2) { + gins(ANOP, Z, Z); + p->to.type = FREGRET; + } +} + +/* welcome to commute */ +static void +commute(Node *n) +{ + Node *l, *r; + + l = n->left; + r = n->right; + if(r->complex > l->complex) { + n->left = r; + n->right = l; + } +} + +void +indexshift(Node *n) +{ + int g; + + if(!typechlpv[n->type->etype]) + return; + simplifyshift(n); + if(n->op == OASHL && n->right->op == OCONST){ + g = vconst(n->right); + if(g >= 0 && g <= 3) + n->addable = 7; + } +} + +/* + * calculate addressability as follows + * NAME ==> 10/11 name+value(SB/SP) + * REGISTER ==> 12 register + * CONST ==> 20 $value + * *(20) ==> 21 value + * &(10) ==> 13 $name+value(SB) + * &(11) ==> 1 $name+value(SP) + * (13) + (20) ==> 13 fold constants + * (1) + (20) ==> 1 fold constants + * *(13) ==> 10 back to name + * *(1) ==> 11 back to name + * + * (20) * (X) ==> 7 multiplier in indexing + * (X,7) + (13,1) ==> 8 adder in indexing (addresses) + * (8) ==> &9(OINDEX) index, almost addressable + * + * calculate complexity (number of registers) + */ +void +xcom(Node *n) +{ + Node *l, *r; + int g; + + if(n == Z) + return; + l = n->left; + r = n->right; + n->complex = 0; + n->addable = 0; + switch(n->op) { + case OCONST: + n->addable = 20; + break; + + case ONAME: + n->addable = 10; + if(n->class == CPARAM || n->class == CAUTO) + n->addable = 11; + break; + + case OREGISTER: + n->addable = 12; + break; + + case OINDREG: + n->addable = 12; + break; + + case OADDR: + xcom(l); + if(l->addable == 10) + n->addable = 13; + else + if(l->addable == 11) + n->addable = 1; + break; + + case OADD: + xcom(l); + xcom(r); + if(n->type->etype != TIND) + break; + + switch(r->addable) { + case 20: + switch(l->addable) { + case 1: + case 13: + commadd: + l->type = n->type; + *n = *l; + l = new(0, Z, Z); + *l = *(n->left); + l->xoffset += r->vconst; + n->left = l; + r = n->right; + goto brk; + } + break; + + case 1: + case 13: + case 10: + case 11: + /* l is the base, r is the index */ + if(l->addable != 20) + n->addable = 8; + break; + } + switch(l->addable) { + case 20: + switch(r->addable) { + case 13: + case 1: + r = n->left; + l = n->right; + n->left = l; + n->right = r; + goto commadd; + } + break; + + case 13: + case 1: + case 10: + case 11: + /* r is the base, l is the index */ + if(r->addable != 20) + n->addable = 8; + break; + } + if(n->addable == 8 && !side(n)) { + indx(n); + l = new1(OINDEX, idx.basetree, idx.regtree); + l->scale = idx.scale; + l->addable = 9; + l->complex = l->right->complex; + l->type = l->left->type; + n->op = OADDR; + n->left = l; + n->right = Z; + n->addable = 8; + break; + } + break; + + case OINDEX: + xcom(l); + xcom(r); + n->addable = 9; + break; + + case OIND: + xcom(l); + if(l->op == OADDR) { + l = l->left; + l->type = n->type; + *n = *l; + return; + } + switch(l->addable) { + case 20: + n->addable = 21; + break; + case 1: + n->addable = 11; + break; + case 13: + n->addable = 10; + break; + } + break; + + case OASHL: + xcom(l); + xcom(r); + indexshift(n); + break; + + case OMUL: + case OLMUL: + xcom(l); + xcom(r); + g = vlog(l); + if(g >= 0) { + n->left = r; + n->right = l; + l = r; + r = n->right; + } + g = vlog(r); + if(g >= 0) { + n->op = OASHL; + r->vconst = g; + r->type = types[TINT]; + indexshift(n); + break; + } + commute(n); + break; + + case OASLDIV: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OASLSHR; + r->vconst = g; + r->type = types[TINT]; + } + break; + + case OLDIV: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OLSHR; + r->vconst = g; + r->type = types[TINT]; + indexshift(n); + break; + } + break; + + case OASLMOD: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OASAND; + r->vconst--; + } + break; + + case OLMOD: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OAND; + r->vconst--; + } + break; + + case OASMUL: + case OASLMUL: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OASASHL; + r->vconst = g; + } + break; + + case OLSHR: + case OASHR: + xcom(l); + xcom(r); + indexshift(n); + break; + + default: + if(l != Z) + xcom(l); + if(r != Z) + xcom(r); + break; + } +brk: + if(n->addable >= 10) + return; + if(l != Z) + n->complex = l->complex; + if(r != Z) { + if(r->complex == n->complex) + n->complex = r->complex+1; + else + if(r->complex > n->complex) + n->complex = r->complex; + } + if(n->complex == 0) + n->complex++; + + switch(n->op) { + + case OFUNC: + n->complex = FNX; + break; + + case OCAST: + if(l->type->etype == TUVLONG && typefd[n->type->etype]) + n->complex += 2; + break; + + case OLMOD: + case OMOD: + case OLMUL: + case OLDIV: + case OMUL: + case ODIV: + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + if(r->complex >= l->complex) { + n->complex = l->complex + 3; + if(r->complex > n->complex) + n->complex = r->complex; + } else { + n->complex = r->complex + 3; + if(l->complex > n->complex) + n->complex = l->complex; + } + break; + + case OLSHR: + case OASHL: + case OASHR: + case OASLSHR: + case OASASHL: + case OASASHR: + if(r->complex >= l->complex) { + n->complex = l->complex + 2; + if(r->complex > n->complex) + n->complex = r->complex; + } else { + n->complex = r->complex + 2; + if(l->complex > n->complex) + n->complex = l->complex; + } + break; + + case OADD: + case OXOR: + case OAND: + case OOR: + /* + * immediate operators, make const on right + */ + if(l->op == OCONST) { + n->left = r; + n->right = l; + } + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + /* + * compare operators, make const on left + */ + if(r->op == OCONST) { + n->left = r; + n->right = l; + n->op = invrel[relindex(n->op)]; + } + break; + } +} + +void +indx(Node *n) +{ + Node *l, *r; + + if(debug['x']) + prtree(n, "indx"); + + l = n->left; + r = n->right; + if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) { + n->right = l; + n->left = r; + l = r; + r = n->right; + } + if(l->addable != 7) { + idx.regtree = l; + idx.scale = 1; + } else + if(l->right->addable == 20) { + idx.regtree = l->left; + idx.scale = 1 << l->right->vconst; + } else + if(l->left->addable == 20) { + idx.regtree = l->right; + idx.scale = 1 << l->left->vconst; + } else + diag(n, "bad index"); + + idx.basetree = r; + if(debug['x']) { + print("scale = %d\n", idx.scale); + prtree(idx.regtree, "index"); + prtree(idx.basetree, "base"); + } +} diff --git a/sys/src/cmd/6c/swt.c b/sys/src/cmd/6c/swt.c new file mode 100644 index 000000000..b201c9cae --- /dev/null +++ b/sys/src/cmd/6c/swt.c @@ -0,0 +1,530 @@ +#include "gc.h" + +void +swit1(C1 *q, int nc, long def, Node *n) +{ + C1 *r; + int i; + Prog *sp; + + if(nc < 5) { + for(i=0; ival); + gcmp(OEQ, n, q->val); + patch(p, q->label); + q++; + } + gbranch(OGOTO); + patch(p, def); + return; + } + i = nc / 2; + r = q+i; + if(debug['W']) + print("case > %.8llux\n", r->val); + gcmp(OGT, n, r->val); + sp = p; + gbranch(OGOTO); + p->as = AJEQ; + patch(p, r->label); + swit1(q, i, def, n); + + if(debug['W']) + print("case < %.8llux\n", r->val); + patch(sp, pc); + swit1(r+1, nc-i-1, def, n); +} + +void +bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) +{ + int sh; + long v; + Node *l; + + /* + * n1 gets adjusted/masked value + * n2 gets address of cell + * n3 gets contents of cell + */ + l = b->left; + if(n2 != Z) { + regalloc(n1, l, nn); + reglcgen(n2, l, Z); + regalloc(n3, l, Z); + gmove(n2, n3); + gmove(n3, n1); + } else { + regalloc(n1, l, nn); + cgen(l, n1); + } + if(b->type->shift == 0 && typeu[b->type->etype]) { + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, tfield, nodconst(v), n1); + } else { + sh = 32 - b->type->shift - b->type->nbits; + if(sh > 0) + gopcode(OASHL, tfield, nodconst(sh), n1); + sh += b->type->shift; + if(sh > 0) + if(typeu[b->type->etype]) + gopcode(OLSHR, tfield, nodconst(sh), n1); + else + gopcode(OASHR, tfield, nodconst(sh), n1); + } +} + +void +bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) +{ + long v; + Node nod; + int sh; + + regalloc(&nod, b->left, Z); + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, types[TLONG], nodconst(v), n1); + gmove(n1, &nod); + if(nn != Z) + gmove(n1, nn); + sh = b->type->shift; + if(sh > 0) + gopcode(OASHL, types[TLONG], nodconst(sh), &nod); + v <<= sh; + gopcode(OAND, types[TLONG], nodconst(~v), n3); + gopcode(OOR, types[TLONG], n3, &nod); + gmove(&nod, n2); + + regfree(&nod); + regfree(n1); + regfree(n2); + regfree(n3); +} + +long +outstring(char *s, long n) +{ + long r; + + if(suppress) + return nstring; + r = nstring; + while(n) { + string[mnstring] = *s++; + mnstring++; + nstring++; + if(mnstring >= NSNAME) { + gpseudo(ADATA, symstring, nodconst(0L)); + p->from.offset += nstring - NSNAME; + p->from.scale = NSNAME; + p->to.type = D_SCONST; + memmove(p->to.sval, string, NSNAME); + mnstring = 0; + } + n--; + } + return r; +} + +void +sextern(Sym *s, Node *a, long o, long w) +{ + long e, lw; + + for(e=0; efrom.offset += o+e; + p->from.scale = lw; + p->to.type = D_SCONST; + memmove(p->to.sval, a->cstring+e, lw); + } +} + +void +gextern(Sym *s, Node *a, long o, long w) +{ + if(0 && a->op == OCONST && typev[a->type->etype]) { + gpseudo(ADATA, s, lo64(a)); + p->from.offset += o; + p->from.scale = 4; + gpseudo(ADATA, s, hi64(a)); + p->from.offset += o + 4; + p->from.scale = 4; + return; + } + gpseudo(ADATA, s, a); + p->from.offset += o; + p->from.scale = w; + switch(p->to.type) { + default: + p->to.index = p->to.type; + p->to.type = D_ADDR; + case D_CONST: + case D_FCONST: + case D_ADDR: + break; + } +} + +void zname(Biobuf*, Sym*, int); +void zaddr(Biobuf*, Adr*, int); +void outhist(Biobuf*); + +void +outcode(void) +{ + struct { Sym *sym; short type; } h[NSYM]; + Prog *p; + Sym *s; + int f, sf, st, t, sym; + Biobuf b; + + if(debug['S']) { + for(p = firstp; p != P; p = p->link) + if(p->as != ADATA && p->as != AGLOBL) + pc--; + for(p = firstp; p != P; p = p->link) { + print("%P\n", p); + if(p->as != ADATA && p->as != AGLOBL) + pc++; + } + } + f = open(outfile, OWRITE); + if(f < 0) { + diag(Z, "cannot open %s", outfile); + return; + } + Binit(&b, f, OWRITE); + Bseek(&b, 0L, 2); + outhist(&b); + for(sym=0; symlink) { + jackpot: + sf = 0; + s = p->from.sym; + while(s != S) { + sf = s->sym; + if(sf < 0 || sf >= NSYM) + sf = 0; + t = p->from.type; + if(t == D_ADDR) + t = p->from.index; + if(h[sf].type == t) + if(h[sf].sym == s) + break; + s->sym = sym; + zname(&b, s, t); + h[sym].sym = s; + h[sym].type = t; + sf = sym; + sym++; + if(sym >= NSYM) + sym = 1; + break; + } + st = 0; + s = p->to.sym; + while(s != S) { + st = s->sym; + if(st < 0 || st >= NSYM) + st = 0; + t = p->to.type; + if(t == D_ADDR) + t = p->to.index; + if(h[st].type == t) + if(h[st].sym == s) + break; + s->sym = sym; + zname(&b, s, t); + h[sym].sym = s; + h[sym].type = t; + st = sym; + sym++; + if(sym >= NSYM) + sym = 1; + if(st == sf) + goto jackpot; + break; + } + Bputc(&b, p->as); + Bputc(&b, p->as>>8); + Bputc(&b, p->lineno); + Bputc(&b, p->lineno>>8); + Bputc(&b, p->lineno>>16); + Bputc(&b, p->lineno>>24); + zaddr(&b, &p->from, sf); + zaddr(&b, &p->to, st); + } + Bflush(&b); + close(f); + firstp = P; + lastp = P; +} + +void +outhist(Biobuf *b) +{ + Hist *h; + char *p, *q, *op, c; + Prog pg; + int n; + + pg = zprog; + pg.as = AHISTORY; + c = pathchar(); + for(h = hist; h != H; h = h->link) { + p = h->name; + op = 0; + /* on windows skip drive specifier in pathname */ + if(systemtype(Windows) && p && p[1] == ':'){ + p += 2; + c = *p; + } + if(p && p[0] != c && h->offset == 0 && pathname){ + /* on windows skip drive specifier in pathname */ + if(systemtype(Windows) && pathname[1] == ':') { + op = p; + p = pathname+2; + c = *p; + } else if(pathname[0] == c){ + op = p; + p = pathname; + } + } + while(p) { + q = utfrune(p, c); + if(q) { + n = q-p; + if(n == 0){ + n = 1; /* leading "/" */ + *p = '/'; /* don't emit "\" on windows */ + } + q++; + } else { + n = strlen(p); + q = 0; + } + if(n) { + Bputc(b, ANAME); + Bputc(b, ANAME>>8); + Bputc(b, D_FILE); + Bputc(b, 1); + Bputc(b, '<'); + Bwrite(b, p, n); + Bputc(b, 0); + } + p = q; + if(p == 0 && op) { + p = op; + op = 0; + } + } + pg.lineno = h->line; + pg.to.type = zprog.to.type; + pg.to.offset = h->offset; + if(h->offset) + pg.to.type = D_CONST; + + Bputc(b, pg.as); + Bputc(b, pg.as>>8); + Bputc(b, pg.lineno); + Bputc(b, pg.lineno>>8); + Bputc(b, pg.lineno>>16); + Bputc(b, pg.lineno>>24); + zaddr(b, &pg.from, 0); + zaddr(b, &pg.to, 0); + } +} + +void +zname(Biobuf *b, Sym *s, int t) +{ + char *n; + ulong sig; + + if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ + sig = sign(s); + Bputc(b, ASIGNAME); + Bputc(b, ASIGNAME>>8); + Bputc(b, sig); + Bputc(b, sig>>8); + Bputc(b, sig>>16); + Bputc(b, sig>>24); + s->sig = SIGDONE; + } + else{ + Bputc(b, ANAME); /* as */ + Bputc(b, ANAME>>8); /* as */ + } + Bputc(b, t); /* type */ + Bputc(b, s->sym); /* sym */ + n = s->name; + while(*n) { + Bputc(b, *n); + n++; + } + Bputc(b, 0); +} + +void +zaddr(Biobuf *b, Adr *a, int s) +{ + long l; + int i, t; + char *n; + Ieee e; + + t = 0; + if(a->index != D_NONE || a->scale != 0) + t |= T_INDEX; + if(s != 0) + t |= T_SYM; + + switch(a->type) { + default: + t |= T_TYPE; + case D_NONE: + if(a->offset != 0) { + t |= T_OFFSET; + l = a->offset; + if((vlong)l != a->offset) + t |= T_64; + } + break; + case D_FCONST: + t |= T_FCONST; + break; + case D_SCONST: + t |= T_SCONST; + break; + } + Bputc(b, t); + + if(t & T_INDEX) { /* implies index, scale */ + Bputc(b, a->index); + Bputc(b, a->scale); + } + if(t & T_OFFSET) { /* implies offset */ + l = a->offset; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + if(t & T_64) { + l = a->offset>>32; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + } + } + if(t & T_SYM) /* implies sym */ + Bputc(b, s); + if(t & T_FCONST) { + ieeedtod(&e, a->dval); + l = e.l; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + l = e.h; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + return; + } + if(t & T_SCONST) { + n = a->sval; + for(i=0; itype); +} + +long +align(long i, Type *t, int op) +{ + long o; + Type *v; + int w; + + o = i; + w = 1; + switch(op) { + default: + diag(Z, "unknown align opcode %d", op); + break; + + case Asu2: /* padding at end of a struct */ + w = SZ_VLONG; + if(packflg) + w = packflg; + break; + + case Ael1: /* initial align of struct element */ + for(v=t; v->etype==TARRAY; v=v->link) + ; + w = ewidth[v->etype]; + if(w <= 0 || w >= SZ_VLONG) + w = SZ_VLONG; + if(packflg) + w = packflg; + break; + + case Ael2: /* width of a struct element */ + o += t->width; + break; + + case Aarg0: /* initial passbyptr argument in arg list */ + if(typesu[t->etype]) { + o = align(o, types[TIND], Aarg1); + o = align(o, types[TIND], Aarg2); + } + break; + + case Aarg1: /* initial align of parameter */ + w = ewidth[t->etype]; + if(w <= 0 || w >= SZ_VLONG) { + w = SZ_VLONG; + break; + } + w = 1; /* little endian no adjustment */ + break; + + case Aarg2: /* width of a parameter */ + o += t->width; + w = SZ_VLONG; + 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_VLONG-1; + if(v > max) + max = round(v, SZ_VLONG); + return max; +} diff --git a/sys/src/cmd/6c/sys.c b/sys/src/cmd/6c/sys.c new file mode 100644 index 000000000..abdc42b04 --- /dev/null +++ b/sys/src/cmd/6c/sys.c @@ -0,0 +1,106 @@ +#include +#include +#include "/sys/src/libc/9syscall/sys.h" + +vlong _sysargs[6*4]; +vlong _callsys(void); + +/* + * syscalls + */ + +int +getpid(void) +{ + _sysargs[0] = -1; + return _callsys(); +} + +long +pread(int fd, void *a, long n, vlong) +{ + _sysargs[0] = PREAD; + _sysargs[1] = fd; + _sysargs[2] = (vlong)a; + _sysargs[3] = n; + return _callsys(); +} + +long +pwrite(int fd, void *a, long n, vlong) +{ + _sysargs[0] = PWRITE; + _sysargs[1] = fd; + _sysargs[2] = (vlong)a; + _sysargs[3] = n; + return _callsys(); +} + +int +close(int fd) +{ + _sysargs[0] = CLOSE; + _sysargs[1] = fd; + return _callsys(); +} + +int +open(char *name, int mode) +{ + _sysargs[0] = OPEN; + _sysargs[1] = (vlong)name; + _sysargs[2] = mode; + return _callsys(); +} + +int +create(char *f, int mode, ulong perm) +{ + _sysargs[0] = CREATE; + _sysargs[1] = (vlong)f; + _sysargs[2] = mode; + _sysargs[3] = perm; + return _callsys(); +} + +void +_exits(char *s) +{ + _sysargs[0] = EXITS; + _sysargs[1] = s!=nil? strlen(s): 0; + _callsys(); +} + +int +dup(int f, int t) +{ + _sysargs[0] = DUP; + _sysargs[1] = f; + _sysargs[2] = t; + return _callsys(); +} + +int +errstr(char *buf, uint n) +{ + _sysargs[0] = ERRSTR; + _sysargs[1] = (vlong)buf; + _sysargs[2] = n; + return _callsys(); +} + +int +brk_(void *a) +{ + _sysargs[0] = BRK_; + _sysargs[1] = (vlong)a; + return _callsys(); +} + +void* +sbrk(ulong n) +{ + _sysargs[0] = -2; + _sysargs[1] = n; + return (void*)_callsys(); +} diff --git a/sys/src/cmd/6c/txt.c b/sys/src/cmd/6c/txt.c new file mode 100644 index 000000000..24ac1db46 --- /dev/null +++ b/sys/src/cmd/6c/txt.c @@ -0,0 +1,1515 @@ +#include "gc.h" + +void +ginit(void) +{ + int i; + Type *t; + + thechar = '6'; + thestring = "amd64"; + exregoffset = REGEXT; + exfregoffset = FREGEXT; + listinit(); + nstring = 0; + mnstring = 0; + nrathole = 0; + pc = 0; + breakpc = -1; + continpc = -1; + cases = C; + firstp = P; + lastp = P; + tfield = types[TINT]; + + typeword = typechlvp; + typeswitch = typechlv; + typecmplx = typesu; + + /* TO DO */ + memmove(typechlpv, typechlp, sizeof(typechlpv)); + typechlpv[TVLONG] = 1; + typechlpv[TUVLONG] = 1; + + zprog.link = P; + zprog.as = AGOK; + zprog.from.type = D_NONE; + zprog.from.index = D_NONE; + zprog.from.scale = 0; + zprog.to = zprog.from; + + lregnode.op = OREGISTER; + lregnode.class = CEXREG; + lregnode.reg = REGTMP; + lregnode.complex = 0; + lregnode.addable = 11; + lregnode.type = types[TLONG]; + + qregnode = lregnode; + qregnode.type = types[TVLONG]; + + constnode.op = OCONST; + constnode.class = CXXX; + constnode.complex = 0; + constnode.addable = 20; + constnode.type = types[TLONG]; + + vconstnode = constnode; + vconstnode.type = types[TVLONG]; + + fconstnode.op = OCONST; + fconstnode.class = CXXX; + fconstnode.complex = 0; + fconstnode.addable = 20; + fconstnode.type = types[TDOUBLE]; + + nodsafe = new(ONAME, Z, Z); + nodsafe->sym = slookup(".safe"); + nodsafe->type = types[TINT]; + nodsafe->etype = types[TINT]->etype; + nodsafe->class = CAUTO; + complex(nodsafe); + + t = typ(TARRAY, types[TCHAR]); + symrathole = slookup(".rathole"); + symrathole->class = CGLOBL; + symrathole->type = t; + + nodrat = new(ONAME, Z, Z); + nodrat->sym = symrathole; + nodrat->type = types[TIND]; + nodrat->etype = TVOID; + nodrat->class = CGLOBL; + complex(nodrat); + nodrat->type = t; + + nodret = new(ONAME, Z, Z); + nodret->sym = slookup(".ret"); + nodret->type = types[TIND]; + nodret->etype = TIND; + nodret->class = CPARAM; + nodret = new(OIND, nodret, Z); + complex(nodret); + + if(0) + com64init(); + + for(i=0; i= D_AX && i <= D_R15 && i != D_SP) + reg[i] = 0; + if(i >= D_X0 && i <= D_X7) + reg[i] = 0; + } +} + +void +gclean(void) +{ + int i; + Sym *s; + + reg[D_SP]--; + for(i=D_AX; i<=D_R15; i++) + if(reg[i]) + diag(Z, "reg %R left allocated", i); + for(i=D_X0; i<=D_X7; i++) + if(reg[i]) + diag(Z, "reg %R left allocated", i); + while(mnstring) + outstring("", 1L); + symstring->type->width = nstring; + symrathole->type->width = nrathole; + for(i=0; ilink) { + if(s->type == T) + continue; + if(s->type->width == 0) + continue; + if(s->class != CGLOBL && s->class != CSTATIC) + continue; + if(s->type == types[TENUM]) + continue; + gpseudo(AGLOBL, s, nodconst(s->type->width)); + } + nextpc(); + p->as = AEND; + outcode(); +} + +void +nextpc(void) +{ + + p = alloc(sizeof(*p)); + *p = zprog; + p->lineno = nearln; + pc++; + if(firstp == P) { + firstp = p; + lastp = p; + return; + } + lastp->link = p; + lastp = p; +} + +void +gargs(Node *n, Node *tn1, Node *tn2) +{ + long regs; + Node fnxargs[20], *fnxp; + + regs = cursafe; + + fnxp = fnxargs; + garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */ + + curarg = 0; + fnxp = fnxargs; + garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */ + + cursafe = regs; +} + +int +nareg(void) +{ + int i, n; + + n = 0; + for(i=D_AX; i<=D_R15; i++) + if(reg[i] == 0) + n++; + return n; +} + +void +garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp) +{ + Node nod; + + if(n == Z) + return; + if(n->op == OLIST) { + garg1(n->left, tn1, tn2, f, fnxp); + garg1(n->right, tn1, tn2, f, fnxp); + return; + } + if(f == 0) { + if(n->complex >= FNX) { + regsalloc(*fnxp, n); + nod = znode; + nod.op = OAS; + nod.left = *fnxp; + nod.right = n; + nod.type = n->type; + cgen(&nod, Z); + (*fnxp)++; + } + return; + } + if(typesu[n->type->etype]) { + regaalloc(tn2, n); + if(n->complex >= FNX) { + sugen(*fnxp, tn2, n->type->width); + (*fnxp)++; + } else + sugen(n, tn2, n->type->width); + return; + } + if(REGARG && curarg == 0 && typechlpv[n->type->etype]) { + regaalloc1(tn1, n); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + return; + } + if(vconst(n) == 0) { + regaalloc(tn2, n); + gmove(n, tn2); + return; + } + regalloc(tn1, n, Z); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + regaalloc(tn2, n); + gmove(tn1, tn2); + regfree(tn1); +} + +Node* +nodgconst(vlong v, Type *t) +{ + if(!typev[t->etype]) + return nodconst((long)v); + vconstnode.vconst = v; + return &vconstnode; +} + +Node* +nodconst(long v) +{ + constnode.vconst = v; + return &constnode; +} + +Node* +nodfconst(double d) +{ + fconstnode.fconst = d; + return &fconstnode; +} + +int +isreg(Node *n, int r) +{ + + if(n->op == OREGISTER) + if(n->reg == r) + return 1; + return 0; +} + +int +nodreg(Node *n, Node *nn, int r) +{ + int et; + + *n = qregnode; + n->reg = r; + if(nn != Z){ + et = nn->type->etype; + if(!typefd[et] && nn->type->width <= SZ_LONG && 0) + n->type = typeu[et]? types[TUINT]: types[TINT]; + else + n->type = nn->type; +//print("nodreg %s [%s]\n", tnames[et], tnames[n->type->etype]); + n->lineno = nn->lineno; + } + if(reg[r] == 0) + return 0; + if(nn != Z) { + if(nn->op == OREGISTER) + if(nn->reg == r) + return 0; + } + return 1; +} + +void +regret(Node *n, Node *nn) +{ + int r; + + r = REGRET; + if(typefd[nn->type->etype]) + r = FREGRET; + nodreg(n, nn, r); + reg[r]++; +} + +void +regalloc(Node *n, Node *tn, Node *o) +{ + int i; + + switch(tn->type->etype) { + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TIND: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i >= D_AX && i <= D_R15) + goto out; + } + for(i=D_AX; i<=D_R15; i++) + if(reg[i] == 0) + goto out; + diag(tn, "out of fixed registers"); + goto err; + + case TFLOAT: + case TDOUBLE: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i >= D_X0 && i <= D_X7) + goto out; + } + for(i=D_X0; i<=D_X7; i++) + if(reg[i] == 0) + goto out; + diag(tn, "out of float registers"); + goto out; + } + diag(tn, "unknown type in regalloc: %T", tn->type); +err: + i = 0; +out: + if(i) + reg[i]++; + nodreg(n, tn, i); +} + +void +regialloc(Node *n, Node *tn, Node *o) +{ + Node nod; + + nod = *tn; + nod.type = types[TIND]; + regalloc(n, &nod, o); +} + +void +regfree(Node *n) +{ + int i; + + i = 0; + if(n->op != OREGISTER && n->op != OINDREG) + goto err; + i = n->reg; + if(i < 0 || i >= sizeof(reg)) + goto err; + if(reg[i] <= 0) + goto err; + reg[i]--; + return; +err: + diag(n, "error in regfree: %R", i); +} + +void +regsalloc(Node *n, Node *nn) +{ + cursafe = align(cursafe, nn->type, Aaut3); + maxargsafe = maxround(maxargsafe, cursafe+curarg); + *n = *nodsafe; + n->xoffset = -(stkoff + cursafe); + n->type = nn->type; + n->etype = nn->type->etype; + n->lineno = nn->lineno; +} + +void +regaalloc1(Node *n, Node *nn) +{ + nodreg(n, nn, REGARG); + reg[REGARG]++; + curarg = align(curarg, nn->type, Aarg1); + curarg = align(curarg, nn->type, Aarg2); + maxargsafe = maxround(maxargsafe, cursafe+curarg); +} + +void +regaalloc(Node *n, Node *nn) +{ + curarg = align(curarg, nn->type, Aarg1); + *n = *nn; + n->op = OINDREG; + n->reg = REGSP; + n->xoffset = curarg; + n->complex = 0; + n->addable = 20; + curarg = align(curarg, nn->type, Aarg2); + maxargsafe = maxround(maxargsafe, cursafe+curarg); +} + +void +regind(Node *n, Node *nn) +{ + + if(n->op != OREGISTER) { + diag(n, "regind not OREGISTER"); + return; + } + n->op = OINDREG; + n->type = nn->type; +} + +void +naddr(Node *n, Adr *a) +{ + long v; + + a->type = D_NONE; + if(n == Z) + return; + switch(n->op) { + default: + bad: + diag(n, "bad in naddr: %O %D", n->op, a); + break; + + case OREGISTER: + a->type = n->reg; + a->sym = S; + break; + + + case OIND: + naddr(n->left, a); + if(a->type >= D_AX && a->type <= D_R15) + a->type += D_INDIR; + else + if(a->type == D_CONST) + a->type = D_NONE+D_INDIR; + else + if(a->type == D_ADDR) { + a->type = a->index; + a->index = D_NONE; + } else + goto bad; + break; + + case OINDEX: + a->type = idx.ptr; + if(n->left->op == OADDR || n->left->op == OCONST) + naddr(n->left, a); + if(a->type >= D_AX && a->type <= D_R15) + a->type += D_INDIR; + else + if(a->type == D_CONST) + a->type = D_NONE+D_INDIR; + else + if(a->type == D_ADDR) { + a->type = a->index; + a->index = D_NONE; + } else + goto bad; + a->index = idx.reg; + a->scale = n->scale; + a->offset += n->xoffset; + break; + + case OINDREG: + a->type = n->reg+D_INDIR; + a->sym = S; + a->offset = n->xoffset; + break; + + case ONAME: + a->etype = n->etype; + a->type = D_STATIC; + a->sym = n->sym; + a->offset = n->xoffset; + if(n->class == CSTATIC) + break; + if(n->class == CEXTERN || n->class == CGLOBL) { + a->type = D_EXTERN; + break; + } + if(n->class == CAUTO) { + a->type = D_AUTO; + break; + } + if(n->class == CPARAM) { + a->type = D_PARAM; + break; + } + goto bad; + + case OCONST: + if(typefd[n->type->etype]) { + a->type = D_FCONST; + a->dval = n->fconst; + break; + } + a->sym = S; + a->type = D_CONST; + if(typev[n->type->etype] || n->type->etype == TIND) + a->offset = n->vconst; + else + a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG); + break; + + case OADDR: + naddr(n->left, a); + if(a->type >= D_INDIR) { + a->type -= D_INDIR; + break; + } + if(a->type == D_EXTERN || a->type == D_STATIC || + a->type == D_AUTO || a->type == D_PARAM) + if(a->index == D_NONE) { + a->index = a->type; + a->type = D_ADDR; + break; + } + goto bad; + + case OADD: + if(n->right->op == OCONST) { + v = n->right->vconst; + naddr(n->left, a); + } else + if(n->left->op == OCONST) { + v = n->left->vconst; + naddr(n->right, a); + } else + goto bad; + a->offset += v; + break; + + } +} + +void +gcmp(int op, Node *n, vlong val) +{ + Node *cn, nod; + + cn = nodgconst(val, n->type); + if(!immconst(cn)){ + regalloc(&nod, n, Z); + gmove(cn, &nod); + gopcode(op, n->type, n, &nod); + regfree(&nod); + }else + gopcode(op, n->type, n, cn); +} + +#define CASE(a,b) ((a<<8)|(b<<0)) + +void +gmove(Node *f, Node *t) +{ + int ft, tt, t64, a; + Node nod, nod1, nod2, nod3; + Prog *p1, *p2; + + ft = f->type->etype; + tt = t->type->etype; + t64 = tt == TVLONG || tt == TUVLONG || tt == TIND; + if(debug['M']) + print("gop: %O %O[%s],%O[%s]\n", OAS, + f->op, tnames[ft], t->op, tnames[tt]); + if(typefd[ft] && f->op == OCONST) { + /* TO DO: pick up special constants, possibly preloaded */ + if(f->fconst == 0.0){ + regalloc(&nod, t, t); + gins(AXORPD, &nod, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + } +/* + * load + */ + if(f->op == ONAME || f->op == OINDREG || + f->op == OIND || f->op == OINDEX) + switch(ft) { + case TCHAR: + a = AMOVBLSX; + if(t64) + a = AMOVBQSX; + goto ld; + case TUCHAR: + a = AMOVBLZX; + if(t64) + a = AMOVBQZX; + goto ld; + case TSHORT: + a = AMOVWLSX; + if(t64) + a = AMOVWQSX; + goto ld; + case TUSHORT: + a = AMOVWLZX; + if(t64) + a = AMOVWQZX; + goto ld; + case TINT: + case TLONG: + if(typefd[tt]) { + regalloc(&nod, t, t); + if(tt == TDOUBLE) + a = ACVTSL2SD; + else + a = ACVTSL2SS; + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + a = AMOVL; + if(t64) + a = AMOVLQSX; + goto ld; + case TUINT: + case TULONG: + a = AMOVL; + if(t64) + a = AMOVLQZX; /* could probably use plain MOVL */ + goto ld; + case TVLONG: + if(typefd[tt]) { + regalloc(&nod, t, t); + if(tt == TDOUBLE) + a = ACVTSQ2SD; + else + a = ACVTSQ2SS; + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + case TUVLONG: + a = AMOVQ; + goto ld; + case TIND: + a = AMOVQ; + + ld: + regalloc(&nod, f, t); + nod.type = t64? types[TVLONG]: types[TINT]; + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + + case TFLOAT: + a = AMOVSS; + goto fld; + case TDOUBLE: + a = AMOVSD; + fld: + regalloc(&nod, f, t); + if(tt != TDOUBLE && tt != TFLOAT){ /* TO DO: why is this here */ + prtree(f, "odd tree"); + nod.type = t64? types[TVLONG]: types[TINT]; + } + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + +/* + * store + */ + if(t->op == ONAME || t->op == OINDREG || + t->op == OIND || t->op == OINDEX) + switch(tt) { + case TCHAR: + case TUCHAR: + a = AMOVB; goto st; + case TSHORT: + case TUSHORT: + a = AMOVW; goto st; + case TINT: + case TUINT: + case TLONG: + case TULONG: + a = AMOVL; goto st; + case TVLONG: + case TUVLONG: + case TIND: + a = AMOVQ; goto st; + + st: + if(f->op == OCONST) { + gins(a, f, t); + return; + } + fst: + regalloc(&nod, t, f); + gmove(f, &nod); + gins(a, &nod, t); + regfree(&nod); + return; + + case TFLOAT: + a = AMOVSS; + goto fst; + case TDOUBLE: + a = AMOVSD; + goto fst; + } + +/* + * convert + */ + switch(CASE(ft,tt)) { + default: +/* + * integer to integer + ******** + a = AGOK; break; + + case CASE( TCHAR, TCHAR): + case CASE( TUCHAR, TCHAR): + case CASE( TSHORT, TCHAR): + case CASE( TUSHORT,TCHAR): + case CASE( TINT, TCHAR): + case CASE( TUINT, TCHAR): + case CASE( TLONG, TCHAR): + case CASE( TULONG, TCHAR): + case CASE( TIND, TCHAR): + + case CASE( TCHAR, TUCHAR): + case CASE( TUCHAR, TUCHAR): + case CASE( TSHORT, TUCHAR): + case CASE( TUSHORT,TUCHAR): + case CASE( TINT, TUCHAR): + case CASE( TUINT, TUCHAR): + case CASE( TLONG, TUCHAR): + case CASE( TULONG, TUCHAR): + case CASE( TIND, TUCHAR): + + case CASE( TSHORT, TSHORT): + case CASE( TUSHORT,TSHORT): + case CASE( TINT, TSHORT): + case CASE( TUINT, TSHORT): + case CASE( TLONG, TSHORT): + case CASE( TULONG, TSHORT): + case CASE( TIND, TSHORT): + + case CASE( TSHORT, TUSHORT): + case CASE( TUSHORT,TUSHORT): + case CASE( TINT, TUSHORT): + case CASE( TUINT, TUSHORT): + case CASE( TLONG, TUSHORT): + case CASE( TULONG, TUSHORT): + case CASE( TIND, TUSHORT): + + case CASE( TINT, TINT): + case CASE( TUINT, TINT): + case CASE( TLONG, TINT): + case CASE( TULONG, TINT): + case CASE( TIND, TINT): + + case CASE( TINT, TUINT): + case CASE( TUINT, TUINT): + case CASE( TLONG, TUINT): + case CASE( TULONG, TUINT): + case CASE( TIND, TUINT): + + case CASE( TUINT, TIND): + case CASE( TVLONG, TUINT): + case CASE( TVLONG, TULONG): + case CASE( TUVLONG, TUINT): + case CASE( TUVLONG, TULONG): + *****/ + a = AMOVL; + break; + + case CASE( TVLONG, TCHAR): + case CASE( TVLONG, TSHORT): + case CASE( TVLONG, TINT): + case CASE( TVLONG, TLONG): + case CASE( TUVLONG, TCHAR): + case CASE( TUVLONG, TSHORT): + case CASE( TUVLONG, TINT): + case CASE( TUVLONG, TLONG): + case CASE( TINT, TVLONG): + case CASE( TINT, TUVLONG): + case CASE( TLONG, TVLONG): + case CASE( TINT, TIND): + case CASE( TLONG, TIND): + a = AMOVLQSX; + if(f->op == OCONST) { + f->vconst &= (uvlong)0xffffffffU; + if(f->vconst & 0x80000000) + f->vconst |= (vlong)0xffffffff << 32; + a = AMOVQ; + } + break; + + case CASE( TUINT, TIND): + case CASE( TUINT, TVLONG): + case CASE( TUINT, TUVLONG): + case CASE( TULONG, TVLONG): + case CASE( TULONG, TUVLONG): + case CASE( TULONG, TIND): + a = AMOVL; /* same effect as AMOVLQZX */ + if(f->op == OCONST) { + f->vconst &= (uvlong)0xffffffffU; + a = AMOVQ; + } + break; + + case CASE( TIND, TVLONG): + case CASE( TVLONG, TVLONG): + case CASE( TUVLONG, TVLONG): + case CASE( TVLONG, TUVLONG): + case CASE( TUVLONG, TUVLONG): + case CASE( TIND, TUVLONG): + case CASE( TVLONG, TIND): + case CASE( TUVLONG, TIND): + case CASE( TIND, TIND): + a = AMOVQ; + break; + + case CASE( TSHORT, TINT): + case CASE( TSHORT, TUINT): + case CASE( TSHORT, TLONG): + case CASE( TSHORT, TULONG): + a = AMOVWLSX; + if(f->op == OCONST) { + f->vconst &= 0xffff; + if(f->vconst & 0x8000) + f->vconst |= 0xffff0000; + a = AMOVL; + } + break; + + case CASE( TSHORT, TVLONG): + case CASE( TSHORT, TUVLONG): + case CASE( TSHORT, TIND): + a = AMOVWQSX; + if(f->op == OCONST) { + f->vconst &= 0xffff; + if(f->vconst & 0x8000){ + f->vconst |= 0xffff0000; + f->vconst |= (vlong)~0 << 32; + } + a = AMOVL; + } + break; + + case CASE( TUSHORT,TINT): + case CASE( TUSHORT,TUINT): + case CASE( TUSHORT,TLONG): + case CASE( TUSHORT,TULONG): + a = AMOVWLZX; + if(f->op == OCONST) { + f->vconst &= 0xffff; + a = AMOVL; + } + break; + + case CASE( TUSHORT,TVLONG): + case CASE( TUSHORT,TUVLONG): + case CASE( TUSHORT,TIND): + a = AMOVWQZX; + if(f->op == OCONST) { + f->vconst &= 0xffff; + a = AMOVL; /* MOVL also zero-extends to 64 bits */ + } + break; + + case CASE( TCHAR, TSHORT): + case CASE( TCHAR, TUSHORT): + case CASE( TCHAR, TINT): + case CASE( TCHAR, TUINT): + case CASE( TCHAR, TLONG): + case CASE( TCHAR, TULONG): + a = AMOVBLSX; + if(f->op == OCONST) { + f->vconst &= 0xff; + if(f->vconst & 0x80) + f->vconst |= 0xffffff00; + a = AMOVL; + } + break; + + case CASE( TCHAR, TVLONG): + case CASE( TCHAR, TUVLONG): + case CASE( TCHAR, TIND): + a = AMOVBQSX; + if(f->op == OCONST) { + f->vconst &= 0xff; + if(f->vconst & 0x80){ + f->vconst |= 0xffffff00; + f->vconst |= (vlong)~0 << 32; + } + a = AMOVQ; + } + break; + + case CASE( TUCHAR, TSHORT): + case CASE( TUCHAR, TUSHORT): + case CASE( TUCHAR, TINT): + case CASE( TUCHAR, TUINT): + case CASE( TUCHAR, TLONG): + case CASE( TUCHAR, TULONG): + a = AMOVBLZX; + if(f->op == OCONST) { + f->vconst &= 0xff; + a = AMOVL; + } + break; + + case CASE( TUCHAR, TVLONG): + case CASE( TUCHAR, TUVLONG): + case CASE( TUCHAR, TIND): + a = AMOVBQZX; + if(f->op == OCONST) { + f->vconst &= 0xff; + a = AMOVL; /* zero-extends to 64-bits */ + } + break; + +/* + * float to fix + */ + case CASE( TFLOAT, TCHAR): + case CASE( TFLOAT, TUCHAR): + case CASE( TFLOAT, TSHORT): + case CASE( TFLOAT, TUSHORT): + case CASE( TFLOAT, TINT): + case CASE( TFLOAT, TUINT): + case CASE( TFLOAT, TLONG): + case CASE( TFLOAT, TULONG): + case CASE( TFLOAT, TVLONG): + case CASE( TFLOAT, TUVLONG): + case CASE( TFLOAT, TIND): + + case CASE( TDOUBLE,TCHAR): + case CASE( TDOUBLE,TUCHAR): + case CASE( TDOUBLE,TSHORT): + case CASE( TDOUBLE,TUSHORT): + case CASE( TDOUBLE,TINT): + case CASE( TDOUBLE,TUINT): + case CASE( TDOUBLE,TLONG): + case CASE( TDOUBLE,TULONG): + case CASE( TDOUBLE,TVLONG): + case CASE( TDOUBLE,TUVLONG): + case CASE( TDOUBLE,TIND): + regalloc(&nod, t, Z); + if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){ + if(ft == TFLOAT) + a = ACVTTSS2SQ; + else + a = ACVTTSD2SQ; + }else{ + if(ft == TFLOAT) + a = ACVTTSS2SL; + else + a = ACVTTSD2SL; + } + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + +/* + * ulong to float + */ + case CASE( TUVLONG, TDOUBLE): + case CASE( TUVLONG, TFLOAT): + a = ACVTSQ2SS; + if(tt == TDOUBLE) + a = ACVTSQ2SD; + regalloc(&nod, f, f); + gmove(f, &nod); + regalloc(&nod1, t, t); + gins(ACMPQ, &nod, nodconst(0)); + gins(AJLT, Z, Z); + p1 = p; + gins(a, &nod, &nod1); + gins(AJMP, Z, Z); + p2 = p; + patch(p1, pc); + regalloc(&nod2, f, Z); + regalloc(&nod3, f, Z); + gmove(&nod, &nod2); + gins(ASHRQ, nodconst(1), &nod2); + gmove(&nod, &nod3); + gins(AANDL, nodconst(1), &nod3); + gins(AORQ, &nod3, &nod2); + gins(a, &nod2, &nod1); + gins(tt == TDOUBLE? AADDSD: AADDSS, &nod1, &nod1); + regfree(&nod2); + regfree(&nod3); + patch(p2, pc); + regfree(&nod); + regfree(&nod1); + return; + + case CASE( TULONG, TDOUBLE): + case CASE( TUINT, TDOUBLE): + case CASE( TULONG, TFLOAT): + case CASE( TUINT, TFLOAT): + a = ACVTSQ2SS; + if(tt == TDOUBLE) + a = ACVTSQ2SD; + regalloc(&nod, f, f); + gins(AMOVLQZX, f, &nod); + regalloc(&nod1, t, t); + gins(a, &nod, &nod1); + gmove(&nod1, t); + regfree(&nod); + regfree(&nod1); + return; + +/* + * fix to float + */ + case CASE( TCHAR, TFLOAT): + case CASE( TUCHAR, TFLOAT): + case CASE( TSHORT, TFLOAT): + case CASE( TUSHORT,TFLOAT): + case CASE( TINT, TFLOAT): + case CASE( TLONG, TFLOAT): + case CASE( TVLONG, TFLOAT): + case CASE( TIND, TFLOAT): + + case CASE( TCHAR, TDOUBLE): + case CASE( TUCHAR, TDOUBLE): + case CASE( TSHORT, TDOUBLE): + case CASE( TUSHORT,TDOUBLE): + case CASE( TINT, TDOUBLE): + case CASE( TLONG, TDOUBLE): + case CASE( TVLONG, TDOUBLE): + case CASE( TIND, TDOUBLE): + regalloc(&nod, t, t); + if(ewidth[ft] == SZ_VLONG){ + if(tt == TFLOAT) + a = ACVTSQ2SS; + else + a = ACVTSQ2SD; + }else{ + if(tt == TFLOAT) + a = ACVTSL2SS; + else + a = ACVTSL2SD; + } + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + +/* + * float to float + */ + case CASE( TFLOAT, TFLOAT): + a = AMOVSS; + break; + case CASE( TDOUBLE,TFLOAT): + a = ACVTSD2SS; + break; + case CASE( TFLOAT, TDOUBLE): + a = ACVTSS2SD; + break; + case CASE( TDOUBLE,TDOUBLE): + a = AMOVSD; + break; + } + if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt]) /* TO DO: check AMOVL */ + if(samaddr(f, t)) + return; + gins(a, f, t); +} + +void +doindex(Node *n) +{ + Node nod, nod1; + long v; + +if(debug['Y']) +prtree(n, "index"); + +if(n->left->complex >= FNX) +print("botch in doindex\n"); + + regalloc(&nod, &qregnode, Z); + v = constnode.vconst; + cgen(n->right, &nod); + idx.ptr = D_NONE; + if(n->left->op == OCONST) + idx.ptr = D_CONST; + else if(n->left->op == OREGISTER) + idx.ptr = n->left->reg; + else if(n->left->op != OADDR) { + reg[D_BP]++; // cant be used as a base + regalloc(&nod1, &qregnode, Z); + cgen(n->left, &nod1); + idx.ptr = nod1.reg; + regfree(&nod1); + reg[D_BP]--; + } + idx.reg = nod.reg; + regfree(&nod); + constnode.vconst = v; +} + +void +gins(int a, Node *f, Node *t) +{ + + if(f != Z && f->op == OINDEX) + doindex(f); + if(t != Z && t->op == OINDEX) + doindex(t); + nextpc(); + p->as = a; + if(f != Z) + naddr(f, &p->from); + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +void +gopcode(int o, Type *ty, Node *f, Node *t) +{ + int a, et; + + et = TLONG; + if(ty != T) + et = ty->etype; + if(debug['M']) { + if(f != Z && f->type != T) + print("gop: %O %O[%s],", o, f->op, tnames[et]); + else + print("gop: %O Z,", o); + if(t != Z && t->type != T) + print("%O[%s]\n", t->op, tnames[t->type->etype]); + else + print("Z\n"); + } + a = AGOK; + switch(o) { + case OCOM: + a = ANOTL; + if(et == TCHAR || et == TUCHAR) + a = ANOTB; + if(et == TSHORT || et == TUSHORT) + a = ANOTW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ANOTQ; + break; + + case ONEG: + a = ANEGL; + if(et == TCHAR || et == TUCHAR) + a = ANEGB; + if(et == TSHORT || et == TUSHORT) + a = ANEGW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ANEGQ; + break; + + case OADDR: + a = ALEAQ; + break; + + case OASADD: + case OADD: + a = AADDL; + if(et == TCHAR || et == TUCHAR) + a = AADDB; + if(et == TSHORT || et == TUSHORT) + a = AADDW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AADDQ; + if(et == TFLOAT) + a = AADDSS; + if(et == TDOUBLE) + a = AADDSD; + break; + + case OASSUB: + case OSUB: + a = ASUBL; + if(et == TCHAR || et == TUCHAR) + a = ASUBB; + if(et == TSHORT || et == TUSHORT) + a = ASUBW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ASUBQ; + if(et == TFLOAT) + a = ASUBSS; + if(et == TDOUBLE) + a = ASUBSD; + break; + + case OASOR: + case OOR: + a = AORL; + if(et == TCHAR || et == TUCHAR) + a = AORB; + if(et == TSHORT || et == TUSHORT) + a = AORW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AORQ; + break; + + case OASAND: + case OAND: + a = AANDL; + if(et == TCHAR || et == TUCHAR) + a = AANDB; + if(et == TSHORT || et == TUSHORT) + a = AANDW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AANDQ; + break; + + case OASXOR: + case OXOR: + a = AXORL; + if(et == TCHAR || et == TUCHAR) + a = AXORB; + if(et == TSHORT || et == TUSHORT) + a = AXORW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AXORQ; + break; + + case OASLSHR: + case OLSHR: + a = ASHRL; + if(et == TCHAR || et == TUCHAR) + a = ASHRB; + if(et == TSHORT || et == TUSHORT) + a = ASHRW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ASHRQ; + break; + + case OASASHR: + case OASHR: + a = ASARL; + if(et == TCHAR || et == TUCHAR) + a = ASARB; + if(et == TSHORT || et == TUSHORT) + a = ASARW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ASARQ; + break; + + case OASASHL: + case OASHL: + a = ASALL; + if(et == TCHAR || et == TUCHAR) + a = ASALB; + if(et == TSHORT || et == TUSHORT) + a = ASALW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ASALQ; + break; + + case OFUNC: + a = ACALL; + break; + + case OASMUL: + case OMUL: + if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0) + t = Z; + a = AIMULL; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AIMULQ; + if(et == TFLOAT) + a = AMULSS; + if(et == TDOUBLE) + a = AMULSD; + break; + + case OASMOD: + case OMOD: + case OASDIV: + case ODIV: + a = AIDIVL; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AIDIVQ; + if(et == TFLOAT) + a = ADIVSS; + if(et == TDOUBLE) + a = ADIVSD; + break; + + case OASLMUL: + case OLMUL: + a = AMULL; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AMULQ; + break; + + case OASLMOD: + case OLMOD: + case OASLDIV: + case OLDIV: + a = ADIVL; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ADIVQ; + break; + + case OEQ: + case ONE: + case OLT: + case OLE: + case OGE: + case OGT: + case OLO: + case OLS: + case OHS: + case OHI: + a = ACMPL; + if(et == TCHAR || et == TUCHAR) + a = ACMPB; + if(et == TSHORT || et == TUSHORT) + a = ACMPW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ACMPQ; + if(et == TFLOAT) + a = AUCOMISS; + if(et == TDOUBLE) + a = AUCOMISD; + gins(a, f, t); + switch(o) { + case OEQ: a = AJEQ; break; + case ONE: a = AJNE; break; + case OLT: a = AJLT; break; + case OLE: a = AJLE; break; + case OGE: a = AJGE; break; + case OGT: a = AJGT; break; + case OLO: a = AJCS; break; + case OLS: a = AJLS; break; + case OHS: a = AJCC; break; + case OHI: a = AJHI; break; + } + gins(a, Z, Z); + return; + } + if(a == AGOK) + diag(Z, "bad in gopcode %O", o); + gins(a, f, t); +} + +int +samaddr(Node *f, Node *t) +{ + return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg; +} + +void +gbranch(int o) +{ + int a; + + a = AGOK; + switch(o) { + case ORETURN: + a = ARET; + break; + case OGOTO: + a = AJMP; + break; + } + nextpc(); + if(a == AGOK) { + diag(Z, "bad in gbranch %O", o); + nextpc(); + } + p->as = a; +} + +void +patch(Prog *op, long pc) +{ + + op->to.offset = pc; + op->to.type = D_BRANCH; +} + +void +gpseudo(int a, Sym *s, Node *n) +{ + + nextpc(); + p->as = a; + p->from.type = D_EXTERN; + p->from.sym = s; + p->from.scale = (profileflg ? 0 : NOPROF); + if(s->class == CSTATIC) + p->from.type = D_STATIC; + naddr(n, &p->to); + if(a == ADATA || a == AGLOBL) + pc--; +} + +int +sconst(Node *n) +{ + long v; + + if(n->op == OCONST && !typefd[n->type->etype]) { + v = n->vconst; + if(v >= -32766L && v < 32766L) + return 1; + } + return 0; +} + +long +exreg(Type *t) +{ + long o; + + if(typechlpv[t->etype]) { + if(exregoffset <= REGEXT-4) + return 0; + o = exregoffset; + exregoffset--; + return o; + } + return 0; +} + +schar ewidth[NTYPE] = +{ + -1, /*[TXXX]*/ + SZ_CHAR, /*[TCHAR]*/ + SZ_CHAR, /*[TUCHAR]*/ + SZ_SHORT, /*[TSHORT]*/ + SZ_SHORT, /*[TUSHORT]*/ + SZ_INT, /*[TINT]*/ + SZ_INT, /*[TUINT]*/ + SZ_LONG, /*[TLONG]*/ + SZ_LONG, /*[TULONG]*/ + SZ_VLONG, /*[TVLONG]*/ + SZ_VLONG, /*[TUVLONG]*/ + SZ_FLOAT, /*[TFLOAT]*/ + SZ_DOUBLE, /*[TDOUBLE]*/ + SZ_IND, /*[TIND]*/ + 0, /*[TFUNC]*/ + -1, /*[TARRAY]*/ + 0, /*[TVOID]*/ + -1, /*[TSTRUCT]*/ + -1, /*[TUNION]*/ + SZ_INT, /*[TENUM]*/ +}; +long ncast[NTYPE] = +{ + 0, /*[TXXX]*/ + BCHAR|BUCHAR, /*[TCHAR]*/ + BCHAR|BUCHAR, /*[TUCHAR]*/ + BSHORT|BUSHORT, /*[TSHORT]*/ + BSHORT|BUSHORT, /*[TUSHORT]*/ + BINT|BUINT|BLONG|BULONG, /*[TINT]*/ + BINT|BUINT|BLONG|BULONG, /*[TUINT]*/ + BINT|BUINT|BLONG|BULONG, /*[TLONG]*/ + BINT|BUINT|BLONG|BULONG, /*[TULONG]*/ + BVLONG|BUVLONG|BIND, /*[TVLONG]*/ + BVLONG|BUVLONG|BIND, /*[TUVLONG]*/ + BFLOAT, /*[TFLOAT]*/ + BDOUBLE, /*[TDOUBLE]*/ + BVLONG|BUVLONG|BIND, /*[TIND]*/ + 0, /*[TFUNC]*/ + 0, /*[TARRAY]*/ + 0, /*[TVOID]*/ + BSTRUCT, /*[TSTRUCT]*/ + BUNION, /*[TUNION]*/ + 0, /*[TENUM]*/ +}; diff --git a/sys/src/cmd/6c/vlrt.c b/sys/src/cmd/6c/vlrt.c new file mode 100644 index 000000000..7c9f1a07b --- /dev/null +++ b/sys/src/cmd/6c/vlrt.c @@ -0,0 +1,746 @@ +typedef unsigned long ulong; +typedef unsigned int uint; +typedef unsigned short ushort; +typedef unsigned char uchar; +typedef signed char schar; + +#define SIGN(n) (1UL<<(n-1)) + +typedef struct Vlong Vlong; +struct Vlong +{ + union + { + struct + { + uint lo; + uint hi; + }; + struct + { + ushort lols; + ushort loms; + ushort hils; + ushort hims; + }; + }; +}; + +void abort(void); + +void _subv(Vlong*, Vlong, Vlong); + +void +_d2v(Vlong *y, double d) +{ + union { double d; struct Vlong; } x; + uint xhi, xlo, ylo, yhi; + int sh; + + x.d = d; + + xhi = (x.hi & 0xfffff) | 0x100000; + xlo = x.lo; + sh = 1075 - ((x.hi >> 20) & 0x7ff); + + ylo = 0; + yhi = 0; + if(sh >= 0) { + /* v = (hi||lo) >> sh */ + if(sh < 32) { + if(sh == 0) { + ylo = xlo; + yhi = xhi; + } else { + ylo = (xlo >> sh) | (xhi << (32-sh)); + yhi = xhi >> sh; + } + } else { + if(sh == 32) { + ylo = xhi; + } else + if(sh < 64) { + ylo = xhi >> (sh-32); + } + } + } else { + /* v = (hi||lo) << -sh */ + sh = -sh; + if(sh <= 10) { + ylo = xlo << sh; + yhi = (xhi << sh) | (xlo >> (32-sh)); + } else { + /* overflow */ + yhi = d; /* causes something awful */ + } + } + if(x.hi & SIGN(32)) { + if(ylo != 0) { + ylo = -ylo; + yhi = ~yhi; + } else + yhi = -yhi; + } + + y->hi = yhi; + y->lo = ylo; +} + +void +_f2v(Vlong *y, float f) +{ + + _d2v(y, f); +} + +double +_v2d(Vlong x) +{ + if(x.hi & SIGN(32)) { + if(x.lo) { + x.lo = -x.lo; + x.hi = ~x.hi; + } else + x.hi = -x.hi; + return -((long)x.hi*4294967296. + x.lo); + } + return (long)x.hi*4294967296. + x.lo; +} + +float +_v2f(Vlong x) +{ + return _v2d(x); +} + +uint _div64by32(Vlong, uint, uint*); +void _mul64by32(Vlong*, Vlong, uint); + +static void +slowdodiv(Vlong num, Vlong den, Vlong *q, Vlong *r) +{ + uint numlo, numhi, denhi, denlo, quohi, quolo, t; + int i; + + numhi = num.hi; + numlo = num.lo; + denhi = den.hi; + denlo = den.lo; + + /* + * get a divide by zero + */ + if(denlo==0 && denhi==0) { + numlo = numlo / denlo; + } + + /* + * set up the divisor and find the number of iterations needed + */ + if(numhi >= SIGN(32)) { + quohi = SIGN(32); + quolo = 0; + } else { + quohi = numhi; + quolo = numlo; + } + i = 0; + while(denhi < quohi || (denhi == quohi && denlo < quolo)) { + denhi = (denhi<<1) | (denlo>>31); + denlo <<= 1; + i++; + } + + quohi = 0; + quolo = 0; + for(; i >= 0; i--) { + quohi = (quohi<<1) | (quolo>>31); + quolo <<= 1; + if(numhi > denhi || (numhi == denhi && numlo >= denlo)) { + t = numlo; + numlo -= denlo; + if(numlo > t) + numhi--; + numhi -= denhi; + quolo |= 1; + } + denlo = (denlo>>1) | (denhi<<31); + denhi >>= 1; + } + + if(q) { + q->lo = quolo; + q->hi = quohi; + } + if(r) { + r->lo = numlo; + r->hi = numhi; + } +} + +static void +dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp) +{ + uint n; + Vlong x, q, r; + + if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){ + if(qp) { + qp->hi = 0; + qp->lo = 0; + } + if(rp) { + rp->hi = num.hi; + rp->lo = num.lo; + } + return; + } + + if(den.hi != 0){ + q.hi = 0; + n = num.hi/den.hi; + _mul64by32(&x, den, n); + if(x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo)) + slowdodiv(num, den, &q, &r); + else { + q.lo = n; + _subv(&r, num, x); + } + } else { + if(num.hi >= den.lo){ + q.hi = n = num.hi/den.lo; + num.hi -= den.lo*n; + } else { + q.hi = 0; + } + q.lo = _div64by32(num, den.lo, &r.lo); + r.hi = 0; + } + if(qp) { + qp->lo = q.lo; + qp->hi = q.hi; + } + if(rp) { + rp->lo = r.lo; + rp->hi = r.hi; + } +} + +void +_divvu(Vlong *q, Vlong n, Vlong d) +{ + + if(n.hi == 0 && d.hi == 0) { + q->hi = 0; + q->lo = n.lo / d.lo; + return; + } + dodiv(n, d, q, 0); +} + +void +_modvu(Vlong *r, Vlong n, Vlong d) +{ + + if(n.hi == 0 && d.hi == 0) { + r->hi = 0; + r->lo = n.lo % d.lo; + return; + } + dodiv(n, d, 0, r); +} + +static void +vneg(Vlong *v) +{ + + if(v->lo == 0) { + v->hi = -v->hi; + return; + } + v->lo = -v->lo; + v->hi = ~v->hi; +} + +void +_divv(Vlong *q, Vlong n, Vlong d) +{ + long nneg, dneg; + + if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { + q->lo = (long)n.lo / (long)d.lo; + q->hi = ((long)q->lo) >> 31; + return; + } + nneg = n.hi >> 31; + if(nneg) + vneg(&n); + dneg = d.hi >> 31; + if(dneg) + vneg(&d); + dodiv(n, d, q, 0); + if(nneg != dneg) + vneg(q); +} + +void +_modv(Vlong *r, Vlong n, Vlong d) +{ + long nneg, dneg; + + if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { + r->lo = (long)n.lo % (long)d.lo; + r->hi = ((long)r->lo) >> 31; + return; + } + nneg = n.hi >> 31; + if(nneg) + vneg(&n); + dneg = d.hi >> 31; + if(dneg) + vneg(&d); + dodiv(n, d, 0, r); + if(nneg) + vneg(r); +} + +void +_rshav(Vlong *r, Vlong a, int b) +{ + long t; + + t = a.hi; + if(b >= 32) { + r->hi = t>>31; + if(b >= 64) { + /* this is illegal re C standard */ + r->lo = t>>31; + return; + } + r->lo = t >> (b-32); + return; + } + if(b <= 0) { + r->hi = t; + r->lo = a.lo; + return; + } + r->hi = t >> b; + r->lo = (t << (32-b)) | (a.lo >> b); +} + +void +_rshlv(Vlong *r, Vlong a, int b) +{ + uint t; + + t = a.hi; + if(b >= 32) { + r->hi = 0; + if(b >= 64) { + /* this is illegal re C standard */ + r->lo = 0; + return; + } + r->lo = t >> (b-32); + return; + } + if(b <= 0) { + r->hi = t; + r->lo = a.lo; + return; + } + r->hi = t >> b; + r->lo = (t << (32-b)) | (a.lo >> b); +} + +void +_lshv(Vlong *r, Vlong a, int b) +{ + uint t; + + t = a.lo; + if(b >= 32) { + r->lo = 0; + if(b >= 64) { + /* this is illegal re C standard */ + r->hi = 0; + return; + } + r->hi = t << (b-32); + return; + } + if(b <= 0) { + r->lo = t; + r->hi = a.hi; + return; + } + r->lo = t << b; + r->hi = (t >> (32-b)) | (a.hi << b); +} + +void +_andv(Vlong *r, Vlong a, Vlong b) +{ + r->hi = a.hi & b.hi; + r->lo = a.lo & b.lo; +} + +void +_orv(Vlong *r, Vlong a, Vlong b) +{ + r->hi = a.hi | b.hi; + r->lo = a.lo | b.lo; +} + +void +_xorv(Vlong *r, Vlong a, Vlong b) +{ + r->hi = a.hi ^ b.hi; + r->lo = a.lo ^ b.lo; +} + +void +_vpp(Vlong *l, Vlong *r) +{ + + l->hi = r->hi; + l->lo = r->lo; + r->lo++; + if(r->lo == 0) + r->hi++; +} + +void +_vmm(Vlong *l, Vlong *r) +{ + + l->hi = r->hi; + l->lo = r->lo; + if(r->lo == 0) + r->hi--; + r->lo--; +} + +void +_ppv(Vlong *l, Vlong *r) +{ + + r->lo++; + if(r->lo == 0) + r->hi++; + l->hi = r->hi; + l->lo = r->lo; +} + +void +_mmv(Vlong *l, Vlong *r) +{ + + if(r->lo == 0) + r->hi--; + r->lo--; + l->hi = r->hi; + l->lo = r->lo; +} + +void +_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv) +{ + Vlong t, u; + + u.lo = 0; + u.hi = 0; + switch(type) { + default: + abort(); + break; + + case 1: /* schar */ + t.lo = *(schar*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(schar*)lv = u.lo; + break; + + case 2: /* uchar */ + t.lo = *(uchar*)lv; + t.hi = 0; + fn(&u, t, rv); + *(uchar*)lv = u.lo; + break; + + case 3: /* short */ + t.lo = *(short*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(short*)lv = u.lo; + break; + + case 4: /* ushort */ + t.lo = *(ushort*)lv; + t.hi = 0; + fn(&u, t, rv); + *(ushort*)lv = u.lo; + break; + + case 9: /* int */ + t.lo = *(int*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(int*)lv = u.lo; + break; + + case 10: /* uint */ + t.lo = *(uint*)lv; + t.hi = 0; + fn(&u, t, rv); + *(uint*)lv = u.lo; + break; + + case 5: /* long */ + t.lo = *(long*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(long*)lv = u.lo; + break; + + case 6: /* uint */ + t.lo = *(uint*)lv; + t.hi = 0; + fn(&u, t, rv); + *(uint*)lv = u.lo; + break; + + case 7: /* vlong */ + case 8: /* uvlong */ + fn(&u, *(Vlong*)lv, rv); + *(Vlong*)lv = u; + break; + } + *ret = u; +} + +void +_p2v(Vlong *ret, void *p) +{ + long t; + + t = (uint)p; + ret->lo = t; + ret->hi = 0; +} + +void +_sl2v(Vlong *ret, long sl) +{ + long t; + + t = sl; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_ul2v(Vlong *ret, uint ul) +{ + long t; + + t = ul; + ret->lo = t; + ret->hi = 0; +} + +void +_si2v(Vlong *ret, int si) +{ + long t; + + t = si; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_ui2v(Vlong *ret, uint ui) +{ + long t; + + t = ui; + ret->lo = t; + ret->hi = 0; +} + +void +_sh2v(Vlong *ret, long sh) +{ + long t; + + t = (sh << 16) >> 16; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_uh2v(Vlong *ret, uint ul) +{ + long t; + + t = ul & 0xffff; + ret->lo = t; + ret->hi = 0; +} + +void +_sc2v(Vlong *ret, long uc) +{ + long t; + + t = (uc << 24) >> 24; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_uc2v(Vlong *ret, uint ul) +{ + long t; + + t = ul & 0xff; + ret->lo = t; + ret->hi = 0; +} + +long +_v2sc(Vlong rv) +{ + long t; + + t = rv.lo & 0xff; + return (t << 24) >> 24; +} + +long +_v2uc(Vlong rv) +{ + + return rv.lo & 0xff; +} + +long +_v2sh(Vlong rv) +{ + long t; + + t = rv.lo & 0xffff; + return (t << 16) >> 16; +} + +long +_v2uh(Vlong rv) +{ + + return rv.lo & 0xffff; +} + +long +_v2sl(Vlong rv) +{ + + return rv.lo; +} + +long +_v2ul(Vlong rv) +{ + + return rv.lo; +} + +long +_v2si(Vlong rv) +{ + + return rv.lo; +} + +long +_v2ui(Vlong rv) +{ + + return rv.lo; +} + +int +_testv(Vlong rv) +{ + return rv.lo || rv.hi; +} + +int +_eqv(Vlong lv, Vlong rv) +{ + return lv.lo == rv.lo && lv.hi == rv.hi; +} + +int +_nev(Vlong lv, Vlong rv) +{ + return lv.lo != rv.lo || lv.hi != rv.hi; +} + +int +_ltv(Vlong lv, Vlong rv) +{ + return (long)lv.hi < (long)rv.hi || + (lv.hi == rv.hi && lv.lo < rv.lo); +} + +int +_lev(Vlong lv, Vlong rv) +{ + return (long)lv.hi < (long)rv.hi || + (lv.hi == rv.hi && lv.lo <= rv.lo); +} + +int +_gtv(Vlong lv, Vlong rv) +{ + return (long)lv.hi > (long)rv.hi || + (lv.hi == rv.hi && lv.lo > rv.lo); +} + +int +_gev(Vlong lv, Vlong rv) +{ + return (long)lv.hi > (long)rv.hi || + (lv.hi == rv.hi && lv.lo >= rv.lo); +} + +int +_lov(Vlong lv, Vlong rv) +{ + return lv.hi < rv.hi || + (lv.hi == rv.hi && lv.lo < rv.lo); +} + +int +_lsv(Vlong lv, Vlong rv) +{ + return lv.hi < rv.hi || + (lv.hi == rv.hi && lv.lo <= rv.lo); +} + +int +_hiv(Vlong lv, Vlong rv) +{ + return lv.hi > rv.hi || + (lv.hi == rv.hi && lv.lo > rv.lo); +} + +int +_hsv(Vlong lv, Vlong rv) +{ + return lv.hi > rv.hi || + (lv.hi == rv.hi && lv.lo >= rv.lo); +} diff --git a/sys/src/cmd/6l/asm.c b/sys/src/cmd/6l/asm.c new file mode 100644 index 000000000..5056aca19 --- /dev/null +++ b/sys/src/cmd/6l/asm.c @@ -0,0 +1,461 @@ +#include "l.h" + +#define Dbufslop 100 + +#define PADDR(a) ((a) & ~0xfffffffff0000000ull) + +vlong +entryvalue(void) +{ + char *a; + Sym *s; + + a = INITENTRY; + if(*a >= '0' && *a <= '9') + return atolwhex(a); + s = lookup(a, 0); + if(s->type == 0) + return INITTEXT; + switch(s->type) { + case STEXT: + break; + case SDATA: + if(dlm) + return s->value+INITDAT; + default: + diag("entry not text: %s", s->name); + } + return s->value; +} + +void +wputl(ushort w) +{ + cput(w); + cput(w>>8); +} + +void +wput(ushort w) +{ + cput(w>>8); + cput(w); +} + +void +lput(long l) +{ + cput(l>>24); + cput(l>>16); + cput(l>>8); + cput(l); +} + +void +llput(vlong v) +{ + lput(v>>32); + lput(v); +} + +void +lputl(long l) +{ + cput(l); + cput(l>>8); + cput(l>>16); + cput(l>>24); +} + +void +strnput(char *s, int n) +{ + for(; *s && n > 0; s++){ + cput(*s); + n--; + } + while(n > 0){ + cput(0); + n--; + } +} + +void +asmb(void) +{ + Prog *p; + long v, magic; + int a; + uchar *op1; + vlong vl; + + if(debug['v']) + Bprint(&bso, "%5.2f asmb\n", cputime()); + Bflush(&bso); + + seek(cout, HEADR, 0); + pc = INITTEXT; + curp = firstp; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->pc != pc) { + if(!debug['a']) + print("%P\n", curp); + diag("phase error %llux sb %llux in %s", p->pc, pc, TNAME); + pc = p->pc; + } + curp = p; + asmins(p); + a = (andptr - and); + if(cbc < a) + cflush(); + if(debug['a']) { + Bprint(&bso, pcstr, pc); + for(op1 = and; op1 < andptr; op1++) + Bprint(&bso, "%.2ux", *op1 & 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 %ld", HEADTYPE); + case 2: + case 5: + seek(cout, HEADR+textsize, 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 2: + case 5: + seek(cout, HEADR+textsize+datsize, 0); + break; + } + if(!debug['s']) + asmsym(); + if(debug['v']) + Bprint(&bso, "%5.2f sp\n", cputime()); + Bflush(&bso); + if(debug['v']) + Bprint(&bso, "%5.2f pc\n", cputime()); + Bflush(&bso); + if(!debug['s']) + asmlc(); + if(dlm) + asmdyn(); + cflush(); + } + else if(dlm){ + seek(cout, HEADR+textsize+datsize, 0); + asmdyn(); + cflush(); + } + if(debug['v']) + Bprint(&bso, "%5.2f headr\n", cputime()); + Bflush(&bso); + seek(cout, 0L, 0); + switch(HEADTYPE) { + default: + case 2: /* plan9 */ + magic = 4*26*26+7; + magic |= 0x00008000; /* fat header */ + if(dlm) + magic |= 0x80000000; /* dlm */ + lput(magic); /* magic */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(symsize); /* nsyms */ + vl = entryvalue(); + lput(PADDR(vl)); /* va of entry */ + lput(spsize); /* sp offsets */ + lput(lcsize); /* line offsets */ + llput(vl); /* va of entry */ + break; + case 3: /* plan9 */ + magic = 4*26*26+7; + if(dlm) + magic |= 0x80000000; + lput(magic); /* magic */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(symsize); /* nsyms */ + lput(entryvalue()); /* va of entry */ + lput(spsize); /* sp offsets */ + lput(lcsize); /* line offsets */ + break; + case 5: + strnput("\177ELF", 4); /* e_ident */ + cput(1); /* class = 32 bit */ + cput(1); /* data = LSB */ + cput(1); /* version = CURRENT */ + strnput("", 9); + wputl(2); /* type = EXEC */ + if(debug['8']) + wputl(3); /* machine = 386 */ + else + wputl(62); /* machine = AMD64 */ + lputl(1L); /* version = CURRENT */ + lputl(PADDR(entryvalue())); /* entry vaddr */ + lputl(52L); /* offset to first phdr */ + lputl(0L); /* offset to first shdr */ + lputl(0L); /* processor specific flags */ + wputl(52); /* Ehdr size */ + wputl(32); /* Phdr size */ + wputl(3); /* # of Phdrs */ + wputl(0); /* Shdr size */ + wputl(0); /* # of Shdrs */ + wputl(0); /* Shdr string size */ + + lputl(1L); /* text - type = PT_LOAD */ + lputl(HEADR); /* file offset */ + lputl(INITTEXT); /* vaddr */ + lputl(PADDR(INITTEXT)); /* paddr */ + lputl(textsize); /* file size */ + lputl(textsize); /* memory size */ + lputl(0x05L); /* protections = RX */ + lputl(INITRND); /* alignment */ + + lputl(1L); /* data - type = PT_LOAD */ + lputl(HEADR+textsize); /* file offset */ + lputl(INITDAT); /* vaddr */ + lputl(PADDR(INITDAT)); /* paddr */ + lputl(datsize); /* file size */ + lputl(datsize+bsssize); /* memory size */ + lputl(0x06L); /* protections = RW */ + lputl(INITRND); /* alignment */ + + lputl(0L); /* symbols - type = PT_NULL */ + lputl(HEADR+textsize+datsize); /* file offset */ + lputl(0L); + lputl(0L); + lputl(symsize); /* symbol table size */ + lputl(lcsize); /* line number size */ + lputl(0x04L); /* protections = R */ + lputl(0x04L); /* alignment */ + break; + } + cflush(); +} + +void +cflush(void) +{ + int n; + + n = sizeof(buf.cbuf) - cbc; + if(n) + write(cout, buf.cbuf, n); + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); +} + +void +datblk(long s, long n) +{ + Prog *p; + uchar *cast; + long l, fl, j; + vlong o; + int i, c; + + memset(buf.dbuf, 0, n+Dbufslop); + for(p = datap; p != P; p = p->link) { + curp = p; + l = p->from.sym->value + p->from.offset - s; + c = p->from.scale; + i = 0; + if(l < 0) { + if(l+c <= 0) + continue; + while(l < 0) { + l++; + i++; + } + } + if(l >= n) + continue; + if(p->as != AINIT && p->as != ADYNT) { + for(j=l+(c-i)-1; j>=l; j--) + if(buf.dbuf[j]) { + print("%P\n", p); + diag("multiple initialization"); + break; + } + } + switch(p->to.type) { + case D_FCONST: + switch(c) { + default: + case 4: + fl = ieeedtof(&p->to.ieee); + cast = (uchar*)&fl; + if(debug['a'] && i == 0) { + Bprint(&bso, pcstr, l+s+INITDAT); + for(j=0; jto.ieee; + if(debug['a'] && i == 0) { + Bprint(&bso, pcstr, l+s+INITDAT); + for(j=0; jto.scon[j] & 0xff); + Bprint(&bso, "\t%P\n", curp); + } + for(; ito.scon[i]; + l++; + } + break; + default: + o = p->to.offset; + if(p->to.type == D_ADDR) { + if(p->to.index != D_STATIC && p->to.index != D_EXTERN) + diag("DADDR type%P", p); + if(p->to.sym) { + if(p->to.sym->type == SUNDEF) + ckoff(p->to.sym, o); + o += p->to.sym->value; + if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF) + o += INITDAT; + if(dlm) + dynreloc(p->to.sym, l+s+INITDAT, 1); + } + } + fl = o; + cast = (uchar*)&fl; + switch(c) { + default: + diag("bad nuxi %d %d\n%P", c, i, curp); + break; + case 1: + if(debug['a'] && i == 0) { + Bprint(&bso, pcstr, l+s+INITDAT); + for(j=0; j +#include +#include +#include "../6c/6.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; +typedef struct Movtab Movtab; + +struct Adr +{ + union + { + vlong u0offset; + char u0scon[8]; + Prog *u0cond; /* not used, but should be D_BRANCH */ + Ieee u0ieee; + } u0; + union + { + Auto* u1autom; + Sym* u1sym; + } u1; + short type; + char index; + char scale; +}; + +#define offset u0.u0offset +#define scon u0.u0scon +#define cond u0.u0cond +#define ieee u0.u0ieee + +#define autom u1.u1autom +#define sym u1.u1sym + +struct Prog +{ + Adr from; + Adr to; + Prog *forwd; + Prog* link; + Prog* pcond; /* work on this */ + vlong pc; + long line; + uchar mark; /* work on these */ + uchar back; + + short as; + char width; /* fake for DATA */ + char mode; /* 16, 32, or 64 */ +}; +struct Auto +{ + Sym* asym; + Auto* link; + long aoffset; + short type; +}; +struct Sym +{ + char *name; + short type; + short version; + short become; + short frame; + uchar subtype; + ushort file; + vlong value; + long sig; + Sym* link; +}; +struct Optab +{ + short as; + uchar* ytab; + uchar prefix; + uchar op[20]; +}; +struct Movtab +{ + short as; + uchar ft; + uchar tt; + uchar code; + uchar op[4]; +}; + +enum +{ + STEXT = 1, + SDATA, + SBSS, + SDATA1, + SXREF, + SFILE, + SCONST, + SUNDEF, + + SIMPORT, + SEXPORT, + + NHASH = 10007, + NHUNK = 100000, + MINSIZ = 8, + STRINGSZ = 200, + MINLC = 1, + MAXIO = 8192, + MAXHIST = 20, /* limit of path elements for history symbols */ + + Yxxx = 0, + Ynone, + Yi0, + Yi1, + Yi8, + Ys32, + Yi32, + Yi64, + Yiauto, + Yal, + Ycl, + Yax, + Ycx, + Yrb, + Yrl, + Yrf, + Yf0, + Yrx, + Ymb, + Yml, + Ym, + Ybr, + Ycol, + + Ycs, Yss, Yds, Yes, Yfs, Ygs, + Ygdtr, Yidtr, Yldtr, Ymsw, Ytask, + Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ycr8, + Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7, + Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64, + Ymr, Ymm, + Yxr, Yxm, + Ymax, + + Zxxx = 0, + + Zlit, + Z_rp, + Zbr, + Zcall, + Zib_, + Zib_rp, + Zibo_m, + Zibo_m_xm, + Zil_, + Zil_rp, + Ziq_rp, + Zilo_m, + Ziqo_m, + Zjmp, + Zloop, + Zo_iw, + Zm_o, + Zm_r, + Zm_r_xm, + Zm_r_i_xm, + Zm_r_3d, + Zm_r_xm_nr, + Zr_m_xm_nr, + Zibm_r, /* mmx1,mmx2/mem64,imm8 */ + Zmb_r, + Zaut_r, + Zo_m, + Zo_m64, + Zpseudo, + Zr_m, + Zr_m_xm, + Zr_m_i_xm, + Zrp_, + Z_ib, + Z_il, + Zm_ibo, + Zm_ilo, + Zib_rr, + Zil_rr, + Zclr, + Zbyte, + Zmax, + + Px = 0, + P32 = 0x32, /* 32-bit only */ + Pe = 0x66, /* operand escape */ + Pm = 0x0f, /* 2byte opcode escape */ + Pq = 0xff, /* both escape */ + Pb = 0xfe, /* byte operands */ + Pf2 = 0xf2, /* xmm escape 1 */ + Pf3 = 0xf3, /* xmm escape 2 */ + Pw = 0x48, /* Rex.w */ + Py = 0x80, /* defaults to 64-bit mode */ + + Rxf = 1<<9, /* internal flag for Rxr on from */ + Rxt = 1<<8, /* internal flag for Rxr on to */ + Rxw = 1<<3, /* =1, 64-bit operand size */ + Rxr = 1<<2, /* extend modrm reg */ + Rxx = 1<<1, /* extend sib index */ + Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */ + + Roffset = 22, /* no. bits for offset in relocation address */ + Rindex = 10, /* no. bits for index in relocation address */ +}; + +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" int +#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* + +#pragma varargck argpos diag 1 + +EXTERN long HEADR; +EXTERN long HEADTYPE; +EXTERN vlong INITDAT; +EXTERN long INITRND; +EXTERN vlong INITTEXT; +EXTERN char* INITENTRY; /* entry point */ +EXTERN Biobuf bso; +EXTERN long bsssize; +EXTERN int cbc; +EXTERN char* cbp; +EXTERN char* pcstr; +EXTERN int cout; +EXTERN Auto* curauto; +EXTERN Auto* curhist; +EXTERN Prog* curp; +EXTERN Prog* curtext; +EXTERN Prog* datap; +EXTERN Prog* edatap; +EXTERN vlong datsize; +EXTERN char debug[128]; +EXTERN char literal[32]; +EXTERN Prog* etextp; +EXTERN Prog* firstp; +EXTERN uchar fnuxi8[8]; +EXTERN uchar fnuxi4[4]; +EXTERN Sym* hash[NHASH]; +EXTERN Sym* histfrog[MAXHIST]; +EXTERN int histfrogp; +EXTERN int histgen; +EXTERN char* library[50]; +EXTERN char* libraryobj[50]; +EXTERN int libraryp; +EXTERN int xrefresolv; +EXTERN char* hunk; +EXTERN uchar inuxi1[1]; +EXTERN uchar inuxi2[2]; +EXTERN uchar inuxi4[4]; +EXTERN uchar inuxi8[8]; +EXTERN char ycover[Ymax*Ymax]; +EXTERN uchar* andptr; +EXTERN uchar* rexptr; +EXTERN uchar and[30]; +EXTERN int reg[D_NONE]; +EXTERN int regrex[D_NONE+1]; +EXTERN Prog* lastp; +EXTERN long lcsize; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN long nsymbol; +EXTERN char* noname; +EXTERN char* outfile; +EXTERN vlong pc; +EXTERN long spsize; +EXTERN Sym* symlist; +EXTERN long symsize; +EXTERN Prog* textp; +EXTERN vlong textsize; +EXTERN long thunk; +EXTERN int version; +EXTERN Prog zprg; +EXTERN int dtype; +EXTERN char* paramspace; + +EXTERN Adr* reloca; +EXTERN int doexp, dlm; +EXTERN int imports, nimports; +EXTERN int exports, nexports; +EXTERN char* EXPTAB; +EXTERN Prog undefp; + +#define UP (&undefp) + +extern Optab optab[]; +extern Optab* opindex[]; +extern char* anames[]; + +int Aconv(Fmt*); +int Dconv(Fmt*); +int Pconv(Fmt*); +int Rconv(Fmt*); +int Sconv(Fmt*); +void addhist(long, int); +Prog* appendp(Prog*); +void asmb(void); +void asmdyn(void); +void asmins(Prog*); +void asmlc(void); +void asmsp(void); +void asmsym(void); +vlong atolwhex(char*); +Prog* brchain(Prog*); +Prog* brloop(Prog*); +void buildop(void); +void cflush(void); +void ckoff(Sym*, long); +Prog* copyp(Prog*); +double cputime(void); +void datblk(long, long); +void diag(char*, ...); +void dodata(void); +void doinit(void); +void doprof1(void); +void doprof2(void); +void dostkoff(void); +void dynreloc(Sym*, ulong, int); +vlong entryvalue(void); +void errorexit(void); +void export(void); +int find1(long, int); +int find2(long, int); +void follow(void); +void gethunk(void); +void histtoauto(void); +double ieeedtod(Ieee*); +long ieeedtof(Ieee*); +void import(void); +void ldobj(int, long, char*); +void loadlib(void); +void listinit(void); +Sym* lookup(char*, int); +void lput(long); +void lputl(long); +void main(int, char*[]); +void mkfwd(void); +void* mysbrk(ulong); +void nuxiinit(void); +void objfile(char*); +int opsize(Prog*); +void patch(void); +Prog* prg(void); +void readundefs(char*, int); +int relinv(int); +long reuse(Prog*, Sym*); +vlong rnd(vlong, vlong); +void span(void); +void undef(void); +void undefsym(Sym*); +vlong vaddr(Adr*); +void wput(ushort); +void xdefine(char*, int, vlong); +void xfol(Prog*); +int zaddr(uchar*, Adr*, Sym*[]); +void zerosig(char*); diff --git a/sys/src/cmd/6l/list.c b/sys/src/cmd/6l/list.c new file mode 100644 index 000000000..1109b02f6 --- /dev/null +++ b/sys/src/cmd/6l/list.c @@ -0,0 +1,350 @@ +#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, "%lld(%R)", a->offset, i-D_INDIR); + else + sprint(str, "(%R)", i-D_INDIR); + goto brk; + } + switch(i) { + + default: + if(a->offset) + sprint(str, "$%lld,%R", a->offset, i); + else + sprint(str, "%R", i); + break; + + case D_NONE: + str[0] = 0; + break; + + case D_BRANCH: + if(bigP != P && bigP->pcond != P) + if(a->sym != S) + sprint(str, "%llux+%s", bigP->pcond->pc, + a->sym->name); + else + sprint(str, "%llux", bigP->pcond->pc); + else + sprint(str, "%lld(PC)", a->offset); + break; + + case D_EXTERN: + sprint(str, "%s+%lld(SB)", a->sym->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<%d>+%lld(SB)", a->sym->name, + a->sym->version, a->offset); + break; + + case D_AUTO: + sprint(str, "%s+%lld(SP)", a->sym->name, a->offset); + break; + + case D_PARAM: + if(a->sym) + sprint(str, "%s+%lld(%s)", a->sym->name, a->offset, paramspace); + else + sprint(str, "%lld(%s)", a->offset, paramspace); + break; + + case D_CONST: + sprint(str, "$%lld", a->offset); + break; + + case D_FCONST: + sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->scon); + break; + + case D_ADDR: + a->type = a->index; + a->index = D_NONE; + sprint(str, "$%D", a); + a->index = a->type; + a->type = D_ADDR; + goto conv; + } +brk: + if(a->index != D_NONE) { + sprint(s, "(%R*%d)", a->index, a->scale); + strcat(str, s); + } +conv: + return fmtstrcpy(fp, str); +} + +char* regstr[] = +{ + "AL", /* [D_AL] */ + "CL", + "DL", + "BL", + "SPB", + "BPB", + "SIB", + "DIB", + "R8B", + "R9B", + "R10B", + "R11B", + "R12B", + "R13B", + "R14B", + "R15B", + + "AX", /* [D_AX] */ + "CX", + "DX", + "BX", + "SP", + "BP", + "SI", + "DI", + "R8", + "R9", + "R10", + "R11", + "R12", + "R13", + "R14", + "R15", + + "AH", + "CH", + "DH", + "BH", + + "F0", /* [D_F0] */ + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + + "M0", + "M1", + "M2", + "M3", + "M4", + "M5", + "M6", + "M7", + + "X0", + "X1", + "X2", + "X3", + "X4", + "X5", + "X6", + "X7", + "X8", + "X9", + "X10", + "X11", + "X12", + "X13", + "X14", + "X15", + + "CS", /* [D_CS] */ + "SS", + "DS", + "ES", + "FS", + "GS", + + "GDTR", /* [D_GDTR] */ + "IDTR", /* [D_IDTR] */ + "LDTR", /* [D_LDTR] */ + "MSW", /* [D_MSW] */ + "TASK", /* [D_TASK] */ + + "CR0", /* [D_CR] */ + "CR1", + "CR2", + "CR3", + "CR4", + "CR5", + "CR6", + "CR7", + "CR8", + "CR9", + "CR10", + "CR11", + "CR12", + "CR13", + "CR14", + "CR15", + + "DR0", /* [D_DR] */ + "DR1", + "DR2", + "DR3", + "DR4", + "DR5", + "DR6", + "DR7", + + "TR0", /* [D_TR] */ + "TR1", + "TR2", + "TR3", + "TR4", + "TR5", + "TR6", + "TR7", + + "NONE", /* [D_NONE] */ +}; + +int +Rconv(Fmt *fp) +{ + char str[20]; + int r; + + r = va_arg(fp->args, int); + if(r >= D_AL && r <= D_NONE) + sprint(str, "%s", regstr[r-D_AL]); + else + sprint(str, "gok(%d)", r); + + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[30], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + default: + if(c < 040 || c >= 0177) + break; /* not portable */ + p[-1] = c; + continue; + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} + +void +diag(char *fmt, ...) +{ + char buf[STRINGSZ], *tn; + va_list arg; + + tn = "??none??"; + if(curtext != P && curtext->from.sym != S) + tn = curtext->from.sym->name; + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + print("%s: %s\n", tn, buf); + + nerrors++; + if(nerrors > 20) { + print("too many errors\n"); + errorexit(); + } +} diff --git a/sys/src/cmd/6l/mkfile b/sys/src/cmd/6l/mkfile new file mode 100644 index 000000000..984224472 --- /dev/null +++ b/sys/src/cmd/6l/mkfile @@ -0,0 +1,31 @@ + + +#ifndef DEFAULT +#define DEFAULT '9' +#endif + +char *noname = ""; +char symname[] = SYMDEF; +char thechar = '6'; +char *thestring = "amd64"; +char *paramspace = "FP"; + +/* + * -H2 -T0x200028 -R0x200000 is plan9 format (was -T4136 -R4096) + * -H3 -T4128 -R4096 is plan9 32-bit format + * -H5 -T0x80110000 -R4096 is ELF32 + * + * options used: 189BLQSWabcjlnpsvz + */ + +static int +isobjfile(char *f) +{ + int n, v; + Biobuf *b; + char buf1[5], buf2[SARMAG]; + + b = Bopen(f, OREAD); + if(b == nil) + return 0; + n = Bread(b, buf1, 5); + if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<')) + v = 1; /* good enough for our purposes */ + else{ + Bseek(b, 0, 0); + n = Bread(b, buf2, SARMAG); + v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0; + } + Bterm(b); + return v; +} + +void +main(int argc, char *argv[]) +{ + int i, c; + char *a; + + Binit(&bso, 1, OWRITE); + cout = -1; + listinit(); + memset(debug, 0, sizeof(debug)); + nerrors = 0; + outfile = "6.out"; + HEADTYPE = -1; + INITTEXT = -1; + INITDAT = -1; + INITRND = -1; + INITENTRY = 0; + ARGBEGIN { + default: + c = ARGC(); + if(c >= 0 && c < sizeof(debug)) + debug[c]++; + break; + case 'o': /* output to (next arg) */ + outfile = ARGF(); + break; + case 'E': + a = ARGF(); + if(a) + INITENTRY = a; + break; + case 'H': + a = ARGF(); + if(a) + HEADTYPE = atolwhex(a); + break; + case 'T': + a = ARGF(); + if(a) + INITTEXT = atolwhex(a); + break; + case 'D': + a = ARGF(); + if(a) + INITDAT = atolwhex(a); + break; + case 'R': + a = ARGF(); + if(a) + INITRND = atolwhex(a); + break; + case 'x': /* produce export table */ + doexp = 1; + if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) + readundefs(ARGF(), SEXPORT); + break; + case 'u': /* produce dynamically loadable module */ + dlm = 1; + debug['l']++; + if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) + readundefs(ARGF(), SIMPORT); + break; + } ARGEND + USED(argc); + if(*argv == 0) { + diag("usage: 6l [-options] objects"); + errorexit(); + } + if(!debug['9'] && !debug['U'] && !debug['B']) + debug[DEFAULT] = 1; + if(HEADTYPE == -1) { + if(debug['B']) + HEADTYPE = 2; + if(debug['9']) + HEADTYPE = 2; + } + switch(HEADTYPE) { + default: + diag("unknown -H option"); + errorexit(); + case 2: /* plan 9 */ + HEADR = 32L+8L; + if(INITTEXT == -1) + INITTEXT = 0x200000+HEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 0x200000; + break; + case 3: /* plan 9 */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 4096+HEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case 5: /* elf32 executable */ + HEADR = rnd(52L+3*32L, 16); + if(INITTEXT == -1) + INITTEXT = 0xf0110000L; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + } + if(INITDAT != 0 && INITRND != 0) + print("warning: -D0x%llux is ignored because of -R0x%lux\n", + INITDAT, INITRND); + if(debug['v']) + Bprint(&bso, "HEADER = -H%ld -T0x%llux -D0x%llux -R0x%lux\n", + HEADTYPE, INITTEXT, INITDAT, INITRND); + Bflush(&bso); + for(i=1; optab[i].as; i++) { + c = optab[i].as; + if(opindex[c] != nil) { + diag("phase error in optab: %d (%A)", i, c); + errorexit(); + } + opindex[c] = &optab[i]; + } + + for(i=0; i= D_AL && i <= D_R15B) { + reg[i] = (i-D_AL) & 7; + if(i >= D_SPB && i <= D_DIB) + regrex[i] = 0x40; + if(i >= D_R8B && i <= D_R15B) + regrex[i] = Rxr | Rxx | Rxb; + } + if(i >= D_AH && i<= D_BH) + reg[i] = 4 + ((i-D_AH) & 7); + if(i >= D_AX && i <= D_R15) { + reg[i] = (i-D_AX) & 7; + if(i >= D_R8) + regrex[i] = Rxr | Rxx | Rxb; + } + if(i >= D_F0 && i <= D_F0+7) + reg[i] = (i-D_F0) & 7; + if(i >= D_M0 && i <= D_M0+7) + reg[i] = (i-D_M0) & 7; + if(i >= D_X0 && i <= D_X0+15) { + reg[i] = (i-D_X0) & 7; + if(i >= D_X0+8) + regrex[i] = Rxr | Rxx | Rxb; + } + if(i >= D_CR+8 && i <= D_CR+15) + regrex[i] = Rxr; + } + + zprg.link = P; + zprg.pcond = P; + zprg.back = 2; + zprg.as = AGOK; + zprg.from.type = D_NONE; + zprg.from.index = D_NONE; + zprg.from.scale = 1; + zprg.to = zprg.from; + zprg.mode = 64; + + pcstr = "%.6llux "; + nuxiinit(); + histgen = 0; + textp = P; + datap = P; + edatap = P; + pc = 0; + dtype = 4; + cout = create(outfile, 1, 0775); + if(cout < 0) { + diag("cannot create %s", outfile); + errorexit(); + } + version = 0; + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); + firstp = prg(); + lastp = firstp; + + if(INITENTRY == 0) { + INITENTRY = "_main"; + if(debug['p']) + INITENTRY = "_mainp"; + if(!debug['l']) + lookup(INITENTRY, 0)->type = SXREF; + } else if(!(*INITENTRY >= '0' && *INITENTRY <= '9')) + lookup(INITENTRY, 0)->type = SXREF; + + while(*argv) + objfile(*argv++); + if(!debug['l']) + loadlib(); + firstp = firstp->link; + if(firstp == P) + errorexit(); + if(doexp || dlm){ + EXPTAB = "_exporttab"; + zerosig(EXPTAB); + zerosig("etext"); + zerosig("edata"); + zerosig("end"); + if(dlm){ + import(); + HEADTYPE = 2; + INITTEXT = 0; + INITDAT = 0; + INITRND = 8; + INITENTRY = EXPTAB; + } + export(); + } + patch(); + follow(); + dodata(); + dostkoff(); + paramspace = "SP"; /* (FP) now (SP) on output */ + if(debug['p']) + if(debug['1']) + doprof1(); + else + doprof2(); + span(); + doinit(); + asmb(); + undef(); + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + Bprint(&bso, "%ld symbols\n", nsymbol); + Bprint(&bso, "%ld memory used\n", thunk); + Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); + Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); + } + Bflush(&bso); + + errorexit(); +} + +void +loadlib(void) +{ + int i; + long h; + Sym *s; + +loop: + xrefresolv = 0; + for(i=0; ilink) + if(s->type == SXREF) + goto loop; +} + +void +errorexit(void) +{ + + if(nerrors) { + if(cout >= 0) + remove(outfile); + exits("error"); + } + exits(0); +} + +void +objfile(char *file) +{ + long off, esym, cnt, l; + int f, work; + Sym *s; + char magbuf[SARMAG]; + char name[100], pname[150]; + struct ar_hdr arhdr; + char *e, *start, *stop; + + if(file[0] == '-' && file[1] == 'l') { + if(debug['9']) + sprint(name, "/%s/lib/lib", thestring); + else + sprint(name, "/usr/%clib/lib", thechar); + strcat(name, file+2); + strcat(name, ".a"); + file = name; + } + if(debug['v']) + Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file); + Bflush(&bso); + f = open(file, 0); + if(f < 0) { + diag("cannot open file: %s", file); + errorexit(); + } + l = read(f, magbuf, SARMAG); + if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){ + /* load it as a regular file */ + l = seek(f, 0L, 2); + seek(f, 0L, 0); + ldobj(f, l, file); + close(f); + return; + } + + l = read(f, &arhdr, SAR_HDR); + if(l != SAR_HDR) { + diag("%s: short read on archive file symbol header", file); + goto out; + } + if(strncmp(arhdr.name, symname, strlen(symname))) { + diag("%s: first entry not symbol header", file); + goto out; + } + + esym = SARMAG + SAR_HDR + atolwhex(arhdr.size); + off = SARMAG + SAR_HDR; + + /* + * just bang the whole symbol file into memory + */ + seek(f, off, 0); + cnt = esym - off; + start = malloc(cnt + 10); + cnt = read(f, start, cnt); + if(cnt <= 0){ + close(f); + return; + } + stop = &start[cnt]; + memset(stop, 0, 10); + + work = 1; + while(work) { + if(debug['v']) + Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file); + Bflush(&bso); + work = 0; + for(e = start; e < stop; e = strchr(e+5, 0) + 1) { + s = lookup(e+5, 0); + if(s->type != SXREF) + continue; + sprint(pname, "%s(%s)", file, s->name); + if(debug['v']) + Bprint(&bso, "%5.2f library: %s\n", cputime(), pname); + Bflush(&bso); + l = e[1] & 0xff; + l |= (e[2] & 0xff) << 8; + l |= (e[3] & 0xff) << 16; + l |= (e[4] & 0xff) << 24; + seek(f, l, 0); + l = read(f, &arhdr, SAR_HDR); + if(l != SAR_HDR) + goto bad; + if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag))) + goto bad; + l = atolwhex(arhdr.size); + ldobj(f, l, pname); + if(s->type == SXREF) { + diag("%s: failed to load: %s", file, s->name); + errorexit(); + } + work = 1; + xrefresolv = 1; + } + } + return; + +bad: + diag("%s: bad or out of date archive", file); +out: + close(f); +} + +int +zaddr(uchar *p, Adr *a, Sym *h[]) +{ + int c, t, i; + long l; + Sym *s; + Auto *u; + + t = p[0]; + c = 1; + if(t & T_INDEX) { + a->index = p[c]; + a->scale = p[c+1]; + c += 2; + } else { + a->index = D_NONE; + a->scale = 0; + } + a->offset = 0; + if(t & T_OFFSET) { + /* + * Hack until Charles fixes the compiler. + a->offset = (long)(p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24)); + */ + l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); + a->offset = l; + c += 4; + if(t & T_64) { + l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); + a->offset = ((vlong)l<<32) | (a->offset & 0xFFFFFFFFUL); + c += 4; + } + } + a->sym = S; + if(t & T_SYM) { + a->sym = h[p[c]]; + c++; + } + a->type = D_NONE; + if(t & T_FCONST) { + a->ieee.l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); + a->ieee.h = p[c+4] | (p[c+5]<<8) | (p[c+6]<<16) | (p[c+7]<<24); + c += 8; + a->type = D_FCONST; + } else + if(t & T_SCONST) { + for(i=0; iscon[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(; iname+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; iname = malloc(2*(histfrogp+1) + 1); + + u->asym = s; + u->type = type; + u->aoffset = line; + u->link = curhist; + curhist = u; + + j = 1; + for(i=0; ivalue; + 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; iname+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; iname+1, ".") == 0) { + memmove(histfrog+i, histfrog+i+1, + (histfrogp-i-1)*sizeof(histfrog[0])); + goto out; + } + + /* + * last chance, just truncate from front + */ + memmove(histfrog+0, histfrog+1, + (histfrogp-1)*sizeof(histfrog[0])); + +out: + histfrog[histfrogp-1] = s; +} + +void +nopout(Prog *p) +{ + p->as = ANOP; + p->from.type = D_NONE; + p->to.type = D_NONE; +} + +uchar* +readsome(int f, uchar *buf, uchar *good, uchar *stop, int max) +{ + int n; + + n = stop - good; + memmove(buf, good, stop - good); + stop = buf + n; + n = MAXIO - n; + if(n > max) + n = max; + n = read(f, stop, n); + if(n <= 0) + return 0; + return stop + n; +} + +void +ldobj(int f, long c, char *pn) +{ + vlong ipc; + Prog *p, *t; + uchar *bloc, *bsize, *stop; + int v, o, r, skip, mode; + Sym *h[NSYM], *s, *di; + ulong sig; + static int files; + static char **filen; + char **nfilen; + + if((files&15) == 0){ + nfilen = malloc((files+16)*sizeof(char*)); + memmove(nfilen, filen, files*sizeof(char*)); + free(filen); + filen = nfilen; + } + filen[files++] = strdup(pn); + + bsize = buf.xbuf; + bloc = buf.xbuf; + di = S; + +newloop: + memset(h, 0, sizeof(h)); + version++; + histfrogp = 0; + ipc = pc; + skip = 0; + mode = 64; + +loop: + if(c <= 0) + goto eof; + r = bsize - bloc; + if(r < 100 && r < c) { /* enough for largest prog */ + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + goto loop; + } + o = bloc[0] | (bloc[1] << 8); + if(o <= AXXX || o >= ALAST) { + if(o < 0) + goto eof; + diag("%s: opcode out of range %d", pn, o); + print(" probably not a .6 file\n"); + errorexit(); + } + + if(o == ANAME || o == ASIGNAME) { + sig = 0; + if(o == ASIGNAME) { + sig = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24); + bloc += 4; + c -= 4; + } + stop = memchr(&bloc[4], 0, bsize-&bloc[4]); + if(stop == 0){ + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + stop = memchr(&bloc[4], 0, bsize-&bloc[4]); + if(stop == 0){ + fprint(2, "%s: name too long\n", pn); + errorexit(); + } + } + v = bloc[2]; /* type */ + o = bloc[3]; /* sym */ + bloc += 4; + c -= 4; + + r = 0; + if(v == D_STATIC) + r = version; + s = lookup((char*)bloc, r); + c -= &stop[1] - bloc; + bloc = stop + 1; + + if(debug['S'] && r == 0) + sig = 1729; + if(sig != 0){ + if(s->sig != 0 && s->sig != sig) + diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name); + s->sig = sig; + s->file = files-1; + } + + if(debug['W']) + print(" ANAME %s\n", s->name); + h[o] = s; + if((v == D_EXTERN || v == D_STATIC) && s->type == 0) + s->type = SXREF; + if(v == D_FILE) { + if(s->type != SFILE) { + histgen++; + s->type = SFILE; + s->value = histgen; + } + if(histfrogp < MAXHIST) { + histfrog[histfrogp] = s; + histfrogp++; + } else + collapsefrog(s); + } + goto loop; + } + + 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; + p->mode = mode; + r = zaddr(bloc+6, &p->from, h) + 6; + r += zaddr(bloc+r, &p->to, h); + bloc += r; + c -= r; + + if(debug['W']) + print("%P\n", p); + + switch(p->as) { + case AHISTORY: + if(p->to.offset == -1) { + addlib(pn); + histfrogp = 0; + goto loop; + } + addhist(p->line, D_FILE); /* 'z' */ + if(p->to.offset) + addhist(p->to.offset, D_FILE1); /* 'Z' */ + histfrogp = 0; + goto loop; + + case AEND: + histtoauto(); + if(curtext != P) + curtext->to.autom = curauto; + curauto = 0; + curtext = P; + if(c) + goto newloop; + return; + + case AGLOBL: + s = p->from.sym; + if(s->type == 0 || s->type == SXREF) { + s->type = SBSS; + s->value = 0; + } + if(s->type != SBSS) { + diag("%s: redefinition: %s in %s", + pn, s->name, TNAME); + s->type = SBSS; + s->value = 0; + } + if(p->to.offset > s->value) + s->value = p->to.offset; + goto loop; + + case ADYNT: + if(p->to.sym == S) { + diag("DYNT without a sym\n%P", p); + break; + } + di = p->to.sym; + p->from.scale = 4; + if(di->type == SXREF) { + if(debug['z']) + Bprint(&bso, "%P set to %d\n", p, dtype); + di->type = SCONST; + di->value = dtype; + dtype += 4; + } + if(p->from.sym == S) + break; + + p->from.offset = di->value; + p->from.sym->type = SDATA; + if(curtext == P) { + diag("DYNT not in text: %P", p); + break; + } + p->to.sym = curtext->from.sym; + p->to.type = D_ADDR; + p->to.index = D_EXTERN; + goto data; + + case AINIT: + if(p->from.sym == S) { + diag("INIT without a sym\n%P", p); + break; + } + if(di == S) { + diag("INIT without previous DYNT\n%P", p); + break; + } + p->from.offset = di->value; + p->from.sym->type = SDATA; + goto data; + + case ADATA: + data: + if(edatap == P) + datap = p; + else + edatap->link = p; + edatap = p; + p->link = P; + goto loop; + + case AGOK: + diag("%s: GOK opcode in %s", pn, TNAME); + pc++; + goto loop; + + case ATEXT: + if(curtext != P) { + histtoauto(); + curtext->to.autom = curauto; + curauto = 0; + } + skip = 0; + curtext = p; + s = p->from.sym; + if(s == S) { + diag("%s: no TEXT symbol: %P", pn, p); + errorexit(); + } + if(s->type != 0 && s->type != SXREF) { + if(p->from.scale & DUPOK) { + skip = 1; + goto casdef; + } + diag("%s: redefinition: %s\n%P", pn, s->name, p); + } + s->type = STEXT; + s->value = pc; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + if(textp == P) { + textp = p; + etextp = p; + goto loop; + } + etextp->pcond = p; + etextp = p; + goto loop; + + case AMODE: + if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){ + switch((int)p->from.offset){ + case 16: case 32: case 64: + mode = p->from.offset; + break; + } + } + goto loop; + + case AFMOVF: + case AFADDF: + case AFSUBF: + case AFSUBRF: + case AFMULF: + case AFDIVF: + case AFDIVRF: + case AFCOMF: + case AFCOMFP: + case AMOVSS: + case AADDSS: + case ASUBSS: + case AMULSS: + case ADIVSS: + case ACOMISS: + case AUCOMISS: + if(skip) + goto casdef; + if(p->from.type == D_FCONST) { + /* size sb 9 max */ + sprint(literal, "$%lux", ieeedtof(&p->from.ieee)); + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SBSS; + s->value = 4; + t = prg(); + t->as = ADATA; + t->line = p->line; + t->from.type = D_EXTERN; + t->from.sym = s; + t->from.scale = 4; + t->to = p->from; + if(edatap == P) + datap = t; + else + edatap->link = t; + edatap = t; + t->link = P; + } + p->from.type = D_EXTERN; + p->from.sym = s; + p->from.offset = 0; + } + goto casdef; + + case AFMOVD: + case AFADDD: + case AFSUBD: + case AFSUBRD: + case AFMULD: + case AFDIVD: + case AFDIVRD: + case AFCOMD: + case AFCOMDP: + case AMOVSD: + case AADDSD: + case ASUBSD: + case AMULSD: + case ADIVSD: + case ACOMISD: + case AUCOMISD: + if(skip) + goto casdef; + if(p->from.type == D_FCONST) { + /* size sb 18 max */ + sprint(literal, "$%lux.%lux", + p->from.ieee.l, p->from.ieee.h); + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SBSS; + s->value = 8; + t = prg(); + t->as = ADATA; + t->line = p->line; + t->from.type = D_EXTERN; + t->from.sym = s; + t->from.scale = 8; + t->to = p->from; + if(edatap == P) + datap = t; + else + edatap->link = t; + edatap = t; + t->link = P; + } + p->from.type = D_EXTERN; + p->from.sym = s; + p->from.offset = 0; + } + goto casdef; + + casdef: + default: + if(skip) + nopout(p); + + if(p->to.type == D_BRANCH) + p->to.offset += ipc; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + goto loop; + } + goto loop; + +eof: + diag("truncated object file: %s", pn); +} + +Sym* +lookup(char *symb, int v) +{ + Sym *s; + char *p; + long h; + int l, c; + + h = v; + for(p=symb; c = *p; p++) + h = h+h+h + c; + l = (p - symb) + 1; + if(h < 0) + h = ~h; + h %= NHASH; + for(s = hash[h]; s != S; s = s->link) + if(s->version == v) + if(memcmp(s->name, symb, l) == 0) + return s; + + 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; + p->mode = q->mode; + 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, *q2, *ps2, *ps4; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 2\n", cputime()); + Bflush(&bso); + + if(debug['e']){ + s2 = lookup("_tracein", 0); + s4 = lookup("_traceout", 0); + }else{ + s2 = lookup("_profin", 0); + s4 = lookup("_profout", 0); + } + if(s2->type != STEXT || s4->type != STEXT) { + if(debug['e']) + diag("_tracein/_traceout not defined %d %d", s2->type, s4->type); + else + 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; + if(debug['e']){ /* embedded tracing */ + q2 = prg(); + p->link = q2; + q2->link = q; + + q2->line = p->line; + q2->pc = p->pc; + + q2->as = AJMP; + q2->to.type = D_BRANCH; + q2->to.sym = p->to.sym; + q2->pcond = q->link; + }else + 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 (default) + */ + if(debug['e']){ /* embedded tracing */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + } + /* + * RET + */ + q = prg(); + q->as = ARET; + q->from = p->from; + q->to = p->to; + q->link = p->link; + p->link = q; + + /* + * JAL profout + */ + p->as = ACALL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->pcond = ps4; + p->to.sym = s4; + + p = q; + + continue; + } + } +} + +void +nuxiinit(void) +{ + int i, c; + + for(i=0; i<4; i++) { + c = find1(0x04030201L, i+1); + if(i < 2) + inuxi2[i] = c; + if(i < 1) + inuxi1[i] = c; + inuxi4[i] = c; + inuxi8[i] = c; + inuxi8[i+4] = c+4; + fnuxi4[i] = c; + fnuxi8[i] = c; + fnuxi8[i+4] = c+4; + } + if(debug['v']) { + Bprint(&bso, "inuxi = "); + for(i=0; i<1; i++) + Bprint(&bso, "%d", inuxi1[i]); + Bprint(&bso, " "); + for(i=0; i<2; i++) + Bprint(&bso, "%d", inuxi2[i]); + Bprint(&bso, " "); + for(i=0; i<4; i++) + Bprint(&bso, "%d", inuxi4[i]); + Bprint(&bso, " "); + for(i=0; i<8; i++) + Bprint(&bso, "%d", inuxi8[i]); + Bprint(&bso, "\nfnuxi = "); + for(i=0; i<4; i++) + Bprint(&bso, "%d", fnuxi4[i]); + Bprint(&bso, " "); + for(i=0; i<8; i++) + Bprint(&bso, "%d", fnuxi8[i]); + Bprint(&bso, "\n"); + } + Bflush(&bso); +} + +int +find1(long l, int c) +{ + char *p; + int i; + + p = (char*)&l; + for(i=0; i<4; i++) + if(*p++ == c) + return i; + return 0; +} + +int +find2(long l, int c) +{ + short *p; + int i; + + p = (short*)&l; + for(i=0; i<4; i+=2) { + if(((*p >> 8) & 0xff) == c) + return i; + if((*p++ & 0xff) == c) + return i+1; + } + return 0; +} + +long +ieeedtof(Ieee *e) +{ + int exp; + long v; + + if(e->h == 0) + return 0; + exp = (e->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + v = (e->h & 0xfffffL) << 3; + v |= (e->l >> 29) & 0x7L; + if((e->l >> 28) & 1) { + v++; + if(v & 0x800000L) { + v = (v & 0x7fffffL) >> 1; + exp++; + } + } + if(exp <= -126 || exp >= 130) + diag("double fp to single fp overflow"); + v |= ((exp + 126) & 0xffL) << 23; + v |= e->h & 0x80000000L; + return v; +} + +double +ieeedtod(Ieee *ieeep) +{ + Ieee e; + double fr; + int exp; + + if(ieeep->h & (1L<<31)) { + e.h = ieeep->h & ~(1L<<31); + e.l = ieeep->l; + return -ieeedtod(&e); + } + if(ieeep->l == 0 && ieeep->h == 0) + return 0; + fr = ieeep->l & ((1L<<16)-1L); + fr /= 1L<<16; + fr += (ieeep->l>>16) & ((1L<<16)-1L); + fr /= 1L<<16; + fr += (ieeep->h & (1L<<20)-1L) | (1L<<20); + fr /= 1L<<21; + exp = (ieeep->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + return ldexp(fr, exp); +} + +void +undefsym(Sym *s) +{ + int n; + + n = imports; + if(s->value != 0) + diag("value != 0 on SXREF"); + if(n >= 1<value = n<type = SUNDEF; + imports++; +} + +void +zerosig(char *sp) +{ + Sym *s; + + s = lookup(sp, 0); + s->sig = 0; +} + +void +readundefs(char *f, int t) +{ + int i, n; + Sym *s; + Biobuf *b; + char *l, buf[256], *fields[64]; + + if(f == nil) + return; + b = Bopen(f, OREAD); + if(b == nil){ + diag("could not open %s: %r", f); + errorexit(); + } + while((l = Brdline(b, '\n')) != nil){ + n = Blinelen(b); + if(n >= sizeof(buf)){ + diag("%s: line too long", f); + errorexit(); + } + memmove(buf, l, n); + buf[n-1] = '\0'; + n = getfields(buf, fields, nelem(fields), 1, " \t\r\n"); + if(n == nelem(fields)){ + diag("%s: bad format", f); + errorexit(); + } + for(i = 0; i < n; i++){ + s = lookup(fields[i], 0); + s->type = SXREF; + s->subtype = t; + if(t == SIMPORT) + nimports++; + else + nexports++; + } + } + Bterm(b); +} diff --git a/sys/src/cmd/6l/optab.c b/sys/src/cmd/6l/optab.c new file mode 100644 index 000000000..c92132461 --- /dev/null +++ b/sys/src/cmd/6l/optab.c @@ -0,0 +1,1183 @@ +#include "l.h" + +uchar ynone[] = +{ + Ynone, Ynone, Zlit, 1, + 0 +}; +uchar ytext[] = +{ + Ymb, Yi32, Zpseudo,1, + 0 +}; +uchar ynop[] = +{ + Ynone, Ynone, Zpseudo,1, + Ynone, Yml, Zpseudo,1, + Ynone, Yrf, Zpseudo,1, + Yml, Ynone, Zpseudo,1, + Yrf, Ynone, Zpseudo,1, + 0 +}; +uchar yxorb[] = +{ + Yi32, Yal, Zib_, 1, + Yi32, Ymb, Zibo_m, 2, + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +uchar yxorl[] = +{ + Yi8, Yml, Zibo_m, 2, + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar yaddl[] = +{ + Yi8, Yml, Zibo_m, 2, + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar yincb[] = +{ + Ynone, Ymb, Zo_m, 2, + 0 +}; +uchar yincw[] = +{ + Ynone, Yml, Zo_m, 2, + 0 +}; +uchar yincl[] = +{ + Ynone, Yml, Zo_m, 2, + 0 +}; +uchar ycmpb[] = +{ + Yal, Yi32, Z_ib, 1, + Ymb, Yi32, Zm_ibo, 2, + Ymb, Yrb, Zm_r, 1, + Yrb, Ymb, Zr_m, 1, + 0 +}; +uchar ycmpl[] = +{ + Yml, Yi8, Zm_ibo, 2, + Yax, Yi32, Z_il, 1, + Yml, Yi32, Zm_ilo, 2, + Yml, Yrl, Zm_r, 1, + Yrl, Yml, Zr_m, 1, + 0 +}; +uchar yshb[] = +{ + Yi1, Ymb, Zo_m, 2, + Yi32, Ymb, Zibo_m, 2, + Ycx, Ymb, Zo_m, 2, + 0 +}; +uchar yshl[] = +{ + Yi1, Yml, Zo_m, 2, + Yi32, Yml, Zibo_m, 2, + Ycl, Yml, Zo_m, 2, + Ycx, Yml, Zo_m, 2, + 0 +}; +uchar ytestb[] = +{ + Yi32, Yal, Zib_, 1, + Yi32, Ymb, Zibo_m, 2, + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +uchar ytestl[] = +{ + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar ymovb[] = +{ + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + Yi32, Yrb, Zib_rp, 1, + Yi32, Ymb, Zibo_m, 2, + 0 +}; +uchar ymbs[] = +{ + Ymb, Ynone, Zm_o, 2, + 0 +}; +uchar ybtl[] = +{ + Yi8, Yml, Zibo_m, 2, + Yrl, Yml, Zr_m, 1, + 0 +}; +uchar ymovw[] = +{ + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + Yi0, Yrl, Zclr, 1, + Yi32, Yrl, Zil_rp, 1, + Yi32, Yml, Zilo_m, 2, + Yiauto, Yrl, Zaut_r, 2, + 0 +}; +uchar ymovl[] = +{ + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + Yi0, Yrl, Zclr, 1, + Yi32, Yrl, Zil_rp, 1, + Yi32, Yml, Zilo_m, 2, + Yml, Ymr, Zm_r_xm, 1, // MMX MOVD + Ymr, Yml, Zr_m_xm, 1, // MMX MOVD + Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit) + Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit) + Yiauto, Yrl, Zaut_r, 2, + 0 +}; +uchar yret[] = +{ + Ynone, Ynone, Zo_iw, 1, + Yi32, Ynone, Zo_iw, 1, + 0 +}; +uchar ymovq[] = +{ + Yrl, Yml, Zr_m, 1, // 0x89 + Yml, Yrl, Zm_r, 1, // 0x8b + Yi0, Yrl, Zclr, 1, // 0x31 + Ys32, Yrl, Zilo_m, 2, // 32 bit signed 0xc7,(0) + Yi64, Yrl, Ziq_rp, 1, // 0xb8 -- 32/64 bit immediate + Yi32, Yml, Zilo_m, 2, // 0xc7,(0) + Ym, Ymr, Zm_r_xm_nr, 1, // MMX MOVQ (shorter encoding) + Ymr, Ym, Zr_m_xm_nr, 1, // MMX MOVQ + Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD + Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD + Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q + Yxr, Ym, Zr_m_xm_nr, 2, // MOVQ xmm store + Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load + Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store + Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ + 0 +}; +uchar ym_rl[] = +{ + Ym, Yrl, Zm_r, 1, + 0 +}; +uchar yrl_m[] = +{ + Yrl, Ym, Zr_m, 1, + 0 +}; +uchar ymb_rl[] = +{ + Ymb, Yrl, Zmb_r, 1, + 0 +}; +uchar yml_rl[] = +{ + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar yrl_ml[] = +{ + Yrl, Yml, Zr_m, 1, + 0 +}; +uchar yml_mb[] = +{ + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +uchar yrb_mb[] = +{ + Yrb, Ymb, Zr_m, 1, + 0 +}; +uchar yml_ml[] = +{ + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar ydivl[] = +{ + Yml, Ynone, Zm_o, 2, + 0 +}; +uchar ydivb[] = +{ + Ymb, Ynone, Zm_o, 2, + 0 +}; +uchar yimul[] = +{ + Yml, Ynone, Zm_o, 2, + Yi8, Yrl, Zib_rr, 1, + Yi32, Yrl, Zil_rr, 1, + Yml, Yrl, Zm_r, 2, + 0 +}; +uchar ybyte[] = +{ + Yi64, Ynone, Zbyte, 1, + 0 +}; +uchar yin[] = +{ + Yi32, Ynone, Zib_, 1, + Ynone, Ynone, Zlit, 1, + 0 +}; +uchar yint[] = +{ + Yi32, Ynone, Zib_, 1, + 0 +}; +uchar ypushl[] = +{ + Yrl, Ynone, Zrp_, 1, + Ym, Ynone, Zm_o, 2, + Yi8, Ynone, Zib_, 1, + Yi32, Ynone, Zil_, 1, + 0 +}; +uchar ypopl[] = +{ + Ynone, Yrl, Z_rp, 1, + Ynone, Ym, Zo_m, 2, + 0 +}; +uchar yscond[] = +{ + Ynone, Ymb, Zo_m, 2, + 0 +}; +uchar yjcond[] = +{ + Ynone, Ybr, Zbr, 1, + 0 +}; +uchar yloop[] = +{ + Ynone, Ybr, Zloop, 1, + 0 +}; +uchar ycall[] = +{ + Ynone, Yml, Zo_m64, 2, + Ynone, Ybr, Zcall, 1, + 0 +}; +uchar yjmp[] = +{ + Ynone, Yml, Zo_m64, 2, + Ynone, Ybr, Zjmp, 1, + 0 +}; + +uchar yfmvd[] = +{ + Ym, Yf0, Zm_o, 2, + Yf0, Ym, Zo_m, 2, + Yrf, Yf0, Zm_o, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfmvdp[] = +{ + Yf0, Ym, Zo_m, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfmvf[] = +{ + Ym, Yf0, Zm_o, 2, + Yf0, Ym, Zo_m, 2, + 0 +}; +uchar yfmvx[] = +{ + Ym, Yf0, Zm_o, 2, + 0 +}; +uchar yfmvp[] = +{ + Yf0, Ym, Zo_m, 2, + 0 +}; +uchar yfadd[] = +{ + Ym, Yf0, Zm_o, 2, + Yrf, Yf0, Zm_o, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfaddp[] = +{ + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfxch[] = +{ + Yf0, Yrf, Zo_m, 2, + Yrf, Yf0, Zm_o, 2, + 0 +}; +uchar ycompp[] = +{ + Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */ + 0 +}; +uchar ystsw[] = +{ + Ynone, Ym, Zo_m, 2, + Ynone, Yax, Zlit, 1, + 0 +}; +uchar ystcw[] = +{ + Ynone, Ym, Zo_m, 2, + Ym, Ynone, Zm_o, 2, + 0 +}; +uchar ysvrs[] = +{ + Ynone, Ym, Zo_m, 2, + Ym, Ynone, Zm_o, 2, + 0 +}; +uchar ymm[] = +{ + Ymm, Ymr, Zm_r_xm, 1, + Yxm, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yxm[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxcvm1[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + Yxm, Ymr, Zm_r_xm, 2, + 0 +}; +uchar yxcvm2[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + Ymm, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yxmq[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yxr[] = +{ + Yxr, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxr_ml[] = +{ + Yxr, Yml, Zr_m_xm, 1, + 0 +}; +uchar ymr[] = +{ + Ymr, Ymr, Zm_r, 1, + 0 +}; +uchar ymr_ml[] = +{ + Ymr, Yml, Zr_m_xm, 1, + 0 +}; +uchar yxcmp[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxcmpi[] = +{ + Yxm, Yxr, Zm_r_i_xm, 2, + 0 +}; +uchar yxmov[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + Yxr, Yxm, Zr_m_xm, 1, + 0 +}; +uchar yxcvfl[] = +{ + Yxm, Yrl, Zm_r_xm, 1, + 0 +}; +uchar yxcvlf[] = +{ + Yml, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxcvfq[] = +{ + Yxm, Yrl, Zm_r_xm, 2, + 0 +}; +uchar yxcvqf[] = +{ + Yml, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yps[] = +{ + Ymm, Ymr, Zm_r_xm, 1, + Yi8, Ymr, Zibo_m_xm, 2, + Yxm, Yxr, Zm_r_xm, 2, + Yi8, Yxr, Zibo_m_xm, 3, + 0 +}; +uchar yxrrl[] = +{ + Yxr, Yrl, Zm_r, 1, + 0 +}; +uchar ymfp[] = +{ + Ymm, Ymr, Zm_r_3d, 1, + 0, +}; +uchar ymrxr[] = +{ + Ymr, Yxr, Zm_r, 1, + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +uchar ymshuf[] = +{ + Ymm, Ymr, Zibm_r, 1, + 0 +}; +uchar yxshuf[] = +{ + Yxm, Yxr, Zibm_r, 1, + 0 +}; +uchar yextrw[] = +{ + Yxr, Yrl, Zibm_r, 1, + 0 +}; +uchar ypsdq[] = +{ + Yi8, Yxr, Zibo_m, 2, + 0 +}; +uchar ymskb[] = +{ + Yxr, Yrl, Zm_r_xm, 2, + Ymr, Yrl, Zm_r_xm, 1, + 0 +}; + +Optab optab[] = +/* as, ytab, andproto, opcode */ +{ + { AXXX }, + { AAAA, ynone, P32, 0x37 }, + { AAAD, ynone, P32, 0xd5,0x0a }, + { AAAM, ynone, P32, 0xd4,0x0a }, + { AAAS, ynone, P32, 0x3f }, + { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 }, + { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADCQ, yxorl, Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADDB, yxorb, Pb, 0x04,0x80,(00),0x00,0x02 }, + { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + { AADDPD, yxm, Pq, 0x58 }, + { AADDPS, yxm, Pm, 0x58 }, + { AADDQ, yaddl, Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + { AADDSD, yxm, Pf2, 0x58 }, + { AADDSS, yxm, Pf3, 0x58 }, + { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + { AADJSP }, + { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 }, + { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, + { AANDNPD, yxm, Pq, 0x55 }, + { AANDNPS, yxm, Pm, 0x55 }, + { AANDPD, yxm, Pq, 0x54 }, + { AANDPS, yxm, Pq, 0x54 }, + { AANDQ, yxorl, Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, + { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, + { AARPL, yrl_ml, P32, 0x63 }, + { ABOUNDL, yrl_m, P32, 0x62 }, + { ABOUNDW, yrl_m, Pe, 0x62 }, + { ABSFL, yml_rl, Pm, 0xbc }, + { ABSFQ, yml_rl, Pw, 0x0f,0xbc }, + { ABSFW, yml_rl, Pq, 0xbc }, + { ABSRL, yml_rl, Pm, 0xbd }, + { ABSRQ, yml_rl, Pw, 0x0f,0xbd }, + { ABSRW, yml_rl, Pq, 0xbd }, + { ABTCL, ybtl, Pm, 0xba,(07),0xbb }, + { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb }, + { ABTCW, ybtl, Pq, 0xba,(07),0xbb }, + { ABTL, ybtl, Pm, 0xba,(04),0xa3 }, + { ABTQ, ybtl, Pw, 0x0f,0xba,(04),0x0f,0xa3}, + { ABTRL, ybtl, Pm, 0xba,(06),0xb3 }, + { ABTRQ, ybtl, Pw, 0x0f,0xba,(06),0x0f,0xb3 }, + { ABTRW, ybtl, Pq, 0xba,(06),0xb3 }, + { ABTSL, ybtl, Pm, 0xba,(05),0xab }, + { ABTSQ, ybtl, Pw, 0x0f,0xba,(05),0x0f,0xab }, + { ABTSW, ybtl, Pq, 0xba,(05),0xab }, + { ABTW, ybtl, Pq, 0xba,(04),0xa3 }, + { ABYTE, ybyte, Px, 1 }, + { ACALL, ycall, Px, 0xff,(02),0xe8 }, + { ACDQ, ynone, Px, 0x99 }, + { ACLC, ynone, Px, 0xf8 }, + { ACLD, ynone, Px, 0xfc }, + { ACLI, ynone, Px, 0xfa }, + { ACLTS, ynone, Pm, 0x06 }, + { ACMC, ynone, Px, 0xf5 }, + { ACMOVLCC, yml_rl, Pm, 0x43 }, + { ACMOVLCS, yml_rl, Pm, 0x42 }, + { ACMOVLEQ, yml_rl, Pm, 0x44 }, + { ACMOVLGE, yml_rl, Pm, 0x4d }, + { ACMOVLGT, yml_rl, Pm, 0x4f }, + { ACMOVLHI, yml_rl, Pm, 0x47 }, + { ACMOVLLE, yml_rl, Pm, 0x4e }, + { ACMOVLLS, yml_rl, Pm, 0x46 }, + { ACMOVLLT, yml_rl, Pm, 0x4c }, + { ACMOVLMI, yml_rl, Pm, 0x48 }, + { ACMOVLNE, yml_rl, Pm, 0x45 }, + { ACMOVLOC, yml_rl, Pm, 0x41 }, + { ACMOVLOS, yml_rl, Pm, 0x40 }, + { ACMOVLPC, yml_rl, Pm, 0x4b }, + { ACMOVLPL, yml_rl, Pm, 0x49 }, + { ACMOVLPS, yml_rl, Pm, 0x4a }, + { ACMOVQCC, yml_rl, Pw, 0x0f,0x43 }, + { ACMOVQCS, yml_rl, Pw, 0x0f,0x42 }, + { ACMOVQEQ, yml_rl, Pw, 0x0f,0x44 }, + { ACMOVQGE, yml_rl, Pw, 0x0f,0x4d }, + { ACMOVQGT, yml_rl, Pw, 0x0f,0x4f }, + { ACMOVQHI, yml_rl, Pw, 0x0f,0x47 }, + { ACMOVQLE, yml_rl, Pw, 0x0f,0x4e }, + { ACMOVQLS, yml_rl, Pw, 0x0f,0x46 }, + { ACMOVQLT, yml_rl, Pw, 0x0f,0x4c }, + { ACMOVQMI, yml_rl, Pw, 0x0f,0x48 }, + { ACMOVQNE, yml_rl, Pw, 0x0f,0x45 }, + { ACMOVQOC, yml_rl, Pw, 0x0f,0x41 }, + { ACMOVQOS, yml_rl, Pw, 0x0f,0x40 }, + { ACMOVQPC, yml_rl, Pw, 0x0f,0x4b }, + { ACMOVQPL, yml_rl, Pw, 0x0f,0x49 }, + { ACMOVQPS, yml_rl, Pw, 0x0f,0x4a }, + { ACMOVWCC, yml_rl, Pq, 0x43 }, + { ACMOVWCS, yml_rl, Pq, 0x42 }, + { ACMOVWEQ, yml_rl, Pq, 0x44 }, + { ACMOVWGE, yml_rl, Pq, 0x4d }, + { ACMOVWGT, yml_rl, Pq, 0x4f }, + { ACMOVWHI, yml_rl, Pq, 0x47 }, + { ACMOVWLE, yml_rl, Pq, 0x4e }, + { ACMOVWLS, yml_rl, Pq, 0x46 }, + { ACMOVWLT, yml_rl, Pq, 0x4c }, + { ACMOVWMI, yml_rl, Pq, 0x48 }, + { ACMOVWNE, yml_rl, Pq, 0x45 }, + { ACMOVWOC, yml_rl, Pq, 0x41 }, + { ACMOVWOS, yml_rl, Pq, 0x40 }, + { ACMOVWPC, yml_rl, Pq, 0x4b }, + { ACMOVWPL, yml_rl, Pq, 0x49 }, + { ACMOVWPS, yml_rl, Pq, 0x4a }, + { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a }, + { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACMPPD, yxcmpi, Px, Pe,0xc2 }, + { ACMPPS, yxcmpi, Pm, 0xc2,0 }, + { ACMPQ, ycmpl, Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACMPSB, ynone, Pb, 0xa6 }, + { ACMPSD, yxcmpi, Px, Pf2,0xc2 }, + { ACMPSL, ynone, Px, 0xa7 }, + { ACMPSQ, ynone, Pw, 0xa7 }, + { ACMPSS, yxcmpi, Px, Pf3,0xc2 }, + { ACMPSW, ynone, Pe, 0xa7 }, + { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACOMISD, yxcmp, Pe, 0x2f }, + { ACOMISS, yxcmp, Pm, 0x2f }, + { ACPUID, ynone, Pm, 0xa2 }, + { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a }, + { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, }, + { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d }, + { ACVTPD2PS, yxm, Pe, 0x5a }, + { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d }, + { ACVTPS2PD, yxm, Pm, 0x5a }, + { API2FW, ymfp, Px, 0x0c }, + { ACVTSD2SL, yxcvfl, Pf2, 0x2d }, + { ACVTSD2SQ, yxcvfq, Pw, Pf2,0x2d }, + { ACVTSD2SS, yxm, Pf2, 0x5a }, + { ACVTSL2SD, yxcvlf, Pf2, 0x2a }, + { ACVTSQ2SD, yxcvqf, Pw, Pf2,0x2a }, + { ACVTSL2SS, yxcvlf, Pf3, 0x2a }, + { ACVTSQ2SS, yxcvqf, Pw, Pf3,0x2a }, + { ACVTSS2SD, yxm, Pf3, 0x5a }, + { ACVTSS2SL, yxcvfl, Pf3, 0x2d }, + { ACVTSS2SQ, yxcvfq, Pw, Pf3,0x2d }, + { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c }, + { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c }, + { ACVTTSD2SL, yxcvfl, Pf2, 0x2c }, + { ACVTTSD2SQ, yxcvfq, Pw, Pf2,0x2c }, + { ACVTTSS2SL, yxcvfl, Pf3, 0x2c }, + { ACVTTSS2SQ, yxcvfq, Pw, Pf3,0x2c }, + { ACWD, ynone, Pe, 0x99 }, + { ACQO, ynone, Pw, 0x99 }, + { ADAA, ynone, P32, 0x27 }, + { ADAS, ynone, P32, 0x2f }, + { ADATA }, + { ADECB, yincb, Pb, 0xfe,(01) }, + { ADECL, yincl, Px, 0xff,(01) }, + { ADECQ, yincl, Pw, 0xff,(01) }, + { ADECW, yincw, Pe, 0xff,(01) }, + { ADIVB, ydivb, Pb, 0xf6,(06) }, + { ADIVL, ydivl, Px, 0xf7,(06) }, + { ADIVPD, yxm, Pe, 0x5e }, + { ADIVPS, yxm, Pm, 0x5e }, + { ADIVQ, ydivl, Pw, 0xf7,(06) }, + { ADIVSD, yxm, Pf2, 0x5e }, + { ADIVSS, yxm, Pf3, 0x5e }, + { ADIVW, ydivl, Pe, 0xf7,(06) }, + { AEMMS, ynone, Pm, 0x77 }, + { AENTER }, /* botch */ + { AFXRSTOR, ysvrs, Pm, 0xae,(01),0xae,(01) }, + { AFXSAVE, ysvrs, Pm, 0xae,(00),0xae,(00) }, + { AFXRSTOR64, ysvrs, Pw, 0x0f,0xae,(01),0x0f,0xae,(01) }, + { AFXSAVE64, ysvrs, Pw, 0x0f,0xae,(00),0x0f,0xae,(00) }, + { AGLOBL }, + { AGOK }, + { AHISTORY }, + { AHLT, ynone, Px, 0xf4 }, + { AIDIVB, ydivb, Pb, 0xf6,(07) }, + { AIDIVL, ydivl, Px, 0xf7,(07) }, + { AIDIVQ, ydivl, Pw, 0xf7,(07) }, + { AIDIVW, ydivl, Pe, 0xf7,(07) }, + { AIMULB, ydivb, Pb, 0xf6,(05) }, + { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf }, + { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf }, + { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf }, + { AINB, yin, Pb, 0xe4,0xec }, + { AINCB, yincb, Pb, 0xfe,(00) }, + { AINCL, yincl, Px, 0xff,(00) }, + { AINCQ, yincl, Pw, 0xff,(00) }, + { AINCW, yincw, Pe, 0xff,(00) }, + { AINL, yin, Px, 0xe5,0xed }, + { AINSB, ynone, Pb, 0x6c }, + { AINSL, ynone, Px, 0x6d }, + { AINSW, ynone, Pe, 0x6d }, + { AINT, yint, Px, 0xcd }, + { AINTO, ynone, P32, 0xce }, + { AINW, yin, Pe, 0xe5,0xed }, + { AIRETL, ynone, Px, 0xcf }, + { AIRETQ, ynone, Pw, 0xcf }, + { AIRETW, ynone, Pe, 0xcf }, + { AJCC, yjcond, Px, 0x73,0x83,(00) }, + { AJCS, yjcond, Px, 0x72,0x82 }, + { AJCXZ, yloop, Px, 0xe3 }, + { AJEQ, yjcond, Px, 0x74,0x84 }, + { AJGE, yjcond, Px, 0x7d,0x8d }, + { AJGT, yjcond, Px, 0x7f,0x8f }, + { AJHI, yjcond, Px, 0x77,0x87 }, + { AJLE, yjcond, Px, 0x7e,0x8e }, + { AJLS, yjcond, Px, 0x76,0x86 }, + { AJLT, yjcond, Px, 0x7c,0x8c }, + { AJMI, yjcond, Px, 0x78,0x88 }, + { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 }, + { AJNE, yjcond, Px, 0x75,0x85 }, + { AJOC, yjcond, Px, 0x71,0x81,(00) }, + { AJOS, yjcond, Px, 0x70,0x80,(00) }, + { AJPC, yjcond, Px, 0x7b,0x8b }, + { AJPL, yjcond, Px, 0x79,0x89 }, + { AJPS, yjcond, Px, 0x7a,0x8a }, + { ALAHF, ynone, Px, 0x9f }, + { ALARL, yml_rl, Pm, 0x02 }, + { ALARW, yml_rl, Pq, 0x02 }, + { ALDMXCSR, ysvrs, Pm, 0xae,(02),0xae,(02) }, + { ALEAL, ym_rl, Px, 0x8d }, + { ALEAQ, ym_rl, Pw, 0x8d }, + { ALEAVEL, ynone, P32, 0xc9 }, + { ALEAVEQ, ynone, Py, 0xc9 }, + { ALEAVEW, ynone, Pe, 0xc9 }, + { ALEAW, ym_rl, Pe, 0x8d }, + { ALOCK, ynone, Px, 0xf0 }, + { ALODSB, ynone, Pb, 0xac }, + { ALODSL, ynone, Px, 0xad }, + { ALODSQ, ynone, Pw, 0xad }, + { ALODSW, ynone, Pe, 0xad }, + { ALONG, ybyte, Px, 4 }, + { ALOOP, yloop, Px, 0xe2 }, + { ALOOPEQ, yloop, Px, 0xe1 }, + { ALOOPNE, yloop, Px, 0xe0 }, + { ALSLL, yml_rl, Pm, 0x03 }, + { ALSLW, yml_rl, Pq, 0x03 }, + { AMASKMOVOU, yxr, Pe, 0xf7 }, + { AMASKMOVQ, ymr, Pm, 0xf7 }, + { AMAXPD, yxm, Pe, 0x5f }, + { AMAXPS, yxm, Pm, 0x5f }, + { AMAXSD, yxm, Pf2, 0x5f }, + { AMAXSS, yxm, Pf3, 0x5f }, + { AMINPD, yxm, Pe, 0x5d }, + { AMINPS, yxm, Pm, 0x5d }, + { AMINSD, yxm, Pf2, 0x5d }, + { AMINSS, yxm, Pf3, 0x5d }, + { AMOVAPD, yxmov, Pe, 0x28,0x29 }, + { AMOVAPS, yxmov, Pm, 0x28,0x29 }, + { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) }, + { AMOVBLSX, ymb_rl, Pm, 0xbe }, + { AMOVBLZX, ymb_rl, Pm, 0xb6 }, + { AMOVBQSX, ymb_rl, Pw, 0x0f,0xbe }, + { AMOVBQZX, ymb_rl, Pw, 0x0f,0xb6 }, + { AMOVBWSX, ymb_rl, Pq, 0xbe }, + { AMOVBWZX, ymb_rl, Pq, 0xb6 }, + { AMOVO, yxmov, Pe, 0x6f,0x7f }, + { AMOVOU, yxmov, Pf3, 0x6f,0x7f }, + { AMOVHLPS, yxr, Pm, 0x12 }, + { AMOVHPD, yxmov, Pe, 0x16,0x17 }, + { AMOVHPS, yxmov, Pm, 0x16,0x17 }, + { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e }, + { AMOVLHPS, yxr, Pm, 0x16 }, + { AMOVLPD, yxmov, Pe, 0x12,0x13 }, + { AMOVLPS, yxmov, Pm, 0x12,0x13 }, + { AMOVLQSX, yml_rl, Pw, 0x63 }, + { AMOVLQZX, yml_rl, Px, 0x63 }, + { AMOVMSKPD, yxrrl, Pq, 0x50 }, + { AMOVMSKPS, yxrrl, Pm, 0x50 }, + { AMOVNTO, yxr_ml, Pe, 0xe7 }, + { AMOVNTPD, yxr_ml, Pe, 0x2b }, + { AMOVNTPS, yxr_ml, Pm, 0x2b }, + { AMOVNTQ, ymr_ml, Pm, 0xe7 }, + { AMOVQ, ymovq, Pw, 0x89,0x8b,0x31,0xc7,(00),0xb8,0xc7,(00),0x6f,0x7f,0x6e,0x7e,Pf2,0xd6,Pe,0xd6,Pe,0x6e,Pe,0x7e }, + { AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e }, + { AMOVSB, ynone, Pb, 0xa4 }, + { AMOVSD, yxmov, Pf2, 0x10,0x11 }, + { AMOVSL, ynone, Px, 0xa5 }, + { AMOVSQ, ynone, Pw, 0xa5 }, + { AMOVSS, yxmov, Pf3, 0x10,0x11 }, + { AMOVSW, ynone, Pe, 0xa5 }, + { AMOVUPD, yxmov, Pe, 0x10,0x11 }, + { AMOVUPS, yxmov, Pm, 0x10,0x11 }, + { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0xb8,0xc7,(00) }, + { AMOVWLSX, yml_rl, Pm, 0xbf }, + { AMOVWLZX, yml_rl, Pm, 0xb7 }, + { AMOVWQSX, yml_rl, Pw, 0x0f,0xbf }, + { AMOVWQZX, yml_rl, Pw, 0x0f,0xb7 }, + { AMULB, ydivb, Pb, 0xf6,(04) }, + { AMULL, ydivl, Px, 0xf7,(04) }, + { AMULPD, yxm, Pe, 0x59 }, + { AMULPS, yxm, Ym, 0x59 }, + { AMULQ, ydivl, Pw, 0xf7,(04) }, + { AMULSD, yxm, Pf2, 0x59 }, + { AMULSS, yxm, Pf3, 0x59 }, + { AMULW, ydivl, Pe, 0xf7,(04) }, + { ANAME }, + { ANEGB, yscond, Pb, 0xf6,(03) }, + { ANEGL, yscond, Px, 0xf7,(03) }, + { ANEGQ, yscond, Pw, 0xf7,(03) }, + { ANEGW, yscond, Pe, 0xf7,(03) }, + { ANOP, ynop, Px, 0,0 }, + { ANOTB, yscond, Pb, 0xf6,(02) }, + { ANOTL, yscond, Px, 0xf7,(02) }, + { ANOTQ, yscond, Pw, 0xf7,(02) }, + { ANOTW, yscond, Pe, 0xf7,(02) }, + { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a }, + { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, + { AORPD, yxm, Pq, 0x56 }, + { AORPS, yxm, Pm, 0x56 }, + { AORQ, yxorl, Pw, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, + { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, + { AOUTB, yin, Pb, 0xe6,0xee }, + { AOUTL, yin, Px, 0xe7,0xef }, + { AOUTSB, ynone, Pb, 0x6e }, + { AOUTSL, ynone, Px, 0x6f }, + { AOUTSW, ynone, Pe, 0x6f }, + { AOUTW, yin, Pe, 0xe7,0xef }, + { APACKSSLW, ymm, Py, 0x6b,Pe,0x6b }, + { APACKSSWB, ymm, Py, 0x63,Pe,0x63 }, + { APACKUSWB, ymm, Py, 0x67,Pe,0x67 }, + { APADDB, ymm, Py, 0xfc,Pe,0xfc }, + { APADDL, ymm, Py, 0xfe,Pe,0xfe }, + { APADDQ, yxm, Pe, 0xd4 }, + { APADDSB, ymm, Py, 0xec,Pe,0xec }, + { APADDSW, ymm, Py, 0xed,Pe,0xed }, + { APADDUSB, ymm, Py, 0xdc,Pe,0xdc }, + { APADDUSW, ymm, Py, 0xdd,Pe,0xdd }, + { APADDW, ymm, Py, 0xfd,Pe,0xfd }, + { APAND, ymm, Py, 0xdb,Pe,0xdb }, + { APANDN, ymm, Py, 0xdf,Pe,0xdf }, + { APAVGB, ymm, Py, 0xe0,Pe,0xe0 }, + { APAVGW, ymm, Py, 0xe3,Pe,0xe3 }, + { APCMPEQB, ymm, Py, 0x74,Pe,0x74 }, + { APCMPEQL, ymm, Py, 0x76,Pe,0x76 }, + { APCMPEQW, ymm, Py, 0x75,Pe,0x75 }, + { APCMPGTB, ymm, Py, 0x64,Pe,0x64 }, + { APCMPGTL, ymm, Py, 0x66,Pe,0x66 }, + { APCMPGTW, ymm, Py, 0x65,Pe,0x65 }, + { APEXTRW, yextrw, Pq, 0xc5 }, + { APF2IL, ymfp, Px, 0x1d }, + { APF2IW, ymfp, Px, 0x1c }, + { API2FL, ymfp, Px, 0x0d }, + { APFACC, ymfp, Px, 0xae }, + { APFADD, ymfp, Px, 0x9e }, + { APFCMPEQ, ymfp, Px, 0xb0 }, + { APFCMPGE, ymfp, Px, 0x90 }, + { APFCMPGT, ymfp, Px, 0xa0 }, + { APFMAX, ymfp, Px, 0xa4 }, + { APFMIN, ymfp, Px, 0x94 }, + { APFMUL, ymfp, Px, 0xb4 }, + { APFNACC, ymfp, Px, 0x8a }, + { APFPNACC, ymfp, Px, 0x8e }, + { APFRCP, ymfp, Px, 0x96 }, + { APFRCPIT1, ymfp, Px, 0xa6 }, + { APFRCPI2T, ymfp, Px, 0xb6 }, + { APFRSQIT1, ymfp, Px, 0xa7 }, + { APFRSQRT, ymfp, Px, 0x97 }, + { APFSUB, ymfp, Px, 0x9a }, + { APFSUBR, ymfp, Px, 0xaa }, + { APINSRW, yextrw, Pq, 0xc4 }, + { APMADDWL, ymm, Py, 0xf5,Pe,0xf5 }, + { APMAXSW, yxm, Pe, 0xee }, + { APMAXUB, yxm, Pe, 0xde }, + { APMINSW, yxm, Pe, 0xea }, + { APMINUB, yxm, Pe, 0xda }, + { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 }, + { APMULHRW, ymfp, Px, 0xb7 }, + { APMULHUW, ymm, Py, 0xe4,Pe,0xe4 }, + { APMULHW, ymm, Py, 0xe5,Pe,0xe5 }, + { APMULLW, ymm, Py, 0xd5,Pe,0xd5 }, + { APMULULQ, ymm, Py, 0xf4,Pe,0xf4 }, + { APOPAL, ynone, P32, 0x61 }, + { APOPAW, ynone, Pe, 0x61 }, + { APOPFL, ynone, P32, 0x9d }, + { APOPFQ, ynone, Py, 0x9d }, + { APOPFW, ynone, Pe, 0x9d }, + { APOPL, ypopl, P32, 0x58,0x8f,(00) }, + { APOPQ, ypopl, Py, 0x58,0x8f,(00) }, + { APOPW, ypopl, Pe, 0x58,0x8f,(00) }, + { APOR, ymm, Py, 0xeb,Pe,0xeb }, + { APSADBW, yxm, Pq, 0xf6 }, + { APSHUFHW, yxshuf, Pf3, 0x70 }, + { APSHUFL, yxshuf, Pq, 0x70 }, + { APSHUFLW, yxshuf, Pf2, 0x70 }, + { APSHUFW, ymshuf, Pm, 0x70 }, + { APSLLO, ypsdq, Pq, 0x73,(07) }, + { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) }, + { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x7e,(06) }, + { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) }, + { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) }, + { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) }, + { APSRLO, ypsdq, Pq, 0x73,(03) }, + { APSRLL, yps, Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) }, + { APSRLQ, yps, Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) }, + { APSRLW, yps, Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) }, + { APSUBB, yxm, Pe, 0xf8 }, + { APSUBL, yxm, Pe, 0xfa }, + { APSUBQ, yxm, Pe, 0xfb }, + { APSUBSB, yxm, Pe, 0xe8 }, + { APSUBSW, yxm, Pe, 0xe9 }, + { APSUBUSB, yxm, Pe, 0xd8 }, + { APSUBUSW, yxm, Pe, 0xd9 }, + { APSUBW, yxm, Pe, 0xf9 }, + { APSWAPL, ymfp, Px, 0xbb }, + { APUNPCKHBW, ymm, Py, 0x68,Pe,0x68 }, + { APUNPCKHLQ, ymm, Py, 0x6a,Pe,0x6a }, + { APUNPCKHQDQ, yxm, Pe, 0x6d }, + { APUNPCKHWL, ymm, Py, 0x69,Pe,0x69 }, + { APUNPCKLBW, ymm, Py, 0x60,Pe,0x60 }, + { APUNPCKLLQ, ymm, Py, 0x62,Pe,0x62 }, + { APUNPCKLQDQ, yxm, Pe, 0x6c }, + { APUNPCKLWL, ymm, Py, 0x61,Pe,0x61 }, + { APUSHAL, ynone, P32, 0x60 }, + { APUSHAW, ynone, Pe, 0x60 }, + { APUSHFL, ynone, P32, 0x9c }, + { APUSHFQ, ynone, Py, 0x9c }, + { APUSHFW, ynone, Pe, 0x9c }, + { APUSHL, ypushl, P32, 0x50,0xff,(06),0x6a,0x68 }, + { APUSHQ, ypushl, Py, 0x50,0xff,(06),0x6a,0x68 }, + { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 }, + { APXOR, ymm, Py, 0xef,Pe,0xef }, + { AQUAD, ybyte, Px, 8 }, + { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) }, + { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCLQ, yshl, Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCPPS, yxm, Pm, 0x53 }, + { ARCPSS, yxm, Pf3, 0x53 }, + { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) }, + { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, + { ARCRQ, yshl, Pw, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, + { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, + { AREP, ynone, Px, 0xf3 }, + { AREPN, ynone, Px, 0xf2 }, + { ARET, ynone, Px, 0xc3 }, + { ARETFW, yret, Pe, 0xcb,0xca }, + { ARETFL, yret, Px, 0xcb,0xca }, + { ARETFQ, yret, Pw, 0xcb,0xca }, + { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) }, + { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, + { AROLQ, yshl, Pw, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, + { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, + { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) }, + { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, + { ARORQ, yshl, Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, + { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, + { ARSQRTPS, yxm, Pm, 0x52 }, + { ARSQRTSS, yxm, Pf3, 0x52 }, + { ASAHF, ynone, Px, 0x86,0xe0,0x50,0x9d }, /* XCHGB AH,AL; PUSH AX; POPFL */ + { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, + { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASALQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) }, + { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, + { ASARQ, yshl, Pw, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, + { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, + { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a }, + { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, + { ASBBQ, yxorl, Pw, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, + { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, + { ASCASB, ynone, Pb, 0xae }, + { ASCASL, ynone, Px, 0xaf }, + { ASCASQ, ynone, Pw, 0xaf }, + { ASCASW, ynone, Pe, 0xaf }, + { ASETCC, yscond, Pm, 0x93,(00) }, + { ASETCS, yscond, Pm, 0x92,(00) }, + { ASETEQ, yscond, Pm, 0x94,(00) }, + { ASETGE, yscond, Pm, 0x9d,(00) }, + { ASETGT, yscond, Pm, 0x9f,(00) }, + { ASETHI, yscond, Pm, 0x97,(00) }, + { ASETLE, yscond, Pm, 0x9e,(00) }, + { ASETLS, yscond, Pm, 0x96,(00) }, + { ASETLT, yscond, Pm, 0x9c,(00) }, + { ASETMI, yscond, Pm, 0x98,(00) }, + { ASETNE, yscond, Pm, 0x95,(00) }, + { ASETOC, yscond, Pm, 0x91,(00) }, + { ASETOS, yscond, Pm, 0x90,(00) }, + { ASETPC, yscond, Pm, 0x96,(00) }, + { ASETPL, yscond, Pm, 0x99,(00) }, + { ASETPS, yscond, Pm, 0x9a,(00) }, + { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, + { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASHLQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) }, + { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, + { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, + { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, + { ASHUFPD, yxshuf, Pq, 0xc6 }, + { ASHUFPS, yxshuf, Pm, 0xc6 }, + { ASQRTPD, yxm, Pe, 0x51 }, + { ASQRTPS, yxm, Pm, 0x51 }, + { ASQRTSD, yxm, Pf2, 0x51 }, + { ASQRTSS, yxm, Pf3, 0x51 }, + { ASTC, ynone, Px, 0xf9 }, + { ASTD, ynone, Px, 0xfd }, + { ASTI, ynone, Px, 0xfb }, + { ASTMXCSR, ysvrs, Pm, 0xae,(03),0xae,(03) }, + { ASTOSB, ynone, Pb, 0xaa }, + { ASTOSL, ynone, Px, 0xab }, + { ASTOSQ, ynone, Pw, 0xab }, + { ASTOSW, ynone, Pe, 0xab }, + { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a }, + { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, + { ASUBPD, yxm, Pe, 0x5c }, + { ASUBPS, yxm, Pm, 0x5c }, + { ASUBQ, yaddl, Pw, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, + { ASUBSD, yxm, Pf2, 0x5c }, + { ASUBSS, yxm, Pf3, 0x5c }, + { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, + { ASWAPGS, ynone, Pm, 0x01,0xf8 }, + { ASYSCALL, ynone, Px, 0x0f,0x05 }, /* fast syscall */ + { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 }, + { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 }, + { ATESTQ, ytestl, Pw, 0xa9,0xf7,(00),0x85,0x85 }, + { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 }, + { ATEXT, ytext, Px }, + { AUCOMISD, yxcmp, Pe, 0x2e }, + { AUCOMISS, yxcmp, Pm, 0x2e }, + { AUNPCKHPD, yxm, Pe, 0x15 }, + { AUNPCKHPS, yxm, Pm, 0x15 }, + { AUNPCKLPD, yxm, Pe, 0x14 }, + { AUNPCKLPS, yxm, Pm, 0x14 }, + { AVERR, ydivl, Pm, 0x00,(04) }, + { AVERW, ydivl, Pm, 0x00,(05) }, + { AWAIT, ynone, Px, 0x9b }, + { AWORD, ybyte, Px, 2 }, + { AXCHGB, yml_mb, Pb, 0x86,0x86 }, + { AXCHGL, yml_ml, Px, 0x87,0x87 }, + { AXCHGQ, yml_ml, Pw, 0x87,0x87 }, + { AXCHGW, yml_ml, Pe, 0x87,0x87 }, + { AXLAT, ynone, Px, 0xd7 }, + { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 }, + { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, + { AXORPD, yxm, Pe, 0x57 }, + { AXORPS, yxm, Pm, 0x57 }, + { AXORQ, yxorl, Pw, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, + { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, + + { AFMOVB, yfmvx, Px, 0xdf,(04) }, + { AFMOVBP, yfmvp, Px, 0xdf,(06) }, + { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) }, + { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) }, + { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) }, + { AFMOVFP, yfmvp, Px, 0xd9,(03) }, + { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) }, + { AFMOVLP, yfmvp, Px, 0xdb,(03) }, + { AFMOVV, yfmvx, Px, 0xdf,(05) }, + { AFMOVVP, yfmvp, Px, 0xdf,(07) }, + { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) }, + { AFMOVWP, yfmvp, Px, 0xdf,(03) }, + { AFMOVX, yfmvx, Px, 0xdb,(05) }, + { AFMOVXP, yfmvp, Px, 0xdb,(07) }, + + { AFCOMB }, + { AFCOMBP }, + { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */ + { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */ + { AFCOMDPP, ycompp, Px, 0xde,(03) }, + { AFCOMF, yfmvx, Px, 0xd8,(02) }, + { AFCOMFP, yfmvx, Px, 0xd8,(03) }, + { AFCOML, yfmvx, Px, 0xda,(02) }, + { AFCOMLP, yfmvx, Px, 0xda,(03) }, + { AFCOMW, yfmvx, Px, 0xde,(02) }, + { AFCOMWP, yfmvx, Px, 0xde,(03) }, + + { AFUCOM, ycompp, Px, 0xdd,(04) }, + { AFUCOMP, ycompp, Px, 0xdd,(05) }, + { AFUCOMPP, ycompp, Px, 0xda,(13) }, + + { AFADDDP, yfaddp, Px, 0xde,(00) }, + { AFADDW, yfmvx, Px, 0xde,(00) }, + { AFADDL, yfmvx, Px, 0xda,(00) }, + { AFADDF, yfmvx, Px, 0xd8,(00) }, + { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) }, + + { AFMULDP, yfaddp, Px, 0xde,(01) }, + { AFMULW, yfmvx, Px, 0xde,(01) }, + { AFMULL, yfmvx, Px, 0xda,(01) }, + { AFMULF, yfmvx, Px, 0xd8,(01) }, + { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) }, + + { AFSUBDP, yfaddp, Px, 0xde,(05) }, + { AFSUBW, yfmvx, Px, 0xde,(04) }, + { AFSUBL, yfmvx, Px, 0xda,(04) }, + { AFSUBF, yfmvx, Px, 0xd8,(04) }, + { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) }, + + { AFSUBRDP, yfaddp, Px, 0xde,(04) }, + { AFSUBRW, yfmvx, Px, 0xde,(05) }, + { AFSUBRL, yfmvx, Px, 0xda,(05) }, + { AFSUBRF, yfmvx, Px, 0xd8,(05) }, + { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) }, + + { AFDIVDP, yfaddp, Px, 0xde,(07) }, + { AFDIVW, yfmvx, Px, 0xde,(06) }, + { AFDIVL, yfmvx, Px, 0xda,(06) }, + { AFDIVF, yfmvx, Px, 0xd8,(06) }, + { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) }, + + { AFDIVRDP, yfaddp, Px, 0xde,(06) }, + { AFDIVRW, yfmvx, Px, 0xde,(07) }, + { AFDIVRL, yfmvx, Px, 0xda,(07) }, + { AFDIVRF, yfmvx, Px, 0xd8,(07) }, + { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) }, + + { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) }, + { AFFREE }, + { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) }, + { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) }, + { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) }, + { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) }, + { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) }, + { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) }, + { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 }, + { AF2XM1, ynone, Px, 0xd9, 0xf0 }, + { AFABS, ynone, Px, 0xd9, 0xe1 }, + { AFCHS, ynone, Px, 0xd9, 0xe0 }, + { AFCLEX, ynone, Px, 0xdb, 0xe2 }, + { AFCOS, ynone, Px, 0xd9, 0xff }, + { AFDECSTP, ynone, Px, 0xd9, 0xf6 }, + { AFINCSTP, ynone, Px, 0xd9, 0xf7 }, + { AFINIT, ynone, Px, 0xdb, 0xe3 }, + { AFLD1, ynone, Px, 0xd9, 0xe8 }, + { AFLDL2E, ynone, Px, 0xd9, 0xea }, + { AFLDL2T, ynone, Px, 0xd9, 0xe9 }, + { AFLDLG2, ynone, Px, 0xd9, 0xec }, + { AFLDLN2, ynone, Px, 0xd9, 0xed }, + { AFLDPI, ynone, Px, 0xd9, 0xeb }, + { AFLDZ, ynone, Px, 0xd9, 0xee }, + { AFNOP, ynone, Px, 0xd9, 0xd0 }, + { AFPATAN, ynone, Px, 0xd9, 0xf3 }, + { AFPREM, ynone, Px, 0xd9, 0xf8 }, + { AFPREM1, ynone, Px, 0xd9, 0xf5 }, + { AFPTAN, ynone, Px, 0xd9, 0xf2 }, + { AFRNDINT, ynone, Px, 0xd9, 0xfc }, + { AFSCALE, ynone, Px, 0xd9, 0xfd }, + { AFSIN, ynone, Px, 0xd9, 0xfe }, + { AFSINCOS, ynone, Px, 0xd9, 0xfb }, + { AFSQRT, ynone, Px, 0xd9, 0xfa }, + { AFTST, ynone, Px, 0xd9, 0xe4 }, + { AFXAM, ynone, Px, 0xd9, 0xe5 }, + { AFXTRACT, ynone, Px, 0xd9, 0xf4 }, + { AFYL2X, ynone, Px, 0xd9, 0xf1 }, + { AFYL2XP1, ynone, Px, 0xd9, 0xf9 }, + + { ACMPXCHGB, yrb_mb, Pb, 0x0f,0xb0 }, + { ACMPXCHGL, yrl_ml, Px, 0x0f,0xb1 }, + { ACMPXCHGW, yrl_ml, Pe, 0x0f,0xb1 }, + { ACMPXCHGQ, yrl_ml, Pw, 0x0f,0xb1 }, + { ACMPXCHG8B, yscond, Pm, 0xc7,(01) }, + { AINVD, ynone, Pm, 0x08 }, + { AINVLPG, ymbs, Pm, 0x01,(07) }, + { ALFENCE, ynone, Pm, 0xae,0xe8 }, + { AMFENCE, ynone, Pm, 0xae,0xf0 }, + { AMOVNTIL, yrl_ml, Pm, 0xc3 }, + { AMOVNTIQ, yrl_ml, Pw, 0x0f,0xc3 }, + { ARDMSR, ynone, Pm, 0x32 }, + { ARDPMC, ynone, Pm, 0x33 }, + { ARDTSC, ynone, Pm, 0x31 }, + { ARSM, ynone, Pm, 0xaa }, + { ASFENCE, ynone, Pm, 0xae,0xf8 }, + { ASYSRET, ynone, Pm, 0x07 }, + { AWBINVD, ynone, Pm, 0x09 }, + { AWRMSR, ynone, Pm, 0x30 }, + + { AXADDB, yrb_mb, Pb, 0x0f,0xc0 }, + { AXADDL, yrl_ml, Px, 0x0f,0xc1 }, + { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 }, + { AXADDW, yrl_ml, Pe, 0x0f,0xc1 }, + + { AEND }, + 0 +}; + +Optab* opindex[ALAST+1]; + +/* +AMOVD 0f 6e/r mmx,reg/mem32[mem64-rex?] +AMOVD 0f 7e/r reg/mem32[64],mmx STORE +AMOVQ 0f 6f/r mmx1,mmx2/mem64 +AMOVQ 0f 7f/r mmx1/mem64,mmx2 +*/ diff --git a/sys/src/cmd/6l/pass.c b/sys/src/cmd/6l/pass.c new file mode 100644 index 000000000..e21171bfb --- /dev/null +++ b/sys/src/cmd/6l/pass.c @@ -0,0 +1,790 @@ +#include "l.h" + +void +dodata(void) +{ + int i; + Sym *s; + Prog *p; + long t, u; + + if(debug['v']) + Bprint(&bso, "%5.2f dodata\n", cputime()); + Bflush(&bso); + for(p = datap; p != P; p = p->link) { + s = p->from.sym; + if(p->as == ADYNT || p->as == AINIT) + s->value = dtype; + if(s->type == SBSS) + s->type = SDATA; + if(s->type != SDATA) + diag("initialize non-data (%d): %s\n%P", + s->type, s->name, p); + t = p->from.offset + p->width; + if(t > s->value) + diag("initialize bounds (%lld): %s\n%P", + s->value, s->name, p); + } + /* allocate small guys */ + datsize = 0; + for(i=0; ilink) { + if(s->type != SDATA) + if(s->type != SBSS) + continue; + t = s->value; + if(t == 0) { + diag("%s: no size", s->name); + t = 1; + } + t = rnd(t, 4); + s->value = t; + if(t > MINSIZ) + continue; + if(t >= 8) + datsize = rnd(datsize, 8); + s->value = datsize; + datsize += t; + s->type = SDATA1; + } + + /* allocate the rest of the data */ + for(i=0; ilink) { + if(s->type != SDATA) { + if(s->type == SDATA1) + s->type = SDATA; + continue; + } + t = s->value; + if(t >= 8) + datsize = rnd(datsize, 8); + s->value = datsize; + datsize += t; + } + if(datsize) + datsize = rnd(datsize, 8); + + if(debug['j']) { + /* + * pad data with bss that fits up to next + * 8k boundary, then push data to 8k + */ + u = rnd(datsize, 8192); + u -= datsize; + for(i=0; ilink) { + 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; ilink) { + if(s->type != SBSS) + continue; + t = s->value; + if(t >= 8) + bsssize = rnd(bsssize, 8); + s->value = bsssize + datsize; + bsssize += t; + } + xdefine("edata", SBSS, datsize); + xdefine("end", SBSS, bsssize + datsize); +} + +Prog* +brchain(Prog *p) +{ + int i; + + for(i=0; i<20; i++) { + if(p == P || p->as != AJMP) + return p; + p = p->pcond; + } + return P; +} + +void +follow(void) +{ + + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + firstp = prg(); + lastp = firstp; + xfol(textp); + lastp->link = P; + firstp = firstp->link; +} + +void +xfol(Prog *p) +{ + Prog *q; + int i; + enum as a; + +loop: + if(p == P) + return; + if(p->as == ATEXT) + curtext = p; + if(p->as == AJMP) + if((q = p->pcond) != P) { + p->mark = 1; + p = q; + if(p->mark == 0) + goto loop; + } + if(p->mark) { + /* copy up to 4 instructions to avoid branch */ + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == P) + break; + if(q == lastp) + break; + a = q->as; + if(a == ANOP) { + i--; + continue; + } + switch(a) { + case AJMP: + case ARET: + case AIRETL: + case AIRETQ: + case AIRETW: + case ARETFL: + case ARETFQ: + case ARETFW: + + case APUSHL: + case APUSHFL: + case APUSHQ: + case APUSHFQ: + case APUSHW: + case APUSHFW: + case APOPL: + case APOPFL: + case APOPQ: + case APOPFQ: + case APOPW: + case APOPFW: + goto brk; + } + if(q->pcond == P || q->pcond->mark) + continue; + if(a == ACALL || a == ALOOP) + continue; + for(;;) { + if(p->as == ANOP) { + p = p->link; + continue; + } + q = copyp(p); + p = p->link; + q->mark = 1; + lastp->link = q; + lastp = q; + if(q->as != a || q->pcond == P || q->pcond->mark) + continue; + + q->as = relinv(q->as); + p = q->pcond; + q->pcond = q->link; + q->link = p; + xfol(q->link); + p = q->link; + if(p->mark) + return; + goto loop; + } + } /* */ + brk:; + q = prg(); + q->as = AJMP; + q->line = p->line; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->pcond = p; + p = q; + } + p->mark = 1; + lastp->link = p; + lastp = p; + a = p->as; + if(a == AJMP || a == ARET || a == AIRETL || a == AIRETQ || a == AIRETW || + a == ARETFL || a == ARETFQ || a == ARETFW) + return; + if(p->pcond != P) + if(a != ACALL) { + q = brchain(p->link); + if(q != P && q->mark) + if(a != ALOOP) { + p->as = relinv(a); + p->link = p->pcond; + p->pcond = q; + } + xfol(p->link); + q = brchain(p->pcond); + if(q->mark) { + p->pcond = q; + return; + } + p = q; + goto loop; + } + p = p->link; + goto loop; +} + +int +relinv(int a) +{ + + switch(a) { + case AJEQ: return AJNE; + case AJNE: return AJEQ; + case AJLE: return AJGT; + case AJLS: return AJHI; + case AJLT: return AJGE; + case AJMI: return AJPL; + case AJGE: return AJLT; + case AJPL: return AJMI; + case AJGT: return AJLE; + case AJHI: return AJLS; + case AJCS: return AJCC; + case AJCC: return AJCS; + case AJPS: return AJPC; + case AJPC: return AJPS; + case AJOS: return AJOC; + case AJOC: return AJOS; + } + diag("unknown relation: %s in %s", anames[a], TNAME); + return a; +} + +void +doinit(void) +{ + Sym *s; + Prog *p; + int x; + + for(p = datap; p != P; p = p->link) { + x = p->to.type; + if(x != D_EXTERN && x != D_STATIC) + continue; + s = p->to.sym; + if(s->type == 0 || s->type == SXREF) + diag("undefined %s initializer of %s", + s->name, p->from.sym->name); + p->to.offset += s->value; + p->to.type = D_CONST; + if(s->type == SDATA || s->type == SBSS) + p->to.offset += INITDAT; + } +} + +void +patch(void) +{ + long c; + Prog *p, *q; + Sym *s; + long vexit; + + if(debug['v']) + Bprint(&bso, "%5.2f mkfwd\n", cputime()); + Bflush(&bso); + mkfwd(); + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + s = lookup("exit", 0); + vexit = s->value; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->as == ACALL || p->as == ARET) { + s = p->to.sym; + if(s) { + if(debug['c']) + Bprint(&bso, "%s calls %s\n", TNAME, s->name); + switch(s->type) { + default: + diag("undefined: %s in %s", s->name, TNAME); + s->type = STEXT; + s->value = vexit; + break; /* or fall through to set offset? */ + case STEXT: + p->to.offset = s->value; + break; + case SUNDEF: + p->pcond = UP; + p->to.offset = 0; + break; + } + p->to.type = D_BRANCH; + } + } + if(p->to.type != D_BRANCH || p->pcond == UP) + continue; + c = p->to.offset; + for(q = firstp; q != P;) { + if(q->forwd != P) + if(c >= q->forwd->pc) { + q = q->forwd; + continue; + } + if(c == q->pc) + break; + q = q->link; + } + if(q == P) { + diag("branch out of range in %s\n%P", TNAME, p); + p->to.type = D_NONE; + } + p->pcond = q; + } + + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + p->mark = 0; /* initialization for follow */ + if(p->pcond != P && p->pcond != UP) { + p->pcond = brloop(p->pcond); + if(p->pcond != P) + if(p->to.type == D_BRANCH) + p->to.offset = p->pcond->pc; + } + } +} + +#define LOG 5 +void +mkfwd(void) +{ + Prog *p; + int i; + long dwn[LOG], cnt[LOG]; + Prog *lst[LOG]; + + for(i=0; ilink) { + if(p->as == ATEXT) + curtext = p; + i--; + if(i < 0) + i = LOG-1; + p->forwd = P; + dwn[i]--; + if(dwn[i] <= 0) { + dwn[i] = cnt[i]; + if(lst[i] != P) + lst[i]->forwd = p; + lst[i] = p; + } + } +} + +Prog* +brloop(Prog *p) +{ + int c; + Prog *q; + + c = 0; + for(q = p; q != P; q = q->pcond) { + if(q->as != AJMP) + break; + c++; + if(c >= 5000) + return P; + } + return q; +} + +void +dostkoff(void) +{ + Prog *p, *q; + long autoffset, deltasp; + int a, f, curframe, curbecome, maxbecome, pcsize; + + curframe = 0; + curbecome = 0; + maxbecome = 0; + curtext = 0; + for(p = firstp; p != P; p = p->link) { + + /* find out how much arg space is used in this TEXT */ + if(p->to.type == (D_INDIR+D_SP)) + if(p->to.offset > curframe) + curframe = p->to.offset; + + switch(p->as) { + case ATEXT: + if(curtext && curtext->from.sym) { + curtext->from.sym->frame = curframe; + curtext->from.sym->become = curbecome; + if(curbecome > maxbecome) + maxbecome = curbecome; + } + curframe = 0; + curbecome = 0; + + curtext = p; + break; + + case ARET: + /* special form of RET is BECOME */ + if(p->from.type == D_CONST) + if(p->from.offset > curbecome) + curbecome = p->from.offset; + break; + } + } + if(curtext && curtext->from.sym) { + curtext->from.sym->frame = curframe; + curtext->from.sym->become = curbecome; + if(curbecome > maxbecome) + maxbecome = curbecome; + } + + if(debug['b']) + print("max become = %d\n", maxbecome); + xdefine("ALEFbecome", STEXT, maxbecome); + + curtext = 0; + for(p = firstp; p != P; p = p->link) { + switch(p->as) { + case ATEXT: + curtext = p; + break; + case ACALL: + if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { + f = maxbecome - curtext->from.sym->frame; + if(f <= 0) + break; + /* calling a become or calling a variable */ + if(p->to.sym == S || p->to.sym->become) { + curtext->to.offset += f; + if(debug['b']) { + curp = p; + print("%D calling %D increase %d\n", + &curtext->from, &p->to, f); + } + } + } + break; + } + } + + autoffset = 0; + deltasp = 0; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + curtext = p; + autoffset = p->to.offset; + if(autoffset < 0) + autoffset = 0; + if(autoffset) { + p = appendp(p); + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = autoffset; + } + deltasp = autoffset; + } + pcsize = p->mode/8; + a = p->from.type; + if(a == D_AUTO) + p->from.offset += deltasp; + if(a == D_PARAM) + p->from.offset += deltasp + pcsize; + a = p->to.type; + if(a == D_AUTO) + p->to.offset += deltasp; + if(a == D_PARAM) + p->to.offset += deltasp + pcsize; + + switch(p->as) { + default: + continue; + case APUSHL: + case APUSHFL: + deltasp += 4; + continue; + case APUSHQ: + case APUSHFQ: + deltasp += 8; + continue; + case APUSHW: + case APUSHFW: + deltasp += 2; + continue; + case APOPL: + case APOPFL: + deltasp -= 4; + continue; + case APOPQ: + case APOPFQ: + deltasp -= 8; + continue; + case APOPW: + case APOPFW: + deltasp -= 2; + continue; + case ARET: + break; + } + + if(autoffset != deltasp) + diag("unbalanced PUSH/POP"); + if(p->from.type == D_CONST) + goto become; + + if(autoffset) { + q = p; + p = appendp(p); + p->as = ARET; + + q->as = AADJSP; + q->from.type = D_CONST; + q->from.offset = -autoffset; + } + continue; + + become: + q = p; + p = appendp(p); + p->as = AJMP; + p->to = q->to; + p->pcond = q->pcond; + + q->as = AADJSP; + q->from = zprg.from; + q->from.type = D_CONST; + q->from.offset = -autoffset; + q->to = zprg.to; + continue; + } +} + +vlong +atolwhex(char *s) +{ + vlong n; + int f; + + n = 0; + f = 0; + while(*s == ' ' || *s == '\t') + s++; + if(*s == '-' || *s == '+') { + if(*s++ == '-') + f = 1; + while(*s == ' ' || *s == '\t') + s++; + } + if(s[0]=='0' && s[1]){ + if(s[1]=='x' || s[1]=='X'){ + s += 2; + for(;;){ + if(*s >= '0' && *s <= '9') + n = n*16 + *s++ - '0'; + else if(*s >= 'a' && *s <= 'f') + n = n*16 + *s++ - 'a' + 10; + else if(*s >= 'A' && *s <= 'F') + n = n*16 + *s++ - 'A' + 10; + else + break; + } + } else + while(*s >= '0' && *s <= '7') + n = n*8 + *s++ - '0'; + } else + while(*s >= '0' && *s <= '9') + n = n*10 + *s++ - '0'; + if(f) + n = -n; + return n; +} + +void +undef(void) +{ + int i; + Sym *s; + + for(i=0; ilink) + if(s->type == SXREF) + diag("%s: not defined", s->name); +} + +void +import(void) +{ + int i; + Sym *s; + + for(i = 0; i < NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){ + if(s->value != 0) + diag("value != 0 on SXREF"); + undefsym(s); + Bprint(&bso, "IMPORT: %s sig=%lux v=%lld\n", s->name, s->sig, s->value); + if(debug['S']) + s->sig = 0; + } +} + +void +ckoff(Sym *s, long v) +{ + if(v < 0 || v >= 1<name); +} + +static Prog* +newdata(Sym *s, int o, int w, int t) +{ + Prog *p; + + p = prg(); + if(edatap == P) + datap = p; + else + edatap->link = p; + edatap = p; + p->as = ADATA; + p->width = w; + p->from.scale = w; + p->from.type = t; + p->from.sym = s; + p->from.offset = o; + p->to.type = D_CONST; + return p; +} + +void +export(void) +{ + int i, j, n, off, nb, sv, ne; + Sym *s, *et, *str, **esyms; + Prog *p; + char buf[NSNAME], *t; + + n = 0; + for(i = 0; i < NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT)) + n++; + esyms = malloc(n*sizeof(Sym*)); + ne = n; + n = 0; + for(i = 0; i < NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT)) + esyms[n++] = s; + for(i = 0; i < ne-1; i++) + for(j = i+1; j < ne; j++) + if(strcmp(esyms[i]->name, esyms[j]->name) > 0){ + s = esyms[i]; + esyms[i] = esyms[j]; + esyms[j] = s; + } + + nb = 0; + off = 0; + et = lookup(EXPTAB, 0); + if(et->type != 0 && et->type != SXREF) + diag("%s already defined", EXPTAB); + et->type = SDATA; + str = lookup(".string", 0); + if(str->type == 0) + str->type = SDATA; + sv = str->value; + for(i = 0; i < ne; i++){ + s = esyms[i]; + if(debug['S']) + s->sig = 0; + /* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */ + + /* signature */ + p = newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + p->to.offset = s->sig; + + /* address */ + p = newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + p->to.type = D_ADDR; + p->to.index = D_EXTERN; + p->to.sym = s; + + /* string */ + t = s->name; + n = strlen(t)+1; + for(;;){ + buf[nb++] = *t; + sv++; + if(nb >= NSNAME){ + p = newdata(str, sv-NSNAME, NSNAME, D_STATIC); + p->to.type = D_SCONST; + memmove(p->to.scon, buf, NSNAME); + nb = 0; + } + if(*t++ == 0) + break; + } + + /* name */ + p = newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + p->to.type = D_ADDR; + p->to.index = D_STATIC; + p->to.sym = str; + p->to.offset = sv-n; + } + + if(nb > 0){ + p = newdata(str, sv-nb, nb, D_STATIC); + p->to.type = D_SCONST; + memmove(p->to.scon, buf, nb); + } + + for(i = 0; i < 3; i++){ + newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + } + et->value = off; + if(sv == 0) + sv = 1; + str->value = sv; + exports = ne; + free(esyms); +} diff --git a/sys/src/cmd/6l/span.c b/sys/src/cmd/6l/span.c new file mode 100644 index 000000000..78399a2b3 --- /dev/null +++ b/sys/src/cmd/6l/span.c @@ -0,0 +1,1746 @@ +#include "l.h" + +static int rexflag; +static int asmode; + +void +span(void) +{ + Prog *p, *q; + long v; + vlong c, idat; + int m, n, again; + + xdefine("etext", STEXT, 0L); + idat = INITDAT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + n = 0; + if(p->to.type == D_BRANCH) + if(p->pcond == P) + p->pcond = p; + if((q = p->pcond) != P) + if(q->back != 2) + n = 1; + p->back = n; + if(p->as == AADJSP) { + p->to.type = D_SP; + v = -p->from.offset; + p->from.offset = v; + p->as = p->mode != 64? AADDL: AADDQ; + if(v < 0) { + p->as = p->mode != 64? ASUBL: ASUBQ; + v = -v; + p->from.offset = v; + } + if(v == 0) + p->as = ANOP; + } + } + n = 0; + +start: + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + Bflush(&bso); + c = INITTEXT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->to.type == D_BRANCH) + if(p->back) + p->pc = c; + asmins(p); + p->pc = c; + m = andptr-and; + p->mark = m; + c += m; + } + +loop: + n++; + if(debug['v']) + Bprint(&bso, "%5.2f span %d\n", cputime(), n); + Bflush(&bso); + if(n > 50) { + print("span must be looping\n"); + errorexit(); + } + again = 0; + c = INITTEXT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->to.type == D_BRANCH || p->back & 0100) { + if(p->back) + p->pc = c; + asmins(p); + m = andptr-and; + if(m != p->mark) { + p->mark = m; + again++; + } + } + p->pc = c; + c += p->mark; + } + if(again) { + textsize = c; + goto loop; + } + if(INITRND) { + INITDAT = rnd(c, INITRND); + if(INITDAT != idat) { + idat = INITDAT; + goto start; + } + } + xdefine("etext", STEXT, c); + if(debug['v']) + Bprint(&bso, "etext = %llux\n", c); + Bflush(&bso); + for(p = textp; p != P; p = p->pcond) + p->from.sym->value = p->pc; + textsize = c - INITTEXT; +} + +void +xdefine(char *p, int t, vlong v) +{ + Sym *s; + + s = lookup(p, 0); + if(s->type == 0 || s->type == SXREF) { + s->type = t; + s->value = v; + } + if(s->type == STEXT && s->value == 0) + s->value = v; +} + +void +putsymb(char *s, int t, vlong v, int ver) +{ + int i, f, l; + + if(t == 'f') + s++; + l = 4; + if(!debug['8']){ + lput(v>>32); + l = 8; + } + lput(v); + if(ver) + t += 'a' - 'A'; + cput(t+0x80); /* 0x80 is variable length */ + + if(t == 'Z' || t == 'z') { + cput(s[0]); + for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) { + cput(s[i]); + cput(s[i+1]); + } + cput(0); + cput(0); + i++; + } + else { + for(i=0; s[i]; i++) + cput(s[i]); + cput(0); + } + symsize += l + 1 + i + 1; + + if(debug['n']) { + if(t == 'z' || t == 'Z') { + Bprint(&bso, "%c %.8llux ", t, v); + for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) { + f = ((s[i]&0xff) << 8) | (s[i+1]&0xff); + Bprint(&bso, "/%x", f); + } + Bprint(&bso, "\n"); + return; + } + if(ver) + Bprint(&bso, "%c %.8llux %s<%d>\n", t, v, s, ver); + else + Bprint(&bso, "%c %.8llux %s\n", t, v, s); + } +} + +void +asmsym(void) +{ + Prog *p; + Auto *a; + Sym *s; + int h; + + s = lookup("etext", 0); + if(s->type == STEXT) + putsymb(s->name, 'T', s->value, s->version); + + for(h=0; hlink) + switch(s->type) { + case SCONST: + putsymb(s->name, 'D', s->value, s->version); + continue; + + case SDATA: + putsymb(s->name, 'D', s->value+INITDAT, s->version); + continue; + + case SBSS: + putsymb(s->name, 'B', s->value+INITDAT, s->version); + continue; + + case SFILE: + putsymb(s->name, 'f', s->value, s->version); + continue; + } + + for(p=textp; p!=P; p=p->pcond) { + s = p->from.sym; + if(s->type != STEXT) + continue; + + /* filenames first */ + for(a=p->to.autom; a; a=a->link) + if(a->type == D_FILE) + putsymb(a->asym->name, 'z', a->aoffset, 0); + else + if(a->type == D_FILE1) + putsymb(a->asym->name, 'Z', a->aoffset, 0); + + putsymb(s->name, 'T', s->value, s->version); + + /* frame, auto and param after */ + putsymb(".frame", 'm', p->to.offset+8, 0); + + for(a=p->to.autom; a; a=a->link) + if(a->type == D_AUTO) + putsymb(a->asym->name, 'a', -a->aoffset, 0); + else + if(a->type == D_PARAM) + putsymb(a->asym->name, 'p', a->aoffset, 0); + } + if(debug['v'] || debug['n']) + Bprint(&bso, "symsize = %lud\n", symsize); + Bflush(&bso); +} + +void +asmlc(void) +{ + vlong oldpc; + Prog *p; + long oldlc, v, s; + + oldpc = INITTEXT; + oldlc = 0; + for(p = firstp; p != P; p = p->link) { + if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) { + if(p->as == ATEXT) + curtext = p; + if(debug['L']) + Bprint(&bso, "%6llux %P\n", + p->pc, p); + continue; + } + if(debug['L']) + Bprint(&bso, "\t\t%6ld", lcsize); + v = (p->pc - oldpc) / MINLC; + while(v) { + s = 127; + if(v < 127) + s = v; + cput(s+128); /* 129-255 +pc */ + if(debug['L']) + Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128); + v -= s; + lcsize++; + } + s = p->line - oldlc; + oldlc = p->line; + oldpc = p->pc + MINLC; + if(s > 64 || s < -64) { + cput(0); /* 0 vv +lc */ + cput(s>>24); + cput(s>>16); + cput(s>>8); + cput(s); + if(debug['L']) { + if(s > 0) + Bprint(&bso, " lc+%ld(%d,%ld)\n", + s, 0, s); + else + Bprint(&bso, " lc%ld(%d,%ld)\n", + s, 0, s); + Bprint(&bso, "%6llux %P\n", + p->pc, p); + } + lcsize += 5; + continue; + } + if(s > 0) { + cput(0+s); /* 1-64 +lc */ + if(debug['L']) { + Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s); + Bprint(&bso, "%6llux %P\n", + p->pc, p); + } + } else { + cput(64-s); /* 65-128 -lc */ + if(debug['L']) { + Bprint(&bso, " lc%ld(%ld)\n", s, 64-s); + Bprint(&bso, "%6llux %P\n", + p->pc, p); + } + } + lcsize++; + } + while(lcsize & 1) { + s = 129; + cput(s); + lcsize++; + } + if(debug['v'] || debug['L']) + Bprint(&bso, "lcsize = %ld\n", lcsize); + Bflush(&bso); +} + +int +oclass(Adr *a) +{ + vlong v; + long l; + + if(a->type >= D_INDIR || a->index != D_NONE) { + if(a->index != D_NONE && a->scale == 0) { + if(a->type == D_ADDR) { + switch(a->index) { + case D_EXTERN: + case D_STATIC: + return Yi32; /* TO DO: Yi64 */ + case D_AUTO: + case D_PARAM: + return Yiauto; + } + return Yxxx; + } + return Ycol; + } + return Ym; + } + switch(a->type) + { + case D_AL: + return Yal; + + case D_AX: + return Yax; + +/* + case D_SPB: +*/ + case D_BPB: + case D_SIB: + case D_DIB: + case D_R8B: + case D_R9B: + case D_R10B: + case D_R11B: + case D_R12B: + case D_R13B: + case D_R14B: + case D_R15B: + if(asmode != 64) + return Yxxx; + case D_DL: + case D_BL: + case D_AH: + case D_CH: + case D_DH: + case D_BH: + return Yrb; + + case D_CL: + return Ycl; + + case D_CX: + return Ycx; + + case D_DX: + case D_BX: + return Yrx; + + case D_R8: /* not really Yrl */ + case D_R9: + case D_R10: + case D_R11: + case D_R12: + case D_R13: + case D_R14: + case D_R15: + if(asmode != 64) + return Yxxx; + case D_SP: + case D_BP: + case D_SI: + case D_DI: + return Yrl; + + case D_F0+0: + return Yf0; + + case D_F0+1: + case D_F0+2: + case D_F0+3: + case D_F0+4: + case D_F0+5: + case D_F0+6: + case D_F0+7: + return Yrf; + + case D_M0+0: + case D_M0+1: + case D_M0+2: + case D_M0+3: + case D_M0+4: + case D_M0+5: + case D_M0+6: + case D_M0+7: + return Ymr; + + case D_X0+0: + case D_X0+1: + case D_X0+2: + case D_X0+3: + case D_X0+4: + case D_X0+5: + case D_X0+6: + case D_X0+7: + case D_X0+8: + case D_X0+9: + case D_X0+10: + case D_X0+11: + case D_X0+12: + case D_X0+13: + case D_X0+14: + case D_X0+15: + return Yxr; + + case D_NONE: + return Ynone; + + case D_CS: return Ycs; + case D_SS: return Yss; + case D_DS: return Yds; + case D_ES: return Yes; + case D_FS: return Yfs; + case D_GS: return Ygs; + + case D_GDTR: return Ygdtr; + case D_IDTR: return Yidtr; + case D_LDTR: return Yldtr; + case D_MSW: return Ymsw; + case D_TASK: return Ytask; + + case D_CR+0: return Ycr0; + case D_CR+1: return Ycr1; + case D_CR+2: return Ycr2; + case D_CR+3: return Ycr3; + case D_CR+4: return Ycr4; + case D_CR+5: return Ycr5; + case D_CR+6: return Ycr6; + case D_CR+7: return Ycr7; + case D_CR+8: return Ycr8; + + case D_DR+0: return Ydr0; + case D_DR+1: return Ydr1; + case D_DR+2: return Ydr2; + case D_DR+3: return Ydr3; + case D_DR+4: return Ydr4; + case D_DR+5: return Ydr5; + case D_DR+6: return Ydr6; + case D_DR+7: return Ydr7; + + case D_TR+0: return Ytr0; + case D_TR+1: return Ytr1; + case D_TR+2: return Ytr2; + case D_TR+3: return Ytr3; + case D_TR+4: return Ytr4; + case D_TR+5: return Ytr5; + case D_TR+6: return Ytr6; + case D_TR+7: return Ytr7; + + case D_EXTERN: + case D_STATIC: + case D_AUTO: + case D_PARAM: + return Ym; + + case D_CONST: + case D_ADDR: + if(a->sym == S) { + v = a->offset; + if(v == 0) + return Yi0; + if(v == 1) + return Yi1; + if(v >= -128 && v <= 127) + return Yi8; + l = v; + if((vlong)l == v) + return Ys32; /* can sign extend */ + if((v>>32) == 0) + return Yi32; /* unsigned */ + return Yi64; + } + return Yi32; /* TO DO: D_ADDR as Yi64 */ + + case D_BRANCH: + return Ybr; + } + return Yxxx; +} + +void +asmidx(Adr *a, int base) +{ + int i; + + switch(a->index) { + default: + goto bad; + + case D_NONE: + i = 4 << 3; + goto bas; + + case D_R8: + case D_R9: + case D_R10: + case D_R11: + case D_R12: + case D_R13: + case D_R14: + case D_R15: + if(asmode != 64) + goto bad; + case D_AX: + case D_CX: + case D_DX: + case D_BX: + case D_BP: + case D_SI: + case D_DI: + i = reg[a->index] << 3; + break; + } + switch(a->scale) { + default: + goto bad; + case 1: + break; + case 2: + i |= (1<<6); + break; + case 4: + i |= (2<<6); + break; + case 8: + i |= (3<<6); + break; + } +bas: + switch(base) { + default: + goto bad; + case D_NONE: /* must be mod=00 */ + i |= 5; + break; + case D_R8: + case D_R9: + case D_R10: + case D_R11: + case D_R12: + case D_R13: + case D_R14: + case D_R15: + if(asmode != 64) + goto bad; + case D_AX: + case D_CX: + case D_DX: + case D_BX: + case D_SP: + case D_BP: + case D_SI: + case D_DI: + i |= reg[base]; + break; + } + *andptr++ = i; + return; +bad: + diag("asmidx: bad address %D", a); + *andptr++ = 0; + return; +} + +static void +put4(long v) +{ + if(dlm && curp != P && reloca != nil){ + dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1); + reloca = nil; + } + andptr[0] = v; + andptr[1] = v>>8; + andptr[2] = v>>16; + andptr[3] = v>>24; + andptr += 4; +} + +static void +put8(vlong v) +{ + if(dlm && curp != P && reloca != nil){ + dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1); /* TO DO */ + reloca = nil; + } + andptr[0] = v; + andptr[1] = v>>8; + andptr[2] = v>>16; + andptr[3] = v>>24; + andptr[4] = v>>32; + andptr[5] = v>>40; + andptr[6] = v>>48; + andptr[7] = v>>56; + andptr += 8; +} + +vlong +vaddr(Adr *a) +{ + int t; + vlong v; + Sym *s; + + t = a->type; + v = a->offset; + if(t == D_ADDR) + t = a->index; + switch(t) { + case D_STATIC: + case D_EXTERN: + s = a->sym; + if(s != nil) { + if(dlm && curp != P) + reloca = a; + switch(s->type) { + case SUNDEF: + ckoff(s, v); + case STEXT: + case SCONST: + if((uvlong)s->value < (uvlong)INITTEXT) + v += INITTEXT; /* TO DO */ + v += s->value; + break; + default: + v += INITDAT + s->value; + } + } + } + return v; +} + +static void +asmandsz(Adr *a, int r, int rex, int m64) +{ + long v; + int t; + Adr aa; + + rex &= (0x40 | Rxr); + v = a->offset; + t = a->type; + if(a->index != D_NONE) { + if(t >= D_INDIR) { + t -= D_INDIR; + rexflag |= (regrex[a->index] & Rxx) | (regrex[t] & Rxb) | rex; + if(t == D_NONE) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(a, t); + put4(v); + return; + } + if(v == 0 && t != D_BP && t != D_R13) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(a, t); + return; + } + if(v >= -128 && v < 128) { + *andptr++ = (1 << 6) | (4 << 0) | (r << 3); + asmidx(a, t); + *andptr++ = v; + return; + } + *andptr++ = (2 << 6) | (4 << 0) | (r << 3); + asmidx(a, t); + put4(v); + return; + } + switch(t) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + aa.type = D_NONE+D_INDIR; + break; + case D_AUTO: + case D_PARAM: + aa.type = D_SP+D_INDIR; + break; + } + aa.offset = vaddr(a); + aa.index = a->index; + aa.scale = a->scale; + asmandsz(&aa, r, rex, m64); + return; + } + if(t >= D_AL && t <= D_X0+15) { + if(v) + goto bad; + *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3); + rexflag |= (regrex[t] & (0x40 | Rxb)) | rex; + return; + } + if(t >= D_INDIR) { + t -= D_INDIR; + rexflag |= (regrex[t] & Rxb) | rex; + if(t == D_NONE) { + if(asmode != 64){ + *andptr++ = (0 << 6) | (5 << 0) | (r << 3); + put4(v); + return; + } + /* temporary */ + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */ + *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */ + put4(v); + return; + } + if(t == D_SP || t == D_R12) { + if(v == 0) { + *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); + asmidx(a, t); + return; + } + if(v >= -128 && v < 128) { + *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3); + asmidx(a, t); + *andptr++ = v; + return; + } + *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); + asmidx(a, t); + put4(v); + return; + } + if(t >= D_AX && t <= D_R15) { + if(v == 0 && t != D_BP && t != D_R13) { + *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); + return; + } + if(v >= -128 && v < 128) { + andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3); + andptr[1] = v; + andptr += 2; + return; + } + *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); + put4(v); + return; + } + goto bad; + } + switch(a->type) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + aa.type = D_NONE+D_INDIR; + break; + case D_AUTO: + case D_PARAM: + aa.type = D_SP+D_INDIR; + break; + } + aa.index = D_NONE; + aa.scale = 1; + aa.offset = vaddr(a); + asmandsz(&aa, r, rex, m64); + return; +bad: + diag("asmand: bad address %D", a); + return; +} + +void +asmand(Adr *a, Adr *ra) +{ + asmandsz(a, reg[ra->type], regrex[ra->type], 0); +} + +void +asmando(Adr *a, int o) +{ + asmandsz(a, o, 0, 0); +} + +static void +bytereg(Adr *a) +{ + if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) + a->type = D_AL + (a->type-D_AX); +} + +#define E 0xff +Movtab ymovtab[] = +{ +/* push */ + {APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0}, + {APUSHL, Yss, Ynone, 0, 0x16,E,0,0}, + {APUSHL, Yds, Ynone, 0, 0x1e,E,0,0}, + {APUSHL, Yes, Ynone, 0, 0x06,E,0,0}, + {APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0}, + {APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0}, + {APUSHQ, Yfs, Ynone, 0, 0x0f,0xa0,E,0}, + {APUSHQ, Ygs, Ynone, 0, 0x0f,0xa8,E,0}, + + {APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0}, + {APUSHW, Yss, Ynone, 0, Pe,0x16,E,0}, + {APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0}, + {APUSHW, Yes, Ynone, 0, Pe,0x06,E,0}, + {APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E}, + {APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E}, + +/* pop */ + {APOPL, Ynone, Yds, 0, 0x1f,E,0,0}, + {APOPL, Ynone, Yes, 0, 0x07,E,0,0}, + {APOPL, Ynone, Yss, 0, 0x17,E,0,0}, + {APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0}, + {APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0}, + {APOPQ, Ynone, Yfs, 0, 0x0f,0xa1,E,0}, + {APOPQ, Ynone, Ygs, 0, 0x0f,0xa9,E,0}, + + {APOPW, Ynone, Yds, 0, Pe,0x1f,E,0}, + {APOPW, Ynone, Yes, 0, Pe,0x07,E,0}, + {APOPW, Ynone, Yss, 0, Pe,0x17,E,0}, + {APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E}, + {APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E}, + +/* mov seg */ + {AMOVW, Yes, Yml, 1, 0x8c,0,0,0}, + {AMOVW, Ycs, Yml, 1, 0x8c,1,0,0}, + {AMOVW, Yss, Yml, 1, 0x8c,2,0,0}, + {AMOVW, Yds, Yml, 1, 0x8c,3,0,0}, + {AMOVW, Yfs, Yml, 1, 0x8c,4,0,0}, + {AMOVW, Ygs, Yml, 1, 0x8c,5,0,0}, + + {AMOVW, Yml, Yes, 2, 0x8e,0,0,0}, + {AMOVW, Yml, Ycs, 2, 0x8e,1,0,0}, + {AMOVW, Yml, Yss, 2, 0x8e,2,0,0}, + {AMOVW, Yml, Yds, 2, 0x8e,3,0,0}, + {AMOVW, Yml, Yfs, 2, 0x8e,4,0,0}, + {AMOVW, Yml, Ygs, 2, 0x8e,5,0,0}, + +/* mov cr */ + {AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0}, + {AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0}, + {AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0}, + {AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0}, + {AMOVL, Ycr8, Yml, 3, 0x0f,0x20,8,0}, + {AMOVQ, Ycr0, Yml, 3, 0x0f,0x20,0,0}, + {AMOVQ, Ycr2, Yml, 3, 0x0f,0x20,2,0}, + {AMOVQ, Ycr3, Yml, 3, 0x0f,0x20,3,0}, + {AMOVQ, Ycr4, Yml, 3, 0x0f,0x20,4,0}, + {AMOVQ, Ycr8, Yml, 3, 0x0f,0x20,8,0}, + + {AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0}, + {AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0}, + {AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0}, + {AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0}, + {AMOVL, Yml, Ycr8, 4, 0x0f,0x22,8,0}, + {AMOVQ, Yml, Ycr0, 4, 0x0f,0x22,0,0}, + {AMOVQ, Yml, Ycr2, 4, 0x0f,0x22,2,0}, + {AMOVQ, Yml, Ycr3, 4, 0x0f,0x22,3,0}, + {AMOVQ, Yml, Ycr4, 4, 0x0f,0x22,4,0}, + {AMOVQ, Yml, Ycr8, 4, 0x0f,0x22,8,0}, + +/* mov dr */ + {AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0}, + {AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0}, + {AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0}, + {AMOVQ, Ydr0, Yml, 3, 0x0f,0x21,0,0}, + {AMOVQ, Ydr6, Yml, 3, 0x0f,0x21,6,0}, + {AMOVQ, Ydr7, Yml, 3, 0x0f,0x21,7,0}, + + {AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0}, + {AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0}, + {AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0}, + {AMOVQ, Yml, Ydr0, 4, 0x0f,0x23,0,0}, + {AMOVQ, Yml, Ydr6, 4, 0x0f,0x23,6,0}, + {AMOVQ, Yml, Ydr7, 4, 0x0f,0x23,7,0}, + +/* mov tr */ + {AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0}, + {AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0}, + + {AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E}, + {AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E}, + +/* lgdt, sgdt, lidt, sidt */ + {AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0}, + {AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0}, + {AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0}, + {AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0}, + {AMOVQ, Ym, Ygdtr, 4, 0x0f,0x01,2,0}, + {AMOVQ, Ygdtr, Ym, 3, 0x0f,0x01,0,0}, + {AMOVQ, Ym, Yidtr, 4, 0x0f,0x01,3,0}, + {AMOVQ, Yidtr, Ym, 3, 0x0f,0x01,1,0}, + +/* lldt, sldt */ + {AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0}, + {AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0}, + +/* lmsw, smsw */ + {AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0}, + {AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0}, + +/* ltr, str */ + {AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0}, + {AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0}, + +/* load full pointer */ + {AMOVL, Yml, Ycol, 5, 0,0,0,0}, + {AMOVW, Yml, Ycol, 5, Pe,0,0,0}, + +/* double shift */ + {ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0}, + {ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0}, + {ASHLQ, Ycol, Yml, 6, Pw,0xa4,0xa5,0}, + {ASHRQ, Ycol, Yml, 6, Pw,0xac,0xad,0}, + {ASHLW, Ycol, Yml, 6, Pe,0xa4,0xa5,0}, + {ASHRW, Ycol, Yml, 6, Pe,0xac,0xad,0}, + 0 +}; + +int +isax(Adr *a) +{ + + switch(a->type) { + case D_AX: + case D_AL: + case D_AH: + case D_INDIR+D_AX: + return 1; + } + if(a->index == D_AX) + return 1; + return 0; +} + +void +subreg(Prog *p, int from, int to) +{ + + if(debug['Q']) + print("\n%P s/%R/%R/\n", p, from, to); + + if(p->from.type == from) + p->from.type = to; + if(p->to.type == from) + p->to.type = to; + + if(p->from.index == from) + p->from.index = to; + if(p->to.index == from) + p->to.index = to; + + from += D_INDIR; + if(p->from.type == from) + p->from.type = to+D_INDIR; + if(p->to.type == from) + p->to.type = to+D_INDIR; + + if(debug['Q']) + print("%P\n", p); +} + +static int +mediaop(Optab *o, int op, int osize, int z) +{ + switch(op){ + case Pm: + case Pe: + case Pf2: + case Pf3: + if(osize != 1){ + if(op != Pm) + *andptr++ = op; + *andptr++ = Pm; + op = o->op[++z]; + break; + } + default: + if(andptr == and || andptr[-1] != Pm) + *andptr++ = Pm; + break; + } + *andptr++ = op; + return z; +} + +void +doasm(Prog *p) +{ + Optab *o; + Prog *q, pp; + uchar *t; + Movtab *mo; + int z, op, ft, tt, xo, l; + vlong v; + + o = opindex[p->as]; + if(o == nil) { + diag("asmins: missing op %P", p); + return; + } + ft = oclass(&p->from) * Ymax; + tt = oclass(&p->to) * Ymax; + t = o->ytab; + if(t == 0) { + diag("asmins: noproto %P", p); + return; + } + xo = o->op[0] == 0x0f; + for(z=0; *t; z+=t[3]+xo,t+=4) + if(ycover[ft+t[0]]) + if(ycover[tt+t[1]]) + goto found; + goto domov; + +found: + switch(o->prefix) { + case Pq: /* 16 bit escape and opcode escape */ + *andptr++ = Pe; + *andptr++ = Pm; + break; + + case Pf2: /* xmm opcode escape */ + case Pf3: + *andptr++ = o->prefix; + *andptr++ = Pm; + break; + + case Pm: /* opcode escape */ + *andptr++ = Pm; + break; + + case Pe: /* 16 bit escape */ + *andptr++ = Pe; + break; + + case Pw: /* 64-bit escape */ + if(p->mode != 64) + diag("asmins: illegal 64: %P", p); + rexflag |= Pw; + break; + + case Pb: /* botch */ + bytereg(&p->from); + bytereg(&p->to); + break; + + case P32: /* 32 bit but illegal if 64-bit mode */ + if(p->mode == 64) + diag("asmins: illegal in 64-bit mode: %P", p); + break; + + case Py: /* 64-bit only, no prefix */ + if(p->mode != 64) + diag("asmins: illegal in %d-bit mode: %P", p->mode, p); + break; + } + v = vaddr(&p->from); + op = o->op[z]; + if(op == 0x0f) { + *andptr++ = op; + op = o->op[++z]; + } + switch(t[2]) { + default: + diag("asmins: unknown z %d %P", t[2], p); + return; + + case Zpseudo: + break; + + case Zlit: + for(; op = o->op[z]; z++) + *andptr++ = op; + break; + + case Zmb_r: + bytereg(&p->from); + /* fall through */ + case Zm_r: + *andptr++ = op; + asmand(&p->from, &p->to); + break; + + case Zm_r_xm: + mediaop(o, op, t[3], z); + asmand(&p->from, &p->to); + break; + + case Zm_r_xm_nr: + rexflag = 0; + mediaop(o, op, t[3], z); + asmand(&p->from, &p->to); + break; + + case Zm_r_i_xm: + mediaop(o, op, t[3], z); + asmand(&p->from, &p->to); + *andptr++ = p->to.offset; + break; + + case Zm_r_3d: + *andptr++ = 0x0f; + *andptr++ = 0x0f; + asmand(&p->from, &p->to); + *andptr++ = op; + break; + + case Zibm_r: + *andptr++ = op; + asmand(&p->from, &p->to); + *andptr++ = p->to.offset; + break; + + case Zaut_r: + *andptr++ = 0x8d; /* leal */ + if(p->from.type != D_ADDR) + diag("asmins: Zaut sb type ADDR"); + p->from.type = p->from.index; + p->from.index = D_NONE; + asmand(&p->from, &p->to); + p->from.index = p->from.type; + p->from.type = D_ADDR; + break; + + case Zm_o: + *andptr++ = op; + asmando(&p->from, o->op[z+1]); + break; + + case Zr_m: + *andptr++ = op; + asmand(&p->to, &p->from); + break; + + case Zr_m_xm: + mediaop(o, op, t[3], z); + asmand(&p->to, &p->from); + break; + + case Zr_m_xm_nr: + rexflag = 0; + mediaop(o, op, t[3], z); + asmand(&p->to, &p->from); + break; + + case Zr_m_i_xm: + mediaop(o, op, t[3], z); + asmand(&p->to, &p->from); + *andptr++ = p->from.offset; + break; + + case Zo_m: + *andptr++ = op; + asmando(&p->to, o->op[z+1]); + break; + + case Zo_m64: + *andptr++ = op; + asmandsz(&p->to, o->op[z+1], 0, 1); + break; + + case Zm_ibo: + v = vaddr(&p->to); + *andptr++ = op; + asmando(&p->from, o->op[z+1]); + *andptr++ = v; + break; + + case Zibo_m: + *andptr++ = op; + asmando(&p->to, o->op[z+1]); + *andptr++ = v; + break; + + case Zibo_m_xm: + z = mediaop(o, op, t[3], z); + asmando(&p->to, o->op[z+1]); + *andptr++ = v; + break; + + case Z_ib: + v = vaddr(&p->to); + case Zib_: + *andptr++ = op; + *andptr++ = v; + break; + + case Zib_rp: + rexflag |= regrex[p->to.type] & (Rxb|0x40); + *andptr++ = op + reg[p->to.type]; + *andptr++ = v; + break; + + case Zil_rp: + rexflag |= regrex[p->to.type] & Rxb; + *andptr++ = op + reg[p->to.type]; + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Zo_iw: + *andptr++ = op; + if(p->from.type != D_NONE){ + *andptr++ = v; + *andptr++ = v>>8; + } + break; + + case Ziq_rp: + l = v>>32; + if(l == 0){ + //p->mark |= 0100; + //print("zero: %llux %P\n", v, p); + rexflag &= ~(0x40|Rxw); + rexflag |= regrex[p->to.type] & Rxb; + *andptr++ = 0xb8 + reg[p->to.type]; + put4(v); + }else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */ + //p->mark |= 0100; + //print("sign: %llux %P\n", v, p); + *andptr ++ = 0xc7; + asmando(&p->to, 0); + put4(v); + }else{ /* need all 8 */ + //print("all: %llux %P\n", v, p); + rexflag |= regrex[p->to.type] & Rxb; + *andptr++ = op + reg[p->to.type]; + put8(v); + } + break; + + case Zib_rr: + *andptr++ = op; + asmand(&p->to, &p->to); + *andptr++ = v; + break; + + case Z_il: + v = vaddr(&p->to); + case Zil_: + *andptr++ = op; + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Zm_ilo: + v = vaddr(&p->to); + *andptr++ = op; + asmando(&p->from, o->op[z+1]); + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Zilo_m: + *andptr++ = op; + asmando(&p->to, o->op[z+1]); + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Zil_rr: + *andptr++ = op; + asmand(&p->to, &p->to); + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Z_rp: + rexflag |= regrex[p->to.type] & (Rxb|0x40); + *andptr++ = op + reg[p->to.type]; + break; + + case Zrp_: + rexflag |= regrex[p->from.type] & (Rxb|0x40); + *andptr++ = op + reg[p->from.type]; + break; + + case Zclr: + *andptr++ = op; + asmand(&p->to, &p->to); + break; + + case Zbr: + q = p->pcond; + if(q) { + v = q->pc - p->pc - 2; + if(v >= -128 && v <= 127) { + *andptr++ = op; + *andptr++ = v; + } else { + v -= 6-2; + *andptr++ = 0x0f; + *andptr++ = o->op[z+1]; + *andptr++ = v; + *andptr++ = v>>8; + *andptr++ = v>>16; + *andptr++ = v>>24; + } + } + break; + + case Zcall: + q = p->pcond; + if(q) { + v = q->pc - p->pc - 5; + if(dlm && curp != P && p->to.sym->type == SUNDEF){ + /* v = 0 - p->pc - 5; */ + v = 0; + ckoff(p->to.sym, v); + v += p->to.sym->value; + dynreloc(p->to.sym, p->pc+1, 0); + } + *andptr++ = op; + *andptr++ = v; + *andptr++ = v>>8; + *andptr++ = v>>16; + *andptr++ = v>>24; + } + break; + + case Zjmp: + q = p->pcond; + if(q) { + v = q->pc - p->pc - 2; + if(v >= -128 && v <= 127) { + *andptr++ = op; + *andptr++ = v; + } else { + v -= 5-2; + *andptr++ = o->op[z+1]; + *andptr++ = v; + *andptr++ = v>>8; + *andptr++ = v>>16; + *andptr++ = v>>24; + } + } + break; + + case Zloop: + q = p->pcond; + if(q) { + v = q->pc - p->pc - 2; + if(v < -128 || v > 127) + diag("loop too far: %P", p); + *andptr++ = op; + *andptr++ = v; + } + break; + + case Zbyte: + *andptr++ = v; + if(op > 1) { + *andptr++ = v>>8; + if(op > 2) { + *andptr++ = v>>16; + *andptr++ = v>>24; + if(op > 4) { + *andptr++ = v>>32; + *andptr++ = v>>40; + *andptr++ = v>>48; + *andptr++ = v>>56; + } + } + } + break; + } + return; + +domov: + for(mo=ymovtab; mo->as; mo++) + if(p->as == mo->as) + if(ycover[ft+mo->ft]) + if(ycover[tt+mo->tt]){ + t = mo->op; + goto mfound; + } +bad: + if(p->mode != 64){ + /* + * here, the assembly has failed. + * if its a byte instruction that has + * unaddressable registers, try to + * exchange registers and reissue the + * instruction with the operands renamed. + */ + pp = *p; + z = p->from.type; + if(z >= D_BP && z <= D_DI) { + if(isax(&p->to)) { + *andptr++ = 0x87; /* xchg lhs,bx */ + asmando(&p->from, reg[D_BX]); + subreg(&pp, z, D_BX); + doasm(&pp); + *andptr++ = 0x87; /* xchg lhs,bx */ + asmando(&p->from, reg[D_BX]); + } else { + *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ + subreg(&pp, z, D_AX); + doasm(&pp); + *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ + } + return; + } + z = p->to.type; + if(z >= D_BP && z <= D_DI) { + if(isax(&p->from)) { + *andptr++ = 0x87; /* xchg rhs,bx */ + asmando(&p->to, reg[D_BX]); + subreg(&pp, z, D_BX); + doasm(&pp); + *andptr++ = 0x87; /* xchg rhs,bx */ + asmando(&p->to, reg[D_BX]); + } else { + *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ + subreg(&pp, z, D_AX); + doasm(&pp); + *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ + } + return; + } + } + diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p); + return; + +mfound: + switch(mo->code) { + default: + diag("asmins: unknown mov %d %P", mo->code, p); + break; + + case 0: /* lit */ + for(z=0; t[z]!=E; z++) + *andptr++ = t[z]; + break; + + case 1: /* r,m */ + *andptr++ = t[0]; + asmando(&p->to, t[1]); + break; + + case 2: /* m,r */ + *andptr++ = t[0]; + asmando(&p->from, t[1]); + break; + + case 3: /* r,m - 2op */ + *andptr++ = t[0]; + *andptr++ = t[1]; + asmando(&p->to, t[2]); + rexflag |= regrex[p->from.type] & (Rxr|0x40); + break; + + case 4: /* m,r - 2op */ + *andptr++ = t[0]; + *andptr++ = t[1]; + asmando(&p->from, t[2]); + rexflag |= regrex[p->to.type] & (Rxr|0x40); + break; + + case 5: /* load full pointer, trash heap */ + if(t[0]) + *andptr++ = t[0]; + switch(p->to.index) { + default: + goto bad; + case D_DS: + *andptr++ = 0xc5; + break; + case D_SS: + *andptr++ = 0x0f; + *andptr++ = 0xb2; + break; + case D_ES: + *andptr++ = 0xc4; + break; + case D_FS: + *andptr++ = 0x0f; + *andptr++ = 0xb4; + break; + case D_GS: + *andptr++ = 0x0f; + *andptr++ = 0xb5; + break; + } + asmand(&p->from, &p->to); + break; + + case 6: /* double shift */ + if(t[0] == Pw){ + if(p->mode != 64) + diag("asmins: illegal 64: %P", p); + rexflag |= Pw; + t++; + }else if(t[0] == Pe){ + *andptr++ = Pe; + t++; + } + z = p->from.type; + switch(z) { + default: + goto bad; + case D_CONST: + *andptr++ = 0x0f; + *andptr++ = t[0]; + asmandsz(&p->to, reg[p->from.index], regrex[p->from.index], 0); + *andptr++ = p->from.offset; + break; + case D_CL: + case D_CX: + *andptr++ = 0x0f; + *andptr++ = t[1]; + asmandsz(&p->to, reg[p->from.index], regrex[p->from.index], 0); + break; + } + break; + } +} + +void +asmins(Prog *p) +{ + int n, np, c; + + rexflag = 0; + andptr = and; + asmode = p->mode; + doasm(p); + if(rexflag){ + /* + * as befits the whole approach of the architecture, + * the rex prefix must appear before the first opcode byte + * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but + * before the 0f opcode escape!), or it might be ignored. + * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'. + */ + if(p->mode != 64) + diag("asmins: illegal in mode %d: %P", p->mode, p); + n = andptr - and; + for(np = 0; np < n; np++) { + c = and[np]; + if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26) + break; + } + memmove(and+np+1, and+np, n-np); + and[np] = 0x40 | rexflag; + andptr++; + } +} + +enum{ + ABSD = 0, + ABSU = 1, + RELD = 2, + RELU = 3, +}; + +int modemap[4] = { 0, 1, -1, 2, }; + +typedef struct Reloc Reloc; + +struct Reloc +{ + int n; + int t; + uchar *m; + ulong *a; +}; + +Reloc rels; + +static void +grow(Reloc *r) +{ + int t; + uchar *m, *nm; + ulong *a, *na; + + t = r->t; + r->t += 64; + m = r->m; + a = r->a; + r->m = nm = malloc(r->t*sizeof(uchar)); + r->a = na = malloc(r->t*sizeof(ulong)); + memmove(nm, m, t*sizeof(uchar)); + memmove(na, a, t*sizeof(ulong)); + free(m); + free(a); +} + +void +dynreloc(Sym *s, ulong v, int abs) +{ + int i, k, n; + uchar *m; + ulong *a; + Reloc *r; + + if(s->type == SUNDEF) + k = abs ? ABSU : RELU; + else + k = abs ? ABSD : RELD; + /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */ + k = modemap[k]; + r = &rels; + n = r->n; + if(n >= r->t) + grow(r); + m = r->m; + a = r->a; + for(i = n; i > 0; i--){ + if(v < a[i-1]){ /* happens occasionally for data */ + m[i] = m[i-1]; + a[i] = a[i-1]; + } + else + break; + } + m[i] = k; + a[i] = v; + r->n++; +} + +static int +sput(char *s) +{ + char *p; + + p = s; + while(*s) + cput(*s++); + cput(0); + return s-p+1; +} + +void +asmdyn() +{ + int i, n, t, c; + Sym *s; + ulong la, ra, *a; + vlong off; + uchar *m; + Reloc *r; + + cflush(); + off = seek(cout, 0, 1); + lput(0); + t = 0; + lput(imports); + t += 4; + for(i = 0; i < NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->type == SUNDEF){ + lput(s->sig); + t += 4; + t += sput(s->name); + } + + la = 0; + r = &rels; + n = r->n; + m = r->m; + a = r->a; + lput(n); + t += 4; + for(i = 0; i < n; i++){ + ra = *a-la; + if(*a < la) + diag("bad relocation order"); + if(ra < 256) + c = 0; + else if(ra < 65536) + c = 1; + else + c = 2; + cput((c<<6)|*m++); + t++; + if(c == 0){ + cput(ra); + t++; + } + else if(c == 1){ + wput(ra); + t += 2; + } + else{ + lput(ra); + t += 4; + } + la = *a++; + } + + cflush(); + seek(cout, off, 0); + lput(t); + + if(debug['v']){ + Bprint(&bso, "import table entries = %d\n", imports); + Bprint(&bso, "export table entries = %d\n", exports); + } +} diff --git a/sys/src/cmd/7c/gc.h b/sys/src/cmd/7c/gc.h index 225a11441..f41384bd4 100644 --- a/sys/src/cmd/7c/gc.h +++ b/sys/src/cmd/7c/gc.h @@ -58,7 +58,7 @@ struct Prog struct Case { Case* link; - long val; + vlong val; long label; char def; char isv; @@ -67,7 +67,7 @@ struct Case struct C1 { - long val; + vlong val; long label; }; diff --git a/sys/src/cmd/7c/swt.c b/sys/src/cmd/7c/swt.c index 937687fa5..a7f20c9ef 100644 --- a/sys/src/cmd/7c/swt.c +++ b/sys/src/cmd/7c/swt.c @@ -20,7 +20,7 @@ swit2(C1 *q, int nc, long def, Node *n, Node *tn) if(nc < 5) { for(i=0; ival); + print("case = %.8llux\n", q->val); if(bval(q->val)) { gopcode(OEQ, n, Z, nodconst(q->val)); } else { @@ -53,7 +53,7 @@ swit2(C1 *q, int nc, long def, Node *n, Node *tn) swit2(r, nc-i, def, n, tn); } /* if(debug['W']) - print("case > %.8lux\n", r->val); + print("case > %.8llux\n", r->val); gmove(nodconst(r->val), tn); gopcode(OLT, tn, n, Z); sp = p; @@ -62,7 +62,7 @@ swit2(C1 *q, int nc, long def, Node *n, Node *tn) swit2(q, i, def, n, tn); if(debug['W']) - print("case < %.8lux\n", r->val); + print("case < %.8llux\n", r->val); patch(sp, pc); swit2(r+1, nc-i-1, def, n, tn); */ } diff --git a/sys/src/cmd/8a/a.h b/sys/src/cmd/8a/a.h index 3095612f8..3bac7ae05 100644 --- a/sys/src/cmd/8a/a.h +++ b/sys/src/cmd/8a/a.h @@ -72,6 +72,7 @@ struct Gen double dval; char sval[8]; long offset; + long offset2; Sym* sym; short type; short index; diff --git a/sys/src/cmd/8a/a.y b/sys/src/cmd/8a/a.y index 167234b43..7c9487f64 100644 --- a/sys/src/cmd/8a/a.y +++ b/sys/src/cmd/8a/a.y @@ -4,6 +4,10 @@ %union { Sym *sym; long lval; + struct { + long v1; + long v2; + } con2; double dval; char sval[8]; Gen gen; @@ -16,16 +20,17 @@ %left '+' '-' %left '*' '/' '%' %token LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4 -%token LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI +%token LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEG %token LCONST LFP LPC LSB %token LBREG LLREG LSREG LFREG %token LFCONST %token LSCONST LSP %token LNAME LLAB LVAR %type con expr pointer offset -%type mem imm reg nam rel rem rim rom omem nmem +%type con2 +%type mem imm imm2 reg nam rel rem rim rom omem nmem %type nonnon nonrel nonrem rimnon rimrem remrim -%type spec1 spec2 spec3 spec4 spec5 spec6 spec7 +%type spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 %% prog: | prog line @@ -73,6 +78,7 @@ inst: | LTYPES spec5 { outcode($1, &$2); } | LTYPEM spec6 { outcode($1, &$2); } | LTYPEI spec7 { outcode($1, &$2); } +| LTYPEG spec8 { outcode($1, &$2); } nonnon: { @@ -219,6 +225,19 @@ spec7: $$.to = $3; } +spec8: /* GLOBL */ + mem ',' imm + { + $$.from = $1; + $$.to = $3; + } +| mem ',' con ',' imm + { + $$.from = $1; + $$.from.scale = $3; + $$.to = $5; + } + rem: reg | mem @@ -236,6 +255,7 @@ rom: } | reg | omem +| imm rim: rem @@ -335,6 +355,37 @@ imm: $$.dval = -$3; } +imm2: + '$' con2 + { + $$ = nullgen; + $$.type = D_CONST2; + $$.offset = $2.v1; + $$.offset2 = $2.v2; + } + +con2: + LCONST + { + $$.v1 = $1; + $$.v2 = 0; + } +| '-' LCONST + { + $$.v1 = -$2; + $$.v2 = 0; + } +| LCONST '-' LCONST + { + $$.v1 = $1; + $$.v2 = $3; + } +| '-' LCONST '-' LCONST + { + $$.v1 = -$2; + $$.v2 = $4; + } + mem: omem | nmem @@ -386,6 +437,12 @@ omem: $$ = nullgen; $$.type = D_INDIR+D_SP; } +| con '(' LSREG ')' + { + $$ = nullgen; + $$.type = D_INDIR+$3; + $$.offset = $1; + } | '(' LLREG '*' con ')' { $$ = nullgen; diff --git a/sys/src/cmd/8a/l.s b/sys/src/cmd/8a/l.s index 09980d488..4bb92ef54 100644 --- a/sys/src/cmd/8a/l.s +++ b/sys/src/cmd/8a/l.s @@ -221,7 +221,7 @@ TEXT mode32bit(SB),$0 * 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 */ + ADDL $(BY2PG-1),AX /* must be page aligned */ ANDL $(~(BY2PG-1)),AX /* ... */ MOVL $(4*1024),CX /* pte's per page */ MOVL $((((4*1024)-1)<>16); Bputc(&obuf, l>>24); } + if(t & T_OFFSET2) { + l = a->offset2; + 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) { diff --git a/sys/src/cmd/8c/8.out.h b/sys/src/cmd/8c/8.out.h index c38ab83f3..a87341a2f 100644 --- a/sys/src/cmd/8c/8.out.h +++ b/sys/src/cmd/8c/8.out.h @@ -2,6 +2,7 @@ #define NSNAME 8 #define NOPROF (1<<0) #define DUPOK (1<<1) +#define NOSPLIT (1<<2) enum as { @@ -353,6 +354,58 @@ enum as ASIGNAME, + AFCOMI, + AFCOMIP, + AFUCOMI, + AFUCOMIP, + ACMPXCHGB, + ACMPXCHGL, + ACMPXCHGW, + + /* conditional move */ + ACMOVLCC, + ACMOVLCS, + ACMOVLEQ, + ACMOVLGE, + ACMOVLGT, + ACMOVLHI, + ACMOVLLE, + ACMOVLLS, + ACMOVLLT, + ACMOVLMI, + ACMOVLNE, + ACMOVLOC, + ACMOVLOS, + ACMOVLPC, + ACMOVLPL, + ACMOVLPS, + ACMOVWCC, + ACMOVWCS, + ACMOVWEQ, + ACMOVWGE, + ACMOVWGT, + ACMOVWHI, + ACMOVWLE, + ACMOVWLS, + ACMOVWLT, + ACMOVWMI, + ACMOVWNE, + ACMOVWOC, + ACMOVWOS, + ACMOVWPC, + ACMOVWPL, + ACMOVWPS, + + AFCMOVCC, + AFCMOVCS, + AFCMOVEQ, + AFCMOVHI, + AFCMOVLS, + AFCMOVNE, + AFCMOVNU, + AFCMOVUN, + + /* add new operations here. nowhere else. here. */ ALAST }; @@ -378,6 +431,7 @@ enum D_DI, D_F0 = 16, + D_F7 = D_F0 + 7, D_CS = 24, D_SS, @@ -413,12 +467,18 @@ enum D_INDIR, /* additive */ + D_CONST2 = D_INDIR+D_INDIR, + + D_SIZE, /* 8l internal */ + T_TYPE = 1<<0, T_INDEX = 1<<1, T_OFFSET = 1<<2, T_FCONST = 1<<3, T_SYM = 1<<4, T_SCONST = 1<<5, + T_OFFSET2 = 1<<6, + T_GOTYPE = 1<<7, REGARG = -1, REGRET = D_AX, diff --git a/sys/src/cmd/8c/cgen.c b/sys/src/cmd/8c/cgen.c index 6fdaf6b01..9436ac698 100644 --- a/sys/src/cmd/8c/cgen.c +++ b/sys/src/cmd/8c/cgen.c @@ -25,6 +25,12 @@ cgen(Node *n, Node *nn) l = n->left; r = n->right; o = n->op; +// Go's version does the following, but it's the wrong place: doesn't allow assignment +// if(o == OEXREG || nn != Z && nn->op == OEXREG) { +// gmove(n, nn); +// return; +// } + if(n->addable >= INDEXED) { if(nn == Z) { switch(o) { @@ -244,7 +250,7 @@ cgen(Node *n, Node *nn) 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(c > 0 && c <= 3 && nareg(1) >= 4) { if(l->left->complex >= r->complex) { regalloc(&nod, l->left, nn); cgen(l->left, &nod); @@ -887,6 +893,7 @@ cgen(Node *n, Node *nn) break; case OFUNC: + l = uncomma(l); if(l->complex >= FNX) { if(l->op != OIND) diag(n, "bad function call"); @@ -1824,6 +1831,12 @@ copy: gins(ACLD, Z, Z); gins(AREP, Z, Z); gins(AMOVSL, Z, Z); + if(w & (SZ_LONG-1)) { + /* odd length of packed structure */ + gins(AMOVL, nodconst(w & (SZ_LONG-1)), &nod3); + gins(AREP, Z, Z); + gins(AMOVSB, Z, Z); + } if(c & 4) { gins(APOPL, Z, &nod3); reg[D_CX]--; diff --git a/sys/src/cmd/8c/cgen64.c b/sys/src/cmd/8c/cgen64.c index dd82adfa2..6c4be5aa9 100644 --- a/sys/src/cmd/8c/cgen64.c +++ b/sys/src/cmd/8c/cgen64.c @@ -188,70 +188,6 @@ storepair(Node *n, Node *nn, int 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 */ @@ -319,26 +255,6 @@ vfunc(Node *n, Node *nn) 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) diff --git a/sys/src/cmd/8c/div.c b/sys/src/cmd/8c/div.c index cb15ab2dd..65aa3570b 100644 --- a/sys/src/cmd/8c/div.c +++ b/sys/src/cmd/8c/div.c @@ -6,7 +6,7 @@ * SIGPLAN Notices, Vol. 29, June 1994, page 61. */ -#define TN(n) (1ULL << (n)) +#define TN(n) ((uvlong)1 << (n)) #define T31 TN(31) #define T32 TN(32) diff --git a/sys/src/cmd/8c/enam.c b/sys/src/cmd/8c/enam.c index 3e293a283..cc6d0bf1d 100644 --- a/sys/src/cmd/8c/enam.c +++ b/sys/src/cmd/8c/enam.c @@ -333,5 +333,52 @@ char* anames[] = "DYNT", "INIT", "SIGNAME", + "FCOMI", + "FCOMIP", + "FUCOMI", + "FUCOMIP", + "CMPXCHGB", + "CMPXCHGL", + "CMPXCHGW", + "CMOVLCC", + "CMOVLCS", + "CMOVLEQ", + "CMOVLGE", + "CMOVLGT", + "CMOVLHI", + "CMOVLLE", + "CMOVLLS", + "CMOVLLT", + "CMOVLMI", + "CMOVLNE", + "CMOVLOC", + "CMOVLOS", + "CMOVLPC", + "CMOVLPL", + "CMOVLPS", + "CMOVWCC", + "CMOVWCS", + "CMOVWEQ", + "CMOVWGE", + "CMOVWGT", + "CMOVWHI", + "CMOVWLE", + "CMOVWLS", + "CMOVWLT", + "CMOVWMI", + "CMOVWNE", + "CMOVWOC", + "CMOVWOS", + "CMOVWPC", + "CMOVWPL", + "CMOVWPS", + "FCMOVCC", + "FCMOVCS", + "FCMOVEQ", + "FCMOVHI", + "FCMOVLS", + "FCMOVNE", + "FCMOVNU", + "FCMOVUN", "LAST", }; diff --git a/sys/src/cmd/8c/gc.h b/sys/src/cmd/8c/gc.h index b72579626..3c0c900d6 100644 --- a/sys/src/cmd/8c/gc.h +++ b/sys/src/cmd/8c/gc.h @@ -61,7 +61,7 @@ struct Prog struct Case { Case* link; - long val; + vlong val; long label; char def; char isv; @@ -70,7 +70,7 @@ struct Case struct C1 { - long val; + vlong val; long label; }; @@ -240,6 +240,7 @@ void nextpc(void); void gargs(Node*, Node*, Node*); void garg1(Node*, Node*, Node*, int, Node**); Node* nodconst(long); +int nareg(int); Node* nodfconst(double); int nodreg(Node*, Node*, int); int isreg(Node*, int); @@ -298,7 +299,7 @@ Reg* rega(void); int rcmp(const void*, const void*); void regopt(Prog*); void addmove(Reg*, int, int, int); -Bits mkvar(Reg*, Adr*); +Bits mkvar(Reg*, Adr*, int); void prop(Reg*, Bits, Bits); void loopit(Reg*, long); void synch(Reg*, Bits); @@ -335,11 +336,6 @@ int BtoF(long); #define D_HI D_NONE #define D_LO D_NONE -/* - * bound - */ -void comtarg(void); - /* * com64 */ diff --git a/sys/src/cmd/8c/list.c b/sys/src/cmd/8c/list.c index 8ee833837..4251a3874 100644 --- a/sys/src/cmd/8c/list.c +++ b/sys/src/cmd/8c/list.c @@ -27,7 +27,7 @@ Bconv(Fmt *fp) if(str[0]) strcat(str, " "); if(var[i].sym == S) { - sprint(ss, "$%ld", var[i].offset); + snprint(ss, sizeof(ss), "$%ld", var[i].offset); s = ss; } else s = var[i].sym->name; @@ -47,13 +47,13 @@ Pconv(Fmt *fp) p = va_arg(fp->args, Prog*); if(p->as == ADATA) - sprint(str, " %A %D/%d,%D", + snprint(str, sizeof(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", + snprint(str, sizeof(str), " %A %D,%d,%D", p->as, &p->from, p->from.scale, &p->to); else - sprint(str, " %A %D,%D", + snprint(str, sizeof(str), " %A %D,%D", p->as, &p->from, &p->to); return fmtstrcpy(fp, str); } @@ -78,18 +78,18 @@ Dconv(Fmt *fp) i = a->type; if(i >= D_INDIR) { if(a->offset) - sprint(str, "%ld(%R)", a->offset, i-D_INDIR); + snprint(str, sizeof(str), "%ld(%R)", a->offset, i-D_INDIR); else - sprint(str, "(%R)", i-D_INDIR); + snprint(str, sizeof(str), "(%R)", i-D_INDIR); goto brk; } switch(i) { default: if(a->offset) - sprint(str, "$%ld,%R", a->offset, i); + snprint(str, sizeof(str), "$%ld,%R", a->offset, i); else - sprint(str, "%R", i); + snprint(str, sizeof(str), "%R", i); break; case D_NONE: @@ -97,53 +97,54 @@ Dconv(Fmt *fp) break; case D_BRANCH: - sprint(str, "%ld(PC)", a->offset-pc); + snprint(str, sizeof(str), "%ld(PC)", a->offset-pc); break; case D_EXTERN: - sprint(str, "%s+%ld(SB)", a->sym->name, a->offset); + snprint(str, sizeof(str), "%s+%ld(SB)", a->sym->name, a->offset); break; case D_STATIC: - sprint(str, "%s<>+%ld(SB)", a->sym->name, + snprint(str, sizeof(str), "%s<>+%ld(SB)", a->sym->name, a->offset); break; case D_AUTO: - sprint(str, "%s+%ld(SP)", a->sym->name, a->offset); + snprint(str, sizeof(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); + snprint(str, sizeof(str), "%s+%ld(FP)", a->sym->name, a->offset); else - sprint(str, "%ld(FP)", a->offset); + snprint(str, sizeof(str), "%ld(FP)", a->offset); break; case D_CONST: - sprint(str, "$%ld", a->offset); + snprint(str, sizeof(str), "$%ld", a->offset); break; case D_FCONST: - sprint(str, "$(%.17e)", a->dval); + snprint(str, sizeof(str), "$(%.17e)", a->dval); break; case D_SCONST: - sprint(str, "$\"%S\"", a->sval); + snprint(str, sizeof(str), "$\"%S\"", a->sval); break; case D_ADDR: a->type = a->index; a->index = D_NONE; - sprint(str, "$%D", a); + snprint(str, sizeof(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); + fmtstrcpy(fp, str); + snprint(s, sizeof(s), "(%R*%d)", (int)a->index, (int)a->scale); + return fmtstrcpy(fp, s); } conv: return fmtstrcpy(fp, str); @@ -229,9 +230,9 @@ Rconv(Fmt *fp) r = va_arg(fp->args, int); if(r >= D_AL && r <= D_NONE) - sprint(str, "%s", regstr[r-D_AL]); + snprint(str, sizeof(str), "%s", regstr[r-D_AL]); else - sprint(str, "gok(%d)", r); + snprint(str, sizeof(str), "gok(%d)", r); return fmtstrcpy(fp, str); } diff --git a/sys/src/cmd/8c/machcap.c b/sys/src/cmd/8c/machcap.c index bf09cdcf7..1734e9c32 100644 --- a/sys/src/cmd/8c/machcap.c +++ b/sys/src/cmd/8c/machcap.c @@ -53,6 +53,7 @@ machcap(Node *n) case OANDAND: case OOROR: case ONOT: + case ODOT: return 1; case OASADD: diff --git a/sys/src/cmd/8c/mkfile b/sys/src/cmd/8c/mkfile index 85abcd2e2..adc9786dd 100644 --- a/sys/src/cmd/8c/mkfile +++ b/sys/src/cmd/8c/mkfile @@ -2,7 +2,6 @@ TARG=8c OFILES=\ - bound.$O\ cgen.$O\ cgen64.$O\ div.$O\ @@ -33,7 +32,6 @@ $LIB: mk install mk clean -bound.$O: bound.h %.$O: ../cc/%.c $CC $CFLAGS ../cc/$stem.c diff --git a/sys/src/cmd/8c/peep.c b/sys/src/cmd/8c/peep.c index d67f75144..5f61925d7 100644 --- a/sys/src/cmd/8c/peep.c +++ b/sys/src/cmd/8c/peep.c @@ -67,8 +67,6 @@ peep(void) pc = 0; /* speculating it won't kill */ loop1: - if(debug['b']) - comtarg(); t = 0; for(r=firstr; r!=R; r=r->link) { @@ -277,6 +275,9 @@ subprop(Reg *r0) case ACWD: case ACDQ: + case ASTOSB: + case ASTOSL: + case AMOVSB: case AMOVSL: case AFSTSW: return 0; @@ -641,10 +642,21 @@ copyu(Prog *p, Adr *v, Adr *s) return 2; goto caseread; - case AMOVSL: case AREP: case AREPN: - if(v->type == D_CX || v->type == D_DI || v->type == D_SI) + if(v->type == D_CX) + return 2; + goto caseread; + + case AMOVSB: + case AMOVSL: + if(v->type == D_DI || v->type == D_SI) + return 2; + goto caseread; + + case ASTOSB: + case ASTOSL: + if(v->type == D_AX || v->type == D_DI) return 2; goto caseread; diff --git a/sys/src/cmd/8c/reg.c b/sys/src/cmd/8c/reg.c index 12ad50ab7..c2bab2d02 100644 --- a/sys/src/cmd/8c/reg.c +++ b/sys/src/cmd/8c/reg.c @@ -119,7 +119,7 @@ regopt(Prog *p) r1->s1 = R; } - bit = mkvar(r, &p->from); + bit = mkvar(r, &p->from, p->as==AMOVL); if(bany(&bit)) switch(p->as) { /* @@ -139,7 +139,7 @@ regopt(Prog *p) break; } - bit = mkvar(r, &p->to); + bit = mkvar(r, &p->to, 0); if(bany(&bit)) switch(p->as) { default: @@ -224,7 +224,9 @@ regopt(Prog *p) */ case AFMOVDP: case AFMOVFP: + case AFMOVLP: case AFMOVVP: + case AFMOVWP: case ACALL: for(z=0; ztype; r->regu |= doregbits(t); r->regu |= doregbits(a->index); + et = a->etype; switch(t) { default: goto none; + case D_INDIR+D_GS: + if(!isro || 1) + goto none; + n = t; + {static Sym er; a->sym = &er;} + a->sym->name = "$extreg"; + break; case D_ADDR: a->type = a->index; - bit = mkvar(r, a); + bit = mkvar(r, a, 0); for(z=0; ztype = t; @@ -674,7 +684,6 @@ mkvar(Reg *r, Adr *a) goto none; if(s->name[0] == '.') goto none; - et = a->etype; o = a->offset; v = var; for(i=0; iuse1.b[z] & bb) { change += CREF * r->loop; - if(p->as == AFMOVL) + if(p->as == AFMOVL || p->as == AFMOVW) if(BtoR(bb) != D_F0) change = -CINF; if(debug['R'] && debug['v']) @@ -1018,7 +1027,7 @@ paint1(Reg *r, int bn) if((r->use2.b[z]|r->set.b[z]) & bb) { change += CREF * r->loop; - if(p->as == AFMOVL) + if(p->as == AFMOVL || p->as == AFMOVW) if(BtoR(bb) != D_F0) change = -CINF; if(debug['R'] && debug['v']) @@ -1028,7 +1037,7 @@ paint1(Reg *r, int bn) if(STORE(r) & r->regdiff.b[z] & bb) { change -= CLOAD * r->loop; - if(p->as == AFMOVL) + if(p->as == AFMOVL || p->as == AFMOVW) if(BtoR(bb) != D_F0) change = -CINF; if(debug['R'] && debug['v']) diff --git a/sys/src/cmd/8c/sgen.c b/sys/src/cmd/8c/sgen.c index df12f903b..9ba278c8c 100644 --- a/sys/src/cmd/8c/sgen.c +++ b/sys/src/cmd/8c/sgen.c @@ -88,6 +88,10 @@ xcom(Node *n) n->addable = 11; break; + case OEXREG: + n->addable = 12; + break; + case OREGISTER: n->addable = 12; break; diff --git a/sys/src/cmd/8c/swt.c b/sys/src/cmd/8c/swt.c index d2c48b40a..f469f18d4 100644 --- a/sys/src/cmd/8c/swt.c +++ b/sys/src/cmd/8c/swt.c @@ -10,7 +10,7 @@ swit1(C1 *q, int nc, long def, Node *n) if(nc < 5) { for(i=0; ival); + print("case = %.8llux\n", q->val); gopcode(OEQ, n->type, n, nodconst(q->val)); patch(p, q->label); q++; @@ -22,7 +22,7 @@ swit1(C1 *q, int nc, long def, Node *n) i = nc / 2; r = q+i; if(debug['W']) - print("case > %.8lux\n", r->val); + print("case > %.8llux\n", r->val); gopcode(OGT, n->type, n, nodconst(r->val)); sp = p; gbranch(OGOTO); @@ -31,7 +31,7 @@ swit1(C1 *q, int nc, long def, Node *n) swit1(q, i, def, n); if(debug['W']) - print("case < %.8lux\n", r->val); + print("case < %.8llux\n", r->val); patch(sp, pc); swit1(r+1, nc-i-1, def, n); } @@ -199,7 +199,6 @@ outcode(void) return; } Binit(&b, f, OWRITE); - Blethal(&b, nil); Bseek(&b, 0L, 2); outhist(&b); for(sym=0; symop = OREGPAIR; + n->complex = 0; /* already in registers */ + n->addable = 11; + n->type = tn->type; + n->lineno = nearln; + n->left = alloc(sizeof(Node)); + n->right = alloc(sizeof(Node)); + if(o != Z && o->op == OREGPAIR) { + regalloc(n->left, ®node, o->left); + regalloc(n->right, ®node, o->right); + } else { + regalloc(n->left, ®node, Z); + regalloc(n->right, ®node, Z); + } + n->right->type = types[TULONG]; + if(tn->type->etype == TUVLONG) + n->left->type = types[TULONG]; + return; } diag(tn, "unknown type in regalloc: %T", tn->type); err: @@ -339,6 +365,12 @@ regfree(Node *n) { int i; + if(n->op == OREGPAIR) { + regfree(n->left); + regfree(n->right); + return; + } + i = 0; if(n->op != OREGISTER && n->op != OINDREG) goto err; @@ -430,6 +462,11 @@ naddr(Node *n, Adr *a) a->sym = S; break; + case OEXREG: + a->type = D_INDIR + D_GS; + a->offset = n->reg - 1; + a->etype = n->etype; + break; case OIND: naddr(n->left, a); @@ -609,9 +646,6 @@ gmove(Node *f, Node *t) case TDOUBLE: gins(AFMOVD, f, t); return; - case TVLONG: - gins(AFMOVV, f, t); - return; } /* @@ -650,9 +684,6 @@ gmove(Node *f, Node *t) case TDOUBLE: gins(AFMOVDP, f, t); return; - case TVLONG: - gins(AFMOVVP, f, t); - return; } /* @@ -980,7 +1011,7 @@ fgopcode(int o, Node *f, Node *t, int pop, int rev) if(et == TFLOAT) a = AFADDF; else - if(et == TDOUBLE || et == TVLONG) { + if(et == TDOUBLE) { a = AFADDD; if(pop) a = AFADDDP; @@ -994,7 +1025,7 @@ fgopcode(int o, Node *f, Node *t, int pop, int rev) if(rev) a = AFSUBRF; } else - if(et == TDOUBLE || et == TVLONG) { + if(et == TDOUBLE) { a = AFSUBD; if(pop) a = AFSUBDP; @@ -1011,7 +1042,7 @@ fgopcode(int o, Node *f, Node *t, int pop, int rev) if(et == TFLOAT) a = AFMULF; else - if(et == TDOUBLE || et == TVLONG) { + if(et == TDOUBLE) { a = AFMULD; if(pop) a = AFMULDP; @@ -1027,7 +1058,7 @@ fgopcode(int o, Node *f, Node *t, int pop, int rev) if(rev) a = AFDIVRF; } else - if(et == TDOUBLE || et == TVLONG) { + if(et == TDOUBLE) { a = AFDIVD; if(pop) a = AFDIVDP; @@ -1054,7 +1085,7 @@ fgopcode(int o, Node *f, Node *t, int pop, int rev) a = AGOK; } } else - if(et == TDOUBLE || et == TVLONG) { + if(et == TDOUBLE) { a = AFCOMF; if(pop) { a = AFCOMDP; @@ -1355,7 +1386,15 @@ long exreg(Type *t) { - USED(t); + int o; + + if(typechlp[t->etype]){ + if(exregoffset >= 32) + return 0; + o = exregoffset; + exregoffset += 4; + return o+1; /* +1 to avoid 0 == failure; naddr case OEXREG will -1. */ + } return 0; } diff --git a/sys/src/cmd/8l/l.h b/sys/src/cmd/8l/l.h index 28b0bb404..e76b77a31 100644 --- a/sys/src/cmd/8l/l.h +++ b/sys/src/cmd/8l/l.h @@ -37,7 +37,7 @@ struct Adr Sym* u1sym; } u1; short type; - char index; + uchar index; char scale; }; @@ -58,11 +58,12 @@ struct Prog Prog* pcond; /* work on this */ long pc; long line; - uchar mark; /* work on these */ - uchar back; - short as; char width; /* fake for DATA */ + char ft; /* oclass cache */ + char tt; + uchar mark; /* work on these */ + uchar back; }; struct Auto { @@ -203,6 +204,7 @@ EXTERN union #pragma varargck type "D" Adr* #pragma varargck type "P" Prog* #pragma varargck type "R" int +#pragma varargck type "R" uint #pragma varargck type "S" char* #pragma varargck argpos diag 1 @@ -270,7 +272,7 @@ EXTERN int dtype; EXTERN Adr* reloca; EXTERN int doexp, dlm; EXTERN int imports, nimports; -EXTERN int exports, nexports; +EXTERN int exports, nexports, allexport; EXTERN char* EXPTAB; EXTERN Prog undefp; @@ -345,3 +347,8 @@ 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 diff --git a/sys/src/cmd/8l/list.c b/sys/src/cmd/8l/list.c index f52477d54..f452b758d 100644 --- a/sys/src/cmd/8l/list.c +++ b/sys/src/cmd/8l/list.c @@ -24,18 +24,18 @@ Pconv(Fmt *fp) switch(p->as) { case ATEXT: if(p->from.scale) { - sprint(str, "(%ld) %A %D,%d,%D", + snprint(str, sizeof(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", + snprint(str, sizeof(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", + snprint(str, sizeof(str), "(%ld) %A %D/%d,%D", p->line, p->as, &p->from, p->from.scale, &p->to); break; } @@ -55,7 +55,7 @@ Aconv(Fmt *fp) int Dconv(Fmt *fp) { - char str[40], s[20]; + char str[STRINGSZ+40], s[20]; Adr *a; int i; @@ -63,15 +63,15 @@ Dconv(Fmt *fp) i = a->type; if(i >= D_INDIR) { if(a->offset) - sprint(str, "%ld(%R)", a->offset, i-D_INDIR); + snprint(str, sizeof(str), "%ld(%R)", a->offset, i-D_INDIR); else - sprint(str, "(%R)", i-D_INDIR); + snprint(str, sizeof(str), "(%R)", i-D_INDIR); goto brk; } switch(i) { default: - sprint(str, "%R", i); + snprint(str, sizeof(str), "%R", i); break; case D_NONE: @@ -81,57 +81,57 @@ Dconv(Fmt *fp) case D_BRANCH: if(bigP != P && bigP->pcond != P) if(a->sym != S) - sprint(str, "%lux+%s", bigP->pcond->pc, + snprint(str, sizeof(str), "%lux+%s", bigP->pcond->pc, a->sym->name); else - sprint(str, "%lux", bigP->pcond->pc); + snprint(str, sizeof(str), "%lux", bigP->pcond->pc); else - sprint(str, "%ld(PC)", a->offset); + snprint(str, sizeof(str), "%ld(PC)", a->offset); break; case D_EXTERN: - sprint(str, "%s+%ld(SB)", a->sym->name, a->offset); + snprint(str, sizeof(str), "%s+%ld(SB)", a->sym->name, a->offset); break; case D_STATIC: - sprint(str, "%s<%d>+%ld(SB)", a->sym->name, + snprint(str, sizeof(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); + snprint(str, sizeof(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); + snprint(str, sizeof(str), "%s+%ld(FP)", a->sym->name, a->offset); else - sprint(str, "%ld(FP)", a->offset); + snprint(str, sizeof(str), "%ld(FP)", a->offset); break; case D_CONST: - sprint(str, "$%ld", a->offset); + snprint(str, sizeof(str), "$%ld", a->offset); break; case D_FCONST: - sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l); + snprint(str, sizeof(str), "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l); break; case D_SCONST: - sprint(str, "$\"%S\"", a->scon); + snprint(str, sizeof(str), "$\"%S\"", a->scon); break; case D_ADDR: a->type = a->index; a->index = D_NONE; - sprint(str, "$%D", a); + snprint(str, sizeof(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); + snprint(s, sizeof(s), "(%R*%d)", a->index, a->scale); strcat(str, s); } conv: @@ -218,9 +218,9 @@ Rconv(Fmt *fp) r = va_arg(fp->args, int); if(r >= D_AL && r <= D_NONE) - sprint(str, "%s", regstr[r-D_AL]); + snprint(str, sizeof(str), "%s", regstr[r-D_AL]); else - sprint(str, "gok(%d)", r); + snprint(str, sizeof(str), "gok(%d)", r); return fmtstrcpy(fp, str); } diff --git a/sys/src/cmd/8l/obj.c b/sys/src/cmd/8l/obj.c index 8044d40df..97d4ba090 100644 --- a/sys/src/cmd/8l/obj.c +++ b/sys/src/cmd/8l/obj.c @@ -95,8 +95,13 @@ main(int argc, char *argv[]) break; case 'x': /* produce export table */ doexp = 1; - if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) - readundefs(ARGF(), SEXPORT); + if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])){ + a = ARGF(); + if(strcmp(a, "*") == 0) + allexport = 1; + else + readundefs(a, SEXPORT); + } break; case 'u': /* produce dynamically loadable module */ dlm = 1; diff --git a/sys/src/cmd/8l/pass.c b/sys/src/cmd/8l/pass.c index fa9d0f7d9..6de027aff 100644 --- a/sys/src/cmd/8l/pass.c +++ b/sys/src/cmd/8l/pass.c @@ -311,7 +311,7 @@ patch(void) switch(s->type) { default: /* diag prints TNAME first */ - diag("%s is undefined", s->name); + diag("undefined: %s", s->name); s->type = STEXT; s->value = vexit; break; /* or fall through to set offset? */ @@ -678,14 +678,14 @@ export(void) 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)) + if(s->type != SXREF && s->type != SUNDEF && (nexports == 0 && s->sig != 0 || s->subtype == SEXPORT || allexport)) 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)) + if(s->type != SXREF && s->type != SUNDEF && (nexports == 0 && s->sig != 0 || s->subtype == SEXPORT || allexport)) esyms[n++] = s; for(i = 0; i < ne-1; i++) for(j = i+1; j < ne; j++) diff --git a/sys/src/cmd/8l/span.c b/sys/src/cmd/8l/span.c index 0adecbb7e..b9f284640 100644 --- a/sys/src/cmd/8l/span.c +++ b/sys/src/cmd/8l/span.c @@ -303,6 +303,24 @@ asmlc(void) Bflush(&bso); } +int +prefixof(Adr *a) +{ + switch(a->type) { + case D_INDIR+D_CS: + return 0x2e; + case D_INDIR+D_DS: + return 0x3e; + case D_INDIR+D_ES: + return 0x26; + case D_INDIR+D_FS: + return 0x64; + case D_INDIR+D_GS: + return 0x65; + } + return 0; +} + int oclass(Adr *a) { @@ -334,6 +352,8 @@ oclass(Adr *a) return Yax; case D_CL: + return Ycl; + case D_DL: case D_BL: case D_AH: @@ -606,7 +626,7 @@ asmand(Adr *a, int r) } if(t >= D_INDIR) { t -= D_INDIR; - if(t == D_NONE) { + if(t == D_NONE || D_CS <= t && t <= D_GS) { *andptr++ = (0 << 6) | (5 << 0) | (r << 3); put4(v); return; @@ -767,6 +787,7 @@ uchar ymovtab[] = ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0, /* extra imul */ + AIMULW, Yml, Yrl, 7, Pq,0xaf,0,0, AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0, 0 }; @@ -821,7 +842,14 @@ doasm(Prog *p) Prog *q, pp; uchar *t; int z, op, ft, tt; - long v; + long v, pre; + + pre = prefixof(&p->from); + if(pre) + *andptr++ = pre; + pre = prefixof(&p->to); + if(pre) + *andptr++ = pre; o = &optab[p->as]; ft = oclass(&p->from) * Ymax; @@ -1061,7 +1089,7 @@ found: q = p->pcond; if(q) { v = q->pc - p->pc - 2; - if(v < -128 && v > 127) + if(v < -128 || v > 127) diag("loop too far: %P", p); *andptr++ = op; *andptr++ = v; diff --git a/sys/src/cmd/audio/mp3enc/main.c b/sys/src/cmd/audio/mp3enc/main.c index 93e67b447..e8f62e3cc 100644 --- a/sys/src/cmd/audio/mp3enc/main.c +++ b/sys/src/cmd/audio/mp3enc/main.c @@ -289,5 +289,5 @@ main(int argc, char **argv) fclose(outf); } close_infile(); - exit(0); + return 0; } diff --git a/sys/src/cmd/bzfs/unbzip.c b/sys/src/cmd/bzfs/unbzip.c index 070e7ba48..b02fd0abf 100644 --- a/sys/src/cmd/bzfs/unbzip.c +++ b/sys/src/cmd/bzfs/unbzip.c @@ -302,7 +302,6 @@ getbits(DState *s, int lll, int *vvv, int nnn) if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; } - return -1; /* KEN */ } #define GET_UCHAR(lll,uuu) \ diff --git a/sys/src/cmd/cc/acid.c b/sys/src/cmd/cc/acid.c index 8ad20a913..d42b47b42 100644 --- a/sys/src/cmd/cc/acid.c +++ b/sys/src/cmd/cc/acid.c @@ -90,6 +90,8 @@ acidinit(void) if(types[TINT]->width != types[TSHORT]->width) warn(Z, "acidmember int not long or short"); } + if(types[TIND]->width == types[TUVLONG]->width) + acidchar[TIND] = 'Y'; } diff --git a/sys/src/cmd/cc/cc.h b/sys/src/cmd/cc/cc.h index c46b972f9..d66faaa11 100644 --- a/sys/src/cmd/cc/cc.h +++ b/sys/src/cmd/cc/cc.h @@ -22,15 +22,15 @@ typedef struct Bits Bits; #define NHUNK 50000L #define BUFSIZ 8192 -#define NSYMB 500 +#define NSYMB 1500 #define NHASH 1024 #define STRINGSZ 200 #define HISTSZ 20 -#define YYMAXDEPTH 500 +#define YYMAXDEPTH 1500 #define NTERM 10 #define MAXALIGN 7 -#define SIGN(n) ((vlong)1<<(n-1)) +#define SIGN(n) (1ULL<<(n-1)) #define MASK(n) (SIGN(n)|(SIGN(n)-1)) #define BITS 5 @@ -294,6 +294,7 @@ enum OINDEX, OFAS, OREGPAIR, + OEXREG, OEND }; @@ -477,6 +478,7 @@ EXTERN int packflg; EXTERN int fproundflg; EXTERN int profileflg; EXTERN int ncontin; +EXTERN int newvlongcode; EXTERN int canreach; EXTERN int warnreach; EXTERN Bits zbits; @@ -507,6 +509,7 @@ extern char typechlvp[]; extern char typechlp[]; extern char typechlpfd[]; +EXTERN char* typeswitch; EXTERN char* typeword; EXTERN char* typecmplx; @@ -614,7 +617,7 @@ int rsametype(Type*, Type*, int, int); int sametype(Type*, Type*); ulong sign(Sym*); ulong signature(Type*); -void suallign(Type*); +void sualign(Type*); void tmerge(Type*, Sym*); void walkparam(Node*, int); void xdecl(int, Type*, Sym*); @@ -632,6 +635,8 @@ int tcomo(Node*, int); int tcomx(Node*); int tlvalue(Node*); void constas(Node*, Type*, Type*); +Node* uncomma(Node*); +Node* uncomargs(Node*); /* * con.c diff --git a/sys/src/cmd/cc/cc.y b/sys/src/cmd/cc/cc.y index 3057547b0..09b788598 100644 --- a/sys/src/cmd/cc/cc.y +++ b/sys/src/cmd/cc/cc.y @@ -8,12 +8,14 @@ struct { Type* t; - char c; + uchar c; } tycl; struct { Type* t1; Type* t2; + Type* t3; + uchar c; } tyty; struct { @@ -895,16 +897,22 @@ sbody: { $$.t1 = strf; $$.t2 = strl; + $$.t3 = lasttype; + $$.c = lastclass; strf = T; strl = T; lastbit = 0; firstbit = 1; + lastclass = CXXX; + lasttype = T; } edecl '}' { $$ = strf; strf = $2.t1; strl = $2.t2; + lasttype = $2.t3; + lastclass = $2.c; } zctlist: @@ -995,7 +1003,7 @@ complex: if($$->link != T) diag(Z, "redeclare tag: %s", $2->name); $$->link = $4; - suallign($$); + sualign($$); } | LSTRUCT sbody { @@ -1003,7 +1011,7 @@ complex: sprint(symb, "_%d_", taggen); $$ = dotag(lookup(), TSTRUCT, autobn); $$->link = $2; - suallign($$); + sualign($$); } | LUNION ltag { @@ -1020,7 +1028,7 @@ complex: if($$->link != T) diag(Z, "redeclare tag: %s", $2->name); $$->link = $4; - suallign($$); + sualign($$); } | LUNION sbody { @@ -1028,7 +1036,7 @@ complex: sprint(symb, "_%d_", taggen); $$ = dotag(lookup(), TUNION, autobn); $$->link = $2; - suallign($$); + sualign($$); } | LENUM ltag { diff --git a/sys/src/cmd/cc/com.c b/sys/src/cmd/cc/com.c index 1401e48d4..8ff7c4663 100644 --- a/sys/src/cmd/cc/com.c +++ b/sys/src/cmd/cc/com.c @@ -1,6 +1,15 @@ #include "cc.h" +typedef struct Com Com; +struct Com +{ + int n; + Node *t[500]; +}; + int compar(Node*, int); +static void comma(Node*); +static Node* commas(Com*, Node*); void complex(Node *n) @@ -15,6 +24,8 @@ complex(Node *n) prtree(n, "pre complex"); if(tcom(n)) return; + if(debug['y'] || 1) + comma(n); if(debug['t']) if(n->op != OCONST) prtree(n, "t complex"); @@ -273,8 +284,11 @@ tcomo(Node *n, int f) goto bad; n->type = l->type; if(n->type->etype == TIND) - if(n->type->link->width < 1) - diag(n, "inc/dec of a void pointer"); + if(n->type->link->width < 1) { + snap(n->type->link); + if(n->type->link->width < 1) + diag(n, "inc/dec of a void pointer"); + } break; case OEQ: @@ -610,6 +624,8 @@ tcomo(Node *n, int f) n->addable = 1; if(n->class == CEXREG) { n->op = OREGISTER; + if(thechar == '8') + n->op = OEXREG; n->reg = n->sym->offset; n->xoffset = 0; break; @@ -881,6 +897,101 @@ tlvalue(Node *n) return 0; } +/* + * hoist comma operators out of expressions + * (a,b) OP c => (a, b OP c) + * OP(a,b) => (a, OP b) + * a OP (b,c) => (b, a OP c) + */ + +static Node* +comargs(Com *com, Node *n) +{ + if(n != Z && n->op == OLIST){ + n->left = comargs(com, n->left); + n->right = comargs(com, n->right); + } + return commas(com, n); +} + +static Node* +commas(Com *com, Node *n) +{ + Node *t; + + if(n == Z) + return n; + switch(n->op){ + case OREGISTER: + case OINDREG: + case OCONST: + case ONAME: + case OSTRING: + /* leaf */ + return n; + + case OCOMMA: + t = commas(com, n->left); + if(com->n >= nelem(com->t)) + fatal(n, "comma list overflow"); + com->t[com->n++] = t; + return commas(com, n->right); + + case OFUNC: + n->left = commas(com, n->left); + n->right = comargs(com, n->right); + return n; + + case OCOND: + n->left = commas(com, n->left); + comma(n->right->left); + comma(n->right->right); + return n; + + case OANDAND: + case OOROR: + n->left = commas(com, n->left); + comma(n->right); + return n; + + case ORETURN: + comma(n->left); + return n; + } + n->left = commas(com, n->left); + if(n->right != Z) + n->right = commas(com, n->right); + return n; +} + +static void +comma(Node *n) +{ + Com com; + Node *nn; + + com.n = 0; + nn = commas(&com, n); + if(com.n > 0){ +if(debug['y'])print("n=%d\n", com.n); +if(debug['y']) prtree(nn, "res"); + if(nn != n) + *n = *nn; + while(com.n > 0){ +if(debug['y']) prtree(com.t[com.n-1], "tree"); + nn = new1(OXXX, Z, Z); + *nn = *n; + n->op = OCOMMA; + n->type = nn->type; + n->left = com.t[--com.n]; + n->right = nn; + n->lineno = n->left->lineno; + } +if(debug['y']) prtree(n, "final"); + }else if(n != nn) + fatal(n, "odd tree"); +} + /* * general rewrite * (IND(ADDR x)) ==> x @@ -934,7 +1045,8 @@ loop: if(n->op == OCONST) break; } - if(nocast(l->type, n->type)) { + if(nocast(l->type, n->type) && + (!typefd[l->type->etype] || typeu[l->type->etype] && typeu[n->type->etype])) { l->type = n->type; *n = *l; } @@ -1342,6 +1454,7 @@ useless: else snprint(cmpbuf, sizeof cmpbuf, "%T %s %s", lt, cmps[relindex(n->op)], xbuf); +if(debug['y']) prtree(n, "strange"); warn(n, "useless or misleading comparison: %s", cmpbuf); return 0; } diff --git a/sys/src/cmd/cc/com64.c b/sys/src/cmd/cc/com64.c index 53c3c9fca..f44a44ffe 100644 --- a/sys/src/cmd/cc/com64.c +++ b/sys/src/cmd/cc/com64.c @@ -274,8 +274,8 @@ com64(Node *n) case ORETURN: case OAS: case OIND: - case OCOMMA: case OLIST: + case OCOMMA: return 1; case OADD: a = nodaddv; diff --git a/sys/src/cmd/cc/dcl.c b/sys/src/cmd/cc/dcl.c index c21375a94..968654165 100644 --- a/sys/src/cmd/cc/dcl.c +++ b/sys/src/cmd/cc/dcl.c @@ -519,7 +519,7 @@ newlist(Node *l, Node *r) } void -suallign(Type *t) +sualign(Type *t) { Type *l; long o, w; @@ -581,7 +581,7 @@ suallign(Type *t) return; default: - diag(Z, "unknown type in suallign: %T", t); + diag(Z, "unknown type in sualign: %T", t); break; } } @@ -1180,12 +1180,6 @@ paramconv(Type *t, int f) { switch(t->etype) { - case TUNION: - case TSTRUCT: - if(t->width <= 0) - diag(Z, "incomplete structure: %s", t->tag->name); - break; - case TARRAY: t = typ(TIND, t->link); t->width = types[TIND]->width; @@ -1283,6 +1277,8 @@ pdecl(int c, Type *t, Sym *s) diag(Z, "parameter cannot have class: %s", s->name); c = CPARAM; } + if(typesu[t->etype] && t->width <= 0) + diag(Z, "incomplete structure: %s", t->tag->name); adecl(c, t, s); } diff --git a/sys/src/cmd/cc/lex.c b/sys/src/cmd/cc/lex.c index 74054aa22..2652cb8f8 100644 --- a/sys/src/cmd/cc/lex.c +++ b/sys/src/cmd/cc/lex.c @@ -1262,9 +1262,7 @@ loop: if(i->f < 0) goto pop; fi.c = read(i->f, i->b, BUFSIZ) - 1; - if(fi.c < -1) - sysfatal("read error: %r"); - if(fi.c == -1) { + if(fi.c < 0) { close(i->f); linehist(0, 0); goto pop; diff --git a/sys/src/cmd/cc/macbody b/sys/src/cmd/cc/macbody index e26dc427a..7c86bac19 100644 --- a/sys/src/cmd/cc/macbody +++ b/sys/src/cmd/cc/macbody @@ -25,7 +25,7 @@ getsym(void) char *cp; c = getnsc(); - if(!isalpha(c) && c != '_') { + if(!isalpha(c) && c != '_' && c < Runeself) { unget(c); return S; } @@ -33,7 +33,7 @@ getsym(void) if(cp <= symb+NSYMB-4) *cp++ = c; c = getc(); - if(isalnum(c) || c == '_') + if(isalnum(c) || c == '_' || c >= Runeself) continue; unget(c); break; diff --git a/sys/src/cmd/cc/pgen.c b/sys/src/cmd/cc/pgen.c index 131ff012b..c9002ac33 100644 --- a/sys/src/cmd/cc/pgen.c +++ b/sys/src/cmd/cc/pgen.c @@ -70,8 +70,12 @@ codgen(Node *n, Node *nn) canreach = 1; warnreach = 1; gen(n); - if(canreach && thisfn->link->etype != TVOID) - warn(Z, "no return at end of function: %s", n1->sym->name); + if(canreach && thisfn->link->etype != TVOID){ + if(debug['B']) + warn(Z, "no return at end of function: %s", n1->sym->name); + else + diag(Z, "no return at end of function: %s", n1->sym->name); + } noretval(3); gbranch(ORETURN); @@ -105,10 +109,20 @@ supgen(Node *n) warnreach = owarn; } +Node* +uncomma(Node *n) +{ + while(n != Z && n->op == OCOMMA) { + cgen(n->left, Z); + n = n->right; + } + return n; +} + void gen(Node *n) { - Node *l, nod; + Node *l, nod, rn; Prog *sp, *spc, *spb; Case *cn; long sbc, scc; @@ -129,6 +143,7 @@ loop: case OLABEL: case OCASE: case OLIST: + case OCOMMA: case OBREAK: case OFOR: case OWHILE: @@ -151,6 +166,7 @@ loop: break; case OLIST: + case OCOMMA: gen(n->left); rloop: @@ -163,7 +179,7 @@ loop: complex(n); if(n->type == T) break; - l = n->left; + l = uncomma(n->left); if(l == Z) { noretval(3); gbranch(ORETURN); @@ -181,6 +197,20 @@ loop: gbranch(ORETURN); break; } + if(newvlongcode && !typefd[n->type->etype]){ + regret(&rn, n); + regfree(&rn); + nod = znode; + nod.op = OAS; + nod.left = &rn; + nod.right = l; + nod.type = n->type; + nod.complex = l->complex; + cgen(&nod, Z); + noretval(2); + gbranch(ORETURN); + break; + } regret(&nod, n); cgen(l, &nod); regfree(&nod); @@ -241,16 +271,15 @@ loop: complex(l); if(l->type == T) goto rloop; - if(l->op == OCONST) - if(typeword[l->type->etype] && l->type->etype != TIND) { - casf(); - cases->val = l->vconst; - cases->def = 0; - cases->label = pc; - cases->isv = typev[l->type->etype]; + if(l->op != OCONST || !typeswitch[l->type->etype]) { + diag(n, "case expression must be integer constant"); goto rloop; } - diag(n, "case expression must be integer constant"); + casf(); + cases->val = l->vconst; + cases->def = 0; + cases->label = pc; + cases->isv = typev[l->type->etype]; goto rloop; case OSWITCH: @@ -258,7 +287,7 @@ loop: complex(l); if(l->type == T) break; - if(!typeword[l->type->etype] || l->type->etype == TIND) { + if(!typeswitch[l->type->etype]) { diag(n, "switch expression must be integer"); break; } @@ -531,6 +560,8 @@ usedset(Node *n, int o) int bcomplex(Node *n, Node *c) { + Node *b, nod; + complex(n); if(n->type != T) @@ -542,6 +573,18 @@ bcomplex(Node *n, Node *c) } if(c != Z && n->op == OCONST && deadheads(c)) return 1; + /* this is not quite right yet, so ignore it for now */ + if(0 && newvlongcode && 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]; + cgen(b, Z); + return 0; + } bool64(n); boolgen(n, 1, Z); return 0; diff --git a/sys/src/cmd/cc/pswt.c b/sys/src/cmd/cc/pswt.c index 6ef4f2fbe..df1cda4a4 100644 --- a/sys/src/cmd/cc/pswt.c +++ b/sys/src/cmd/cc/pswt.c @@ -16,8 +16,10 @@ void doswit(Node *n) { Case *c; - C1 *q, *iq; - long def, nc, i, isv; + C1 *q, *iq, *iqh, *iql; + long def, nc, i, j, isv, nh; + Prog *hsb; + Node *vr[2]; int dup; def = 0; @@ -33,14 +35,20 @@ doswit(Node *n) isv |= c->isv; nc++; } - if(isv && !typev[n->type->etype]) + if(typev[n->type->etype]) + isv = 1; + else if(isv){ warn(n, "32-bit switch expression with 64-bit case constant"); + isv = 0; + } iq = alloc(nc*sizeof(C1)); q = iq; for(c = cases; c->link != C; c = c->link) { if(c->def) continue; + if(c->isv && !isv) + continue; /* can never match */ q->label = c->label; if(isv) q->val = c->val; @@ -64,7 +72,53 @@ doswit(Node *n) def = breakpc; nbreak++; } - swit1(iq, nc, def, n); + if(!isv || ewidth[TIND] > ewidth[TLONG] || n->op == OREGISTER) { + swit1(iq, nc, def, n); + return; + } + + /* + * 64-bit case on 32-bit machine: + * switch on high-order words, and + * in each of those, switch on low-order words + */ + if(n->op != OREGPAIR) + fatal(n, "internal: expected register pair"); + if(thechar == '8'){ /* TO DO: need an enquiry function */ + vr[0] = n->left; /* low */ + vr[1] = n->right; /* high */ + }else{ + vr[0] = n->right; + vr[1] = n->left; + } + vr[0]->type = types[TLONG]; + vr[1]->type = types[TLONG]; + gbranch(OGOTO); + hsb = p; + iqh = alloc(nc*sizeof(C1)); + iql = alloc(nc*sizeof(C1)); + nh = 0; + for(i=0; i> 32; + q = iql; + /* iq is sorted, so equal top halves are adjacent */ + for(j = i; j < nc; j++){ + if((iq[j].val>>32) != iqh[nh].val) + break; + q->val = (long)iq[j].val; + q->label = iq[j].label; + q++; + } + qsort(iql, q-iql, sizeof(C1), swcmp); +if(0){for(int k=0; k<(q-iql); k++)print("nh=%ld k=%d h=%#llux l=%#llux lab=%ld\n", nh, k, (vlong)iqh[nh].val, (vlong)iql[k].val, iql[k].label);} + iqh[nh].label = pc; + nh++; + swit1(iql, q-iql, def, vr[0]); + i = j; + } + patch(hsb, pc); +if(0){for(int k=0; kdisk, &table, sizeof(Table), 0, Toffset); if(table.magic[0] != Magic0 || table.magic[1] != Magic1) diff --git a/sys/src/cmd/grap/main.c b/sys/src/cmd/grap/main.c index 821405ecb..642077911 100644 --- a/sys/src/cmd/grap/main.c +++ b/sys/src/cmd/grap/main.c @@ -34,6 +34,7 @@ extern void setdefaults(void); extern void getdata(void); extern int unlink(char *); +void main(int argc, char *argv[]) { extern void onintr(int), fpecatch(int); diff --git a/sys/src/cmd/kc/gc.h b/sys/src/cmd/kc/gc.h index 1ff5a633a..60435b4dd 100644 --- a/sys/src/cmd/kc/gc.h +++ b/sys/src/cmd/kc/gc.h @@ -54,7 +54,7 @@ struct Prog struct Case { Case* link; - long val; + vlong val; long label; char def; char isv; @@ -63,7 +63,7 @@ struct Case struct C1 { - long val; + vlong val; long label; }; diff --git a/sys/src/cmd/ki/ki.c b/sys/src/cmd/ki/ki.c index 6a07e7be5..38427584a 100644 --- a/sys/src/cmd/ki/ki.c +++ b/sys/src/cmd/ki/ki.c @@ -2,6 +2,7 @@ #include #include #include +#include #define Extern #include "sparc.h" @@ -277,12 +278,22 @@ reset(void) void initstk(int argc, char *argv[]) { - ulong size, sp, ap; + ulong size, sp, ap, tos; int i; char *p; initmap(); - sp = STACKTOP - 4; + tos = STACKTOP - sizeof(Tos)*2; /* we'll assume twice the host's is big enough */ + sp = tos; + for (i = 0; i < sizeof(Tos)*2; i++) + putmem_b(tos + i, 0); + + /* + * pid is second word from end of tos and needs to be set for nsec(). + * we know sparc is a 32-bit cpu, so we'll assume knowledge of the Tos + * struct for now, and use our pid. + */ + putmem_w(tos + 4*4 + 2*sizeof(ulong) + 3*sizeof(uvlong), getpid()); /* Build exec stack */ size = strlen(file)+1+BY2WD+BY2WD+(BY2WD*2); @@ -292,7 +303,7 @@ initstk(int argc, char *argv[]) sp -= size; sp &= ~7; reg.r[1] = sp; - reg.r[7] = STACKTOP-4; /* Plan 9 profiling clock */ + reg.r[7] = tos; /* Plan 9 profiling clock, etc. */ /* Push argc */ putmem_w(sp, argc+1); diff --git a/sys/src/cmd/lp/lpdaemon.c b/sys/src/cmd/lp/lpdaemon.c index b646a005b..bfd974e59 100644 --- a/sys/src/cmd/lp/lpdaemon.c +++ b/sys/src/cmd/lp/lpdaemon.c @@ -319,6 +319,7 @@ alarmhandler(int sig) { error("alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]); } +void main() { unsigned char *ap, *bp, *cp, *savbufpnt; diff --git a/sys/src/cmd/lp/lpdsend.c b/sys/src/cmd/lp/lpdsend.c index 308028bef..c841bc50b 100644 --- a/sys/src/cmd/lp/lpdsend.c +++ b/sys/src/cmd/lp/lpdsend.c @@ -278,6 +278,7 @@ netmkaddr(char *linear, char *defnet, char *defsrv) return addr; } +void main(int argc, char *argv[]) { int c, usgflg = 0, inputfd, printerfd, sendport; diff --git a/sys/src/cmd/postscript/text2post/text2post.c b/sys/src/cmd/postscript/text2post/text2post.c index 9f547f4d3..963911305 100644 --- a/sys/src/cmd/postscript/text2post/text2post.c +++ b/sys/src/cmd/postscript/text2post/text2post.c @@ -469,6 +469,7 @@ finish(void) { } +void main(int argc, char *argv[]) { int i; char *t; diff --git a/sys/src/cmd/postscript/tr2post/ps_include.c b/sys/src/cmd/postscript/tr2post/ps_include.c index 27d020a3a..182ba2e34 100644 --- a/sys/src/cmd/postscript/tr2post/ps_include.c +++ b/sys/src/cmd/postscript/tr2post/ps_include.c @@ -11,7 +11,7 @@ extern int curfontsize; typedef struct {long start, end;} Section; static char *buf; -static +static void copy(Biobufhdr *fin, Biobufhdr *fout, Section *s) { int cond; if (s->end <= s->start) diff --git a/sys/src/cmd/postscript/tr2post/readDESC.c b/sys/src/cmd/postscript/tr2post/readDESC.c index 473470d38..a6fdb8f93 100644 --- a/sys/src/cmd/postscript/tr2post/readDESC.c +++ b/sys/src/cmd/postscript/tr2post/readDESC.c @@ -54,7 +54,7 @@ readDESC(void) { sprint(descfilename, descnameformat, FONTDIR, devname); if ((bfd = Bopen(descfilename, OREAD)) == 0) { error(WARNING, "cannot open file %s\n", descfilename); - return(0); + return(FALSE); } Bfd = &(bfd->Biobufhdr); @@ -136,4 +136,5 @@ readDESC(void) { } } Bterm(Bfd); + return(TRUE); } diff --git a/sys/src/cmd/postscript/tr2post/tr2post.c b/sys/src/cmd/postscript/tr2post/tr2post.c index 7965eff4a..a2a8686d1 100644 --- a/sys/src/cmd/postscript/tr2post/tr2post.c +++ b/sys/src/cmd/postscript/tr2post/tr2post.c @@ -95,6 +95,7 @@ cleanup(void) { remove(tmpfilename); } +void main(int argc, char *argv[]) { Biobuf *binp; Biobufhdr *Binp; diff --git a/sys/src/cmd/qc/gc.h b/sys/src/cmd/qc/gc.h index c130a6139..0ba612311 100644 --- a/sys/src/cmd/qc/gc.h +++ b/sys/src/cmd/qc/gc.h @@ -57,7 +57,7 @@ struct Prog struct Case { Case* link; - long val; + vlong val; long label; char def; char isv; @@ -66,7 +66,7 @@ struct Case struct C1 { - long val; + vlong val; long label; }; diff --git a/sys/src/cmd/qc/txt.c b/sys/src/cmd/qc/txt.c index 1c6f4d7f8..e5f96fb42 100644 --- a/sys/src/cmd/qc/txt.c +++ b/sys/src/cmd/qc/txt.c @@ -15,6 +15,7 @@ ginit(void) thestring = "power"; exregoffset = REGEXT; exfregoffset = FREGEXT; + newvlongcode = 1; listinit(); nstring = 0; mnstring = 0; @@ -27,6 +28,8 @@ ginit(void) lastp = P; tfield = types[TLONG]; + typeswitch = typechlv; + zprog.link = P; zprog.as = AGOK; zprog.reg = NREG; diff --git a/sys/src/cmd/qi/qi.c b/sys/src/cmd/qi/qi.c index ebccc5e46..a76356e72 100644 --- a/sys/src/cmd/qi/qi.c +++ b/sys/src/cmd/qi/qi.c @@ -2,6 +2,7 @@ #include #include #include +#include #define Extern #include "power.h" @@ -51,6 +52,12 @@ main(int argc, char **argv) cmd(); } +/* + * we're rounding segment boundaries to the nearest 1MB on power now, + * and mach->pgsize is actually what to round segment boundaries up to. + */ +#define SEGROUND mach->pgsize + void initmap(void) { @@ -58,10 +65,10 @@ initmap(void) ulong t, d, b, bssend; Segment *s; - t = (fhdr.txtaddr+fhdr.txtsz+(BY2PG-1)) & ~(BY2PG-1); - d = (t + fhdr.datsz + (BY2PG-1)) & ~(BY2PG-1); + t = (fhdr.txtaddr+fhdr.txtsz+(SEGROUND-1)) & ~(SEGROUND-1); + d = (t + fhdr.datsz + (SEGROUND-1)) & ~(SEGROUND-1); bssend = t + fhdr.datsz + fhdr.bsssz; - b = (bssend + (BY2PG-1)) & ~(BY2PG-1); + b = (bssend + (SEGROUND-1)) & ~(SEGROUND-1); s = &memory.seg[Text]; s->type = Text; @@ -278,12 +285,22 @@ reset(void) void initstk(int argc, char *argv[]) { - ulong size, sp, ap; + ulong size, sp, ap, tos; int i; char *p; initmap(); - sp = STACKTOP - 4; + tos = STACKTOP - sizeof(Tos)*2; /* we'll assume twice the host's is big enough */ + sp = tos; + for (i = 0; i < sizeof(Tos)*2; i++) + putmem_b(tos + i, 0); + + /* + * pid is second word from end of tos and needs to be set for nsec(). + * we know power is a 32-bit cpu, so we'll assume knowledge of the Tos + * struct for now, and use our pid. + */ + putmem_w(tos + 4*4 + 2*sizeof(ulong) + 3*sizeof(uvlong), getpid()); /* Build exec stack */ size = strlen(file)+1+BY2WD+BY2WD+(BY2WD*2); @@ -293,7 +310,7 @@ initstk(int argc, char *argv[]) sp -= size; sp &= ~7; reg.r[1] = sp; - reg.r[3] = STACKTOP-4; /* Plan 9 profiling clock */ + reg.r[3] = tos; /* Plan 9 profiling clock, etc. */ /* Push argc */ putmem_w(sp, argc+1); diff --git a/sys/src/cmd/vc/gc.h b/sys/src/cmd/vc/gc.h index 29fc0bc56..e09194259 100644 --- a/sys/src/cmd/vc/gc.h +++ b/sys/src/cmd/vc/gc.h @@ -55,7 +55,7 @@ struct Prog struct Case { Case* link; - long val; + vlong val; long label; char def; char isv; @@ -64,7 +64,7 @@ struct Case struct C1 { - long val; + vlong val; long label; }; diff --git a/sys/src/cmd/vc/swt.c b/sys/src/cmd/vc/swt.c index cdc58e1bb..08d9f1d10 100644 --- a/sys/src/cmd/vc/swt.c +++ b/sys/src/cmd/vc/swt.c @@ -20,7 +20,7 @@ swit2(C1 *q, int nc, long def, Node *n, Node *tn) if(nc < 5) { for(i=0; ival); + print("case = %.8llux\n", q->val); gmove(nodconst(q->val), tn); gopcode(OEQ, n, tn, Z); patch(p, q->label); @@ -33,7 +33,7 @@ swit2(C1 *q, int nc, long def, Node *n, Node *tn) i = nc / 2; r = q+i; if(debug['W']) - print("case > %.8lux\n", r->val); + print("case > %.8llux\n", r->val); gmove(nodconst(r->val), tn); gopcode(OLT, tn, n, Z); sp = p; @@ -42,7 +42,7 @@ swit2(C1 *q, int nc, long def, Node *n, Node *tn) swit2(q, i, def, n, tn); if(debug['W']) - print("case < %.8lux\n", r->val); + print("case < %.8llux\n", r->val); patch(sp, pc); swit2(r+1, nc-i-1, def, n, tn); } diff --git a/sys/src/cmd/vi/vi.c b/sys/src/cmd/vi/vi.c index bc31b5bf1..5ef36fe4a 100644 --- a/sys/src/cmd/vi/vi.c +++ b/sys/src/cmd/vi/vi.c @@ -2,6 +2,7 @@ #include #include #include +#include #define Extern #include "mips.h" @@ -291,12 +292,22 @@ void initstk(int argc, char *argv[]) { ulong size; - ulong sp, ap; + ulong sp, ap, tos; int i; char *p; initmap(); - sp = STACKTOP - 4; + tos = STACKTOP - sizeof(Tos)*2; /* we'll assume twice the host's is big enough */ + sp = tos; + for (i = 0; i < sizeof(Tos)*2; i++) + putmem_b(tos + i, 0); + + /* + * pid is second word from end of tos and needs to be set for nsec(). + * we know mips is a 32-bit cpu, so we'll assume knowledge of the Tos + * struct for now, and use our pid. + */ + putmem_w(tos + 4*4 + 2*sizeof(ulong) + 3*sizeof(uvlong), getpid()); /* Build exec stack */ size = strlen(file)+1+BY2WD+BY2WD+BY2WD; @@ -306,7 +317,7 @@ initstk(int argc, char *argv[]) sp -= size; sp &= ~3; reg.r[29] = sp; - reg.r[1] = STACKTOP-4; /* Plan 9 profiling clock */ + reg.r[1] = tos; /* Plan 9 profiling clock, etc. */ /* Push argc */ putmem_w(sp, argc+1); diff --git a/sys/src/libmach/5db.c b/sys/src/libmach/5db.c index 848281f59..e490d11a6 100644 --- a/sys/src/libmach/5db.c +++ b/sys/src/libmach/5db.c @@ -61,7 +61,7 @@ static int arminstlen(Map*, uvlong); */ Machdata armmach = { - {0, 0, 0, 0xD}, /* break point */ + {0x70, 0x00, 0x20, 0xD1}, /* break point */ /* D1200070 */ 4, /* break point size */ leswab, /* short to local byte order */ @@ -135,18 +135,26 @@ char* addsub[2] = int armclass(long w) { - int op; + int op, done; op = (w >> 25) & 0x7; switch(op) { case 0: /* data processing r,r,r */ op = ((w >> 4) & 0xf); if(op == 0x9) { - op = 48+16; /* mul */ + op = 48+16; /* mul, swp or *rex */ + if((w & 0x0ff00fff) == 0x01900f9f) { + op = 93; /* ldrex */ + break; + } + if((w & 0x0ff00ff0) == 0x01800f90) { + op = 94; /* strex */ + break; + } if(w & (1<<24)) { op += 2; if(w & (1<<22)) - op++; /* swap */ + op++; /* swpb */ break; } if(w & (1<<23)) { /* mullu */ @@ -174,12 +182,38 @@ armclass(long w) op = (48) + ((w >> 21) & 0xf); break; case 2: /* load/store byte/word i(r) */ + if ((w & 0xffffff8f) == 0xf57ff00f) { /* barriers, clrex */ + done = 1; + switch ((w >> 4) & 7) { + case 1: + op = 95; /* clrex */ + break; + case 4: + op = 96; /* dsb */ + break; + case 5: + op = 97; /* dmb */ + break; + case 6: + op = 98; /* isb */ + break; + default: + done = 0; + break; + } + if (done) + break; + } op = (48+24) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2); break; case 3: /* load/store byte/word (r)(r) */ op = (48+24+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2); break; case 4: /* block data transfer (r)(r) */ + if ((w & 0xfe50ffff) == 0xf8100a00) { /* v7 RFE */ + op = 99; + break; + } op = (48+24+4+4) + ((w >> 20) & 0x1); break; case 5: /* branch / branch link */ @@ -188,7 +222,7 @@ armclass(long w) case 7: /* coprocessor crap */ op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1); break; - default: + default: op = (48+24+4+4+2+2+4+4); break; } @@ -602,19 +636,16 @@ armaddr(Map *map, Rgetter rget, Instr *i) char buf[8]; ulong rn; - sprint(buf, "R%ld", (i->w >> 16) & 0xf); + snprint(buf, sizeof(buf), "R%ld", (i->w >> 16) & 0xf); rn = rget(map, buf); - if((i->w & (1<<24)) == 0) { /* POSTIDX */ - sprint(buf, "R%ld", rn); - return rget(map, buf); - } + if((i->w & (1<<24)) == 0) /* POSTIDX */ + return rn; if((i->w & (1<<25)) == 0) { /* OFFSET */ - sprint(buf, "R%ld", rn); if(i->w & (1U<<23)) - return rget(map, buf) + (i->w & BITS(0,11)); - return rget(map, buf) - (i->w & BITS(0,11)); + return rn + (i->w & BITS(0,11)); + return rn - (i->w & BITS(0,11)); } else { /* REGOFF */ ulong index = 0; uchar c; @@ -823,8 +854,22 @@ static Opcode opcodes[] = "MULL%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)", "MULAL%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)", -/* 48+24+4+4+2+2+4+4 */ +/* 48+24+4+4+2+2+4+4 = 92 */ "UNK", armunk, 0, "", + + /* new v7 arch instructions */ +/* 93 */ + "LDREX", armdpi, 0, "(R%n),R%d", + "STREX", armdpi, 0, "R%s,(R%n),R%d", + "CLREX", armunk, 0, "", + +/* 96 */ + "DSB", armunk, 0, "", + "DMB", armunk, 0, "", + "ISB", armunk, 0, "", + +/* 99 */ + "RFEV7%P%a", armbdt, 0, "(R%n)", }; static void diff --git a/sys/src/libmach/6.c b/sys/src/libmach/6.c index 6aca0006f..a3566f60b 100644 --- a/sys/src/libmach/6.c +++ b/sys/src/libmach/6.c @@ -105,10 +105,10 @@ Mach mamd64= 0, /* link register */ "setSB", /* static base register name (bogus anyways) */ 0, /* static base register value */ - 0x1000, /* page size */ - 0xFFFFFFFF80110000ULL, /* kernel base */ - 0xFFFF800000000000ULL, /* kernel text mask */ - 0x00007FFFFFFFF000ULL, /* user stack top */ + 0x200000, /* page size */ + 0xfffffffff0110000ull, /* kernel base */ + 0xffff800000000000ull, /* kernel text mask */ + 0x00007ffffffff000ull, /* user stack top */ 1, /* quantization of pc */ 8, /* szaddr */ 4, /* szreg */ diff --git a/sys/src/libmach/9.c b/sys/src/libmach/9.c index 6eb98be96..824c0aba4 100644 --- a/sys/src/libmach/9.c +++ b/sys/src/libmach/9.c @@ -101,21 +101,21 @@ Mach mpower64 = { "power64", MPOWER64, /* machine type */ - power64reglist, /* register set */ - REGSIZE, /* number of bytes in register set */ - FPREGSIZE, /* number of bytes in FP register set */ - "PC", /* name of PC */ - "SP", /* name of SP */ - "LR", /* name of link register */ - "setSB", /* static base register name */ - 0, /* value */ - 0x1000, /* page size */ - 0x80000000ULL, /* kernel base */ - 0, /* kernel text mask */ - 0x7FFFFFFFULL, /* user stack top */ - 4, /* quantization of pc */ - 8, /* szaddr */ - 8, /* szreg */ - 4, /* szfloat */ - 8, /* szdouble */ + power64reglist, /* register set */ + REGSIZE, /* number of bytes in register set */ + FPREGSIZE, /* number of bytes in FP register set */ + "PC", /* name of PC */ + "SP", /* name of SP */ + "LR", /* name of link register */ + "setSB", /* static base register name */ + 0, /* value */ + 0x100000, /* page size (TODO, too many choices) */ + 0xffffffff80000000ull, /* kernel base (TODO, likely incorrect) */ + 0xf000000000000000ull, /* kernel text mask (TODO, likely incorrect) */ + 0x00007ffffff00000ull, /* user stack top (TODO, likely incorrect) */ + 4, /* quantization of pc */ + 8, /* szaddr */ + 8, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ }; diff --git a/sys/src/libmach/elf.h b/sys/src/libmach/elf.h index 5d755b7a6..94fa7331c 100644 --- a/sys/src/libmach/elf.h +++ b/sys/src/libmach/elf.h @@ -1,5 +1,5 @@ /* - * Definitions needed for accessing Irix ELF headers + * Definitions needed for accessing ELF headers */ typedef struct { uchar ident[16]; /* ident bytes */ @@ -18,6 +18,23 @@ typedef struct { ushort shstrndx; /* shdr string index */ } Ehdr; +typedef struct { + u8int ident[16]; /* ident bytes */ + u16int type; /* file type */ + u16int machine; /* target machine */ + u32int version; /* file version */ + u64int elfentry; /* start address */ + u64int phoff; /* phdr file offset */ + u64int shoff; /* shdr file offset */ + u32int flags; /* file flags */ + u16int ehsize; /* sizeof ehdr */ + u16int phentsize; /* sizeof phdr */ + u16int phnum; /* number phdrs */ + u16int shentsize; /* sizeof shdr */ + u16int shnum; /* number shdrs */ + u16int shstrndx; /* shdr string index */ +} E64hdr; + typedef struct { int type; /* entry type */ ulong offset; /* file offset */ @@ -29,6 +46,17 @@ typedef struct { int align; /* memory/file alignment */ } Phdr; +typedef struct { + u32int type; /* entry type */ + u32int flags; /* entry flags */ + u64int offset; /* file offset */ + u64int vaddr; /* virtual address */ + u64int paddr; /* physical address */ + u64int filesz; /* file size */ + u64int memsz; /* memory size */ + u64int align; /* memory/file alignment */ +} P64hdr; + typedef struct { ulong name; /* section name */ ulong type; /* SHT_... */ @@ -42,6 +70,19 @@ typedef struct { ulong entsize; /* entry size if table */ } Shdr; +typedef struct { + u32int name; /* section name */ + u32int type; /* SHT_... */ + u64int flags; /* SHF_... */ + u64int addr; /* virtual address */ + u64int offset; /* file offset */ + u64int size; /* section size */ + u32int link; /* misc info */ + u32int info; /* misc info */ + u64int addralign; /* memory alignment */ + u64int entsize; /* entry size if table */ +} S64hdr; + enum { /* Ehdr codes */ MAG0 = 0, /* ident[] indexes */ @@ -80,8 +121,10 @@ enum { S370 = 9, /* Amdhal */ SPARC64 = 18, /* Sun SPARC v9 */ POWER = 20, /* PowerPC */ - ARM = 40, /* ARM */ + POWER64 = 21, /* PowerPC64 */ + ARM = 40, /* ARM */ AMD64 = 62, /* Amd64 */ + ARM64 = 183, /* ARM64 */ NO_VERSION = 0, /* version, ident[VERSION] */ CURRENT = 1, diff --git a/sys/src/libmach/executable.c b/sys/src/libmach/executable.c index 614285651..4dbe94d92 100644 --- a/sys/src/libmach/executable.c +++ b/sys/src/libmach/executable.c @@ -17,6 +17,7 @@ typedef struct { uvlong hdr[1]; }; Ehdr; /* elf.h */ + E64hdr; struct mipsexec; /* bootexec.h */ struct mips4kexec; /* bootexec.h */ struct sparcexec; /* bootexec.h */ @@ -52,7 +53,7 @@ typedef struct Exectable{ uchar _magic; /* _MAGIC() magic */ Mach *mach; /* Per-machine data */ long hsize; /* header size */ - ulong (*swal)(ulong); /* header swap, beswal or leswal */ + ulong (*swal)(ulong); /* beswal or leswal */ int (*hparse)(int, Fhdr*, ExecHdr*); } ExecTable; @@ -186,7 +187,7 @@ ExecTable exectab[] = 1, &mamd64, sizeof(Exec)+8, - beswal, + nil, commonllp64 }, { Q_MAGIC, /* PowerPC q.out & boot image */ "power plan 9 executable", @@ -204,9 +205,9 @@ ExecTable exectab[] = 1, &mpower64, sizeof(Exec)+8, - beswal, + nil, commonllp64 }, - { ELF_MAG, /* any elf32 */ + { ELF_MAG, /* any ELF */ "elf executable", nil, FNONE, @@ -409,7 +410,13 @@ commonboot(Fhdr *fp) fp->type = FAMD64B; fp->txtaddr = fp->entry; fp->name = "amd64 plan 9 boot image"; - fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize); + fp->dataddr = _round(fp->txtaddr+fp->txtsz, 4096); + break; + case FPOWER64: + fp->type = FPOWER64B; + fp->txtaddr = fp->entry; + fp->name = "power64 plan 9 boot image"; + fp->dataddr = fp->txtaddr+fp->txtsz; break; default: return; @@ -441,6 +448,7 @@ commonllp64(int, Fhdr *fp, ExecHdr *hp) long pgsize; uvlong entry; + hswal(&hp->e, sizeof(Exec)/sizeof(long), beswal); if(!(hp->e.magic & HDR_MAGIC)) return 0; @@ -561,12 +569,124 @@ nextboot(int fd, Fhdr *fp, ExecHdr *hp) } /* - * Elf32 binaries. + * ELF64 binaries. */ static int -elfdotout(int fd, Fhdr *fp, ExecHdr *hp) +elf64dotout(int fd, Fhdr *fp, ExecHdr *hp) { + E64hdr *ep; + P64hdr *ph; + ushort (*swab)(ushort); + ulong (*swal)(ulong); + uvlong (*swav)(uvlong); + int i, it, id, is, phsz; + uvlong uvl; + ep = &hp->e; + if(ep->ident[DATA] == ELFDATA2LSB) { + swab = leswab; + swal = leswal; + swav = leswav; + } else if(ep->ident[DATA] == ELFDATA2MSB) { + swab = beswab; + swal = beswal; + swav = beswav; + } else { + werrstr("bad ELF64 encoding - not big or little endian"); + return 0; + } + + ep->type = swab(ep->type); + ep->machine = swab(ep->machine); + ep->version = swal(ep->version); + if(ep->type != EXEC || ep->version != CURRENT) + return 0; + ep->elfentry = swav(ep->elfentry); + ep->phoff = swav(ep->phoff); + ep->shoff = swav(ep->shoff); + ep->flags = swal(ep->flags); + ep->ehsize = swab(ep->ehsize); + ep->phentsize = swab(ep->phentsize); + ep->phnum = swab(ep->phnum); + ep->shentsize = swab(ep->shentsize); + ep->shnum = swab(ep->shnum); + ep->shstrndx = swab(ep->shstrndx); + + fp->magic = ELF_MAG; + fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15; + switch(ep->machine) { + default: + return 0; + case AMD64: + mach = &mamd64; + fp->type = FAMD64; + fp->name = "amd64 ELF64 executable"; + break; + case POWER64: + mach = &mpower64; + fp->type = FPOWER64; + fp->name = "power64 ELF64 executable"; + break; + } + + if(ep->phentsize != sizeof(P64hdr)) { + werrstr("bad ELF64 header size"); + return 0; + } + phsz = sizeof(P64hdr)*ep->phnum; + ph = malloc(phsz); + if(!ph) + return 0; + seek(fd, ep->phoff, 0); + if(read(fd, ph, phsz) < 0) { + free(ph); + return 0; + } + for(i = 0; i < ep->phnum; i++) { + ph[i].type = swal(ph[i].type); + ph[i].flags = swal(ph[i].flags); + ph[i].offset = swav(ph[i].offset); + ph[i].vaddr = swav(ph[i].vaddr); + ph[i].paddr = swav(ph[i].paddr); + ph[i].filesz = swav(ph[i].filesz); + ph[i].memsz = swav(ph[i].memsz); + ph[i].align = swav(ph[i].align); + } + + /* find text, data and symbols and install them */ + it = id = is = -1; + for(i = 0; i < ep->phnum; i++) { + if(ph[i].type == LOAD + && (ph[i].flags & (R|X)) == (R|X) && it == -1) + it = i; + else if(ph[i].type == LOAD + && (ph[i].flags & (R|W)) == (R|W) && id == -1) + id = i; + else if(ph[i].type == NOPTYPE && is == -1) + is = i; + } + if(it == -1 || id == -1) { + werrstr("No ELF64 TEXT or DATA sections"); + free(ph); + return 0; + } + + settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset); + /* 8c: out of fixed registers */ + uvl = ph[id].memsz - ph[id].filesz; + setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, uvl); + if(is != -1) + setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset); + free(ph); + return 1; +} + +/* + * ELF32 binaries. + */ +static int +elf32dotout(int fd, Fhdr *fp, ExecHdr *hp) +{ ulong (*swal)(ulong); ushort (*swab)(ushort); Ehdr *ep; @@ -575,10 +695,6 @@ elfdotout(int fd, Fhdr *fp, ExecHdr *hp) /* bitswap the header according to the DATA format */ ep = &hp->e; - if(ep->ident[CLASS] != ELFCLASS32) { - werrstr("bad ELF class - not 32 bit"); - return 0; - } if(ep->ident[DATA] == ELFDATA2LSB) { swab = leswab; swal = leswal; @@ -586,7 +702,7 @@ elfdotout(int fd, Fhdr *fp, ExecHdr *hp) swab = beswab; swal = beswal; } else { - werrstr("bad ELF encoding - not big or little endian"); + werrstr("bad ELF32 encoding - not big or little endian"); return 0; } @@ -613,33 +729,44 @@ elfdotout(int fd, Fhdr *fp, ExecHdr *hp) case I386: mach = &mi386; fp->type = FI386; + fp->name = "386 ELF32 executable"; break; case MIPS: mach = &mmips; fp->type = FMIPS; + fp->name = "mips ELF32 executable"; break; case SPARC64: mach = &msparc64; fp->type = FSPARC64; + fp->name = "sparc64 ELF32 executable"; break; case POWER: mach = &mpower; fp->type = FPOWER; + fp->name = "power ELF32 executable"; + break; + case POWER64: + mach = &mpower64; + fp->type = FPOWER64; + fp->name = "power64 ELF32 executable"; break; case AMD64: mach = &mamd64; fp->type = FAMD64; + fp->name = "amd64 ELF32 executable"; break; case ARM: mach = &marm; fp->type = FARM; + fp->name = "arm ELF32 executable"; break; default: return 0; } if(ep->phentsize != sizeof(Phdr)) { - werrstr("bad ELF header size"); + werrstr("bad ELF32 header size"); return 0; } phsz = sizeof(Phdr)*ep->phnum; @@ -689,7 +816,7 @@ elfdotout(int fd, Fhdr *fp, ExecHdr *hp) return 1; } - werrstr("No TEXT or DATA sections"); + werrstr("No ELF32 TEXT or DATA sections"); free(ph); return 0; } @@ -702,6 +829,25 @@ elfdotout(int fd, Fhdr *fp, ExecHdr *hp) return 1; } +/* + * Elf binaries. + */ +static int +elfdotout(int fd, Fhdr *fp, ExecHdr *hp) +{ + Ehdr *ep; + + /* bitswap the header according to the DATA format */ + ep = &hp->e; + if(ep->ident[CLASS] == ELFCLASS32) + return elf32dotout(fd, fp, hp); + else if(ep->ident[CLASS] == ELFCLASS64) + return elf64dotout(fd, fp, hp); + + werrstr("bad ELF class - not 32 bit"); + return 0; +} + /* * (Free|Net)BSD ARM header. */ diff --git a/sys/src/libmach/map.c b/sys/src/libmach/map.c index c668defd1..c745d82a6 100644 --- a/sys/src/libmach/map.c +++ b/sys/src/libmach/map.c @@ -89,13 +89,11 @@ attachproc(int pid, int kflag, int corefd, Fhdr *fp) map = newmap(0, 4); if (!map) return 0; - if(kflag) { + if(kflag) regs = "kregs"; - mode = OREAD; - } else { + else regs = "regs"; - mode = ORDWR; - } + mode = ORDWR; if (mach->regsize) { sprint(buf, "/proc/%d/%s", pid, regs); fd = open(buf, mode); diff --git a/sys/src/libmach/mkfile b/sys/src/libmach/mkfile index a71bcfd88..27ab477ae 100644 --- a/sys/src/libmach/mkfile +++ b/sys/src/libmach/mkfile @@ -55,3 +55,15 @@ UPDATE=mkfile\ symoff, 0); nsym = 0; size = 0; + if((fp->_magic && (fp->magic & HDR_MAGIC)) || mach->szaddr == 8) + svalsz = 8; + else + svalsz = 4; for(p = symbols; size < fp->symsz; p++, nsym++) { - if(fp->_magic && (fp->magic & HDR_MAGIC)){ - svalsz = 8; + if(svalsz == 8){ if(Bread(&b, &vl, 8) != 8) return symerrmsg(8, "symbol"); p->value = beswav(vl); } else{ - svalsz = 4; if(Bread(&b, &l, 4) != 4) return symerrmsg(4, "symbol"); p->value = (u32int)beswal(l); diff --git a/sys/src/mkfile.proto b/sys/src/mkfile.proto index 8458a2472..947e5fe3f 100644 --- a/sys/src/mkfile.proto +++ b/sys/src/mkfile.proto @@ -2,7 +2,7 @@ # common mkfile parameters shared by all architectures # -OS=578qv +OS=5678qv CPUS=arm alpha 386 power mips CFLAGS=-FTVw LEX=lex