From: Rob Pike Date: Wed, 4 Jun 2008 21:37:38 +0000 (-0700) Subject: Add compiler source to new directory structure X-Git-Tag: weekly.2009-11-06~3772 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=0cafb9ea3d3d34627e8f492ccafa6ba9b633a213;p=gostls13.git Add compiler source to new directory structure SVN=121164 --- diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h new file mode 100644 index 0000000000..47adbc81f3 --- /dev/null +++ b/src/cmd/6a/a.h @@ -0,0 +1,206 @@ +// Inferno utils/6a/a.h +// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include +#include +#include "../6l/6.out.h" +#include "compat.h" + + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Sym Sym; +typedef struct Ref Ref; +typedef struct Gen Gen; +typedef struct Io Io; +typedef struct Hist Hist; +typedef struct Gen2 Gen2; + +#define MAXALIGN 7 +#define FPCHIP 1 +#define NSYMB 500 +#define BUFSIZ 8192 +#define HISTSZ 20 +#define NINCLUDE 10 +#define NHUNK 10000 +#define EOF (-1) +#define IGN (-2) +#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) +#define NHASH 503 +#define STRINGSZ 200 +#define NMACRO 10 + +struct Sym +{ + Sym* link; + Ref* ref; + char* macro; + vlong value; + ushort type; + char *name; + char sym; +}; +#define S ((Sym*)0) + +struct Ref +{ + int class; +}; + +EXTERN struct +{ + char* p; + int c; +} fi; + +struct Io +{ + Io* link; + char b[BUFSIZ]; + char* p; + short c; + short f; +}; +#define I ((Io*)0) + +EXTERN struct +{ + Sym* sym; + short type; +} h[NSYM]; + +struct Gen +{ + double dval; + char sval[8]; + vlong offset; + Sym* sym; + short type; + short index; + short scale; +}; +struct Gen2 +{ + Gen from; + Gen to; +}; + +struct Hist +{ + Hist* link; + char* name; + long line; + vlong offset; +}; +#define H ((Hist*)0) + +enum +{ + CLAST, + CMACARG, + CMACRO, + CPREPROC, +}; + + +EXTERN char debug[256]; +EXTERN Sym* hash[NHASH]; +EXTERN char* Dlist[30]; +EXTERN int nDlist; +EXTERN Hist* ehist; +EXTERN int newflag; +EXTERN Hist* hist; +EXTERN char* hunk; +EXTERN char* include[NINCLUDE]; +EXTERN Io* iofree; +EXTERN Io* ionext; +EXTERN Io* iostack; +EXTERN long lineno; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN int ninclude; +EXTERN Gen nullgen; +EXTERN char* outfile; +EXTERN int pass; +EXTERN char* pathname; +EXTERN long pc; +EXTERN int peekc; +EXTERN int sym; +EXTERN char symb[NSYMB]; +EXTERN int thechar; +EXTERN char* thestring; +EXTERN long thunk; +EXTERN Biobuf obuf; + +void* allocn(void*, long, long); +void errorexit(void); +void pushio(void); +void newio(void); +void newfile(char*, int); +Sym* slookup(char*); +Sym* lookup(void); +void syminit(Sym*); +long yylex(void); +int getc(void); +int getnsc(void); +void unget(int); +int escchar(int); +void cinit(void); +void checkscale(int); +void pinit(char*); +void cclean(void); +int isreg(Gen*); +void outcode(int, Gen2*); +void outhist(void); +void zaddr(Gen*, int); +void zname(char*, int, int); +void ieeedtod(Ieee*, double); +int filbuf(void); +Sym* getsym(void); +void domacro(void); +void macund(void); +void macdef(void); +void macexpand(Sym*, char*); +void macinc(void); +void macprag(void); +void maclin(void); +void macif(int); +void macend(void); +void dodefine(char*); +void prfile(long); +void linehist(char*, int); +void gethunk(void); +void yyerror(char*, ...); +int yyparse(void); +void setinclude(char*); +int assemble(char*); diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y new file mode 100644 index 0000000000..698e73e567 --- /dev/null +++ b/src/cmd/6a/a.y @@ -0,0 +1,592 @@ +// Inferno utils/6a/a.y +// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.y +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +%{ +#include "a.h" +%} +%union { + Sym *sym; + vlong lval; + double dval; + char sval[8]; + Gen gen; + Gen2 gen2; +} +%left '|' +%left '^' +%left '&' +%left '<' '>' +%left '+' '-' +%left '*' '/' '%' +%token 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/src/cmd/6a/lex.c b/src/cmd/6a/lex.c new file mode 100644 index 0000000000..ff0a0d56ee --- /dev/null +++ b/src/cmd/6a/lex.c @@ -0,0 +1,1337 @@ +// Inferno utils/6a/lex.c +// http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define EXTERN +#include "a.h" +#include "y.tab.h" +#include + +void +main(int argc, char *argv[]) +{ + char *p; + int nout, nproc, status, i, c; + + thechar = '6'; + thestring = "amd64"; + memset(debug, 0, sizeof(debug)); + cinit(); + outfile = 0; + include[ninclude++] = "."; + ARGBEGIN { + default: + c = ARGC(); + if(c >= 0 || c < sizeof(debug)) + debug[c] = 1; + break; + + case 'o': + outfile = ARGF(); + break; + + case 'D': + p = ARGF(); + if(p) + Dlist[nDlist++] = p; + break; + + case 'I': + p = ARGF(); + setinclude(p); + break; + } ARGEND + if(*argv == 0) { + print("usage: %ca [-options] file.s\n", thechar); + errorexit(); + } + if(argc > 1 && systemtype(Windows)){ + print("can't assemble multiple files on windows\n"); + errorexit(); + } + if(argc > 1 && !systemtype(Windows)) { + nproc = 1; + if(p = getenv("NPROC")) + nproc = atol(p); /* */ + c = 0; + nout = 0; + for(;;) { + while(nout < nproc && argc > 0) { + i = myfork(); + if(i < 0) { + i = mywait(&status); + if(i < 0) + errorexit(); + if(status) + c++; + nout--; + continue; + } + if(i == 0) { + print("%s:\n", *argv); + if(assemble(*argv)) + errorexit(); + exits(0); + } + nout++; + argc--; + argv++; + } + i = mywait(&status); + if(i < 0) { + if(c) + errorexit(); + exits(0); + } + if(status) + c++; + nout--; + } + } + if(assemble(argv[0])) + errorexit(); + exits(0); +} + +int +assemble(char *file) +{ + char ofile[100], incfile[20], *p; + int i, of; + + strcpy(ofile, file); + p = utfrrune(ofile, pathchar()); + if(p) { + include[0] = ofile; + *p++ = 0; + } else + p = ofile; + if(outfile == 0) { + outfile = p; + if(outfile){ + p = utfrrune(outfile, '.'); + if(p) + if(p[1] == 's' && p[2] == 0) + p[0] = 0; + p = utfrune(outfile, 0); + p[0] = '.'; + p[1] = thechar; + p[2] = 0; + } else + outfile = "/dev/null"; + } + p = getenv("INCLUDE"); + if(p) { + setinclude(p); + } else { + if(systemtype(Plan9)) { + sprint(incfile,"/%s/include", thestring); + setinclude(strdup(incfile)); + } + } + + of = mycreate(outfile, 0664); + if(of < 0) { + yyerror("%ca: cannot create %s", thechar, outfile); + errorexit(); + } + Binit(&obuf, of, OWRITE); + + pass = 1; + pinit(file); + + Bprint(&obuf, "x86-64\n"); + + for(i=0; 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) + pc++; +} + +void +outhist(void) +{ + Gen g; + Hist *h; + char *p, *q, *op, c; + int n; + + g = nullgen; + c = pathchar(); + for(h = hist; h != H; h = h->link) { + p = h->name; + op = 0; + /* on windows skip drive specifier in pathname */ + if(systemtype(Windows) && p && p[1] == ':'){ + p += 2; + c = *p; + } + if(p && p[0] != c && h->offset == 0 && pathname){ + /* on windows skip drive specifier in pathname */ + if(systemtype(Windows) && pathname[1] == ':') { + op = p; + p = pathname+2; + c = *p; + } else if(pathname[0] == c){ + op = p; + p = pathname; + } + } + while(p) { + q = strchr(p, c); + if(q) { + n = q-p; + if(n == 0){ + n = 1; /* leading "/" */ + *p = '/'; /* don't emit "\" on windows */ + } + q++; + } else { + n = strlen(p); + q = 0; + } + if(n) { + Bputc(&obuf, ANAME); + Bputc(&obuf, ANAME>>8); + Bputc(&obuf, D_FILE); /* type */ + Bputc(&obuf, 1); /* sym */ + Bputc(&obuf, '<'); + Bwrite(&obuf, p, n); + Bputc(&obuf, 0); + } + p = q; + if(p == 0 && op) { + p = op; + op = 0; + } + } + g.offset = h->offset; + + Bputc(&obuf, AHISTORY); + Bputc(&obuf, AHISTORY>>8); + Bputc(&obuf, h->line); + Bputc(&obuf, h->line>>8); + Bputc(&obuf, h->line>>16); + Bputc(&obuf, h->line>>24); + zaddr(&nullgen, 0); + zaddr(&g, 0); + } +} + +void +pragbldicks(void) +{ + while(getnsc() != '\n') + ; +} + +void +praghjdicks(void) +{ + while(getnsc() != '\n') + ; +} + +#include "../cc/lexbody" +#include "../cc/macbody" diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c new file mode 100644 index 0000000000..7463aa6a3c --- /dev/null +++ b/src/cmd/6c/cgen.c @@ -0,0 +1,1971 @@ +// Inferno utils/6c/cgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/cgen.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +/* ,x/^(print|prtree)\(/i/\/\/ */ +int castup(Type*, Type*); + +void +cgen(Node *n, Node *nn) +{ + Node *l, *r, *t; + Prog *p1; + Node nod, nod1, nod2, nod3, nod4; + int o, hardleft; + long v, curs; + vlong c; + + if(debug['g']) { + prtree(nn, "cgen lhs"); + prtree(n, "cgen"); + } + if(n == Z || n->type == T) + return; + if(typesu[n->type->etype]) { + sugen(n, nn, n->type->width); + return; + } + l = n->left; + r = n->right; + o = n->op; + if(n->addable >= INDEXED) { + if(nn == Z) { + switch(o) { + default: + nullwarn(Z, Z); + break; + case OINDEX: + nullwarn(l, r); + break; + } + return; + } + gmove(n, nn); + return; + } + curs = cursafe; + + if(l->complex >= FNX) + if(r != Z && r->complex >= FNX) + switch(o) { + default: + if(cond(o) && typesu[l->type->etype]) + break; + + regret(&nod, r); + cgen(r, &nod); + + regsalloc(&nod1, r); + gmove(&nod, &nod1); + + regfree(&nod); + nod = *n; + nod.right = &nod1; + + cgen(&nod, nn); + return; + + case OFUNC: + case OCOMMA: + case OANDAND: + case OOROR: + case OCOND: + case ODOT: + break; + } + + hardleft = l->addable < INDEXED || l->complex >= FNX; + switch(o) { + default: + diag(n, "unknown op in cgen: %O", o); + break; + + case ONEG: + case OCOM: + if(nn == Z) { + nullwarn(l, Z); + break; + } + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, n->type, Z, &nod); + gmove(&nod, nn); + regfree(&nod); + break; + + case OAS: + if(l->op == OBIT) + goto bitas; + if(!hardleft) { + if(nn != Z || r->addable < INDEXED || hardconst(r)) { + if(r->complex >= FNX && nn == Z) + regret(&nod, r); + else + regalloc(&nod, r, nn); + cgen(r, &nod); + gmove(&nod, l); + if(nn != Z) + gmove(&nod, nn); + regfree(&nod); + } else + gmove(r, l); + break; + } + if(l->complex >= r->complex) { + if(l->op == OINDEX && immconst(r)) { + gmove(r, l); + break; + } + reglcgen(&nod1, l, Z); + if(r->addable >= INDEXED && !hardconst(r)) { + gmove(r, &nod1); + if(nn != Z) + gmove(r, nn); + regfree(&nod1); + break; + } + regalloc(&nod, r, nn); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + reglcgen(&nod1, l, Z); + } + gmove(&nod, &nod1); + regfree(&nod); + regfree(&nod1); + break; + + bitas: + n = l->left; + regalloc(&nod, r, nn); + if(l->complex >= r->complex) { + reglcgen(&nod1, n, Z); + cgen(r, &nod); + } else { + cgen(r, &nod); + reglcgen(&nod1, n, Z); + } + regalloc(&nod2, n, Z); + gmove(&nod1, &nod2); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OBIT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + bitload(n, &nod, Z, Z, nn); + gmove(&nod, nn); + regfree(&nod); + break; + + case OLSHR: + case OASHL: + case OASHR: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(r->op == OCONST) { + if(r->vconst == 0) { + cgen(l, nn); + break; + } + regalloc(&nod, l, nn); + cgen(l, &nod); + if(o == OASHL && r->vconst == 1) + gopcode(OADD, n->type, &nod, &nod); + else + gopcode(o, n->type, r, &nod); + gmove(&nod, nn); + regfree(&nod); + break; + } + + /* + * get nod to be D_CX + */ + if(nodreg(&nod, nn, D_CX)) { + regsalloc(&nod1, n); + gmove(&nod, &nod1); + cgen(n, &nod); /* probably a bug */ + gmove(&nod, nn); + gmove(&nod1, &nod); + break; + } + reg[D_CX]++; + if(nn->op == OREGISTER && nn->reg == D_CX) + regalloc(&nod1, l, Z); + else + regalloc(&nod1, l, nn); + if(r->complex >= l->complex) { + cgen(r, &nod); + cgen(l, &nod1); + } else { + cgen(l, &nod1); + cgen(r, &nod); + } + gopcode(o, n->type, &nod, &nod1); + gmove(&nod1, nn); + regfree(&nod); + regfree(&nod1); + break; + + case OADD: + case OSUB: + case OOR: + case OXOR: + case OAND: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(typefd[n->type->etype]) + goto fop; + if(r->op == OCONST) { + if(r->vconst == 0 && o != OAND) { + cgen(l, nn); + break; + } + } + if(n->op == OADD && l->op == OASHL && l->right->op == OCONST + && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) { + c = l->right->vconst; + if(c > 0 && c <= 3) { + if(l->left->complex >= r->complex) { + regalloc(&nod, l->left, nn); + cgen(l->left, &nod); + if(r->addable < INDEXED) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + genmuladd(&nod, &nod, 1 << c, &nod1); + regfree(&nod1); + } + else + genmuladd(&nod, &nod, 1 << c, r); + } + else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l->left, Z); + cgen(l->left, &nod1); + genmuladd(&nod, &nod1, 1 << c, &nod); + regfree(&nod1); + } + gmove(&nod, nn); + regfree(&nod); + break; + } + } + if(r->addable >= INDEXED && !hardconst(r)) { + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, n->type, r, &nod); + gmove(&nod, nn); + regfree(&nod); + break; + } + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, n->type, &nod1, &nod); + } else { + regalloc(&nod1, r, nn); + cgen(r, &nod1); + regalloc(&nod, l, Z); + cgen(l, &nod); + gopcode(o, n->type, &nod1, &nod); + } + gmove(&nod, nn); + regfree(&nod); + regfree(&nod1); + break; + + case OLMOD: + case OMOD: + case OLMUL: + case OLDIV: + case OMUL: + case ODIV: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(typefd[n->type->etype]) + goto fop; + if(r->op == OCONST && typechl[n->type->etype]) { /* TO DO */ + SET(v); + switch(o) { + case ODIV: + case OMOD: + c = r->vconst; + if(c < 0) + c = -c; + v = log2(c); + if(v < 0) + break; + /* fall thru */ + case OMUL: + case OLMUL: + regalloc(&nod, l, nn); + cgen(l, &nod); + switch(o) { + case OMUL: + case OLMUL: + mulgen(n->type, r, &nod); + break; + case ODIV: + sdiv2(r->vconst, v, l, &nod); + break; + case OMOD: + smod2(r->vconst, v, l, &nod); + break; + } + gmove(&nod, nn); + regfree(&nod); + goto done; + case OLDIV: + c = r->vconst; + if((c & 0x80000000) == 0) + break; + regalloc(&nod1, l, Z); + cgen(l, &nod1); + regalloc(&nod, l, nn); + zeroregm(&nod); + gins(ACMPL, &nod1, nodconst(c)); + gins(ASBBL, nodconst(-1), &nod); + regfree(&nod1); + gmove(&nod, nn); + regfree(&nod); + goto done; + } + } + + if(o == OMUL) { + if(l->addable >= INDEXED) { + t = l; + l = r; + r = t; + } + /* should favour AX */ + regalloc(&nod, l, nn); + cgen(l, &nod); + if(r->addable < INDEXED || hardconst(r)) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(OMUL, n->type, &nod1, &nod); + regfree(&nod1); + }else + gopcode(OMUL, n->type, r, &nod); /* addressible */ + gmove(&nod, nn); + regfree(&nod); + break; + } + + /* + * get nod to be D_AX + * get nod1 to be D_DX + */ + if(nodreg(&nod, nn, D_AX)) { + regsalloc(&nod2, n); + gmove(&nod, &nod2); + v = reg[D_AX]; + reg[D_AX] = 0; + + if(isreg(l, D_AX)) { + nod3 = *n; + nod3.left = &nod2; + cgen(&nod3, nn); + } else + if(isreg(r, D_AX)) { + nod3 = *n; + nod3.right = &nod2; + cgen(&nod3, nn); + } else + cgen(n, nn); + + gmove(&nod2, &nod); + reg[D_AX] = v; + break; + } + if(nodreg(&nod1, nn, D_DX)) { + regsalloc(&nod2, n); + gmove(&nod1, &nod2); + v = reg[D_DX]; + reg[D_DX] = 0; + + if(isreg(l, D_DX)) { + nod3 = *n; + nod3.left = &nod2; + cgen(&nod3, nn); + } else + if(isreg(r, D_DX)) { + nod3 = *n; + nod3.right = &nod2; + cgen(&nod3, nn); + } else + cgen(n, nn); + + gmove(&nod2, &nod1); + reg[D_DX] = v; + break; + } + reg[D_AX]++; + + if(r->op == OCONST && (o == ODIV || o == OLDIV) && immconst(r) && typechl[r->type->etype]) { + reg[D_DX]++; + if(l->addable < INDEXED) { + regalloc(&nod2, l, Z); + cgen(l, &nod2); + l = &nod2; + } + if(o == ODIV) + sdivgen(l, r, &nod, &nod1); + else + udivgen(l, r, &nod, &nod1); + gmove(&nod1, nn); + if(l == &nod2) + regfree(l); + goto freeaxdx; + } + + if(l->complex >= r->complex) { + cgen(l, &nod); + reg[D_DX]++; + if(o == ODIV || o == OMOD) + gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); + if(o == OLDIV || o == OLMOD) + zeroregm(&nod1); + if(r->addable < INDEXED || r->op == OCONST) { + regsalloc(&nod3, r); + cgen(r, &nod3); + gopcode(o, n->type, &nod3, Z); + } else + gopcode(o, n->type, r, Z); + } else { + regsalloc(&nod3, r); + cgen(r, &nod3); + cgen(l, &nod); + reg[D_DX]++; + if(o == ODIV || o == OMOD) + gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); + if(o == OLDIV || o == OLMOD) + zeroregm(&nod1); + gopcode(o, n->type, &nod3, Z); + } + if(o == OMOD || o == OLMOD) + gmove(&nod1, nn); + else + gmove(&nod, nn); + freeaxdx: + regfree(&nod); + regfree(&nod1); + break; + + case OASLSHR: + case OASASHL: + case OASASHR: + if(r->op == OCONST) + goto asand; + if(l->op == OBIT) + goto asbitop; + if(typefd[n->type->etype]) + goto asand; /* can this happen? */ + + /* + * get nod to be D_CX + */ + if(nodreg(&nod, nn, D_CX)) { + regsalloc(&nod1, n); + gmove(&nod, &nod1); + cgen(n, &nod); + if(nn != Z) + gmove(&nod, nn); + gmove(&nod1, &nod); + break; + } + reg[D_CX]++; + + if(r->complex >= l->complex) { + cgen(r, &nod); + if(hardleft) + reglcgen(&nod1, l, Z); + else + nod1 = *l; + } else { + if(hardleft) + reglcgen(&nod1, l, Z); + else + nod1 = *l; + cgen(r, &nod); + } + + gopcode(o, l->type, &nod, &nod1); + regfree(&nod); + if(nn != Z) + gmove(&nod1, nn); + if(hardleft) + regfree(&nod1); + break; + + case OASAND: + case OASADD: + case OASSUB: + case OASXOR: + case OASOR: + asand: + if(l->op == OBIT) + goto asbitop; + if(typefd[l->type->etype] || typefd[r->type->etype]) + goto asfop; + if(l->complex >= r->complex) { + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + if(!immconst(r)) { + regalloc(&nod1, r, nn); + cgen(r, &nod1); + gopcode(o, l->type, &nod1, &nod); + regfree(&nod1); + } else + gopcode(o, l->type, r, &nod); + } else { + regalloc(&nod1, r, nn); + cgen(r, &nod1); + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + gopcode(o, l->type, &nod1, &nod); + regfree(&nod1); + } + if(nn != Z) + gmove(&nod, nn); + if(hardleft) + regfree(&nod); + break; + + asfop: + if(l->complex >= r->complex) { + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + if(r->addable < INDEXED){ + regalloc(&nod1, r, nn); + cgen(r, &nod1); + }else + nod1 = *r; + regalloc(&nod2, r, Z); + gmove(&nod, &nod2); + gopcode(o, r->type, &nod1, &nod2); + gmove(&nod2, &nod); + regfree(&nod2); + if(r->addable < INDEXED) + regfree(&nod1); + } else { + regalloc(&nod1, r, nn); + cgen(r, &nod1); + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + if(o != OASMUL && o != OASADD) { + regalloc(&nod2, r, Z); + gmove(&nod, &nod2); + gopcode(o, r->type, &nod1, &nod2); + regfree(&nod1); + gmove(&nod2, &nod); + regfree(&nod2); + } else { + gopcode(o, r->type, &nod, &nod1); + gmove(&nod1, &nod); + regfree(&nod1); + } + } + if(nn != Z) + gmove(&nod, nn); + if(hardleft) + regfree(&nod); + break; + + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + if(l->op == OBIT) + goto asbitop; + if(typefd[n->type->etype] || typefd[r->type->etype]) + goto asfop; + if(r->op == OCONST && typechl[n->type->etype]) { + SET(v); + switch(o) { + case OASDIV: + case OASMOD: + c = r->vconst; + if(c < 0) + c = -c; + v = log2(c); + if(v < 0) + break; + /* fall thru */ + case OASMUL: + case OASLMUL: + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod, l, nn); + cgen(&nod2, &nod); + switch(o) { + case OASMUL: + case OASLMUL: + mulgen(n->type, r, &nod); + break; + case OASDIV: + sdiv2(r->vconst, v, l, &nod); + break; + case OASMOD: + smod2(r->vconst, v, l, &nod); + break; + } + havev: + gmove(&nod, &nod2); + if(nn != Z) + gmove(&nod, nn); + if(hardleft) + regfree(&nod2); + regfree(&nod); + goto done; + case OASLDIV: + c = r->vconst; + if((c & 0x80000000) == 0) + break; + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod1, l, nn); + cgen(&nod2, &nod1); + regalloc(&nod, l, nn); + zeroregm(&nod); + gins(ACMPL, &nod1, nodconst(c)); + gins(ASBBL, nodconst(-1), &nod); + regfree(&nod1); + goto havev; + } + } + + if(o == OASMUL) { + /* should favour AX */ + regalloc(&nod, l, nn); + if(r->complex >= FNX) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + r = &nod1; + } + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + cgen(&nod2, &nod); + if(r->addable < INDEXED || hardconst(r)) { + if(r->complex < FNX) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + } + gopcode(OASMUL, n->type, &nod1, &nod); + regfree(&nod1); + } + else + gopcode(OASMUL, n->type, r, &nod); + if(r == &nod1) + regfree(r); + gmove(&nod, &nod2); + if(nn != Z) + gmove(&nod, nn); + regfree(&nod); + if(hardleft) + regfree(&nod2); + break; + } + + /* + * get nod to be D_AX + * get nod1 to be D_DX + */ + if(nodreg(&nod, nn, D_AX)) { + regsalloc(&nod2, n); + gmove(&nod, &nod2); + v = reg[D_AX]; + reg[D_AX] = 0; + + if(isreg(l, D_AX)) { + nod3 = *n; + nod3.left = &nod2; + cgen(&nod3, nn); + } else + if(isreg(r, D_AX)) { + nod3 = *n; + nod3.right = &nod2; + cgen(&nod3, nn); + } else + cgen(n, nn); + + gmove(&nod2, &nod); + reg[D_AX] = v; + break; + } + if(nodreg(&nod1, nn, D_DX)) { + regsalloc(&nod2, n); + gmove(&nod1, &nod2); + v = reg[D_DX]; + reg[D_DX] = 0; + + if(isreg(l, D_DX)) { + nod3 = *n; + nod3.left = &nod2; + cgen(&nod3, nn); + } else + if(isreg(r, D_DX)) { + nod3 = *n; + nod3.right = &nod2; + cgen(&nod3, nn); + } else + cgen(n, nn); + + gmove(&nod2, &nod1); + reg[D_DX] = v; + break; + } + reg[D_AX]++; + reg[D_DX]++; + + if(l->complex >= r->complex) { + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + cgen(&nod2, &nod); + if(r->op == OCONST && typechl[r->type->etype]) { + switch(o) { + case OASDIV: + sdivgen(&nod2, r, &nod, &nod1); + goto divdone; + case OASLDIV: + udivgen(&nod2, r, &nod, &nod1); + divdone: + gmove(&nod1, &nod2); + if(nn != Z) + gmove(&nod1, nn); + goto freelxaxdx; + } + } + if(o == OASDIV || o == OASMOD) + gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); + if(o == OASLDIV || o == OASLMOD) + zeroregm(&nod1); + if(r->addable < INDEXED || r->op == OCONST || + !typeil[r->type->etype]) { + regalloc(&nod3, r, Z); + cgen(r, &nod3); + gopcode(o, l->type, &nod3, Z); + regfree(&nod3); + } else + gopcode(o, n->type, r, Z); + } else { + regalloc(&nod3, r, Z); + cgen(r, &nod3); + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + cgen(&nod2, &nod); + if(o == OASDIV || o == OASMOD) + gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); + if(o == OASLDIV || o == OASLMOD) + zeroregm(&nod1); + gopcode(o, l->type, &nod3, Z); + regfree(&nod3); + } + if(o == OASMOD || o == OASLMOD) { + gmove(&nod1, &nod2); + if(nn != Z) + gmove(&nod1, nn); + } else { + gmove(&nod, &nod2); + if(nn != Z) + gmove(&nod, nn); + } + freelxaxdx: + if(hardleft) + regfree(&nod2); + regfree(&nod); + regfree(&nod1); + break; + + fop: + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + if(r->addable < INDEXED) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, n->type, &nod1, &nod); + regfree(&nod1); + } else + gopcode(o, n->type, r, &nod); + } else { + /* TO DO: could do better with r->addable >= INDEXED */ + regalloc(&nod1, r, Z); + cgen(r, &nod1); + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, n->type, &nod1, &nod); + regfree(&nod1); + } + gmove(&nod, nn); + regfree(&nod); + break; + + asbitop: + regalloc(&nod4, n, nn); + if(l->complex >= r->complex) { + bitload(l, &nod, &nod1, &nod2, &nod4); + regalloc(&nod3, r, Z); + cgen(r, &nod3); + } else { + regalloc(&nod3, r, Z); + cgen(r, &nod3); + bitload(l, &nod, &nod1, &nod2, &nod4); + } + gmove(&nod, &nod4); + + { /* TO DO: check floating point source */ + Node onod; + + /* incredible grot ... */ + onod = nod3; + onod.op = o; + onod.complex = 2; + onod.addable = 0; + onod.type = tfield; + onod.left = &nod4; + onod.right = &nod3; + cgen(&onod, Z); + } + regfree(&nod3); + gmove(&nod4, &nod); + regfree(&nod4); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OADDR: + if(nn == Z) { + nullwarn(l, Z); + break; + } + lcgen(l, nn); + break; + + case OFUNC: + if(l->complex >= FNX) { + if(l->op != OIND) + diag(n, "bad function call"); + + regret(&nod, l->left); + cgen(l->left, &nod); + regsalloc(&nod1, l->left); + gmove(&nod, &nod1); + regfree(&nod); + + nod = *n; + nod.left = &nod2; + nod2 = *l; + nod2.left = &nod1; + nod2.complex = 1; + cgen(&nod, nn); + + return; + } + o = reg[REGARG]; + gargs(r, &nod, &nod1); + if(l->addable < INDEXED) { + reglcgen(&nod, l, nn); + nod.op = OREGISTER; + gopcode(OFUNC, n->type, Z, &nod); + regfree(&nod); + } else + gopcode(OFUNC, n->type, Z, l); + if(REGARG) + if(o != reg[REGARG]) + reg[REGARG]--; + if(nn != Z) { + regret(&nod, n); + gmove(&nod, nn); + regfree(&nod); + } + break; + + case OIND: + if(nn == Z) { + nullwarn(l, Z); + break; + } + regialloc(&nod, n, nn); + r = l; + while(r->op == OADD) + r = r->right; + if(sconst(r)) { + v = r->vconst; + r->vconst = 0; + cgen(l, &nod); + nod.xoffset += v; + r->vconst = v; + } else + cgen(l, &nod); + regind(&nod, n); + gmove(&nod, nn); + regfree(&nod); + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OLO: + case OLS: + case OHI: + case OHS: + if(nn == Z) { + nullwarn(l, r); + break; + } + boolgen(n, 1, nn); + break; + + case OANDAND: + case OOROR: + boolgen(n, 1, nn); + if(nn == Z) + patch(p, pc); + break; + + case ONOT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + boolgen(n, 1, nn); + break; + + case OCOMMA: + cgen(l, Z); + cgen(r, nn); + break; + + case OCAST: + if(nn == Z) { + nullwarn(l, Z); + break; + } + /* + * convert from types l->n->nn + */ + if(nocast(l->type, n->type) && nocast(n->type, nn->type)) { + /* both null, gen l->nn */ + cgen(l, nn); + break; + } + if(ewidth[n->type->etype] < ewidth[l->type->etype]){ + if(l->type->etype == TIND && typechlp[n->type->etype]) + warn(n, "conversion of pointer to shorter integer"); + }else if(0){ + if(nocast(n->type, nn->type) || castup(n->type, nn->type)){ + if(typefd[l->type->etype] != typefd[nn->type->etype]) + regalloc(&nod, l, nn); + else + regalloc(&nod, nn, nn); + cgen(l, &nod); + gmove(&nod, nn); + regfree(&nod); + break; + } + } + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, n, &nod); + gmove(&nod, &nod1); + gmove(&nod1, nn); + regfree(&nod1); + regfree(&nod); + break; + + case ODOT: + sugen(l, nodrat, l->type->width); + if(nn == Z) + break; + warn(n, "non-interruptable temporary"); + nod = *nodrat; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += (long)r->vconst; + nod.type = n->type; + cgen(&nod, nn); + break; + + case OCOND: + bcgen(l, 1); + p1 = p; + cgen(r->left, nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + cgen(r->right, nn); + patch(p1, pc); + break; + + case OPOSTINC: + case OPOSTDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPOSTDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + if(nn == Z) + goto pre; + + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + + gmove(&nod, nn); + if(typefd[n->type->etype]) { + regalloc(&nod1, l, Z); + gmove(&nod, &nod1); + if(v < 0) + gopcode(OSUB, n->type, nodfconst(-v), &nod1); + else + gopcode(OADD, n->type, nodfconst(v), &nod1); + gmove(&nod1, &nod); + regfree(&nod1); + } else + gopcode(OADD, n->type, nodconst(v), &nod); + if(hardleft) + regfree(&nod); + break; + + case OPREINC: + case OPREDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPREDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + + pre: + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + if(typefd[n->type->etype]) { + regalloc(&nod1, l, Z); + gmove(&nod, &nod1); + if(v < 0) + gopcode(OSUB, n->type, nodfconst(-v), &nod1); + else + gopcode(OADD, n->type, nodfconst(v), &nod1); + gmove(&nod1, &nod); + regfree(&nod1); + } else + gopcode(OADD, n->type, nodconst(v), &nod); + if(nn != Z) + gmove(&nod, nn); + if(hardleft) + regfree(&nod); + break; + + bitinc: + if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { + bitload(l, &nod, &nod1, &nod2, Z); + gmove(&nod, nn); + gopcode(OADD, tfield, nodconst(v), &nod); + bitstore(l, &nod, &nod1, &nod2, Z); + break; + } + bitload(l, &nod, &nod1, &nod2, nn); + gopcode(OADD, tfield, nodconst(v), &nod); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + } +done: + cursafe = curs; +} + +void +reglcgen(Node *t, Node *n, Node *nn) +{ + Node *r; + long v; + + regialloc(t, n, nn); + if(n->op == OIND) { + r = n->left; + while(r->op == OADD) + r = r->right; + if(sconst(r)) { + v = r->vconst; + r->vconst = 0; + lcgen(n, t); + t->xoffset += v; + r->vconst = v; + regind(t, n); + return; + } + } + lcgen(n, t); + regind(t, n); +} + +void +lcgen(Node *n, Node *nn) +{ + Prog *p1; + Node nod; + + if(debug['g']) { + prtree(nn, "lcgen lhs"); + prtree(n, "lcgen"); + } + if(n == Z || n->type == T) + return; + if(nn == Z) { + nn = &nod; + regalloc(&nod, n, Z); + } + switch(n->op) { + default: + if(n->addable < INDEXED) { + diag(n, "unknown op in lcgen: %O", n->op); + break; + } + gopcode(OADDR, n->type, n, nn); + break; + + case OCOMMA: + cgen(n->left, n->left); + lcgen(n->right, nn); + break; + + case OIND: + cgen(n->left, nn); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + lcgen(n->right->left, nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + lcgen(n->right->right, nn); + patch(p1, pc); + break; + } +} + +void +bcgen(Node *n, int true) +{ + + if(n->type == T) + gbranch(OGOTO); + else + boolgen(n, true, Z); +} + +void +boolgen(Node *n, int true, Node *nn) +{ + int o; + Prog *p1, *p2; + Node *l, *r, nod, nod1; + long curs; + + if(debug['g']) { + prtree(nn, "boolgen lhs"); + prtree(n, "boolgen"); + } + curs = cursafe; + l = n->left; + r = n->right; + switch(n->op) { + + default: + o = ONE; + if(true) + o = OEQ; + /* bad, 13 is address of external that becomes constant */ + if(n->addable >= INDEXED && n->addable != 13) { + if(typefd[n->type->etype]) { + regalloc(&nod1, n, Z); + gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */ + gopcode(o, n->type, n, &nod1); + regfree(&nod1); + } else + gopcode(o, n->type, n, nodconst(0)); + goto com; + } + regalloc(&nod, n, nn); + cgen(n, &nod); + if(typefd[n->type->etype]) { + regalloc(&nod1, n, Z); + gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */ + gopcode(o, n->type, &nod, &nod1); + regfree(&nod1); + } else + gopcode(o, n->type, &nod, nodconst(0)); + regfree(&nod); + goto com; + + case OCONST: + o = vconst(n); + if(!true) + o = !o; + gbranch(OGOTO); + if(o) { + p1 = p; + gbranch(OGOTO); + patch(p1, pc); + } + goto com; + + case OCOMMA: + cgen(l, Z); + boolgen(r, true, nn); + break; + + case ONOT: + boolgen(l, !true, nn); + break; + + case OCOND: + bcgen(l, 1); + p1 = p; + bcgen(r->left, true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + bcgen(r->right, !true); + patch(p2, pc); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OANDAND: + if(!true) + goto caseor; + + caseand: + bcgen(l, true); + p1 = p; + bcgen(r, !true); + p2 = p; + patch(p1, pc); + gbranch(OGOTO); + patch(p2, pc); + goto com; + + case OOROR: + if(!true) + goto caseand; + + caseor: + bcgen(l, !true); + p1 = p; + bcgen(r, !true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + o = n->op; + if(true) + o = comrel[relindex(o)]; + if(l->complex >= FNX && r->complex >= FNX) { + regret(&nod, r); + cgen(r, &nod); + regsalloc(&nod1, r); + gmove(&nod, &nod1); + regfree(&nod); + nod = *n; + nod.right = &nod1; + boolgen(&nod, true, nn); + break; + } + if(immconst(l)) { + o = invrel[relindex(o)]; + /* bad, 13 is address of external that becomes constant */ + if(r->addable < INDEXED || r->addable == 13) { + regalloc(&nod, r, nn); + cgen(r, &nod); + gopcode(o, l->type, &nod, l); + regfree(&nod); + } else + gopcode(o, l->type, r, l); + goto com; + } + if(typefd[l->type->etype]) + o = invrel[relindex(logrel[relindex(o)])]; + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + if(r->addable < INDEXED || hardconst(r) || typefd[l->type->etype]) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, l->type, &nod, &nod1); + regfree(&nod1); + } else + gopcode(o, l->type, &nod, r); + regfree(&nod); + goto com; + } + regalloc(&nod, r, nn); + cgen(r, &nod); + if(l->addable < INDEXED || l->addable == 13 || hardconst(l)) { + regalloc(&nod1, l, Z); + cgen(l, &nod1); + if(typechl[l->type->etype] && ewidth[l->type->etype] <= ewidth[TINT]) + gopcode(o, types[TINT], &nod1, &nod); + else + gopcode(o, l->type, &nod1, &nod); + regfree(&nod1); + } else + gopcode(o, l->type, l, &nod); + regfree(&nod); + + com: + if(nn != Z) { + p1 = p; + gmove(nodconst(1L), nn); + gbranch(OGOTO); + p2 = p; + patch(p1, pc); + gmove(nodconst(0L), nn); + patch(p2, pc); + } + break; + } + cursafe = curs; +} + +void +sugen(Node *n, Node *nn, long w) +{ + Prog *p1; + Node nod0, nod1, nod2, nod3, nod4, *l, *r; + Type *t; + int c, mt, mo; + vlong o0, o1; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + prtree(nn, "sugen lhs"); + prtree(n, "sugen"); + } + if(nn == nodrat) + if(w > nrathole) + nrathole = w; + switch(n->op) { + case OIND: + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + default: + goto copy; + + case OCONST: + goto copy; + + case ODOT: + l = n->left; + sugen(l, nodrat, l->type->width); + if(nn == Z) + break; + warn(n, "non-interruptable temporary"); + nod1 = *nodrat; + r = n->right; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod1.xoffset += (long)r->vconst; + nod1.type = n->type; + sugen(&nod1, nn, w); + break; + + case OSTRUCT: + /* + * rewrite so lhs has no fn call + */ + if(nn != Z && side(nn)) { + nod1 = *n; + nod1.type = typ(TIND, n->type); + regret(&nod2, &nod1); + lcgen(nn, &nod2); + regsalloc(&nod0, &nod1); + cgen(&nod2, &nod0); + regfree(&nod2); + + nod1 = *n; + nod1.op = OIND; + nod1.left = &nod0; + nod1.right = Z; + nod1.complex = 1; + + sugen(n, &nod1, w); + return; + } + + r = n->left; + for(t = n->type->link; t != T; t = t->down) { + l = r; + if(r->op == OLIST) { + l = r->left; + r = r->right; + } + if(nn == Z) { + cgen(l, nn); + continue; + } + /* + * hand craft *(&nn + o) = l + */ + nod0 = znode; + nod0.op = OAS; + nod0.type = t; + nod0.left = &nod1; + nod0.right = nil; + + nod1 = znode; + nod1.op = OIND; + nod1.type = t; + nod1.left = &nod2; + + nod2 = znode; + nod2.op = OADD; + nod2.type = typ(TIND, t); + nod2.left = &nod3; + nod2.right = &nod4; + + nod3 = znode; + nod3.op = OADDR; + nod3.type = nod2.type; + nod3.left = nn; + + nod4 = znode; + nod4.op = OCONST; + nod4.type = nod2.type; + nod4.vconst = t->offset; + + ccom(&nod0); + acom(&nod0); + xcom(&nod0); + nod0.addable = 0; + nod0.right = l; + + /* prtree(&nod0, "hand craft"); /* */ + cgen(&nod0, Z); + } + break; + + case OAS: + if(nn == Z) { + if(n->addable < INDEXED) + sugen(n->right, n->left, w); + break; + } + + sugen(n->right, nodrat, w); + warn(n, "non-interruptable temporary"); + sugen(nodrat, n->left, w); + sugen(nodrat, nn, w); + break; + + case OFUNC: + if(nn == Z) { + sugen(n, nodrat, w); + break; + } + if(nn->op != OIND) { + nn = new1(OADDR, nn, Z); + nn->type = types[TIND]; + nn->addable = 0; + } else + nn = nn->left; + n = new(OFUNC, n->left, new(OLIST, nn, n->right)); + n->type = types[TVOID]; + n->left->type = types[TVOID]; + cgen(n, Z); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + sugen(n->right->left, nn, w); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + sugen(n->right->right, nn, w); + patch(p1, pc); + break; + + case OCOMMA: + cgen(n->left, Z); + sugen(n->right, nn, w); + break; + } + return; + +copy: + if(nn == Z) { + switch(n->op) { + case OASADD: + case OASSUB: + case OASAND: + case OASOR: + case OASXOR: + + case OASMUL: + case OASLMUL: + + + case OASASHL: + case OASASHR: + case OASLSHR: + break; + + case OPOSTINC: + case OPOSTDEC: + case OPREINC: + case OPREDEC: + break; + + default: + return; + } + } + + if(n->complex >= FNX && nn != nil && nn->complex >= FNX) { + t = nn->type; + nn->type = types[TLONG]; + regialloc(&nod1, nn, Z); + lcgen(nn, &nod1); + regsalloc(&nod2, nn); + nn->type = t; + + gins(AMOVL, &nod1, &nod2); + regfree(&nod1); + + nod2.type = typ(TIND, t); + + nod1 = nod2; + nod1.op = OIND; + nod1.left = &nod2; + nod1.right = Z; + nod1.complex = 1; + nod1.type = t; + + sugen(n, &nod1, w); + return; + } + + if(w <= 32) { + c = cursafe; + if(n->left != Z && n->left->complex >= FNX + && n->right != Z && n->right->complex >= FNX) { + regsalloc(&nod1, n->right); + cgen(n->right, &nod1); + nod2 = *n; + nod2.right = &nod1; + cgen(&nod2, nn); + cursafe = c; + return; + } + if(w & 7) { + mt = TLONG; + mo = AMOVL; + } else { + mt = TVLONG; + mo = AMOVQ; + } + if(n->complex > nn->complex) { + t = n->type; + n->type = types[mt]; + regalloc(&nod0, n, Z); + if(!vaddr(n, 0)) { + reglcgen(&nod1, n, Z); + n->type = t; + n = &nod1; + } + else + n->type = t; + + t = nn->type; + nn->type = types[mt]; + if(!vaddr(nn, 0)) { + reglcgen(&nod2, nn, Z); + nn->type = t; + nn = &nod2; + } + else + nn->type = t; + } else { + t = nn->type; + nn->type = types[mt]; + regalloc(&nod0, nn, Z); + if(!vaddr(nn, 0)) { + reglcgen(&nod2, nn, Z); + nn->type = t; + nn = &nod2; + } + else + nn->type = t; + + t = n->type; + n->type = types[mt]; + if(!vaddr(n, 0)) { + reglcgen(&nod1, n, Z); + n->type = t; + n = &nod1; + } + else + n->type = t; + } + o0 = n->xoffset; + o1 = nn->xoffset; + w /= ewidth[mt]; + while(--w >= 0) { + gins(mo, n, &nod0); + gins(mo, &nod0, nn); + n->xoffset += ewidth[mt]; + nn->xoffset += ewidth[mt]; + } + n->xoffset = o0; + nn->xoffset = o1; + if(nn == &nod2) + regfree(&nod2); + if(n == &nod1) + regfree(&nod1); + regfree(&nod0); + return; + } + + /* botch, need to save in .safe */ + c = 0; + if(n->complex > nn->complex) { + t = n->type; + n->type = types[TLONG]; + nodreg(&nod1, n, D_SI); + if(reg[D_SI]) { + gins(APUSHQ, &nod1, Z); + c |= 1; + reg[D_SI]++; + } + lcgen(n, &nod1); + n->type = t; + + t = nn->type; + nn->type = types[TLONG]; + nodreg(&nod2, nn, D_DI); + if(reg[D_DI]) { +warn(Z, "DI botch"); + gins(APUSHQ, &nod2, Z); + c |= 2; + reg[D_DI]++; + } + lcgen(nn, &nod2); + nn->type = t; + } else { + t = nn->type; + nn->type = types[TLONG]; + nodreg(&nod2, nn, D_DI); + if(reg[D_DI]) { +warn(Z, "DI botch"); + gins(APUSHQ, &nod2, Z); + c |= 2; + reg[D_DI]++; + } + lcgen(nn, &nod2); + nn->type = t; + + t = n->type; + n->type = types[TLONG]; + nodreg(&nod1, n, D_SI); + if(reg[D_SI]) { + gins(APUSHQ, &nod1, Z); + c |= 1; + reg[D_SI]++; + } + lcgen(n, &nod1); + n->type = t; + } + nodreg(&nod3, n, D_CX); + if(reg[D_CX]) { + gins(APUSHQ, &nod3, Z); + c |= 4; + reg[D_CX]++; + } + gins(AMOVL, nodconst(w/SZ_INT), &nod3); + gins(ACLD, Z, Z); + gins(AREP, Z, Z); + gins(AMOVSL, Z, Z); + if(c & 4) { + gins(APOPQ, Z, &nod3); + reg[D_CX]--; + } + if(c & 2) { + gins(APOPQ, Z, &nod2); + reg[nod2.reg]--; + } + if(c & 1) { + gins(APOPQ, Z, &nod1); + reg[nod1.reg]--; + } +} + +/* + * TO DO + */ +void +layout(Node *f, Node *t, int c, int cv, Node *cn) +{ + Node t1, t2; + + while(c > 3) { + layout(f, t, 2, 0, Z); + c -= 2; + } + + regalloc(&t1, &lregnode, Z); + regalloc(&t2, &lregnode, Z); + if(c > 0) { + gmove(f, &t1); + f->xoffset += SZ_INT; + } + if(cn != Z) + gmove(nodconst(cv), cn); + if(c > 1) { + gmove(f, &t2); + f->xoffset += SZ_INT; + } + if(c > 0) { + gmove(&t1, t); + t->xoffset += SZ_INT; + } + if(c > 2) { + gmove(f, &t1); + f->xoffset += SZ_INT; + } + if(c > 1) { + gmove(&t2, t); + t->xoffset += SZ_INT; + } + if(c > 2) { + gmove(&t1, t); + t->xoffset += SZ_INT; + } + regfree(&t1); + regfree(&t2); +} + +/* + * constant is not vlong or fits as 32-bit signed immediate + */ +int +immconst(Node *n) +{ + long v; + + if(n->op != OCONST || !typechlpv[n->type->etype]) + return 0; + if(typechl[n->type->etype]) + return 1; + v = n->vconst; + return n->vconst == (vlong)v; +} + +/* + * if a constant and vlong, doesn't fit as 32-bit signed immediate + */ +int +hardconst(Node *n) +{ + return n->op == OCONST && !immconst(n); +} + +/* + * casting up to t2 covers an intermediate cast to t1 + */ +int +castup(Type *t1, Type *t2) +{ + int ft; + + if(!nilcast(t1, t2)) + return 0; + /* known to be small to large */ + ft = t1->etype; + switch(t2->etype){ + case TINT: + case TLONG: + return ft == TLONG || ft == TINT || ft == TSHORT || ft == TCHAR; + case TUINT: + case TULONG: + return ft == TULONG || ft == TUINT || ft == TUSHORT || ft == TUCHAR; + case TVLONG: + return ft == TLONG || ft == TINT || ft == TSHORT; + case TUVLONG: + return ft == TULONG || ft == TUINT || ft == TUSHORT; + } + return 0; +} + +void +zeroregm(Node *n) +{ + gins(AMOVL, nodconst(0), n); +} + +/* do we need to load the address of a vlong? */ +int +vaddr(Node *n, int a) +{ + switch(n->op) { + case ONAME: + if(a) + return 1; + return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC); + + case OCONST: + case OREGISTER: + case OINDREG: + return 1; + } + return 0; +} + +long +hi64v(Node *n) +{ + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + return (long)(n->vconst) & ~0L; + else + return (long)((uvlong)n->vconst>>32) & ~0L; +} + +long +lo64v(Node *n) +{ + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + return (long)((uvlong)n->vconst>>32) & ~0L; + else + return (long)(n->vconst) & ~0L; +} + +Node * +hi64(Node *n) +{ + return nodconst(hi64v(n)); +} + +Node * +lo64(Node *n) +{ + return nodconst(lo64v(n)); +} + +int +cond(int op) +{ + switch(op) { + case OANDAND: + case OOROR: + case ONOT: + return 1; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + return 1; + } + return 0; +} diff --git a/src/cmd/6c/div.c b/src/cmd/6c/div.c new file mode 100644 index 0000000000..4b63ddc1e8 --- /dev/null +++ b/src/cmd/6c/div.c @@ -0,0 +1,236 @@ +// Inferno utils/6c/div.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/div.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +/* + * Based on: Granlund, T.; Montgomery, P.L. + * "Division by Invariant Integers using Multiplication". + * SIGPLAN Notices, Vol. 29, June 1994, page 61. + */ + +#define TN(n) ((uvlong)1 << (n)) +#define T31 TN(31) +#define T32 TN(32) + +int +multiplier(ulong d, int p, uvlong *mp) +{ + int l; + uvlong mlo, mhi, tlo, thi; + + l = topbit(d - 1) + 1; + mlo = (((TN(l) - d) << 32) / d) + T32; + if(l + p == 64) + mhi = (((TN(l) + 1 - d) << 32) / d) + T32; + else + mhi = (TN(32 + l) + TN(32 + l - p)) / d; + /*assert(mlo < mhi);*/ + while(l > 0) { + tlo = mlo >> 1; + thi = mhi >> 1; + if(tlo == thi) + break; + mlo = tlo; + mhi = thi; + l--; + } + *mp = mhi; + return l; +} + +int +sdiv(ulong d, ulong *mp, int *sp) +{ + int s; + uvlong m; + + s = multiplier(d, 32 - 1, &m); + *mp = m; + *sp = s; + if(m >= T31) + return 1; + else + return 0; +} + +int +udiv(ulong d, ulong *mp, int *sp, int *pp) +{ + int p, s; + uvlong m; + + s = multiplier(d, 32, &m); + p = 0; + if(m >= T32) { + while((d & 1) == 0) { + d >>= 1; + p++; + } + s = multiplier(d, 32 - p, &m); + } + *mp = m; + *pp = p; + if(m >= T32) { + /*assert(p == 0);*/ + *sp = s - 1; + return 1; + } + else { + *sp = s; + return 0; + } +} + +void +sdivgen(Node *l, Node *r, Node *ax, Node *dx) +{ + int a, s; + ulong m; + vlong c; + + c = r->vconst; + if(c < 0) + c = -c; + a = sdiv(c, &m, &s); +//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m); + gins(AMOVL, nodconst(m), ax); + gins(AIMULL, l, Z); + gins(AMOVL, l, ax); + if(a) + gins(AADDL, ax, dx); + gins(ASHRL, nodconst(31), ax); + gins(ASARL, nodconst(s), dx); + gins(AADDL, ax, dx); + if(r->vconst < 0) + gins(ANEGL, Z, dx); +} + +void +udivgen(Node *l, Node *r, Node *ax, Node *dx) +{ + int a, s, t; + ulong m; + Node nod; + + a = udiv(r->vconst, &m, &s, &t); +//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m); + if(t != 0) { + gins(AMOVL, l, ax); + gins(ASHRL, nodconst(t), ax); + gins(AMOVL, nodconst(m), dx); + gins(AMULL, dx, Z); + } + else if(a) { + if(l->op != OREGISTER) { + regalloc(&nod, l, Z); + gins(AMOVL, l, &nod); + l = &nod; + } + gins(AMOVL, nodconst(m), ax); + gins(AMULL, l, Z); + gins(AADDL, l, dx); + gins(ARCRL, nodconst(1), dx); + if(l == &nod) + regfree(l); + } + else { + gins(AMOVL, nodconst(m), ax); + gins(AMULL, l, Z); + } + if(s != 0) + gins(ASHRL, nodconst(s), dx); +} + +void +sext(Node *d, Node *s, Node *l) +{ + if(s->reg == D_AX && !nodreg(d, Z, D_DX)) { + reg[D_DX]++; + gins(ACDQ, Z, Z); + } + else { + regalloc(d, l, Z); + gins(AMOVL, s, d); + gins(ASARL, nodconst(31), d); + } +} + +void +sdiv2(long c, int v, Node *l, Node *n) +{ + Node nod; + + if(v > 0) { + if(v > 1) { + sext(&nod, n, l); + gins(AANDL, nodconst((1 << v) - 1), &nod); + gins(AADDL, &nod, n); + regfree(&nod); + } + else { + gins(ACMPL, n, nodconst(0x80000000)); + gins(ASBBL, nodconst(-1), n); + } + gins(ASARL, nodconst(v), n); + } + if(c < 0) + gins(ANEGL, Z, n); +} + +void +smod2(long c, int v, Node *l, Node *n) +{ + Node nod; + + if(c == 1) { + zeroregm(n); + return; + } + + sext(&nod, n, l); + if(v == 0) { + zeroregm(n); + gins(AXORL, &nod, n); + gins(ASUBL, &nod, n); + } + else if(v > 1) { + gins(AANDL, nodconst((1 << v) - 1), &nod); + gins(AADDL, &nod, n); + gins(AANDL, nodconst((1 << v) - 1), n); + gins(ASUBL, &nod, n); + } + else { + gins(AANDL, nodconst(1), n); + gins(AXORL, &nod, n); + gins(ASUBL, &nod, n); + } + regfree(&nod); +} diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h new file mode 100644 index 0000000000..dee9966cab --- /dev/null +++ b/src/cmd/6c/gc.h @@ -0,0 +1,411 @@ +// Inferno utils/6c/gc.h +// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "../cc/cc.h" +#include "../6l/6.out.h" + +/* + * 6c/amd64 + * Intel 386 with AMD64 extensions + */ +#define SZ_CHAR 1 +#define SZ_SHORT 2 +#define SZ_INT 4 +#define SZ_LONG 4 +#define SZ_IND 8 +#define SZ_FLOAT 4 +#define SZ_VLONG 8 +#define SZ_DOUBLE 8 +#define FNX 100 + +typedef struct Adr Adr; +typedef struct Prog Prog; +typedef struct Case Case; +typedef struct C1 C1; +typedef struct Var Var; +typedef struct Reg Reg; +typedef struct Rgn Rgn; +typedef struct Renv Renv; + +EXTERN struct +{ + Node* regtree; + Node* basetree; + short scale; + short reg; + short ptr; +} idx; + +struct Adr +{ + vlong offset; + double dval; + char sval[NSNAME]; + + Sym* sym; + uchar type; + uchar index; + uchar etype; + uchar scale; /* doubles as width in DATA op */ +}; +#define A ((Adr*)0) + +#define INDEXED 9 +struct Prog +{ + Adr from; + Adr to; + Prog* link; + long lineno; + short as; +}; +#define P ((Prog*)0) + +struct Case +{ + Case* link; + vlong val; + long label; + char def; + char isv; +}; +#define C ((Case*)0) + +struct C1 +{ + vlong val; + long label; +}; + +struct Var +{ + vlong offset; + Sym* sym; + char name; + char etype; +}; + +struct Reg +{ + long pc; + long rpo; /* reverse post ordering */ + + Bits set; + Bits use1; + Bits use2; + + Bits refbehind; + Bits refahead; + Bits calbehind; + Bits calahead; + Bits regdiff; + Bits act; + + long regu; + long loop; /* could be shorter */ + + Reg* log5; + long active; + + Reg* p1; + Reg* p2; + Reg* p2link; + Reg* s1; + Reg* s2; + Reg* link; + Prog* prog; +}; +#define R ((Reg*)0) + +struct Renv +{ + int safe; + Node base; + Node* saved; + Node* scope; +}; + +#define NRGN 600 +struct Rgn +{ + Reg* enter; + short cost; + short varno; + short regno; +}; + +EXTERN long breakpc; +EXTERN long nbreak; +EXTERN Case* cases; +EXTERN Node constnode; +EXTERN Node fconstnode; +EXTERN Node vconstnode; +EXTERN long continpc; +EXTERN long curarg; +EXTERN long cursafe; +EXTERN Prog* firstp; +EXTERN Prog* lastp; +EXTERN long maxargsafe; +EXTERN int mnstring; +EXTERN Node* nodrat; +EXTERN Node* nodret; +EXTERN Node* nodsafe; +EXTERN long nrathole; +EXTERN long nstring; +EXTERN Prog* p; +EXTERN long pc; +EXTERN Node lregnode; +EXTERN Node qregnode; +EXTERN char string[NSNAME]; +EXTERN Sym* symrathole; +EXTERN Node znode; +EXTERN Prog zprog; +EXTERN int reg[D_NONE]; +EXTERN long exregoffset; +EXTERN long exfregoffset; +EXTERN uchar typechlpv[NTYPE]; + +#define BLOAD(r) band(bnot(r->refbehind), r->refahead) +#define BSTORE(r) band(bnot(r->calbehind), r->calahead) +#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z]) +#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z]) + +#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32)) + +#define CLOAD 5 +#define CREF 5 +#define CINF 1000 +#define LOOP 3 + +EXTERN Rgn region[NRGN]; +EXTERN Rgn* rgp; +EXTERN int nregion; +EXTERN int nvar; + +EXTERN Bits externs; +EXTERN Bits params; +EXTERN Bits consts; +EXTERN Bits addrs; + +EXTERN long regbits; +EXTERN long exregbits; + +EXTERN int change; +EXTERN int suppress; + +EXTERN Reg* firstr; +EXTERN Reg* lastr; +EXTERN Reg zreg; +EXTERN Reg* freer; +EXTERN Var var[NVAR]; +EXTERN long* idom; +EXTERN Reg** rpo2r; +EXTERN long maxnr; + +extern char* anames[]; + +/* + * sgen.c + */ +void codgen(Node*, Node*); +void gen(Node*); +void noretval(int); +void usedset(Node*, int); +void xcom(Node*); +void indx(Node*); +int bcomplex(Node*, Node*); + +/* + * cgen.c + */ +void zeroregm(Node*); +void cgen(Node*, Node*); +void reglcgen(Node*, Node*, Node*); +void lcgen(Node*, Node*); +void bcgen(Node*, int); +void boolgen(Node*, int, Node*); +void sugen(Node*, Node*, long); +int needreg(Node*, int); +int hardconst(Node*); +int immconst(Node*); + +/* + * cgen64.c + */ +int vaddr(Node*, int); +void loadpair(Node*, Node*); +int cgen64(Node*, Node*); +void testv(Node*, int); + +/* + * txt.c + */ +void ginit(void); +void gclean(void); +void nextpc(void); +void gargs(Node*, Node*, Node*); +void garg1(Node*, Node*, Node*, int, Node**); +Node* nodconst(long); +Node* nodfconst(double); +Node* nodgconst(vlong, Type*); +int nodreg(Node*, Node*, int); +int isreg(Node*, int); +void regret(Node*, Node*); +void regalloc(Node*, Node*, Node*); +void regfree(Node*); +void regialloc(Node*, Node*, Node*); +void regsalloc(Node*, Node*); +void regaalloc1(Node*, Node*); +void regaalloc(Node*, Node*); +void regind(Node*, Node*); +void gprep(Node*, Node*); +void naddr(Node*, Adr*); +void gcmp(int, Node*, vlong); +void gmove(Node*, Node*); +void gins(int a, Node*, Node*); +void gopcode(int, Type*, Node*, Node*); +int samaddr(Node*, Node*); +void gbranch(int); +void patch(Prog*, long); +int sconst(Node*); +void gpseudo(int, Sym*, Node*); + +/* + * swt.c + */ +int swcmp(const void*, const void*); +void doswit(Node*); +void swit1(C1*, int, long, Node*); +void cas(void); +void bitload(Node*, Node*, Node*, Node*, Node*); +void bitstore(Node*, Node*, Node*, Node*, Node*); +long outstring(char*, long); +void nullwarn(Node*, Node*); +void sextern(Sym*, Node*, long, long); +void gextern(Sym*, Node*, long, long); +void outcode(void); +void ieeedtod(Ieee*, double); + +/* + * list + */ +void listinit(void); +int Pconv(Fmt*); +int Aconv(Fmt*); +int Dconv(Fmt*); +int Sconv(Fmt*); +int Rconv(Fmt*); +int Xconv(Fmt*); +int Bconv(Fmt*); + +/* + * reg.c + */ +Reg* rega(void); +int rcmp(const void*, const void*); +void regopt(Prog*); +void addmove(Reg*, int, int, int); +Bits mkvar(Reg*, Adr*); +void prop(Reg*, Bits, Bits); +void loopit(Reg*, long); +void synch(Reg*, Bits); +ulong allreg(ulong, Rgn*); +void paint1(Reg*, int); +ulong paint2(Reg*, int); +void paint3(Reg*, int, long, int); +void addreg(Adr*, int); + +/* + * peep.c + */ +void peep(void); +void excise(Reg*); +Reg* uniqp(Reg*); +Reg* uniqs(Reg*); +int regtyp(Adr*); +int anyvar(Adr*); +int subprop(Reg*); +int copyprop(Reg*); +int copy1(Adr*, Adr*, Reg*, int); +int copyu(Prog*, Adr*, Adr*); + +int copyas(Adr*, Adr*); +int copyau(Adr*, Adr*); +int copysub(Adr*, Adr*, Adr*, int); +int copysub1(Prog*, Adr*, Adr*, int); + +long RtoB(int); +long FtoB(int); +int BtoR(long); +int BtoF(long); + +#define D_HI D_NONE +#define D_LO D_NONE + +#define isregtype(t) ((t)>= D_AX && (t)<=D_R15) + +/* + * bound + */ +void comtarg(void); + +/* + * com64 + */ +int cond(int); +int com64(Node*); +void com64init(void); +void bool64(Node*); +long lo64v(Node*); +long hi64v(Node*); +Node* lo64(Node*); +Node* hi64(Node*); + +/* + * div/mul + */ +void sdivgen(Node*, Node*, Node*, Node*); +void udivgen(Node*, Node*, Node*, Node*); +void sdiv2(long, int, Node*, Node*); +void smod2(long, int, Node*, Node*); +void mulgen(Type*, Node*, Node*); +void genmuladd(Node*, Node*, int, Node*); +void shiftit(Type*, Node*, Node*); + +#pragma varargck type "A" int +#pragma varargck type "B" Bits +#pragma varargck type "D" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "R" int +#pragma varargck type "S" char* + +#define D_X7 (D_X0+7) + +void fgopcode(int, Node*, Node*, int, int); diff --git a/src/cmd/6c/list.c b/src/cmd/6c/list.c new file mode 100644 index 0000000000..4aae5a3a7e --- /dev/null +++ b/src/cmd/6c/list.c @@ -0,0 +1,372 @@ +// Inferno utils/6c/list.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define EXTERN +#include "gc.h" + +void +listinit(void) +{ + + fmtinstall('A', Aconv); + fmtinstall('B', Bconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('D', Dconv); + fmtinstall('R', Rconv); +} + +int +Bconv(Fmt *fp) +{ + char str[STRINGSZ], ss[STRINGSZ], *s; + Bits bits; + int i; + + str[0] = 0; + bits = va_arg(fp->args, Bits); + while(bany(&bits)) { + i = bnum(bits); + if(str[0]) + strcat(str, " "); + if(var[i].sym == S) { + sprint(ss, "$%lld", var[i].offset); + s = ss; + } else + s = var[i].sym->name; + if(strlen(str) + strlen(s) + 1 >= STRINGSZ) + break; + strcat(str, s); + bits.b[i/32] &= ~(1L << (i%32)); + } + return fmtstrcpy(fp, str); +} + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ]; + Prog *p; + + p = va_arg(fp->args, Prog*); + if(p->as == ADATA) + sprint(str, " %A %D/%d,%D", + p->as, &p->from, p->from.scale, &p->to); + else if(p->as == ATEXT) + sprint(str, " %A %D,%d,%D", + p->as, &p->from, p->from.scale, &p->to); + else + sprint(str, " %A %D,%D", + p->as, &p->from, &p->to); + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + int i; + + i = va_arg(fp->args, int); + return fmtstrcpy(fp, anames[i]); +} + +int +Dconv(Fmt *fp) +{ + char str[40], s[20]; + Adr *a; + int i; + + a = va_arg(fp->args, Adr*); + i = a->type; + if(i >= D_INDIR) { + if(a->offset) + sprint(str, "%lld(%R)", a->offset, i-D_INDIR); + else + sprint(str, "(%R)", i-D_INDIR); + goto brk; + } + switch(i) { + + default: + if(a->offset) + sprint(str, "$%lld,%R", a->offset, i); + else + sprint(str, "%R", i); + break; + + case D_NONE: + str[0] = 0; + break; + + case D_BRANCH: + sprint(str, "%lld(PC)", a->offset-pc); + break; + + case D_EXTERN: + sprint(str, "%s+%lld(SB)", a->sym->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<>+%lld(SB)", a->sym->name, + a->offset); + break; + + case D_AUTO: + if(a->sym) { + sprint(str, "%s+%lld(SP)", a->sym->name, a->offset); + break; + } + sprint(str, "%lld(SP)", a->offset); + break; + + case D_PARAM: + if(a->sym) { + sprint(str, "%s+%lld(FP)", a->sym->name, a->offset); + break; + } + sprint(str, "%lld(FP)", a->offset); + break; + + case D_CONST: + sprint(str, "$%lld", a->offset); + break; + + case D_FCONST: + sprint(str, "$(%.17e)", a->dval); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + + case D_ADDR: + a->type = a->index; + a->index = D_NONE; + sprint(str, "$%D", a); + a->index = a->type; + a->type = D_ADDR; + goto conv; + } +brk: + if(a->index != D_NONE) { + sprint(s, "(%R*%d)", (int)a->index, (int)a->scale); + strcat(str, s); + } +conv: + return fmtstrcpy(fp, str); +} + +char* regstr[] = +{ + "AL", /* [D_AL] */ + "CL", + "DL", + "BL", + "SPB", + "BPB", + "SIB", + "DIB", + "R8B", + "R9B", + "R10B", + "R11B", + "R12B", + "R13B", + "R14B", + "R15B", + + "AX", /* [D_AX] */ + "CX", + "DX", + "BX", + "SP", + "BP", + "SI", + "DI", + "R8", + "R9", + "R10", + "R11", + "R12", + "R13", + "R14", + "R15", + + "AH", + "CH", + "DH", + "BH", + + "F0", /* [D_F0] */ + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + + "M0", + "M1", + "M2", + "M3", + "M4", + "M5", + "M6", + "M7", + + "X0", + "X1", + "X2", + "X3", + "X4", + "X5", + "X6", + "X7", + "X8", + "X9", + "X10", + "X11", + "X12", + "X13", + "X14", + "X15", + + "CS", /* [D_CS] */ + "SS", + "DS", + "ES", + "FS", + "GS", + + "GDTR", /* [D_GDTR] */ + "IDTR", /* [D_IDTR] */ + "LDTR", /* [D_LDTR] */ + "MSW", /* [D_MSW] */ + "TASK", /* [D_TASK] */ + + "CR0", /* [D_CR] */ + "CR1", + "CR2", + "CR3", + "CR4", + "CR5", + "CR6", + "CR7", + "CR8", + "CR9", + "CR10", + "CR11", + "CR12", + "CR13", + "CR14", + "CR15", + + "DR0", /* [D_DR] */ + "DR1", + "DR2", + "DR3", + "DR4", + "DR5", + "DR6", + "DR7", + + "TR0", /* [D_TR] */ + "TR1", + "TR2", + "TR3", + "TR4", + "TR5", + "TR6", + "TR7", + + "NONE", /* [D_NONE] */ +}; + +int +Rconv(Fmt *fp) +{ + char str[20]; + int r; + + r = va_arg(fp->args, int); + if(r >= D_AL && r <= D_NONE) + sprint(str, "%s", regstr[r-D_AL]); + else + sprint(str, "gok(%d)", r); + + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[30], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + default: + if(c < 040 || c >= 0177) + break; /* not portable */ + p[-1] = c; + continue; + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} diff --git a/src/cmd/6c/machcap.c b/src/cmd/6c/machcap.c new file mode 100644 index 0000000000..d4f6bfabec --- /dev/null +++ b/src/cmd/6c/machcap.c @@ -0,0 +1,108 @@ +// Inferno utils/6c/machcap.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/machcap.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +int +machcap(Node *n) +{ + + if(n == Z) + return 1; /* test */ + + switch(n->op) { + case OMUL: + case OLMUL: + case OASMUL: + case OASLMUL: + if(typechl[n->type->etype]) + return 1; + if(typev[n->type->etype]) { + return 1; + } + break; + + case OCOM: + case ONEG: + case OADD: + case OAND: + case OOR: + case OSUB: + case OXOR: + case OASHL: + case OLSHR: + case OASHR: + if(typechlv[n->left->type->etype]) + return 1; + break; + + case OCAST: + return 1; + + case OCOND: + case OCOMMA: + case OLIST: + case OANDAND: + case OOROR: + case ONOT: + return 1; + + case OASADD: + case OASSUB: + case OASAND: + case OASOR: + case OASXOR: + return 1; + + case OASASHL: + case OASASHR: + case OASLSHR: + return 1; + + case OPOSTINC: + case OPOSTDEC: + case OPREINC: + case OPREDEC: + return 1; + + case OEQ: + case ONE: + case OLE: + case OGT: + case OLT: + case OGE: + case OHI: + case OHS: + case OLO: + case OLS: + return 1; + } + return 0; +} diff --git a/src/cmd/6c/mul.c b/src/cmd/6c/mul.c new file mode 100644 index 0000000000..7fd2012f11 --- /dev/null +++ b/src/cmd/6c/mul.c @@ -0,0 +1,458 @@ +// Inferno utils/6c/mul.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/mul.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +typedef struct Malg Malg; +typedef struct Mparam Mparam; + +struct Malg +{ + char vals[10]; +}; + +struct Mparam +{ + ulong value; + char alg; + char neg; + char shift; + char arg; + char off; +}; + +static Mparam multab[32]; +static int mulptr; + +static Malg malgs[] = +{ + {0, 100}, + {-1, 1, 100}, + {-9, -5, -3, 3, 5, 9, 100}, + {6, 10, 12, 18, 20, 24, 36, 40, 72, 100}, + {-8, -4, -2, 2, 4, 8, 100}, +}; + +/* + * return position of lowest 1 + */ +int +lowbit(ulong v) +{ + int s, i; + ulong m; + + s = 0; + m = 0xFFFFFFFFUL; + for(i = 16; i > 0; i >>= 1) { + m >>= i; + if((v & m) == 0) { + v >>= i; + s += i; + } + } + return s; +} + +void +genmuladd(Node *d, Node *s, int m, Node *a) +{ + Node nod; + + nod.op = OINDEX; + nod.left = a; + nod.right = s; + nod.scale = m; + nod.type = types[TIND]; + nod.xoffset = 0; + xcom(&nod); + gopcode(OADDR, d->type, &nod, d); +} + +void +mulparam(ulong m, Mparam *mp) +{ + int c, i, j, n, o, q, s; + int bc, bi, bn, bo, bq, bs, bt; + char *p; + long u; + ulong t; + + bc = bq = 10; + bi = bn = bo = bs = bt = 0; + for(i = 0; i < nelem(malgs); i++) { + for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++) + for(s = 0; s < 2; s++) { + c = 10; + q = 10; + u = m - o; + if(u == 0) + continue; + if(s) { + o = -o; + if(o > 0) + continue; + u = -u; + } + n = lowbit(u); + t = (ulong)u >> n; + switch(i) { + case 0: + if(t == 1) { + c = s + 1; + q = 0; + break; + } + switch(t) { + case 3: + case 5: + case 9: + c = s + 1; + if(n) + c++; + q = 0; + break; + } + if(s) + break; + switch(t) { + case 15: + case 25: + case 27: + case 45: + case 81: + c = 2; + if(n) + c++; + q = 1; + break; + } + break; + case 1: + if(t == 1) { + c = 3; + q = 3; + break; + } + switch(t) { + case 3: + case 5: + case 9: + c = 3; + q = 2; + break; + } + break; + case 2: + if(t == 1) { + c = 3; + q = 2; + break; + } + break; + case 3: + if(s) + break; + if(t == 1) { + c = 3; + q = 1; + break; + } + break; + case 4: + if(t == 1) { + c = 3; + q = 0; + break; + } + break; + } + if(c < bc || (c == bc && q > bq)) { + bc = c; + bi = i; + bn = n; + bo = o; + bq = q; + bs = s; + bt = t; + } + } + } + mp->value = m; + if(bc <= 3) { + mp->alg = bi; + mp->shift = bn; + mp->off = bo; + mp->neg = bs; + mp->arg = bt; + } + else + mp->alg = -1; +} + +int +m0(int a) +{ + switch(a) { + case -2: + case 2: + return 2; + case -3: + case 3: + return 2; + case -4: + case 4: + return 4; + case -5: + case 5: + return 4; + case 6: + return 2; + case -8: + case 8: + return 8; + case -9: + case 9: + return 8; + case 10: + return 4; + case 12: + return 2; + case 15: + return 2; + case 18: + return 8; + case 20: + return 4; + case 24: + return 2; + case 25: + return 4; + case 27: + return 2; + case 36: + return 8; + case 40: + return 4; + case 45: + return 4; + case 72: + return 8; + case 81: + return 8; + } + diag(Z, "bad m0"); + return 0; +} + +int +m1(int a) +{ + switch(a) { + case 15: + return 4; + case 25: + return 4; + case 27: + return 8; + case 45: + return 8; + case 81: + return 8; + } + diag(Z, "bad m1"); + return 0; +} + +int +m2(int a) +{ + switch(a) { + case 6: + return 2; + case 10: + return 2; + case 12: + return 4; + case 18: + return 2; + case 20: + return 4; + case 24: + return 8; + case 36: + return 4; + case 40: + return 8; + case 72: + return 8; + } + diag(Z, "bad m2"); + return 0; +} + +void +shiftit(Type *t, Node *s, Node *d) +{ + long c; + + c = (long)s->vconst & 31; + switch(c) { + case 0: + break; + case 1: + gopcode(OADD, t, d, d); + break; + default: + gopcode(OASHL, t, s, d); + } +} + +static int +mulgen1(ulong v, Node *n) +{ + int i, o; + Mparam *p; + Node nod, nods; + + for(i = 0; i < nelem(multab); i++) { + p = &multab[i]; + if(p->value == v) + goto found; + } + + p = &multab[mulptr]; + if(++mulptr == nelem(multab)) + mulptr = 0; + + mulparam(v, p); + +found: +// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off); + if(p->alg < 0) + return 0; + + nods = *nodconst(p->shift); + + o = OADD; + if(p->alg > 0) { + regalloc(&nod, n, Z); + if(p->off < 0) + o = OSUB; + } + + switch(p->alg) { + case 0: + switch(p->arg) { + case 1: + shiftit(n->type, &nods, n); + break; + case 15: + case 25: + case 27: + case 45: + case 81: + genmuladd(n, n, m1(p->arg), n); + /* fall thru */ + case 3: + case 5: + case 9: + genmuladd(n, n, m0(p->arg), n); + shiftit(n->type, &nods, n); + break; + default: + goto bad; + } + if(p->neg == 1) + gins(ANEGL, Z, n); + break; + case 1: + switch(p->arg) { + case 1: + gmove(n, &nod); + shiftit(n->type, &nods, &nod); + break; + case 3: + case 5: + case 9: + genmuladd(&nod, n, m0(p->arg), n); + shiftit(n->type, &nods, &nod); + break; + default: + goto bad; + } + if(p->neg) + gopcode(o, n->type, &nod, n); + else { + gopcode(o, n->type, n, &nod); + gmove(&nod, n); + } + break; + case 2: + genmuladd(&nod, n, m0(p->off), n); + shiftit(n->type, &nods, n); + goto comop; + case 3: + genmuladd(&nod, n, m0(p->off), n); + shiftit(n->type, &nods, n); + genmuladd(n, &nod, m2(p->off), n); + break; + case 4: + genmuladd(&nod, n, m0(p->off), nodconst(0)); + shiftit(n->type, &nods, n); + goto comop; + default: + diag(Z, "bad mul alg"); + break; + comop: + if(p->neg) { + gopcode(o, n->type, n, &nod); + gmove(&nod, n); + } + else + gopcode(o, n->type, &nod, n); + } + + if(p->alg > 0) + regfree(&nod); + + return 1; + +bad: + diag(Z, "mulgen botch"); + return 1; +} + +void +mulgen(Type *t, Node *r, Node *n) +{ + if(!mulgen1(r->vconst, n)) + gopcode(OMUL, t, r, n); +} diff --git a/src/cmd/6c/peep.c b/src/cmd/6c/peep.c new file mode 100644 index 0000000000..77c034b07b --- /dev/null +++ b/src/cmd/6c/peep.c @@ -0,0 +1,876 @@ +// Inferno utils/6c/peep.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +static int +needc(Prog *p) +{ + while(p != P) { + switch(p->as) { + case AADCL: + case AADCQ: + case ASBBL: + case ASBBQ: + case ARCRL: + case ARCRQ: + return 1; + case AADDL: + case AADDQ: + case ASUBL: + case ASUBQ: + case AJMP: + case ARET: + case ACALL: + return 0; + default: + if(p->to.type == D_BRANCH) + return 0; + } + p = p->link; + } + return 0; +} + +static Reg* +rnops(Reg *r) +{ + Prog *p; + Reg *r1; + + if(r != R) + for(;;){ + p = r->prog; + if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE) + break; + r1 = uniqs(r); + if(r1 == R) + break; + r = r1; + } + return r; +} + +void +peep(void) +{ + Reg *r, *r1, *r2; + Prog *p, *p1; + int t; + + /* + * complete R structure + */ + t = 0; + for(r=firstr; r!=R; r=r1) { + r1 = r->link; + if(r1 == R) + break; + p = r->prog->link; + while(p != r1->prog) + switch(p->as) { + default: + r2 = rega(); + r->link = r2; + r2->link = r1; + + r2->prog = p; + r2->p1 = r; + r->s1 = r2; + r2->s1 = r1; + r1->p1 = r2; + + r = r2; + t++; + + case ADATA: + case AGLOBL: + case ANAME: + case ASIGNAME: + p = p->link; + } + } + + pc = 0; /* speculating it won't kill */ + +loop1: + + t = 0; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + case AMOVL: + case AMOVQ: + case AMOVSS: + case AMOVSD: + if(regtyp(&p->to)) + if(regtyp(&p->from)) { + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + break; + + case AMOVBLZX: + case AMOVWLZX: + case AMOVBLSX: + case AMOVWLSX: + if(regtyp(&p->to)) { + r1 = rnops(uniqs(r)); + if(r1 != R) { + p1 = r1->prog; + if(p->as == p1->as && p->to.type == p1->from.type){ + p1->as = AMOVL; + t++; + } + } + } + break; + + case AMOVBQSX: + case AMOVBQZX: + case AMOVWQSX: + case AMOVWQZX: + case AMOVLQSX: + case AMOVLQZX: + if(regtyp(&p->to)) { + r1 = rnops(uniqs(r)); + if(r1 != R) { + p1 = r1->prog; + if(p->as == p1->as && p->to.type == p1->from.type){ + p1->as = AMOVQ; + t++; + } + } + } + break; + + case AADDL: + case AADDQ: + case AADDW: + if(p->from.type != D_CONST || needc(p->link)) + break; + if(p->from.offset == -1){ + if(p->as == AADDQ) + p->as = ADECQ; + else if(p->as == AADDL) + p->as = ADECL; + else + p->as = ADECW; + p->from = zprog.from; + } + else if(p->from.offset == 1){ + if(p->as == AADDQ) + p->as = AINCQ; + else if(p->as == AADDL) + p->as = AINCL; + else + p->as = AINCW; + p->from = zprog.from; + } + break; + + case ASUBL: + case ASUBQ: + case ASUBW: + if(p->from.type != D_CONST || needc(p->link)) + break; + if(p->from.offset == -1) { + if(p->as == ASUBQ) + p->as = AINCQ; + else if(p->as == ASUBL) + p->as = AINCL; + else + p->as = AINCW; + p->from = zprog.from; + } + else if(p->from.offset == 1){ + if(p->as == ASUBQ) + p->as = ADECQ; + else if(p->as == ASUBL) + p->as = ADECL; + else + p->as = ADECW; + p->from = zprog.from; + } + break; + } + } + if(t) + goto loop1; +} + +void +excise(Reg *r) +{ + Prog *p; + + p = r->prog; + p->as = ANOP; + p->from = zprog.from; + p->to = zprog.to; +} + +Reg* +uniqp(Reg *r) +{ + Reg *r1; + + r1 = r->p1; + if(r1 == R) { + r1 = r->p2; + if(r1 == R || r1->p2link != R) + return R; + } else + if(r->p2 != R) + return R; + return r1; +} + +Reg* +uniqs(Reg *r) +{ + Reg *r1; + + r1 = r->s1; + if(r1 == R) { + r1 = r->s2; + if(r1 == R) + return R; + } else + if(r->s2 != R) + return R; + return r1; +} + +int +regtyp(Adr *a) +{ + int t; + + t = a->type; + if(t >= D_AX && t <= D_R15) + return 1; + if(t >= D_X0 && t <= D_X0+15) + return 1; + return 0; +} + +/* + * the idea is to substitute + * one register for another + * from one MOV to another + * MOV a, R0 + * ADD b, R0 / no use of R1 + * MOV R0, R1 + * would be converted to + * MOV a, R1 + * ADD b, R1 + * MOV R1, R0 + * hopefully, then the former or latter MOV + * will be eliminated by copy propagation. + */ +int +subprop(Reg *r0) +{ + Prog *p; + Adr *v1, *v2; + Reg *r; + int t; + + p = r0->prog; + v1 = &p->from; + if(!regtyp(v1)) + return 0; + v2 = &p->to; + if(!regtyp(v2)) + return 0; + for(r=uniqp(r0); r!=R; r=uniqp(r)) { + if(uniqs(r) == R) + break; + p = r->prog; + switch(p->as) { + case ACALL: + return 0; + + case AIMULL: + case AIMULQ: + case AIMULW: + if(p->to.type != D_NONE) + break; + + case ADIVB: + case ADIVL: + case ADIVQ: + case ADIVW: + case AIDIVB: + case AIDIVL: + case AIDIVQ: + case AIDIVW: + case AIMULB: + case AMULB: + case AMULL: + case AMULQ: + case AMULW: + + case AROLB: + case AROLL: + case AROLQ: + case AROLW: + case ARORB: + case ARORL: + case ARORQ: + case ARORW: + case ASALB: + case ASALL: + case ASALQ: + case ASALW: + case ASARB: + case ASARL: + case ASARQ: + case ASARW: + case ASHLB: + case ASHLL: + case ASHLQ: + case ASHLW: + case ASHRB: + case ASHRL: + case ASHRQ: + case ASHRW: + + case AREP: + case AREPN: + + case ACWD: + case ACDQ: + case ACQO: + + case AMOVSL: + case AMOVSQ: + return 0; + + case AMOVL: + case AMOVQ: + if(p->to.type == v1->type) + goto gotit; + break; + } + if(copyau(&p->from, v2) || + copyau(&p->to, v2)) + break; + if(copysub(&p->from, v1, v2, 0) || + copysub(&p->to, v1, v2, 0)) + break; + } + return 0; + +gotit: + copysub(&p->to, v1, v2, 1); + if(debug['P']) { + print("gotit: %D->%D\n%P", v1, v2, r->prog); + if(p->from.type == v2->type) + print(" excise"); + print("\n"); + } + for(r=uniqs(r); r!=r0; r=uniqs(r)) { + p = r->prog; + copysub(&p->from, v1, v2, 1); + copysub(&p->to, v1, v2, 1); + if(debug['P']) + print("%P\n", r->prog); + } + t = v1->type; + v1->type = v2->type; + v2->type = t; + if(debug['P']) + print("%P last\n", r->prog); + return 1; +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success + */ +int +copyprop(Reg *r0) +{ + Prog *p; + Adr *v1, *v2; + Reg *r; + + p = r0->prog; + v1 = &p->from; + v2 = &p->to; + if(copyas(v1, v2)) + return 1; + for(r=firstr; r!=R; r=r->link) + r->active = 0; + return copy1(v1, v2, r0->s1, 0); +} + +int +copy1(Adr *v1, Adr *v2, Reg *r, int f) +{ + int t; + Prog *p; + + if(r->active) { + if(debug['P']) + print("act set; return 1\n"); + return 1; + } + r->active = 1; + if(debug['P']) + print("copy %D->%D f=%d\n", v1, v2, f); + for(; r != R; r = r->s1) { + p = r->prog; + if(debug['P']) + print("%P", p); + if(!f && uniqp(r) == R) { + f = 1; + if(debug['P']) + print("; merge; f=%d", f); + } + t = copyu(p, v2, A); + switch(t) { + case 2: /* rar, cant split */ + if(debug['P']) + print("; %D rar; return 0\n", v2); + return 0; + + case 3: /* set */ + if(debug['P']) + print("; %D set; return 1\n", v2); + return 1; + + case 1: /* used, substitute */ + case 4: /* use and set */ + if(f) { + if(!debug['P']) + return 0; + if(t == 4) + print("; %D used+set and f=%d; return 0\n", v2, f); + else + print("; %D used and f=%d; return 0\n", v2, f); + return 0; + } + if(copyu(p, v2, v1)) { + if(debug['P']) + print("; sub fail; return 0\n"); + return 0; + } + if(debug['P']) + print("; sub %D/%D", v2, v1); + if(t == 4) { + if(debug['P']) + print("; %D used+set; return 1\n", v2); + return 1; + } + break; + } + if(!f) { + t = copyu(p, v1, A); + if(!f && (t == 2 || t == 3 || t == 4)) { + f = 1; + if(debug['P']) + print("; %D set and !f; f=%d", v1, f); + } + } + if(debug['P']) + print("\n"); + if(r->s2) + if(!copy1(v1, v2, r->s2, f)) + return 0; + } + return 1; +} + +/* + * return + * 1 if v only used (and substitute), + * 2 if read-alter-rewrite + * 3 if set + * 4 if set and used + * 0 otherwise (not touched) + */ +int +copyu(Prog *p, Adr *v, Adr *s) +{ + + switch(p->as) { + + default: + if(debug['P']) + print("unknown op %A\n", p->as); + /* SBBL; ADCL; FLD1; SAHF */ + return 2; + + + case ANEGB: + case ANEGW: + case ANEGL: + case ANEGQ: + case ANOTB: + case ANOTW: + case ANOTL: + case ANOTQ: + if(copyas(&p->to, v)) + return 2; + break; + + case ALEAL: /* lhs addr, rhs store */ + case ALEAQ: + if(copyas(&p->from, v)) + return 2; + + + case ANOP: /* rhs store */ + case AMOVL: + case AMOVQ: + case AMOVBLSX: + case AMOVBLZX: + case AMOVBQSX: + case AMOVBQZX: + case AMOVLQSX: + case AMOVLQZX: + case AMOVWLSX: + case AMOVWLZX: + case AMOVWQSX: + case AMOVWQZX: + + case AMOVSS: + case AMOVSD: + case ACVTSD2SL: + case ACVTSD2SQ: + case ACVTSD2SS: + case ACVTSL2SD: + case ACVTSL2SS: + case ACVTSQ2SD: + case ACVTSQ2SS: + case ACVTSS2SD: + case ACVTSS2SL: + case ACVTSS2SQ: + case ACVTTSD2SL: + case ACVTTSD2SQ: + case ACVTTSS2SL: + case ACVTTSS2SQ: + if(copyas(&p->to, v)) { + if(s != A) + return copysub(&p->from, v, s, 1); + if(copyau(&p->from, v)) + return 4; + return 3; + } + goto caseread; + + case AROLB: + case AROLL: + case AROLQ: + case AROLW: + case ARORB: + case ARORL: + case ARORQ: + case ARORW: + case ASALB: + case ASALL: + case ASALQ: + case ASALW: + case ASARB: + case ASARL: + case ASARQ: + case ASARW: + case ASHLB: + case ASHLL: + case ASHLQ: + case ASHLW: + case ASHRB: + case ASHRL: + case ASHRQ: + case ASHRW: + if(copyas(&p->to, v)) + return 2; + if(copyas(&p->from, v)) + if(p->from.type == D_CX) + return 2; + goto caseread; + + case AADDB: /* rhs rar */ + case AADDL: + case AADDQ: + case AADDW: + case AANDB: + case AANDL: + case AANDQ: + case AANDW: + case ADECL: + case ADECQ: + case ADECW: + case AINCL: + case AINCQ: + case AINCW: + case ASUBB: + case ASUBL: + case ASUBQ: + case ASUBW: + case AORB: + case AORL: + case AORQ: + case AORW: + case AXORB: + case AXORL: + case AXORQ: + case AXORW: + case AMOVB: + case AMOVW: + + case AADDSD: + case AADDSS: + case ACMPSD: + case ACMPSS: + case ADIVSD: + case ADIVSS: + case AMAXSD: + case AMAXSS: + case AMINSD: + case AMINSS: + case AMULSD: + case AMULSS: + case ARCPSS: + case ARSQRTSS: + case ASQRTSD: + case ASQRTSS: + case ASUBSD: + case ASUBSS: + case AXORPD: + if(copyas(&p->to, v)) + return 2; + goto caseread; + + case ACMPL: /* read only */ + case ACMPW: + case ACMPB: + case ACMPQ: + + case ACOMISD: + case ACOMISS: + case AUCOMISD: + case AUCOMISS: + caseread: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + return copysub(&p->to, v, s, 1); + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + break; + + case AJGE: /* no reference */ + case AJNE: + case AJLE: + case AJEQ: + case AJHI: + case AJLS: + case AJMI: + case AJPL: + case AJGT: + case AJLT: + case AJCC: + case AJCS: + + case AADJSP: + case AWAIT: + case ACLD: + break; + + case AIMULL: + case AIMULQ: + case AIMULW: + if(p->to.type != D_NONE) { + if(copyas(&p->to, v)) + return 2; + goto caseread; + } + + case ADIVB: + case ADIVL: + case ADIVQ: + case ADIVW: + case AIDIVB: + case AIDIVL: + case AIDIVQ: + case AIDIVW: + case AIMULB: + case AMULB: + case AMULL: + case AMULQ: + case AMULW: + + case ACWD: + case ACDQ: + case ACQO: + if(v->type == D_AX || v->type == D_DX) + return 2; + goto caseread; + + case AMOVSL: + case AMOVSQ: + case AREP: + case AREPN: + if(v->type == D_CX || v->type == D_DI || v->type == D_SI) + return 2; + goto caseread; + + case AJMP: /* funny */ + if(s != A) { + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->to, v)) + return 1; + return 0; + + case ARET: /* funny */ + if(v->type == REGRET || v->type == FREGRET) + return 2; + if(s != A) + return 1; + return 3; + + case ACALL: /* funny */ + if(REGEXT && v->type <= REGEXT && v->type > exregoffset) + return 2; + if(REGARG && v->type == REGARG) + return 2; + + if(s != A) { + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->to, v)) + return 4; + return 3; + + case ATEXT: /* funny */ + if(REGARG && v->type == REGARG) + return 3; + return 0; + } + return 0; +} + +/* + * direct reference, + * could be set/use depending on + * semantics + */ +int +copyas(Adr *a, Adr *v) +{ + if(a->type != v->type) + return 0; + if(regtyp(v)) + return 1; + if(v->type == D_AUTO || v->type == D_PARAM) + if(v->offset == a->offset) + return 1; + return 0; +} + +/* + * either direct or indirect + */ +int +copyau(Adr *a, Adr *v) +{ + + if(copyas(a, v)) + return 1; + if(regtyp(v)) { + if(a->type-D_INDIR == v->type) + return 1; + if(a->index == v->type) + return 1; + } + return 0; +} + +/* + * substitute s for v in a + * return failure to substitute + */ +int +copysub(Adr *a, Adr *v, Adr *s, int f) +{ + int t; + + if(copyas(a, v)) { + t = s->type; + if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) { + if(f) + a->type = t; + } + return 0; + } + if(regtyp(v)) { + t = v->type; + if(a->type == t+D_INDIR) { + if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE) + return 1; /* can't use BP-base with index */ + if(f) + a->type = s->type+D_INDIR; +// return 0; + } + if(a->index == t) { + if(f) + a->index = s->type; + return 0; + } + return 0; + } + return 0; +} diff --git a/src/cmd/6c/pgen.c b/src/cmd/6c/pgen.c new file mode 100644 index 0000000000..ae0b1b40cd --- /dev/null +++ b/src/cmd/6c/pgen.c @@ -0,0 +1,550 @@ +// Inferno utils/6c/sgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +void +codgen(Node *n, Node *nn) +{ + Prog *sp; + Node *n1, nod, nod1; + + cursafe = 0; + curarg = 0; + maxargsafe = 0; + + /* + * isolate name + */ + for(n1 = nn;; n1 = n1->left) { + if(n1 == Z) { + diag(nn, "cant find function name"); + return; + } + if(n1->op == ONAME) + break; + } + nearln = nn->lineno; + gpseudo(ATEXT, n1->sym, nodconst(stkoff)); + sp = p; + + /* + * isolate first argument + */ + if(REGARG) { + if(typecmplx[thisfn->link->etype]) { + nod1 = *nodret->left; + nodreg(&nod, &nod1, REGARG); + gmove(&nod, &nod1); + } else + if(firstarg && typeword[firstargtype->etype]) { + nod1 = *nodret->left; + nod1.sym = firstarg; + nod1.type = firstargtype; + nod1.xoffset = align(0, firstargtype, Aarg1); + nod1.etype = firstargtype->etype; + nodreg(&nod, &nod1, REGARG); + gmove(&nod, &nod1); + } + } + + canreach = 1; + warnreach = 1; + gen(n); + if(canreach && thisfn->link->etype != TVOID) + warn(Z, "no return at end of function: %s", n1->sym->name); + noretval(3); + gbranch(ORETURN); + + if(!debug['N'] || debug['R'] || debug['P']) + regopt(sp); + + if(thechar=='6' || thechar=='7') /* [sic] */ + maxargsafe = xround(maxargsafe, 8); + sp->to.offset += maxargsafe; +} + +void +supgen(Node *n) +{ + int owarn; + long spc; + Prog *sp; + + if(n == Z) + return; + suppress++; + owarn = warnreach; + warnreach = 0; + spc = pc; + sp = lastp; + gen(n); + lastp = sp; + pc = spc; + sp->link = nil; + suppress--; + warnreach = owarn; +} + +void +gen(Node *n) +{ + Node *l, nod; + Prog *sp, *spc, *spb; + Case *cn; + long sbc, scc; + int snbreak, sncontin; + int f, o, oldreach; + +loop: + if(n == Z) + return; + nearln = n->lineno; + o = n->op; + if(debug['G']) + if(o != OLIST) + print("%L %O\n", nearln, o); + + if(!canreach) { + switch(o) { + case OLABEL: + case OCASE: + case OLIST: + case OBREAK: + case OFOR: + case OWHILE: + case ODWHILE: + /* all handled specially - see switch body below */ + break; + default: + if(warnreach) { + warn(n, "unreachable code %O", o); + warnreach = 0; + } + } + } + + switch(o) { + + default: + complex(n); + cgen(n, Z); + break; + + case OLIST: + gen(n->left); + + rloop: + n = n->right; + goto loop; + + case ORETURN: + canreach = 0; + warnreach = !suppress; + complex(n); + if(n->type == T) + break; + l = n->left; + if(l == Z) { + noretval(3); + gbranch(ORETURN); + break; + } + if(typecmplx[n->type->etype]) { + sugen(l, nodret, n->type->width); + noretval(3); + gbranch(ORETURN); + break; + } + regret(&nod, n); + cgen(l, &nod); + regfree(&nod); + if(typefd[n->type->etype]) + noretval(1); + else + noretval(2); + gbranch(ORETURN); + break; + + case OLABEL: + canreach = 1; + l = n->left; + if(l) { + l->pc = pc; + if(l->label) + patch(l->label, pc); + } + gbranch(OGOTO); /* prevent self reference in reg */ + patch(p, pc); + goto rloop; + + case OGOTO: + canreach = 0; + warnreach = !suppress; + n = n->left; + if(n == Z) + return; + if(n->complex == 0) { + diag(Z, "label undefined: %s", n->sym->name); + return; + } + if(suppress) + return; + gbranch(OGOTO); + if(n->pc) { + patch(p, n->pc); + return; + } + if(n->label) + patch(n->label, pc-1); + n->label = p; + return; + + case OCASE: + canreach = 1; + l = n->left; + if(cases == C) + diag(n, "case/default outside a switch"); + if(l == Z) { + cas(); + cases->val = 0; + cases->def = 1; + cases->label = pc; + cases->isv = 0; + goto rloop; + } + complex(l); + if(l->type == T) + goto rloop; + if(l->op == OCONST) + if(typeword[l->type->etype] && l->type->etype != TIND) { + cas(); + cases->val = l->vconst; + cases->def = 0; + cases->label = pc; + cases->isv = typev[l->type->etype]; + goto rloop; + } + diag(n, "case expression must be integer constant"); + goto rloop; + + case OSWITCH: + l = n->left; + complex(l); + if(l->type == T) + break; + if(!typeword[l->type->etype] || l->type->etype == TIND) { + diag(n, "switch expression must be integer"); + break; + } + + gbranch(OGOTO); /* entry */ + sp = p; + + cn = cases; + cases = C; + cas(); + + sbc = breakpc; + breakpc = pc; + snbreak = nbreak; + nbreak = 0; + gbranch(OGOTO); + spb = p; + + gen(n->right); /* body */ + if(canreach){ + gbranch(OGOTO); + patch(p, breakpc); + nbreak++; + } + + patch(sp, pc); + regalloc(&nod, l, Z); + /* always signed */ + if(typev[l->type->etype]) + nod.type = types[TVLONG]; + else + nod.type = types[TLONG]; + cgen(l, &nod); + doswit(&nod); + regfree(&nod); + patch(spb, pc); + + cases = cn; + breakpc = sbc; + canreach = nbreak!=0; + if(canreach == 0) + warnreach = !suppress; + nbreak = snbreak; + break; + + case OWHILE: + case ODWHILE: + l = n->left; + gbranch(OGOTO); /* entry */ + sp = p; + + scc = continpc; + continpc = pc; + gbranch(OGOTO); + spc = p; + + sbc = breakpc; + breakpc = pc; + snbreak = nbreak; + nbreak = 0; + gbranch(OGOTO); + spb = p; + + patch(spc, pc); + if(n->op == OWHILE) + patch(sp, pc); + bcomplex(l, Z); /* test */ + patch(p, breakpc); + if(l->op != OCONST || vconst(l) == 0) + nbreak++; + + if(n->op == ODWHILE) + patch(sp, pc); + gen(n->right); /* body */ + gbranch(OGOTO); + patch(p, continpc); + + patch(spb, pc); + continpc = scc; + breakpc = sbc; + canreach = nbreak!=0; + if(canreach == 0) + warnreach = !suppress; + nbreak = snbreak; + break; + + case OFOR: + l = n->left; + if(!canreach && l->right->left && warnreach) { + warn(n, "unreachable code FOR"); + warnreach = 0; + } + gen(l->right->left); /* init */ + gbranch(OGOTO); /* entry */ + sp = p; + + /* + * if there are no incoming labels in the + * body and the top's not reachable, warn + */ + if(!canreach && warnreach && deadheads(n)) { + warn(n, "unreachable code %O", o); + warnreach = 0; + } + + scc = continpc; + continpc = pc; + gbranch(OGOTO); + spc = p; + + sbc = breakpc; + breakpc = pc; + snbreak = nbreak; + nbreak = 0; + sncontin = ncontin; + ncontin = 0; + gbranch(OGOTO); + spb = p; + + patch(spc, pc); + gen(l->right->right); /* inc */ + patch(sp, pc); + if(l->left != Z) { /* test */ + bcomplex(l->left, Z); + patch(p, breakpc); + if(l->left->op != OCONST || vconst(l->left) == 0) + nbreak++; + } + canreach = 1; + gen(n->right); /* body */ + if(canreach){ + gbranch(OGOTO); + patch(p, continpc); + ncontin++; + } + if(!ncontin && l->right->right && warnreach) { + warn(l->right->right, "unreachable FOR inc"); + warnreach = 0; + } + + patch(spb, pc); + continpc = scc; + breakpc = sbc; + canreach = nbreak!=0; + if(canreach == 0) + warnreach = !suppress; + nbreak = snbreak; + ncontin = sncontin; + break; + + case OCONTINUE: + if(continpc < 0) { + diag(n, "continue not in a loop"); + break; + } + gbranch(OGOTO); + patch(p, continpc); + ncontin++; + canreach = 0; + warnreach = !suppress; + break; + + case OBREAK: + if(breakpc < 0) { + diag(n, "break not in a loop"); + break; + } + /* + * Don't complain about unreachable break statements. + * There are breaks hidden in yacc's output and some people + * write return; break; in their switch statements out of habit. + * However, don't confuse the analysis by inserting an + * unreachable reference to breakpc either. + */ + if(!canreach) + break; + gbranch(OGOTO); + patch(p, breakpc); + nbreak++; + canreach = 0; + warnreach = !suppress; + break; + + case OIF: + l = n->left; + if(bcomplex(l, n->right)) { + if(typefd[l->type->etype]) + f = !l->fconst; + else + f = !l->vconst; + if(debug['c']) + print("%L const if %s\n", nearln, f ? "false" : "true"); + if(f) { + canreach = 1; + supgen(n->right->left); + oldreach = canreach; + canreach = 1; + gen(n->right->right); + /* + * treat constant ifs as regular ifs for + * reachability warnings. + */ + if(!canreach && oldreach && debug['w'] < 2) + warnreach = 0; + } + else { + canreach = 1; + gen(n->right->left); + oldreach = canreach; + canreach = 1; + supgen(n->right->right); + /* + * treat constant ifs as regular ifs for + * reachability warnings. + */ + if(!oldreach && canreach && debug['w'] < 2) + warnreach = 0; + canreach = oldreach; + } + } + else { + sp = p; + canreach = 1; + if(n->right->left != Z) + gen(n->right->left); + oldreach = canreach; + canreach = 1; + if(n->right->right != Z) { + gbranch(OGOTO); + patch(sp, pc); + sp = p; + gen(n->right->right); + } + patch(sp, pc); + canreach = canreach || oldreach; + if(canreach == 0) + warnreach = !suppress; + } + break; + + case OSET: + case OUSED: + usedset(n->left, o); + break; + } +} + +void +usedset(Node *n, int o) +{ + if(n->op == OLIST) { + usedset(n->left, o); + usedset(n->right, o); + return; + } + complex(n); + switch(n->op) { + case OADDR: /* volatile */ + gins(ANOP, n, Z); + break; + case ONAME: + if(o == OSET) + gins(ANOP, Z, n); + else + gins(ANOP, n, Z); + break; + } +} + +int +bcomplex(Node *n, Node *c) +{ + + complex(n); + if(n->type != T) + if(tcompat(n, T, n->type, tnot)) + n->type = T; + if(n->type == T) { + gbranch(OGOTO); + return 0; + } + if(c != Z && n->op == OCONST && deadheads(c)) + return 1; + bool64(n); + boolgen(n, 1, Z); + return 0; +} diff --git a/src/cmd/6c/pswt.c b/src/cmd/6c/pswt.c new file mode 100644 index 0000000000..f4149f17b3 --- /dev/null +++ b/src/cmd/6c/pswt.c @@ -0,0 +1,168 @@ +// Inferno utils/6c/swt.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +int +swcmp(const void *a1, const void *a2) +{ + C1 *p1, *p2; + + p1 = (C1*)a1; + p2 = (C1*)a2; + if(p1->val < p2->val) + return -1; + return p1->val > p2->val; +} + +void +doswit(Node *n) +{ + Case *c; + C1 *q, *iq; + long def, nc, i, isv; + + def = 0; + nc = 0; + isv = 0; + for(c = cases; c->link != C; c = c->link) { + if(c->def) { + if(def) + diag(n, "more than one default in switch"); + def = c->label; + continue; + } + isv |= c->isv; + nc++; + } + if(isv && !typev[n->type->etype]) + warn(n, "32-bit switch expression with 64-bit case constant"); + + iq = alloc(nc*sizeof(C1)); + q = iq; + for(c = cases; c->link != C; c = c->link) { + if(c->def) + continue; + q->label = c->label; + if(isv) + q->val = c->val; + else + q->val = (long)c->val; /* cast ensures correct value for 32-bit switch on 64-bit architecture */ + q++; + } + qsort(iq, nc, sizeof(C1), swcmp); + if(debug['W']) + for(i=0; ilink = cases; + cases = c; +} + +long +outlstring(ushort *s, long n) +{ + char buf[2]; + int c; + long r; + + if(suppress) + return nstring; + while(nstring & 1) + outstring("", 1); + r = nstring; + while(n > 0) { + c = *s++; + if(align(0, types[TCHAR], Aarg1)) { + buf[0] = c>>8; + buf[1] = c; + } else { + buf[0] = c; + buf[1] = c>>8; + } + outstring(buf, 2); + n -= sizeof(ushort); + } + return r; +} + +void +nullwarn(Node *l, Node *r) +{ + warn(Z, "result of operation not used"); + if(l != Z) + cgen(l, Z); + if(r != Z) + cgen(r, Z); +} + +void +ieeedtod(Ieee *ieee, double native) +{ + double fr, ho, f; + int exp; + + if(native < 0) { + ieeedtod(ieee, -native); + ieee->h |= 0x80000000L; + return; + } + if(native == 0) { + ieee->l = 0; + ieee->h = 0; + return; + } + fr = frexp(native, &exp); + f = 2097152L; /* shouldnt use fp constants here */ + fr = modf(fr*f, &ho); + ieee->h = ho; + ieee->h &= 0xfffffL; + ieee->h |= (exp+1022L) << 20; + f = 65536L; + fr = modf(fr*f, &ho); + ieee->l = ho; + ieee->l <<= 16; + ieee->l |= (long)(fr*f); +} diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c new file mode 100644 index 0000000000..a03d1ca47b --- /dev/null +++ b/src/cmd/6c/reg.c @@ -0,0 +1,1386 @@ +// Inferno utils/6c/reg.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +Reg* +rega(void) +{ + Reg *r; + + r = freer; + if(r == R) { + r = alloc(sizeof(*r)); + } else + freer = r->link; + + *r = zreg; + return r; +} + +int +rcmp(const void *a1, const void *a2) +{ + Rgn *p1, *p2; + int c1, c2; + + p1 = (Rgn*)a1; + p2 = (Rgn*)a2; + c1 = p2->cost; + c2 = p1->cost; + if(c1 -= c2) + return c1; + return p2->varno - p1->varno; +} + +void +regopt(Prog *p) +{ + Reg *r, *r1, *r2; + Prog *p1; + int i, z; + long initpc, val, npc; + ulong vreg; + Bits bit; + struct + { + long m; + long c; + Reg* p; + } log5[6], *lp; + + firstr = R; + lastr = R; + nvar = 0; + regbits = RtoB(D_SP) | RtoB(D_AX) | RtoB(D_X0); + for(z=0; 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/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c new file mode 100644 index 0000000000..63a86ba2db --- /dev/null +++ b/src/cmd/6c/sgen.c @@ -0,0 +1,465 @@ +// Inferno utils/6c/sgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +void +noretval(int n) +{ + + if(n & 1) { + gins(ANOP, Z, Z); + p->to.type = REGRET; + } + if(n & 2) { + gins(ANOP, Z, Z); + p->to.type = FREGRET; + } +} + +/* welcome to commute */ +static void +commute(Node *n) +{ + Node *l, *r; + + l = n->left; + r = n->right; + if(r->complex > l->complex) { + n->left = r; + n->right = l; + } +} + +void +indexshift(Node *n) +{ + int g; + + if(!typechlpv[n->type->etype]) + return; + simplifyshift(n); + if(n->op == OASHL && n->right->op == OCONST){ + g = vconst(n->right); + if(g >= 0 && g <= 3) + n->addable = 7; + } +} + +/* + * calculate addressability as follows + * NAME ==> 10/11 name+value(SB/SP) + * REGISTER ==> 12 register + * CONST ==> 20 $value + * *(20) ==> 21 value + * &(10) ==> 13 $name+value(SB) + * &(11) ==> 1 $name+value(SP) + * (13) + (20) ==> 13 fold constants + * (1) + (20) ==> 1 fold constants + * *(13) ==> 10 back to name + * *(1) ==> 11 back to name + * + * (20) * (X) ==> 7 multiplier in indexing + * (X,7) + (13,1) ==> 8 adder in indexing (addresses) + * (8) ==> &9(OINDEX) index, almost addressable + * + * calculate complexity (number of registers) + */ +void +xcom(Node *n) +{ + Node *l, *r; + int g; + + if(n == Z) + return; + l = n->left; + r = n->right; + n->complex = 0; + n->addable = 0; + switch(n->op) { + case OCONST: + n->addable = 20; + break; + + case ONAME: + n->addable = 10; + if(n->class == CPARAM || n->class == CAUTO) + n->addable = 11; + break; + + case OREGISTER: + n->addable = 12; + break; + + case OINDREG: + n->addable = 12; + break; + + case OADDR: + xcom(l); + if(l->addable == 10) + n->addable = 13; + else + if(l->addable == 11) + n->addable = 1; + break; + + case OADD: + xcom(l); + xcom(r); + if(n->type->etype != TIND) + break; + + switch(r->addable) { + case 20: + switch(l->addable) { + case 1: + case 13: + commadd: + l->type = n->type; + *n = *l; + l = new(0, Z, Z); + *l = *(n->left); + l->xoffset += r->vconst; + n->left = l; + r = n->right; + goto brk; + } + break; + + case 1: + case 13: + case 10: + case 11: + /* l is the base, r is the index */ + if(l->addable != 20) + n->addable = 8; + break; + } + switch(l->addable) { + case 20: + switch(r->addable) { + case 13: + case 1: + r = n->left; + l = n->right; + n->left = l; + n->right = r; + goto commadd; + } + break; + + case 13: + case 1: + case 10: + case 11: + /* r is the base, l is the index */ + if(r->addable != 20) + n->addable = 8; + break; + } + if(n->addable == 8 && !side(n)) { + indx(n); + l = new1(OINDEX, idx.basetree, idx.regtree); + l->scale = idx.scale; + l->addable = 9; + l->complex = l->right->complex; + l->type = l->left->type; + n->op = OADDR; + n->left = l; + n->right = Z; + n->addable = 8; + break; + } + break; + + case OINDEX: + xcom(l); + xcom(r); + n->addable = 9; + break; + + case OIND: + xcom(l); + if(l->op == OADDR) { + l = l->left; + l->type = n->type; + *n = *l; + return; + } + switch(l->addable) { + case 20: + n->addable = 21; + break; + case 1: + n->addable = 11; + break; + case 13: + n->addable = 10; + break; + } + break; + + case OASHL: + xcom(l); + xcom(r); + indexshift(n); + break; + + case OMUL: + case OLMUL: + xcom(l); + xcom(r); + g = vlog(l); + if(g >= 0) { + n->left = r; + n->right = l; + l = r; + r = n->right; + } + g = vlog(r); + if(g >= 0) { + n->op = OASHL; + r->vconst = g; + r->type = types[TINT]; + indexshift(n); + break; + } + commute(n); + break; + + case OASLDIV: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OASLSHR; + r->vconst = g; + r->type = types[TINT]; + } + break; + + case OLDIV: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OLSHR; + r->vconst = g; + r->type = types[TINT]; + indexshift(n); + break; + } + break; + + case OASLMOD: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OASAND; + r->vconst--; + } + break; + + case OLMOD: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OAND; + r->vconst--; + } + break; + + case OASMUL: + case OASLMUL: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OASASHL; + r->vconst = g; + } + break; + + case OLSHR: + case OASHR: + xcom(l); + xcom(r); + indexshift(n); + break; + + default: + if(l != Z) + xcom(l); + if(r != Z) + xcom(r); + break; + } +brk: + if(n->addable >= 10) + return; + if(l != Z) + n->complex = l->complex; + if(r != Z) { + if(r->complex == n->complex) + n->complex = r->complex+1; + else + if(r->complex > n->complex) + n->complex = r->complex; + } + if(n->complex == 0) + n->complex++; + + switch(n->op) { + + case OFUNC: + n->complex = FNX; + break; + + case OCAST: + if(l->type->etype == TUVLONG && typefd[n->type->etype]) + n->complex += 2; + break; + + case OLMOD: + case OMOD: + case OLMUL: + case OLDIV: + case OMUL: + case ODIV: + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + if(r->complex >= l->complex) { + n->complex = l->complex + 3; + if(r->complex > n->complex) + n->complex = r->complex; + } else { + n->complex = r->complex + 3; + if(l->complex > n->complex) + n->complex = l->complex; + } + break; + + case OLSHR: + case OASHL: + case OASHR: + case OASLSHR: + case OASASHL: + case OASASHR: + if(r->complex >= l->complex) { + n->complex = l->complex + 2; + if(r->complex > n->complex) + n->complex = r->complex; + } else { + n->complex = r->complex + 2; + if(l->complex > n->complex) + n->complex = l->complex; + } + break; + + case OADD: + case OXOR: + case OAND: + case OOR: + /* + * immediate operators, make const on right + */ + if(l->op == OCONST) { + n->left = r; + n->right = l; + } + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + /* + * compare operators, make const on left + */ + if(r->op == OCONST) { + n->left = r; + n->right = l; + n->op = invrel[relindex(n->op)]; + } + break; + } +} + +void +indx(Node *n) +{ + Node *l, *r; + + if(debug['x']) + prtree(n, "indx"); + + l = n->left; + r = n->right; + if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) { + n->right = l; + n->left = r; + l = r; + r = n->right; + } + if(l->addable != 7) { + idx.regtree = l; + idx.scale = 1; + } else + if(l->right->addable == 20) { + idx.regtree = l->left; + idx.scale = 1 << l->right->vconst; + } else + if(l->left->addable == 20) { + idx.regtree = l->right; + idx.scale = 1 << l->left->vconst; + } else + diag(n, "bad index"); + + idx.basetree = r; + if(debug['x']) { + print("scale = %d\n", idx.scale); + prtree(idx.regtree, "index"); + prtree(idx.basetree, "base"); + } +} diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c new file mode 100644 index 0000000000..5b2a6ca1eb --- /dev/null +++ b/src/cmd/6c/swt.c @@ -0,0 +1,566 @@ +// Inferno utils/6c/swt.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +void +swit1(C1 *q, int nc, long def, Node *n) +{ + C1 *r; + int i; + Prog *sp; + + if(nc < 5) { + for(i=0; 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); + + Bprint(&b, "x86-64\n"); + Bprint(&b, "!\n"); + + 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 = t->width; + if(w > SZ_VLONG) + w = SZ_VLONG; + break; + + case Aaut3: /* total allign of automatic */ + o = align(o, t, Ael1); + o = align(o, t, Ael2); + break; + } + o = xround(o, w); + if(debug['A']) + print("align %s %ld %T = %ld\n", bnames[op], i, t, o); + return o; +} + +long +maxround(long max, long v) +{ + v += SZ_VLONG-1; + if(v > max) + max = xround(v, SZ_VLONG); + return max; +} diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c new file mode 100644 index 0000000000..eb560f5f87 --- /dev/null +++ b/src/cmd/6c/txt.c @@ -0,0 +1,1546 @@ +// Inferno utils/6c/txt.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +void +ginit(void) +{ + int i; + Type *t; + + thechar = '6'; + thestring = "amd64"; + exregoffset = REGEXT; + exfregoffset = FREGEXT; + listinit(); + nstring = 0; + mnstring = 0; + nrathole = 0; + pc = 0; + breakpc = -1; + continpc = -1; + cases = C; + firstp = P; + lastp = P; + tfield = types[TINT]; + + typeword = typechlvp; + typecmplx = typesu; + + /* TO DO */ + memmove(typechlpv, typechlp, sizeof(typechlpv)); + typechlpv[TVLONG] = 1; + typechlpv[TUVLONG] = 1; + + zprog.link = P; + zprog.as = AGOK; + zprog.from.type = D_NONE; + zprog.from.index = D_NONE; + zprog.from.scale = 0; + zprog.to = zprog.from; + + lregnode.op = OREGISTER; + lregnode.class = CEXREG; + lregnode.reg = REGTMP; + lregnode.complex = 0; + lregnode.addable = 11; + lregnode.type = types[TLONG]; + + qregnode = lregnode; + qregnode.type = types[TVLONG]; + + constnode.op = OCONST; + constnode.class = CXXX; + constnode.complex = 0; + constnode.addable = 20; + constnode.type = types[TLONG]; + + vconstnode = constnode; + vconstnode.type = types[TVLONG]; + + fconstnode.op = OCONST; + fconstnode.class = CXXX; + fconstnode.complex = 0; + fconstnode.addable = 20; + fconstnode.type = types[TDOUBLE]; + + nodsafe = new(ONAME, Z, Z); + nodsafe->sym = slookup(".safe"); + nodsafe->type = types[TINT]; + nodsafe->etype = types[TINT]->etype; + nodsafe->class = CAUTO; + complex(nodsafe); + + t = typ(TARRAY, types[TCHAR]); + symrathole = slookup(".rathole"); + symrathole->class = CGLOBL; + symrathole->type = t; + + nodrat = new(ONAME, Z, Z); + nodrat->sym = symrathole; + nodrat->type = types[TIND]; + nodrat->etype = TVOID; + nodrat->class = CGLOBL; + complex(nodrat); + nodrat->type = t; + + nodret = new(ONAME, Z, Z); + nodret->sym = slookup(".ret"); + nodret->type = types[TIND]; + nodret->etype = TIND; + nodret->class = CPARAM; + nodret = new(OIND, nodret, Z); + complex(nodret); + + if(0) + com64init(); + + for(i=0; i= 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) +{ + if(REGARG == 0) + diag(n, "regaalloc1 and REGARG==0"); + nodreg(n, nn, REGARG); + reg[REGARG]++; + curarg = align(curarg, nn->type, Aarg1); + curarg = align(curarg, nn->type, Aarg2); + maxargsafe = maxround(maxargsafe, cursafe+curarg); +} + +void +regaalloc(Node *n, Node *nn) +{ + curarg = align(curarg, nn->type, Aarg1); + *n = *nn; + n->op = OINDREG; + n->reg = REGSP; + n->xoffset = curarg; + n->complex = 0; + n->addable = 20; + curarg = align(curarg, nn->type, Aarg2); + maxargsafe = maxround(maxargsafe, cursafe+curarg); +} + +void +regind(Node *n, Node *nn) +{ + + if(n->op != OREGISTER) { + diag(n, "regind not OREGISTER"); + return; + } + n->op = OINDREG; + n->type = nn->type; +} + +void +naddr(Node *n, Adr *a) +{ + long v; + + a->type = D_NONE; + if(n == Z) + return; + switch(n->op) { + default: + bad: + diag(n, "bad in naddr: %O %D", n->op, a); + break; + + case OREGISTER: + a->type = n->reg; + a->sym = S; + break; + + + case OIND: + naddr(n->left, a); + if(a->type >= D_AX && a->type <= D_R15) + a->type += D_INDIR; + else + if(a->type == D_CONST) + a->type = D_NONE+D_INDIR; + else + if(a->type == D_ADDR) { + a->type = a->index; + a->index = D_NONE; + } else + goto bad; + break; + + case OINDEX: + a->type = idx.ptr; + if(n->left->op == OADDR || n->left->op == OCONST) + naddr(n->left, a); + if(a->type >= D_AX && a->type <= D_R15) + a->type += D_INDIR; + else + if(a->type == D_CONST) + a->type = D_NONE+D_INDIR; + else + if(a->type == D_ADDR) { + a->type = a->index; + a->index = D_NONE; + } else + goto bad; + a->index = idx.reg; + a->scale = n->scale; + a->offset += n->xoffset; + break; + + case OINDREG: + a->type = n->reg+D_INDIR; + a->sym = S; + a->offset = n->xoffset; + break; + + case ONAME: + a->etype = n->etype; + a->type = D_STATIC; + a->sym = n->sym; + a->offset = n->xoffset; + if(n->class == CSTATIC) + break; + if(n->class == CEXTERN || n->class == CGLOBL) { + a->type = D_EXTERN; + break; + } + if(n->class == CAUTO) { + a->type = D_AUTO; + break; + } + if(n->class == CPARAM) { + a->type = D_PARAM; + break; + } + goto bad; + + case OCONST: + if(typefd[n->type->etype]) { + a->type = D_FCONST; + a->dval = n->fconst; + break; + } + a->sym = S; + a->type = D_CONST; + if(typev[n->type->etype] || n->type->etype == TIND) + a->offset = n->vconst; + else + a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG); + break; + + case OADDR: + naddr(n->left, a); + if(a->type >= D_INDIR) { + a->type -= D_INDIR; + break; + } + if(a->type == D_EXTERN || a->type == D_STATIC || + a->type == D_AUTO || a->type == D_PARAM) + if(a->index == D_NONE) { + a->index = a->type; + a->type = D_ADDR; + break; + } + goto bad; + + case OADD: + if(n->right->op == OCONST) { + v = n->right->vconst; + naddr(n->left, a); + } else + if(n->left->op == OCONST) { + v = n->left->vconst; + naddr(n->right, a); + } else + goto bad; + a->offset += v; + break; + + } +} + +void +gcmp(int op, Node *n, vlong val) +{ + Node *cn, nod; + + cn = nodgconst(val, n->type); + if(!immconst(cn)){ + regalloc(&nod, n, Z); + gmove(cn, &nod); + gopcode(op, n->type, n, &nod); + regfree(&nod); + }else + gopcode(op, n->type, n, cn); +} + +#define CASE(a,b) ((a<<8)|(b<<0)) + +void +gmove(Node *f, Node *t) +{ + int ft, tt, t64, a; + Node nod, nod1, nod2, nod3; + Prog *p1, *p2; + + ft = f->type->etype; + tt = t->type->etype; + t64 = tt == TVLONG || tt == TUVLONG || tt == TIND; + if(debug['M']) + print("gop: %O %O[%s],%O[%s]\n", OAS, + f->op, tnames[ft], t->op, tnames[tt]); + if(typefd[ft] && f->op == OCONST) { + /* TO DO: pick up special constants, possibly preloaded */ + if(f->fconst == 0.0){ + regalloc(&nod, t, t); + gins(AXORPD, &nod, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + } +/* + * load + */ + if(f->op == ONAME || f->op == OINDREG || + f->op == OIND || f->op == OINDEX) + switch(ft) { + case TCHAR: + a = AMOVBLSX; + if(t64) + a = AMOVBQSX; + goto ld; + case TUCHAR: + a = AMOVBLZX; + if(t64) + a = AMOVBQZX; + goto ld; + case TSHORT: + a = AMOVWLSX; + if(t64) + a = AMOVWQSX; + goto ld; + case TUSHORT: + a = AMOVWLZX; + if(t64) + a = AMOVWQZX; + goto ld; + case TINT: + case TLONG: + if(typefd[tt]) { + regalloc(&nod, t, t); + if(tt == TDOUBLE) + a = ACVTSL2SD; + else + a = ACVTSL2SS; + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + a = AMOVL; + if(t64) + a = AMOVLQSX; + goto ld; + case TUINT: + case TULONG: + a = AMOVL; + if(t64) + a = AMOVLQZX; /* could probably use plain MOVL */ + goto ld; + case TVLONG: + if(typefd[tt]) { + regalloc(&nod, t, t); + if(tt == TDOUBLE) + a = ACVTSQ2SD; + else + a = ACVTSQ2SS; + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + case TUVLONG: + a = AMOVQ; + goto ld; + case TIND: + a = AMOVQ; + + ld: + regalloc(&nod, f, t); + nod.type = t64? types[TVLONG]: types[TINT]; + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + + case TFLOAT: + a = AMOVSS; + goto fld; + case TDOUBLE: + a = AMOVSD; + fld: + regalloc(&nod, f, t); + if(tt != TDOUBLE && tt != TFLOAT){ /* TO DO: why is this here */ + prtree(f, "odd tree"); + nod.type = t64? types[TVLONG]: types[TINT]; + } + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + +/* + * store + */ + if(t->op == ONAME || t->op == OINDREG || + t->op == OIND || t->op == OINDEX) + switch(tt) { + case TCHAR: + case TUCHAR: + a = AMOVB; goto st; + case TSHORT: + case TUSHORT: + a = AMOVW; goto st; + case TINT: + case TUINT: + case TLONG: + case TULONG: + a = AMOVL; goto st; + case TVLONG: + case TUVLONG: + case TIND: + a = AMOVQ; goto st; + + st: + if(f->op == OCONST) { + gins(a, f, t); + return; + } + fst: + regalloc(&nod, t, f); + gmove(f, &nod); + gins(a, &nod, t); + regfree(&nod); + return; + + case TFLOAT: + a = AMOVSS; + goto fst; + case TDOUBLE: + a = AMOVSD; + goto fst; + } + +/* + * convert + */ + switch(CASE(ft,tt)) { + default: +/* + * integer to integer + ******** + a = AGOK; break; + + case CASE( TCHAR, TCHAR): + case CASE( TUCHAR, TCHAR): + case CASE( TSHORT, TCHAR): + case CASE( TUSHORT,TCHAR): + case CASE( TINT, TCHAR): + case CASE( TUINT, TCHAR): + case CASE( TLONG, TCHAR): + case CASE( TULONG, TCHAR): + case CASE( TIND, TCHAR): + + case CASE( TCHAR, TUCHAR): + case CASE( TUCHAR, TUCHAR): + case CASE( TSHORT, TUCHAR): + case CASE( TUSHORT,TUCHAR): + case CASE( TINT, TUCHAR): + case CASE( TUINT, TUCHAR): + case CASE( TLONG, TUCHAR): + case CASE( TULONG, TUCHAR): + case CASE( TIND, TUCHAR): + + case CASE( TSHORT, TSHORT): + case CASE( TUSHORT,TSHORT): + case CASE( TINT, TSHORT): + case CASE( TUINT, TSHORT): + case CASE( TLONG, TSHORT): + case CASE( TULONG, TSHORT): + case CASE( TIND, TSHORT): + + case CASE( TSHORT, TUSHORT): + case CASE( TUSHORT,TUSHORT): + case CASE( TINT, TUSHORT): + case CASE( TUINT, TUSHORT): + case CASE( TLONG, TUSHORT): + case CASE( TULONG, TUSHORT): + case CASE( TIND, TUSHORT): + + case CASE( TINT, TINT): + case CASE( TUINT, TINT): + case CASE( TLONG, TINT): + case CASE( TULONG, TINT): + case CASE( TIND, TINT): + + case CASE( TINT, TUINT): + case CASE( TUINT, TUINT): + case CASE( TLONG, TUINT): + case CASE( TULONG, TUINT): + case CASE( TIND, TUINT): + + case CASE( TUINT, TIND): + case CASE( TVLONG, TUINT): + case CASE( TVLONG, TULONG): + case CASE( TUVLONG, TUINT): + case CASE( TUVLONG, TULONG): + *****/ + a = AMOVL; + break; + + case CASE( TVLONG, TCHAR): + case CASE( TVLONG, TSHORT): + case CASE( TVLONG, TINT): + case CASE( TVLONG, TLONG): + case CASE( TUVLONG, TCHAR): + case CASE( TUVLONG, TSHORT): + case CASE( TUVLONG, TINT): + case CASE( TUVLONG, TLONG): + case CASE( TINT, TVLONG): + case CASE( TINT, TUVLONG): + case CASE( TLONG, TVLONG): + case CASE( TINT, TIND): + case CASE( TLONG, TIND): + a = AMOVLQSX; + if(f->op == OCONST) { + f->vconst &= (uvlong)0xffffffffU; + if(f->vconst & 0x80000000) + f->vconst |= (vlong)0xffffffff << 32; + a = AMOVQ; + } + break; + + case CASE( TUINT, TIND): + case CASE( TUINT, TVLONG): + case CASE( TUINT, TUVLONG): + case CASE( TULONG, TVLONG): + case CASE( TULONG, TUVLONG): + case CASE( TULONG, TIND): + a = AMOVL; /* same effect as AMOVLQZX */ + if(f->op == OCONST) { + f->vconst &= (uvlong)0xffffffffU; + a = AMOVQ; + } + break; + + case CASE( TIND, TVLONG): + case CASE( TVLONG, TVLONG): + case CASE( TUVLONG, TVLONG): + case CASE( TVLONG, TUVLONG): + case CASE( TUVLONG, TUVLONG): + case CASE( TIND, TUVLONG): + case CASE( TVLONG, TIND): + case CASE( TUVLONG, TIND): + case CASE( TIND, TIND): + a = AMOVQ; + break; + + case CASE( TSHORT, TINT): + case CASE( TSHORT, TUINT): + case CASE( TSHORT, TLONG): + case CASE( TSHORT, TULONG): + a = AMOVWLSX; + if(f->op == OCONST) { + f->vconst &= 0xffff; + if(f->vconst & 0x8000) + f->vconst |= 0xffff0000; + a = AMOVL; + } + break; + + case CASE( TSHORT, TVLONG): + case CASE( TSHORT, TUVLONG): + case CASE( TSHORT, TIND): + a = AMOVWQSX; + if(f->op == OCONST) { + f->vconst &= 0xffff; + if(f->vconst & 0x8000){ + f->vconst |= 0xffff0000; + f->vconst |= (vlong)~0 << 32; + } + a = AMOVL; + } + break; + + case CASE( TUSHORT,TINT): + case CASE( TUSHORT,TUINT): + case CASE( TUSHORT,TLONG): + case CASE( TUSHORT,TULONG): + a = AMOVWLZX; + if(f->op == OCONST) { + f->vconst &= 0xffff; + a = AMOVL; + } + break; + + case CASE( TUSHORT,TVLONG): + case CASE( TUSHORT,TUVLONG): + case CASE( TUSHORT,TIND): + a = AMOVWQZX; + if(f->op == OCONST) { + f->vconst &= 0xffff; + a = AMOVL; /* MOVL also zero-extends to 64 bits */ + } + break; + + case CASE( TCHAR, TSHORT): + case CASE( TCHAR, TUSHORT): + case CASE( TCHAR, TINT): + case CASE( TCHAR, TUINT): + case CASE( TCHAR, TLONG): + case CASE( TCHAR, TULONG): + a = AMOVBLSX; + if(f->op == OCONST) { + f->vconst &= 0xff; + if(f->vconst & 0x80) + f->vconst |= 0xffffff00; + a = AMOVL; + } + break; + + case CASE( TCHAR, TVLONG): + case CASE( TCHAR, TUVLONG): + case CASE( TCHAR, TIND): + a = AMOVBQSX; + if(f->op == OCONST) { + f->vconst &= 0xff; + if(f->vconst & 0x80){ + f->vconst |= 0xffffff00; + f->vconst |= (vlong)~0 << 32; + } + a = AMOVQ; + } + break; + + case CASE( TUCHAR, TSHORT): + case CASE( TUCHAR, TUSHORT): + case CASE( TUCHAR, TINT): + case CASE( TUCHAR, TUINT): + case CASE( TUCHAR, TLONG): + case CASE( TUCHAR, TULONG): + a = AMOVBLZX; + if(f->op == OCONST) { + f->vconst &= 0xff; + a = AMOVL; + } + break; + + case CASE( TUCHAR, TVLONG): + case CASE( TUCHAR, TUVLONG): + case CASE( TUCHAR, TIND): + a = AMOVBQZX; + if(f->op == OCONST) { + f->vconst &= 0xff; + a = AMOVL; /* zero-extends to 64-bits */ + } + break; + +/* + * float to fix + */ + case CASE( TFLOAT, TCHAR): + case CASE( TFLOAT, TUCHAR): + case CASE( TFLOAT, TSHORT): + case CASE( TFLOAT, TUSHORT): + case CASE( TFLOAT, TINT): + case CASE( TFLOAT, TUINT): + case CASE( TFLOAT, TLONG): + case CASE( TFLOAT, TULONG): + case CASE( TFLOAT, TVLONG): + case CASE( TFLOAT, TUVLONG): + case CASE( TFLOAT, TIND): + + case CASE( TDOUBLE,TCHAR): + case CASE( TDOUBLE,TUCHAR): + case CASE( TDOUBLE,TSHORT): + case CASE( TDOUBLE,TUSHORT): + case CASE( TDOUBLE,TINT): + case CASE( TDOUBLE,TUINT): + case CASE( TDOUBLE,TLONG): + case CASE( TDOUBLE,TULONG): + case CASE( TDOUBLE,TVLONG): + case CASE( TDOUBLE,TUVLONG): + case CASE( TDOUBLE,TIND): + regalloc(&nod, t, Z); + if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){ + if(ft == TFLOAT) + a = ACVTTSS2SQ; + else + a = ACVTTSD2SQ; + }else{ + if(ft == TFLOAT) + a = ACVTTSS2SL; + else + a = ACVTTSD2SL; + } + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + +/* + * ulong to float + */ + case CASE( TUVLONG, TDOUBLE): + case CASE( TUVLONG, TFLOAT): + a = ACVTSQ2SS; + if(tt == TDOUBLE) + a = ACVTSQ2SD; + regalloc(&nod, f, f); + gmove(f, &nod); + regalloc(&nod1, t, t); + gins(ACMPQ, &nod, nodconst(0)); + gins(AJLT, Z, Z); + p1 = p; + gins(a, &nod, &nod1); + gins(AJMP, Z, Z); + p2 = p; + patch(p1, pc); + regalloc(&nod2, f, Z); + regalloc(&nod3, f, Z); + gmove(&nod, &nod2); + gins(ASHRQ, nodconst(1), &nod2); + gmove(&nod, &nod3); + gins(AANDL, nodconst(1), &nod3); + gins(AORQ, &nod3, &nod2); + gins(a, &nod2, &nod1); + gins(tt == TDOUBLE? AADDSD: AADDSS, &nod1, &nod1); + regfree(&nod2); + regfree(&nod3); + patch(p2, pc); + regfree(&nod); + regfree(&nod1); + return; + + case CASE( TULONG, TDOUBLE): + case CASE( TUINT, TDOUBLE): + case CASE( TULONG, TFLOAT): + case CASE( TUINT, TFLOAT): + a = ACVTSQ2SS; + if(tt == TDOUBLE) + a = ACVTSQ2SD; + regalloc(&nod, f, f); + gins(AMOVLQZX, f, &nod); + regalloc(&nod1, t, t); + gins(a, &nod, &nod1); + gmove(&nod1, t); + regfree(&nod); + regfree(&nod1); + return; + +/* + * fix to float + */ + case CASE( TCHAR, TFLOAT): + case CASE( TUCHAR, TFLOAT): + case CASE( TSHORT, TFLOAT): + case CASE( TUSHORT,TFLOAT): + case CASE( TINT, TFLOAT): + case CASE( TLONG, TFLOAT): + case CASE( TVLONG, TFLOAT): + case CASE( TIND, TFLOAT): + + case CASE( TCHAR, TDOUBLE): + case CASE( TUCHAR, TDOUBLE): + case CASE( TSHORT, TDOUBLE): + case CASE( TUSHORT,TDOUBLE): + case CASE( TINT, TDOUBLE): + case CASE( TLONG, TDOUBLE): + case CASE( TVLONG, TDOUBLE): + case CASE( TIND, TDOUBLE): + regalloc(&nod, t, t); + if(ewidth[ft] == SZ_VLONG){ + if(tt == TFLOAT) + a = ACVTSQ2SS; + else + a = ACVTSQ2SD; + }else{ + if(tt == TFLOAT) + a = ACVTSL2SS; + else + a = ACVTSL2SD; + } + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + +/* + * float to float + */ + case CASE( TFLOAT, TFLOAT): + a = AMOVSS; + break; + case CASE( TDOUBLE,TFLOAT): + a = ACVTSD2SS; + break; + case CASE( TFLOAT, TDOUBLE): + a = ACVTSS2SD; + break; + case CASE( TDOUBLE,TDOUBLE): + a = AMOVSD; + break; + } + if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt]) /* TO DO: check AMOVL */ + if(samaddr(f, t)) + return; + gins(a, f, t); +} + +void +doindex(Node *n) +{ + Node nod, nod1; + long v; + +if(debug['Y']) +prtree(n, "index"); + +if(n->left->complex >= FNX) +print("botch in doindex\n"); + + regalloc(&nod, &qregnode, Z); + v = constnode.vconst; + cgen(n->right, &nod); + idx.ptr = D_NONE; + if(n->left->op == OCONST) + idx.ptr = D_CONST; + else if(n->left->op == OREGISTER) + idx.ptr = n->left->reg; + else if(n->left->op != OADDR) { + reg[D_BP]++; // cant be used as a base + regalloc(&nod1, &qregnode, Z); + cgen(n->left, &nod1); + idx.ptr = nod1.reg; + regfree(&nod1); + reg[D_BP]--; + } + idx.reg = nod.reg; + regfree(&nod); + constnode.vconst = v; +} + +void +gins(int a, Node *f, Node *t) +{ + + if(f != Z && f->op == OINDEX) + doindex(f); + if(t != Z && t->op == OINDEX) + doindex(t); + nextpc(); + p->as = a; + if(f != Z) + naddr(f, &p->from); + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +void +gopcode(int o, Type *ty, Node *f, Node *t) +{ + int a, et; + + et = TLONG; + if(ty != T) + et = ty->etype; + if(debug['M']) { + if(f != Z && f->type != T) + print("gop: %O %O[%s],", o, f->op, tnames[et]); + else + print("gop: %O Z,", o); + if(t != Z && t->type != T) + print("%O[%s]\n", t->op, tnames[t->type->etype]); + else + print("Z\n"); + } + a = AGOK; + switch(o) { + case OCOM: + a = ANOTL; + if(et == TCHAR || et == TUCHAR) + a = ANOTB; + if(et == TSHORT || et == TUSHORT) + a = ANOTW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ANOTQ; + break; + + case ONEG: + a = ANEGL; + if(et == TCHAR || et == TUCHAR) + a = ANEGB; + if(et == TSHORT || et == TUSHORT) + a = ANEGW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ANEGQ; + break; + + case OADDR: + a = ALEAQ; + break; + + case OASADD: + case OADD: + a = AADDL; + if(et == TCHAR || et == TUCHAR) + a = AADDB; + if(et == TSHORT || et == TUSHORT) + a = AADDW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AADDQ; + if(et == TFLOAT) + a = AADDSS; + if(et == TDOUBLE) + a = AADDSD; + break; + + case OASSUB: + case OSUB: + a = ASUBL; + if(et == TCHAR || et == TUCHAR) + a = ASUBB; + if(et == TSHORT || et == TUSHORT) + a = ASUBW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ASUBQ; + if(et == TFLOAT) + a = ASUBSS; + if(et == TDOUBLE) + a = ASUBSD; + break; + + case OASOR: + case OOR: + a = AORL; + if(et == TCHAR || et == TUCHAR) + a = AORB; + if(et == TSHORT || et == TUSHORT) + a = AORW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AORQ; + break; + + case OASAND: + case OAND: + a = AANDL; + if(et == TCHAR || et == TUCHAR) + a = AANDB; + if(et == TSHORT || et == TUSHORT) + a = AANDW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AANDQ; + break; + + case OASXOR: + case OXOR: + a = AXORL; + if(et == TCHAR || et == TUCHAR) + a = AXORB; + if(et == TSHORT || et == TUSHORT) + a = AXORW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AXORQ; + break; + + case OASLSHR: + case OLSHR: + a = ASHRL; + if(et == TCHAR || et == TUCHAR) + a = ASHRB; + if(et == TSHORT || et == TUSHORT) + a = ASHRW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ASHRQ; + break; + + case OASASHR: + case OASHR: + a = ASARL; + if(et == TCHAR || et == TUCHAR) + a = ASARB; + if(et == TSHORT || et == TUSHORT) + a = ASARW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ASARQ; + break; + + case OASASHL: + case OASHL: + a = ASALL; + if(et == TCHAR || et == TUCHAR) + a = ASALB; + if(et == TSHORT || et == TUSHORT) + a = ASALW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ASALQ; + break; + + case OFUNC: + a = ACALL; + break; + + case OASMUL: + case OMUL: + if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0) + t = Z; + a = AIMULL; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AIMULQ; + if(et == TFLOAT) + a = AMULSS; + if(et == TDOUBLE) + a = AMULSD; + break; + + case OASMOD: + case OMOD: + case OASDIV: + case ODIV: + a = AIDIVL; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AIDIVQ; + if(et == TFLOAT) + a = ADIVSS; + if(et == TDOUBLE) + a = ADIVSD; + break; + + case OASLMUL: + case OLMUL: + a = AMULL; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = AMULQ; + break; + + case OASLMOD: + case OLMOD: + case OASLDIV: + case OLDIV: + a = ADIVL; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ADIVQ; + break; + + case OEQ: + case ONE: + case OLT: + case OLE: + case OGE: + case OGT: + case OLO: + case OLS: + case OHS: + case OHI: + a = ACMPL; + if(et == TCHAR || et == TUCHAR) + a = ACMPB; + if(et == TSHORT || et == TUSHORT) + a = ACMPW; + if(et == TVLONG || et == TUVLONG || et == TIND) + a = ACMPQ; + if(et == TFLOAT) + a = AUCOMISS; + if(et == TDOUBLE) + a = AUCOMISD; + gins(a, f, t); + switch(o) { + case OEQ: a = AJEQ; break; + case ONE: a = AJNE; break; + case OLT: a = AJLT; break; + case OLE: a = AJLE; break; + case OGE: a = AJGE; break; + case OGT: a = AJGT; break; + case OLO: a = AJCS; break; + case OLS: a = AJLS; break; + case OHS: a = AJCC; break; + case OHI: a = AJHI; break; + } + gins(a, Z, Z); + return; + } + if(a == AGOK) + diag(Z, "bad in gopcode %O", o); + gins(a, f, t); +} + +int +samaddr(Node *f, Node *t) +{ + return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg; +} + +void +gbranch(int o) +{ + int a; + + a = AGOK; + switch(o) { + case ORETURN: + a = ARET; + break; + case OGOTO: + a = AJMP; + break; + } + nextpc(); + if(a == AGOK) { + diag(Z, "bad in gbranch %O", o); + nextpc(); + } + p->as = a; +} + +void +patch(Prog *op, long pc) +{ + + op->to.offset = pc; + op->to.type = D_BRANCH; +} + +void +gpseudo(int a, Sym *s, Node *n) +{ + + nextpc(); + p->as = a; + p->from.type = D_EXTERN; + p->from.sym = s; + p->from.scale = (profileflg ? 0 : NOPROF); + if(s->class == CSTATIC) + p->from.type = D_STATIC; + naddr(n, &p->to); + if(a == ADATA || a == AGLOBL) + pc--; +} + +int +sconst(Node *n) +{ + long v; + + if(n->op == OCONST && !typefd[n->type->etype]) { + v = n->vconst; + if(v >= -32766L && v < 32766L) + return 1; + } + return 0; +} + +long +exreg(Type *t) +{ + long o; + + if(typechlpv[t->etype]) { + if(exregoffset <= REGEXT-4) + return 0; + o = exregoffset; + exregoffset--; + return o; + } + return 0; +} + +schar ewidth[NTYPE] = +{ + -1, /*[TXXX]*/ + SZ_CHAR, /*[TCHAR]*/ + SZ_CHAR, /*[TUCHAR]*/ + SZ_SHORT, /*[TSHORT]*/ + SZ_SHORT, /*[TUSHORT]*/ + SZ_INT, /*[TINT]*/ + SZ_INT, /*[TUINT]*/ + SZ_LONG, /*[TLONG]*/ + SZ_LONG, /*[TULONG]*/ + SZ_VLONG, /*[TVLONG]*/ + SZ_VLONG, /*[TUVLONG]*/ + SZ_FLOAT, /*[TFLOAT]*/ + SZ_DOUBLE, /*[TDOUBLE]*/ + SZ_IND, /*[TIND]*/ + 0, /*[TFUNC]*/ + -1, /*[TARRAY]*/ + 0, /*[TVOID]*/ + -1, /*[TSTRUCT]*/ + -1, /*[TUNION]*/ + SZ_INT, /*[TENUM]*/ +}; +long ncast[NTYPE] = +{ + 0, /*[TXXX]*/ + BCHAR|BUCHAR, /*[TCHAR]*/ + BCHAR|BUCHAR, /*[TUCHAR]*/ + BSHORT|BUSHORT, /*[TSHORT]*/ + BSHORT|BUSHORT, /*[TUSHORT]*/ + BINT|BUINT|BLONG|BULONG, /*[TINT]*/ + BINT|BUINT|BLONG|BULONG, /*[TUINT]*/ + BINT|BUINT|BLONG|BULONG, /*[TLONG]*/ + BINT|BUINT|BLONG|BULONG, /*[TULONG]*/ + BVLONG|BUVLONG|BIND, /*[TVLONG]*/ + BVLONG|BUVLONG|BIND, /*[TUVLONG]*/ + BFLOAT, /*[TFLOAT]*/ + BDOUBLE, /*[TDOUBLE]*/ + BVLONG|BUVLONG|BIND, /*[TIND]*/ + 0, /*[TFUNC]*/ + 0, /*[TARRAY]*/ + 0, /*[TVOID]*/ + BSTRUCT, /*[TSTRUCT]*/ + BUNION, /*[TUNION]*/ + 0, /*[TENUM]*/ +}; diff --git a/src/cmd/6g/align.c b/src/cmd/6g/align.c new file mode 100644 index 0000000000..6538d3c86b --- /dev/null +++ b/src/cmd/6g/align.c @@ -0,0 +1,210 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "gg.h" + +/* + * machine size and rounding + * alignment is dictated around + * the size of a pointer. + * the size of the generic types + * are pulled from the typedef table. + */ + +static int wptr = 8; // width of a pointer +static int wmax = 8; // max rounding + +static char* +typedefs[] = +{ + "short", "int16", // shorts + "ushort", "uint16", + + "int", "int32", // ints + "uint", "uint32", + "rune", "uint32", + + "long", "int64", // longs + "ulong", "uint64", + + "vlong", "int64", // vlongs + "uvlong", "uint64", + + "float", "float32", // floats + "double", "float64", + +}; + +ulong +rnd(ulong o, ulong r) +{ + if(r > wmax) + r = wmax; + if(r != 0) + while(o%r != 0) + o++; + return o; +} + +void +offmod(Type *t) +{ + Type *f; + long o; + + o = 0; + for(f=t->type; f!=T; f=f->down) { + if(f->etype != TFIELD) + fatal("widstruct: not TFIELD: %lT", f); + if(f->type->etype != TFUNC) + continue; + f->width = o; + o += wptr; + } +} + +ulong +widstruct(Type *t, ulong o, int flag) +{ + Type *f; + long w; + + for(f=t->type; f!=T; f=f->down) { + if(f->etype != TFIELD) + fatal("widstruct: not TFIELD: %lT", f); + dowidth(f->type); + w = f->type->width; + o = rnd(o, w); + f->width = o; // really offset for TFIELD + o += w; + } + // final width is rounded + if(flag) + o = rnd(o, maxround); + t->width = o; + return o; +} + +void +dowidth(Type *t) +{ + ulong w; + + w = 0; + if(t == T) + return; + + switch(t->etype) { + default: + fatal("dowidth: unknown type: %E", t->etype); + break; + + case TINT8: + case TUINT8: + case TBOOL: // bool is int8 + w = 1; + break; + case TINT16: + case TUINT16: + w = 2; + break; + case TINT32: + case TUINT32: + case TFLOAT32: + case TPTR32: + w = 4; + break; + case TINT64: + case TUINT64: + case TFLOAT64: + case TPTR64: + w = 8; + break; + case TFLOAT80: + w = 10; + break; + case TINTER: // implemented as 2 pointers + offmod(t); + w = 2*wptr; + break; + case TCHAN: // implemented as pointer + dowidth(t->type); + dowidth(t->down); + w = wptr; + break; + case TMAP: // implemented as pointer + dowidth(t->type); + w = wptr; + break; + case TFORW: // implemented as pointer + w = wptr; + break; + case TANY: // implemented as pointer + w = wptr; + break; + case TSTRING: // implemented as pointer + w = wptr; + break; + case TARRAY: + case TDARRAY: + if(t->type == T) + break; + dowidth(t->type); + w = t->bound * t->type->width; + break; + + case TSTRUCT: + w = widstruct(t, 0, 1); + offmod(t); + break; + + case TFUNC: + // function is 3 cated structures + w = widstruct(*getthis(t), 0, 0); + w = widstruct(*getinarg(t), w, 0); + w = widstruct(*getoutarg(t), w, 1); + w = 0; + break; + } + t->width = w; +} + +void +besetptr(void) +{ + maxround = wmax; + widthptr = wptr; + + types[TPTR32] = typ(TPTR32); + dowidth(types[TPTR32]); + + types[TPTR64] = typ(TPTR64); + dowidth(types[TPTR64]); + + tptr = TPTR32; + if(wptr == 8) + tptr = TPTR64; +} + +void +belexinit(int lextype) +{ + int i; + Sym *s0, *s1; + + for(i=0; ilexical != lextype) + yyerror("need %s to define %s", + typedefs[i+1], typedefs[i+0]); + s0 = lookup(typedefs[i+0]); + s0->lexical = s1->lexical; + s0->otype = s1->otype; + } + + symstringo = lookup(".stringo"); // strings + + listinit(); + buildtxt(); +} diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c new file mode 100644 index 0000000000..7a00688392 --- /dev/null +++ b/src/cmd/6g/cgen.c @@ -0,0 +1,638 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "gg.h" + +void +cgen(Node *n, Node *res) +{ + long lno; + Node *nl, *nr, *r; + Node n1, tmp; + int a; + Prog *p1, *p2, *p3; + + if(debug['g']) { + dump("\ncgen-l", res); + dump("cgen-r", n); + } + if(n == N || n->type == T) + return; + if(res == N || res->type == T) + fatal("cgen: res nil"); + + lno = dynlineno; + if(n->op != ONAME) + dynlineno = n->lineno; // for diagnostics + + if(isfat(n->type)) { + sgen(n, res, n->type->width); + goto ret; + } + + if(!res->addable) { + igen(res, &n1, N); + cgen(n, &n1); + regfree(&n1); + goto ret; + } + + if(n->addable) { + gmove(n, res); + goto ret; + } + + nl = n->left; + nr = n->right; + if(nl != N && nl->ullman >= UINF) + if(nr != N && nr->ullman >= UINF) { + fatal("cgen: both sides functions"); + goto ret; + } + + switch(n->op) { + default: + dump("cgen", n); + fatal("cgen: unknown op %N", n); + break; + + // these call bgen to get a bool value + case OOROR: + case OANDAND: + case OEQ: + case ONE: + case OLT: + case OLE: + case OGE: + case OGT: + case ONOT: + p1 = gbranch(AJMP, T); + p2 = pc; + gmove(booltrue, res); + p3 = gbranch(AJMP, T); + patch(p1, pc); + bgen(n, 1, p2); + gmove(boolfalse, res); + patch(p3, pc); + goto ret; + + case OPLUS: + cgen(nl, res); + goto ret; + + // unary + case OMINUS: + case OCOM: + a = optoas(n->op, nl->type); + goto uop; + + // symmetric binary + case OAND: + case OOR: + case OXOR: + case OADD: + case OMUL: + a = optoas(n->op, nl->type); + goto sbop; + + // asymmetric binary + case OMOD: + case OSUB: + case ODIV: + case OLSH: + case ORSH: + a = optoas(n->op, nl->type); + goto abop; + + case OCONV: + if(eqtype(n->type, nl->type, 0)) { + cgen(nl, res); + break; + } + regalloc(&n1, nl->type, res); + cgen(nl, &n1); + gmove(&n1, res); + regfree(&n1); + break; + +// case OINDEXPTRSTR: +// nl = n->left; +// nr = n->right; +// if(nl->addable) { +// cgen(nr); +// cgen(nl); +// gopcode(P_LOADI, T_ADDR, N); +// gopcodet(P_INDEXZ, nr->type, N); +// break; +// } +// break; + +// case OINDEXSTR: +// nl = n->left; +// nr = n->right; +// if(nl->addable) { +// cgen(nr); +// gopcodet(P_INDEXZ, nr->type, nl); +// break; +// } +// cgen(nl); +// r = tempname(nl->type); +// gopcodet(P_STORE, nl->type, r); +// cgen(nr); +// gopcodet(P_INDEXZ, nr->type, r); +// break; + +// case OSLICESTR: +// case OSLICEPTRSTR: +// nl = n->left; // name +// nr = n->right; +// +// r = nr->right; // index2 +// if(!r->addable) { +// cgen(r); +// r = tempname(r->type); +// gopcodet(P_STORE, r->type, r); +// } +// +// // string into T_ADDR +// if(!nl->addable) { +// cgen(nl); +// gconv(T_ADDR, nl->type->etype); +// } else +// gopcode(P_LOAD, T_ADDR, nl); +// +// if(n->op == OSLICEPTRSTR) +// gopcode(P_LOADI, T_ADDR, N); +// +// // offset in int reg +// cgen(nr->left); +// +// // index 2 addressed +// gopcodet(P_SLICE, r->type, r); +// break; + + case OS2I: + case OI2I: + case OI2S: + + case OINDEXPTR: + case OINDEX: + case ODOT: + case ODOTPTR: + case OIND: + igen(n, &n1, res); + gmove(&n1, res); + regfree(&n1); + break; + + case OLEN: + if(isptrto(nl->type, TSTRING)) { + regalloc(&n1, types[tptr], res); + cgen(nl, res); + n1.op = OINDREG; + n1.type = types[TINT32]; + gmove(&n1, res); + regfree(&n1); + break; + } + fatal("cgen: OLEN: unknown type %lT", nl->type); + break; + +// case ODOTMETH: +// case ODOTINTER: +// cgen(n->left); +// break; + + case OADDR: + agen(nl, res); + break; + + case OCALLMETH: + cgen_callmeth(n); + cgen_callret(n, res); + break; + + case OCALLINTER: + cgen_callinter(n, res); + cgen_callret(n, res); + break; + + case OCALL: + cgen_call(n); + cgen_callret(n, res); + break; + } + goto ret; + +sbop: // symmetric binary + if(nl->ullman < nr->ullman) { + r = nl; + nl = nr; + nr = r; + } + +abop: // asymmetric binary + if(nr->addable) { + regalloc(&n1, nl->type, res); + cgen(nl, &n1); + gins(a, nr, &n1); + gmove(&n1, res); + regfree(&n1); + goto ret; + } + + tempname(&tmp, nr->type); + regalloc(&n1, nr->type, res); + cgen(nr, &n1); + gmove(&n1, &tmp); + regfree(&n1); + + regalloc(&n1, nl->type, res); + cgen(nl, &n1); + gins(a, &tmp, &n1); + gmove(&n1, res); + regfree(&n1); + goto ret; + +uop: // unary + regalloc(&n1, nl->type, res); + cgen(nl, &n1); + gins(a, N, &n1); + gmove(&n1, res); + regfree(&n1); + goto ret; + +ret: + dynlineno = lno; +} + +void +agen(Node *n, Node *res) +{ + Node *nl, *nr; + Node n1, n2, n3, tmp; + ulong w; + Type *t; + + if(n == N || n->type == T) + return; + + if(!isptr[res->type->etype]) + fatal("agen: not tptr: %T", res->type); + + if(n->addable) { + regalloc(&n1, types[tptr], res); + gins(ALEAQ, n, &n1); + gmove(&n1, res); + regfree(&n1); + return; + } + + switch(n->op) { + default: + fatal("agen: unknown op %N", n); + break; + +// case ONAME: +// regalloc(&n1, types[tptr], res); +// gins(optoas(OADDR, types[tptr]), n, &n1); +// gmove(&n1, res); +// regfree(&n1); +// break; + + case OINDEXPTR: + nl = n->left; + nr = n->right; + w = n->type->width; + if(nr->addable) + goto iprad; + if(nl->addable) { + regalloc(&n1, nr->type, N); + cgen(nr, &n1); + cgen(nl, res); + goto index; + } + cgen(nr, res); + tempname(&tmp, nr->type); + gmove(res, &tmp); + + iprad: + cgen(nl, res); + regalloc(&n1, nr->type, N); + cgen(nr, &n1); + goto index; + + case OS2I: + case OI2I: + case OI2S: + agen_inter(n, res); + break; + +// case OINDREG: + + case OINDEX: + nl = n->left; + nr = n->right; + w = n->type->width; + if(nr->addable) + goto irad; + if(nl->addable) { + regalloc(&n1, nr->type, N); + cgen(nr, &n1); + agen(nl, res); + goto index; + } + cgen(nr, res); + tempname(&tmp, nr->type); + gmove(res, &tmp); + + irad: + agen(nl, res); + regalloc(&n1, nr->type, N); + cgen(nr, &n1); + goto index; + + index: + // &a is in res + // i is in &n1 + // w is width + if(issigned[n1.type->etype]) { + nodconst(&n3, types[TINT64], w); // w/tint64 + regalloc(&n2, types[TINT64], &n1); // i/int64 + gmove(&n1, &n2); + gins(optoas(OMUL, types[TINT64]), &n3, &n2); + gins(optoas(OADD, types[tptr]), &n2, res); + regfree(&n1); + regfree(&n2); + break; + } + // unsigned multiply is a pain in the ass + fatal("agen: unsigned index"); + break; + +// case OIND: +// nl = n->left; +// if(nl->addable) { +// gopcode(P_LOAD, T_ADDR, nl); +// break; +// } +// cgen(nl); +// gconv(T_ADDR, nl->type->etype); +// break; + + case ODOT: + nl = n->left; + t = nl->type; + agen(nl, res); + if(n->xoffset != 0) { + nodconst(&n1, types[TINT64], n->xoffset); + gins(optoas(OADD, types[tptr]), &n1, res); + } + break; + + case ODOTPTR: + nl = n->left; + t = nl->type; + if(!isptr[t->etype]) + fatal("agen: not ptr %N", n); + cgen(nl, res); + if(n->xoffset != 0) { + nodconst(&n1, types[TINT64], n->xoffset); + gins(optoas(OADD, types[tptr]), &n1, res); + } + break; + } +} + +vlong +fieldoffset(Type *t, Node *n) +{ + if(t->etype != TSTRUCT) + fatal("fieldoffset: not struct %lT", t); + if(n->op != ONAME) + fatal("fieldoffset: not field name %N", n); + return 0; +} + +void +igen(Node *n, Node *a, Node *res) +{ + regalloc(a, types[tptr], res); + agen(n, a); + a->op = OINDREG; + a->type = n->type; +} + +void +bgen(Node *n, int true, Prog *to) +{ + long lno; + int et, a, b; + Node *nl, *nr, *r; + Node n1, n2, tmp; + Prog *p1, *p2; + + if(n == N) + n = booltrue; + + lno = dynlineno; + if(n->op != ONAME) + dynlineno = n->lineno; // for diagnostics + + if(n->type == T) { + convlit(n, types[TBOOL]); + if(n->type == T) + goto ret; + } + + et = n->type->etype; + if(et != TBOOL) { + yyerror("cgen: bad type %T for %O", n->type, n->op); + patch(gins(AEND, N, N), to); + goto ret; + } + nl = N; + nr = N; + + switch(n->op) { + default: + regalloc(&n1, n->type, N); + cgen(n, &n1); + nodconst(&n2, n->type, 0); + gins(optoas(OCMP, n->type), &n1, &n2); + a = AJNE; + if(!true) + a = AJEQ; + patch(gbranch(a, n->type), to); + regfree(&n1); + goto ret; + + case OLITERAL: + if(!true == !n->val.vval) + patch(gbranch(AJMP, T), to); + goto ret; + + case ONAME: + nodconst(&n1, n->type, 0); + gins(optoas(OCMP, n->type), n, &n1); + a = AJNE; + if(!true) + a = AJEQ; + patch(gbranch(a, n->type), to); + goto ret; + + case OANDAND: + if(!true) + goto caseor; + + caseand: + p1 = gbranch(AJMP, T); + p2 = gbranch(AJMP, T); + patch(p1, pc); + bgen(n->left, !true, p2); + bgen(n->right, !true, p2); + p1 = gbranch(AJMP, T); + patch(p1, to); + patch(p2, pc); + goto ret; + + case OOROR: + if(!true) + goto caseand; + + caseor: + bgen(n->left, true, to); + bgen(n->right, true, to); + goto ret; + + case OEQ: + case ONE: + case OLT: + case OGT: + case OLE: + case OGE: + nr = n->right; + if(nr == N || nr->type == T) + goto ret; + + case ONOT: // unary + nl = n->left; + if(nl == N || nl->type == T) + goto ret; + } + + switch(n->op) { + + case ONOT: + bgen(nl, !true, to); + goto ret; + + case OEQ: + case ONE: + case OLT: + case OGT: + case OLE: + case OGE: + a = n->op; + if(!true) + a = brcom(a); + + // make simplest on right + if(nl->ullman < nr->ullman) { + a = brrev(a); + r = nl; + nl = nr; + nr = r; + } + a = optoas(a, nr->type); + + if(nr->addable) { + regalloc(&n1, nl->type, N); + cgen(nl, &n1); + b = optoas(OCMP, nr->type); + + switch(b) { + case ACMPQ: + if(nr->op == OLITERAL) + if(nr->val.vval >= (1LL<<32)) + goto dolit; + + case AUCOMISS: + if(nr->op == OLITERAL) + goto dolit; + if(nr->op == ONAME) + goto dolit; + } + + gins(b, &n1, nr); + patch(gbranch(a, nr->type), to); + regfree(&n1); + break; + + dolit: + regalloc(&n2, nr->type, N); + cgen(nr, &n2); + gins(b, &n1, &n2); + patch(gbranch(a, nr->type), to); + regfree(&n2); + regfree(&n1); + break; + } + + tempname(&tmp, nr->type); + cgen(nr, &tmp); + + regalloc(&n1, nl->type, N); + cgen(nl, &n1); + + gins(optoas(OCMP, nr->type), &n1, &tmp); + patch(gbranch(a, nr->type), to); + regfree(&n1); + break; + } + goto ret; + +ret: + dynlineno = lno; +} + +void +sgen(Node *n, Node *ns, ulong w) +{ + Node nodl, nodr; + long c; + + if(w == 0) + return; + if(n->ullman >= UINF && ns->ullman >= UINF) { + fatal("sgen UINF"); + } + + nodreg(&nodl, types[tptr], D_DI); + nodreg(&nodr, types[tptr], D_SI); + + if(n->ullman >= ns->ullman) { + agen(n, &nodr); + agen(ns, &nodl); + } else { + agen(ns, &nodl); + agen(n, &nodr); + } + + gins(ACLD, N, N); // clear direction flag + + c = w / 8; + if(c > 0) { + gconreg(AMOVQ, c, D_CX); + gins(AREP, N, N); // repeat + gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+ + } + + c = w % 8; + if(c > 0) { + gconreg(AMOVQ, c, D_CX); + gins(AREP, N, N); // repeat + gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+ + } +} diff --git a/src/cmd/6g/gen.c b/src/cmd/6g/gen.c new file mode 100644 index 0000000000..700057405d --- /dev/null +++ b/src/cmd/6g/gen.c @@ -0,0 +1,820 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + + +#undef EXTERN +#define EXTERN +#include "gg.h" + +enum +{ + // random unused opcode + AJMPX = AADDPD, +}; + +static Node* curfn; + +void +compile(Node *fn) +{ + Plist *pl; + Node nod1; + Prog *ptxt; + + if(fn->nbody == N) + return; + + curfn = fn; + dowidth(curfn->type); + + if(nerrors != 0) { + walk(curfn); + return; + } + + if(debug['w']) + dump("--- pre walk ---", curfn->nbody); + + maxarg = 0; + stksize = 0; + + walk(curfn); + if(nerrors != 0) + return; + + if(debug['w']) + dump("--- post walk ---", curfn->nbody); + + allocparams(); + + continpc = P; + breakpc = P; + + pl = newplist(); + pl->name = curfn->nname; + pl->locals = autodcl; + + nodconst(&nod1, types[TINT32], 0); + ptxt = gins(ATEXT, curfn->nname, &nod1); + +// inarggen(); + + ginit(); + gen(curfn->nbody); + gclean(); + +// if(curfn->type->outtuple != 0) +// gins(AGOK, N, N); + + pc->as = ARET; // overwrite AEND + + // fill in final stack size + ptxt->to.offset = rnd(stksize+maxarg, maxround); + + if(debug['f']) + frame(0); +} + +void +allocparams(void) +{ + Dcl *d; + Iter list; + Type *t; + Node *n; + ulong w; + + /* + * allocate (set xoffset) the stack + * slots for this, inargs, outargs + * these are allocated positavely + * from 0 up. + * note that this uses the 'width' + * field, which, in the OFIELD of the + * parameters, is the offset in the + * parameter list. + */ + d = autodcl; + t = funcfirst(&list, curfn->type); + while(t != T) { + if(d == D) + fatal("allocparams: this nil"); + if(d->op != ONAME) { + d = d->forw; + continue; + } + + n = d->dnode; + if(n->class != PPARAM) + fatal("allocparams: this class"); + + n->xoffset = t->width; + d = d->forw; + t = funcnext(&list); + } + + /* + * allocate (set xoffset) the stack + * slots for all automatics. + * allocated starting at -w down. + */ + for(d=autodcl; d!=D; d=d->forw) { + if(d->op != ONAME) + continue; + + n = d->dnode; + if(n->class != PAUTO) + continue; + + dowidth(n->type); + w = n->type->width; + stksize += w; + stksize = rnd(stksize, w); + + n->xoffset = -stksize; + } +} + +/* + * compile statements + */ +void +gen(Node *n) +{ + long lno; + Prog *scontin, *sbreak; + Prog *p1, *p2, *p3; + Sym *s; + + lno = dynlineno; + +loop: + if(n == N) + goto ret; + dynlineno = n->lineno; // for diagnostics + + switch(n->op) { + default: + fatal("gen: unknown op %N", n); + break; + + case OLIST: + gen(n->left); + n = n->right; + goto loop; + + case OPANIC: + genpanic(); + break; + + case OCASE: + case OFALL: + case OXCASE: + case OXFALL: + case OEMPTY: + break; + + case OLABEL: + // before declaration, s->label points at + // a link list of PXGOTO instructions. + // after declaration, s->label points + // at a AJMP to .+1 + + s = n->left->sym; + p1 = (Prog*)s->label; + + if(p1 != P) { + if(p1->as == AJMP) { + yyerror("label redeclared: %S", s); + break; + } + while(p1 != P) { + if(p1->as != AJMPX) + fatal("bad label pointer: %S", s); + p1->as = AJMP; + p2 = p1->to.branch; + patch(p1, pc); + p1 = p2; + } + } + + s->label = pc; + p1 = gbranch(AJMP, T); + patch(p1, pc); + break; + + case OGOTO: + s = n->left->sym; + p1 = (Prog*)s->label; + if(p1 != P && p1->as == AJMP) { + // already declared + p2 = gbranch(AJMP, T); + patch(p2, p1->to.branch); + break; + } + + // link thru to.branch + p2 = gbranch(AJMPX, T); + p2->to.branch = p1; + s->label = p2; + break; + + case OBREAK: + if(breakpc == P) { + yyerror("gen: break is not in a loop"); + break; + } + patch(gbranch(AJMP, T), breakpc); + break; + + case OCONTINUE: + if(continpc == P) { + yyerror("gen: continue is not in a loop"); + break; + } + patch(gbranch(AJMP, T), continpc); + break; + + case OFOR: + gen(n->ninit); // init + p1 = gbranch(AJMP, T); // goto test + sbreak = breakpc; + breakpc = gbranch(AJMP, T); // break: goto done + scontin = continpc; + continpc = pc; + gen(n->nincr); // contin: incr + patch(p1, pc); // test: + bgen(n->ntest, 0, breakpc); // if(!test) goto break + gen(n->nbody); // body + patch(gbranch(AJMP, T), continpc); // goto contin + patch(breakpc, pc); // done: + continpc = scontin; + breakpc = sbreak; + break; + + case OIF: + gen(n->ninit); // init + p1 = gbranch(AJMP, T); // goto test + p2 = gbranch(AJMP, T); // p2: goto else + patch(p1, pc); // test: + bgen(n->ntest, 0, p2); // if(!test) goto p2 + gen(n->nbody); // then + p3 = gbranch(AJMP, T); // goto done + patch(p2, pc); // else: + gen(n->nelse); // else + patch(p3, pc); // done: + break; + + case OSWITCH: + gen(n->ninit); // init + p1 = gbranch(AJMP, T); // goto test + sbreak = breakpc; + breakpc = gbranch(AJMP, T); // break: goto done + patch(p1, pc); // test: + swgen(n); // switch(test) body + patch(breakpc, pc); // done: + breakpc = sbreak; + break; + + case OASOP: + cgen_asop(n->left, n->right, n->etype); + break; + + case OAS: + cgen_as(n->left, n->right, n->op); + break; + + case OCALLMETH: + cgen_callmeth(n); + break; + + case OCALLINTER: + cgen_callinter(n, N); + break; + + case OCALL: + cgen_call(n); + break; + + case ORETURN: + cgen_ret(n); + break; + } + +ret: + dynlineno = lno; +} + +void +agen_inter(Node *n, Node *res) +{ + Node nodo, nodr, nodt; + Sym *s; + char *e; + long o; + + // stack offset + memset(&nodo, 0, sizeof(nodo)); + nodo.op = OINDREG; + nodo.val.vval = D_SP; + nodo.addable = 1; + nodo.type = types[tptr]; + + // pointer register + regalloc(&nodr, types[tptr], res); + + switch(n->op) { + default: + fatal("agen_inter %O\n", n->op); + + case OS2I: + // ifaces2i(*sigi, *sigs, i.map, i.s) + // i.s is input + // (i.map, i.s) is output + + cgen(n->left, &nodr); + nodo.xoffset = 3*widthptr; + cgen_as(&nodo, &nodr, 0); + + nodtypesig(&nodt, n->type); + agen(&nodt, &nodr); + nodo.xoffset = 0*widthptr; + cgen_as(&nodo, &nodr, 0); + + nodtypesig(&nodt, n->left->type); + agen(&nodt, &nodr); + nodo.xoffset = 1*widthptr; + cgen_as(&nodo, &nodr, 0); + + e = "ifaces2i"; + if(maxarg < 4*widthptr) + maxarg = 4*widthptr; + o = 2*widthptr; + break; + + case OI2I: + // ifacei2i(*sigi, i.map, i.s) + // (i.map, i.s) is input + // (i.map, i.s) is output + + nodo.xoffset = 1*widthptr; + if(!n->left->addable) { + agen(n->left, &nodr); + gmove(&nodr, &nodo); + fatal("agen_inter i2i"); + } else { + cgen(n->left, &nodo); + } + + nodtypesig(&nodt, n->type); + agen(&nodt, &nodr); + nodo.xoffset = 0*widthptr; + cgen_as(&nodo, &nodr, 0); + + e = "ifacei2i"; + if(maxarg < 3*widthptr) + maxarg = 3*widthptr; + o = 1*widthptr; + break; + + case OI2S: + // ifacei2s(*sigs, i.map, i.s) + // (i.map, i.s) is input + // i.s is output + + nodo.xoffset = 1*widthptr; + if(!n->left->addable) { + agen(n->left, &nodr); + gmove(&nodr, &nodo); + fatal("agen_inter i2s"); + } else + gmove(n->left, &nodo); + + nodtypesig(&nodt, n->type); + agen(&nodt, &nodr); + nodo.xoffset = 0*widthptr; + cgen_as(&nodo, &nodr, 0); + + e = "ifacei2s"; + if(maxarg < 3*widthptr) + maxarg = 3*widthptr; + o = 2*widthptr; + break; + } + + s = pkglookup(e, "sys"); + if(s->oname == N) { + s->oname = newname(s); + s->oname->class = PEXTERN; + } + gins(ACALL, N, s->oname); + + nodo.xoffset = o; + gins(ALEAQ, &nodo, res); + + regfree(&nodr); +} + +void +swgen(Node *n) +{ + Node *c1, *c2; + Node n1, tmp; + Case *s0, *se, *s; + Prog *p1, *dflt; + long lno; + int any; + Iter save1, save2; + +// botch - put most of this code in +// walk. gen binary search for +// sequence of constant cases + + lno = dynlineno; + + p1 = gbranch(AJMP, T); + s0 = C; + se = C; + + // walk thru the body placing breaks + // and labels into the case statements + + any = 0; + dflt = P; + c1 = listfirst(&save1, &n->nbody); + while(c1 != N) { + dynlineno = c1->lineno; // for diagnostics + if(c1->op != OCASE) { + if(s0 == C) + yyerror("unreachable statements in a switch"); + gen(c1); + + any = 1; + if(c1->op == OFALL) + any = 0; + c1 = listnext(&save1); + continue; + } + + // put in the break between cases + if(any) { + patch(gbranch(AJMP, T), breakpc); + any = 0; + } + + // over case expressions + c2 = listfirst(&save2, &c1->left); + if(c2 == N) + dflt = pc; + + while(c2 != N) { + + s = mal(sizeof(*s)); + if(s0 == C) + s0 = s; + else + se->slink = s; + se = s; + + s->scase = c2; // case expression + s->sprog = pc; // where to go + + c2 = listnext(&save2); + } + + c1 = listnext(&save1); + } + + if(any) + patch(gbranch(AJMP, T), breakpc); + + patch(p1, pc); + + tempname(&tmp, n->ntest->type); + cgen(n->ntest, &tmp); + + for(s=s0; s!=C; s=s->slink) { + memset(&n1, 0, sizeof(n1)); + n1.op = OEQ; + n1.left = &tmp; + n1.right = s->scase; + walktype(&n1, 0); + bgen(&n1, 1, s->sprog); + } + if(dflt != P) { + patch(gbranch(AJMP, T), dflt); + goto ret; + } + patch(gbranch(AJMP, T), breakpc); + +ret: + dynlineno = lno; +} + +void +inarggen(void) +{ + fatal("inarggen"); +} + +void +genpanic(void) +{ + Node n1, n2; + Prog *p; + + nodconst(&n1, types[TINT64], 0xf0); + nodreg(&n2, types[TINT64], D_AX); + gins(AMOVL, &n1, &n2); + p = pc; + gins(AMOVQ, &n2, N); + p->to.type = D_INDIR+D_AX; +} + +void +cgen_callinter(Node *n, Node *res) +{ + Node *i, *f; + Node tmpi, nodo, nodr, nodsp; + + i = n->left; + if(i->op != ODOTINTER) + fatal("cgen_callinter: not ODOTINTER %O", i->op); + + f = i->right; // field + if(f->op != ONAME) + fatal("cgen_callinter: not ONAME %O", f->op); + + i = i->left; // interface + + if(!i->addable) { + tempname(&tmpi, i->type); + cgen(i, &tmpi); + i = &tmpi; + } + + gen(n->right); // args + + regalloc(&nodr, types[tptr], res); + regalloc(&nodo, types[tptr], &nodr); + nodo.op = OINDREG; + + agen(i, &nodr); // REG = &inter + + nodindreg(&nodsp, types[tptr], D_SP); + nodo.xoffset += widthptr; + cgen(&nodo, &nodsp); // 0(SP) = 8(REG) -- i.s + + nodo.xoffset -= widthptr; + cgen(&nodo, &nodr); // REG = 0(REG) -- i.m + +//print("field = %N\n", f); +//print("offset = %ld\n", n->left->xoffset); + + nodo.xoffset = n->left->xoffset + 4*widthptr; + cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.m->fun[f] + + gins(ACALL, N, &nodr); + regfree(&nodr); + regfree(&nodr); + + setmaxarg(n->left->type); +} + +void +cgen_callmeth(Node *n) +{ + Node *l; + + // generate a rewrite for method call + // (p.f)(...) goes to (f)(p,...) + + l = n->left; + + n->op = OCALL; + n->left = n->left->right; + n->left->type = l->type; + + if(n->left->op == ONAME) + n->left->class = PEXTERN; + cgen_call(n); +} + +void +cgen_call(Node *n) +{ + Type *t; + Node nod, afun; + + if(n == N) + return; + + if(n->left->ullman >= UINF) { + // if name involves a fn call + // precompute the address of the fn + tempname(&afun, types[tptr]); + if(isptr[n->left->type->etype]) + cgen(n->left, &afun); + else + agen(n->left, &afun); + } + + gen(n->right); // assign the args + t = n->left->type; + if(isptr[t->etype]) + t = t->type; + + setmaxarg(t); + + // call tempname pointer + if(n->left->ullman >= UINF) { + regalloc(&nod, types[tptr], N); + cgen_as(&nod, &afun, 0); + gins(ACALL, N, &nod); + regfree(&nod); + return; + } + + // call pointer + if(isptr[n->left->type->etype]) { + regalloc(&nod, types[tptr], N); + cgen_as(&nod, n->left, 0); + gins(ACALL, N, &nod); + regfree(&nod); + return; + } + + // call direct + gins(ACALL, N, n->left); +} + +void +cgen_callret(Node *n, Node *res) +{ + Node nod; + Type *fp, *t; + Iter flist; + + t = n->left->type; + if(t->etype == TPTR32 || t->etype == TPTR64) + t = t->type; + + fp = structfirst(&flist, getoutarg(t)); + if(fp == T) + fatal("cgen_callret: nil"); + + memset(&nod, 0, sizeof(nod)); + nod.op = OINDREG; + nod.val.vval = D_SP; + nod.addable = 1; + + nod.xoffset = fp->width; + nod.type = fp->type; + cgen_as(res, &nod, 0); +} + +void +cgen_ret(Node *n) +{ + gen(n->left); // copy out args + gins(ARET, N, N); +} + +void +cgen_asop(Node *nl, Node *nr, int op) +{ + Node n1, n2; + int a; + + // botch compare ullman numbers + // and use temp for functions + + a = optoas(op, nl->type); + regalloc(&n1, nl->type, N); + if(nl->addable) { + cgen(nr, &n1); + gins(a, nl, &n1); + gmove(&n1, nl); + regfree(&n1); + return; + } + + igen(nl, &n2, N); + cgen(nr, &n1); + gins(a, &n2, &n1); + gmove(&n1, &n2); + regfree(&n1); + regfree(&n2); +} + +void +cgen_as(Node *nl, Node *nr, int op) +{ + Node nc, n1; + Type *tl; + ulong w, c; + + if(nl == N) + return; + + tl = nl->type; + if(tl == T) + return; + + if(nr == N) { + if(isfat(tl)) { + /* clear a fat object */ + if(debug['g']) + dump("\nclearfat", nl); + + w = nl->type->width; + if(w > 0) + gconreg(AMOVQ, 0, D_AX); + + if(w > 0) { + nodreg(&n1, types[tptr], D_DI); + agen(nl, &n1); + gins(ACLD, N, N); // clear direction flag + } + + c = w / 8; + if(c > 0) { + gconreg(AMOVQ, c, D_CX); + gins(AREP, N, N); // repeat + gins(ASTOSQ, N, N); // STOQ AL,*(DI)+ + } + + c = w % 8; + if(c > 0) { + gconreg(AMOVQ, c, D_CX); + gins(AREP, N, N); // repeat + gins(ASTOSB, N, N); // STOB AL,*(DI)+ + } + return; + } + + /* invent a "zero" for the rhs */ + nr = &nc; + memset(nr, 0, sizeof(*nr)); + switch(tl->etype) { + default: + fatal("cgen_as: tl %T", tl); + break; + + case TINT8: + case TUINT8: + case TINT16: + case TUINT16: + case TINT32: + case TUINT32: + case TINT64: + case TUINT64: + nr->val.ctype = CTINT; + nr->val.vval = 0; + break; + + case TFLOAT32: + case TFLOAT64: + case TFLOAT80: + nr->val.ctype = CTFLT; + nr->val.dval = 0.0; + break; + + case TBOOL: + nr->val.ctype = CTBOOL; + nr->val.vval = 0; + break; + + case TPTR32: + case TPTR64: + if(isptrto(nl->type, TSTRING)) { + nr->val.ctype = CTSTR; + nr->val.sval = &emptystring; + break; + } + nr->val.ctype = CTNIL; + nr->val.vval = 0; + break; + +// case TINTER: +// nodreg(&n1, types[tptr], D_DI); +// agen(nl, &n1); +// n1.op = OINDREG; +// +// nodreg(&nc, types[tptr], D_AX); +// gconreg(AMOVQ, 0, D_AX); +// +// gins(AMOVQ, &nc, &n1); +// n1.xoffset += widthptr; +// gins(AMOVQ, &nc, &n1); +// return; + + } + nr->op = OLITERAL; + nr->type = tl; + nr->addable = 1; + ullmancalc(nr); + } + cgen(nr, nl); +} diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h new file mode 100644 index 0000000000..5cd31b4aeb --- /dev/null +++ b/src/cmd/6g/gg.h @@ -0,0 +1,203 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + + +#include +#include + +#include "../gc/go.h" +#include "../6l/6.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Prog Prog; +typedef struct Addr Addr; + +struct Addr +{ + vlong offset; + double dval; + Prog* branch; + char sval[NSNAME]; + + Sym* sym; + uchar type; + uchar index; + uchar etype; + uchar scale; /* doubles as width in DATA op */ +}; +#define A ((Addr*)0) + +struct Prog +{ + short as; // opcode + ulong loc; // pc offset in this func + ulong lineno; // source line that generated this + Addr from; // src address + Addr to; // dst address + Prog* link; // next instruction in this func +}; +#define P ((Prog*)0) + +typedef struct Plist Plist; +struct Plist +{ + Node* name; + Dcl* locals; + Prog* firstpc; + int recur; + Plist* link; +}; + +typedef struct Sig Sig; +struct Sig +{ + char* name; + Sym* sym; + ulong hash; + long offset; + Sig* link; +}; + +typedef struct Case Case; +struct Case +{ + Prog* sprog; + Node* scase; + Case* slink; +}; +#define C ((Case*)0) + +typedef struct Pool Pool; +struct Pool +{ + String* sval; + Pool* link; +}; + +EXTERN Prog* continpc; +EXTERN Prog* breakpc; +EXTERN Prog* pc; +EXTERN Prog* firstpc; +EXTERN Plist* plist; +EXTERN Plist* plast; +EXTERN Pool* poolist; +EXTERN Pool* poolast; +EXTERN Biobuf* bout; +EXTERN long dynloc; +EXTERN uchar reg[D_NONE]; +EXTERN ushort txt[NTYPE*NTYPE]; +EXTERN long maxround; +EXTERN long widthptr; +EXTERN long maxarg; +EXTERN long stksize; +EXTERN Sym* symstringo; // string objects +EXTERN long stringo; // size of string objects +EXTERN long pcloc; // instruction counter +EXTERN String emptystring; +extern char* anames[]; + +/* + * gen.c + */ +void compile(Node*); +void proglist(void); +void gen(Node*); +void swgen(Node*); +Node* lookdot(Node*, Node*, int); +void inarggen(void); +void agen_inter(Node*, Node*); +void cgen_as(Node*, Node*, int); +void cgen_asop(Node*, Node*, int); +void cgen_ret(Node*); +void cgen_call(Node*); +void cgen_callmeth(Node*); +void cgen_callinter(Node*, Node*); +void cgen_callret(Node*, Node*); +void genpanic(void); +int needconvert(Type*, Type*); +void genconv(Type*, Type*); +void allocparams(void); + +/* + * cgen + */ +void cgen(Node*, Node*); +void agen(Node*, Node*); +void igen(Node*, Node*, Node*); +vlong fieldoffset(Type*, Node*); +void bgen(Node*, int, Prog*); +void sgen(Node*, Node*, ulong); +void gmove(Node*, Node*); +Prog* gins(int, Node*, Node*); +int samaddr(Node*, Node*); +void naddr(Node*, Addr*); + +/* + * gsubr.c + */ +void clearp(Prog*); +void proglist(void); +Prog* gbranch(int, Type*); +void patch(Prog*, Prog*); +Prog* prog(int); +void gaddoffset(Node*); +void gconv(int, int); +int conv2pt(Type*); +void belexinit(int); +vlong convvtox(vlong, int); +int brcom(int); +int brrev(int); +void fnparam(Type*, int, int); +Sig* lsort(Sig*, int(*)(Sig*, Sig*)); +Prog* gop(int, Node*, Node*, Node*); +void setconst(Addr*, vlong); +void setaddr(Addr*, Node*); +int optoas(int, Type*); +void ginit(void); +void gclean(void); +void regalloc(Node*, Type*, Node*); +void regfree(Node*); +void regsalloc(Node*, Type*); // replace w tmpvar +void regret(Node*, Type*); +Node* nodarg(Type*, int); +void nodreg(Node*, Type*, int); +void nodindreg(Node*, Type*, int); +void nodconst(Node*, Type*, vlong); +Sym* signame(Type*); +void nodtypesig(Node*, Type*); +void gconreg(int, vlong, int); +void buildtxt(void); +void stringpool(Node*); +void tempname(Node*, Type*); +Plist* newplist(void); +int isfat(Type*); +void setmaxarg(Type*); + +/* + * list.c + */ +int Aconv(Fmt*); +int Dconv(Fmt*); +int Pconv(Fmt*); +int Rconv(Fmt*); +int Yconv(Fmt*); +void listinit(void); + +/* + * obj + */ +void zname(Biobuf*, Sym*, int); +void zaddr(Biobuf*, Addr*, int); +void ieeedtod(Ieee*, double); +void dumpstrings(void); +void dumpsignatures(void); + +/* + * align + */ +void dowidth(Type*); +ulong rnd(ulong, ulong); diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c new file mode 100644 index 0000000000..9ced8fe2f5 --- /dev/null +++ b/src/cmd/6g/gsubr.c @@ -0,0 +1,1649 @@ +// Derived from Inferno utils/6c/txt.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gg.h" + +void +clearp(Prog *p) +{ + p->as = AEND; + p->from.type = D_NONE; + p->from.index = D_NONE; + p->to.type = D_NONE; + p->to.index = D_NONE; + p->loc = pcloc; + pcloc++; +} + +Prog* +prog(int as) +{ + Prog *p; + + p = pc; + pc = mal(sizeof(*pc)); + + clearp(pc); + + p->as = as; + p->lineno = dynlineno; + p->link = pc; + return p; +} + +Prog* +gbranch(int as, Type *t) +{ + Prog *p; + + p = prog(as); + p->to.type = D_BRANCH; + p->to.branch = P; + return p; +} + +void +patch(Prog *p, Prog *to) +{ + if(p->to.type != D_BRANCH) + fatal("patch: not a branch"); + p->to.branch = to; + p->to.offset = to->loc; +} + +Plist* +newplist(void) +{ + Plist *pl; + + pl = mal(sizeof(*pl)); + if(plist == nil) + plist = pl; + else + plast->link = pl; + plast = pl; + + pc = mal(sizeof(*pc)); + clearp(pc); + pl->firstpc = pc; + + return pl; +} + +void +ginit(void) +{ + int i; + + for(i=0; ietype) { + case TINT8: + case TUINT8: + case TINT16: + case TUINT16: + case TINT32: + case TUINT32: + case TINT64: + case TUINT64: + case TPTR32: + case TPTR64: + case TBOOL: + if(o != N && o->op == OREGISTER) { + i = o->val.vval; + if(i >= D_AX && i <= D_R15) + goto out; + } + for(i=D_AX; i<=D_R15; i++) + if(reg[i] == 0) + goto out; + + yyerror("out of fixed registers"); + goto err; + + case TFLOAT32: + case TFLOAT64: + case TFLOAT80: + if(o != N && o->op == OREGISTER) { + i = o->val.vval; + if(i >= D_X0 && i <= D_X7) + goto out; + } + for(i=D_X0; i<=D_X7; i++) + if(reg[i] == 0) + goto out; + yyerror("out of floating registers"); + goto err; + } + yyerror("regalloc: unknown type %T", t); + +err: + nodreg(n, t, 0); + return; + +out: + reg[i]++; + nodreg(n, t, i); +} + +void +regfree(Node *n) +{ + int i; + + if(n->op != OREGISTER && n->op != OINDREG) + fatal("regfree: not a register"); + i = n->val.vval; + if(i < 0 || i >= sizeof(reg)) + fatal("regfree: reg out of range"); + if(reg[i] <= 0) + fatal("regfree: reg not allocated"); + reg[i]--; +} + +void +regret(Node *n, Type *t) +{ + if(t == T) + fatal("regret: t nil"); + fatal("regret"); +} + +void +nodreg(Node *n, Type *t, int r) +{ + if(t == T) + fatal("nodreg: t nil"); + + memset(n, 0, sizeof(*n)); + n->op = OREGISTER; + n->addable = 1; + ullmancalc(n); + n->val.vval = r; + n->type = t; +} + +void +nodindreg(Node *n, Type *t, int r) +{ + nodreg(n, t, r); + n->op = OINDREG; +} + +Node* +nodarg(Type *t, int fp) +{ + Node *n; + + if(t->etype != TFIELD) + fatal("nodarg: not field %T", t); + + n = nod(ONAME, N, N); + n->type = t->type; + n->sym = t->sym; + n->xoffset = t->width; + n->addable = 1; + + switch(fp) { + case 0: // output arg + n->op = OINDREG; + n->val.vval = D_SP; + break; + + case 1: // input arg + n->class = PPARAM; + break; + + case 2: // offset output arg +fatal("shpuldnt be used"); + n->op = OINDREG; + n->val.vval = D_SP; + n->xoffset += types[tptr]->width; + break; + } + return n; +} + +void +nodconst(Node *n, Type *t, vlong v) +{ + memset(n, 0, sizeof(*n)); + n->op = OLITERAL; + n->addable = 1; + ullmancalc(n); + n->val.vval = v; + n->val.ctype = CTINT; + n->type = t; + + switch(t->etype) { + case TFLOAT32: + case TFLOAT64: + case TFLOAT80: + fatal("nodconst: bad type %T", t); + + case TPTR32: + case TPTR64: + case TUINT8: + case TUINT16: + case TUINT32: + case TUINT64: + n->val.ctype = CTUINT; + break; + } +} + +Sym* +signame(Type *t) +{ + Sym *s; + char *e; + +loop: + if(t == T) + fatal("signame: nil type"); + + switch(t->etype) { + default: + fatal("signame: unknown type %T", t); + + case TPTR32: + case TPTR64: + t = t->type; + goto loop; + case TSTRUCT: + e = "sigs"; + break; + case TINTER: + e = "sigi"; + break; + } + + s = t->sym; + if(s == S) + fatal("nodtypesig: no sym for type"); + + snprint(namebuf, sizeof(namebuf), "%s_%s", e, s->name); + s = pkglookup(namebuf, s->package); + return s; +} + +void +nodtypesig(Node *n, Type *t) +{ + memset(n, 0, sizeof(*n)); + n->op = ONAME; + n->type = types[TUINT8]; + n->etype = TUINT8; + n->xoffset = 0; + n->sym = signame(t); + n->class = PEXTERN; + n->addable = 1; + n->ullman = 0; +} + +void +gconreg(int as, vlong c, int reg) +{ + Node n1, n2; + + nodconst(&n1, types[TINT64], c); + nodreg(&n2, types[TINT64], reg); + gins(as, &n1, &n2); +} + +#define CASE(a,b) (((a)<<16)|((b)<<0)) + +void +gmove(Node *f, Node *t) +{ + int ft, tt, t64, a; + Node nod, nod1, nod2, nod3, nodc; + Prog *p1, *p2; + + ft = f->type->etype; + tt = t->type->etype; + + t64 = 0; + if(tt == TINT64 || tt == TUINT64 || tt == TPTR64) + t64 = 1; + + if(debug['M']) + print("gop: %O %O[%E],%O[%E]\n", OAS, + f->op, ft, t->op, tt); + if(isfloat[ft] && f->op == OCONST) { + /* TO DO: pick up special constants, possibly preloaded */ + if(f->val.dval == 0.0){ + regalloc(&nod, t->type, t); + gins(AXORPD, &nod, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + } +/* + * load + */ + if(f->op == ONAME || f->op == OINDREG || + f->op == OIND || f->op == OINDEX) + switch(ft) { + case TINT8: + a = AMOVBLSX; + if(t64) + a = AMOVBQSX; + goto ld; + case TBOOL: + case TUINT8: + a = AMOVBLZX; + if(t64) + a = AMOVBQZX; + goto ld; + case TINT16: + a = AMOVWLSX; + if(t64) + a = AMOVWQSX; + goto ld; + case TUINT16: + a = AMOVWLZX; + if(t64) + a = AMOVWQZX; + goto ld; + case TINT32: + if(isfloat[tt]) { + regalloc(&nod, t->type, t); + if(tt == TFLOAT64) + a = ACVTSL2SD; + else + a = ACVTSL2SS; + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + a = AMOVL; + if(t64) + a = AMOVLQSX; + goto ld; + case TUINT32: + case TPTR32: + a = AMOVL; + if(t64) + a = AMOVLQZX; /* could probably use plain MOVL */ + goto ld; + case TINT64: + if(isfloat[tt]) { + regalloc(&nod, t->type, t); + if(tt == TFLOAT64) + a = ACVTSQ2SD; + else + a = ACVTSQ2SS; + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + case TUINT64: + case TPTR64: + a = AMOVQ; + + ld: + regalloc(&nod, f->type, t); + nod.type = t64? types[TINT64]: types[TINT32]; + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + + case TFLOAT32: + a = AMOVSS; + goto fld; + case TFLOAT64: + a = AMOVSD; + fld: + regalloc(&nod, f->type, t); + if(tt != TFLOAT64 && tt != TFLOAT32){ /* TO DO: why is this here */ + dump("odd tree", f); + nod.type = t64? types[TINT64]: types[TINT32]; + } + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + +/* + * store + */ + if(t->op == ONAME || t->op == OINDREG || + t->op == OIND || t->op == OINDEX) + switch(tt) { + case TBOOL: + case TINT8: + case TUINT8: + a = AMOVB; + goto st; + case TINT16: + case TUINT16: + a = AMOVW; + goto st; + case TINT32: + case TUINT32: + case TPTR32: + a = AMOVL; + goto st; + case TINT64: + case TUINT64: + case TPTR64: + a = AMOVQ; + goto st; + + st: + if(f->op == OCONST) { + gins(a, f, t); + return; + } + fst: + regalloc(&nod, t->type, f); + gmove(f, &nod); + gins(a, &nod, t); + regfree(&nod); + return; + + case TFLOAT32: + a = AMOVSS; + goto fst; + case TFLOAT64: + a = AMOVSD; + goto fst; + } + +/* + * convert + */ + switch(CASE(ft, tt)) { + default: +/* + * integer to integer + ******** + a = AGOK; break; + + case CASE(TBOOL, TBOOL): + case CASE(TINT8, TBOOL): + case CASE(TUINT8, TBOOL): + case CASE(TINT16, TBOOL): + case CASE(TUINT16, TBOOL): + case CASE(TINT32, TBOOL): + case CASE(TUINT32, TBOOL): + case CASE(TPTR64, TBOOL): + + case CASE(TBOOL, TINT8): + case CASE(TINT8, TINT8): + case CASE(TUINT8, TINT8): + case CASE(TINT16, TINT8): + case CASE(TUINT16, TINT8): + case CASE(TINT32, TINT8): + case CASE(TUINT32, TINT8): + case CASE(TPTR64, TINT8): + + case CASE(TBOOL, TUINT8): + case CASE(TINT8, TUINT8): + case CASE(TUINT8, TUINT8): + case CASE(TINT16, TUINT8): + case CASE(TUINT16, TUINT8): + case CASE(TINT32, TUINT8): + case CASE(TUINT32, TUINT8): + case CASE(TPTR64, TUINT8): + + case CASE(TINT16, TINT16): + case CASE(TUINT16, TINT16): + case CASE(TINT32, TINT16): + case CASE(TUINT32, TINT16): + case CASE(TPTR64, TINT16): + + case CASE(TINT16, TUINT16): + case CASE(TUINT16, TUINT16): + case CASE(TINT32, TUINT16): + case CASE(TUINT32, TUINT16): + case CASE(TPTR64, TUINT16): + + case CASE(TINT64, TUINT): + case CASE(TINT64, TUINT32): + case CASE(TUINT64, TUINT32): + *****/ + a = AMOVL; + break; + + case CASE(TINT64, TINT8): + case CASE(TINT64, TINT16): + case CASE(TINT64, TINT32): + case CASE(TUINT64, TINT8): + case CASE(TUINT64, TINT16): + case CASE(TUINT64, TINT32): + case CASE(TINT32, TINT64): + case CASE(TINT32, TPTR64): + a = AMOVLQSX; + if(f->op == OCONST) { + f->val.vval &= (uvlong)0xffffffffU; + if(f->val.vval & 0x80000000) + f->val.vval |= (vlong)0xffffffff << 32; + a = AMOVQ; + } + break; + + case CASE(TUINT32, TINT64): + case CASE(TUINT32, TUINT64): + case CASE(TUINT32, TPTR64): + a = AMOVL; /* same effect as AMOVLQZX */ + if(f->op == OCONST) { + f->val.vval &= (uvlong)0xffffffffU; + a = AMOVQ; + } + break; + + case CASE(TPTR64, TINT64): + case CASE(TINT64, TINT64): + case CASE(TUINT64, TINT64): + case CASE(TINT64, TUINT64): + case CASE(TUINT64, TUINT64): + case CASE(TPTR64, TUINT64): + case CASE(TINT64, TPTR64): + case CASE(TUINT64, TPTR64): + case CASE(TPTR64, TPTR64): + a = AMOVQ; + break; + + case CASE(TINT16, TINT32): + case CASE(TINT16, TUINT32): + a = AMOVWLSX; + if(f->op == OCONST) { + f->val.vval &= 0xffff; + if(f->val.vval & 0x8000) + f->val.vval |= 0xffff0000; + a = AMOVL; + } + break; + + case CASE(TINT16, TINT64): + case CASE(TINT16, TUINT64): + case CASE(TINT16, TPTR64): + a = AMOVWQSX; + if(f->op == OCONST) { + f->val.vval &= 0xffff; + if(f->val.vval & 0x8000){ + f->val.vval |= 0xffff0000; + f->val.vval |= (vlong)~0 << 32; + } + a = AMOVL; + } + break; + + case CASE(TUINT16, TINT32): + case CASE(TUINT16, TUINT32): + a = AMOVWLZX; + if(f->op == OCONST) { + f->val.vval &= 0xffff; + a = AMOVL; + } + break; + + case CASE(TUINT16, TINT64): + case CASE(TUINT16, TUINT64): + case CASE(TUINT16, TPTR64): + a = AMOVWQZX; + if(f->op == OCONST) { + f->val.vval &= 0xffff; + a = AMOVL; /* MOVL also zero-extends to 64 bits */ + } + break; + + case CASE(TINT8, TINT16): + case CASE(TINT8, TUINT16): + case CASE(TINT8, TINT32): + case CASE(TINT8, TUINT32): + a = AMOVBLSX; + if(f->op == OCONST) { + f->val.vval &= 0xff; + if(f->val.vval & 0x80) + f->val.vval |= 0xffffff00; + a = AMOVL; + } + break; + + case CASE(TINT8, TINT64): + case CASE(TINT8, TUINT64): + case CASE(TINT8, TPTR64): + a = AMOVBQSX; + if(f->op == OCONST) { + f->val.vval &= 0xff; + if(f->val.vval & 0x80){ + f->val.vval |= 0xffffff00; + f->val.vval |= (vlong)~0 << 32; + } + a = AMOVQ; + } + break; + + case CASE(TBOOL, TINT16): + case CASE(TBOOL, TUINT16): + case CASE(TBOOL, TINT32): + case CASE(TBOOL, TUINT32): + case CASE(TUINT8, TINT16): + case CASE(TUINT8, TUINT16): + case CASE(TUINT8, TINT32): + case CASE(TUINT8, TUINT32): + a = AMOVBLZX; + if(f->op == OCONST) { + f->val.vval &= 0xff; + a = AMOVL; + } + break; + + case CASE(TBOOL, TINT64): + case CASE(TBOOL, TUINT64): + case CASE(TBOOL, TPTR64): + case CASE(TUINT8, TINT64): + case CASE(TUINT8, TUINT64): + case CASE(TUINT8, TPTR64): + a = AMOVBQZX; + if(f->op == OCONST) { + f->val.vval &= 0xff; + a = AMOVL; /* zero-extends to 64-bits */ + } + break; + +/* + * float to fix + */ + case CASE(TFLOAT32, TINT8): + case CASE(TFLOAT32, TINT16): + case CASE(TFLOAT32, TINT32): + regalloc(&nod, t->type, N); + gins(ACVTTSS2SL, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + + case CASE(TFLOAT32, TBOOL): + case CASE(TFLOAT32, TUINT8): + case CASE(TFLOAT32, TUINT16): + case CASE(TFLOAT32, TUINT32): + case CASE(TFLOAT32, TINT64): + case CASE(TFLOAT32, TUINT64): + case CASE(TFLOAT32, TPTR64): + regalloc(&nod, t->type, N); + gins(ACVTTSS2SQ, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + + case CASE(TFLOAT64, TINT8): + case CASE(TFLOAT64, TINT16): + case CASE(TFLOAT64, TINT32): + regalloc(&nod, t->type, N); + gins(ACVTTSD2SL, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + + case CASE(TFLOAT64, TBOOL): + case CASE(TFLOAT64, TUINT8): + case CASE(TFLOAT64, TUINT16): + case CASE(TFLOAT64, TUINT32): + case CASE(TFLOAT64, TINT64): + case CASE(TFLOAT64, TUINT64): + case CASE(TFLOAT64, TPTR64): + regalloc(&nod, t->type, N); + gins(ACVTTSD2SQ, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + +/* + * ulong to float + */ + case CASE(TUINT64, TFLOAT64): + case CASE(TUINT64, TFLOAT32): + a = ACVTSQ2SS; + if(tt == TFLOAT64) + a = ACVTSQ2SD; + regalloc(&nod, f->type, f); + gmove(f, &nod); + regalloc(&nod1, t->type, t); +nodconst(&nodc, types[TUINT64], 0); + gins(ACMPQ, &nod, &nodc); + p1 = pc; + gins(AJLT, N, N); + gins(a, &nod, &nod1); + p2 = pc; + gins(AJMP, N, N); + patch(p1, pc); + regalloc(&nod2, f->type, N); + regalloc(&nod3, f->type, N); + gmove(&nod, &nod2); +nodconst(&nodc, types[TUINT64], 1); + gins(ASHRQ, &nodc, &nod2); + gmove(&nod, &nod3); + gins(AANDL, &nodc, &nod3); + gins(AORQ, &nod3, &nod2); + gins(a, &nod2, &nod1); + gins(tt == TFLOAT64? AADDSD: AADDSS, &nod1, &nod1); + regfree(&nod2); + regfree(&nod3); + patch(p2, pc); + regfree(&nod); + regfree(&nod1); + return; + + case CASE(TUINT32, TFLOAT64): + case CASE(TUINT32, TFLOAT32): + a = ACVTSQ2SS; + if(tt == TFLOAT64) + a = ACVTSQ2SD; + regalloc(&nod, f->type, f); + gins(AMOVLQZX, f, &nod); + regalloc(&nod1, t->type, t); + gins(a, &nod, &nod1); + gmove(&nod1, t); + regfree(&nod); + regfree(&nod1); + return; + +/* + * fix to float + */ + case CASE(TINT64, TFLOAT32): + case CASE(TPTR64, TFLOAT32): + regalloc(&nod, t->type, t); + gins(ACVTSQ2SS, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + + case CASE(TINT64, TFLOAT64): + case CASE(TPTR64, TFLOAT64): + regalloc(&nod, t->type, t); + gins(ACVTSQ2SD, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + + case CASE(TBOOL, TFLOAT32): + case CASE(TINT8, TFLOAT32): + case CASE(TUINT8, TFLOAT32): + case CASE(TINT16, TFLOAT32): + case CASE(TUINT16, TFLOAT32): + case CASE(TINT32, TFLOAT32): + regalloc(&nod, t->type, t); + gins(ACVTSL2SS, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + + case CASE(TBOOL, TFLOAT64): + case CASE(TINT8, TFLOAT64): + case CASE(TUINT8, TFLOAT64): + case CASE(TINT16, TFLOAT64): + case CASE(TUINT16, TFLOAT64): + case CASE(TINT32, TFLOAT64): + regalloc(&nod, t->type, t); + gins(ACVTSL2SD, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + +/* + * float to float + */ + case CASE(TFLOAT32, TFLOAT32): + a = AMOVSS; + break; + case CASE(TFLOAT64, TFLOAT32): + a = ACVTSD2SS; + break; + case CASE(TFLOAT32, TFLOAT64): + a = ACVTSS2SD; + break; + case CASE(TFLOAT64, TFLOAT64): + a = AMOVSD; + break; + } + if(a == AMOVQ || + a == AMOVSD || + a == AMOVSS || + a == AMOVL && f->type->width == t->type->width) /* TO DO: check AMOVL */ + if(samaddr(f, t)) + return; + gins(a, f, t); +} + +void +buildtxt(void) +{ + Type t1, t2; + int i, j, a; + + memset(&t1, 0, sizeof(t1)); + memset(&t2, 0, sizeof(t2)); + + for(i=0; i= t2.width) { + a = AMOVL; + if(t1.width >= 8) + a = AMOVQ; + txt[i*NTYPE+j] = a; + continue; + } + switch(i) { + case TINT8: + a = AMOVBLSX; + if(t1.width >= 8) + a = AMOVBQSX; + break; + case TINT16: + a = AMOVWLSX; + if(t1.width >= 8) + a = AMOVWQSX; + break; + case TINT32: + a = AMOVLQSX; + break; + case TBOOL: + case TUINT8: + a = AMOVBLZX; + if(t1.width >= 8) + a = AMOVBQZX; + break; + case TUINT16: + a = AMOVWLZX; + if(t1.width >= 8) + a = AMOVLQZX; + break; + case TPTR32: + case TUINT32: + a = AMOVWQZX; + break; + } + txt[i*NTYPE+j] = a; + continue; + } + if(isfloat[j]) { + } + } + if(isint[j] || isptr[j] || j==TBOOL) { + if(isfloat[i]) { + } + } + } +} + +void +regsalloc(Node *f, Type *t) +{ + fatal("regsalloc"); +} + +int +samaddr(Node *f, Node *t) +{ + + if(f->op != t->op) + return 0; + + switch(f->op) { + case OREGISTER: + if(f->val.vval != t->val.vval) + break; + return 1; + } + return 0; +} + +Prog* +gins(int as, Node *f, Node *t) +{ +// Node nod; +// long v; + Prog *p; + +// if(f != N && f->op == OINDEX) { +// regalloc(&nod, ®node, Z); +// v = constnode.vconst; +// cgen(f->right, &nod); +// constnode.vconst = v; +// idx.reg = nod.reg; +// regfree(&nod); +// } +// if(t != N && t->op == OINDEX) { +// regalloc(&nod, ®node, Z); +// v = constnode.vconst; +// cgen(t->right, &nod); +// constnode.vconst = v; +// idx.reg = nod.reg; +// regfree(&nod); +// } + + p = prog(as); + if(f != N) + naddr(f, &p->from); + if(t != N) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); + return p; +} + +void +naddr(Node *n, Addr *a) +{ + + a->type = D_NONE; + if(n == N) + return; + + switch(n->op) { + default: + fatal("naddr: bad %O %D", n->op, a); + break; + + case OREGISTER: + a->type = n->val.vval; + a->sym = S; + break; + +// case OINDEX: +// case OIND: +// naddr(n->left, a); +// if(a->type >= D_AX && a->type <= D_DI) +// a->type += D_INDIR; +// else +// if(a->type == D_CONST) +// a->type = D_NONE+D_INDIR; +// else +// if(a->type == D_ADDR) { +// a->type = a->index; +// a->index = D_NONE; +// } else +// goto bad; +// if(n->op == OINDEX) { +// a->index = idx.reg; +// a->scale = n->scale; +// } +// break; + + case OINDREG: + a->type = n->val.vval+D_INDIR; + a->sym = n->sym; + a->offset = n->xoffset; + break; + + case ONAME: + a->etype = n->etype; + a->offset = n->xoffset; + a->sym = n->sym; + if(a->sym == S) + a->sym = lookup(".noname"); + + switch(n->class) { + default: + fatal("naddr: ONAME class %S %d\n", n->sym, n->class); + case PEXTERN: + a->type = D_EXTERN; + break; + case PAUTO: + a->type = D_AUTO; + break; + case PPARAM: + a->type = D_PARAM; + break; + case PSTATIC: + a->type = D_STATIC; + break; + } + break; + + case OLITERAL: + if(isfloat[n->type->etype]) { + a->type = D_FCONST; + a->dval = n->val.dval; + break; + } + if(isptrto(n->type, TSTRING)) { + a->etype = n->etype; + a->sym = symstringo; + a->type = D_ADDR; + a->index = D_STATIC; + a->offset = symstringo->offset; + stringpool(n); + break; + } + if(isint[n->type->etype] || + isptr[n->type->etype] || + n->type->etype == TBOOL) { + a->sym = S; + a->type = D_CONST; + a->offset = n->val.vval; + break; + } + fatal("naddr: const %lT", n->type); + break; + +// case OADDR: +// naddr(n->left, a); +// if(a->type >= D_INDIR) { +// a->type -= D_INDIR; +// break; +// } +// if(a->type == D_EXTERN || a->type == D_STATIC || +// a->type == D_AUTO || a->type == D_PARAM) +// if(a->index == D_NONE) { +// a->index = a->type; +// a->type = D_ADDR; +// break; +// } +// goto bad; + +// case OADD: +// if(n->right->op == OLITERAL) { +// v = n->right->vconst; +// naddr(n->left, a); +// } else +// if(n->left->op == OLITERAL) { +// v = n->left->vconst; +// naddr(n->right, a); +// } else +// goto bad; +// a->offset += v; +// break; + + } +} + +int +optoas(int op, Type *t) +{ + int a; + + if(t == T) + fatal("optoas: t is nil"); + + a = AGOK; + switch(CASE(op, t->etype)) { + default: + fatal("optoas: no entry %O-%T", op, t); + break; + + case CASE(OADDR, TPTR32): + a = ALEAL; + break; + + case CASE(OADDR, TPTR64): + a = ALEAQ; + break; + + case CASE(OEQ, TBOOL): + case CASE(OEQ, TINT8): + case CASE(OEQ, TUINT8): + case CASE(OEQ, TINT16): + case CASE(OEQ, TUINT16): + case CASE(OEQ, TINT32): + case CASE(OEQ, TUINT32): + case CASE(OEQ, TINT64): + case CASE(OEQ, TUINT64): + case CASE(OEQ, TFLOAT32): + case CASE(OEQ, TFLOAT64): + case CASE(OEQ, TPTR32): + case CASE(OEQ, TPTR64): + a = AJEQ; + break; + + case CASE(ONE, TBOOL): + case CASE(ONE, TINT8): + case CASE(ONE, TUINT8): + case CASE(ONE, TINT16): + case CASE(ONE, TUINT16): + case CASE(ONE, TINT32): + case CASE(ONE, TUINT32): + case CASE(ONE, TINT64): + case CASE(ONE, TUINT64): + case CASE(ONE, TFLOAT32): + case CASE(ONE, TFLOAT64): + case CASE(ONE, TPTR32): + case CASE(ONE, TPTR64): + a = AJNE; + break; + + case CASE(OLT, TINT8): + case CASE(OLT, TINT16): + case CASE(OLT, TINT32): + case CASE(OLT, TINT64): + case CASE(OLT, TFLOAT32): + case CASE(OLT, TFLOAT64): + a = AJLT; + break; + + case CASE(OLT, TUINT8): + case CASE(OLT, TUINT16): + case CASE(OLT, TUINT32): + case CASE(OLT, TUINT64): + a = AJCS; + break; + + case CASE(OLE, TINT8): + case CASE(OLE, TINT16): + case CASE(OLE, TINT32): + case CASE(OLE, TINT64): + case CASE(OLE, TFLOAT32): + case CASE(OLE, TFLOAT64): + a = AJLE; + break; + + case CASE(OLE, TUINT8): + case CASE(OLE, TUINT16): + case CASE(OLE, TUINT32): + case CASE(OLE, TUINT64): + a = AJLS; + break; + + case CASE(OGT, TINT8): + case CASE(OGT, TINT16): + case CASE(OGT, TINT32): + case CASE(OGT, TINT64): + case CASE(OGT, TFLOAT32): + case CASE(OGT, TFLOAT64): + a = AJGT; + break; + + case CASE(OGT, TUINT8): + case CASE(OGT, TUINT16): + case CASE(OGT, TUINT32): + case CASE(OGT, TUINT64): + a = AJHI; + break; + + case CASE(OGE, TINT8): + case CASE(OGE, TINT16): + case CASE(OGE, TINT32): + case CASE(OGE, TINT64): + case CASE(OGE, TFLOAT32): + case CASE(OGE, TFLOAT64): + a = AJGE; + break; + + case CASE(OGE, TUINT8): + case CASE(OGE, TUINT16): + case CASE(OGE, TUINT32): + case CASE(OGE, TUINT64): + a = AJCC; + break; + + case CASE(OCMP, TBOOL): + case CASE(OCMP, TINT8): + case CASE(OCMP, TUINT8): + a = ACMPB; + break; + + case CASE(OCMP, TINT16): + case CASE(OCMP, TUINT16): + a = ACMPW; + break; + + case CASE(OCMP, TINT32): + case CASE(OCMP, TUINT32): + case CASE(OCMP, TPTR32): + a = ACMPL; + break; + + case CASE(OCMP, TINT64): + case CASE(OCMP, TUINT64): + case CASE(OCMP, TPTR64): + a = ACMPQ; + break; + + case CASE(OCMP, TFLOAT32): + a = AUCOMISS; + break; + + case CASE(OCMP, TFLOAT64): + a = AUCOMISD; + break; + + case CASE(OADD, TINT8): + case CASE(OADD, TUINT8): + a = AADDB; + break; + + case CASE(OADD, TINT16): + case CASE(OADD, TUINT16): + a = AADDW; + break; + + case CASE(OADD, TINT32): + case CASE(OADD, TUINT32): + case CASE(OADD, TPTR32): + a = AADDL; + break; + + case CASE(OADD, TINT64): + case CASE(OADD, TUINT64): + case CASE(OADD, TPTR64): + a = AADDQ; + break; + + case CASE(OADD, TFLOAT32): + a = AADDSS; + break; + + case CASE(OADD, TFLOAT64): + a = AADDSD; + break; + + case CASE(OSUB, TINT8): + case CASE(OSUB, TUINT8): + a = ASUBB; + break; + + case CASE(OSUB, TINT16): + case CASE(OSUB, TUINT16): + a = ASUBW; + break; + + case CASE(OSUB, TINT32): + case CASE(OSUB, TUINT32): + case CASE(OSUB, TPTR32): + a = ASUBL; + break; + + case CASE(OSUB, TINT64): + case CASE(OSUB, TUINT64): + case CASE(OSUB, TPTR64): + a = ASUBQ; + break; + + case CASE(OSUB, TFLOAT32): + a = ASUBSS; + break; + + case CASE(OSUB, TFLOAT64): + a = ASUBSD; + break; + + case CASE(OMINUS, TINT8): + case CASE(OMINUS, TUINT8): + a = ANEGB; + break; + + case CASE(OMINUS, TINT16): + case CASE(OMINUS, TUINT16): + a = ANEGW; + break; + + case CASE(OMINUS, TINT32): + case CASE(OMINUS, TUINT32): + case CASE(OMINUS, TPTR32): + a = ANEGL; + break; + + case CASE(OMINUS, TINT64): + case CASE(OMINUS, TUINT64): + case CASE(OMINUS, TPTR64): + a = ANEGQ; + break; + + case CASE(OMUL, TINT8): + a = AIMULB; + break; + + case CASE(OMUL, TUINT8): + a = AMULB; + break; + + case CASE(OMUL, TINT16): + a = AIMULW; + break; + + case CASE(OMUL, TUINT16): + a = AMULW; + break; + + case CASE(OMUL, TINT32): + a = AIMULL; + break; + + case CASE(OMUL, TUINT32): + case CASE(OMUL, TPTR32): + a = AMULL; + break; + + case CASE(OMUL, TINT64): + a = AIMULQ; + break; + + case CASE(OMUL, TUINT64): + case CASE(OMUL, TPTR64): + a = AMULQ; + break; + + case CASE(OMUL, TFLOAT32): + a = AMULSS; + break; + + case CASE(OMUL, TFLOAT64): + a = AMULSD; + break; + + case CASE(ODIV, TINT8): + a = AIDIVB; + break; + + case CASE(ODIV, TUINT8): + a = ADIVB; + break; + + case CASE(ODIV, TINT16): + a = AIDIVW; + break; + + case CASE(ODIV, TUINT16): + a = ADIVW; + break; + + case CASE(ODIV, TINT32): + a = AIDIVL; + break; + + case CASE(ODIV, TUINT32): + case CASE(ODIV, TPTR32): + a = ADIVL; + break; + + case CASE(ODIV, TINT64): + a = AIDIVQ; + break; + + case CASE(ODIV, TUINT64): + case CASE(ODIV, TPTR64): + a = ADIVQ; + break; + + case CASE(ODIV, TFLOAT32): + a = ADIVSS; + break; + + case CASE(ODIV, TFLOAT64): + a = ADIVSD; + break; + + } + return a; +} + +int +isfat(Type *t) +{ + if(t != T) + switch(t->etype) { + case TSTRUCT: + case TARRAY: + case TDARRAY: + case TINTER: // maybe remove later + return 1; + } + return 0; +} + +/* + * return unsigned(op) + * eg GT -> HS + */ +int +brunsigned(int a) +{ + switch(a) { + case AJLT: return AJGE; + case AJGT: return AJLE; + case AJLE: return AJGT; + case AJGE: return AJLT; + } + return a; +} + +/* + * return !(op) + * eg == <=> != + */ +int +brcom(int a) +{ + switch(a) { + case OEQ: return ONE; + case ONE: return OEQ; + case OLT: return OGE; + case OGT: return OLE; + case OLE: return OGT; + case OGE: return OLT; + } + fatal("brcom: no com for %A\n", a); + return a; +} + +/* + * return reverse(op) + * eg a op b <=> b r(op) a + */ +int +brrev(int a) +{ + switch(a) { + case OEQ: return OEQ; + case ONE: return ONE; + case OLT: return OGT; + case OGT: return OLT; + case OLE: return OGE; + case OGE: return OLE; + } + fatal("brcom: no rev for %A\n", a); + return a; +} + +/* + * make a new off the books + */ +void +tempname(Node *n, Type *t) +{ + Sym *s; + ulong w; + + if(t == T) { + yyerror("tempname called with nil type"); + t = types[TINT32]; + } + + s = lookup("!tmpname!"); + + memset(n, 0, sizeof(*n)); + n->op = ONAME; + n->sym = s; + n->type = t; + n->sym = s; + n->etype = t->etype; + n->class = PAUTO; + n->addable = 1; + n->ullman = 0; + + dowidth(t); + w = t->width; + stksize += w; + stksize = rnd(stksize, w); + n->xoffset = -stksize; +} + +void +stringpool(Node *n) +{ + Pool *p; + int w; + + if(n->op != OLITERAL || n->val.ctype != CTSTR) + fatal("stringpool: not string"); + + p = mal(sizeof(*p)); + + p->sval = n->val.sval; + p->link = nil; + + if(poolist == nil) + poolist = p; + else + poolast->link = p; + poolast = p; + + w = types[TINT32]->width; + symstringo->offset += w; // len + symstringo->offset += p->sval->len; // str[len] + symstringo->offset = rnd(symstringo->offset, w); +} + +Sig* +lsort(Sig *l, int(*f)(Sig*, Sig*)) +{ + Sig *l1, *l2, *le; + + if(l == 0 || l->link == 0) + return l; + + l1 = l; + l2 = l; + for(;;) { + l2 = l2->link; + if(l2 == 0) + break; + l2 = l2->link; + if(l2 == 0) + break; + l1 = l1->link; + } + + l2 = l1->link; + l1->link = 0; + l1 = lsort(l, f); + l2 = lsort(l2, f); + + /* set up lead element */ + if((*f)(l1, l2) < 0) { + l = l1; + l1 = l1->link; + } else { + l = l2; + l2 = l2->link; + } + le = l; + + for(;;) { + if(l1 == 0) { + while(l2) { + le->link = l2; + le = l2; + l2 = l2->link; + } + le->link = 0; + break; + } + if(l2 == 0) { + while(l1) { + le->link = l1; + le = l1; + l1 = l1->link; + } + break; + } + if((*f)(l1, l2) < 0) { + le->link = l1; + le = l1; + l1 = l1->link; + } else { + le->link = l2; + le = l2; + l2 = l2->link; + } + } + le->link = 0; + return l; +} + +void +setmaxarg(Type *t) +{ + Type *to; + long w; + + to = *getoutarg(t); + w = to->width; + if(w > maxarg) + maxarg = w; +} diff --git a/src/cmd/6g/list.c b/src/cmd/6g/list.c new file mode 100644 index 0000000000..361eb3cb9f --- /dev/null +++ b/src/cmd/6g/list.c @@ -0,0 +1,336 @@ +// Derived from Inferno utils/6c/list.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gg.h" + +static int sconsize; +void +listinit(void) +{ + + fmtinstall('A', Aconv); // as + fmtinstall('P', Pconv); // Prog* + fmtinstall('D', Dconv); // Addr* + fmtinstall('R', Rconv); // reg + fmtinstall('Y', Yconv); // sconst +} + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ]; + Prog *p; + + p = va_arg(fp->args, Prog*); + sconsize = 8; + if(p->as == ADATA) { + sconsize = p->from.scale; + snprint(str, sizeof(str), "%.4ld %-7A %D/%d,%D", + p->loc, p->as, &p->from, sconsize, &p->to); + return fmtstrcpy(fp, str); + } + snprint(str, sizeof(str), "%.4ld %-7A %D,%D", + p->loc, p->as, &p->from, &p->to); + return fmtstrcpy(fp, str); +} + +int +Dconv(Fmt *fp) +{ + char str[40], s[20]; + Addr *a; + int i; + + a = va_arg(fp->args, Addr*); + i = a->type; + if(i >= D_INDIR) { + if(a->offset) + sprint(str, "%lld(%R)", a->offset, i-D_INDIR); + else + sprint(str, "(%R)", i-D_INDIR); + goto brk; + } + switch(i) { + + default: + if(a->offset) + sprint(str, "$%lld,%R", a->offset, i); + else + sprint(str, "%R", i); + break; + + case D_NONE: + str[0] = 0; + break; + + case D_BRANCH: + snprint(str, sizeof(str), "%ld", a->branch->loc); + break; + + case D_EXTERN: + sprint(str, "%S+%lld(SB)", a->sym, a->offset); + break; + + case D_STATIC: + sprint(str, "%S<>+%lld(SB)", a->sym, a->offset); + break; + + case D_AUTO: + sprint(str, "%S+%lld(SP)", a->sym, a->offset); + break; + + case D_PARAM: + sprint(str, "%S+%lld(FP)", a->sym, a->offset); + break; + + case D_CONST: + sprint(str, "$%lld", a->offset); + break; + + case D_FCONST: + sprint(str, "$(%.17e)", a->dval); + break; + + case D_SCONST: + sprint(str, "$\"%Y\"", a->sval); + break; + + case D_ADDR: + a->type = a->index; + a->index = D_NONE; + sprint(str, "$%D", a); + a->index = a->type; + a->type = D_ADDR; + goto conv; + } +brk: + if(a->index != D_NONE) { + sprint(s, "(%R*%d)", (int)a->index, (int)a->scale); + strcat(str, s); + } +conv: + return fmtstrcpy(fp, str); +} + +static char* regstr[] = +{ + "AL", /* [D_AL] */ + "CL", + "DL", + "BL", + "SPB", + "BPB", + "SIB", + "DIB", + "R8B", + "R9B", + "R10B", + "R11B", + "R12B", + "R13B", + "R14B", + "R15B", + + "AX", /* [D_AX] */ + "CX", + "DX", + "BX", + "SP", + "BP", + "SI", + "DI", + "R8", + "R9", + "R10", + "R11", + "R12", + "R13", + "R14", + "R15", + + "AH", + "CH", + "DH", + "BH", + + "F0", /* [D_F0] */ + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + + "M0", + "M1", + "M2", + "M3", + "M4", + "M5", + "M6", + "M7", + + "X0", + "X1", + "X2", + "X3", + "X4", + "X5", + "X6", + "X7", + "X8", + "X9", + "X10", + "X11", + "X12", + "X13", + "X14", + "X15", + + "CS", /* [D_CS] */ + "SS", + "DS", + "ES", + "FS", + "GS", + + "GDTR", /* [D_GDTR] */ + "IDTR", /* [D_IDTR] */ + "LDTR", /* [D_LDTR] */ + "MSW", /* [D_MSW] */ + "TASK", /* [D_TASK] */ + + "CR0", /* [D_CR] */ + "CR1", + "CR2", + "CR3", + "CR4", + "CR5", + "CR6", + "CR7", + "CR8", + "CR9", + "CR10", + "CR11", + "CR12", + "CR13", + "CR14", + "CR15", + + "DR0", /* [D_DR] */ + "DR1", + "DR2", + "DR3", + "DR4", + "DR5", + "DR6", + "DR7", + + "TR0", /* [D_TR] */ + "TR1", + "TR2", + "TR3", + "TR4", + "TR5", + "TR6", + "TR7", + + "NONE", /* [D_NONE] */ +}; + +int +Rconv(Fmt *fp) +{ + char str[STRINGSZ]; + int r; + + r = va_arg(fp->args, int); + if(r < 0 || r >= nelem(regstr) || regstr[r] == nil) { + snprint(str, sizeof(str), "BAD_R(%d)", r); + return fmtstrcpy(fp, str); + } + return fmtstrcpy(fp, regstr[r]); +} + +int +Aconv(Fmt *fp) +{ + int i; + + i = va_arg(fp->args, int); + return fmtstrcpy(fp, anames[i]); +} + + +int +Yconv(Fmt *fp) +{ + int i, c; + char str[30], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + default: + if(c < 040 || c >= 0177) + break; /* not portable */ + p[-1] = c; + continue; + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} diff --git a/src/cmd/6g/obj.c b/src/cmd/6g/obj.c new file mode 100644 index 0000000000..47ae0abf05 --- /dev/null +++ b/src/cmd/6g/obj.c @@ -0,0 +1,604 @@ +// Derived from Inferno utils/6c/swt.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gg.h" + +void +dumpobj(void) +{ + Plist *pl; + Prog *p; + Dcl *d; + Sym *s; + Node *n; + struct { Sym *sym; short type; } h[NSYM]; + int sf, st, t, sym; + Node n1; + + // add nil plist w AEND + newplist(); + + bout = Bopen(outfile, OWRITE); + if(bout == nil) + fatal("cant open %s", outfile); + + Bprint(bout, "x86-64\n"); + Bprint(bout, " exports automatically generated from\n"); + Bprint(bout, " %s in package \"%s\"\n", curio.infile, package); + dumpexport(); + Bprint(bout, "\n!\n"); + + // add globals + nodconst(&n1, types[TINT32], 0); + for(d=externdcl; d!=D; d=d->forw) { + if(d->op != ONAME) + continue; + + s = d->dsym; + if(s == S) + fatal("external nil"); + n = d->dnode; + if(n == N || n->type == T) + fatal("external %S nil\n", s); + + if(n->type->etype == TFUNC) + continue; + + dowidth(n->type); + n1.val.vval = n->type->width; + + p = pc; + gins(AGLOBL, s->oname, &n1); + p->lineno = s->oname->lineno; + } + + dumpstrings(); + dumpsignatures(); + + for(sym=0; symlink) { + + if(debug['S']) { + s = S; + if(pl->name != N) + s = pl->name->sym; + print("\n--- prog list \"%S\" ---\n", s); + for(p=pl->firstpc; p!=P; p=p->link) + print("%P\n", p); + } + + for(p=pl->firstpc; p!=P; p=p->link) { + jackpot: + sf = 0; + s = p->from.sym; + while(s != S) { + sf = s->sym; + if(sf < 0 || sf >= NSYM) + sf = 0; + t = p->from.type; + if(t == D_ADDR) + t = p->from.index; + if(h[sf].type == t) + if(h[sf].sym == s) + break; + s->sym = sym; + zname(bout, s, t); + h[sym].sym = s; + h[sym].type = t; + sf = sym; + sym++; + if(sym >= NSYM) + sym = 1; + break; + } + st = 0; + s = p->to.sym; + while(s != S) { + st = s->sym; + if(st < 0 || st >= NSYM) + st = 0; + t = p->to.type; + if(t == D_ADDR) + t = p->to.index; + if(h[st].type == t) + if(h[st].sym == s) + break; + s->sym = sym; + zname(bout, s, t); + h[sym].sym = s; + h[sym].type = t; + st = sym; + sym++; + if(sym >= NSYM) + sym = 1; + if(st == sf) + goto jackpot; + break; + } + Bputc(bout, p->as); + Bputc(bout, p->as>>8); + Bputc(bout, p->lineno); + Bputc(bout, p->lineno>>8); + Bputc(bout, p->lineno>>16); + Bputc(bout, p->lineno>>24); + zaddr(bout, &p->from, sf); + zaddr(bout, &p->to, st); + } + } +} + +void +zname(Biobuf *b, Sym *s, int t) +{ + char *n; + + Bputc(b, ANAME); /* as */ + Bputc(b, ANAME>>8); /* as */ + Bputc(b, t); /* type */ + Bputc(b, s->sym); /* sym */ + + for(n=s->opackage; *n; n++) + Bputc(b, *n); + Bputc(b, '_'); + for(n=s->name; *n; n++) + Bputc(b, *n); + Bputc(b, 0); +} + +void +zaddr(Biobuf *b, Addr *a, int s) +{ + long l; + int i, t; + char *n; + Ieee e; + + t = 0; + if(a->index != D_NONE || a->scale != 0) + t |= T_INDEX; + if(s != 0) + t |= T_SYM; + + switch(a->type) { + default: + t |= T_TYPE; + case D_NONE: + if(a->offset != 0) { + t |= T_OFFSET; + l = a->offset; + if((vlong)l != a->offset) + t |= T_64; + } + break; + case D_FCONST: + t |= T_FCONST; + break; + case D_SCONST: + t |= T_SCONST; + break; + } + Bputc(b, t); + + if(t & T_INDEX) { /* implies index, scale */ + Bputc(b, a->index); + Bputc(b, a->scale); + } + if(t & T_OFFSET) { /* implies offset */ + l = a->offset; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + if(t & T_64) { + l = a->offset>>32; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + } + } + if(t & T_SYM) /* implies sym */ + Bputc(b, s); + if(t & T_FCONST) { + ieeedtod(&e, a->dval); + l = e.l; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + l = e.h; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + return; + } + if(t & T_SCONST) { + n = a->sval; + for(i=0; itype); +} + +void +ieeedtod(Ieee *ieee, double native) +{ + double fr, ho, f; + int exp; + + if(native < 0) { + ieeedtod(ieee, -native); + ieee->h |= 0x80000000L; + return; + } + if(native == 0) { + ieee->l = 0; + ieee->h = 0; + return; + } + fr = frexp(native, &exp); + f = 2097152L; /* shouldnt use fp constants here */ + fr = modf(fr*f, &ho); + ieee->h = ho; + ieee->h &= 0xfffffL; + ieee->h |= (exp+1022L) << 20; + f = 65536L; + fr = modf(fr*f, &ho); + ieee->l = ho; + ieee->l <<= 16; + ieee->l |= (long)(fr*f); +} + +void +datastring(char *s, int len) +{ + int w; + Prog *p; + Addr ac, ao; + + // string + memset(&ao, 0, sizeof(ao)); + ao.type = D_STATIC; + ao.index = D_NONE; + ao.etype = TINT32; + ao.sym = symstringo; + ao.offset = 0; // fill in + + // constant + memset(&ac, 0, sizeof(ac)); + ac.type = D_CONST; + ac.index = D_NONE; + ac.offset = 0; // fill in + + for(w=0; w+oo, [NSNAME], $"xxx" + p->from = ao; + p->from.offset = stringo; + + p->from.scale = NSNAME; + if(w+8 > len) + p->from.scale = len-w; + + p->to = ac; + p->to.type = D_SCONST; + p->to.offset = len; + memmove(p->to.sval, s+w, p->from.scale); + stringo += p->from.scale; + } +} + +void +dumpstrings(void) +{ + Pool *l; + Prog *p; + Addr ac, ao; + long wi; + + if(poolist == nil) + return; + + memset(&ac, 0, sizeof(ac)); + memset(&ao, 0, sizeof(ao)); + + // constant + ac.type = D_CONST; + ac.index = D_NONE; + ac.offset = 0; // fill in + + // string len+ptr + ao.type = D_STATIC; + ao.index = D_NONE; + ao.etype = TINT32; + ao.sym = symstringo; + ao.offset = 0; // fill in + + wi = types[TINT32]->width; + + // lay out (count+string) + for(l=poolist; l!=nil; l=l->link) { + + p = pc; + gins(ADATA, N, N); + + // .stringo<>+xx, wi, $len + stringo = rnd(stringo, wi); + p->from = ao; + p->from.offset = stringo; + p->from.scale = wi; + p->to = ac; + p->to.offset = l->sval->len; + stringo += wi; + + datastring(l->sval->s, l->sval->len); + } +} + +static int +sigcmp(Sig *a, Sig *b) +{ + return strcmp(a->name, b->name); +} + +void +dumpsignatures(void) +{ + Dcl *d; + Type *t, *f; + Sym *s1, *s; + int et, o, wi, ot; + Sig *a, *b; + Addr at, ao, ac, ad; + Prog *p; + char *sp; + + /* + * put all the names into a linked + * list so that it may be generated in sorted order. + * the runtime will be linear rather than quadradic + */ + + memset(&at, 0, sizeof(at)); + memset(&ao, 0, sizeof(ao)); + memset(&ac, 0, sizeof(ac)); + memset(&ad, 0, sizeof(ad)); + + // sig structure + at.type = D_EXTERN; + at.index = D_NONE; + at.sym = S; // fill in + at.offset = 0; // fill in + + // $string + ao.type = D_ADDR; + ao.index = D_STATIC; + ao.etype = TINT32; + ao.sym = symstringo; + ao.offset = 0; // fill in + + // constant + ac.type = D_CONST; + ac.index = D_NONE; + ac.offset = 0; // fill in + + // $method + ad.type = D_ADDR; + ad.index = D_EXTERN; + ad.sym = S; // fill in + ad.offset = 0; + + wi = types[TINT32]->width; + + for(d=externdcl; d!=D; d=d->forw) { + if(d->op != OTYPE) + continue; + + t = d->dtype; + et = t->etype; + if(et != TSTRUCT && et != TINTER) + continue; + + s = d->dsym; + if(s == S) + continue; + + if(s->name[0] == '_') + continue; + + if(strcmp(s->opackage, package) != 0) + continue; + + at.sym = signame(t); + + a = nil; + o = 0; + for(f=t->type; f!=T; f=f->down) { + if(f->type->etype != TFUNC) + continue; + + if(f->etype != TFIELD) + fatal("dumpsignatures: not field"); + + s1 = f->sym; + if(s1 == nil) + continue; + if(s1->name[0] == '_') + continue; + + b = mal(sizeof(*b)); + b->link = a; + a = b; + + a->name = s1->name; + sp = strchr(s1->name, '_'); + if(sp != nil) + a->name = sp+1; + + a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0); + a->sym = f->sym; + a->offset = o; + o++; + } + + a = lsort(a, sigcmp); + ot = 0; + + if(et == TINTER) { + o = 0; + for(b=a; b!=nil; b=b->link) + o++; + + // sigi[0].name = "" + ot = rnd(ot, maxround); + p = pc; + gins(ADATA, N, N); + p->from = at; + p->from.offset = ot; + p->from.scale = widthptr; + p->to = ao; + p->to.offset = stringo; + ot += widthptr; + + // sigi[0].hash = 0 + ot = rnd(ot, wi); + p = pc; + gins(ADATA, N, N); + p->from = at; + p->from.offset = ot; + p->from.scale = wi; + p->to = ac; + p->to.offset = 0; + ot += wi; + + // sigi[0].offset = count + ot = rnd(ot, wi); + p = pc; + gins(ADATA, N, N); + p->from = at; + p->from.offset = ot; + p->from.scale = wi; + p->to = ac; + p->to.offset = o; + ot += wi; + + datastring("", 1); + + } + + for(b=a; b!=nil; b=b->link) { + + // sigx[++].name = "fieldname" + ot = rnd(ot, maxround); + p = pc; + gins(ADATA, N, N); + p->from = at; + p->from.offset = ot; + p->from.scale = widthptr; + p->to = ao; + p->to.offset = stringo; + ot += widthptr; + + // sigx[++].hash = hashcode + ot = rnd(ot, wi); + p = pc; + gins(ADATA, N, N); + p->from = at; + p->from.offset = ot; + p->from.scale = wi; + p->to = ac; + p->to.offset = b->hash; + ot += wi; + + if(et == TINTER) { + // sigi[++].offset = offset of method + ot = rnd(ot, wi); + p = pc; + gins(ADATA, N, N); + p->from = at; + p->from.offset = ot; + p->from.scale = wi; + p->to = ac; + p->to.offset = b->offset; + ot += wi; + } else { + // sigs[++].fun = &method + ot = rnd(ot, widthptr); + p = pc; + gins(ADATA, N, N); + p->from = at; + p->from.offset = ot; + p->from.scale = widthptr; + p->to = ad; + p->to.sym = b->sym; + ot += widthptr; + } + datastring(b->name, strlen(b->name)+1); + } + + // nil field name at end + ot = rnd(ot, maxround); + p = pc; + gins(ADATA, N, N); + p->from = at; + p->from.offset = ot; + p->from.scale = widthptr; + p->to = ac; + p->to.offset = 0; + ot += widthptr; + + p = pc; + gins(AGLOBL, N, N); + p->from = at; + p->to = ac; + p->to.offset = ot; + } + + if(stringo > 0) { + p = pc; + gins(AGLOBL, N, N); + p->from = ao; + p->to = ac; + p->to.offset = stringo; + } +} diff --git a/src/cmd/6g/runtime.c b/src/cmd/6g/runtime.c new file mode 100644 index 0000000000..482e013196 --- /dev/null +++ b/src/cmd/6g/runtime.c @@ -0,0 +1,595 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" + +int32 debug = 0; + +void +sys_printbool(bool v) +{ + if(v) { + sys_write(1, (byte*)"true", 4); + return; + } + sys_write(1, (byte*)"false", 5); +} + +void +sys_printfloat(float64 v) +{ + sys_write(1, "printfloat", 10); +} + +void +sys_printint(int64 v) +{ + byte buf[100]; + int32 i, s; + + s = 0; + if(v < 0) { + v = -v; + s = 1; + if(v < 0) { + sys_write(1, (byte*)"-oo", 3); + return; + } + } + + for(i=nelem(buf)-1; i>0; i--) { + buf[i] = v%10 + '0'; + if(v < 10) + break; + v = v/10; + } + if(s) { + i--; + buf[i] = '-'; + } + sys_write(1, buf+i, nelem(buf)-i); +} + +void +sys_printpointer(void *p) +{ + uint64 v; + byte buf[100]; + int32 i; + + v = (int64)p; + for(i=nelem(buf)-1; i>0; i--) { + buf[i] = v%16 + '0'; + if(buf[i] > '9') + buf[i] += 'a'-'0'-10; + if(v < 16) + break; + v = v/16; + } + sys_write(1, buf+i, nelem(buf)-i); +} + +void +sys_panicl(int32 lno) +{ + prints("\npanic on line "); + sys_printint(lno); + prints("\n"); + *(int32*)0 = 0; +} + +void +sys_printstring(string v) +{ + sys_write(1, v->str, v->len); +} + +int32 +strlen(int8 *s) +{ + int32 l; + + for(l=0; s[l]!=0; l++) + ; + return l; +} + +void +prints(int8 *s) +{ + sys_write(1, s, strlen(s)); +} + +dump(byte *p, int32 n) +{ + uint32 v; + int32 i; + + for(i=0; i>4)); + sys_printpointer((byte*)(p[i]&0xf)); + if((i&15) == 15) + prints("\n"); + else + prints(" "); + } + if(n & 15) + prints("\n"); +} + +static uint8* hunk; +static uint32 nhunk; +static uint64 nmmap; +static uint64 nmal; +enum +{ + NHUNK = 20<<20, + + PROT_NONE = 0x00, + PROT_READ = 0x01, + PROT_WRITE = 0x02, + PROT_EXEC = 0x04, + + MAP_FILE = 0x0000, + MAP_SHARED = 0x0001, + MAP_PRIVATE = 0x0002, + MAP_FIXED = 0x0010, + MAP_ANON = 0x1000, +}; + +static void +throw(int8 *s) +{ + prints("throw: "); + prints(s); + prints("\n"); + sys_exit(1); +} + +static void +mcpy(byte *t, byte *f, uint32 n) +{ + while(n > 0) { + *t = *f; + t++; + f++; + n--; + } +} + +static byte* +brk(uint32 n) +{ + byte* v; + + v = sys_mmap(nil, NHUNK, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0); + sys_memclr(v, n); + nmmap += n; + return v; +} + +static void* +mal(uint32 n) +{ + byte* v; + + // round to keep everything 64-bit alligned + while(n & 7) + n++; + + nmal += n; + + // do we have enough in contiguous hunk + if(n > nhunk) { + + // if it is big allocate it separately + if(n > NHUNK) + return brk(n); + + // allocate a new contiguous hunk + hunk = brk(NHUNK); + nhunk = NHUNK; + } + + // allocate from the contiguous hunk + v = hunk; + hunk += n; + nhunk -= n; + return v; +} + +void +sys_mal(uint32 n, uint8 *ret) +{ + ret = mal(n); + FLUSH(&ret); +} + +void +sys_catstring(string s1, string s2, string s3) +{ + uint32 l; + + if(s1->len == 0) { + s3 = s2; + goto out; + } + if(s2->len == 0) { + s3 = s1; + goto out; + } + + l = s1->len + s2->len; + + s3 = mal(sizeof(s3->len)+l); + s3->len = l; + mcpy(s3->str, s1->str, s1->len); + mcpy(s3->str+s1->len, s2->str, s2->len); + +out: + FLUSH(&s3); +} + +void +sys_cmpstring(string s1, string s2, int32 v) +{ + uint32 i, l; + byte c1, c2; + + l = s1->len; + if(s2->len < l) + l = s2->len; + for(i=0; istr[i]; + c2 = s2->str[i]; + if(c1 < c2) { + v = -1; + goto out; + } + if(c1 > c2) { + v = +1; + goto out; + } + } + if(s1->len < s2->len) { + v = -1; + goto out; + } + if(s1->len > s2->len) { + v = +1; + goto out; + } + v = 0; + +out: + FLUSH(&v); +} + +static int32 +strcmp(byte *s1, byte *s2) +{ + uint32 i; + byte c1, c2; + + for(i=0;; i++) { + c1 = s1[i]; + c2 = s2[i]; + if(c1 < c2) + return -1; + if(c1 > c2) + return +1; + if(c1 == 0) + return 0; + } +} + +static void +prbounds(int8* s, int32 a, int32 b, int32 c) +{ + int32 i; + + prints(s); + prints(" "); + sys_printint(a); + prints("<"); + sys_printint(b); + prints(">"); + sys_printint(c); + prints("\n"); + throw("bounds"); +} + +void +sys_slicestring(string si, int32 lindex, int32 hindex, string so) +{ + string s, str; + int32 l; + + if(lindex < 0 || lindex > si->len || + hindex < lindex || hindex > si->len) + prbounds("slice", lindex, si->len, hindex); + + l = hindex-lindex; + so = mal(sizeof(so->len)+l); + so->len = l; + mcpy(so->str, si->str+lindex, l); + FLUSH(&so); +} + +void +sys_indexstring(string s, int32 i, byte b) +{ + if(i < 0 || i >= s->len) + prbounds("index", 0, i, s->len); + + b = s->str[i]; + FLUSH(&b); +} + +/* + * this is the plan9 runetochar + * extended for 36 bits in 7 bytes + * note that it truncates to 32 bits + * through the argument passing. + */ +static int32 +runetochar(byte *str, uint32 c) +{ + int32 i, n; + uint32 mask, mark; + + /* + * one character in 7 bits + */ + if(c <= 0x07FUL) { + str[0] = c; + return 1; + } + + /* + * every new character picks up 5 bits + * one less in the first byte and + * six more in an extension byte + */ + mask = 0x7ffUL; + mark = 0xC0UL; + for(n=1;; n++) { + if(c <= mask) + break; + mask = (mask<<5) | 0x1fUL; + mark = (mark>>1) | 0x80UL; + } + + /* + * lay down the bytes backwards + * n is the number of extension bytes + * mask is the max codepoint + * mark is the zeroth byte indicator + */ + for(i=n; i>0; i--) { + str[i] = 0x80UL | (c&0x3fUL); + c >>= 6; + } + + str[0] = mark|c; + return n+1; +} + +void +sys_intstring(int64 v, string s) +{ + int32 l; + + s = mal(sizeof(s->len)+8); + s->len = runetochar(s->str, v); + FLUSH(&s); +} + +void +sys_byteastring(byte *a, int32 l, string s) +{ + s = mal(sizeof(s->len)+l); + s->len = l; + mcpy(s->str, a, l); + FLUSH(&s); +} + +static Map* hash[1009]; + +static Map* +hashmap(Sigi *si, Sigs *ss) +{ + int32 ns, ni; + uint32 ihash, h; + byte *sname, *iname; + Map *m; + + h = ((uint32)si + (uint32)ss) % nelem(hash); + for(m=hash[h]; m!=nil; m=m->link) { + if(m->si == si && m->ss == ss) { + if(m->bad) { + throw("bad hashmap"); + m = nil; + } + // prints("old hashmap\n"); + return m; + } + } + + ni = si[0].offset; // first word has size + m = mal(sizeof(*m) + ni*sizeof(m->fun[0])); + m->si = si; + m->ss = ss; + + ni = 1; // skip first word + ns = 0; + +loop1: + // pick up next name from + // interface signature + iname = si[ni].name; + if(iname == nil) { + m->link = hash[h]; + hash[h] = m; + // prints("new hashmap\n"); + return m; + } + ihash = si[ni].hash; + +loop2: + // pick up and comapre next name + // from structure signature + sname = ss[ns].name; + if(sname == nil) { + prints((int8*)iname); + prints(": "); + throw("hashmap: failed to find method"); + m->bad = 1; + m->link = hash[h]; + hash[h] = m; + return nil; + } + if(ihash != ss[ns].hash || + strcmp(sname, iname) != 0) { + ns++; + goto loop2; + } + + m->fun[si[ni].offset] = ss[ns].fun; + ni++; + goto loop1; +} + +void +sys_ifaces2i(Sigi *si, Sigs *ss, Map *m, void *s) +{ + + if(debug) { + prints("s2i sigi="); + sys_printpointer(si); + prints(" sigs="); + sys_printpointer(ss); + prints(" s="); + sys_printpointer(s); + } + + if(s == nil) { + throw("ifaces2i: nil pointer"); + m = nil; + FLUSH(&m); + return; + } + + m = hashmap(si, ss); + + if(debug) { + prints(" returning m="); + sys_printpointer(m); + prints(" s="); + sys_printpointer(s); + prints("\n"); + dump((byte*)m, 64); + } + + FLUSH(&m); +} + +void +sys_ifacei2i(Sigi *si, Map *m, void *s) +{ + + if(debug) { + prints("i2i sigi="); + sys_printpointer(si); + prints(" m="); + sys_printpointer(m); + prints(" s="); + sys_printpointer(s); + } + + if(m == nil) { + throw("ifacei2i: nil map"); + s = nil; + FLUSH(&s); + return; + } + + if(m->si == nil) { + throw("ifacei2i: nil pointer"); + return; + } + + if(m->si != si) { + m = hashmap(si, m->ss); + FLUSH(&m); + } + + if(debug) { + prints(" returning m="); + sys_printpointer(m); + prints(" s="); + sys_printpointer(s); + prints("\n"); + dump((byte*)m, 64); + } +} + +void +sys_ifacei2s(Sigs *ss, Map *m, void *s) +{ + + if(debug) { + prints("i2s m="); + sys_printpointer(m); + prints(" s="); + sys_printpointer(s); + prints("\n"); + } + + if(m == nil) { + throw("ifacei2s: nil map"); + s = nil; + FLUSH(&s); + return; + } + + if(m->ss != ss) { + dump((byte*)m, 64); + throw("ifacei2s: wrong pointer"); + s = nil; + FLUSH(&s); + return; + } +} + +void +check(void) +{ + int8 a; + uint8 b; + int16 c; + uint16 d; + int32 e; + uint32 f; + int64 g; + uint64 h; + float32 i; + float64 j; + void* k; + uint16* l; + + if(sizeof(a) != 1) throw("bad a"); + if(sizeof(b) != 1) throw("bad b"); + if(sizeof(c) != 2) throw("bad c"); + if(sizeof(d) != 2) throw("bad d"); + if(sizeof(e) != 4) throw("bad e"); + if(sizeof(f) != 4) throw("bad f"); + if(sizeof(g) != 8) throw("bad g"); + if(sizeof(h) != 8) throw("bad h"); + if(sizeof(i) != 4) throw("bad i"); + if(sizeof(j) != 8) throw("bad j"); + if(sizeof(k) != 8) throw("bad k"); + if(sizeof(l) != 8) throw("bad l"); +// prints(1"check ok\n"); +} diff --git a/src/cmd/6g/runtime.h b/src/cmd/6g/runtime.h new file mode 100644 index 0000000000..6220a034b0 --- /dev/null +++ b/src/cmd/6g/runtime.h @@ -0,0 +1,107 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + + +/* + * basic types + */ +typedef signed char int8; +typedef unsigned char uint8; +typedef signed short int16; +typedef unsigned short uint16; +typedef signed int int32; +typedef unsigned int uint32; +typedef signed long long int int64; +typedef unsigned long long int uint64; +typedef float float32; +typedef double float64; + +/* + * get rid of C types + */ +#define unsigned XXunsigned +#define signed XXsigned +#define char XXchar +#define short XXshort +#define int XXint +#define long XXlong +#define float XXfloat +#define double XXdouble + +/* + * defined types + */ +typedef uint8 bool; +typedef uint8 byte; +typedef struct +{ + int32 len; + byte str[1]; +} *string; +typedef struct +{ + byte* name; + uint32 hash; + void (*fun)(void); +} Sigs; +typedef struct +{ + byte* name; + uint32 hash; + uint32 offset; +} Sigi; +typedef struct Map Map; +struct Map +{ + Sigi* si; + Sigs* ss; + Map* link; + int32 bad; + int32 unused; + void (*fun[])(void); +}; + +/* + * defined constants + */ +enum +{ + true = 1, + false = 0, +}; + +/* + * defined macros + * you need super-goru privilege + * to add this list. + */ +#define nelem(x) (sizeof(x)/sizeof((x)[0])) +#define nil ((void*)0) + +/* + * very low level + */ +void FLUSH(void*); +void prints(int8*); +void sys_exit(int32); +void sys_write(int32, void*, int32); +void sys_breakpoint(void); +uint8* sys_mmap(byte*, uint32, int32, int32, int32, uint32); +void sys_memclr(byte*, uint32); + +/* + * runtime + */ +void sys_printbool(bool); +void sys_printfloat(float64); +void sys_printint(int64); +void sys_printstring(string); +void sys_catstring(string, string, string); +void sys_cmpstring(string, string, int32); +void sys_slicestring(string, int32, int32, string); +void sys_indexstring(string, int32, byte); +void sys_intstring(int64, string); +void sys_ifaces2i(Sigi*, Sigs*, Map*, void*); +void sys_ifacei2i(Sigi*, Map*, void*); +void sys_ifacei2s(Sigs*, Map*, void*); diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h new file mode 100644 index 0000000000..8006826405 --- /dev/null +++ b/src/cmd/6l/6.out.h @@ -0,0 +1,857 @@ +// Inferno utils/6c/6.out.h +// http://code.google.com/p/inferno-os/source/browse/utils/6c/6.out.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define NSYM 50 +#define NSNAME 8 +#define NOPROF (1<<0) +#define DUPOK (1<<1) + +/* + * amd64 + */ + +enum as +{ + AXXX, + AAAA, + AAAD, + AAAM, + AAAS, + AADCB, + AADCL, + AADCW, + AADDB, + AADDL, + AADDW, + AADJSP, + AANDB, + AANDL, + AANDW, + AARPL, + ABOUNDL, + ABOUNDW, + ABSFL, + ABSFW, + ABSRL, + ABSRW, + ABTL, + ABTW, + ABTCL, + ABTCW, + ABTRL, + ABTRW, + ABTSL, + ABTSW, + ABYTE, + ACALL, + ACLC, + ACLD, + ACLI, + ACLTS, + ACMC, + ACMPB, + ACMPL, + ACMPW, + ACMPSB, + ACMPSL, + ACMPSW, + ADAA, + ADAS, + ADATA, + ADECB, + ADECL, + ADECQ, + ADECW, + ADIVB, + ADIVL, + ADIVW, + AENTER, + AGLOBL, + AGOK, + AHISTORY, + AHLT, + AIDIVB, + AIDIVL, + AIDIVW, + AIMULB, + AIMULL, + AIMULW, + AINB, + AINL, + AINW, + AINCB, + AINCL, + AINCQ, + AINCW, + AINSB, + AINSL, + AINSW, + AINT, + AINTO, + AIRETL, + AIRETW, + AJCC, + AJCS, + AJCXZ, + AJEQ, + AJGE, + AJGT, + AJHI, + AJLE, + AJLS, + AJLT, + AJMI, + AJMP, + AJNE, + AJOC, + AJOS, + AJPC, + AJPL, + AJPS, + ALAHF, + ALARL, + ALARW, + ALEAL, + ALEAW, + ALEAVEL, + ALEAVEW, + ALOCK, + ALODSB, + ALODSL, + ALODSW, + ALONG, + ALOOP, + ALOOPEQ, + ALOOPNE, + ALSLL, + ALSLW, + AMOVB, + AMOVL, + AMOVW, + AMOVBLSX, + AMOVBLZX, + AMOVBQSX, + AMOVBQZX, + AMOVBWSX, + AMOVBWZX, + AMOVWLSX, + AMOVWLZX, + AMOVWQSX, + AMOVWQZX, + AMOVSB, + AMOVSL, + AMOVSW, + AMULB, + AMULL, + AMULW, + ANAME, + ANEGB, + ANEGL, + ANEGW, + ANOP, + ANOTB, + ANOTL, + ANOTW, + AORB, + AORL, + AORW, + AOUTB, + AOUTL, + AOUTW, + AOUTSB, + AOUTSL, + AOUTSW, + APOPAL, + APOPAW, + APOPFL, + APOPFW, + APOPL, + APOPW, + APUSHAL, + APUSHAW, + APUSHFL, + APUSHFW, + APUSHL, + APUSHW, + ARCLB, + ARCLL, + ARCLW, + ARCRB, + ARCRL, + ARCRW, + AREP, + AREPN, + ARET, + AROLB, + AROLL, + AROLW, + ARORB, + ARORL, + ARORW, + ASAHF, + ASALB, + ASALL, + ASALW, + ASARB, + ASARL, + ASARW, + ASBBB, + ASBBL, + ASBBW, + ASCASB, + ASCASL, + ASCASW, + ASETCC, + ASETCS, + ASETEQ, + ASETGE, + ASETGT, + ASETHI, + ASETLE, + ASETLS, + ASETLT, + ASETMI, + ASETNE, + ASETOC, + ASETOS, + ASETPC, + ASETPL, + ASETPS, + ACDQ, + ACWD, + ASHLB, + ASHLL, + ASHLW, + ASHRB, + ASHRL, + ASHRW, + ASTC, + ASTD, + ASTI, + ASTOSB, + ASTOSL, + ASTOSW, + ASUBB, + ASUBL, + ASUBW, + ASYSCALL, + ATESTB, + ATESTL, + ATESTW, + ATEXT, + AVERR, + AVERW, + AWAIT, + AWORD, + AXCHGB, + AXCHGL, + AXCHGW, + AXLAT, + AXORB, + AXORL, + AXORW, + + AFMOVB, + AFMOVBP, + AFMOVD, + AFMOVDP, + AFMOVF, + AFMOVFP, + AFMOVL, + AFMOVLP, + AFMOVV, + AFMOVVP, + AFMOVW, + AFMOVWP, + AFMOVX, + AFMOVXP, + + AFCOMB, + AFCOMBP, + AFCOMD, + AFCOMDP, + AFCOMDPP, + AFCOMF, + AFCOMFP, + AFCOML, + AFCOMLP, + AFCOMW, + AFCOMWP, + AFUCOM, + AFUCOMP, + AFUCOMPP, + + AFADDDP, + AFADDW, + AFADDL, + AFADDF, + AFADDD, + + AFMULDP, + AFMULW, + AFMULL, + AFMULF, + AFMULD, + + AFSUBDP, + AFSUBW, + AFSUBL, + AFSUBF, + AFSUBD, + + AFSUBRDP, + AFSUBRW, + AFSUBRL, + AFSUBRF, + AFSUBRD, + + AFDIVDP, + AFDIVW, + AFDIVL, + AFDIVF, + AFDIVD, + + AFDIVRDP, + AFDIVRW, + AFDIVRL, + AFDIVRF, + AFDIVRD, + + AFXCHD, + AFFREE, + + AFLDCW, + AFLDENV, + AFRSTOR, + AFSAVE, + AFSTCW, + AFSTENV, + AFSTSW, + + AF2XM1, + AFABS, + AFCHS, + AFCLEX, + AFCOS, + AFDECSTP, + AFINCSTP, + AFINIT, + AFLD1, + AFLDL2E, + AFLDL2T, + AFLDLG2, + AFLDLN2, + AFLDPI, + AFLDZ, + AFNOP, + AFPATAN, + AFPREM, + AFPREM1, + AFPTAN, + AFRNDINT, + AFSCALE, + AFSIN, + AFSINCOS, + AFSQRT, + AFTST, + AFXAM, + AFXTRACT, + AFYL2X, + AFYL2XP1, + + AEND, + + ADYNT, + AINIT, + + ASIGNAME, + + /* extra 32-bit operations */ + ACMPXCHGB, + ACMPXCHGL, + ACMPXCHGW, + ACMPXCHG8B, + ACPUID, + AINVD, + AINVLPG, + ALFENCE, + AMFENCE, + AMOVNTIL, + ARDMSR, + ARDPMC, + ARDTSC, + ARSM, + ASFENCE, + ASYSRET, + AWBINVD, + AWRMSR, + AXADDB, + AXADDL, + AXADDW, + + /* conditional move */ + ACMOVLCC, + ACMOVLCS, + ACMOVLEQ, + ACMOVLGE, + ACMOVLGT, + ACMOVLHI, + ACMOVLLE, + ACMOVLLS, + ACMOVLLT, + ACMOVLMI, + ACMOVLNE, + ACMOVLOC, + ACMOVLOS, + ACMOVLPC, + ACMOVLPL, + ACMOVLPS, + ACMOVQCC, + ACMOVQCS, + ACMOVQEQ, + ACMOVQGE, + ACMOVQGT, + ACMOVQHI, + ACMOVQLE, + ACMOVQLS, + ACMOVQLT, + ACMOVQMI, + ACMOVQNE, + ACMOVQOC, + ACMOVQOS, + ACMOVQPC, + ACMOVQPL, + ACMOVQPS, + ACMOVWCC, + ACMOVWCS, + ACMOVWEQ, + ACMOVWGE, + ACMOVWGT, + ACMOVWHI, + ACMOVWLE, + ACMOVWLS, + ACMOVWLT, + ACMOVWMI, + ACMOVWNE, + ACMOVWOC, + ACMOVWOS, + ACMOVWPC, + ACMOVWPL, + ACMOVWPS, + + /* 64-bit */ + AADCQ, + AADDQ, + AANDQ, + ABSFQ, + ABSRQ, + ABTCQ, + ABTQ, + ABTRQ, + ABTSQ, + ACMPQ, + ACMPSQ, + ACMPXCHGQ, + ACQO, + ADIVQ, + AIDIVQ, + AIMULQ, + AIRETQ, + ALEAQ, + ALEAVEQ, + ALODSQ, + AMOVQ, + AMOVLQSX, + AMOVLQZX, + AMOVNTIQ, + AMOVSQ, + AMULQ, + ANEGQ, + ANOTQ, + AORQ, + APOPFQ, + APOPQ, + APUSHFQ, + APUSHQ, + ARCLQ, + ARCRQ, + AROLQ, + ARORQ, + AQUAD, + ASALQ, + ASARQ, + ASBBQ, + ASCASQ, + ASHLQ, + ASHRQ, + ASTOSQ, + ASUBQ, + ATESTQ, + AXADDQ, + AXCHGQ, + AXORQ, + + /* media */ + AADDPD, + AADDPS, + AADDSD, + AADDSS, + AANDNPD, + AANDNPS, + AANDPD, + AANDPS, + ACMPPD, + ACMPPS, + ACMPSD, + ACMPSS, + ACOMISD, + ACOMISS, + ACVTPD2PL, + ACVTPD2PS, + ACVTPL2PD, + ACVTPL2PS, + ACVTPS2PD, + ACVTPS2PL, + ACVTSD2SL, + ACVTSD2SQ, + ACVTSD2SS, + ACVTSL2SD, + ACVTSL2SS, + ACVTSQ2SD, + ACVTSQ2SS, + ACVTSS2SD, + ACVTSS2SL, + ACVTSS2SQ, + ACVTTPD2PL, + ACVTTPS2PL, + ACVTTSD2SL, + ACVTTSD2SQ, + ACVTTSS2SL, + ACVTTSS2SQ, + ADIVPD, + ADIVPS, + ADIVSD, + ADIVSS, + AEMMS, + AFXRSTOR, + AFXRSTOR64, + AFXSAVE, + AFXSAVE64, + ALDMXCSR, + AMASKMOVOU, + AMASKMOVQ, + AMAXPD, + AMAXPS, + AMAXSD, + AMAXSS, + AMINPD, + AMINPS, + AMINSD, + AMINSS, + AMOVAPD, + AMOVAPS, + AMOVOU, + AMOVHLPS, + AMOVHPD, + AMOVHPS, + AMOVLHPS, + AMOVLPD, + AMOVLPS, + AMOVMSKPD, + AMOVMSKPS, + AMOVNTO, + AMOVNTPD, + AMOVNTPS, + AMOVNTQ, + AMOVO, + AMOVQOZX, + AMOVSD, + AMOVSS, + AMOVUPD, + AMOVUPS, + AMULPD, + AMULPS, + AMULSD, + AMULSS, + AORPD, + AORPS, + APACKSSLW, + APACKSSWB, + APACKUSWB, + APADDB, + APADDL, + APADDQ, + APADDSB, + APADDSW, + APADDUSB, + APADDUSW, + APADDW, + APANDB, + APANDL, + APANDSB, + APANDSW, + APANDUSB, + APANDUSW, + APANDW, + APAND, + APANDN, + APAVGB, + APAVGW, + APCMPEQB, + APCMPEQL, + APCMPEQW, + APCMPGTB, + APCMPGTL, + APCMPGTW, + APEXTRW, + APFACC, + APFADD, + APFCMPEQ, + APFCMPGE, + APFCMPGT, + APFMAX, + APFMIN, + APFMUL, + APFNACC, + APFPNACC, + APFRCP, + APFRCPIT1, + APFRCPI2T, + APFRSQIT1, + APFRSQRT, + APFSUB, + APFSUBR, + APINSRW, + APMADDWL, + APMAXSW, + APMAXUB, + APMINSW, + APMINUB, + APMOVMSKB, + APMULHRW, + APMULHUW, + APMULHW, + APMULLW, + APMULULQ, + APOR, + APSADBW, + APSHUFHW, + APSHUFL, + APSHUFLW, + APSHUFW, + APSLLO, + APSLLL, + APSLLQ, + APSLLW, + APSRAL, + APSRAW, + APSRLO, + APSRLL, + APSRLQ, + APSRLW, + APSUBB, + APSUBL, + APSUBQ, + APSUBSB, + APSUBSW, + APSUBUSB, + APSUBUSW, + APSUBW, + APSWAPL, + APUNPCKHBW, + APUNPCKHLQ, + APUNPCKHQDQ, + APUNPCKHWL, + APUNPCKLBW, + APUNPCKLLQ, + APUNPCKLQDQ, + APUNPCKLWL, + APXOR, + ARCPPS, + ARCPSS, + ARSQRTPS, + ARSQRTSS, + ASHUFPD, + ASHUFPS, + ASQRTPD, + ASQRTPS, + ASQRTSD, + ASQRTSS, + ASTMXCSR, + ASUBPD, + ASUBPS, + ASUBSD, + ASUBSS, + AUCOMISD, + AUCOMISS, + AUNPCKHPD, + AUNPCKHPS, + AUNPCKLPD, + AUNPCKLPS, + AXORPD, + AXORPS, + + APF2IW, + APF2IL, + API2FW, + API2FL, + ARETFW, + ARETFL, + ARETFQ, + ASWAPGS, + + AMODE, + + ALAST +}; + +enum +{ + + D_AL = 0, + D_CL, + D_DL, + D_BL, + D_SPB, + D_BPB, + D_SIB, + D_DIB, + D_R8B, + D_R9B, + D_R10B, + D_R11B, + D_R12B, + D_R13B, + D_R14B, + D_R15B, + + D_AX = 16, + D_CX, + D_DX, + D_BX, + D_SP, + D_BP, + D_SI, + D_DI, + D_R8, + D_R9, + D_R10, + D_R11, + D_R12, + D_R13, + D_R14, + D_R15, + + D_AH = 32, + D_CH, + D_DH, + D_BH, + + D_F0 = 36, + + D_M0 = 44, + + D_X0 = 52, + D_X1, + D_X2, + D_X3, + D_X4, + D_X5, + D_X6, + D_X7, + + D_CS = 68, + D_SS, + D_DS, + D_ES, + D_FS, + D_GS, + + D_GDTR, /* global descriptor table register */ + D_IDTR, /* interrupt descriptor table register */ + D_LDTR, /* local descriptor table register */ + D_MSW, /* machine status word */ + D_TASK, /* task register */ + + D_CR = 79, + D_DR = 95, + D_TR = 103, + + D_NONE = 111, + + D_BRANCH = 112, + D_EXTERN = 113, + D_STATIC = 114, + D_AUTO = 115, + D_PARAM = 116, + D_CONST = 117, + D_FCONST = 118, + D_SCONST = 119, + D_ADDR = 120, + + D_FILE, + D_FILE1, + + D_INDIR, /* additive */ + + T_TYPE = 1<<0, + T_INDEX = 1<<1, + T_OFFSET = 1<<2, + T_FCONST = 1<<3, + T_SYM = 1<<4, + T_SCONST = 1<<5, + T_64 = 1<<6, + + REGARG = 0, + REGRET = D_AX, + FREGRET = D_X0, + REGSP = D_SP, + REGTMP = D_DI, + REGEXT = D_R15, /* compiler allocates external registers R15 down */ + FREGMIN = D_X0+5, /* first register variable */ + FREGEXT = D_X0+7 /* first external register */ +}; + +/* + * this is the ranlib header + */ +#define SYMDEF "__.SYMDEF" + +/* + * this is the simulated IEEE floating point + */ +typedef struct ieee Ieee; +struct ieee +{ + long l; /* contains ls-man 0xffffffff */ + long h; /* contains sign 0x80000000 + exp 0x7ff00000 + ms-man 0x000fffff */ +}; diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c new file mode 100644 index 0000000000..4d1e9d9a34 --- /dev/null +++ b/src/cmd/6l/asm.c @@ -0,0 +1,617 @@ +// Inferno utils/6l/asm.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "l.h" + +#define Dbufslop 100 + +#define PADDR(a) ((ulong)(a) & ~0x80000000) + +vlong +entryvalue(void) +{ + char *a; + Sym *s; + + a = INITENTRY; + if(*a >= '0' && *a <= '9') + return atolwhex(a); + s = lookup(a, 0); + if(s->type == 0) + return INITTEXT; + switch(s->type) { + case STEXT: + break; + case SDATA: + if(dlm) + return s->value+INITDAT; + default: + diag("entry not text: %s", s->name); + } + return s->value; +} + +void +wputl(ushort w) +{ + cput(w); + cput(w>>8); +} + +void +wput(ushort w) +{ + cput(w>>8); + cput(w); +} + +void +lput(long l) +{ + cput(l>>24); + cput(l>>16); + cput(l>>8); + cput(l); +} + +void +llput(vlong v) +{ + lput(v>>32); + lput(v); +} + +void +lputl(long l) +{ + cput(l); + cput(l>>8); + cput(l>>16); + cput(l>>24); +} + +void +strnput(char *s, int n) +{ + int i; + + for(i=0; ilink) { + if(p->as == ATEXT) + curtext = p; + if(p->pc != pc) { + if(!debug['a']) + print("%P\n", curp); + diag("phase error %llux sb %llux in %s", p->pc, pc, TNAME); + pc = p->pc; + } + curp = p; + asmins(p); + a = (andptr - and); + if(cbc < a) + cflush(); + if(debug['a']) { + Bprint(&bso, pcstr, pc); + for(op1 = and; op1 < andptr; op1++) + Bprint(&bso, "%.2ux", *op1); + for(; op1 < and+Maxand; op1++) + Bprint(&bso, " "); + Bprint(&bso, "%P\n", curp); + } + if(dlm) { + if(p->as == ATEXT) + reloca = nil; + else if(reloca != nil) + diag("reloc failure: %P", curp); + } + memmove(cbp, and, a); + cbp += a; + pc += a; + cbc -= a; + } + cflush(); + switch(HEADTYPE) { + default: + diag("unknown header type %ld", HEADTYPE); + case 2: + case 5: + seek(cout, HEADR+textsize, 0); + break; + case 6: + v = HEADR+textsize; + myseek(cout, v); + v = rnd(v, 4096) - v; + while(v > 0) { + cput(0); + v--; + } + cflush(); + break; + } + + if(debug['v']) + Bprint(&bso, "%5.2f datblk\n", cputime()); + Bflush(&bso); + + if(dlm){ + char buf[8]; + + write(cout, buf, INITDAT-textsize); + textsize = INITDAT; + } + + for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) { + if(datsize-v > sizeof(buf)-Dbufslop) + datblk(v, sizeof(buf)-Dbufslop); + else + datblk(v, datsize-v); + } + + symsize = 0; + spsize = 0; + lcsize = 0; + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f sym\n", cputime()); + Bflush(&bso); + switch(HEADTYPE) { + default: + case 2: + case 5: + seek(cout, HEADR+textsize+datsize, 0); + break; + case 6: + debug['s'] = 1; + break; + } + if(!debug['s']) + asmsym(); + if(debug['v']) + Bprint(&bso, "%5.2f sp\n", cputime()); + Bflush(&bso); + if(debug['v']) + Bprint(&bso, "%5.2f pc\n", cputime()); + Bflush(&bso); + if(!debug['s']) + asmlc(); + if(dlm) + asmdyn(); + cflush(); + } + else if(dlm){ + seek(cout, HEADR+textsize+datsize, 0); + asmdyn(); + cflush(); + } + if(debug['v']) + Bprint(&bso, "%5.2f headr\n", cputime()); + Bflush(&bso); + seek(cout, 0L, 0); + switch(HEADTYPE) { + default: + case 2: /* plan9 */ + magic = 4*26*26+7; + magic |= 0x00008000; /* fat header */ + if(dlm) + magic |= 0x80000000; /* dlm */ + lput(magic); /* magic */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(symsize); /* nsyms */ + vl = entryvalue(); + lput(PADDR(vl)); /* va of entry */ + lput(spsize); /* sp offsets */ + lput(lcsize); /* line offsets */ + llput(vl); /* va of entry */ + break; + case 3: /* plan9 */ + magic = 4*26*26+7; + if(dlm) + magic |= 0x80000000; + lput(magic); /* magic */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(symsize); /* nsyms */ + lput(entryvalue()); /* va of entry */ + lput(spsize); /* sp offsets */ + lput(lcsize); /* line offsets */ + break; + case 5: + strnput("\177ELF", 4); /* e_ident */ + cput(1); /* class = 32 bit */ + cput(1); /* data = LSB */ + cput(1); /* version = CURRENT */ + strnput("", 9); + wputl(2); /* type = EXEC */ + wputl(62); /* machine = AMD64 */ + lputl(1L); /* version = CURRENT */ + lputl(PADDR(entryvalue())); /* entry vaddr */ + lputl(52L); /* offset to first phdr */ + lputl(0L); /* offset to first shdr */ + lputl(0L); /* processor specific flags */ + wputl(52); /* Ehdr size */ + wputl(32); /* Phdr size */ + wputl(3); /* # of Phdrs */ + wputl(0); /* Shdr size */ + wputl(0); /* # of Shdrs */ + wputl(0); /* Shdr string size */ + + lputl(1L); /* text - type = PT_LOAD */ + lputl(HEADR); /* file offset */ + lputl(INITTEXT); /* vaddr */ + lputl(PADDR(INITTEXT)); /* paddr */ + lputl(textsize); /* file size */ + lputl(textsize); /* memory size */ + lputl(0x05L); /* protections = RX */ + lputl(INITRND); /* alignment */ + + lputl(1L); /* data - type = PT_LOAD */ + lputl(HEADR+textsize); /* file offset */ + lputl(INITDAT); /* vaddr */ + lputl(PADDR(INITDAT)); /* paddr */ + lputl(datsize); /* file size */ + lputl(datsize+bsssize); /* memory size */ + lputl(0x06L); /* protections = RW */ + lputl(INITRND); /* alignment */ + + lputl(0L); /* data - type = PT_NULL */ + lputl(HEADR+textsize+datsize); /* file offset */ + lputl(0L); + lputl(0L); + lputl(symsize); /* symbol table size */ + lputl(lcsize); /* line number size */ + lputl(0x04L); /* protections = R */ + lputl(0x04L); /* alignment */ + break; + case 6: + /* apple MACH */ + va = 4096; + + lputl(0xfeedfacf); /* 64-bit */ + lputl((1<<24)|7); /* cputype - x86/ABI64 */ + lputl(3); /* subtype - x86 */ + lputl(2); /* file type - mach executable */ + lputl(4); /* number of loads */ + lputl(machheadr()-32); /* size of loads */ + lputl(1); /* flags - no undefines */ + lputl(0); /* reserved */ + + machseg("__PAGEZERO", + 0,va, /* vaddr vsize */ + 0,0, /* fileoffset filesize */ + 0,0, /* protects */ + 0,0); /* sections flags */ + + v = rnd(HEADR+textsize, INITRND); + machseg("__TEXT", + va, /* vaddr */ + v, /* vsize */ + 0,v, /* fileoffset filesize */ + 7,5, /* protects */ + 1,0); /* sections flags */ + machsect("__text", "__TEXT", + va+HEADR,v-HEADR, /* addr size */ + HEADR,0,0,0, /* offset align reloc nreloc */ + 0|0x400); /* flag - some instructions */ + + w = datsize+bsssize; + machseg("__DATA", + va+v, /* vaddr */ + w, /* vsize */ + v,datsize, /* fileoffset filesize */ + 7,3, /* protects */ + 2,0); /* sections flags */ + machsect("__data", "__DATA", + va+v,datsize, /* addr size */ + v,0,0,0, /* offset align reloc nreloc */ + 0); /* flag */ + machsect("__bss", "__DATA", + va+v+datsize,bsssize, /* addr size */ + 0,0,0,0, /* offset align reloc nreloc */ + 1); /* flag - zero fill */ + machstack(va+HEADR); + break; + } + cflush(); +} + +void +cflush(void) +{ + int n; + + n = sizeof(buf.cbuf) - cbc; + if(n) + write(cout, buf.cbuf, n); + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); +} + +void +outa(int n, uchar *cast, uchar *map, vlong l) +{ + int i, j; + + Bprint(&bso, pcstr, l); + for(i=0; ilink) { + curp = p; + l = p->from.sym->value + p->from.offset - s; + c = p->from.scale; + i = 0; + if(l < 0) { + if(l+c <= 0) + continue; + while(l < 0) { + l++; + i++; + } + } + if(l >= n) + continue; + if(p->as != AINIT && p->as != ADYNT) { + for(j=l+(c-i)-1; j>=l; j--) + if(buf.dbuf[j]) { + print("%P\n", p); + diag("multiple initialization"); + break; + } + } + + switch(p->to.type) { + case D_FCONST: + switch(c) { + default: + case 4: + fl = ieeedtof(&p->to.ieee); + cast = (uchar*)&fl; + if(debug['a'] && i == 0) + outa(c, cast, fnuxi4, l+s+INITDAT); + for(; ito.ieee; + if(debug['a'] && i == 0) + outa(c, cast, fnuxi8, l+s+INITDAT); + for(; ito.scon, nil, l+s+INITDAT); + 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) + outa(c, cast, inuxi1, l+s+INITDAT); + for(; i>32); +} + +void +machseg(char *name, vlong vaddr, vlong vsize, vlong foff, vlong fsize, + ulong prot1, ulong prot2, ulong nsect, ulong flag) +{ + lputl(25); // section + lputl(72 + 80*nsect); + strnput(name, 16); + vputl(vaddr); + vputl(vsize); + vputl(foff); + vputl(fsize); + lputl(prot1); + lputl(prot2); + lputl(nsect); + lputl(flag); +} + +void +machsect(char *name, char *seg, vlong addr, vlong size, ulong off, + ulong align, ulong reloc, ulong nreloc, ulong flag) +{ + strnput(name, 16); + strnput(seg, 16); + vputl(addr); + vputl(size); + lputl(off); + lputl(align); + lputl(reloc); + lputl(nreloc); + lputl(flag); + lputl(0); /* reserved */ + lputl(0); /* reserved */ + lputl(0); /* reserved */ +} + +void +machstack(vlong e) +{ + int i; + + lputl(5); /* unix thread */ + lputl((42+4)*4); /* total byte count */ + + lputl(4); /* thread type */ + lputl(42); /* word count */ + + for(i=0; i<32; i++) + lputl(0); + vputl(e); + for(i=0; i<8; i++) + lputl(0); +} + +ulong +machheadr(void) +{ + ulong a; + + a = 8; /* a.out header */ + a += 18; /* page zero seg */ + a += 18; /* text seg */ + a += 20; /* text sect */ + a += 18; /* data seg */ + a += 20; /* data sect */ + a += 20; /* bss sect */ + a += 46; /* stack sect */ + + return a*4; +} diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h new file mode 100644 index 0000000000..137474b928 --- /dev/null +++ b/src/cmd/6l/l.h @@ -0,0 +1,430 @@ +// Inferno utils/6l/l.h +// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include +#include +#include "../6l/6.out.h" +#include "compat.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +#define P ((Prog*)0) +#define S ((Sym*)0) +#define TNAME (curtext?curtext->from.sym->name:noname) +#define cput(c)\ + { *cbp++ = c;\ + if(--cbc <= 0)\ + cflush(); } + +typedef struct Adr Adr; +typedef struct Prog Prog; +typedef struct Sym Sym; +typedef struct Auto Auto; +typedef struct Optab Optab; +typedef struct Movtab Movtab; + +struct Adr +{ + union + { + vlong u0offset; + char u0scon[8]; + Prog *u0cond; /* not used, but should be D_BRANCH */ + Ieee u0ieee; + } u0; + union + { + Auto* u1autom; + Sym* u1sym; + } u1; + short type; + char index; + char scale; +}; + +#define offset u0.u0offset +#define scon u0.u0scon +#define cond u0.u0cond +#define ieee u0.u0ieee + +#define autom u1.u1autom +#define sym u1.u1sym + +struct Prog +{ + Adr from; + Adr to; + Prog *forwd; + Prog* link; + Prog* pcond; /* work on this */ + vlong pc; + long line; + uchar mark; /* work on these */ + uchar back; + + short as; + char width; /* fake for DATA */ + char mode; /* 16, 32, or 64 */ +}; +struct Auto +{ + Sym* asym; + Auto* link; + long aoffset; + short type; +}; +struct Sym +{ + char *name; + short type; + short version; + short become; + short frame; + uchar subtype; + ushort file; + vlong value; + long sig; + Sym* link; +}; +struct Optab +{ + short as; + uchar* ytab; + uchar prefix; + uchar op[20]; +}; +struct Movtab +{ + short as; + uchar ft; + uchar tt; + uchar code; + uchar op[4]; +}; + +enum +{ + STEXT = 1, + SDATA, + SBSS, + SDATA1, + SXREF, + SFILE, + SCONST, + SUNDEF, + + SIMPORT, + SEXPORT, + + NHASH = 10007, + NHUNK = 100000, + MINSIZ = 8, + STRINGSZ = 200, + MINLC = 1, + MAXIO = 8192, + MAXHIST = 20, /* limit of path elements for history symbols */ + + Yxxx = 0, + Ynone, + Yi0, + Yi1, + Yi8, + Ys32, + Yi32, + Yi64, + Yiauto, + Yal, + Ycl, + Yax, + Ycx, + Yrb, + Yrl, + Yrf, + Yf0, + Yrx, + Ymb, + Yml, + Ym, + Ybr, + Ycol, + + Ycs, Yss, Yds, Yes, Yfs, Ygs, + Ygdtr, Yidtr, Yldtr, Ymsw, Ytask, + Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ycr8, + Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7, + Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64, + Ymr, Ymm, + Yxr, Yxm, + Ymax, + + Zxxx = 0, + + Zlit, + Z_rp, + Zbr, + Zcall, + Zib_, + Zib_rp, + Zibo_m, + Zibo_m_xm, + Zil_, + Zil_rp, + Ziq_rp, + Zilo_m, + Ziqo_m, + Zjmp, + Zloop, + Zo_iw, + Zm_o, + Zm_r, + Zm_r_xm, + Zm_r_i_xm, + Zm_r_3d, + Zm_r_xm_nr, + Zr_m_xm_nr, + Zibm_r, /* mmx1,mmx2/mem64,imm8 */ + Zmb_r, + Zaut_r, + Zo_m, + Zo_m64, + Zpseudo, + Zr_m, + Zr_m_xm, + Zr_m_i_xm, + Zrp_, + Z_ib, + Z_il, + Zm_ibo, + Zm_ilo, + Zib_rr, + Zil_rr, + Zclr, + Zbyte, + Zmax, + + Px = 0, + P32 = 0x32, /* 32-bit only */ + Pe = 0x66, /* operand escape */ + Pm = 0x0f, /* 2byte opcode escape */ + Pq = 0xff, /* both escape */ + Pb = 0xfe, /* byte operands */ + Pf2 = 0xf2, /* xmm escape 1 */ + Pf3 = 0xf3, /* xmm escape 2 */ + Pw = 0x48, /* Rex.w */ + Py = 0x80, /* defaults to 64-bit mode */ + + Rxf = 1<<9, /* internal flag for Rxr on from */ + Rxt = 1<<8, /* internal flag for Rxr on to */ + Rxw = 1<<3, /* =1, 64-bit operand size */ + Rxr = 1<<2, /* extend modrm reg */ + Rxx = 1<<1, /* extend sib index */ + Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */ + + Roffset = 22, /* no. bits for offset in relocation address */ + Rindex = 10, /* no. bits for index in relocation address */ + Maxand = 10, /* in -a output width of the byte codes */ +}; + +EXTERN union +{ + struct + { + char obuf[MAXIO]; /* output buffer */ + uchar ibuf[MAXIO]; /* input buffer */ + } u; + char dbuf[1]; +} buf; + +#define cbuf u.obuf +#define xbuf u.ibuf + +#pragma varargck type "A" uint +#pragma varargck type "D" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "R" int +#pragma varargck type "S" char* + +EXTERN long HEADR; +EXTERN long HEADTYPE; +EXTERN vlong INITDAT; +EXTERN long INITRND; +EXTERN vlong INITTEXT; +EXTERN char* INITENTRY; /* entry point */ +EXTERN Biobuf bso; +EXTERN long bsssize; +EXTERN int cbc; +EXTERN char* cbp; +EXTERN char* pcstr; +EXTERN int cout; +EXTERN Auto* curauto; +EXTERN Auto* curhist; +EXTERN Prog* curp; +EXTERN Prog* curtext; +EXTERN Prog* datap; +EXTERN Prog* edatap; +EXTERN vlong datsize; +EXTERN char debug[128]; +EXTERN char literal[32]; +EXTERN Prog* etextp; +EXTERN Prog* firstp; +EXTERN uchar fnuxi8[8]; +EXTERN uchar fnuxi4[4]; +EXTERN Sym* hash[NHASH]; +EXTERN Sym* histfrog[MAXHIST]; +EXTERN int histfrogp; +EXTERN int histgen; +EXTERN char* library[50]; +EXTERN char* libraryobj[50]; +EXTERN int libraryp; +EXTERN int xrefresolv; +EXTERN char* hunk; +EXTERN uchar inuxi1[1]; +EXTERN uchar inuxi2[2]; +EXTERN uchar inuxi4[4]; +EXTERN uchar inuxi8[8]; +EXTERN char ycover[Ymax*Ymax]; +EXTERN uchar* andptr; +EXTERN uchar* rexptr; +EXTERN uchar and[30]; +EXTERN int reg[D_NONE]; +EXTERN int regrex[D_NONE+1]; +EXTERN Prog* lastp; +EXTERN long lcsize; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN long nsymbol; +EXTERN char* noname; +EXTERN char* outfile; +EXTERN vlong pc; +EXTERN long spsize; +EXTERN Sym* symlist; +EXTERN long symsize; +EXTERN Prog* textp; +EXTERN vlong textsize; +EXTERN long thunk; +EXTERN int version; +EXTERN Prog zprg; +EXTERN int dtype; +EXTERN char* paramspace; + +EXTERN Adr* reloca; +EXTERN int doexp, dlm; +EXTERN int imports, nimports; +EXTERN int exports, nexports; +EXTERN char* EXPTAB; +EXTERN Prog undefp; + +#define UP (&undefp) + +extern Optab optab[]; +extern Optab* opindex[]; +extern char* anames[]; + +int Aconv(Fmt*); +int Dconv(Fmt*); +int Pconv(Fmt*); +int Rconv(Fmt*); +int Sconv(Fmt*); +void addhist(long, int); +Prog* appendp(Prog*); +void asmb(void); +void asmdyn(void); +void asmins(Prog*); +void asmlc(void); +void asmsp(void); +void asmsym(void); +vlong atolwhex(char*); +Prog* brchain(Prog*); +Prog* brloop(Prog*); +void buildop(void); +void cflush(void); +void ckoff(Sym*, long); +Prog* copyp(Prog*); +double cputime(void); +void datblk(long, long); +void diag(char*, ...); +void dodata(void); +void doinit(void); +void doprof1(void); +void doprof2(void); +void dostkoff(void); +void dynreloc(Sym*, ulong, int); +vlong entryvalue(void); +void errorexit(void); +void export(void); +int find1(long, int); +int find2(long, int); +void follow(void); +void gethunk(void); +void histtoauto(void); +double ieeedtod(Ieee*); +long ieeedtof(Ieee*); +void import(void); +void ldobj(int, long, char*); +void loadlib(void); +void listinit(void); +Sym* lookup(char*, int); +void lput(long); +void lputl(long); +void main(int, char*[]); +void mkfwd(void); +void* mysbrk(ulong); +void nuxiinit(void); +void objfile(char*); +int opsize(Prog*); +void patch(void); +Prog* prg(void); +void readundefs(char*, int); +int relinv(int); +long reuse(Prog*, Sym*); +vlong rnd(vlong, vlong); +void span(void); +void undef(void); +void undefsym(Sym*); +vlong vaddr(Adr*); +void wput(ushort); +void xdefine(char*, int, vlong); +void xfol(Prog*); +int zaddr(uchar*, Adr*, Sym*[]); +void zerosig(char*); + +void machseg(char*, vlong, vlong, vlong, vlong, ulong, ulong, ulong, ulong); +void machsect(char*, char*, vlong, vlong, ulong, ulong, ulong, ulong, ulong); +void machstack(vlong); +ulong machheadr(void); + +#pragma varargck type "D" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "R" int +#pragma varargck type "A" int +#pragma varargck argpos diag 1 diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c new file mode 100644 index 0000000000..3af0192809 --- /dev/null +++ b/src/cmd/6l/list.c @@ -0,0 +1,397 @@ +// Inferno utils/6l/list.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/list.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "l.h" + +static Prog* bigP; + +void +listinit(void) +{ + + fmtinstall('R', Rconv); + fmtinstall('A', Aconv); + fmtinstall('D', Dconv); + fmtinstall('S', Sconv); + fmtinstall('P', Pconv); +} + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ], str1[STRINGSZ]; + Prog *p; + + p = va_arg(fp->args, Prog*); + bigP = p; + + sprint(str1, "(%ld)", p->line); + switch(p->as) { + case ATEXT: + if(p->from.scale) { + sprint(str, "%-7s %-7A %D,%d,%D", + str1, p->as, &p->from, p->from.scale, &p->to); + break; + } + + default: + sprint(str, "%-7s %-7A %D,%D", + str1, p->as, &p->from, &p->to); + break; + + case ADATA: + case AINIT: + case ADYNT: + sprint(str, "%-7s %-7A %D/%d,%D", + str1, p->as, &p->from, p->from.scale, &p->to); + break; + } + bigP = P; + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + int i; + + i = va_arg(fp->args, int); + return fmtstrcpy(fp, anames[i]); +} + +int +Dconv(Fmt *fp) +{ + char str[40], s[20]; + Adr *a; + int i; + + a = va_arg(fp->args, Adr*); + i = a->type; + if(i >= D_INDIR) { + if(a->offset) + sprint(str, "%lld(%R)", a->offset, i-D_INDIR); + else + sprint(str, "(%R)", i-D_INDIR); + goto brk; + } + switch(i) { + + default: + if(a->offset) + sprint(str, "$%lld,%R", a->offset, i); + else + sprint(str, "%R", i); + break; + + case D_NONE: + str[0] = 0; + break; + + case D_BRANCH: + if(bigP != P && bigP->pcond != P) + if(a->sym != S) + sprint(str, "%llux+%s", bigP->pcond->pc, + a->sym->name); + else + sprint(str, "%llux", bigP->pcond->pc); + else + sprint(str, "%lld(PC)", a->offset); + break; + + case D_EXTERN: + if(a->sym) { + sprint(str, "%s+%lld(SB)", a->sym->name, a->offset); + break; + } + sprint(str, "!!noname!!+%lld(SB)", a->offset); + break; + + case D_STATIC: + if(a->sym) { + sprint(str, "%s<%d>+%lld(SB)", a->sym->name, + a->sym->version, a->offset); + break; + } + sprint(str, "!!noname!!<999>+%lld(SB)", a->offset); + break; + + case D_AUTO: + if(a->sym) { + sprint(str, "%s+%lld(SP)", a->sym->name, a->offset); + break; + } + sprint(str, "!!noname!!+%lld(SP)", a->offset); + break; + + case D_PARAM: + if(a->sym) { + sprint(str, "%s+%lld(%s)", a->sym->name, a->offset, paramspace); + break; + } + sprint(str, "!!noname!!+%lld(%s)", a->offset, paramspace); + break; + + case D_CONST: + sprint(str, "$%lld", a->offset); + break; + + case D_FCONST: + sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->scon); + break; + + case D_ADDR: + a->type = a->index; + a->index = D_NONE; + sprint(str, "$%D", a); + a->index = a->type; + a->type = D_ADDR; + goto conv; + } +brk: + if(a->index != D_NONE) { + sprint(s, "(%R*%d)", a->index, a->scale); + strcat(str, s); + } +conv: + return fmtstrcpy(fp, str); +} + +char* regstr[] = +{ + "AL", /* [D_AL] */ + "CL", + "DL", + "BL", + "SPB", + "BPB", + "SIB", + "DIB", + "R8B", + "R9B", + "R10B", + "R11B", + "R12B", + "R13B", + "R14B", + "R15B", + + "AX", /* [D_AX] */ + "CX", + "DX", + "BX", + "SP", + "BP", + "SI", + "DI", + "R8", + "R9", + "R10", + "R11", + "R12", + "R13", + "R14", + "R15", + + "AH", + "CH", + "DH", + "BH", + + "F0", /* [D_F0] */ + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + + "M0", + "M1", + "M2", + "M3", + "M4", + "M5", + "M6", + "M7", + + "X0", + "X1", + "X2", + "X3", + "X4", + "X5", + "X6", + "X7", + "X8", + "X9", + "X10", + "X11", + "X12", + "X13", + "X14", + "X15", + + "CS", /* [D_CS] */ + "SS", + "DS", + "ES", + "FS", + "GS", + + "GDTR", /* [D_GDTR] */ + "IDTR", /* [D_IDTR] */ + "LDTR", /* [D_LDTR] */ + "MSW", /* [D_MSW] */ + "TASK", /* [D_TASK] */ + + "CR0", /* [D_CR] */ + "CR1", + "CR2", + "CR3", + "CR4", + "CR5", + "CR6", + "CR7", + "CR8", + "CR9", + "CR10", + "CR11", + "CR12", + "CR13", + "CR14", + "CR15", + + "DR0", /* [D_DR] */ + "DR1", + "DR2", + "DR3", + "DR4", + "DR5", + "DR6", + "DR7", + + "TR0", /* [D_TR] */ + "TR1", + "TR2", + "TR3", + "TR4", + "TR5", + "TR6", + "TR7", + + "NONE", /* [D_NONE] */ +}; + +int +Rconv(Fmt *fp) +{ + char str[20]; + int r; + + r = va_arg(fp->args, int); + if(r >= D_AL && r <= D_NONE) + sprint(str, "%s", regstr[r-D_AL]); + else + sprint(str, "gok(%d)", r); + + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[30], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + default: + if(c < 040 || c >= 0177) + break; /* not portable */ + p[-1] = c; + continue; + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} + +void +diag(char *fmt, ...) +{ + char buf[STRINGSZ], *tn; + va_list arg; + + tn = "??none??"; + if(curtext != P && curtext->from.sym != S) + tn = curtext->from.sym->name; + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + print("%s: %s\n", tn, buf); + + nerrors++; + if(nerrors > 20) { + print("too many errors\n"); + errorexit(); + } +} diff --git a/src/cmd/6l/mkenam b/src/cmd/6l/mkenam new file mode 100644 index 0000000000..fc918281b1 --- /dev/null +++ b/src/cmd/6l/mkenam @@ -0,0 +1,45 @@ +# Inferno utils/6c/mkenam +# http://code.google.com/p/inferno-os/source/browse/utils/6c/mkenam +# +# Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +# Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +# Portions Copyright © 1997-1999 Vita Nuova Limited +# Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +# Portions Copyright © 2004,2006 Bruce Ellis +# Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +# Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +# Portions Copyright © 2009 The Go Authors. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +ed - ../6l/6.out.h <<'!' +v/^ A/d +,s/^ A/ "/ +g/ .*$/s/// +,s/,*$/",/ +1i +char* anames[] = +{ +. +$a +}; +. +w enam.c +Q +! diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c new file mode 100644 index 0000000000..55dcaacc5e --- /dev/null +++ b/src/cmd/6l/obj.c @@ -0,0 +1,1595 @@ +// Inferno utils/6l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define EXTERN +#include "l.h" +#include + +#ifndef DEFAULT +#define DEFAULT '9' +#endif + +char *noname = ""; +char symname[] = SYMDEF; +char thechar = '6'; +char *thestring = "amd64"; +char *paramspace = "FP"; + +/* + * -H2 -T4136 -R4096 is plan9 64-bit format + * -H3 -T4128 -R4096 is plan9 32-bit format + * -H5 -T0x80110000 -R4096 is ELF32 + * -H6 -Tx -Rx is apple MH-exec + * + * options used: 189BLQSWabcjlnpsvz + */ + +static int +isobjfile(char *f) +{ + int n, v; + Biobuf *b; + char buf1[5], buf2[SARMAG]; + + b = Bopen(f, OREAD); + if(b == nil) + return 0; + n = Bread(b, buf1, 5); + if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<')) + v = 1; /* good enough for our purposes */ + else{ + Bseek(b, 0, 0); + n = Bread(b, buf2, SARMAG); + v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0; + } + Bterm(b); + return v; +} + +void +main(int argc, char *argv[]) +{ + int i, c; + char *a; + + Binit(&bso, 1, OWRITE); + cout = -1; + listinit(); + memset(debug, 0, sizeof(debug)); + nerrors = 0; + outfile = "6.out"; + HEADTYPE = -1; + INITTEXT = -1; + INITDAT = -1; + INITRND = -1; + INITENTRY = 0; +HEADTYPE = 6; // botch + ARGBEGIN { + default: + c = ARGC(); + if(c >= 0 && c < sizeof(debug)) + debug[c]++; + break; + case 'o': /* output to (next arg) */ + outfile = ARGF(); + break; + case 'E': + a = ARGF(); + if(a) + INITENTRY = a; + break; + case 'H': + a = ARGF(); + if(a) + HEADTYPE = atolwhex(a); + break; + case 'T': + a = ARGF(); + if(a) + INITTEXT = atolwhex(a); + break; + case 'D': + a = ARGF(); + if(a) + INITDAT = atolwhex(a); + break; + case 'R': + a = ARGF(); + if(a) + INITRND = atolwhex(a); + break; + case 'x': /* produce export table */ + doexp = 1; + if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) + readundefs(ARGF(), SEXPORT); + break; + case 'u': /* produce dynamically loadable module */ + dlm = 1; + debug['l']++; + if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) + readundefs(ARGF(), SIMPORT); + break; + } ARGEND + USED(argc); + if(*argv == 0) { + diag("usage: 6l [-options] objects"); + errorexit(); + } + if(!debug['9'] && !debug['U'] && !debug['B']) + debug[DEFAULT] = 1; + if(HEADTYPE == -1) { + if(debug['B']) + HEADTYPE = 2; + if(debug['9']) + HEADTYPE = 2; + } + switch(HEADTYPE) { + default: + diag("unknown -H option"); + errorexit(); + case 2: /* plan 9 */ + HEADR = 32L+8L; + if(INITTEXT == -1) + INITTEXT = 4096+HEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case 3: /* plan 9 */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 4096+32; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case 5: /* elf32 executable */ + HEADR = rnd(52L+3*32L, 16); + if(INITTEXT == -1) + INITTEXT = 0x80110000L; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case 6: /* apple MACH */ + HEADR = machheadr(); + if(INITTEXT == -1) + INITTEXT = 4096+HEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + } + if(INITDAT != 0 && INITRND != 0) + print("warning: -D0x%llux is ignored because of -R0x%lux\n", + INITDAT, INITRND); + if(debug['v']) + Bprint(&bso, "HEADER = -H%ld -T0x%llux -D0x%llux -R0x%lux\n", + HEADTYPE, INITTEXT, INITDAT, INITRND); + Bflush(&bso); + for(i=1; optab[i].as; i++) { + c = optab[i].as; + if(opindex[c] != nil) { + diag("phase error in optab: %d (%A)", i, c); + errorexit(); + } + opindex[c] = &optab[i]; + } + + for(i=0; i= 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; + } + } + + u = mal(sizeof(*u)); + u->link = curauto; + curauto = u; + u->asym = s; + u->aoffset = l; + u->type = t; + return c; +} + +void +addlib(char *obj) +{ + char name[1024], comp[256], *p; + int i; + + if(histfrogp <= 0) + return; + + if(histfrog[0]->name[1] == '/') { + sprint(name, ""); + i = 1; + } else + if(histfrog[0]->name[1] == '.') { + sprint(name, "."); + i = 0; + } else { + if(debug['9']) + sprint(name, "/%s/lib", thestring); + else + sprint(name, "/usr/%clib", thechar); + i = 0; + } + + for(; 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); + + di = S; + + /* check the header */ + bsize = readsome(f, buf.xbuf, buf.xbuf, buf.xbuf, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + r = bsize - bloc; + if(r < 7) + goto eof; + if(memcmp(bloc, "x86-64\n", 7) != 0) { + diag("file not x86-64: %s\n", pn); + return; + } + +hloop: + /* skip over exports */ + while(bloc+3 <= bsize) { + if(bloc[0] == '\n' && bloc[1] == '!' && bloc[2] == '\n') { + bloc += 3; + c -= 3; + goto newloop; + } + bloc++; + c--; + } + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + r = bsize - bloc; + if(r < 3) + goto eof; + goto hloop; + +newloop: + memset(h, 0, sizeof(h)); + version++; + histfrogp = 0; + ipc = pc; + skip = 0; + mode = 64; + +loop: + if(c <= 0) + goto eof; + r = bsize - bloc; + if(r < 100 && r < c) { /* enough for largest prog */ + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + goto loop; + } + o = bloc[0] | (bloc[1] << 8); + if(o <= AXXX || o >= ALAST) { + if(o < 0) + goto eof; + diag("%s: opcode out of range %d", pn, o); + print(" probably not a .6 file\n"); + errorexit(); + } + + if(o == ANAME || o == ASIGNAME) { + sig = 0; + if(o == ASIGNAME) { + sig = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24); + bloc += 4; + c -= 4; + } + stop = memchr(&bloc[4], 0, bsize-&bloc[4]); + if(stop == 0){ + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + stop = memchr(&bloc[4], 0, bsize-&bloc[4]); + if(stop == 0){ + fprint(2, "%s: name too long\n", pn); + errorexit(); + } + } + v = bloc[2]; /* type */ + o = bloc[3]; /* sym */ + bloc += 4; + c -= 4; + + r = 0; + if(v == D_STATIC) + r = version; + s = lookup((char*)bloc, r); + c -= &stop[1] - bloc; + bloc = stop + 1; + + if(debug['S'] && r == 0) + sig = 1729; + if(sig != 0){ + if(s->sig != 0 && s->sig != sig) + diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name); + s->sig = sig; + s->file = files-1; + } + + if(debug['W']) + print(" ANAME %s\n", s->name); + h[o] = s; + if((v == D_EXTERN || v == D_STATIC) && s->type == 0) + s->type = SXREF; + if(v == D_FILE) { + if(s->type != SFILE) { + histgen++; + s->type = SFILE; + s->value = histgen; + } + if(histfrogp < MAXHIST) { + histfrog[histfrogp] = s; + histfrogp++; + } else + collapsefrog(s); + } + goto loop; + } + + p = mal(sizeof(*p)); + p->as = o; + p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24); + p->back = 2; + p->mode = mode; + r = zaddr(bloc+6, &p->from, h) + 6; + r += zaddr(bloc+r, &p->to, h); + bloc += r; + c -= r; + + if(debug['W']) + print("%P\n", p); + + switch(p->as) { + case AHISTORY: + if(p->to.offset == -1) { + addlib(pn); + histfrogp = 0; + goto loop; + } + addhist(p->line, D_FILE); /* 'z' */ + if(p->to.offset) + addhist(p->to.offset, D_FILE1); /* 'Z' */ + histfrogp = 0; + goto loop; + + case AEND: + histtoauto(); + if(curtext != P) + curtext->to.autom = curauto; + curauto = 0; + curtext = P; + if(c) + goto newloop; + return; + + case AGLOBL: + s = p->from.sym; + if(s->type == 0 || s->type == SXREF) { + s->type = SBSS; + s->value = 0; + } + if(s->type != SBSS) { + diag("%s: redefinition: %s in %s", + pn, s->name, TNAME); + s->type = SBSS; + s->value = 0; + } + if(p->to.offset > s->value) + s->value = p->to.offset; + goto loop; + + case ADYNT: + if(p->to.sym == S) { + diag("DYNT without a sym\n%P", p); + break; + } + di = p->to.sym; + p->from.scale = 4; + if(di->type == SXREF) { + if(debug['z']) + Bprint(&bso, "%P set to %d\n", p, dtype); + di->type = SCONST; + di->value = dtype; + dtype += 4; + } + if(p->from.sym == S) + break; + + p->from.offset = di->value; + p->from.sym->type = SDATA; + if(curtext == P) { + diag("DYNT not in text: %P", p); + break; + } + p->to.sym = curtext->from.sym; + p->to.type = D_ADDR; + p->to.index = D_EXTERN; + goto data; + + case AINIT: + if(p->from.sym == S) { + diag("INIT without a sym\n%P", p); + break; + } + if(di == S) { + diag("INIT without previous DYNT\n%P", p); + break; + } + p->from.offset = di->value; + p->from.sym->type = SDATA; + goto data; + + case ADATA: + data: + if(edatap == P) + datap = p; + else + edatap->link = p; + edatap = p; + p->link = P; + goto loop; + + case AGOK: + diag("%s: GOK opcode in %s", pn, TNAME); + pc++; + goto loop; + + case ATEXT: + if(curtext != P) { + histtoauto(); + curtext->to.autom = curauto; + curauto = 0; + } + skip = 0; + curtext = p; + s = p->from.sym; + if(s == S) { + diag("%s: no TEXT symbol: %P", pn, p); + errorexit(); + } + if(s->type != 0 && s->type != SXREF) { + if(p->from.scale & DUPOK) { + skip = 1; + goto casdef; + } + diag("%s: redefinition: %s\n%P", pn, s->name, p); + } + s->type = STEXT; + s->value = pc; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + if(textp == P) { + textp = p; + etextp = p; + goto loop; + } + etextp->pcond = p; + etextp = p; + goto loop; + + case AMODE: + if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){ + switch((int)p->from.offset){ + case 16: case 32: case 64: + mode = p->from.offset; + break; + } + } + goto loop; + + case AFMOVF: + case AFADDF: + case AFSUBF: + case AFSUBRF: + case AFMULF: + case AFDIVF: + case AFDIVRF: + case AFCOMF: + case AFCOMFP: + case AMOVSS: + case AADDSS: + case ASUBSS: + case AMULSS: + case ADIVSS: + case ACOMISS: + case AUCOMISS: + if(skip) + goto casdef; + if(p->from.type == D_FCONST) { + /* size sb 9 max */ + sprint(literal, "$%lux", ieeedtof(&p->from.ieee)); + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SBSS; + s->value = 4; + t = prg(); + t->as = ADATA; + t->line = p->line; + t->from.type = D_EXTERN; + t->from.sym = s; + t->from.scale = 4; + t->to = p->from; + if(edatap == P) + datap = t; + else + edatap->link = t; + edatap = t; + t->link = P; + } + p->from.type = D_EXTERN; + p->from.sym = s; + p->from.offset = 0; + } + goto casdef; + + case AFMOVD: + case AFADDD: + case AFSUBD: + case AFSUBRD: + case AFMULD: + case AFDIVD: + case AFDIVRD: + case AFCOMD: + case AFCOMDP: + case AMOVSD: + case AADDSD: + case ASUBSD: + case AMULSD: + case ADIVSD: + case ACOMISD: + case AUCOMISD: + if(skip) + goto casdef; + if(p->from.type == D_FCONST) { + /* size sb 18 max */ + sprint(literal, "$%lux.%lux", + p->from.ieee.l, p->from.ieee.h); + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SBSS; + s->value = 8; + t = prg(); + t->as = ADATA; + t->line = p->line; + t->from.type = D_EXTERN; + t->from.sym = s; + t->from.scale = 8; + t->to = p->from; + if(edatap == P) + datap = t; + else + edatap->link = t; + edatap = t; + t->link = P; + } + p->from.type = D_EXTERN; + p->from.sym = s; + p->from.offset = 0; + } + goto casdef; + + casdef: + default: + if(skip) + nopout(p); + + if(p->to.type == D_BRANCH) + p->to.offset += ipc; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + goto loop; + } + goto loop; + +eof: + diag("truncated object file: %s", pn); +} + +Sym* +lookup(char *symb, int v) +{ + Sym *s; + char *p; + long h; + int l, c; + + h = v; + for(p=symb; c = *p; p++) + h = h+h+h + c; + l = (p - symb) + 1; + if(h < 0) + h = ~h; + h %= NHASH; + for(s = hash[h]; s != S; s = s->link) + if(s->version == v) + if(memcmp(s->name, symb, l) == 0) + return s; + + s = mal(sizeof(*s)); + + s->name = malloc(l + 1); + memmove(s->name, symb, l); + + s->link = hash[h]; + s->type = 0; + s->version = v; + s->value = 0; + s->sig = 0; + hash[h] = s; + nsymbol++; + return s; +} + +Prog* +prg(void) +{ + Prog *p; + + p = mal(sizeof(*p)); + + *p = zprg; + return p; +} + +Prog* +copyp(Prog *q) +{ + Prog *p; + + p = prg(); + *p = *q; + return p; +} + +Prog* +appendp(Prog *q) +{ + Prog *p; + + p = prg(); + p->link = q->link; + q->link = p; + p->line = q->line; + p->mode = q->mode; + return p; +} + +void +doprof1(void) +{ + Sym *s; + long n; + Prog *p, *q; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 1\n", cputime()); + Bflush(&bso); + s = lookup("__mcount", 0); + n = 1; + for(p = firstp->link; p != P; p = p->link) { + if(p->as == ATEXT) { + q = prg(); + q->line = p->line; + q->link = datap; + datap = q; + q->as = ADATA; + q->from.type = D_EXTERN; + q->from.offset = n*4; + q->from.sym = s; + q->from.scale = 4; + q->to = p->from; + q->to.type = D_CONST; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AADDL; + p->from.type = D_CONST; + p->from.offset = 1; + p->to.type = D_EXTERN; + p->to.sym = s; + p->to.offset = n*4 + 4; + + n += 2; + continue; + } + } + q = prg(); + q->line = 0; + q->link = datap; + datap = q; + + q->as = ADATA; + q->from.type = D_EXTERN; + q->from.sym = s; + q->from.scale = 4; + q->to.type = D_CONST; + q->to.offset = n; + + s->type = SBSS; + s->value = n*4; +} + +void +doprof2(void) +{ + Sym *s2, *s4; + Prog *p, *q, *ps2, *ps4; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 2\n", cputime()); + Bflush(&bso); + + s2 = lookup("_profin", 0); + s4 = lookup("_profout", 0); + if(s2->type != STEXT || s4->type != STEXT) { + diag("_profin/_profout not defined"); + return; + } + + ps2 = P; + ps4 = P; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + if(p->from.sym == s2) { + p->from.scale = 1; + ps2 = p; + } + if(p->from.sym == s4) { + p->from.scale = 1; + ps4 = p; + } + } + } + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + curtext = p; + + if(p->from.scale & NOPROF) { /* dont profile */ + for(;;) { + q = p->link; + if(q == P) + break; + if(q->as == ATEXT) + break; + p = q; + } + continue; + } + + /* + * JMPL profin + */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = ps2; + p->to.sym = s2; + + continue; + } + if(p->as == ARET) { + /* + * RET + */ + q = prg(); + q->as = ARET; + q->from = p->from; + q->to = p->to; + q->link = p->link; + p->link = q; + + /* + * JAL profout + */ + p->as = ACALL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->pcond = ps4; + p->to.sym = s4; + + p = q; + + continue; + } + } +} + +void +nuxiinit(void) +{ + int i, c; + + for(i=0; i<4; i++) { + c = find1(0x04030201L, i+1); + if(i < 2) + inuxi2[i] = c; + if(i < 1) + inuxi1[i] = c; + inuxi4[i] = c; + inuxi8[i] = c; + inuxi8[i+4] = c+4; + fnuxi4[i] = c; + fnuxi8[i] = c; + fnuxi8[i+4] = c+4; + } + if(debug['v']) { + Bprint(&bso, "inuxi = "); + for(i=0; i<1; i++) + Bprint(&bso, "%d", inuxi1[i]); + Bprint(&bso, " "); + for(i=0; i<2; i++) + Bprint(&bso, "%d", inuxi2[i]); + Bprint(&bso, " "); + for(i=0; i<4; i++) + Bprint(&bso, "%d", inuxi4[i]); + Bprint(&bso, " "); + for(i=0; i<8; i++) + Bprint(&bso, "%d", inuxi8[i]); + Bprint(&bso, "\nfnuxi = "); + for(i=0; i<4; i++) + Bprint(&bso, "%d", fnuxi4[i]); + Bprint(&bso, " "); + for(i=0; i<8; i++) + Bprint(&bso, "%d", fnuxi8[i]); + Bprint(&bso, "\n"); + } + Bflush(&bso); +} + +int +find1(long l, int c) +{ + char *p; + int i; + + p = (char*)&l; + for(i=0; i<4; i++) + if(*p++ == c) + return i; + return 0; +} + +int +find2(long l, int c) +{ + short *p; + int i; + + p = (short*)&l; + for(i=0; i<4; i+=2) { + if(((*p >> 8) & 0xff) == c) + return i; + if((*p++ & 0xff) == c) + return i+1; + } + return 0; +} + +long +ieeedtof(Ieee *e) +{ + int exp; + long v; + + if(e->h == 0) + return 0; + exp = (e->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + v = (e->h & 0xfffffL) << 3; + v |= (e->l >> 29) & 0x7L; + if((e->l >> 28) & 1) { + v++; + if(v & 0x800000L) { + v = (v & 0x7fffffL) >> 1; + exp++; + } + } + if(exp <= -126 || exp >= 130) + diag("double fp to single fp overflow"); + v |= ((exp + 126) & 0xffL) << 23; + v |= e->h & 0x80000000L; + return v; +} + +double +ieeedtod(Ieee *ieeep) +{ + Ieee e; + double fr; + int exp; + + if(ieeep->h & (1L<<31)) { + e.h = ieeep->h & ~(1L<<31); + e.l = ieeep->l; + return -ieeedtod(&e); + } + if(ieeep->l == 0 && ieeep->h == 0) + return 0; + fr = ieeep->l & ((1L<<16)-1L); + fr /= 1L<<16; + fr += (ieeep->l>>16) & ((1L<<16)-1L); + fr /= 1L<<16; + fr += (ieeep->h & (1L<<20)-1L) | (1L<<20); + fr /= 1L<<21; + exp = (ieeep->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + return ldexp(fr, exp); +} + +void +undefsym(Sym *s) +{ + int n; + + n = imports; + if(s->value != 0) + diag("value != 0 on SXREF"); + if(n >= 1<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/src/cmd/6l/optab.c b/src/cmd/6l/optab.c new file mode 100644 index 0000000000..d997971662 --- /dev/null +++ b/src/cmd/6l/optab.c @@ -0,0 +1,1213 @@ +// Inferno utils/6l/optab.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/optab.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "l.h" + +uchar ynone[] = +{ + Ynone, Ynone, Zlit, 1, + 0 +}; +uchar ytext[] = +{ + Ymb, Yi32, Zpseudo,1, + 0 +}; +uchar ynop[] = +{ + Ynone, Ynone, Zpseudo,1, + Ynone, Yml, Zpseudo,1, + Ynone, Yrf, Zpseudo,1, + Yml, Ynone, Zpseudo,1, + Yrf, Ynone, Zpseudo,1, + 0 +}; +uchar yxorb[] = +{ + Yi32, Yal, Zib_, 1, + Yi32, Ymb, Zibo_m, 2, + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +uchar yxorl[] = +{ + Yi8, Yml, Zibo_m, 2, + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar yaddl[] = +{ + Yi8, Yml, Zibo_m, 2, + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar yincb[] = +{ + Ynone, Ymb, Zo_m, 2, + 0 +}; +uchar yincw[] = +{ + Ynone, Yml, Zo_m, 2, + 0 +}; +uchar yincl[] = +{ + Ynone, Yml, Zo_m, 2, + 0 +}; +uchar ycmpb[] = +{ + Yal, Yi32, Z_ib, 1, + Ymb, Yi32, Zm_ibo, 2, + Ymb, Yrb, Zm_r, 1, + Yrb, Ymb, Zr_m, 1, + 0 +}; +uchar ycmpl[] = +{ + Yml, Yi8, Zm_ibo, 2, + Yax, Yi32, Z_il, 1, + Yml, Yi32, Zm_ilo, 2, + Yml, Yrl, Zm_r, 1, + Yrl, Yml, Zr_m, 1, + 0 +}; +uchar yshb[] = +{ + Yi1, Ymb, Zo_m, 2, + Yi32, Ymb, Zibo_m, 2, + Ycx, Ymb, Zo_m, 2, + 0 +}; +uchar yshl[] = +{ + Yi1, Yml, Zo_m, 2, + Yi32, Yml, Zibo_m, 2, + Ycl, Yml, Zo_m, 2, + Ycx, Yml, Zo_m, 2, + 0 +}; +uchar ytestb[] = +{ + Yi32, Yal, Zib_, 1, + Yi32, Ymb, Zibo_m, 2, + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +uchar ytestl[] = +{ + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar ymovb[] = +{ + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + Yi32, Yrb, Zib_rp, 1, + Yi32, Ymb, Zibo_m, 2, + 0 +}; +uchar ymbs[] = +{ + Ymb, Ynone, Zm_o, 2, + 0 +}; +uchar ybtl[] = +{ + Yi8, Yml, Zibo_m, 2, + Yrl, Yml, Zr_m, 1, + 0 +}; +uchar ymovw[] = +{ + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + Yi0, Yrl, Zclr, 1, + Yi32, Yrl, Zil_rp, 1, + Yi32, Yml, Zilo_m, 2, + Yiauto, Yrl, Zaut_r, 2, + 0 +}; +uchar ymovl[] = +{ + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + Yi0, Yrl, Zclr, 1, + Yi32, Yrl, Zil_rp, 1, + Yi32, Yml, Zilo_m, 2, + Yml, Ymr, Zm_r_xm, 1, // MMX MOVD + Ymr, Yml, Zr_m_xm, 1, // MMX MOVD + Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit) + Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit) + Yiauto, Yrl, Zaut_r, 2, + 0 +}; +uchar yret[] = +{ + Ynone, Ynone, Zo_iw, 1, + Yi32, Ynone, Zo_iw, 1, + 0 +}; +uchar ymovq[] = +{ + Yrl, Yml, Zr_m, 1, // 0x89 + Yml, Yrl, Zm_r, 1, // 0x8b + Yi0, Yrl, Zclr, 1, // 0x31 + Ys32, Yrl, Zilo_m, 2, // 32 bit signed 0xc7,(0) + Yi64, Yrl, Ziq_rp, 1, // 0xb8 -- 32/64 bit immediate + Yi32, Yml, Zilo_m, 2, // 0xc7,(0) + Ym, Ymr, Zm_r_xm_nr, 1, // MMX MOVQ (shorter encoding) + Ymr, Ym, Zr_m_xm_nr, 1, // MMX MOVQ + Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD + Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD + Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q + Yxr, Ym, Zr_m_xm_nr, 2, // MOVQ xmm store + Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load + Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store + Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ + 0 +}; +uchar ym_rl[] = +{ + Ym, Yrl, Zm_r, 1, + 0 +}; +uchar yrl_m[] = +{ + Yrl, Ym, Zr_m, 1, + 0 +}; +uchar ymb_rl[] = +{ + Ymb, Yrl, Zmb_r, 1, + 0 +}; +uchar yml_rl[] = +{ + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar yrl_ml[] = +{ + Yrl, Yml, Zr_m, 1, + 0 +}; +uchar yml_mb[] = +{ + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +uchar yrb_mb[] = +{ + Yrb, Ymb, Zr_m, 1, + 0 +}; +uchar yml_ml[] = +{ + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar ydivl[] = +{ + Yml, Ynone, Zm_o, 2, + 0 +}; +uchar ydivb[] = +{ + Ymb, Ynone, Zm_o, 2, + 0 +}; +uchar yimul[] = +{ + Yml, Ynone, Zm_o, 2, + Yi8, Yrl, Zib_rr, 1, + Yi32, Yrl, Zil_rr, 1, + Yml, Yrl, Zm_r, 2, + 0 +}; +uchar ybyte[] = +{ + Yi64, Ynone, Zbyte, 1, + 0 +}; +uchar yin[] = +{ + Yi32, Ynone, Zib_, 1, + Ynone, Ynone, Zlit, 1, + 0 +}; +uchar yint[] = +{ + Yi32, Ynone, Zib_, 1, + 0 +}; +uchar ypushl[] = +{ + Yrl, Ynone, Zrp_, 1, + Ym, Ynone, Zm_o, 2, + Yi8, Ynone, Zib_, 1, + Yi32, Ynone, Zil_, 1, + 0 +}; +uchar ypopl[] = +{ + Ynone, Yrl, Z_rp, 1, + Ynone, Ym, Zo_m, 2, + 0 +}; +uchar yscond[] = +{ + Ynone, Ymb, Zo_m, 2, + 0 +}; +uchar yjcond[] = +{ + Ynone, Ybr, Zbr, 1, + 0 +}; +uchar yloop[] = +{ + Ynone, Ybr, Zloop, 1, + 0 +}; +uchar ycall[] = +{ + Ynone, Yml, Zo_m64, 2, + Ynone, Ybr, Zcall, 1, + 0 +}; +uchar yjmp[] = +{ + Ynone, Yml, Zo_m64, 2, + Ynone, Ybr, Zjmp, 1, + 0 +}; + +uchar yfmvd[] = +{ + Ym, Yf0, Zm_o, 2, + Yf0, Ym, Zo_m, 2, + Yrf, Yf0, Zm_o, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfmvdp[] = +{ + Yf0, Ym, Zo_m, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfmvf[] = +{ + Ym, Yf0, Zm_o, 2, + Yf0, Ym, Zo_m, 2, + 0 +}; +uchar yfmvx[] = +{ + Ym, Yf0, Zm_o, 2, + 0 +}; +uchar yfmvp[] = +{ + Yf0, Ym, Zo_m, 2, + 0 +}; +uchar yfadd[] = +{ + Ym, Yf0, Zm_o, 2, + Yrf, Yf0, Zm_o, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfaddp[] = +{ + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfxch[] = +{ + Yf0, Yrf, Zo_m, 2, + Yrf, Yf0, Zm_o, 2, + 0 +}; +uchar ycompp[] = +{ + Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */ + 0 +}; +uchar ystsw[] = +{ + Ynone, Ym, Zo_m, 2, + Ynone, Yax, Zlit, 1, + 0 +}; +uchar ystcw[] = +{ + Ynone, Ym, Zo_m, 2, + Ym, Ynone, Zm_o, 2, + 0 +}; +uchar ysvrs[] = +{ + Ynone, Ym, Zo_m, 2, + Ym, Ynone, Zm_o, 2, + 0 +}; +uchar ymm[] = +{ + Ymm, Ymr, Zm_r_xm, 1, + Yxm, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yxm[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxcvm1[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + Yxm, Ymr, Zm_r_xm, 2, + 0 +}; +uchar yxcvm2[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + Ymm, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yxmq[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yxr[] = +{ + Yxr, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxr_ml[] = +{ + Yxr, Yml, Zr_m_xm, 1, + 0 +}; +uchar ymr[] = +{ + Ymr, Ymr, Zm_r, 1, + 0 +}; +uchar ymr_ml[] = +{ + Ymr, Yml, Zr_m_xm, 1, + 0 +}; +uchar yxcmp[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxcmpi[] = +{ + Yxm, Yxr, Zm_r_i_xm, 2, + 0 +}; +uchar yxmov[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + Yxr, Yxm, Zr_m_xm, 1, + 0 +}; +uchar yxcvfl[] = +{ + Yxm, Yrl, Zm_r_xm, 1, + 0 +}; +uchar yxcvlf[] = +{ + Yml, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxcvfq[] = +{ + Yxm, Yrl, Zm_r_xm, 2, + 0 +}; +uchar yxcvqf[] = +{ + Yml, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yps[] = +{ + Ymm, Ymr, Zm_r_xm, 1, + Yi8, Ymr, Zibo_m_xm, 2, + Yxm, Yxr, Zm_r_xm, 2, + Yi8, Yxr, Zibo_m_xm, 3, + 0 +}; +uchar yxrrl[] = +{ + Yxr, Yrl, Zm_r, 1, + 0 +}; +uchar ymfp[] = +{ + Ymm, Ymr, Zm_r_3d, 1, + 0, +}; +uchar ymrxr[] = +{ + Ymr, Yxr, Zm_r, 1, + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +uchar ymshuf[] = +{ + Ymm, Ymr, Zibm_r, 1, + 0 +}; +uchar yxshuf[] = +{ + Yxm, Yxr, Zibm_r, 1, + 0 +}; +uchar yextrw[] = +{ + Yxr, Yrl, Zibm_r, 1, + 0 +}; +uchar ypsdq[] = +{ + Yi8, Yxr, Zibo_m, 2, + 0 +}; +uchar ymskb[] = +{ + Yxr, Yrl, Zm_r_xm, 2, + Ymr, Yrl, Zm_r_xm, 1, + 0 +}; + +Optab optab[] = +/* as, ytab, andproto, opcode */ +{ + { AXXX }, + { AAAA, ynone, P32, 0x37 }, + { AAAD, ynone, P32, 0xd5,0x0a }, + { AAAM, ynone, P32, 0xd4,0x0a }, + { AAAS, ynone, P32, 0x3f }, + { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 }, + { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADCQ, yxorl, Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADDB, yxorb, Pb, 0x04,0x80,(00),0x00,0x02 }, + { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + { AADDPD, yxm, Pq, 0x58 }, + { AADDPS, yxm, Pm, 0x58 }, + { AADDQ, yaddl, Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + { AADDSD, yxm, Pf2, 0x58 }, + { AADDSS, yxm, Pf3, 0x58 }, + { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + { AADJSP }, + { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 }, + { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, + { AANDNPD, yxm, Pq, 0x55 }, + { AANDNPS, yxm, Pm, 0x55 }, + { AANDPD, yxm, Pq, 0x54 }, + { AANDPS, yxm, Pq, 0x54 }, + { AANDQ, yxorl, Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, + { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, + { AARPL, yrl_ml, P32, 0x63 }, + { ABOUNDL, yrl_m, P32, 0x62 }, + { ABOUNDW, yrl_m, Pe, 0x62 }, + { ABSFL, yml_rl, Pm, 0xbc }, + { ABSFQ, yml_rl, Pw, 0x0f,0xbc }, + { ABSFW, yml_rl, Pq, 0xbc }, + { ABSRL, yml_rl, Pm, 0xbd }, + { ABSRQ, yml_rl, Pw, 0x0f,0xbd }, + { ABSRW, yml_rl, Pq, 0xbd }, + { ABTCL, ybtl, Pm, 0xba,(07),0xbb }, + { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb }, + { ABTCW, ybtl, Pq, 0xba,(07),0xbb }, + { ABTL, ybtl, Pm, 0xba,(04),0xa3 }, + { ABTQ, ybtl, Pw, 0x0f,0xba,(04),0x0f,0xa3}, + { ABTRL, ybtl, Pm, 0xba,(06),0xb3 }, + { ABTRQ, ybtl, Pw, 0x0f,0xba,(06),0x0f,0xb3 }, + { ABTRW, ybtl, Pq, 0xba,(06),0xb3 }, + { ABTSL, ybtl, Pm, 0xba,(05),0xab }, + { ABTSQ, ybtl, Pw, 0x0f,0xba,(05),0x0f,0xab }, + { ABTSW, ybtl, Pq, 0xba,(05),0xab }, + { ABTW, ybtl, Pq, 0xba,(04),0xa3 }, + { ABYTE, ybyte, Px, 1 }, + { ACALL, ycall, Px, 0xff,(02),0xe8 }, + { ACDQ, ynone, Px, 0x99 }, + { ACLC, ynone, Px, 0xf8 }, + { ACLD, ynone, Px, 0xfc }, + { ACLI, ynone, Px, 0xfa }, + { ACLTS, ynone, Pm, 0x06 }, + { ACMC, ynone, Px, 0xf5 }, + { ACMOVLCC, yml_rl, Pm, 0x43 }, + { ACMOVLCS, yml_rl, Pm, 0x42 }, + { ACMOVLEQ, yml_rl, Pm, 0x44 }, + { ACMOVLGE, yml_rl, Pm, 0x4d }, + { ACMOVLGT, yml_rl, Pm, 0x4f }, + { ACMOVLHI, yml_rl, Pm, 0x47 }, + { ACMOVLLE, yml_rl, Pm, 0x4e }, + { ACMOVLLS, yml_rl, Pm, 0x46 }, + { ACMOVLLT, yml_rl, Pm, 0x4c }, + { ACMOVLMI, yml_rl, Pm, 0x48 }, + { ACMOVLNE, yml_rl, Pm, 0x45 }, + { ACMOVLOC, yml_rl, Pm, 0x41 }, + { ACMOVLOS, yml_rl, Pm, 0x40 }, + { ACMOVLPC, yml_rl, Pm, 0x4b }, + { ACMOVLPL, yml_rl, Pm, 0x49 }, + { ACMOVLPS, yml_rl, Pm, 0x4a }, + { ACMOVQCC, yml_rl, Pw, 0x0f,0x43 }, + { ACMOVQCS, yml_rl, Pw, 0x0f,0x42 }, + { ACMOVQEQ, yml_rl, Pw, 0x0f,0x44 }, + { ACMOVQGE, yml_rl, Pw, 0x0f,0x4d }, + { ACMOVQGT, yml_rl, Pw, 0x0f,0x4f }, + { ACMOVQHI, yml_rl, Pw, 0x0f,0x47 }, + { ACMOVQLE, yml_rl, Pw, 0x0f,0x4e }, + { ACMOVQLS, yml_rl, Pw, 0x0f,0x46 }, + { ACMOVQLT, yml_rl, Pw, 0x0f,0x4c }, + { ACMOVQMI, yml_rl, Pw, 0x0f,0x48 }, + { ACMOVQNE, yml_rl, Pw, 0x0f,0x45 }, + { ACMOVQOC, yml_rl, Pw, 0x0f,0x41 }, + { ACMOVQOS, yml_rl, Pw, 0x0f,0x40 }, + { ACMOVQPC, yml_rl, Pw, 0x0f,0x4b }, + { ACMOVQPL, yml_rl, Pw, 0x0f,0x49 }, + { ACMOVQPS, yml_rl, Pw, 0x0f,0x4a }, + { ACMOVWCC, yml_rl, Pq, 0x43 }, + { ACMOVWCS, yml_rl, Pq, 0x42 }, + { ACMOVWEQ, yml_rl, Pq, 0x44 }, + { ACMOVWGE, yml_rl, Pq, 0x4d }, + { ACMOVWGT, yml_rl, Pq, 0x4f }, + { ACMOVWHI, yml_rl, Pq, 0x47 }, + { ACMOVWLE, yml_rl, Pq, 0x4e }, + { ACMOVWLS, yml_rl, Pq, 0x46 }, + { ACMOVWLT, yml_rl, Pq, 0x4c }, + { ACMOVWMI, yml_rl, Pq, 0x48 }, + { ACMOVWNE, yml_rl, Pq, 0x45 }, + { ACMOVWOC, yml_rl, Pq, 0x41 }, + { ACMOVWOS, yml_rl, Pq, 0x40 }, + { ACMOVWPC, yml_rl, Pq, 0x4b }, + { ACMOVWPL, yml_rl, Pq, 0x49 }, + { ACMOVWPS, yml_rl, Pq, 0x4a }, + { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a }, + { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACMPPD, yxcmpi, Px, Pe,0xc2 }, + { ACMPPS, yxcmpi, Pm, 0xc2,0 }, + { ACMPQ, ycmpl, Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACMPSB, ynone, Pb, 0xa6 }, + { ACMPSD, yxcmpi, Px, Pf2,0xc2 }, + { ACMPSL, ynone, Px, 0xa7 }, + { ACMPSQ, ynone, Pw, 0xa7 }, + { ACMPSS, yxcmpi, Px, Pf3,0xc2 }, + { ACMPSW, ynone, Pe, 0xa7 }, + { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACOMISD, yxcmp, Pe, 0x2f }, + { ACOMISS, yxcmp, Pm, 0x2f }, + { ACPUID, ynone, Pm, 0xa2 }, + { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a }, + { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, }, + { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d }, + { ACVTPD2PS, yxm, Pe, 0x5a }, + { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d }, + { ACVTPS2PD, yxm, Pm, 0x5a }, + { API2FW, ymfp, Px, 0x0c }, + { ACVTSD2SL, yxcvfl, Pf2, 0x2d }, + { ACVTSD2SQ, yxcvfq, Pw, Pf2,0x2d }, + { ACVTSD2SS, yxm, Pf2, 0x5a }, + { ACVTSL2SD, yxcvlf, Pf2, 0x2a }, + { ACVTSQ2SD, yxcvqf, Pw, Pf2,0x2a }, + { ACVTSL2SS, yxcvlf, Pf3, 0x2a }, + { ACVTSQ2SS, yxcvqf, Pw, Pf3,0x2a }, + { ACVTSS2SD, yxm, Pf3, 0x5a }, + { ACVTSS2SL, yxcvfl, Pf3, 0x2d }, + { ACVTSS2SQ, yxcvfq, Pw, Pf3,0x2d }, + { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c }, + { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c }, + { ACVTTSD2SL, yxcvfl, Pf2, 0x2c }, + { ACVTTSD2SQ, yxcvfq, Pw, Pf2,0x2c }, + { ACVTTSS2SL, yxcvfl, Pf3, 0x2c }, + { ACVTTSS2SQ, yxcvfq, Pw, Pf3,0x2c }, + { ACWD, ynone, Pe, 0x99 }, + { ACQO, ynone, Pw, 0x99 }, + { ADAA, ynone, P32, 0x27 }, + { ADAS, ynone, P32, 0x2f }, + { ADATA }, + { ADECB, yincb, Pb, 0xfe,(01) }, + { ADECL, yincl, Px, 0xff,(01) }, + { ADECQ, yincl, Pw, 0xff,(01) }, + { ADECW, yincw, Pe, 0xff,(01) }, + { ADIVB, ydivb, Pb, 0xf6,(06) }, + { ADIVL, ydivl, Px, 0xf7,(06) }, + { ADIVPD, yxm, Pe, 0x5e }, + { ADIVPS, yxm, Pm, 0x5e }, + { ADIVQ, ydivl, Pw, 0xf7,(06) }, + { ADIVSD, yxm, Pf2, 0x5e }, + { ADIVSS, yxm, Pf3, 0x5e }, + { ADIVW, ydivl, Pe, 0xf7,(06) }, + { AEMMS, ynone, Pm, 0x77 }, + { AENTER }, /* botch */ + { AFXRSTOR, ysvrs, Pm, 0xae,(01),0xae,(01) }, + { AFXSAVE, ysvrs, Pm, 0xae,(00),0xae,(00) }, + { AFXRSTOR64, ysvrs, Pw, 0x0f,0xae,(01),0x0f,0xae,(01) }, + { AFXSAVE64, ysvrs, Pw, 0x0f,0xae,(00),0x0f,0xae,(00) }, + { AGLOBL }, + { AGOK }, + { AHISTORY }, + { AHLT, ynone, Px, 0xf4 }, + { AIDIVB, ydivb, Pb, 0xf6,(07) }, + { AIDIVL, ydivl, Px, 0xf7,(07) }, + { AIDIVQ, ydivl, Pw, 0xf7,(07) }, + { AIDIVW, ydivl, Pe, 0xf7,(07) }, + { AIMULB, ydivb, Pb, 0xf6,(05) }, + { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf }, + { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf }, + { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf }, + { AINB, yin, Pb, 0xe4,0xec }, + { AINCB, yincb, Pb, 0xfe,(00) }, + { AINCL, yincl, Px, 0xff,(00) }, + { AINCQ, yincl, Pw, 0xff,(00) }, + { AINCW, yincw, Pe, 0xff,(00) }, + { AINL, yin, Px, 0xe5,0xed }, + { AINSB, ynone, Pb, 0x6c }, + { AINSL, ynone, Px, 0x6d }, + { AINSW, ynone, Pe, 0x6d }, + { AINT, yint, Px, 0xcd }, + { AINTO, ynone, P32, 0xce }, + { AINW, yin, Pe, 0xe5,0xed }, + { AIRETL, ynone, Px, 0xcf }, + { AIRETQ, ynone, Pw, 0xcf }, + { AIRETW, ynone, Pe, 0xcf }, + { AJCC, yjcond, Px, 0x73,0x83,(00) }, + { AJCS, yjcond, Px, 0x72,0x82 }, + { AJCXZ, yloop, Px, 0xe3 }, + { AJEQ, yjcond, Px, 0x74,0x84 }, + { AJGE, yjcond, Px, 0x7d,0x8d }, + { AJGT, yjcond, Px, 0x7f,0x8f }, + { AJHI, yjcond, Px, 0x77,0x87 }, + { AJLE, yjcond, Px, 0x7e,0x8e }, + { AJLS, yjcond, Px, 0x76,0x86 }, + { AJLT, yjcond, Px, 0x7c,0x8c }, + { AJMI, yjcond, Px, 0x78,0x88 }, + { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 }, + { AJNE, yjcond, Px, 0x75,0x85 }, + { AJOC, yjcond, Px, 0x71,0x81,(00) }, + { AJOS, yjcond, Px, 0x70,0x80,(00) }, + { AJPC, yjcond, Px, 0x7b,0x8b }, + { AJPL, yjcond, Px, 0x79,0x89 }, + { AJPS, yjcond, Px, 0x7a,0x8a }, + { ALAHF, ynone, Px, 0x9f }, + { ALARL, yml_rl, Pm, 0x02 }, + { ALARW, yml_rl, Pq, 0x02 }, + { ALDMXCSR, ysvrs, Pm, 0xae,(02),0xae,(02) }, + { ALEAL, ym_rl, Px, 0x8d }, + { ALEAQ, ym_rl, Pw, 0x8d }, + { ALEAVEL, ynone, P32, 0xc9 }, + { ALEAVEQ, ynone, Py, 0xc9 }, + { ALEAVEW, ynone, Pe, 0xc9 }, + { ALEAW, ym_rl, Pe, 0x8d }, + { ALOCK, ynone, Px, 0xf0 }, + { ALODSB, ynone, Pb, 0xac }, + { ALODSL, ynone, Px, 0xad }, + { ALODSQ, ynone, Pw, 0xad }, + { ALODSW, ynone, Pe, 0xad }, + { ALONG, ybyte, Px, 4 }, + { ALOOP, yloop, Px, 0xe2 }, + { ALOOPEQ, yloop, Px, 0xe1 }, + { ALOOPNE, yloop, Px, 0xe0 }, + { ALSLL, yml_rl, Pm, 0x03 }, + { ALSLW, yml_rl, Pq, 0x03 }, + { AMASKMOVOU, yxr, Pe, 0xf7 }, + { AMASKMOVQ, ymr, Pm, 0xf7 }, + { AMAXPD, yxm, Pe, 0x5f }, + { AMAXPS, yxm, Pm, 0x5f }, + { AMAXSD, yxm, Pf2, 0x5f }, + { AMAXSS, yxm, Pf3, 0x5f }, + { AMINPD, yxm, Pe, 0x5d }, + { AMINPS, yxm, Pm, 0x5d }, + { AMINSD, yxm, Pf2, 0x5d }, + { AMINSS, yxm, Pf3, 0x5d }, + { AMOVAPD, yxmov, Pe, 0x28,0x29 }, + { AMOVAPS, yxmov, Pm, 0x28,0x29 }, + { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) }, + { AMOVBLSX, ymb_rl, Pm, 0xbe }, + { AMOVBLZX, ymb_rl, Pm, 0xb6 }, + { AMOVBQSX, ymb_rl, Pw, 0x0f,0xbe }, + { AMOVBQZX, ymb_rl, Pw, 0x0f,0xb6 }, + { AMOVBWSX, ymb_rl, Pq, 0xbe }, + { AMOVBWZX, ymb_rl, Pq, 0xb6 }, + { AMOVO, yxmov, Pe, 0x6f,0x7f }, + { AMOVOU, yxmov, Pf2, 0x6f,0x7f }, + { AMOVHLPS, yxr, Pm, 0x12 }, + { AMOVHPD, yxmov, Pe, 0x16,0x17 }, + { AMOVHPS, yxmov, Pm, 0x16,0x17 }, + { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e }, + { AMOVLHPS, yxr, Pm, 0x16 }, + { AMOVLPD, yxmov, Pe, 0x12,0x13 }, + { AMOVLPS, yxmov, Pm, 0x12,0x13 }, + { AMOVLQSX, yml_rl, Pw, 0x63 }, + { AMOVLQZX, yml_rl, Px, 0x63 }, + { AMOVMSKPD, yxrrl, Pq, 0x50 }, + { AMOVMSKPS, yxrrl, Pm, 0x50 }, + { AMOVNTO, yxr_ml, Pe, 0xe7 }, + { AMOVNTPD, yxr_ml, Pe, 0x2b }, + { AMOVNTPS, yxr_ml, Pm, 0x2b }, + { AMOVNTQ, ymr_ml, Pm, 0xe7 }, + { AMOVQ, ymovq, Pw, 0x89,0x8b,0x31,0xc7,(00),0xb8,0xc7,(00),0x6f,0x7f,0x6e,0x7e,Pf2,0xd6,Pe,0xd6,Pe,0x6e,Pe,0x7e }, + { AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e }, + { AMOVSB, ynone, Pb, 0xa4 }, + { AMOVSD, yxmov, Pf2, 0x10,0x11 }, + { AMOVSL, ynone, Px, 0xa5 }, + { AMOVSQ, ynone, Pw, 0xa5 }, + { AMOVSS, yxmov, Pf3, 0x10,0x11 }, + { AMOVSW, ynone, Pe, 0xa5 }, + { AMOVUPD, yxmov, Pe, 0x10,0x11 }, + { AMOVUPS, yxmov, Pm, 0x10,0x11 }, + { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0xb8,0xc7,(00) }, + { AMOVWLSX, yml_rl, Pm, 0xbf }, + { AMOVWLZX, yml_rl, Pm, 0xb7 }, + { AMOVWQSX, yml_rl, Pw, 0x0f,0xbf }, + { AMOVWQZX, yml_rl, Pw, 0x0f,0xb7 }, + { AMULB, ydivb, Pb, 0xf6,(04) }, + { AMULL, ydivl, Px, 0xf7,(04) }, + { AMULPD, yxm, Pe, 0x59 }, + { AMULPS, yxm, Ym, 0x59 }, + { AMULQ, ydivl, Pw, 0xf7,(04) }, + { AMULSD, yxm, Pf2, 0x59 }, + { AMULSS, yxm, Pf3, 0x59 }, + { AMULW, ydivl, Pe, 0xf7,(04) }, + { ANAME }, + { ANEGB, yscond, Pb, 0xf6,(03) }, + { ANEGL, yscond, Px, 0xf7,(03) }, + { ANEGQ, yscond, Pw, 0xf7,(03) }, + { ANEGW, yscond, Pe, 0xf7,(03) }, + { ANOP, ynop, Px, 0,0 }, + { ANOTB, yscond, Pb, 0xf6,(02) }, + { ANOTL, yscond, Px, 0xf7,(02) }, + { ANOTQ, yscond, Pw, 0xf7,(02) }, + { ANOTW, yscond, Pe, 0xf7,(02) }, + { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a }, + { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, + { AORPD, yxm, Pq, 0x56 }, + { AORPS, yxm, Pm, 0x56 }, + { AORQ, yxorl, Pw, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, + { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, + { AOUTB, yin, Pb, 0xe6,0xee }, + { AOUTL, yin, Px, 0xe7,0xef }, + { AOUTSB, ynone, Pb, 0x6e }, + { AOUTSL, ynone, Px, 0x6f }, + { AOUTSW, ynone, Pe, 0x6f }, + { AOUTW, yin, Pe, 0xe7,0xef }, + { APACKSSLW, ymm, Py, 0x6b,Pe,0x6b }, + { APACKSSWB, ymm, Py, 0x63,Pe,0x63 }, + { APACKUSWB, ymm, Py, 0x67,Pe,0x67 }, + { APADDB, ymm, Py, 0xfc,Pe,0xfc }, + { APADDL, ymm, Py, 0xfe,Pe,0xfe }, + { APADDQ, yxm, Pe, 0xd4 }, + { APADDSB, ymm, Py, 0xec,Pe,0xec }, + { APADDSW, ymm, Py, 0xed,Pe,0xed }, + { APADDUSB, ymm, Py, 0xdc,Pe,0xdc }, + { APADDUSW, ymm, Py, 0xdd,Pe,0xdd }, + { APADDW, ymm, Py, 0xfd,Pe,0xfd }, + { APAND, ymm, Py, 0xdb,Pe,0xdb }, + { APANDN, ymm, Py, 0xdf,Pe,0xdf }, + { APAVGB, ymm, Py, 0xe0,Pe,0xe0 }, + { APAVGW, ymm, Py, 0xe3,Pe,0xe3 }, + { APCMPEQB, ymm, Py, 0x74,Pe,0x74 }, + { APCMPEQL, ymm, Py, 0x76,Pe,0x76 }, + { APCMPEQW, ymm, Py, 0x75,Pe,0x75 }, + { APCMPGTB, ymm, Py, 0x64,Pe,0x64 }, + { APCMPGTL, ymm, Py, 0x66,Pe,0x66 }, + { APCMPGTW, ymm, Py, 0x65,Pe,0x65 }, + { APEXTRW, yextrw, Pq, 0xc5 }, + { APF2IL, ymfp, Px, 0x1d }, + { APF2IW, ymfp, Px, 0x1c }, + { API2FL, ymfp, Px, 0x0d }, + { APFACC, ymfp, Px, 0xae }, + { APFADD, ymfp, Px, 0x9e }, + { APFCMPEQ, ymfp, Px, 0xb0 }, + { APFCMPGE, ymfp, Px, 0x90 }, + { APFCMPGT, ymfp, Px, 0xa0 }, + { APFMAX, ymfp, Px, 0xa4 }, + { APFMIN, ymfp, Px, 0x94 }, + { APFMUL, ymfp, Px, 0xb4 }, + { APFNACC, ymfp, Px, 0x8a }, + { APFPNACC, ymfp, Px, 0x8e }, + { APFRCP, ymfp, Px, 0x96 }, + { APFRCPIT1, ymfp, Px, 0xa6 }, + { APFRCPI2T, ymfp, Px, 0xb6 }, + { APFRSQIT1, ymfp, Px, 0xa7 }, + { APFRSQRT, ymfp, Px, 0x97 }, + { APFSUB, ymfp, Px, 0x9a }, + { APFSUBR, ymfp, Px, 0xaa }, + { APINSRW, yextrw, Pq, 0xc4 }, + { APMADDWL, ymm, Py, 0xf5,Pe,0xf5 }, + { APMAXSW, yxm, Pe, 0xee }, + { APMAXUB, yxm, Pe, 0xde }, + { APMINSW, yxm, Pe, 0xea }, + { APMINUB, yxm, Pe, 0xda }, + { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 }, + { APMULHRW, ymfp, Px, 0xb7 }, + { APMULHUW, ymm, Py, 0xe4,Pe,0xe4 }, + { APMULHW, ymm, Py, 0xe5,Pe,0xe5 }, + { APMULLW, ymm, Py, 0xd5,Pe,0xd5 }, + { APMULULQ, ymm, Py, 0xf4,Pe,0xf4 }, + { APOPAL, ynone, P32, 0x61 }, + { APOPAW, ynone, Pe, 0x61 }, + { APOPFL, ynone, P32, 0x9d }, + { APOPFQ, ynone, Py, 0x9d }, + { APOPFW, ynone, Pe, 0x9d }, + { APOPL, ypopl, P32, 0x58,0x8f,(00) }, + { APOPQ, ypopl, Py, 0x58,0x8f,(00) }, + { APOPW, ypopl, Pe, 0x58,0x8f,(00) }, + { APOR, ymm, Py, 0xeb,Pe,0xeb }, + { APSADBW, yxm, Pw, Pe,0xf6 }, + { APSHUFHW, yxshuf, Pf3, 0x70 }, + { APSHUFL, yxm, Pw, Pe,0x70 }, + { APSHUFLW, yxshuf, Pf2, 0x70 }, + { APSHUFW, ymshuf, Pm, 0x70 }, + { APSLLO, ypsdq, Pq, 0x73,(07) }, + { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) }, + { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x7e,(06) }, + { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) }, + { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) }, + { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) }, + { APSRLO, ypsdq, Pq, 0x73,(03) }, + { APSRLL, yps, Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) }, + { APSRLQ, yps, Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) }, + { APSRLW, yps, Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) }, + { APSUBB, yxm, Pe, 0xf8 }, + { APSUBL, yxm, Pe, 0xfa }, + { APSUBQ, yxm, Pe, 0xfb }, + { APSUBSB, yxm, Pe, 0xe8 }, + { APSUBSW, yxm, Pe, 0xe9 }, + { APSUBUSB, yxm, Pe, 0xd8 }, + { APSUBUSW, yxm, Pe, 0xd9 }, + { APSUBW, yxm, Pe, 0xf9 }, + { APSWAPL, ymfp, Px, 0xbb }, + { APUNPCKHBW, ymm, Py, 0x68,Pe,0x68 }, + { APUNPCKHLQ, ymm, Py, 0x6a,Pe,0x6a }, + { APUNPCKHQDQ, yxm, Pe, 0x6d }, + { APUNPCKHWL, ymm, Py, 0x69,Pe,0x69 }, + { APUNPCKLBW, ymm, Py, 0x60,Pe,0x60 }, + { APUNPCKLLQ, ymm, Py, 0x62,Pe,0x62 }, + { APUNPCKLQDQ, yxm, Pe, 0x6c }, + { APUNPCKLWL, ymm, Py, 0x61,Pe,0x61 }, + { APUSHAL, ynone, P32, 0x60 }, + { APUSHAW, ynone, Pe, 0x60 }, + { APUSHFL, ynone, P32, 0x9c }, + { APUSHFQ, ynone, Py, 0x9c }, + { APUSHFW, ynone, Pe, 0x9c }, + { APUSHL, ypushl, P32, 0x50,0xff,(06),0x6a,0x68 }, + { APUSHQ, ypushl, Py, 0x50,0xff,(06),0x6a,0x68 }, + { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 }, + { APXOR, ymm, Py, 0xef,Pe,0xef }, + { AQUAD, ybyte, Px, 8 }, + { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) }, + { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCLQ, yshl, Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCPPS, yxm, Pm, 0x53 }, + { ARCPSS, yxm, Pf3, 0x53 }, + { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) }, + { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, + { ARCRQ, yshl, Pw, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, + { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, + { AREP, ynone, Px, 0xf3 }, + { AREPN, ynone, Px, 0xf2 }, + { ARET, ynone, Px, 0xc3 }, + { ARETFW, yret, Pe, 0xcb,0xca }, + { ARETFL, yret, Px, 0xcb,0xca }, + { ARETFQ, yret, Pw, 0xcb,0xca }, + { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) }, + { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, + { AROLQ, yshl, Pw, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, + { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, + { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) }, + { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, + { ARORQ, yshl, Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, + { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, + { ARSQRTPS, yxm, Pm, 0x52 }, + { ARSQRTSS, yxm, Pf3, 0x52 }, + { ASAHF, ynone, Px, 0x86,0xe0,0x50,0x9d }, /* XCHGB AH,AL; PUSH AX; POPFL */ + { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, + { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASALQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) }, + { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, + { ASARQ, yshl, Pw, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, + { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, + { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a }, + { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, + { ASBBQ, yxorl, Pw, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, + { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, + { ASCASB, ynone, Pb, 0xae }, + { ASCASL, ynone, Px, 0xaf }, + { ASCASQ, ynone, Pw, 0xaf }, + { ASCASW, ynone, Pe, 0xaf }, + { ASETCC, yscond, Pm, 0x93,(00) }, + { ASETCS, yscond, Pm, 0x92,(00) }, + { ASETEQ, yscond, Pm, 0x94,(00) }, + { ASETGE, yscond, Pm, 0x9d,(00) }, + { ASETGT, yscond, Pm, 0x9f,(00) }, + { ASETHI, yscond, Pm, 0x97,(00) }, + { ASETLE, yscond, Pm, 0x9e,(00) }, + { ASETLS, yscond, Pm, 0x96,(00) }, + { ASETLT, yscond, Pm, 0x9c,(00) }, + { ASETMI, yscond, Pm, 0x98,(00) }, + { ASETNE, yscond, Pm, 0x95,(00) }, + { ASETOC, yscond, Pm, 0x91,(00) }, + { ASETOS, yscond, Pm, 0x90,(00) }, + { ASETPC, yscond, Pm, 0x96,(00) }, + { ASETPL, yscond, Pm, 0x99,(00) }, + { ASETPS, yscond, Pm, 0x9a,(00) }, + { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, + { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASHLQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) }, + { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, + { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, + { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, + { ASHUFPD, yxshuf, Pq, 0xc6 }, + { ASHUFPS, yxshuf, Pm, 0xc6 }, + { ASQRTPD, yxm, Pe, 0x51 }, + { ASQRTPS, yxm, Pm, 0x51 }, + { ASQRTSD, yxm, Pf2, 0x51 }, + { ASQRTSS, yxm, Pf3, 0x51 }, + { ASTC, ynone, Px, 0xf9 }, + { ASTD, ynone, Px, 0xfd }, + { ASTI, ynone, Px, 0xfb }, + { ASTMXCSR, ysvrs, Pm, 0xae,(03),0xae,(03) }, + { ASTOSB, ynone, Pb, 0xaa }, + { ASTOSL, ynone, Px, 0xab }, + { ASTOSQ, ynone, Pw, 0xab }, + { ASTOSW, ynone, Pe, 0xab }, + { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a }, + { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, + { ASUBPD, yxm, Pe, 0x5c }, + { ASUBPS, yxm, Pm, 0x5c }, + { ASUBQ, yaddl, Pw, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, + { ASUBSD, yxm, Pf2, 0x5c }, + { ASUBSS, yxm, Pf3, 0x5c }, + { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, + { ASWAPGS, ynone, Pm, 0x01,0xf8 }, + { ASYSCALL, ynone, Px, 0x0f,0x05 }, /* fast syscall */ + { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 }, + { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 }, + { ATESTQ, ytestl, Pw, 0xa9,0xf7,(00),0x85,0x85 }, + { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 }, + { ATEXT, ytext, Px }, + { AUCOMISD, yxcmp, Pe, 0x2e }, + { AUCOMISS, yxcmp, Pm, 0x2e }, + { AUNPCKHPD, yxm, Pe, 0x15 }, + { AUNPCKHPS, yxm, Pm, 0x15 }, + { AUNPCKLPD, yxm, Pe, 0x14 }, + { AUNPCKLPS, yxm, Pm, 0x14 }, + { AVERR, ydivl, Pm, 0x00,(04) }, + { AVERW, ydivl, Pm, 0x00,(05) }, + { AWAIT, ynone, Px, 0x9b }, + { AWORD, ybyte, Px, 2 }, + { AXCHGB, yml_mb, Pb, 0x86,0x86 }, + { AXCHGL, yml_ml, Px, 0x87,0x87 }, + { AXCHGQ, yml_ml, Pw, 0x87,0x87 }, + { AXCHGW, yml_ml, Pe, 0x87,0x87 }, + { AXLAT, ynone, Px, 0xd7 }, + { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 }, + { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, + { AXORPD, yxm, Pe, 0x57 }, + { AXORPS, yxm, Pm, 0x57 }, + { AXORQ, yxorl, Pw, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, + { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, + + { AFMOVB, yfmvx, Px, 0xdf,(04) }, + { AFMOVBP, yfmvp, Px, 0xdf,(06) }, + { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) }, + { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) }, + { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) }, + { AFMOVFP, yfmvp, Px, 0xd9,(03) }, + { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) }, + { AFMOVLP, yfmvp, Px, 0xdb,(03) }, + { AFMOVV, yfmvx, Px, 0xdf,(05) }, + { AFMOVVP, yfmvp, Px, 0xdf,(07) }, + { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) }, + { AFMOVWP, yfmvp, Px, 0xdf,(03) }, + { AFMOVX, yfmvx, Px, 0xdb,(05) }, + { AFMOVXP, yfmvp, Px, 0xdb,(07) }, + + { AFCOMB }, + { AFCOMBP }, + { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */ + { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */ + { AFCOMDPP, ycompp, Px, 0xde,(03) }, + { AFCOMF, yfmvx, Px, 0xd8,(02) }, + { AFCOMFP, yfmvx, Px, 0xd8,(03) }, + { AFCOML, yfmvx, Px, 0xda,(02) }, + { AFCOMLP, yfmvx, Px, 0xda,(03) }, + { AFCOMW, yfmvx, Px, 0xde,(02) }, + { AFCOMWP, yfmvx, Px, 0xde,(03) }, + + { AFUCOM, ycompp, Px, 0xdd,(04) }, + { AFUCOMP, ycompp, Px, 0xdd,(05) }, + { AFUCOMPP, ycompp, Px, 0xda,(13) }, + + { AFADDDP, yfaddp, Px, 0xde,(00) }, + { AFADDW, yfmvx, Px, 0xde,(00) }, + { AFADDL, yfmvx, Px, 0xda,(00) }, + { AFADDF, yfmvx, Px, 0xd8,(00) }, + { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) }, + + { AFMULDP, yfaddp, Px, 0xde,(01) }, + { AFMULW, yfmvx, Px, 0xde,(01) }, + { AFMULL, yfmvx, Px, 0xda,(01) }, + { AFMULF, yfmvx, Px, 0xd8,(01) }, + { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) }, + + { AFSUBDP, yfaddp, Px, 0xde,(05) }, + { AFSUBW, yfmvx, Px, 0xde,(04) }, + { AFSUBL, yfmvx, Px, 0xda,(04) }, + { AFSUBF, yfmvx, Px, 0xd8,(04) }, + { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) }, + + { AFSUBRDP, yfaddp, Px, 0xde,(04) }, + { AFSUBRW, yfmvx, Px, 0xde,(05) }, + { AFSUBRL, yfmvx, Px, 0xda,(05) }, + { AFSUBRF, yfmvx, Px, 0xd8,(05) }, + { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) }, + + { AFDIVDP, yfaddp, Px, 0xde,(07) }, + { AFDIVW, yfmvx, Px, 0xde,(06) }, + { AFDIVL, yfmvx, Px, 0xda,(06) }, + { AFDIVF, yfmvx, Px, 0xd8,(06) }, + { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) }, + + { AFDIVRDP, yfaddp, Px, 0xde,(06) }, + { AFDIVRW, yfmvx, Px, 0xde,(07) }, + { AFDIVRL, yfmvx, Px, 0xda,(07) }, + { AFDIVRF, yfmvx, Px, 0xd8,(07) }, + { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) }, + + { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) }, + { AFFREE }, + { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) }, + { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) }, + { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) }, + { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) }, + { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) }, + { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) }, + { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 }, + { AF2XM1, ynone, Px, 0xd9, 0xf0 }, + { AFABS, ynone, Px, 0xd9, 0xe1 }, + { AFCHS, ynone, Px, 0xd9, 0xe0 }, + { AFCLEX, ynone, Px, 0xdb, 0xe2 }, + { AFCOS, ynone, Px, 0xd9, 0xff }, + { AFDECSTP, ynone, Px, 0xd9, 0xf6 }, + { AFINCSTP, ynone, Px, 0xd9, 0xf7 }, + { AFINIT, ynone, Px, 0xdb, 0xe3 }, + { AFLD1, ynone, Px, 0xd9, 0xe8 }, + { AFLDL2E, ynone, Px, 0xd9, 0xea }, + { AFLDL2T, ynone, Px, 0xd9, 0xe9 }, + { AFLDLG2, ynone, Px, 0xd9, 0xec }, + { AFLDLN2, ynone, Px, 0xd9, 0xed }, + { AFLDPI, ynone, Px, 0xd9, 0xeb }, + { AFLDZ, ynone, Px, 0xd9, 0xee }, + { AFNOP, ynone, Px, 0xd9, 0xd0 }, + { AFPATAN, ynone, Px, 0xd9, 0xf3 }, + { AFPREM, ynone, Px, 0xd9, 0xf8 }, + { AFPREM1, ynone, Px, 0xd9, 0xf5 }, + { AFPTAN, ynone, Px, 0xd9, 0xf2 }, + { AFRNDINT, ynone, Px, 0xd9, 0xfc }, + { AFSCALE, ynone, Px, 0xd9, 0xfd }, + { AFSIN, ynone, Px, 0xd9, 0xfe }, + { AFSINCOS, ynone, Px, 0xd9, 0xfb }, + { AFSQRT, ynone, Px, 0xd9, 0xfa }, + { AFTST, ynone, Px, 0xd9, 0xe4 }, + { AFXAM, ynone, Px, 0xd9, 0xe5 }, + { AFXTRACT, ynone, Px, 0xd9, 0xf4 }, + { AFYL2X, ynone, Px, 0xd9, 0xf1 }, + { AFYL2XP1, ynone, Px, 0xd9, 0xf9 }, + + { ACMPXCHGB, yrb_mb, Pb, 0x0f,0xb0 }, + { ACMPXCHGL, yrl_ml, Px, 0x0f,0xb1 }, + { ACMPXCHGW, yrl_ml, Pe, 0x0f,0xb1 }, + { ACMPXCHGQ, yrl_ml, Pw, 0x0f,0xb1 }, + { ACMPXCHG8B, yscond, Pm, 0xc7,(01) }, + { AINVD, ynone, Pm, 0x08 }, + { AINVLPG, ymbs, Pm, 0x01,(07) }, + { ALFENCE, ynone, Pm, 0xae,0xe8 }, + { AMFENCE, ynone, Pm, 0xae,0xf0 }, + { AMOVNTIL, yrl_ml, Pm, 0xc3 }, + { AMOVNTIQ, yrl_ml, Pw, 0x0f,0xc3 }, + { ARDMSR, ynone, Pm, 0x32 }, + { ARDPMC, ynone, Pm, 0x33 }, + { ARDTSC, ynone, Pm, 0x31 }, + { ARSM, ynone, Pm, 0xaa }, + { ASFENCE, ynone, Pm, 0xae,0xf8 }, + { ASYSRET, ynone, Pm, 0x07 }, + { AWBINVD, ynone, Pm, 0x09 }, + { AWRMSR, ynone, Pm, 0x30 }, + + { AXADDB, yrb_mb, Pb, 0x0f,0xc0 }, + { AXADDL, yrl_ml, Px, 0x0f,0xc1 }, + { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 }, + { AXADDW, yrl_ml, Pe, 0x0f,0xc1 }, + + { AEND }, + 0 +}; + +Optab* opindex[ALAST+1]; + +/* +AMOVD 0f 6e/r mmx,reg/mem32[mem64-rex?] +AMOVD 0f 7e/r reg/mem32[64],mmx STORE +AMOVQ 0f 6f/r mmx1,mmx2/mem64 +AMOVQ 0f 7f/r mmx1/mem64,mmx2 +*/ diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c new file mode 100644 index 0000000000..5884022383 --- /dev/null +++ b/src/cmd/6l/pass.c @@ -0,0 +1,820 @@ +// Inferno utils/6l/pass.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "l.h" + +void +dodata(void) +{ + int i; + Sym *s; + Prog *p; + long t, u; + + if(debug['v']) + Bprint(&bso, "%5.2f dodata\n", cputime()); + Bflush(&bso); + for(p = datap; p != P; p = p->link) { + s = p->from.sym; + if(p->as == ADYNT || p->as == AINIT) + s->value = dtype; + if(s->type == SBSS) + s->type = SDATA; + if(s->type != SDATA) + diag("initialize non-data (%d): %s\n%P", + s->type, s->name, p); + t = p->from.offset + p->width; + if(t > s->value) + diag("initialize bounds (%lld): %s\n%P", + s->value, s->name, p); + } + /* allocate small guys */ + datsize = 0; + for(i=0; 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/src/cmd/6l/span.c b/src/cmd/6l/span.c new file mode 100644 index 0000000000..4b225da8ca --- /dev/null +++ b/src/cmd/6l/span.c @@ -0,0 +1,1776 @@ +// Inferno utils/6l/span.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "l.h" + +static int rexflag; +static int asmode; + +void +span(void) +{ + Prog *p, *q; + long v; + vlong c, idat; + int m, n, again; + + xdefine("etext", STEXT, 0L); + idat = INITDAT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + n = 0; + if(p->to.type == D_BRANCH) + if(p->pcond == P) + p->pcond = p; + if((q = p->pcond) != P) + if(q->back != 2) + n = 1; + p->back = n; + if(p->as == AADJSP) { + p->to.type = D_SP; + v = -p->from.offset; + p->from.offset = v; + p->as = p->mode != 64? AADDL: AADDQ; + if(v < 0) { + p->as = p->mode != 64? ASUBL: ASUBQ; + v = -v; + p->from.offset = v; + } + if(v == 0) + p->as = ANOP; + } + } + n = 0; + +start: + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + Bflush(&bso); + c = INITTEXT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->to.type == D_BRANCH) + if(p->back) + p->pc = c; + asmins(p); + p->pc = c; + m = andptr-and; + p->mark = m; + c += m; + } + +loop: + n++; + if(debug['v']) + Bprint(&bso, "%5.2f span %d\n", cputime(), n); + Bflush(&bso); + if(n > 50) { + print("span must be looping\n"); + errorexit(); + } + again = 0; + c = INITTEXT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->to.type == D_BRANCH || p->back & 0100) { + if(p->back) + p->pc = c; + asmins(p); + m = andptr-and; + if(m != p->mark) { + p->mark = m; + again++; + } + } + p->pc = c; + c += p->mark; + } + if(again) { + textsize = c; + goto loop; + } + if(INITRND) { + INITDAT = rnd(c, INITRND); + if(INITDAT != idat) { + idat = INITDAT; + goto start; + } + } + xdefine("etext", STEXT, c); + if(debug['v']) + Bprint(&bso, "etext = %llux\n", c); + Bflush(&bso); + for(p = textp; p != P; p = p->pcond) + p->from.sym->value = p->pc; + textsize = c - INITTEXT; +} + +void +xdefine(char *p, int t, vlong v) +{ + Sym *s; + + s = lookup(p, 0); + if(s->type == 0 || s->type == SXREF) { + s->type = t; + s->value = v; + } + if(s->type == STEXT && s->value == 0) + s->value = v; +} + +void +putsymb(char *s, int t, vlong v, int ver) +{ + int i, f, l; + + if(t == 'f') + s++; + l = 4; + if(!debug['8']){ + lput(v>>32); + l = 8; + } + lput(v); + if(ver) + t += 'a' - 'A'; + cput(t+0x80); /* 0x80 is variable length */ + + if(t == 'Z' || t == 'z') { + cput(s[0]); + for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) { + cput(s[i]); + cput(s[i+1]); + } + cput(0); + cput(0); + i++; + } + else { + for(i=0; s[i]; i++) + cput(s[i]); + cput(0); + } + symsize += l + 1 + i + 1; + + if(debug['n']) { + if(t == 'z' || t == 'Z') { + Bprint(&bso, "%c %.8llux ", t, v); + for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) { + f = ((s[i]&0xff) << 8) | (s[i+1]&0xff); + Bprint(&bso, "/%x", f); + } + Bprint(&bso, "\n"); + return; + } + if(ver) + Bprint(&bso, "%c %.8llux %s<%d>\n", t, v, s, ver); + else + Bprint(&bso, "%c %.8llux %s\n", t, v, s); + } +} + +void +asmsym(void) +{ + Prog *p; + Auto *a; + Sym *s; + int h; + + s = lookup("etext", 0); + if(s->type == STEXT) + putsymb(s->name, 'T', s->value, s->version); + + for(h=0; 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[(int)a->index] << 3; + break; + } + switch(a->scale) { + default: + goto bad; + case 1: + break; + case 2: + i |= (1<<6); + break; + case 4: + i |= (2<<6); + break; + case 8: + i |= (3<<6); + break; + } +bas: + switch(base) { + default: + goto bad; + case D_NONE: /* must be mod=00 */ + i |= 5; + break; + case D_R8: + case D_R9: + case D_R10: + case D_R11: + case D_R12: + case D_R13: + case D_R14: + case D_R15: + if(asmode != 64) + goto bad; + case D_AX: + case D_CX: + case D_DX: + case D_BX: + case D_SP: + case D_BP: + case D_SI: + case D_DI: + i |= reg[base]; + break; + } + *andptr++ = i; + return; +bad: + diag("asmidx: bad address %D", a); + *andptr++ = 0; + return; +} + +static void +put4(long v) +{ + if(dlm && curp != P && reloca != nil){ + dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1); + reloca = nil; + } + andptr[0] = v; + andptr[1] = v>>8; + andptr[2] = v>>16; + andptr[3] = v>>24; + andptr += 4; +} + +static void +put8(vlong v) +{ + if(dlm && curp != P && reloca != nil){ + dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1); /* TO DO */ + reloca = nil; + } + andptr[0] = v; + andptr[1] = v>>8; + andptr[2] = v>>16; + andptr[3] = v>>24; + andptr[4] = v>>32; + andptr[5] = v>>40; + andptr[6] = v>>48; + andptr[7] = v>>56; + andptr += 8; +} + +vlong +vaddr(Adr *a) +{ + int t; + vlong v; + Sym *s; + + t = a->type; + v = a->offset; + if(t == D_ADDR) + t = a->index; + switch(t) { + case D_STATIC: + case D_EXTERN: + s = a->sym; + if(s != nil) { + if(dlm && curp != P) + reloca = a; + switch(s->type) { + case SUNDEF: + ckoff(s, v); + case STEXT: + case SCONST: + if((uvlong)s->value < (uvlong)INITTEXT) + v += INITTEXT; /* TO DO */ + v += s->value; + break; + default: + v += INITDAT + s->value; + } + } + } + return v; +} + +static void +asmandsz(Adr *a, int r, int rex, int m64) +{ + long v; + int t; + Adr aa; + + rex &= (0x40 | Rxr); + v = a->offset; + t = a->type; + if(a->index != D_NONE) { + if(t >= D_INDIR) { + t -= D_INDIR; + rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex; + if(t == D_NONE) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(a, t); + put4(v); + return; + } + if(v == 0 && t != D_BP && t != D_R13) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(a, t); + return; + } + if(v >= -128 && v < 128) { + *andptr++ = (1 << 6) | (4 << 0) | (r << 3); + asmidx(a, t); + *andptr++ = v; + return; + } + *andptr++ = (2 << 6) | (4 << 0) | (r << 3); + asmidx(a, t); + put4(v); + return; + } + switch(t) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + aa.type = D_NONE+D_INDIR; + break; + case D_AUTO: + case D_PARAM: + aa.type = D_SP+D_INDIR; + break; + } + aa.offset = vaddr(a); + aa.index = a->index; + aa.scale = a->scale; + asmandsz(&aa, r, rex, m64); + return; + } + if(t >= D_AL && t <= D_X0+15) { + if(v) + goto bad; + *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3); + rexflag |= (regrex[t] & (0x40 | Rxb)) | rex; + return; + } + if(t >= D_INDIR) { + t -= D_INDIR; + rexflag |= (regrex[t] & Rxb) | rex; + if(t == D_NONE) { + if(asmode != 64){ + *andptr++ = (0 << 6) | (5 << 0) | (r << 3); + put4(v); + return; + } + /* temporary */ + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */ + *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */ + put4(v); + return; + } + if(t == D_SP || t == D_R12) { + if(v == 0) { + *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); + asmidx(a, t); + return; + } + if(v >= -128 && v < 128) { + *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3); + asmidx(a, t); + *andptr++ = v; + return; + } + *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); + asmidx(a, t); + put4(v); + return; + } + if(t >= D_AX && t <= D_R15) { + if(v == 0 && t != D_BP && t != D_R13) { + *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); + return; + } + if(v >= -128 && v < 128) { + andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3); + andptr[1] = v; + andptr += 2; + return; + } + *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); + put4(v); + return; + } + goto bad; + } + switch(a->type) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + aa.type = D_NONE+D_INDIR; + break; + case D_AUTO: + case D_PARAM: + aa.type = D_SP+D_INDIR; + break; + } + aa.index = D_NONE; + aa.scale = 1; + aa.offset = vaddr(a); + asmandsz(&aa, r, rex, m64); + return; +bad: + diag("asmand: bad address %D", a); + return; +} + +void +asmand(Adr *a, Adr *ra) +{ + asmandsz(a, reg[ra->type], regrex[ra->type], 0); +} + +void +asmando(Adr *a, int o) +{ + asmandsz(a, o, 0, 0); +} + +static void +bytereg(Adr *a) +{ + if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) + a->type = D_AL + (a->type-D_AX); +} + +#define E 0xff +Movtab ymovtab[] = +{ +/* push */ + {APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0}, + {APUSHL, Yss, Ynone, 0, 0x16,E,0,0}, + {APUSHL, Yds, Ynone, 0, 0x1e,E,0,0}, + {APUSHL, Yes, Ynone, 0, 0x06,E,0,0}, + {APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0}, + {APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0}, + {APUSHQ, Yfs, Ynone, 0, 0x0f,0xa0,E,0}, + {APUSHQ, Ygs, Ynone, 0, 0x0f,0xa8,E,0}, + + {APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0}, + {APUSHW, Yss, Ynone, 0, Pe,0x16,E,0}, + {APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0}, + {APUSHW, Yes, Ynone, 0, Pe,0x06,E,0}, + {APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E}, + {APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E}, + +/* pop */ + {APOPL, Ynone, Yds, 0, 0x1f,E,0,0}, + {APOPL, Ynone, Yes, 0, 0x07,E,0,0}, + {APOPL, Ynone, Yss, 0, 0x17,E,0,0}, + {APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0}, + {APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0}, + {APOPQ, Ynone, Yfs, 0, 0x0f,0xa1,E,0}, + {APOPQ, Ynone, Ygs, 0, 0x0f,0xa9,E,0}, + + {APOPW, Ynone, Yds, 0, Pe,0x1f,E,0}, + {APOPW, Ynone, Yes, 0, Pe,0x07,E,0}, + {APOPW, Ynone, Yss, 0, Pe,0x17,E,0}, + {APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E}, + {APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E}, + +/* mov seg */ + {AMOVW, Yes, Yml, 1, 0x8c,0,0,0}, + {AMOVW, Ycs, Yml, 1, 0x8c,1,0,0}, + {AMOVW, Yss, Yml, 1, 0x8c,2,0,0}, + {AMOVW, Yds, Yml, 1, 0x8c,3,0,0}, + {AMOVW, Yfs, Yml, 1, 0x8c,4,0,0}, + {AMOVW, Ygs, Yml, 1, 0x8c,5,0,0}, + + {AMOVW, Yml, Yes, 2, 0x8e,0,0,0}, + {AMOVW, Yml, Ycs, 2, 0x8e,1,0,0}, + {AMOVW, Yml, Yss, 2, 0x8e,2,0,0}, + {AMOVW, Yml, Yds, 2, 0x8e,3,0,0}, + {AMOVW, Yml, Yfs, 2, 0x8e,4,0,0}, + {AMOVW, Yml, Ygs, 2, 0x8e,5,0,0}, + +/* mov cr */ + {AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0}, + {AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0}, + {AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0}, + {AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0}, + {AMOVL, Ycr8, Yml, 3, 0x0f,0x20,8,0}, + {AMOVQ, Ycr0, Yml, 3, 0x0f,0x20,0,0}, + {AMOVQ, Ycr2, Yml, 3, 0x0f,0x20,2,0}, + {AMOVQ, Ycr3, Yml, 3, 0x0f,0x20,3,0}, + {AMOVQ, Ycr4, Yml, 3, 0x0f,0x20,4,0}, + {AMOVQ, Ycr8, Yml, 3, 0x0f,0x20,8,0}, + + {AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0}, + {AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0}, + {AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0}, + {AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0}, + {AMOVL, Yml, Ycr8, 4, 0x0f,0x22,8,0}, + {AMOVQ, Yml, Ycr0, 4, 0x0f,0x22,0,0}, + {AMOVQ, Yml, Ycr2, 4, 0x0f,0x22,2,0}, + {AMOVQ, Yml, Ycr3, 4, 0x0f,0x22,3,0}, + {AMOVQ, Yml, Ycr4, 4, 0x0f,0x22,4,0}, + {AMOVQ, Yml, Ycr8, 4, 0x0f,0x22,8,0}, + +/* mov dr */ + {AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0}, + {AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0}, + {AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0}, + {AMOVQ, Ydr0, Yml, 3, 0x0f,0x21,0,0}, + {AMOVQ, Ydr6, Yml, 3, 0x0f,0x21,6,0}, + {AMOVQ, Ydr7, Yml, 3, 0x0f,0x21,7,0}, + + {AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0}, + {AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0}, + {AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0}, + {AMOVQ, Yml, Ydr0, 4, 0x0f,0x23,0,0}, + {AMOVQ, Yml, Ydr6, 4, 0x0f,0x23,6,0}, + {AMOVQ, Yml, Ydr7, 4, 0x0f,0x23,7,0}, + +/* mov tr */ + {AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0}, + {AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0}, + + {AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E}, + {AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E}, + +/* lgdt, sgdt, lidt, sidt */ + {AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0}, + {AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0}, + {AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0}, + {AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0}, + {AMOVQ, Ym, Ygdtr, 4, 0x0f,0x01,2,0}, + {AMOVQ, Ygdtr, Ym, 3, 0x0f,0x01,0,0}, + {AMOVQ, Ym, Yidtr, 4, 0x0f,0x01,3,0}, + {AMOVQ, Yidtr, Ym, 3, 0x0f,0x01,1,0}, + +/* lldt, sldt */ + {AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0}, + {AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0}, + +/* lmsw, smsw */ + {AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0}, + {AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0}, + +/* ltr, str */ + {AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0}, + {AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0}, + +/* load full pointer */ + {AMOVL, Yml, Ycol, 5, 0,0,0,0}, + {AMOVW, Yml, Ycol, 5, Pe,0,0,0}, + +/* double shift */ + {ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0}, + {ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0}, + {ASHLQ, Ycol, Yml, 6, Pw,0xa4,0xa5,0}, + {ASHRQ, Ycol, Yml, 6, Pw,0xac,0xad,0}, + {ASHLW, Ycol, Yml, 6, Pe,0xa4,0xa5,0}, + {ASHRW, Ycol, Yml, 6, Pe,0xac,0xad,0}, + 0 +}; + +int +isax(Adr *a) +{ + + switch(a->type) { + case D_AX: + case D_AL: + case D_AH: + case D_INDIR+D_AX: + return 1; + } + if(a->index == D_AX) + return 1; + return 0; +} + +void +subreg(Prog *p, int from, int to) +{ + + if(debug['Q']) + print("\n%P s/%R/%R/\n", p, from, to); + + if(p->from.type == from) + p->from.type = to; + if(p->to.type == from) + p->to.type = to; + + if(p->from.index == from) + p->from.index = to; + if(p->to.index == from) + p->to.index = to; + + from += D_INDIR; + if(p->from.type == from) + p->from.type = to+D_INDIR; + if(p->to.type == from) + p->to.type = to+D_INDIR; + + if(debug['Q']) + print("%P\n", p); +} + +static int +mediaop(Optab *o, int op, int osize, int z) +{ + switch(op){ + case Pm: + case Pe: + case Pf2: + case Pf3: + if(osize != 1){ + if(op != Pm) + *andptr++ = op; + *andptr++ = Pm; + op = o->op[++z]; + break; + } + default: + if(andptr == and || andptr[-1] != Pm) + *andptr++ = Pm; + break; + } + *andptr++ = op; + return z; +} + +void +doasm(Prog *p) +{ + Optab *o; + Prog *q, pp; + uchar *t; + Movtab *mo; + int z, op, ft, tt, xo, l; + vlong v; + + o = opindex[p->as]; + if(o == nil) { + diag("asmins: missing op %P", p); + return; + } + ft = oclass(&p->from) * Ymax; + tt = oclass(&p->to) * Ymax; + t = o->ytab; + if(t == 0) { + diag("asmins: noproto %P", p); + return; + } + xo = o->op[0] == 0x0f; + for(z=0; *t; z+=t[3]+xo,t+=4) + if(ycover[ft+t[0]]) + if(ycover[tt+t[1]]) + goto found; + goto domov; + +found: + switch(o->prefix) { + case Pq: /* 16 bit escape and opcode escape */ + *andptr++ = Pe; + *andptr++ = Pm; + break; + + case Pf2: /* xmm opcode escape */ + case Pf3: + *andptr++ = o->prefix; + *andptr++ = Pm; + break; + + case Pm: /* opcode escape */ + *andptr++ = Pm; + break; + + case Pe: /* 16 bit escape */ + *andptr++ = Pe; + break; + + case Pw: /* 64-bit escape */ + if(p->mode != 64) + diag("asmins: illegal 64: %P", p); + rexflag |= Pw; + break; + + case Pb: /* botch */ + bytereg(&p->from); + bytereg(&p->to); + break; + + case P32: /* 32 bit but illegal if 64-bit mode */ + if(p->mode == 64) + diag("asmins: illegal in 64-bit mode: %P", p); + break; + + case Py: /* 64-bit only, no prefix */ + if(p->mode != 64) + diag("asmins: illegal in %d-bit mode: %P", p->mode, p); + break; + } + v = vaddr(&p->from); + op = o->op[z]; + if(op == 0x0f) { + *andptr++ = op; + op = o->op[++z]; + } + switch(t[2]) { + default: + diag("asmins: unknown z %d %P", t[2], p); + return; + + case Zpseudo: + break; + + case Zlit: + for(; op = o->op[z]; z++) + *andptr++ = op; + break; + + case Zmb_r: + bytereg(&p->from); + /* fall through */ + case Zm_r: + *andptr++ = op; + asmand(&p->from, &p->to); + break; + + case Zm_r_xm: + mediaop(o, op, t[3], z); + asmand(&p->from, &p->to); + break; + + case Zm_r_xm_nr: + rexflag = 0; + mediaop(o, op, t[3], z); + asmand(&p->from, &p->to); + break; + + case Zm_r_i_xm: + mediaop(o, op, t[3], z); + asmand(&p->from, &p->to); + *andptr++ = p->to.offset; + break; + + case Zm_r_3d: + *andptr++ = 0x0f; + *andptr++ = 0x0f; + asmand(&p->from, &p->to); + *andptr++ = op; + break; + + case Zibm_r: + *andptr++ = op; + asmand(&p->from, &p->to); + *andptr++ = p->to.offset; + break; + + case Zaut_r: + *andptr++ = 0x8d; /* leal */ + if(p->from.type != D_ADDR) + diag("asmins: Zaut sb type ADDR"); + p->from.type = p->from.index; + p->from.index = D_NONE; + asmand(&p->from, &p->to); + p->from.index = p->from.type; + p->from.type = D_ADDR; + break; + + case Zm_o: + *andptr++ = op; + asmando(&p->from, o->op[z+1]); + break; + + case Zr_m: + *andptr++ = op; + asmand(&p->to, &p->from); + break; + + case Zr_m_xm: + mediaop(o, op, t[3], z); + asmand(&p->to, &p->from); + break; + + case Zr_m_xm_nr: + rexflag = 0; + mediaop(o, op, t[3], z); + asmand(&p->to, &p->from); + break; + + case Zr_m_i_xm: + mediaop(o, op, t[3], z); + asmand(&p->to, &p->from); + *andptr++ = p->from.offset; + break; + + case Zo_m: + *andptr++ = op; + asmando(&p->to, o->op[z+1]); + break; + + case Zo_m64: + *andptr++ = op; + asmandsz(&p->to, o->op[z+1], 0, 1); + break; + + case Zm_ibo: + v = vaddr(&p->to); + *andptr++ = op; + asmando(&p->from, o->op[z+1]); + *andptr++ = v; + break; + + case Zibo_m: + *andptr++ = op; + asmando(&p->to, o->op[z+1]); + *andptr++ = v; + break; + + case Zibo_m_xm: + z = mediaop(o, op, t[3], z); + asmando(&p->to, o->op[z+1]); + *andptr++ = v; + break; + + case Z_ib: + v = vaddr(&p->to); + case Zib_: + *andptr++ = op; + *andptr++ = v; + break; + + case Zib_rp: + rexflag |= regrex[p->to.type] & (Rxb|0x40); + *andptr++ = op + reg[p->to.type]; + *andptr++ = v; + break; + + case Zil_rp: + rexflag |= regrex[p->to.type] & Rxb; + *andptr++ = op + reg[p->to.type]; + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Zo_iw: + *andptr++ = op; + if(p->from.type != D_NONE){ + *andptr++ = v; + *andptr++ = v>>8; + } + break; + + case Ziq_rp: + l = v>>32; + if(l == 0){ + //p->mark |= 0100; + //print("zero: %llux %P\n", v, p); + rexflag &= ~(0x40|Rxw); + rexflag |= regrex[p->to.type] & Rxb; + *andptr++ = 0xb8 + reg[p->to.type]; + put4(v); + }else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */ + //p->mark |= 0100; + //print("sign: %llux %P\n", v, p); + *andptr ++ = 0xc7; + asmando(&p->to, 0); + put4(v); + }else{ /* need all 8 */ + //print("all: %llux %P\n", v, p); + rexflag |= regrex[p->to.type] & Rxb; + *andptr++ = op + reg[p->to.type]; + put8(v); + } + break; + + case Zib_rr: + *andptr++ = op; + asmand(&p->to, &p->to); + *andptr++ = v; + break; + + case Z_il: + v = vaddr(&p->to); + case Zil_: + *andptr++ = op; + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Zm_ilo: + v = vaddr(&p->to); + *andptr++ = op; + asmando(&p->from, o->op[z+1]); + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Zilo_m: + *andptr++ = op; + asmando(&p->to, o->op[z+1]); + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Zil_rr: + *andptr++ = op; + asmand(&p->to, &p->to); + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Z_rp: + rexflag |= regrex[p->to.type] & (Rxb|0x40); + *andptr++ = op + reg[p->to.type]; + break; + + case Zrp_: + rexflag |= regrex[p->from.type] & (Rxb|0x40); + *andptr++ = op + reg[p->from.type]; + break; + + case Zclr: + *andptr++ = op; + asmand(&p->to, &p->to); + break; + + case Zbr: + q = p->pcond; + if(q) { + v = q->pc - p->pc - 2; + if(v >= -128 && v <= 127) { + *andptr++ = op; + *andptr++ = v; + } else { + v -= 6-2; + *andptr++ = 0x0f; + *andptr++ = o->op[z+1]; + *andptr++ = v; + *andptr++ = v>>8; + *andptr++ = v>>16; + *andptr++ = v>>24; + } + } + break; + + case Zcall: + q = p->pcond; + if(q) { + v = q->pc - p->pc - 5; + if(dlm && curp != P && p->to.sym->type == SUNDEF){ + /* v = 0 - p->pc - 5; */ + v = 0; + ckoff(p->to.sym, v); + v += p->to.sym->value; + dynreloc(p->to.sym, p->pc+1, 0); + } + *andptr++ = op; + *andptr++ = v; + *andptr++ = v>>8; + *andptr++ = v>>16; + *andptr++ = v>>24; + } + break; + + case Zjmp: + q = p->pcond; + if(q) { + v = q->pc - p->pc - 2; + if(v >= -128 && v <= 127) { + *andptr++ = op; + *andptr++ = v; + } else { + v -= 5-2; + *andptr++ = o->op[z+1]; + *andptr++ = v; + *andptr++ = v>>8; + *andptr++ = v>>16; + *andptr++ = v>>24; + } + } + break; + + case Zloop: + q = p->pcond; + if(q) { + v = q->pc - p->pc - 2; + if(v < -128 && v > 127) + diag("loop too far: %P", p); + *andptr++ = op; + *andptr++ = v; + } + break; + + case Zbyte: + *andptr++ = v; + if(op > 1) { + *andptr++ = v>>8; + if(op > 2) { + *andptr++ = v>>16; + *andptr++ = v>>24; + if(op > 4) { + *andptr++ = v>>32; + *andptr++ = v>>40; + *andptr++ = v>>48; + *andptr++ = v>>56; + } + } + } + break; + } + return; + +domov: + for(mo=ymovtab; mo->as; mo++) + if(p->as == mo->as) + if(ycover[ft+mo->ft]) + if(ycover[tt+mo->tt]){ + t = mo->op; + goto mfound; + } +bad: + if(p->mode != 64){ + /* + * here, the assembly has failed. + * if its a byte instruction that has + * unaddressable registers, try to + * exchange registers and reissue the + * instruction with the operands renamed. + */ + pp = *p; + z = p->from.type; + if(z >= D_BP && z <= D_DI) { + if(isax(&p->to)) { + *andptr++ = 0x87; /* xchg lhs,bx */ + asmando(&p->from, reg[D_BX]); + subreg(&pp, z, D_BX); + doasm(&pp); + *andptr++ = 0x87; /* xchg lhs,bx */ + asmando(&p->from, reg[D_BX]); + } else { + *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ + subreg(&pp, z, D_AX); + doasm(&pp); + *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ + } + return; + } + z = p->to.type; + if(z >= D_BP && z <= D_DI) { + if(isax(&p->from)) { + *andptr++ = 0x87; /* xchg rhs,bx */ + asmando(&p->to, reg[D_BX]); + subreg(&pp, z, D_BX); + doasm(&pp); + *andptr++ = 0x87; /* xchg rhs,bx */ + asmando(&p->to, reg[D_BX]); + } else { + *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ + subreg(&pp, z, D_AX); + doasm(&pp); + *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ + } + return; + } + } + diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p); + return; + +mfound: + switch(mo->code) { + default: + diag("asmins: unknown mov %d %P", mo->code, p); + break; + + case 0: /* lit */ + for(z=0; t[z]!=E; z++) + *andptr++ = t[z]; + break; + + case 1: /* r,m */ + *andptr++ = t[0]; + asmando(&p->to, t[1]); + break; + + case 2: /* m,r */ + *andptr++ = t[0]; + asmando(&p->from, t[1]); + break; + + case 3: /* r,m - 2op */ + *andptr++ = t[0]; + *andptr++ = t[1]; + asmando(&p->to, t[2]); + rexflag |= regrex[p->from.type] & (Rxr|0x40); + break; + + case 4: /* m,r - 2op */ + *andptr++ = t[0]; + *andptr++ = t[1]; + asmando(&p->from, t[2]); + rexflag |= regrex[p->to.type] & (Rxr|0x40); + break; + + case 5: /* load full pointer, trash heap */ + if(t[0]) + *andptr++ = t[0]; + switch(p->to.index) { + default: + goto bad; + case D_DS: + *andptr++ = 0xc5; + break; + case D_SS: + *andptr++ = 0x0f; + *andptr++ = 0xb2; + break; + case D_ES: + *andptr++ = 0xc4; + break; + case D_FS: + *andptr++ = 0x0f; + *andptr++ = 0xb4; + break; + case D_GS: + *andptr++ = 0x0f; + *andptr++ = 0xb5; + break; + } + asmand(&p->from, &p->to); + break; + + case 6: /* double shift */ + if(t[0] == Pw){ + if(p->mode != 64) + diag("asmins: illegal 64: %P", p); + rexflag |= Pw; + t++; + }else if(t[0] == Pe){ + *andptr++ = Pe; + t++; + } + z = p->from.type; + switch(z) { + default: + goto bad; + case D_CONST: + *andptr++ = 0x0f; + *andptr++ = t[0]; + asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0); + *andptr++ = p->from.offset; + break; + case D_CL: + case D_CX: + *andptr++ = 0x0f; + *andptr++ = t[1]; + asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0); + break; + } + break; + } +} + +void +asmins(Prog *p) +{ + int n, np, c; + + rexflag = 0; + andptr = and; + asmode = p->mode; + doasm(p); + if(rexflag){ + /* + * as befits the whole approach of the architecture, + * the rex prefix must appear before the first opcode byte + * (and thus after any 66/67/f2/f3 prefix bytes, but + * before the 0f opcode escape!), or it might be ignored. + * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'. + */ + if(p->mode != 64) + diag("asmins: illegal in mode %d: %P", p->mode, p); + n = andptr - and; + for(np = 0; np < n; np++) { + c = and[np]; + if(c != 0x66 && c != 0xf2 && c != 0xf3 && c != 0x67) + break; + } + memmove(and+np+1, and+np, n-np); + and[np] = 0x40 | rexflag; + andptr++; + } +} + +enum{ + ABSD = 0, + ABSU = 1, + RELD = 2, + RELU = 3, +}; + +int modemap[4] = { 0, 1, -1, 2, }; + +typedef struct Reloc Reloc; + +struct Reloc +{ + int n; + int t; + uchar *m; + ulong *a; +}; + +Reloc rels; + +static void +grow(Reloc *r) +{ + int t; + uchar *m, *nm; + ulong *a, *na; + + t = r->t; + r->t += 64; + m = r->m; + a = r->a; + r->m = nm = malloc(r->t*sizeof(uchar)); + r->a = na = malloc(r->t*sizeof(ulong)); + memmove(nm, m, t*sizeof(uchar)); + memmove(na, a, t*sizeof(ulong)); + free(m); + free(a); +} + +void +dynreloc(Sym *s, ulong v, int abs) +{ + int i, k, n; + uchar *m; + ulong *a; + Reloc *r; + + if(s->type == SUNDEF) + k = abs ? ABSU : RELU; + else + k = abs ? ABSD : RELD; + /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */ + k = modemap[k]; + r = &rels; + n = r->n; + if(n >= r->t) + grow(r); + m = r->m; + a = r->a; + for(i = n; i > 0; i--){ + if(v < a[i-1]){ /* happens occasionally for data */ + m[i] = m[i-1]; + a[i] = a[i-1]; + } + else + break; + } + m[i] = k; + a[i] = v; + r->n++; +} + +static int +sput(char *s) +{ + char *p; + + p = s; + while(*s) + cput(*s++); + cput(0); + return s-p+1; +} + +void +asmdyn() +{ + int i, n, t, c; + Sym *s; + ulong la, ra, *a; + vlong off; + uchar *m; + Reloc *r; + + cflush(); + off = seek(cout, 0, 1); + lput(0); + t = 0; + lput(imports); + t += 4; + for(i = 0; i < NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->type == SUNDEF){ + lput(s->sig); + t += 4; + t += sput(s->name); + } + + la = 0; + r = &rels; + n = r->n; + m = r->m; + a = r->a; + lput(n); + t += 4; + for(i = 0; i < n; i++){ + ra = *a-la; + if(*a < la) + diag("bad relocation order"); + if(ra < 256) + c = 0; + else if(ra < 65536) + c = 1; + else + c = 2; + cput((c<<6)|*m++); + t++; + if(c == 0){ + cput(ra); + t++; + } + else if(c == 1){ + wput(ra); + t += 2; + } + else{ + lput(ra); + t += 4; + } + la = *a++; + } + + cflush(); + seek(cout, off, 0); + lput(t); + + if(debug['v']){ + Bprint(&bso, "import table entries = %d\n", imports); + Bprint(&bso, "export table entries = %d\n", exports); + } +} diff --git a/src/cmd/cc/acid.c b/src/cmd/cc/acid.c new file mode 100644 index 0000000000..62be5e82b7 --- /dev/null +++ b/src/cmd/cc/acid.c @@ -0,0 +1,331 @@ +// Inferno utils/cc/acid.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/acid.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +static char *kwd[] = +{ + "$adt", "$aggr", "$append", "$complex", "$defn", + "$delete", "$do", "$else", "$eval", "$head", "$if", + "$local", "$loop", "$return", "$tail", "$then", + "$union", "$whatis", "$while", +}; + +char* +amap(char *s) +{ + int i, bot, top, new; + + bot = 0; + top = bot + nelem(kwd) - 1; + while(bot <= top){ + new = bot + (top - bot)/2; + i = strcmp(kwd[new]+1, s); + if(i == 0) + return kwd[new]; + + if(i < 0) + bot = new + 1; + else + top = new - 1; + } + return s; +} + +Sym* +acidsue(Type *t) +{ + int h; + Sym *s; + + if(t != T) + for(h=0; hlink) + if(s->suetag && s->suetag->link == t) + return s; + return 0; +} + +Sym* +acidfun(Type *t) +{ + int h; + Sym *s; + + for(h=0; hlink) + if(s->type == t) + return s; + return 0; +} + +char acidchar[NTYPE]; +Init acidcinit[] = +{ + TCHAR, 'C', 0, + TUCHAR, 'b', 0, + TSHORT, 'd', 0, + TUSHORT, 'u', 0, + TLONG, 'D', 0, + TULONG, 'U', 0, + TVLONG, 'V', 0, + TUVLONG, 'W', 0, + TFLOAT, 'f', 0, + TDOUBLE, 'F', 0, + TARRAY, 'a', 0, + TIND, 'X', 0, + -1, 0, 0, +}; + +static void +acidinit(void) +{ + Init *p; + + for(p=acidcinit; p->code >= 0; p++) + acidchar[p->code] = p->value; + + acidchar[TINT] = acidchar[TLONG]; + acidchar[TUINT] = acidchar[TULONG]; + if(types[TINT]->width != types[TLONG]->width) { + acidchar[TINT] = acidchar[TSHORT]; + acidchar[TUINT] = acidchar[TUSHORT]; + if(types[TINT]->width != types[TSHORT]->width) + warn(Z, "acidmember int not long or short"); + } + +} + +void +acidmember(Type *t, long off, int flag) +{ + Sym *s, *s1; + Type *l; + static int acidcharinit = 0; + + if(acidcharinit == 0) { + acidinit(); + acidcharinit = 1; + } + s = t->sym; + switch(t->etype) { + default: + Bprint(&outbuf, " T%d\n", t->etype); + break; + + case TIND: + if(s == S) + break; + if(flag) { + for(l=t; l->etype==TIND; l=l->link) + ; + if(typesu[l->etype]) { + s1 = acidsue(l->link); + if(s1 != S) { + Bprint(&outbuf, " 'A' %s %ld %s;\n", + amap(s1->name), + t->offset+off, amap(s->name)); + break; + } + } + } else { + Bprint(&outbuf, + "\tprint(\"\t%s\t\", addr.%s\\X, \"\\n\");\n", + amap(s->name), amap(s->name)); + break; + } + + case TINT: + case TUINT: + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TFLOAT: + case TDOUBLE: + case TARRAY: + if(s == S) + break; + if(flag) { + Bprint(&outbuf, " '%c' %ld %s;\n", + acidchar[t->etype], t->offset+off, amap(s->name)); + } else { + Bprint(&outbuf, "\tprint(\"\t%s\t\", addr.%s, \"\\n\");\n", + amap(s->name), amap(s->name)); + } + break; + + case TSTRUCT: + case TUNION: + s1 = acidsue(t->link); + if(s1 == S) + break; + if(flag) { + if(s == S) { + Bprint(&outbuf, " {\n"); + for(l = t->link; l != T; l = l->down) + acidmember(l, t->offset+off, flag); + Bprint(&outbuf, " };\n"); + } else { + Bprint(&outbuf, " %s %ld %s;\n", + amap(s1->name), + t->offset+off, amap(s->name)); + } + } else { + if(s != S) { + Bprint(&outbuf, "\tprint(\"%s %s {\\n\");\n", + amap(s1->name), amap(s->name)); + Bprint(&outbuf, "\t%s(addr.%s);\n", + amap(s1->name), amap(s->name)); + Bprint(&outbuf, "\tprint(\"}\\n\");\n"); + } else { + Bprint(&outbuf, "\tprint(\"%s {\\n\");\n", + amap(s1->name)); + Bprint(&outbuf, "\t\t%s(addr+%ld);\n", + amap(s1->name), t->offset+off); + Bprint(&outbuf, "\tprint(\"}\\n\");\n"); + } + } + break; + } +} + +void +acidtype(Type *t) +{ + Sym *s; + Type *l; + Io *i; + int n; + char *an; + + if(!debug['a']) + return; + if(debug['a'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return; + } + s = acidsue(t->link); + if(s == S) + return; + switch(t->etype) { + default: + Bprint(&outbuf, "T%d\n", t->etype); + return; + + case TUNION: + case TSTRUCT: + if(debug['s']) + goto asmstr; + an = amap(s->name); + Bprint(&outbuf, "sizeof%s = %ld;\n", an, t->width); + Bprint(&outbuf, "aggr %s\n{\n", an); + for(l = t->link; l != T; l = l->down) + acidmember(l, 0, 1); + Bprint(&outbuf, "};\n\n"); + + Bprint(&outbuf, "defn\n%s(addr) {\n\tcomplex %s addr;\n", an, an); + for(l = t->link; l != T; l = l->down) + acidmember(l, 0, 0); + Bprint(&outbuf, "};\n\n"); + break; + asmstr: + if(s == S) + break; + for(l = t->link; l != T; l = l->down) + if(l->sym != S) + Bprint(&outbuf, "#define\t%s.%s\t%ld\n", + s->name, + l->sym->name, + l->offset); + break; + } +} + +void +acidvar(Sym *s) +{ + int n; + Io *i; + Type *t; + Sym *s1, *s2; + + if(!debug['a'] || debug['s']) + return; + if(debug['a'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return; + } + t = s->type; + while(t && t->etype == TIND) + t = t->link; + if(t == T) + return; + if(t->etype == TENUM) { + Bprint(&outbuf, "%s = ", amap(s->name)); + if(!typefd[t->etype]) + Bprint(&outbuf, "%lld;\n", s->vconst); + else + Bprint(&outbuf, "%f\n;", s->fconst); + return; + } + if(!typesu[t->etype]) + return; + s1 = acidsue(t->link); + if(s1 == S) + return; + switch(s->class) { + case CAUTO: + case CPARAM: + s2 = acidfun(thisfn); + if(s2) + Bprint(&outbuf, "complex %s %s:%s;\n", + amap(s1->name), amap(s2->name), amap(s->name)); + break; + + case CSTATIC: + case CEXTERN: + case CGLOBL: + case CLOCAL: + Bprint(&outbuf, "complex %s %s;\n", + amap(s1->name), amap(s->name)); + break; + } +} diff --git a/src/cmd/cc/bits.c b/src/cmd/cc/bits.c new file mode 100644 index 0000000000..31e788c8a9 --- /dev/null +++ b/src/cmd/cc/bits.c @@ -0,0 +1,119 @@ +// Inferno utils/cc/bits.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +Bits +bor(Bits a, Bits b) +{ + Bits c; + int i; + + for(i=0; ib[i]) + return 1; + return 0; +} + +int +beq(Bits a, Bits b) +{ + int i; + + for(i=0; i +#include +#include +#include +#include "compat.h" + +#pragma lib "../cc/cc.a$O" + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Node Node; +typedef struct Sym Sym; +typedef struct Type Type; +typedef struct Funct Funct; +typedef struct Decl Decl; +typedef struct Io Io; +typedef struct Hist Hist; +typedef struct Term Term; +typedef struct Init Init; +typedef struct Bits Bits; + +#define NHUNK 50000L +#define BUFSIZ 8192 +#define NSYMB 500 +#define NHASH 1024 +#define STRINGSZ 200 +#define HISTSZ 20 +#define YYMAXDEPTH 500 +#define NTERM 10 +#define MAXALIGN 7 + +#define SIGN(n) ((vlong)1<<(n-1)) +#define MASK(n) (SIGN(n)|(SIGN(n)-1)) + +#define BITS 5 +#define NVAR (BITS*sizeof(ulong)*8) +struct Bits +{ + ulong b[BITS]; +}; + +struct Node +{ + Node* left; + Node* right; + void* label; + long pc; + int reg; + long xoffset; + double fconst; /* fp constant */ + vlong vconst; /* non fp const */ + char* cstring; /* character string */ + ushort* rstring; /* rune string */ + + Sym* sym; + Type* type; + long lineno; + uchar op; + uchar oldop; + uchar xcast; + uchar class; + uchar etype; + uchar complex; + uchar addable; + uchar scale; + uchar garb; +}; +#define Z ((Node*)0) + +struct Sym +{ + Sym* link; + Type* type; + Type* suetag; + Type* tenum; + char* macro; + long varlineno; + long offset; + vlong vconst; + double fconst; + Node* label; + ushort lexical; + char *name; + ushort block; + ushort sueblock; + uchar class; + uchar sym; + uchar aused; + uchar sig; +}; +#define S ((Sym*)0) + +enum{ + SIGNONE = 0, + SIGDONE = 1, + SIGINTERN = 2, + + SIGNINTERN = 1729*325*1729, +}; + +struct Decl +{ + Decl* link; + Sym* sym; + Type* type; + long varlineno; + long offset; + short val; + ushort block; + uchar class; + uchar aused; +}; +#define D ((Decl*)0) + +struct Type +{ + Sym* sym; + Sym* tag; + Funct* funct; + Type* link; + Type* down; + long width; + long offset; + long lineno; + uchar shift; + uchar nbits; + uchar etype; + uchar garb; +}; + +#define T ((Type*)0) +#define NODECL ((void(*)(int, Type*, Sym*))0) + +struct Init /* general purpose initialization */ +{ + int code; + ulong value; + char* s; +}; + +EXTERN struct +{ + char* p; + int c; +} fi; + +struct Io +{ + Io* link; + char* p; + char b[BUFSIZ]; + short c; + short f; +}; +#define I ((Io*)0) + +struct Hist +{ + Hist* link; + char* name; + long line; + long offset; +}; +#define H ((Hist*)0) +EXTERN Hist* hist; + +struct Term +{ + vlong mult; + Node *node; +}; + +enum +{ + Axxx, + Ael1, + Ael2, + Asu2, + Aarg0, + Aarg1, + Aarg2, + Aaut3, + NALIGN, +}; + +enum +{ + DMARK, + DAUTO, + DSUE, + DLABEL, +}; +enum +{ + OXXX, + OADD, + OADDR, + OAND, + OANDAND, + OARRAY, + OAS, + OASI, + OASADD, + OASAND, + OASASHL, + OASASHR, + OASDIV, + OASHL, + OASHR, + OASLDIV, + OASLMOD, + OASLMUL, + OASLSHR, + OASMOD, + OASMUL, + OASOR, + OASSUB, + OASXOR, + OBIT, + OBREAK, + OCASE, + OCAST, + OCOMMA, + OCOND, + OCONST, + OCONTINUE, + ODIV, + ODOT, + ODOTDOT, + ODWHILE, + OENUM, + OEQ, + OFOR, + OFUNC, + OGE, + OGOTO, + OGT, + OHI, + OHS, + OIF, + OIND, + OINDREG, + OINIT, + OLABEL, + OLDIV, + OLE, + OLIST, + OLMOD, + OLMUL, + OLO, + OLS, + OLSHR, + OLT, + OMOD, + OMUL, + ONAME, + ONE, + ONOT, + OOR, + OOROR, + OPOSTDEC, + OPOSTINC, + OPREDEC, + OPREINC, + OPROTO, + OREGISTER, + ORETURN, + OSET, + OSIGN, + OSIZE, + OSTRING, + OLSTRING, + OSTRUCT, + OSUB, + OSWITCH, + OUNION, + OUSED, + OWHILE, + OXOR, + ONEG, + OCOM, + OPOS, + OELEM, + + OTST, /* used in some compilers */ + OINDEX, + OFAS, + OREGPAIR, + + OEND +}; +enum +{ + TXXX, + TCHAR, + TUCHAR, + TSHORT, + TUSHORT, + TINT, + TUINT, + TLONG, + TULONG, + TVLONG, + TUVLONG, + TFLOAT, + TDOUBLE, + TIND, + TFUNC, + TARRAY, + TVOID, + TSTRUCT, + TUNION, + TENUM, + NTYPE, + + TAUTO = NTYPE, + TEXTERN, + TSTATIC, + TTYPEDEF, + TTYPESTR, + TREGISTER, + TCONSTNT, + TVOLATILE, + TUNSIGNED, + TSIGNED, + TDOT, + TFILE, + TOLD, + NALLTYPES, +}; +enum +{ + CXXX, + CAUTO, + CEXTERN, + CGLOBL, + CSTATIC, + CLOCAL, + CTYPEDEF, + CTYPESTR, + CPARAM, + CSELEM, + CLABEL, + CEXREG, + NCTYPES, +}; +enum +{ + GXXX = 0, + GCONSTNT = 1<<0, + GVOLATILE = 1<<1, + NGTYPES = 1<<2, + + GINCOMPLETE = 1<<2, +}; +enum +{ + BCHAR = 1L< ltag +%type gctname gcname cname gname tname +%type gctnlist gcnlist zgnlist +%type tlist sbody complex +%type types +%type zarglist arglist zcexpr +%type name block stmnt cexpr expr xuexpr pexpr +%type zelist elist adecl slist uexpr string lstring +%type xdecor xdecor2 labels label ulstmnt +%type adlist edecor tag qual qlist +%type abdecor abdecor1 abdecor2 abdecor3 +%type zexpr lexpr init ilist forexpr + +%left ';' +%left ',' +%right '=' LPE LME LMLE LDVE LMDE LRSHE LLSHE LANDE LXORE LORE +%right '?' ':' +%left LOROR +%left LANDAND +%left '|' +%left '^' +%left '&' +%left LEQ LNE +%left '<' '>' LLE LGE +%left LLSH LRSH +%left '+' '-' +%left '*' '/' '%' +%right LMM LPP LMG '.' '[' '(' + +%token LNAME LTYPE +%token LFCONST LDCONST +%token LCONST LLCONST LUCONST LULCONST LVLCONST LUVLCONST +%token LSTRING LLSTRING +%token LAUTO LBREAK LCASE LCHAR LCONTINUE LDEFAULT LDO +%token LDOUBLE LELSE LEXTERN LFLOAT LFOR LGOTO +%token LIF LINT LLONG LREGISTER LRETURN LSHORT LSIZEOF LUSED +%token LSTATIC LSTRUCT LSWITCH LTYPEDEF LTYPESTR LUNION LUNSIGNED +%token LWHILE LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF +%token LRESTRICT LINLINE +%% +prog: +| prog xdecl + +/* + * external declarator + */ +xdecl: + zctlist ';' + { + dodecl(xdecl, lastclass, lasttype, Z); + } +| zctlist xdlist ';' +| zctlist xdecor + { + lastdcl = T; + firstarg = S; + dodecl(xdecl, lastclass, lasttype, $2); + if(lastdcl == T || lastdcl->etype != TFUNC) { + diag($2, "not a function"); + lastdcl = types[TFUNC]; + } + thisfn = lastdcl; + markdcl(); + firstdcl = dclstack; + argmark($2, 0); + } + pdecl + { + argmark($2, 1); + } + block + { + Node *n; + + n = revertdcl(); + if(n) + $6 = new(OLIST, n, $6); + if(!debug['a'] && !debug['Z']) + codgen($6, $2); + } + +xdlist: + xdecor + { + dodecl(xdecl, lastclass, lasttype, $1); + } +| xdecor + { + $1 = dodecl(xdecl, lastclass, lasttype, $1); + } + '=' init + { + doinit($1->sym, $1->type, 0L, $4); + } +| xdlist ',' xdlist + +xdecor: + xdecor2 +| '*' zgnlist xdecor + { + $$ = new(OIND, $3, Z); + $$->garb = simpleg($2); + } + +xdecor2: + tag +| '(' xdecor ')' + { + $$ = $2; + } +| xdecor2 '(' zarglist ')' + { + $$ = new(OFUNC, $1, $3); + } +| xdecor2 '[' zexpr ']' + { + $$ = new(OARRAY, $1, $3); + } + +/* + * automatic declarator + */ +adecl: + ctlist ';' + { + $$ = dodecl(adecl, lastclass, lasttype, Z); + } +| ctlist adlist ';' + { + $$ = $2; + } + +adlist: + xdecor + { + dodecl(adecl, lastclass, lasttype, $1); + $$ = Z; + } +| xdecor + { + $1 = dodecl(adecl, lastclass, lasttype, $1); + } + '=' init + { + long w; + + w = $1->sym->type->width; + $$ = doinit($1->sym, $1->type, 0L, $4); + $$ = contig($1->sym, $$, w); + } +| adlist ',' adlist + { + $$ = $1; + if($3 != Z) { + $$ = $3; + if($1 != Z) + $$ = new(OLIST, $1, $3); + } + } + +/* + * parameter declarator + */ +pdecl: +| pdecl ctlist pdlist ';' + +pdlist: + xdecor + { + dodecl(pdecl, lastclass, lasttype, $1); + } +| pdlist ',' pdlist + +/* + * structure element declarator + */ +edecl: + tlist + { + lasttype = $1; + } + zedlist ';' +| edecl tlist + { + lasttype = $2; + } + zedlist ';' + +zedlist: /* extension */ + { + lastfield = 0; + edecl(CXXX, lasttype, S); + } +| edlist + +edlist: + edecor + { + dodecl(edecl, CXXX, lasttype, $1); + } +| edlist ',' edlist + +edecor: + xdecor + { + lastbit = 0; + firstbit = 1; + } +| tag ':' lexpr + { + $$ = new(OBIT, $1, $3); + } +| ':' lexpr + { + $$ = new(OBIT, Z, $2); + } + +/* + * abstract declarator + */ +abdecor: + { + $$ = (Z); + } +| abdecor1 + +abdecor1: + '*' zgnlist + { + $$ = new(OIND, (Z), Z); + $$->garb = simpleg($2); + } +| '*' zgnlist abdecor1 + { + $$ = new(OIND, $3, Z); + $$->garb = simpleg($2); + } +| abdecor2 + +abdecor2: + abdecor3 +| abdecor2 '(' zarglist ')' + { + $$ = new(OFUNC, $1, $3); + } +| abdecor2 '[' zexpr ']' + { + $$ = new(OARRAY, $1, $3); + } + +abdecor3: + '(' ')' + { + $$ = new(OFUNC, (Z), Z); + } +| '[' zexpr ']' + { + $$ = new(OARRAY, (Z), $2); + } +| '(' abdecor1 ')' + { + $$ = $2; + } + +init: + expr +| '{' ilist '}' + { + $$ = new(OINIT, invert($2), Z); + } + +qual: + '[' lexpr ']' + { + $$ = new(OARRAY, $2, Z); + } +| '.' ltag + { + $$ = new(OELEM, Z, Z); + $$->sym = $2; + } +| qual '=' + +qlist: + init ',' +| qlist init ',' + { + $$ = new(OLIST, $1, $2); + } +| qual +| qlist qual + { + $$ = new(OLIST, $1, $2); + } + +ilist: + qlist +| init +| qlist init + { + $$ = new(OLIST, $1, $2); + } + +zarglist: + { + $$ = Z; + } +| arglist + { + $$ = invert($1); + } + + +arglist: + name +| tlist abdecor + { + $$ = new(OPROTO, $2, Z); + $$->type = $1; + } +| tlist xdecor + { + $$ = new(OPROTO, $2, Z); + $$->type = $1; + } +| '.' '.' '.' + { + $$ = new(ODOTDOT, Z, Z); + } +| arglist ',' arglist + { + $$ = new(OLIST, $1, $3); + } + +block: + '{' slist '}' + { + $$ = invert($2); + // if($2 != Z) + // $$ = new(OLIST, $2, $$); + if($$ == Z) + $$ = new(OLIST, Z, Z); + } + +slist: + { + $$ = Z; + } +| slist adecl + { + $$ = new(OLIST, $1, $2); + } +| slist stmnt + { + $$ = new(OLIST, $1, $2); + } + +labels: + label +| labels label + { + $$ = new(OLIST, $1, $2); + } + +label: + LCASE expr ':' + { + $$ = new(OCASE, $2, Z); + } +| LDEFAULT ':' + { + $$ = new(OCASE, Z, Z); + } +| LNAME ':' + { + $$ = new(OLABEL, dcllabel($1, 1), Z); + } + +stmnt: + error ';' + { + $$ = Z; + } +| ulstmnt +| labels ulstmnt + { + $$ = new(OLIST, $1, $2); + } + +forexpr: + zcexpr +| ctlist adlist + { + $$ = $2; + } + +ulstmnt: + zcexpr ';' +| { + markdcl(); + } + block + { + $$ = revertdcl(); + if($$) + $$ = new(OLIST, $$, $2); + else + $$ = $2; + } +| LIF '(' cexpr ')' stmnt + { + $$ = new(OIF, $3, new(OLIST, $5, Z)); + if($5 == Z) + warn($3, "empty if body"); + } +| LIF '(' cexpr ')' stmnt LELSE stmnt + { + $$ = new(OIF, $3, new(OLIST, $5, $7)); + if($5 == Z) + warn($3, "empty if body"); + if($7 == Z) + warn($3, "empty else body"); + } +| { markdcl(); } LFOR '(' forexpr ';' zcexpr ';' zcexpr ')' stmnt + { + $$ = revertdcl(); + if($$){ + if($4) + $4 = new(OLIST, $$, $4); + else + $4 = $$; + } + $$ = new(OFOR, new(OLIST, $6, new(OLIST, $4, $8)), $10); + } +| LWHILE '(' cexpr ')' stmnt + { + $$ = new(OWHILE, $3, $5); + } +| LDO stmnt LWHILE '(' cexpr ')' ';' + { + $$ = new(ODWHILE, $5, $2); + } +| LRETURN zcexpr ';' + { + $$ = new(ORETURN, $2, Z); + $$->type = thisfn->link; + } +| LSWITCH '(' cexpr ')' stmnt + { + $$ = new(OCONST, Z, Z); + $$->vconst = 0; + $$->type = types[TINT]; + $3 = new(OSUB, $$, $3); + + $$ = new(OCONST, Z, Z); + $$->vconst = 0; + $$->type = types[TINT]; + $3 = new(OSUB, $$, $3); + + $$ = new(OSWITCH, $3, $5); + } +| LBREAK ';' + { + $$ = new(OBREAK, Z, Z); + } +| LCONTINUE ';' + { + $$ = new(OCONTINUE, Z, Z); + } +| LGOTO ltag ';' + { + $$ = new(OGOTO, dcllabel($2, 0), Z); + } +| LUSED '(' zelist ')' ';' + { + $$ = new(OUSED, $3, Z); + } +| LSET '(' zelist ')' ';' + { + $$ = new(OSET, $3, Z); + } + +zcexpr: + { + $$ = Z; + } +| cexpr + +zexpr: + { + $$ = Z; + } +| lexpr + +lexpr: + expr + { + $$ = new(OCAST, $1, Z); + $$->type = types[TLONG]; + } + +cexpr: + expr +| cexpr ',' cexpr + { + $$ = new(OCOMMA, $1, $3); + } + +expr: + xuexpr +| expr '*' expr + { + $$ = new(OMUL, $1, $3); + } +| expr '/' expr + { + $$ = new(ODIV, $1, $3); + } +| expr '%' expr + { + $$ = new(OMOD, $1, $3); + } +| expr '+' expr + { + $$ = new(OADD, $1, $3); + } +| expr '-' expr + { + $$ = new(OSUB, $1, $3); + } +| expr LRSH expr + { + $$ = new(OASHR, $1, $3); + } +| expr LLSH expr + { + $$ = new(OASHL, $1, $3); + } +| expr '<' expr + { + $$ = new(OLT, $1, $3); + } +| expr '>' expr + { + $$ = new(OGT, $1, $3); + } +| expr LLE expr + { + $$ = new(OLE, $1, $3); + } +| expr LGE expr + { + $$ = new(OGE, $1, $3); + } +| expr LEQ expr + { + $$ = new(OEQ, $1, $3); + } +| expr LNE expr + { + $$ = new(ONE, $1, $3); + } +| expr '&' expr + { + $$ = new(OAND, $1, $3); + } +| expr '^' expr + { + $$ = new(OXOR, $1, $3); + } +| expr '|' expr + { + $$ = new(OOR, $1, $3); + } +| expr LANDAND expr + { + $$ = new(OANDAND, $1, $3); + } +| expr LOROR expr + { + $$ = new(OOROR, $1, $3); + } +| expr '?' cexpr ':' expr + { + $$ = new(OCOND, $1, new(OLIST, $3, $5)); + } +| expr '=' expr + { + $$ = new(OAS, $1, $3); + } +| expr LPE expr + { + $$ = new(OASADD, $1, $3); + } +| expr LME expr + { + $$ = new(OASSUB, $1, $3); + } +| expr LMLE expr + { + $$ = new(OASMUL, $1, $3); + } +| expr LDVE expr + { + $$ = new(OASDIV, $1, $3); + } +| expr LMDE expr + { + $$ = new(OASMOD, $1, $3); + } +| expr LLSHE expr + { + $$ = new(OASASHL, $1, $3); + } +| expr LRSHE expr + { + $$ = new(OASASHR, $1, $3); + } +| expr LANDE expr + { + $$ = new(OASAND, $1, $3); + } +| expr LXORE expr + { + $$ = new(OASXOR, $1, $3); + } +| expr LORE expr + { + $$ = new(OASOR, $1, $3); + } + +xuexpr: + uexpr +| '(' tlist abdecor ')' xuexpr + { + $$ = new(OCAST, $5, Z); + dodecl(NODECL, CXXX, $2, $3); + $$->type = lastdcl; + $$->xcast = 1; + } +| '(' tlist abdecor ')' '{' ilist '}' /* extension */ + { + $$ = new(OSTRUCT, $6, Z); + dodecl(NODECL, CXXX, $2, $3); + $$->type = lastdcl; + } + +uexpr: + pexpr +| '*' xuexpr + { + $$ = new(OIND, $2, Z); + } +| '&' xuexpr + { + $$ = new(OADDR, $2, Z); + } +| '+' xuexpr + { + $$ = new(OPOS, $2, Z); + } +| '-' xuexpr + { + $$ = new(ONEG, $2, Z); + } +| '!' xuexpr + { + $$ = new(ONOT, $2, Z); + } +| '~' xuexpr + { + $$ = new(OCOM, $2, Z); + } +| LPP xuexpr + { + $$ = new(OPREINC, $2, Z); + } +| LMM xuexpr + { + $$ = new(OPREDEC, $2, Z); + } +| LSIZEOF uexpr + { + $$ = new(OSIZE, $2, Z); + } +| LSIGNOF uexpr + { + $$ = new(OSIGN, $2, Z); + } + +pexpr: + '(' cexpr ')' + { + $$ = $2; + } +| LSIZEOF '(' tlist abdecor ')' + { + $$ = new(OSIZE, Z, Z); + dodecl(NODECL, CXXX, $3, $4); + $$->type = lastdcl; + } +| LSIGNOF '(' tlist abdecor ')' + { + $$ = new(OSIGN, Z, Z); + dodecl(NODECL, CXXX, $3, $4); + $$->type = lastdcl; + } +| pexpr '(' zelist ')' + { + $$ = new(OFUNC, $1, Z); + if($1->op == ONAME) + if($1->type == T) + dodecl(xdecl, CXXX, types[TINT], $$); + $$->right = invert($3); + } +| pexpr '[' cexpr ']' + { + $$ = new(OIND, new(OADD, $1, $3), Z); + } +| pexpr LMG ltag + { + $$ = new(ODOT, new(OIND, $1, Z), Z); + $$->sym = $3; + } +| pexpr '.' ltag + { + $$ = new(ODOT, $1, Z); + $$->sym = $3; + } +| pexpr LPP + { + $$ = new(OPOSTINC, $1, Z); + } +| pexpr LMM + { + $$ = new(OPOSTDEC, $1, Z); + } +| name +| LCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TINT]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LLCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TLONG]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LUCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TUINT]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LULCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TULONG]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LDCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TDOUBLE]; + $$->fconst = $1; + $$->cstring = strdup(symb); + } +| LFCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TFLOAT]; + $$->fconst = $1; + $$->cstring = strdup(symb); + } +| LVLCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TVLONG]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LUVLCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TUVLONG]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| string +| lstring + +string: + LSTRING + { + $$ = new(OSTRING, Z, Z); + $$->type = typ(TARRAY, types[TCHAR]); + $$->type->width = $1.l + 1; + $$->cstring = $1.s; + $$->sym = symstring; + $$->etype = TARRAY; + $$->class = CSTATIC; + } +| string LSTRING + { + char *s; + int n; + + n = $1->type->width - 1; + s = alloc(n+$2.l+MAXALIGN); + + memcpy(s, $1->cstring, n); + memcpy(s+n, $2.s, $2.l); + s[n+$2.l] = 0; + + $$ = $1; + $$->type->width += $2.l; + $$->cstring = s; + } + +lstring: + LLSTRING + { + $$ = new(OLSTRING, Z, Z); + $$->type = typ(TARRAY, types[TUSHORT]); + $$->type->width = $1.l + sizeof(ushort); + $$->rstring = (ushort*)$1.s; + $$->sym = symstring; + $$->etype = TARRAY; + $$->class = CSTATIC; + } +| lstring LLSTRING + { + char *s; + int n; + + n = $1->type->width - sizeof(ushort); + s = alloc(n+$2.l+MAXALIGN); + + memcpy(s, $1->rstring, n); + memcpy(s+n, $2.s, $2.l); + *(ushort*)(s+n+$2.l) = 0; + + $$ = $1; + $$->type->width += $2.l; + $$->rstring = (ushort*)s; + } + +zelist: + { + $$ = Z; + } +| elist + +elist: + expr +| elist ',' elist + { + $$ = new(OLIST, $1, $3); + } + +sbody: + '{' + { + $$.t1 = strf; + $$.t2 = strl; + strf = T; + strl = T; + lastbit = 0; + firstbit = 1; + } + edecl '}' + { + $$ = strf; + strf = $2.t1; + strl = $2.t2; + } + +zctlist: + { + lastclass = CXXX; + lasttype = types[TINT]; + } +| ctlist + +types: + complex + { + $$.t = $1; + $$.c = CXXX; + } +| tname + { + $$.t = simplet($1); + $$.c = CXXX; + } +| gcnlist + { + $$.t = simplet($1); + $$.c = simplec($1); + $$.t = garbt($$.t, $1); + } +| complex gctnlist + { + $$.t = $1; + $$.c = simplec($2); + $$.t = garbt($$.t, $2); + if($2 & ~BCLASS & ~BGARB) + diag(Z, "duplicate types given: %T and %Q", $1, $2); + } +| tname gctnlist + { + $$.t = simplet(typebitor($1, $2)); + $$.c = simplec($2); + $$.t = garbt($$.t, $2); + } +| gcnlist complex zgnlist + { + $$.t = $2; + $$.c = simplec($1); + $$.t = garbt($$.t, $1|$3); + } +| gcnlist tname + { + $$.t = simplet($2); + $$.c = simplec($1); + $$.t = garbt($$.t, $1); + } +| gcnlist tname gctnlist + { + $$.t = simplet(typebitor($2, $3)); + $$.c = simplec($1|$3); + $$.t = garbt($$.t, $1|$3); + } + +tlist: + types + { + $$ = $1.t; + if($1.c != CXXX) + diag(Z, "illegal combination of class 4: %s", cnames[$1.c]); + } + +ctlist: + types + { + lasttype = $1.t; + lastclass = $1.c; + } + +complex: + LSTRUCT ltag + { + dotag($2, TSTRUCT, 0); + $$ = $2->suetag; + } +| LSTRUCT ltag + { + dotag($2, TSTRUCT, autobn); + } + sbody + { + $$ = $2->suetag; + if($$->link != T) + diag(Z, "redeclare tag: %s", $2->name); + $$->link = $4; + suallign($$); + } +| LSTRUCT sbody + { + taggen++; + sprint(symb, "_%d_", taggen); + $$ = dotag(lookup(), TSTRUCT, autobn); + $$->link = $2; + suallign($$); + } +| LUNION ltag + { + dotag($2, TUNION, 0); + $$ = $2->suetag; + } +| LUNION ltag + { + dotag($2, TUNION, autobn); + } + sbody + { + $$ = $2->suetag; + if($$->link != T) + diag(Z, "redeclare tag: %s", $2->name); + $$->link = $4; + suallign($$); + } +| LUNION sbody + { + taggen++; + sprint(symb, "_%d_", taggen); + $$ = dotag(lookup(), TUNION, autobn); + $$->link = $2; + suallign($$); + } +| LENUM ltag + { + dotag($2, TENUM, 0); + $$ = $2->suetag; + if($$->link == T) + $$->link = types[TINT]; + $$ = $$->link; + } +| LENUM ltag + { + dotag($2, TENUM, autobn); + } + '{' + { + en.tenum = T; + en.cenum = T; + } + enum '}' + { + $$ = $2->suetag; + if($$->link != T) + diag(Z, "redeclare tag: %s", $2->name); + if(en.tenum == T) { + diag(Z, "enum type ambiguous: %s", $2->name); + en.tenum = types[TINT]; + } + $$->link = en.tenum; + $$ = en.tenum; + } +| LENUM '{' + { + en.tenum = T; + en.cenum = T; + } + enum '}' + { + $$ = en.tenum; + } +| LTYPE + { + $$ = tcopy($1->type); + } + +gctnlist: + gctname +| gctnlist gctname + { + $$ = typebitor($1, $2); + } + +zgnlist: + { + $$ = 0; + } +| zgnlist gname + { + $$ = typebitor($1, $2); + } + +gctname: + tname +| gname +| cname + +gcnlist: + gcname +| gcnlist gcname + { + $$ = typebitor($1, $2); + } + +gcname: + gname +| cname + +enum: + LNAME + { + doenum($1, Z); + } +| LNAME '=' expr + { + doenum($1, $3); + } +| enum ',' +| enum ',' enum + +tname: /* type words */ + LCHAR { $$ = BCHAR; } +| LSHORT { $$ = BSHORT; } +| LINT { $$ = BINT; } +| LLONG { $$ = BLONG; } +| LSIGNED { $$ = BSIGNED; } +| LUNSIGNED { $$ = BUNSIGNED; } +| LFLOAT { $$ = BFLOAT; } +| LDOUBLE { $$ = BDOUBLE; } +| LVOID { $$ = BVOID; } + +cname: /* class words */ + LAUTO { $$ = BAUTO; } +| LSTATIC { $$ = BSTATIC; } +| LEXTERN { $$ = BEXTERN; } +| LTYPEDEF { $$ = BTYPEDEF; } +| LTYPESTR { $$ = BTYPESTR; } +| LREGISTER { $$ = BREGISTER; } +| LINLINE { $$ = 0; } + +gname: /* garbage words */ + LCONSTNT { $$ = BCONSTNT; } +| LVOLATILE { $$ = BVOLATILE; } +| LRESTRICT { $$ = 0; } + +name: + LNAME + { + $$ = new(ONAME, Z, Z); + if($1->class == CLOCAL) + $1 = mkstatic($1); + $$->sym = $1; + $$->type = $1->type; + $$->etype = TVOID; + if($$->type != T) + $$->etype = $$->type->etype; + $$->xoffset = $1->offset; + $$->class = $1->class; + $1->aused = 1; + } +tag: + ltag + { + $$ = new(ONAME, Z, Z); + $$->sym = $1; + $$->type = $1->type; + $$->etype = TVOID; + if($$->type != T) + $$->etype = $$->type->etype; + $$->xoffset = $1->offset; + $$->class = $1->class; + } +ltag: + LNAME +| LTYPE +%% diff --git a/src/cmd/cc/com.c b/src/cmd/cc/com.c new file mode 100644 index 0000000000..b0b1620ce1 --- /dev/null +++ b/src/cmd/cc/com.c @@ -0,0 +1,1378 @@ +// Inferno utils/cc/com.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/com.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +int compar(Node*, int); + +void +complex(Node *n) +{ + + if(n == Z) + return; + + nearln = n->lineno; + if(debug['t']) + if(n->op != OCONST) + prtree(n, "pre complex"); + if(tcom(n)) + return; + if(debug['t']) + if(n->op != OCONST) + prtree(n, "t complex"); + ccom(n); + if(debug['t']) + if(n->op != OCONST) + prtree(n, "c complex"); + acom(n); + if(debug['t']) + if(n->op != OCONST) + prtree(n, "a complex"); + xcom(n); + if(debug['t']) + if(n->op != OCONST) + prtree(n, "x complex"); +} + +/* + * evaluate types + * evaluate lvalues (addable == 1) + */ +enum +{ + ADDROF = 1<<0, + CASTOF = 1<<1, + ADDROP = 1<<2, +}; + +int +tcom(Node *n) +{ + + return tcomo(n, ADDROF); +} + +int +tcomo(Node *n, int f) +{ + Node *l, *r; + Type *t; + int o; + + if(n == Z) { + diag(Z, "Z in tcom"); + errorexit(); + } + n->addable = 0; + l = n->left; + r = n->right; + + switch(n->op) { + default: + diag(n, "unknown op in type complex: %O", n->op); + goto bad; + + case ODOTDOT: + /* + * tcom has already been called on this subtree + */ + *n = *n->left; + if(n->type == T) + goto bad; + break; + + case OCAST: + if(n->type == T) + break; + if(n->type->width == types[TLONG]->width) { + if(tcomo(l, ADDROF|CASTOF)) + goto bad; + } else + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, n->type, tcast)) + goto bad; + break; + + case ORETURN: + if(l == Z) { + if(n->type->etype != TVOID) + warn(n, "null return of a typed function"); + break; + } + if(tcom(l)) + goto bad; + typeext(n->type, l); + if(tcompat(n, n->type, l->type, tasign)) + break; + constas(n, n->type, l->type); + if(!sametype(n->type, l->type)) { + l = new1(OCAST, l, Z); + l->type = n->type; + n->left = l; + } + break; + + case OASI: /* same as as, but no test for const */ + n->op = OAS; + o = tcom(l); + if(o | tcom(r)) + goto bad; + + typeext(l->type, r); + if(tlvalue(l) || tcompat(n, l->type, r->type, tasign)) + goto bad; + if(!sametype(l->type, r->type)) { + r = new1(OCAST, r, Z); + r->type = l->type; + n->right = r; + } + n->type = l->type; + break; + + case OAS: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + typeext(l->type, r); + if(tcompat(n, l->type, r->type, tasign)) + goto bad; + constas(n, l->type, r->type); + if(!sametype(l->type, r->type)) { + r = new1(OCAST, r, Z); + r->type = l->type; + n->right = r; + } + n->type = l->type; + break; + + case OASADD: + case OASSUB: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + typeext1(l->type, r); + if(tcompat(n, l->type, r->type, tasadd)) + goto bad; + constas(n, l->type, r->type); + t = l->type; + arith(n, 0); + while(n->left->op == OCAST) + n->left = n->left->left; + if(!sametype(t, n->type) && !mixedasop(t, n->type)) { + r = new1(OCAST, n->right, Z); + r->type = t; + n->right = r; + n->type = t; + } + break; + + case OASMUL: + case OASLMUL: + case OASDIV: + case OASLDIV: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + typeext1(l->type, r); + if(tcompat(n, l->type, r->type, tmul)) + goto bad; + constas(n, l->type, r->type); + t = l->type; + arith(n, 0); + while(n->left->op == OCAST) + n->left = n->left->left; + if(!sametype(t, n->type) && !mixedasop(t, n->type)) { + r = new1(OCAST, n->right, Z); + r->type = t; + n->right = r; + n->type = t; + } + if(typeu[n->type->etype]) { + if(n->op == OASDIV) + n->op = OASLDIV; + if(n->op == OASMUL) + n->op = OASLMUL; + } + break; + + case OASLSHR: + case OASASHR: + case OASASHL: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + n->type = l->type; + if(typeu[n->type->etype]) { + if(n->op == OASASHR) + n->op = OASLSHR; + } + break; + + case OASMOD: + case OASLMOD: + case OASOR: + case OASAND: + case OASXOR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + t = l->type; + arith(n, 0); + while(n->left->op == OCAST) + n->left = n->left->left; + if(!sametype(t, n->type) && !mixedasop(t, n->type)) { + r = new1(OCAST, n->right, Z); + r->type = t; + n->right = r; + n->type = t; + } + if(typeu[n->type->etype]) { + if(n->op == OASMOD) + n->op = OASLMOD; + } + break; + + case OPREINC: + case OPREDEC: + case OPOSTINC: + case OPOSTDEC: + if(tcom(l)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, types[TINT], tadd)) + goto bad; + n->type = l->type; + if(n->type->etype == TIND) + if(n->type->link->width < 1) + diag(n, "inc/dec of a void pointer"); + break; + + case OEQ: + case ONE: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + typeext(l->type, r); + typeext(r->type, l); + if(tcompat(n, l->type, r->type, trel)) + goto bad; + arith(n, 0); + n->type = types[TINT]; + break; + + case OLT: + case OGE: + case OGT: + case OLE: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + typeext1(l->type, r); + typeext1(r->type, l); + if(tcompat(n, l->type, r->type, trel)) + goto bad; + arith(n, 0); + if(typeu[n->type->etype]) + n->op = logrel[relindex(n->op)]; + n->type = types[TINT]; + break; + + case OCOND: + o = tcom(l); + o |= tcom(r->left); + if(o | tcom(r->right)) + goto bad; + if(r->right->type->etype == TIND && vconst(r->left) == 0) { + r->left->type = r->right->type; + r->left->vconst = 0; + } + if(r->left->type->etype == TIND && vconst(r->right) == 0) { + r->right->type = r->left->type; + r->right->vconst = 0; + } + if(sametype(r->right->type, r->left->type)) { + r->type = r->right->type; + n->type = r->type; + break; + } + if(tcompat(r, r->left->type, r->right->type, trel)) + goto bad; + arith(r, 0); + n->type = r->type; + break; + + case OADD: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tadd)) + goto bad; + arith(n, 1); + break; + + case OSUB: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tsub)) + goto bad; + arith(n, 1); + break; + + case OMUL: + case OLMUL: + case ODIV: + case OLDIV: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tmul)) + goto bad; + arith(n, 1); + if(typeu[n->type->etype]) { + if(n->op == ODIV) + n->op = OLDIV; + if(n->op == OMUL) + n->op = OLMUL; + } + break; + + case OLSHR: + case OASHL: + case OASHR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + n->right = Z; + arith(n, 1); + n->right = new1(OCAST, r, Z); + n->right->type = types[TINT]; + if(typeu[n->type->etype]) + if(n->op == OASHR) + n->op = OLSHR; + break; + + case OAND: + case OOR: + case OXOR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + arith(n, 1); + break; + + case OMOD: + case OLMOD: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + arith(n, 1); + if(typeu[n->type->etype]) + n->op = OLMOD; + break; + + case OPOS: + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + + r = l; + l = new(OCONST, Z, Z); + l->vconst = 0; + l->type = types[TINT]; + n->op = OADD; + n->right = r; + n->left = l; + + if(tcom(l)) + goto bad; + if(tcompat(n, l->type, r->type, tsub)) + goto bad; + arith(n, 1); + break; + + case ONEG: + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + + if(!machcap(n)) { + r = l; + l = new(OCONST, Z, Z); + l->vconst = 0; + l->type = types[TINT]; + n->op = OSUB; + n->right = r; + n->left = l; + + if(tcom(l)) + goto bad; + if(tcompat(n, l->type, r->type, tsub)) + goto bad; + } + arith(n, 1); + break; + + case OCOM: + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + + if(!machcap(n)) { + r = l; + l = new(OCONST, Z, Z); + l->vconst = -1; + l->type = types[TINT]; + n->op = OXOR; + n->right = r; + n->left = l; + + if(tcom(l)) + goto bad; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + } + arith(n, 1); + break; + + case ONOT: + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, T, l->type, tnot)) + goto bad; + n->type = types[TINT]; + break; + + case OANDAND: + case OOROR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tcompat(n, T, l->type, tnot) | + tcompat(n, T, r->type, tnot)) + goto bad; + n->type = types[TINT]; + break; + + case OCOMMA: + o = tcom(l); + if(o | tcom(r)) + goto bad; + n->type = r->type; + break; + + + case OSIGN: /* extension signof(type) returns a hash */ + if(l != Z) { + if(l->op != OSTRING && l->op != OLSTRING) + if(tcomo(l, 0)) + goto bad; + if(l->op == OBIT) { + diag(n, "signof bitfield"); + goto bad; + } + n->type = l->type; + } + if(n->type == T) + goto bad; + if(n->type->width < 0) { + diag(n, "signof undefined type"); + goto bad; + } + n->op = OCONST; + n->left = Z; + n->right = Z; + n->vconst = convvtox(signature(n->type), TULONG); + n->type = types[TULONG]; + break; + + case OSIZE: + if(l != Z) { + if(l->op != OSTRING && l->op != OLSTRING) + if(tcomo(l, 0)) + goto bad; + if(l->op == OBIT) { + diag(n, "sizeof bitfield"); + goto bad; + } + n->type = l->type; + } + if(n->type == T) + goto bad; + if(n->type->width <= 0) { + diag(n, "sizeof undefined type"); + goto bad; + } + if(n->type->etype == TFUNC) { + diag(n, "sizeof function"); + goto bad; + } + n->op = OCONST; + n->left = Z; + n->right = Z; + n->vconst = convvtox(n->type->width, TINT); + n->type = types[TINT]; + break; + + case OFUNC: + o = tcomo(l, 0); + if(o) + goto bad; + if(l->type->etype == TIND && l->type->link->etype == TFUNC) { + l = new1(OIND, l, Z); + l->type = l->left->type->link; + n->left = l; + } + if(tcompat(n, T, l->type, tfunct)) + goto bad; + if(o | tcoma(l, r, l->type->down, 1)) + goto bad; + n->type = l->type->link; + if(!debug['B']) + if(l->type->down == T || l->type->down->etype == TOLD) { + nerrors--; + diag(n, "function args not checked: %F", l); + } + dpcheck(n); + break; + + case ONAME: + if(n->type == T) { + diag(n, "name not declared: %F", n); + goto bad; + } + if(n->type->etype == TENUM) { + n->op = OCONST; + n->type = n->sym->tenum; + if(!typefd[n->type->etype]) + n->vconst = n->sym->vconst; + else + n->fconst = n->sym->fconst; + break; + } + n->addable = 1; + if(n->class == CEXREG) { + n->op = OREGISTER; + n->reg = n->sym->offset; + n->xoffset = 0; + break; + } + break; + + case OLSTRING: + if(n->type->link != types[TUSHORT]) { + o = outstring(0, 0); + while(o & 3) { + ushort a[1]; + a[0] = 0; + outlstring(a, sizeof(ushort)); + o = outlstring(0, 0); + } + } + n->op = ONAME; + n->xoffset = outlstring(n->rstring, n->type->width); + n->addable = 1; + break; + + case OSTRING: + if(n->type->link != types[TCHAR]) { + o = outstring(0, 0); + while(o & 3) { + outstring("", 1); + o = outstring(0, 0); + } + } + n->op = ONAME; + n->xoffset = outstring(n->cstring, n->type->width); + n->addable = 1; + break; + + case OCONST: + break; + + case ODOT: + if(tcom(l)) + goto bad; + if(tcompat(n, T, l->type, tdot)) + goto bad; + if(tcomd(n)) + goto bad; + break; + + case OADDR: + if(tcomo(l, ADDROP)) + goto bad; + if(tlvalue(l)) + goto bad; + if(l->type->nbits) { + diag(n, "address of a bit field"); + goto bad; + } + if(l->op == OREGISTER) { + diag(n, "address of a register"); + goto bad; + } + n->type = typ(TIND, l->type); + n->type->width = types[TIND]->width; + break; + + case OIND: + if(tcom(l)) + goto bad; + if(tcompat(n, T, l->type, tindir)) + goto bad; + n->type = l->type->link; + n->addable = 1; + break; + + case OSTRUCT: + if(tcomx(n)) + goto bad; + break; + } + t = n->type; + if(t == T) + goto bad; + if(t->width < 0) { + snap(t); + if(t->width < 0) { + if(typesu[t->etype] && t->tag) + diag(n, "structure not fully declared %s", t->tag->name); + else + diag(n, "structure not fully declared"); + goto bad; + } + } + if(typeaf[t->etype]) { + if(f & ADDROF) + goto addaddr; + if(f & ADDROP) + warn(n, "address of array/func ignored"); + } + return 0; + +addaddr: + if(tlvalue(n)) + goto bad; + l = new1(OXXX, Z, Z); + *l = *n; + n->op = OADDR; + if(l->type->etype == TARRAY) + l->type = l->type->link; + n->left = l; + n->right = Z; + n->addable = 0; + n->type = typ(TIND, l->type); + n->type->width = types[TIND]->width; + return 0; + +bad: + n->type = T; + return 1; +} + +int +tcoma(Node *l, Node *n, Type *t, int f) +{ + Node *n1; + int o; + + if(t != T) + if(t->etype == TOLD || t->etype == TDOT) /* .../old in prototype */ + t = T; + if(n == Z) { + if(t != T && !sametype(t, types[TVOID])) { + diag(n, "not enough function arguments: %F", l); + return 1; + } + return 0; + } + if(n->op == OLIST) { + o = tcoma(l, n->left, t, 0); + if(t != T) { + t = t->down; + if(t == T) + t = types[TVOID]; + } + return o | tcoma(l, n->right, t, 1); + } + if(f && t != T) + tcoma(l, Z, t->down, 0); + if(tcom(n) || tcompat(n, T, n->type, targ)) + return 1; + if(sametype(t, types[TVOID])) { + diag(n, "too many function arguments: %F", l); + return 1; + } + if(t != T) { + typeext(t, n); + if(stcompat(nodproto, t, n->type, tasign)) { + diag(l, "argument prototype mismatch \"%T\" for \"%T\": %F", + n->type, t, l); + return 1; + } + switch(t->etype) { + case TCHAR: + case TSHORT: + t = types[TINT]; + break; + + case TUCHAR: + case TUSHORT: + t = types[TUINT]; + break; + } + } else + switch(n->type->etype) + { + case TCHAR: + case TSHORT: + t = types[TINT]; + break; + + case TUCHAR: + case TUSHORT: + t = types[TUINT]; + break; + + case TFLOAT: + t = types[TDOUBLE]; + } + if(t != T && !sametype(t, n->type)) { + n1 = new1(OXXX, Z, Z); + *n1 = *n; + n->op = OCAST; + n->left = n1; + n->right = Z; + n->type = t; + n->addable = 0; + } + return 0; +} + +int +tcomd(Node *n) +{ + Type *t; + long o; + + o = 0; + t = dotsearch(n->sym, n->left->type->link, n, &o); + if(t == T) { + diag(n, "not a member of struct/union: %F", n); + return 1; + } + makedot(n, t, o); + return 0; +} + +int +tcomx(Node *n) +{ + Type *t; + Node *l, *r, **ar, **al; + int e; + + e = 0; + if(n->type->etype != TSTRUCT) { + diag(n, "constructor must be a structure"); + return 1; + } + l = invert(n->left); + n->left = l; + al = &n->left; + for(t = n->type->link; t != T; t = t->down) { + if(l == Z) { + diag(n, "constructor list too short"); + return 1; + } + if(l->op == OLIST) { + r = l->left; + ar = &l->left; + al = &l->right; + l = l->right; + } else { + r = l; + ar = al; + l = Z; + } + if(tcom(r)) + e++; + typeext(t, r); + if(tcompat(n, t, r->type, tasign)) + e++; + constas(n, t, r->type); + if(!e && !sametype(t, r->type)) { + r = new1(OCAST, r, Z); + r->type = t; + *ar = r; + } + } + if(l != Z) { + diag(n, "constructor list too long"); + return 1; + } + return e; +} + +int +tlvalue(Node *n) +{ + + if(!n->addable) { + diag(n, "not an l-value"); + return 1; + } + return 0; +} + +/* + * general rewrite + * (IND(ADDR x)) ==> x + * (ADDR(IND x)) ==> x + * remove some zero operands + * remove no op casts + * evaluate constants + */ +void +ccom(Node *n) +{ + Node *l, *r; + int t; + +loop: + if(n == Z) + return; + l = n->left; + r = n->right; + switch(n->op) { + + case OAS: + case OASXOR: + case OASAND: + case OASOR: + case OASMOD: + case OASLMOD: + case OASLSHR: + case OASASHR: + case OASASHL: + case OASDIV: + case OASLDIV: + case OASMUL: + case OASLMUL: + case OASSUB: + case OASADD: + ccom(l); + ccom(r); + if(n->op == OASLSHR || n->op == OASASHR || n->op == OASASHL) + if(r->op == OCONST) { + t = n->type->width * 8; /* bits per byte */ + if(r->vconst >= t || r->vconst < 0) + warn(n, "stupid shift: %lld", r->vconst); + } + break; + + case OCAST: + ccom(l); + if(l->op == OCONST) { + evconst(n); + if(n->op == OCONST) + break; + } + if(nocast(l->type, n->type)) { + l->type = n->type; + *n = *l; + } + break; + + case OCOND: + ccom(l); + ccom(r); + if(l->op == OCONST) + if(vconst(l) == 0) + *n = *r->right; + else + *n = *r->left; + break; + + case OREGISTER: + case OINDREG: + case OCONST: + case ONAME: + break; + + case OADDR: + ccom(l); + l->etype = TVOID; + if(l->op == OIND) { + l->left->type = n->type; + *n = *l->left; + break; + } + goto common; + + case OIND: + ccom(l); + if(l->op == OADDR) { + l->left->type = n->type; + *n = *l->left; + break; + } + goto common; + + case OEQ: + case ONE: + + case OLE: + case OGE: + case OLT: + case OGT: + + case OLS: + case OHS: + case OLO: + case OHI: + ccom(l); + ccom(r); + if(compar(n, 0) || compar(n, 1)) + break; + relcon(l, r); + relcon(r, l); + goto common; + + case OASHR: + case OASHL: + case OLSHR: + ccom(l); + if(vconst(l) == 0 && !side(r)) { + *n = *l; + break; + } + ccom(r); + if(vconst(r) == 0) { + *n = *l; + break; + } + if(r->op == OCONST) { + t = n->type->width * 8; /* bits per byte */ + if(r->vconst >= t || r->vconst <= -t) + warn(n, "stupid shift: %lld", r->vconst); + } + goto common; + + case OMUL: + case OLMUL: + ccom(l); + t = vconst(l); + if(t == 0 && !side(r)) { + *n = *l; + break; + } + if(t == 1) { + *n = *r; + goto loop; + } + ccom(r); + t = vconst(r); + if(t == 0 && !side(l)) { + *n = *r; + break; + } + if(t == 1) { + *n = *l; + break; + } + goto common; + + case ODIV: + case OLDIV: + ccom(l); + if(vconst(l) == 0 && !side(r)) { + *n = *l; + break; + } + ccom(r); + t = vconst(r); + if(t == 0) { + diag(n, "divide check"); + *n = *r; + break; + } + if(t == 1) { + *n = *l; + break; + } + goto common; + + case OSUB: + ccom(r); + if(r->op == OCONST) { + if(typefd[r->type->etype]) { + n->op = OADD; + r->fconst = -r->fconst; + goto loop; + } else { + n->op = OADD; + r->vconst = -r->vconst; + goto loop; + } + } + ccom(l); + goto common; + + case OXOR: + case OOR: + case OADD: + ccom(l); + if(vconst(l) == 0) { + *n = *r; + goto loop; + } + ccom(r); + if(vconst(r) == 0) { + *n = *l; + break; + } + goto commute; + + case OAND: + ccom(l); + ccom(r); + if(vconst(l) == 0 && !side(r)) { + *n = *l; + break; + } + if(vconst(r) == 0 && !side(l)) { + *n = *r; + break; + } + + commute: + /* look for commutative constant */ + if(r->op == OCONST) { + if(l->op == n->op) { + if(l->left->op == OCONST) { + n->right = l->right; + l->right = r; + goto loop; + } + if(l->right->op == OCONST) { + n->right = l->left; + l->left = r; + goto loop; + } + } + } + if(l->op == OCONST) { + if(r->op == n->op) { + if(r->left->op == OCONST) { + n->left = r->right; + r->right = l; + goto loop; + } + if(r->right->op == OCONST) { + n->left = r->left; + r->left = l; + goto loop; + } + } + } + goto common; + + case OANDAND: + ccom(l); + if(vconst(l) == 0) { + *n = *l; + break; + } + ccom(r); + goto common; + + case OOROR: + ccom(l); + if(l->op == OCONST && l->vconst != 0) { + *n = *l; + n->vconst = 1; + break; + } + ccom(r); + goto common; + + default: + if(l != Z) + ccom(l); + if(r != Z) + ccom(r); + common: + if(l != Z) + if(l->op != OCONST) + break; + if(r != Z) + if(r->op != OCONST) + break; + evconst(n); + } +} + +/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */ +static char *cmps[12] = +{ + "==", "!=", "<=", "<=", "<", "<", ">=", ">=", ">", ">", +}; + +/* 128-bit numbers */ +typedef struct Big Big; +struct Big +{ + vlong a; + uvlong b; +}; +static int +cmp(Big x, Big y) +{ + if(x.a != y.a){ + if(x.a < y.a) + return -1; + return 1; + } + if(x.b != y.b){ + if(x.b < y.b) + return -1; + return 1; + } + return 0; +} +static Big +add(Big x, int y) +{ + uvlong ob; + + ob = x.b; + x.b += y; + if(y > 0 && x.b < ob) + x.a++; + if(y < 0 && x.b > ob) + x.a--; + return x; +} + +Big +big(vlong a, uvlong b) +{ + Big x; + + x.a = a; + x.b = b; + return x; +} + +int +compar(Node *n, int reverse) +{ + Big lo, hi, x; + int op; + char xbuf[40], cmpbuf[50]; + Node *l, *r; + Type *lt, *rt; + + /* + * The point of this function is to diagnose comparisons + * that can never be true or that look misleading because + * of the `usual arithmetic conversions'. As an example + * of the latter, if x is a ulong, then if(x <= -1) really means + * if(x <= 0xFFFFFFFF), while if(x <= -1LL) really means + * what it says (but 8c compiles it wrong anyway). + */ + + if(reverse){ + r = n->left; + l = n->right; + op = comrel[relindex(n->op)]; + }else{ + l = n->left; + r = n->right; + op = n->op; + } + + /* + * Skip over left casts to find out the original expression range. + */ + while(l->op == OCAST) + l = l->left; + if(l->op == OCONST) + return 0; + lt = l->type; + if(l->op == ONAME && l->sym->type){ + lt = l->sym->type; + if(lt->etype == TARRAY) + lt = lt->link; + } + if(lt == T) + return 0; + if(lt->etype == TXXX || lt->etype > TUVLONG) + return 0; + + /* + * Skip over the right casts to find the on-screen value. + */ + if(r->op != OCONST) + return 0; + while(r->oldop == OCAST && !r->xcast) + r = r->left; + rt = r->type; + if(rt == T) + return 0; + + x.b = r->vconst; + x.a = 0; + if((rt->etype&1) && r->vconst < 0) /* signed negative */ + x.a = ~0ULL; + + if((lt->etype&1)==0){ + /* unsigned */ + lo = big(0, 0); + if(lt->width == 8) + hi = big(0, ~0ULL); + else + hi = big(0, (1LL<<(l->type->width*8))-1); + }else{ + lo = big(~0ULL, -(1LL<<(l->type->width*8-1))); + hi = big(0, (1LL<<(l->type->width*8-1))-1); + } + + switch(op){ + case OLT: + case OLO: + case OGE: + case OHS: + if(cmp(x, lo) <= 0) + goto useless; + if(cmp(x, add(hi, 1)) >= 0) + goto useless; + break; + case OLE: + case OLS: + case OGT: + case OHI: + if(cmp(x, add(lo, -1)) <= 0) + goto useless; + if(cmp(x, hi) >= 0) + goto useless; + break; + case OEQ: + case ONE: + /* + * Don't warn about comparisons if the expression + * is as wide as the value: the compiler-supplied casts + * will make both outcomes possible. + */ + if(lt->width >= rt->width && debug['w'] < 2) + return 0; + if(cmp(x, lo) < 0 || cmp(x, hi) > 0) + goto useless; + break; + } + return 0; + +useless: + if((x.a==0 && x.b<=9) || (x.a==~0LL && x.b >= -9ULL)) + snprint(xbuf, sizeof xbuf, "%lld", x.b); + else if(x.a == 0) + snprint(xbuf, sizeof xbuf, "%#llux", x.b); + else + snprint(xbuf, sizeof xbuf, "%#llx", x.b); + if(reverse) + snprint(cmpbuf, sizeof cmpbuf, "%s %s %T", + xbuf, cmps[relindex(n->op)], lt); + else + snprint(cmpbuf, sizeof cmpbuf, "%T %s %s", + lt, cmps[relindex(n->op)], xbuf); + warn(n, "useless or misleading comparison: %s", cmpbuf); + return 0; +} + diff --git a/src/cmd/cc/com64.c b/src/cmd/cc/com64.c new file mode 100644 index 0000000000..8d6e07d1b6 --- /dev/null +++ b/src/cmd/cc/com64.c @@ -0,0 +1,643 @@ +// Inferno utils/cc/com64.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/com64.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +/* + * this is machine depend, but it is totally + * common on all of the 64-bit symulating machines. + */ + +#define FNX 100 /* botch -- redefinition */ + +Node* nodaddv; +Node* nodsubv; +Node* nodmulv; +Node* noddivv; +Node* noddivvu; +Node* nodmodv; +Node* nodmodvu; +Node* nodlshv; +Node* nodrshav; +Node* nodrshlv; +Node* nodandv; +Node* nodorv; +Node* nodxorv; +Node* nodnegv; +Node* nodcomv; + +Node* nodtestv; +Node* nodeqv; +Node* nodnev; +Node* nodlev; +Node* nodltv; +Node* nodgev; +Node* nodgtv; +Node* nodhiv; +Node* nodhsv; +Node* nodlov; +Node* nodlsv; + +Node* nodf2v; +Node* nodd2v; +Node* nodp2v; +Node* nodsi2v; +Node* nodui2v; +Node* nodsl2v; +Node* nodul2v; +Node* nodsh2v; +Node* noduh2v; +Node* nodsc2v; +Node* noduc2v; + +Node* nodv2f; +Node* nodv2d; +Node* nodv2ui; +Node* nodv2si; +Node* nodv2ul; +Node* nodv2sl; +Node* nodv2uh; +Node* nodv2sh; +Node* nodv2uc; +Node* nodv2sc; + +Node* nodvpp; +Node* nodppv; +Node* nodvmm; +Node* nodmmv; + +Node* nodvasop; + +char etconv[NTYPE]; /* for _vasop */ +Init initetconv[] = +{ + TCHAR, 1, 0, + TUCHAR, 2, 0, + TSHORT, 3, 0, + TUSHORT, 4, 0, + TLONG, 5, 0, + TULONG, 6, 0, + TVLONG, 7, 0, + TUVLONG, 8, 0, + TINT, 9, 0, + TUINT, 10, 0, + -1, 0, 0, +}; + +Node* +fvn(char *name, int type) +{ + Node *n; + + n = new(ONAME, Z, Z); + n->sym = slookup(name); + n->sym->sig = SIGINTERN; + if(fntypes[type] == 0) + fntypes[type] = typ(TFUNC, types[type]); + n->type = fntypes[type]; + n->etype = type; + n->class = CGLOBL; + n->addable = 10; + n->complex = 0; + return n; +} + +void +com64init(void) +{ + Init *p; + + nodaddv = fvn("_addv", TVLONG); + nodsubv = fvn("_subv", TVLONG); + nodmulv = fvn("_mulv", TVLONG); + noddivv = fvn("_divv", TVLONG); + noddivvu = fvn("_divvu", TVLONG); + nodmodv = fvn("_modv", TVLONG); + nodmodvu = fvn("_modvu", TVLONG); + nodlshv = fvn("_lshv", TVLONG); + nodrshav = fvn("_rshav", TVLONG); + nodrshlv = fvn("_rshlv", TVLONG); + nodandv = fvn("_andv", TVLONG); + nodorv = fvn("_orv", TVLONG); + nodxorv = fvn("_xorv", TVLONG); + nodnegv = fvn("_negv", TVLONG); + nodcomv = fvn("_comv", TVLONG); + + nodtestv = fvn("_testv", TLONG); + nodeqv = fvn("_eqv", TLONG); + nodnev = fvn("_nev", TLONG); + nodlev = fvn("_lev", TLONG); + nodltv = fvn("_ltv", TLONG); + nodgev = fvn("_gev", TLONG); + nodgtv = fvn("_gtv", TLONG); + nodhiv = fvn("_hiv", TLONG); + nodhsv = fvn("_hsv", TLONG); + nodlov = fvn("_lov", TLONG); + nodlsv = fvn("_lsv", TLONG); + + nodf2v = fvn("_f2v", TVLONG); + nodd2v = fvn("_d2v", TVLONG); + nodp2v = fvn("_p2v", TVLONG); + nodsi2v = fvn("_si2v", TVLONG); + nodui2v = fvn("_ui2v", TVLONG); + nodsl2v = fvn("_sl2v", TVLONG); + nodul2v = fvn("_ul2v", TVLONG); + nodsh2v = fvn("_sh2v", TVLONG); + noduh2v = fvn("_uh2v", TVLONG); + nodsc2v = fvn("_sc2v", TVLONG); + noduc2v = fvn("_uc2v", TVLONG); + + nodv2f = fvn("_v2f", TFLOAT); + nodv2d = fvn("_v2d", TDOUBLE); + nodv2sl = fvn("_v2sl", TLONG); + nodv2ul = fvn("_v2ul", TULONG); + nodv2si = fvn("_v2si", TINT); + nodv2ui = fvn("_v2ui", TUINT); + nodv2sh = fvn("_v2sh", TSHORT); + nodv2uh = fvn("_v2ul", TUSHORT); + nodv2sc = fvn("_v2sc", TCHAR); + nodv2uc = fvn("_v2uc", TUCHAR); + + nodvpp = fvn("_vpp", TVLONG); + nodppv = fvn("_ppv", TVLONG); + nodvmm = fvn("_vmm", TVLONG); + nodmmv = fvn("_mmv", TVLONG); + + nodvasop = fvn("_vasop", TVLONG); + + for(p = initetconv; p->code >= 0; p++) + etconv[p->code] = p->value; +} + +int +com64(Node *n) +{ + Node *l, *r, *a, *t; + int lv, rv; + + if(n->type == 0) + return 0; + + l = n->left; + r = n->right; + + lv = 0; + if(l && l->type && typev[l->type->etype]) + lv = 1; + rv = 0; + if(r && r->type && typev[r->type->etype]) + rv = 1; + + if(lv) { + switch(n->op) { + case OEQ: + a = nodeqv; + goto setbool; + case ONE: + a = nodnev; + goto setbool; + case OLE: + a = nodlev; + goto setbool; + case OLT: + a = nodltv; + goto setbool; + case OGE: + a = nodgev; + goto setbool; + case OGT: + a = nodgtv; + goto setbool; + case OHI: + a = nodhiv; + goto setbool; + case OHS: + a = nodhsv; + goto setbool; + case OLO: + a = nodlov; + goto setbool; + case OLS: + a = nodlsv; + goto setbool; + + case OANDAND: + case OOROR: + if(machcap(n)) + return 1; + + if(rv) { + r = new(OFUNC, nodtestv, r); + n->right = r; + r->complex = FNX; + r->op = OFUNC; + r->type = types[TLONG]; + } + + case OCOND: + case ONOT: + if(machcap(n)) + return 1; + + l = new(OFUNC, nodtestv, l); + n->left = l; + l->complex = FNX; + l->op = OFUNC; + l->type = types[TLONG]; + n->complex = FNX; + return 1; + } + } + + if(rv) { + if(machcap(n)) + return 1; + switch(n->op) { + case OANDAND: + case OOROR: + r = new(OFUNC, nodtestv, r); + n->right = r; + r->complex = FNX; + r->op = OFUNC; + r->type = types[TLONG]; + return 1; + } + } + + if(typev[n->type->etype]) { + if(machcap(n)) + return 1; + switch(n->op) { + default: + diag(n, "unknown vlong %O", n->op); + case OFUNC: + n->complex = FNX; + case ORETURN: + case OAS: + case OIND: + return 1; + case OADD: + a = nodaddv; + goto setbop; + case OSUB: + a = nodsubv; + goto setbop; + case OMUL: + case OLMUL: + a = nodmulv; + goto setbop; + case ODIV: + a = noddivv; + goto setbop; + case OLDIV: + a = noddivvu; + goto setbop; + case OMOD: + a = nodmodv; + goto setbop; + case OLMOD: + a = nodmodvu; + goto setbop; + case OASHL: + a = nodlshv; + goto setbop; + case OASHR: + a = nodrshav; + goto setbop; + case OLSHR: + a = nodrshlv; + goto setbop; + case OAND: + a = nodandv; + goto setbop; + case OOR: + a = nodorv; + goto setbop; + case OXOR: + a = nodxorv; + goto setbop; + case OPOSTINC: + a = nodvpp; + goto setvinc; + case OPOSTDEC: + a = nodvmm; + goto setvinc; + case OPREINC: + a = nodppv; + goto setvinc; + case OPREDEC: + a = nodmmv; + goto setvinc; + case ONEG: + a = nodnegv; + goto setfnx; + case OCOM: + a = nodcomv; + goto setfnx; + case OCAST: + switch(l->type->etype) { + case TCHAR: + a = nodsc2v; + goto setfnxl; + case TUCHAR: + a = noduc2v; + goto setfnxl; + case TSHORT: + a = nodsh2v; + goto setfnxl; + case TUSHORT: + a = noduh2v; + goto setfnxl; + case TINT: + a = nodsi2v; + goto setfnx; + case TUINT: + a = nodui2v; + goto setfnx; + case TLONG: + a = nodsl2v; + goto setfnx; + case TULONG: + a = nodul2v; + goto setfnx; + case TFLOAT: + a = nodf2v; + goto setfnx; + case TDOUBLE: + a = nodd2v; + goto setfnx; + case TIND: + a = nodp2v; + goto setfnx; + } + diag(n, "unknown %T->vlong cast", l->type); + return 1; + case OASADD: + a = nodaddv; + goto setasop; + case OASSUB: + a = nodsubv; + goto setasop; + case OASMUL: + case OASLMUL: + a = nodmulv; + goto setasop; + case OASDIV: + a = noddivv; + goto setasop; + case OASLDIV: + a = noddivvu; + goto setasop; + case OASMOD: + a = nodmodv; + goto setasop; + case OASLMOD: + a = nodmodvu; + goto setasop; + case OASASHL: + a = nodlshv; + goto setasop; + case OASASHR: + a = nodrshav; + goto setasop; + case OASLSHR: + a = nodrshlv; + goto setasop; + case OASAND: + a = nodandv; + goto setasop; + case OASOR: + a = nodorv; + goto setasop; + case OASXOR: + a = nodxorv; + goto setasop; + } + } + + if(typefd[n->type->etype] && l && l->op == OFUNC) { + switch(n->op) { + case OASADD: + case OASSUB: + case OASMUL: + case OASLMUL: + case OASDIV: + case OASLDIV: + case OASMOD: + case OASLMOD: + case OASASHL: + case OASASHR: + case OASLSHR: + case OASAND: + case OASOR: + case OASXOR: + if(l->right && typev[l->right->etype]) { + diag(n, "sorry float vlong not implemented\n"); + } + } + } + + if(n->op == OCAST) { + if(l->type && typev[l->type->etype]) { + if(machcap(n)) + return 1; + switch(n->type->etype) { + case TDOUBLE: + a = nodv2d; + goto setfnx; + case TFLOAT: + a = nodv2f; + goto setfnx; + case TLONG: + a = nodv2sl; + goto setfnx; + case TULONG: + a = nodv2ul; + goto setfnx; + case TINT: + a = nodv2si; + goto setfnx; + case TUINT: + a = nodv2ui; + goto setfnx; + case TSHORT: + a = nodv2sh; + goto setfnx; + case TUSHORT: + a = nodv2uh; + goto setfnx; + case TCHAR: + a = nodv2sc; + goto setfnx; + case TUCHAR: + a = nodv2uc; + goto setfnx; + case TIND: // small pun here + a = nodv2ul; + goto setfnx; + } + diag(n, "unknown vlong->%T cast", n->type); + return 1; + } + } + + return 0; + +setbop: + n->left = a; + n->right = new(OLIST, l, r); + n->complex = FNX; + n->op = OFUNC; + return 1; + +setfnxl: + l = new(OCAST, l, 0); + l->type = types[TLONG]; + l->complex = l->left->complex; + +setfnx: + n->left = a; + n->right = l; + n->complex = FNX; + n->op = OFUNC; + return 1; + +setvinc: + n->left = a; + l = new(OADDR, l, Z); + l->type = typ(TIND, l->left->type); + n->right = new(OLIST, l, r); + n->complex = FNX; + n->op = OFUNC; + return 1; + +setbool: + if(machcap(n)) + return 1; + n->left = a; + n->right = new(OLIST, l, r); + n->complex = FNX; + n->op = OFUNC; + n->type = types[TLONG]; + return 1; + +setasop: + if(l->op == OFUNC) { + l = l->right; + goto setasop; + } + + t = new(OCONST, 0, 0); + t->vconst = etconv[l->type->etype]; + t->type = types[TLONG]; + t->addable = 20; + r = new(OLIST, t, r); + + t = new(OADDR, a, 0); + t->type = typ(TIND, a->type); + r = new(OLIST, t, r); + + t = new(OADDR, l, 0); + t->type = typ(TIND, l->type); + r = new(OLIST, t, r); + + n->left = nodvasop; + n->right = r; + n->complex = FNX; + n->op = OFUNC; + + return 1; +} + +void +bool64(Node *n) +{ + Node *n1; + + if(machcap(Z)) + return; + if(typev[n->type->etype]) { + n1 = new(OXXX, 0, 0); + *n1 = *n; + + n->right = n1; + n->left = nodtestv; + n->complex = FNX; + n->addable = 0; + n->op = OFUNC; + n->type = types[TLONG]; + } +} + +/* + * more machine depend stuff. + * this is common for 8,16,32,64 bit machines. + * this is common for ieee machines. + */ +double +convvtof(vlong v) +{ + double d; + + d = v; /* BOTCH */ + return d; +} + +vlong +convftov(double d) +{ + vlong v; + + + v = d; /* BOTCH */ + return v; +} + +double +convftox(double d, int et) +{ + + if(!typefd[et]) + diag(Z, "bad type in castftox %s", tnames[et]); + return d; +} + +vlong +convvtox(vlong c, int et) +{ + int n; + + n = 8 * ewidth[et]; + c &= MASK(n); + if(!typeu[et]) + if(c & SIGN(n)) + c |= ~MASK(n); + return c; +} diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c new file mode 100644 index 0000000000..f44c340077 --- /dev/null +++ b/src/cmd/cc/dcl.c @@ -0,0 +1,1664 @@ +// Inferno utils/cc/dcl.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/dcl.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +Node* +dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n) +{ + Sym *s; + Node *n1; + long v; + + nearln = lineno; + lastfield = 0; + +loop: + if(n != Z) + switch(n->op) { + default: + diag(n, "unknown declarator: %O", n->op); + break; + + case OARRAY: + t = typ(TARRAY, t); + t->width = 0; + n1 = n->right; + n = n->left; + if(n1 != Z) { + complex(n1); + v = -1; + if(n1->op == OCONST) + v = n1->vconst; + if(v <= 0) { + diag(n, "array size must be a positive constant"); + v = 1; + } + t->width = v * t->link->width; + } + goto loop; + + case OIND: + t = typ(TIND, t); + t->garb = n->garb; + n = n->left; + goto loop; + + case OFUNC: + t = typ(TFUNC, t); + t->down = fnproto(n); + n = n->left; + goto loop; + + case OBIT: + n1 = n->right; + complex(n1); + lastfield = -1; + if(n1->op == OCONST) + lastfield = n1->vconst; + if(lastfield < 0) { + diag(n, "field width must be non-negative constant"); + lastfield = 1; + } + if(lastfield == 0) { + lastbit = 0; + firstbit = 1; + if(n->left != Z) { + diag(n, "zero width named field"); + lastfield = 1; + } + } + if(!typei[t->etype]) { + diag(n, "field type must be int-like"); + t = types[TINT]; + lastfield = 1; + } + if(lastfield > tfield->width*8) { + diag(n, "field width larger than field unit"); + lastfield = 1; + } + lastbit += lastfield; + if(lastbit > tfield->width*8) { + lastbit = lastfield; + firstbit = 1; + } + n = n->left; + goto loop; + + case ONAME: + if(f == NODECL) + break; + s = n->sym; + (*f)(c, t, s); + if(s->class == CLOCAL) + s = mkstatic(s); + firstbit = 0; + n->sym = s; + n->type = s->type; + n->xoffset = s->offset; + n->class = s->class; + n->etype = TVOID; + if(n->type != T) + n->etype = n->type->etype; + if(debug['d']) + dbgdecl(s); + acidvar(s); + s->varlineno = lineno; + break; + } + lastdcl = t; + return n; +} + +Sym* +mkstatic(Sym *s) +{ + Sym *s1; + + if(s->class != CLOCAL) + return s; + snprint(symb, NSYMB, "%s$%d", s->name, s->block); + s1 = lookup(); + if(s1->class != CSTATIC) { + s1->type = s->type; + s1->offset = s->offset; + s1->block = s->block; + s1->class = CSTATIC; + } + return s1; +} + +/* + * make a copy of a typedef + * the problem is to split out incomplete + * arrays so that it is in the variable + * rather than the typedef. + */ +Type* +tcopy(Type *t) +{ + Type *tl, *tx; + int et; + + if(t == T) + return t; + et = t->etype; + if(typesu[et]) + return t; + tl = tcopy(t->link); + if(tl != t->link || + (et == TARRAY && t->width == 0)) { + tx = copytyp(t); + tx->link = tl; + return tx; + } + return t; +} + +Node* +doinit(Sym *s, Type *t, long o, Node *a) +{ + Node *n; + + if(t == T) + return Z; + if(s->class == CEXTERN) { + s->class = CGLOBL; + if(debug['d']) + dbgdecl(s); + } + if(debug['i']) { + print("t = %T; o = %ld; n = %s\n", t, o, s->name); + prtree(a, "doinit value"); + } + + + n = initlist; + if(a->op == OINIT) + a = a->left; + initlist = a; + + a = init1(s, t, o, 0); + if(initlist != Z) + diag(initlist, "more initializers than structure: %s", + s->name); + initlist = n; + + return a; +} + +/* + * get next major operator, + * dont advance initlist. + */ +Node* +peekinit(void) +{ + Node *a; + + a = initlist; + +loop: + if(a == Z) + return a; + if(a->op == OLIST) { + a = a->left; + goto loop; + } + return a; +} + +/* + * consume and return next element on + * initlist. expand strings. + */ +Node* +nextinit(void) +{ + Node *a, *b, *n; + + a = initlist; + n = Z; + + if(a == Z) + return a; + if(a->op == OLIST) { + n = a->right; + a = a->left; + } + if(a->op == OUSED) { + a = a->left; + b = new(OCONST, Z, Z); + b->type = a->type->link; + if(a->op == OSTRING) { + b->vconst = convvtox(*a->cstring, TCHAR); + a->cstring++; + } + if(a->op == OLSTRING) { + b->vconst = convvtox(*a->rstring, TUSHORT); + a->rstring++; + } + a->type->width -= b->type->width; + if(a->type->width <= 0) + initlist = n; + return b; + } + initlist = n; + return a; +} + +int +isstruct(Node *a, Type *t) +{ + Node *n; + + switch(a->op) { + case ODOTDOT: + n = a->left; + if(n && n->type && sametype(n->type, t)) + return 1; + case OSTRING: + case OLSTRING: + case OCONST: + case OINIT: + case OELEM: + return 0; + } + + n = new(ODOTDOT, Z, Z); + *n = *a; + + /* + * ODOTDOT is a flag for tcom + * a second tcom will not be performed + */ + a->op = ODOTDOT; + a->left = n; + a->right = Z; + + if(tcom(n)) + return 0; + + if(sametype(n->type, t)) + return 1; + return 0; +} + +Node* +init1(Sym *s, Type *t, long o, int exflag) +{ + Node *a, *l, *r, nod; + Type *t1; + long e, w, so, mw; + + a = peekinit(); + if(a == Z) + return Z; + + if(debug['i']) { + print("t = %T; o = %ld; n = %s\n", t, o, s->name); + prtree(a, "init1 value"); + } + + if(exflag && a->op == OINIT) + return doinit(s, t, o, nextinit()); + + switch(t->etype) { + default: + diag(Z, "unknown type in initialization: %T to: %s", t, s->name); + return Z; + + case TCHAR: + case TUCHAR: + case TINT: + case TUINT: + case TSHORT: + case TUSHORT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TFLOAT: + case TDOUBLE: + case TIND: + single: + if(a->op == OARRAY || a->op == OELEM) + return Z; + + a = nextinit(); + if(a == Z) + return Z; + + if(t->nbits) + diag(Z, "cannot initialize bitfields"); + if(s->class == CAUTO) { + l = new(ONAME, Z, Z); + l->sym = s; + l->type = t; + l->etype = TVOID; + if(s->type) + l->etype = s->type->etype; + l->xoffset = s->offset + o; + l->class = s->class; + + l = new(OASI, l, a); + return l; + } + + complex(a); + if(a->type == T) + return Z; + + if(a->op == OCONST) { + if(vconst(a) && t->etype == TIND && a->type && a->type->etype != TIND){ + diag(a, "initialize pointer to an integer: %s", s->name); + return Z; + } + if(!sametype(a->type, t)) { + /* hoop jumping to save malloc */ + if(nodcast == Z) + nodcast = new(OCAST, Z, Z); + nod = *nodcast; + nod.left = a; + nod.type = t; + nod.lineno = a->lineno; + complex(&nod); + if(nod.type) + *a = nod; + } + if(a->op != OCONST) { + diag(a, "initializer is not a constant: %s", + s->name); + return Z; + } + if(vconst(a) == 0) + return Z; + goto gext; + } + if(t->etype == TIND) { + while(a->op == OCAST) { + warn(a, "CAST in initialization ignored"); + a = a->left; + } + if(!sametype(t, a->type)) { + diag(a, "initialization of incompatible pointers: %s\n%T and %T", + s->name, t, a->type); + } + if(a->op == OADDR) + a = a->left; + goto gext; + } + + while(a->op == OCAST) + a = a->left; + if(a->op == OADDR) { + warn(a, "initialize pointer to an integer: %s", s->name); + a = a->left; + goto gext; + } + diag(a, "initializer is not a constant: %s", s->name); + return Z; + + gext: + gextern(s, a, o, t->width); + + return Z; + + case TARRAY: + w = t->link->width; + if(a->op == OSTRING || a->op == OLSTRING) + if(typei[t->link->etype]) { + /* + * get rid of null if sizes match exactly + */ + a = nextinit(); + mw = t->width/w; + so = a->type->width/a->type->link->width; + if(mw && so > mw) { + if(so != mw+1) + diag(a, "string initialization larger than array"); + a->type->width -= a->type->link->width; + } + + /* + * arrange strings to be expanded + * inside OINIT braces. + */ + a = new(OUSED, a, Z); + return doinit(s, t, o, a); + } + + mw = -w; + l = Z; + for(e=0;;) { + /* + * peek ahead for element initializer + */ + a = peekinit(); + if(a == Z) + break; + if(a->op == OELEM && t->link->etype != TSTRUCT) + break; + if(a->op == OARRAY) { + if(e && exflag) + break; + a = nextinit(); + r = a->left; + complex(r); + if(r->op != OCONST) { + diag(r, "initializer subscript must be constant"); + return Z; + } + e = r->vconst; + if(t->width != 0) + if(e < 0 || e*w >= t->width) { + diag(a, "initialization index out of range: %ld", e); + continue; + } + } + + so = e*w; + if(so > mw) + mw = so; + if(t->width != 0) + if(mw >= t->width) + break; + r = init1(s, t->link, o+so, 1); + l = newlist(l, r); + e++; + } + if(t->width == 0) + t->width = mw+w; + return l; + + case TUNION: + case TSTRUCT: + /* + * peek ahead to find type of rhs. + * if its a structure, then treat + * this element as a variable + * rather than an aggregate. + */ + if(isstruct(a, t)) + goto single; + + if(t->width <= 0) { + diag(Z, "incomplete structure: %s", s->name); + return Z; + } + l = Z; + + again: + for(t1 = t->link; t1 != T; t1 = t1->down) { + if(a->op == OARRAY && t1->etype != TARRAY) + break; + if(a->op == OELEM) { + if(t1->sym != a->sym) + continue; + nextinit(); + } + r = init1(s, t1, o+t1->offset, 1); + l = newlist(l, r); + a = peekinit(); + if(a == Z) + break; + if(a->op == OELEM) + goto again; + } + if(a && a->op == OELEM) + diag(a, "structure element not found %F", a); + return l; + } +} + +Node* +newlist(Node *l, Node *r) +{ + if(r == Z) + return l; + if(l == Z) + return r; + return new(OLIST, l, r); +} + +void +suallign(Type *t) +{ + Type *l; + long o, w; + + o = 0; + switch(t->etype) { + + case TSTRUCT: + t->offset = 0; + w = 0; + for(l = t->link; l != T; l = l->down) { + if(l->nbits) { + if(l->shift <= 0) { + l->shift = -l->shift; + w = xround(w, tfield->width); + o = w; + w += tfield->width; + } + l->offset = o; + } else { + if(l->width <= 0) + if(l->down != T) + if(l->sym) + diag(Z, "incomplete structure element: %s", + l->sym->name); + else + diag(Z, "incomplete structure element"); + w = align(w, l, Ael1); + l->offset = w; + w = align(w, l, Ael2); + } + } + w = align(w, t, Asu2); + t->width = w; + acidtype(t); + pickletype(t); + return; + + case TUNION: + t->offset = 0; + w = 0; + for(l = t->link; l != T; l = l->down) { + if(l->width <= 0) + if(l->sym) + diag(Z, "incomplete union element: %s", + l->sym->name); + else + diag(Z, "incomplete union element"); + l->offset = 0; + l->shift = 0; + o = align(align(0, l, Ael1), l, Ael2); + if(o > w) + w = o; + } + w = align(w, t, Asu2); + t->width = w; + acidtype(t); + pickletype(t); + return; + + default: + diag(Z, "unknown type in suallign: %T", t); + break; + } +} + +long +xround(long v, int w) +{ + int r; + + if(w <= 0 || w > 8) { + diag(Z, "rounding by %d", w); + w = 1; + } + r = v%w; + if(r) + v += w-r; + return v; +} + +Type* +ofnproto(Node *n) +{ + Type *tl, *tr, *t; + + if(n == Z) + return T; + switch(n->op) { + case OLIST: + tl = ofnproto(n->left); + tr = ofnproto(n->right); + if(tl == T) + return tr; + tl->down = tr; + return tl; + + case ONAME: + t = copytyp(n->sym->type); + t->down = T; + return t; + } + return T; +} + +#define ANSIPROTO 1 +#define OLDPROTO 2 + +void +argmark(Node *n, int pass) +{ + Type *t; + + autoffset = align(0, thisfn->link, Aarg0); + stkoff = 0; + for(; n->left != Z; n = n->left) { + if(n->op != OFUNC || n->left->op != ONAME) + continue; + walkparam(n->right, pass); + if(pass != 0 && anyproto(n->right) == OLDPROTO) { + t = typ(TFUNC, n->left->sym->type->link); + t->down = typ(TOLD, T); + t->down->down = ofnproto(n->right); + tmerge(t, n->left->sym); + n->left->sym->type = t; + } + break; + } + autoffset = 0; + stkoff = 0; +} + +void +walkparam(Node *n, int pass) +{ + Sym *s; + Node *n1; + + if(n != Z && n->op == OPROTO && n->left == Z && n->type == types[TVOID]) + return; + +loop: + if(n == Z) + return; + switch(n->op) { + default: + diag(n, "argument not a name/prototype: %O", n->op); + break; + + case OLIST: + walkparam(n->left, pass); + n = n->right; + goto loop; + + case OPROTO: + for(n1 = n; n1 != Z; n1=n1->left) + if(n1->op == ONAME) { + if(pass == 0) { + s = n1->sym; + push1(s); + s->offset = -1; + break; + } + dodecl(pdecl, CPARAM, n->type, n->left); + break; + } + if(n1) + break; + if(pass == 0) { + /* + * extension: + * allow no name in argument declaration + diag(Z, "no name in argument declaration"); + */ + break; + } + dodecl(NODECL, CPARAM, n->type, n->left); + pdecl(CPARAM, lastdcl, S); + break; + + case ODOTDOT: + break; + + case ONAME: + s = n->sym; + if(pass == 0) { + push1(s); + s->offset = -1; + break; + } + if(s->offset != -1) { + if(autoffset == 0) { + firstarg = s; + firstargtype = s->type; + } + autoffset = align(autoffset, s->type, Aarg1); + s->offset = autoffset; + autoffset = align(autoffset, s->type, Aarg2); + } else + dodecl(pdecl, CXXX, types[TINT], n); + break; + } +} + +void +markdcl(void) +{ + Decl *d; + + blockno++; + d = push(); + d->val = DMARK; + d->offset = autoffset; + d->block = autobn; + autobn = blockno; +} + +Node* +revertdcl(void) +{ + Decl *d; + Sym *s; + Node *n, *n1; + + n = Z; + for(;;) { + d = dclstack; + if(d == D) { + diag(Z, "pop off dcl stack"); + break; + } + dclstack = d->link; + s = d->sym; + switch(d->val) { + case DMARK: + autoffset = d->offset; + autobn = d->block; + return n; + + case DAUTO: + if(debug['d']) + print("revert1 \"%s\"\n", s->name); + if(s->aused == 0) { + nearln = s->varlineno; + if(s->class == CAUTO) + warn(Z, "auto declared and not used: %s", s->name); + if(s->class == CPARAM) + warn(Z, "param declared and not used: %s", s->name); + } + if(s->type && (s->type->garb & GVOLATILE)) { + n1 = new(ONAME, Z, Z); + n1->sym = s; + n1->type = s->type; + n1->etype = TVOID; + if(n1->type != T) + n1->etype = n1->type->etype; + n1->xoffset = s->offset; + n1->class = s->class; + + n1 = new(OADDR, n1, Z); + n1 = new(OUSED, n1, Z); + if(n == Z) + n = n1; + else + n = new(OLIST, n1, n); + } + s->type = d->type; + s->class = d->class; + s->offset = d->offset; + s->block = d->block; + s->varlineno = d->varlineno; + s->aused = d->aused; + break; + + case DSUE: + if(debug['d']) + print("revert2 \"%s\"\n", s->name); + s->suetag = d->type; + s->sueblock = d->block; + break; + + case DLABEL: + if(debug['d']) + print("revert3 \"%s\"\n", s->name); + if(s->label && s->label->addable == 0) + warn(s->label, "label declared and not used \"%s\"", s->name); + s->label = Z; + break; + } + } + return n; +} + +Type* +fnproto(Node *n) +{ + int r; + + r = anyproto(n->right); + if(r == 0 || (r & OLDPROTO)) { + if(r & ANSIPROTO) + diag(n, "mixed ansi/old function declaration: %F", n->left); + return T; + } + return fnproto1(n->right); +} + +int +anyproto(Node *n) +{ + int r; + + r = 0; + +loop: + if(n == Z) + return r; + switch(n->op) { + case OLIST: + r |= anyproto(n->left); + n = n->right; + goto loop; + + case ODOTDOT: + case OPROTO: + return r | ANSIPROTO; + } + return r | OLDPROTO; +} + +Type* +fnproto1(Node *n) +{ + Type *t; + + if(n == Z) + return T; + switch(n->op) { + case OLIST: + t = fnproto1(n->left); + if(t != T) + t->down = fnproto1(n->right); + return t; + + case OPROTO: + lastdcl = T; + dodecl(NODECL, CXXX, n->type, n->left); + t = typ(TXXX, T); + if(lastdcl != T) + *t = *paramconv(lastdcl, 1); + return t; + + case ONAME: + diag(n, "incomplete argument prototype"); + return typ(TINT, T); + + case ODOTDOT: + return typ(TDOT, T); + } + diag(n, "unknown op in fnproto"); + return T; +} + +void +dbgdecl(Sym *s) +{ + print("decl \"%s\": C=%s [B=%d:O=%ld] T=%T\n", + s->name, cnames[s->class], s->block, s->offset, s->type); +} + +Decl* +push(void) +{ + Decl *d; + + d = alloc(sizeof(*d)); + d->link = dclstack; + dclstack = d; + return d; +} + +Decl* +push1(Sym *s) +{ + Decl *d; + + d = push(); + d->sym = s; + d->val = DAUTO; + d->type = s->type; + d->class = s->class; + d->offset = s->offset; + d->block = s->block; + d->varlineno = s->varlineno; + d->aused = s->aused; + return d; +} + +int +sametype(Type *t1, Type *t2) +{ + + if(t1 == t2) + return 1; + return rsametype(t1, t2, 5, 1); +} + +int +rsametype(Type *t1, Type *t2, int n, int f) +{ + int et; + + n--; + for(;;) { + if(t1 == t2) + return 1; + if(t1 == T || t2 == T) + return 0; + if(n <= 0) + return 1; + et = t1->etype; + if(et != t2->etype) + return 0; + if(et == TFUNC) { + if(!rsametype(t1->link, t2->link, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + while(t1 != T && t2 != T) { + if(t1->etype == TOLD) { + t1 = t1->down; + continue; + } + if(t2->etype == TOLD) { + t2 = t2->down; + continue; + } + while(t1 != T || t2 != T) { + if(!rsametype(t1, t2, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + } + break; + } + return 1; + } + if(et == TARRAY) + if(t1->width != t2->width && t1->width != 0 && t2->width != 0) + return 0; + if(typesu[et]) { + if(t1->link == T) + snap(t1); + if(t2->link == T) + snap(t2); + t1 = t1->link; + t2 = t2->link; + for(;;) { + if(t1 == t2) + return 1; + if(!rsametype(t1, t2, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + } + } + t1 = t1->link; + t2 = t2->link; + if((f || !debug['V']) && et == TIND) { + if(t1 != T && t1->etype == TVOID) + return 1; + if(t2 != T && t2->etype == TVOID) + return 1; + } + } +} + +typedef struct Typetab Typetab; + +struct Typetab{ + int n; + Type **a; +}; + +static int +sigind(Type *t, Typetab *tt) +{ + int n; + Type **a, **na, **p, **e; + + n = tt->n; + a = tt->a; + e = a+n; + /* linear search seems ok */ + for(p = a ; p < e; p++) + if(sametype(*p, t)) + return p-a; + if((n&15) == 0){ + na = malloc((n+16)*sizeof(Type*)); + memmove(na, a, n*sizeof(Type*)); + free(a); + a = tt->a = na; + } + a[tt->n++] = t; + return -1; +} + +static ulong +signat(Type *t, Typetab *tt) +{ + int i; + Type *t1; + long s; + + s = 0; + for(; t; t=t->link) { + s = s*thash1 + thash[t->etype]; + if(t->garb&GINCOMPLETE) + return s; + switch(t->etype) { + default: + return s; + case TARRAY: + s = s*thash2 + 0; /* was t->width */ + break; + case TFUNC: + for(t1=t->down; t1; t1=t1->down) + s = s*thash3 + signat(t1, tt); + break; + case TSTRUCT: + case TUNION: + if((i = sigind(t, tt)) >= 0){ + s = s*thash2 + i; + return s; + } + for(t1=t->link; t1; t1=t1->down) + s = s*thash3 + signat(t1, tt); + return s; + case TIND: + break; + } + } + return s; +} + +ulong +signature(Type *t) +{ + ulong s; + Typetab tt; + + tt.n = 0; + tt.a = nil; + s = signat(t, &tt); + free(tt.a); + return s; +} + +ulong +sign(Sym *s) +{ + ulong v; + Type *t; + + if(s->sig == SIGINTERN) + return SIGNINTERN; + if((t = s->type) == T) + return 0; + v = signature(t); + if(v == 0) + v = SIGNINTERN; + return v; +} + +void +snap(Type *t) +{ + if(typesu[t->etype]) + if(t->link == T && t->tag && t->tag->suetag) { + t->link = t->tag->suetag->link; + t->width = t->tag->suetag->width; + } +} + +Type* +dotag(Sym *s, int et, int bn) +{ + Decl *d; + + if(bn != 0 && bn != s->sueblock) { + d = push(); + d->sym = s; + d->val = DSUE; + d->type = s->suetag; + d->block = s->sueblock; + s->suetag = T; + } + if(s->suetag == T) { + s->suetag = typ(et, T); + s->sueblock = autobn; + } + if(s->suetag->etype != et) + diag(Z, "tag used for more than one type: %s", + s->name); + if(s->suetag->tag == S) + s->suetag->tag = s; + return s->suetag; +} + +Node* +dcllabel(Sym *s, int f) +{ + Decl *d, d1; + Node *n; + + n = s->label; + if(n != Z) { + if(f) { + if(n->complex) + diag(Z, "label reused: %s", s->name); + n->complex = 1; // declared + } else + n->addable = 1; // used + return n; + } + + d = push(); + d->sym = s; + d->val = DLABEL; + dclstack = d->link; + + d1 = *firstdcl; + *firstdcl = *d; + *d = d1; + + firstdcl->link = d; + firstdcl = d; + + n = new(OXXX, Z, Z); + n->sym = s; + n->complex = f; + n->addable = !f; + s->label = n; + + if(debug['d']) + dbgdecl(s); + return n; +} + +Type* +paramconv(Type *t, int f) +{ + + switch(t->etype) { + case TUNION: + case TSTRUCT: + if(t->width <= 0) + diag(Z, "incomplete structure: %s", t->tag->name); + break; + + case TARRAY: + t = typ(TIND, t->link); + t->width = types[TIND]->width; + break; + + case TFUNC: + t = typ(TIND, t); + t->width = types[TIND]->width; + break; + + case TFLOAT: + if(!f) + t = types[TDOUBLE]; + break; + + case TCHAR: + case TSHORT: + if(!f) + t = types[TINT]; + break; + + case TUCHAR: + case TUSHORT: + if(!f) + t = types[TUINT]; + break; + } + return t; +} + +void +adecl(int c, Type *t, Sym *s) +{ + + if(c == CSTATIC) + c = CLOCAL; + if(t->etype == TFUNC) { + if(c == CXXX) + c = CEXTERN; + if(c == CLOCAL) + c = CSTATIC; + if(c == CAUTO || c == CEXREG) + diag(Z, "function cannot be %s %s", cnames[c], s->name); + } + if(c == CXXX) + c = CAUTO; + if(s) { + if(s->class == CSTATIC) + if(c == CEXTERN || c == CGLOBL) { + warn(Z, "just say static: %s", s->name); + c = CSTATIC; + } + if(s->class == CAUTO || s->class == CPARAM || s->class == CLOCAL) + if(s->block == autobn) + diag(Z, "auto redeclaration of: %s", s->name); + if(c != CPARAM) + push1(s); + s->block = autobn; + s->offset = 0; + s->type = t; + s->class = c; + s->aused = 0; + } + switch(c) { + case CAUTO: + autoffset = align(autoffset, t, Aaut3); + stkoff = maxround(stkoff, autoffset); + s->offset = -autoffset; + break; + + case CPARAM: + if(autoffset == 0) { + firstarg = s; + firstargtype = t; + } + autoffset = align(autoffset, t, Aarg1); + if(s) + s->offset = autoffset; + autoffset = align(autoffset, t, Aarg2); + break; + } +} + +void +pdecl(int c, Type *t, Sym *s) +{ + if(s && s->offset != -1) { + diag(Z, "not a parameter: %s", s->name); + return; + } + t = paramconv(t, c==CPARAM); + if(c == CXXX) + c = CPARAM; + if(c != CPARAM) { + diag(Z, "parameter cannot have class: %s", s->name); + c = CPARAM; + } + adecl(c, t, s); +} + +void +xdecl(int c, Type *t, Sym *s) +{ + long o; + + o = 0; + switch(c) { + case CEXREG: + o = exreg(t); + if(o == 0) + c = CEXTERN; + if(s->class == CGLOBL) + c = CGLOBL; + break; + + case CEXTERN: + if(s->class == CGLOBL) + c = CGLOBL; + break; + + case CXXX: + c = CGLOBL; + if(s->class == CEXTERN) + s->class = CGLOBL; + break; + + case CAUTO: + diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]); + c = CEXTERN; + break; + + case CTYPESTR: + if(!typesuv[t->etype]) { + diag(Z, "typestr must be struct/union: %s", s->name); + break; + } + dclfunct(t, s); + break; + } + + if(s->class == CSTATIC) + if(c == CEXTERN || c == CGLOBL) { + warn(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]); + c = CSTATIC; + } + if(s->type != T) + if(s->class != c || !sametype(t, s->type) || t->etype == TENUM) { + diag(Z, "external redeclaration of: %s", s->name); + Bprint(&diagbuf, " %s %T %L\n", cnames[c], t, nearln); + Bprint(&diagbuf, " %s %T %L\n", cnames[s->class], s->type, s->varlineno); + } + tmerge(t, s); + s->type = t; + s->class = c; + s->block = 0; + s->offset = o; +} + +void +tmerge(Type *t1, Sym *s) +{ + Type *ta, *tb, *t2; + + t2 = s->type; +/*print("merge %T; %T\n", t1, t2);/**/ + for(;;) { + if(t1 == T || t2 == T || t1 == t2) + break; + if(t1->etype != t2->etype) + break; + switch(t1->etype) { + case TFUNC: + ta = t1->down; + tb = t2->down; + if(ta == T) { + t1->down = tb; + break; + } + if(tb == T) + break; + while(ta != T && tb != T) { + if(ta == tb) + break; + /* ignore old-style flag */ + if(ta->etype == TOLD) { + ta = ta->down; + continue; + } + if(tb->etype == TOLD) { + tb = tb->down; + continue; + } + /* checking terminated by ... */ + if(ta->etype == TDOT && tb->etype == TDOT) { + ta = T; + tb = T; + break; + } + if(!sametype(ta, tb)) + break; + ta = ta->down; + tb = tb->down; + } + if(ta != tb) + diag(Z, "function inconsistently declared: %s", s->name); + + /* take new-style over old-style */ + ta = t1->down; + tb = t2->down; + if(ta != T && ta->etype == TOLD) + if(tb != T && tb->etype != TOLD) + t1->down = tb; + break; + + case TARRAY: + /* should we check array size change? */ + if(t2->width > t1->width) + t1->width = t2->width; + break; + + case TUNION: + case TSTRUCT: + return; + } + t1 = t1->link; + t2 = t2->link; + } +} + +void +edecl(int c, Type *t, Sym *s) +{ + Type *t1; + + if(s == S) { + if(!typesu[t->etype]) + diag(Z, "unnamed structure element must be struct/union"); + if(c != CXXX) + diag(Z, "unnamed structure element cannot have class"); + } else + if(c != CXXX) + diag(Z, "structure element cannot have class: %s", s->name); + t1 = t; + t = copytyp(t1); + t->sym = s; + t->down = T; + if(lastfield) { + t->shift = lastbit - lastfield; + t->nbits = lastfield; + if(firstbit) + t->shift = -t->shift; + if(typeu[t->etype]) + t->etype = tufield->etype; + else + t->etype = tfield->etype; + } + if(strf == T) + strf = t; + else + strl->down = t; + strl = t; +} + +/* + * this routine is very suspect. + * ansi requires the enum type to + * be represented as an 'int' + * this means that 0x81234567 + * would be illegal. this routine + * makes signed and unsigned go + * to unsigned. + */ +Type* +maxtype(Type *t1, Type *t2) +{ + + if(t1 == T) + return t2; + if(t2 == T) + return t1; + if(t1->etype > t2->etype) + return t1; + return t2; +} + +void +doenum(Sym *s, Node *n) +{ + + if(n) { + complex(n); + if(n->op != OCONST) { + diag(n, "enum not a constant: %s", s->name); + return; + } + en.cenum = n->type; + en.tenum = maxtype(en.cenum, en.tenum); + + if(!typefd[en.cenum->etype]) + en.lastenum = n->vconst; + else + en.floatenum = n->fconst; + } + if(dclstack) + push1(s); + xdecl(CXXX, types[TENUM], s); + + if(en.cenum == T) { + en.tenum = types[TINT]; + en.cenum = types[TINT]; + en.lastenum = 0; + } + s->tenum = en.cenum; + + if(!typefd[s->tenum->etype]) { + s->vconst = convvtox(en.lastenum, s->tenum->etype); + en.lastenum++; + } else { + s->fconst = en.floatenum; + en.floatenum++; + } + + if(debug['d']) + dbgdecl(s); + acidvar(s); +} + +void +symadjust(Sym *s, Node *n, long del) +{ + + switch(n->op) { + default: + if(n->left) + symadjust(s, n->left, del); + if(n->right) + symadjust(s, n->right, del); + return; + + case ONAME: + if(n->sym == s) + n->xoffset -= del; + return; + + case OCONST: + case OSTRING: + case OLSTRING: + case OINDREG: + case OREGISTER: + return; + } +} + +Node* +contig(Sym *s, Node *n, long v) +{ + Node *p, *r, *q, *m; + long w; + Type *zt; + + if(debug['i']) { + print("contig v = %ld; s = %s\n", v, s->name); + prtree(n, "doinit value"); + } + + if(n == Z) + goto no; + w = s->type->width; + + /* + * nightmare: an automatic array whose size + * increases when it is initialized + */ + if(v != w) { + if(v != 0) + diag(n, "automatic adjustable array: %s", s->name); + v = s->offset; + autoffset = align(autoffset, s->type, Aaut3); + s->offset = -autoffset; + stkoff = maxround(stkoff, autoffset); + symadjust(s, n, v - s->offset); + } + if(w <= ewidth[TIND]) + goto no; + if(n->op == OAS) + diag(Z, "oops in contig"); +/*ZZZ this appears incorrect +need to check if the list completely covers the data. +if not, bail + */ + if(n->op == OLIST) + goto no; + if(n->op == OASI) + if(n->left->type) + if(n->left->type->width == w) + goto no; + while(w & (ewidth[TIND]-1)) + w++; +/* + * insert the following code, where long becomes vlong if pointers are fat + * + *(long**)&X = (long*)((char*)X + sizeof(X)); + do { + *(long**)&X -= 1; + **(long**)&X = 0; + } while(*(long**)&X); + */ + + for(q=n; q->op != ONAME; q=q->left) + ; + + zt = ewidth[TIND] > ewidth[TLONG]? types[TVLONG]: types[TLONG]; + + p = new(ONAME, Z, Z); + *p = *q; + p->type = typ(TIND, zt); + p->xoffset = s->offset; + + r = new(ONAME, Z, Z); + *r = *p; + r = new(OPOSTDEC, r, Z); + + q = new(ONAME, Z, Z); + *q = *p; + q = new(OIND, q, Z); + + m = new(OCONST, Z, Z); + m->vconst = 0; + m->type = zt; + + q = new(OAS, q, m); + + r = new(OLIST, r, q); + + q = new(ONAME, Z, Z); + *q = *p; + r = new(ODWHILE, q, r); + + q = new(ONAME, Z, Z); + *q = *p; + q->type = q->type->link; + q->xoffset += w; + q = new(OADDR, q, 0); + + q = new(OASI, p, q); + r = new(OLIST, q, r); + + n = new(OLIST, r, n); + +no: + return n; +} diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c new file mode 100644 index 0000000000..6a8193435e --- /dev/null +++ b/src/cmd/cc/dpchk.c @@ -0,0 +1,524 @@ +// Inferno utils/cc/dpchk.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/dpchk.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" +#include "y.tab.h" + +enum +{ + Fnone = 0, + Fl, + Fvl, + Fignor, + Fstar, + Fadj, + + Fverb = 10, +}; + +typedef struct Tprot Tprot; +struct Tprot +{ + Type* type; + Bits flag; + Tprot* link; +}; + +typedef struct Tname Tname; +struct Tname +{ + char* name; + int param; + Tname* link; +}; + +static Type* indchar; +static uchar flagbits[512]; +static char fmtbuf[100]; +static int lastadj; +static int lastverb; +static int nstar; +static Tprot* tprot; +static Tname* tname; + +void +argflag(int c, int v) +{ + + switch(v) { + case Fignor: + case Fstar: + case Fl: + case Fvl: + flagbits[c] = v; + break; + case Fverb: + flagbits[c] = lastverb; +/*print("flag-v %c %d\n", c, lastadj);*/ + lastverb++; + break; + case Fadj: + flagbits[c] = lastadj; +/*print("flag-l %c %d\n", c, lastadj);*/ + lastadj++; + break; + } +} + +Bits +getflag(char *s) +{ + Bits flag; + int f; + char *fmt; + Rune c; + + fmt = fmtbuf; + flag = zbits; + nstar = 0; + for(;;) { + s += chartorune(&c, s); + if(c == 0 || c >= nelem(flagbits)) + break; + fmt += runetochar(fmt, &c); + f = flagbits[c]; + switch(f) { + case Fnone: + argflag(c, Fverb); + f = flagbits[c]; + break; + case Fstar: + nstar++; + case Fignor: + continue; + case Fl: + if(bset(flag, Fl)) + flag = bor(flag, blsh(Fvl)); + } + flag = bor(flag, blsh(f)); + if(f >= Fverb) + break; + } + *fmt = 0; + return flag; +} + +void +newprot(Sym *m, Type *t, char *s) +{ + Bits flag; + Tprot *l; + + if(t == T) { + warn(Z, "%s: newprot: type not defined", m->name); + return; + } + flag = getflag(s); + for(l=tprot; l; l=l->link) + if(beq(flag, l->flag) && sametype(t, l->type)) + return; + l = alloc(sizeof(*l)); + l->type = t; + l->flag = flag; + l->link = tprot; + tprot = l; +} + +void +newname(char *s, int p) +{ + Tname *l; + + for(l=tname; l; l=l->link) + if(strcmp(l->name, s) == 0) { + if(l->param != p) + yyerror("vargck %s already defined\n", s); + return; + } + l = alloc(sizeof(*l)); + l->name = s; + l->param = p; + l->link = tname; + tname = l; +} + +void +arginit(void) +{ + int i; + +/* debug['F'] = 1;*/ +/* debug['w'] = 1;*/ + + lastadj = Fadj; + lastverb = Fverb; + indchar = typ(TIND, types[TCHAR]); + + memset(flagbits, Fnone, sizeof(flagbits)); + + for(i='0'; i<='9'; i++) + argflag(i, Fignor); + argflag('.', Fignor); + argflag('#', Fignor); + argflag('u', Fignor); + argflag('h', Fignor); + argflag('+', Fignor); + argflag('-', Fignor); + + argflag('*', Fstar); + argflag('l', Fl); + + argflag('o', Fverb); + flagbits['x'] = flagbits['o']; + flagbits['X'] = flagbits['o']; +} + +void +pragvararg(void) +{ + Sym *s; + int n, c; + char *t; + Rune r; + Type *ty; + + if(!debug['F']) + goto out; + s = getsym(); + if(s && strcmp(s->name, "argpos") == 0) + goto ckpos; + if(s && strcmp(s->name, "type") == 0) + goto cktype; + if(s && strcmp(s->name, "flag") == 0) + goto ckflag; + yyerror("syntax in #pragma varargck"); + goto out; + +ckpos: +/*#pragma varargck argpos warn 2*/ + s = getsym(); + if(s == S) + goto bad; + n = getnsn(); + if(n < 0) + goto bad; + newname(s->name, n); + goto out; + +ckflag: +/*#pragma varargck flag 'c'*/ + c = getnsc(); + if(c != '\'') + goto bad; + c = getr(); + if(c == '\\') + c = getr(); + else if(c == '\'') + goto bad; + if(c == '\n') + goto bad; + if(getc() != '\'') + goto bad; + argflag(c, Fignor); + goto out; + +cktype: +/*#pragma varargck type O int*/ + c = getnsc(); + if(c != '"') + goto bad; + t = fmtbuf; + for(;;) { + r = getr(); + if(r == ' ' || r == '\n') + goto bad; + if(r == '"') + break; + t += runetochar(t, &r); + } + *t = 0; + t = strdup(fmtbuf); + s = getsym(); + if(s == S) + goto bad; + ty = s->type; + while((c = getnsc()) == '*') + ty = typ(TIND, ty); + unget(c); + newprot(s, ty, t); + goto out; + +bad: + yyerror("syntax in #pragma varargck"); + +out: + while(getnsc() != '\n') + ; +} + +Node* +nextarg(Node *n, Node **a) +{ + if(n == Z) { + *a = Z; + return Z; + } + if(n->op == OLIST) { + *a = n->left; + return n->right; + } + *a = n; + return Z; +} + +void +checkargs(Node *nn, char *s, int pos) +{ + Node *a, *n; + Bits flag; + Tprot *l; + + if(!debug['F']) + return; + n = nn; + for(;;) { + s = strchr(s, '%'); + if(s == 0) { + nextarg(n, &a); + if(a != Z) + warn(nn, "more arguments than format %T", + a->type); + return; + } + s++; + flag = getflag(s); + while(nstar > 0) { + n = nextarg(n, &a); + pos++; + nstar--; + if(a == Z) { + warn(nn, "more format than arguments %s", + fmtbuf); + return; + } + if(a->type == T) + continue; + if(!sametype(types[TINT], a->type) && + !sametype(types[TUINT], a->type)) + warn(nn, "format mismatch '*' in %s %T, arg %d", + fmtbuf, a->type, pos); + } + for(l=tprot; l; l=l->link) + if(sametype(types[TVOID], l->type)) { + if(beq(flag, l->flag)) { + s++; + goto loop; + } + } + + n = nextarg(n, &a); + pos++; + if(a == Z) { + warn(nn, "more format than arguments %s", + fmtbuf); + return; + } + if(a->type == 0) + continue; + for(l=tprot; l; l=l->link) + if(sametype(a->type, l->type)) { +/*print("checking %T/%ulx %T/%ulx\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/ + if(beq(flag, l->flag)) + goto loop; + } + warn(nn, "format mismatch %s %T, arg %d", fmtbuf, a->type, pos); + loop:; + } +} + +void +dpcheck(Node *n) +{ + char *s; + Node *a, *b; + Tname *l; + int i; + + if(n == Z) + return; + b = n->left; + if(b == Z || b->op != ONAME) + return; + s = b->sym->name; + for(l=tname; l; l=l->link) + if(strcmp(s, l->name) == 0) + break; + if(l == 0) + return; + + i = l->param; + b = n->right; + while(i > 0) { + b = nextarg(b, &a); + i--; + } + if(a == Z) { + warn(n, "cant find format arg"); + return; + } + if(!sametype(indchar, a->type)) { + warn(n, "format arg type %T", a->type); + return; + } + if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) { +/* warn(n, "format arg not constant string");*/ + return; + } + s = a->left->cstring; + checkargs(b, s, l->param); +} + +void +pragpack(void) +{ + Sym *s; + + packflg = 0; + s = getsym(); + if(s) { + packflg = atoi(s->name+1); + if(strcmp(s->name, "on") == 0 || + strcmp(s->name, "yes") == 0) + packflg = 1; + } + while(getnsc() != '\n') + ; + if(debug['f']) + if(packflg) + print("%4ld: pack %d\n", lineno, packflg); + else + print("%4ld: pack off\n", lineno); +} + +void +pragfpround(void) +{ + Sym *s; + + fproundflg = 0; + s = getsym(); + if(s) { + fproundflg = atoi(s->name+1); + if(strcmp(s->name, "on") == 0 || + strcmp(s->name, "yes") == 0) + fproundflg = 1; + } + while(getnsc() != '\n') + ; + if(debug['f']) + if(fproundflg) + print("%4ld: fproundflg %d\n", lineno, fproundflg); + else + print("%4ld: fproundflg off\n", lineno); +} + +void +pragprofile(void) +{ + Sym *s; + + profileflg = 0; + s = getsym(); + if(s) { + profileflg = atoi(s->name+1); + if(strcmp(s->name, "on") == 0 || + strcmp(s->name, "yes") == 0) + profileflg = 1; + } + while(getnsc() != '\n') + ; + if(debug['f']) + if(profileflg) + print("%4ld: profileflg %d\n", lineno, profileflg); + else + print("%4ld: profileflg off\n", lineno); +} + +void +pragincomplete(void) +{ + Sym *s; + Type *t; + int istag, w, et; + + istag = 0; + s = getsym(); + if(s == nil) + goto out; + et = 0; + w = s->lexical; + if(w == LSTRUCT) + et = TSTRUCT; + else if(w == LUNION) + et = TUNION; + if(et != 0){ + s = getsym(); + if(s == nil){ + yyerror("missing struct/union tag in pragma incomplete"); + goto out; + } + if(s->lexical != LNAME && s->lexical != LTYPE){ + yyerror("invalid struct/union tag: %s", s->name); + goto out; + } + dotag(s, et, 0); + istag = 1; + }else if(strcmp(s->name, "_off_") == 0){ + debug['T'] = 0; + goto out; + }else if(strcmp(s->name, "_on_") == 0){ + debug['T'] = 1; + goto out; + } + t = s->type; + if(istag) + t = s->suetag; + if(t == T) + yyerror("unknown type %s in pragma incomplete", s->name); + else if(!typesu[t->etype]) + yyerror("not struct/union type in pragma incomplete: %s", s->name); + else + t->garb |= GINCOMPLETE; +out: + while(getnsc() != '\n') + ; + if(debug['f']) + print("%s incomplete\n", s->name); +} diff --git a/src/cmd/cc/funct.c b/src/cmd/cc/funct.c new file mode 100644 index 0000000000..21d86258ff --- /dev/null +++ b/src/cmd/cc/funct.c @@ -0,0 +1,430 @@ +// Inferno utils/cc/funct.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/funct.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +typedef struct Ftab Ftab; +struct Ftab +{ + char op; + char* name; + char typ; +}; +typedef struct Gtab Gtab; +struct Gtab +{ + char etype; + char* name; +}; + +Ftab ftabinit[OEND]; +Gtab gtabinit[NTYPE]; + +int +isfunct(Node *n) +{ + Type *t, *t1; + Funct *f; + Node *l; + Sym *s; + int o; + + o = n->op; + if(n->left == Z) + goto no; + t = n->left->type; + if(t == T) + goto no; + f = t->funct; + + switch(o) { + case OAS: // put cast on rhs + case OASI: + case OASADD: + case OASAND: + case OASASHL: + case OASASHR: + case OASDIV: + case OASLDIV: + case OASLMOD: + case OASLMUL: + case OASLSHR: + case OASMOD: + case OASMUL: + case OASOR: + case OASSUB: + case OASXOR: + if(n->right == Z) + goto no; + t1 = n->right->type; + if(t1 == T) + goto no; + if(t1->funct == f) + break; + + l = new(OXXX, Z, Z); + *l = *n->right; + + n->right->left = l; + n->right->right = Z; + n->right->type = t; + n->right->op = OCAST; + + if(!isfunct(n->right)) + prtree(n, "isfunc !"); + break; + + case OCAST: // t f(T) or T f(t) + t1 = n->type; + if(t1 == T) + goto no; + if(f != nil) { + s = f->castfr[t1->etype]; + if(s == S) + goto no; + n->right = n->left; + goto build; + } + f = t1->funct; + if(f != nil) { + s = f->castto[t->etype]; + if(s == S) + goto no; + n->right = n->left; + goto build; + } + goto no; + } + + if(f == nil) + goto no; + s = f->sym[o]; + if(s == S) + goto no; + + /* + * the answer is yes, + * now we rewrite the node + * and give diagnostics + */ + switch(o) { + default: + diag(n, "isfunct op missing %O\n", o); + goto bad; + + case OADD: // T f(T, T) + case OAND: + case OASHL: + case OASHR: + case ODIV: + case OLDIV: + case OLMOD: + case OLMUL: + case OLSHR: + case OMOD: + case OMUL: + case OOR: + case OSUB: + case OXOR: + + case OEQ: // int f(T, T) + case OGE: + case OGT: + case OHI: + case OHS: + case OLE: + case OLO: + case OLS: + case OLT: + case ONE: + if(n->right == Z) + goto bad; + t1 = n->right->type; + if(t1 == T) + goto bad; + if(t1->funct != f) + goto bad; + n->right = new(OLIST, n->left, n->right); + break; + + case OAS: // structure copies done by the compiler + case OASI: + goto no; + + case OASADD: // T f(T*, T) + case OASAND: + case OASASHL: + case OASASHR: + case OASDIV: + case OASLDIV: + case OASLMOD: + case OASLMUL: + case OASLSHR: + case OASMOD: + case OASMUL: + case OASOR: + case OASSUB: + case OASXOR: + if(n->right == Z) + goto bad; + t1 = n->right->type; + if(t1 == T) + goto bad; + if(t1->funct != f) + goto bad; + n->right = new(OLIST, new(OADDR, n->left, Z), n->right); + break; + + case OPOS: // T f(T) + case ONEG: + case ONOT: + case OCOM: + n->right = n->left; + break; + + + } + +build: + l = new(ONAME, Z, Z); + l->sym = s; + l->type = s->type; + l->etype = s->type->etype; + l->xoffset = s->offset; + l->class = s->class; + tcomo(l, 0); + + n->op = OFUNC; + n->left = l; + n->type = l->type->link; + if(tcompat(n, T, l->type, tfunct)) + goto bad; + if(tcoma(n->left, n->right, l->type->down, 1)) + goto bad; + return 1; + +no: + return 0; + +bad: + diag(n, "cant rewrite typestr for op %O\n", o); + prtree(n, "isfunct"); + n->type = T; + return 1; +} + +void +dclfunct(Type *t, Sym *s) +{ + Funct *f; + Node *n; + Type *f1, *f2, *f3, *f4; + int o, i, c; + char str[100]; + + if(t->funct) + return; + + // recognize generated tag of dorm _%d_ + if(t->tag == S) + goto bad; + for(i=0; c = t->tag->name[i]; i++) { + if(c == '_') { + if(i == 0 || t->tag->name[i+1] == 0) + continue; + break; + } + if(c < '0' || c > '9') + break; + } + if(c == 0) + goto bad; + + f = alloc(sizeof(*f)); + for(o=0; osym); o++) + f->sym[o] = S; + + t->funct = f; + + f1 = typ(TFUNC, t); + f1->down = copytyp(t); + f1->down->down = t; + + f2 = typ(TFUNC, types[TINT]); + f2->down = copytyp(t); + f2->down->down = t; + + f3 = typ(TFUNC, t); + f3->down = typ(TIND, t); + f3->down->down = t; + + f4 = typ(TFUNC, t); + f4->down = t; + + for(i=0;; i++) { + o = ftabinit[i].op; + if(o == OXXX) + break; + sprint(str, "%s_%s_", t->tag->name, ftabinit[i].name); + n = new(ONAME, Z, Z); + n->sym = slookup(str); + f->sym[o] = n->sym; + switch(ftabinit[i].typ) { + default: + diag(Z, "dclfunct op missing %d\n", ftabinit[i].typ); + break; + + case 1: // T f(T,T) + + dodecl(xdecl, CEXTERN, f1, n); + break; + + case 2: // int f(T,T) == + dodecl(xdecl, CEXTERN, f2, n); + break; + + case 3: // void f(T*,T) += + dodecl(xdecl, CEXTERN, f3, n); + break; + + case 4: // T f(T) ~ + dodecl(xdecl, CEXTERN, f4, n); + break; + } + } + for(i=0;; i++) { + o = gtabinit[i].etype; + if(o == TXXX) + break; + + /* + * OCAST types T1 _T2_T1_(T2) + */ + sprint(str, "_%s%s_", gtabinit[i].name, t->tag->name); + n = new(ONAME, Z, Z); + n->sym = slookup(str); + f->castto[o] = n->sym; + + f1 = typ(TFUNC, t); + f1->down = types[o]; + dodecl(xdecl, CEXTERN, f1, n); + + sprint(str, "%s_%s_", t->tag->name, gtabinit[i].name); + n = new(ONAME, Z, Z); + n->sym = slookup(str); + f->castfr[o] = n->sym; + + f1 = typ(TFUNC, types[o]); + f1->down = t; + dodecl(xdecl, CEXTERN, f1, n); + } + return; +bad: + diag(Z, "dclfunct bad %T %s\n", t, s->name); +} + +Gtab gtabinit[NTYPE] = +{ + TCHAR, "c", + TUCHAR, "uc", + TSHORT, "h", + TUSHORT, "uh", + TINT, "i", + TUINT, "ui", + TLONG, "l", + TULONG, "ul", + TVLONG, "v", + TUVLONG, "uv", + TFLOAT, "f", + TDOUBLE, "d", + TXXX +}; + +Ftab ftabinit[OEND] = +{ + OADD, "add", 1, + OAND, "and", 1, + OASHL, "ashl", 1, + OASHR, "ashr", 1, + ODIV, "div", 1, + OLDIV, "ldiv", 1, + OLMOD, "lmod", 1, + OLMUL, "lmul", 1, + OLSHR, "lshr", 1, + OMOD, "mod", 1, + OMUL, "mul", 1, + OOR, "or", 1, + OSUB, "sub", 1, + OXOR, "xor", 1, + + OEQ, "eq", 2, + OGE, "ge", 2, + OGT, "gt", 2, + OHI, "hi", 2, + OHS, "hs", 2, + OLE, "le", 2, + OLO, "lo", 2, + OLS, "ls", 2, + OLT, "lt", 2, + ONE, "ne", 2, + + OASADD, "asadd", 3, + OASAND, "asand", 3, + OASASHL, "asashl", 3, + OASASHR, "asashr", 3, + OASDIV, "asdiv", 3, + OASLDIV, "asldiv", 3, + OASLMOD, "aslmod", 3, + OASLMUL, "aslmul", 3, + OASLSHR, "aslshr", 3, + OASMOD, "asmod", 3, + OASMUL, "asmul", 3, + OASOR, "asor", 3, + OASSUB, "assub", 3, + OASXOR, "asxor", 3, + + OPOS, "pos", 4, + ONEG, "neg", 4, + OCOM, "com", 4, + ONOT, "not", 4, + +// OPOSTDEC, +// OPOSTINC, +// OPREDEC, +// OPREINC, + + OXXX, +}; + +// Node* nodtestv; + +// Node* nodvpp; +// Node* nodppv; +// Node* nodvmm; +// Node* nodmmv; diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c new file mode 100644 index 0000000000..e3a8e440d8 --- /dev/null +++ b/src/cmd/cc/lex.c @@ -0,0 +1,1542 @@ +// Inferno utils/cc/lex.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/lex.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" +#include "y.tab.h" + +#ifndef CPP +#define CPP "/bin/cpp" +#endif + +/* + * known debug flags + * -a acid declaration output + * -A !B + * -B non ANSI + * -d print declarations + * -D name define + * -F format specification check + * -i print initialization + * -I path include + * -l generate little-endian code + * -L print every NAME symbol + * -M constant multiplication + * -m print add/sub/mul trees + * -n print acid to file (%.c=%.acid) (with -a or -aa) + * -o file output file + * -p use standard cpp ANSI preprocessor (not on windows) + * -r print registerization + * -s print structure offsets (with -a or -aa) + * -S print assembly + * -t print type trees + * -V enable void* conversion warnings + * -v verbose printing + * -w print warnings + * -X abort on error + * -. Inhibit search for includes in source directory + */ + +void +main(int argc, char *argv[]) +{ + char *defs[50], *p; + int nproc, nout, status, i, c, ndef; + + memset(debug, 0, sizeof(debug)); + tinit(); + cinit(); + ginit(); + arginit(); + + profileflg = 1; /* #pragma can turn it off */ + tufield = simplet((1L<etype) | BUNSIGNED); + ndef = 0; + outfile = 0; + include[ninclude++] = "."; + ARGBEGIN { + default: + c = ARGC(); + if(c >= 0 && c < sizeof(debug)) + debug[c]++; + break; + + case 'l': /* for little-endian mips */ + if(thechar != 'v'){ + print("can only use -l with vc"); + errorexit(); + } + thechar = '0'; + thestring = "spim"; + break; + + case 'o': + outfile = ARGF(); + break; + + case 'D': + p = ARGF(); + if(p) { + defs[ndef++] = p; + dodefine(p); + } + break; + + case 'I': + p = ARGF(); + setinclude(p); + break; + } ARGEND + if(argc < 1 && outfile == 0) { + print("usage: %cc [-options] files\n", thechar); + errorexit(); + } + if(argc > 1 && systemtype(Windows)){ + print("can't compile multiple files on windows\n"); + errorexit(); + } + if(argc > 1 && !systemtype(Windows)) { + nproc = 1; + /* + * if we're writing acid to standard output, don't compile + * concurrently, to avoid interleaving output. + */ + if(((!debug['a'] && !debug['Z']) || debug['n']) && + (p = getenv("NPROC")) != nil) + nproc = atol(p); /* */ + c = 0; + nout = 0; + for(;;) { + while(nout < nproc && argc > 0) { + i = myfork(); + if(i < 0) { + i = mywait(&status); + if(i < 0) { + print("cannot create a process\n"); + errorexit(); + } + if(status) + c++; + nout--; + continue; + } + if(i == 0) { + fprint(2, "%s:\n", *argv); + if (compile(*argv, defs, ndef)) + errorexit(); + exits(0); + } + nout++; + argc--; + argv++; + } + i = mywait(&status); + if(i < 0) { + if(c) + errorexit(); + exits(0); + } + if(status) + c++; + nout--; + } + } + + if(argc == 0) + c = compile("stdin", defs, ndef); + else + c = compile(argv[0], defs, ndef); + + if(c) + errorexit(); + exits(0); +} + +int +compile(char *file, char **defs, int ndef) +{ + char ofile[400], incfile[20]; + char *p, *av[100], opt[256]; + int i, c, fd[2]; + static int first = 1; + + strcpy(ofile, file); + p = utfrrune(ofile, pathchar()); + if(p) { + *p++ = 0; + if(!debug['.']) + include[0] = strdup(ofile); + } else + p = ofile; + + if(outfile == 0) { + outfile = p; + if(outfile) { + if(p = utfrrune(outfile, '.')) + if(p[1] == 'c' && p[2] == 0) + p[0] = 0; + p = utfrune(outfile, 0); + if(debug['a'] && debug['n']) + strcat(p, ".acid"); + else if(debug['Z'] && debug['n']) + strcat(p, "_pickle.c"); + else { + p[0] = '.'; + p[1] = thechar; + p[2] = 0; + } + } else + outfile = "/dev/null"; + } + + if(p = getenv("INCLUDE")) { + setinclude(p); + } else { + if(systemtype(Plan9)) { + sprint(incfile, "/%s/include", thestring); + setinclude(strdup(incfile)); + setinclude("/sys/include"); + } + } + if (first) + Binit(&diagbuf, 1, OWRITE); + /* + * if we're writing acid to standard output, don't keep scratching + * outbuf. + */ + if((debug['a'] || debug['Z']) && !debug['n']) { + if (first) { + outfile = 0; + Binit(&outbuf, dup(1, -1), OWRITE); + dup(2, 1); + } + } else { + c = mycreate(outfile, 0664); + if(c < 0) { + diag(Z, "cannot open %s - %r", outfile); + outfile = 0; + errorexit(); + } + Binit(&outbuf, c, OWRITE); + } + newio(); + first = 0; + + /* Use an ANSI preprocessor */ + if(debug['p']) { + if(systemtype(Windows)) { + diag(Z, "-p option not supported on windows"); + errorexit(); + } + if(myaccess(file) < 0) { + diag(Z, "%s does not exist", file); + errorexit(); + } + if(mypipe(fd) < 0) { + diag(Z, "pipe failed"); + errorexit(); + } + switch(myfork()) { + case -1: + diag(Z, "fork failed"); + errorexit(); + case 0: + close(fd[0]); + mydup(fd[1], 1); + close(fd[1]); + av[0] = CPP; + i = 1; + if(debug['.']){ + sprint(opt, "-."); + av[i++] = strdup(opt); + } + if(debug['+']) { + sprint(opt, "-+"); + av[i++] = strdup(opt); + } + for(c = 0; c < ndef; c++) { + sprint(opt, "-D%s", defs[c]); + av[i++] = strdup(opt); + } + for(c = 0; c < ninclude; c++) { + sprint(opt, "-I%s", include[c]); + av[i++] = strdup(opt); + } + if(strcmp(file, "stdin") != 0) + av[i++] = file; + av[i] = 0; + if(debug['p'] > 1) { + for(c = 0; c < i; c++) + fprint(2, "%s ", av[c]); + fprint(2, "\n"); + } + myexec(av[0], av); + fprint(2, "can't exec C preprocessor %s: %r\n", CPP); + errorexit(); + default: + close(fd[1]); + newfile(file, fd[0]); + break; + } + } else { + if(strcmp(file, "stdin") == 0) + newfile(file, 0); + else + newfile(file, -1); + } + yyparse(); + if(!debug['a'] && !debug['Z']) + gclean(); + return nerrors; +} + +void +errorexit(void) +{ + if(outfile) + remove(outfile); + exits("error"); +} + +void +pushio(void) +{ + Io *i; + + i = iostack; + if(i == I) { + yyerror("botch in pushio"); + errorexit(); + } + i->p = fi.p; + i->c = fi.c; +} + +void +newio(void) +{ + Io *i; + static int pushdepth = 0; + + i = iofree; + if(i == I) { + pushdepth++; + if(pushdepth > 1000) { + yyerror("macro/io expansion too deep"); + errorexit(); + } + i = alloc(sizeof(*i)); + } else + iofree = i->link; + i->c = 0; + i->f = -1; + ionext = i; +} + +void +newfile(char *s, int f) +{ + Io *i; + + if(debug['e']) + print("%L: %s\n", lineno, s); + + i = ionext; + i->link = iostack; + iostack = i; + i->f = f; + if(f < 0) + i->f = open(s, 0); + if(i->f < 0) { + yyerror("%cc: %r: %s", thechar, s); + errorexit(); + } + fi.c = 0; + linehist(s, 0); +} + +Sym* +slookup(char *s) +{ + + strcpy(symb, s); + return lookup(); +} + +Sym* +lookup(void) +{ + Sym *s; + ulong h; + char *p; + int c, n; + + h = 0; + for(p=symb; *p;) { + h = h * 3; + h += *p++; + } + n = (p - symb) + 1; + if((long)h < 0) + h = ~h; + h %= NHASH; + c = symb[0]; + for(s = hash[h]; s != S; s = s->link) { + if(s->name[0] != c) + continue; + if(strcmp(s->name, symb) == 0) + return s; + } + s = alloc(sizeof(*s)); + s->name = alloc(n); + memmove(s->name, symb, n); + + strcpy(s->name, symb); + s->link = hash[h]; + hash[h] = s; + syminit(s); + + return s; +} + +void +syminit(Sym *s) +{ + s->lexical = LNAME; + s->block = 0; + s->offset = 0; + s->type = T; + s->suetag = T; + s->class = CXXX; + s->aused = 0; + s->sig = SIGNONE; +} + +#define EOF (-1) +#define IGN (-2) +#define ESC (1<<20) +#define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff)) + +enum +{ + Numdec = 1<<0, + Numlong = 1<<1, + Numuns = 1<<2, + Numvlong = 1<<3, + Numflt = 1<<4, +}; + +long +yylex(void) +{ + vlong vv; + long c, c1, t; + char *cp; + Rune rune; + Sym *s; + + if(peekc != IGN) { + c = peekc; + peekc = IGN; + goto l1; + } +l0: + c = GETC(); + +l1: + if(c >= Runeself) { + /* + * extension -- + * all multibyte runes are alpha + */ + cp = symb; + goto talph; + } + if(isspace(c)) { + if(c == '\n') + lineno++; + goto l0; + } + if(isalpha(c)) { + cp = symb; + if(c != 'L') + goto talph; + *cp++ = c; + c = GETC(); + if(c == '\'') { + /* L'x' */ + c = escchar('\'', 1, 0); + if(c == EOF) + c = '\''; + c1 = escchar('\'', 1, 0); + if(c1 != EOF) { + yyerror("missing '"); + peekc = c1; + } + yylval.vval = convvtox(c, TUSHORT); + return LUCONST; + } + if(c == '"') { + goto caselq; + } + goto talph; + } + if(isdigit(c)) + goto tnum; + switch(c) + { + + case EOF: + peekc = EOF; + return -1; + + case '_': + cp = symb; + goto talph; + + case '#': + domacro(); + goto l0; + + case '.': + c1 = GETC(); + if(isdigit(c1)) { + cp = symb; + *cp++ = c; + c = c1; + c1 = 0; + goto casedot; + } + break; + + case '"': + strcpy(symb, "\"\""); + cp = alloc(0); + c1 = 0; + + /* "..." */ + for(;;) { + c = escchar('"', 0, 1); + if(c == EOF) + break; + if(c & ESC) { + cp = allocn(cp, c1, 1); + cp[c1++] = c; + } else { + rune = c; + c = runelen(rune); + cp = allocn(cp, c1, c); + runetochar(cp+c1, &rune); + c1 += c; + } + } + yylval.sval.l = c1; + do { + cp = allocn(cp, c1, 1); + cp[c1++] = 0; + } while(c1 & MAXALIGN); + yylval.sval.s = cp; + return LSTRING; + + caselq: + /* L"..." */ + strcpy(symb, "\"L\""); + cp = alloc(0); + c1 = 0; + for(;;) { + c = escchar('"', 1, 0); + if(c == EOF) + break; + cp = allocn(cp, c1, sizeof(ushort)); + *(ushort*)(cp + c1) = c; + c1 += sizeof(ushort); + } + yylval.sval.l = c1; + do { + cp = allocn(cp, c1, sizeof(ushort)); + *(ushort*)(cp + c1) = 0; + c1 += sizeof(ushort); + } while(c1 & MAXALIGN); + yylval.sval.s = cp; + return LLSTRING; + + case '\'': + /* '.' */ + c = escchar('\'', 0, 0); + if(c == EOF) + c = '\''; + c1 = escchar('\'', 0, 0); + if(c1 != EOF) { + yyerror("missing '"); + peekc = c1; + } + vv = c; + yylval.vval = convvtox(vv, TUCHAR); + if(yylval.vval != vv) + yyerror("overflow in character constant: 0x%lx", c); + else + if(c & 0x80){ + nearln = lineno; + warn(Z, "sign-extended character constant"); + } + yylval.vval = convvtox(vv, TCHAR); + return LCONST; + + case '/': + c1 = GETC(); + if(c1 == '*') { + for(;;) { + c = getr(); + while(c == '*') { + c = getr(); + if(c == '/') + goto l0; + } + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + } + } + if(c1 == '/') { + for(;;) { + c = getr(); + if(c == '\n') + goto l0; + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + } + } + if(c1 == '=') + return LDVE; + break; + + case '*': + c1 = GETC(); + if(c1 == '=') + return LMLE; + break; + + case '%': + c1 = GETC(); + if(c1 == '=') + return LMDE; + break; + + case '+': + c1 = GETC(); + if(c1 == '+') + return LPP; + if(c1 == '=') + return LPE; + break; + + case '-': + c1 = GETC(); + if(c1 == '-') + return LMM; + if(c1 == '=') + return LME; + if(c1 == '>') + return LMG; + break; + + case '>': + c1 = GETC(); + if(c1 == '>') { + c = LRSH; + c1 = GETC(); + if(c1 == '=') + return LRSHE; + break; + } + if(c1 == '=') + return LGE; + break; + + case '<': + c1 = GETC(); + if(c1 == '<') { + c = LLSH; + c1 = GETC(); + if(c1 == '=') + return LLSHE; + break; + } + if(c1 == '=') + return LLE; + break; + + case '=': + c1 = GETC(); + if(c1 == '=') + return LEQ; + break; + + case '!': + c1 = GETC(); + if(c1 == '=') + return LNE; + break; + + case '&': + c1 = GETC(); + if(c1 == '&') + return LANDAND; + if(c1 == '=') + return LANDE; + break; + + case '|': + c1 = GETC(); + if(c1 == '|') + return LOROR; + if(c1 == '=') + return LORE; + break; + + case '^': + c1 = GETC(); + if(c1 == '=') + return LXORE; + break; + + default: + return c; + } + peekc = c1; + return c; + +talph: + /* + * cp is set to symb and some + * prefix has been stored + */ + for(;;) { + if(c >= Runeself) { + for(c1=0;;) { + cp[c1++] = c; + if(fullrune(cp, c1)) + break; + c = GETC(); + } + cp += c1; + c = GETC(); + continue; + } + if(!isalnum(c) && c != '_') + break; + *cp++ = c; + c = GETC(); + } + *cp = 0; + if(debug['L']) + print("%L: %s\n", lineno, symb); + peekc = c; + s = lookup(); + if(s->macro) { + newio(); + cp = ionext->b; + macexpand(s, cp); + pushio(); + ionext->link = iostack; + iostack = ionext; + fi.p = cp; + fi.c = strlen(cp); + if(peekc != IGN) { + cp[fi.c++] = peekc; + cp[fi.c] = 0; + peekc = IGN; + } + goto l0; + } + yylval.sym = s; + if(s->class == CTYPEDEF || s->class == CTYPESTR) + return LTYPE; + return s->lexical; + +tnum: + c1 = 0; + cp = symb; + if(c != '0') { + c1 |= Numdec; + for(;;) { + *cp++ = c; + c = GETC(); + if(isdigit(c)) + continue; + goto dc; + } + } + *cp++ = c; + c = GETC(); + if(c == 'x' || c == 'X') + for(;;) { + *cp++ = c; + c = GETC(); + if(isdigit(c)) + continue; + if(c >= 'a' && c <= 'f') + continue; + if(c >= 'A' && c <= 'F') + continue; + if(cp == symb+2) + yyerror("malformed hex constant"); + goto ncu; + } + if(c < '0' || c > '7') + goto dc; + for(;;) { + if(c >= '0' && c <= '7') { + *cp++ = c; + c = GETC(); + continue; + } + goto ncu; + } + +dc: + if(c == '.') + goto casedot; + if(c == 'e' || c == 'E') + goto casee; + +ncu: + if((c == 'U' || c == 'u') && !(c1 & Numuns)) { + c = GETC(); + c1 |= Numuns; + goto ncu; + } + if((c == 'L' || c == 'l') && !(c1 & Numvlong)) { + c = GETC(); + if(c1 & Numlong) + c1 |= Numvlong; + c1 |= Numlong; + goto ncu; + } + *cp = 0; + peekc = c; + if(mpatov(symb, &yylval.vval)) + yyerror("overflow in constant"); + + vv = yylval.vval; + if(c1 & Numvlong) { + if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) { + c = LUVLCONST; + t = TUVLONG; + goto nret; + } + c = LVLCONST; + t = TVLONG; + goto nret; + } + if(c1 & Numlong) { + if((c1 & Numuns) || convvtox(vv, TLONG) < 0) { + c = LULCONST; + t = TULONG; + goto nret; + } + c = LLCONST; + t = TLONG; + goto nret; + } + if((c1 & Numuns) || convvtox(vv, TINT) < 0) { + c = LUCONST; + t = TUINT; + goto nret; + } + c = LCONST; + t = TINT; + goto nret; + +nret: + yylval.vval = convvtox(vv, t); + if(yylval.vval != vv){ + nearln = lineno; + warn(Z, "truncated constant: %T %s", types[t], symb); + } + return c; + +casedot: + for(;;) { + *cp++ = c; + c = GETC(); + if(!isdigit(c)) + break; + } + if(c != 'e' && c != 'E') + goto caseout; + +casee: + *cp++ = 'e'; + c = GETC(); + if(c == '+' || c == '-') { + *cp++ = c; + c = GETC(); + } + if(!isdigit(c)) + yyerror("malformed fp constant exponent"); + while(isdigit(c)) { + *cp++ = c; + c = GETC(); + } + +caseout: + if(c == 'L' || c == 'l') { + c = GETC(); + c1 |= Numlong; + } else + if(c == 'F' || c == 'f') { + c = GETC(); + c1 |= Numflt; + } + *cp = 0; + peekc = c; + yylval.dval = strtod(symb, nil); + if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) { + yyerror("overflow in float constant"); + yylval.dval = 0; + } + if(c1 & Numflt) + return LFCONST; + return LDCONST; +} + +/* + * convert a string, s, to vlong in *v + * return conversion overflow. + * required syntax is [0[x]]d* + */ +int +mpatov(char *s, vlong *v) +{ + vlong n, nn; + int c; + + n = 0; + c = *s; + if(c == '0') + goto oct; + while(c = *s++) { + if(c >= '0' && c <= '9') + nn = n*10 + c-'0'; + else + goto bad; + if(n < 0 && nn >= 0) + goto bad; + n = nn; + } + goto out; + +oct: + s++; + c = *s; + if(c == 'x' || c == 'X') + goto hex; + while(c = *s++) { + if(c >= '0' || c <= '7') + nn = n*8 + c-'0'; + else + goto bad; + if(n < 0 && nn >= 0) + goto bad; + n = nn; + } + goto out; + +hex: + s++; + while(c = *s++) { + if(c >= '0' && c <= '9') + c += 0-'0'; + else + if(c >= 'a' && c <= 'f') + c += 10-'a'; + else + if(c >= 'A' && c <= 'F') + c += 10-'A'; + else + goto bad; + nn = n*16 + c; + if(n < 0 && nn >= 0) + goto bad; + n = nn; + } +out: + *v = n; + return 0; + +bad: + *v = ~0; + return 1; +} + +int +getc(void) +{ + int c; + + if(peekc != IGN) { + c = peekc; + peekc = IGN; + } else + c = GETC(); + if(c == '\n') + lineno++; + if(c == EOF) { + yyerror("End of file"); + errorexit(); + } + return c; +} + +long +getr(void) +{ + int c, i; + char str[UTFmax+1]; + Rune rune; + + + c = getc(); + if(c < Runeself) + return c; + i = 0; + str[i++] = c; + +loop: + c = getc(); + str[i++] = c; + if(!fullrune(str, i)) + goto loop; + c = chartorune(&rune, str); + if(rune == Runeerror && c == 1) { + nearln = lineno; + diag(Z, "illegal rune in string"); + for(c=0; c0; i--) { + c = getc(); + if(c >= '0' && c <= '9') { + l = l*16 + c-'0'; + continue; + } + if(c >= 'a' && c <= 'f') { + l = l*16 + c-'a' + 10; + continue; + } + if(c >= 'A' && c <= 'F') { + l = l*16 + c-'A' + 10; + continue; + } + unget(c); + break; + } + if(escflg) + l |= ESC; + return l; + } + if(c >= '0' && c <= '7') { + /* + * note this is not ansi, + * supposed to only accept 3 oct + */ + i = 2; + if(longflg) + i = 5; + l = c - '0'; + for(; i>0; i--) { + c = getc(); + if(c >= '0' && c <= '7') { + l = l*8 + c-'0'; + continue; + } + unget(c); + } + if(escflg) + l |= ESC; + return l; + } + switch(c) + { + case '\n': goto loop; + case 'n': return '\n'; + case 't': return '\t'; + case 'b': return '\b'; + case 'r': return '\r'; + case 'f': return '\f'; + case 'a': return '\a'; + case 'v': return '\v'; + } + return c; +} + +struct +{ + char *name; + ushort lexical; + ushort type; +} itab[] = +{ + "auto", LAUTO, 0, + "break", LBREAK, 0, + "case", LCASE, 0, + "char", LCHAR, TCHAR, + "const", LCONSTNT, 0, + "continue", LCONTINUE, 0, + "default", LDEFAULT, 0, + "do", LDO, 0, + "double", LDOUBLE, TDOUBLE, + "else", LELSE, 0, + "enum", LENUM, 0, + "extern", LEXTERN, 0, + "float", LFLOAT, TFLOAT, + "for", LFOR, 0, + "goto", LGOTO, 0, + "if", LIF, 0, + "inline", LINLINE, 0, + "int", LINT, TINT, + "long", LLONG, TLONG, + "register", LREGISTER, 0, + "restrict", LRESTRICT, 0, + "return", LRETURN, 0, + "SET", LSET, 0, + "short", LSHORT, TSHORT, + "signed", LSIGNED, 0, + "signof", LSIGNOF, 0, + "sizeof", LSIZEOF, 0, + "static", LSTATIC, 0, + "struct", LSTRUCT, 0, + "switch", LSWITCH, 0, + "typedef", LTYPEDEF, 0, + "typestr", LTYPESTR, 0, + "union", LUNION, 0, + "unsigned", LUNSIGNED, 0, + "USED", LUSED, 0, + "void", LVOID, TVOID, + "volatile", LVOLATILE, 0, + "while", LWHILE, 0, + 0 +}; + +void +cinit(void) +{ + Sym *s; + int i; + Type *t; + + nerrors = 0; + lineno = 1; + iostack = I; + iofree = I; + peekc = IGN; + nhunk = 0; + + types[TXXX] = T; + types[TCHAR] = typ(TCHAR, T); + types[TUCHAR] = typ(TUCHAR, T); + types[TSHORT] = typ(TSHORT, T); + types[TUSHORT] = typ(TUSHORT, T); + types[TINT] = typ(TINT, T); + types[TUINT] = typ(TUINT, T); + types[TLONG] = typ(TLONG, T); + types[TULONG] = typ(TULONG, T); + types[TVLONG] = typ(TVLONG, T); + types[TUVLONG] = typ(TUVLONG, T); + types[TFLOAT] = typ(TFLOAT, T); + types[TDOUBLE] = typ(TDOUBLE, T); + types[TVOID] = typ(TVOID, T); + types[TENUM] = typ(TENUM, T); + types[TFUNC] = typ(TFUNC, types[TINT]); + types[TIND] = typ(TIND, types[TVOID]); + + for(i=0; ilexical = itab[i].lexical; + if(itab[i].type != 0) + s->type = types[itab[i].type]; + } + blockno = 0; + autobn = 0; + autoffset = 0; + + t = typ(TARRAY, types[TCHAR]); + t->width = 0; + symstring = slookup(".string"); + symstring->class = CSTATIC; + symstring->type = t; + + t = typ(TARRAY, types[TCHAR]); + t->width = 0; + + nodproto = new(OPROTO, Z, Z); + dclstack = D; + + pathname = allocn(pathname, 0, 100); + if(mygetwd(pathname, 99) == 0) { + pathname = allocn(pathname, 100, 900); + if(mygetwd(pathname, 999) == 0) + strcpy(pathname, "/???"); + } + + fmtinstall('O', Oconv); + fmtinstall('T', Tconv); + fmtinstall('F', FNconv); + fmtinstall('L', Lconv); + fmtinstall('Q', Qconv); + fmtinstall('|', VBconv); +} + +int +filbuf(void) +{ + Io *i; + +loop: + i = iostack; + if(i == I) + return EOF; + if(i->f < 0) + goto pop; + fi.c = read(i->f, i->b, BUFSIZ) - 1; + if(fi.c < 0) { + close(i->f); + linehist(0, 0); + goto pop; + } + fi.p = i->b + 1; + return i->b[0] & 0xff; + +pop: + iostack = i->link; + i->link = iofree; + iofree = i; + i = iostack; + if(i == I) + return EOF; + fi.p = i->p; + fi.c = i->c; + if(--fi.c < 0) + goto loop; + return *fi.p++ & 0xff; +} + +int +Oconv(Fmt *fp) +{ + int a; + + a = va_arg(fp->args, int); + if(a < OXXX || a > OEND) + return fmtprint(fp, "***badO %d***", a); + + return fmtstrcpy(fp, onames[a]); +} + +int +Lconv(Fmt *fp) +{ + char str[STRINGSZ], s[STRINGSZ]; + Hist *h; + struct + { + Hist* incl; /* start of this include file */ + long idel; /* delta line number to apply to include */ + Hist* line; /* start of this #line directive */ + long ldel; /* delta line number to apply to #line */ + } a[HISTSZ]; + long l, d; + int i, n; + + l = va_arg(fp->args, long); + n = 0; + for(h = hist; h != H; h = h->link) { + if(l < h->line) + break; + if(h->name) { + if(h->offset != 0) { /* #line directive, not #pragma */ + if(n > 0 && n < HISTSZ && h->offset >= 0) { + a[n-1].line = h; + a[n-1].ldel = h->line - h->offset + 1; + } + } else { + if(n < HISTSZ) { /* beginning of file */ + a[n].incl = h; + a[n].idel = h->line; + a[n].line = 0; + } + n++; + } + continue; + } + n--; + if(n > 0 && n < HISTSZ) { + d = h->line - a[n].incl->line; + a[n-1].ldel += d; + a[n-1].idel += d; + } + } + if(n > HISTSZ) + n = HISTSZ; + str[0] = 0; + for(i=n-1; i>=0; i--) { + if(i != n-1) { + if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */ + break; + strcat(str, " "); + } + if(a[i].line) + snprint(s, STRINGSZ, "%s:%ld[%s:%ld]", + a[i].line->name, l-a[i].ldel+1, + a[i].incl->name, l-a[i].idel+1); + else + snprint(s, STRINGSZ, "%s:%ld", + a[i].incl->name, l-a[i].idel+1); + if(strlen(s)+strlen(str) >= STRINGSZ-10) + break; + strcat(str, s); + l = a[i].incl->line - 1; /* now print out start of this file */ + } + if(n == 0) + strcat(str, ""); + return fmtstrcpy(fp, str); +} + +int +Tconv(Fmt *fp) +{ + char str[STRINGSZ+20], s[STRINGSZ+20]; + Type *t, *t1; + int et; + long n; + + str[0] = 0; + for(t = va_arg(fp->args, Type*); t != T; t = t->link) { + et = t->etype; + if(str[0]) + strcat(str, " "); + if(t->garb&~GINCOMPLETE) { + sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + sprint(s, "%s", tnames[et]); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + if(et == TFUNC && (t1 = t->down)) { + sprint(s, "(%T", t1); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + while(t1 = t1->down) { + sprint(s, ", %T", t1); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, ")"); + } + if(et == TARRAY) { + n = t->width; + if(t->link && t->link->width) + n /= t->link->width; + sprint(s, "[%ld]", n); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + if(t->nbits) { + sprint(s, " %d:%d", t->shift, t->nbits); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + if(typesu[et]) { + if(t->tag) { + strcat(str, " "); + if(strlen(str) + strlen(t->tag->name) < STRINGSZ) + strcat(str, t->tag->name); + } else + strcat(str, " {}"); + break; + } + } + return fmtstrcpy(fp, str); +} + +int +FNconv(Fmt *fp) +{ + char *str; + Node *n; + + n = va_arg(fp->args, Node*); + str = ""; + if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM)) + str = n->sym->name; + return fmtstrcpy(fp, str); +} + +int +Qconv(Fmt *fp) +{ + char str[STRINGSZ+20], *s; + long b; + int i; + + str[0] = 0; + for(b = va_arg(fp->args, long); b;) { + i = bitno(b); + if(str[0]) + strcat(str, " "); + s = qnames[i]; + if(strlen(str) + strlen(s) >= STRINGSZ) + break; + strcat(str, s); + b &= ~(1L << i); + } + return fmtstrcpy(fp, str); +} + +int +VBconv(Fmt *fp) +{ + char str[STRINGSZ]; + int i, n, t, pc; + + n = va_arg(fp->args, int); + pc = 0; /* BUG: was printcol */ + i = 0; + while(pc < n) { + t = (pc+4) & ~3; + if(t <= n) { + str[i++] = '\t'; + pc = t; + continue; + } + str[i++] = ' '; + pc++; + } + str[i] = 0; + + return fmtstrcpy(fp, str); +} + +void +setinclude(char *p) +{ + int i; + char *e; + + while(*p != 0) { + e = strchr(p, ' '); + if(e != 0) + *e = '\0'; + + for(i=1; i < ninclude; i++) + if(strcmp(p, include[i]) == 0) + break; + + if(i >= ninclude) + include[ninclude++] = p; + + if(ninclude > nelem(include)) { + diag(Z, "ninclude too small %d", nelem(include)); + exits("ninclude"); + } + + if(e == 0) + break; + p = e+1; + } +} diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody new file mode 100644 index 0000000000..f7ba6d0fce --- /dev/null +++ b/src/cmd/cc/lexbody @@ -0,0 +1,723 @@ +// Inferno utils/cc/lexbody +// http://code.google.com/p/inferno-os/source/browse/utils/cc/lexbody +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/* + * common code for all the assemblers + */ + +void +pragpack(void) +{ + while(getnsc() != '\n') + ; +} + +void +pragvararg(void) +{ + while(getnsc() != '\n') + ; +} + +void +pragfpround(void) +{ + while(getnsc() != '\n') + ; +} + +void +pragprofile(void) +{ + while(getnsc() != '\n') + ; +} + +void +pragincomplete(void) +{ + while(getnsc() != '\n') + ; +} + +void +gethunk(void) +{ + hunk = malloc(NHUNK); + memset(hunk, 0, NHUNK); + nhunk = NHUNK; +} + +void* +alloc(long n) +{ + void *p; + + while((uintptr)hunk & MAXALIGN) { + hunk++; + nhunk--; + } + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void* +allocn(void *p, long on, long n) +{ + void *q; + + q = (uchar*)p + on; + if(q != hunk || nhunk < n) { + while(nhunk < on+n) + gethunk(); + memmove(hunk, p, on); + p = hunk; + hunk += on; + nhunk -= on; + } + hunk += n; + nhunk -= n; + return p; +} + +void +setinclude(char *p) +{ + int i; + + if(p == 0) + return; + for(i=1; i < ninclude; i++) + if(strcmp(p, include[i]) == 0) + return; + + if(ninclude >= nelem(include)) { + yyerror("ninclude too small %d", nelem(include)); + exits("ninclude"); + } + include[ninclude++] = p; +} + +void +errorexit(void) +{ + + if(outfile) + remove(outfile); + exits("error"); +} + +void +pushio(void) +{ + Io *i; + + i = iostack; + if(i == I) { + yyerror("botch in pushio"); + errorexit(); + } + i->p = fi.p; + i->c = fi.c; +} + +void +newio(void) +{ + Io *i; + static int pushdepth = 0; + + i = iofree; + if(i == I) { + pushdepth++; + if(pushdepth > 1000) { + yyerror("macro/io expansion too deep"); + errorexit(); + } + i = alloc(sizeof(*i)); + } else + iofree = i->link; + i->c = 0; + i->f = -1; + ionext = i; +} + +void +newfile(char *s, int f) +{ + Io *i; + + i = ionext; + i->link = iostack; + iostack = i; + i->f = f; + if(f < 0) + i->f = open(s, 0); + if(i->f < 0) { + yyerror("%ca: %r: %s", thechar, s); + errorexit(); + } + fi.c = 0; + linehist(s, 0); +} + +Sym* +slookup(char *s) +{ + + strcpy(symb, s); + return lookup(); +} + +Sym* +lookup(void) +{ + Sym *s; + long h; + char *p; + int c, l; + + h = 0; + for(p=symb; c = *p; p++) + h = h+h+h + c; + l = (p - symb) + 1; + if(h < 0) + h = ~h; + h %= NHASH; + c = symb[0]; + for(s = hash[h]; s != S; s = s->link) { + if(s->name[0] != c) + continue; + if(memcmp(s->name, symb, l) == 0) + return s; + } + s = alloc(sizeof(*s)); + s->name = alloc(l); + memmove(s->name, symb, l); + + s->link = hash[h]; + hash[h] = s; + syminit(s); + return s; +} + +long +yylex(void) +{ + int c, c1; + char *cp; + Sym *s; + + c = peekc; + if(c != IGN) { + peekc = IGN; + goto l1; + } +l0: + c = GETC(); + +l1: + if(c == EOF) { + peekc = EOF; + return -1; + } + if(isspace(c)) { + if(c == '\n') { + lineno++; + return ';'; + } + goto l0; + } + if(isalpha(c)) + goto talph; + if(isdigit(c)) + goto tnum; + switch(c) + { + case '\n': + lineno++; + return ';'; + + case '#': + domacro(); + goto l0; + + case '.': + c = GETC(); + if(isalpha(c)) { + cp = symb; + *cp++ = '.'; + goto aloop; + } + if(isdigit(c)) { + cp = symb; + *cp++ = '.'; + goto casedot; + } + peekc = c; + return '.'; + + talph: + case '_': + case '@': + cp = symb; + + aloop: + *cp++ = c; + c = GETC(); + if(isalpha(c) || isdigit(c) || c == '_' || c == '$') + goto aloop; + *cp = 0; + peekc = c; + s = lookup(); + if(s->macro) { + newio(); + cp = ionext->b; + macexpand(s, cp); + pushio(); + ionext->link = iostack; + iostack = ionext; + fi.p = cp; + fi.c = strlen(cp); + if(peekc != IGN) { + cp[fi.c++] = peekc; + cp[fi.c] = 0; + peekc = IGN; + } + goto l0; + } + if(s->type == 0) + s->type = LNAME; + if(s->type == LNAME || + s->type == LVAR || + s->type == LLAB) { + yylval.sym = s; + return s->type; + } + yylval.lval = s->value; + return s->type; + + tnum: + cp = symb; + if(c != '0') + goto dc; + *cp++ = c; + c = GETC(); + c1 = 3; + if(c == 'x' || c == 'X') { + c1 = 4; + c = GETC(); + } else + if(c < '0' || c > '7') + goto dc; + yylval.lval = 0; + for(;;) { + if(c >= '0' && c <= '9') { + if(c > '7' && c1 == 3) + break; + yylval.lval <<= c1; + yylval.lval += c - '0'; + c = GETC(); + continue; + } + if(c1 == 3) + break; + if(c >= 'A' && c <= 'F') + c += 'a' - 'A'; + if(c >= 'a' && c <= 'f') { + yylval.lval <<= c1; + yylval.lval += c - 'a' + 10; + c = GETC(); + continue; + } + break; + } + goto ncu; + + dc: + for(;;) { + if(!isdigit(c)) + break; + *cp++ = c; + c = GETC(); + } + if(c == '.') + goto casedot; + if(c == 'e' || c == 'E') + goto casee; + *cp = 0; + if(sizeof(yylval.lval) == sizeof(vlong)) + yylval.lval = strtoll(symb, nil, 10); + else + yylval.lval = strtol(symb, nil, 10); + + ncu: + while(c == 'U' || c == 'u' || c == 'l' || c == 'L') + c = GETC(); + peekc = c; + return LCONST; + + casedot: + for(;;) { + *cp++ = c; + c = GETC(); + if(!isdigit(c)) + break; + } + if(c == 'e' || c == 'E') + goto casee; + goto caseout; + + casee: + *cp++ = 'e'; + c = GETC(); + if(c == '+' || c == '-') { + *cp++ = c; + c = GETC(); + } + while(isdigit(c)) { + *cp++ = c; + c = GETC(); + } + + caseout: + *cp = 0; + peekc = c; + if(FPCHIP) { + yylval.dval = atof(symb); + return LFCONST; + } + yyerror("assembler cannot interpret fp constants"); + yylval.lval = 1L; + return LCONST; + + case '"': + memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval)); + cp = yylval.sval; + c1 = 0; + for(;;) { + c = escchar('"'); + if(c == EOF) + break; + if(c1 < sizeof(yylval.sval)) + *cp++ = c; + c1++; + } + if(c1 > sizeof(yylval.sval)) + yyerror("string constant too long"); + return LSCONST; + + case '\'': + c = escchar('\''); + if(c == EOF) + c = '\''; + if(escchar('\'') != EOF) + yyerror("missing '"); + yylval.lval = c; + return LCONST; + + case '/': + c1 = GETC(); + if(c1 == '/') { + for(;;) { + c = GETC(); + if(c == '\n') { + lineno++; + goto l1; + } + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + } + } + if(c1 == '*') { + for(;;) { + c = GETC(); + while(c == '*') { + c = GETC(); + if(c == '/') + goto l0; + } + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + if(c == '\n') + lineno++; + } + } + break; + + default: + return c; + } + peekc = c1; + return c; +} + +int +getc(void) +{ + int c; + + c = peekc; + if(c != IGN) { + peekc = IGN; + return c; + } + c = GETC(); + if(c == '\n') + lineno++; + if(c == EOF) { + yyerror("End of file"); + errorexit(); + } + return c; +} + +int +getnsc(void) +{ + int c; + + for(;;) { + c = getc(); + if(!isspace(c) || c == '\n') + return c; + } +} + +void +unget(int c) +{ + + peekc = c; + if(c == '\n') + lineno--; +} + +int +escchar(int e) +{ + int c, l; + +loop: + c = getc(); + if(c == '\n') { + yyerror("newline in string"); + return EOF; + } + if(c != '\\') { + if(c == e) + return EOF; + return c; + } + c = getc(); + if(c >= '0' && c <= '7') { + l = c - '0'; + c = getc(); + if(c >= '0' && c <= '7') { + l = l*8 + c-'0'; + c = getc(); + if(c >= '0' && c <= '7') { + l = l*8 + c-'0'; + return l; + } + } + peekc = c; + return l; + } + switch(c) + { + case '\n': goto loop; + case 'n': return '\n'; + case 't': return '\t'; + case 'b': return '\b'; + case 'r': return '\r'; + case 'f': return '\f'; + case 'a': return 0x07; + case 'v': return 0x0b; + case 'z': return 0x00; + } + return c; +} + +void +pinit(char *f) +{ + int i; + Sym *s; + + lineno = 1; + newio(); + newfile(f, -1); + pc = 0; + peekc = IGN; + sym = 1; + for(i=0; ilink) + s->macro = 0; +} + +int +filbuf(void) +{ + Io *i; + +loop: + i = iostack; + if(i == I) + return EOF; + if(i->f < 0) + goto pop; + fi.c = read(i->f, i->b, BUFSIZ) - 1; + if(fi.c < 0) { + close(i->f); + linehist(0, 0); + goto pop; + } + fi.p = i->b + 1; + return i->b[0]; + +pop: + iostack = i->link; + i->link = iofree; + iofree = i; + i = iostack; + if(i == I) + return EOF; + fi.p = i->p; + fi.c = i->c; + if(--fi.c < 0) + goto loop; + return *fi.p++; +} + +void +yyerror(char *a, ...) +{ + char buf[200]; + va_list arg; + + /* + * hack to intercept message from yaccpar + */ + if(strcmp(a, "syntax error") == 0) { + yyerror("syntax error, last name: %s", symb); + return; + } + prfile(lineno); + va_start(arg, a); + vseprint(buf, buf+sizeof(buf), a, arg); + va_end(arg); + print("%s\n", buf); + nerrors++; + if(nerrors > 10) { + print("too many errors\n"); + errorexit(); + } +} + +void +prfile(long l) +{ + int i, n; + Hist a[HISTSZ], *h; + long d; + + n = 0; + for(h = hist; h != H; h = h->link) { + if(l < h->line) + break; + if(h->name) { + if(h->offset == 0) { + if(n >= 0 && n < HISTSZ) + a[n] = *h; + n++; + continue; + } + if(n > 0 && n < HISTSZ) + if(a[n-1].offset == 0) { + a[n] = *h; + n++; + } else + a[n-1] = *h; + continue; + } + n--; + if(n >= 0 && n < HISTSZ) { + d = h->line - a[n].line; + for(i=0; i HISTSZ) + n = HISTSZ; + for(i=0; ih |= 0x80000000L; + return; + } + if(native == 0) { + ieee->l = 0; + ieee->h = 0; + return; + } + fr = frexp(native, &exp); + f = 2097152L; /* shouldnt use fp constants here */ + fr = modf(fr*f, &ho); + ieee->h = ho; + ieee->h &= 0xfffffL; + ieee->h |= (exp+1022L) << 20; + f = 65536L; + fr = modf(fr*f, &ho); + ieee->l = ho; + ieee->l <<= 16; + ieee->l |= (long)(fr*f); +} diff --git a/src/cmd/cc/mac.c b/src/cmd/cc/mac.c new file mode 100644 index 0000000000..c08cd9c973 --- /dev/null +++ b/src/cmd/cc/mac.c @@ -0,0 +1,33 @@ +// Inferno utils/cc/mac.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/mac.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +#include "macbody" diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody new file mode 100644 index 0000000000..9d309c10d4 --- /dev/null +++ b/src/cmd/cc/macbody @@ -0,0 +1,842 @@ +// Inferno utils/cc/macbody +// http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define VARMAC 0x80 + +long +getnsn(void) +{ + long n; + int c; + + c = getnsc(); + if(c < '0' || c > '9') + return -1; + n = 0; + while(c >= '0' && c <= '9') { + n = n*10 + c-'0'; + c = getc(); + } + unget(c); + return n; +} + +Sym* +getsym(void) +{ + int c; + char *cp; + + c = getnsc(); + if(!isalpha(c) && c != '_') { + unget(c); + return S; + } + for(cp = symb;;) { + if(cp <= symb+NSYMB-4) + *cp++ = c; + c = getc(); + if(isalnum(c) || c == '_') + continue; + unget(c); + break; + } + *cp = 0; + if(cp > symb+NSYMB-4) + yyerror("symbol too large: %s", symb); + return lookup(); +} + +Sym* +getsymdots(int *dots) +{ + int c; + Sym *s; + + s = getsym(); + if(s != S) + return s; + + c = getnsc(); + if(c != '.'){ + unget(c); + return S; + } + if(getc() != '.' || getc() != '.') + yyerror("bad dots in macro"); + *dots = 1; + return slookup("__VA_ARGS__"); +} + +int +getcom(void) +{ + int c; + + for(;;) { + c = getnsc(); + if(c != '/') + break; + c = getc(); + if(c == '/') { + while(c != '\n') + c = getc(); + break; + } + if(c != '*') + break; + c = getc(); + for(;;) { + if(c == '*') { + c = getc(); + if(c != '/') + continue; + c = getc(); + break; + } + if(c == '\n') { + yyerror("comment across newline"); + break; + } + c = getc(); + } + if(c == '\n') + break; + } + return c; +} + +void +dodefine(char *cp) +{ + Sym *s; + char *p; + long l; + + strcpy(symb, cp); + p = strchr(symb, '='); + if(p) { + *p++ = 0; + s = lookup(); + l = strlen(p) + 2; /* +1 null, +1 nargs */ + s->macro = alloc(l); + strcpy(s->macro+1, p); + } else { + s = lookup(); + s->macro = "\0001"; /* \000 is nargs */ + } + if(debug['m']) + print("#define (-D) %s %s\n", s->name, s->macro+1); +} + +struct +{ + char *macname; + void (*macf)(void); +} mactab[] = +{ + "ifdef", 0, /* macif(0) */ + "ifndef", 0, /* macif(1) */ + "else", 0, /* macif(2) */ + + "line", maclin, + "define", macdef, + "include", macinc, + "undef", macund, + + "pragma", macprag, + "endif", macend, + 0 +}; + +void +domacro(void) +{ + int i; + Sym *s; + + s = getsym(); + if(s == S) + s = slookup("endif"); + for(i=0; mactab[i].macname; i++) + if(strcmp(s->name, mactab[i].macname) == 0) { + if(mactab[i].macf) + (*mactab[i].macf)(); + else + macif(i); + return; + } + yyerror("unknown #: %s", s->name); + macend(); +} + +void +macund(void) +{ + Sym *s; + + s = getsym(); + macend(); + if(s == S) { + yyerror("syntax in #undef"); + return; + } + s->macro = 0; +} + +#define NARG 25 +void +macdef(void) +{ + Sym *s, *a; + char *args[NARG], *np, *base; + int n, i, c, len, dots; + int ischr; + + s = getsym(); + if(s == S) + goto bad; + if(s->macro) + yyerror("macro redefined: %s", s->name); + c = getc(); + n = -1; + dots = 0; + if(c == '(') { + n++; + c = getnsc(); + if(c != ')') { + unget(c); + for(;;) { + a = getsymdots(&dots); + if(a == S) + goto bad; + if(n >= NARG) { + yyerror("too many arguments in #define: %s", s->name); + goto bad; + } + args[n++] = a->name; + c = getnsc(); + if(c == ')') + break; + if(c != ',' || dots) + goto bad; + } + } + c = getc(); + } + if(isspace(c)) + if(c != '\n') + c = getnsc(); + base = hunk; + len = 1; + ischr = 0; + for(;;) { + if(isalpha(c) || c == '_') { + np = symb; + *np++ = c; + c = getc(); + while(isalnum(c) || c == '_') { + *np++ = c; + c = getc(); + } + *np = 0; + for(i=0; i= n) { + i = strlen(symb); + base = allocn(base, len, i); + memcpy(base+len, symb, i); + len += i; + continue; + } + base = allocn(base, len, 2); + base[len++] = '#'; + base[len++] = 'a' + i; + continue; + } + if(ischr){ + if(c == '\\'){ + base = allocn(base, len, 1); + base[len++] = c; + c = getc(); + }else if(c == ischr) + ischr = 0; + }else{ + if(c == '"' || c == '\''){ + base = allocn(base, len, 1); + base[len++] = c; + ischr = c; + c = getc(); + continue; + } + if(c == '/') { + c = getc(); + if(c == '/'){ + c = getc(); + for(;;) { + if(c == '\n') + break; + c = getc(); + } + continue; + } + if(c == '*'){ + c = getc(); + for(;;) { + if(c == '*') { + c = getc(); + if(c != '/') + continue; + c = getc(); + break; + } + if(c == '\n') { + yyerror("comment and newline in define: %s", s->name); + break; + } + c = getc(); + } + continue; + } + base = allocn(base, len, 1); + base[len++] = '/'; + continue; + } + } + if(c == '\\') { + c = getc(); + if(c == '\n') { + c = getc(); + continue; + } + else if(c == '\r') { + c = getc(); + if(c == '\n') { + c = getc(); + continue; + } + } + base = allocn(base, len, 1); + base[len++] = '\\'; + continue; + } + if(c == '\n') + break; + if(c == '#') + if(n > 0) { + base = allocn(base, len, 1); + base[len++] = c; + } + base = allocn(base, len, 1); + base[len++] = c; + c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff)); + if(c == '\n') + lineno++; + if(c == -1) { + yyerror("eof in a macro: %s", s->name); + break; + } + } + do { + base = allocn(base, len, 1); + base[len++] = 0; + } while(len & 3); + + *base = n+1; + if(dots) + *base |= VARMAC; + s->macro = base; + if(debug['m']) + print("#define %s %s\n", s->name, s->macro+1); + return; + +bad: + if(s == S) + yyerror("syntax in #define"); + else + yyerror("syntax in #define: %s", s->name); + macend(); +} + +void +macexpand(Sym *s, char *b) +{ + char buf[2000]; + int n, l, c, nargs; + char *arg[NARG], *cp, *ob, *ecp, dots; + + ob = b; + if(*s->macro == 0) { + strcpy(b, s->macro+1); + if(debug['m']) + print("#expand %s %s\n", s->name, ob); + return; + } + + nargs = (char)(*s->macro & ~VARMAC) - 1; + dots = *s->macro & VARMAC; + + c = getnsc(); + if(c != '(') + goto bad; + n = 0; + c = getc(); + if(c != ')') { + unget(c); + l = 0; + cp = buf; + ecp = cp + sizeof(buf)-4; + arg[n++] = cp; + for(;;) { + if(cp >= ecp) + goto toobig; + c = getc(); + if(c == '"') + for(;;) { + if(cp >= ecp) + goto toobig; + *cp++ = c; + c = getc(); + if(c == '\\') { + *cp++ = c; + c = getc(); + continue; + } + if(c == '\n') + goto bad; + if(c == '"') + break; + } + if(c == '\'') + for(;;) { + if(cp >= ecp) + goto toobig; + *cp++ = c; + c = getc(); + if(c == '\\') { + *cp++ = c; + c = getc(); + continue; + } + if(c == '\n') + goto bad; + if(c == '\'') + break; + } + if(c == '/') { + c = getc(); + switch(c) { + case '*': + for(;;) { + c = getc(); + if(c == '*') { + c = getc(); + if(c == '/') + break; + } + } + *cp++ = ' '; + continue; + case '/': + while((c = getc()) != '\n') + ; + break; + default: + unget(c); + c = '/'; + } + } + if(l == 0) { + if(c == ',') { + if(n == nargs && dots) { + *cp++ = ','; + continue; + } + *cp++ = 0; + arg[n++] = cp; + if(n > nargs) + break; + continue; + } + if(c == ')') + break; + } + if(c == '\n') + c = ' '; + *cp++ = c; + if(c == '(') + l++; + if(c == ')') + l--; + } + *cp = 0; + } + if(n != nargs) { + yyerror("argument mismatch expanding: %s", s->name); + *b = 0; + return; + } + cp = s->macro+1; + for(;;) { + c = *cp++; + if(c == '\n') + c = ' '; + if(c != '#') { + *b++ = c; + if(c == 0) + break; + continue; + } + c = *cp++; + if(c == 0) + goto bad; + if(c == '#') { + *b++ = c; + continue; + } + c -= 'a'; + if(c < 0 || c >= n) + continue; + strcpy(b, arg[c]); + b += strlen(arg[c]); + } + *b = 0; + if(debug['m']) + print("#expand %s %s\n", s->name, ob); + return; + +bad: + yyerror("syntax in macro expansion: %s", s->name); + *b = 0; + return; + +toobig: + yyerror("too much text in macro expansion: %s", s->name); + *b = 0; +} + +void +macinc(void) +{ + int c0, c, i, f; + char str[STRINGSZ], *hp; + + c0 = getnsc(); + if(c0 != '"') { + c = c0; + if(c0 != '<') + goto bad; + c0 = '>'; + } + for(hp = str;;) { + c = getc(); + if(c == c0) + break; + if(c == '\n') + goto bad; + *hp++ = c; + } + *hp = 0; + + c = getcom(); + if(c != '\n') + goto bad; + + f = -1; + for(i=0; i') + continue; + strcpy(symb, include[i]); + strcat(symb, "/"); + if(strcmp(symb, "./") == 0) + symb[0] = 0; + strcat(symb, str); + f = myopen(symb); + if(f >= 0) + break; + } + if(f < 0) + strcpy(symb, str); + c = strlen(symb) + 1; + hp = alloc(c); + memcpy(hp, symb, c); + newio(); + pushio(); + newfile(hp, f); + return; + +bad: + unget(c); + yyerror("syntax in #include"); + macend(); +} + +void +maclin(void) +{ + char *cp; + int c; + long n; + + n = getnsn(); + c = getc(); + if(n < 0) + goto bad; + + for(;;) { + if(c == ' ' || c == '\t') { + c = getc(); + continue; + } + if(c == '"') + break; + if(c == '\n') { + strcpy(symb, ""); + goto nn; + } + goto bad; + } + cp = symb; + for(;;) { + c = getc(); + if(c == '"') + break; + *cp++ = c; + } + *cp = 0; + c = getcom(); + if(c != '\n') + goto bad; + +nn: + c = strlen(symb) + 1; + cp = alloc(c); + memcpy(cp, symb, c); + linehist(cp, n); + return; + +bad: + unget(c); + yyerror("syntax in #line"); + macend(); +} + +void +macif(int f) +{ + int c, l, bol; + Sym *s; + + if(f == 2) + goto skip; + s = getsym(); + if(s == S) + goto bad; + if(getcom() != '\n') + goto bad; + if((s->macro != 0) ^ f) + return; + +skip: + bol = 1; + l = 0; + for(;;) { + c = getc(); + if(c != '#') { + if(!isspace(c)) + bol = 0; + if(c == '\n') + bol = 1; + continue; + } + if(!bol) + continue; + s = getsym(); + if(s == S) + continue; + if(strcmp(s->name, "endif") == 0) { + if(l) { + l--; + continue; + } + macend(); + return; + } + if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) { + l++; + continue; + } + if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) { + macend(); + return; + } + } + +bad: + yyerror("syntax in #if(n)def"); + macend(); +} + +void +macprag(void) +{ + Sym *s; + int c0, c; + char *hp; + Hist *h; + + s = getsym(); + + if(s && strcmp(s->name, "lib") == 0) + goto praglib; + if(s && strcmp(s->name, "pack") == 0) { + pragpack(); + return; + } + if(s && strcmp(s->name, "fpround") == 0) { + pragfpround(); + return; + } + if(s && strcmp(s->name, "profile") == 0) { + pragprofile(); + return; + } + if(s && strcmp(s->name, "varargck") == 0) { + pragvararg(); + return; + } + if(s && strcmp(s->name, "incomplete") == 0) { + pragincomplete(); + return; + } + while(getnsc() != '\n') + ; + return; + +praglib: + c0 = getnsc(); + if(c0 != '"') { + c = c0; + if(c0 != '<') + goto bad; + c0 = '>'; + } + for(hp = symb;;) { + c = getc(); + if(c == c0) + break; + if(c == '\n') + goto bad; + *hp++ = c; + } + *hp = 0; + c = getcom(); + if(c != '\n') + goto bad; + + /* + * put pragma-line in as a funny history + */ + c = strlen(symb) + 1; + hp = alloc(c); + memcpy(hp, symb, c); + + h = alloc(sizeof(Hist)); + h->name = hp; + h->line = lineno; + h->offset = -1; + h->link = H; + if(ehist == H) { + hist = h; + ehist = h; + return; + } + ehist->link = h; + ehist = h; + return; + +bad: + unget(c); + yyerror("syntax in #pragma lib"); + macend(); +} + +void +macend(void) +{ + int c; + + for(;;) { + c = getnsc(); + if(c < 0 || c == '\n') + return; + } +} + +void +linehist(char *f, int offset) +{ + Hist *h; + + /* + * overwrite the last #line directive if + * no alloc has happened since the last one + */ + if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0) + if(f && ehist->name && strcmp(f, ehist->name) == 0) { + ehist->line = lineno; + ehist->offset = offset; + return; + } + + if(debug['f']) + if(f) { + if(offset) + print("%4ld: %s (#line %d)\n", lineno, f, offset); + else + print("%4ld: %s\n", lineno, f); + } else + print("%4ld: \n", lineno); + newflag = 0; + + h = alloc(sizeof(Hist)); + h->name = f; + h->line = lineno; + h->offset = offset; + h->link = H; + if(ehist == H) { + hist = h; + ehist = h; + return; + } + ehist->link = h; + ehist = h; +} diff --git a/src/cmd/cc/omachcap.c b/src/cmd/cc/omachcap.c new file mode 100644 index 0000000000..ec5aa86e93 --- /dev/null +++ b/src/cmd/cc/omachcap.c @@ -0,0 +1,38 @@ +// Inferno utils/cc/machcap.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/machcap.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +/* default, like old cc */ +int +machcap(Node *n) +{ + return 0; +} diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c new file mode 100644 index 0000000000..ae0b1b40cd --- /dev/null +++ b/src/cmd/cc/pgen.c @@ -0,0 +1,550 @@ +// Inferno utils/6c/sgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +void +codgen(Node *n, Node *nn) +{ + Prog *sp; + Node *n1, nod, nod1; + + cursafe = 0; + curarg = 0; + maxargsafe = 0; + + /* + * isolate name + */ + for(n1 = nn;; n1 = n1->left) { + if(n1 == Z) { + diag(nn, "cant find function name"); + return; + } + if(n1->op == ONAME) + break; + } + nearln = nn->lineno; + gpseudo(ATEXT, n1->sym, nodconst(stkoff)); + sp = p; + + /* + * isolate first argument + */ + if(REGARG) { + if(typecmplx[thisfn->link->etype]) { + nod1 = *nodret->left; + nodreg(&nod, &nod1, REGARG); + gmove(&nod, &nod1); + } else + if(firstarg && typeword[firstargtype->etype]) { + nod1 = *nodret->left; + nod1.sym = firstarg; + nod1.type = firstargtype; + nod1.xoffset = align(0, firstargtype, Aarg1); + nod1.etype = firstargtype->etype; + nodreg(&nod, &nod1, REGARG); + gmove(&nod, &nod1); + } + } + + canreach = 1; + warnreach = 1; + gen(n); + if(canreach && thisfn->link->etype != TVOID) + warn(Z, "no return at end of function: %s", n1->sym->name); + noretval(3); + gbranch(ORETURN); + + if(!debug['N'] || debug['R'] || debug['P']) + regopt(sp); + + if(thechar=='6' || thechar=='7') /* [sic] */ + maxargsafe = xround(maxargsafe, 8); + sp->to.offset += maxargsafe; +} + +void +supgen(Node *n) +{ + int owarn; + long spc; + Prog *sp; + + if(n == Z) + return; + suppress++; + owarn = warnreach; + warnreach = 0; + spc = pc; + sp = lastp; + gen(n); + lastp = sp; + pc = spc; + sp->link = nil; + suppress--; + warnreach = owarn; +} + +void +gen(Node *n) +{ + Node *l, nod; + Prog *sp, *spc, *spb; + Case *cn; + long sbc, scc; + int snbreak, sncontin; + int f, o, oldreach; + +loop: + if(n == Z) + return; + nearln = n->lineno; + o = n->op; + if(debug['G']) + if(o != OLIST) + print("%L %O\n", nearln, o); + + if(!canreach) { + switch(o) { + case OLABEL: + case OCASE: + case OLIST: + case OBREAK: + case OFOR: + case OWHILE: + case ODWHILE: + /* all handled specially - see switch body below */ + break; + default: + if(warnreach) { + warn(n, "unreachable code %O", o); + warnreach = 0; + } + } + } + + switch(o) { + + default: + complex(n); + cgen(n, Z); + break; + + case OLIST: + gen(n->left); + + rloop: + n = n->right; + goto loop; + + case ORETURN: + canreach = 0; + warnreach = !suppress; + complex(n); + if(n->type == T) + break; + l = n->left; + if(l == Z) { + noretval(3); + gbranch(ORETURN); + break; + } + if(typecmplx[n->type->etype]) { + sugen(l, nodret, n->type->width); + noretval(3); + gbranch(ORETURN); + break; + } + regret(&nod, n); + cgen(l, &nod); + regfree(&nod); + if(typefd[n->type->etype]) + noretval(1); + else + noretval(2); + gbranch(ORETURN); + break; + + case OLABEL: + canreach = 1; + l = n->left; + if(l) { + l->pc = pc; + if(l->label) + patch(l->label, pc); + } + gbranch(OGOTO); /* prevent self reference in reg */ + patch(p, pc); + goto rloop; + + case OGOTO: + canreach = 0; + warnreach = !suppress; + n = n->left; + if(n == Z) + return; + if(n->complex == 0) { + diag(Z, "label undefined: %s", n->sym->name); + return; + } + if(suppress) + return; + gbranch(OGOTO); + if(n->pc) { + patch(p, n->pc); + return; + } + if(n->label) + patch(n->label, pc-1); + n->label = p; + return; + + case OCASE: + canreach = 1; + l = n->left; + if(cases == C) + diag(n, "case/default outside a switch"); + if(l == Z) { + cas(); + cases->val = 0; + cases->def = 1; + cases->label = pc; + cases->isv = 0; + goto rloop; + } + complex(l); + if(l->type == T) + goto rloop; + if(l->op == OCONST) + if(typeword[l->type->etype] && l->type->etype != TIND) { + cas(); + cases->val = l->vconst; + cases->def = 0; + cases->label = pc; + cases->isv = typev[l->type->etype]; + goto rloop; + } + diag(n, "case expression must be integer constant"); + goto rloop; + + case OSWITCH: + l = n->left; + complex(l); + if(l->type == T) + break; + if(!typeword[l->type->etype] || l->type->etype == TIND) { + diag(n, "switch expression must be integer"); + break; + } + + gbranch(OGOTO); /* entry */ + sp = p; + + cn = cases; + cases = C; + cas(); + + sbc = breakpc; + breakpc = pc; + snbreak = nbreak; + nbreak = 0; + gbranch(OGOTO); + spb = p; + + gen(n->right); /* body */ + if(canreach){ + gbranch(OGOTO); + patch(p, breakpc); + nbreak++; + } + + patch(sp, pc); + regalloc(&nod, l, Z); + /* always signed */ + if(typev[l->type->etype]) + nod.type = types[TVLONG]; + else + nod.type = types[TLONG]; + cgen(l, &nod); + doswit(&nod); + regfree(&nod); + patch(spb, pc); + + cases = cn; + breakpc = sbc; + canreach = nbreak!=0; + if(canreach == 0) + warnreach = !suppress; + nbreak = snbreak; + break; + + case OWHILE: + case ODWHILE: + l = n->left; + gbranch(OGOTO); /* entry */ + sp = p; + + scc = continpc; + continpc = pc; + gbranch(OGOTO); + spc = p; + + sbc = breakpc; + breakpc = pc; + snbreak = nbreak; + nbreak = 0; + gbranch(OGOTO); + spb = p; + + patch(spc, pc); + if(n->op == OWHILE) + patch(sp, pc); + bcomplex(l, Z); /* test */ + patch(p, breakpc); + if(l->op != OCONST || vconst(l) == 0) + nbreak++; + + if(n->op == ODWHILE) + patch(sp, pc); + gen(n->right); /* body */ + gbranch(OGOTO); + patch(p, continpc); + + patch(spb, pc); + continpc = scc; + breakpc = sbc; + canreach = nbreak!=0; + if(canreach == 0) + warnreach = !suppress; + nbreak = snbreak; + break; + + case OFOR: + l = n->left; + if(!canreach && l->right->left && warnreach) { + warn(n, "unreachable code FOR"); + warnreach = 0; + } + gen(l->right->left); /* init */ + gbranch(OGOTO); /* entry */ + sp = p; + + /* + * if there are no incoming labels in the + * body and the top's not reachable, warn + */ + if(!canreach && warnreach && deadheads(n)) { + warn(n, "unreachable code %O", o); + warnreach = 0; + } + + scc = continpc; + continpc = pc; + gbranch(OGOTO); + spc = p; + + sbc = breakpc; + breakpc = pc; + snbreak = nbreak; + nbreak = 0; + sncontin = ncontin; + ncontin = 0; + gbranch(OGOTO); + spb = p; + + patch(spc, pc); + gen(l->right->right); /* inc */ + patch(sp, pc); + if(l->left != Z) { /* test */ + bcomplex(l->left, Z); + patch(p, breakpc); + if(l->left->op != OCONST || vconst(l->left) == 0) + nbreak++; + } + canreach = 1; + gen(n->right); /* body */ + if(canreach){ + gbranch(OGOTO); + patch(p, continpc); + ncontin++; + } + if(!ncontin && l->right->right && warnreach) { + warn(l->right->right, "unreachable FOR inc"); + warnreach = 0; + } + + patch(spb, pc); + continpc = scc; + breakpc = sbc; + canreach = nbreak!=0; + if(canreach == 0) + warnreach = !suppress; + nbreak = snbreak; + ncontin = sncontin; + break; + + case OCONTINUE: + if(continpc < 0) { + diag(n, "continue not in a loop"); + break; + } + gbranch(OGOTO); + patch(p, continpc); + ncontin++; + canreach = 0; + warnreach = !suppress; + break; + + case OBREAK: + if(breakpc < 0) { + diag(n, "break not in a loop"); + break; + } + /* + * Don't complain about unreachable break statements. + * There are breaks hidden in yacc's output and some people + * write return; break; in their switch statements out of habit. + * However, don't confuse the analysis by inserting an + * unreachable reference to breakpc either. + */ + if(!canreach) + break; + gbranch(OGOTO); + patch(p, breakpc); + nbreak++; + canreach = 0; + warnreach = !suppress; + break; + + case OIF: + l = n->left; + if(bcomplex(l, n->right)) { + if(typefd[l->type->etype]) + f = !l->fconst; + else + f = !l->vconst; + if(debug['c']) + print("%L const if %s\n", nearln, f ? "false" : "true"); + if(f) { + canreach = 1; + supgen(n->right->left); + oldreach = canreach; + canreach = 1; + gen(n->right->right); + /* + * treat constant ifs as regular ifs for + * reachability warnings. + */ + if(!canreach && oldreach && debug['w'] < 2) + warnreach = 0; + } + else { + canreach = 1; + gen(n->right->left); + oldreach = canreach; + canreach = 1; + supgen(n->right->right); + /* + * treat constant ifs as regular ifs for + * reachability warnings. + */ + if(!oldreach && canreach && debug['w'] < 2) + warnreach = 0; + canreach = oldreach; + } + } + else { + sp = p; + canreach = 1; + if(n->right->left != Z) + gen(n->right->left); + oldreach = canreach; + canreach = 1; + if(n->right->right != Z) { + gbranch(OGOTO); + patch(sp, pc); + sp = p; + gen(n->right->right); + } + patch(sp, pc); + canreach = canreach || oldreach; + if(canreach == 0) + warnreach = !suppress; + } + break; + + case OSET: + case OUSED: + usedset(n->left, o); + break; + } +} + +void +usedset(Node *n, int o) +{ + if(n->op == OLIST) { + usedset(n->left, o); + usedset(n->right, o); + return; + } + complex(n); + switch(n->op) { + case OADDR: /* volatile */ + gins(ANOP, n, Z); + break; + case ONAME: + if(o == OSET) + gins(ANOP, Z, n); + else + gins(ANOP, n, Z); + break; + } +} + +int +bcomplex(Node *n, Node *c) +{ + + complex(n); + if(n->type != T) + if(tcompat(n, T, n->type, tnot)) + n->type = T; + if(n->type == T) { + gbranch(OGOTO); + return 0; + } + if(c != Z && n->op == OCONST && deadheads(c)) + return 1; + bool64(n); + boolgen(n, 1, Z); + return 0; +} diff --git a/src/cmd/cc/pickle.c b/src/cmd/cc/pickle.c new file mode 100644 index 0000000000..3626e4ad79 --- /dev/null +++ b/src/cmd/cc/pickle.c @@ -0,0 +1,298 @@ +// Inferno utils/cc/pickle.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/pickle.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +static char *kwd[] = +{ + "$adt", "$aggr", "$append", "$complex", "$defn", + "$delete", "$do", "$else", "$eval", "$head", "$if", + "$local", "$loop", "$return", "$tail", "$then", + "$union", "$whatis", "$while", +}; +static char picklestr[] = "\tbp = pickle(bp, ep, un, "; + +static char* +pmap(char *s) +{ + int i, bot, top, new; + + bot = 0; + top = bot + nelem(kwd) - 1; + while(bot <= top){ + new = bot + (top - bot)/2; + i = strcmp(kwd[new]+1, s); + if(i == 0) + return kwd[new]; + + if(i < 0) + bot = new + 1; + else + top = new - 1; + } + return s; +} + +Sym* +picklesue(Type *t) +{ + int h; + Sym *s; + + if(t != T) + for(h=0; hlink) + if(s->suetag && s->suetag->link == t) + return s; + return 0; +} + +Sym* +picklefun(Type *t) +{ + int h; + Sym *s; + + for(h=0; hlink) + if(s->type == t) + return s; + return 0; +} + +char picklechar[NTYPE]; +Init picklecinit[] = +{ + TCHAR, 'C', 0, + TUCHAR, 'b', 0, + TSHORT, 'd', 0, + TUSHORT, 'u', 0, + TLONG, 'D', 0, + TULONG, 'U', 0, + TVLONG, 'V', 0, + TUVLONG, 'W', 0, + TFLOAT, 'f', 0, + TDOUBLE, 'F', 0, + TARRAY, 'a', 0, + TIND, 'X', 0, + -1, 0, 0, +}; + +static void +pickleinit(void) +{ + Init *p; + + for(p=picklecinit; p->code >= 0; p++) + picklechar[p->code] = p->value; + + picklechar[TINT] = picklechar[TLONG]; + picklechar[TUINT] = picklechar[TULONG]; + if(types[TINT]->width != types[TLONG]->width) { + picklechar[TINT] = picklechar[TSHORT]; + picklechar[TUINT] = picklechar[TUSHORT]; + if(types[TINT]->width != types[TSHORT]->width) + warn(Z, "picklemember int not long or short"); + } + +} + +void +picklemember(Type *t, long off) +{ + Sym *s, *s1; + static int picklecharinit = 0; + + if(picklecharinit == 0) { + pickleinit(); + picklecharinit = 1; + } + s = t->sym; + switch(t->etype) { + default: + Bprint(&outbuf, " T%d\n", t->etype); + break; + + case TIND: + if(s == S) + Bprint(&outbuf, + "%s\"p\", (char*)addr+%ld+_i*%ld);\n", + picklestr, t->offset+off, t->width); + else + Bprint(&outbuf, + "%s\"p\", &addr->%s);\n", + picklestr, pmap(s->name)); + break; + + case TINT: + case TUINT: + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TFLOAT: + case TDOUBLE: + if(s == S) + Bprint(&outbuf, "%s\"%c\", (char*)addr+%ld+_i*%ld);\n", + picklestr, picklechar[t->etype], t->offset+off, t->width); + else + Bprint(&outbuf, "%s\"%c\", &addr->%s);\n", + picklestr, picklechar[t->etype], pmap(s->name)); + break; + case TARRAY: + Bprint(&outbuf, "\tfor(_i = 0; _i < %ld; _i++) {\n\t", + t->width/t->link->width); + picklemember(t->link, t->offset+off); + Bprint(&outbuf, "\t}\n\t_i = 0;\n\tUSED(_i);\n"); + break; + + case TSTRUCT: + case TUNION: + s1 = picklesue(t->link); + if(s1 == S) + break; + if(s == S) { + Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%ld+_i*%ld));\n", + pmap(s1->name), pmap(s1->name), t->offset+off, t->width); + } else { + Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, &addr->%s);\n", + pmap(s1->name), pmap(s->name)); + } + break; + } +} + +void +pickletype(Type *t) +{ + Sym *s; + Type *l; + Io *i; + int n; + char *an; + + if(!debug['P']) + return; + if(debug['P'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return; + } + s = picklesue(t->link); + if(s == S) + return; + switch(t->etype) { + default: + Bprint(&outbuf, "T%d\n", t->etype); + return; + + case TUNION: + case TSTRUCT: + if(debug['s']) + goto asmstr; + an = pmap(s->name); + + Bprint(&outbuf, "char *\npickle_%s(char *bp, char *ep, int un, %s *addr)\n{\n\tint _i = 0;\n\n\tUSED(_i);\n", an, an); + for(l = t->link; l != T; l = l->down) + picklemember(l, 0); + Bprint(&outbuf, "\treturn bp;\n}\n\n"); + break; + asmstr: + if(s == S) + break; + for(l = t->link; l != T; l = l->down) + if(l->sym != S) + Bprint(&outbuf, "#define\t%s.%s\t%ld\n", + s->name, + l->sym->name, + l->offset); + break; + } +} + +void +picklevar(Sym *s) +{ + int n; + Io *i; + Type *t; + Sym *s1, *s2; + + if(!debug['P'] || debug['s']) + return; + if(debug['P'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return; + } + t = s->type; + while(t && t->etype == TIND) + t = t->link; + if(t == T) + return; + if(t->etype == TENUM) { + Bprint(&outbuf, "%s = ", pmap(s->name)); + if(!typefd[t->etype]) + Bprint(&outbuf, "%lld;\n", s->vconst); + else + Bprint(&outbuf, "%f\n;", s->fconst); + return; + } + if(!typesu[t->etype]) + return; + s1 = picklesue(t->link); + if(s1 == S) + return; + switch(s->class) { + case CAUTO: + case CPARAM: + s2 = picklefun(thisfn); + if(s2) + Bprint(&outbuf, "complex %s %s:%s;\n", + pmap(s1->name), pmap(s2->name), pmap(s->name)); + break; + + case CSTATIC: + case CEXTERN: + case CGLOBL: + case CLOCAL: + Bprint(&outbuf, "complex %s %s;\n", + pmap(s1->name), pmap(s->name)); + break; + } +} diff --git a/src/cmd/cc/pswt.c b/src/cmd/cc/pswt.c new file mode 100644 index 0000000000..f4149f17b3 --- /dev/null +++ b/src/cmd/cc/pswt.c @@ -0,0 +1,168 @@ +// Inferno utils/6c/swt.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +int +swcmp(const void *a1, const void *a2) +{ + C1 *p1, *p2; + + p1 = (C1*)a1; + p2 = (C1*)a2; + if(p1->val < p2->val) + return -1; + return p1->val > p2->val; +} + +void +doswit(Node *n) +{ + Case *c; + C1 *q, *iq; + long def, nc, i, isv; + + def = 0; + nc = 0; + isv = 0; + for(c = cases; c->link != C; c = c->link) { + if(c->def) { + if(def) + diag(n, "more than one default in switch"); + def = c->label; + continue; + } + isv |= c->isv; + nc++; + } + if(isv && !typev[n->type->etype]) + warn(n, "32-bit switch expression with 64-bit case constant"); + + iq = alloc(nc*sizeof(C1)); + q = iq; + for(c = cases; c->link != C; c = c->link) { + if(c->def) + continue; + q->label = c->label; + if(isv) + q->val = c->val; + else + q->val = (long)c->val; /* cast ensures correct value for 32-bit switch on 64-bit architecture */ + q++; + } + qsort(iq, nc, sizeof(C1), swcmp); + if(debug['W']) + for(i=0; ilink = cases; + cases = c; +} + +long +outlstring(ushort *s, long n) +{ + char buf[2]; + int c; + long r; + + if(suppress) + return nstring; + while(nstring & 1) + outstring("", 1); + r = nstring; + while(n > 0) { + c = *s++; + if(align(0, types[TCHAR], Aarg1)) { + buf[0] = c>>8; + buf[1] = c; + } else { + buf[0] = c; + buf[1] = c>>8; + } + outstring(buf, 2); + n -= sizeof(ushort); + } + return r; +} + +void +nullwarn(Node *l, Node *r) +{ + warn(Z, "result of operation not used"); + if(l != Z) + cgen(l, Z); + if(r != Z) + cgen(r, Z); +} + +void +ieeedtod(Ieee *ieee, double native) +{ + double fr, ho, f; + int exp; + + if(native < 0) { + ieeedtod(ieee, -native); + ieee->h |= 0x80000000L; + return; + } + if(native == 0) { + ieee->l = 0; + ieee->h = 0; + return; + } + fr = frexp(native, &exp); + f = 2097152L; /* shouldnt use fp constants here */ + fr = modf(fr*f, &ho); + ieee->h = ho; + ieee->h &= 0xfffffL; + ieee->h |= (exp+1022L) << 20; + f = 65536L; + fr = modf(fr*f, &ho); + ieee->l = ho; + ieee->l <<= 16; + ieee->l |= (long)(fr*f); +} diff --git a/src/cmd/cc/scon.c b/src/cmd/cc/scon.c new file mode 100644 index 0000000000..3047ca44f6 --- /dev/null +++ b/src/cmd/cc/scon.c @@ -0,0 +1,636 @@ +// Inferno utils/cc/scon.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/scon.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +static Node* +acast(Type *t, Node *n) +{ + if(n->type->etype != t->etype || n->op == OBIT) { + n = new1(OCAST, n, Z); + if(nocast(n->left->type, t)) + *n = *n->left; + n->type = t; + } + return n; +} + + +void +evconst(Node *n) +{ + Node *l, *r; + int et, isf; + vlong v; + double d; + + if(n == Z || n->type == T) + return; + + et = n->type->etype; + isf = typefd[et]; + + l = n->left; + r = n->right; + + d = 0; + v = 0; + + switch(n->op) { + default: + return; + + case ONEG: + if(isf) + d = -l->fconst; + else + v = -l->vconst; + break; + + case OCOM: + v = ~l->vconst; + break; + + case OCAST: + if(et == TVOID) + return; + et = l->type->etype; + if(isf) { + if(typefd[et]) + d = l->fconst; + else + d = l->vconst; + } else { + if(typefd[et]) + v = l->fconst; + else + v = convvtox(l->vconst, n->type->etype); + } + break; + + case OCONST: + break; + + case OADD: + if(isf) + d = l->fconst + r->fconst; + else { + v = l->vconst + r->vconst; + } + break; + + case OSUB: + if(isf) + d = l->fconst - r->fconst; + else + v = l->vconst - r->vconst; + break; + + case OMUL: + if(isf) + d = l->fconst * r->fconst; + else { + v = l->vconst * r->vconst; + } + break; + + case OLMUL: + v = (uvlong)l->vconst * (uvlong)r->vconst; + break; + + + case ODIV: + if(vconst(r) == 0) { + warn(n, "divide by zero"); + return; + } + if(isf) + d = l->fconst / r->fconst; + else + v = l->vconst / r->vconst; + break; + + case OLDIV: + if(vconst(r) == 0) { + warn(n, "divide by zero"); + return; + } + v = (uvlong)l->vconst / (uvlong)r->vconst; + break; + + case OMOD: + if(vconst(r) == 0) { + warn(n, "modulo by zero"); + return; + } + v = l->vconst % r->vconst; + break; + + case OLMOD: + if(vconst(r) == 0) { + warn(n, "modulo by zero"); + return; + } + v = (uvlong)l->vconst % (uvlong)r->vconst; + break; + + case OAND: + v = l->vconst & r->vconst; + break; + + case OOR: + v = l->vconst | r->vconst; + break; + + case OXOR: + v = l->vconst ^ r->vconst; + break; + + case OLSHR: + v = (uvlong)l->vconst >> r->vconst; + break; + + case OASHR: + v = l->vconst >> r->vconst; + break; + + case OASHL: + v = l->vconst << r->vconst; + break; + + case OLO: + v = (uvlong)l->vconst < (uvlong)r->vconst; + break; + + case OLT: + if(typefd[l->type->etype]) + v = l->fconst < r->fconst; + else + v = l->vconst < r->vconst; + break; + + case OHI: + v = (uvlong)l->vconst > (uvlong)r->vconst; + break; + + case OGT: + if(typefd[l->type->etype]) + v = l->fconst > r->fconst; + else + v = l->vconst > r->vconst; + break; + + case OLS: + v = (uvlong)l->vconst <= (uvlong)r->vconst; + break; + + case OLE: + if(typefd[l->type->etype]) + v = l->fconst <= r->fconst; + else + v = l->vconst <= r->vconst; + break; + + case OHS: + v = (uvlong)l->vconst >= (uvlong)r->vconst; + break; + + case OGE: + if(typefd[l->type->etype]) + v = l->fconst >= r->fconst; + else + v = l->vconst >= r->vconst; + break; + + case OEQ: + if(typefd[l->type->etype]) + v = l->fconst == r->fconst; + else + v = l->vconst == r->vconst; + break; + + case ONE: + if(typefd[l->type->etype]) + v = l->fconst != r->fconst; + else + v = l->vconst != r->vconst; + break; + + case ONOT: + if(typefd[l->type->etype]) + v = !l->fconst; + else + v = !l->vconst; + break; + + case OANDAND: + if(typefd[l->type->etype]) + v = l->fconst && r->fconst; + else + v = l->vconst && r->vconst; + break; + + case OOROR: + if(typefd[l->type->etype]) + v = l->fconst || r->fconst; + else + v = l->vconst || r->vconst; + break; + } + if(isf) { + n->fconst = d; + } else { + n->vconst = convvtox(v, n->type->etype); + } + n->oldop = n->op; + n->op = OCONST; +} + +void +acom(Node *n) +{ + Type *t; + Node *l, *r; + int i; + + switch(n->op) + { + + case ONAME: + case OCONST: + case OSTRING: + case OINDREG: + case OREGISTER: + return; + + case ONEG: + l = n->left; + if(addo(n) && addo(l)) + break; + acom(l); + return; + + case OADD: + case OSUB: + case OMUL: + l = n->left; + r = n->right; + if(addo(n)) { + if(addo(r)) + break; + if(addo(l)) + break; + } + acom(l); + acom(r); + return; + + default: + l = n->left; + r = n->right; + if(l != Z) + acom(l); + if(r != Z) + acom(r); + return; + } + + /* bust terms out */ + t = n->type; + term[0].mult = 0; + term[0].node = Z; + nterm = 1; + acom1(1, n); + if(debug['m']) + for(i=0; itype = t; +} + +int +acomcmp1(const void *a1, const void *a2) +{ + vlong c1, c2; + Term *t1, *t2; + + t1 = (Term*)a1; + t2 = (Term*)a2; + c1 = t1->mult; + if(c1 < 0) + c1 = -c1; + c2 = t2->mult; + if(c2 < 0) + c2 = -c2; + if(c1 > c2) + return 1; + if(c1 < c2) + return -1; + c1 = 1; + if(t1->mult < 0) + c1 = 0; + c2 = 1; + if(t2->mult < 0) + c2 = 0; + if(c2 -= c1) + return c2; + if(t2 > t1) + return 1; + return -1; +} + +int +acomcmp2(const void *a1, const void *a2) +{ + vlong c1, c2; + Term *t1, *t2; + + t1 = (Term*)a1; + t2 = (Term*)a2; + c1 = t1->mult; + c2 = t2->mult; + if(c1 > c2) + return 1; + if(c1 < c2) + return -1; + if(t2 > t1) + return 1; + return -1; +} + +void +acom2(Node *n, Type *t) +{ + Node *l, *r; + Term trm[NTERM]; + int et, nt, i, j; + vlong c1, c2; + + /* + * copy into automatic + */ + c2 = 0; + nt = nterm; + for(i=0; ioldop = n->op; + n->op = OCONST; + n->vconst = c1; + return; + } + et = t->etype; + + /* + * prepare constant term, + * combine it with an addressing term + */ + if(c1 != 0) { + l = new1(OCONST, Z, Z); + l->type = t; + l->vconst = c1; + trm[0].mult = 1; + for(i=1; iop != OADDR) + continue; + r->type = t; + l = new1(OADD, r, l); + l->type = t; + trm[i].mult = 0; + break; + } + trm[0].node = l; + } + /* + * look for factorable terms + * c1*i + c1*c2*j -> c1*(i + c2*j) + */ + qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp1); + for(i=nt-1; i>=0; i--) { + c1 = trm[i].mult; + if(c1 < 0) + c1 = -c1; + if(c1 <= 1) + continue; + for(j=i+1; jtype->etype != et) + r = acast(t, r); + c2 = trm[j].mult/trm[i].mult; + if(c2 != 1 && c2 != -1) { + r = new1(OMUL, r, new(OCONST, Z, Z)); + r->type = t; + r->right->type = t; + r->right->vconst = c2; + } + l = trm[i].node; + if(l->type->etype != et) + l = acast(t, l); + r = new1(OADD, l, r); + r->type = t; + if(c2 == -1) + r->op = OSUB; + trm[i].node = r; + trm[j].mult = 0; + } + } + if(debug['m']) { + print("\n"); + for(i=0; i=0; i--) { + c1 = trm[i].mult; + if(c1 == 0) + continue; + r = trm[i].node; + if(r->type->etype != et || r->op == OBIT) + r = acast(t, r); + if(c1 != 1 && c1 != -1) { + r = new1(OMUL, r, new(OCONST, Z, Z)); + r->type = t; + r->right->type = t; + if(c1 < 0) { + r->right->vconst = -c1; + c1 = -1; + } else { + r->right->vconst = c1; + c1 = 1; + } + } + if(l == Z) { + l = r; + c2 = c1; + continue; + } + if(c1 < 0) + if(c2 < 0) + l = new1(OADD, l, r); + else + l = new1(OSUB, l, r); + else + if(c2 < 0) { + l = new1(OSUB, r, l); + c2 = 1; + } else + l = new1(OADD, l, r); + l->type = t; + } + if(c2 < 0) { + r = new1(OCONST, 0, 0); + r->vconst = 0; + r->type = t; + l = new1(OSUB, r, l); + l->type = t; + } + *n = *l; +} + +void +acom1(vlong v, Node *n) +{ + Node *l, *r; + + if(v == 0 || nterm >= NTERM) + return; + if(!addo(n)) { + if(n->op == OCONST) + if(!typefd[n->type->etype]) { + term[0].mult += v*n->vconst; + return; + } + term[nterm].mult = v; + term[nterm].node = n; + nterm++; + return; + } + switch(n->op) { + + case OCAST: + acom1(v, n->left); + break; + + case ONEG: + acom1(-v, n->left); + break; + + case OADD: + acom1(v, n->left); + acom1(v, n->right); + break; + + case OSUB: + acom1(v, n->left); + acom1(-v, n->right); + break; + + case OMUL: + l = n->left; + r = n->right; + if(l->op == OCONST) + if(!typefd[n->type->etype]) { + acom1(v*l->vconst, r); + break; + } + if(r->op == OCONST) + if(!typefd[n->type->etype]) { + acom1(v*r->vconst, l); + break; + } + break; + + default: + diag(n, "not addo"); + } +} + +int +addo(Node *n) +{ + + if(n != Z) + if(!typefd[n->type->etype]) + if(!typev[n->type->etype] || ewidth[TVLONG] == ewidth[TIND]) + switch(n->op) { + + case OCAST: + if(nilcast(n->left->type, n->type)) + return 1; + break; + + case ONEG: + case OADD: + case OSUB: + return 1; + + case OMUL: + if(n->left->op == OCONST) + return 1; + if(n->right->op == OCONST) + return 1; + } + return 0; +} diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c new file mode 100644 index 0000000000..fcf915cb8c --- /dev/null +++ b/src/cmd/cc/sub.c @@ -0,0 +1,2054 @@ +// Inferno utils/cc/sub.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/sub.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +Node* +new(int t, Node *l, Node *r) +{ + Node *n; + + n = alloc(sizeof(*n)); + n->op = t; + n->left = l; + n->right = r; + if(l && t != OGOTO) + n->lineno = l->lineno; + else if(r) + n->lineno = r->lineno; + else + n->lineno = lineno; + newflag = 1; + return n; +} + +Node* +new1(int o, Node *l, Node *r) +{ + Node *n; + + n = new(o, l, r); + n->lineno = nearln; + return n; +} + +void +prtree(Node *n, char *s) +{ + + print(" == %s ==\n", s); + prtree1(n, 0, 0); + print("\n"); +} + +void +prtree1(Node *n, int d, int f) +{ + int i; + + if(f) + for(i=0; iop == OLIST) { + prtree1(n->left, d, 0); + prtree1(n->right, d, 1); + return; + } + d++; + print("%O", n->op); + i = 3; + switch(n->op) + { + case ONAME: + print(" \"%F\"", n); + print(" %ld", n->xoffset); + i = 0; + break; + + case OINDREG: + print(" %ld(R%d)", n->xoffset, n->reg); + i = 0; + break; + + case OREGISTER: + if(n->xoffset) + print(" %ld+R%d", n->xoffset, n->reg); + else + print(" R%d", n->reg); + i = 0; + break; + + case OSTRING: + print(" \"%s\"", n->cstring); + i = 0; + break; + + case OLSTRING: + print(" \"%S\"", n->rstring); + i = 0; + break; + + case ODOT: + case OELEM: + print(" \"%F\"", n); + break; + + case OCONST: + if(typefd[n->type->etype]) + print(" \"%.8e\"", n->fconst); + else + print(" \"%lld\"", n->vconst); + i = 0; + break; + } + if(n->addable != 0) + print(" <%d>", n->addable); + if(n->type != T) + print(" %T", n->type); + if(n->complex != 0) + print(" (%d)", n->complex); + print(" %L\n", n->lineno); + if(i & 2) + prtree1(n->left, d, 1); + if(i & 1) + prtree1(n->right, d, 1); +} + +Type* +typ(int et, Type *d) +{ + Type *t; + + t = alloc(sizeof(*t)); + t->etype = et; + t->link = d; + t->down = T; + t->sym = S; + t->width = ewidth[et]; + t->offset = 0; + t->shift = 0; + t->nbits = 0; + t->garb = 0; + return t; +} + +Type* +copytyp(Type *t) +{ + Type *nt; + + nt = typ(TXXX, T); + *nt = *t; + return nt; +} + +Type* +garbt(Type *t, long b) +{ + Type *t1; + + if(b & BGARB) { + t1 = copytyp(t); + t1->garb = simpleg(b); + return t1; + } + return t; +} + +int +simpleg(long b) +{ + + b &= BGARB; + switch(b) { + case BCONSTNT: + return GCONSTNT; + case BVOLATILE: + return GVOLATILE; + case BVOLATILE|BCONSTNT: + return GCONSTNT|GVOLATILE; + } + return GXXX; +} + +int +simplec(long b) +{ + + b &= BCLASS; + switch(b) { + case 0: + case BREGISTER: + return CXXX; + case BAUTO: + case BAUTO|BREGISTER: + return CAUTO; + case BEXTERN: + return CEXTERN; + case BEXTERN|BREGISTER: + return CEXREG; + case BSTATIC: + return CSTATIC; + case BTYPEDEF: + return CTYPEDEF; + case BTYPESTR: + return CTYPESTR; + } + diag(Z, "illegal combination of classes %Q", b); + return CXXX; +} + +Type* +simplet(long b) +{ + + b &= ~BCLASS & ~BGARB; + switch(b) { + case BCHAR: + case BCHAR|BSIGNED: + return types[TCHAR]; + + case BCHAR|BUNSIGNED: + return types[TUCHAR]; + + case BSHORT: + case BSHORT|BINT: + case BSHORT|BSIGNED: + case BSHORT|BINT|BSIGNED: + return types[TSHORT]; + + case BUNSIGNED|BSHORT: + case BUNSIGNED|BSHORT|BINT: + return types[TUSHORT]; + + case 0: + case BINT: + case BINT|BSIGNED: + case BSIGNED: + return types[TINT]; + + case BUNSIGNED: + case BUNSIGNED|BINT: + return types[TUINT]; + + case BLONG: + case BLONG|BINT: + case BLONG|BSIGNED: + case BLONG|BINT|BSIGNED: + return types[TLONG]; + + case BUNSIGNED|BLONG: + case BUNSIGNED|BLONG|BINT: + return types[TULONG]; + + case BVLONG|BLONG: + case BVLONG|BLONG|BINT: + case BVLONG|BLONG|BSIGNED: + case BVLONG|BLONG|BINT|BSIGNED: + return types[TVLONG]; + + case BVLONG|BLONG|BUNSIGNED: + case BVLONG|BLONG|BINT|BUNSIGNED: + return types[TUVLONG]; + + case BFLOAT: + return types[TFLOAT]; + + case BDOUBLE: + case BDOUBLE|BLONG: + case BFLOAT|BLONG: + return types[TDOUBLE]; + + case BVOID: + return types[TVOID]; + } + + diag(Z, "illegal combination of types %Q", b); + return types[TINT]; +} + +int +stcompat(Node *n, Type *t1, Type *t2, long ttab[]) +{ + int i; + ulong b; + + i = 0; + if(t2 != T) + i = t2->etype; + b = 1L << i; + i = 0; + if(t1 != T) + i = t1->etype; + if(b & ttab[i]) { + if(ttab == tasign) + if(b == BSTRUCT || b == BUNION) + if(!sametype(t1, t2)) + return 1; + if(n->op != OCAST) + if(b == BIND && i == TIND) + if(!sametype(t1, t2)) + return 1; + return 0; + } + return 1; +} + +int +tcompat(Node *n, Type *t1, Type *t2, long ttab[]) +{ + + if(stcompat(n, t1, t2, ttab)) { + if(t1 == T) + diag(n, "incompatible type: \"%T\" for op \"%O\"", + t2, n->op); + else + diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"", + t1, t2, n->op); + return 1; + } + return 0; +} + +void +makedot(Node *n, Type *t, long o) +{ + Node *n1, *n2; + + if(t->nbits) { + n1 = new(OXXX, Z, Z); + *n1 = *n; + n->op = OBIT; + n->left = n1; + n->right = Z; + n->type = t; + n->addable = n1->left->addable; + n = n1; + } + n->addable = n->left->addable; + if(n->addable == 0) { + n1 = new1(OCONST, Z, Z); + n1->vconst = o; + n1->type = types[TLONG]; + n->right = n1; + n->type = t; + return; + } + n->left->type = t; + if(o == 0) { + *n = *n->left; + return; + } + n->type = t; + n1 = new1(OCONST, Z, Z); + n1->vconst = o; + t = typ(TIND, t); + t->width = types[TIND]->width; + n1->type = t; + + n2 = new1(OADDR, n->left, Z); + n2->type = t; + + n1 = new1(OADD, n1, n2); + n1->type = t; + + n->op = OIND; + n->left = n1; + n->right = Z; +} + +Type* +dotsearch(Sym *s, Type *t, Node *n, long *off) +{ + Type *t1, *xt, *rt; + + xt = T; + + /* + * look it up by name + */ + for(t1 = t; t1 != T; t1 = t1->down) + if(t1->sym == s) { + if(xt != T) + goto ambig; + xt = t1; + } + + /* + * look it up by type + */ + if(s->class == CTYPEDEF || s->class == CTYPESTR) + for(t1 = t; t1 != T; t1 = t1->down) + if(t1->sym == S && typesu[t1->etype]) + if(sametype(s->type, t1)) { + if(xt != T) + goto ambig; + xt = t1; + } + if(xt != T) { + *off = xt->offset; + return xt; + } + + /* + * look it up in unnamed substructures + */ + for(t1 = t; t1 != T; t1 = t1->down) + if(t1->sym == S && typesu[t1->etype]){ + rt = dotsearch(s, t1->link, n, off); + if(rt != T) { + if(xt != T) + goto ambig; + xt = rt; + *off += t1->offset; + } + } + return xt; + +ambig: + diag(n, "ambiguous structure element: %s", s->name); + return xt; +} + +long +dotoffset(Type *st, Type *lt, Node *n) +{ + Type *t; + Sym *g; + long o, o1; + + o = -1; + /* + * first try matching at the top level + * for matching tag names + */ + g = st->tag; + if(g != S) + for(t=lt->link; t!=T; t=t->down) + if(t->sym == S) + if(g == t->tag) { + if(o >= 0) + goto ambig; + o = t->offset; + } + if(o >= 0) + return o; + + /* + * second try matching at the top level + * for similar types + */ + for(t=lt->link; t!=T; t=t->down) + if(t->sym == S) + if(sametype(st, t)) { + if(o >= 0) + goto ambig; + o = t->offset; + } + if(o >= 0) + return o; + + /* + * last try matching sub-levels + */ + for(t=lt->link; t!=T; t=t->down) + if(t->sym == S) + if(typesu[t->etype]) { + o1 = dotoffset(st, t, n); + if(o1 >= 0) { + if(o >= 0) + goto ambig; + o = o1 + t->offset; + } + } + return o; + +ambig: + diag(n, "ambiguous unnamed structure element"); + return o; +} + +/* + * look into tree for floating point constant expressions + */ +int +allfloat(Node *n, int flag) +{ + + if(n != Z) { + if(n->type->etype != TDOUBLE) + return 1; + switch(n->op) { + case OCONST: + if(flag) + n->type = types[TFLOAT]; + return 1; + case OADD: /* no need to get more exotic than this */ + case OSUB: + case OMUL: + case ODIV: + if(!allfloat(n->right, flag)) + break; + case OCAST: + if(!allfloat(n->left, flag)) + break; + if(flag) + n->type = types[TFLOAT]; + return 1; + } + } + return 0; +} + +void +constas(Node *n, Type *il, Type *ir) +{ + Type *l, *r; + + l = il; + r = ir; + + if(l == T) + return; + if(l->garb & GCONSTNT) { + warn(n, "assignment to a constant type (%T)", il); + return; + } + if(r == T) + return; + for(;;) { + if(l->etype != TIND || r->etype != TIND) + break; + l = l->link; + r = r->link; + if(l == T || r == T) + break; + if(r->garb & GCONSTNT) + if(!(l->garb & GCONSTNT)) { + warn(n, "assignment of a constant pointer type (%T)", ir); + break; + } + } +} + +void +typeext1(Type *st, Node *l) +{ + if(st->etype == TFLOAT && allfloat(l, 0)) + allfloat(l, 1); +} + +void +typeext(Type *st, Node *l) +{ + Type *lt; + Node *n1, *n2; + long o; + + lt = l->type; + if(lt == T) + return; + if(st->etype == TIND && vconst(l) == 0) { + l->type = st; + l->vconst = 0; + return; + } + typeext1(st, l); + + /* + * extension of C + * if assign of struct containing unnamed sub-struct + * to type of sub-struct, insert the DOT. + * if assign of *struct containing unnamed substruct + * to type of *sub-struct, insert the add-offset + */ + if(typesu[st->etype] && typesu[lt->etype]) { + o = dotoffset(st, lt, l); + if(o >= 0) { + n1 = new1(OXXX, Z, Z); + *n1 = *l; + l->op = ODOT; + l->left = n1; + l->right = Z; + makedot(l, st, o); + } + return; + } + if(st->etype == TIND && typesu[st->link->etype]) + if(lt->etype == TIND && typesu[lt->link->etype]) { + o = dotoffset(st->link, lt->link, l); + if(o >= 0) { + l->type = st; + if(o == 0) + return; + n1 = new1(OXXX, Z, Z); + *n1 = *l; + n2 = new1(OCONST, Z, Z); + n2->vconst = o; + n2->type = st; + l->op = OADD; + l->left = n1; + l->right = n2; + } + return; + } +} + +/* + * a cast that generates no code + * (same size move) + */ +int +nocast(Type *t1, Type *t2) +{ + int i, b; + + if(t1->nbits) + return 0; + i = 0; + if(t2 != T) + i = t2->etype; + b = 1<etype; + if(b & ncast[i]) + return 1; + return 0; +} + +/* + * a cast that has a noop semantic + * (small to large, convert) + */ +int +nilcast(Type *t1, Type *t2) +{ + int et1, et2; + + if(t1 == T) + return 0; + if(t1->nbits) + return 0; + if(t2 == T) + return 0; + et1 = t1->etype; + et2 = t2->etype; + if(et1 == et2) + return 1; + if(typefd[et1] && typefd[et2]) { + if(ewidth[et1] < ewidth[et2]) + return 1; + return 0; + } + if(typechlp[et1] && typechlp[et2]) { + if(ewidth[et1] < ewidth[et2]) + return 1; + return 0; + } + return 0; +} + +/* + * "the usual arithmetic conversions are performed" + */ +void +arith(Node *n, int f) +{ + Type *t1, *t2; + int i, j, k; + Node *n1; + long w; + + t1 = n->left->type; + if(n->right == Z) + t2 = t1; + else + t2 = n->right->type; + i = TXXX; + if(t1 != T) + i = t1->etype; + j = TXXX; + if(t2 != T) + j = t2->etype; + k = tab[i][j]; + if(k == TIND) { + if(i == TIND) + n->type = t1; + else + if(j == TIND) + n->type = t2; + } else { + /* convert up to at least int */ + if(f == 1) + while(k < TINT) + k += 2; + n->type = types[k]; + } + if(n->op == OSUB) + if(i == TIND && j == TIND) { + w = n->right->type->link->width; + if(w < 1 || n->left->type->link == T || n->left->type->link->width < 1) + goto bad; + n->type = types[ewidth[TIND] <= ewidth[TLONG]? TLONG: TVLONG]; + if(1 && ewidth[TIND] > ewidth[TLONG]){ + n1 = new1(OXXX, Z, Z); + *n1 = *n; + n->op = OCAST; + n->left = n1; + n->right = Z; + n->type = types[TLONG]; + } + if(w > 1) { + n1 = new1(OXXX, Z, Z); + *n1 = *n; + n->op = ODIV; + n->left = n1; + n1 = new1(OCONST, Z, Z); + n1->vconst = w; + n1->type = n->type; + n->right = n1; + w = vlog(n1); + if(w >= 0) { + n->op = OASHR; + n1->vconst = w; + } + } + return; + } + if(!sametype(n->type, n->left->type)) { + n->left = new1(OCAST, n->left, Z); + n->left->type = n->type; + if(n->type->etype == TIND) { + w = n->type->link->width; + if(w < 1) { + snap(n->type->link); + w = n->type->link->width; + if(w < 1) + goto bad; + } + if(w > 1) { + n1 = new1(OCONST, Z, Z); + n1->vconst = w; + n1->type = n->type; + n->left = new1(OMUL, n->left, n1); + n->left->type = n->type; + } + } + } + if(n->right != Z) + if(!sametype(n->type, n->right->type)) { + n->right = new1(OCAST, n->right, Z); + n->right->type = n->type; + if(n->type->etype == TIND) { + w = n->type->link->width; + if(w < 1) { + snap(n->type->link); + w = n->type->link->width; + if(w < 1) + goto bad; + } + if(w != 1) { + n1 = new1(OCONST, Z, Z); + n1->vconst = w; + n1->type = n->type; + n->right = new1(OMUL, n->right, n1); + n->right->type = n->type; + } + } + } + return; +bad: + diag(n, "pointer addition not fully declared: %T", n->type->link); +} + +/* + * try to rewrite shift & mask + */ +void +simplifyshift(Node *n) +{ + ulong c3; + int o, s1, s2, c1, c2; + + if(!typechlp[n->type->etype]) + return; + switch(n->op) { + default: + return; + case OASHL: + s1 = 0; + break; + case OLSHR: + s1 = 1; + break; + case OASHR: + s1 = 2; + break; + } + if(n->right->op != OCONST) + return; + if(n->left->op != OAND) + return; + if(n->left->right->op != OCONST) + return; + switch(n->left->left->op) { + default: + return; + case OASHL: + s2 = 0; + break; + case OLSHR: + s2 = 1; + break; + case OASHR: + s2 = 2; + break; + } + if(n->left->left->right->op != OCONST) + return; + + c1 = n->right->vconst; + c2 = n->left->left->right->vconst; + c3 = n->left->right->vconst; + +/* + if(debug['h']) + print("%.3o %ld %ld %d #%.lux\n", + (s1<<3)|s2, c1, c2, topbit(c3), c3); +*/ + + o = n->op; + switch((s1<<3)|s2) { + case 000: /* (((e <>= c2; + c1 += c2; + if(c1 >= 32) + break; + goto rewrite1; + + case 002: /* (((e >>s c2) & c3) <= (32-c2)) + break; + case 001: /* (((e >>u c2) & c3) < c2) { + c3 <<= c2; + c1 -= c2; + o = OASHL; + goto rewrite1; + } + c3 <<= c1; + if(c1 == c2) + goto rewrite0; + c1 = c2-c1; + o = OLSHR; + goto rewrite2; + + case 022: /* (((e >>s c2) & c3) >>s c1) */ + if(c2 <= 0) + break; + case 012: /* (((e >>s c2) & c3) >>u c1) */ + if(topbit(c3) >= (32-c2)) + break; + goto s11; + case 021: /* (((e >>u c2) & c3) >>s c1) */ + if(topbit(c3) >= 31 && c2 <= 0) + break; + goto s11; + case 011: /* (((e >>u c2) & c3) >>u c1) */ + s11: + c3 <<= c2; + c1 += c2; + if(c1 >= 32) + break; + o = OLSHR; + goto rewrite1; + + case 020: /* (((e <>s c1) */ + if(topbit(c3) >= 31) + break; + case 010: /* (((e <>u c1) */ + c3 >>= c1; + if(c1 == c2) + goto rewrite0; + if(c1 > c2) { + c1 -= c2; + goto rewrite2; + } + c1 = c2 - c1; + o = OASHL; + goto rewrite2; + } + return; + +rewrite0: /* get rid of both shifts */ +if(debug['<'])prtree(n, "rewrite0"); + *n = *n->left; + n->left = n->left->left; + n->right->vconst = c3; + return; +rewrite1: /* get rid of lower shift */ +if(debug['<'])prtree(n, "rewrite1"); + n->left->left = n->left->left->left; + n->left->right->vconst = c3; + n->right->vconst = c1; + n->op = o; + return; +rewrite2: /* get rid of upper shift */ +if(debug['<'])prtree(n, "rewrite2"); + *n = *n->left; + n->right->vconst = c3; + n->left->right->vconst = c1; + n->left->op = o; +} + +int +side(Node *n) +{ + +loop: + if(n != Z) + switch(n->op) { + case OCAST: + case ONOT: + case OADDR: + case OIND: + n = n->left; + goto loop; + + case OCOND: + if(side(n->left)) + break; + n = n->right; + + case OEQ: + case ONE: + case OLT: + case OGE: + case OGT: + case OLE: + case OADD: + case OSUB: + case OMUL: + case OLMUL: + case ODIV: + case OLDIV: + case OLSHR: + case OASHL: + case OASHR: + case OAND: + case OOR: + case OXOR: + case OMOD: + case OLMOD: + case OANDAND: + case OOROR: + case OCOMMA: + case ODOT: + if(side(n->left)) + break; + n = n->right; + goto loop; + + case OSIGN: + case OSIZE: + case OCONST: + case OSTRING: + case OLSTRING: + case ONAME: + return 0; + } + return 1; +} + +int +vconst(Node *n) +{ + int i; + + if(n == Z) + goto no; + if(n->op != OCONST) + goto no; + if(n->type == T) + goto no; + switch(n->type->etype) + { + case TFLOAT: + case TDOUBLE: + i = 100; + if(n->fconst > i || n->fconst < -i) + goto no; + i = n->fconst; + if(i != n->fconst) + goto no; + return i; + + case TVLONG: + case TUVLONG: + i = n->vconst; + if(i != n->vconst) + goto no; + return i; + + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + i = n->vconst; + if(i != n->vconst) + goto no; + return i; + } +no: + return -159; /* first uninteresting constant */ +} + +/* + * return log(n) if n is a power of 2 constant + */ +int +xlog2(uvlong v) +{ + int s, i; + uvlong m; + + s = 0; + m = MASK(8*sizeof(uvlong)); + for(i=32; i; i>>=1) { + m >>= i; + if(!(v & m)) { + v >>= i; + s += i; + } + } + if(v == 1) + return s; + return -1; +} + +int +vlog(Node *n) +{ + if(n->op != OCONST) + goto bad; + if(typefd[n->type->etype]) + goto bad; + + return xlog2(n->vconst); + +bad: + return -1; +} + +int +topbit(ulong v) +{ + int i; + + for(i = -1; v; i++) + v >>= 1; + return i; +} + +/* + * try to cast a constant down + * rather than cast a variable up + * example: + * if(c == 'a') + */ +void +relcon(Node *l, Node *r) +{ + vlong v; + + if(l->op != OCONST) + return; + if(r->op != OCAST) + return; + if(!nilcast(r->left->type, r->type)) + return; + switch(r->type->etype) { + default: + return; + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + v = convvtox(l->vconst, r->type->etype); + if(v != l->vconst) + return; + break; + } + l->type = r->left->type; + *r = *r->left; +} + +int +relindex(int o) +{ + + switch(o) { + default: + diag(Z, "bad in relindex: %O", o); + case OEQ: return 0; + case ONE: return 1; + case OLE: return 2; + case OLS: return 3; + case OLT: return 4; + case OLO: return 5; + case OGE: return 6; + case OHS: return 7; + case OGT: return 8; + case OHI: return 9; + } +} + +Node* +invert(Node *n) +{ + Node *i; + + if(n == Z || n->op != OLIST) + return n; + i = n; + for(n = n->left; n != Z; n = n->left) { + if(n->op != OLIST) + break; + i->left = n->right; + n->right = i; + i = n; + } + i->left = n; + return i; +} + +int +bitno(long b) +{ + int i; + + for(i=0; i<32; i++) + if(b & (1L< vlong */ + else + warn(Z, "once is enough: %Q", a & b); + return c; +} + +void +diag(Node *n, char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf); + + if(debug['X']){ + Bflush(&diagbuf); + abort(); + } + if(n != Z) + if(debug['v']) + prtree(n, "diagnostic"); + + nerrors++; + if(nerrors > 10) { + Bprint(&diagbuf, "too many errors\n"); + errorexit(); + } +} + +void +warn(Node *n, char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + if(debug['w']) { + Bprint(&diagbuf, "warning: "); + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf); + + if(n != Z) + if(debug['v']) + prtree(n, "warning"); + } +} + +void +yyerror(char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + /* + * hack to intercept message from yaccpar + */ + if(strcmp(fmt, "syntax error") == 0) { + yyerror("syntax error, last name: %s", symb); + return; + } + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + Bprint(&diagbuf, "%L %s\n", lineno, buf); + nerrors++; + if(nerrors > 10) { + Bprint(&diagbuf, "too many errors\n"); + errorexit(); + } +} + +void +fatal(Node *n, char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf); + + if(debug['X']){ + Bflush(&diagbuf); + abort(); + } + if(n != Z) + if(debug['v']) + prtree(n, "diagnostic"); + + nerrors++; + errorexit(); +} + +ulong thash1 = 0x2edab8c9; +ulong thash2 = 0x1dc74fb8; +ulong thash3 = 0x1f241331; +ulong thash[NALLTYPES]; +Init thashinit[] = +{ + TXXX, 0x17527bbd, 0, + TCHAR, 0x5cedd32b, 0, + TUCHAR, 0x552c4454, 0, + TSHORT, 0x63040b4b, 0, + TUSHORT, 0x32a45878, 0, + TINT, 0x4151d5bd, 0, + TUINT, 0x5ae707d6, 0, + TLONG, 0x5ef20f47, 0, + TULONG, 0x36d8eb8f, 0, + TVLONG, 0x6e5e9590, 0, + TUVLONG, 0x75910105, 0, + TFLOAT, 0x25fd7af1, 0, + TDOUBLE, 0x7c40a1b2, 0, + TIND, 0x1b832357, 0, + TFUNC, 0x6babc9cb, 0, + TARRAY, 0x7c50986d, 0, + TVOID, 0x44112eff, 0, + TSTRUCT, 0x7c2da3bf, 0, + TUNION, 0x3eb25e98, 0, + TENUM, 0x44b54f61, 0, + TFILE, 0x19242ac3, 0, + TOLD, 0x22b15988, 0, + TDOT, 0x0204f6b3, 0, + -1, 0, 0, +}; + +char* bnames[NALIGN]; +Init bnamesinit[] = +{ + Axxx, 0, "Axxx", + Ael1, 0, "el1", + Ael2, 0, "el2", + Asu2, 0, "su2", + Aarg0, 0, "arg0", + Aarg1, 0, "arg1", + Aarg2, 0, "arg2", + Aaut3, 0, "aut3", + -1, 0, 0, +}; + +char* tnames[NALLTYPES]; +Init tnamesinit[] = +{ + TXXX, 0, "TXXX", + TCHAR, 0, "CHAR", + TUCHAR, 0, "UCHAR", + TSHORT, 0, "SHORT", + TUSHORT, 0, "USHORT", + TINT, 0, "INT", + TUINT, 0, "UINT", + TLONG, 0, "LONG", + TULONG, 0, "ULONG", + TVLONG, 0, "VLONG", + TUVLONG, 0, "UVLONG", + TFLOAT, 0, "FLOAT", + TDOUBLE, 0, "DOUBLE", + TIND, 0, "IND", + TFUNC, 0, "FUNC", + TARRAY, 0, "ARRAY", + TVOID, 0, "VOID", + TSTRUCT, 0, "STRUCT", + TUNION, 0, "UNION", + TENUM, 0, "ENUM", + TFILE, 0, "FILE", + TOLD, 0, "OLD", + TDOT, 0, "DOT", + -1, 0, 0, +}; + +char* gnames[NGTYPES]; +Init gnamesinit[] = +{ + GXXX, 0, "GXXX", + GCONSTNT, 0, "CONST", + GVOLATILE, 0, "VOLATILE", + GVOLATILE|GCONSTNT, 0, "CONST-VOLATILE", + -1, 0, 0, +}; + +char* qnames[NALLTYPES]; +Init qnamesinit[] = +{ + TXXX, 0, "TXXX", + TCHAR, 0, "CHAR", + TUCHAR, 0, "UCHAR", + TSHORT, 0, "SHORT", + TUSHORT, 0, "USHORT", + TINT, 0, "INT", + TUINT, 0, "UINT", + TLONG, 0, "LONG", + TULONG, 0, "ULONG", + TVLONG, 0, "VLONG", + TUVLONG, 0, "UVLONG", + TFLOAT, 0, "FLOAT", + TDOUBLE, 0, "DOUBLE", + TIND, 0, "IND", + TFUNC, 0, "FUNC", + TARRAY, 0, "ARRAY", + TVOID, 0, "VOID", + TSTRUCT, 0, "STRUCT", + TUNION, 0, "UNION", + TENUM, 0, "ENUM", + + TAUTO, 0, "AUTO", + TEXTERN, 0, "EXTERN", + TSTATIC, 0, "STATIC", + TTYPEDEF, 0, "TYPEDEF", + TTYPESTR, 0, "TYPESTR", + TREGISTER, 0, "REGISTER", + TCONSTNT, 0, "CONSTNT", + TVOLATILE, 0, "VOLATILE", + TUNSIGNED, 0, "UNSIGNED", + TSIGNED, 0, "SIGNED", + TDOT, 0, "DOT", + TFILE, 0, "FILE", + TOLD, 0, "OLD", + -1, 0, 0, +}; +char* cnames[NCTYPES]; +Init cnamesinit[] = +{ + CXXX, 0, "CXXX", + CAUTO, 0, "AUTO", + CEXTERN, 0, "EXTERN", + CGLOBL, 0, "GLOBL", + CSTATIC, 0, "STATIC", + CLOCAL, 0, "LOCAL", + CTYPEDEF, 0, "TYPEDEF", + CTYPESTR, 0, "TYPESTR", + CPARAM, 0, "PARAM", + CSELEM, 0, "SELEM", + CLABEL, 0, "LABEL", + CEXREG, 0, "EXREG", + -1, 0, 0, +}; + +char* onames[OEND+1]; +Init onamesinit[] = +{ + OXXX, 0, "OXXX", + OADD, 0, "ADD", + OADDR, 0, "ADDR", + OAND, 0, "AND", + OANDAND, 0, "ANDAND", + OARRAY, 0, "ARRAY", + OAS, 0, "AS", + OASI, 0, "ASI", + OASADD, 0, "ASADD", + OASAND, 0, "ASAND", + OASASHL, 0, "ASASHL", + OASASHR, 0, "ASASHR", + OASDIV, 0, "ASDIV", + OASHL, 0, "ASHL", + OASHR, 0, "ASHR", + OASLDIV, 0, "ASLDIV", + OASLMOD, 0, "ASLMOD", + OASLMUL, 0, "ASLMUL", + OASLSHR, 0, "ASLSHR", + OASMOD, 0, "ASMOD", + OASMUL, 0, "ASMUL", + OASOR, 0, "ASOR", + OASSUB, 0, "ASSUB", + OASXOR, 0, "ASXOR", + OBIT, 0, "BIT", + OBREAK, 0, "BREAK", + OCASE, 0, "CASE", + OCAST, 0, "CAST", + OCOMMA, 0, "COMMA", + OCOND, 0, "COND", + OCONST, 0, "CONST", + OCONTINUE, 0, "CONTINUE", + ODIV, 0, "DIV", + ODOT, 0, "DOT", + ODOTDOT, 0, "DOTDOT", + ODWHILE, 0, "DWHILE", + OENUM, 0, "ENUM", + OEQ, 0, "EQ", + OFOR, 0, "FOR", + OFUNC, 0, "FUNC", + OGE, 0, "GE", + OGOTO, 0, "GOTO", + OGT, 0, "GT", + OHI, 0, "HI", + OHS, 0, "HS", + OIF, 0, "IF", + OIND, 0, "IND", + OINDREG, 0, "INDREG", + OINIT, 0, "INIT", + OLABEL, 0, "LABEL", + OLDIV, 0, "LDIV", + OLE, 0, "LE", + OLIST, 0, "LIST", + OLMOD, 0, "LMOD", + OLMUL, 0, "LMUL", + OLO, 0, "LO", + OLS, 0, "LS", + OLSHR, 0, "LSHR", + OLT, 0, "LT", + OMOD, 0, "MOD", + OMUL, 0, "MUL", + ONAME, 0, "NAME", + ONE, 0, "NE", + ONOT, 0, "NOT", + OOR, 0, "OR", + OOROR, 0, "OROR", + OPOSTDEC, 0, "POSTDEC", + OPOSTINC, 0, "POSTINC", + OPREDEC, 0, "PREDEC", + OPREINC, 0, "PREINC", + OPROTO, 0, "PROTO", + OREGISTER, 0, "REGISTER", + ORETURN, 0, "RETURN", + OSET, 0, "SET", + OSIGN, 0, "SIGN", + OSIZE, 0, "SIZE", + OSTRING, 0, "STRING", + OLSTRING, 0, "LSTRING", + OSTRUCT, 0, "STRUCT", + OSUB, 0, "SUB", + OSWITCH, 0, "SWITCH", + OUNION, 0, "UNION", + OUSED, 0, "USED", + OWHILE, 0, "WHILE", + OXOR, 0, "XOR", + OPOS, 0, "POS", + ONEG, 0, "NEG", + OCOM, 0, "COM", + OELEM, 0, "ELEM", + OTST, 0, "TST", + OINDEX, 0, "INDEX", + OFAS, 0, "FAS", + OREGPAIR, 0, "REGPAIR", + OEND, 0, "END", + -1, 0, 0, +}; + +/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */ +uchar comrel[12] = +{ + ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS, +}; +uchar invrel[12] = +{ + OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO, +}; +uchar logrel[12] = +{ + OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI, +}; + +uchar typei[NTYPE]; +int typeiinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1, +}; +uchar typeu[NTYPE]; +int typeuinit[] = +{ + TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1, +}; + +uchar typesuv[NTYPE]; +int typesuvinit[] = +{ + TVLONG, TUVLONG, TSTRUCT, TUNION, -1, +}; + +uchar typeilp[NTYPE]; +int typeilpinit[] = +{ + TINT, TUINT, TLONG, TULONG, TIND, -1 +}; + +uchar typechl[NTYPE]; +uchar typechlv[NTYPE]; +uchar typechlvp[NTYPE]; +int typechlinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1, +}; + +uchar typechlp[NTYPE]; +int typechlpinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1, +}; + +uchar typechlpfd[NTYPE]; +int typechlpfdinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1, +}; + +uchar typec[NTYPE]; +int typecinit[] = +{ + TCHAR, TUCHAR, -1 +}; + +uchar typeh[NTYPE]; +int typehinit[] = +{ + TSHORT, TUSHORT, -1, +}; + +uchar typeil[NTYPE]; +int typeilinit[] = +{ + TINT, TUINT, TLONG, TULONG, -1, +}; + +uchar typev[NTYPE]; +int typevinit[] = +{ + TVLONG, TUVLONG, -1, +}; + +uchar typefd[NTYPE]; +int typefdinit[] = +{ + TFLOAT, TDOUBLE, -1, +}; + +uchar typeaf[NTYPE]; +int typeafinit[] = +{ + TFUNC, TARRAY, -1, +}; + +uchar typesu[NTYPE]; +int typesuinit[] = +{ + TSTRUCT, TUNION, -1, +}; + +long tasign[NTYPE]; +Init tasigninit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BIND, 0, + TSTRUCT, BSTRUCT, 0, + TUNION, BUNION, 0, + -1, 0, 0, +}; + +long tasadd[NTYPE]; +Init tasaddinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BINTEGER, 0, + -1, 0, 0, +}; + +long tcast[NTYPE]; +Init tcastinit[] = +{ + TCHAR, BNUMBER|BIND|BVOID, 0, + TUCHAR, BNUMBER|BIND|BVOID, 0, + TSHORT, BNUMBER|BIND|BVOID, 0, + TUSHORT, BNUMBER|BIND|BVOID, 0, + TINT, BNUMBER|BIND|BVOID, 0, + TUINT, BNUMBER|BIND|BVOID, 0, + TLONG, BNUMBER|BIND|BVOID, 0, + TULONG, BNUMBER|BIND|BVOID, 0, + TVLONG, BNUMBER|BIND|BVOID, 0, + TUVLONG, BNUMBER|BIND|BVOID, 0, + TFLOAT, BNUMBER|BVOID, 0, + TDOUBLE, BNUMBER|BVOID, 0, + TIND, BINTEGER|BIND|BVOID, 0, + TVOID, BVOID, 0, + TSTRUCT, BSTRUCT|BVOID, 0, + TUNION, BUNION|BVOID, 0, + -1, 0, 0, +}; + +long tadd[NTYPE]; +Init taddinit[] = +{ + TCHAR, BNUMBER|BIND, 0, + TUCHAR, BNUMBER|BIND, 0, + TSHORT, BNUMBER|BIND, 0, + TUSHORT, BNUMBER|BIND, 0, + TINT, BNUMBER|BIND, 0, + TUINT, BNUMBER|BIND, 0, + TLONG, BNUMBER|BIND, 0, + TULONG, BNUMBER|BIND, 0, + TVLONG, BNUMBER|BIND, 0, + TUVLONG, BNUMBER|BIND, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BINTEGER, 0, + -1, 0, 0, +}; + +long tsub[NTYPE]; +Init tsubinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BINTEGER|BIND, 0, + -1, 0, 0, +}; + +long tmul[NTYPE]; +Init tmulinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + -1, 0, 0, +}; + +long tand[NTYPE]; +Init tandinit[] = +{ + TCHAR, BINTEGER, 0, + TUCHAR, BINTEGER, 0, + TSHORT, BINTEGER, 0, + TUSHORT, BINTEGER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BINTEGER, 0, + TULONG, BINTEGER, 0, + TVLONG, BINTEGER, 0, + TUVLONG, BINTEGER, 0, + -1, 0, 0, +}; + +long trel[NTYPE]; +Init trelinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BIND, 0, + -1, 0, 0, +}; + +long tfunct[1] = +{ + BFUNC, +}; + +long tindir[1] = +{ + BIND, +}; + +long tdot[1] = +{ + BSTRUCT|BUNION, +}; + +long tnot[1] = +{ + BNUMBER|BIND, +}; + +long targ[1] = +{ + BNUMBER|BIND|BSTRUCT|BUNION, +}; + +uchar tab[NTYPE][NTYPE] = +{ +/*TXXX*/ { 0, + }, + +/*TCHAR*/ { 0, TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUCHAR*/ { 0, TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TSHORT*/ { 0, TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUSHORT*/ { 0, TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TINT*/ { 0, TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUINT*/ { 0, TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TLONG*/ { 0, TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TULONG*/ { 0, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TVLONG*/ { 0, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, + TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUVLONG*/ { 0, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, + TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TFLOAT*/ { 0, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, + TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND, + }, +/*TDOUBLE*/ { 0, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, + TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND, + }, +/*TIND*/ { 0, TIND, TIND, TIND, TIND, TIND, TIND, TIND, + TIND, TIND, TIND, TIND, TIND, TIND, + }, +}; + +void +urk(char *name, int max, int i) +{ + if(i >= max) { + fprint(2, "bad tinit: %s %d>=%d\n", name, i, max); + exits("init"); + } +} + +void +tinit(void) +{ + int *ip; + Init *p; + + for(p=thashinit; p->code >= 0; p++) { + urk("thash", nelem(thash), p->code); + thash[p->code] = p->value; + } + for(p=bnamesinit; p->code >= 0; p++) { + urk("bnames", nelem(bnames), p->code); + bnames[p->code] = p->s; + } + for(p=tnamesinit; p->code >= 0; p++) { + urk("tnames", nelem(tnames), p->code); + tnames[p->code] = p->s; + } + for(p=gnamesinit; p->code >= 0; p++) { + urk("gnames", nelem(gnames), p->code); + gnames[p->code] = p->s; + } + for(p=qnamesinit; p->code >= 0; p++) { + urk("qnames", nelem(qnames), p->code); + qnames[p->code] = p->s; + } + for(p=cnamesinit; p->code >= 0; p++) { + urk("cnames", nelem(cnames), p->code); + cnames[p->code] = p->s; + } + for(p=onamesinit; p->code >= 0; p++) { + urk("onames", nelem(onames), p->code); + onames[p->code] = p->s; + } + for(ip=typeiinit; *ip>=0; ip++) { + urk("typei", nelem(typei), *ip); + typei[*ip] = 1; + } + for(ip=typeuinit; *ip>=0; ip++) { + urk("typeu", nelem(typeu), *ip); + typeu[*ip] = 1; + } + for(ip=typesuvinit; *ip>=0; ip++) { + urk("typesuv", nelem(typesuv), *ip); + typesuv[*ip] = 1; + } + for(ip=typeilpinit; *ip>=0; ip++) { + urk("typeilp", nelem(typeilp), *ip); + typeilp[*ip] = 1; + } + for(ip=typechlinit; *ip>=0; ip++) { + urk("typechl", nelem(typechl), *ip); + typechl[*ip] = 1; + typechlv[*ip] = 1; + typechlvp[*ip] = 1; + } + for(ip=typechlpinit; *ip>=0; ip++) { + urk("typechlp", nelem(typechlp), *ip); + typechlp[*ip] = 1; + typechlvp[*ip] = 1; + } + for(ip=typechlpfdinit; *ip>=0; ip++) { + urk("typechlpfd", nelem(typechlpfd), *ip); + typechlpfd[*ip] = 1; + } + for(ip=typecinit; *ip>=0; ip++) { + urk("typec", nelem(typec), *ip); + typec[*ip] = 1; + } + for(ip=typehinit; *ip>=0; ip++) { + urk("typeh", nelem(typeh), *ip); + typeh[*ip] = 1; + } + for(ip=typeilinit; *ip>=0; ip++) { + urk("typeil", nelem(typeil), *ip); + typeil[*ip] = 1; + } + for(ip=typevinit; *ip>=0; ip++) { + urk("typev", nelem(typev), *ip); + typev[*ip] = 1; + typechlv[*ip] = 1; + typechlvp[*ip] = 1; + } + for(ip=typefdinit; *ip>=0; ip++) { + urk("typefd", nelem(typefd), *ip); + typefd[*ip] = 1; + } + for(ip=typeafinit; *ip>=0; ip++) { + urk("typeaf", nelem(typeaf), *ip); + typeaf[*ip] = 1; + } + for(ip=typesuinit; *ip >= 0; ip++) { + urk("typesu", nelem(typesu), *ip); + typesu[*ip] = 1; + } + for(p=tasigninit; p->code >= 0; p++) { + urk("tasign", nelem(tasign), p->code); + tasign[p->code] = p->value; + } + for(p=tasaddinit; p->code >= 0; p++) { + urk("tasadd", nelem(tasadd), p->code); + tasadd[p->code] = p->value; + } + for(p=tcastinit; p->code >= 0; p++) { + urk("tcast", nelem(tcast), p->code); + tcast[p->code] = p->value; + } + for(p=taddinit; p->code >= 0; p++) { + urk("tadd", nelem(tadd), p->code); + tadd[p->code] = p->value; + } + for(p=tsubinit; p->code >= 0; p++) { + urk("tsub", nelem(tsub), p->code); + tsub[p->code] = p->value; + } + for(p=tmulinit; p->code >= 0; p++) { + urk("tmul", nelem(tmul), p->code); + tmul[p->code] = p->value; + } + for(p=tandinit; p->code >= 0; p++) { + urk("tand", nelem(tand), p->code); + tand[p->code] = p->value; + } + for(p=trelinit; p->code >= 0; p++) { + urk("trel", nelem(trel), p->code); + trel[p->code] = p->value; + } + + /* 32-bit defaults */ + typeword = typechlp; + typecmplx = typesuv; +} + +/* + * return 1 if it is impossible to jump into the middle of n. + */ +static int +deadhead(Node *n, int caseok) +{ +loop: + if(n == Z) + return 1; + switch(n->op) { + case OLIST: + if(!deadhead(n->left, caseok)) + return 0; + rloop: + n = n->right; + goto loop; + + case ORETURN: + break; + + case OLABEL: + return 0; + + case OGOTO: + break; + + case OCASE: + if(!caseok) + return 0; + goto rloop; + + case OSWITCH: + return deadhead(n->right, 1); + + case OWHILE: + case ODWHILE: + goto rloop; + + case OFOR: + goto rloop; + + case OCONTINUE: + break; + + case OBREAK: + break; + + case OIF: + return deadhead(n->right->left, caseok) && deadhead(n->right->right, caseok); + + case OSET: + case OUSED: + break; + } + return 1; +} + +int +deadheads(Node *c) +{ + return deadhead(c->left, 0) && deadhead(c->right, 0); +} + +int +mixedasop(Type *l, Type *r) +{ + return !typefd[l->etype] && typefd[r->etype]; +} diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c new file mode 100644 index 0000000000..cc8e7321a0 --- /dev/null +++ b/src/cmd/gc/const.c @@ -0,0 +1,370 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go.h" +#define TUP(x,y) (((x)<<16)|(y)) + +void +convlit(Node *n, Type *t) +{ + int et; + + if(n->op != OLITERAL) + return; + if(t == T) + return; + + n->type = t; + et = t->etype; + + switch(whatis(n)) { + case Wlitint: + if(isptrto(t, TSTRING)) { + Rune rune; + int l; + String *s; + + rune = n->val.vval; + l = runelen(rune); + s = mal(sizeof(*s)+l); + s->len = l; + runetochar((char*)(s->s), &rune); + + n->val.sval = s; + n->val.ctype = CTSTR; + break; + } + if(isint[et]) { + if(n->val.vval < minintval[et]) + goto bad2; + if(n->val.vval > maxintval[et]) + goto bad2; + break; + } + if(isfloat[et]) { + if(n->val.vval < minfloatval[et]) + goto bad2; + if(n->val.vval > maxfloatval[et]) + goto bad2; + n->val.dval = n->val.vval; + n->val.ctype = CTFLT; + break; + } + goto bad1; + + case Wlitfloat: + if(isint[et]) { + if(n->val.dval < minintval[et]) + goto bad2; + if(n->val.dval > maxintval[et]) + goto bad2; + n->val.vval = n->val.dval; + n->val.ctype = CTINT; + break; + } + if(isfloat[et]) { + if(n->val.dval < minfloatval[et]) + goto bad2; + if(n->val.dval > maxfloatval[et]) + goto bad2; + break; + } + goto bad1; + } + return; + +bad1: + yyerror("illegal conversion of constant to %T", t); + return; + +bad2: + yyerror("overflow converting constant to %T", t); + return; +} + +void +evconst(Node *n) +{ + Node *nl, *nr; + long len; + String *str; + int wl, wr; + + nl = n->left; + if(nl == N) + return; + + wl = whatis(nl); + switch(wl) { + default: + return; + + case Wlitint: + case Wlitfloat: + case Wlitbool: + case Wlitstr: + break; + } + + nr = n->right; + if(nr == N) + goto unary; + + wr = whatis(nr); + switch(wr) { + default: + return; + + case Wlitint: + case Wlitfloat: + case Wlitbool: + case Wlitstr: + break; + } + if(wl != wr) { + yyerror("illegal combination of literals %d %d", nl->etype, nr->etype); + return; + } + + switch(TUP(n->op, wl)) { + default: + yyerror("illegal combination of literals %O %d", n->op, wl); + return; + + case TUP(OADD, Wlitint): + nl->val.vval += nr->val.vval; + break; + case TUP(OSUB, Wlitint): + nl->val.vval -= nr->val.vval; + break; + case TUP(OMUL, Wlitint): + nl->val.vval *= nr->val.vval; + break; + case TUP(ODIV, Wlitint): + nl->val.vval /= nr->val.vval; + break; + case TUP(OMOD, Wlitint): + nl->val.vval %= nr->val.vval; + break; + case TUP(OLSH, Wlitint): + nl->val.vval <<= nr->val.vval; + break; + case TUP(ORSH, Wlitint): + nl->val.vval >>= nr->val.vval; + break; + case TUP(OOR, Wlitint): + nl->val.vval |= nr->val.vval; + break; + case TUP(OAND, Wlitint): + nl->val.vval &= nr->val.vval; + break; + + case TUP(OADD, Wlitfloat): + nl->val.dval += nr->val.dval; + break; + case TUP(OSUB, Wlitfloat): + nl->val.dval -= nr->val.dval; + break; + case TUP(OMUL, Wlitfloat): + nl->val.dval *= nr->val.dval; + break; + case TUP(ODIV, Wlitfloat): + nl->val.dval /= nr->val.dval; + break; + + case TUP(OEQ, Wlitint): + if(nl->val.vval == nr->val.vval) + goto settrue; + goto setfalse; + case TUP(ONE, Wlitint): + if(nl->val.vval != nr->val.vval) + goto settrue; + goto setfalse; + case TUP(OLT, Wlitint): + if(nl->val.vval < nr->val.vval) + goto settrue; + goto setfalse; + case TUP(OLE, Wlitint): + if(nl->val.vval <= nr->val.vval) + goto settrue; + goto setfalse; + case TUP(OGE, Wlitint): + if(nl->val.vval >= nr->val.vval) + goto settrue; + goto setfalse; + case TUP(OGT, Wlitint): + if(nl->val.vval > nr->val.vval) + goto settrue; + goto setfalse; + + case TUP(OEQ, Wlitfloat): + if(nl->val.dval == nr->val.dval) + goto settrue; + goto setfalse; + case TUP(ONE, Wlitfloat): + if(nl->val.dval != nr->val.dval) + goto settrue; + goto setfalse; + case TUP(OLT, Wlitfloat): + if(nl->val.dval < nr->val.dval) + goto settrue; + goto setfalse; + case TUP(OLE, Wlitfloat): + if(nl->val.dval <= nr->val.dval) + goto settrue; + goto setfalse; + case TUP(OGE, Wlitfloat): + if(nl->val.dval >= nr->val.dval) + goto settrue; + goto setfalse; + case TUP(OGT, Wlitfloat): + if(nl->val.dval > nr->val.dval) + goto settrue; + goto setfalse; + + + case TUP(OEQ, Wlitstr): + if(cmpslit(nl, nr) == 0) + goto settrue; + goto setfalse; + case TUP(ONE, Wlitstr): + if(cmpslit(nl, nr) != 0) + goto settrue; + goto setfalse; + case TUP(OLT, Wlitstr): + if(cmpslit(nl, nr) < 0) + goto settrue; + goto setfalse; + case TUP(OLE, Wlitstr): + if(cmpslit(nl, nr) <= 0) + goto settrue; + goto setfalse; + case TUP(OGE, Wlitstr): + if(cmpslit(nl, nr) >= 0l) + goto settrue; + goto setfalse; + case TUP(OGT, Wlitstr): + if(cmpslit(nl, nr) > 0) + goto settrue; + goto setfalse; + case TUP(OADD, Wlitstr): + len = nl->val.sval->len + nr->val.sval->len; + str = mal(sizeof(*str) + len); + str->len = len; + memcpy(str->s, nl->val.sval->s, nl->val.sval->len); + memcpy(str->s+nl->val.sval->len, nr->val.sval->s, nr->val.sval->len); + str->len = len; + nl->val.sval = str; + break; + + case TUP(OOROR, Wlitbool): + if(nl->val.vval || nr->val.vval) + goto settrue; + goto setfalse; + case TUP(OANDAND, Wlitbool): + if(nl->val.vval && nr->val.vval) + goto settrue; + goto setfalse; + } + *n = *nl; + return; + +settrue: + *n = *booltrue; + return; + +setfalse: + *n = *boolfalse; + return; + +unary: + switch(TUP(n->op, wl)) { + default: + yyerror("illegal combination of literals %O %d", n->op, wl); + return; + + case TUP(OPLUS, Wlitint): + nl->val.vval = +nl->val.vval; + break; + case TUP(OMINUS, Wlitint): + nl->val.vval = -nl->val.vval; + break; + case TUP(OCOM, Wlitint): + nl->val.vval = ~nl->val.vval; + break; + + case TUP(OPLUS, Wlitfloat): + nl->val.dval = +nl->val.dval; + break; + case TUP(OMINUS, Wlitfloat): + nl->val.dval = -nl->val.dval; + break; + + case TUP(ONOT, Wlitbool): + if(nl->val.vval) + goto settrue; + goto setfalse; + } + *n = *nl; +} + +void +defaultlit(Node *n) +{ + if(n == N) + return; + if(n->type != T) + return; + if(n->op != OLITERAL) + return; + + switch(n->val.ctype) { + default: + yyerror("defaultlit: unknown literal: %N", n); + break; + case CTINT: + case CTSINT: + case CTUINT: + n->type = types[TINT32]; + break; + case CTFLT: + n->type = types[TFLOAT64]; + break; + case CTBOOL: + n->type = types[TBOOL]; + break; + case CTSTR: + n->type = types[TSTRING]; + break; + } +} + +int +cmpslit(Node *l, Node *r) +{ + long l1, l2, i, m; + char *s1, *s2; + + l1 = l->val.sval->len; + l2 = r->val.sval->len; + s1 = l->val.sval->s; + s2 = r->val.sval->s; + + m = l1; + if(l2 < m) + m = l2; + + for(i=0; i s2[i]) + return +1; + return -1; + } + if(l1 == l2) + return 0; + if(l1 > l2) + return +1; + return -1; +} diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c new file mode 100644 index 0000000000..3eae5f33b6 --- /dev/null +++ b/src/cmd/gc/dcl.c @@ -0,0 +1,814 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go.h" +#include "y.tab.h" + +void +dodclvar(Node *n, Type *t) +{ + +loop: + if(n == N) + return; + + if(n->op == OLIST) { + dodclvar(n->left, t); + n = n->right; + goto loop; + } + + addvar(n, t, dclcontext); +} + +void +dodcltype(Type *n, Type *t) +{ + + if(n == T) + return; + addtyp(n, t, dclcontext); +} + +void +dodclconst(Node *n, Node *e) +{ + Sym *s; + Dcl *r, *d; + +loop: + if(n == N) + return; + if(n->op == OLIST) { + dodclconst(n->left, e); + n = n->right; + goto loop; + } + + if(n->op != ONAME) + fatal("dodclconst: not a name"); + + if(e->op != OLITERAL) { + yyerror("expression must be a constant"); + goto loop; + } + s = n->sym; + + s->oconst = e; + s->lexical = LACONST; + + r = autodcl; + if(dclcontext == PEXTERN) + r = externdcl; + + d = dcl(); + d->dsym = s; + d->dnode = e; + d->op = OCONST; + + r->back->forw = d; + r->back = d; + + if(debug['d']) + print("const-dcl %S %N\n", n->sym, n->sym->oconst); +} + +/* + * return nelem of list + */ +int +listcount(Node *n) +{ + int v; + + v = 0; + while(n != N) { + v++; + if(n->op != OLIST) + break; + n = n->right; + } + return v; +} + +/* + * turn a parsed function declaration + * into a type + */ +Type* +functype(Node *this, Node *in, Node *out) +{ + Type *t; + + t = typ(TFUNC); + + t->type = dostruct(this, TSTRUCT); + t->type->down = dostruct(out, TSTRUCT); + t->type->down->down = dostruct(in, TSTRUCT); + + t->thistuple = listcount(this); + t->outtuple = listcount(out); + t->intuple = listcount(in); + + dowidth(t); + return t; +} + +void +funcnam(Type *t, char *nam) +{ + Node *n; + Sym *s; + char buf[100]; + + if(nam == nil) { + vargen++; + snprint(buf, sizeof(buf), "_f%.3ld", vargen); + nam = buf; + } + + if(t->etype != TFUNC) + fatal("funcnam: not func %T\n", t); + + if(t->thistuple > 0) { + vargen++; + snprint(namebuf, sizeof(namebuf), "_t%.3ld", vargen); + s = lookup(namebuf); + addtyp(newtype(s), t->type, PEXTERN); + n = newname(s); + n->vargen = vargen; + t->type->nname = n; + } + if(t->outtuple > 0) { + vargen++; + snprint(namebuf, sizeof(namebuf), "_o%.3ld", vargen); + s = lookup(namebuf); + addtyp(newtype(s), t->type->down, PEXTERN); + n = newname(s); + n->vargen = vargen; + t->type->down->nname = n; + } + if(t->intuple > 0) { + vargen++; + snprint(namebuf, sizeof(namebuf), "_i%.3ld", vargen); + s = lookup(namebuf); + addtyp(newtype(s), t->type->down->down, PEXTERN); + n = newname(s); + n->vargen = vargen; + t->type->down->down->nname = n; + } +} + +int +methcmp(Type *t1, Type *t2) +{ + if(t1->etype != TFUNC) + return 0; + if(t2->etype != TFUNC) + return 0; + + t1 = t1->type->down; // skip this arg + t2 = t2->type->down; // skip this arg + for(;;) { + if(t1 == t2) + break; + if(t1 == T || t2 == T) + return 0; + if(t1->etype != TSTRUCT || t2->etype != TSTRUCT) + return 0; + + if(!eqtype(t1->type, t2->type, 0)) + return 0; + + t1 = t1->down; + t2 = t2->down; + } + return 1; +} + +Node* +methodname(Node *n, Type *t) +{ + if(isptr[t->etype]) + t = t->type; + if(t->etype != TSTRUCT) + goto bad; + if(t->sym == S) + goto bad; + + snprint(namebuf, sizeof(namebuf), "%s_%s", t->sym->name, n->sym->name); + return newname(lookup(namebuf)); + +bad: + yyerror("illegal pointer"); + return n; +} + +/* + * add a method, declared as a function, + * into the structure + */ +void +addmethod(Node *n, Type *pa, Type *t) +{ + Type *f, *d, *p; + Sym *s; + + if(n->op != ONAME) + goto bad; + s = n->sym; + if(s == S) + goto bad; + if(pa == T) + goto bad; + if(!isptr[pa->etype]) + goto bad; + p = pa->type; + if(p == T) + goto bad; + if(p->etype != TSTRUCT) + goto bad; + if(p->sym == S) + goto bad; + + if(p->type == T) { + n = nod(ODCLFIELD, newname(s), N); + n->type = t; + + stotype(n, &p->type); + return; + } + + d = T; // last found + for(f=p->type; f!=T; f=f->down) { + if(f->etype != TFIELD) + fatal("addmethod: not TFIELD: %N", f); + + if(strcmp(s->name, f->sym->name) != 0) { + d = f; + continue; + } + + // if a field matches a non-this function + // then delete it and let it be redeclared + if(methcmp(t, f->type)) { + if(d == T) { + p->type = f->down; + continue; + } + d->down = f->down; + continue; + } + if(!eqtype(t, f->type, 0)) + yyerror("field redeclared as method: %S", s); + return; + } + + n = nod(ODCLFIELD, newname(s), N); + n->type = t; + + if(d == T) + stotype(n, &p->type); + else + stotype(n, &d->down); + return; + +bad: + yyerror("unknown method pointer: %T", pa); +} + +/* + * declare the function proper. + * and declare the arguments + * called in extern-declaration context + * returns in auto-declaration context. + */ +void +funchdr(Node *n) +{ + Node *on; + Sym *s; + + s = n->nname->sym; + on = s->oname; + + // check for same types + if(on != N) { + if(eqtype(n->type, on->type, 0)) { + if(!eqargs(n->type, on->type)) + yyerror("foreward declarations not the same: %S", s); + } else { + yyerror("redeclare of function: %S", s); + on = N; + } + } + + // check for foreward declaration + if(on == N) { + // initial declaration or redeclaration + // declare fun name, argument types and argument names + funcnam(n->type, s->name); + n->nname->type = n->type; + if(n->type->thistuple == 0) + addvar(n->nname, n->type, PEXTERN); + else + n->nname->class = PEXTERN; + } else { + // identical redeclaration + // steal previous names + n->nname = on; + n->type = on->type; + n->class = on->class; + n->sym = s; + if(debug['d']) + print("forew var-dcl %S %T\n", n->sym, n->type); + } + + // change the declaration context from extern to auto + autodcl = dcl(); + autodcl->back = autodcl; + + if(dclcontext != PEXTERN) + fatal("funchdr: dclcontext"); + + dclcontext = PAUTO; + markdcl("func"); + funcargs(n->type); + + if(n->type->thistuple > 0) { + Type *t; + t = *getthis(n->type); + addmethod(n->nname, t->type->type, n->type); + } +} + +void +funcargs(Type *t) +{ + Type *n1; + Iter save; + + // declare the this argument + n1 = funcfirst(&save, t); + while(n1 != T) { + if(n1->nname != N) + addvar(n1->nname, n1->type, PPARAM); + n1 = funcnext(&save); + } + + // declare the outgoing arguments +// n1 = structfirst(&save, getoutarg(t)); +// while(n1 != T) { +// n1->left = newname(n1->sym); +// if(n1->nname != N) +// addvar(n1->nname, n1->type, PPARAM); +// n1 = structnext(&save); +// } +} + +/* + * compile the function. + * called in auto-declaration context. + * returns in extern-declaration context. + */ +void +funcbody(Node *n) +{ + + compile(n); + + // change the declaration context from auto to extern + if(dclcontext != PAUTO) + fatal("funcbody: dclcontext"); + popdcl("func"); + dclcontext = PEXTERN; +} + +/* + * turn a parsed struct into a type + */ +Type** +stotype(Node *n, Type **t) +{ + Type *f; + Iter save; + + n = listfirst(&save, &n); + +loop: + if(n == N) { + *t = T; + return t; + } + + if(n->op == OLIST) { + // recursive because it can be lists of lists + t = stotype(n, t); + goto next; + } + + if(n->op != ODCLFIELD || n->type == T) + fatal("stotype: oops %N\n", n); + + if(n->type->etype == TDARRAY) + yyerror("type of a structure field cannot be an open array"); + + f = typ(TFIELD); + f->type = n->type; + + if(n->left != N && n->left->op == ONAME) { + f->nname = n->left; + } else { + vargen++; + snprint(namebuf, sizeof(namebuf), "_e%.3ld", vargen); + f->nname = newname(lookup(namebuf)); + } + f->sym = f->nname->sym; + + *t = f; + t = &f->down; + +next: + n = listnext(&save); + goto loop; +} + +Type* +dostruct(Node *n, int et) +{ + Type *t; + + /* + * convert a parsed id/type list into + * a type for struct/interface/arglist + */ + + t = typ(et); + stotype(n, &t->type); + dowidth(t); + return t; +} + +Type* +sortinter(Type *t) +{ + return t; +} + +void +dcopy(Sym *a, Sym *b) +{ + a->name = b->name; + a->oname = b->oname; + a->otype = b->otype; + a->oconst = b->oconst; + a->package = b->package; + a->opackage = b->opackage; + a->forwtype = b->forwtype; + a->lexical = b->lexical; + a->undef = b->undef; + a->vargen = b->vargen; +} + +Sym* +push(void) +{ + Sym *d; + + d = mal(sizeof(*d)); + d->link = dclstack; + dclstack = d; + return d; +} + +Sym* +pushdcl(Sym *s) +{ + Sym *d; + + d = push(); + dcopy(d, s); + return d; +} + +void +popdcl(char *why) +{ + Sym *d, *s; + +// if(debug['d']) +// print("revert\n"); + for(d=dclstack; d!=S; d=d->link) { + if(d->name == nil) + break; + s = pkglookup(d->name, d->package); + dcopy(s, d); + if(debug['d']) + print("\t%ld pop %S\n", curio.lineno, s); + } + if(d == S) + fatal("popdcl: no mark"); + if(strcmp(why, d->package) != 0) + fatal("popdcl: pushed as %s poped as %s", d->package, why); + dclstack = d->link; +} + +void +poptodcl(void) +{ + Sym *d, *s; + + for(d=dclstack; d!=S; d=d->link) { + if(d->name == nil) + break; + s = pkglookup(d->name, d->package); + dcopy(s, d); + if(debug['d']) + print("\t%ld pop %S\n", curio.lineno, s); + } + if(d == S) + fatal("poptodcl: no mark"); +} + +void +markdcl(char *why) +{ + Sym *d; + + d = push(); + d->name = nil; // used as a mark in fifo + d->package = why; // diagnostic for unmatched +// if(debug['d']) +// print("markdcl\n"); +} + +void +markdclstack(void) +{ + Sym *d, *s; + + markdcl("fnlit"); + + // copy the entire pop of the stack + // all the way back to block0. + // after this the symbol table is at + // block0 and popdcl will restore it. + for(d=dclstack; d!=S; d=d->link) { + if(d == b0stack) + break; + if(d->name != nil) { + s = pkglookup(d->name, d->package); + pushdcl(s); + dcopy(s, d); + } + } +} + +void +testdclstack(void) +{ + Sym *d; + + for(d=dclstack; d!=S; d=d->link) { + if(d->name == nil) { + yyerror("mark left on the stack"); + continue; + } + } +} + +void +addvar(Node *n, Type *t, int ctxt) +{ + Dcl *r, *d; + Sym *s; + Type *ot; + Node *on; + int gen; + + if(n==N || n->sym == S || n->op != ONAME || t == T) + fatal("addvar: n=%N t=%T nil", n, t); + + ot = t; + if(isptr[ot->etype]) + ot = ot->type; + + if(ot->etype == TSTRUCT && ot->vargen == 0) { + vargen++; + snprint(namebuf, sizeof(namebuf), "_s%.3ld", vargen); + s = lookup(namebuf); + addtyp(newtype(s), ot, PEXTERN); + } + + s = n->sym; + vargen++; + gen = vargen; + + r = autodcl; + if(ctxt == PEXTERN) { + on = s->oname; + if(on != N) { + if(eqtype(t, on->type, 0)) { + warn("%S redeclared", s); + return; + } + yyerror("%S redeclared (%T %T)", s, + on->type, t); + } + r = externdcl; + gen = 0; + } + + if(ctxt != PEXTERN) + pushdcl(s); + + s->vargen = gen; + s->oname = n; + s->offset = 0; + + n->type = t; + n->vargen = gen; + n->class = ctxt; + + d = dcl(); + d->dsym = s; + d->dnode = n; + d->op = ONAME; + + r->back->forw = d; + r->back = d; + + if(debug['d']) { + if(ctxt == PEXTERN) + print("extern var-dcl %S G%ld %T\n", s, s->vargen, t); + else + print("auto var-dcl %S G%ld %T\n", s, s->vargen, t); + } +} + +void +addtyp(Type *n, Type *t, int ctxt) +{ + Dcl *r, *d; + Sym *s; + Type *f, *ot; + + if(n==T || n->sym == S || t == T) + fatal("addtyp: n=%T t=%T nil", n, t); + + s = n->sym; + + r = autodcl; + if(ctxt == PEXTERN) { + ot = s->otype; + if(ot != T) { + // allow nil interface to be + // redeclared as an interface + if(ot->etype == TINTER && ot->type == T && t->etype == TINTER) { + if(debug['d']) + print("forew typ-dcl %S G%ld %T\n", s, s->vargen, t); + s->otype = t; + return; + } + if(eqtype(t, ot, 0)) { + warn("%S redeclared", s); + return; + } + yyerror("%S redeclared (%T %T)", s, + ot, t); + } + r = externdcl; + } + + if(ctxt != PEXTERN) + pushdcl(s); + + if(t->sym != S) + warn("addtyp: renaming %S/%lT to %S/%lT", t->sym, t->sym->otype, s, n); + + vargen++; + s->vargen = vargen; + s->otype = t; + s->lexical = LATYPE; + + t->sym = s; + t->vargen = vargen; + + for(f=s->forwtype; f!=T; f=f->nforw) { + if(!isptr[f->etype]) + fatal("addtyp: foreward"); + f->type = t; + } + s->forwtype = T; + + d = dcl(); + d->dsym = s; + d->dtype = t; + d->op = OTYPE; + + r->back->forw = d; + r->back = d; + + if(debug['d']) { + if(ctxt == PEXTERN) + print("extern typ-dcl %S G%ld %T\n", s, s->vargen, t); + else + print("auto typ-dcl %S G%ld %T\n", s, s->vargen, t); + } +} + +Node* +fakethis(void) +{ + Node *n; + Type *t; + + n = nod(ODCLFIELD, N, N); + t = dostruct(N, TSTRUCT); + t = ptrto(t); + n->type = t; + return n; +} + +/* + * this generates a new name that is + * pushed down on the declaration list. + * no diagnostics are produced as this + * name will soon be declared. + */ +Node* +newname(Sym *s) +{ + Node *n; + + n = nod(ONAME, N, N); + n->sym = s; + n->type = T; + n->addable = 1; + n->ullman = 0; + return n; +} + +/* + * this will return an old name + * that has already been pushed on the + * declaration list. a diagnostic is + * generated if no name has been defined. + */ +Node* +oldname(Sym *s) +{ + Node *n; + + n = s->oname; + if(n == N) { + yyerror("%S undefined", s); + n = newname(s); + dodclvar(n, types[TINT32]); + } + return n; +} + +/* + * same for types + */ +Type* +newtype(Sym *s) +{ + Type *t; + + t = typ(TFORW); + t->sym = s; + t->type = T; + return t; +} + +Type* +oldtype(Sym *s) +{ + Type *t; + + t = s->otype; + if(t == T) + fatal("%S not a type", s); // cant happen + return t; +} + +Type* +forwdcl(Sym *s) +{ + Type *t; + + // this type has no meaning and + // will cause an error if referenced. + // it will be patched when/if the + // type is ever assigned. + + t = typ(TFORW); + t = ptrto(t); + + t->nforw = s->forwtype; + s->forwtype = t; + return t; +} diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c new file mode 100644 index 0000000000..336ad63685 --- /dev/null +++ b/src/cmd/gc/export.c @@ -0,0 +1,578 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go.h" +#include "y.tab.h" + +void +markexport(Node *n) +{ + Sym *s; + Dcl *d, *r; + +loop: + if(n == N) + return; + if(n->op == OLIST) { + markexport(n->left); + n = n->right; + goto loop; + } + if(n->op != OEXPORT) + fatal("markexport: op no OEXPORT: %O", n->op); + + s = n->sym; + if(n->psym != S) + s = pkglookup(n->sym->name, n->psym->name); + + if(s->export != 0) + return; + s->export = 1; + + d = mal(sizeof(*d)); + d->dsym = s; + d->dnode = N; + d->lineno = curio.lineno; + + r = exportlist; + d->back = r->back; + r->back->forw = d; + r->back = d; +} + +void +reexport(Type *t) +{ + Sym *s; + + if(t == T) + fatal("reexport: type nil\n"); + + s = t->sym; + if(s == S/* || s->name[0] == '_'*/) { + exportgen++; + snprint(namebuf, sizeof(namebuf), "_e%.3ld", exportgen); + s = lookup(namebuf); + s->lexical = LATYPE; + s->otype = t; + t->sym = s; + } + dumpexporttype(s); +} + +void +dumpexportconst(Sym *s) +{ + Node *n; + Type *t; + + if(s->exported != 0) + return; + s->exported = 1; + + n = s->oconst; + if(n == N || n->op != OLITERAL) + fatal("dumpexportconst: oconst nil: %S\n", s); + + t = n->type; // may or may not be specified + if(t != T) + reexport(t); + + Bprint(bout, "\tconst "); + if(s->export != 0) + Bprint(bout, "!"); + Bprint(bout, "%lS ", s); + if(t != T) + Bprint(bout, "%lS ", t->sym); + + switch(n->val.ctype) { + default: + fatal("dumpexportconst: unknown ctype: %S\n", s); + case CTINT: + case CTSINT: + case CTUINT: + case CTBOOL: + Bprint(bout, "0x%llux\n", n->val.vval); + break; + case CTFLT: + Bprint(bout, "%.17e\n", n->val.dval); + break; + case CTSTR: + Bprint(bout, "\"%Z\"\n", n->val.sval); + break; + } +} + +void +dumpexportvar(Sym *s) +{ + Node *n; + Type *t; + + if(s->exported != 0) + return; + s->exported = 1; + + n = s->oname; + if(n == N || n->type == T) + fatal("dumpexportvar: oname nil: %S\n", s); + + t = n->type; + reexport(t); + + Bprint(bout, "\tvar "); + if(s->export != 0) + Bprint(bout, "!"); + Bprint(bout, "%lS %lS\n", s, t->sym); +} + +void +dumpexporttype(Sym *s) +{ + Type *t, *f; + Sym *ts; + int et; + + if(s->exported != 0) + return; + s->exported = 1; + + t = s->otype; + if(t == T) + fatal("dumpexporttype: otype nil: %S\n", s); + if(t->sym != s) + fatal("dumpexporttype: cross reference: %S\n", s); + + et = t->etype; + switch(et) { + default: + if(et < 0 || et >= nelem(types) || types[et] == T) + fatal("dumpexporttype: basic type: %S %E\n", s, et); + /* type 5 */ + Bprint(bout, "\ttype %lS %d\n", s, et); + break; + + case TARRAY: + reexport(t->type); + + /* type 2 */ + Bprint(bout, "\ttype "); + if(s->export != 0) + Bprint(bout, "!"); + Bprint(bout, "%lS [%lud] %lS\n", s, t->bound, t->type->sym); + break; + + case TPTR32: + case TPTR64: + reexport(t->type); + + /* type 6 */ + Bprint(bout, "\ttype "); + if(s->export != 0) + Bprint(bout, "!"); + Bprint(bout, "%lS *%lS\n", s, t->type->sym); + break; + + case TFUNC: + for(f=t->type; f!=T; f=f->down) { + if(f->etype != TSTRUCT) + fatal("dumpexporttype: funct not field: %T\n", f); + reexport(f); + } + + /* type 3 */ + Bprint(bout, "\ttype "); + if(s->export != 0) + Bprint(bout, "!"); + Bprint(bout, "%lS (", s); + for(f=t->type; f!=T; f=f->down) { + if(f != t->type) + Bprint(bout, " "); + Bprint(bout, "%lS", f->sym); + } + Bprint(bout, ")\n"); + break; + + case TSTRUCT: + case TINTER: + for(f=t->type; f!=T; f=f->down) { + if(f->etype != TFIELD) + fatal("dumpexporttype: funct not field: %lT\n", f); + reexport(f->type); + } + + /* type 4 */ + Bprint(bout, "\ttype "); + if(s->export) + Bprint(bout, "!"); + Bprint(bout, "%lS %c", s, (et==TSTRUCT)? '{': '<'); + for(f=t->type; f!=T; f=f->down) { + ts = f->type->sym; + if(f != t->type) + Bprint(bout, " "); + Bprint(bout, "%s %lS", f->sym->name, ts); + } + Bprint(bout, "%c\n", (et==TSTRUCT)? '}': '>'); + break; + } +} + +void +dumpe(Sym *s) +{ + switch(s->lexical) { + default: + yyerror("unknown export symbol: %S\n", s, s->lexical); + break; + case LPACK: + yyerror("package export symbol: %S\n", s); + break; + case LATYPE: + case LBASETYPE: + dumpexporttype(s); + break; + case LNAME: + dumpexportvar(s); + break; + case LACONST: + dumpexportconst(s); + break; + } +} + +void +dumpexport(void) +{ + Dcl *d; + long lno; + + lno = dynlineno; + + Bprint(bout, " import\n"); + Bprint(bout, " ((\n"); + + // print it depth first + for(d=exportlist->forw; d!=D; d=d->forw) { + dynlineno = d->lineno; + dumpe(d->dsym); + } + + Bprint(bout, " ))\n"); + + dynlineno = lno; +} + +/* + * ******* import ******* + */ +Type* +importlooktype(Node *n) +{ + Sym *s; + + if(n->op != OIMPORT) + fatal("importlooktype: oops1 %N\n", n); + + s = pkglookup(n->sym->name, n->psym->name); + if(s->otype == T) + fatal("importlooktype: oops2 %S\n", s); + + return s->otype; +} + +Type** +importstotype(Node *fl, Type **t, Type *uber) +{ + Type *f; + Iter save; + Node *n; + + n = listfirst(&save, &fl); + +loop: + if(n == N) { + *t = T; + return t; + } + f = typ(TFIELD); + f->type = importlooktype(n); + + if(n->fsym != S) { + f->nname = newname(n->fsym); + } else { + vargen++; + snprint(namebuf, sizeof(namebuf), "_m%.3ld", vargen); + f->nname = newname(lookup(namebuf)); + } + f->sym = f->nname->sym; + + *t = f; + t = &f->down; + + n = listnext(&save); + goto loop; +} + +int +importcount(Type *t) +{ + int i; + Type *f; + + if(t == T || t->etype != TSTRUCT) + fatal("importcount: not a struct: %N", t); + + i = 0; + for(f=t->type; f!=T; f=f->down) + i = i+1; + return i; +} + +void +importfuncnam(Type *t) +{ + Node *n; + Type *t1; + + if(t->etype != TFUNC) + fatal("importfuncnam: not func %T\n", t); + + if(t->thistuple > 0) { + t1 = t->type; + if(t1->sym == S) + fatal("importfuncnam: no this"); + n = newname(t1->sym); + vargen++; + n->vargen = vargen; + t1->nname = n; + } + if(t->outtuple > 0) { + t1 = t->type->down; + if(t1->sym == S) + fatal("importfuncnam: no output"); + n = newname(t1->sym); + vargen++; + n->vargen = vargen; + t1->nname = n; + } + if(t->intuple > 0) { + t1 = t->type->down->down; + if(t1->sym == S) + fatal("importfuncnam: no input"); + n = newname(t1->sym); + vargen++; + n->vargen = vargen; + t1->nname = n; + } +} + +Sym* +getimportsym(Node *ss) +{ + char *pkg; + Sym *s; + + pkg = ss->psym->name; + if(pkgmyname != S) + pkg = pkgmyname->name; + + s = pkglookup(ss->sym->name, pkg); + /* botch - need some diagnostic checking for the following assignment */ + s->opackage = ss->osym->name; + return s; +} + +void +importaddtyp(Node *ss, Type *t) +{ + Sym *s; + + s = getimportsym(ss); + if(s->otype == T || !eqtype(t, s->otype, 0)) { + addtyp(newtype(s), t, PEXTERN); + } +} + +/* + * LCONST importsym LITERAL + * untyped constant + */ +void +doimportc1(Node *ss, Val *v) +{ + Node *n; + Sym *s; + + n = nod(OLITERAL, N, N); + n->val = *v; + + s = getimportsym(ss); + if(s->oconst == N) { + // botch sould ask if already declared the same + dodclconst(newname(s), n); + } +} + +/* + * LCONST importsym importsym LITERAL + * typed constant + */ +void +doimportc2(Node *ss, Node *st, Val *v) +{ + Node *n; + Type *t; + Sym *s; + + n = nod(OLITERAL, N, N); + n->val = *v; + + t = importlooktype(st); + n->type = t; + + s = getimportsym(ss); + if(s->oconst == N) { + // botch sould ask if already declared the same + dodclconst(newname(s), n); + } +} + +/* + * LVAR importsym importsym + * variable + */ +void +doimportv1(Node *ss, Node *st) +{ + Type *t; + Sym *s; + + t = importlooktype(st); + s = getimportsym(ss); + if(s->oname == N || !eqtype(t, s->oname->type, 0)) { + addvar(newname(s), t, dclcontext); + } +} + +/* + * LTYPE importsym [ importsym ] importsym + * array type + */ +void +doimport1(Node *ss, Node *ss1, Node *s) +{ + fatal("doimport1"); +} + +/* + * LTYPE importsym [ LLITERAL ] importsym + * array type + */ +void +doimport2(Node *ss, Val *b, Node *st) +{ + Type *t; + Sym *s; + + t = typ(TARRAY); + t->bound = b->vval; + s = pkglookup(st->sym->name, st->psym->name); + t->type = s->otype; + + importaddtyp(ss, t); +} + +/* + * LTYPE importsym '(' importsym_list ')' + * function/method type + */ +void +doimport3(Node *ss, Node *n) +{ + Type *t; + + t = typ(TFUNC); + + t->type = importlooktype(n->left); + t->type->down = importlooktype(n->right->left); + t->type->down->down = importlooktype(n->right->right); + + t->thistuple = importcount(t->type); + t->outtuple = importcount(t->type->down); + t->intuple = importcount(t->type->down->down); + + importfuncnam(t); + + importaddtyp(ss, t); +} + +/* + * LTYPE importsym '{' importsym_list '}' + * structure type + */ +void +doimport4(Node *ss, Node *n) +{ + Type *t; + + t = typ(TSTRUCT); + importstotype(n, &t->type, t); + + importaddtyp(ss, t); +} + +/* + * LTYPE importsym LLITERAL + * basic type + */ +void +doimport5(Node *ss, Val *v) +{ + int et; + Type *t; + + et = v->vval; + if(et <= 0 || et >= nelem(types) || types[et] == T) + fatal("doimport5: bad type index: %E\n", et); + + t = typ(et); + t->sym = S; + + importaddtyp(ss, t); +} + +/* + * LTYPE importsym * importsym + * pointer type + */ +void +doimport6(Node *ss, Node *st) +{ + Type *t; + Sym *s; + + s = pkglookup(st->sym->name, st->psym->name); + t = s->otype; + if(t == T) + t = forwdcl(s); + else + t = ptrto(t); + + importaddtyp(ss, t); +} + +/* + * LTYPE importsym '<' importsym '>' + * interface type + */ +void +doimport7(Node *ss, Node *n) +{ + Type *t; + + t = typ(TINTER); + importstotype(n, &t->type, t); + + importaddtyp(ss, t); +} diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h new file mode 100644 index 0000000000..ecd33a8ead --- /dev/null +++ b/src/cmd/gc/go.h @@ -0,0 +1,553 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +todo: + 1. dyn arrays + 2. multi + 3. block 0 +tothinkabout: + 2. argument in import +*/ + +#include +#include +#include + +#ifndef EXTERN +#define EXTERN extern +#endif +enum +{ + NHUNK = 50000, + BUFSIZ = 8192, + NSYMB = 500, + NHASH = 1024, + STRINGSZ = 200, + YYMAXDEPTH = 500, + MAXALIGN = 7, + UINF = 100, + + PRIME1 = 3, + PRIME2 = 10007, + PRIME3 = 10009, + PRIME4 = 10037, + PRIME5 = 10039, + PRIME6 = 10061, + PRIME7 = 10067, + PRIME8 = 10079, + PRIME9 = 10091, +}; + +/* + * note this is the representation + * of the compilers string literals, + * it happens to also be the runtime + * representation, ignoring sizes and + * alignment, but that may change. + */ +typedef struct String String; +struct String +{ + long len; + char s[3]; // variable +}; + +typedef struct Val Val; +struct Val +{ + int ctype; + double dval; + vlong vval; + String* sval; +}; + +typedef struct Sym Sym; +typedef struct Node Node; +typedef struct Type Type; + +struct Type +{ + int etype; + int chan; + uchar recur; // to detect loops + uchar trecur; // to detect loops + Sym* sym; + long vargen; // unique name for OTYPE/ONAME + + // most nodes + Type* type; + vlong width; // offset in TFIELD, width in all others + + // TFIELD + Type* down; // also used in TMAP + + // TPTR + Type* nforw; + + // TFUNCT + Type* this; + Type* argout; + Type* argin; + Node* nname; + + uchar thistuple; + uchar outtuple; + uchar intuple; + + // TARRAY + long bound; +}; +#define T ((Type*)0) + +struct Node +{ + int op; + + // most nodes + Node* left; + Node* right; + Type* type; + + // for-body + Node* ninit; + Node* ntest; + Node* nincr; + Node* nbody; + + // if-body + Node* nelse; + + // cases + Node* ncase; + + // func + Node* nname; + + // OLITERAL + Val val; + + Sym* osym; // import + Sym* fsym; // import + Sym* psym; // import + Sym* sym; // various + uchar ullman; // sethi/ullman number + uchar addable; // type of addressability - 0 is not addressable + uchar trecur; // to detect loops + uchar etype; // op for OASOP, etype for OTYPE, exclam for export + uchar class; // PPARAM, PAUTO, PEXTERN, PSTATIC + long vargen; // unique name for OTYPE/ONAME + ulong lineno; + vlong xoffset; +}; +#define N ((Node*)0) + +struct Sym +{ + char* opackage; // original package name + char* package; // package name + char* name; // variable name + Node* oname; // ONAME node if a var + Type* otype; // TYPE node if a type + Node* oconst; // OLITERAL node if a const + Type* forwtype; // TPTR iff foreward declared + void* label; // pointer to Prog* of label + vlong offset; // stack location if automatic + long lexical; + long vargen; // unique variable number + uchar undef; // a diagnostic has been generated + uchar export; // marked as export + uchar exported; // has been exported + uchar sym; // huffman encoding in object file + Sym* link; +}; +#define S ((Sym*)0) + +typedef struct Dcl Dcl; +struct Dcl +{ + int op; + Sym* dsym; // for printing only + Node* dnode; // oname + Type* dtype; // otype + long lineno; + + Dcl* forw; + Dcl* back; // sentinel has pointer to last +}; +#define D ((Dcl*)0) + +typedef struct Iter Iter; +struct Iter +{ + int done; + Type* tfunc; + Type* t; + Node** an; + Node* n; +}; + +enum +{ + OXXX, + + OTYPE, OCONST, OVAR, OEXPORT, OIMPORT, + + ONAME, + ODOT, ODOTPTR, ODOTMETH, ODOTINTER, + ODCLFUNC, ODCLFIELD, ODCLARG, + OLIST, OCMP, + OPTR, OARRAY, + ORETURN, OFOR, OIF, OSWITCH, OI2S, OS2I, OI2I, + OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL, + OGOTO, OPROC, ONEW, OPANIC, OPRINT, OEMPTY, + + OOROR, + OANDAND, + OEQ, ONE, OLT, OLE, OGE, OGT, + OADD, OSUB, OOR, OXOR, + OMUL, ODIV, OMOD, OLSH, ORSH, OAND, + ODEC, OINC, + OLEN, + OFUNC, + OLABEL, + OBREAK, + OCONTINUE, + OADDR, + OIND, + OCALL, OCALLMETH, OCALLINTER, + OINDEX, OINDEXPTR, OSLICE, + ONOT, OCOM, OPLUS, OMINUS, OSEND, ORECV, + OLITERAL, OREGISTER, OINDREG, + OCONV, + OBAD, + + OEND, +}; +enum +{ + Txxx, // 0 + + TINT8, TUINT8, // 1 + TINT16, TUINT16, + TINT32, TUINT32, + TINT64, TUINT64, + + TFLOAT32, // 9 + TFLOAT64, + TFLOAT80, + + TBOOL, // 12 + + TPTR32, TPTR64, // 13 + + TFUNC, + TARRAY, + TDARRAY, + TSTRUCT, + TCHAN, + TMAP, + TINTER, + TFORW, + TFIELD, + TANY, + TSTRING, + + NTYPE, // 26 +}; +enum +{ + CTxxx, + + CTINT, + CTSINT, + CTUINT, + CTFLT, + + CTSTR, + CTBOOL, + CTNIL, +}; + +enum +{ + /* indications for whatis() */ + Wnil = 0, + Wtnil, + + Wtfloat, + Wtint, + Wtbool, + Wtstr, + + Wlitfloat, + Wlitint, + Wlitbool, + Wlitstr, + + Wtunkn, +}; + +enum +{ + /* types of channel */ + Cxxx, + Cboth, + Crecv, + Csend, +}; + +enum +{ + Pxxx, + + PEXTERN, // declaration context + PAUTO, + PPARAM, + PSTATIC, +}; + +typedef struct Io Io; +struct Io +{ + char* infile; + Biobuf* bin; + long lineno; + int peekc; + char* cp; // used for content when bin==nil +}; + +EXTERN Io curio; +EXTERN Io pushedio; + +EXTERN char* outfile; +EXTERN char* package; +EXTERN Biobuf* bout; +EXTERN int nerrors; +EXTERN char namebuf[NSYMB]; +EXTERN char debug[256]; +EXTERN long dynlineno; +EXTERN Sym* hash[NHASH]; +EXTERN Sym* dclstack; +EXTERN Sym* b0stack; +EXTERN Sym* pkgmyname; // my name for package +EXTERN int tptr; // either TPTR32 or TPTR64 +extern char* sysimport; + +EXTERN Type* types[NTYPE]; +EXTERN uchar isptr[NTYPE]; +EXTERN uchar isint[NTYPE]; +EXTERN uchar isfloat[NTYPE]; +EXTERN uchar issigned[NTYPE]; +EXTERN uchar okforeq[NTYPE]; +EXTERN uchar okforadd[NTYPE]; +EXTERN uchar okforand[NTYPE]; +EXTERN double minfloatval[NTYPE]; +EXTERN double maxfloatval[NTYPE]; +EXTERN vlong minintval[NTYPE]; +EXTERN vlong maxintval[NTYPE]; + +EXTERN Dcl* autodcl; +EXTERN Dcl* externdcl; +EXTERN Dcl* exportlist; +EXTERN int dclcontext; // PEXTERN/PAUTO +EXTERN int importflag; + +EXTERN Node* booltrue; +EXTERN Node* boolfalse; +EXTERN ulong iota; +EXTERN long vargen; +EXTERN long exportgen; + +EXTERN Node* retnil; +EXTERN Node* fskel; + +EXTERN char* context; +EXTERN int thechar; +EXTERN char* thestring; +EXTERN char* hunk; +EXTERN long nhunk; +EXTERN long thunk; + +/* + * y.tab.c + */ +int yyparse(void); + +/* + * lex.c + */ +int main(int, char*[]); +void importfile(Val*); +void cannedimports(void); +void unimportfile(); +long yylex(void); +void lexinit(void); +char* lexname(int); +long getr(void); +int getnsc(void); +long escchar(long, int*); +int getc(void); +void ungetc(int); +void mkpackage(char*); + +/* + * mpatof.c + */ +int mpatof(char*, double*); +int mpatov(char*, vlong*); + +/* + * subr.c + */ +void myexit(int); +void* mal(long); +void* remal(void*, long, long); +void errorexit(void); +ulong stringhash(char*); +Sym* lookup(char*); +Sym* pkglookup(char*, char*); +void yyerror(char*, ...); +void warn(char*, ...); +void fatal(char*, ...); +Node* nod(int, Node*, Node*); +Type* typ(int); +Dcl* dcl(void); +Node* rev(Node*); +Node* unrev(Node*); +void dodump(Node*, int); +void dump(char*, Node*); +Type* aindex(Node*, Type*); +int isnil(Node*); +int isptrto(Type*, int); +int isinter(Type*); +int isbytearray(Type*); +int eqtype(Type*, Type*, int); +int eqargs(Type*, Type*); +ulong typehash(Type*, int); +void frame(int); +Node* literal(long); +Node* dobad(void); +Node* nodintconst(long); +void ullmancalc(Node*); +void badtype(int, Type*, Type*); +Type* ptrto(Type*); +Node* cleanidlist(Node*); + +Type** getthis(Type*); +Type** getoutarg(Type*); +Type** getinarg(Type*); + +Type* getthisx(Type*); +Type* getoutargx(Type*); +Type* getinargx(Type*); + +Node* listfirst(Iter*, Node**); +Node* listnext(Iter*); +Type* structfirst(Iter*, Type**); +Type* structnext(Iter*); +Type* funcfirst(Iter*, Type*); +Type* funcnext(Iter*); + +int Econv(Fmt*); +int Jconv(Fmt*); +int Oconv(Fmt*); +int Sconv(Fmt*); +int Tconv(Fmt*); +int Nconv(Fmt*); +int Zconv(Fmt*); + +/* + * dcl.c + */ +void dodclvar(Node*, Type*); +void dodcltype(Type*, Type*); +void dodclconst(Node*, Node*); +void defaultlit(Node*); +int listcount(Node*); +Node* methodname(Node*, Type*); +Type* functype(Node*, Node*, Node*); +char* thistypenam(Node*); +void funcnam(Type*, char*); +void funchdr(Node*); +void funcargs(Type*); +void funcbody(Node*); +Type* dostruct(Node*, int); +Type** stotype(Node*, Type**); +Type* sortinter(Type*); +void markdcl(char*); +void popdcl(char*); +void poptodcl(void); +void markdclstack(void); +void testdclstack(void); +Sym* pushdcl(Sym*); +void addvar(Node*, Type*, int); +void addtyp(Type*, Type*, int); +Node* fakethis(void); +Node* newname(Sym*); +Node* oldname(Sym*); +Type* newtype(Sym*); +Type* oldtype(Sym*); +Type* forwdcl(Sym*); + +/* + * export.c + */ +void markexport(Node*); +void dumpe(Sym*); +void dumpexport(void); +void dumpexporttype(Sym*); +void dumpexportvar(Sym*); +void dumpexportconst(Sym*); +void doimportv1(Node*, Node*); +void doimportc1(Node*, Val*); +void doimportc2(Node*, Node*, Val*); +void doimport1(Node*, Node*, Node*); +void doimport2(Node*, Val*, Node*); +void doimport3(Node*, Node*); +void doimport4(Node*, Node*); +void doimport5(Node*, Val*); +void doimport6(Node*, Node*); +void doimport7(Node*, Node*); + +/* + * walk.c + */ +void walk(Node*); +void walktype(Node*, int); +Type* walkswitch(Node*, Node*, Type*(*)(Node*, Type*)); +int casebody(Node*); +int whatis(Node*); +void walkdot(Node*); +Node* ascompatee(int, Node**, Node**); +Node* ascompatet(int, Node**, Type**, int); +Node* ascompatte(int, Type**, Node**, int); +int ascompat(Type*, Type*); +Node* prcompat(Node*); +Node* nodpanic(long); +Node* newcompat(Node*); +Node* stringop(Node*); +Node* convas(Node*); +Node* reorder(Node*); + +/* + * const.c + */ +void convlit(Node*, Type*); +void evconst(Node*); +int cmpslit(Node *l, Node *r); + +/* + * gen.c/gsubr.c/obj.c + */ +void belexinit(int); +void besetptr(void); +vlong convvtox(vlong, int); +void compile(Node*); +void proglist(void); +int optopop(int); +void dumpobj(void); +void dowidth(Type*); +void argspace(long); +Node* nodarg(Type*, int); diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y new file mode 100644 index 0000000000..a3f8e98dce --- /dev/null +++ b/src/cmd/gc/go.y @@ -0,0 +1,1292 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +%{ +#include "go.h" +%} +%union { + Node* node; + Type* type; + Sym* sym; + struct Val val; + int lint; +} +%token LNAME LBASETYPE LATYPE LANY LPACK LACONST +%token LLITERAL LASOP +%token LPACKAGE LIMPORT LEXPORT +%token LMAP LCHAN LINTERFACE LFUNC LSTRUCT +%token LCOLAS LFALL LRETURN +%token LNEW LLEN +%token LVAR LTYPE LCONST LCONVERT +%token LFOR LIF LELSE LSWITCH LCASE LDEFAULT +%token LBREAK LCONTINUE LGO LGOTO LRANGE +%token LOROR LANDAND LEQ LNE LLE LLT LGE LGT +%token LLSH LRSH LINC LDEC +%token LNIL LTRUE LFALSE LIOTA +%token LPANIC LPRINT LIGNORE + +%type sym laconst lname latype +%type chandir +%type xdcl xdcl_list_r oxdcl_list common_dcl +%type oarg_type_list arg_type_list_r arg_type +%type stmt empty_stmt else_stmt +%type complex_stmt compound_stmt stmt_list_r ostmt_list +%type for_stmt for_body for_header +%type if_stmt if_body if_header +%type range_header range_body range_stmt +%type simple_stmt osimple_stmt +%type expr uexpr pexpr expr_list oexpr oexpr_list expr_list_r +%type name name_name new_name new_name_list_r +%type vardcl_list_r vardcl +%type interfacedcl_list_r interfacedcl +%type structdcl_list_r structdcl +%type export_list_r export +%type hidden_importsym_list_r ohidden_importsym_list hidden_importsym isym +%type hidden_importfield_list_r ohidden_importfield_list hidden_importfield +%type fnbody +%type fnres fnliteral xfndcl fndcl +%type keyval_list_r keyval + +%type type fntypeh fntype fnlitdcl intype new_type + +%left LOROR +%left LANDAND +%left LEQ LNE LLE LGE LLT LGT +%left '+' '-' '|' '^' +%left '*' '/' '%' '&' LLSH LRSH +%% +file: + package import_there imports oxdcl_list + { + if(debug['f']) + frame(1); + testdclstack(); + } + +package: + { + yyerror("package statement must be first"); + mkpackage("main"); + cannedimports(); + } +| LPACKAGE sym + { + mkpackage($2->name); + cannedimports(); + } + +imports: +| imports import + +import: + LIMPORT import_stmt +| LIMPORT '(' import_stmt_list_r osemi ')' + +import_stmt: + import_here import_there + +import_here: + LLITERAL + { + // import with original name + pkgmyname = S; + importfile(&$1); + } +| sym LLITERAL + { + // import with given name + pkgmyname = $1; + pkgmyname->lexical = LPACK; + importfile(&$2); + } +| '.' LLITERAL + { + // import with my name + pkgmyname = lookup(package); + importfile(&$2); + } + +import_there: + hidden_import_list_r ')' ')' + { + unimportfile(); + } +| LIMPORT '(' '(' hidden_import_list_r ')' ')' + +/* + * declarations + */ +xdcl: + common_dcl +| LEXPORT export_list_r + { + markexport(rev($2)); + } +| LEXPORT '(' export_list_r ')' + { + markexport(rev($3)); + } +| xfndcl +| ';' + { + $$ = N; + } + +common_dcl: + LVAR vardcl + { + $$ = $2; + } +| LVAR '(' vardcl_list_r osemi ')' + { + $$ = rev($3); + } +| LCONST constdcl + { + $$ = N; + iota = 0; + } +| LCONST '(' constdcl_list_r osemi ')' + { + $$ = N; + iota = 0; + } +| LTYPE typedcl + { + $$ = N; + } +| LTYPE '(' typedcl_list_r osemi ')' + { + $$ = N; + } + +vardcl: + new_name_list_r type + { + $$ = rev($1); + dodclvar($$, $2); + + $$ = nod(OAS, $$, N); + } +| new_name_list_r type '=' oexpr_list + { + $$ = rev($1); + dodclvar($$, $2); + + $$ = nod(OAS, $$, $4); + } +| new_name '=' expr + { + walktype($3, 0); // this is a little harry + defaultlit($3); + dodclvar($1, $3->type); + + $$ = nod(OAS, $1, $3); + } + +constdcl: + new_name '=' expr + { + walktype($3, 0); + dodclconst($1, $3); + iota += 1; + } +| new_name type '=' expr + { + walktype($4, 0); + convlit($4, $2); + dodclconst($1, $4); + iota += 1; + } + +typedcl: + new_type type + { + dodcltype($1, $2); + } + +/* + * statements + */ +stmt: + error ';' + { + $$ = N; + context = nil; + } +| common_dcl ';' + { + $$ = $1; + } +| simple_stmt ';' +| complex_stmt +| compound_stmt +| empty_stmt + +empty_stmt: + ';' + { + $$ = nod(OEMPTY, N, N); + } + +else_stmt: + stmt + { + $$ = $1; + switch($$->op) { + case OLABEL: + case OXCASE: + case OXFALL: + yyerror("statement cannot be labeled"); + } + } + +simple_stmt: + expr + { + $$ = $1; + } +| expr LINC + { + $$ = nod(OASOP, $1, literal(1)); + $$->etype = OADD; + } +| expr LDEC + { + $$ = nod(OASOP, $1, literal(1)); + $$->etype = OSUB; + } +| expr LASOP expr + { + $$ = nod(OASOP, $1, $3); + $$->etype = $2.vval; // rathole to pass opcode + } +| expr_list '=' expr_list + { + $$ = nod(OAS, $1, $3); + } +| new_name LCOLAS expr + { + walktype($3, 0); // this is a little harry + defaultlit($3); + dodclvar($1, $3->type); + + $$ = nod(OAS, $1, $3); + } + +complex_stmt: + LFOR for_stmt + { + /* FOR and WHILE are the same keyword */ + popdcl("for/while"); + $$ = $2; + } +| LSWITCH if_stmt + { + popdcl("if/switch"); + if(!casebody($2->nbody)) + yyerror("switch statement must have case labels"); + $$ = $2; + $$->op = OSWITCH; + } +| LIF if_stmt + { + popdcl("if/switch"); + $$ = $2; + } +| LIF if_stmt LELSE else_stmt + { + popdcl("if/switch"); + $$ = $2; + $$->nelse = $4; + } +| LRANGE range_stmt + { + popdcl("range"); + $$ = $2; + } +| LRETURN oexpr_list ';' + { + $$ = nod(ORETURN, $2, N); + } +| LCASE expr_list ':' + { + // will be converted to OCASE + // right will point to next case + // done in casebody() + poptodcl(); + $$ = nod(OXCASE, $2, N); + } +| LDEFAULT ':' + { + poptodcl(); + $$ = nod(OXCASE, N, N); + } +| LFALL ';' + { + // will be converted to OFALL + $$ = nod(OXFALL, N, N); + } +| LBREAK oexpr ';' + { + $$ = nod(OBREAK, $2, N); + } +| LCONTINUE oexpr ';' + { + $$ = nod(OCONTINUE, $2, N); + } +| LGO pexpr '(' oexpr_list ')' ';' + { + $$ = nod(OPROC, $2, $4); + } +| LPRINT expr_list ';' + { + $$ = nod(OPRINT, $2, N); + } +| LPANIC oexpr_list ';' + { + $$ = nod(OPANIC, $2, N); + } +| LGOTO new_name ';' + { + $$ = nod(OGOTO, $2, N); + } +| new_name ':' + { + $$ = nod(OLABEL, $1, N); + } + +compound_stmt: + '{' + { + markdcl("compound"); + } ostmt_list '}' + { + $$ = $3; + if($$ == N) + $$ = nod(OEMPTY, N, N); + popdcl("compound"); + } + +for_header: + osimple_stmt ';' osimple_stmt ';' osimple_stmt + { + // init ; test ; incr + $$ = nod(OFOR, N, N); + $$->ninit = $1; + $$->ntest = $3; + $$->nincr = $5; + } +| osimple_stmt + { + // test + $$ = nod(OFOR, N, N); + $$->ninit = N; + $$->ntest = $1; + $$->nincr = N; + } + +for_body: + for_header compound_stmt + { + $$ = $1; + $$->nbody = $2; + } + +for_stmt: + { + markdcl("for/while"); + } for_body + { + $$ = $2; + } + +if_header: + osimple_stmt + { + // test + $$ = nod(OIF, N, N); + $$->ninit = N; + $$->ntest = $1; + } +| osimple_stmt ';' osimple_stmt + { + // init ; test + $$ = nod(OIF, N, N); + $$->ninit = $1; + $$->ntest = $3; + } + +if_body: + if_header compound_stmt + { + $$ = $1; + $$->nbody = $2; + } + +if_stmt: + { + markdcl("if/switch"); + } if_body + { + $$ = $2; + } + +range_header: + new_name LCOLAS expr + { + $$ = N; + } +| new_name ',' new_name LCOLAS expr + { + $$ = N; + } +| new_name ',' new_name '=' expr + { + yyerror("range statement only allows := assignment"); + $$ = N; + } + +range_body: + range_header compound_stmt + { + $$ = $1; + $$->nbody = $2; + } + +range_stmt: + { + markdcl("range"); + } range_body + { + $$ = $2; + } + +/* + * expressions + */ +expr: + uexpr +| expr LOROR expr + { + $$ = nod(OOROR, $1, $3); + } +| expr LANDAND expr + { + $$ = nod(OANDAND, $1, $3); + } +| expr LEQ expr + { + $$ = nod(OEQ, $1, $3); + } +| expr LNE expr + { + $$ = nod(ONE, $1, $3); + } +| expr LLT expr + { + $$ = nod(OLT, $1, $3); + } +| expr LLE expr + { + $$ = nod(OLE, $1, $3); + } +| expr LGE expr + { + $$ = nod(OGE, $1, $3); + } +| expr LGT expr + { + $$ = nod(OGT, $1, $3); + } +| expr '+' expr + { + $$ = nod(OADD, $1, $3); + } +| expr '-' expr + { + $$ = nod(OSUB, $1, $3); + } +| expr '|' expr + { + $$ = nod(OOR, $1, $3); + } +| expr '^' expr + { + $$ = nod(OXOR, $1, $3); + } +| expr '*' expr + { + $$ = nod(OMUL, $1, $3); + } +| expr '/' expr + { + $$ = nod(ODIV, $1, $3); + } +| expr '%' expr + { + $$ = nod(OMOD, $1, $3); + } +| expr '&' expr + { + $$ = nod(OAND, $1, $3); + } +| expr LLSH expr + { + $$ = nod(OLSH, $1, $3); + } +| expr LRSH expr + { + $$ = nod(ORSH, $1, $3); + } + +uexpr: + pexpr +| '*' uexpr + { + $$ = nod(OIND, $2, N); + } +| '&' uexpr + { + $$ = nod(OADDR, $2, N); + } +| '+' uexpr + { + $$ = nod(OPLUS, $2, N); + } +| '-' uexpr + { + $$ = nod(OMINUS, $2, N); + } +| '!' uexpr + { + $$ = nod(ONOT, $2, N); + } +| '~' uexpr + { + yyerror("the OCOM operator is ^"); + $$ = nod(OCOM, $2, N); + } +| '^' uexpr + { + $$ = nod(OCOM, $2, N); + } +| LLT uexpr + { + $$ = nod(ORECV, $2, N); + } +| LGT uexpr + { + $$ = nod(OSEND, $2, N); + } + +pexpr: + LLITERAL + { + $$ = nod(OLITERAL, N, N); + $$->val = $1; + } +| laconst + { + $$ = nod(OLITERAL, N, N); + $$->val = $1->oconst->val; + $$->type = $1->oconst->type; + } +| LNIL + { + $$ = nod(OLITERAL, N, N); + $$->val.ctype = CTNIL; + $$->val.vval = 0; + } +| LTRUE + { + $$ = booltrue; + } +| LFALSE + { + $$ = boolfalse; + } +| LIOTA + { + $$ = literal(iota); + } +| name +| '(' expr ')' + { + $$ = $2; + } +| pexpr '.' sym + { + $$ = nod(ODOT, $1, newname($3)); + } +| pexpr '.' '(' type ')' + { + $$ = nod(OCONV, $1, N); + $$->type = $4; + } +| pexpr '[' expr ']' + { + $$ = nod(OINDEX, $1, $3); + } +| pexpr '[' keyval ']' + { + $$ = nod(OSLICE, $1, $3); + } +| pexpr '(' oexpr_list ')' + { + $$ = nod(OCALL, $1, $3); + } +| LLEN '(' name ')' + { + $$ = nod(OLEN, $3, N); + } +| LNEW '(' type ')' + { + $$ = nod(ONEW, N, N); + $$->type = ptrto($3); + } +| fnliteral +| '[' expr_list ']' + { + // array literal + $$ = N; + } +| '[' keyval_list_r ']' + { + // map literal + $$ = N; + } +| latype '(' oexpr_list ')' + { + // struct literal and conversions + $$ = nod(OCONV, $3, N); + $$->type = $1->otype; + } +| LCONVERT '(' type ',' expr ')' + { + $$ = nod(OCONV, $5, N); + $$->type = $3; + } + +/* + * lexical symbols that can be + * from other packages + */ +lpack: + LPACK + { + context = $1->name; + } + +laconst: + LACONST +| lpack '.' LACONST + { + $$ = $3; + context = nil; + } + +lname: + LNAME +| lpack '.' LNAME + { + $$ = $3; + context = nil; + } + +latype: + LATYPE +| lpack '.' LATYPE + { + $$ = $3; + context = nil; + } + +/* + * names and types + * newname is used before declared + * oldname is used after declared + */ +name_name: + LNAME + { + $$ = newname($1); + } + +new_name: + sym + { + $$ = newname($1); + } + +new_type: + sym + { + $$ = newtype($1); + } + +sym: + LATYPE +| LNAME +| LACONST +| LPACK + +name: + lname + { + $$ = oldname($1); + } + +type: + latype + { + $$ = oldtype($1); + } +| '[' oexpr ']' type + { + $$ = aindex($2, $4); + } +| LCHAN chandir type + { + $$ = typ(TCHAN); + $$->type = $3; + $$->chan = $2; + } +| LMAP '[' type ']' type + { + $$ = typ(TMAP); + $$->down = $3; + $$->type = $5; + } +| LSTRUCT '{' structdcl_list_r osemi '}' + { + $$ = dostruct(rev($3), TSTRUCT); + } +| LSTRUCT '{' '}' + { + $$ = dostruct(N, TSTRUCT); + } +| LINTERFACE '{' interfacedcl_list_r osemi '}' + { + $$ = dostruct(rev($3), TINTER); + $$ = sortinter($$); + } +| LINTERFACE '{' '}' + { + $$ = dostruct(N, TINTER); + } +| LANY + { + $$ = typ(TANY); + } +| fntypeh +| '*' type + { + $$ = ptrto($2); + } +| '*' lname + { + // dont know if this is an error or not + if(dclcontext != PEXTERN) + yyerror("foreward type in function body %s", $2->name); + $$ = forwdcl($2); + } + +chandir: + { + $$ = Cboth; + } +| LLT + { + $$ = Crecv; + } +| LGT + { + $$ = Csend; + } + +keyval: + expr ':' expr + { + $$ = nod(OLIST, $1, $3); + } + +/* + * function stuff + * all in one place to show how crappy it all is + */ +xfndcl: + LFUNC fndcl fnbody + { + $$ = $2; + $$->nbody = $3; + funcbody($$); + } + +fndcl: + new_name '(' oarg_type_list ')' fnres + { + b0stack = dclstack; // mark base for fn literals + $$ = nod(ODCLFUNC, N, N); + $$->nname = $1; + $$->type = functype(N, $3, $5); + funchdr($$); + } +| '(' oarg_type_list ')' new_name '(' oarg_type_list ')' fnres + { + b0stack = dclstack; // mark base for fn literals + if($2 == N || $2->op == OLIST) + yyerror("syntax error in method receiver"); + $$ = nod(ODCLFUNC, N, N); + $$->nname = methodname($4, $2->type); + $$->type = functype($2, $6, $8); + funchdr($$); + } + +fntypeh: + LFUNC '(' oarg_type_list ')' fnres + { + $$ = functype(N, $3, $5); + funcnam($$, nil); + } +| LFUNC '(' oarg_type_list ')' '.' '(' oarg_type_list ')' fnres + /* i dont believe that this form is useful for anything */ + { + if($3 == N || $3->op == OLIST) + yyerror("syntax error in method receiver"); + $$ = functype($3, $7, $9); + funcnam($$, nil); + } + +fntype: + fntypeh +| latype + { + $$ = oldtype($1); + if($$ == T || $$->etype != TFUNC) + yyerror("illegal type for function literal"); + } + +fnlitdcl: + fntype + { + markdclstack(); // save dcl stack and revert to block0 + $$ = $1; + funcargs($$); + } + +fnliteral: + fnlitdcl '{' ostmt_list '}' + { + popdcl("fnlit"); + + vargen++; + snprint(namebuf, sizeof(namebuf), "_f%.3ld", vargen); + + $$ = newname(lookup(namebuf)); + addvar($$, $1, PEXTERN); + + { + Node *n; + + n = nod(ODCLFUNC, N, N); + n->nname = $$; + n->type = $1; + n->nbody = $3; + if(n->nbody == N) + n->nbody = nod(ORETURN, N, N); + compile(n); + } + + $$ = nod(OADDR, $$, N); + } + +fnbody: + compound_stmt + { + $$ = $1; + if($$->op == OEMPTY) + $$ = nod(ORETURN, N, N); + } +| ';' + { + $$ = N; + } + +fnres: + { + $$ = N; + } +| type + { + $$ = nod(ODCLFIELD, N, N); + $$->type = $1; + $$ = cleanidlist($$); + } +| '(' oarg_type_list ')' + { + $$ = $2; + } + +/* + * lists of things + * note that they are left recursive + * to conserve yacc stack. they need to + * be reversed to interpret correctly + */ +xdcl_list_r: + xdcl +| xdcl_list_r xdcl + { + $$ = nod(OLIST, $1, $2); + } + +vardcl_list_r: + vardcl +| vardcl_list_r ';' vardcl + { + $$ = nod(OLIST, $1, $3); + } + +constdcl_list_r: + constdcl +| constdcl_list_r ';' constdcl + +typedcl_list_r: + typedcl +| typedcl_list_r ';' typedcl + +structdcl_list_r: + structdcl + { + $$ = cleanidlist($1); + } +| structdcl_list_r ';' structdcl + { + $$ = cleanidlist($3); + $$ = nod(OLIST, $1, $$); + } + +interfacedcl_list_r: + interfacedcl + { + $$ = cleanidlist($1); + } +| interfacedcl_list_r ';' interfacedcl + { + $$ = cleanidlist($3); + $$ = nod(OLIST, $1, $$); + } + +structdcl: + new_name ',' structdcl + { + $$ = nod(ODCLFIELD, $1, N); + $$ = nod(OLIST, $$, $3); + } +| new_name type + { + $$ = nod(ODCLFIELD, $1, N); + $$->type = $2; + } + +interfacedcl: + new_name ',' interfacedcl + { + $$ = nod(ODCLFIELD, $1, N); + $$ = nod(OLIST, $$, $3); + } +| new_name intype + { + $$ = nod(ODCLFIELD, $1, N); + $$->type = $2; + } + +intype: + '(' oarg_type_list ')' fnres + { + // without func keyword + $$ = functype(fakethis(), $2, $4); + funcnam($$, nil); + } +| LFUNC '(' oarg_type_list ')' fnres + { + // with func keyword + $$ = functype(fakethis(), $3, $5); + funcnam($$, nil); + } +| latype + { + $$ = oldtype($1); + if($$ == T || $$->etype != TFUNC) + yyerror("illegal type for function literal"); + } + +arg_type: + name_name + { + $$ = nod(ODCLFIELD, $1, N); + } +| type + { + $$ = nod(ODCLFIELD, N, N); + $$->type = $1; + } +| new_name type + { + $$ = nod(ODCLFIELD, $1, N); + $$->type = $2; + } + +arg_type_list_r: + arg_type +| arg_type_list_r ',' arg_type + { + $$ = nod(OLIST, $1, $3); + } + +stmt_list_r: + stmt + { + $$ = $1; + } +| stmt_list_r stmt + { + $$ = nod(OLIST, $1, $2); + } + +expr_list_r: + expr +| expr_list_r ',' expr + { + $$ = nod(OLIST, $1, $3); + } + +new_name_list_r: + new_name +| new_name_list_r ',' new_name + { + $$ = nod(OLIST, $1, $3); + } + +export_list_r: + export +| export_list_r ocomma export + { + $$ = nod(OLIST, $1, $3); + } + +export: + sym + { + $$ = nod(OEXPORT, N, N); + $$->sym = $1; + } +| sym '.' sym + { + $$ = nod(OEXPORT, N, N); + $$->psym = $1; + $$->sym = $3; + } + +import_stmt_list_r: + import_stmt +| import_stmt_list_r osemi import_stmt + +hidden_import_list_r: + hidden_import +| hidden_import_list_r hidden_import + +hidden_importsym_list_r: + hidden_importsym +| hidden_importsym_list_r hidden_importsym + { + $$ = nod(OLIST, $1, $2); + } + +hidden_importfield_list_r: + hidden_importfield +| hidden_importfield_list_r hidden_importfield + { + $$ = nod(OLIST, $1, $2); + } + +keyval_list_r: + keyval +| keyval_list_r ',' keyval + { + $$ = nod(OLIST, $1, $3); + } + +/* + * the one compromise of a + * non-reversed list + */ +expr_list: + expr_list_r + { + $$ = rev($1); + } + +/* + * optional things + */ +osemi: +| ';' + +ocomma: +| ',' + +oexpr: + { + $$ = N; + } +| expr + +oexpr_list: + { + $$ = N; + } +| expr_list + +osimple_stmt: + { + $$ = N; + } +| simple_stmt + +ostmt_list: + { + $$ = N; + } +| stmt_list_r + { + $$ = rev($1); + } + +oxdcl_list: + { + $$ = N; + } +| xdcl_list_r + { + $$ = rev($1); + } + +ohidden_importsym_list: + { + $$ = N; + } +| hidden_importsym_list_r + { + $$ = rev($1); + } + +ohidden_importfield_list: + { + $$ = N; + } +| hidden_importfield_list_r + { + $$ = rev($1); + } + +oarg_type_list: + { + $$ = N; + } +| arg_type_list_r + { + $$ = cleanidlist(rev($1)); + } + +/* + * import syntax from header of + * an output package + */ +hidden_import: + /* variables */ + LVAR hidden_importsym hidden_importsym + { + // var + doimportv1($2, $3); + } + + /* constants */ +| LCONST hidden_importsym LLITERAL + { + doimportc1($2, &$3); + } +| LCONST hidden_importsym hidden_importsym LLITERAL + { + doimportc2($2, $3, &$4); + } + + /* types */ +| LTYPE hidden_importsym '[' hidden_importsym ']' hidden_importsym + { + // type map + doimport1($2, $4, $6); + } +| LTYPE hidden_importsym '[' LLITERAL ']' hidden_importsym + { + // type array + doimport2($2, &$4, $6); + } +| LTYPE hidden_importsym '(' ohidden_importsym_list ')' + { + // type function + doimport3($2, $4); + } +| LTYPE hidden_importsym '{' ohidden_importfield_list '}' + { + // type structure + doimport4($2, $4); + } +| LTYPE hidden_importsym LLITERAL + { + // type basic + doimport5($2, &$3); + } +| LTYPE hidden_importsym '*' hidden_importsym + { + // type pointer + doimport6($2, $4); + } +| LTYPE hidden_importsym LLT ohidden_importfield_list LGT + { + // type interface + doimport7($2, $4); + } + +isym: + sym '.' sym + { + $1->lexical = LPACK; + $$ = nod(OIMPORT, N, N); + $$->osym = $1; + $$->psym = $1; + $$->sym = $3; + } +| '(' sym ')' sym '.' sym + { + $$ = nod(OIMPORT, N, N); + $$->osym = $2; + $$->psym = $4; + $$->sym = $6; + } + +hidden_importsym: + isym +| '!' isym + { + $$ = $2; + } + +hidden_importfield: + sym isym + { + $$ = $2; + $$->fsym = $1; + } diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c new file mode 100644 index 0000000000..b44540cd71 --- /dev/null +++ b/src/cmd/gc/lex.c @@ -0,0 +1,1088 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + + +#define EXTERN +#include "go.h" +#include "y.tab.h" + +#define DBG if(!debug['x']);else print +enum +{ + EOF = -1, +}; + +int +main(int argc, char *argv[]) +{ + int c; + + outfile = nil; + package = "____"; + ARGBEGIN { + default: + c = ARGC(); + if(c >= 0 && c < sizeof(debug)) + debug[c]++; + break; + + case 'o': + outfile = ARGF(); + break; + + case 'k': + package = ARGF(); + break; + } ARGEND + + if(argc != 1) + goto usage; + + fmtinstall('O', Oconv); // node opcodes + fmtinstall('E', Econv); // etype opcodes + fmtinstall('J', Jconv); // all the node flags + fmtinstall('S', Sconv); // sym pointer + fmtinstall('T', Tconv); // type pointer + fmtinstall('N', Nconv); // node pointer + fmtinstall('Z', Zconv); // escaped string + + lexinit(); + + curio.infile = argv[0]; + + curio.bin = Bopen(curio.infile, OREAD); + if(curio.bin == nil) + fatal("cant open: %s", curio.infile); + + externdcl = mal(sizeof(*externdcl)); + externdcl->back = externdcl; + dclcontext = PEXTERN; + + exportlist = mal(sizeof(*exportlist)); + exportlist->back = exportlist; + + // function field skeleton + fskel = nod(OLIST, N, nod(OLIST, N, N)); + fskel->left = nod(ODCLFIELD, N, N); + fskel->right->left = nod(ODCLFIELD, N, N); + fskel->right->right = nod(ODCLFIELD, N, N); + + curio.peekc = 0; + curio.lineno = 1; + nerrors = 0; + yyparse(); + + Bterm(curio.bin); + if(bout != nil) + Bterm(bout); + + if(nerrors) + errorexit(); + + dumpobj(); + + myexit(0); + return 0; + +usage: + print("flags:\n"); + print(" -d print declarations\n"); + print(" -f print stack frame structure\n"); + print(" -k name specify package name\n"); + print(" -o file specify output file\n"); + print(" -p print the assembly language\n"); + print(" -w print the parse tree after typing\n"); + print(" -x print lex tokens\n"); + print(" -h panic on an error\n"); + myexit(0); + return 0; +} + +void +importfile(Val *f) +{ + Biobuf *imp; + long c; + + if(f->ctype != CTSTR) { + yyerror("import statement not a string"); + return; + } + // BOTCH need to get .8 from backend + snprint(namebuf, sizeof(namebuf), "%Z.8", f->sval); + + imp = Bopen(namebuf, OREAD); + if(imp == nil) { + yyerror("cant open import: %s", namebuf); + return; + } + + /* + * position the input right + * after (( and return + */ + pushedio = curio; + curio.bin = imp; + curio.lineno = 1; + curio.peekc = 0; + curio.infile = strdup(namebuf); + for(;;) { + c = getc(); + if(c == EOF) + break; + if(c != '(') + continue; + c = getc(); + if(c == EOF) + break; + if(c != '(') + continue; + return; + } + yyerror("no import in: %Z", f->sval); + unimportfile(); +} + +void +unimportfile(void) +{ + if(curio.bin != nil) { + Bterm(curio.bin); + curio.bin = nil; + } + curio = pushedio; + pushedio.bin = nil; +} + +void +cannedimports(void) +{ + pushedio = curio; + curio.bin = nil; + curio.lineno = 1; + curio.peekc = 0; + curio.infile = "internal sys.go"; + curio.cp = sysimport; + pkgmyname = S; +} + +long +yylex(void) +{ + long c, c1; + char *cp; + Rune rune; + int escflag; + Sym *s; + +l0: + c = getc(); + if(isspace(c)) + goto l0; + + if(c >= Runeself) { + /* all multibyte runes are alpha */ + cp = namebuf; + goto talph; + } + + if(isalpha(c)) { + cp = namebuf; + goto talph; + } + + if(isdigit(c)) + goto tnum; + + switch(c) { + case EOF: + ungetc(EOF); + return -1; + + case '_': + cp = namebuf; + goto talph; + + case '.': + c1 = getc(); + if(isdigit(c1)) { + cp = namebuf; + *cp++ = c; + c = c1; + c1 = 0; + goto casedot; + } + break; + + case '"': + /* "..." */ + strcpy(namebuf, "\"\""); + cp = mal(sizeof(long)); + c1 = 4; + + caseq: + for(;;) { + c = escchar('"', &escflag); + if(c == EOF) + break; + if(escflag) { + cp = remal(cp, c1, 1); + cp[c1++] = c; + } else { + rune = c; + c = runelen(rune); + cp = remal(cp, c1, c); + runetochar(cp+c1, &rune); + c1 += c; + } + } + goto catem; + + case '`': + /* `...` */ + strcpy(namebuf, "``"); + cp = mal(sizeof(long)); + c1 = 4; + + casebq: + for(;;) { + c = getc(); + if(c == EOF || c == '`') + break; + cp = remal(cp, c1, 1); + cp[c1++] = c; + } + + catem: + for(;;) { + /* it takes 2 peekc's to skip comments */ + c = getc(); + if(isspace(c)) + continue; + if(c == '"') + goto caseq; + if(c == '`') + goto casebq; + ungetc(c); + break; + } + + *(long*)cp = c1-4; // length + do { + cp = remal(cp, c1, 1); + cp[c1++] = 0; + } while(c1 & MAXALIGN); + yylval.val.sval = (String*)cp; + yylval.val.ctype = CTSTR; + DBG("lex: string literal\n"); + return LLITERAL; + + case '\'': + /* '.' */ + c = escchar('\'', &escflag); + if(c == EOF) + c = '\''; + c1 = escchar('\'', &escflag); + if(c1 != EOF) { + yyerror("missing '"); + ungetc(c1); + } + yylval.val.vval = c; + yylval.val.ctype = CTINT; + DBG("lex: codepoint literal\n"); + return LLITERAL; + + case '/': + c1 = getc(); + if(c1 == '*') { + for(;;) { + c = getr(); + while(c == '*') { + c = getr(); + if(c == '/') + goto l0; + } + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + } + } + if(c1 == '/') { + for(;;) { + c = getr(); + if(c == '\n') + goto l0; + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + } + } + if(c1 == '=') { + c = ODIV; + goto asop; + } + break; + + case ':': + c1 = getc(); + if(c1 == '=') { + c = LCOLAS; + goto lx; + } + break; + + case '*': + c1 = getc(); + if(c1 == '=') { + c = OMUL; + goto asop; + } + break; + + case '%': + c1 = getc(); + if(c1 == '=') { + c = OMOD; + goto asop; + } + break; + + case '+': + c1 = getc(); + if(c1 == '+') { + c = LINC; + goto lx; + } + if(c1 == '=') { + c = OADD; + goto asop; + } + break; + + case '-': + c1 = getc(); + if(c1 == '-') { + c = LDEC; + goto lx; + } + if(c1 == '=') { + c = OSUB; + goto asop; + } + break; + + case '>': + c1 = getc(); + if(c1 == '>') { + c = LRSH; + c1 = getc(); + if(c1 == '=') { + c = ORSH; + goto asop; + } + break; + } + if(c1 == '=') { + c = LGE; + goto lx; + } + c = LGT; + break; + + case '<': + c1 = getc(); + if(c1 == '<') { + c = LLSH; + c1 = getc(); + if(c1 == '=') { + c = OLSH; + goto asop; + } + break; + } + if(c1 == '=') { + c = LLE; + goto lx; + } + c = LLT; + break; + + case '=': + c1 = getc(); + if(c1 == '=') { + c = LEQ; + goto lx; + } + break; + + case '!': + c1 = getc(); + if(c1 == '=') { + c = LNE; + goto lx; + } + break; + + case '&': + c1 = getc(); + if(c1 == '&') { + c = LANDAND; + goto lx; + } + if(c1 == '=') { + c = OAND; + goto asop; + } + break; + + case '|': + c1 = getc(); + if(c1 == '|') { + c = LOROR; + goto lx; + } + if(c1 == '=') { + c = OOR; + goto asop; + } + break; + + case '^': + c1 = getc(); + if(c1 == '=') { + c = OXOR; + goto asop; + } + break; + + default: + goto lx; + } + ungetc(c1); + +lx: + if(c > 0xff) + DBG("lex: TOKEN %s\n", lexname(c)); + else + DBG("lex: TOKEN '%c'\n", c); + return c; + +asop: + yylval.val.vval = c; // rathole to hold which asop + DBG("lex: TOKEN ASOP %c\n", c); + return LASOP; + +talph: + /* + * cp is set to namebuf and some + * prefix has been stored + */ + for(;;) { + if(c >= Runeself) { + for(c1=0;;) { + cp[c1++] = c; + if(fullrune(cp, c1)) + break; + c = getc(); + } + cp += c1; + c = getc(); + continue; + } + if(!isalnum(c) && c != '_') + break; + *cp++ = c; + c = getc(); + } + *cp = 0; + ungetc(c); + + s = lookup(namebuf); + if(s->lexical == LIGNORE) + goto l0; + + if(context != nil) { + s = pkglookup(s->name, context); + if(s->lexical == LIGNORE) + goto l0; + } + + DBG("lex: %S %s\n", s, lexname(s->lexical)); + yylval.sym = s; + if(s->lexical == LBASETYPE) + return LATYPE; + return s->lexical; + +tnum: + c1 = 0; + cp = namebuf; + if(c != '0') { + for(;;) { + *cp++ = c; + c = getc(); + if(isdigit(c)) + continue; + goto dc; + } + } + *cp++ = c; + c = getc(); + if(c == 'x' || c == 'X') + for(;;) { + *cp++ = c; + c = getc(); + if(isdigit(c)) + continue; + if(c >= 'a' && c <= 'f') + continue; + if(c >= 'A' && c <= 'F') + continue; + if(cp == namebuf+2) + yyerror("malformed hex constant"); + goto ncu; + } + if(c < '0' || c > '7') + goto dc; + for(;;) { + if(c >= '0' && c <= '7') { + *cp++ = c; + c = getc(); + continue; + } + goto ncu; + } + +dc: + if(c == '.') + goto casedot; + if(c == 'e' || c == 'E') + goto casee; + +ncu: + *cp = 0; + ungetc(c); + if(mpatov(namebuf, &yylval.val.vval)) { + yyerror("overflow in constant"); + yylval.val.vval = 0; + } + yylval.val.ctype = CTINT; + DBG("lex: integer literal\n"); + return LLITERAL; + +casedot: + for(;;) { + *cp++ = c; + c = getc(); + if(!isdigit(c)) + break; + } + if(c != 'e' && c != 'E') + goto caseout; + +casee: + *cp++ = 'e'; + c = getc(); + if(c == '+' || c == '-') { + *cp++ = c; + c = getc(); + } + if(!isdigit(c)) + yyerror("malformed fp constant exponent"); + while(isdigit(c)) { + *cp++ = c; + c = getc(); + } + +caseout: + *cp = 0; + ungetc(c); + if(mpatof(namebuf, &yylval.val.dval)) { + yyerror("overflow in float constant"); + yylval.val.dval = 0; + } + yylval.val.ctype = CTFLT; + DBG("lex: floating literal\n"); + return LLITERAL; +} + +int +getc(void) +{ + int c; + + c = curio.peekc; + if(c != 0) { + curio.peekc = 0; + if(c == '\n') + curio.lineno++; + return c; + } + + if(curio.bin == nil) { + c = *curio.cp & 0xff; + if(c != 0) + curio.cp++; + } else + c = Bgetc(curio.bin); + + switch(c) { + case 0: + case EOF: + return EOF; + + case '\n': + curio.lineno++; + break; + } + return c; +} + +void +ungetc(int c) +{ + curio.peekc = c; + if(c == '\n') + curio.lineno--; +} + +long +getr(void) +{ + int c, i; + char str[UTFmax+1]; + Rune rune; + + c = getc(); + if(c < Runeself) + return c; + i = 0; + str[i++] = c; + +loop: + c = getc(); + str[i++] = c; + if(!fullrune(str, i)) + goto loop; + c = chartorune(&rune, str); + if(rune == Runeerror && c == 1) { + yyerror("illegal rune in string"); + for(c=0; c0; i--) { + c = getc(); + if(c >= '0' && c <= '9') { + l = l*16 + c-'0'; + continue; + } + if(c >= 'a' && c <= 'f') { + l = l*16 + c-'a' + 10; + continue; + } + if(c >= 'A' && c <= 'F') { + l = l*16 + c-'A' + 10; + continue; + } + warn("non-hex character in escape sequence: %c", c); + ungetc(c); + break; + } + *escflg = 1; + return l; + +oct: + l = c - '0'; + for(i=2; i>0; i--) { + c = getc(); + if(c >= '0' && c <= '7') { + l = l*8 + c-'0'; + continue; + } + warn("non-oct character in escape sequence: %c", c); + ungetc(c); + } + if(l > 255) + warn("oct escape value > 255: %d", l); + *escflg = 1; + return l; +} + +static struct +{ + char* name; + int lexical; + int etype; +} syms[] = +{ +/* name lexical etype + */ +/* basic types */ + "int8", LBASETYPE, TINT8, + "int16", LBASETYPE, TINT16, + "int32", LBASETYPE, TINT32, + "int64", LBASETYPE, TINT64, + + "uint8", LBASETYPE, TUINT8, + "uint16", LBASETYPE, TUINT16, + "uint32", LBASETYPE, TUINT32, + "uint64", LBASETYPE, TUINT64, + + "float32", LBASETYPE, TFLOAT32, + "float64", LBASETYPE, TFLOAT64, + "float80", LBASETYPE, TFLOAT80, + + "bool", LBASETYPE, TBOOL, + "byte", LBASETYPE, TUINT8, + "char", LBASETYPE, TUINT8, // temp?? + "string", LBASETYPE, TSTRING, + +/* keywords */ + "any", LANY, Txxx, + "break", LBREAK, Txxx, + "case", LCASE, Txxx, + "chan", LCHAN, Txxx, + "const", LCONST, Txxx, + "continue", LCONTINUE, Txxx, + "convert", LCONVERT, Txxx, + "default", LDEFAULT, Txxx, + "else", LELSE, Txxx, + "export", LEXPORT, Txxx, + "fallthrough", LFALL, Txxx, + "false", LFALSE, Txxx, + "for", LFOR, Txxx, + "func", LFUNC, Txxx, + "go", LGO, Txxx, + "goto", LGOTO, Txxx, + "if", LIF, Txxx, + "import", LIMPORT, Txxx, + "interface", LINTERFACE, Txxx, + "iota", LIOTA, Txxx, + "map", LMAP, Txxx, + "new", LNEW, Txxx, + "len", LLEN, Txxx, + "nil", LNIL, Txxx, + "package", LPACKAGE, Txxx, + "panic", LPANIC, Txxx, + "print", LPRINT, Txxx, + "range", LRANGE, Txxx, + "return", LRETURN, Txxx, + "struct", LSTRUCT, Txxx, + "switch", LSWITCH, Txxx, + "true", LTRUE, Txxx, + "type", LTYPE, Txxx, + "var", LVAR, Txxx, + + "notwithstanding", LIGNORE, Txxx, + "thetruthofthematter", LIGNORE, Txxx, + "despiteallobjections", LIGNORE, Txxx, + "whereas", LIGNORE, Txxx, + "insofaras", LIGNORE, Txxx, +}; + +void +lexinit(void) +{ + int i, etype, lex; + Sym *s; + Type *t; + + besetptr(); + + for(i=TINT8; i<=TUINT64; i++) + isint[i] = 1; + for(i=TFLOAT32; i<=TFLOAT80; i++) + isfloat[i] = 1; + isptr[TPTR32] = 1; + isptr[TPTR64] = 1; + + issigned[TINT8] = 1; + issigned[TINT16] = 1; + issigned[TINT32] = 1; + issigned[TINT64] = 1; + + /* + * initialize okfor + */ + for(i=0; ilexical = lex; + + if(lex != LBASETYPE) + continue; + + etype = syms[i].etype; + if(etype < 0 || etype >= nelem(types)) + fatal("lexinit: %s bad etype", s->name); + + t = types[etype]; + if(t != T) { + s->otype = t; + continue; + } + t = typ(etype); + switch(etype) { + case TSTRING: + case TCHAN: + case TMAP: + t = ptrto(t); + } + + t->sym = s; + t->recur = 1; // supresses printing beyond name + + dowidth(t); + types[etype] = t; + s->otype = t; + } + + /* pick up the backend typedefs */ + belexinit(LBASETYPE); + + booltrue = nod(OLITERAL, N, N); + booltrue->val.ctype = CTBOOL; + booltrue->val.vval = 1; + booltrue->type = types[TBOOL]; + booltrue->addable = 1; + + boolfalse = nod(OLITERAL, N, N); + boolfalse->val.ctype = CTBOOL; + boolfalse->val.vval = 0; + boolfalse->type = types[TBOOL]; + boolfalse->addable = 1; +} + +struct +{ + int lex; + char* name; +} lexn[] = +{ + LANDAND, "ANDAND", + LASOP, "ASOP", + LACONST, "ACONST", + LATYPE, "ATYPE", + LBASETYPE, "BASETYPE", + LBREAK, "BREAK", + LCASE, "CASE", + LCHAN, "CHAN", + LCOLAS, "COLAS", + LCONST, "CONST", + LCONTINUE, "CONTINUE", + LDEC, "DEC", + LELSE, "ELSE", + LEQ, "EQ", + LFUNC, "FUNC", + LGE, "GE", + LGO, "GO", + LGOTO, "GOTO", + LGT, "GT", + LIF, "IF", + LINC, "INC", + LINTERFACE, "INTERFACE", + LLE, "LE", + LLITERAL, "LITERAL", + LLSH, "LSH", + LLT, "LT", + LMAP, "MAP", + LNAME, "NAME", + LNE, "NE", + LOROR, "OROR", + LPACK, "PACK", + LRANGE, "RANGE", + LRETURN, "RETURN", + LRSH, "RSH", + LSTRUCT, "STRUCT", + LSWITCH, "SWITCH", + LTYPE, "TYPE", + LVAR, "VAR", + LFOR, "FOR", + LNEW, "NEW", + LLEN, "LEN", + LFALL, "FALL", + LCONVERT, "CONVERT", + LIOTA, "IOTA", + LPRINT, "PRINT", + LPACKAGE, "PACKAGE", + LIMPORT, "IMPORT", + LEXPORT, "EXPORT", + LPANIC, "PANIC", +}; + +char* +lexname(int lex) +{ + int i; + static char buf[100]; + + for(i=0; ilink) { + s->package = package; + s->opackage = package; + } + + if(outfile == nil) { + // BOTCH need to get .6 from backend + snprint(namebuf, sizeof(namebuf), "%s.6", package); + outfile = strdup(namebuf); + } +} diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash new file mode 100644 index 0000000000..edd1c9df78 --- /dev/null +++ b/src/cmd/gc/mksys.bash @@ -0,0 +1,19 @@ +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +6g sys.go +echo '1,/((/d +/))/+1,$d +1,$s/foop/sys/g +1,$s/^[ ]*/ "/g +1,$s/$/\\n"/g +1i +char* sysimport = +. +$a +; + +. +w sysimport.c +q' | ed foop.6 diff --git a/src/cmd/gc/mpatof.c b/src/cmd/gc/mpatof.c new file mode 100644 index 0000000000..07bcf4a27a --- /dev/null +++ b/src/cmd/gc/mpatof.c @@ -0,0 +1,342 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include +#include + +int mpatof(char*, double*); +int mpatov(char *s, vlong *v); + +enum +{ + Mpscale = 29, /* safely smaller than bits in a long */ + Mpprec = 36, /* Mpscale*Mpprec sb > largest fp exp */ + Mpbase = 1L<= '0' && c <= '9') { + ex = ex*10 + (c-'0'); + continue; + } + break; + } + if(ef) + ex = -ex; + case 0: + break; + } + break; + } + if(a.ovf) + goto bad; + if(zer) { + *d = 0; + return 0; + } + if(dp) + dp--; + dp -= ex; + if(dp > 0) { + /* + * must divide by 10**dp + */ + if(mptof(&a, &d1)) + goto bad; + + /* + * trial exponent of 8**dp + * 8 (being between 5 and 10) + * should pick up all underflows + * in the division of 5**dp. + */ + d2 = frexp(d1, &ex); + d2 = ldexp(d2, ex-3*dp); + if(d2 == 0) + goto bad; + + /* + * decompose each 10 into 5*2. + * create 5**dp in fixed point + * and then play with the exponent + * for the remaining 2**dp. + * note that 5**dp will overflow + * with as few as 134 input digits. + */ + mpint(&a, 1); + mppow(&a, 5, dp); + if(mptof(&a, &d2)) + goto bad; + d1 = frexp(d1/d2, &ex); + d1 = ldexp(d1, ex-dp); + if(d1 == 0) + goto bad; + } else { + /* + * must multiply by 10**|dp| -- + * just do it in fixed point. + */ + mppow(&a, 10, -dp); + if(mptof(&a, &d1)) + goto bad; + } + if(f) + d1 = -d1; + *d = d1; + return 0; + +bad: + return 1; +} + +/* + * convert a to floating in *d + * return conversion overflow + */ +static int +mptof(Mp *a, double *d) +{ + double f, g; + long x, *a1; + int i; + + if(a->ovf) + return 1; + a1 = a->a; + f = ldexp(*a1++, 0); + for(i=Mpscale; iovf) + a->ovf = 1; + if(a->ovf) + return; + c = 0; + a1 = a->a; + b1 = b->a; + for(i=0; i= Mpbase) { + x -= Mpbase; + c = 1; + } + *a1++ = x; + } + a->ovf = c; +} + +/* + * return a = c + */ +static void +mpint(Mp *a, int c) +{ + + memset(a, 0, sizeof(*a)); + a->a[0] = c; +} + +/* + * return a *= c + */ +static void +mpmul(Mp *a, int c) +{ + Mp p; + int b; + memmove(&p, a, sizeof(p)); + if(!(c & 1)) + memset(a, 0, sizeof(*a)); + c &= ~1; + for(b=2; c; b<<=1) { + mpadd(&p, &p); + if(c & b) { + mpadd(a, &p); + c &= ~b; + } + } +} + +/* + * return a *= b**e + */ +static void +mppow(Mp *a, int b, int e) +{ + int b1; + + b1 = b*b; + b1 = b1*b1; + while(e >= 4) { + mpmul(a, b1); + e -= 4; + if(a->ovf) + return; + } + while(e > 0) { + mpmul(a, b); + e--; + } +} + +/* + * convert a string, s, to vlong in *v + * return conversion overflow. + * required syntax is [0[x]]d* + */ +int +mpatov(char *s, vlong *v) +{ + vlong n, nn; + int c; + n = 0; + c = *s; + if(c == '0') + goto oct; + while(c = *s++) { + if(c >= '0' && c <= '9') + nn = n*10 + c-'0'; + else + goto bad; + if(n < 0 && nn >= 0) + goto bad; + n = nn; + } + goto out; +oct: + s++; + c = *s; + if(c == 'x' || c == 'X') + goto hex; + while(c = *s++) { + if(c >= '0' || c <= '7') + nn = n*8 + c-'0'; + else + goto bad; + if(n < 0 && nn >= 0) + goto bad; + n = nn; + } + goto out; +hex: + s++; + while(c = *s++) { + if(c >= '0' && c <= '9') + c += 0-'0'; + else + if(c >= 'a' && c <= 'f') + c += 10-'a'; + else + if(c >= 'A' && c <= 'F') + c += 10-'A'; + else + goto bad; + nn = n*16 + c; + if(n < 0 && nn >= 0) + goto bad; + n = nn; + } +out: + *v = n; + return 0; + +bad: + *v = ~0; + return 1; +} diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c new file mode 100644 index 0000000000..6f1ad12ab2 --- /dev/null +++ b/src/cmd/gc/subr.c @@ -0,0 +1,1591 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go.h" +#include "y.tab.h" + +void +errorexit(void) +{ + if(outfile) + remove(outfile); + myexit(1); +} + +void +myexit(int x) +{ + if(x) + exits("error"); + exits(nil); +} + +void +yyerror(char *fmt, ...) +{ + va_list arg; + long lno; + + lno = dynlineno; + if(lno == 0) + lno = curio.lineno; + + print("%s:%ld: ", curio.infile, lno); + va_start(arg, fmt); + vfprint(1, fmt, arg); + va_end(arg); + print("\n"); + if(debug['h']) + *(int*)0 = 0; + + nerrors++; + if(nerrors >= 10) + fatal("too many errors"); +} + +void +warn(char *fmt, ...) +{ + va_list arg; + long lno; + + lno = dynlineno; + if(lno == 0) + lno = curio.lineno; + + print("%s:%ld: ", curio.infile, lno); + va_start(arg, fmt); + vfprint(1, fmt, arg); + va_end(arg); + print("\n"); + if(debug['h']) + *(int*)0 = 0; +} + +void +fatal(char *fmt, ...) +{ + va_list arg; + long lno; + + lno = dynlineno; + if(lno == 0) + lno = curio.lineno; + + print("%s:%ld: fatal error: ", curio.infile, lno); + va_start(arg, fmt); + vfprint(1, fmt, arg); + va_end(arg); + print("\n"); + if(debug['h']) + *(int*)0 = 0; + myexit(1); +} + +ulong +stringhash(char *p) +{ + long h; + int c; + + h = 0; + for(;;) { + c = *p++; + if(c == 0) + break; + h = h*PRIME1 + c; + } + + if(h < 0) { + h = -h; + if(h < 0) + h = 0; + } + return h; +} + +Sym* +lookup(char *p) +{ + Sym *s; + ulong h; + int c; + + h = stringhash(p) % NHASH; + c = p[0]; + + for(s = hash[h]; s != S; s = s->link) { + if(s->name[0] != c) + continue; + if(strcmp(s->name, p) == 0) + if(strcmp(s->package, package) == 0) + return s; + } + + s = mal(sizeof(*s)); + s->lexical = LNAME; + s->name = mal(strlen(p)+1); + s->opackage = package; + s->package = package; + + strcpy(s->name, p); + + s->link = hash[h]; + hash[h] = s; + + return s; +} + +Sym* +pkglookup(char *p, char *k) +{ + Sym *s; + ulong h; + int c; + + h = stringhash(p) % NHASH; + c = p[0]; + for(s = hash[h]; s != S; s = s->link) { + if(s->name[0] != c) + continue; + if(strcmp(s->name, p) == 0) + if(strcmp(s->package, k) == 0) + return s; + } + + s = mal(sizeof(*s)); + s->lexical = LNAME; + s->name = mal(strlen(p)+1); + strcpy(s->name, p); + + // botch - should probably try to reuse the pkg string + s->package = mal(strlen(k)+1); + s->opackage = s->package; + strcpy(s->package, k); + + s->link = hash[h]; + hash[h] = s; + + return s; +} + +void +gethunk(void) +{ + char *h; + long nh; + + nh = NHUNK; + if(thunk >= 10L*NHUNK) + nh = 10L*NHUNK; + h = (char*)malloc(nh); + if(h == (char*)-1) { + yyerror("out of memory"); + errorexit(); + } + hunk = h; + nhunk = nh; + thunk += nh; +} + +void* +mal(long n) +{ + void *p; + + while((ulong)hunk & MAXALIGN) { + hunk++; + nhunk--; + } + while(nhunk < n) + gethunk(); + + p = hunk; + nhunk -= n; + hunk += n; + memset(p, 0, n); + return p; +} + +void* +remal(void *p, long on, long n) +{ + void *q; + + q = (uchar*)p + on; + if(q != hunk || nhunk < n) { + while(nhunk < on+n) + gethunk(); + memmove(hunk, p, on); + p = hunk; + hunk += on; + nhunk -= on; + } + hunk += n; + nhunk -= n; + return p; +} + +Dcl* +dcl(void) +{ + Dcl *d; + + d = mal(sizeof(*d)); + d->lineno = dynlineno; + return d; +} + +Node* +nod(int op, Node *nleft, Node *nright) +{ + Node *n; + + n = mal(sizeof(*n)); + n->op = op; + n->left = nleft; + n->right = nright; + n->lineno = dynlineno; + if(dynlineno == 0) + n->lineno = curio.lineno; + return n; +} + +Type* +typ(int et) +{ + Type *t; + + t = mal(sizeof(*t)); + t->etype = et; + return t; +} + +Node* +dobad(void) +{ + return nod(OBAD, N, N); +} + +Node* +nodintconst(long v) +{ + Node *c; + + c = nod(OLITERAL, N, N); + c->addable = 1; + c->val.vval = v; + c->val.ctype = CTINT; + c->type = types[TINT32]; + ullmancalc(c); + return c; +} + +Node* +rev(Node *na) +{ + Node *i, *n; + + /* + * since yacc wants to build lists + * stacked down on the left - + * this routine converts them to + * stack down on the right - + * in memory without recursion + */ + + if(na == N || na->op != OLIST) + return na; + i = na; + for(n = na->left; n != N; n = n->left) { + if(n->op != OLIST) + break; + i->left = n->right; + n->right = i; + i = n; + } + i->left = n; + return i; +} + +Node* +unrev(Node *na) +{ + Node *i, *n; + + /* + * this restores a reverse list + */ + if(na == N || na->op != OLIST) + return na; + i = na; + for(n = na->right; n != N; n = n->right) { + if(n->op != OLIST) + break; + i->right = n->left; + n->left = i; + i = n; + } + i->right = n; + return i; +} + +Type* +aindex(Node *b, Type *t) +{ + Type *r; + + r = typ(TARRAY); + r->type = t; + + if(t->etype == TDARRAY) + yyerror("dynamic array type cannot be a dynamic array"); + + walktype(b, 0); + switch(whatis(b)) { + default: + yyerror("array bound must be a constant integer expression"); + break; + + case Wnil: // default zero lb + r->bound = 0; + break; + + case Wlitint: // fixed lb + r->bound = b->val.vval; + break; + } + return r; +} + +void +indent(int dep) +{ + int i; + + for(i=0; iop) { + case OLIST: + if(n->left != N && n->left->op == OLIST) + dodump(n->left, dep+1); + else + dodump(n->left, dep); + n = n->right; + goto loop; + +// case ODCLFUNC: +// dodump(n->nname, dep); +// if(n->this) { +// indent(dep); +// print("%O-this\n", n->op); +// dodump(n->this, dep+1); +// } +// if(n->argout) { +// indent(dep); +// print("%O-outarg\n", n->op); +// dodump(n->argout, dep+1); +// } +// if(n->argin) { +// indent(dep); +// print("%O-inarg\n", n->op); +// dodump(n->argin, dep+1); +// } +// n = n->nbody; +// goto loop; + + case OIF: + case OSWITCH: + case OFOR: + dodump(n->ninit, dep); + break; + } + + indent(dep); + if(dep > 10) { + print("...\n"); + return; + } + + switch(n->op) { + default: + print("%N\n", n); + break; + + case OTYPE: + print("%O-%E %lT\n", n->op, n->etype, n); + break; + + case OIF: + print("%O%J\n", n->op, n); + dodump(n->ntest, dep+1); + if(n->nbody != N) { + indent(dep); + print("%O-then\n", n->op); + dodump(n->nbody, dep+1); + } + if(n->nelse != N) { + indent(dep); + print("%O-else\n", n->op); + dodump(n->nelse, dep+1); + } + return; + + case OSWITCH: + case OFOR: + print("%O%J\n", n->op, n); + dodump(n->ntest, dep+1); + + if(n->nbody != N) { + indent(dep); + print("%O-body\n", n->op); + dodump(n->nbody, dep+1); + } + + if(n->nincr != N) { + indent(dep); + print("%O-incr\n", n->op); + dodump(n->nincr, dep+1); + } + return; + + case OCASE: + // the right side points to the next case + print("%O%J\n", n->op, n); + dodump(n->left, dep+1); + return; + } + + dodump(n->left, dep+1); + n = n->right; + dep++; + goto loop; +} + +void +dump(char *s, Node *n) +{ + print("%s\n", s); + dodump(n, 1); +} + +int +whatis(Node *n) +{ + Type *t; + + if(n == N) + return Wnil; + + if(n->op == OLITERAL) { + switch(n->val.ctype) { + default: + break; + case CTINT: + case CTSINT: + case CTUINT: + return Wlitint; + case CTFLT: + return Wlitfloat; + case CTBOOL: + return Wlitbool; + case CTSTR: + return Wlitstr; + } + return Wtunkn; + } + + t = n->type; + if(t == T) + return Wtnil; + + switch(t->etype) { + case TINT8: + case TINT16: + case TINT32: + case TINT64: + case TUINT8: + case TUINT16: + case TUINT32: + case TUINT64: + return Wtint; + case TFLOAT32: + case TFLOAT64: + case TFLOAT80: + return Wtfloat; + case TBOOL: + return Wtbool; + + case TPTR32: + case TPTR64: + if(isptrto(t, TSTRING)) + return Wtstr; + break; + } + return Wtunkn; +} + +/* +s%,%,\n%g +s%\n+%\n%g +s%^[ ]*O%%g +s%,.*%%g +s%.+% [O&] = "&",%g +s%^ ........*\]%&~%g +s%~ %%g +*/ + +static char* +opnames[] = +{ + [OADDR] = "ADDR", + [OADD] = "ADD", + [OANDAND] = "ANDAND", + [OAND] = "AND", + [OARRAY] = "ARRAY", + [OASOP] = "ASOP", + [OAS] = "AS", + [OBAD] = "BAD", + [OBREAK] = "BREAK", + [OCALL] = "CALL", + [OCALLMETH] = "CALLMETH", + [OCALLINTER] = "CALLINTER", + [OCASE] = "CASE", + [OXCASE] = "XCASE", + [OCMP] = "CMP", + [OFALL] = "FALL", + [OCONV] = "CONV", + [OCOM] = "COM", + [OCONST] = "CONST", + [OCONTINUE] = "CONTINUE", + [ODCLARG] = "DCLARG", + [ODCLFIELD] = "DCLFIELD", + [ODCLFUNC] = "DCLFUNC", + [ODIV] = "DIV", + [ODOT] = "DOT", + [ODOTPTR] = "DOTPTR", + [ODOTMETH] = "DOTMETH", + [ODOTINTER] = "DOTINTER", + [OEMPTY] = "EMPTY", + [OEND] = "END", + [OEQ] = "EQ", + [OFOR] = "FOR", + [OFUNC] = "FUNC", + [OGE] = "GE", + [OPROC] = "PROC", + [OGOTO] = "GOTO", + [OGT] = "GT", + [OIF] = "IF", + [OINDEX] = "INDEX", + [OINDEXPTR] = "INDEXPTR", + [OIND] = "IND", + [OLABEL] = "LABEL", + [OLE] = "LE", + [OLEN] = "LEN", + [OLIST] = "LIST", + [OLITERAL] = "LITERAL", + [OLSH] = "LSH", + [OLT] = "LT", + [OMINUS] = "MINUS", + [OMOD] = "MOD", + [OMUL] = "MUL", + [ONAME] = "NAME", + [ONE] = "NE", + [ONOT] = "NOT", + [OOROR] = "OROR", + [OOR] = "OR", + [OPLUS] = "PLUS", + [ODEC] = "DEC", + [OINC] = "INC", + [OREGISTER] = "REGISTER", + [OINDREG] = "INDREG", + [OSEND] = "SEND", + [ORECV] = "RECV", + [OPTR] = "PTR", + [ORETURN] = "RETURN", + [ORSH] = "RSH", + [OI2S] = "I2S", + [OS2I] = "S2I", + [OI2I] = "I2I", + [OSLICE] = "SLICE", + [OSUB] = "SUB", + [OSWITCH] = "SWITCH", + [OTYPE] = "TYPE", + [OVAR] = "VAR", + [OEXPORT] = "EXPORT", + [OIMPORT] = "IMPORT", + [OXOR] = "XOR", + [ONEW] = "NEW", + [OFALL] = "FALL", + [OXFALL] = "XFALL", + [OPANIC] = "PANIC", + [OPRINT] = "PRINT", + [OXXX] = "XXX", +}; + +int +Oconv(Fmt *fp) +{ + char buf[500]; + int o; + + o = va_arg(fp->args, int); + if(o < 0 || o >= nelem(opnames) || opnames[o] == nil) { + snprint(buf, sizeof(buf), "O-%d", o); + return fmtstrcpy(fp, buf); + } + return fmtstrcpy(fp, opnames[o]); +} + +/* +s%,%,\n%g +s%\n+%\n%g +s%^[ ]*T%%g +s%,.*%%g +s%.+% [T&] = "&",%g +s%^ ........*\]%&~%g +s%~ %%g +*/ + +static char* +etnames[] = +{ + [TINT8] = "INT8", + [TUINT8] = "UINT8", + [TINT16] = "INT16", + [TUINT16] = "UINT16", + [TINT32] = "INT32", + [TUINT32] = "UINT32", + [TINT64] = "INT64", + [TUINT64] = "UINT64", + [TFLOAT32] = "FLOAT32", + [TFLOAT64] = "FLOAT64", + [TFLOAT80] = "FLOAT80", + [TBOOL] = "BOOL", + [TPTR32] = "PTR32", + [TPTR64] = "PTR64", + [TFUNC] = "FUNC", + [TARRAY] = "ARRAY", + [TDARRAY] = "DARRAY", + [TSTRUCT] = "STRUCT", + [TCHAN] = "CHAN", + [TMAP] = "MAP", + [TINTER] = "INTER", + [TFORW] = "FORW", + [TFIELD] = "FIELD", + [TSTRING] = "STRING", + [TCHAN] = "CHAN", +}; + +int +Econv(Fmt *fp) +{ + char buf[500]; + int et; + + et = va_arg(fp->args, int); + if(et < 0 || et >= nelem(etnames) || etnames[et] == nil) { + snprint(buf, sizeof(buf), "E-%d", et); + return fmtstrcpy(fp, buf); + } + return fmtstrcpy(fp, etnames[et]); +} + +int +Jconv(Fmt *fp) +{ + char buf[500], buf1[100]; + Node *n; + + n = va_arg(fp->args, Node*); + strcpy(buf, ""); + + if(n->ullman != 0) { + snprint(buf1, sizeof(buf1), " u(%d)", n->ullman); + strncat(buf, buf1, sizeof(buf)); + } + + if(n->addable != 0) { + snprint(buf1, sizeof(buf1), " a(%d)", n->addable); + strncat(buf, buf1, sizeof(buf)); + } + + if(n->vargen != 0) { + snprint(buf1, sizeof(buf1), " g(%ld)", n->vargen); + strncat(buf, buf1, sizeof(buf)); + } + + if(n->lineno != 0) { + snprint(buf1, sizeof(buf1), " l(%ld)", n->lineno); + strncat(buf, buf1, sizeof(buf)); + } + + return fmtstrcpy(fp, buf); +} + +int +Gconv(Fmt *fp) +{ + char buf[100]; + Type *t; + + t = va_arg(fp->args, Type*); + + if(t->etype == TFUNC) { + if(t->vargen != 0) { + snprint(buf, sizeof(buf), "-%d%d%d g(%ld)", + t->thistuple, t->outtuple, t->intuple, t->vargen); + goto out; + } + snprint(buf, sizeof(buf), "-%d%d%d", + t->thistuple, t->outtuple, t->intuple); + goto out; + } + if(t->vargen != 0) { + snprint(buf, sizeof(buf), " g(%ld)", t->vargen); + goto out; + } + strcpy(buf, ""); + +out: + return fmtstrcpy(fp, buf); +} + +int +Sconv(Fmt *fp) +{ + char buf[500]; + Sym *s; + char *opk, *pkg, *nam; + + s = va_arg(fp->args, Sym*); + if(s == S) { + snprint(buf, sizeof(buf), ""); + goto out; + } + + pkg = ""; + nam = pkg; + opk = pkg; + + if(s->opackage != nil) + opk = s->opackage; + if(s->package != nil) + pkg = s->package; + if(s->name != nil) + nam = s->name; + + if(strcmp(pkg, package) || strcmp(opk, package) || (fp->flags & FmtLong)) { + if(strcmp(opk, pkg) == 0) { + snprint(buf, sizeof(buf), "%s.%s", pkg, nam); + goto out; + } + snprint(buf, sizeof(buf), "(%s)%s.%s", opk, pkg, nam); + goto out; + } + snprint(buf, sizeof(buf), "%s", nam); + +out: + return fmtstrcpy(fp, buf); +} + +int +Tconv(Fmt *fp) +{ + char buf[500], buf1[500]; + Type *t, *t1; + int et; + + t = va_arg(fp->args, Type*); + if(t == T) + return fmtstrcpy(fp, ""); + + t->trecur++; + et = t->etype; + + strcpy(buf, ""); + if(t->sym != S) { + snprint(buf, sizeof(buf), "<%S>", t->sym); + } + if(t->trecur > 5) { + strncat(buf, "...", sizeof(buf)); + goto out; + } + + switch(et) { + default: + snprint(buf1, sizeof(buf1), "%E", et); + strncat(buf, buf1, sizeof(buf)); + if(t->type != T) { + snprint(buf1, sizeof(buf1), " %T", t->type); + strncat(buf, buf1, sizeof(buf)); + } + break; + + case TFIELD: + snprint(buf1, sizeof(buf1), "%T", t->type); + strncat(buf, buf1, sizeof(buf)); + break; + + case TFUNC: + if(fp->flags & FmtLong) + snprint(buf1, sizeof(buf1), "%d%d%d(%lT,%lT,%lT)", + t->thistuple, t->outtuple, t->intuple, + t->type, t->type->down, t->type->down->down); + else + snprint(buf1, sizeof(buf1), "%d%d%d(%T,%T,%T)", + t->thistuple, t->outtuple, t->intuple, + t->type, t->type->down, t->type->down->down); + strncat(buf, buf1, sizeof(buf)); + break; + + case TINTER: + strncat(buf, "I{", sizeof(buf)); + if(fp->flags & FmtLong) { + for(t1=t->type; t1!=T; t1=t1->down) { + snprint(buf1, sizeof(buf1), "%lT;", t1); + strncat(buf, buf1, sizeof(buf)); + } + } + strncat(buf, "}", sizeof(buf)); + break; + + case TSTRUCT: + strncat(buf, "{", sizeof(buf)); + if(fp->flags & FmtLong) { + for(t1=t->type; t1!=T; t1=t1->down) { + snprint(buf1, sizeof(buf1), "%lT;", t1); + strncat(buf, buf1, sizeof(buf)); + } + } + strncat(buf, "}", sizeof(buf)); + break; + + case TMAP: + snprint(buf, sizeof(buf), "[%T]%T", t->down, t->type); + break; + + case TARRAY: + snprint(buf1, sizeof(buf1), "[%ld]%T", t->bound, t->type); + strncat(buf, buf1, sizeof(buf)); + break; + + case TDARRAY: + snprint(buf1, sizeof(buf1), "[]%T", t->type); + strncat(buf, buf1, sizeof(buf)); + break; + + case TPTR32: + case TPTR64: + snprint(buf1, sizeof(buf1), "*%T", t->type); + strncat(buf, buf1, sizeof(buf)); + break; + } + +out: + t->trecur--; + return fmtstrcpy(fp, buf); +} + +int +Nconv(Fmt *fp) +{ + char buf[500], buf1[500]; + Node *n; + + n = va_arg(fp->args, Node*); + if(n == N) { + snprint(buf, sizeof(buf), ""); + goto out; + } + + switch(n->op) { + default: + snprint(buf, sizeof(buf), "%O%J", n->op, n); + break; + + case ONAME: + if(n->sym == S) { + snprint(buf, sizeof(buf), "%O%J", n->op, n); + break; + } + snprint(buf, sizeof(buf), "%O-%S G%ld%J", n->op, + n->sym, n->sym->vargen, n); + goto ptyp; + + case OREGISTER: + snprint(buf, sizeof(buf), "%O-%R%J", n->op, (int)n->val.vval, n); + break; + + case OLITERAL: + switch(n->val.ctype) { + default: + snprint(buf1, sizeof(buf1), "LITERAL-ctype=%d%lld", n->val.ctype, n->val.vval); + break; + case CTINT: + snprint(buf1, sizeof(buf1), "I%lld", n->val.vval); + break; + case CTSINT: + snprint(buf1, sizeof(buf1), "S%lld", n->val.vval); + break; + case CTUINT: + snprint(buf1, sizeof(buf1), "U%lld", n->val.vval); + break; + case CTFLT: + snprint(buf1, sizeof(buf1), "F%g", n->val.dval); + break; + case CTSTR: + snprint(buf1, sizeof(buf1), "S\"%Z\"", n->val.sval); + break; + case CTBOOL: + snprint(buf1, sizeof(buf1), "B%lld", n->val.vval); + break; + case CTNIL: + snprint(buf1, sizeof(buf1), "N"); + break; + } + snprint(buf, sizeof(buf), "%O-%s%J", n->op, buf1, n); + break; + + case OASOP: + snprint(buf, sizeof(buf), "%O-%O%J", n->op, n->etype, n); + break; + + case OTYPE: + snprint(buf, sizeof(buf), "%O-%E%J", n->op, n->etype, n); + break; + } + if(n->sym != S) { + snprint(buf1, sizeof(buf1), " %S G%ld", n->sym, n->sym->vargen); + strncat(buf, buf1, sizeof(buf)); + } + +ptyp: + if(n->type != T) { + snprint(buf1, sizeof(buf1), " %T", n->type); + strncat(buf, buf1, sizeof(buf)); + } + +out: + return fmtstrcpy(fp, buf); +} + +int +Zconv(Fmt *fp) +{ + char *s, *se; + char *p; + char buf[500]; + int c; + String *sp; + + sp = va_arg(fp->args, String*); + if(sp == nil) { + snprint(buf, sizeof(buf), ""); + goto out; + } + s = sp->s; + se = s + sp->len; + + p = buf; + +loop: + c = *s++; + if(s > se) + c = 0; + switch(c) { + default: + *p++ = c; + break; + case 0: + *p = 0; + goto out; + case '\t': + *p++ = '\\'; + *p++ = 't'; + break; + case '\n': + *p++ = '\\'; + *p++ = 'n'; + break; + } + goto loop; + +out: + return fmtstrcpy(fp, buf); +} + +int +isnil(Node *n) +{ + if(n == N) + return 0; + if(n->op != OLITERAL) + return 0; + if(n->val.ctype != CTNIL) + return 0; + return 1; +} + +int +isptrto(Type *t, int et) +{ + if(t == T) + return 0; + if(!isptr[t->etype]) + return 0; + t = t->type; + if(t == T) + return 0; + if(t->etype != et) + return 0; + return 1; +} + +int +isinter(Type *t) +{ + if(t != T && t->etype == TINTER) + return 1; + return 0; +} + +int +isbytearray(Type *t) +{ + if(t == T) + return 0; + if(isptr[t->etype]) { + t = t->type; + if(t == T) + return 0; + } + if(t->etype != TARRAY) + return 0; + return t->bound+1; +} + +int +eqtype(Type *t1, Type *t2, int d) +{ + if(d >= 10) + return 1; + + if(t1 == t2) + return 1; + if(t1 == T || t2 == T) + return 0; + + if(t1->etype != t2->etype) + return 0; + + switch(t1->etype) { + case TINTER: + case TSTRUCT: + t1 = t1->type; + t2 = t2->type; + for(;;) { + if(!eqtype(t1, t2, 0)) + return 0; + if(t1 == T) + return 1; + if(t1->nname != N && t1->nname->sym != S) { + if(t2->nname == N || t2->nname->sym == S) + return 0; + if(strcmp(t1->nname->sym->name, t2->nname->sym->name) != 0) { + // assigned names dont count + if(t1->nname->sym->name[0] != '_' || + t2->nname->sym->name[0] != '_') + return 0; + } + } + t1 = t1->down; + t2 = t2->down; + } + return 1; + + case TFUNC: + t1 = t1->type; + t2 = t2->type; + for(;;) { + if(t1 == t2) + break; + if(t1 == T || t2 == T) + return 0; + if(t1->etype != TSTRUCT || t2->etype != TSTRUCT) + return 0; + + if(!eqtype(t1->type, t2->type, 0)) + return 0; + + t1 = t1->down; + t2 = t2->down; + } + return 1; + } + return eqtype(t1->type, t2->type, d+1); +} + +/* + * are the arg names of two + * functions the same. we know + * that eqtype has been called + * and has returned true. + */ +int +eqargs(Type *t1, Type *t2) +{ + if(t1 == t2) + return 1; + if(t1 == T || t2 == T) + return 0; + + if(t1->etype != t2->etype) + return 0; + + if(t1->etype != TFUNC) + fatal("eqargs: oops %E", t1->etype); + + t1 = t1->type; + t2 = t2->type; + for(;;) { + if(t1 == t2) + break; + if(!eqtype(t1, t2, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + } + return 1; +} + +ulong +typehash(Type *at, int d) +{ + ulong h; + Type *t; + + if(at == T) + return PRIME2; + if(d >= 5) + return PRIME3; + + if(at->recur) + return 0; + at->recur = 1; + + h = at->etype*PRIME4; + + switch(at->etype) { + default: + h += PRIME5 * typehash(at->type, d+1); + break; + + case TINTER: + // botch -- should be sorted? + for(t=at->type; t!=T; t=t->down) + h += PRIME6 * typehash(t, d+1); + break; + + case TSTRUCT: + for(t=at->type; t!=T; t=t->down) + h += PRIME7 * typehash(t, d+1); + break; + + case TFUNC: + t = at->type; + // skip this argument + if(t != T) + t = t->down; + for(; t!=T; t=t->down) + h += PRIME7 * typehash(t, d+1); + break; + } + + at->recur = 0; + return h; +} + +Type* +ptrto(Type *t) +{ + Type *t1; + + if(tptr == 0) + fatal("ptrto: nil"); + t1 = typ(tptr); + t1->type = t; + return t1; +} + +Node* +literal(long v) +{ + Node *n; + + n = nod(OLITERAL, N, N); + n->val.ctype = CTINT; + n->val.vval = v; + return n; +} + +void +frame(int context) +{ + char *p; + Dcl *d; + int flag; + + p = "stack"; + d = autodcl; + if(context) { + p = "external"; + d = externdcl; + } + + flag = 1; + for(; d!=D; d=d->forw) { + switch(d->op) { + case ONAME: + if(flag) + print("--- %s frame ---\n", p); + print("%O %S G%ld T\n", d->op, d->dsym, d->dnode->vargen, d->dnode->type); + flag = 0; + break; + + case OTYPE: + if(flag) + print("--- %s frame ---\n", p); + print("%O %lT\n", d->op, d->dnode); + flag = 0; + break; + } + } +} + +/* + * calculate sethi/ullman number + * roughly how many registers needed to + * compile a node. used to compile the + * hardest side first to minimize registers. + */ +void +ullmancalc(Node *n) +{ + int ul, ur; + + if(n == N) + return; + + switch(n->op) { + case OLITERAL: + case ONAME: + ul = 0; + goto out; + case OS2I: + case OI2S: + case OI2I: + case OCALL: + ul = UINF; + goto out; + } + ul = 0; + if(n->left != N) + ul = n->left->ullman; + ur = 0; + if(n->right != N) + ur = n->right->ullman; + if(ul == ur) + ul += 1; + if(ur > ul) + ul = ur; + +out: + n->ullman = ul; +} + +void +badtype(int o, Type *tl, Type *tr) +{ + yyerror("illegal types for operand"); + if(tl != T) + print(" (%T)", tl); + print(" %O ", o); + if(tr != T) + print("(%T)", tr); + print("\n"); +} + +/* + * this routine gets the parsing of + * a parameter list that can have + * name, type and name-type. + * it must distribute lone names + * with trailing types to give every + * name a type. (a,b,c int) comes out + * (a int, b int, c int). + */ +Node* +cleanidlist(Node *r) +{ + Node *t, *n, *nn, *l; + Type *dt; + + t = N; // untyped name + nn = r; // next node to take + +loop: + n = nn; + if(n == N) { + if(t != N) { + yyerror("syntax error in parameter list"); + dt = types[TINT32]; + goto distrib; + } + return r; + } + + l = n; + nn = N; + if(l->op == OLIST) { + nn = l->right; + l = l->left; + } + + if(l->op != ODCLFIELD) + fatal("cleanformal: %O", n->op); + + if(l->type == T) { + if(t == N) + t = n; + goto loop; + } + + if(t == N) + goto loop; + + dt = l->type; // type to be distributed + +distrib: + while(t != n) { + if(t->op != OLIST) { + if(t->type == T) + t->type = dt; + break; + } + if(t->left->type == T) + t->left->type = dt; + t = t->right; + } + + t = N; + goto loop; +} + +/* + * iterator to walk a structure declaration + */ +Type* +structfirst(Iter *s, Type **nn) +{ + Type *n, *t; + + n = *nn; + if(n == T) + goto bad; + + switch(n->etype) { + default: + goto bad; + + case TSTRUCT: + case TINTER: + case TFUNC: + break; + } + + t = n->type; + if(t == T) + goto rnil; + + if(t->etype != TFIELD) + fatal("structfirst: not field %T", t); + + s->t = t; + return t; + +bad: + fatal("structfirst: not struct %T", n); + +rnil: + return T; +} + +Type* +structnext(Iter *s) +{ + Type *n, *t; + + n = s->t; + t = n->down; + if(t == T) + goto rnil; + + if(t->etype != TFIELD) + goto bad; + + s->t = t; + return t; + +bad: + fatal("structnext: not struct %T", n); + +rnil: + return T; +} + +/* + * iterator to this and inargs in a function + */ +Type* +funcfirst(Iter *s, Type *t) +{ + Type *fp; + + if(t == T) + goto bad; + + if(t->etype != TFUNC) + goto bad; + + s->tfunc = t; + s->done = 0; + fp = structfirst(s, getthis(t)); + if(fp == T) { + s->done = 1; + fp = structfirst(s, getinarg(t)); + } + return fp; + +bad: + fatal("funcfirst: not func %T", t); + return T; +} + +Type* +funcnext(Iter *s) +{ + Type *fp; + + fp = structnext(s); + if(fp == T && !s->done) { + s->done = 1; + fp = structfirst(s, getinarg(s->tfunc)); + } + return fp; +} + +/* + * iterator to walk a list + */ +Node* +listfirst(Iter *s, Node **nn) +{ + Node *n; + + n = *nn; + if(n == N) { + s->done = 1; + s->an = &s->n; + s->n = N; + return N; + } + + if(n->op == OLIST) { + s->done = 0; + s->n = n; + s->an = &n->left; + return n->left; + } + + s->done = 1; + s->an = nn; + return n; +} + +Node* +listnext(Iter *s) +{ + Node *n, *r; + + if(s->done) { + s->an = &s->n; + s->n = N; + return N; + } + + n = s->n; + r = n->right; + if(r->op == OLIST) { + s->n = r; + s->an = &r->left; + return r->left; + } + + s->done = 1; + s->an = &n->right; + return n->right; +} + +Type** +getthis(Type *t) +{ + if(t->etype != TFUNC) + fatal("getthis: not a func %N", t); + return &t->type; +} + +Type** +getoutarg(Type *t) +{ + if(t->etype != TFUNC) + fatal("getoutarg: not a func %N", t); + return &t->type->down; +} + +Type** +getinarg(Type *t) +{ + if(t->etype != TFUNC) + fatal("getinarg: not a func %N", t); + return &t->type->down->down; +} + +Type* +getthisx(Type *t) +{ + return *getthis(t); +} + +Type* +getoutargx(Type *t) +{ + return *getoutarg(t); +} + +Type* +getinargx(Type *t) +{ + return *getinarg(t); +} diff --git a/src/cmd/gc/sys.go b/src/cmd/gc/sys.go new file mode 100644 index 0000000000..19b5c2e86a --- /dev/null +++ b/src/cmd/gc/sys.go @@ -0,0 +1,44 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + + +package foop // rename to avoid redeclaration + +func mal(uint32) *byte; +func breakpoint(); +func panicl(int32); + +func printbool(bool); +func printfloat(double); +func printint(int64); +func printstring(string); +func printpointer(*byte); + +func catstring(string, string) string; +func cmpstring(string, string) int32; +func slicestring(string, int32, int32) string; +func indexstring(string, int32) byte; +func intstring(int64) string; +func byteastring(*byte, int32) string; +func mkiface(*byte, *byte, *struct{}) interface{}; + +export + mal + breakpoint + panicl + + printbool + printfloat + printint + printstring + printpointer + + catstring + cmpstring + slicestring + indexstring + intstring + byteastring + mkiface + ; diff --git a/src/cmd/gc/sysimport.c b/src/cmd/gc/sysimport.c new file mode 100644 index 0000000000..f6ff105b29 --- /dev/null +++ b/src/cmd/gc/sysimport.c @@ -0,0 +1,2 @@ +; + diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c new file mode 100644 index 0000000000..995c641a5c --- /dev/null +++ b/src/cmd/gc/walk.c @@ -0,0 +1,1278 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go.h" + +static Type* sw1(Node*, Type*); +static Type* sw2(Node*, Type*); +static Type* sw3(Node*, Type*); +static Node* curfn; + +void +walk(Node *fn) +{ + curfn = fn; + walktype(fn->nbody, 1); +} + +void +walktype(Node *n, int top) +{ + Node *r, *l; + Type *t; + Sym *s; + long lno; + int et; + + /* + * walk the whole tree of the body of a function. + * the types expressions are calculated. + * compile-time constants are evaluated. + */ + + lno = dynlineno; + +loop: + if(n == N) + goto ret; + if(n->op != ONAME) + dynlineno = n->lineno; // for diagnostics + + t = T; + et = Txxx; + + switch(n->op) { + default: + fatal("walktype: switch 1 unknown op %N", n); + goto ret; + + case OPRINT: + walktype(n->left, 0); + *n = *prcompat(n->left); + goto ret; + + case OPANIC: + walktype(n->left, 0); + *n = *nod(OLIST, prcompat(n->left), nodpanic(n->lineno)); + goto ret; + + case OLITERAL: + n->addable = 1; + ullmancalc(n); + goto ret; + + case ONAME: + n->addable = 1; + ullmancalc(n); + if(n->type == T) { + s = n->sym; + if(s->undef == 0) { + yyerror("walktype: %N undeclared", n); + s->undef = 1; + } + } + goto ret; + + case OLIST: + walktype(n->left, top); + n = n->right; + goto loop; + + case OFOR: + if(!top) + goto nottop; + walktype(n->ninit, 1); + walktype(n->ntest, 1); + walktype(n->nincr, 1); + n = n->nbody; + goto loop; + + case OSWITCH: + if(!top) + goto nottop; + + if(n->ntest == N) + n->ntest = booltrue; + walktype(n->ninit, 1); + walktype(n->ntest, 1); + walktype(n->nbody, 1); + + // find common type + if(n->ntest->type == T) + n->ntest->type = walkswitch(n->ntest, n->nbody, sw1); + + // if that fails pick a type + if(n->ntest->type == T) + n->ntest->type = walkswitch(n->ntest, n->nbody, sw2); + + // set the type on all literals + if(n->ntest->type != T) + walkswitch(n->ntest, n->nbody, sw3); + + walktype(n->ntest, 1); + + n = n->nincr; + goto loop; + + case OEMPTY: + if(!top) + goto nottop; + goto ret; + + case OIF: + if(!top) + goto nottop; + walktype(n->ninit, 1); + walktype(n->ntest, 1); + walktype(n->nelse, 1); + n = n->nbody; + goto loop; + + case OCALLMETH: + case OCALLINTER: + case OCALL: + n->ullman = UINF; + if(n->type != T) + goto ret; + + walktype(n->left, 0); + if(n->left == N) + goto ret; + + t = n->left->type; + if(t == T) + goto ret; + + dowidth(t); + if(n->left->op == ODOTMETH) + n->op = OCALLMETH; + if(n->left->op == ODOTINTER) + n->op = OCALLINTER; + + if(isptr[t->etype]) + t = t->type; + + if(t->etype != TFUNC) { + yyerror("call of a non-function %T", t); + goto ret; + } + + n->type = *getoutarg(t); + if(t->outtuple == 1) + n->type = n->type->type->type; + else + if(!top) + yyerror("function call must be single valued (%d)", t->outtuple); + + walktype(n->right, 0); + + switch(n->op) { + default: + fatal("walk: op: %O", n->op); + + case OCALLINTER: + l = ascompatte(n->op, getinarg(t), &n->right, 0); + n->right = reorder(l); + break; + + case OCALL: + l = ascompatte(n->op, getinarg(t), &n->right, 0); + n->right = reorder(l); + break; + + case OCALLMETH: + // add this-pointer to the arg list + l = ascompatte(n->op, getinarg(t), &n->right, 0); + r = ascompatte(n->op, getthis(t), &n->left->left, 0); + if(l != N) + r = nod(OLIST, r, l); + n->right = reorder(r); + break; + } + goto ret; + + case OAS: + if(!top) + goto nottop; + + r = n->right; + if(r == N) + goto ret; + l = n->left; + if(l == N) + goto ret; + + if(r->op == OCALL && l->op == OLIST) { + // botch callmulti - need to do more + walktype(l, 0); + walktype(r, 0); + l = ascompatet(n->op, &n->left, &r->type, 0); + if(l != N && l->op == OAS) + *n = *reorder(l); + goto ret; + } + + walktype(l, 0); + walktype(r, 0); + l = ascompatee(n->op, &n->left, &n->right); + if(l != N) + *n = *reorder(l); + goto ret; + + case OBREAK: + case OCONTINUE: + case OGOTO: + case OLABEL: + goto ret; + + case OXCASE: + yyerror("case statement out of place"); + n->op = OCASE; + + case OCASE: + n = n->left; + goto loop; + + case OXFALL: + yyerror("fallthrough statement out of place"); + n->op = OFALL; + + case OFALL: + case OINDREG: + goto ret; + + case OS2I: + case OI2S: + case OI2I: + n->addable = 0; + walktype(n->left, 0); + goto ret; + + case OCONV: + walktype(n->left, 0); + if(n->left == N) + goto ret; + + convlit(n->left, n->type); + + // nil conversion + if(eqtype(n->type, n->left->type, 0)) { + if(n->left->op != ONAME) + *n = *n->left; + goto ret; + } + + // simple fix-float + if(isint[n->left->type->etype] || isfloat[n->left->type->etype]) + if(isint[n->type->etype] || isfloat[n->type->etype]) { + evconst(n); + goto ret; + } + + // to string + if(isptrto(n->type, TSTRING)) { + if(isint[n->left->type->etype]) { + *n = *stringop(n); + goto ret; + } + if(isbytearray(n->left->type) != 0) { + n->op = OARRAY; + *n = *stringop(n); + goto ret; + } + } + + badtype(n->op, n->left->type, n->type); + goto ret; + + case ORETURN: + walktype(n->left, 0); + l = ascompatte(n->op, getoutarg(curfn->type), &n->left, 1); + if(l != N) + n->left = reorder(l); + goto ret; + + case ONOT: + walktype(n->left, 0); + if(n->left == N || n->left->type == T) + goto ret; + et = n->left->type->etype; + break; + + case OASOP: + if(!top) + goto nottop; + + case OLSH: + case ORSH: + case OMOD: + case OAND: + case OOR: + case OXOR: + case OANDAND: + case OOROR: + case OEQ: + case ONE: + case OLT: + case OLE: + case OGE: + case OGT: + case OADD: + case OSUB: + case OMUL: + case ODIV: + walktype(n->left, 0); + walktype(n->right, 0); + if(n->left == N || n->right == N) + goto ret; + convlit(n->left, n->right->type); + convlit(n->right, n->left->type); + evconst(n); + if(n->op == OLITERAL) + goto ret; + if(n->left->type == T || n->right->type == T) + goto ret; + if(!ascompat(n->left->type, n->right->type)) + goto badt; + + switch(n->op) { + case OEQ: + case ONE: + case OLT: + case OLE: + case OGE: + case OGT: + case OADD: + case OASOP: + if(isptrto(n->left->type, TSTRING)) { + *n = *stringop(n); + goto ret; + } + } + break; + + case OMINUS: + case OPLUS: + case OCOM: + walktype(n->left, 0); + if(n->left == N) + goto ret; + evconst(n); + ullmancalc(n); + if(n->op == OLITERAL) + goto ret; + break; + + case OLEN: + walktype(n->left, 0); + evconst(n); + ullmancalc(n); + t = n->left->type; + if(t != T && isptr[t->etype]) + t = t->type; + if(t == T) + goto ret; + switch(t->etype) { + default: + goto badt; + case TSTRING: + break; + } + n->type = types[TINT32]; + goto ret; + + case OINDEX: + case OINDEXPTR: + walktype(n->left, 0); + walktype(n->right, 0); + ullmancalc(n); + if(n->left == N || n->right == N) + goto ret; + t = n->left->type; + if(t == T) + goto ret; + + // map + if(isptrto(t, TMAP)) { + fatal("index map"); + goto ret; + } + + // right side must be an int + if(n->right->type == T) + convlit(n->right, types[TINT32]); + if(n->left->type == T || n->right->type == T) + goto ret; + if(!isint[n->right->type->etype]) + goto badt; + + // left side is string + if(isptrto(t, TSTRING)) { + *n = *stringop(n); + goto ret; + } + + // left side is array + if(isptr[t->etype]) { + t = t->type; + n->op = OINDEXPTR; + } + if(t->etype != TARRAY && t->etype != TDARRAY) + goto badt; + n->type = t->type; + goto ret; + + case OSLICE: + walktype(n->left, 0); + walktype(n->right, 0); + if(n->left == N || n->right == N) + goto ret; + if(isptrto(n->left->type, TSTRING)) { + *n = *stringop(n); + goto ret; + } + badtype(OSLICE, n->left->type, T); + goto ret; + + case ODOT: + case ODOTPTR: + case ODOTMETH: + case ODOTINTER: + walkdot(n); + goto ret; + + case OADDR: + walktype(n->left, 0); + if(n->left == N) + goto ret; + t = n->left->type; + if(t == T) + goto ret; + n->type = ptrto(t); + goto ret; + + case OIND: + walktype(n->left, 0); + if(n->left == N) + goto ret; + t = n->left->type; + if(t == T) + goto ret; + if(!isptr[t->etype]) + goto badt; + n->type = t->type; + goto ret; + + case ONEW: + *n = *newcompat(n); + goto ret; + } + +/* + * ======== second switch ======== + */ + + switch(n->op) { + default: + fatal("walktype: switch 2 unknown op %N", n); + goto ret; + + case OASOP: + break; + + case ONOT: + case OANDAND: + case OOROR: + et = n->left->type->etype; + if(et != TBOOL) + goto badt; + t = types[TBOOL]; + break; + + case OEQ: + case ONE: + et = n->left->type->etype; + if(!okforeq[et]) + goto badt; + t = types[TBOOL]; + break; + + case OLT: + case OLE: + case OGE: + case OGT: + et = n->left->type->etype; + if(!okforadd[et]) + if(!isptrto(n->left->type, TSTRING)) + goto badt; + t = types[TBOOL]; + break; + + case OADD: + case OSUB: + case OMUL: + case ODIV: + case OPLUS: + et = n->left->type->etype; + if(!okforadd[et]) + goto badt; + break; + + case OMINUS: + et = n->left->type->etype; + if(!okforadd[et]) + goto badt; + if(!isfloat[et]) + break; + + l = nod(OLITERAL, N, N); + l->val.ctype = CTFLT; + l->val.dval = 0; + + l = nod(OSUB, l, n->left); + *n = *l; + walktype(n, 0); + goto ret; + + case OLSH: + case ORSH: + case OAND: + case OOR: + case OXOR: + case OMOD: + case OCOM: + et = n->left->type->etype; + if(!okforand[et]) + goto badt; + break; + } + + if(t == T) + t = n->left->type; + n->type = t; + goto ret; + +nottop: + fatal("walktype: not top %O", n->op); + +badt: + if(n->right == N) { + if(n->left == N) { + badtype(n->op, T, T); + goto ret; + } + badtype(n->op, n->left->type, T); + goto ret; + } + badtype(n->op, n->left->type, n->right->type); + goto ret; + +ret: + ullmancalc(n); + dynlineno = lno; +} + +/* + * return the first type + */ +Type* +sw1(Node *c, Type *place) +{ + if(place == T) + return c->type; + return place; +} + +/* + * return a suitable type + */ +Type* +sw2(Node *c, Type *place) +{ + return types[TINT32]; // botch +} + +/* + * check that selected type + * is compat with all the cases + */ +Type* +sw3(Node *c, Type *place) +{ + if(place == T) + return c->type; + if(c->type == T) + c->type = place; + convlit(c, place); + if(!ascompat(place, c->type)) + badtype(OSWITCH, place, c->type); + return place; +} + +Type* +walkswitch(Node *test, Node *body, Type*(*call)(Node*, Type*)) +{ + Node *n, *c; + Type *place; + + place = call(test, T); + + n = body; + if(n->op == OLIST) + n = n->left; + + for(; n!=N; n=n->right) { + if(n->op != OCASE) + fatal("walkswitch: not case %O\n", n->op); + for(c=n->left; c!=N; c=c->right) { + if(c->op != OLIST) { + place = call(c, place); + break; + } + place = call(c->left, place); + } + } + return place; +} + +int +casebody(Node *n) +{ + Node *oc, *ot, *t; + Iter save; + + + /* + * look to see if statements at top level have + * case labels attached to them. convert the illegal + * ops XFALL and XCASE into legal ops FALL and CASE. + * all unconverted ops will thus be caught as illegal + */ + + oc = N; // last case statement + ot = N; // last statement (look for XFALL) + + t = listfirst(&save, &n); + + if(t->op != OXCASE) + return 0; + +loop: + if(t == N) { + if(oc == N) + return 0; + return 1; + } + if(t->op == OXCASE) { + /* rewrite and link top level cases */ + t->op = OCASE; + if(oc != N) + oc->right = t; + oc = t; + + /* rewrite top fall that preceed case */ + if(ot != N && ot->op == OXFALL) + ot->op = OFALL; + } + + /* if first statement is not case then return 0 */ + if(oc == N) + return 0; + + ot = t; + t = listnext(&save); + goto loop; +} + +/* + * allowable type combinations for + * normal binary operations. + */ +Type* +lookdot(Node *n, Type *t, int d) +{ + Type *f, *r, *c; + Sym *s; + +//dowidth(t); +//print("\nlookdot %T\n", t); +//for(f=t->type; f!=T; f=f->down) { +//print(" %3ld", f->width); +//print(" %S\n", f->sym); +//} + + r = T; + s = n->sym; + if(d > 0) + goto deep; + + for(f=t->type; f!=T; f=f->down) { + if(f->sym == S) + continue; + if(f->sym != s) + continue; + if(r != T) { + yyerror("ambiguous DOT reference %s", s->name); + break; + } + r = f; + } + return r; + +deep: + /* deeper look after shallow failed */ + for(f=t->type; f!=T; f=f->down) { + // only look at unnamed sub-structures + // BOTCH no such thing -- all are assigned temp names + if(f->sym != S) + continue; + c = f->type; + if(c->etype != TSTRUCT) + continue; + c = lookdot(n, c, d-1); + if(c == T) + continue; + if(r != T) { + yyerror("ambiguous unnamed DOT reference %s", s->name); + break; + } + r = c; + } + return r; +} + +void +walkdot(Node *n) +{ + Node *mn; + Type *t, *f; + int i; + + if(n->left == N || n->right == N) + return; + + walktype(n->left, 0); + if(n->right->op != ONAME) { + yyerror("rhs of . must be a name"); + return; + } + + t = n->left->type; + if(t == T) + return; + + if(isptr[t->etype]) { + t = t->type; + if(t == T) + return; + n->op = ODOTPTR; + } + + if(n->right->op != ONAME) + fatal("walkdot: not name %O", n->right->op); + + switch(t->etype) { + default: + badtype(ODOT, t, T); + return; + + case TSTRUCT: + case TINTER: + for(i=0; i<5; i++) { + f = lookdot(n->right, t, i); + if(f != T) + break; + } + + // look up the field as TYPE_name + // for a mothod. botch this should + // be done better. + if(f == T && t->etype == TSTRUCT) { + mn = methodname(n->right, t); + for(i=0; i<5; i++) { + f = lookdot(mn, t, i); + if(f != T) + break; + } + } + + if(f == T) { + yyerror("undefined DOT reference %N", n->right); + break; + } + + n->xoffset = f->width; + n->right = f->nname; // substitute real name + n->type = f->type; + if(n->type->etype == TFUNC) { + n->op = ODOTMETH; + if(t->etype == TINTER) { + n->op = ODOTINTER; + } + } + break; + } +} + + +/* + * check assign expression list to + * a expression list. called in + * expr-list = expr-list + */ +Node* +ascompatee(int op, Node **nl, Node **nr) +{ + Node *l, *r, *nn, *a; + Iter savel, saver; + + l = listfirst(&savel, nl); + r = listfirst(&saver, nr); + nn = N; + + +loop: + if(l == N || r == N) { + if(l != r) + yyerror("error in shape across assignment"); + return nn; + } + + convlit(r, l->type); + if(!ascompat(l->type, r->type)) { + badtype(op, l->type, r->type); + return N; + } + + a = nod(OAS, l, r); + a = convas(a); + if(nn == N) + nn = a; + else + nn = nod(OLIST, nn, a); + + l = listnext(&savel); + r = listnext(&saver); + goto loop; +} + +/* + * check assign type list to + * a expression list. called in + * expr-list = func() + */ +Node* +ascompatet(int op, Node **nl, Type **nr, int fp) +{ + Node *l, *nn, *a; + Type *r; + Iter savel, saver; + + l = listfirst(&savel, nl); + r = structfirst(&saver, nr); + nn = N; + +loop: + if(l == N || r == T) { + if(l != N || r != T) + yyerror("error in shape across assignment"); + return nn; + } + + if(!ascompat(l->type, r->type)) { + badtype(op, l->type, r->type); + return N; + } + + a = nod(OAS, l, nodarg(r, fp)); + a = convas(a); + if(nn == N) + nn = a; + else + nn = nod(OLIST, nn, a); + + l = listnext(&savel); + r = structnext(&saver); + + goto loop; +} + +/* + * check assign expression list to + * a type list. called in + * return expr-list + * func(expr-list) + */ +Node* +ascompatte(int op, Type **nl, Node **nr, int fp) +{ + Type *l; + Node *r, *nn, *a; + Iter savel, saver; + + l = structfirst(&savel, nl); + r = listfirst(&saver, nr); + nn = N; + +loop: + if(l == T || r == N) { + if(l != T || r != N) + yyerror("error in shape across assignment"); + return nn; + } + + convlit(r, l->type); + if(!ascompat(l->type, r->type)) { + badtype(op, l->type, r->type); + return N; + } + + a = nod(OAS, nodarg(l, fp), r); + a = convas(a); + if(nn == N) + nn = a; + else + nn = nod(OLIST, nn, a); + + l = structnext(&savel); + r = listnext(&saver); + + goto loop; +} + +/* + * can we assign var of type t2 to var of type t1 + */ +int +ascompat(Type *t1, Type *t2) +{ + if(eqtype(t1, t2, 0)) + return 1; + +// if(eqtype(t1, nilptr, 0)) +// return 1; +// if(eqtype(t2, nilptr, 0)) +// return 1; + + if(isinter(t1)) + if(isptrto(t2, TSTRUCT) || isinter(t2)) + return 1; + + if(isinter(t2)) + if(isptrto(t1, TSTRUCT)) + return 1; + + return 0; +} + +Node* +prcompat(Node *n) +{ + Node *l, *r; + Type *t; + Iter save; + int w; + char *name; + Sym *s; + + r = N; + l = listfirst(&save, &n); + +loop: + if(l == N) { + walktype(r, 1); + return r; + } + + w = whatis(l); + switch(w) { + default: + badtype(n->op, l->type, T); + l = listnext(&save); + goto loop; + case Wlitint: + case Wtint: + name = "printint"; + break; + case Wlitfloat: + case Wtfloat: + name = "printfloat"; + break; + case Wlitbool: + case Wtbool: + name = "printbool"; + break; + case Wlitstr: + case Wtstr: + name = "printstring"; + break; + } + + s = pkglookup(name, "sys"); + if(s == S || s->oname == N) + fatal("prcompat: cant find sys_%s", name); + + t = *getinarg(s->oname->type); + if(t != nil) + t = t->type; + if(t != nil) + t = t->type; + + if(!eqtype(t, l->type, 0)) { + l = nod(OCONV, l, N); + l->type = t; + } + + if(r == N) + r = nod(OCALL, s->oname, l); + else + r = nod(OLIST, r, nod(OCALL, s->oname, l)); + + l = listnext(&save); + goto loop; +} + +Node* +nodpanic(long lineno) +{ + Sym *s; + char *name; + Node *n; + + name = "panicl"; + s = pkglookup(name, "sys"); + if(s == S || s->oname == N) + fatal("prcompat: cant find sys_%s", name); + + n = nodintconst(lineno); + n = nod(OCALL, s->oname, n); + walktype(n, 1); + return n; +} + +Node* +newcompat(Node *n) +{ + Node *r; + Type *t; + Sym *s; + + if(n->left != N) + yyerror("dont know what new(,e) means"); + t = n->type; + if(t == T || !isptr[t->etype]) + fatal("NEW sb pointer %lT", t); + + dowidth(t->type); + + s = pkglookup("mal", "sys"); + if(s == S || s->oname == N) + fatal("newcompat: cant find sys_mal"); + + r = nodintconst(t->type->width); + r = nod(OCALL, s->oname, r); + walktype(r, 0); + +// r = nod(OCONV, r, N); + r->type = t; + + return r; +} + +Node* +stringop(Node *n) +{ + Node *r, *c; + Sym *s; + long lno; + long l; + + lno = dynlineno; + dynlineno = n->lineno; + + switch(n->op) { + default: + fatal("stringop: unknown op %E", n->op); + + case OEQ: + case ONE: + case OGE: + case OGT: + case OLE: + case OLT: + // sys_cmpstring(s1, s2) :: 0 + s = pkglookup("cmpstring", "sys"); + if(s == S || s->oname == N) + fatal("stringop: cant find sys_cmpstring"); + + r = nod(OLIST, n->left, n->right); + r = nod(OCALL, s->oname, r); + c = nodintconst(0); + r = nod(n->op, r, c); + break; + + case OADD: + // sys_catstring(s1, s2) + s = pkglookup("catstring", "sys"); + if(s == S || s->oname == N) + fatal("stringop: cant find sys_catstring"); + r = nod(OLIST, n->left, n->right); + r = nod(OCALL, s->oname, r); + break; + + case OASOP: + // sys_catstring(s1, s2) + switch(n->etype) { + default: + fatal("stringop: unknown op %E-%E", n->op, n->etype); + + case OADD: + // s1 = sys_catstring(s1, s2) + s = pkglookup("catstring", "sys"); + if(s == S || s->oname == N || n->etype != OADD) + fatal("stringop: cant find sys_catstring"); + r = nod(OLIST, n->left, n->right); + r = nod(OCALL, s->oname, r); + r = nod(OAS, n->left, r); + break; + } + break; + + case OSLICE: + // sys_slicestring(s, lb, hb) + s = pkglookup("slicestring", "sys"); + if(s == S || s->oname == N) + fatal("stringop: cant find sys_slicestring"); + + r = nod(OCONV, n->right->left, N); + r->type = types[TINT32]; + + c = nod(OCONV, n->right->right, N); + c->type = types[TINT32]; + + r = nod(OLIST, r, c); + + r = nod(OLIST, n->left, r); + + r = nod(OCALL, s->oname, r); + break; + + case OINDEX: + // sys_indexstring(s, i) + s = pkglookup("indexstring", "sys"); + if(s == S || s->oname == N) + fatal("stringop: cant find sys_indexstring"); + + r = nod(OCONV, n->right, N); + r->type = types[TINT32]; + + r = nod(OLIST, n->left, r); + r = nod(OCALL, s->oname, r); + break; + + case OCONV: + // sys_intstring(v) + s = pkglookup("intstring", "sys"); + if(s == S || s->oname == N) + fatal("stringop: cant find sys_intstring"); + + r = nod(OCONV, n->left, N); + r->type = types[TINT64]; + + r = nod(OCALL, s->oname, r); + break; + + case OARRAY: + // byteastring(a, l) + s = pkglookup("byteastring", "sys"); + if(s == S || s->oname == N) + fatal("stringop: cant find sys_byteastring"); + + c = nodintconst(0); + r = nod(OINDEX, n->left, c); + r = nod(OADDR, r, N); + + l = isbytearray(n->left->type); + c = nodintconst(l-1); + + r = nod(OLIST, r, c); + r = nod(OCALL, s->oname, r); + break; + } + + walktype(r, 1); + dynlineno = lno; + return r; +} + +void +diagnamed(Type *t) +{ + if(isinter(t)) + if(t->sym == S) + yyerror("interface type must be named"); + if(isptrto(t, TSTRUCT)) + if(t->type == T || t->type->sym == S) + yyerror("structure type must be named"); +} + +Node* +convas(Node *n) +{ + int o; + Node *l, *r; + Type *lt, *rt; + + if(n->op != OAS) + fatal("convas: not as %O", n->op); + + l = n->left; + r = n->right; + if(l == N || r == N) + return n; + + lt = l->type; + rt = r->type; + if(lt == T || rt == T) + return n; + + if(eqtype(lt, rt, 0)) + return n; + + if(isinter(lt)) { + if(isptrto(rt, TSTRUCT)) { + o = OS2I; + goto ret; + } + if(isinter(rt)) { + o = OI2I; + goto ret; + } + } + + if(isptrto(lt, TSTRUCT)) { + if(isinter(rt)) { + o = OI2S; + goto ret; + } + } + + badtype(n->op, lt, rt); + return n; + +ret: + diagnamed(lt); + diagnamed(rt); + + n->right = nod(o, r, N); + n->right->type = l->type; + walktype(n, 1); + return n; +} + +Node* +reorder(Node *n) +{ + return n; +}