cc/ 775 0 0 0 11600177213 71275ustar00syssyscc/acid.c 664 0 0 12316 11402320254 10211ustar00syssys#include "cc.h" static char *kwd[] = { "$adt", "$aggr", "$append", "$builtin", "$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; } } cc/bits.c 664 0 0 1522 7024572551 10225ustar00syssys#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 #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 */ Rune* rstring; /* rune string */ Sym* sym; Type* type; long lineno; char op; char oldop; char xcast; char class; char etype; char complex; char addable; char scale; char 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; char class; char sym; char aused; char 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; char class; char aused; }; #define D ((Decl*)0) struct Type { Sym* sym; Sym* tag; Funct* funct; Type* link; Type* down; long width; long offset; long lineno; schar shift; char nbits; char etype; char 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 /* also in ../{8a,0a}.h */ { Plan9 = 1<<0, Unix = 1<<1, Windows = 1<<2, }; 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, TDOT, NTYPE, TAUTO = NTYPE, TEXTERN, TSTATIC, TTYPEDEF, TTYPESTR, TREGISTER, TCONSTNT, TVOLATILE, TUNSIGNED, TSIGNED, TFILE, TOLD, NALLTYPES, /* * bootstrapping */ // TRUNE = TUINT, TRUNE = TUSHORT + 2*(sizeof(Rune)==4), }; 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[TRUNE]); $$->type->width = $1.l + sizeof(Rune); $$->rstring = (Rune*)$1.s; $$->sym = symstring; $$->etype = TARRAY; $$->class = CSTATIC; } | lstring LLSTRING { char *s; int n; n = $1->type->width - sizeof(Rune); s = alloc(n+$2.l+MAXALIGN); memcpy(s, $1->rstring, n); memcpy(s+n, $2.s, $2.l); *(Rune*)(s+n+$2.l) = 0; $$ = $1; $$->type->width += $2.l; $$->rstring = (Rune*)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 %% ; } 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 ')' scc/com.c 664 0 0 53474 11357775141 10123ustar00syssys#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; n->right = new1(OCAST, r, Z); n->right->type = types[TINT]; 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[TRUNE]) { o = outstring(0, 0); while(o & 3) { // outlstring(L"", sizeof(Rune)); uint str[1] = {0}; outlstring(str, sizeof(Rune)); 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; } 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"); } returncc/com64.c 664 0 0 23567 11253721074 10264ustar00syssys#include "cc.h" /* * this is machine dependent, 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; case OCOND: 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: case OLIST: 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); l->complex = l->left->complex; 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); t->complex = l->complex; 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; } cc/compat 664 0 0 1254 7437503571 10334ustar00syssys int myaccess(char *f) { return access(f, AEXIST); } void* mysbrk(ulong size) { return sbrk(size); } int mycreat(char *n, int p) { return create(n, 1, p); } int mywait(int *s) { int p; Waitmsg *w; if((w = wait()) == nil) return -1; else{ p = w->pid; *s = 0; if(w->msg[0]) *s = 1; free(w); return p; } } int mydup(int f1, int f2) { return dup(f1,f2); } int mypipe(int *fd) { return pipe(fd); } int systemtype(int sys) { return sys & Plan9; } int pathchar(void) { return '/'; } char* mygetwd(char *path, int len) { return getwd(path, len); } int myexec(char *path, char *argv[]) { return exec(path, argv); } int myfork(void) { return fork(); } nt 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", TVLONGcc/compat.c 664 0 0 706 10337753303 10547ustar00syssys#include "cc.h" #include "compat" /* * fake mallocs */ void* malloc(ulong n) { return alloc(n); } void* calloc(ulong m, ulong n) { return alloc(m*n); } void* realloc(void*, ulong) { fprint(2, "realloc called\n"); abort(); return 0; } void free(void*) { } /* needed when profiling */ void* mallocz(ulong size, int clr) { void *v; v = alloc(size); if(clr && v != nil) memset(v, 0, size); return v; } void setmalloctag(void*, ulong) { } cc/dcl.c 664 0 0 65177 11305011255 10070ustar00syssys#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 = round(w, tfield->width); o = w; w += tfield->width; } l->offset = o; } else { if(l->width < 0 || l->width == 0 && 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 round(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); if(t1 != t2 && t1->link == T && t2->link == T){ /* structs with missing or different tag names aren't considered equal */ if(t1->tag == nil || t2->tag == nil || strcmp(t1->tag->name, t2->tag->name) != 0) return 0; } 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; } 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: cc/dpchk.c 664 0 0 17120 11337702547 10420ustar00syssys#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); fmt += runetochar(fmt, &c); if(c == 0 || c >= nelem(flagbits)) break; 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); } ); } 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(ncc/funct.c 664 0 0 14027 7254316256 10432ustar00syssys#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; ++; 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) returcc/lex.c 664 0 0 60136 11506474366 10127ustar00syssys#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 = mycreat(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, TRUNE); 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(Rune)); *(Rune*)(cp + c1) = c; c1 += sizeof(Rune); } yylval.sval.l = c1; do { cp = allocn(cp, c1, sizeof(Rune)); *(Rune*)(cp + c1) = 0; c1 += sizeof(Rune); } while(c1 & MAXALIGN); yylval.sval.s = cp; return LLSTRING; case '\'': /* '.' */ c = escchar('\'', 0, 0); if(c == EOF) c = '\''; c1 = escchar('\'', 0, 0); if(c1 != EOF) { yyerror("missing '"); peekc = c1; } vv = c; yylval.vval = convvtox(vv, TUCHAR); if(yylval.vval != vv) yyerror("overflow in character constant: 0x%lx", c); else if(c & 0x80){ nearln = lineno; warn(Z, "sign-extended character constant"); } yylval.vval = convvtox(vv, TCHAR); return LCONST; case '/': c1 = GETC(); if(c1 == '*') { for(;;) { c = getr(); while(c == '*') { c = getr(); if(c == '/') goto l0; } if(c == EOF) { yyerror("eof in comment"); errorexit(); } } } if(c1 == '/') { for(;;) { c = getr(); if(c == '\n') goto l0; if(c == EOF) { yyerror("eof in comment"); errorexit(); } } } if(c1 == '=') return LDVE; break; case '*': c1 = GETC(); if(c1 == '=') return LMLE; break; case '%': c1 = GETC(); if(c1 == '=') return LMDE; break; case '+': c1 = GETC(); if(c1 == '+') return LPP; if(c1 == '=') return LPE; break; case '-': c1 = GETC(); if(c1 == '-') return LMM; if(c1 == '=') return LME; if(c1 == '>') return LMG; break; case '>': c1 = GETC(); if(c1 == '>') { c = LRSH; c1 = GETC(); if(c1 == '=') return LRSHE; break; } if(c1 == '=') return LGE; break; case '<': c1 = GETC(); if(c1 == '<') { c = LLSH; c1 = GETC(); if(c1 == '=') return LLSHE; break; } if(c1 == '=') return LLE; break; case '=': c1 = GETC(); if(c1 == '=') return LEQ; break; case '!': c1 = GETC(); if(c1 == '=') return LNE; break; case '&': c1 = GETC(); if(c1 == '&') return LANDAND; if(c1 == '=') return LANDE; break; case '|': c1 = GETC(); if(c1 == '|') return LOROR; if(c1 == '=') return LORE; break; case '^': c1 = GETC(); if(c1 == '=') return LXORE; break; default: return c; } peekc = c1; return c; talph: /* * cp is set to symb and some * prefix has been stored */ for(;;) { if(c >= Runeself) { for(c1=0;;) { cp[c1++] = c; if(fullrune(cp, c1)) break; c = GETC(); } cp += c1; c = GETC(); continue; } if(!isalnum(c) && c != '_') break; *cp++ = c; c = GETC(); } *cp = 0; if(debug['L']) print("%L: %s\n", lineno, symb); peekc = c; s = lookup(); if(s->macro) { newio(); cp = ionext->b; macexpand(s, cp); pushio(); ionext->link = iostack; iostack = ionext; fi.p = cp; fi.c = strlen(cp); if(peekc != IGN) { cp[fi.c++] = peekc; cp[fi.c] = 0; peekc = IGN; } goto l0; } yylval.sym = s; if(s->class == CTYPEDEF || s->class == CTYPESTR) return LTYPE; return s->lexical; tnum: c1 = 0; cp = symb; if(c != '0') { c1 |= Numdec; for(;;) { *cp++ = c; c = GETC(); if(isdigit(c)) continue; goto dc; } } *cp++ = c; c = GETC(); if(c == 'x' || c == 'X') for(;;) { *cp++ = c; c = GETC(); if(isdigit(c)) continue; if(c >= 'a' && c <= 'f') continue; if(c >= 'A' && c <= 'F') continue; if(cp == symb+2) yyerror("malformed hex constant"); goto ncu; } if(c < '0' || c > '7') goto dc; for(;;) { if(c >= '0' && c <= '7') { *cp++ = c; c = GETC(); continue; } goto ncu; } dc: if(c == '.') goto casedot; if(c == 'e' || c == 'E') goto casee; ncu: if((c == 'U' || c == 'u') && !(c1 & Numuns)) { c = GETC(); c1 |= Numuns; goto ncu; } if((c == 'L' || c == 'l') && !(c1 & Numvlong)) { c = GETC(); if(c1 & Numlong) c1 |= Numvlong; c1 |= Numlong; goto ncu; } *cp = 0; peekc = c; if(mpatov(symb, &yylval.vval)) yyerror("overflow in constant"); vv = yylval.vval; if(c1 & Numvlong) { if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) { c = LUVLCONST; t = TUVLONG; goto nret; } c = LVLCONST; t = TVLONG; goto nret; } if(c1 & Numlong) { if((c1 & Numuns) || convvtox(vv, TLONG) < 0) { c = LULCONST; t = TULONG; goto nret; } c = LLCONST; t = TLONG; goto nret; } if((c1 & Numuns) || convvtox(vv, TINT) < 0) { c = LUCONST; t = TUINT; goto nret; } c = LCONST; t = TINT; goto nret; nret: yylval.vval = convvtox(vv, t); if(yylval.vval != vv){ nearln = lineno; warn(Z, "truncated constant: %T %s", types[t], symb); } return c; casedot: for(;;) { *cp++ = c; c = GETC(); if(!isdigit(c)) break; } if(c != 'e' && c != 'E') goto caseout; casee: *cp++ = 'e'; c = GETC(); if(c == '+' || c == '-') { *cp++ = c; c = GETC(); } if(!isdigit(c)) yyerror("malformed fp constant exponent"); while(isdigit(c)) { *cp++ = c; c = GETC(); } caseout: if(c == 'L' || c == 'l') { c = GETC(); c1 |= Numlong; } else if(c == 'F' || c == 'f') { c = GETC(); c1 |= Numflt; } *cp = 0; peekc = c; yylval.dval = strtod(symb, nil); if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) { yyerror("overflow in float constant"); yylval.dval = 0; } if(c1 & Numflt) return LFCONST; return LDCONST; } /* * convert a string, s, to vlong in *v * return conversion overflow. * required syntax is [0[x]]d* */ int mpatov(char *s, vlong *v) { vlong n, nn; int c; n = 0; c = *s; if(c == '0') goto oct; while(c = *s++) { if(c >= '0' && c <= '9') nn = n*10 + c-'0'; else goto bad; if(n < 0 && nn >= 0) goto bad; n = nn; } goto out; oct: s++; c = *s; if(c == 'x' || c == 'X') goto hex; while(c = *s++) { if(c >= '0' || c <= '7') nn = n*8 + c-'0'; else goto bad; if(n < 0 && nn >= 0) goto bad; n = nn; } goto out; hex: s++; while(c = *s++) { if(c >= '0' && c <= '9') c += 0-'0'; else if(c >= 'a' && c <= 'f') c += 10-'a'; else if(c >= 'A' && c <= 'F') c += 10-'A'; else goto bad; nn = n*16 + c; if(n < 0 && nn >= 0) goto bad; n = nn; } out: *v = n; return 0; bad: *v = ~0; return 1; } int getc(void) { int c; if(peekc != IGN) { c = peekc; peekc = IGN; } else c = GETC(); if(c == '\n') lineno++; if(c == EOF) { yyerror("End of file"); errorexit(); } return c; } long getr(void) { int c, i; char str[UTFmax+1]; Rune rune; c = getc(); if(c < Runeself) return c; i = 0; str[i++] = c; loop: c = getc(); str[i++] = c; if(!fullrune(str, i)) goto loop; c = chartorune(&rune, str); if(rune == Runeerror && c == 1) { nearln = lineno; diag(Z, "illegal rune in string"); for(c=0; c= Runeself || !isspace(c)) return c; if(c == '\n') { lineno++; return c; } c = GETC(); } } void unget(int c) { peekc = c; if(c == '\n') lineno--; } long escchar(long e, int longflg, int escflg) { long c, l; int i; loop: c = getr(); if(c == '\n') { yyerror("newline in string"); return EOF; } if(c != '\\') { if(c == e) c = EOF; return c; } c = getr(); if(c == 'x') { /* * note this is not ansi, * supposed to only accept 2 hex */ i = 2; if(longflg) i = 6; l = 0; for(; i>0; i--) { c = getc(); if(c >= '0' && c <= '9') { l = l*16 + c-'0'; continue; } if(c >= 'a' && c <= 'f') { l = l*16 + c-'a' + 10; continue; } if(c >= 'A' && c <= 'F') { l = l*16 + c-'A' + 10; continue; } unget(c); break; } if(escflg) l |= ESC; return l; } if(c >= '0' && c <= '7') { /* * note this is not ansi, * supposed to only accept 3 oct */ i = 2; if(longflg) i = 8; 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); } /* * real allocs */ 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; 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; } } '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'cc/lexbody 664 0 0 21715 11304060324 10541ustar00syssys/* * 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') ; } /* * real allocs */ 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') 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); } clude > nelem(include)) { diag(Z, "ninclude too cc/mac.c 664 0 0 44 7024572450 7760ustar00syssys#include "cc.h" #include "macbody" cc/macbody 664 0 0 30134 11546133737 11563ustar00quanstrosys#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; } static void nextsym(int c) { int c1; char *cp; for(cp = symb;;) { if(c >= Runeself) { for(c1=0;;) { if(cp <= symb+NSYMB-4) cp[c1++] = c; if(fullrune(cp, c1)) break; c = getc(); } cp += c1; }else if(cp <= symb+NSYMB-4) *cp++ = c; c = getc(); if(c >= Runeself || isalnum(c) || c == '_') continue; unget(c); break; } *cp = 0; if(cp > symb+NSYMB-4) yyerror("symbol too large: %s", symb); } Sym* getsym(void) { int c; c = getnsc(); if(c < Runeself && !isalpha(c) && c != '_') { unget(c); return S; } nextsym(c); 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 */ while(l & 3) l++; while(nhunk < l) gethunk(); *hunk = 0; strcpy(hunk+1, p); s->macro = hunk; hunk += l; nhunk -= l; } 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], *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(c >= Runeself || isalpha(c) || c == '_') { nextsym(c); c = getc(); 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(0 && 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 = open(symb, 0); if(f >= 0) break; } if(f < 0) strcpy(symb, str); c = strlen(symb) + 1; while(c & 3) c++; while(nhunk < c) gethunk(); hp = hunk; memcpy(hunk, symb, c); nhunk -= c; hunk += 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; while(c & 3) c++; while(nhunk < c) gethunk(); cp = hunk; memcpy(hunk, symb, c); nhunk -= c; hunk += 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; while(c & 3) c++; while(nhunk < c) gethunk(); hp = hunk; memcpy(hunk, symb, c); nhunk -= c; hunk += 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; } void gethunk(void) { char *h; long nh; nh = NHUNK; if(thunk >= 10L*NHUNK) nh = 10L*NHUNK; h = (char*)mysbrk(nh); if(h == (char*)-1) { yyerror("out of memory"); errorexit(); } hunk = h; nhunk = nh; thunk += nh; } n, "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 maccc/mkfile 664 0 0 1124 10524237332 10322ustar00syssysleft) { 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; if(typecmplx[thisfn->link->etype]) { if(nodret == nil) { nodret = new(ONAME, Z, Z); nodret->sym = slookup(".ret"); nodret->class = CPARAM; nodret->type = types[TIND]; nodret->etype = TIND; nodret = new(OIND, nodret, Z); } n1 = nodret->left; if(n1->type == T || n1->type->link != thisfn->link) { n1->type = typ(TIND, thisfn->link); n1->etype = n1->type->etype; nodret = new(OIND, n1, Z); complex(nodret); } } /* * isolate first argument */ if(REGARG >= 0) { if(typecmplx[thisfn->link->etype]) { nod1 = *nodret->left; nodreg(&nod, &nod1, REGARG); gmove(&nod, &nod1); } else if(firstarg && typeword[firstargtype->etype]) { nod1 = znode; nod1.op = ONAME; nod1.sym = firstarg; nod1.type = firstargtype; nod1.class = CPARAM; nod1.xoffset = align(0, firstargtype, Aarg1); nod1.etype = firstargtype->etype; xcom(&nod1); 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' || thechar=='9' || hasdoubled) /* [sic] */ maxargsafe = round(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]) { nod = znode; nod.op = OAS; nod.left = nodret; nod.right = l; nod.type = n->type; nod.complex = l->complex; cgen(&nod, Z); 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) { casf(); 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) { casf(); 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; casf(); 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; } cc/pickle.c 664 0 0 11337 11262412720 10566ustar00syssys#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, "uchar*\npickle_%s(uchar *bp, uchar *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; } } galloc(&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) warnreaccc/pswt.c 664 0 0 4465 11330457646 10314ustar00syssys#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; int dup; 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(Rune *s, long n) { char buf[UTFmax]; int c, i; long r; if(suppress) return nstring; while(nstring & 1) outstring("", 1); r = nstring; while(n > 0) { c = *s++; if(align(0, types[TCHAR], Aarg1)) { for(i = 0; i < sizeof buf; i++) buf[i] = c>>8*(sizeof buf - i - 1); } else { for(i = 0; i < sizeof buf; i++) buf[i] = c>>8*i; } outstring(buf, sizeof(Rune)); n -= sizeof(Rune); } 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); } 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 cc/scon.c 664 0 0 21124 11364347370 10267ustar00syssys#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; } 0; i < sizeof buf; i++) buf[i] = c>>8*i; } outstring(buf, sizeof(Rune)); n -= sizeof(Rune); } 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) { cc/sub.c 664 0 0 102734 10413060761 10133ustar00syssys#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 log2(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 log2(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 */ char comrel[12] = { ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS, }; char invrel[12] = { OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO, }; char logrel[12] = { OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI, }; char typei[NTYPE]; int typeiinit[] = { TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1, }; char typeu[NTYPE]; int typeuinit[] = { TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1, }; char typesuv[NTYPE]; int typesuvinit[] = { TVLONG, TUVLONG, TSTRUCT, TUNION, -1, }; char typeilp[NTYPE]; int typeilpinit[] = { TINT, TUINT, TLONG, TULONG, TIND, -1 }; char typechl[NTYPE]; char typechlv[NTYPE]; char typechlvp[NTYPE]; int typechlinit[] = { TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1, }; char typechlp[NTYPE]; int typechlpinit[] = { TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1, }; char typechlpfd[NTYPE]; int typechlpfdinit[] = { TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1, }; char typec[NTYPE]; int typecinit[] = { TCHAR, TUCHAR, -1 }; char typeh[NTYPE]; int typehinit[] = { TSHORT, TUSHORT, -1, }; char typeil[NTYPE]; int typeilinit[] = { TINT, TUINT, TLONG, TULONG, -1, }; char typev[NTYPE]; int typevinit[] = { TVLONG, TUVLONG, -1, }; char typefd[NTYPE]; int typefdinit[] = { TFLOAT, TDOUBLE, -1, }; char typeaf[NTYPE]; int typeafinit[] = { TFUNC, TARRAY, -1, }; char 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, }; char 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]; } t[] = { TCHAR, TUCHAR, TSHORT, TUSH8c/ 775 0 0 0 11546133762 70665ustar00syssys8c/8.out.h 664 0 0 10030 10411232277 10215ustar00syssys#define NSYM 50 #define NSNAME 8 #define NOPROF (1<<0) #define DUPOK (1<<1) enum as { AXXX, AAAA, AAAD, AAAM, AAAS, AADCB, AADCL, AADCW, AADDB, AADDL, AADDW, AADJSP, AANDB, AANDL, AANDW, AARPL, ABOUNDL, ABOUNDW, ABSFL, ABSFW, ABSRL, ABSRW, ABTL, ABTW, ABTCL, ABTCW, ABTRL, ABTRW, ABTSL, ABTSW, ABYTE, ACALL, ACLC, ACLD, ACLI, ACLTS, ACMC, ACMPB, ACMPL, ACMPW, ACMPSB, ACMPSL, ACMPSW, ADAA, ADAS, ADATA, ADECB, ADECL, ADECW, ADIVB, ADIVL, ADIVW, AENTER, AGLOBL, AGOK, AHISTORY, AHLT, AIDIVB, AIDIVL, AIDIVW, AIMULB, AIMULL, AIMULW, AINB, AINL, AINW, AINCB, AINCL, AINCW, AINSB, AINSL, AINSW, AINT, AINTO, AIRETL, AIRETW, AJCC, AJCS, AJCXZ, AJEQ, AJGE, AJGT, AJHI, AJLE, AJLS, AJLT, AJMI, AJMP, AJNE, AJOC, AJOS, AJPC, AJPL, AJPS, ALAHF, ALARL, ALARW, ALEAL, ALEAW, ALEAVEL, ALEAVEW, ALOCK, ALODSB, ALODSL, ALODSW, ALONG, ALOOP, ALOOPEQ, ALOOPNE, ALSLL, ALSLW, AMOVB, AMOVL, AMOVW, AMOVBLSX, AMOVBLZX, AMOVBWSX, AMOVBWZX, AMOVWLSX, AMOVWLZX, AMOVSB, AMOVSL, AMOVSW, AMULB, AMULL, AMULW, ANAME, ANEGB, ANEGL, ANEGW, ANOP, ANOTB, ANOTL, ANOTW, AORB, AORL, AORW, AOUTB, AOUTL, AOUTW, AOUTSB, AOUTSL, AOUTSW, APOPAL, APOPAW, APOPFL, APOPFW, APOPL, APOPW, APUSHAL, APUSHAW, APUSHFL, APUSHFW, APUSHL, APUSHW, ARCLB, ARCLL, ARCLW, ARCRB, ARCRL, ARCRW, AREP, AREPN, ARET, AROLB, AROLL, AROLW, ARORB, ARORL, ARORW, ASAHF, ASALB, ASALL, ASALW, ASARB, ASARL, ASARW, ASBBB, ASBBL, ASBBW, ASCASB, ASCASL, ASCASW, ASETCC, ASETCS, ASETEQ, ASETGE, ASETGT, ASETHI, ASETLE, ASETLS, ASETLT, ASETMI, ASETNE, ASETOC, ASETOS, ASETPC, ASETPL, ASETPS, ACDQ, ACWD, ASHLB, ASHLL, ASHLW, ASHRB, ASHRL, ASHRW, ASTC, ASTD, ASTI, ASTOSB, ASTOSL, ASTOSW, ASUBB, ASUBL, ASUBW, ASYSCALL, ATESTB, ATESTL, ATESTW, ATEXT, AVERR, AVERW, AWAIT, AWORD, AXCHGB, AXCHGL, AXCHGW, AXLAT, AXORB, AXORL, AXORW, AFMOVB, AFMOVBP, AFMOVD, AFMOVDP, AFMOVF, AFMOVFP, AFMOVL, AFMOVLP, AFMOVV, AFMOVVP, AFMOVW, AFMOVWP, AFMOVX, AFMOVXP, AFCOMB, AFCOMBP, AFCOMD, AFCOMDP, AFCOMDPP, AFCOMF, AFCOMFP, AFCOML, AFCOMLP, AFCOMW, AFCOMWP, AFUCOM, AFUCOMP, AFUCOMPP, AFADDDP, AFADDW, AFADDL, AFADDF, AFADDD, AFMULDP, AFMULW, AFMULL, AFMULF, AFMULD, AFSUBDP, AFSUBW, AFSUBL, AFSUBF, AFSUBD, AFSUBRDP, AFSUBRW, AFSUBRL, AFSUBRF, AFSUBRD, AFDIVDP, AFDIVW, AFDIVL, AFDIVF, AFDIVD, AFDIVRDP, AFDIVRW, AFDIVRL, AFDIVRF, AFDIVRD, AFXCHD, AFFREE, AFLDCW, AFLDENV, AFRSTOR, AFSAVE, AFSTCW, AFSTENV, AFSTSW, AF2XM1, AFABS, AFCHS, AFCLEX, AFCOS, AFDECSTP, AFINCSTP, AFINIT, AFLD1, AFLDL2E, AFLDL2T, AFLDLG2, AFLDLN2, AFLDPI, AFLDZ, AFNOP, AFPATAN, AFPREM, AFPREM1, AFPTAN, AFRNDINT, AFSCALE, AFSIN, AFSINCOS, AFSQRT, AFTST, AFXAM, AFXTRACT, AFYL2X, AFYL2XP1, AEND, ADYNT, AINIT, ASIGNAME, ALAST }; enum { D_AL = 0, D_CL, D_DL, D_BL, D_AH = 4, D_CH, D_DH, D_BH, D_AX = 8, D_CX, D_DX, D_BX, D_SP, D_BP, D_SI, D_DI, D_F0 = 16, D_CS = 24, D_SS, D_DS, D_ES, D_FS, D_GS, D_GDTR, /* global descriptor table register */ D_IDTR, /* interrupt descriptor table register */ D_LDTR, /* local descriptor table register */ D_MSW, /* machine status word */ D_TASK, /* task register */ D_CR = 35, D_DR = 43, D_TR = 51, D_NONE = 59, D_BRANCH = 60, D_EXTERN = 61, D_STATIC = 62, D_AUTO = 63, D_PARAM = 64, D_CONST = 65, D_FCONST = 66, D_SCONST = 67, D_ADDR = 68, D_FILE, D_FILE1, D_INDIR, /* additive */ T_TYPE = 1<<0, T_INDEX = 1<<1, T_OFFSET = 1<<2, T_FCONST = 1<<3, T_SYM = 1<<4, T_SCONST = 1<<5, REGARG = -1, REGRET = D_AX, FREGRET = D_F0, REGSP = D_SP, REGTMP = D_DI, }; /* * this is the ranlib header */ #define SYMDEF "__.SYMDEF" /* * this is the simulated IEEE floating point */ typedef struct ieee Ieee; struct ieee { long l; /* contains ls-man 0xffffffff */ long h; /* contains sign 0x80000000 exp 0x7ff00000 ms-man 0x000fffff */ }; G, 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, }, 8c/bound.c 664 0 0 37605 10413060767 10370ustar00syssys#include "gc.h" #include "bound.h" static BB* bbfree; static BBset* bbsfree; static int bballoc; static int bbsalloc; static BB bbz; static BBset bbsz; static BB* firstbb; static BB* lastbb; static BB* wounded; static BB* bbaux; static BBset* recalc; static BBset* bbhash[BBHASH]; static BB** ordered; static int bcount; static BBset** heap; static int heapn; static int bsize; static char bbbuff[BBBSIZE]; static int bchange; #define bdebug (debug['v']) #define dbg 0 #define bcheck 0 static long Rn(Reg *r) { if(r == R) return -1; return r->rpo; } static BB* bba(void) { BB *b; bballoc++; b = bbfree; if(b == nil) { b = alloc(sizeof(*b)); } else bbfree = b->link; *b = bbz; return b; } static void bfree(BB *b) { bballoc--; b->link = bbfree; bbfree = b; } static BBset* bbsa(void) { BBset *b; bballoc++; b = bbsfree; if(b == nil) { b = alloc(sizeof(*b)); } else bbsfree = b->link; *b = bbsz; return b; } static void bsfree(BBset *b) { bballoc--; b->link = bbsfree; bbsfree = b; } static void dumpheap(void) { int i; for(i = 1; i <= heapn; i++) print(" %d", heap[i]->damage); } static void checkheap(void) { int N, N2, n, c; N = heapn; N2 = N >> 1; for(n = 1; n <= N2; n++) { c = n << 1; if((heap[c]->damage > heap[n]->damage) || ((c < N) && (heap[c + 1]->damage > heap[n]->damage))) { print("bad heap (%d:%d) %d [", n, heap[n]->damage, heapn); dumpheap(); print(" ]\n"); abort(); } } } static void downheap(int n) { int N, N2, d, c; BBset *s, *t, *u; s = heap[n]; d = s->damage; //print("down %d %d", n, d); N = heapn; N2 = N >> 1; while(n <= N2) { c = n << 1; t = heap[c]; if(c < N) { u = heap[c + 1]; if(t->damage < u->damage) { t = u; c++; } } //print(" [%d %d]", c, t->damage); if(t->damage < d) break; heap[n] = t; t->index = n; n = c; } heap[n] = s; s->index = n; //print("\n"); //checkheap(); } static void upheap(int n) { int f, d; BBset *s, *t; s = heap[n]; d = s->damage; //print("up %d %d", n, d); while(n > 1) { f = n >> 1; t = heap[f]; //print(" [%d %d]", f, t->damage); if(t->damage >= d) break; heap[n] = t; t->index = n; n = f; } heap[n] = s; s->index = n; //print("\n"); //checkheap(); } static void heapremove(BBset *s) { int x; BBset *t; x = s->index; s->index = 0; if(x == 0) return; if(x == heapn) { heapn--; return; } t = heap[heapn--]; heap[x] = t; t->index = x; if(s->damage < t->damage) upheap(x); else downheap(x); } static void heapadd(BBset *s) { int n; n = heapn + 1; heap[n] = s; s->index = n; heapn = n; upheap(n); } static void bbsrecalc(BBset *s) { if(s->recalc) return; s->recalc = 1; s->link = recalc; recalc = s; heapremove(s); } static void bbadd(BB *b, Hval h) { int k; BBset *s; k = h[0] & BBMASK; for(s = bbhash[k]; s != nil; s = s->next) { if(BBEQ(s->hash, h)) { b->set = s; b->link = s->ents; s->ents = b; bbsrecalc(s); return; } } s = bbsa(); s->next = bbhash[k]; bbhash[k] = s; b->set = s; b->link = nil; s->ents = b; BBCP(s->hash, h); bbsrecalc(s); } static int hashbb(BB *b, Hval h) { Reg *r; Prog *p; char *s; int c, f, i, n; r = b->first; s = bbbuff; i = 0; n = BBBSIZE; for(;;) { p = r->prog; if(p->as != ANOP) { if(p->to.type == D_BRANCH) p->to.offset = r->s2->rpo; c = snprint(s, n, "%P", p); s += c; n -= c; i++; } if(r == b->last) break; r = r->link; } if(n == 0) return Bbig; b->len = i; BBMKHASH(bbbuff, BBBSIZE - n, h); f = b->flags; if(i == 1 && r->prog->as == AJMP && b->first->p1 == R) f = Bjo; else if(b->first->p1 != R) f |= Bpre; if(bdebug) print("A %x %s %ux %ux\n", f, bbbuff, h[0], h[1]); return f; } static void enterbb(BB *b) { Hval h; b->flags = hashbb(b, h); if(b->flags != Bbig) bbadd(b, h); } static void preproc(BB *b, int x) { BB *n; Reg *r; ordered[x] = b; if(b->last->rpo - b->first->rpo > BBBIG) { b->flags = Bbig; return; } if(b->first->p2 == nil) { b->flags = Bdel; return; } switch(b->last->prog->as) { case ARET: case AJMP: case AIRETL: break; default: b->flags = Bdel; n = bba(); n->first = b->first; for(r = b->last->link; r != R; r = r->link) { switch(r->prog->as) { case ARET: case AJMP: case AIRETL: n->last = r; n->flags = Bpin; enterbb(n); if(n->flags & Bpin) { n->aux = bbaux; bbaux = n; } else bfree(n); return; } } bfree(n); return; } enterbb(b); } static int p2len(Reg *r) { int c; c = 0; for(r = r->p2; r != nil; r = r->p2link) c++; return c; } static void calcdamage(BBset *s) { BB *f; int d, t; s->recalc = 0; f = s->ents; if(f == nil) return; if(f->flags & Bjo) { if(bdebug) print("add %ld jo\n", f->first->rpo); s->damage = COSTJO; heapadd(s); return; } if(f->link == nil) { if(bdebug) print("solo %x %x\n", s->hash[0], s->hash[1]); return; } d = 0; t = 0; while(f != nil) { if((f->flags & (Bpre|Bpin)) == 0 && f->last->link != R) { t = 1; d += (f->last->rpo - f->first->rpo) >> 1; } d += p2len(f->first); f = f->link; } if(t == 0) { if(bdebug) print("all pre %ld\n", s->ents->first->rpo); return; } if(bdebug) print("add %ld %d\n", s->ents->first->rpo, d); if(d > COSTHI) d = COSTHI; s->damage = d; heapadd(s); } static Reg* findjump(BB *b) { Reg *r, *l; r = b->first; l = b->last; for(;;) { if(r->prog->as == AJMP) break; if(r == l) { diag(Z, "findjump botch"); break; } r = r->link; } return r; } static BB* findset(int r) { BB *s, **p; int n, n2; if(r < ordered[0]->first->rpo) return nil; n = bcount; p = ordered; while(n > 0) { n2 = n >> 1; s = p[n2]; if(r < s->first->rpo) { n = n2; continue; } if(r > s->last->rpo) { n2++; p += n2; n -= n2; continue; } return s; } diag(Z, "findset botch"); return nil; } static void wound(Reg *r) { BB *b, *p, **n; BBset *s; b = findset(r->rpo); if(b == nil) return; s = b->set; if(s == nil) return; for(n = &s->ents; (p = *n) != nil; n = &(*n)->link) { if(p == b) { *n = b->link; b->link = wounded; wounded = b; bbsrecalc(s); return; } } } static void printbl(Reg *l) { if(l == nil) { print("Z"); return; } print("%ld", l->rpo); while((l = l->p2link) != nil) print(" %ld", l->rpo); } static void appset(Reg *e, Reg *s) { for(;;) { if(s->p2link == R) { s->p2link = e; return; } s = s->p2link; } } static Reg* delset(Reg *e, Reg *s) { Reg *c, *l; c = s; l = nil; for(;;) { if(e == c) { if(l == nil) return s->p2link; l->p2link = c->p2link; return s; } l = c; c = c->p2link; if(c == nil) return s; } } static void redest(Reg *s, Reg *d) { while(s != R) { s->s2 = d; s = s->p2link; } } static void changedest(Reg *s, Reg *d, int x) { Reg *l; if(bdebug) { print("change %ld [", s->rpo); printbl(s->p2); print("] -> %ld [", d->rpo); printbl(d->p2); print("]\n"); } if(s->p2 == nil) { // print("deadjmp\n"); return; } l = s->p2; for(;;) { if(bdebug) print("s2 %ld = %ld\n", l->rpo, d->rpo); l->s2 = d; wound(l); if(l->p2link == nil) break; l = l->p2link; } if(x) { l->p2link = delset(s, d->p2); d->p2 = s->p2; } else { l->p2link = d->p2; d->p2 = s->p2; s->p2 = nil; } if(bdebug) { print("result ["); printbl(d->p2); print("]\n"); } bchange = 1; } static void bexcise(BB *b) { Reg *r, *l; l = b->last; r = b->first; if(bdebug) print("excise %ld to %ld\n", r->rpo, l->rpo); for(;;) { r->prog->as = ANOP; r->prog->to.type = D_NONE; r->p2 = R; if(r->s2 != R) { r->s2->p2 = delset(r, r->s2->p2); r->s2 = R; } if(r == l) break; r = r->link; } } static int backtrack(Reg *s, Reg *d) { int i; char l[BINST], r[BINST]; //print("backtrack %ld %ld\n", Rn(s), Rn(d)); i = 0; while(s != nil && d != nil) { if(snprint(l, BINST, "%P", s->prog) == BINST) break; if(snprint(r, BINST, "%P", d->prog) == BINST) break; //print("%s\t%s\n", l, r); if(strcmp(l, r) != 0) break; i++; s = s->p2link; d = d->p2link; } return i; } static void checktails(void) { int c; Reg *r; c = 0; for(r = firstr; r->link != R; r = r->link) { if(r->prog->as == AJMP && r->s2 != nil) c += backtrack(r->p1, r->s2->p1); } if(c > 0) print("tails %s %d\n", firstr->prog->from.sym->name, c); } static void process(BBset *s) { Reg *h; BB *f, *o, *p, *t; if(bdebug) print("process %d %x %x\n", s->damage, s->hash[0], s->hash[1]); f = s->ents; if(f->flags & Bjo) { s->ents = nil; h = findjump(f)->s2; o = nil; while(f != nil) { t = f->link; if((f->flags & Bjo) != 0 && f->first->s2 != f->first) { changedest(f->first, h, 1); bexcise(f); } else { f->link = o; o = f; } f = t; } s->ents = o; } else { o = nil; p = nil; while(f != nil) { t = f->link; if((f->flags & (Bpre|Bpin)) != 0 || (f->last->link == R)) { f->link = p; p = f; } else { f->link = o; o = f; } f = t; } if(o == nil) { diag(Z, "all Bpre"); return; } if(p == nil) { p = o; o = p->link; p->link = nil; s->ents = p; } else s->ents = p; h = p->first; // oblit o list repl with jmp to h while(o != nil) { changedest(o->first, h, 1); bexcise(o); o = o->link; } bbsrecalc(s); } } static void iterate(void) { BBset *s; BB *b, *t; heapn = 0; for(;;) { for(b = wounded; b != nil; b = t) { t = b->link; enterbb(b); } wounded = nil; for(s = recalc; s != nil; s = s->link) calcdamage(s); recalc = nil; if(heapn == 0) return; s = heap[1]; heapremove(s); process(s); } } static void cleanup(void) { int i; BB *l, *n; BBset *b, *t; for(i = 0; i < BBHASH; i++) { b = bbhash[i]; bbhash[i] = nil; while(b != nil) { t = b->next; bsfree(b); b = t; } } for(i = 0; i < bcount; i++) bfree(ordered[i]); for(l = bbaux; l != nil; l = n) { n = l->aux; bfree(l); } bbaux = nil; } static void prreg(Reg *r) { Prog *p; p = r->prog; if(p->to.type == D_BRANCH) p->to.offset = r->s2->rpo; print("%ld:%P\tr %lX ", r->rpo, r->prog, r->regu); print("p1 %ld p2 %ld p2l %ld s1 %ld s2 %ld link %ld", Rn(r->p1), Rn(r->p2), Rn(r->p2link), Rn(r->s1), Rn(r->s2), Rn(r->link)); if(!r->active) print(" d"); // print(" %p %p\n", r->prog, r->prog->link); print("\n"); } static void prfunc(char*); static void checkr(int d) { Prog *p; Reg *r, *t; for(r = firstr; r->link != R; r = r->link) { for(p = r->prog->link; p != P && p != r->link->prog; p = p->link) ; if(p == P) { print("%ld: bad prog link\n", r->rpo); if(d) prfunc(nil); abort(); } if(r->s1 != R && (r->s1 != r->link || r->link->p1 != r)) { print("%ld: bad s1 p1\n", r->rpo); if(d) prfunc(nil); abort(); } if(r->s2 != R && r->s2->p2 == nil) { print("%ld: no p2 for s2\n", r->rpo); if(d) prfunc(nil); abort(); } if(r->p2 != R) { t = r->p2->s2; while(t != r) { t = t->p2link; if(t == R) { print("%ld: bad s2 for p2\n", r->rpo); if(d) prfunc(nil); abort(); } } } } } static void prfunc(char *s) { Reg *r; if(s != nil) print("%s structure %s\n", s, firstr->prog->from.sym->name); for(r = firstr; r != R; r = r->link) prreg(r); if(s != nil) { print("end\n"); checkr(0); } } /* find p in r's list and replace with l */ static void adjprog(Reg *r, Prog *p, Prog *l) { Prog *t, **n; for(n = &r->prog->link; (t = *n) != nil; n = &t->link) { if(t == p) { *n = l; return; } } print("adjprog botch\n"); abort(); } static void jumptojump(void) { Reg *r; for(r = firstr; r != R; r = r->link) { if(r->prog->as == AJMP && r->p2 != R && r->s2 != r) { if(bdebug) print("jump as dest %ld -> %ld\n", r->rpo, r->s2->rpo); changedest(r, r->s2, 0); bchange++; } } } /* drag a tail to replace a jump. seems to be a bad idea. */ static void rearrange(void) { int i; Reg *j, *t; BB *b, *p, *s; for(i = 0; i < bcount; i++) { b = ordered[i]; if(b->flags & Bdel) continue; j = b->last; if(j->prog->as == AJMP && j->s2->p1 == R) { t = j->s2; if(t == b->first) continue; s = findset(t->rpo); if(s == nil) { diag(Z, "no self"); continue; } if(s == ordered[0]) continue; if(s->flags & Bdel) continue; if(s->last->link == R) continue; if(bdebug) print("drag %ld to %ld\n", t->rpo, j->rpo); p = findset(t->rpo - 1); if(p == nil) { diag(Z, "no predec"); continue; } if(p->last->link != t) { diag(Z, "bad predec %ld %ld", p->last->rpo, t->rpo); continue; } /* poison everything in sight */ b->flags |= Bdel; s->flags |= Bdel; findset(j->link->rpo)->flags |= Bdel; findset(s->last->link->rpo)->flags |= Bdel; /* remove */ adjprog(p->last, t->prog, s->last->link->prog); p->last->link = s->last->link; /* fix tail */ adjprog(s->last, s->last->link->prog, j->link->prog); s->last->link = j->link; /* fix head */ adjprog(j, j->link->prog, t->prog); j->link = t; /* nop the jump */ j->prog->as = ANOP; j->prog->to.type = D_NONE; j->s2 = nil; j->link->p2 = delset(j, j->link->p2); j->s1 = t; t->p1 = j; if(bcheck) checkr(1); bchange++; } } } void jumptodot(void) { Reg *r; for(r = firstr; r != R; r = r->link) { if(r->prog->as == AJMP && r->s2 == r->link) { if(debug['v']) print("jump to next %ld\n", r->rpo); r->prog->as = ANOP; r->prog->to.type = D_NONE; r->s2 = nil; r->link->p2 = delset(r, r->link->p2); findset(r->rpo)->flags |= Bdel; findset(r->link->rpo)->flags |= Bdel; bchange++; } } } void comtarg(void) { int n; BB *b, *c; Reg *r, *l, *p, *t; loop: bchange = 0; /* excise NOPS because they just get in the way */ /* some have p2 because they are excised labelled moves */ if(debug['v']) { n = 0; for(r = firstr; r != R; r = r->link) r->rpo = n++; prfunc("prenop"); } r = firstr; l = r->link; while(l != R) { if(l->prog->as == ANOP) { t = l->p1; p = l->p2; if(dbg) print("nop %ld [", l->rpo); if(dbg) printbl(p); for(;;) { adjprog(r, l->prog, l->prog->link); r->link = l->link; l->link = freer; freer = l; l = r->link; if(l->prog->as != ANOP) break; if(dbg) print("] %ld [", l->rpo); if(dbg) printbl(l->p2); if(p == R) p = l->p2; else if(l->p2 != nil) appset(l->p2, p); } if(dbg) print("] %ld [", l->rpo); if(dbg) printbl(l->p2); if(p != R) { redest(p, l); if(l->p2 != R) appset(p, l->p2); else l->p2 = p; } if(dbg) print("] -> ["); if(dbg) printbl(l->p2); if(dbg) print("]\n"); if(r->s1 != R) r->s1 = l; l->p1 = t; } r = l; l = r->link; } n = 0; for(r = firstr; r != R; r = r->link) r->rpo = n++; if(debug['v']) prfunc("input"); firstbb = nil; lastbb = nil; if(debug['v']) print("bbstart\n"); n = 0; r = firstr; do { b = bba(); b->first = r; for(;;) { l = r; r = r->link; switch(l->prog->as) { case ARET: case AJMP: case AIRETL: goto out; } if(r->p2 != R) break; } out: b->last = l; if(lastbb == nil) firstbb = b; else lastbb->link = b; lastbb = b; if(bdebug) print("BB %ld %ld\n", b->first->rpo, b->last->rpo); n++; } while(r != R); if(debug['v']) print("end\n"); if(n > bsize) { bsize = n * 3 / 2; if(bsize < BBINIT) bsize = BBINIT; ordered = alloc(bsize * sizeof(*ordered)); heap = alloc((bsize + 1) * sizeof(*ordered)); } if(debug['v']) print("preprocstart\n"); n = 0; for(b = firstbb; b != nil; b = c) { c = b->link; preproc(b, n++); } if(debug['v']) print("end\n"); bcount = n; jumptojump(); if(debug['v']) print("iteratestart\n"); iterate(); //checktails(); if(debug['v']) print("end\n"); if(debug['v']) print("extrastart\n"); jumptodot(); // rearrange(); if(debug['v']) print("end\n"); cleanup(); if(bballoc || bbsalloc) diag(Z, "bballoc %d %d", bballoc, bbsalloc); if(debug['v']) prfunc("output"); if(1 && bchange) goto loop; } ->rpo); if(b == nil) return; s = b->set; if(s == nil) return; for(n = &s->ents; (p = *n) != nil; n = &(*n)->link) {8c/bound.h 664 0 0 1607 10050735522 10341ustar00syssys/* * Bounding Box stuff (brucee 04/03/30). */ #include #include typedef struct BB BB; typedef struct BBset BBset; typedef uchar Hval[SHA1dlen]; #define BBEQ(a, b) (memcmp((a), (b), SHA1dlen) == 0) #define BBMKHASH(b, n, h) sha1((uchar *)(b), (n), (h), nil) #define BBCP(d, s) memmove(d, s, SHA1dlen) enum { Bpre = 1 << 0, /* has a flow in */ Bjo = 1 << 1, /* a jump only */ Bbig = 1 << 2, /* too big */ Bdel = 1 << 3, /* deleted or not of interest */ Bpin = 1 << 4, /* pinned by embedded labels */ BBHASH = 64, /* power of 2 <= 256 */ BBMASK = BBHASH - 1, BBINIT = 128, BBBIG = 64, BBBSIZE = 8192, BINST = 128, COSTHI = 0x7F, COSTJO = 0xFF, }; struct BB { Reg* first; Reg* last; BBset* set; BB* link; BB* aux; short flags; short len; }; struct BBset { Hval hash; BB* ents; BBset* next; BBset* link; short index; uchar damage; uchar recalc; }; if(bdebug) print("excise %ld to %ld\n", r->rpo, l->rpo); for(;;) { r->prog->as = ANOP; r->prog->to.type = D_NONE;8c/cgen.c 664 0 0 77031 11443711141 10163ustar00syssys#include "gc.h" /* ,x/^(print|prtree)\(/i/\/\/ */ void cgen(Node *n, Node *nn) { Node *l, *r, *t; Prog *p1; Node nod, nod1, nod2, nod3, nod4; int o, hardleft; long v, curs; vlong c; if(debug['g']) { prtree(nn, "cgen lhs"); prtree(n, "cgen"); } if(n == Z || n->type == T) return; if(typesuv[n->type->etype]) { sugen(n, nn, n->type->width); return; } l = n->left; r = n->right; o = n->op; if(n->addable >= INDEXED) { if(nn == Z) { switch(o) { default: nullwarn(Z, Z); break; case OINDEX: nullwarn(l, r); break; } return; } gmove(n, nn); return; } curs = cursafe; if(l->complex >= FNX) if(r != Z && r->complex >= FNX) switch(o) { default: if(cond(o) && typesuv[l->type->etype]) break; regret(&nod, r); cgen(r, &nod); regsalloc(&nod1, r); gmove(&nod, &nod1); regfree(&nod); nod = *n; nod.right = &nod1; cgen(&nod, nn); return; case OFUNC: case OCOMMA: case OANDAND: case OOROR: case OCOND: case ODOT: break; } hardleft = l->addable < INDEXED || l->complex >= FNX; switch(o) { default: diag(n, "unknown op in cgen: %O", o); break; case ONEG: case OCOM: if(nn == Z) { nullwarn(l, Z); break; } regalloc(&nod, l, nn); cgen(l, &nod); gopcode(o, n->type, Z, &nod); gmove(&nod, nn); regfree(&nod); break; case OAS: if(typefd[n->type->etype]) { cgen(r, &fregnode0); if(nn != Z) gins(AFMOVD, &fregnode0, &fregnode0); if(l->addable < INDEXED) { reglcgen(&nod, l, Z); gmove(&fregnode0, &nod); regfree(&nod); } else gmove(&fregnode0, l); if(nn != Z) gmove(&fregnode0, nn); return; } if(l->op == OBIT) goto bitas; if(!hardleft) { if(nn != Z || r->addable < INDEXED) { if(r->complex >= FNX && nn == Z) regret(&nod, r); else regalloc(&nod, r, nn); cgen(r, &nod); gmove(&nod, l); if(nn != Z) gmove(&nod, nn); regfree(&nod); } else gmove(r, l); break; } if(l->complex >= r->complex) { if(l->op == OINDEX && r->op == OCONST) { gmove(r, l); break; } reglcgen(&nod1, l, Z); if(r->addable >= INDEXED) { gmove(r, &nod1); if(nn != Z) gmove(r, nn); regfree(&nod1); break; } regalloc(&nod, r, nn); cgen(r, &nod); } else { regalloc(&nod, r, nn); cgen(r, &nod); reglcgen(&nod1, l, Z); } gmove(&nod, &nod1); regfree(&nod); regfree(&nod1); break; bitas: n = l->left; regalloc(&nod, r, nn); if(l->complex >= r->complex) { reglcgen(&nod1, n, Z); cgen(r, &nod); } else { cgen(r, &nod); reglcgen(&nod1, n, Z); } regalloc(&nod2, n, Z); gmove(&nod1, &nod2); bitstore(l, &nod, &nod1, &nod2, nn); break; case OBIT: if(nn == Z) { nullwarn(l, Z); break; } bitload(n, &nod, Z, Z, nn); gmove(&nod, nn); regfree(&nod); break; case OLSHR: case OASHL: case OASHR: if(nn == Z) { nullwarn(l, r); break; } if(r->op == OCONST) { if(r->vconst == 0) { cgen(l, nn); break; } regalloc(&nod, l, nn); cgen(l, &nod); if(o == OASHL && r->vconst == 1) gopcode(OADD, n->type, &nod, &nod); else gopcode(o, n->type, r, &nod); gmove(&nod, nn); regfree(&nod); break; } /* * get nod to be D_CX */ if(nodreg(&nod, nn, D_CX)) { regsalloc(&nod1, n); gmove(&nod, &nod1); cgen(n, &nod); /* probably a bug */ gmove(&nod, nn); gmove(&nod1, &nod); break; } reg[D_CX]++; if(nn->op == OREGISTER && nn->reg == D_CX) regalloc(&nod1, l, Z); else regalloc(&nod1, l, nn); if(r->complex >= l->complex) { cgen(r, &nod); cgen(l, &nod1); } else { cgen(l, &nod1); cgen(r, &nod); } gopcode(o, n->type, &nod, &nod1); gmove(&nod1, nn); regfree(&nod); regfree(&nod1); break; case OADD: case OSUB: case OOR: case OXOR: case OAND: if(nn == Z) { nullwarn(l, r); break; } if(typefd[n->type->etype]) goto fop; if(r->op == OCONST) { if(r->vconst == 0 && o != OAND) { cgen(l, nn); break; } } if(n->op == OADD && l->op == OASHL && l->right->op == OCONST && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) { c = l->right->vconst; if(c > 0 && c <= 3) { if(l->left->complex >= r->complex) { regalloc(&nod, l->left, nn); cgen(l->left, &nod); if(r->addable < INDEXED) { regalloc(&nod1, r, Z); cgen(r, &nod1); genmuladd(&nod, &nod, 1 << c, &nod1); regfree(&nod1); } else genmuladd(&nod, &nod, 1 << c, r); } else { regalloc(&nod, r, nn); cgen(r, &nod); regalloc(&nod1, l->left, Z); cgen(l->left, &nod1); genmuladd(&nod, &nod1, 1 << c, &nod); regfree(&nod1); } gmove(&nod, nn); regfree(&nod); break; } } if(r->addable >= INDEXED) { regalloc(&nod, l, nn); cgen(l, &nod); gopcode(o, n->type, r, &nod); gmove(&nod, nn); regfree(&nod); break; } if(l->complex >= r->complex) { regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, r, Z); cgen(r, &nod1); gopcode(o, n->type, &nod1, &nod); } else { regalloc(&nod1, r, nn); cgen(r, &nod1); regalloc(&nod, l, Z); cgen(l, &nod); gopcode(o, n->type, &nod1, &nod); } gmove(&nod, nn); regfree(&nod); regfree(&nod1); break; case OLMOD: case OMOD: case OLMUL: case OLDIV: case OMUL: case ODIV: if(nn == Z) { nullwarn(l, r); break; } if(typefd[n->type->etype]) goto fop; if(r->op == OCONST) { SET(v); switch(o) { case ODIV: case OMOD: c = r->vconst; if(c < 0) c = -c; v = log2(c); if(v < 0) break; /* fall thru */ case OMUL: case OLMUL: regalloc(&nod, l, nn); cgen(l, &nod); switch(o) { case OMUL: case OLMUL: mulgen(n->type, r, &nod); break; case ODIV: sdiv2(r->vconst, v, l, &nod); break; case OMOD: smod2(r->vconst, v, l, &nod); break; } gmove(&nod, nn); regfree(&nod); goto done; case OLDIV: c = r->vconst; if((c & 0x80000000) == 0) break; regalloc(&nod1, l, Z); cgen(l, &nod1); regalloc(&nod, l, nn); zeroregm(&nod); gins(ACMPL, &nod1, nodconst(c)); gins(ASBBL, nodconst(-1), &nod); regfree(&nod1); gmove(&nod, nn); regfree(&nod); goto done; } } if(o == OMUL) { if(l->addable >= INDEXED) { t = l; l = r; r = t; goto imula; } else if(r->addable >= INDEXED) { imula: /* should favour AX */ regalloc(&nod, l, nn); cgen(l, &nod); gopcode(OMUL, n->type, r, &nod); } else { /* should favour AX */ regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, r, Z); cgen(r, &nod1); gopcode(OMUL, n->type, &nod1, &nod); regfree(&nod1); } gmove(&nod, nn); regfree(&nod); goto done; } /* * 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) { switch(o) { case ODIV: reg[D_DX]++; if(l->addable < INDEXED) { regalloc(&nod2, l, Z); cgen(l, &nod2); l = &nod2; } sdivgen(l, r, &nod, &nod1); gmove(&nod1, nn); if(l == &nod2) regfree(l); goto freeaxdx; case OLDIV: reg[D_DX]++; if(l->addable < INDEXED) { regalloc(&nod2, l, Z); cgen(l, &nod2); l = &nod2; } udivgen(l, r, &nod, &nod1); gmove(&nod1, nn); if(l == &nod2) regfree(l); goto freeaxdx; } } if(l->complex >= r->complex) { cgen(l, &nod); reg[D_DX]++; if(o == ODIV || o == OMOD) gins(ACDQ, Z, Z); if(o == OLDIV || o == OLMOD) zeroregm(&nod1); if(r->addable < INDEXED || r->op == OCONST) { regsalloc(&nod3, r); cgen(r, &nod3); gopcode(o, n->type, &nod3, Z); } else gopcode(o, n->type, r, Z); } else { regsalloc(&nod3, r); cgen(r, &nod3); cgen(l, &nod); reg[D_DX]++; if(o == ODIV || o == OMOD) gins(ACDQ, Z, Z); if(o == OLDIV || o == OLMOD) zeroregm(&nod1); gopcode(o, n->type, &nod3, Z); } if(o == OMOD || o == OLMOD) gmove(&nod1, nn); else gmove(&nod, nn); freeaxdx: regfree(&nod); regfree(&nod1); break; case OASLSHR: case OASASHL: case OASASHR: if(r->op == OCONST) goto asand; if(l->op == OBIT) goto asbitop; if(typefd[n->type->etype]) goto asfop; /* * get nod to be D_CX */ if(nodreg(&nod, nn, D_CX)) { regsalloc(&nod1, n); gmove(&nod, &nod1); cgen(n, &nod); if(nn != Z) gmove(&nod, nn); gmove(&nod1, &nod); break; } reg[D_CX]++; if(r->complex >= l->complex) { cgen(r, &nod); if(hardleft) reglcgen(&nod1, l, Z); else nod1 = *l; } else { if(hardleft) reglcgen(&nod1, l, Z); else nod1 = *l; cgen(r, &nod); } gopcode(o, l->type, &nod, &nod1); regfree(&nod); if(nn != Z) gmove(&nod1, nn); if(hardleft) regfree(&nod1); break; case OASAND: case OASADD: case OASSUB: case OASXOR: case OASOR: asand: if(l->op == OBIT) goto asbitop; if(typefd[n->type->etype]||typefd[r->type->etype]) goto asfop; if(l->complex >= r->complex) { if(hardleft) reglcgen(&nod, l, Z); else nod = *l; if(r->op != OCONST) { regalloc(&nod1, r, nn); cgen(r, &nod1); gopcode(o, l->type, &nod1, &nod); regfree(&nod1); } else gopcode(o, l->type, r, &nod); } else { regalloc(&nod1, r, nn); cgen(r, &nod1); if(hardleft) reglcgen(&nod, l, Z); else nod = *l; gopcode(o, l->type, &nod1, &nod); regfree(&nod1); } if(nn != Z) gmove(&nod, nn); if(hardleft) regfree(&nod); break; case OASLMUL: case OASLDIV: case OASLMOD: case OASMUL: case OASDIV: case OASMOD: if(l->op == OBIT) goto asbitop; if(typefd[n->type->etype]||typefd[r->type->etype]) goto asfop; if(r->op == OCONST) { SET(v); switch(o) { case OASDIV: case OASMOD: c = r->vconst; if(c < 0) c = -c; v = log2(c); if(v < 0) break; /* fall thru */ case OASMUL: case OASLMUL: if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, l, nn); cgen(&nod2, &nod); switch(o) { case OASMUL: case OASLMUL: mulgen(n->type, r, &nod); break; case OASDIV: sdiv2(r->vconst, v, l, &nod); break; case OASMOD: smod2(r->vconst, v, l, &nod); break; } havev: gmove(&nod, &nod2); if(nn != Z) gmove(&nod, nn); if(hardleft) regfree(&nod2); regfree(&nod); goto done; case OASLDIV: c = r->vconst; if((c & 0x80000000) == 0) break; if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod1, l, nn); cgen(&nod2, &nod1); regalloc(&nod, l, nn); zeroregm(&nod); gins(ACMPL, &nod1, nodconst(c)); gins(ASBBL, nodconst(-1), &nod); regfree(&nod1); goto havev; } } if(o == OASMUL) { /* should favour AX */ regalloc(&nod, l, nn); if(r->complex >= FNX) { regalloc(&nod1, r, Z); cgen(r, &nod1); r = &nod1; } if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; cgen(&nod2, &nod); if(r->addable < INDEXED) { if(r->complex < FNX) { regalloc(&nod1, r, Z); cgen(r, &nod1); } gopcode(OASMUL, n->type, &nod1, &nod); regfree(&nod1); } else gopcode(OASMUL, n->type, r, &nod); if(r == &nod1) regfree(r); gmove(&nod, &nod2); if(nn != Z) gmove(&nod, nn); regfree(&nod); if(hardleft) regfree(&nod2); goto done; } /* * get nod to be D_AX * get nod1 to be D_DX */ if(nodreg(&nod, nn, D_AX)) { regsalloc(&nod2, n); gmove(&nod, &nod2); v = reg[D_AX]; reg[D_AX] = 0; if(isreg(l, D_AX)) { nod3 = *n; nod3.left = &nod2; cgen(&nod3, nn); } else if(isreg(r, D_AX)) { nod3 = *n; nod3.right = &nod2; cgen(&nod3, nn); } else cgen(n, nn); gmove(&nod2, &nod); reg[D_AX] = v; break; } if(nodreg(&nod1, nn, D_DX)) { regsalloc(&nod2, n); gmove(&nod1, &nod2); v = reg[D_DX]; reg[D_DX] = 0; if(isreg(l, D_DX)) { nod3 = *n; nod3.left = &nod2; cgen(&nod3, nn); } else if(isreg(r, D_DX)) { nod3 = *n; nod3.right = &nod2; cgen(&nod3, nn); } else cgen(n, nn); gmove(&nod2, &nod1); reg[D_DX] = v; break; } reg[D_AX]++; reg[D_DX]++; if(l->complex >= r->complex) { if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; cgen(&nod2, &nod); if(r->op == OCONST) { switch(o) { case OASDIV: sdivgen(&nod2, r, &nod, &nod1); goto divdone; case OASLDIV: udivgen(&nod2, r, &nod, &nod1); divdone: gmove(&nod1, &nod2); if(nn != Z) gmove(&nod1, nn); goto freelxaxdx; } } if(o == OASDIV || o == OASMOD) gins(ACDQ, Z, Z); if(o == OASLDIV || o == OASLMOD) zeroregm(&nod1); if(r->addable < INDEXED || r->op == OCONST || !typeil[r->type->etype]) { regalloc(&nod3, r, Z); cgen(r, &nod3); gopcode(o, l->type, &nod3, Z); regfree(&nod3); } else gopcode(o, n->type, r, Z); } else { regalloc(&nod3, r, Z); cgen(r, &nod3); if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; cgen(&nod2, &nod); if(o == OASDIV || o == OASMOD) gins(ACDQ, Z, Z); if(o == OASLDIV || o == OASLMOD) zeroregm(&nod1); gopcode(o, l->type, &nod3, Z); regfree(&nod3); } if(o == OASMOD || o == OASLMOD) { gmove(&nod1, &nod2); if(nn != Z) gmove(&nod1, nn); } else { gmove(&nod, &nod2); if(nn != Z) gmove(&nod, nn); } freelxaxdx: if(hardleft) regfree(&nod2); regfree(&nod); regfree(&nod1); break; fop: if(l->complex >= r->complex) { cgen(l, &fregnode0); if(r->addable < INDEXED) { cgen(r, &fregnode0); fgopcode(o, &fregnode0, &fregnode1, 1, 0); } else fgopcode(o, r, &fregnode0, 0, 0); } else { cgen(r, &fregnode0); if(l->addable < INDEXED) { cgen(l, &fregnode0); fgopcode(o, &fregnode0, &fregnode1, 1, 1); } else fgopcode(o, l, &fregnode0, 0, 1); } gmove(&fregnode0, nn); break; asfop: if(l->complex >= r->complex) { if(hardleft) reglcgen(&nod, l, Z); else nod = *l; cgen(r, &fregnode0); } else { cgen(r, &fregnode0); if(hardleft) reglcgen(&nod, l, Z); else nod = *l; } if(!typefd[l->type->etype]) { gmove(&nod, &fregnode0); fgopcode(o, &fregnode0, &fregnode1, 1, 1); } else fgopcode(o, &nod, &fregnode0, 0, 1); if(nn != Z) gins(AFMOVD, &fregnode0, &fregnode0); gmove(&fregnode0, &nod); if(nn != Z) gmove(&fregnode0, nn); if(hardleft) regfree(&nod); break; asbitop: regalloc(&nod4, n, nn); if(l->complex >= r->complex) { bitload(l, &nod, &nod1, &nod2, &nod4); regalloc(&nod3, r, Z); cgen(r, &nod3); } else { regalloc(&nod3, r, Z); cgen(r, &nod3); bitload(l, &nod, &nod1, &nod2, &nod4); } gmove(&nod, &nod4); if(typefd[nod3.type->etype]) fgopcode(o, &fregnode0, &fregnode1, 1, 1); else { Node onod; /* incredible grot ... */ onod = nod3; onod.op = o; onod.complex = 2; onod.addable = 0; onod.type = tfield; onod.left = &nod4; onod.right = &nod3; cgen(&onod, Z); } regfree(&nod3); gmove(&nod4, &nod); regfree(&nod4); bitstore(l, &nod, &nod1, &nod2, nn); break; case OADDR: if(nn == Z) { nullwarn(l, Z); break; } lcgen(l, nn); break; case OFUNC: if(l->complex >= FNX) { if(l->op != OIND) diag(n, "bad function call"); regret(&nod, l->left); cgen(l->left, &nod); regsalloc(&nod1, l->left); gmove(&nod, &nod1); regfree(&nod); nod = *n; nod.left = &nod2; nod2 = *l; nod2.left = &nod1; nod2.complex = 1; cgen(&nod, nn); return; } gargs(r, &nod, &nod1); if(l->addable < INDEXED) { reglcgen(&nod, l, nn); nod.op = OREGISTER; gopcode(OFUNC, n->type, Z, &nod); regfree(&nod); } else gopcode(OFUNC, n->type, Z, l); if(REGARG>=0 && reg[REGARG]) reg[REGARG]--; if(nn != Z) { regret(&nod, n); gmove(&nod, nn); regfree(&nod); } else if(typefd[n->type->etype]) gins(AFMOVDP, &fregnode0, &fregnode0); break; case OIND: if(nn == Z) { nullwarn(l, Z); break; } regialloc(&nod, n, nn); r = l; while(r->op == OADD) r = r->right; if(sconst(r)) { v = r->vconst; r->vconst = 0; cgen(l, &nod); nod.xoffset += v; r->vconst = v; } else cgen(l, &nod); regind(&nod, n); gmove(&nod, nn); regfree(&nod); break; case OEQ: case ONE: case OLE: case OLT: case OGE: case OGT: case OLO: case OLS: case OHI: case OHS: if(nn == Z) { nullwarn(l, r); break; } boolgen(n, 1, nn); break; case OANDAND: case OOROR: boolgen(n, 1, nn); if(nn == Z) patch(p, pc); break; case ONOT: if(nn == Z) { nullwarn(l, Z); break; } boolgen(n, 1, nn); break; case OCOMMA: cgen(l, Z); cgen(r, nn); break; case OCAST: if(nn == Z) { nullwarn(l, Z); break; } /* * convert from types l->n->nn */ if(nocast(l->type, n->type) && nocast(n->type, nn->type)) { /* both null, gen l->nn */ cgen(l, nn); break; } if(typev[l->type->etype]) { cgen64(n, nn); break; } regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, n, &nod); gmove(&nod, &nod1); gmove(&nod1, nn); regfree(&nod1); regfree(&nod); break; case ODOT: sugen(l, nodrat, l->type->width); if(nn == Z) break; warn(n, "non-interruptable temporary"); nod = *nodrat; if(!r || r->op != OCONST) { diag(n, "DOT and no offset"); break; } nod.xoffset += (long)r->vconst; nod.type = n->type; cgen(&nod, nn); break; case OCOND: bcgen(l, 1); p1 = p; cgen(r->left, nn); gbranch(OGOTO); patch(p1, pc); p1 = p; cgen(r->right, nn); patch(p1, pc); break; case OPOSTINC: case OPOSTDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPOSTDEC) v = -v; if(l->op == OBIT) goto bitinc; if(nn == Z) goto pre; if(hardleft) reglcgen(&nod, l, Z); else nod = *l; if(typefd[n->type->etype]) goto fltinc; gmove(&nod, nn); gopcode(OADD, n->type, nodconst(v), &nod); if(hardleft) regfree(&nod); break; case OPREINC: case OPREDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPREDEC) v = -v; if(l->op == OBIT) goto bitinc; pre: if(hardleft) reglcgen(&nod, l, Z); else nod = *l; if(typefd[n->type->etype]) goto fltinc; gopcode(OADD, n->type, nodconst(v), &nod); if(nn != Z) gmove(&nod, nn); if(hardleft) regfree(&nod); break; fltinc: gmove(&nod, &fregnode0); if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) gins(AFMOVD, &fregnode0, &fregnode0); gins(AFLD1, Z, Z); if(v < 0) fgopcode(OSUB, &fregnode0, &fregnode1, 1, 0); else fgopcode(OADD, &fregnode0, &fregnode1, 1, 0); if(nn != Z && (o == OPREINC || o == OPREDEC)) gins(AFMOVD, &fregnode0, &fregnode0); gmove(&fregnode0, &nod); if(hardleft) regfree(&nod); break; bitinc: if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { bitload(l, &nod, &nod1, &nod2, Z); gmove(&nod, nn); gopcode(OADD, tfield, nodconst(v), &nod); bitstore(l, &nod, &nod1, &nod2, Z); break; } bitload(l, &nod, &nod1, &nod2, nn); gopcode(OADD, tfield, nodconst(v), &nod); bitstore(l, &nod, &nod1, &nod2, nn); break; } done: cursafe = curs; } void reglcgen(Node *t, Node *n, Node *nn) { Node *r; long v; regialloc(t, n, nn); if(n->op == OIND) { r = n->left; while(r->op == OADD) r = r->right; if(sconst(r)) { v = r->vconst; r->vconst = 0; lcgen(n, t); t->xoffset += v; r->vconst = v; regind(t, n); return; } } lcgen(n, t); regind(t, n); } void lcgen(Node *n, Node *nn) { Prog *p1; Node nod; if(debug['g']) { prtree(nn, "lcgen lhs"); prtree(n, "lcgen"); } if(n == Z || n->type == T) return; if(nn == Z) { nn = &nod; regalloc(&nod, n, Z); } switch(n->op) { default: if(n->addable < INDEXED) { diag(n, "unknown op in lcgen: %O", n->op); break; } gopcode(OADDR, n->type, n, nn); break; case OCOMMA: cgen(n->left, n->left); lcgen(n->right, nn); break; case OIND: cgen(n->left, nn); break; case OCOND: bcgen(n->left, 1); p1 = p; lcgen(n->right->left, nn); gbranch(OGOTO); patch(p1, pc); p1 = p; lcgen(n->right->right, nn); patch(p1, pc); break; } } void bcgen(Node *n, int true) { if(n->type == T) gbranch(OGOTO); else boolgen(n, true, Z); } void boolgen(Node *n, int true, Node *nn) { int o; Prog *p1, *p2; Node *l, *r, nod, nod1; long curs; if(debug['g']) { prtree(nn, "boolgen lhs"); prtree(n, "boolgen"); } curs = cursafe; l = n->left; r = n->right; switch(n->op) { default: if(typev[n->type->etype]) { testv(n, true); goto com; } o = ONE; if(true) o = OEQ; if(typefd[n->type->etype]) { if(n->addable < INDEXED) { cgen(n, &fregnode0); gins(AFLDZ, Z, Z); fgopcode(o, &fregnode0, &fregnode1, 1, 1); } else { gins(AFLDZ, Z, Z); fgopcode(o, n, &fregnode0, 0, 1); } goto com; } /* bad, 13 is address of external that becomes constant */ if(n->addable >= INDEXED && n->addable != 13) { gopcode(o, n->type, n, nodconst(0)); goto com; } regalloc(&nod, n, nn); cgen(n, &nod); gopcode(o, n->type, &nod, nodconst(0)); regfree(&nod); goto com; case OCONST: o = vconst(n); if(!true) o = !o; gbranch(OGOTO); if(o) { p1 = p; gbranch(OGOTO); patch(p1, pc); } goto com; case OCOMMA: cgen(l, Z); boolgen(r, true, nn); break; case ONOT: boolgen(l, !true, nn); break; case OCOND: bcgen(l, 1); p1 = p; bcgen(r->left, true); p2 = p; gbranch(OGOTO); patch(p1, pc); p1 = p; bcgen(r->right, !true); patch(p2, pc); p2 = p; gbranch(OGOTO); patch(p1, pc); patch(p2, pc); goto com; case OANDAND: if(!true) goto caseor; caseand: bcgen(l, true); p1 = p; bcgen(r, !true); p2 = p; patch(p1, pc); gbranch(OGOTO); patch(p2, pc); goto com; case OOROR: if(!true) goto caseand; caseor: bcgen(l, !true); p1 = p; bcgen(r, !true); p2 = p; gbranch(OGOTO); patch(p1, pc); patch(p2, pc); goto com; case OEQ: case ONE: case OLE: case OLT: case OGE: case OGT: case OHI: case OHS: case OLO: case OLS: o = n->op; if(typev[l->type->etype]) { if(!true) n->op = comrel[relindex(o)]; cgen64(n, Z); goto com; } if(true) o = comrel[relindex(o)]; if(l->complex >= FNX && r->complex >= FNX) { regret(&nod, r); cgen(r, &nod); regsalloc(&nod1, r); gmove(&nod, &nod1); regfree(&nod); nod = *n; nod.right = &nod1; boolgen(&nod, true, nn); break; } if(typefd[l->type->etype]) { if(l->complex >= r->complex) { cgen(l, &fregnode0); if(r->addable < INDEXED) { cgen(r, &fregnode0); o = invrel[relindex(o)]; fgopcode(o, &fregnode0, &fregnode1, 1, 1); } else fgopcode(o, r, &fregnode0, 0, 1); } else { o = invrel[relindex(o)]; cgen(r, &fregnode0); if(l->addable < INDEXED) { cgen(l, &fregnode0); o = invrel[relindex(o)]; fgopcode(o, &fregnode0, &fregnode1, 1, 1); } else fgopcode(o, l, &fregnode0, 0, 1); } goto com; } if(l->op == OCONST) { o = invrel[relindex(o)]; /* bad, 13 is address of external that becomes constant */ if(r->addable < INDEXED || r->addable == 13) { regalloc(&nod, r, nn); cgen(r, &nod); gopcode(o, l->type, &nod, l); regfree(&nod); } else gopcode(o, l->type, r, l); goto com; } if(l->complex >= r->complex) { regalloc(&nod, l, nn); cgen(l, &nod); if(r->addable < INDEXED) { regalloc(&nod1, r, Z); cgen(r, &nod1); gopcode(o, l->type, &nod, &nod1); regfree(&nod1); } else gopcode(o, l->type, &nod, r); regfree(&nod); goto com; } regalloc(&nod, r, nn); cgen(r, &nod); if(l->addable < INDEXED || l->addable == 13) { regalloc(&nod1, l, Z); cgen(l, &nod1); if(typechlp[l->type->etype]) gopcode(o, types[TINT], &nod1, &nod); else gopcode(o, l->type, &nod1, &nod); regfree(&nod1); } else gopcode(o, l->type, l, &nod); regfree(&nod); com: if(nn != Z) { p1 = p; gmove(nodconst(1L), nn); gbranch(OGOTO); p2 = p; patch(p1, pc); gmove(nodconst(0L), nn); patch(p2, pc); } break; } cursafe = curs; } void sugen(Node *n, Node *nn, long w) { Prog *p1; Node nod0, nod1, nod2, nod3, nod4, *h, *l, *r; Type *t; int c, v, x; if(n == Z || n->type == T) return; if(debug['g']) { prtree(nn, "sugen lhs"); prtree(n, "sugen"); } if(nn == nodrat) if(w > nrathole) nrathole = w; switch(n->op) { case OIND: if(nn == Z) { nullwarn(n->left, Z); break; } default: goto copy; case OCONST: if(n->type && typev[n->type->etype]) { if(nn == Z) { nullwarn(n->left, Z); break; } if(nn->op == OREGPAIR) { loadpair(n, nn); break; } else if(!vaddr(nn, 0)) { t = nn->type; nn->type = types[TLONG]; reglcgen(&nod1, nn, Z); nn->type = t; gmove(lo64(n), &nod1); nod1.xoffset += SZ_LONG; gmove(hi64(n), &nod1); regfree(&nod1); } else { gins(AMOVL, lo64(n), nn); nn->xoffset += SZ_LONG; gins(AMOVL, hi64(n), nn); nn->xoffset -= SZ_LONG; break; } break; } goto copy; case ODOT: l = n->left; sugen(l, nodrat, l->type->width); if(nn == Z) break; warn(n, "non-interruptable temporary"); nod1 = *nodrat; r = n->right; if(!r || r->op != OCONST) { diag(n, "DOT and no offset"); break; } nod1.xoffset += (long)r->vconst; nod1.type = n->type; sugen(&nod1, nn, w); break; case OSTRUCT: /* * rewrite so lhs has no fn call */ if(nn != Z && side(nn)) { nod1 = *n; nod1.type = typ(TIND, n->type); regret(&nod2, &nod1); lcgen(nn, &nod2); regsalloc(&nod0, &nod1); cgen(&nod2, &nod0); regfree(&nod2); nod1 = *n; nod1.op = OIND; nod1.left = &nod0; nod1.right = Z; nod1.complex = 1; sugen(n, &nod1, w); return; } r = n->left; for(t = n->type->link; t != T; t = t->down) { l = r; if(r->op == OLIST) { l = r->left; r = r->right; } if(nn == Z) { cgen(l, nn); continue; } /* * hand craft *(&nn + o) = l */ nod0 = znode; nod0.op = OAS; nod0.type = t; nod0.left = &nod1; nod0.right = nil; nod1 = znode; nod1.op = OIND; nod1.type = t; nod1.left = &nod2; nod2 = znode; nod2.op = OADD; nod2.type = typ(TIND, t); nod2.left = &nod3; nod2.right = &nod4; nod3 = znode; nod3.op = OADDR; nod3.type = nod2.type; nod3.left = nn; nod4 = znode; nod4.op = OCONST; nod4.type = nod2.type; nod4.vconst = t->offset; ccom(&nod0); acom(&nod0); xcom(&nod0); nod0.addable = 0; nod0.right = l; /* prtree(&nod0, "hand craft"); /* */ cgen(&nod0, Z); } break; case OAS: if(nn == Z) { if(n->addable < INDEXED) sugen(n->right, n->left, w); break; } sugen(n->right, nodrat, w); warn(n, "non-interruptable temporary"); sugen(nodrat, n->left, w); sugen(nodrat, nn, w); break; case OFUNC: if(nn == Z) { sugen(n, nodrat, w); break; } h = nn; if(nn->op == OREGPAIR) { regsalloc(&nod1, nn); nn = &nod1; } if(nn->op != OIND) { nn = new1(OADDR, nn, Z); nn->type = types[TIND]; nn->addable = 0; } else nn = nn->left; n = new(OFUNC, n->left, new(OLIST, nn, n->right)); n->type = types[TVOID]; n->left->type = types[TVOID]; cgen(n, Z); if(h->op == OREGPAIR) loadpair(nn->left, h); break; case OCOND: bcgen(n->left, 1); p1 = p; sugen(n->right->left, nn, w); gbranch(OGOTO); patch(p1, pc); p1 = p; sugen(n->right->right, nn, w); patch(p1, pc); break; case OCOMMA: cgen(n->left, Z); sugen(n->right, nn, w); break; } return; copy: if(nn == Z) { switch(n->op) { case OASADD: case OASSUB: case OASAND: case OASOR: case OASXOR: case OASMUL: case OASLMUL: case OASASHL: case OASASHR: case OASLSHR: break; case OPOSTINC: case OPOSTDEC: case OPREINC: case OPREDEC: break; default: return; } } if(n->complex >= FNX && nn != nil && nn->complex >= FNX) { t = nn->type; nn->type = types[TLONG]; regialloc(&nod1, nn, Z); lcgen(nn, &nod1); regsalloc(&nod2, nn); nn->type = t; gins(AMOVL, &nod1, &nod2); regfree(&nod1); nod2.type = typ(TIND, t); nod1 = nod2; nod1.op = OIND; nod1.left = &nod2; nod1.right = Z; nod1.complex = 1; nod1.type = t; sugen(n, &nod1, w); return; } x = 0; v = w == 8; if(v) { c = cursafe; if(n->left != Z && n->left->complex >= FNX && n->right != Z && n->right->complex >= FNX) { // warn(n, "toughie"); regsalloc(&nod1, n->right); cgen(n->right, &nod1); nod2 = *n; nod2.right = &nod1; cgen(&nod2, nn); cursafe = c; return; } if(cgen64(n, nn)) { cursafe = c; return; } if(n->op == OCOM) { n = n->left; x = 1; } } /* botch, need to save in .safe */ c = 0; if(n->complex > nn->complex) { t = n->type; n->type = types[TLONG]; if(v) { regalloc(&nod0, n, Z); if(!vaddr(n, 0)) { reglcgen(&nod1, n, Z); n->type = t; n = &nod1; } else n->type = t; } else { nodreg(&nod1, n, D_SI); if(reg[D_SI]) { gins(APUSHL, &nod1, Z); c |= 1; reg[D_SI]++; } lcgen(n, &nod1); n->type = t; } t = nn->type; nn->type = types[TLONG]; if(v) { if(!vaddr(nn, 0)) { reglcgen(&nod2, nn, Z); nn->type = t; nn = &nod2; } else nn->type = t; } else { nodreg(&nod2, nn, D_DI); if(reg[D_DI]) { gins(APUSHL, &nod2, Z); c |= 2; reg[D_DI]++; } lcgen(nn, &nod2); nn->type = t; } } else { t = nn->type; nn->type = types[TLONG]; if(v) { regalloc(&nod0, nn, Z); if(!vaddr(nn, 0)) { reglcgen(&nod2, nn, Z); nn->type = t; nn = &nod2; } else nn->type = t; } else { nodreg(&nod2, nn, D_DI); if(reg[D_DI]) { gins(APUSHL, &nod2, Z); c |= 2; reg[D_DI]++; } lcgen(nn, &nod2); nn->type = t; } t = n->type; n->type = types[TLONG]; if(v) { if(!vaddr(n, 0)) { reglcgen(&nod1, n, Z); n->type = t; n = &nod1; } else n->type = t; } else { nodreg(&nod1, n, D_SI); if(reg[D_SI]) { gins(APUSHL, &nod1, Z); c |= 1; reg[D_SI]++; } lcgen(n, &nod1); n->type = t; } } if(v) { gins(AMOVL, n, &nod0); if(x) gins(ANOTL, Z, &nod0); gins(AMOVL, &nod0, nn); n->xoffset += SZ_LONG; nn->xoffset += SZ_LONG; gins(AMOVL, n, &nod0); if(x) gins(ANOTL, Z, &nod0); gins(AMOVL, &nod0, nn); n->xoffset -= SZ_LONG; nn->xoffset -= SZ_LONG; if(nn == &nod2) regfree(&nod2); if(n == &nod1) regfree(&nod1); regfree(&nod0); return; } nodreg(&nod3, n, D_CX); if(reg[D_CX]) { gins(APUSHL, &nod3, Z); c |= 4; reg[D_CX]++; } gins(AMOVL, nodconst(w/SZ_LONG), &nod3); gins(ACLD, Z, Z); gins(AREP, Z, Z); gins(AMOVSL, Z, Z); if(x = w & SZ_LONG-1){ warn(n, "packed assignment"); gins(AMOVL, nodconst(x), &nod3); // gins(ACLD, Z, Z); gins(AREP, Z, Z); gins(AMOVSB, Z, Z); } if(c & 4) { gins(APOPL, Z, &nod3); reg[D_CX]--; } if(c & 2) { gins(APOPL, Z, &nod2); reg[nod2.reg]--; } if(c & 1) { gins(APOPL, Z, &nod1); reg[nod1.reg]--; } } != 13) { gopcode(o, n->type, n, nodconst(0)); goto com; } regalloc(&nod, n, nn); cgen(n, &nod); gopcode(o, n->type, &nod, nodconst(0)); regfree(&nod); goto com; case OCONST: o = vconst(n); if(!true) o = !o; gbranch(OGOTO); if(o) { p1 = p; gbranch(OGOTO); patch(p1, pc); } goto com; case OCOMMA: cgen(l, Z); boolgen(r, true, nn); break; case ONOT: boolgen(l, !true, nn); break; case OCOND: bcgen(l, 1); p1 = p; bcgen(r->le8c/cgen64.c 664 0 0 132175 11254007252 10357ustar00syssys#include "gc.h" void zeroregm(Node *n) { gins(AMOVL, nodconst(0), n); } /* do we need to load the address of a vlong? */ int vaddr(Node *n, int a) { switch(n->op) { case ONAME: if(a) return 1; return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC); case OCONST: case OREGISTER: case OINDREG: return 1; } return 0; } long hi64v(Node *n) { if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ return (long)(n->vconst) & ~0L; else return (long)((uvlong)n->vconst>>32) & ~0L; } long lo64v(Node *n) { if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ return (long)((uvlong)n->vconst>>32) & ~0L; else return (long)(n->vconst) & ~0L; } Node * hi64(Node *n) { return nodconst(hi64v(n)); } Node * lo64(Node *n) { return nodconst(lo64v(n)); } static Node * anonreg(void) { Node *n; n = new(OREGISTER, Z, Z); n->reg = D_NONE; n->type = types[TLONG]; return n; } static Node * regpair(Node *n, Node *t) { Node *r; if(n != Z && n->op == OREGPAIR) return n; r = new(OREGPAIR, anonreg(), anonreg()); if(n != Z) r->type = n->type; else r->type = t->type; return r; } static void evacaxdx(Node *r) { Node nod1, nod2; if(r->reg == D_AX || r->reg == D_DX) { reg[D_AX]++; reg[D_DX]++; /* * this is just an optim that should * check for spill */ r->type = types[TULONG]; regalloc(&nod1, r, Z); nodreg(&nod2, Z, r->reg); gins(AMOVL, &nod2, &nod1); regfree(r); r->reg = nod1.reg; reg[D_AX]--; reg[D_DX]--; } } /* lazy instantiation of register pair */ static int instpair(Node *n, Node *l) { int r; r = 0; if(n->left->reg == D_NONE) { if(l != Z) { n->left->reg = l->reg; r = 1; } else regalloc(n->left, n->left, Z); } if(n->right->reg == D_NONE) regalloc(n->right, n->right, Z); return r; } static void zapreg(Node *n) { if(n->reg != D_NONE) { regfree(n); n->reg = D_NONE; } } static void freepair(Node *n) { regfree(n->left); regfree(n->right); } /* n is not OREGPAIR, nn is */ void loadpair(Node *n, Node *nn) { Node nod; instpair(nn, Z); if(n->op == OCONST) { gins(AMOVL, lo64(n), nn->left); n->xoffset += SZ_LONG; gins(AMOVL, hi64(n), nn->right); n->xoffset -= SZ_LONG; return; } if(!vaddr(n, 0)) { /* steal the right register for the laddr */ nod = regnode; nod.reg = nn->right->reg; lcgen(n, &nod); n = &nod; regind(n, n); n->xoffset = 0; } gins(AMOVL, n, nn->left); n->xoffset += SZ_LONG; gins(AMOVL, n, nn->right); n->xoffset -= SZ_LONG; } /* n is OREGPAIR, nn is not */ static void storepair(Node *n, Node *nn, int f) { Node nod; if(!vaddr(nn, 0)) { reglcgen(&nod, nn, Z); nn = &nod; } gins(AMOVL, n->left, nn); nn->xoffset += SZ_LONG; gins(AMOVL, n->right, nn); nn->xoffset -= SZ_LONG; if(nn == &nod) regfree(&nod); if(f) freepair(n); } /* generate a cast t from n to tt */ static void cast(Node *n, Type *t, Node *nn) { Node *r; r = new(OCAST, n, Z); r->type = t; sugen(r, nn, 8); } static void swapregs(Node *a, Node *b) { int t; t = a->reg; a->reg = b->reg; b->reg = t; } static void swappairs(Node *a, Node *b) { swapregs(a->left, b->left); swapregs(a->right, b->right); } static int saveme(Node *n) { int r; r = n->reg; return r >= D_AX && r <= D_DI; } static void saveit(Node *n, Node *t, Node *r) { Node nod; if(saveme(n)) { t->reg = n->reg; gins(AMOVL, t, r); r->xoffset += SZ_LONG; if(n->reg == D_AX) { regalloc(&nod, n, Z); regfree(n); n->reg = nod.reg; } } } static void restoreit(Node *n, Node *t, Node *r) { if(saveme(n)) { t->reg = n->reg; gins(AMOVL, r, t); r->xoffset += SZ_LONG; } } enum { /* 4 only, see WW */ WNONE = 0, WCONST, WADDR, WHARD, }; static int whatof(Node *n, int a) { if(n->op == OCONST) return WCONST; return !vaddr(n, a) ? WHARD : WADDR; } /* can upgrade an extern to addr for AND */ static int reduxv(Node *n) { return lo64v(n) == 0 || hi64v(n) == 0; } int cond(int op) { switch(op) { case OANDAND: case OOROR: case ONOT: return 1; case OEQ: case ONE: case OLE: case OLT: case OGE: case OGT: case OHI: case OHS: case OLO: case OLS: return 1; } return 0; } /* * for a func operand call it and then return * the safe node */ static Node * vfunc(Node *n, Node *nn) { Node *t; if(n->op != OFUNC) return n; t = new(0, Z, Z); if(nn == Z || nn == nodret) nn = n; regsalloc(t, nn); sugen(n, t, 8); return t; } static int forcereg(Node *d, int r, int o, Node *t) { int a; if(d->reg != D_NONE) diag(Z, "force alloc"); d->reg = r; a = 0; if(reg[r]) { reg[o]++; regalloc(t, d, Z); a = 1; gins(AMOVL, d, t); reg[o]--; } reg[r]++; return a; } /* try to steal a reg */ static int getreg(Node **np, Node *t, int r) { Node *n, *p; n = *np; if(n->reg == r) { p = new(0, Z, Z); regalloc(p, n, Z); gins(AMOVL, n, p); *t = *n; *np = p; return 1; } return 0; } static Node * snarfreg(Node *n, Node *t, int r, Node *d, Node *c) { if(n == Z || n->op != OREGPAIR || (!getreg(&n->left, t, r) && !getreg(&n->right, t, r))) { if(nodreg(t, Z, r)) { regalloc(c, d, Z); gins(AMOVL, t, c); reg[r]++; return c; } reg[r]++; } return Z; } enum { Vstart = OEND, Vgo, Vamv, Vmv, Vzero, Vop, Vopx, Vins, Vins0, Vinsl, Vinsr, Vinsla, Vinsra, Vinsx, Vmul, Vshll, VT, VF, V_l_lo_f, V_l_hi_f, V_l_lo_t, V_l_hi_t, V_l_lo_u, V_l_hi_u, V_r_lo_f, V_r_hi_f, V_r_lo_t, V_r_hi_t, V_r_lo_u, V_r_hi_u, Vspazz, Vend, V_T0, V_T1, V_F0, V_F1, V_a0, V_a1, V_f0, V_f1, V_p0, V_p1, V_p2, V_p3, V_p4, V_s0, V_s1, V_s2, V_s3, V_s4, C00, C01, C31, C32, O_l_lo, O_l_hi, O_r_lo, O_r_hi, O_t_lo, O_t_hi, O_l, O_r, O_l_rp, O_r_rp, O_t_rp, O_r0, O_r1, O_Zop, O_a0, O_a1, V_C0, V_C1, V_S0, V_S1, VOPS = 5, VLEN = 5, VARGS = 2, S00 = 0, Sc0, Sc1, Sc2, Sac3, Sac4, S10, SAgen = 0, SAclo, SAc32, SAchi, SAdgen, SAdclo, SAdc32, SAdchi, B0c = 0, Bca, Bac, T0i = 0, Tii, Bop0 = 0, Bop1, }; /* * _testv: * CMPL lo,$0 * JNE true * CMPL hi,$0 * JNE true * GOTO false * false: * GOTO code * true: * GOTO patchme * code: */ static uchar testi[][VLEN] = { {Vop, ONE, O_l_lo, C00}, {V_s0, Vop, ONE, O_l_hi, C00}, {V_s1, Vgo, V_s2, Vgo, V_s3}, {VF, V_p0, V_p1, VT, V_p2}, {Vgo, V_p3}, {VT, V_p0, V_p1, VF, V_p2}, {Vend}, }; /* shift left general case */ static uchar shll00[][VLEN] = { {Vop, OGE, O_r, C32}, {V_s0, Vinsl, ASHLL, O_r, O_l_rp}, {Vins, ASHLL, O_r, O_l_lo, Vgo}, {V_p0, V_s0}, {Vins, ASHLL, O_r, O_l_lo}, {Vins, AMOVL, O_l_lo, O_l_hi}, {Vzero, O_l_lo, V_p0, Vend}, }; /* shift left rp, const < 32 */ static uchar shllc0[][VLEN] = { {Vinsl, ASHLL, O_r, O_l_rp}, {Vshll, O_r, O_l_lo, Vend}, }; /* shift left rp, const == 32 */ static uchar shllc1[][VLEN] = { {Vins, AMOVL, O_l_lo, O_l_hi}, {Vzero, O_l_lo, Vend}, }; /* shift left rp, const > 32 */ static uchar shllc2[][VLEN] = { {Vshll, O_r, O_l_lo}, {Vins, AMOVL, O_l_lo, O_l_hi}, {Vzero, O_l_lo, Vend}, }; /* shift left addr, const == 32 */ static uchar shllac3[][VLEN] = { {Vins, AMOVL, O_l_lo, O_t_hi}, {Vzero, O_t_lo, Vend}, }; /* shift left addr, const > 32 */ static uchar shllac4[][VLEN] = { {Vins, AMOVL, O_l_lo, O_t_hi}, {Vshll, O_r, O_t_hi}, {Vzero, O_t_lo, Vend}, }; /* shift left of constant */ static uchar shll10[][VLEN] = { {Vop, OGE, O_r, C32}, {V_s0, Vins, AMOVL, O_l_lo, O_t_lo}, {Vins, AMOVL, O_l_hi, O_t_hi}, {Vinsl, ASHLL, O_r, O_t_rp}, {Vins, ASHLL, O_r, O_t_lo, Vgo}, {V_p0, V_s0}, {Vins, AMOVL, O_l_lo, O_t_hi}, {V_l_lo_t, Vins, ASHLL, O_r, O_t_hi}, {Vzero, O_t_lo, V_p0, Vend}, }; static uchar (*shlltab[])[VLEN] = { shll00, shllc0, shllc1, shllc2, shllac3, shllac4, shll10, }; /* shift right general case */ static uchar shrl00[][VLEN] = { {Vop, OGE, O_r, C32}, {V_s0, Vinsr, ASHRL, O_r, O_l_rp}, {Vins, O_a0, O_r, O_l_hi, Vgo}, {V_p0, V_s0}, {Vins, O_a0, O_r, O_l_hi}, {Vins, AMOVL, O_l_hi, O_l_lo}, {V_T1, Vzero, O_l_hi}, {V_F1, Vins, ASARL, C31, O_l_hi}, {V_p0, Vend}, }; /* shift right rp, const < 32 */ static uchar shrlc0[][VLEN] = { {Vinsr, ASHRL, O_r, O_l_rp}, {Vins, O_a0, O_r, O_l_hi, Vend}, }; /* shift right rp, const == 32 */ static uchar shrlc1[][VLEN] = { {Vins, AMOVL, O_l_hi, O_l_lo}, {V_T1, Vzero, O_l_hi}, {V_F1, Vins, ASARL, C31, O_l_hi}, {Vend}, }; /* shift right rp, const > 32 */ static uchar shrlc2[][VLEN] = { {Vins, O_a0, O_r, O_l_hi}, {Vins, AMOVL, O_l_hi, O_l_lo}, {V_T1, Vzero, O_l_hi}, {V_F1, Vins, ASARL, C31, O_l_hi}, {Vend}, }; /* shift right addr, const == 32 */ static uchar shrlac3[][VLEN] = { {Vins, AMOVL, O_l_hi, O_t_lo}, {V_T1, Vzero, O_t_hi}, {V_F1, Vins, AMOVL, O_t_lo, O_t_hi}, {V_F1, Vins, ASARL, C31, O_t_hi}, {Vend}, }; /* shift right addr, const > 32 */ static uchar shrlac4[][VLEN] = { {Vins, AMOVL, O_l_hi, O_t_lo}, {Vins, O_a0, O_r, O_t_lo}, {V_T1, Vzero, O_t_hi}, {V_F1, Vins, AMOVL, O_t_lo, O_t_hi}, {V_F1, Vins, ASARL, C31, O_t_hi}, {Vend}, }; /* shift right of constant */ static uchar shrl10[][VLEN] = { {Vop, OGE, O_r, C32}, {V_s0, Vins, AMOVL, O_l_lo, O_t_lo}, {Vins, AMOVL, O_l_hi, O_t_hi}, {Vinsr, ASHRL, O_r, O_t_rp}, {Vins, O_a0, O_r, O_t_hi, Vgo}, {V_p0, V_s0}, {Vins, AMOVL, O_l_hi, O_t_lo}, {V_l_hi_t, Vins, O_a0, O_r, O_t_lo}, {V_l_hi_u, V_S1}, {V_T1, Vzero, O_t_hi, V_p0}, {V_F1, Vins, AMOVL, O_t_lo, O_t_hi}, {V_F1, Vins, ASARL, C31, O_t_hi}, {Vend}, }; static uchar (*shrltab[])[VLEN] = { shrl00, shrlc0, shrlc1, shrlc2, shrlac3, shrlac4, shrl10, }; /* shift asop left general case */ static uchar asshllgen[][VLEN] = { {V_a0, V_a1}, {Vop, OGE, O_r, C32}, {V_s0, Vins, AMOVL, O_l_lo, O_r0}, {Vins, AMOVL, O_l_hi, O_r1}, {Vinsla, ASHLL, O_r, O_r0}, {Vins, ASHLL, O_r, O_r0}, {Vins, AMOVL, O_r1, O_l_hi}, {Vins, AMOVL, O_r0, O_l_lo, Vgo}, {V_p0, V_s0}, {Vins, AMOVL, O_l_lo, O_r0}, {Vzero, O_l_lo}, {Vins, ASHLL, O_r, O_r0}, {Vins, AMOVL, O_r0, O_l_hi, V_p0}, {V_f0, V_f1, Vend}, }; /* shift asop left, const < 32 */ static uchar asshllclo[][VLEN] = { {V_a0, V_a1}, {Vins, AMOVL, O_l_lo, O_r0}, {Vins, AMOVL, O_l_hi, O_r1}, {Vinsla, ASHLL, O_r, O_r0}, {Vshll, O_r, O_r0}, {Vins, AMOVL, O_r1, O_l_hi}, {Vins, AMOVL, O_r0, O_l_lo}, {V_f0, V_f1, Vend}, }; /* shift asop left, const == 32 */ static uchar asshllc32[][VLEN] = { {V_a0}, {Vins, AMOVL, O_l_lo, O_r0}, {Vzero, O_l_lo}, {Vins, AMOVL, O_r0, O_l_hi}, {V_f0, Vend}, }; /* shift asop left, const > 32 */ static uchar asshllchi[][VLEN] = { {V_a0}, {Vins, AMOVL, O_l_lo, O_r0}, {Vzero, O_l_lo}, {Vshll, O_r, O_r0}, {Vins, AMOVL, O_r0, O_l_hi}, {V_f0, Vend}, }; /* shift asop dest left general case */ static uchar asdshllgen[][VLEN] = { {Vop, OGE, O_r, C32}, {V_s0, Vins, AMOVL, O_l_lo, O_t_lo}, {Vins, AMOVL, O_l_hi, O_t_hi}, {Vinsl, ASHLL, O_r, O_t_rp}, {Vins, ASHLL, O_r, O_t_lo}, {Vins, AMOVL, O_t_hi, O_l_hi}, {Vins, AMOVL, O_t_lo, O_l_lo, Vgo}, {V_p0, V_s0}, {Vins, AMOVL, O_l_lo, O_t_hi}, {Vzero, O_l_lo}, {Vins, ASHLL, O_r, O_t_hi}, {Vzero, O_t_lo}, {Vins, AMOVL, O_t_hi, O_l_hi, V_p0}, {Vend}, }; /* shift asop dest left, const < 32 */ static uchar asdshllclo[][VLEN] = { {Vins, AMOVL, O_l_lo, O_t_lo}, {Vins, AMOVL, O_l_hi, O_t_hi}, {Vinsl, ASHLL, O_r, O_t_rp}, {Vshll, O_r, O_t_lo}, {Vins, AMOVL, O_t_hi, O_l_hi}, {Vins, AMOVL, O_t_lo, O_l_lo}, {Vend}, }; /* shift asop dest left, const == 32 */ static uchar asdshllc32[][VLEN] = { {Vins, AMOVL, O_l_lo, O_t_hi}, {Vzero, O_t_lo}, {Vins, AMOVL, O_t_hi, O_l_hi}, {Vins, AMOVL, O_t_lo, O_l_lo}, {Vend}, }; /* shift asop dest, const > 32 */ static uchar asdshllchi[][VLEN] = { {Vins, AMOVL, O_l_lo, O_t_hi}, {Vzero, O_t_lo}, {Vshll, O_r, O_t_hi}, {Vins, AMOVL, O_t_lo, O_l_lo}, {Vins, AMOVL, O_t_hi, O_l_hi}, {Vend}, }; static uchar (*asshlltab[])[VLEN] = { asshllgen, asshllclo, asshllc32, asshllchi, asdshllgen, asdshllclo, asdshllc32, asdshllchi, }; /* shift asop right general case */ static uchar asshrlgen[][VLEN] = { {V_a0, V_a1}, {Vop, OGE, O_r, C32}, {V_s0, Vins, AMOVL, O_l_lo, O_r0}, {Vins, AMOVL, O_l_hi, O_r1}, {Vinsra, ASHRL, O_r, O_r0}, {Vinsx, Bop0, O_r, O_r1}, {Vins, AMOVL, O_r0, O_l_lo}, {Vins, AMOVL, O_r1, O_l_hi, Vgo}, {V_p0, V_s0}, {Vins, AMOVL, O_l_hi, O_r0}, {Vinsx, Bop0, O_r, O_r0}, {V_T1, Vzero, O_l_hi}, {Vins, AMOVL, O_r0, O_l_lo}, {V_F1, Vins, ASARL, C31, O_r0}, {V_F1, Vins, AMOVL, O_r0, O_l_hi}, {V_p0, V_f0, V_f1, Vend}, }; /* shift asop right, const < 32 */ static uchar asshrlclo[][VLEN] = { {V_a0, V_a1}, {Vins, AMOVL, O_l_lo, O_r0}, {Vins, AMOVL, O_l_hi, O_r1}, {Vinsra, ASHRL, O_r, O_r0}, {Vinsx, Bop0, O_r, O_r1}, {Vins, AMOVL, O_r0, O_l_lo}, {Vins, AMOVL, O_r1, O_l_hi}, {V_f0, V_f1, Vend}, }; /* shift asop right, const == 32 */ static uchar asshrlc32[][VLEN] = { {V_a0}, {Vins, AMOVL, O_l_hi, O_r0}, {V_T1, Vzero, O_l_hi}, {Vins, AMOVL, O_r0, O_l_lo}, {V_F1, Vins, ASARL, C31, O_r0}, {V_F1, Vins, AMOVL, O_r0, O_l_hi}, {V_f0, Vend}, }; /* shift asop right, const > 32 */ static uchar asshrlchi[][VLEN] = { {V_a0}, {Vins, AMOVL, O_l_hi, O_r0}, {V_T1, Vzero, O_l_hi}, {Vinsx, Bop0, O_r, O_r0}, {Vins, AMOVL, O_r0, O_l_lo}, {V_F1, Vins, ASARL, C31, O_r0}, {V_F1, Vins, AMOVL, O_r0, O_l_hi}, {V_f0, Vend}, }; /* shift asop dest right general case */ static uchar asdshrlgen[][VLEN] = { {Vop, OGE, O_r, C32}, {V_s0, Vins, AMOVL, O_l_lo, O_t_lo}, {Vins, AMOVL, O_l_hi, O_t_hi}, {Vinsr, ASHRL, O_r, O_t_rp}, {Vinsx, Bop0, O_r, O_t_hi}, {Vins, AMOVL, O_t_lo, O_l_lo}, {Vins, AMOVL, O_t_hi, O_l_hi, Vgo}, {V_p0, V_s0}, {Vins, AMOVL, O_l_hi, O_t_lo}, {V_T1, Vzero, O_t_hi}, {Vinsx, Bop0, O_r, O_t_lo}, {V_F1, Vins, AMOVL, O_t_lo, O_t_hi}, {V_F1, Vins, ASARL, C31, O_t_hi}, {Vins, AMOVL, O_t_hi, O_l_hi, V_p0}, {Vend}, }; /* shift asop dest right, const < 32 */ static uchar asdshrlclo[][VLEN] = { {Vins, AMOVL, O_l_lo, O_t_lo}, {Vins, AMOVL, O_l_hi, O_t_hi}, {Vinsr, ASHRL, O_r, O_t_rp}, {Vinsx, Bop0, O_r, O_t_hi}, {Vins, AMOVL, O_t_lo, O_l_lo}, {Vins, AMOVL, O_t_hi, O_l_hi}, {Vend}, }; /* shift asop dest right, const == 32 */ static uchar asdshrlc32[][VLEN] = { {Vins, AMOVL, O_l_hi, O_t_lo}, {V_T1, Vzero, O_t_hi}, {V_F1, Vins, AMOVL, O_t_lo, O_t_hi}, {V_F1, Vins, ASARL, C31, O_t_hi}, {Vins, AMOVL, O_t_lo, O_l_lo}, {Vins, AMOVL, O_t_hi, O_l_hi}, {Vend}, }; /* shift asop dest, const > 32 */ static uchar asdshrlchi[][VLEN] = { {Vins, AMOVL, O_l_hi, O_t_lo}, {V_T1, Vzero, O_t_hi}, {Vinsx, Bop0, O_r, O_t_lo}, {V_T1, Vins, AMOVL, O_t_hi, O_l_hi}, {V_T1, Vins, AMOVL, O_t_lo, O_l_lo}, {V_F1, Vins, AMOVL, O_t_lo, O_t_hi}, {V_F1, Vins, ASARL, C31, O_t_hi}, {V_F1, Vins, AMOVL, O_t_lo, O_l_lo}, {V_F1, Vins, AMOVL, O_t_hi, O_l_hi}, {Vend}, }; static uchar (*asshrltab[])[VLEN] = { asshrlgen, asshrlclo, asshrlc32, asshrlchi, asdshrlgen, asdshrlclo, asdshrlc32, asdshrlchi, }; static uchar shrlargs[] = { ASHRL, 1 }; static uchar sarlargs[] = { ASARL, 0 }; /* ++ -- */ static uchar incdec[][VLEN] = { {Vinsx, Bop0, C01, O_l_lo}, {Vinsx, Bop1, C00, O_l_hi, Vend}, }; /* ++ -- *p */ static uchar incdecpre[][VLEN] = { {Vins, AMOVL, O_l_lo, O_t_lo}, {Vins, AMOVL, O_l_hi, O_t_hi}, {Vinsx, Bop0, C01, O_t_lo}, {Vinsx, Bop1, C00, O_t_hi}, {Vins, AMOVL, O_t_lo, O_l_lo}, {Vins, AMOVL, O_t_hi, O_l_hi, Vend}, }; /* *p ++ -- */ static uchar incdecpost[][VLEN] = { {Vins, AMOVL, O_l_lo, O_t_lo}, {Vins, AMOVL, O_l_hi, O_t_hi}, {Vinsx, Bop0, C01, O_l_lo}, {Vinsx, Bop1, C00, O_l_hi, Vend}, }; /* binop rp, rp */ static uchar binop00[][VLEN] = { {Vinsx, Bop0, O_r_lo, O_l_lo}, {Vinsx, Bop1, O_r_hi, O_l_hi, Vend}, {Vend}, }; /* binop rp, addr */ static uchar binoptmp[][VLEN] = { {V_a0, Vins, AMOVL, O_r_lo, O_r0}, {Vinsx, Bop0, O_r0, O_l_lo}, {Vins, AMOVL, O_r_hi, O_r0}, {Vinsx, Bop1, O_r0, O_l_hi}, {V_f0, Vend}, }; /* binop t = *a op *b */ static uchar binop11[][VLEN] = { {Vins, AMOVL, O_l_lo, O_t_lo}, {Vinsx, Bop0, O_r_lo, O_t_lo}, {Vins, AMOVL, O_l_hi, O_t_hi}, {Vinsx, Bop1, O_r_hi, O_t_hi, Vend}, }; /* binop t = rp +- c */ static uchar add0c[][VLEN] = { {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo}, {V_r_lo_f, Vamv, Bop0, Bop1}, {Vinsx, Bop1, O_r_hi, O_l_hi}, {Vend}, }; /* binop t = rp & c */ static uchar and0c[][VLEN] = { {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo}, {V_r_lo_f, Vins, AMOVL, C00, O_l_lo}, {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi}, {V_r_hi_f, Vins, AMOVL, C00, O_l_hi}, {Vend}, }; /* binop t = rp | c */ static uchar or0c[][VLEN] = { {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo}, {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi}, {Vend}, }; /* binop t = c - rp */ static uchar sub10[][VLEN] = { {V_a0, Vins, AMOVL, O_l_lo, O_r0}, {Vinsx, Bop0, O_r_lo, O_r0}, {Vins, AMOVL, O_l_hi, O_r_lo}, {Vinsx, Bop1, O_r_hi, O_r_lo}, {Vspazz, V_f0, Vend}, }; /* binop t = c + *b */ static uchar addca[][VLEN] = { {Vins, AMOVL, O_r_lo, O_t_lo}, {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo}, {V_l_lo_f, Vamv, Bop0, Bop1}, {Vins, AMOVL, O_r_hi, O_t_hi}, {Vinsx, Bop1, O_l_hi, O_t_hi}, {Vend}, }; /* binop t = c & *b */ static uchar andca[][VLEN] = { {V_l_lo_t, Vins, AMOVL, O_r_lo, O_t_lo}, {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo}, {V_l_lo_f, Vzero, O_t_lo}, {V_l_hi_t, Vins, AMOVL, O_r_hi, O_t_hi}, {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi}, {V_l_hi_f, Vzero, O_t_hi}, {Vend}, }; /* binop t = c | *b */ static uchar orca[][VLEN] = { {Vins, AMOVL, O_r_lo, O_t_lo}, {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo}, {Vins, AMOVL, O_r_hi, O_t_hi}, {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi}, {Vend}, }; /* binop t = c - *b */ static uchar subca[][VLEN] = { {Vins, AMOVL, O_l_lo, O_t_lo}, {Vins, AMOVL, O_l_hi, O_t_hi}, {Vinsx, Bop0, O_r_lo, O_t_lo}, {Vinsx, Bop1, O_r_hi, O_t_hi}, {Vend}, }; /* binop t = *a +- c */ static uchar addac[][VLEN] = { {Vins, AMOVL, O_l_lo, O_t_lo}, {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo}, {V_r_lo_f, Vamv, Bop0, Bop1}, {Vins, AMOVL, O_l_hi, O_t_hi}, {Vinsx, Bop1, O_r_hi, O_t_hi}, {Vend}, }; /* binop t = *a | c */ static uchar orac[][VLEN] = { {Vins, AMOVL, O_l_lo, O_t_lo}, {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo}, {Vins, AMOVL, O_l_hi, O_t_hi}, {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_t_hi}, {Vend}, }; /* binop t = *a & c */ static uchar andac[][VLEN] = { {V_r_lo_t, Vins, AMOVL, O_l_lo, O_t_lo}, {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo}, {V_r_lo_f, Vzero, O_t_lo}, {V_r_hi_t, Vins, AMOVL, O_l_hi, O_t_hi}, {V_r_hi_t, Vinsx, Bop0, O_r_hi, O_t_hi}, {V_r_hi_f, Vzero, O_t_hi}, {Vend}, }; static uchar ADDargs[] = { AADDL, AADCL }; static uchar ANDargs[] = { AANDL, AANDL }; static uchar ORargs[] = { AORL, AORL }; static uchar SUBargs[] = { ASUBL, ASBBL }; static uchar XORargs[] = { AXORL, AXORL }; static uchar (*ADDtab[])[VLEN] = { add0c, addca, addac, }; static uchar (*ANDtab[])[VLEN] = { and0c, andca, andac, }; static uchar (*ORtab[])[VLEN] = { or0c, orca, orac, }; static uchar (*SUBtab[])[VLEN] = { add0c, subca, addac, }; /* mul of const32 */ static uchar mulc32[][VLEN] = { {V_a0, Vop, ONE, O_l_hi, C00}, {V_s0, Vins, AMOVL, O_r_lo, O_r0}, {Vins, AMULL, O_r0, O_Zop}, {Vgo, V_p0, V_s0}, {Vins, AMOVL, O_l_hi, O_r0}, {Vmul, O_r_lo, O_r0}, {Vins, AMOVL, O_r_lo, O_l_hi}, {Vins, AMULL, O_l_hi, O_Zop}, {Vins, AADDL, O_r0, O_l_hi}, {V_f0, V_p0, Vend}, }; /* mul of const64 */ static uchar mulc64[][VLEN] = { {V_a0, Vins, AMOVL, O_r_hi, O_r0}, {Vop, OOR, O_l_hi, O_r0}, {Vop, ONE, O_r0, C00}, {V_s0, Vins, AMOVL, O_r_lo, O_r0}, {Vins, AMULL, O_r0, O_Zop}, {Vgo, V_p0, V_s0}, {Vmul, O_r_lo, O_l_hi}, {Vins, AMOVL, O_l_lo, O_r0}, {Vmul, O_r_hi, O_r0}, {Vins, AADDL, O_l_hi, O_r0}, {Vins, AMOVL, O_r_lo, O_l_hi}, {Vins, AMULL, O_l_hi, O_Zop}, {Vins, AADDL, O_r0, O_l_hi}, {V_f0, V_p0, Vend}, }; /* mul general */ static uchar mull[][VLEN] = { {V_a0, Vins, AMOVL, O_r_hi, O_r0}, {Vop, OOR, O_l_hi, O_r0}, {Vop, ONE, O_r0, C00}, {V_s0, Vins, AMOVL, O_r_lo, O_r0}, {Vins, AMULL, O_r0, O_Zop}, {Vgo, V_p0, V_s0}, {Vins, AIMULL, O_r_lo, O_l_hi}, {Vins, AMOVL, O_l_lo, O_r0}, {Vins, AIMULL, O_r_hi, O_r0}, {Vins, AADDL, O_l_hi, O_r0}, {Vins, AMOVL, O_r_lo, O_l_hi}, {Vins, AMULL, O_l_hi, O_Zop}, {Vins, AADDL, O_r0, O_l_hi}, {V_f0, V_p0, Vend}, }; /* cast rp l to rp t */ static uchar castrp[][VLEN] = { {Vmv, O_l, O_t_lo}, {VT, Vins, AMOVL, O_t_lo, O_t_hi}, {VT, Vins, ASARL, C31, O_t_hi}, {VF, Vzero, O_t_hi}, {Vend}, }; /* cast rp l to addr t */ static uchar castrpa[][VLEN] = { {VT, V_a0, Vmv, O_l, O_r0}, {VT, Vins, AMOVL, O_r0, O_t_lo}, {VT, Vins, ASARL, C31, O_r0}, {VT, Vins, AMOVL, O_r0, O_t_hi}, {VT, V_f0}, {VF, Vmv, O_l, O_t_lo}, {VF, Vzero, O_t_hi}, {Vend}, }; static uchar netab0i[][VLEN] = { {Vop, ONE, O_l_lo, O_r_lo}, {V_s0, Vop, ONE, O_l_hi, O_r_hi}, {V_s1, Vgo, V_s2, Vgo, V_s3}, {VF, V_p0, V_p1, VT, V_p2}, {Vgo, V_p3}, {VT, V_p0, V_p1, VF, V_p2}, {Vend}, }; static uchar netabii[][VLEN] = { {V_a0, Vins, AMOVL, O_l_lo, O_r0}, {Vop, ONE, O_r0, O_r_lo}, {V_s0, Vins, AMOVL, O_l_hi, O_r0}, {Vop, ONE, O_r0, O_r_hi}, {V_s1, Vgo, V_s2, Vgo, V_s3}, {VF, V_p0, V_p1, VT, V_p2}, {Vgo, V_p3}, {VT, V_p0, V_p1, VF, V_p2}, {V_f0, Vend}, }; static uchar cmptab0i[][VLEN] = { {Vopx, Bop0, O_l_hi, O_r_hi}, {V_s0, Vins0, AJNE}, {V_s1, Vopx, Bop1, O_l_lo, O_r_lo}, {V_s2, Vgo, V_s3, Vgo, V_s4}, {VT, V_p1, V_p3}, {VF, V_p0, V_p2}, {Vgo, V_p4}, {VT, V_p0, V_p2}, {VF, V_p1, V_p3}, {Vend}, }; static uchar cmptabii[][VLEN] = { {V_a0, Vins, AMOVL, O_l_hi, O_r0}, {Vopx, Bop0, O_r0, O_r_hi}, {V_s0, Vins0, AJNE}, {V_s1, Vins, AMOVL, O_l_lo, O_r0}, {Vopx, Bop1, O_r0, O_r_lo}, {V_s2, Vgo, V_s3, Vgo, V_s4}, {VT, V_p1, V_p3}, {VF, V_p0, V_p2}, {Vgo, V_p4}, {VT, V_p0, V_p2}, {VF, V_p1, V_p3}, {V_f0, Vend}, }; static uchar (*NEtab[])[VLEN] = { netab0i, netabii, }; static uchar (*cmptab[])[VLEN] = { cmptab0i, cmptabii, }; static uchar GEargs[] = { OGT, OHS }; static uchar GTargs[] = { OGT, OHI }; static uchar HIargs[] = { OHI, OHI }; static uchar HSargs[] = { OHI, OHS }; /* Big Generator */ static void biggen(Node *l, Node *r, Node *t, int true, uchar code[][VLEN], uchar *a) { int i, j, g, oc, op, lo, ro, to, xo, *xp; Type *lt; Prog *pr[VOPS]; Node *ot, *tl, *tr, tmps[2]; uchar *c, (*cp)[VLEN], args[VARGS]; if(a != nil) memmove(args, a, VARGS); //print("biggen %d %d %d\n", args[0], args[1], args[2]); //if(l) prtree(l, "l"); //if(r) prtree(r, "r"); //if(t) prtree(t, "t"); lo = ro = to = 0; cp = code; for (;;) { c = *cp++; g = 1; i = 0; //print("code %d %d %d %d %d\n", c[0], c[1], c[2], c[3], c[4]); for(;;) { switch(op = c[i]) { case Vgo: if(g) gbranch(OGOTO); i++; break; case Vamv: i += 3; if(i > VLEN) { diag(l, "bad Vop"); return; } if(g) args[c[i - 1]] = args[c[i - 2]]; break; case Vzero: i += 2; if(i > VLEN) { diag(l, "bad Vop"); return; } j = i - 1; goto op; case Vspazz: // nasty hack to save a reg in SUB //print("spazz\n"); if(g) { //print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg); ot = r->right; r->right = r->left; tl = new(0, Z, Z); *tl = tmps[0]; r->left = tl; tmps[0] = *ot; //print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg); } i++; break; case Vmv: case Vmul: case Vshll: i += 3; if(i > VLEN) { diag(l, "bad Vop"); return; } j = i - 2; goto op; case Vins0: i += 2; if(i > VLEN) { diag(l, "bad Vop"); return; } gins(c[i - 1], Z, Z); break; case Vop: case Vopx: case Vins: case Vinsl: case Vinsr: case Vinsla: case Vinsra: case Vinsx: i += 4; if(i > VLEN) { diag(l, "bad Vop"); return; } j = i - 2; goto op; op: if(!g) break; tl = Z; tr = Z; for(; j < i; j++) { switch(c[j]) { case C00: ot = nodconst(0); break; case C01: ot = nodconst(1); break; case C31: ot = nodconst(31); break; case C32: ot = nodconst(32); break; case O_l: case O_l_lo: ot = l; xp = &lo; xo = 0; goto op0; case O_l_hi: ot = l; xp = &lo; xo = SZ_LONG; goto op0; case O_r: case O_r_lo: ot = r; xp = &ro; xo = 0; goto op0; case O_r_hi: ot = r; xp = &ro; xo = SZ_LONG; goto op0; case O_t_lo: ot = t; xp = &to; xo = 0; goto op0; case O_t_hi: ot = t; xp = &to; xo = SZ_LONG; goto op0; case O_l_rp: ot = l; break; case O_r_rp: ot = r; break; case O_t_rp: ot = t; break; case O_r0: case O_r1: ot = &tmps[c[j] - O_r0]; break; case O_Zop: ot = Z; break; op0: switch(ot->op) { case OCONST: if(xo) ot = hi64(ot); else ot = lo64(ot); break; case OREGPAIR: if(xo) ot = ot->right; else ot = ot->left; break; case OREGISTER: break; default: if(xo != *xp) { ot->xoffset += xo - *xp; *xp = xo; } } break; default: diag(l, "bad V_lop"); return; } if(tl == nil) tl = ot; else tr = ot; } if(op == Vzero) { zeroregm(tl); break; } oc = c[i - 3]; if(op == Vinsx || op == Vopx) { //print("%d -> %d\n", oc, args[oc]); oc = args[oc]; } else { switch(oc) { case O_a0: case O_a1: oc = args[oc - O_a0]; break; } } switch(op) { case Vmul: mulgen(tr->type, tl, tr); break; case Vmv: gmove(tl, tr); break; case Vshll: shiftit(tr->type, tl, tr); break; case Vop: case Vopx: gopcode(oc, types[TULONG], tl, tr); break; case Vins: case Vinsx: gins(oc, tl, tr); break; case Vinsl: gins(oc, tl, tr->right); p->from.index = tr->left->reg; break; case Vinsr: gins(oc, tl, tr->left); p->from.index = tr->right->reg; break; case Vinsla: gins(oc, tl, tr + 1); p->from.index = tr->reg; break; case Vinsra: gins(oc, tl, tr); p->from.index = (tr + 1)->reg; break; } break; case VT: g = true; i++; break; case VF: g = !true; i++; break; case V_T0: case V_T1: g = args[op - V_T0]; i++; break; case V_F0: case V_F1: g = !args[op - V_F0]; i++; break; case V_C0: case V_C1: if(g) args[op - V_C0] = 0; i++; break; case V_S0: case V_S1: if(g) args[op - V_S0] = 1; i++; break; case V_l_lo_f: g = lo64v(l) == 0; i++; break; case V_l_hi_f: g = hi64v(l) == 0; i++; break; case V_l_lo_t: g = lo64v(l) != 0; i++; break; case V_l_hi_t: g = hi64v(l) != 0; i++; break; case V_l_lo_u: g = lo64v(l) >= 0; i++; break; case V_l_hi_u: g = hi64v(l) >= 0; i++; break; case V_r_lo_f: g = lo64v(r) == 0; i++; break; case V_r_hi_f: g = hi64v(r) == 0; i++; break; case V_r_lo_t: g = lo64v(r) != 0; i++; break; case V_r_hi_t: g = hi64v(r) != 0; i++; break; case V_r_lo_u: g = lo64v(r) >= 0; i++; break; case V_r_hi_u: g = hi64v(r) >= 0; i++; break; case Vend: goto out; case V_a0: case V_a1: if(g) { lt = l->type; l->type = types[TULONG]; regalloc(&tmps[op - V_a0], l, Z); l->type = lt; } i++; break; case V_f0: case V_f1: if(g) regfree(&tmps[op - V_f0]); i++; break; case V_p0: case V_p1: case V_p2: case V_p3: case V_p4: if(g) patch(pr[op - V_p0], pc); i++; break; case V_s0: case V_s1: case V_s2: case V_s3: case V_s4: if(g) pr[op - V_s0] = p; i++; break; default: diag(l, "bad biggen: %d", op); return; } if(i == VLEN || c[i] == 0) break; } } out: if(lo) l->xoffset -= lo; if(ro) r->xoffset -= ro; if(to) t->xoffset -= to; } int cgen64(Node *n, Node *nn) { Type *dt; uchar *args, (*cp)[VLEN], (**optab)[VLEN]; int li, ri, lri, dr, si, m, op, sh, cmp, true; Node *c, *d, *l, *r, *t, *s, nod1, nod2, nod3, nod4, nod5; if(debug['g']) { prtree(nn, "cgen64 lhs"); prtree(n, "cgen64"); print("AX = %d\n", reg[D_AX]); } cmp = 0; sh = 0; switch(n->op) { case ONEG: d = regpair(nn, n); sugen(n->left, d, 8); gins(ANOTL, Z, d->right); gins(ANEGL, Z, d->left); gins(ASBBL, nodconst(-1), d->right); break; case OCOM: if(!vaddr(n->left, 0) || !vaddr(nn, 0)) d = regpair(nn, n); else return 0; sugen(n->left, d, 8); gins(ANOTL, Z, d->left); gins(ANOTL, Z, d->right); break; case OADD: optab = ADDtab; args = ADDargs; goto twoop; case OAND: optab = ANDtab; args = ANDargs; goto twoop; case OOR: optab = ORtab; args = ORargs; goto twoop; case OSUB: optab = SUBtab; args = SUBargs; goto twoop; case OXOR: optab = ORtab; args = XORargs; goto twoop; case OASHL: sh = 1; args = nil; optab = shlltab; goto twoop; case OLSHR: sh = 1; args = shrlargs; optab = shrltab; goto twoop; case OASHR: sh = 1; args = sarlargs; optab = shrltab; goto twoop; case OEQ: cmp = 1; args = nil; optab = nil; goto twoop; case ONE: cmp = 1; args = nil; optab = nil; goto twoop; case OLE: cmp = 1; args = nil; optab = nil; goto twoop; case OLT: cmp = 1; args = nil; optab = nil; goto twoop; case OGE: cmp = 1; args = nil; optab = nil; goto twoop; case OGT: cmp = 1; args = nil; optab = nil; goto twoop; case OHI: cmp = 1; args = nil; optab = nil; goto twoop; case OHS: cmp = 1; args = nil; optab = nil; goto twoop; case OLO: cmp = 1; args = nil; optab = nil; goto twoop; case OLS: cmp = 1; args = nil; optab = nil; goto twoop; twoop: dr = nn != Z && nn->op == OREGPAIR; l = vfunc(n->left, nn); if(sh) r = n->right; else r = vfunc(n->right, nn); li = l->op == ONAME || l->op == OINDREG || l->op == OCONST; ri = r->op == ONAME || r->op == OINDREG || r->op == OCONST; #define IMM(l, r) ((l) | ((r) << 1)) lri = IMM(li, ri); /* find out what is so easy about some operands */ if(li) li = whatof(l, sh | cmp); if(ri) ri = whatof(r, cmp); if(sh) goto shift; if(cmp) goto cmp; /* evaluate hard subexps, stealing nn if possible. */ switch(lri) { case IMM(0, 0): bin00: if(l->complex > r->complex) { if(dr) t = nn; else t = regpair(Z, n); sugen(l, t, 8); l = t; t = regpair(Z, n); sugen(r, t, 8); r = t; } else { t = regpair(Z, n); sugen(r, t, 8); r = t; if(dr) t = nn; else t = regpair(Z, n); sugen(l, t, 8); l = t; } break; case IMM(0, 1): if(dr) t = nn; else t = regpair(Z, n); sugen(l, t, 8); l = t; break; case IMM(1, 0): if(n->op == OSUB && l->op == OCONST && hi64v(l) == 0) { lri = IMM(0, 0); goto bin00; } if(dr) t = nn; else t = regpair(Z, n); sugen(r, t, 8); r = t; break; case IMM(1, 1): break; } #define WW(l, r) ((l) | ((r) << 2)) d = Z; dt = nn->type; nn->type = types[TLONG]; switch(lri) { case IMM(0, 0): biggen(l, r, Z, 0, binop00, args); break; case IMM(0, 1): switch(ri) { case WNONE: diag(r, "bad whatof\n"); break; case WCONST: biggen(l, r, Z, 0, optab[B0c], args); break; case WHARD: reglcgen(&nod2, r, Z); r = &nod2; /* fall thru */ case WADDR: biggen(l, r, Z, 0, binoptmp, args); if(ri == WHARD) regfree(r); break; } break; case IMM(1, 0): if(n->op == OSUB) { switch(li) { case WNONE: diag(l, "bad whatof\n"); break; case WHARD: reglcgen(&nod2, l, Z); l = &nod2; /* fall thru */ case WADDR: case WCONST: biggen(l, r, Z, 0, sub10, args); break; } if(li == WHARD) regfree(l); } else { switch(li) { case WNONE: diag(l, "bad whatof\n"); break; case WCONST: biggen(r, l, Z, 0, optab[B0c], args); break; case WHARD: reglcgen(&nod2, l, Z); l = &nod2; /* fall thru */ case WADDR: biggen(r, l, Z, 0, binoptmp, args); if(li == WHARD) regfree(l); break; } } break; case IMM(1, 1): switch(WW(li, ri)) { case WW(WCONST, WHARD): if(r->op == ONAME && n->op == OAND && reduxv(l)) ri = WADDR; break; case WW(WHARD, WCONST): if(l->op == ONAME && n->op == OAND && reduxv(r)) li = WADDR; break; } if(li == WHARD) { reglcgen(&nod3, l, Z); l = &nod3; } if(ri == WHARD) { reglcgen(&nod2, r, Z); r = &nod2; } d = regpair(nn, n); instpair(d, Z); switch(WW(li, ri)) { case WW(WCONST, WADDR): case WW(WCONST, WHARD): biggen(l, r, d, 0, optab[Bca], args); break; case WW(WADDR, WCONST): case WW(WHARD, WCONST): biggen(l, r, d, 0, optab[Bac], args); break; case WW(WADDR, WADDR): case WW(WADDR, WHARD): case WW(WHARD, WADDR): case WW(WHARD, WHARD): biggen(l, r, d, 0, binop11, args); break; default: diag(r, "bad whatof pair %d %d\n", li, ri); break; } if(li == WHARD) regfree(l); if(ri == WHARD) regfree(r); break; } nn->type = dt; if(d != Z) goto finished; switch(lri) { case IMM(0, 0): freepair(r); /* fall thru */; case IMM(0, 1): if(!dr) storepair(l, nn, 1); break; case IMM(1, 0): if(!dr) storepair(r, nn, 1); break; case IMM(1, 1): break; } return 1; shift: c = Z; /* evaluate hard subexps, stealing nn if possible. */ /* must also secure CX. not as many optims as binop. */ switch(lri) { case IMM(0, 0): imm00: if(l->complex + 1 > r->complex) { if(dr) t = nn; else t = regpair(Z, l); sugen(l, t, 8); l = t; t = &nod1; c = snarfreg(l, t, D_CX, r, &nod2); cgen(r, t); r = t; } else { t = &nod1; c = snarfreg(nn, t, D_CX, r, &nod2); cgen(r, t); r = t; if(dr) t = nn; else t = regpair(Z, l); sugen(l, t, 8); l = t; } break; case IMM(0, 1): imm01: if(ri != WCONST) { lri = IMM(0, 0); goto imm00; } if(dr) t = nn; else t = regpair(Z, n); sugen(l, t, 8); l = t; break; case IMM(1, 0): imm10: if(li != WCONST) { lri = IMM(0, 0); goto imm00; } t = &nod1; c = snarfreg(nn, t, D_CX, r, &nod2); cgen(r, t); r = t; break; case IMM(1, 1): if(ri != WCONST) { lri = IMM(1, 0); goto imm10; } if(li == WHARD) { lri = IMM(0, 1); goto imm01; } break; } d = Z; switch(lri) { case IMM(0, 0): biggen(l, r, Z, 0, optab[S00], args); break; case IMM(0, 1): switch(ri) { case WNONE: case WADDR: case WHARD: diag(r, "bad whatof\n"); break; case WCONST: m = r->vconst & 63; s = nodconst(m); if(m < 32) cp = optab[Sc0]; else if(m == 32) cp = optab[Sc1]; else cp = optab[Sc2]; biggen(l, s, Z, 0, cp, args); break; } break; case IMM(1, 0): /* left is const */ d = regpair(nn, n); instpair(d, Z); biggen(l, r, d, 0, optab[S10], args); regfree(r); break; case IMM(1, 1): d = regpair(nn, n); instpair(d, Z); switch(WW(li, ri)) { case WW(WADDR, WCONST): m = r->vconst & 63; s = nodconst(m); if(m < 32) { loadpair(l, d); l = d; cp = optab[Sc0]; } else if(m == 32) cp = optab[Sac3]; else cp = optab[Sac4]; biggen(l, s, d, 0, cp, args); break; default: diag(r, "bad whatof pair %d %d\n", li, ri); break; } break; } if(c != Z) { gins(AMOVL, c, r); regfree(c); } if(d != Z) goto finished; switch(lri) { case IMM(0, 0): regfree(r); /* fall thru */ case IMM(0, 1): if(!dr) storepair(l, nn, 1); break; case IMM(1, 0): regfree(r); break; case IMM(1, 1): break; } return 1; cmp: op = n->op; /* evaluate hard subexps */ switch(lri) { case IMM(0, 0): if(l->complex > r->complex) { t = regpair(Z, l); sugen(l, t, 8); l = t; t = regpair(Z, r); sugen(r, t, 8); r = t; } else { t = regpair(Z, r); sugen(r, t, 8); r = t; t = regpair(Z, l); sugen(l, t, 8); l = t; } break; case IMM(1, 0): t = r; r = l; l = t; ri = li; op = invrel[relindex(op)]; /* fall thru */ case IMM(0, 1): t = regpair(Z, l); sugen(l, t, 8); l = t; break; case IMM(1, 1): break; } true = 1; optab = cmptab; switch(op) { case OEQ: optab = NEtab; true = 0; break; case ONE: optab = NEtab; break; case OLE: args = GTargs; true = 0; break; case OGT: args = GTargs; break; case OLS: args = HIargs; true = 0; break; case OHI: args = HIargs; break; case OLT: args = GEargs; true = 0; break; case OGE: args = GEargs; break; case OLO: args = HSargs; true = 0; break; case OHS: args = HSargs; break; default: diag(n, "bad cmp\n"); SET(optab); } switch(lri) { case IMM(0, 0): biggen(l, r, Z, true, optab[T0i], args); break; case IMM(0, 1): case IMM(1, 0): switch(ri) { case WNONE: diag(l, "bad whatof\n"); break; case WCONST: biggen(l, r, Z, true, optab[T0i], args); break; case WHARD: reglcgen(&nod2, r, Z); r = &nod2; /* fall thru */ case WADDR: biggen(l, r, Z, true, optab[T0i], args); if(ri == WHARD) regfree(r); break; } break; case IMM(1, 1): if(li == WHARD) { reglcgen(&nod3, l, Z); l = &nod3; } if(ri == WHARD) { reglcgen(&nod2, r, Z); r = &nod2; } biggen(l, r, Z, true, optab[Tii], args); if(li == WHARD) regfree(l); if(ri == WHARD) regfree(r); break; } switch(lri) { case IMM(0, 0): freepair(r); /* fall thru */; case IMM(0, 1): case IMM(1, 0): freepair(l); break; case IMM(1, 1): break; } return 1; case OASMUL: case OASLMUL: m = 0; goto mulop; case OMUL: case OLMUL: m = 1; goto mulop; mulop: dr = nn != Z && nn->op == OREGPAIR; l = vfunc(n->left, nn); r = vfunc(n->right, nn); if(r->op != OCONST) { if(l->complex > r->complex) { if(m) { t = l; l = r; r = t; } else if(!vaddr(l, 1)) { reglcgen(&nod5, l, Z); l = &nod5; evacaxdx(l); } } if(l->op == OSUB && l->right != Z && l->right->op == OCAST) warn(n, "likely vlong bug"); t = regpair(Z, n); sugen(r, t, 8); r = t; evacaxdx(r->left); evacaxdx(r->right); if(l->complex <= r->complex && !m && !vaddr(l, 1)) { reglcgen(&nod5, l, Z); l = &nod5; evacaxdx(l); } } if(dr) t = nn; else t = regpair(Z, n); c = Z; d = Z; if(!nodreg(&nod1, t->left, D_AX)) { if(t->left->reg != D_AX){ t->left->reg = D_AX; reg[D_AX]++; }else if(reg[D_AX] == 0) fatal(Z, "vlong mul AX botch"); } if(!nodreg(&nod2, t->right, D_DX)) { if(t->right->reg != D_DX){ t->right->reg = D_DX; reg[D_DX]++; }else if(reg[D_DX] == 0) fatal(Z, "vlong mul DX botch"); } if(m) sugen(l, t, 8); else loadpair(l, t); if(t->left->reg != D_AX) { c = &nod3; regsalloc(c, t->left); gmove(&nod1, c); gmove(t->left, &nod1); zapreg(t->left); } if(t->right->reg != D_DX) { fatal(Z, "vlong double-spill botch"); d = &nod4; regsalloc(d, t->right); gmove(&nod2, d); gmove(t->right, &nod2); zapreg(t->right); } if(c != Z || d != Z) { s = regpair(Z, n); s->left = &nod1; s->right = &nod2; } else s = t; if(r->op == OCONST) { if(hi64v(r) == 0) biggen(s, r, Z, 0, mulc32, nil); else biggen(s, r, Z, 0, mulc64, nil); } else biggen(s, r, Z, 0, mull, nil); instpair(t, Z); if(c != Z) { gmove(&nod1, t->left); gmove(&nod3, &nod1); } if(d != Z) { gmove(&nod2, t->right); gmove(&nod4, &nod2); } if(r->op == OREGPAIR) freepair(r); if(!m) storepair(t, l, 0); if(l == &nod5) regfree(l); if(!dr) { if(nn != Z) storepair(t, nn, 1); else freepair(t); } return 1; case OASADD: args = ADDargs; goto vasop; case OASAND: args = ANDargs; goto vasop; case OASOR: args = ORargs; goto vasop; case OASSUB: args = SUBargs; goto vasop; case OASXOR: args = XORargs; goto vasop; vasop: l = n->left; r = n->right; dr = nn != Z && nn->op == OREGPAIR; m = 0; if(l->complex > r->complex) { if(!vaddr(l, 1)) { reglcgen(&nod1, l, Z); l = &nod1; } if(!vaddr(r, 1) || nn != Z || r->op == OCONST) { if(dr) t = nn; else t = regpair(Z, r); sugen(r, t, 8); r = t; m = 1; } } else { if(!vaddr(r, 1) || nn != Z || r->op == OCONST) { if(dr) t = nn; else t = regpair(Z, r); sugen(r, t, 8); r = t; m = 1; } if(!vaddr(l, 1)) { reglcgen(&nod1, l, Z); l = &nod1; } } if(nn != Z) { if(n->op == OASSUB) biggen(l, r, Z, 0, sub10, args); else biggen(r, l, Z, 0, binoptmp, args); storepair(r, l, 0); } else { if(m) biggen(l, r, Z, 0, binop00, args); else biggen(l, r, Z, 0, binoptmp, args); } if(l == &nod1) regfree(&nod1); if(m) { if(nn == Z) freepair(r); else if(!dr) storepair(r, nn, 1); } return 1; case OASASHL: args = nil; optab = asshlltab; goto assh; case OASLSHR: args = shrlargs; optab = asshrltab; goto assh; case OASASHR: args = sarlargs; optab = asshrltab; goto assh; assh: c = Z; l = n->left; r = n->right; if(r->op == OCONST) { m = r->vconst & 63; if(m < 32) m = SAclo; else if(m == 32) m = SAc32; else m = SAchi; } else m = SAgen; if(l->complex > r->complex) { if(!vaddr(l, 0)) { reglcgen(&nod1, l, Z); l = &nod1; } if(m == SAgen) { t = &nod2; if(l->reg == D_CX) { regalloc(t, r, Z); gmove(l, t); l->reg = t->reg; t->reg = D_CX; } else c = snarfreg(nn, t, D_CX, r, &nod3); cgen(r, t); r = t; } } else { if(m == SAgen) { t = &nod2; c = snarfreg(nn, t, D_CX, r, &nod3); cgen(r, t); r = t; } if(!vaddr(l, 0)) { reglcgen(&nod1, l, Z); l = &nod1; } } if(nn != Z) { m += SAdgen - SAgen; d = regpair(nn, n); instpair(d, Z); biggen(l, r, d, 0, optab[m], args); if(l == &nod1) { regfree(&nod1); l = Z; } if(r == &nod2 && c == Z) { regfree(&nod2); r = Z; } if(d != nn) storepair(d, nn, 1); } else biggen(l, r, Z, 0, optab[m], args); if(c != Z) { gins(AMOVL, c, r); regfree(c); } if(l == &nod1) regfree(&nod1); if(r == &nod2) regfree(&nod2); return 1; case OPOSTINC: args = ADDargs; cp = incdecpost; goto vinc; case OPOSTDEC: args = SUBargs; cp = incdecpost; goto vinc; case OPREINC: args = ADDargs; cp = incdecpre; goto vinc; case OPREDEC: args = SUBargs; cp = incdecpre; goto vinc; vinc: l = n->left; if(!vaddr(l, 1)) { reglcgen(&nod1, l, Z); l = &nod1; } if(nn != Z) { d = regpair(nn, n); instpair(d, Z); biggen(l, Z, d, 0, cp, args); if(l == &nod1) { regfree(&nod1); l = Z; } if(d != nn) storepair(d, nn, 1); } else biggen(l, Z, Z, 0, incdec, args); if(l == &nod1) regfree(&nod1); return 1; case OCAST: l = n->left; if(typev[l->type->etype]) { if(!vaddr(l, 1)) { if(l->complex + 1 > nn->complex) { d = regpair(Z, l); sugen(l, d, 8); if(!vaddr(nn, 1)) { reglcgen(&nod1, nn, Z); r = &nod1; } else r = nn; } else { if(!vaddr(nn, 1)) { reglcgen(&nod1, nn, Z); r = &nod1; } else r = nn; d = regpair(Z, l); sugen(l, d, 8); } // d->left->type = r->type; d->left->type = types[TLONG]; gmove(d->left, r); freepair(d); } else { if(nn->op != OREGISTER && !vaddr(nn, 1)) { reglcgen(&nod1, nn, Z); r = &nod1; } else r = nn; // l->type = r->type; l->type = types[TLONG]; gmove(l, r); } if(r != nn) regfree(r); } else { if(typeu[l->type->etype] || cond(l->op)) si = TUNSIGNED; else si = TSIGNED; regalloc(&nod1, l, Z); cgen(l, &nod1); if(nn->op == OREGPAIR) { m = instpair(nn, &nod1); biggen(&nod1, Z, nn, si == TSIGNED, castrp, nil); } else { m = 0; if(!vaddr(nn, si != TSIGNED)) { dt = nn->type; nn->type = types[TLONG]; reglcgen(&nod2, nn, Z); nn->type = dt; nn = &nod2; } dt = nn->type; nn->type = types[TLONG]; biggen(&nod1, Z, nn, si == TSIGNED, castrpa, nil); nn->type = dt; if(nn == &nod2) regfree(&nod2); } if(!m) regfree(&nod1); } return 1; default: if(n->op == OREGPAIR) { storepair(n, nn, 1); return 1; } if(nn->op == OREGPAIR) { loadpair(n, nn); return 1; } return 0; } finished: if(d != nn) storepair(d, nn, 1); return 1; } void testv(Node *n, int true) { Type *t; Node *nn, nod, *b; if(machcap(Z)) { b = &nod; b->op = true ? ONE : OEQ; b->left = n; b->right = new(0, Z, Z); *b->right = *nodconst(0); b->right->type = n->type; b->type = types[TLONG]; cgen64(b, Z); return; } switch(n->op) { case OINDREG: case ONAME: biggen(n, Z, Z, true, testi, nil); break; default: n = vfunc(n, n); if(n->addable >= INDEXED) { t = n->type; n->type = types[TLONG]; reglcgen(&nod, n, Z); n->type = t; n = &nod; biggen(n, Z, Z, true, testi, nil); if(n == &nod) regfree(n); } else { nn = regpair(Z, n); sugen(n, nn, 8); biggen(nn, Z, Z, true, testi, nil); freepair(nn); } } } atof pair %d %d\n", li, ri); break; } break; } if(c != Z) { gins(AMOVL, c, r); regfree(c); } if(d != Z) goto finished; switch(lri) { case IMM(0, 0): regfree(r); /* fall thru */ case IMM(0, 1): if(!dr) storepair(l, nn, 1); break; case IMM(1, 0): regfree(r); break; case IMM(1, 1): break; } return 1; cmp: op = n->op8c/div.c 664 0 0 6341 10122622617 10007ustar00syssys#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) (1ULL << (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); } mulc64, nil); } else biggen(s, r, Z, 0, mull, nil); instpair(t, Z); if(c != Z) { gmove(&nod1, t->left); gmove(&nod3, &nod1); } if(d != Z) { gmove(&nod2, t->right); gmove(&nod4, &nod2); } if(r->op == OREGPAIR) freepair(r); if(!m) storepair(t, l, 0)8c/enam.c 664 0 0 6233 10073261355 10150ustar00syssyschar* anames[] = { "XXX", "AAA", "AAD", "AAM", "AAS", "ADCB", "ADCL", "ADCW", "ADDB", "ADDL", "ADDW", "ADJSP", "ANDB", "ANDL", "ANDW", "ARPL", "BOUNDL", "BOUNDW", "BSFL", "BSFW", "BSRL", "BSRW", "BTL", "BTW", "BTCL", "BTCW", "BTRL", "BTRW", "BTSL", "BTSW", "BYTE", "CALL", "CLC", "CLD", "CLI", "CLTS", "CMC", "CMPB", "CMPL", "CMPW", "CMPSB", "CMPSL", "CMPSW", "DAA", "DAS", "DATA", "DECB", "DECL", "DECW", "DIVB", "DIVL", "DIVW", "ENTER", "GLOBL", "GOK", "HISTORY", "HLT", "IDIVB", "IDIVL", "IDIVW", "IMULB", "IMULL", "IMULW", "INB", "INL", "INW", "INCB", "INCL", "INCW", "INSB", "INSL", "INSW", "INT", "INTO", "IRETL", "IRETW", "JCC", "JCS", "JCXZ", "JEQ", "JGE", "JGT", "JHI", "JLE", "JLS", "JLT", "JMI", "JMP", "JNE", "JOC", "JOS", "JPC", "JPL", "JPS", "LAHF", "LARL", "LARW", "LEAL", "LEAW", "LEAVEL", "LEAVEW", "LOCK", "LODSB", "LODSL", "LODSW", "LONG", "LOOP", "LOOPEQ", "LOOPNE", "LSLL", "LSLW", "MOVB", "MOVL", "MOVW", "MOVBLSX", "MOVBLZX", "MOVBWSX", "MOVBWZX", "MOVWLSX", "MOVWLZX", "MOVSB", "MOVSL", "MOVSW", "MULB", "MULL", "MULW", "NAME", "NEGB", "NEGL", "NEGW", "NOP", "NOTB", "NOTL", "NOTW", "ORB", "ORL", "ORW", "OUTB", "OUTL", "OUTW", "OUTSB", "OUTSL", "OUTSW", "POPAL", "POPAW", "POPFL", "POPFW", "POPL", "POPW", "PUSHAL", "PUSHAW", "PUSHFL", "PUSHFW", "PUSHL", "PUSHW", "RCLB", "RCLL", "RCLW", "RCRB", "RCRL", "RCRW", "REP", "REPN", "RET", "ROLB", "ROLL", "ROLW", "RORB", "RORL", "RORW", "SAHF", "SALB", "SALL", "SALW", "SARB", "SARL", "SARW", "SBBB", "SBBL", "SBBW", "SCASB", "SCASL", "SCASW", "SETCC", "SETCS", "SETEQ", "SETGE", "SETGT", "SETHI", "SETLE", "SETLS", "SETLT", "SETMI", "SETNE", "SETOC", "SETOS", "SETPC", "SETPL", "SETPS", "CDQ", "CWD", "SHLB", "SHLL", "SHLW", "SHRB", "SHRL", "SHRW", "STC", "STD", "STI", "STOSB", "STOSL", "STOSW", "SUBB", "SUBL", "SUBW", "SYSCALL", "TESTB", "TESTL", "TESTW", "TEXT", "VERR", "VERW", "WAIT", "WORD", "XCHGB", "XCHGL", "XCHGW", "XLAT", "XORB", "XORL", "XORW", "FMOVB", "FMOVBP", "FMOVD", "FMOVDP", "FMOVF", "FMOVFP", "FMOVL", "FMOVLP", "FMOVV", "FMOVVP", "FMOVW", "FMOVWP", "FMOVX", "FMOVXP", "FCOMB", "FCOMBP", "FCOMD", "FCOMDP", "FCOMDPP", "FCOMF", "FCOMFP", "FCOML", "FCOMLP", "FCOMW", "FCOMWP", "FUCOM", "FUCOMP", "FUCOMPP", "FADDDP", "FADDW", "FADDL", "FADDF", "FADDD", "FMULDP", "FMULW", "FMULL", "FMULF", "FMULD", "FSUBDP", "FSUBW", "FSUBL", "FSUBF", "FSUBD", "FSUBRDP", "FSUBRW", "FSUBRL", "FSUBRF", "FSUBRD", "FDIVDP", "FDIVW", "FDIVL", "FDIVF", "FDIVD", "FDIVRDP", "FDIVRW", "FDIVRL", "FDIVRF", "FDIVRD", "FXCHD", "FFREE", "FLDCW", "FLDENV", "FRSTOR", "FSAVE", "FSTCW", "FSTENV", "FSTSW", "F2XM1", "FABS", "FCHS", "FCLEX", "FCOS", "FDECSTP", "FINCSTP", "FINIT", "FLD1", "FLDL2E", "FLDL2T", "FLDLG2", "FLDLN2", "FLDPI", "FLDZ", "FNOP", "FPATAN", "FPREM", "FPREM1", "FPTAN", "FRNDINT", "FSCALE", "FSIN", "FSINCOS", "FSQRT", "FTST", "FXAM", "FXTRACT", "FYL2X", "FYL2XP1", "END", "DYNT", "INIT", "SIGNAME", "LAST", }; } else r = nn; d = regpair(Z, l); sugen(l, d, 8); } // d->left->type = r->type; d->left->type = types[TLONG]; gmove(d->left, r); freepair(d); } else { if(nn->op != OREGISTER && !vaddr(nn, 1)) { reglcgen(&nod1, nn, Z); r = &nod1; } else r = nn; // l->type = r->type; l->ty8c/gc.h 664 0 0 14440 11262413065 7643ustar00syssys#include "../cc/cc.h" #include "../8c/8.out.h" /* * 8c/386 * Intel 386 */ #define SZ_CHAR 1 #define SZ_SHORT 2 #define SZ_INT 4 #define SZ_LONG 4 #define SZ_IND 4 #define SZ_FLOAT 4 #define SZ_VLONG 8 #define SZ_DOUBLE 8 #define FNX 100 typedef struct Adr Adr; typedef struct Prog Prog; typedef struct Case Case; typedef struct C1 C1; typedef struct Var Var; typedef struct Reg Reg; typedef struct Rgn Rgn; typedef struct Renv Renv; EXTERN struct { Node* regtree; Node* basetree; short scale; short reg; short ptr; } idx; struct Adr { long offset; double dval; char sval[NSNAME]; Sym* sym; uchar type; uchar index; uchar etype; uchar scale; /* doubles as width in DATA op */ }; #define A ((Adr*)0) #define INDEXED 9 struct Prog { Adr from; Adr to; Prog* link; long lineno; short as; }; #define P ((Prog*)0) struct Case { Case* link; long val; long label; char def; char isv; }; #define C ((Case*)0) struct C1 { long val; long label; }; struct Var { long offset; Sym* sym; char name; char etype; }; struct Reg { long pc; long rpo; /* reverse post ordering */ Bits set; Bits use1; Bits use2; Bits refbehind; Bits refahead; Bits calbehind; Bits calahead; Bits regdiff; Bits act; long regu; long loop; /* could be shorter */ Reg* log5; long active; Reg* p1; Reg* p2; Reg* p2link; Reg* s1; Reg* s2; Reg* link; Prog* prog; }; #define R ((Reg*)0) struct Renv { int safe; Node base; Node* saved; Node* scope; }; #define NRGN 600 struct Rgn { Reg* enter; short cost; short varno; short regno; }; EXTERN long breakpc; EXTERN long nbreak; EXTERN Case* cases; EXTERN Node constnode; EXTERN Node fconstnode; EXTERN long continpc; EXTERN long curarg; EXTERN long cursafe; EXTERN Prog* firstp; EXTERN Prog* lastp; EXTERN long maxargsafe; EXTERN int mnstring; EXTERN Node* nodrat; EXTERN Node* nodret; EXTERN Node* nodsafe; EXTERN long nrathole; EXTERN long nstring; EXTERN Prog* p; EXTERN long pc; EXTERN Node regnode; EXTERN Node fregnode0; EXTERN Node fregnode1; EXTERN char string[NSNAME]; EXTERN Sym* symrathole; EXTERN Node znode; EXTERN Prog zprog; EXTERN int reg[D_NONE]; EXTERN long exregoffset; EXTERN long exfregoffset; #define BLOAD(r) band(bnot(r->refbehind), r->refahead) #define BSTORE(r) band(bnot(r->calbehind), r->calahead) #define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z]) #define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z]) #define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32)) #define CLOAD 5 #define CREF 5 #define CINF 1000 #define LOOP 3 EXTERN Rgn region[NRGN]; EXTERN Rgn* rgp; EXTERN int nregion; EXTERN int nvar; EXTERN Bits externs; EXTERN Bits params; EXTERN Bits consts; EXTERN Bits addrs; EXTERN long regbits; EXTERN long exregbits; EXTERN int change; EXTERN int suppress; EXTERN Reg* firstr; EXTERN Reg* lastr; EXTERN Reg zreg; EXTERN Reg* freer; EXTERN Var var[NVAR]; EXTERN long* idom; EXTERN Reg** rpo2r; EXTERN long maxnr; extern char* anames[]; /* * sgen.c */ void codgen(Node*, Node*); void gen(Node*); void noretval(int); void usedset(Node*, int); void xcom(Node*); void indx(Node*); int bcomplex(Node*, Node*); /* * cgen.c */ void zeroregm(Node*); void cgen(Node*, Node*); void reglcgen(Node*, Node*, Node*); void lcgen(Node*, Node*); void bcgen(Node*, int); void boolgen(Node*, int, Node*); void sugen(Node*, Node*, long); int needreg(Node*, int); /* * cgen64.c */ int vaddr(Node*, int); void loadpair(Node*, Node*); int cgen64(Node*, Node*); void testv(Node*, int); /* * txt.c */ void ginit(void); void gclean(void); void nextpc(void); void gargs(Node*, Node*, Node*); void garg1(Node*, Node*, Node*, int, Node**); Node* nodconst(long); Node* nodfconst(double); int nodreg(Node*, Node*, int); int isreg(Node*, int); void regret(Node*, Node*); void regalloc(Node*, Node*, Node*); void regfree(Node*); void regialloc(Node*, Node*, Node*); void regsalloc(Node*, Node*); void regaalloc1(Node*, Node*); void regaalloc(Node*, Node*); void regind(Node*, Node*); void gprep(Node*, Node*); void naddr(Node*, Adr*); void gmove(Node*, Node*); void gins(int a, Node*, Node*); void fgopcode(int, Node*, Node*, int, int); void gopcode(int, Type*, Node*, Node*); int samaddr(Node*, Node*); void gbranch(int); void patch(Prog*, long); int sconst(Node*); void gpseudo(int, Sym*, Node*); /* * swt.c */ int swcmp(const void*, const void*); void doswit(Node*); void swit1(C1*, int, long, Node*); void casf(void); void bitload(Node*, Node*, Node*, Node*, Node*); void bitstore(Node*, Node*, Node*, Node*, Node*); long outstring(char*, long); void nullwarn(Node*, Node*); void sextern(Sym*, Node*, long, long); void gextern(Sym*, Node*, long, long); void outcode(void); void ieeedtod(Ieee*, double); /* * list */ void listinit(void); int Pconv(Fmt*); int Aconv(Fmt*); int Dconv(Fmt*); int Sconv(Fmt*); int Rconv(Fmt*); int Xconv(Fmt*); int Bconv(Fmt*); /* * reg.c */ Reg* rega(void); int rcmp(const void*, const void*); void regopt(Prog*); void addmove(Reg*, int, int, int); Bits mkvar(Reg*, Adr*); void prop(Reg*, Bits, Bits); void loopit(Reg*, long); void synch(Reg*, Bits); ulong allreg(ulong, Rgn*); void paint1(Reg*, int); ulong paint2(Reg*, int); void paint3(Reg*, int, long, int); void addreg(Adr*, int); /* * peep.c */ void peep(void); void excise(Reg*); Reg* uniqp(Reg*); Reg* uniqs(Reg*); int regtyp(Adr*); int anyvar(Adr*); int subprop(Reg*); int copyprop(Reg*); int copy1(Adr*, Adr*, Reg*, int); int copyu(Prog*, Adr*, Adr*); int copyas(Adr*, Adr*); int copyau(Adr*, Adr*); int copysub(Adr*, Adr*, Adr*, int); int copysub1(Prog*, Adr*, Adr*, int); long RtoB(int); long FtoB(int); int BtoR(long); int BtoF(long); #define D_HI D_NONE #define D_LO D_NONE /* * bound */ void comtarg(void); /* * com64 */ int cond(int); int com64(Node*); void com64init(void); void bool64(Node*); long lo64v(Node*); long hi64v(Node*); Node* lo64(Node*); Node* hi64(Node*); /* * div/mul */ void sdivgen(Node*, Node*, Node*, Node*); void udivgen(Node*, Node*, Node*, Node*); void sdiv2(long, int, Node*, Node*); void smod2(long, int, Node*, Node*); void mulgen(Type*, Node*, Node*); void genmuladd(Node*, Node*, int, Node*); void shiftit(Type*, Node*, Node*); #pragma varargck type "A" int #pragma varargck type "B" Bits #pragma varargck type "D" Adr* #pragma varargck type "P" Prog* #pragma varargck type "R" int #pragma varargck type "S" char* /* wrecklessly steal a field */ #define rplink label "BYTE", "CALL", "CLC", "CLD", "CLI", "CLTS", "CMC", "CMPB", "CMPL", "CMPW", "CMPSB", "CMPSL", "CMPSW", "DAA", "DAS", "DATA", "DECB", "DECL", "DECW", "DIVB", "DIVL", "DIVW", "ENTER", "GLOBL", "GOK", "8c/list.c 664 0 0 7607 7751017724 10201ustar00syssys#define EXTERN #include "gc.h" void listinit(void) { fmtinstall('A', Aconv); fmtinstall('B', Bconv); fmtinstall('P', Pconv); fmtinstall('S', Sconv); fmtinstall('D', Dconv); fmtinstall('R', Rconv); } int Bconv(Fmt *fp) { char str[STRINGSZ], ss[STRINGSZ], *s; Bits bits; int i; str[0] = 0; bits = va_arg(fp->args, Bits); while(bany(&bits)) { i = bnum(bits); if(str[0]) strcat(str, " "); if(var[i].sym == S) { sprint(ss, "$%ld", var[i].offset); s = ss; } else s = var[i].sym->name; if(strlen(str) + strlen(s) + 1 >= STRINGSZ) break; strcat(str, s); bits.b[i/32] &= ~(1L << (i%32)); } return fmtstrcpy(fp, str); } int Pconv(Fmt *fp) { char str[STRINGSZ]; Prog *p; p = va_arg(fp->args, Prog*); if(p->as == ADATA) sprint(str, " %A %D/%d,%D", p->as, &p->from, p->from.scale, &p->to); else if(p->as == ATEXT) sprint(str, " %A %D,%d,%D", p->as, &p->from, p->from.scale, &p->to); else sprint(str, " %A %D,%D", p->as, &p->from, &p->to); return fmtstrcpy(fp, str); } int Aconv(Fmt *fp) { int i; i = va_arg(fp->args, int); return fmtstrcpy(fp, anames[i]); } int Dconv(Fmt *fp) { char str[40], s[20]; Adr *a; int i; a = va_arg(fp->args, Adr*); i = a->type; if(i >= D_INDIR) { if(a->offset) sprint(str, "%ld(%R)", a->offset, i-D_INDIR); else sprint(str, "(%R)", i-D_INDIR); goto brk; } switch(i) { default: if(a->offset) sprint(str, "$%ld,%R", a->offset, i); else sprint(str, "%R", i); break; case D_NONE: str[0] = 0; break; case D_BRANCH: sprint(str, "%ld(PC)", a->offset-pc); break; case D_EXTERN: sprint(str, "%s+%ld(SB)", a->sym->name, a->offset); break; case D_STATIC: sprint(str, "%s<>+%ld(SB)", a->sym->name, a->offset); break; case D_AUTO: sprint(str, "%s+%ld(SP)", a->sym->name, a->offset); break; case D_PARAM: if(a->sym) sprint(str, "%s+%ld(FP)", a->sym->name, a->offset); else sprint(str, "%ld(FP)", a->offset); break; case D_CONST: sprint(str, "$%ld", a->offset); break; case D_FCONST: sprint(str, "$(%.17e)", a->dval); break; case D_SCONST: sprint(str, "$\"%S\"", a->sval); break; case D_ADDR: a->type = a->index; a->index = D_NONE; sprint(str, "$%D", a); a->index = a->type; a->type = D_ADDR; goto conv; } brk: if(a->index != D_NONE) { sprint(s, "(%R*%d)", (int)a->index, (int)a->scale); strcat(str, s); } conv: return fmtstrcpy(fp, str); } char* regstr[] = { "AL", /*[D_AL]*/ "CL", "DL", "BL", "AH", "CH", "DH", "BH", "AX", /*[D_AX]*/ "CX", "DX", "BX", "SP", "BP", "SI", "DI", "F0", /*[D_F0]*/ "F1", "F2", "F3", "F4", "F5", "F6", "F7", "CS", /*[D_CS]*/ "SS", "DS", "ES", "FS", "GS", "GDTR", /*[D_GDTR]*/ "IDTR", /*[D_IDTR]*/ "LDTR", /*[D_LDTR]*/ "MSW", /*[D_MSW] */ "TASK", /*[D_TASK]*/ "CR0", /*[D_CR]*/ "CR1", "CR2", "CR3", "CR4", "CR5", "CR6", "CR7", "DR0", /*[D_DR]*/ "DR1", "DR2", "DR3", "DR4", "DR5", "DR6", "DR7", "TR0", /*[D_TR]*/ "TR1", "TR2", "TR3", "TR4", "TR5", "TR6", "TR7", "NONE", /*[D_NONE]*/ }; int Rconv(Fmt *fp) { char str[20]; int r; r = va_arg(fp->args, int); if(r >= D_AL && r <= D_NONE) sprint(str, "%s", regstr[r-D_AL]); else sprint(str, "gok(%d)", r); return fmtstrcpy(fp, str); } int Sconv(Fmt *fp) { int i, c; char str[30], *p, *a; a = va_arg(fp->args, char*); p = str; for(i=0; i= '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); } char isv; }; #define C ((Case*)0) struct C1 { long val; long label; }; struct Var { long offset; Sym* sym; char na8c/machcap.c 664 0 0 2261 10073261354 10620ustar00syssys#include "gc.h" int machcap(Node *n) { // return 0; 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]) { // if(typev[n->type->etype] && n->right->op == OCONST) { // if(hi64v(n->right) == 0) return 1; } break; case OCOM: case ONEG: case OADD: case OAND: case OOR: case OSUB: case OXOR: case OASHL: case OLSHR: case OASHR: if(typechlv[n->left->type->etype]) return 1; break; case OCAST: if(typev[n->type->etype]) { if(typechlp[n->left->type->etype]) return 1; } else if(!typefd[n->type->etype]) { if(typev[n->left->type->etype]) return 1; } break; case OCOND: case OCOMMA: case OLIST: case OANDAND: case OOROR: case ONOT: return 1; case OASADD: case OASSUB: case OASAND: case OASOR: case OASXOR: return 1; case OASASHL: case OASASHR: case OASLSHR: return 1; case OPOSTINC: case OPOSTDEC: case OPREINC: case OPREDEC: return 1; case OEQ: case ONE: case OLE: case OGT: case OLT: case OGE: case OHI: case OHS: case OLO: case OLS: //print("%O\n", n->op); return 1; } return 0; } xregbits; 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*, in8c/mkenam 664 0 0 160 7024572332 10212ustar00syssysed - ../8c/8.out.h <<'!' v/^ A/d ,s/^ A/ "/ g/ .*$/s/// ,s/,*$/",/ 1i char* anames[] = { . $a }; . w enam.c Q ! 8c/mkfile 664 0 0 604 10411073200 10214ustar00syssys 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); } (Case*)0) struct C1 { long val; long label; }; struct Var { long offset; Sym* sym; char na8c/peep.c 664 0 0 25661 10411076203 10177ustar00syssys#include "gc.h" static int needc(Prog *p) { while(p != P) { switch(p->as) { case AADCL: case ASBBL: case ARCRL: return 1; case AADDL: case ASUBL: case AJMP: case ARET: case ACALL: return 0; default: if(p->to.type == D_BRANCH) return 0; } p = p->link; } return 0; } void peep(void) { Reg *r, *r1, *r2; Prog *p, *p1; int t; /* * complete R structure */ t = 0; for(r=firstr; r!=R; r=r1) { r1 = r->link; if(r1 == R) break; p = r->prog->link; while(p != r1->prog) switch(p->as) { default: r2 = rega(); r->link = r2; r2->link = r1; r2->prog = p; r2->p1 = r; r->s1 = r2; r2->s1 = r1; r1->p1 = r2; r = r2; t++; case ADATA: case AGLOBL: case ANAME: case ASIGNAME: p = p->link; } } pc = 0; /* speculating it won't kill */ loop1: if(debug['b']) comtarg(); t = 0; for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { case AMOVL: if(regtyp(&p->to)) if(regtyp(&p->from)) { if(copyprop(r)) { excise(r); t++; } if(subprop(r) && copyprop(r)) { excise(r); t++; } } break; case AMOVBLSX: case AMOVBLZX: case AMOVWLSX: case AMOVWLZX: if(regtyp(&p->to)) { r1 = uniqs(r); if(r1 != R) { p1 = r1->prog; if(p->as == p1->as && p->to.type == p1->from.type) p1->as = AMOVL; } } break; case AADDL: case AADDW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1){ if(p->as == AADDL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; } else if(p->from.offset == 1){ if(p->as == AADDL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; } break; case ASUBL: case ASUBW: if(p->from.type != D_CONST || needc(p->link)) break; if(p->from.offset == -1) { if(p->as == ASUBL) p->as = AINCL; else p->as = AINCW; p->from = zprog.from; } else if(p->from.offset == 1){ if(p->as == ASUBL) p->as = ADECL; else p->as = ADECW; p->from = zprog.from; } break; } } if(t) goto loop1; } void excise(Reg *r) { Prog *p; p = r->prog; p->as = ANOP; p->from = zprog.from; p->to = zprog.to; } Reg* uniqp(Reg *r) { Reg *r1; r1 = r->p1; if(r1 == R) { r1 = r->p2; if(r1 == R || r1->p2link != R) return R; } else if(r->p2 != R) return R; return r1; } Reg* uniqs(Reg *r) { Reg *r1; r1 = r->s1; if(r1 == R) { r1 = r->s2; if(r1 == R) return R; } else if(r->s2 != R) return R; return r1; } int regtyp(Adr *a) { int t; t = a->type; if(t >= D_AX && t <= D_DI) return 1; return 0; } /* * the idea is to substitute * one register for another * from one MOV to another * MOV a, R0 * ADD b, R0 / no use of R1 * MOV R0, R1 * would be converted to * MOV a, R1 * ADD b, R1 * MOV R1, R0 * hopefully, then the former or latter MOV * will be eliminated by copy propagation. */ int subprop(Reg *r0) { Prog *p; Adr *v1, *v2; Reg *r; int t; p = r0->prog; v1 = &p->from; if(!regtyp(v1)) return 0; v2 = &p->to; if(!regtyp(v2)) return 0; for(r=uniqp(r0); r!=R; r=uniqp(r)) { if(uniqs(r) == R) break; p = r->prog; switch(p->as) { case ACALL: return 0; case AIMULL: case AIMULW: if(p->to.type != D_NONE) break; case ADIVB: case ADIVL: case ADIVW: case AIDIVB: case AIDIVL: case AIDIVW: case AIMULB: case AMULB: case AMULL: case AMULW: case AROLB: case AROLL: case AROLW: case ARORB: case ARORL: case ARORW: case ASALB: case ASALL: case ASALW: case ASARB: case ASARL: case ASARW: case ASHLB: case ASHLL: case ASHLW: case ASHRB: case ASHRL: case ASHRW: case AREP: case AREPN: case ACWD: case ACDQ: case AMOVSL: case AFSTSW: return 0; case AMOVL: if(p->to.type == v1->type) goto gotit; break; } if(copyau(&p->from, v2) || copyau(&p->to, v2)) break; if(copysub(&p->from, v1, v2, 0) || copysub(&p->to, v1, v2, 0)) break; } return 0; gotit: copysub(&p->to, v1, v2, 1); if(debug['P']) { print("gotit: %D->%D\n%P", v1, v2, r->prog); if(p->from.type == v2->type) print(" excise"); print("\n"); } for(r=uniqs(r); r!=r0; r=uniqs(r)) { p = r->prog; copysub(&p->from, v1, v2, 1); copysub(&p->to, v1, v2, 1); if(debug['P']) print("%P\n", r->prog); } t = v1->type; v1->type = v2->type; v2->type = t; if(debug['P']) print("%P last\n", r->prog); return 1; } /* * The idea is to remove redundant copies. * v1->v2 F=0 * (use v2 s/v2/v1/)* * set v1 F=1 * use v2 return fail * ----------------- * v1->v2 F=0 * (use v2 s/v2/v1/)* * set v1 F=1 * set v2 return success */ int copyprop(Reg *r0) { Prog *p; Adr *v1, *v2; Reg *r; p = r0->prog; v1 = &p->from; v2 = &p->to; if(copyas(v1, v2)) return 1; for(r=firstr; r!=R; r=r->link) r->active = 0; return copy1(v1, v2, r0->s1, 0); } int copy1(Adr *v1, Adr *v2, Reg *r, int f) { int t; Prog *p; if(r->active) { if(debug['P']) print("act set; return 1\n"); return 1; } r->active = 1; if(debug['P']) print("copy %D->%D f=%d\n", v1, v2, f); for(; r != R; r = r->s1) { p = r->prog; if(debug['P']) print("%P", p); if(!f && uniqp(r) == R) { f = 1; if(debug['P']) print("; merge; f=%d", f); } t = copyu(p, v2, A); switch(t) { case 2: /* rar, cant split */ if(debug['P']) print("; %D rar; return 0\n", v2); return 0; case 3: /* set */ if(debug['P']) print("; %D set; return 1\n", v2); return 1; case 1: /* used, substitute */ case 4: /* use and set */ if(f) { if(!debug['P']) return 0; if(t == 4) print("; %D used+set and f=%d; return 0\n", v2, f); else print("; %D used and f=%d; return 0\n", v2, f); return 0; } if(copyu(p, v2, v1)) { if(debug['P']) print("; sub fail; return 0\n"); return 0; } if(debug['P']) print("; sub %D/%D", v2, v1); if(t == 4) { if(debug['P']) print("; %D used+set; return 1\n", v2); return 1; } break; } if(!f) { t = copyu(p, v1, A); if(!f && (t == 2 || t == 3 || t == 4)) { f = 1; if(debug['P']) print("; %D set and !f; f=%d", v1, f); } } if(debug['P']) print("\n"); if(r->s2) if(!copy1(v1, v2, r->s2, f)) return 0; } return 1; } /* * return * 1 if v only used (and substitute), * 2 if read-alter-rewrite * 3 if set * 4 if set and used * 0 otherwise (not touched) */ int copyu(Prog *p, Adr *v, Adr *s) { switch(p->as) { default: if(debug['P']) print("unknown op %A\n", p->as); return 2; case ANEGB: case ANEGW: case ANEGL: case ANOTB: case ANOTW: case ANOTL: if(copyas(&p->to, v)) return 2; break; case ALEAL: /* lhs addr, rhs store */ if(copyas(&p->from, v)) return 2; case ANOP: /* rhs store */ case AMOVL: case AMOVBLSX: case AMOVBLZX: case AMOVWLSX: case AMOVWLZX: if(copyas(&p->to, v)) { if(s != A) return copysub(&p->from, v, s, 1); if(copyau(&p->from, v)) return 4; return 3; } goto caseread; case AROLB: case AROLL: case AROLW: case ARORB: case ARORL: case ARORW: case ASALB: case ASALL: case ASALW: case ASARB: case ASARL: case ASARW: case ASHLB: case ASHLL: case ASHLW: case ASHRB: case ASHRL: case ASHRW: if(copyas(&p->to, v)) return 2; if(copyas(&p->from, v)) if(p->from.type == D_CX) return 2; goto caseread; case AADDB: /* rhs rar */ case AADDL: case AADDW: case AANDB: case AANDL: case AANDW: case ADECL: case ADECW: case AINCL: case AINCW: case ASUBB: case ASUBL: case ASUBW: case AORB: case AORL: case AORW: case AXORB: case AXORL: case AXORW: case AMOVB: case AMOVW: case AFMOVB: case AFMOVBP: case AFMOVD: case AFMOVDP: case AFMOVF: case AFMOVFP: case AFMOVL: case AFMOVLP: case AFMOVV: case AFMOVVP: case AFMOVW: case AFMOVWP: case AFMOVX: case AFMOVXP: case AFADDDP: case AFADDW: case AFADDL: case AFADDF: case AFADDD: case AFMULDP: case AFMULW: case AFMULL: case AFMULF: case AFMULD: case AFSUBDP: case AFSUBW: case AFSUBL: case AFSUBF: case AFSUBD: case AFSUBRDP: case AFSUBRW: case AFSUBRL: case AFSUBRF: case AFSUBRD: case AFDIVDP: case AFDIVW: case AFDIVL: case AFDIVF: case AFDIVD: case AFDIVRDP: case AFDIVRW: case AFDIVRL: case AFDIVRF: case AFDIVRD: if(copyas(&p->to, v)) return 2; goto caseread; case ACMPL: /* read only */ case ACMPW: case ACMPB: case AFCOMB: case AFCOMBP: case AFCOMD: case AFCOMDP: case AFCOMDPP: case AFCOMF: case AFCOMFP: case AFCOML: case AFCOMLP: case AFCOMW: case AFCOMWP: case AFUCOM: case AFUCOMP: case AFUCOMPP: caseread: if(s != A) { if(copysub(&p->from, v, s, 1)) return 1; return copysub(&p->to, v, s, 1); } if(copyau(&p->from, v)) return 1; if(copyau(&p->to, v)) return 1; break; case AJGE: /* no reference */ case AJNE: case AJLE: case AJEQ: case AJHI: case AJLS: case AJMI: case AJPL: case AJGT: case AJLT: case AJCC: case AJCS: case AADJSP: case AFLDZ: case AWAIT: break; case AIMULL: case AIMULW: if(p->to.type != D_NONE) { if(copyas(&p->to, v)) return 2; goto caseread; } case ADIVB: case ADIVL: case ADIVW: case AIDIVB: case AIDIVL: case AIDIVW: case AIMULB: case AMULB: case AMULL: case AMULW: case ACWD: case ACDQ: if(v->type == D_AX || v->type == D_DX) return 2; goto caseread; case AMOVSL: case AREP: case AREPN: if(v->type == D_CX || v->type == D_DI || v->type == D_SI) return 2; goto caseread; case AFSTSW: if(v->type == D_AX) return 2; goto caseread; case AJMP: /* funny */ if(s != A) { if(copysub(&p->to, v, s, 1)) return 1; return 0; } if(copyau(&p->to, v)) return 1; return 0; case ARET: /* funny */ if(v->type == REGRET) return 2; if(s != A) return 1; return 3; case ACALL: /* funny */ if(REGARG>=0 && v->type == REGARG) return 2; if(s != A) { if(copysub(&p->to, v, s, 1)) return 1; return 0; } if(copyau(&p->to, v)) return 4; return 3; } return 0; } /* * direct reference, * could be set/use depending on * semantics */ int copyas(Adr *a, Adr *v) { if(a->type != v->type) return 0; if(regtyp(v)) return 1; if(v->type == D_AUTO || v->type == D_PARAM) if(v->offset == a->offset) return 1; return 0; } /* * either direct or indirect */ int copyau(Adr *a, Adr *v) { if(copyas(a, v)) return 1; if(regtyp(v)) { if(a->type-D_INDIR == v->type) return 1; if(a->index == v->type) return 1; } return 0; } /* * substitute s for v in a * return failure to substitute */ int copysub(Adr *a, Adr *v, Adr *s, int f) { int t; if(copyas(a, v)) { t = s->type; if(t >= D_AX && t <= D_DI) { if(f) a->type = t; } return 0; } if(regtyp(v)) { t = v->type; if(a->type == t+D_INDIR) { if(s->type == D_BP && a->index != D_NONE) return 1; /* can't use BP-base with index */ if(f) a->type = s->type+D_INDIR; // return 0; } if(a->index == t) { if(f) a->index = s->type; return 0; } return 0; } return 0; } ase AMOVL: if(regtyp(&p->to)) if(regtyp(&p->from)) { if(copyprop(r)) 8c/reg.c 664 0 0 50134 10227773460 10032ustar00syssys#include "gc.h" Reg* rega(void) { Reg *r; r = freer; if(r == R) { r = alloc(sizeof(*r)); } else freer = r->link; *r = zreg; return r; } int rcmp(const void *a1, const void *a2) { Rgn *p1, *p2; int c1, c2; p1 = (Rgn*)a1; p2 = (Rgn*)a2; c1 = p2->cost; c2 = p1->cost; if(c1 -= c2) return c1; return p2->varno - p1->varno; } void regopt(Prog *p) { Reg *r, *r1, *r2; Prog *p1; int i, z; long initpc, val, npc; ulong vreg; Bits bit; struct { long m; long c; Reg* p; } log5[6], *lp; firstr = R; lastr = R; nvar = 0; regbits = RtoB(D_SP) | RtoB(D_AX); for(z=0; 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: r->p1 = R; r1->s1 = R; } bit = mkvar(r, &p->from); if(bany(&bit)) switch(p->as) { /* * funny */ case ALEAL: 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 ACMPW: for(z=0; zuse2.b[z] |= bit.b[z]; break; /* * right side write */ case ANOP: case AMOVL: case AMOVB: case AMOVW: case AMOVBLSX: case AMOVBLZX: case AMOVWLSX: case AMOVWLZX: for(z=0; zset.b[z] |= bit.b[z]; break; /* * right side read+write */ case AADDB: case AADDL: case AADDW: case AANDB: case AANDL: case AANDW: case ASUBB: case ASUBL: case ASUBW: case AORB: case AORL: case AORW: case AXORB: case AXORL: case AXORW: case ASALB: case ASALL: case ASALW: case ASARB: case ASARL: case ASARW: case AROLB: case AROLL: case AROLW: case ARORB: case ARORL: case ARORW: case ASHLB: case ASHLL: case ASHLW: case ASHRB: case ASHRL: case ASHRW: case AIMULL: case AIMULW: case ANEGL: case ANOTL: case AADCL: case ASBBL: for(z=0; zset.b[z] |= bit.b[z]; r->use2.b[z] |= bit.b[z]; } break; /* * funny */ case AFMOVDP: case AFMOVFP: case AFMOVVP: case ACALL: for(z=0; zas) { case AIMULL: case AIMULW: if(p->to.type != D_NONE) break; case AIDIVB: case AIDIVL: case AIDIVW: case AIMULB: case ADIVB: case ADIVL: case ADIVW: case AMULB: case AMULL: case AMULW: case ACWD: case ACDQ: r->regu |= RtoB(D_AX) | RtoB(D_DX); break; case AREP: case AREPN: case ALOOP: case ALOOPEQ: case ALOOPNE: r->regu |= RtoB(D_CX); break; case AMOVSB: case AMOVSL: case AMOVSW: case ACMPSB: case ACMPSL: case ACMPSW: r->regu |= RtoB(D_SI) | RtoB(D_DI); break; case ASTOSB: case ASTOSL: case ASTOSW: case ASCASB: case ASCASL: case ASCASW: r->regu |= RtoB(D_AX) | RtoB(D_DI); break; case AINSB: case AINSL: case AINSW: case AOUTSB: case AOUTSL: case AOUTSW: r->regu |= RtoB(D_DI) | RtoB(D_DX); break; case AFSTSW: case ASAHF: r->regu |= RtoB(D_AX); break; } } if(firstr == R) return; initpc = pc - val; npc = val; /* * pass 2 * turn branch references to pointers * build back pointers */ for(r = firstr; r != R; r = r->link) { p = r->prog; if(p->to.type == D_BRANCH) { val = p->to.offset - initpc; r1 = firstr; while(r1 != R) { r2 = r1->log5; if(r2 != R && val >= r2->pc) { r1 = r2; continue; } if(r1->pc == val) break; r1 = r1->link; } if(r1 == R) { nearln = p->lineno; diag(Z, "ref not found\n%P", p); continue; } if(r1 == r) { nearln = p->lineno; diag(Z, "ref to self\n%P", p); continue; } r->s2 = r1; r->p2link = r1->p2; r1->p2 = r; } } if(debug['R']) { p = firstr->prog; print("\n%L %D\n", p->lineno, &p->from); } /* * pass 2.5 * find looping structure */ for(r = firstr; r != R; r = r->link) r->active = 0; change = 0; loopit(firstr, npc); if(debug['R'] && debug['v']) { print("\nlooping structure:\n"); for(r = firstr; r != R; r = r->link) { print("%ld:%P", r->loop, r->prog); for(z=0; 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; p1->from.type = rn; if(!f) { p1->from = *a; *a = zprog.from; a->type = rn; if(v->etype == TUCHAR) p1->as = AMOVB; if(v->etype == TUSHORT) p1->as = AMOVW; } if(debug['R']) print("%P\t.a%P\n", p, p1); } ulong doregbits(int r) { ulong b; b = 0; if(r >= D_INDIR) r -= D_INDIR; if(r >= D_AX && r <= D_DI) b |= RtoB(r); else if(r >= D_AL && r <= D_BL) b |= RtoB(r-D_AL+D_AX); else if(r >= D_AH && r <= D_BH) b |= RtoB(r-D_AH+D_AX); return b; } Bits mkvar(Reg *r, Adr *a) { Var *v; int i, t, n, et, z; long o; Bits bit; Sym *s; /* * mark registers used */ t = a->type; r->regu |= doregbits(t); r->regu |= doregbits(a->index); switch(t) { default: goto none; case D_ADDR: a->type = a->index; bit = mkvar(r, a); for(z=0; 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]) /* 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 TIND: case TARRAY: i = BtoR(~b); if(i && r->cost > 0) { r->regno = i; return RtoB(i); } break; case TDOUBLE: case TFLOAT: break; } return 0; } void paint1(Reg *r, int bn) { Reg *r1; Prog *p; int z; ulong bb; z = bn/32; bb = 1L<<(bn%32); if(r->act.b[z] & bb) return; for(;;) { if(!(r->refbehind.b[z] & bb)) break; r1 = r->p1; if(r1 == R) break; if(!(r1->refahead.b[z] & bb)) break; if(r1->act.b[z] & bb) break; r = r1; } if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) { change -= CLOAD * r->loop; if(debug['R'] && debug['v']) print("%ld%P\tld %B $%d\n", r->loop, r->prog, blsh(bn), change); } for(;;) { r->act.b[z] |= bb; p = r->prog; if(r->use1.b[z] & bb) { change += CREF * r->loop; if(p->as == AFMOVL) if(BtoR(bb) != D_F0) change = -CINF; if(debug['R'] && debug['v']) print("%ld%P\tu1 %B $%d\n", r->loop, p, blsh(bn), change); } if((r->use2.b[z]|r->set.b[z]) & bb) { change += CREF * r->loop; if(p->as == AFMOVL) if(BtoR(bb) != D_F0) change = -CINF; if(debug['R'] && debug['v']) print("%ld%P\tu2 %B $%d\n", r->loop, p, blsh(bn), change); } if(STORE(r) & r->regdiff.b[z] & bb) { change -= CLOAD * r->loop; if(p->as == AFMOVL) if(BtoR(bb) != D_F0) change = -CINF; if(debug['R'] && debug['v']) print("%ld%P\tst %B $%d\n", r->loop, p, blsh(bn), change); } if(r->refbehind.b[z] & bb) for(r1 = r->p2; r1 != R; r1 = r1->p2link) if(r1->refahead.b[z] & bb) paint1(r1, bn); if(!(r->refahead.b[z] & bb)) break; r1 = r->s2; if(r1 != R) if(r1->refbehind.b[z] & bb) paint1(r1, bn); r = r->s1; if(r == R) break; if(r->act.b[z] & bb) break; if(!(r->refbehind.b[z] & bb)) break; } } ulong regset(Reg *r, ulong bb) { ulong b, set; Adr v; int c; set = 0; v = zprog.from; while(b = bb & ~(bb-1)) { v.type = BtoR(b); c = copyu(r->prog, &v, A); if(c == 3) set |= b; bb &= ~b; } return set; } ulong reguse(Reg *r, ulong bb) { ulong b, set; Adr v; int c; set = 0; v = zprog.from; while(b = bb & ~(bb-1)) { v.type = BtoR(b); c = copyu(r->prog, &v, A); if(c == 1 || c == 2 || c == 4) set |= b; bb &= ~b; } return set; } ulong paint2(Reg *r, int bn) { Reg *r1; int z; ulong bb, vreg, x; z = bn/32; bb = 1L << (bn%32); vreg = regbits; if(!(r->act.b[z] & bb)) return vreg; for(;;) { if(!(r->refbehind.b[z] & bb)) break; r1 = r->p1; if(r1 == R) break; if(!(r1->refahead.b[z] & bb)) break; if(!(r1->act.b[z] & bb)) break; r = r1; } for(;;) { r->act.b[z] &= ~bb; vreg |= r->regu; if(r->refbehind.b[z] & bb) for(r1 = r->p2; r1 != R; r1 = r1->p2link) if(r1->refahead.b[z] & bb) vreg |= paint2(r1, bn); if(!(r->refahead.b[z] & bb)) break; r1 = r->s2; if(r1 != R) if(r1->refbehind.b[z] & bb) vreg |= paint2(r1, bn); r = r->s1; if(r == R) break; if(!(r->act.b[z] & bb)) break; if(!(r->refbehind.b[z] & bb)) break; } bb = vreg; for(; r; r=r->s1) { x = r->regu & ~bb; if(x) { vreg |= reguse(r, x); bb |= regset(r, x); } } return vreg; } void paint3(Reg *r, int bn, long rb, int rn) { Reg *r1; Prog *p; int z; ulong bb; z = bn/32; bb = 1L << (bn%32); if(r->act.b[z] & bb) return; for(;;) { if(!(r->refbehind.b[z] & bb)) break; r1 = r->p1; if(r1 == R) break; if(!(r1->refahead.b[z] & bb)) break; if(r1->act.b[z] & bb) break; r = r1; } if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) addmove(r, bn, rn, 0); for(;;) { r->act.b[z] |= bb; p = r->prog; if(r->use1.b[z] & bb) { if(debug['R']) print("%P", p); addreg(&p->from, rn); if(debug['R']) print("\t.c%P\n", p); } if((r->use2.b[z]|r->set.b[z]) & bb) { if(debug['R']) print("%P", p); addreg(&p->to, rn); if(debug['R']) print("\t.c%P\n", p); } if(STORE(r) & r->regdiff.b[z] & bb) addmove(r, bn, rn, 1); r->regu |= rb; if(r->refbehind.b[z] & bb) for(r1 = r->p2; r1 != R; r1 = r1->p2link) if(r1->refahead.b[z] & bb) paint3(r1, bn, rb, rn); if(!(r->refahead.b[z] & bb)) break; r1 = r->s2; if(r1 != R) if(r1->refbehind.b[z] & bb) paint3(r1, bn, rb, rn); r = r->s1; if(r == R) break; if(r->act.b[z] & bb) break; if(!(r->refbehind.b[z] & bb)) break; } } void addreg(Adr *a, int rn) { a->sym = 0; a->offset = 0; a->type = rn; } long RtoB(int r) { if(r < D_AX || r > D_DI) return 0; return 1L << (r-D_AX); } int BtoR(long b) { b &= 0xffL; if(b == 0) return 0; return bitno(b) + D_AX; } * * 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] == '.') 8c/sgen.c 664 0 0 14565 10411076203 10203ustar00syssys#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; } if((n&3) == 3) if(thisfn && thisfn->link && typefd[thisfn->link->etype]) gins(AFLDZ, Z, Z); } /* welcome to commute */ static void commute(Node *n) { Node *l, *r; l = n->left; r = n->right; if(r->complex > l->complex) { n->left = r; n->right = l; } } void indexshift(Node *n) { int g; if(!typechlp[n->type->etype]) return; simplifyshift(n); if(n->op == OASHL && n->right->op == OCONST){ g = vconst(n->right); if(g >= 0 && g < 4) n->addable = 7; } } /* * calculate addressability as follows * NAME ==> 10/11 name+value(SB/SP) * REGISTER ==> 12 register * CONST ==> 20 $value * *(20) ==> 21 value * &(10) ==> 13 $name+value(SB) * &(11) ==> 1 $name+value(SP) * (13) + (20) ==> 13 fold constants * (1) + (20) ==> 1 fold constants * *(13) ==> 10 back to name * *(1) ==> 11 back to name * * (20) * (X) ==> 7 multiplier in indexing * (X,7) + (13,1) ==> 8 adder in indexing (addresses) * (8) ==> &9(OINDEX) index, almost addressable * * calculate complexity (number of registers) */ void xcom(Node *n) { Node *l, *r; int g; if(n == Z) return; l = n->left; r = n->right; n->complex = 0; n->addable = 0; switch(n->op) { case OCONST: n->addable = 20; break; case ONAME: n->addable = 10; if(n->class == CPARAM || n->class == CAUTO) n->addable = 11; break; case OREGISTER: n->addable = 12; break; case OINDREG: n->addable = 12; break; case OADDR: xcom(l); if(l->addable == 10) n->addable = 13; else if(l->addable == 11) n->addable = 1; break; case OADD: xcom(l); xcom(r); if(n->type->etype != TIND) break; switch(r->addable) { case 20: switch(l->addable) { case 1: case 13: commadd: l->type = n->type; *n = *l; l = new(0, Z, Z); *l = *(n->left); l->xoffset += r->vconst; n->left = l; r = n->right; goto brk; } break; case 1: case 13: case 10: case 11: /* l is the base, r is the index */ if(l->addable != 20) n->addable = 8; break; } switch(l->addable) { case 20: switch(r->addable) { case 13: case 1: r = n->left; l = n->right; n->left = l; n->right = r; goto commadd; } break; case 13: case 1: case 10: case 11: /* r is the base, l is the index */ if(r->addable != 20) n->addable = 8; break; } if(n->addable == 8 && !side(n)) { indx(n); l = new1(OINDEX, idx.basetree, idx.regtree); l->scale = idx.scale; l->addable = 9; l->complex = l->right->complex; l->type = l->left->type; n->op = OADDR; n->left = l; n->right = Z; n->addable = 8; break; } break; case OINDEX: xcom(l); xcom(r); n->addable = 9; break; case OIND: xcom(l); if(l->op == OADDR) { l = l->left; l->type = n->type; *n = *l; return; } switch(l->addable) { case 20: n->addable = 21; break; case 1: n->addable = 11; break; case 13: n->addable = 10; break; } break; case OASHL: xcom(l); xcom(r); indexshift(n); break; case OMUL: case OLMUL: xcom(l); xcom(r); g = vlog(l); if(g >= 0) { n->left = r; n->right = l; l = r; r = n->right; } g = vlog(r); if(g >= 0) { n->op = OASHL; r->vconst = g; r->type = types[TINT]; indexshift(n); break; } commute(n); break; case OASLDIV: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OASLSHR; r->vconst = g; r->type = types[TINT]; } break; case OLDIV: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OLSHR; r->vconst = g; r->type = types[TINT]; indexshift(n); break; } break; case OASLMOD: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OASAND; r->vconst--; } break; case OLMOD: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OAND; r->vconst--; } break; case OASMUL: case OASLMUL: xcom(l); xcom(r); g = vlog(r); if(g >= 0) { n->op = OASASHL; r->vconst = g; } break; case OLSHR: case OASHR: xcom(l); xcom(r); indexshift(n); break; default: if(l != Z) xcom(l); if(r != Z) xcom(r); break; } brk: if(n->addable >= 10) return; if(l != Z) n->complex = l->complex; if(r != Z) { if(r->complex == n->complex) n->complex = r->complex+1; else if(r->complex > n->complex) n->complex = r->complex; } if(n->complex == 0) n->complex++; if(com64(n)) return; switch(n->op) { case OFUNC: n->complex = FNX; break; case OLMOD: case OMOD: case OLMUL: case OLDIV: case OMUL: case ODIV: case OASLMUL: case OASLDIV: case OASLMOD: case OASMUL: case OASDIV: case OASMOD: if(r->complex >= l->complex) { n->complex = l->complex + 3; if(r->complex > n->complex) n->complex = r->complex; } else { n->complex = r->complex + 3; if(l->complex > n->complex) n->complex = l->complex; } break; case OLSHR: case OASHL: case OASHR: case OASLSHR: case OASASHL: case OASASHR: if(r->complex >= l->complex) { n->complex = l->complex + 2; if(r->complex > n->complex) n->complex = r->complex; } else { n->complex = r->complex + 2; if(l->complex > n->complex) n->complex = l->complex; } break; case OADD: case OXOR: case OAND: case OOR: /* * immediate operators, make const on right */ if(l->op == OCONST) { n->left = r; n->right = l; } break; case OEQ: case ONE: case OLE: case OLT: case OGE: case OGT: case OHI: case OHS: case OLO: case OLS: /* * compare operators, make const on left */ if(r->op == OCONST) { n->left = r; n->right = l; n->op = invrel[relindex(n->op)]; } break; } } void indx(Node *n) { Node *l, *r; if(debug['x']) prtree(n, "indx"); l = n->left; r = n->right; if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) { n->right = l; n->left = r; l = r; r = n->right; } if(l->addable != 7) { idx.regtree = l; idx.scale = 1; } else if(l->right->addable == 20) { idx.regtree = l->left; idx.scale = 1 << l->right->vconst; } else if(l->left->addable == 20) { idx.regtree = l->right; idx.scale = 1 << l->left->vconst; } else diag(n, "bad index"); idx.basetree = r; if(debug['x']) { print("scale = %d\n", idx.scale); prtree(idx.regtree, "index"); prtree(idx.basetree, "base"); } } c; set = 0; v = zprog.from; while(b = bb & ~(bb-1)) { v.type = BtoR(b); c = copyu(r->prog, &v, A); if(c == 3) set |= b; bb &8c/swt.c 664 0 0 21476 10411525327 10071ustar00syssys#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); gopcode(OEQ, n->type, n, nodconst(q->val)); patch(p, q->label); q++; } gbranch(OGOTO); patch(p, def); return; } i = nc / 2; r = q+i; if(debug['W']) print("case > %.8lux\n", r->val); gopcode(OGT, n->type, n, nodconst(r->val)); sp = p; gbranch(OGOTO); p->as = AJEQ; patch(p, r->label); swit1(q, i, def, n); if(debug['W']) print("case < %.8lux\n", r->val); patch(sp, pc); swit1(r+1, nc-i-1, def, n); } void bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) { int sh; long v; Node *l; /* * n1 gets adjusted/masked value * n2 gets address of cell * n3 gets contents of cell */ l = b->left; if(n2 != Z) { regalloc(n1, l, nn); reglcgen(n2, l, Z); regalloc(n3, l, Z); gmove(n2, n3); gmove(n3, n1); } else { regalloc(n1, l, nn); cgen(l, n1); } if(b->type->shift == 0 && typeu[b->type->etype]) { v = ~0 + (1L << b->type->nbits); gopcode(OAND, types[TLONG], nodconst(v), n1); } else { sh = 32 - b->type->shift - b->type->nbits; if(sh > 0) gopcode(OASHL, types[TLONG], nodconst(sh), n1); sh += b->type->shift; if(sh > 0) if(typeu[b->type->etype]) gopcode(OLSHR, types[TLONG], nodconst(sh), n1); else gopcode(OASHR, types[TLONG], nodconst(sh), n1); } } void bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) { long v; Node nod; int sh; regalloc(&nod, b->left, Z); v = ~0 + (1L << b->type->nbits); gopcode(OAND, types[TLONG], nodconst(v), n1); gmove(n1, &nod); if(nn != Z) gmove(n1, nn); sh = b->type->shift; if(sh > 0) gopcode(OASHL, types[TLONG], nodconst(sh), &nod); v <<= sh; gopcode(OAND, types[TLONG], nodconst(~v), n3); gopcode(OOR, types[TLONG], n3, &nod); gmove(&nod, n2); regfree(&nod); regfree(n1); regfree(n2); regfree(n3); } long outstring(char *s, long n) { long r; if(suppress) return nstring; r = nstring; while(n) { string[mnstring] = *s++; mnstring++; nstring++; if(mnstring >= NSNAME) { gpseudo(ADATA, symstring, nodconst(0L)); p->from.offset += nstring - NSNAME; p->from.scale = NSNAME; p->to.type = D_SCONST; memmove(p->to.sval, string, NSNAME); mnstring = 0; } n--; } return r; } 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(a->op == OCONST && typev[a->type->etype]) { gpseudo(ADATA, s, lo64(a)); p->from.offset += o; p->from.scale = 4; gpseudo(ADATA, s, hi64(a)); p->from.offset += o + 4; p->from.scale = 4; return; } gpseudo(ADATA, s, a); p->from.offset += o; p->from.scale = w; switch(p->to.type) { default: p->to.index = p->to.type; p->to.type = D_ADDR; case D_CONST: case D_FCONST: case D_ADDR: break; } } void zname(Biobuf*, Sym*, int); void zaddr(Biobuf*, Adr*, int); void outhist(Biobuf*); void outcode(void) { struct { Sym *sym; short type; } h[NSYM]; Prog *p; Sym *s; int f, sf, st, t, sym; Biobuf b; if(debug['S']) { for(p = firstp; p != P; p = p->link) if(p->as != ADATA && p->as != AGLOBL) pc--; for(p = firstp; p != P; p = p->link) { print("%P\n", p); if(p->as != ADATA && p->as != AGLOBL) pc++; } } f = open(outfile, OWRITE); if(f < 0) { diag(Z, "cannot open %s", outfile); return; } Binit(&b, f, OWRITE); Bseek(&b, 0L, 2); outhist(&b); for(sym=0; symlink) { jackpot: sf = 0; s = p->from.sym; while(s != S) { sf = s->sym; if(sf < 0 || sf >= NSYM) sf = 0; t = p->from.type; if(t == D_ADDR) t = p->from.index; if(h[sf].type == t) if(h[sf].sym == s) break; s->sym = sym; zname(&b, s, t); h[sym].sym = s; h[sym].type = t; sf = sym; sym++; if(sym >= NSYM) sym = 1; break; } st = 0; s = p->to.sym; while(s != S) { st = s->sym; if(st < 0 || st >= NSYM) st = 0; t = p->to.type; if(t == D_ADDR) t = p->to.index; if(h[st].type == t) if(h[st].sym == s) break; s->sym = sym; zname(&b, s, t); h[sym].sym = s; h[sym].type = t; st = sym; sym++; if(sym >= NSYM) sym = 1; if(st == sf) goto jackpot; break; } Bputc(&b, p->as); Bputc(&b, p->as>>8); Bputc(&b, p->lineno); Bputc(&b, p->lineno>>8); Bputc(&b, p->lineno>>16); Bputc(&b, p->lineno>>24); zaddr(&b, &p->from, sf); zaddr(&b, &p->to, st); } Bflush(&b); close(f); firstp = P; lastp = P; } void outhist(Biobuf *b) { Hist *h; char *p, *q, *op, c; Prog pg; int n; pg = zprog; pg.as = AHISTORY; c = pathchar(); for(h = hist; h != H; h = h->link) { p = h->name; op = 0; /* on windows skip drive specifier in pathname */ if(systemtype(Windows) && p && p[1] == ':'){ p += 2; c = *p; } if(p && p[0] != c && h->offset == 0 && pathname){ /* on windows skip drive specifier in pathname */ if(systemtype(Windows) && pathname[1] == ':') { op = p; p = pathname+2; c = *p; } else if(pathname[0] == c){ op = p; p = pathname; } } while(p) { q = utfrune(p, c); if(q) { n = q-p; if(n == 0){ n = 1; /* leading "/" */ *p = '/'; /* don't emit "\" on windows */ } q++; } else { n = strlen(p); q = 0; } if(n) { Bputc(b, ANAME); Bputc(b, ANAME>>8); Bputc(b, D_FILE); Bputc(b, 1); Bputc(b, '<'); Bwrite(b, p, n); Bputc(b, 0); } p = q; if(p == 0 && op) { p = op; op = 0; } } pg.lineno = h->line; pg.to.type = zprog.to.type; pg.to.offset = h->offset; if(h->offset) pg.to.type = D_CONST; Bputc(b, pg.as); Bputc(b, pg.as>>8); Bputc(b, pg.lineno); Bputc(b, pg.lineno>>8); Bputc(b, pg.lineno>>16); Bputc(b, pg.lineno>>24); zaddr(b, &pg.from, 0); zaddr(b, &pg.to, 0); } } void zname(Biobuf *b, Sym *s, int t) { char *n; ulong sig; if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ sig = sign(s); Bputc(b, ASIGNAME); Bputc(b, ASIGNAME>>8); Bputc(b, sig); Bputc(b, sig>>8); Bputc(b, sig>>16); Bputc(b, sig>>24); s->sig = SIGDONE; } else{ Bputc(b, ANAME); /* as */ Bputc(b, ANAME>>8); /* as */ } Bputc(b, t); /* type */ Bputc(b, s->sym); /* sym */ n = s->name; while(*n) { Bputc(b, *n); n++; } Bputc(b, 0); } void zaddr(Biobuf *b, Adr *a, int s) { long l; int i, t; char *n; Ieee e; t = 0; if(a->index != D_NONE || a->scale != 0) t |= T_INDEX; if(s != 0) t |= T_SYM; switch(a->type) { default: t |= T_TYPE; case D_NONE: if(a->offset != 0) t |= T_OFFSET; break; case D_FCONST: t |= T_FCONST; break; case D_SCONST: t |= T_SCONST; break; } Bputc(b, t); if(t & T_INDEX) { /* implies index, scale */ Bputc(b, a->index); Bputc(b, a->scale); } if(t & T_OFFSET) { /* implies offset */ l = a->offset; Bputc(b, l); Bputc(b, l>>8); Bputc(b, l>>16); Bputc(b, l>>24); } if(t & T_SYM) /* implies sym */ Bputc(b, s); if(t & T_FCONST) { ieeedtod(&e, a->dval); l = e.l; Bputc(b, l); Bputc(b, l>>8); Bputc(b, l>>16); Bputc(b, l>>24); l = e.h; Bputc(b, l); Bputc(b, l>>8); Bputc(b, l>>16); Bputc(b, l>>24); return; } if(t & T_SCONST) { n = a->sval; for(i=0; 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_LONG; if(packflg) w = packflg; break; case Ael1: /* initial allign of struct element */ for(v=t; v->etype==TARRAY; v=v->link) ; w = ewidth[v->etype]; if(w <= 0 || w >= SZ_LONG) w = SZ_LONG; if(packflg) w = packflg; break; case Ael2: /* width of a struct element */ o += t->width; break; case Aarg0: /* initial passbyptr argument in arg list */ if(typesuv[t->etype]) { o = align(o, types[TIND], Aarg1); o = align(o, types[TIND], Aarg2); } break; case Aarg1: /* initial allign of parameter */ w = ewidth[t->etype]; if(w <= 0 || w >= SZ_LONG) { w = SZ_LONG; break; } w = 1; /* little endian no adjustment */ break; case Aarg2: /* width of a parameter */ o += t->width; w = SZ_LONG; break; case Aaut3: /* total allign of automatic */ o = align(o, t, Ael1); o = align(o, t, Ael2); break; } o = round(o, w); if(debug['A']) print("align %s %ld %T = %ld\n", bnames[op], i, t, o); return o; } long maxround(long max, long v) { v += SZ_LONG-1; if(v > max) max = round(v, SZ_LONG); return max; } t; 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; } 8c/txt.c 664 0 0 56477 11510377623 10111ustar00syssys#include "gc.h" void ginit(void) { int i; Type *t; thechar = '8'; thestring = "386"; exregoffset = 0; exfregoffset = 0; listinit(); nstring = 0; mnstring = 0; nrathole = 0; pc = 0; breakpc = -1; continpc = -1; cases = C; firstp = P; lastp = P; tfield = types[TLONG]; zprog.link = P; zprog.as = AGOK; zprog.from.type = D_NONE; zprog.from.index = D_NONE; zprog.from.scale = 0; zprog.to = zprog.from; regnode.op = OREGISTER; regnode.class = CEXREG; regnode.reg = REGTMP; regnode.complex = 0; regnode.addable = 11; regnode.type = types[TLONG]; fregnode0 = regnode; fregnode0.reg = D_F0; fregnode0.type = types[TDOUBLE]; fregnode1 = fregnode0; fregnode1.reg = D_F0+1; constnode.op = OCONST; constnode.class = CXXX; constnode.complex = 0; constnode.addable = 20; constnode.type = types[TLONG]; fconstnode.op = OCONST; fconstnode.class = CXXX; fconstnode.complex = 0; fconstnode.addable = 20; fconstnode.type = types[TDOUBLE]; nodsafe = new(ONAME, Z, Z); nodsafe->sym = slookup(".safe"); nodsafe->type = types[TINT]; nodsafe->etype = types[TINT]->etype; nodsafe->class = CAUTO; complex(nodsafe); t = typ(TARRAY, types[TCHAR]); symrathole = slookup(".rathole"); symrathole->class = CGLOBL; symrathole->type = t; nodrat = new(ONAME, Z, Z); nodrat->sym = symrathole; nodrat->type = types[TIND]; nodrat->etype = TVOID; nodrat->class = CGLOBL; complex(nodrat); nodrat->type = t; nodret = new(ONAME, Z, Z); nodret->sym = slookup(".ret"); nodret->type = types[TIND]; nodret->etype = TIND; nodret->class = CPARAM; nodret = new(OIND, nodret, Z); complex(nodret); com64init(); for(i=0; i= D_AX && i <= D_DI && i != D_SP) reg[i] = 0; } } void gclean(void) { int i; Sym *s; reg[D_SP]--; for(i=D_AX; i<=D_DI; i++) if(reg[i]) diag(Z, "reg %R left allocated", i); while(mnstring) outstring("", 1L); symstring->type->width = nstring; symrathole->type->width = nrathole; for(i=0; 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_DI; i++) if(reg[i] == 0) n++; return n; } void garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp) { Node nod; if(n == Z) return; if(n->op == OLIST) { garg1(n->left, tn1, tn2, f, fnxp); garg1(n->right, tn1, tn2, f, fnxp); return; } if(f == 0) { if(n->complex >= FNX) { regsalloc(*fnxp, n); nod = znode; nod.op = OAS; nod.left = *fnxp; nod.right = n; nod.type = n->type; cgen(&nod, Z); (*fnxp)++; } return; } if(typesu[n->type->etype] || typev[n->type->etype]) { regaalloc(tn2, n); if(n->complex >= FNX) { sugen(*fnxp, tn2, n->type->width); (*fnxp)++; } else sugen(n, tn2, n->type->width); return; } if(REGARG>=0 && curarg == 0 && typeilp[n->type->etype]) { regaalloc1(tn1, n); if(n->complex >= FNX) { cgen(*fnxp, tn1); (*fnxp)++; } else cgen(n, tn1); return; } if(vconst(n) == 0) { regaalloc(tn2, n); gmove(n, tn2); return; } regalloc(tn1, n, Z); if(n->complex >= FNX) { cgen(*fnxp, tn1); (*fnxp)++; } else cgen(n, tn1); regaalloc(tn2, n); gmove(tn1, tn2); regfree(tn1); } Node* nodconst(long v) { constnode.vconst = v; return &constnode; } Node* nodfconst(double d) { fconstnode.fconst = d; return &fconstnode; } int isreg(Node *n, int r) { if(n->op == OREGISTER) if(n->reg == r) return 1; return 0; } int nodreg(Node *n, Node *nn, int r) { *n = regnode; n->reg = r; if(reg[r] == 0) return 0; if(nn != Z) { n->type = nn->type; n->lineno = nn->lineno; if(nn->op == OREGISTER) if(nn->reg == r) return 0; } return 1; } void regret(Node *n, Node *nn) { int r; r = REGRET; if(typefd[nn->type->etype]) r = FREGRET; nodreg(n, nn, r); reg[r]++; } void regalloc(Node *n, Node *tn, Node *o) { int i; switch(tn->type->etype) { case TCHAR: case TUCHAR: case TSHORT: case TUSHORT: case TINT: case TUINT: case TLONG: case TULONG: case TIND: if(o != Z && o->op == OREGISTER) { i = o->reg; if(i >= D_AX && i <= D_DI) goto out; } for(i=D_AX; i<=D_DI; i++) if(reg[i] == 0) goto out; fatal(tn, "out of fixed registers"); goto err; case TFLOAT: case TDOUBLE: case TVLONG: i = D_F0; goto out; } diag(tn, "unknown type in regalloc: %T", tn->type); err: i = 0; out: if(i) reg[i]++; nodreg(n, tn, i); //print("+ %R %d\n", i, reg[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]--; //print("- %R %d\n", i, 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) { USED(nn); if(REGARG < 0) { diag(n, "regaalloc1"); return; } /* not reached 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); //prtree(n, "naddr"); break; case OREGISTER: a->type = n->reg; a->sym = S; break; case OIND: naddr(n->left, a); if(a->type >= D_AX && a->type <= D_DI) a->type += D_INDIR; else if(a->type == D_CONST) a->type = D_NONE+D_INDIR; else if(a->type == D_ADDR) { a->type = a->index; a->index = D_NONE; } else goto bad; break; case OINDEX: a->type = idx.ptr; if(n->left->op == OADDR || n->left->op == OCONST) naddr(n->left, a); if(a->type >= D_AX && a->type <= D_DI) a->type += D_INDIR; else if(a->type == D_CONST) a->type = D_NONE+D_INDIR; else if(a->type == D_ADDR) { a->type = a->index; a->index = D_NONE; } else goto bad; a->index = idx.reg; a->scale = n->scale; a->offset += n->xoffset; break; case OINDREG: a->type = n->reg+D_INDIR; a->sym = S; a->offset = n->xoffset; break; case ONAME: a->etype = n->etype; a->type = D_STATIC; a->sym = n->sym; a->offset = n->xoffset; if(n->class == CSTATIC) break; if(n->class == CEXTERN || n->class == CGLOBL) { a->type = D_EXTERN; break; } if(n->class == CAUTO) { a->type = D_AUTO; break; } if(n->class == CPARAM) { a->type = D_PARAM; break; } goto bad; case OCONST: if(typefd[n->type->etype]) { a->type = D_FCONST; a->dval = n->fconst; break; } a->sym = S; a->type = D_CONST; a->offset = n->vconst; break; case OADDR: naddr(n->left, a); if(a->type >= D_INDIR) { a->type -= D_INDIR; break; } if(a->type == D_EXTERN || a->type == D_STATIC || a->type == D_AUTO || a->type == D_PARAM) if(a->index == D_NONE) { a->index = a->type; a->type = D_ADDR; break; } goto bad; case OADD: if(n->right->op == OCONST) { v = n->right->vconst; naddr(n->left, a); } else if(n->left->op == OCONST) { v = n->left->vconst; naddr(n->right, a); } else goto bad; a->offset += v; break; } } #define CASE(a,b) ((a<<8)|(b<<0)) void gmove(Node *f, Node *t) { int ft, tt, a; Node nod, nod1; Prog *p1; ft = f->type->etype; tt = t->type->etype; if(debug['M']) print("gop: %O %O[%s],%O[%s]\n", OAS, f->op, tnames[ft], t->op, tnames[tt]); if(typefd[ft] && f->op == OCONST) { if(f->fconst == 0) gins(AFLDZ, Z, Z); else if(f->fconst == 1) gins(AFLD1, Z, Z); else gins(AFMOVD, f, &fregnode0); gmove(&fregnode0, t); return; } /* * load */ if(f->op == ONAME || f->op == OINDREG || f->op == OIND || f->op == OINDEX) switch(ft) { case TCHAR: a = AMOVBLSX; goto ld; case TUCHAR: a = AMOVBLZX; goto ld; case TSHORT: if(typefd[tt]) { gins(AFMOVW, f, &fregnode0); gmove(&fregnode0, t); return; } a = AMOVWLSX; goto ld; case TUSHORT: a = AMOVWLZX; goto ld; case TINT: case TUINT: case TLONG: case TULONG: case TIND: if(typefd[tt]) { gins(AFMOVL, f, &fregnode0); gmove(&fregnode0, t); return; } a = AMOVL; ld: regalloc(&nod, f, t); nod.type = types[TLONG]; gins(a, f, &nod); gmove(&nod, t); regfree(&nod); return; case TFLOAT: gins(AFMOVF, f, t); return; case TDOUBLE: gins(AFMOVD, f, t); return; case TVLONG: gins(AFMOVV, f, t); return; } /* * store */ if(t->op == ONAME || t->op == OINDREG || t->op == OIND || t->op == OINDEX) switch(tt) { case TCHAR: case TUCHAR: a = AMOVB; goto st; case TSHORT: case TUSHORT: a = AMOVW; goto st; case TINT: case TUINT: case TLONG: case TULONG: case TIND: a = AMOVL; goto st; st: if(f->op == OCONST) { gins(a, f, t); return; } regalloc(&nod, t, f); gmove(f, &nod); gins(a, &nod, t); regfree(&nod); return; case TFLOAT: gins(AFMOVFP, f, t); return; case TDOUBLE: gins(AFMOVDP, f, t); return; case TVLONG: gins(AFMOVVP, f, t); return; } /* * convert */ switch(CASE(ft,tt)) { default: /* * integer to integer ******** a = AGOK; break; case CASE( TCHAR, TCHAR): case CASE( TUCHAR, TCHAR): case CASE( TSHORT, TCHAR): case CASE( TUSHORT,TCHAR): case CASE( TINT, TCHAR): case CASE( TUINT, TCHAR): case CASE( TLONG, TCHAR): case CASE( TULONG, TCHAR): case CASE( TIND, TCHAR): case CASE( TCHAR, TUCHAR): case CASE( TUCHAR, TUCHAR): case CASE( TSHORT, TUCHAR): case CASE( TUSHORT,TUCHAR): case CASE( TINT, TUCHAR): case CASE( TUINT, TUCHAR): case CASE( TLONG, TUCHAR): case CASE( TULONG, TUCHAR): case CASE( TIND, TUCHAR): case CASE( TSHORT, TSHORT): case CASE( TUSHORT,TSHORT): case CASE( TINT, TSHORT): case CASE( TUINT, TSHORT): case CASE( TLONG, TSHORT): case CASE( TULONG, TSHORT): case CASE( TIND, TSHORT): case CASE( TSHORT, TUSHORT): case CASE( TUSHORT,TUSHORT): case CASE( TINT, TUSHORT): case CASE( TUINT, TUSHORT): case CASE( TLONG, TUSHORT): case CASE( TULONG, TUSHORT): case CASE( TIND, TUSHORT): case CASE( TINT, TINT): case CASE( TUINT, TINT): case CASE( TLONG, TINT): case CASE( TULONG, TINT): case CASE( TIND, TINT): case CASE( TINT, TUINT): case CASE( TUINT, TUINT): case CASE( TLONG, TUINT): case CASE( TULONG, TUINT): case CASE( TIND, TUINT): case CASE( TINT, TLONG): case CASE( TUINT, TLONG): case CASE( TLONG, TLONG): case CASE( TULONG, TLONG): case CASE( TIND, TLONG): case CASE( TINT, TULONG): case CASE( TUINT, TULONG): case CASE( TLONG, TULONG): case CASE( TULONG, TULONG): case CASE( TIND, TULONG): case CASE( TINT, TIND): case CASE( TUINT, TIND): case CASE( TLONG, TIND): case CASE( TULONG, TIND): case CASE( TIND, TIND): *****/ a = AMOVL; break; case CASE( TSHORT, TINT): case CASE( TSHORT, TUINT): case CASE( TSHORT, TLONG): case CASE( TSHORT, TULONG): case CASE( TSHORT, TIND): a = AMOVWLSX; if(f->op == OCONST) { f->vconst &= 0xffff; if(f->vconst & 0x8000) f->vconst |= 0xffff0000; a = AMOVL; } break; case CASE( TUSHORT,TINT): case CASE( TUSHORT,TUINT): case CASE( TUSHORT,TLONG): case CASE( TUSHORT,TULONG): case CASE( TUSHORT,TIND): a = AMOVWLZX; if(f->op == OCONST) { f->vconst &= 0xffff; a = AMOVL; } break; case CASE( TCHAR, TSHORT): case CASE( TCHAR, TUSHORT): case CASE( TCHAR, TINT): case CASE( TCHAR, TUINT): case CASE( TCHAR, TLONG): case CASE( TCHAR, TULONG): case CASE( TCHAR, TIND): a = AMOVBLSX; if(f->op == OCONST) { f->vconst &= 0xff; if(f->vconst & 0x80) f->vconst |= 0xffffff00; a = AMOVL; } break; case CASE( TUCHAR, TSHORT): case CASE( TUCHAR, TUSHORT): case CASE( TUCHAR, TINT): case CASE( TUCHAR, TUINT): case CASE( TUCHAR, TLONG): case CASE( TUCHAR, TULONG): case CASE( TUCHAR, TIND): a = AMOVBLZX; if(f->op == OCONST) { f->vconst &= 0xff; a = AMOVL; } break; /* * float to fix */ case CASE( TFLOAT, TCHAR): case CASE( TFLOAT, TUCHAR): case CASE( TFLOAT, TSHORT): case CASE( TFLOAT, TUSHORT): case CASE( TFLOAT, TINT): case CASE( TFLOAT, TLONG): 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,TLONG): case CASE( TDOUBLE,TIND): if(fproundflg) { regsalloc(&nod, ®node); gins(AFMOVLP, f, &nod); gmove(&nod, t); return; } regsalloc(&nod, ®node); regsalloc(&nod1, ®node); gins(AFSTCW, Z, &nod1); nod1.xoffset += 2; gins(AMOVW, nodconst(0xf7f), &nod1); gins(AFLDCW, &nod1, Z); gins(AFMOVLP, f, &nod); nod1.xoffset -= 2; gins(AFLDCW, &nod1, Z); gmove(&nod, t); return; /* * float to ulong */ case CASE( TDOUBLE, TULONG): case CASE( TFLOAT, TULONG): case CASE( TDOUBLE, TUINT): case CASE( TFLOAT, TUINT): regsalloc(&nod, ®node); gmove(f, &fregnode0); gins(AFADDD, nodfconst(-2147483648.), &fregnode0); gins(AFMOVLP, f, &nod); gins(ASUBL, nodconst(-2147483648), &nod); gmove(&nod, t); return; /* * ulong to float */ case CASE( TULONG, TDOUBLE): case CASE( TULONG, TFLOAT): case CASE( TUINT, TDOUBLE): case CASE( TUINT, TFLOAT): regalloc(&nod, f, f); gmove(f, &nod); regsalloc(&nod1, ®node); gmove(&nod, &nod1); gins(AFMOVL, &nod1, &fregnode0); gins(ACMPL, &nod, nodconst(0)); gins(AJGE, Z, Z); p1 = p; gins(AFADDD, nodfconst(4294967296.), &fregnode0); patch(p1, pc); regfree(&nod); return; /* * fix to float */ case CASE( TCHAR, TFLOAT): case CASE( TUCHAR, TFLOAT): case CASE( TSHORT, TFLOAT): case CASE( TUSHORT,TFLOAT): case CASE( TINT, TFLOAT): case CASE( TLONG, TFLOAT): case CASE( TIND, TFLOAT): case CASE( TCHAR, TDOUBLE): case CASE( TUCHAR, TDOUBLE): case CASE( TSHORT, TDOUBLE): case CASE( TUSHORT,TDOUBLE): case CASE( TINT, TDOUBLE): case CASE( TLONG, TDOUBLE): case CASE( TIND, TDOUBLE): regsalloc(&nod, ®node); gmove(f, &nod); gins(AFMOVL, &nod, &fregnode0); return; /* * float to float */ case CASE( TFLOAT, TFLOAT): case CASE( TDOUBLE,TFLOAT): case CASE( TFLOAT, TDOUBLE): case CASE( TDOUBLE,TDOUBLE): a = AFMOVD; break; } if(a == AMOVL || a == AFMOVD) if(samaddr(f, t)) return; gins(a, f, t); } void doindex(Node *n) { Node nod, nod1; long v; if(debug['Y']) prtree(n, "index"); if(n->left->complex >= FNX) print("botch in doindex\n"); regalloc(&nod, ®node, Z); v = constnode.vconst; cgen(n->right, &nod); idx.ptr = D_NONE; if(n->left->op == OCONST) idx.ptr = D_CONST; else if(n->left->op == OREGISTER) // else if(n->left->op == OREGISTER && typeil[n->left->type->etype]) idx.ptr = n->left->reg; else if(n->left->op != OADDR) { reg[D_BP]++; // cant be used as a base regalloc(&nod1, ®node, Z); cgen(n->left, &nod1); idx.ptr = nod1.reg; regfree(&nod1); reg[D_BP]--; } idx.reg = nod.reg; regfree(&nod); constnode.vconst = v; } void gins(int a, Node *f, Node *t) { if(f != Z && f->op == OINDEX) doindex(f); if(t != Z && t->op == OINDEX) doindex(t); nextpc(); p->as = a; if(f != Z) naddr(f, &p->from); if(t != Z) naddr(t, &p->to); if(debug['g']) print("%P\n", p); } void fgopcode(int o, Node *f, Node *t, int pop, int rev) { int a, et; Node nod; et = TLONG; if(f != Z && f->type != T) et = f->type->etype; if(!typefd[et]) { diag(f, "fop: integer %O", o); return; } if(debug['M']) { if(t != Z && t->type != T) print("gop: %O %O-%s Z\n", o, f->op, tnames[et]); else print("gop: %O %O-%s %O-%s\n", o, f->op, tnames[et], t->op, tnames[t->type->etype]); } a = AGOK; switch(o) { case OASADD: case OADD: if(et == TFLOAT) a = AFADDF; else if(et == TDOUBLE || et == TVLONG) { a = AFADDD; if(pop) a = AFADDDP; } break; case OASSUB: case OSUB: if(et == TFLOAT) { a = AFSUBF; if(rev) a = AFSUBRF; } else if(et == TDOUBLE || et == TVLONG) { a = AFSUBD; if(pop) a = AFSUBDP; if(rev) { a = AFSUBRD; if(pop) a = AFSUBRDP; } } break; case OASMUL: case OMUL: if(et == TFLOAT) a = AFMULF; else if(et == TDOUBLE || et == TVLONG) { a = AFMULD; if(pop) a = AFMULDP; } break; case OASMOD: case OMOD: case OASDIV: case ODIV: if(et == TFLOAT) { a = AFDIVF; if(rev) a = AFDIVRF; } else if(et == TDOUBLE || et == TVLONG) { a = AFDIVD; if(pop) a = AFDIVDP; if(rev) { a = AFDIVRD; if(pop) a = AFDIVRDP; } } break; case OEQ: case ONE: case OLT: case OLE: case OGE: case OGT: pop += rev; if(et == TFLOAT) { a = AFCOMF; if(pop) { a = AFCOMFP; if(pop > 1) a = AGOK; } } else if(et == TDOUBLE || et == TVLONG) { a = AFCOMF; if(pop) { a = AFCOMDP; if(pop > 1) a = AFCOMDPP; } } gins(a, f, t); regalloc(&nod, ®node, Z); if(nod.reg != D_AX) { regfree(&nod); nod.reg = D_AX; gins(APUSHL, &nod, Z); gins(AWAIT, Z, Z); gins(AFSTSW, Z, &nod); gins(ASAHF, Z, Z); gins(APOPL, Z, &nod); } else { gins(AWAIT, Z, Z); gins(AFSTSW, Z, &nod); gins(ASAHF, Z, Z); regfree(&nod); } switch(o) { case OEQ: a = AJEQ; break; case ONE: a = AJNE; break; case OLT: a = AJCS; break; case OLE: a = AJLS; break; case OGE: a = AJCC; break; case OGT: a = AJHI; break; } gins(a, Z, Z); return; } if(a == AGOK) diag(Z, "bad in gopcode %O", o); gins(a, f, t); } void gopcode(int o, Type *ty, Node *f, Node *t) { int a, et; et = TLONG; if(ty != T) et = ty->etype; if(typefd[et] && o != OADDR && o != OFUNC) { diag(f, "gop: float %O", o); return; } if(debug['M']) { if(f != Z && f->type != T) print("gop: %O %O[%s],", o, f->op, tnames[et]); else print("gop: %O Z,", o); if(t != Z && t->type != T) print("%O[%s]\n", t->op, tnames[t->type->etype]); else print("Z\n"); } a = AGOK; switch(o) { case OCOM: a = ANOTL; if(et == TCHAR || et == TUCHAR) a = ANOTB; if(et == TSHORT || et == TUSHORT) a = ANOTW; break; case ONEG: a = ANEGL; if(et == TCHAR || et == TUCHAR) a = ANEGB; if(et == TSHORT || et == TUSHORT) a = ANEGW; break; case OADDR: a = ALEAL; break; case OASADD: case OADD: a = AADDL; if(et == TCHAR || et == TUCHAR) a = AADDB; if(et == TSHORT || et == TUSHORT) a = AADDW; break; case OASSUB: case OSUB: a = ASUBL; if(et == TCHAR || et == TUCHAR) a = ASUBB; if(et == TSHORT || et == TUSHORT) a = ASUBW; break; case OASOR: case OOR: a = AORL; if(et == TCHAR || et == TUCHAR) a = AORB; if(et == TSHORT || et == TUSHORT) a = AORW; break; case OASAND: case OAND: a = AANDL; if(et == TCHAR || et == TUCHAR) a = AANDB; if(et == TSHORT || et == TUSHORT) a = AANDW; break; case OASXOR: case OXOR: a = AXORL; if(et == TCHAR || et == TUCHAR) a = AXORB; if(et == TSHORT || et == TUSHORT) a = AXORW; break; case OASLSHR: case OLSHR: a = ASHRL; if(et == TCHAR || et == TUCHAR) a = ASHRB; if(et == TSHORT || et == TUSHORT) a = ASHRW; break; case OASASHR: case OASHR: a = ASARL; if(et == TCHAR || et == TUCHAR) a = ASARB; if(et == TSHORT || et == TUSHORT) a = ASARW; break; case OASASHL: case OASHL: a = ASALL; if(et == TCHAR || et == TUCHAR) a = ASALB; if(et == TSHORT || et == TUSHORT) a = ASALW; break; case OFUNC: a = ACALL; break; case OASMUL: case OMUL: if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0) t = Z; a = AIMULL; break; case OASMOD: case OMOD: case OASDIV: case ODIV: a = AIDIVL; break; case OASLMUL: case OLMUL: a = AMULL; break; case OASLMOD: case OLMOD: case OASLDIV: case OLDIV: a = ADIVL; break; case OEQ: case ONE: case OLT: case OLE: case OGE: case OGT: case OLO: case OLS: case OHS: case OHI: a = ACMPL; if(et == TCHAR || et == TUCHAR) a = ACMPB; if(et == TSHORT || et == TUSHORT) a = ACMPW; gins(a, f, t); switch(o) { case OEQ: a = AJEQ; break; case ONE: a = AJNE; break; case OLT: a = AJLT; break; case OLE: a = AJLE; break; case OGE: a = AJGE; break; case OGT: a = AJGT; break; case OLO: a = AJCS; break; case OLS: a = AJLS; break; case OHS: a = AJCC; break; case OHI: a = AJHI; break; } gins(a, Z, Z); return; } if(a == AGOK) diag(Z, "bad in gopcode %O", o); gins(a, f, t); } int samaddr(Node *f, Node *t) { if(f->op != t->op) return 0; switch(f->op) { case OREGISTER: if(f->reg != t->reg) break; return 1; } return 0; } void gbranch(int o) { int a; a = AGOK; switch(o) { case ORETURN: a = ARET; break; case OGOTO: a = AJMP; break; } nextpc(); if(a == AGOK) { diag(Z, "bad in gbranch %O", o); nextpc(); } p->as = a; } void patch(Prog *op, long pc) { op->to.offset = pc; op->to.type = D_BRANCH; } void gpseudo(int a, Sym *s, Node *n) { nextpc(); p->as = a; p->from.type = D_EXTERN; p->from.sym = s; p->from.scale = (profileflg ? 0 : NOPROF); if(s->class == CSTATIC) p->from.type = D_STATIC; naddr(n, &p->to); if(a == ADATA || a == AGLOBL) pc--; } int sconst(Node *n) { long v; if(n->op == OCONST && !typefd[n->type->etype]) { v = n->vconst; if(v >= -32766L && v < 32766L) return 1; } return 0; } long exreg(Type *t) { USED(t); return 0; } schar ewidth[NTYPE] = { -1, /*[TXXX]*/ SZ_CHAR, /*[TCHAR]*/ SZ_CHAR, /*[TUCHAR]*/ SZ_SHORT, /*[TSHORT]*/ SZ_SHORT, /*[TUSHORT]*/ SZ_INT, /*[TINT]*/ SZ_INT, /*[TUINT]*/ SZ_LONG, /*[TLONG]*/ SZ_LONG, /*[TULONG]*/ SZ_VLONG, /*[TVLONG]*/ SZ_VLONG, /*[TUVLONG]*/ SZ_FLOAT, /*[TFLOAT]*/ SZ_DOUBLE, /*[TDOUBLE]*/ SZ_IND, /*[TIND]*/ 0, /*[TFUNC]*/ -1, /*[TARRAY]*/ 0, /*[TVOID]*/ -1, /*[TSTRUCT]*/ -1, /*[TUNION]*/ SZ_INT, /*[TENUM]*/ }; long ncast[NTYPE] = { 0, /*[TXXX]*/ BCHAR|BUCHAR, /*[TCHAR]*/ BCHAR|BUCHAR, /*[TUCHAR]*/ BSHORT|BUSHORT, /*[TSHORT]*/ BSHORT|BUSHORT, /*[TUSHORT]*/ BINT|BUINT|BLONG|BULONG|BIND, /*[TINT]*/ BINT|BUINT|BLONG|BULONG|BIND, /*[TUINT]*/ BINT|BUINT|BLONG|BULONG|BIND, /*[TLONG]*/ BINT|BUINT|BLONG|BULONG|BIND, /*[TULONG]*/ BVLONG|BUVLONG, /*[TVLONG]*/ BVLONG|BUVLONG, /*[TUVLONG]*/ BFLOAT, /*[TFLOAT]*/ BDOUBLE, /*[TDOUBLE]*/ BLONG|BULONG|BIND, /*[TIND]*/ 0, /*[TFUNC]*/ 0, /*[TARRAY]*/ 0, /*[TVOID]*/ BSTRUCT, /*[TSTRUCT]*/ BUNION, /*[TUNION]*/ 0, /*[TENUM]*/ }; ASE( TDOUBLE,TUCHAR): case CASE( TDOUBLE,TSHORT): case CASE( TDOUBLE,TUSHORT): case CASE( TDOUBLE,TINT): case CASE( TDOUBLE,TLONG): case CASE( TDOUBLE,TIND): if(fproundflg) { regsallo5c/ 775 0 0 0 11466070233 70555ustar00syssys5c/5.out.h 664 0 0 5052 10645763400 10205ustar00syssys#define NSNAME 8 #define NSYM 50 #define NREG 16 #define NOPROF (1<<0) #define DUPOK (1<<1) #define ALLTHUMBS (1<<2) #define REGRET 0 #define REGARG 0 /* compiler allocates R1 up as temps */ /* compiler allocates register variables R2 up */ #define REGMIN 2 #define REGMAX 8 #define REGEXT 10 /* compiler allocates external registers R10 down */ #define REGTMP 11 #define REGSB 12 #define REGSP 13 #define REGLINK 14 #define REGPC 15 #define REGTMPT 7 /* used by the loader for thumb code */ #define NFREG 8 #define FREGRET 0 #define FREGEXT 7 /* compiler allocates register variables F0 up */ /* compiler allocates external registers F7 down */ enum as { AXXX, AAND, AEOR, ASUB, ARSB, AADD, AADC, ASBC, ARSC, ATST, ATEQ, ACMP, ACMN, AORR, ABIC, AMVN, AB, ABL, /* * Do not reorder or fragment the conditional branch * opcodes, or the predication code will break */ ABEQ, ABNE, ABCS, ABHS, ABCC, ABLO, ABMI, ABPL, ABVS, ABVC, ABHI, ABLS, ABGE, ABLT, ABGT, ABLE, AMOVWD, AMOVWF, AMOVDW, AMOVFW, AMOVFD, AMOVDF, AMOVF, AMOVD, ACMPF, ACMPD, AADDF, AADDD, ASUBF, ASUBD, AMULF, AMULD, ADIVF, ADIVD, ASRL, ASRA, ASLL, AMULU, ADIVU, AMUL, ADIV, AMOD, AMODU, AMOVB, AMOVBU, AMOVH, AMOVHU, AMOVW, AMOVM, ASWPBU, ASWPW, ANOP, ARFE, ASWI, AMULA, ADATA, AGLOBL, AGOK, AHISTORY, ANAME, ARET, ATEXT, AWORD, ADYNT, AINIT, ABCASE, ACASE, AEND, AMULL, AMULAL, AMULLU, AMULALU, ABX, ABXRET, ADWORD, ASIGNAME, ALAST, }; /* scond byte */ #define C_SCOND ((1<<4)-1) #define C_SBIT (1<<4) #define C_PBIT (1<<5) #define C_WBIT (1<<6) #define C_FBIT (1<<7) /* psr flags-only */ #define C_UBIT (1<<7) /* up bit */ /* type/name */ #define D_GOK 0 #define D_NONE 1 /* type */ #define D_BRANCH (D_NONE+1) #define D_OREG (D_NONE+2) #define D_CONST (D_NONE+7) #define D_FCONST (D_NONE+8) #define D_SCONST (D_NONE+9) #define D_PSR (D_NONE+10) #define D_REG (D_NONE+12) #define D_FREG (D_NONE+13) #define D_FILE (D_NONE+16) #define D_OCONST (D_NONE+17) #define D_FILE1 (D_NONE+18) #define D_SHIFT (D_NONE+19) #define D_FPCR (D_NONE+20) #define D_REGREG (D_NONE+21) /* name */ #define D_EXTERN (D_NONE+3) #define D_STATIC (D_NONE+4) #define D_AUTO (D_NONE+5) #define D_PARAM (D_NONE+6) /* * 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 */ }; D; if(pop) a = AFSUBRDP; } } break; case OASMUL: case OMUL: if(et == TFLOAT) a = AFMULF; else if(et == TDOUBLE || et == TVLONG) { a = AFMULD; if(pop) a = AFMULDP; } break; case OASMOD: case OMOD: case OASDIV: case ODIV: if(et == TFLOAT) { a = AFDIVF; if(rev) a = AFDIVRF; } else if(et == TDOUBLE || et == TVLONG) { a = AFDIVD; if(pop) a = AFDIVDP; if(rev) { a = AFDIVRD; if(pop) a 5c/cgen.c 664 0 0 47731 11443771673 10204ustar00syssys#include "gc.h" void cgen(Node *n, Node *nn) { cgenrel(n, nn, 0); } void cgenrel(Node *n, Node *nn, int inrel) { Node *l, *r; Prog *p1; Node nod, nod1, nod2, nod3, nod4; int o, t; long v, curs; if(debug['g']) { prtree(nn, "cgen lhs"); prtree(n, "cgen"); } if(n == Z || n->type == T) return; if(typesuv[n->type->etype]) { sugen(n, nn, n->type->width); return; } l = n->left; r = n->right; o = n->op; if(n->addable >= INDEXED) { if(nn == Z) { switch(o) { default: nullwarn(Z, Z); break; case OINDEX: nullwarn(l, r); break; } return; } gmove(n, nn); return; } curs = cursafe; if(n->complex >= FNX) if(l->complex >= FNX) if(r != Z && r->complex >= FNX) switch(o) { default: regret(&nod, r); cgen(r, &nod); regsalloc(&nod1, r); gopcode(OAS, &nod, Z, &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; } switch(o) { default: diag(n, "unknown op in cgen: %O", o); break; case OAS: if(l->op == OBIT) goto bitas; if(l->addable >= INDEXED && l->complex < FNX) { if(nn != Z || r->addable < INDEXED) { if(r->complex >= FNX && nn == Z) regret(&nod, r); else regalloc(&nod, r, nn); cgen(r, &nod); gmove(&nod, l); if(nn != Z) gmove(&nod, nn); regfree(&nod); } else gmove(r, l); break; } if(l->complex >= r->complex) { reglcgen(&nod1, l, Z); if(r->addable >= INDEXED) { gmove(r, &nod1); if(nn != Z) gmove(r, nn); regfree(&nod1); break; } regalloc(&nod, r, nn); cgen(r, &nod); } else { regalloc(&nod, r, nn); cgen(r, &nod); reglcgen(&nod1, l, Z); } gmove(&nod, &nod1); regfree(&nod); regfree(&nod1); break; bitas: n = l->left; regalloc(&nod, r, nn); if(l->complex >= r->complex) { reglcgen(&nod1, n, Z); cgen(r, &nod); } else { cgen(r, &nod); reglcgen(&nod1, n, Z); } regalloc(&nod2, n, Z); gopcode(OAS, &nod1, Z, &nod2); bitstore(l, &nod, &nod1, &nod2, nn); break; case OBIT: if(nn == Z) { nullwarn(l, Z); break; } bitload(n, &nod, Z, Z, nn); gopcode(OAS, &nod, Z, nn); regfree(&nod); break; case ODIV: case OMOD: if(nn != Z) if((t = vlog(r)) >= 0) { /* signed div/mod by constant power of 2 */ cgen(l, nn); gopcode(OGE, nodconst(0), nn, Z); p1 = p; if(o == ODIV) { gopcode(OADD, nodconst((1<op == OCONST) if(!typefd[n->type->etype]) { cgen(r, nn); gopcode(o, Z, l, nn); break; } case OADD: case OAND: case OOR: case OXOR: case OLSHR: case OASHL: case OASHR: /* * immediate operands */ if(nn != Z) if(r->op == OCONST) if(!typefd[n->type->etype]) { cgen(l, nn); if(r->vconst == 0) if(o != OAND) break; if(nn != Z) gopcode(o, r, Z, nn); break; } case OLMUL: case OLDIV: case OLMOD: case OMUL: muldiv: if(nn == Z) { nullwarn(l, r); break; } if(o == OMUL || o == OLMUL) { if(mulcon(n, nn)) break; } if(l->complex >= r->complex) { regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, r, Z); cgen(r, &nod1); gopcode(o, &nod1, Z, &nod); } else { regalloc(&nod, r, nn); cgen(r, &nod); regalloc(&nod1, l, Z); cgen(l, &nod1); gopcode(o, &nod, &nod1, &nod); } gopcode(OAS, &nod, Z, nn); regfree(&nod); regfree(&nod1); break; case OASLSHR: case OASASHL: case OASASHR: case OASAND: case OASADD: case OASSUB: case OASXOR: case OASOR: if(l->op == OBIT) goto asbitop; if(r->op == OCONST) if(!typefd[r->type->etype]) if(!typefd[n->type->etype]) { if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, r, nn); gopcode(OAS, &nod2, Z, &nod); gopcode(o, r, Z, &nod); gopcode(OAS, &nod, Z, &nod2); regfree(&nod); if(l->addable < INDEXED) regfree(&nod2); break; } case OASLMUL: case OASLDIV: case OASLMOD: case OASMUL: case OASDIV: case OASMOD: if(l->op == OBIT) goto asbitop; if(l->complex >= r->complex) { if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod1, r, Z); cgen(r, &nod1); } else { regalloc(&nod1, r, Z); cgen(r, &nod1); if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; } regalloc(&nod, n, nn); gmove(&nod2, &nod); gopcode(o, &nod1, Z, &nod); gmove(&nod, &nod2); if(nn != Z) gopcode(OAS, &nod, Z, nn); regfree(&nod); regfree(&nod1); if(l->addable < INDEXED) regfree(&nod2); 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); gopcode(o, &nod3, Z, &nod4); 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); gopcode(OAS, &nod, Z, &nod1); regfree(&nod); nod = *n; nod.left = &nod2; nod2 = *l; nod2.left = &nod1; nod2.complex = 1; cgen(&nod, nn); return; } if(REGARG >= 0) o = reg[REGARG]; gargs(r, &nod, &nod1); if(l->addable < INDEXED) { reglcgen(&nod, l, Z); gopcode(OFUNC, Z, Z, &nod); regfree(&nod); } else gopcode(OFUNC, Z, Z, l); if(REGARG >= 0) if(o != reg[REGARG]) reg[REGARG]--; if(nn != Z) { regret(&nod, n); gopcode(OAS, &nod, Z, 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+nod.xoffset) > -4096 && v < 4096) { v = r->vconst; r->vconst = 0; cgen(l, &nod); nod.xoffset += v; r->vconst = v; } else cgen(l, &nod); regind(&nod, n); gopcode(OAS, &nod, Z, 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)) { if(nocast(n->type, nn->type)) { cgen(l, nn); break; } } regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, n, &nod); if(inrel) gmover(&nod, &nod1); else gopcode(OAS, &nod, Z, &nod1); gopcode(OAS, &nod1, Z, nn); regfree(&nod1); regfree(&nod); break; case ODOT: sugen(l, nodrat, l->type->width); if(nn != Z) { 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(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, l, nn); gopcode(OAS, &nod2, Z, &nod); regalloc(&nod1, l, Z); if(typefd[l->type->etype]) { regalloc(&nod3, l, Z); if(v < 0) { gopcode(OAS, nodfconst(-v), Z, &nod3); gopcode(OSUB, &nod3, &nod, &nod1); } else { gopcode(OAS, nodfconst(v), Z, &nod3); gopcode(OADD, &nod3, &nod, &nod1); } regfree(&nod3); } else gopcode(OADD, nodconst(v), &nod, &nod1); gopcode(OAS, &nod1, Z, &nod2); regfree(&nod); regfree(&nod1); if(l->addable < INDEXED) regfree(&nod2); 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(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, l, nn); gopcode(OAS, &nod2, Z, &nod); if(typefd[l->type->etype]) { regalloc(&nod3, l, Z); if(v < 0) { gopcode(OAS, nodfconst(-v), Z, &nod3); gopcode(OSUB, &nod3, Z, &nod); } else { gopcode(OAS, nodfconst(v), Z, &nod3); gopcode(OADD, &nod3, Z, &nod); } regfree(&nod3); } else gopcode(OADD, nodconst(v), Z, &nod); gopcode(OAS, &nod, Z, &nod2); if(nn && l->op == ONAME) /* in x=++i, emit USED(i) */ gins(ANOP, l, Z); regfree(&nod); if(l->addable < INDEXED) regfree(&nod2); break; bitinc: if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { bitload(l, &nod, &nod1, &nod2, Z); gopcode(OAS, &nod, Z, nn); gopcode(OADD, nodconst(v), Z, &nod); bitstore(l, &nod, &nod1, &nod2, Z); break; } bitload(l, &nod, &nod1, &nod2, nn); gopcode(OADD, nodconst(v), Z, &nod); bitstore(l, &nod, &nod1, &nod2, nn); break; } cursafe = curs; return; } 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+t->xoffset) > -4096 && v < 4096) { v = r->vconst; r->vconst = 0; lcgen(n, t); t->xoffset += v; r->vconst = v; regind(t, n); return; } } else if(n->op == OINDREG) { if((v = n->xoffset) > -4096 && v < 4096) { n->op = OREGISTER; cgen(n, t); t->xoffset += v; n->op = OINDREG; regind(t, n); return; } } lcgen(n, t); regind(t, n); } void reglpcgen(Node *n, Node *nn, int f) { Type *t; t = nn->type; nn->type = types[TLONG]; if(f) reglcgen(n, nn, Z); else { regialloc(n, nn, Z); lcgen(nn, n); regind(n, nn); } nn->type = t; } 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; } nod = *n; nod.op = OADDR; nod.left = n; nod.right = Z; nod.type = types[TIND]; gopcode(OAS, &nod, Z, 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: regalloc(&nod, n, nn); cgen(n, &nod); o = ONE; if(true) o = comrel[relindex(o)]; if(typefd[n->type->etype]) { gopcode(o, nodfconst(0), &nod, Z); } else gopcode(o, nodconst(0), &nod, Z); 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); cgenrel(r, &nod, 1); regsalloc(&nod1, r); gopcode(OAS, &nod, Z, &nod1); regfree(&nod); nod = *n; nod.right = &nod1; boolgen(&nod, true, nn); break; } if(sconst(l)) { regalloc(&nod, r, nn); cgenrel(r, &nod, 1); o = invrel[relindex(o)]; gopcode(o, l, &nod, Z); regfree(&nod); goto com; } if(sconst(r)) { regalloc(&nod, l, nn); cgenrel(l, &nod, 1); gopcode(o, r, &nod, Z); regfree(&nod); goto com; } if(l->complex >= r->complex) { regalloc(&nod1, l, nn); cgenrel(l, &nod1, 1); regalloc(&nod, r, Z); cgenrel(r, &nod, 1); } else { regalloc(&nod, r, nn); cgenrel(r, &nod, 1); regalloc(&nod1, l, Z); cgenrel(l, &nod1, 1); } gopcode(o, &nod, &nod1, Z); regfree(&nod); regfree(&nod1); com: if(nn != Z) { p1 = p; gopcode(OAS, nodconst(1), Z, nn); gbranch(OGOTO); p2 = p; patch(p1, pc); gopcode(OAS, nodconst(0), Z, 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; long pc1; int i, m, c, x; if(n == Z || n->type == T) return; if(debug['g']) { prtree(nn, "sugen lhs"); prtree(n, "sugen"); } if(nn == nodrat) if(w > nrathole) nrathole = w; switch(n->op) { case OIND: if(nn == Z) { nullwarn(n->left, Z); break; } default: goto copy; case OCONST: if(n->type && typev[n->type->etype]) { if(nn == Z) { nullwarn(n->left, Z); break; } t = nn->type; nn->type = types[TLONG]; reglcgen(&nod1, nn, Z); nn->type = t; if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); else gopcode(OAS, nod32const(n->vconst), Z, &nod1); nod1.xoffset += SZ_LONG; if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ gopcode(OAS, nod32const(n->vconst), Z, &nod1); else gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); regfree(&nod1); break; } goto copy; case ODOT: l = n->left; sugen(l, nodrat, l->type->width); if(nn != Z) { 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 && nn->complex >= FNX) { nod1 = *n; nod1.type = typ(TIND, n->type); regret(&nod2, &nod1); lcgen(nn, &nod2); regsalloc(&nod0, &nod1); gopcode(OAS, &nod2, Z, &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 = l; 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; 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) return; if(n->complex >= FNX && nn->complex >= FNX) { t = nn->type; nn->type = types[TLONG]; regialloc(&nod1, nn, Z); lcgen(nn, &nod1); regsalloc(&nod2, nn); nn->type = t; gopcode(OAS, &nod1, Z, &nod2); regfree(&nod1); nod2.type = typ(TIND, t); nod1 = nod2; nod1.op = OIND; nod1.left = &nod2; nod1.right = Z; nod1.complex = 1; nod1.type = t; sugen(n, &nod1, w); return; } x = w & SZ_LONG-1; w /= SZ_LONG; if(x) warn(n, "packed assignment"); else if(w <= 2) { if(n->complex > nn->complex) { reglpcgen(&nod1, n, 1); reglpcgen(&nod2, nn, 1); } else { reglpcgen(&nod2, nn, 1); reglpcgen(&nod1, n, 1); } regalloc(&nod3, ®node, Z); regalloc(&nod4, ®node, Z); if(nod3.reg > nod4.reg){ /* code below assumes nod3 loaded first */ Node t = nod3; nod3 = nod4; nod4 = t; } nod0 = *nodconst((1<complex > nn->complex) { reglpcgen(&nod1, n, 0); reglpcgen(&nod2, nn, 0); } else { reglpcgen(&nod2, nn, 0); reglpcgen(&nod1, n, 0); } m = 0; for(c = 0; c < w && c < 4; c++) { i = tmpreg(); if (i == 0) break; reg[i]++; m |= 1<c; w-=c) { gmovm(&nod1, &nod4, 1); gmovm(&nod4, &nod2, 1); } goto out; } regalloc(&nod3, ®node, Z); gopcode(OAS, nodconst(w/c), Z, &nod3); w %= c; pc1 = pc; gmovm(&nod1, &nod4, 1); gmovm(&nod4, &nod2, 1); gopcode(OSUB, nodconst(1), Z, &nod3); gopcode(OEQ, nodconst(0), &nod3, Z); p->as = ABGT; patch(p, pc1); regfree(&nod3); out: if (w) { i = 0; while (c>w) { while ((m&(1<0); if(x){ regalloc(&nod3, ®node, Z); nod1.xoffset += SZ_LONG*w; nod2.xoffset += SZ_LONG*w; nod1.type->etype = types[TUSHORT]->etype; nod2.type->etype = types[TUSHORT]->etype; for(; x >= SZ_SHORT; x -= SZ_SHORT){ gmove(&nod1, &nod3); gmove(&nod3, &nod2); nod1.xoffset += SZ_SHORT; nod2.xoffset += SZ_SHORT; } nod1.type->etype = types[TUCHAR]->etype; nod2.type->etype = types[TUCHAR]->etype; for(; x >= SZ_CHAR; x -= SZ_CHAR){ gmove(&nod1, &nod3); gmove(&nod3, &nod2); nod1.xoffset += SZ_CHAR; nod2.xoffset += SZ_CHAR; } regfree(&nod3); } regfree(&nod1); regfree(&nod2); } t->xoffset += v; r->vconst = v; 5c/enam.c 664 0 0 1521 10073261347 10141ustar00syssyschar* anames[] = { "XXX", "AND", "EOR", "SUB", "RSB", "ADD", "ADC", "SBC", "RSC", "TST", "TEQ", "CMP", "CMN", "ORR", "BIC", "MVN", "B", "BL", "BEQ", "BNE", "BCS", "BHS", "BCC", "BLO", "BMI", "BPL", "BVS", "BVC", "BHI", "BLS", "BGE", "BLT", "BGT", "BLE", "MOVWD", "MOVWF", "MOVDW", "MOVFW", "MOVFD", "MOVDF", "MOVF", "MOVD", "CMPF", "CMPD", "ADDF", "ADDD", "SUBF", "SUBD", "MULF", "MULD", "DIVF", "DIVD", "SRL", "SRA", "SLL", "MULU", "DIVU", "MUL", "DIV", "MOD", "MODU", "MOVB", "MOVBU", "MOVH", "MOVHU", "MOVW", "MOVM", "SWPBU", "SWPW", "NOP", "RFE", "SWI", "MULA", "DATA", "GLOBL", "GOK", "HISTORY", "NAME", "RET", "TEXT", "WORD", "DYNT", "INIT", "BCASE", "CASE", "END", "MULL", "MULAL", "MULLU", "MULALU", "BX", "BXRET", "DWORD", "SIGNAME", "LAST", }; 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-5c/gc.h 664 0 0 14003 11262413046 7632ustar00syssys#include "../cc/cc.h" #include "../5c/5.out.h" /* * 5c/arm * Arm 7500 */ #define SZ_CHAR 1 #define SZ_SHORT 2 #define SZ_INT 4 #define SZ_LONG 4 #define SZ_IND 4 #define SZ_FLOAT 4 #define SZ_VLONG 8 #define SZ_DOUBLE 8 #define FNX 100 typedef struct Adr Adr; typedef struct Prog Prog; typedef struct Case Case; typedef struct C1 C1; typedef struct Multab Multab; typedef struct Hintab Hintab; typedef struct Var Var; typedef struct Reg Reg; typedef struct Rgn Rgn; #define R0ISZERO 0 struct Adr { long offset; double dval; char sval[NSNAME]; Ieee ieee; Sym* sym; char type; char reg; char name; char etype; }; #define A ((Adr*)0) #define INDEXED 9 struct Prog { Adr from; Adr to; Prog* link; long lineno; char as; char reg; uchar scond; }; #define P ((Prog*)0) struct Case { Case* link; long val; long label; char def; char isv; }; #define C ((Case*)0) struct C1 { long val; long label; }; struct Multab { long val; char code[20]; }; struct Hintab { ushort val; char hint[10]; }; struct Var { long offset; Sym* sym; char name; char etype; }; struct Reg { long pc; long rpo; /* reverse post ordering */ Bits set; Bits use1; Bits use2; Bits refbehind; Bits refahead; Bits calbehind; Bits calahead; Bits regdiff; Bits act; long regu; long loop; /* could be shorter */ Reg* log5; long active; Reg* p1; Reg* p2; Reg* p2link; Reg* s1; Reg* s2; Reg* link; Prog* prog; }; #define R ((Reg*)0) #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 long continpc; EXTERN long curarg; EXTERN long cursafe; EXTERN Prog* firstp; EXTERN Prog* lastp; EXTERN long maxargsafe; EXTERN int mnstring; EXTERN Multab multab[20]; EXTERN int hintabsize; EXTERN Node* nodrat; EXTERN Node* nodret; EXTERN Node* nodsafe; EXTERN long nrathole; EXTERN long nstring; EXTERN Prog* p; EXTERN long pc; EXTERN Node regnode; EXTERN char string[NSNAME]; EXTERN Sym* symrathole; EXTERN Node znode; EXTERN Prog zprog; EXTERN char reg[NREG+NFREG]; EXTERN long exregoffset; EXTERN long exfregoffset; EXTERN int suppress; #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 4 #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 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[]; extern Hintab hintab[]; /* * sgen.c */ void codgen(Node*, Node*); void gen(Node*); void noretval(int); void usedset(Node*, int); void xcom(Node*); int bcomplex(Node*, Node*); /* * cgen.c */ void cgen(Node*, Node*); void cgenrel(Node*, Node*, int); void reglcgen(Node*, Node*, Node*); void lcgen(Node*, Node*); void bcgen(Node*, int); void boolgen(Node*, int, Node*); void sugen(Node*, Node*, long); void layout(Node*, Node*, int, int, Node*); /* * 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* nod32const(vlong); Node* nodfconst(double); void nodreg(Node*, Node*, int); void regret(Node*, Node*); int tmpreg(void); 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 raddr(Node*, Prog*); void naddr(Node*, Adr*); void gmovm(Node*, Node*, int); void gmove(Node*, Node*); void gmover(Node*, Node*); void gins(int a, Node*, Node*); void gopcode(int, Node*, Node*, Node*); int samaddr(Node*, Node*); void gbranch(int); void patch(Prog*, long); int sconst(Node*); int sval(long); void gpseudo(int, Sym*, Node*); /* * swt.c */ int swcmp(const void*, const void*); void doswit(Node*); void swit1(C1*, int, long, Node*); void swit2(C1*, int, long, Node*, Node*); void casf(void); void bitload(Node*, Node*, Node*, Node*, Node*); void bitstore(Node*, Node*, Node*, Node*, Node*); long outstring(char*, long); int mulcon(Node*, Node*); Multab* mulcon0(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 Nconv(Fmt*); int Bconv(Fmt*); int Rconv(Fmt*); /* * reg.c */ Reg* rega(void); int rcmp(const void*, const void*); void regopt(Prog*); void addmove(Reg*, int, int, int); Bits mkvar(Adr*, int); 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 regzer(Adr*); int anyvar(Adr*); int subprop(Reg*); int copyprop(Reg*); int shiftprop(Reg*); void constprop(Adr*, Adr*, Reg*); int copy1(Adr*, Adr*, Reg*, int); int copyu(Prog*, Adr*, Adr*); int copyas(Adr*, Adr*); int copyau(Adr*, Adr*); int copyau1(Prog*, 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); void predicate(void); int isbranch(Prog *); int predicable(Prog *p); int modifiescpsr(Prog *p); #pragma varargck type "A" int #pragma varargck type "B" Bits #pragma varargck type "D" Adr* #pragma varargck type "N" Adr* #pragma varargck type "R" Adr* #pragma varargck type "P" Prog* #pragma varargck type "S" char* & nod1.xoffset == 0) gmovm(&nod1, &nod0, 0); else { gmove(&nod1, &nod3); if(w == 2) { nod1.xoffset += SZ_LONG; gmove(&nod1, &nod4); } } if(w == 2 && nod2.xoffset == 0) gmovm(&nod0, &nod2, 0); else { gmove(&nod3, &nod2); if(w == 2) { nod2.xoffset += SZ_LONG; gmove(&nod4, &nod2); } } regfree(&nod1); regfree(&nod2); regfree(&nod3); regfree(&nod4); return; } if(n->complex > nn->complex) { reglpcgen(&nod1, n, 0); reglpcgen(&nod2, nn, 0); } el5c/list.c 664 0 0 12252 7751020026 10173ustar00syssys#define EXTERN #include "gc.h" void listinit(void) { fmtinstall('A', Aconv); fmtinstall('P', Pconv); fmtinstall('S', Sconv); fmtinstall('N', Nconv); fmtinstall('B', Bconv); fmtinstall('D', Dconv); fmtinstall('R', Rconv); } int Bconv(Fmt *fp) { char str[STRINGSZ], ss[STRINGSZ], *s; Bits bits; int i; str[0] = 0; bits = va_arg(fp->args, Bits); while(bany(&bits)) { i = bnum(bits); if(str[0]) strcat(str, " "); if(var[i].sym == S) { sprint(ss, "$%ld", var[i].offset); s = ss; } else s = var[i].sym->name; if(strlen(str) + strlen(s) + 1 >= STRINGSZ) break; strcat(str, s); bits.b[i/32] &= ~(1L << (i%32)); } return fmtstrcpy(fp, str); } char *extra [] = { ".EQ", ".NE", ".CS", ".CC", ".MI", ".PL", ".VS", ".VC", ".HI", ".LS", ".GE", ".LT", ".GT", ".LE", "", ".NV", }; int Pconv(Fmt *fp) { char str[STRINGSZ], sc[20]; Prog *p; int a, s; p = va_arg(fp->args, Prog*); a = p->as; s = p->scond; strcpy(sc, extra[s & C_SCOND]); if(s & C_SBIT) strcat(sc, ".S"); if(s & C_PBIT) strcat(sc, ".P"); if(s & C_WBIT) strcat(sc, ".W"); if(s & C_UBIT) /* ambiguous with FBIT */ strcat(sc, ".U"); if(a == AMOVM) { if(p->from.type == D_CONST) sprint(str, " %A%s %R,%D", a, sc, &p->from, &p->to); else if(p->to.type == D_CONST) sprint(str, " %A%s %D,%R", a, sc, &p->from, &p->to); else sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to); } else if(a == ADATA) sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to); else if(p->as == ATEXT) sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to); else if(p->reg == NREG) sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to); else if(p->from.type != D_FREG) sprint(str, " %A%s %D,R%d,%D", a, sc, &p->from, p->reg, &p->to); else sprint(str, " %A%s %D,F%d,%D", a, sc, &p->from, p->reg, &p->to); return fmtstrcpy(fp, str); } int Aconv(Fmt *fp) { char *s; int a; a = va_arg(fp->args, int); s = "???"; if(a >= AXXX && a < ALAST) s = anames[a]; return fmtstrcpy(fp, s); } int Dconv(Fmt *fp) { char str[STRINGSZ]; Adr *a; char *op; int v; a = va_arg(fp->args, Adr*); switch(a->type) { default: sprint(str, "GOK-type(%d)", a->type); break; case D_NONE: str[0] = 0; if(a->name != D_NONE || a->reg != NREG || a->sym != S) sprint(str, "%N(R%d)(NONE)", a, a->reg); break; case D_CONST: if(a->reg != NREG) sprint(str, "$%N(R%d)", a, a->reg); else sprint(str, "$%N", a); break; case D_SHIFT: v = a->offset; op = "<<>>->@>" + (((v>>5) & 3) << 1); if(v & (1<<4)) sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15); else sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31); if(a->reg != NREG) sprint(str+strlen(str), "(R%d)", a->reg); break; case D_OREG: if(a->reg != NREG) sprint(str, "%N(R%d)", a, a->reg); else sprint(str, "%N", a); break; case D_REG: sprint(str, "R%d", a->reg); if(a->name != D_NONE || a->sym != S) sprint(str, "%N(R%d)(REG)", a, a->reg); break; case D_FREG: sprint(str, "F%d", a->reg); if(a->name != D_NONE || a->sym != S) sprint(str, "%N(R%d)(REG)", a, a->reg); break; case D_PSR: sprint(str, "PSR"); if(a->name != D_NONE || a->sym != S) sprint(str, "%N(PSR)(REG)", a); break; case D_BRANCH: sprint(str, "%ld(PC)", a->offset-pc); break; case D_FCONST: sprint(str, "$%.17e", a->dval); break; case D_SCONST: sprint(str, "$\"%S\"", a->sval); break; } return fmtstrcpy(fp, str); } int Rconv(Fmt *fp) { char str[STRINGSZ]; Adr *a; int i, v; a = va_arg(fp->args, Adr*); sprint(str, "GOK-reglist"); switch(a->type) { case D_CONST: if(a->reg != NREG) break; if(a->sym != S) break; v = a->offset; strcpy(str, ""); for(i=0; iargs, char*); p = str; for(i=0; i= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == ' ' || c == '%') { *p++ = c; continue; } *p++ = '\\'; switch(c) { case 0: *p++ = 'z'; continue; case '\\': case '"': *p++ = c; continue; case '\n': *p++ = 'n'; continue; case '\t': *p++ = 't'; continue; case '\r': *p++ = 'r'; continue; case '\f': *p++ = 'f'; continue; } *p++ = (c>>6) + '0'; *p++ = ((c>>3) & 7) + '0'; *p++ = (c & 7) + '0'; } *p = 0; return fmtstrcpy(fp, str); } int Nconv(Fmt *fp) { char str[STRINGSZ]; Adr *a; Sym *s; a = va_arg(fp->args, Adr*); s = a->sym; if(s == S) { sprint(str, "%ld", a->offset); goto out; } switch(a->name) { default: sprint(str, "GOK-name(%d)", a->name); break; case D_NONE: sprint(str, "%ld", a->offset); break; case D_EXTERN: sprint(str, "%s+%ld(SB)", s->name, a->offset); break; case D_STATIC: sprint(str, "%s<>+%ld(SB)", s->name, a->offset); break; case D_AUTO: sprint(str, "%s-%ld(SP)", s->name, -a->offset); break; case D_PARAM: sprint(str, "%s+%ld(FP)", s->name, a->offset); break; } out: return fmtstrcpy(fp, str); } fine 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 4 #define CREF 5 #define CINF 1000 #define LOOP 3 EXTERN5c/mkenam 664 0 0 160 7024572323 10207ustar00syssysed - ../5c/5.out.h <<'!' v/^ A/d ,s/^ A/ "/ g/ .*$/s/// ,s/,*$/",/ 1i char* anames[] = { . $a }; . w enam.c Q ! 5c/mkfile 664 0 0 566 10411073177 10235ustar00syssysval == v) { if(m->code[0] == 0) return 0; return m; } m++; } /* * select a spot in cache to overwrite */ multabp++; if(multabp < 0 || multabp >= nelem(multab)) multabp = 0; m = multab+multabp; m->val = v; mulval = v; /* * look in execption hint table */ a1 = 0; a2 = hintabsize; for(;;) { if(a1 >= a2) goto no; g = (a2 + a1)/2; if(v < hintab[g].val) { a2 = g; continue; } if(v > hintab[g].val) { a1 = g+1; continue; } break; } if(docode(hintab[g].hint, m->code, 1, 0)) return m; print("multiply table failure %ld\n", v); m->code[0] = 0; return 0; no: /* * try to search */ hint[0] = 0; for(g=1; g<=maxmulops; g++) { if(g >= maxmulops && v >= 65535) break; mulcp = hint+g; *mulcp = 0; if(gen1(g)) { if(docode(hint, m->code, 1, 0)) return m; print("multiply table failure %ld\n", v); break; } } /* * try a recur followed by a shift */ g = 0; while(!(v & 1)) { g++; v >>= 1; } if(g) { m1 = mulcon0(v); if(m1) { strcpy(m->code, m1->code); sprint(strchr(m->code, 0), "%c0", g+'a'); return m; } } m->code[0] = 0; return 0; } static int docode(char *hp, char *cp, int r0, int r1) { int c, i; c = *hp++; *cp = c; cp += 2; switch(c) { default: c -= 'a'; if(c < 1 || c >= 30) break; for(i=0; i<4; i++) { switch(i) { case 0: if(docode(hp, cp, r0<= mulval) break; } if(mulval == 1) return 1; len--; for(i=1; i<=shmax; i++) if(gen2(len, 1<= r1 || r1 > valmax) return 0; len--; if(len == 0) goto calcr0; if(!(flag & UR1)) { f1 = UR1|SR1; for(i=1; i<=shmax; i++) { x = r0< valmax) break; if(gen3(len, r0, x, f1)) { i += 'a'; goto out; } } } if(!(flag & UR0)) { f1 = UR1|SR1; for(i=1; i<=shmax; i++) { x = r1< valmax) break; if(gen3(len, r1, x, f1)) { i += 'a'; goto out; } } } if(!(flag & SR1)) { f1 = UR1|SR1|(flag&UR0); for(i=1; i<=shmax; i++) { x = r1< valmax) break; if(gen3(len, r0, x, f1)) { i += 'a'; goto out; } } } if(!(flag & SR0)) { f1 = UR0|SR0|(flag&(SR1|UR1)); f2 = UR1|SR1; if(flag & UR1) f2 |= UR0; if(flag & SR1) f2 |= SR0; for(i=1; i<=shmax; i++) { x = r0< valmax) break; if(x > r1) { if(gen3(len, r1, x, f2)) { i += 'a'; goto out; } } else if(gen3(len, x, r1, f1)) { i += 'a'; goto out; } } } x = r1+r0; if(gen3(len, r0, x, UR1)) { i = '+'; goto out; } if(gen3(len, r1, x, UR1)) { i = '+'; goto out; } x = r1-r0; if(gen3(len, x, r1, UR0)) { i = '-'; goto out; } if(x > r0) { if(gen3(len, r0, x, UR1)) { i = '-'; goto out; } } else if(gen3(len, x, r0, UR0)) { i = '-'; goto out; } return 0; calcr0: f1 = flag & (UR0|UR1); if(f1 == UR1) { for(i=1; i<=shmax; i++) { x = r1<= mulval) { if(x == mulval) { i += 'a'; goto out; } break; } } } if(mulval == r1+r0) { i = '+'; goto out; } if(mulval == r1-r0) { i = '-'; goto out; } return 0; out: *--mulcp = i; return 1; } /* * hint table has numbers that * the search algorithm fails on. * <1000: * all numbers * <5000: * ÷ by 5 * <10000: * ÷ by 50 * <65536: * ÷ by 250 */ Hintab hintab[] = { 683, "b++d+e+", 687, "b+e++e-", 691, "b++d+e+", 731, "b++d+e+", 811, "b++d+i+", 821, "b++e+e+", 843, "b+d++e+", 851, "b+f-+e-", 853, "b++e+e+", 877, "c++++g-", 933, "b+c++g-", 981, "c-+e-d+", 1375, "b+c+b+h-", 1675, "d+b++h+", 2425, "c++f-e+", 2675, "c+d++f-", 2750, "b+d-b+h-", 2775, "c-+g-e-", 3125, "b++e+g+", 3275, "b+c+g+e+", 3350, "c++++i+", 3475, "c-+e-f-", 3525, "c-+d+g-", 3625, "c-+e-j+", 3675, "b+d+d+e+", 3725, "b+d-+h+", 3925, "b+d+f-d-", 4275, "b+g++e+", 4325, "b+h-+d+", 4425, "b+b+g-j-", 4525, "b+d-d+f+", 4675, "c++d-g+", 4775, "b+d+b+g-", 4825, "c+c-+i-", 4850, "c++++i-", 4925, "b++e-g-", 4975, "c+f++e-", 5500, "b+g-c+d+", 6700, "d+b++i+", 9700, "d++++j-", 11000, "b+f-c-h-", 11750, "b+d+g+j-", 12500, "b+c+e-k+", 13250, "b+d+e-f+", 13750, "b+h-c-d+", 14250, "b+g-c+e-", 14500, "c+f+j-d-", 14750, "d-g--f+", 16750, "b+e-d-n+", 17750, "c+h-b+e+", 18250, "d+b+h-d+", 18750, "b+g-++f+", 19250, "b+e+b+h+", 19750, "b++h--f-", 20250, "b+e-l-c+", 20750, "c++bi+e-", 21250, "b+i+l+c+", 22000, "b+e+d-g-", 22250, "b+d-h+k-", 22750, "b+d-e-g+", 23250, "b+c+h+e-", 23500, "b+g-c-g-", 23750, "b+g-b+h-", 24250, "c++g+m-", 24750, "b+e+e+j-", 25000, "b++dh+g+", 25250, "b+e+d-g-", 25750, "b+e+b+j+", 26250, "b+h+c+e+", 26500, "b+h+c+g+", 26750, "b+d+e+g-", 27250, "b+e+e+f+", 27500, "c-i-c-d+", 27750, "b+bd++j+", 28250, "d-d-++i-", 28500, "c+c-h-e-", 29000, "b+g-d-f+", 29500, "c+h+++e-", 29750, "b+g+f-c+", 30250, "b+f-g-c+", 33500, "c-f-d-n+", 33750, "b+d-b+j-", 34250, "c+e+++i+", 35250, "e+b+d+k+", 35500, "c+e+d-g-", 35750, "c+i-++e+", 36250, "b+bh-d+e+", 36500, "c+c-h-e-", 36750, "d+e--i+", 37250, "b+g+g+b+", 37500, "b+h-b+f+", 37750, "c+be++j-", 38500, "b+e+b+i+", 38750, "d+i-b+d+", 39250, "b+g-l-+d+", 39500, "b+g-c+g-", 39750, "b+bh-c+f-", 40250, "b+bf+d+g-", 40500, "b+g-c+g+", 40750, "c+b+i-e+", 41250, "d++bf+h+", 41500, "b+j+c+d-", 41750, "c+f+b+h-", 42500, "c+h++g+", 42750, "b+g+d-f-", 43250, "b+l-e+d-", 43750, "c+bd+h+f-", 44000, "b+f+g-d-", 44250, "b+d-g--f+", 44500, "c+e+c+h+", 44750, "b+e+d-h-", 45250, "b++g+j-g+", 45500, "c+d+e-g+", 45750, "b+d-h-e-", 46250, "c+bd++j+", 46500, "b+d-c-j-", 46750, "e-e-b+g-", 47000, "b+c+d-j-", 47250, "b+e+e-g-", 47500, "b+g-c-h-", 47750, "b+f-c+h-", 48250, "d--h+n-", 48500, "b+c-g+m-", 48750, "b+e+e-g+", 49500, "c-f+e+j-", 49750, "c+c+g++f-", 50000, "b+e+e+k+", 50250, "b++i++g+", 50500, "c+g+f-i+", 50750, "b+e+d+k-", 51500, "b+i+c-f+", 51750, "b+bd+g-e-", 52250, "b+d+g-j+", 52500, "c+c+f+g+", 52750, "b+c+e+i+", 53000, "b+i+c+g+", 53500, "c+g+g-n+", 53750, "b+j+d-c+", 54250, "b+d-g-j-", 54500, "c-f+e+f+", 54750, "b+f-+c+g+", 55000, "b+g-d-g-", 55250, "b+e+e+g+", 55500, "b+cd++j+", 55750, "b+bh-d-f-", 56250, "c+d-b+j-", 56500, "c+d+c+i+", 56750, "b+e+d++h-", 57000, "b+d+g-f+", 57250, "b+f-m+d-", 57750, "b+i+c+e-", 58000, "b+e+d+h+", 58250, "c+b+g+g+", 58750, "d-e-j--e+", 59000, "d-i-+e+", 59250, "e--h-m+", 59500, "c+c-h+f-", 59750, "b+bh-e+i-", 60250, "b+bh-e-e-", 60500, "c+c-g-g-", 60750, "b+e-l-e-", 61250, "b+g-g-c+", 61750, "b+g-c+g+", 62250, "f--+c-i-", 62750, "e+f--+g+", 64750, "b+f+d+p-", }; int hintabsize = nelem(hintab); list.$O\ mul.$O\ peep.$O\ pgen.$O\ pswt.$O\ reg.$O\ sgen.$O\ swt.$O\ txt.$O\ HFILES=\ gc.h\ 5.out.h\ ../cc/cc.h\ LIB=../cc/cc.a$O BIN=/$objtype/bin 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; } } loop1: t = 0; for(r=firstr; r!=R; r=r->link) { p = r->prog; if(p->as == ASLL || p->as == ASRL || p->as == ASRA) { /* * elide shift into D_SHIFT operand of subsequent instruction */ if(shiftprop(r)) { excise(r); t++; } } if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD) if(regtyp(&p->to)) { if(p->from.type == D_CONST) constprop(&p->from, &p->to, r->s1); else if(regtyp(&p->from)) if(p->from.type == p->to.type) { if(copyprop(r)) { excise(r); t++; } else if(subprop(r) && copyprop(r)) { excise(r); t++; } } } } if(t) goto loop1; /* * look for MOVB x,R; MOVB R,R */ for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { default: continue; case AEOR: /* * EOR -1,x,y => MVN x,y */ if(p->from.type == D_CONST && p->from.offset == -1) { p->as = AMVN; p->from.type = D_REG; if(p->reg != NREG) p->from.reg = p->reg; else p->from.reg = p->to.reg; p->reg = NREG; } continue; case AMOVH: case AMOVHU: case AMOVB: case AMOVBU: if(p->to.type != D_REG) continue; break; } r1 = r->link; if(r1 == R) continue; p1 = r1->prog; if(p1->as != p->as) continue; if(p1->from.type != D_REG || p1->from.reg != p->to.reg) continue; if(p1->to.type != D_REG || p1->to.reg != p->to.reg) continue; excise(r1); } for(r=firstr; r!=R; r=r->link) { p = r->prog; switch(p->as) { case AMOVW: case AMOVB: case AMOVBU: if(p->from.type == D_OREG && p->from.offset == 0) xtramodes(r, &p->from); else if(p->to.type == D_OREG && p->to.offset == 0) xtramodes(r, &p->to); else continue; break; case ACMP: /* * elide CMP $0,x if calculation of x can set condition codes */ if(p->from.type != D_CONST || p->from.offset != 0) continue; r2 = r->s1; if(r2 == R) continue; t = r2->prog->as; switch(t) { default: continue; case ABEQ: case ABNE: case ABMI: case ABPL: break; case ABGE: t = ABPL; break; case ABLT: t = ABMI; break; case ABHI: t = ABNE; break; case ABLS: t = ABEQ; break; } r1 = r; do r1 = uniqp(r1); while (r1 != R && r1->prog->as == ANOP); if(r1 == R) continue; p1 = r1->prog; if(p1->to.type != D_REG) continue; if(p1->to.reg != p->reg) if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg)) continue; switch(p1->as) { default: continue; case AMOVW: if(p1->from.type != D_REG) continue; case AAND: case AEOR: case AORR: case ABIC: case AMVN: case ASUB: case ARSB: case AADD: case AADC: case ASBC: case ARSC: break; } p1->scond |= C_SBIT; r2->prog->as = t; excise(r); continue; } } predicate(); } void excise(Reg *r) { Prog *p; p = r->prog; p->as = ANOP; p->scond = zprog.scond; p->from = zprog.from; p->to = zprog.to; p->reg = zprog.reg; /**/ } 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) { if(a->type == D_REG) return 1; if(a->type == D_FREG) 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 ABL: return 0; case ACMP: case ACMN: case AADD: case ASUB: case ARSB: case ASLL: case ASRL: case ASRA: case AORR: case AAND: case AEOR: case AMUL: case ADIV: case ADIVU: case ACMPF: case ACMPD: case AADDD: case AADDF: case ASUBD: case ASUBF: case AMULD: case AMULF: case ADIVD: case ADIVF: if(p->to.type == v1->type) if(p->to.reg == v1->reg) { if(p->reg == NREG) p->reg = p->to.reg; goto gotit; } break; case AMOVF: case AMOVD: case AMOVW: if(p->to.type == v1->type) if(p->to.reg == v1->reg) goto gotit; break; case AMOVM: t = 1<reg; if((p->from.type == D_CONST && (p->from.offset&t)) || (p->to.type == D_CONST && (p->to.offset&t))) return 0; break; } if(copyau(&p->from, v2) || copyau1(p, v2) || copyau(&p->to, v2)) break; if(copysub(&p->from, v1, v2, 0) || copysub1(p, 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); copysub1(p, v1, v2, 1); copysub(&p->to, v1, v2, 1); if(debug['P']) print("%P\n", r->prog); } t = v1->reg; v1->reg = v2->reg; v2->reg = 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("; %Drar; return 0\n", v2); return 0; case 3: /* set */ if(debug['P']) print("; %Dset; 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("; %Dused+set and f=%d; return 0\n", v2, f); else print("; %Dused 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("; %Dused+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("; %Dset 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; } /* * The idea is to remove redundant constants. * $c1->v1 * ($c1->v2 s/$c1/v1)* * set v1 return * The v1->v2 should be eliminated by copy propagation. */ void constprop(Adr *c1, Adr *v1, Reg *r) { Prog *p; if(debug['C']) print("constprop %D->%D\n", c1, v1); for(; r != R; r = r->s1) { p = r->prog; if(debug['C']) print("%P", p); if(uniqp(r) == R) { if(debug['C']) print("; merge; return\n"); return; } if(p->as == AMOVW && copyas(&p->from, c1)) { if(debug['C']) print("; sub%D/%D", &p->from, v1); p->from = *v1; } else if(copyu(p, v1, A) > 1) { if(debug['C']) print("; %Dset; return\n", v1); return; } if(debug['C']) print("\n"); if(r->s2) constprop(c1, v1, r->s2); } } /* * ASLL x,y,w * .. (not use w, not set x y w) * AXXX w,a,b (a != w) * .. (not use w) * (set w) * ----------- changed to * .. * AXXX (x<prog; if(p->to.type != D_REG) FAIL("BOTCH: result not reg"); n = p->to.reg; a = zprog.from; if(p->reg != NREG && p->reg != p->to.reg) { a.type = D_REG; a.reg = p->reg; } if(debug['H']) print("shiftprop\n%P", p); r1 = r; for(;;) { /* find first use of shift result; abort if shift operands or result are changed */ r1 = uniqs(r1); if(r1 == R) FAIL("branch"); if(uniqp(r1) == R) FAIL("merge"); p1 = r1->prog; if(debug['H']) print("\n%P", p1); switch(copyu(p1, &p->to, A)) { case 0: /* not used or set */ if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) || (a.type == D_REG && copyu(p1, &a, A) > 1)) FAIL("args modified"); continue; case 3: /* set, not used */ FAIL("BOTCH: noref"); } break; } /* check whether substitution can be done */ switch(p1->as) { default: FAIL("non-dpi"); case AAND: case AEOR: case AADD: case AADC: case AORR: case ASUB: case ARSB: case ASBC: case ARSC: if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) { if(p1->from.type != D_REG) FAIL("can't swap"); p1->reg = p1->from.reg; p1->from.reg = n; switch(p1->as) { case ASUB: p1->as = ARSB; break; case ARSB: p1->as = ASUB; break; case ASBC: p1->as = ARSC; break; case ARSC: p1->as = ASBC; break; } if(debug['H']) print("\t=>%P", p1); } case ABIC: case ACMP: case ACMN: if(p1->reg == n) FAIL("can't swap"); if(p1->reg == NREG && p1->to.reg == n) FAIL("shift result used twice"); case AMVN: if(p1->from.type == D_SHIFT) FAIL("shift result used in shift"); if(p1->from.type != D_REG || p1->from.reg != n) FAIL("BOTCH: where is it used?"); break; } /* check whether shift result is used subsequently */ p2 = p1; if(p1->to.reg != n) for (;;) { r1 = uniqs(r1); if(r1 == R) FAIL("inconclusive"); p1 = r1->prog; if(debug['H']) print("\n%P", p1); switch(copyu(p1, &p->to, A)) { case 0: /* not used or set */ continue; case 3: /* set, not used */ break; default:/* used */ FAIL("reused"); } break; } /* make the substitution */ p2->from.type = D_SHIFT; p2->from.reg = NREG; o = p->reg; if(o == NREG) o = p->to.reg; switch(p->from.type){ case D_CONST: o |= (p->from.offset&0x1f)<<7; break; case D_REG: o |= (1<<4) | (p->from.reg<<8); break; } switch(p->as){ case ASLL: o |= 0<<5; break; case ASRL: o |= 1<<5; break; case ASRA: o |= 2<<5; break; } p2->from.offset = o; if(debug['H']) print("\t=>%P\tSUCCEED\n", p2); return 1; } Reg* findpre(Reg *r, Adr *v) { Reg *r1; for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) { if(uniqs(r1) != r) return R; switch(copyu(r1->prog, v, A)) { case 1: /* used */ case 2: /* read-alter-rewrite */ return R; case 3: /* set */ case 4: /* set and used */ return r1; } } return R; } Reg* findinc(Reg *r, Reg *r2, Adr *v) { Reg *r1; Prog *p; for(r1=uniqs(r); r1!=R && r1!=r2; r=r1,r1=uniqs(r)) { if(uniqp(r1) != r) return R; switch(copyu(r1->prog, v, A)) { case 0: /* not touched */ continue; case 4: /* set and used */ p = r1->prog; if(p->as == AADD) if(p->from.type == D_CONST) if(p->from.offset > -4096 && p->from.offset < 4096) return r1; default: return R; } } return R; } int nochange(Reg *r, Reg *r2, Prog *p) { Adr a[3]; int i, n; if(r == r2) return 1; n = 0; if(p->reg != NREG && p->reg != p->to.reg) { a[n].type = D_REG; a[n++].reg = p->reg; } switch(p->from.type) { case D_SHIFT: a[n].type = D_REG; a[n++].reg = p->from.offset&0xf; case D_REG: a[n].type = D_REG; a[n++].reg = p->from.reg; } if(n == 0) return 1; for(; r!=R && r!=r2; r=uniqs(r)) { p = r->prog; for(i=0; i 1) return 0; } return 1; } int findu1(Reg *r, Adr *v) { for(; r != R; r = r->s1) { if(r->active) return 0; r->active = 1; switch(copyu(r->prog, v, A)) { case 1: /* used */ case 2: /* read-alter-rewrite */ case 4: /* set and used */ return 1; case 3: /* set */ return 0; } if(r->s2) if (findu1(r->s2, v)) return 1; } return 0; } int finduse(Reg *r, Adr *v) { Reg *r1; for(r1=firstr; r1!=R; r1=r1->link) r1->active = 0; return findu1(r, v); } int xtramodes(Reg *r, Adr *a) { Reg *r1, *r2, *r3; Prog *p, *p1; Adr v; p = r->prog; if(debug['h'] && p->as == AMOVB && p->from.type == D_OREG) /* byte load */ return 0; v = *a; v.type = D_REG; r1 = findpre(r, &v); if(r1 != R) { p1 = r1->prog; if(p1->to.type == D_REG && p1->to.reg == v.reg) switch(p1->as) { case AADD: if(p1->from.type == D_REG || (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 && (p->as != AMOVB || (a == &p->from && (p1->from.offset&~0xf) == 0))) || (p1->from.type == D_CONST && p1->from.offset > -4096 && p1->from.offset < 4096)) if(nochange(uniqs(r1), r, p1)) { if(a != &p->from || v.reg != p->to.reg) if (finduse(r->s1, &v)) { if(p1->reg == NREG || p1->reg == v.reg) /* pre-indexing */ p->scond |= C_WBIT; else return 0; } switch (p1->from.type) { case D_REG: /* register offset */ a->type = D_SHIFT; a->offset = p1->from.reg; break; case D_SHIFT: /* scaled register offset */ a->type = D_SHIFT; case D_CONST: /* immediate offset */ a->offset = p1->from.offset; break; } if(p1->reg != NREG) a->reg = p1->reg; excise(r1); return 1; } break; case AMOVW: if(p1->from.type == D_REG) if((r2 = findinc(r1, r, &p1->from)) != R) { for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3)) ; if(r3 == r) { /* post-indexing */ p1 = r2->prog; a->reg = p1->to.reg; a->offset = p1->from.offset; p->scond |= C_PBIT; if(!finduse(r, &r1->prog->to)) excise(r1); excise(r2); return 1; } } break; } } if(a != &p->from || a->reg != p->to.reg) if((r1 = findinc(r, R, &v)) != R) { /* post-indexing */ p1 = r1->prog; a->offset = p1->from.offset; p->scond |= C_PBIT; excise(r1); return 1; } return 0; } /* * 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(" (???)"); return 2; case AMOVM: if(v->type != D_REG) return 0; if(p->from.type == D_CONST) { /* read reglist, read/rar */ if(s != A) { if(p->from.offset&(1<reg)) return 1; if(copysub(&p->to, v, s, 1)) return 1; return 0; } if(copyau(&p->to, v)) { if(p->scond&C_WBIT) return 2; return 1; } if(p->from.offset&(1<reg)) return 1; } else { /* read/rar, write reglist */ if(s != A) { if(p->to.offset&(1<reg)) return 1; if(copysub(&p->from, v, s, 1)) return 1; return 0; } if(copyau(&p->from, v)) { if(p->scond&C_WBIT) return 2; if(p->to.offset&(1<reg)) return 4; return 1; } if(p->to.offset&(1<reg)) return 3; } return 0; case ANOP: /* read, write */ case AMOVW: case AMOVF: case AMOVD: case AMOVH: case AMOVHU: case AMOVB: case AMOVBU: case AMOVDW: case AMOVWD: case AMOVFD: case AMOVDF: if(p->scond&(C_WBIT|C_PBIT)) if(v->type == D_REG) { if(p->from.type == D_OREG || p->from.type == D_SHIFT) { if(p->from.reg == v->reg) return 2; } else { if(p->to.reg == v->reg) return 2; } } if(s != A) { if(copysub(&p->from, v, s, 1)) return 1; if(!copyas(&p->to, v)) if(copysub(&p->to, v, s, 1)) return 1; return 0; } if(copyas(&p->to, v)) { if(copyau(&p->from, v)) return 4; return 3; } if(copyau(&p->from, v)) return 1; if(copyau(&p->to, v)) return 1; return 0; case AADD: /* read, read, write */ case ASUB: case ARSB: case ASLL: case ASRL: case ASRA: case AORR: case AAND: case AEOR: case AMUL: case ADIV: case ADIVU: case AADDF: case AADDD: case ASUBF: case ASUBD: case AMULF: case AMULD: case ADIVF: case ADIVD: case ACMPF: case ACMPD: case ACMP: case ACMN: case ACASE: if(s != A) { if(copysub(&p->from, v, s, 1)) return 1; if(copysub1(p, v, s, 1)) return 1; if(!copyas(&p->to, v)) if(copysub(&p->to, v, s, 1)) return 1; return 0; } if(copyas(&p->to, v)) { if(p->reg == NREG) p->reg = p->to.reg; if(copyau(&p->from, v)) return 4; if(copyau1(p, v)) return 4; return 3; } if(copyau(&p->from, v)) return 1; if(copyau1(p, v)) return 1; if(copyau(&p->to, v)) return 1; return 0; case ABEQ: /* read, read */ case ABNE: case ABCS: case ABHS: case ABCC: case ABLO: case ABMI: case ABPL: case ABVS: case ABVC: case ABHI: case ABLS: case ABGE: case ABLT: case ABGT: case ABLE: if(s != A) { if(copysub(&p->from, v, s, 1)) return 1; return copysub1(p, v, s, 1); } if(copyau(&p->from, v)) return 1; if(copyau1(p, v)) return 1; return 0; case AB: /* 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 == D_REG) if(v->reg == REGRET) return 2; if(v->type == D_FREG) if(v->reg == FREGRET) return 2; case ABL: /* funny */ if(v->type == D_REG) { if(v->reg <= REGEXT && v->reg > exregoffset) return 2; if(v->reg == REGARG) return 2; } if(v->type == D_FREG) if(v->reg <= FREGEXT && v->reg > exfregoffset) 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(v->type == D_REG) if(v->reg == REGARG) return 3; return 0; } } int a2type(Prog *p) { switch(p->as) { case ACMP: case ACMN: case AADD: case ASUB: case ARSB: case ASLL: case ASRL: case ASRA: case AORR: case AAND: case AEOR: case AMUL: case ADIV: case ADIVU: return D_REG; case ACMPF: case ACMPD: case AADDF: case AADDD: case ASUBF: case ASUBD: case AMULF: case AMULD: case ADIVF: case ADIVD: return D_FREG; } return D_NONE; } /* * direct reference, * could be set/use depending on * semantics */ int copyas(Adr *a, Adr *v) { if(regtyp(v)) { if(a->type == v->type) if(a->reg == v->reg) return 1; } else if(v->type == D_CONST) { /* for constprop */ if(a->type == v->type) if(a->name == v->name) if(a->sym == v->sym) if(a->reg == v->reg) if(a->offset == v->offset) return 1; } return 0; } /* * either direct or indirect */ int copyau(Adr *a, Adr *v) { if(copyas(a, v)) return 1; if(v->type == D_REG) { if(a->type == D_OREG) { if(v->reg == a->reg) return 1; } else if(a->type == D_SHIFT) { if((a->offset&0xf) == v->reg) return 1; if((a->offset&(1<<4)) && (a->offset>>8) == v->reg) return 1; } } return 0; } int copyau1(Prog *p, Adr *v) { if(regtyp(v)) { if(a2type(p) == v->type) if(p->reg == v->reg) { if(a2type(p) != v->type) print("botch a2type %P\n", p); return 1; } } return 0; } /* * substitute s for v in a * return failure to substitute */ int copysub(Adr *a, Adr *v, Adr *s, int f) { if(f) if(copyau(a, v)) { if(a->type == D_SHIFT) { if((a->offset&0xf) == v->reg) a->offset = (a->offset&~0xf)|s->reg; if((a->offset&(1<<4)) && (a->offset>>8) == v->reg) a->offset = (a->offset&~(0xf<<8))|(s->reg<<8); } else a->reg = s->reg; } return 0; } int copysub1(Prog *p1, Adr *v, Adr *s, int f) { if(f) if(copyau1(p1, v)) p1->reg = s->reg; return 0; } struct { int opcode; int notopcode; int scond; int notscond; } predinfo[] = { { ABEQ, ABNE, 0x0, 0x1, }, { ABNE, ABEQ, 0x1, 0x0, }, { ABCS, ABCC, 0x2, 0x3, }, { ABHS, ABLO, 0x2, 0x3, }, { ABCC, ABCS, 0x3, 0x2, }, { ABLO, ABHS, 0x3, 0x2, }, { ABMI, ABPL, 0x4, 0x5, }, { ABPL, ABMI, 0x5, 0x4, }, { ABVS, ABVC, 0x6, 0x7, }, { ABVC, ABVS, 0x7, 0x6, }, { ABHI, ABLS, 0x8, 0x9, }, { ABLS, ABHI, 0x9, 0x8, }, { ABGE, ABLT, 0xA, 0xB, }, { ABLT, ABGE, 0xB, 0xA, }, { ABGT, ABLE, 0xC, 0xD, }, { ABLE, ABGT, 0xD, 0xC, }, }; typedef struct { Reg *start; Reg *last; Reg *end; int len; } Joininfo; enum { Join, Split, End, Branch, Setcond, Toolong }; enum { Falsecond, Truecond, Delbranch, Keepbranch }; int isbranch(Prog *p) { return (ABEQ <= p->as) && (p->as <= ABLE); } int predicable(Prog *p) { if (isbranch(p) || p->as == ANOP || p->as == AXXX || p->as == ADATA || p->as == AGLOBL || p->as == AGOK || p->as == AHISTORY || p->as == ANAME || p->as == ASIGNAME || p->as == ATEXT || p->as == AWORD || p->as == ADYNT || p->as == AINIT || p->as == ABCASE || p->as == ACASE) return 0; return 1; } /* * Depends on an analysis of the encodings performed by 5l. * These seem to be all of the opcodes that lead to the "S" bit * being set in the instruction encodings. * * C_SBIT may also have been set explicitly in p->scond. */ int modifiescpsr(Prog *p) { return (p->scond&C_SBIT) || p->as == ATST || p->as == ATEQ || p->as == ACMN || p->as == ACMP || p->as == AMULU || p->as == ADIVU || p->as == AMUL || p->as == ADIV || p->as == AMOD || p->as == AMODU || p->as == ABL; } /* * Find the maximal chain of instructions starting with r which could * be executed conditionally */ int joinsplit(Reg *r, Joininfo *j) { j->start = r; j->last = r; j->len = 0; do { if (r->p2 && (r->p1 || r->p2->p2link)) { j->end = r; return Join; } if (r->s1 && r->s2) { j->end = r; return Split; } j->last = r; if (r->prog->as != ANOP) j->len++; if (!r->s1 && !r->s2) { j->end = r->link; return End; } if (r->s2) { j->end = r->s2; return Branch; } if (modifiescpsr(r->prog)) { j->end = r->s1; return Setcond; } r = r->s1; } while (j->len < 4); j->end = r; return Toolong; } Reg * successor(Reg *r) { if (r->s1) return r->s1; else return r->s2; } void applypred(Reg *rstart, Joininfo *j, int cond, int branch) { int pred; Reg *r; if(j->len == 0) return; if (cond == Truecond) pred = predinfo[rstart->prog->as - ABEQ].scond; else pred = predinfo[rstart->prog->as - ABEQ].notscond; for (r = j->start; ; r = successor(r)) { if (r->prog->as == AB) { if (r != j->last || branch == Delbranch) excise(r); else { if (cond == Truecond) r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode; else r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode; } } else if (predicable(r->prog)) r->prog->scond = (r->prog->scond&~C_SCOND)|pred; if (r->s1 != r->link) { r->s1 = r->link; r->link->p1 = r; } if (r == j->last) break; } } void predicate(void) { Reg *r; int t1, t2; Joininfo j1, j2; for(r=firstr; r!=R; r=r->link) { if (isbranch(r->prog)) { t1 = joinsplit(r->s1, &j1); t2 = joinsplit(r->s2, &j2); if(j1.last->link != j2.start) continue; if(j1.end == j2.end) if((t1 == Branch && (t2 == Join || t2 == Setcond)) || (t2 == Join && (t1 == Join || t1 == Setcond))) { applypred(r, &j1, Falsecond, Delbranch); applypred(r, &j2, Truecond, Delbranch); excise(r); continue; } if(t1 == End || t1 == Branch) { applypred(r, &j1, Falsecond, Keepbranch); excise(r); continue; } } } } ; case D_SHIFT: /* scaled register offset */ a->type = D_SHIFT; case D_CONST: /* immediate offs5c/reg.c 664 0 0 46052 10645763400 10030ustar00syssys#include "gc.h" void addsplits(void); 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 = 0; 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 AB: case ARFE: r->p1 = R; r1->s1 = R; } /* * left side always read */ bit = mkvar(&p->from, p->as==AMOVW); for(z=0; zuse1.b[z] |= bit.b[z]; /* * right side depends on opcode */ bit = mkvar(&p->to, 0); if(bany(&bit)) switch(p->as) { default: diag(Z, "reg: unknown asop: %A", p->as); break; /* * right side write */ case ANOP: case AMOVB: case AMOVBU: case AMOVH: case AMOVHU: case AMOVW: case AMOVF: case AMOVD: for(z=0; zset.b[z] |= bit.b[z]; break; /* * funny */ case ABL: for(z=0; zas == AMOVM) { if(p->from.type == D_CONST) z = p->from.offset; else z = p->to.offset; for(i=0; z; i++) { if(z&1) regbits |= RtoB(i); z >>= 1; } } } 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); /* * 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; addsplits(); if(debug['R'] && debug['v']) { print("\nprop structure:\n"); for(r = firstr; r != R; r = r->link) { print("%ld:%P", r->loop, r->prog); for(z=0; zset.b[z] | r->refahead.b[z] | r->calahead.b[z] | r->refbehind.b[z] | r->calbehind.b[z] | r->use1.b[z] | r->use2.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); if(bany(&r->refahead)) print(" ra=%B", r->refahead); if(bany(&r->calahead)) print(" ca=%B", r->calahead); if(bany(&r->refbehind)) print(" rb=%B", r->refbehind); if(bany(&r->calbehind)) print(" cb=%B", r->calbehind); } print("\n"); } } /* * 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); } } for(r = firstr; r != R; r = r->link) r->act = zbits; rgp = region; nregion = 0; for(r = firstr; r != R; r = r->link) { 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']) { if(rgp->regno >= NREG) print("%L $%d F%d: %B\n", rgp->enter->prog->lineno, rgp->cost, rgp->regno-NREG, bit); else print("%L $%d R%d: %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; } } void addsplits(void) { Reg *r, *r1; int z, i; Bits bit; for(r = firstr; r != R; r = r->link) { if(r->loop > 1) continue; if(r->prog->as == ABL) continue; for(r1 = r->p2; r1 != R; r1 = r1->p2link) { if(r1->loop <= 1) continue; for(z=0; zcalbehind.b[z] & (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) & ~(r->calahead.b[z] & addrs.b[z]); while(bany(&bit)) { i = bnum(bit); bit.b[i/32] &= ~(1L << (i%32)); } } } } /* * 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->name = v->name; a->offset = v->offset; a->etype = v->etype; a->type = D_OREG; if(a->etype == TARRAY || a->sym == S) a->type = D_CONST; p1->as = AMOVW; if(v->etype == TCHAR || v->etype == TUCHAR) p1->as = AMOVB; if(v->etype == TSHORT || v->etype == TUSHORT) p1->as = AMOVH; if(v->etype == TFLOAT) p1->as = AMOVF; if(v->etype == TDOUBLE) p1->as = AMOVD; p1->from.type = D_REG; p1->from.reg = rn; if(rn >= NREG) { p1->from.type = D_FREG; p1->from.reg = rn-NREG; } if(!f) { p1->from = *a; *a = zprog.from; a->type = D_REG; a->reg = rn; if(rn >= NREG) { a->type = D_FREG; a->reg = rn-NREG; } if(v->etype == TUCHAR) p1->as = AMOVBU; if(v->etype == TUSHORT) p1->as = AMOVHU; } if(debug['R']) print("%P\t.a%P\n", p, p1); } Bits mkvar(Adr *a, int docon) { Var *v; int i, t, n, et, z; long o; Bits bit; Sym *s; t = a->type; if(t == D_REG && a->reg != NREG) regbits |= RtoB(a->reg); if(t == D_FREG && a->reg != NREG) regbits |= FtoB(a->reg); s = a->sym; o = a->offset; et = a->etype; if(s == S) { if(t != D_CONST || !docon || a->reg != NREG) goto none; et = TLONG; } if(t == D_CONST) { if(s == S && sval(o)) goto none; } n = a->name; v = var; for(i=0; isym) if(n == v->name) if(o == v->offset) goto out; v++; } if(s) if(s->name[0] == '.') goto none; 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->etype = et; v->name = n; 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]) /* 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 ABL: 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 TIND: case TARRAY: i = BtoR(~b); if(i && r->cost >= 0) { r->regno = i; return RtoB(i); } break; case TVLONG: case TDOUBLE: case TFLOAT: i = BtoF(~b); if(i && r->cost >= 0) { r->regno = i+NREG; 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 paint2(Reg *r, int bn) { Reg *r1; int z; ulong bb, vreg; 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; } 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->name = D_NONE; a->type = D_REG; a->reg = rn; if(rn >= NREG) { a->type = D_FREG; a->reg = rn-NREG; } } /* * bit reg * 0 R0 * 1 R1 * ... ... * 10 R10 */ long RtoB(int r) { if(r >= REGMIN && r <= REGMAX) return 1L << r; return 0; } int BtoR(long b) { b &= 0x01fcL; if(b == 0) return 0; return bitno(b); } /* * bit reg * 18 F2 * 19 F3 * ... ... * 23 F7 */ long FtoB(int f) { if(f < 2 || f > NFREG-1) return 0; return 1L << (f + 16); } int BtoF(long b) { b &= 0xfc0000L; if(b == 0) return 0; return bitno(b) - 16; } } if(debug['R']) print("%P\t.a%P\n", p, p1); } Bits mkvar(Adr *a, int docon) { Var *v; int i, t, n, et, z; long o; Bits bit; Sym *s; t = a->type; if(t == D_REG && a->reg != NREG) regbits |= RtoB(a->reg); if(t == D_FREG && a->reg != NREG) regbits |= FtoB(a->reg); s = a->sym; o = a->offset; et = a->etype; if(s == S) { if(t != D_CONST || !docon || a->reg != NREG) goto none; et = TLONG; } if(t == D_CONST) { if(s == S && sval(o)) goto5c/sgen.c 664 0 0 5772 10411076200 10155ustar00syssys#include "gc.h" void noretval(int n) { if(n & 1) { gins(ANOP, Z, Z); p->to.type = D_REG; p->to.reg = REGRET; } if(n & 2) { gins(ANOP, Z, Z); p->to.type = D_FREG; p->to.reg = FREGRET; } } /* * calculate addressability as follows * CONST ==> 20 $value * NAME ==> 10 name * REGISTER ==> 11 register * INDREG ==> 12 *[(reg)+offset] * &10 ==> 2 $name * ADD(2, 20) ==> 2 $name+offset * ADD(3, 20) ==> 3 $(reg)+offset * &12 ==> 3 $(reg)+offset * *11 ==> 11 ?? * *2 ==> 10 name * *3 ==> 12 *(reg)+offset * calculate complexity (number of registers) */ void xcom(Node *n) { Node *l, *r; int t; if(n == Z) return; l = n->left; r = n->right; n->addable = 0; n->complex = 0; switch(n->op) { case OCONST: n->addable = 20; return; case OREGISTER: n->addable = 11; return; case OINDREG: n->addable = 12; return; case ONAME: n->addable = 10; return; case OADDR: xcom(l); if(l->addable == 10) n->addable = 2; if(l->addable == 12) n->addable = 3; break; case OIND: xcom(l); if(l->addable == 11) n->addable = 12; if(l->addable == 3) n->addable = 12; if(l->addable == 2) n->addable = 10; break; case OADD: xcom(l); xcom(r); if(l->addable == 20) { if(r->addable == 2) n->addable = 2; if(r->addable == 3) n->addable = 3; } if(r->addable == 20) { if(l->addable == 2) n->addable = 2; if(l->addable == 3) n->addable = 3; } break; case OASLMUL: case OASMUL: xcom(l); xcom(r); t = vlog(r); if(t >= 0) { n->op = OASASHL; r->vconst = t; r->type = types[TINT]; } break; case OMUL: case OLMUL: xcom(l); xcom(r); t = vlog(r); if(t >= 0) { n->op = OASHL; r->vconst = t; r->type = types[TINT]; } t = vlog(l); if(t >= 0) { n->op = OASHL; n->left = r; n->right = l; r = l; l = n->left; r->vconst = t; r->type = types[TINT]; } break; case OASLDIV: xcom(l); xcom(r); t = vlog(r); if(t >= 0) { n->op = OASLSHR; r->vconst = t; r->type = types[TINT]; } break; case OLDIV: xcom(l); xcom(r); t = vlog(r); if(t >= 0) { n->op = OLSHR; r->vconst = t; r->type = types[TINT]; } break; case OASLMOD: xcom(l); xcom(r); t = vlog(r); if(t >= 0) { n->op = OASAND; r->vconst--; } break; case OLMOD: xcom(l); xcom(r); t = vlog(r); if(t >= 0) { n->op = OAND; r->vconst--; } break; default: if(l != Z) xcom(l); if(r != Z) xcom(r); break; } if(n->addable >= 10) return; if(l != Z) n->complex = l->complex; if(r != Z) { if(r->complex == n->complex) n->complex = r->complex+1; else if(r->complex > n->complex) n->complex = r->complex; } if(n->complex == 0) n->complex++; if(com64(n)) return; switch(n->op) { case OFUNC: n->complex = FNX; break; case OADD: case OXOR: case OAND: case OOR: case OEQ: case ONE: /* * immediate operators, make const on right */ if(l->op == OCONST) { n->left = r; n->right = l; } break; } } o)) 5c/swt.c 664 0 0 25424 10411525326 10062ustar00syssys#include "gc.h" void swit1(C1 *q, int nc, long def, Node *n) { Node tn; regalloc(&tn, ®node, Z); swit2(q, nc, def, n, &tn); regfree(&tn); } void swit2(C1 *q, int nc, long def, Node *n, Node *tn) { C1 *r; int i; long v; Prog *sp; if(nc >= 3) { i = (q+nc-1)->val - (q+0)->val; if(i > 0 && i < nc*2) goto direct; } if(nc < 5) { for(i=0; ival); gopcode(OEQ, nodconst(q->val), n, Z); patch(p, q->label); q++; } gbranch(OGOTO); patch(p, def); return; } i = nc / 2; r = q+i; if(debug['W']) print("case > %.8lux\n", r->val); gopcode(OGT, nodconst(r->val), n, Z); sp = p; gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */ patch(p, r->label); swit2(q, i, def, n, tn); if(debug['W']) print("case < %.8lux\n", r->val); patch(sp, pc); swit2(r+1, nc-i-1, def, n, tn); return; direct: v = q->val; if(v != 0) gopcode(OSUB, nodconst(v), Z, n); gopcode(OCASE, nodconst((q+nc-1)->val - v), n, Z); patch(p, def); for(i=0; ival); while(q->val != v) { nextpc(); p->as = ABCASE; patch(p, def); v++; } nextpc(); p->as = ABCASE; patch(p, q->label); q++; v++; } gbranch(OGOTO); /* so that regopt() won't be confused */ patch(p, def); } 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); gopcode(OAS, n2, Z, n3); gopcode(OAS, n3, Z, 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, nodconst(v), Z, n1); } else { sh = 32 - b->type->shift - b->type->nbits; if(sh > 0) gopcode(OASHL, nodconst(sh), Z, n1); sh += b->type->shift; if(sh > 0) if(typeu[b->type->etype]) gopcode(OLSHR, nodconst(sh), Z, n1); else gopcode(OASHR, nodconst(sh), Z, n1); } } void bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) { long v; Node nod, *l; int sh; /* * n1 has adjusted/masked value * n2 has address of cell * n3 has contents of cell */ l = b->left; regalloc(&nod, l, Z); v = ~0 + (1L << b->type->nbits); gopcode(OAND, nodconst(v), Z, n1); gopcode(OAS, n1, Z, &nod); if(nn != Z) gopcode(OAS, n1, Z, nn); sh = b->type->shift; if(sh > 0) gopcode(OASHL, nodconst(sh), Z, &nod); v <<= sh; gopcode(OAND, nodconst(~v), Z, n3); gopcode(OOR, n3, Z, &nod); gopcode(OAS, &nod, Z, 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->reg = NSNAME; p->to.type = D_SCONST; memmove(p->to.sval, string, NSNAME); mnstring = 0; } n--; } return r; } int mulcon(Node *n, Node *nn) { Node *l, *r, nod1, nod2; Multab *m; long v, vs; int o; char code[sizeof(m->code)+2], *p; if(typefd[n->type->etype]) return 0; l = n->left; r = n->right; if(l->op == OCONST) { l = r; r = n->left; } if(r->op != OCONST) return 0; v = convvtox(r->vconst, n->type->etype); if(v != r->vconst) { if(debug['M']) print("%L multiply conv: %lld\n", n->lineno, r->vconst); return 0; } m = mulcon0(v); if(!m) { if(debug['M']) print("%L multiply table: %lld\n", n->lineno, r->vconst); return 0; } if(debug['M'] && debug['v']) print("%L multiply: %ld\n", n->lineno, v); memmove(code, m->code, sizeof(m->code)); code[sizeof(m->code)] = 0; p = code; if(p[1] == 'i') p += 2; regalloc(&nod1, n, nn); cgen(l, &nod1); vs = v; regalloc(&nod2, n, Z); loop: switch(*p) { case 0: regfree(&nod2); if(vs < 0) { gopcode(OAS, &nod1, Z, &nod1); gopcode(OSUB, &nod1, nodconst(0), nn); } else gopcode(OAS, &nod1, Z, nn); regfree(&nod1); return 1; case '+': o = OADD; goto addsub; case '-': o = OSUB; addsub: /* number is r,n,l */ v = p[1] - '0'; r = &nod1; if(v&4) r = &nod2; n = &nod1; if(v&2) n = &nod2; l = &nod1; if(v&1) l = &nod2; gopcode(o, l, n, r); break; default: /* op is shiftcount, number is r,l */ v = p[1] - '0'; r = &nod1; if(v&2) r = &nod2; l = &nod1; if(v&1) l = &nod2; v = *p - 'a'; if(v < 0 || v >= 32) { diag(n, "mulcon unknown op: %c%c", p[0], p[1]); break; } gopcode(OASHL, nodconst(v), l, r); break; } p += 2; goto loop; } void sextern(Sym *s, Node *a, long o, long w) { long e, lw; for(e=0; efrom.offset += o+e; p->reg = lw; p->to.type = D_SCONST; memmove(p->to.sval, a->cstring+e, lw); } } void gextern(Sym *s, Node *a, long o, long w) { if(a->op == OCONST && typev[a->type->etype]) { if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ gpseudo(ADATA, s, nod32const(a->vconst>>32)); else gpseudo(ADATA, s, nod32const(a->vconst)); p->from.offset += o; p->reg = 4; if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ gpseudo(ADATA, s, nod32const(a->vconst)); else gpseudo(ADATA, s, nod32const(a->vconst>>32)); p->from.offset += o + 4; p->reg = 4; return; } gpseudo(ADATA, s, a); p->from.offset += o; p->reg = w; if(p->to.type == D_OREG) p->to.type = D_CONST; } void zname(Biobuf*, Sym*, int); char* zaddr(char*, Adr*, int); void zwrite(Biobuf*, Prog*, int, int); void outhist(Biobuf*); void zwrite(Biobuf *b, Prog *p, int sf, int st) { char bf[100], *bp; bf[0] = p->as; bf[1] = p->scond; bf[2] = p->reg; bf[3] = p->lineno; bf[4] = p->lineno>>8; bf[5] = p->lineno>>16; bf[6] = p->lineno>>24; bp = zaddr(bf+7, &p->from, sf); bp = zaddr(bp, &p->to, st); Bwrite(b, bf, bp-bf); } void outcode(void) { struct { Sym *sym; short type; } h[NSYM]; Prog *p; Sym *s; int sf, st, t, sym; 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++; } } outhist(&outbuf); 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.name; if(h[sf].type == t) if(h[sf].sym == s) break; s->sym = sym; zname(&outbuf, 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.name; if(h[st].type == t) if(h[st].sym == s) break; s->sym = sym; zname(&outbuf, s, t); h[sym].sym = s; h[sym].type = t; st = sym; sym++; if(sym >= NSYM) sym = 1; if(st == sf) goto jackpot; break; } zwrite(&outbuf, p, sf, st); } 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, 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; zwrite(b, &pg, 0, 0); } } void zname(Biobuf *b, Sym *s, int t) { char *n, bf[7]; ulong sig; n = s->name; if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ sig = sign(s); bf[0] = ASIGNAME; bf[1] = sig; bf[2] = sig>>8; bf[3] = sig>>16; bf[4] = sig>>24; bf[5] = t; bf[6] = s->sym; Bwrite(b, bf, 7); s->sig = SIGDONE; } else{ bf[0] = ANAME; bf[1] = t; /* type */ bf[2] = s->sym; /* sym */ Bwrite(b, bf, 3); } Bwrite(b, n, strlen(n)+1); } char* zaddr(char *bp, Adr *a, int s) { long l; Ieee e; bp[0] = a->type; bp[1] = a->reg; bp[2] = s; bp[3] = a->name; bp += 4; switch(a->type) { default: diag(Z, "unknown type %d in zaddr", a->type); case D_NONE: case D_REG: case D_FREG: case D_PSR: break; case D_OREG: case D_CONST: case D_BRANCH: case D_SHIFT: l = a->offset; bp[0] = l; bp[1] = l>>8; bp[2] = l>>16; bp[3] = l>>24; bp += 4; break; case D_SCONST: memmove(bp, a->sval, NSNAME); bp += NSNAME; break; case D_FCONST: ieeedtod(&e, a->dval); l = e.l; bp[0] = l; bp[1] = l>>8; bp[2] = l>>16; bp[3] = l>>24; bp += 4; l = e.h; bp[0] = l; bp[1] = l>>8; bp[2] = l>>16; bp[3] = l>>24; bp += 4; break; } return bp; } long align(long i, Type *t, int op) { long o; Type *v; int w; o = i; w = 1; switch(op) { default: diag(Z, "unknown align opcode %d", op); break; case Asu2: /* padding at end of a struct */ w = SZ_LONG; if(packflg) w = packflg; break; case Ael1: /* initial allign of struct element */ for(v=t; v->etype==TARRAY; v=v->link) ; w = ewidth[v->etype]; if(w <= 0 || w >= SZ_LONG) w = SZ_LONG; if(packflg) w = packflg; break; case Ael2: /* width of a struct element */ o += t->width; break; case Aarg0: /* initial passbyptr argument in arg list */ if(typesuv[t->etype]) { o = align(o, types[TIND], Aarg1); o = align(o, types[TIND], Aarg2); } break; case Aarg1: /* initial allign of parameter */ w = ewidth[t->etype]; if(w <= 0 || w >= SZ_LONG) { w = SZ_LONG; break; } w = 1; /* little endian no adjustment */ break; case Aarg2: /* width of a parameter */ o += t->width; w = SZ_LONG; break; case Aaut3: /* total allign of automatic */ o = align(o, t, Ael2); o = align(o, t, Ael1); w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */ break; } o = round(o, w); if(debug['A']) print("align %s %ld %T = %ld\n", bnames[op], i, t, o); return o; } long maxround(long max, long v) { v = round(v, SZ_LONG); if(v > max) return v; return max; } if(debug['W']) print("case < %.8lux\n", r->val); patch(sp, pc); swit2(r+1, nc-i-1, def, n, tn); return; direct: v = q->val; if(v != 0) gopcode(OSUB, nodconst(v), Z, n); gopcode(OCASE, nodconst((q+nc-1)->val - v), n, Z); p5c/txt.c 664 0 0 46604 11450001126 10056ustar00syssys#include "gc.h" static char resvreg[nelem(reg)]; void ginit(void) { Type *t; thechar = '5'; thestring = "arm"; 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[TLONG]; zprog.link = P; zprog.as = AGOK; zprog.reg = NREG; zprog.from.type = D_NONE; zprog.from.name = D_NONE; zprog.from.reg = NREG; zprog.to = zprog.from; zprog.scond = 0xE; regnode.op = OREGISTER; regnode.class = CEXREG; regnode.reg = REGTMP; regnode.complex = 0; regnode.addable = 11; regnode.type = types[TLONG]; constnode.op = OCONST; constnode.class = CXXX; constnode.complex = 0; constnode.addable = 20; constnode.type = types[TLONG]; fconstnode.op = OCONST; fconstnode.class = CXXX; fconstnode.complex = 0; fconstnode.addable = 20; fconstnode.type = types[TDOUBLE]; nodsafe = new(ONAME, Z, Z); nodsafe->sym = slookup(".safe"); nodsafe->type = types[TINT]; nodsafe->etype = types[TINT]->etype; nodsafe->class = CAUTO; complex(nodsafe); t = typ(TARRAY, types[TCHAR]); symrathole = slookup(".rathole"); symrathole->class = CGLOBL; symrathole->type = t; nodrat = new(ONAME, Z, Z); nodrat->sym = symrathole; nodrat->type = types[TIND]; nodrat->etype = TVOID; nodrat->class = CGLOBL; complex(nodrat); nodrat->type = t; nodret = new(ONAME, Z, Z); nodret->sym = slookup(".ret"); nodret->type = types[TIND]; nodret->etype = TIND; nodret->class = CPARAM; nodret = new(OIND, nodret, Z); complex(nodret); com64init(); memset(reg, 0, sizeof(reg)); /* don't allocate */ reg[REGTMP] = 1; reg[REGSB] = 1; reg[REGSP] = 1; reg[REGLINK] = 1; reg[REGPC] = 1; /* keep two external registers */ reg[REGEXT] = 1; reg[REGEXT-1] = 1; memmove(resvreg, reg, sizeof(reg)); } void gclean(void) { int i; Sym *s; for(i=0; itype->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; } 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(typesuv[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 >= 0 && curarg == 0 && typechlp[n->type->etype]) { regaalloc1(tn1, n); if(n->complex >= FNX) { cgen(*fnxp, tn1); (*fnxp)++; } else cgen(n, tn1); return; } regalloc(tn1, n, Z); if(n->complex >= FNX) { cgen(*fnxp, tn1); (*fnxp)++; } else cgen(n, tn1); regaalloc(tn2, n); gopcode(OAS, tn1, Z, tn2); regfree(tn1); } Node* nodconst(long v) { constnode.vconst = v; return &constnode; } Node* nod32const(vlong v) { constnode.vconst = v & MASK(32); return &constnode; } Node* nodfconst(double d) { fconstnode.fconst = d; return &fconstnode; } void nodreg(Node *n, Node *nn, int reg) { *n = regnode; n->reg = reg; n->type = nn->type; n->lineno = nn->lineno; } void regret(Node *n, Node *nn) { int r; r = REGRET; if(typefd[nn->type->etype]) r = FREGRET+NREG; nodreg(n, nn, r); reg[r]++; } int tmpreg(void) { int i; for(i=REGRET+1; itype->etype) { case TCHAR: case TUCHAR: case TSHORT: case TUSHORT: case TINT: case TUINT: case TLONG: case TULONG: case TIND: if(o != Z && o->op == OREGISTER) { i = o->reg; if(i >= 0 && i < NREG) goto out; } j = lasti + REGRET+1; for(i=REGRET+1; i= NREG) j = REGRET+1; if(reg[j] == 0 && resvreg[j] == 0) { i = j; goto out; } j++; } diag(tn, "out of fixed registers"); goto err; case TFLOAT: case TDOUBLE: case TVLONG: if(o != Z && o->op == OREGISTER) { i = o->reg; if(i >= NREG && i < NREG+NFREG) goto out; } j = 0*2 + NREG; for(i=NREG; i= NREG+NFREG) j = NREG; if(reg[j] == 0) { i = j; goto out; } j++; } diag(tn, "out of float registers"); goto err; } diag(tn, "unknown type in regalloc: %T", tn->type); err: nodreg(n, tn, 0); return; out: reg[i]++; lasti++; if(lasti >= 5) lasti = 0; 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: %d", i); } void regsalloc(Node *n, Node *nn) { cursafe = align(cursafe, nn->type, Aaut3); maxargsafe = maxround(maxargsafe, cursafe+curarg); *n = *nodsafe; n->xoffset = -(stkoff + cursafe); n->type = nn->type; n->etype = nn->type->etype; n->lineno = nn->lineno; } void regaalloc1(Node *n, Node *nn) { nodreg(n, nn, REGARG); reg[REGARG]++; curarg = align(curarg, nn->type, Aarg1); curarg = align(curarg, nn->type, Aarg2); maxargsafe = maxround(maxargsafe, cursafe+curarg); } void regaalloc(Node *n, Node *nn) { curarg = align(curarg, nn->type, Aarg1); *n = *nn; n->op = OINDREG; n->reg = REGSP; n->xoffset = curarg + SZ_LONG; 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 raddr(Node *n, Prog *p) { Adr a; naddr(n, &a); if(R0ISZERO && a.type == D_CONST && a.offset == 0) { a.type = D_REG; a.reg = 0; } if(a.type != D_REG && a.type != D_FREG) { if(n) diag(n, "bad in raddr: %O", n->op); else diag(n, "bad in raddr: "); p->reg = NREG; } else p->reg = a.reg; } 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", n->op); break; case OREGISTER: a->type = D_REG; a->sym = S; a->reg = n->reg; if(a->reg >= NREG) { a->type = D_FREG; a->reg -= NREG; } break; case OIND: naddr(n->left, a); if(a->type == D_REG) { a->type = D_OREG; break; } if(a->type == D_CONST) { a->type = D_OREG; break; } goto bad; case OINDREG: a->type = D_OREG; a->sym = S; a->offset = n->xoffset; a->reg = n->reg; break; case ONAME: a->etype = n->etype; a->type = D_OREG; a->name = D_STATIC; a->sym = n->sym; a->offset = n->xoffset; if(n->class == CSTATIC) break; if(n->class == CEXTERN || n->class == CGLOBL) { a->name = D_EXTERN; break; } if(n->class == CAUTO) { a->name = D_AUTO; break; } if(n->class == CPARAM) { a->name = D_PARAM; break; } goto bad; case OCONST: a->sym = S; a->reg = NREG; if(typefd[n->type->etype]) { a->type = D_FCONST; a->dval = n->fconst; } else { a->type = D_CONST; a->offset = n->vconst; } break; case OADDR: naddr(n->left, a); if(a->type == D_OREG) { a->type = D_CONST; break; } goto bad; case OADD: if(n->left->op == OCONST) { naddr(n->left, a); v = a->offset; naddr(n->right, a); } else { naddr(n->right, a); v = a->offset; naddr(n->left, a); } a->offset += v; break; } } void fop(int as, int f1, int f2, Node *t) { Node nod1, nod2, nod3; nodreg(&nod1, t, NREG+f1); nodreg(&nod2, t, NREG+f2); regalloc(&nod3, t, t); gopcode(as, &nod1, &nod2, &nod3); gmove(&nod3, t); regfree(&nod3); } void gmovm(Node *f, Node *t, int w) { gins(AMOVM, f, t); p->scond |= C_UBIT; if(w) p->scond |= C_WBIT; } void gmove(Node *f, Node *t) { int ft, tt, a; Node nod; ft = f->type->etype; tt = t->type->etype; if(ft == TDOUBLE && f->op == OCONST) { } if(ft == TFLOAT && f->op == OCONST) { } /* * a load -- * put it into a register then * worry what to do with it. */ if(f->op == ONAME || f->op == OINDREG || f->op == OIND) { switch(ft) { default: a = AMOVW; break; case TFLOAT: a = AMOVF; break; case TDOUBLE: a = AMOVD; break; case TCHAR: a = AMOVB; break; case TUCHAR: a = AMOVBU; break; case TSHORT: a = AMOVH; break; case TUSHORT: a = AMOVHU; break; } if(typechlp[ft] && typeilp[tt]) regalloc(&nod, t, t); else regalloc(&nod, f, t); gins(a, f, &nod); gmove(&nod, t); regfree(&nod); return; } /* * a store -- * put it into a register then * store it. */ if(t->op == ONAME || t->op == OINDREG || t->op == OIND) { switch(tt) { default: a = AMOVW; break; case TUCHAR: a = AMOVBU; break; case TCHAR: a = AMOVB; break; case TUSHORT: a = AMOVHU; break; case TSHORT: a = AMOVH; break; case TFLOAT: a = AMOVF; break; case TVLONG: case TDOUBLE: a = AMOVD; break; } if(ft == tt) regalloc(&nod, t, f); else regalloc(&nod, t, Z); gmove(f, &nod); gins(a, &nod, t); regfree(&nod); return; } /* * type x type cross table */ a = AGOK; switch(ft) { case TDOUBLE: case TVLONG: case TFLOAT: switch(tt) { case TDOUBLE: case TVLONG: a = AMOVD; if(ft == TFLOAT) a = AMOVFD; break; case TFLOAT: a = AMOVDF; if(ft == TFLOAT) a = AMOVF; break; case TINT: case TUINT: case TLONG: case TULONG: case TIND: a = AMOVDW; if(ft == TFLOAT) a = AMOVFW; break; case TSHORT: case TUSHORT: case TCHAR: case TUCHAR: a = AMOVDW; if(ft == TFLOAT) a = AMOVFW; break; } break; case TUINT: case TINT: case TULONG: case TLONG: case TIND: switch(tt) { case TDOUBLE: a = AMOVWD; adju: gins(a, f, t); if(ft == TUINT || ft == TULONG || ft == TIND) { Prog *p1; Node dnod; regalloc(&nod, f, Z); gmove(nodconst(1<<31), &nod); gins(AAND, f, &nod); p->scond |= C_SBIT; gins(ABEQ, Z, Z); p1 = p; regalloc(&dnod, t, Z); gmove(nodfconst(4294967296.), &dnod); gins(a==AMOVWD? AADDD: AADDF, &dnod, t); regfree(&dnod); patch(p1, pc); regfree(&nod); } return; case TVLONG: gins(AMOVWD, f, t); if(ft == TULONG) { } return; case TFLOAT: a = AMOVWF; goto adju; case TINT: case TUINT: case TLONG: case TULONG: case TIND: case TSHORT: case TUSHORT: case TCHAR: case TUCHAR: a = AMOVW; break; } break; case TSHORT: switch(tt) { case TDOUBLE: case TVLONG: regalloc(&nod, f, Z); gins(AMOVH, f, &nod); gins(AMOVWD, &nod, t); regfree(&nod); return; case TFLOAT: regalloc(&nod, f, Z); gins(AMOVH, f, &nod); gins(AMOVWF, &nod, t); regfree(&nod); return; case TUINT: case TINT: case TULONG: case TLONG: case TIND: a = AMOVH; break; case TSHORT: case TUSHORT: case TCHAR: case TUCHAR: a = AMOVW; break; } break; case TUSHORT: switch(tt) { case TDOUBLE: case TVLONG: regalloc(&nod, f, Z); gins(AMOVHU, f, &nod); gins(AMOVWD, &nod, t); regfree(&nod); return; case TFLOAT: regalloc(&nod, f, Z); gins(AMOVHU, f, &nod); gins(AMOVWF, &nod, t); regfree(&nod); return; case TINT: case TUINT: case TLONG: case TULONG: case TIND: a = AMOVHU; break; case TSHORT: case TUSHORT: case TCHAR: case TUCHAR: a = AMOVW; break; } break; case TCHAR: switch(tt) { case TDOUBLE: case TVLONG: regalloc(&nod, f, Z); gins(AMOVB, f, &nod); gins(AMOVWD, &nod, t); regfree(&nod); return; case TFLOAT: regalloc(&nod, f, Z); gins(AMOVB, f, &nod); gins(AMOVWF, &nod, t); regfree(&nod); return; case TINT: case TUINT: case TLONG: case TULONG: case TIND: case TSHORT: case TUSHORT: a = AMOVB; break; case TCHAR: case TUCHAR: a = AMOVW; break; } break; case TUCHAR: switch(tt) { case TDOUBLE: case TVLONG: regalloc(&nod, f, Z); gins(AMOVBU, f, &nod); gins(AMOVWD, &nod, t); regfree(&nod); return; case TFLOAT: regalloc(&nod, f, Z); gins(AMOVBU, f, &nod); gins(AMOVWF, &nod, t); regfree(&nod); return; case TINT: case TUINT: case TLONG: case TULONG: case TIND: case TSHORT: case TUSHORT: a = AMOVBU; break; case TCHAR: case TUCHAR: a = AMOVW; break; } break; } if(a == AGOK) diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type); if(a == AMOVW || a == AMOVF || a == AMOVD) if(samaddr(f, t)) return; gins(a, f, t); } void gmover(Node *f, Node *t) { int ft, tt, a; ft = f->type->etype; tt = t->type->etype; a = AGOK; if(typechlp[ft] && typechlp[tt] && ewidth[ft] >= ewidth[tt]){ switch(tt){ case TSHORT: a = AMOVH; break; case TUSHORT: a = AMOVHU; break; case TCHAR: a = AMOVB; break; case TUCHAR: a = AMOVBU; break; } } if(a == AGOK) gmove(f, t); else gins(a, f, t); } void gins(int a, Node *f, Node *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, Node *f1, Node *f2, Node *t) { int a, et; Adr ta; et = TLONG; if(f1 != Z && f1->type != T) et = f1->type->etype; a = AGOK; switch(o) { case OAS: gmove(f1, t); return; case OASADD: case OADD: a = AADD; if(et == TFLOAT) a = AADDF; else if(et == TDOUBLE || et == TVLONG) a = AADDD; break; case OASSUB: case OSUB: if(f2 && f2->op == OCONST) { Node *t = f1; f1 = f2; f2 = t; a = ARSB; } else a = ASUB; if(et == TFLOAT) a = ASUBF; else if(et == TDOUBLE || et == TVLONG) a = ASUBD; break; case OASOR: case OOR: a = AORR; break; case OASAND: case OAND: a = AAND; break; case OASXOR: case OXOR: a = AEOR; break; case OASLSHR: case OLSHR: a = ASRL; break; case OASASHR: case OASHR: a = ASRA; break; case OASASHL: case OASHL: a = ASLL; break; case OFUNC: a = ABL; break; case OASMUL: case OMUL: a = AMUL; if(et == TFLOAT) a = AMULF; else if(et == TDOUBLE || et == TVLONG) a = AMULD; break; case OASDIV: case ODIV: a = ADIV; if(et == TFLOAT) a = ADIVF; else if(et == TDOUBLE || et == TVLONG) a = ADIVD; break; case OASMOD: case OMOD: a = AMOD; break; case OASLMUL: case OLMUL: a = AMULU; break; case OASLMOD: case OLMOD: a = AMODU; break; case OASLDIV: case OLDIV: a = ADIVU; break; case OCASE: case OEQ: case ONE: case OLT: case OLE: case OGE: case OGT: case OLO: case OLS: case OHS: case OHI: a = ACMP; if(et == TFLOAT) a = ACMPF; else if(et == TDOUBLE || et == TVLONG) a = ACMPD; nextpc(); p->as = a; naddr(f1, &p->from); if(a == ACMP && f1->op == OCONST && p->from.offset < 0) { p->as = ACMN; p->from.offset = -p->from.offset; } raddr(f2, p); switch(o) { case OEQ: a = ABEQ; break; case ONE: a = ABNE; break; case OLT: a = ABLT; break; case OLE: a = ABLE; break; case OGE: a = ABGE; break; case OGT: a = ABGT; break; case OLO: a = ABLO; break; case OLS: a = ABLS; break; case OHS: a = ABHS; break; case OHI: a = ABHI; break; case OCASE: nextpc(); p->as = ACASE; p->scond = 0x9; naddr(f2, &p->from); a = ABHI; break; } f1 = Z; f2 = Z; break; } if(a == AGOK) diag(Z, "bad in gopcode %O", o); nextpc(); p->as = a; if(f1 != Z) naddr(f1, &p->from); if(f2 != Z) { naddr(f2, &ta); p->reg = ta.reg; } if(t != Z) naddr(t, &p->to); if(debug['g']) print("%P\n", p); } samaddr(Node *f, Node *t) { if(f->op != t->op) return 0; switch(f->op) { case OREGISTER: if(f->reg != t->reg) break; return 1; } return 0; } void gbranch(int o) { int a; a = AGOK; switch(o) { case ORETURN: a = ARET; break; case OGOTO: a = AB; 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_OREG; p->from.sym = s; p->from.name = D_EXTERN; if(a == ATEXT) p->reg = (profileflg ? 0 : NOPROF); if(s->class == CSTATIC) p->from.name = D_STATIC; naddr(n, &p->to); if(a == ADATA || a == AGLOBL) pc--; } int sconst(Node *n) { vlong vv; if(n->op == OCONST) { if(!typefd[n->type->etype]) { vv = n->vconst; if(vv >= (vlong)(-32766) && vv < (vlong)32766) return 1; /* * should be specialised for constant values which will * fit in different instructionsl; for now, let 5l * sort it out */ return 1; } } return 0; } int sval(long v) { int i; for(i=0; i<16; i++) { if((v & ~0xff) == 0) return 1; if((~v & ~0xff) == 0) return 1; v = (v<<2) | ((ulong)v>>30); } return 0; } long exreg(Type *t) { long o; if(typechlp[t->etype]) { if(exregoffset <= REGEXT-2) return 0; o = exregoffset; if(reg[o] && !resvreg[o]) return 0; resvreg[o] = reg[o] = 1; exregoffset--; return o; } if(typefd[t->etype]) { if(exfregoffset <= NFREG-1) return 0; o = exfregoffset + NREG; if(reg[o] && !resvreg[o]) return 0; resvreg[o] = reg[o] = 1; exfregoffset--; 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|BIND, /* [TINT] */ BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */ BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */ BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */ BVLONG|BUVLONG, /* [TVLONG] */ BVLONG|BUVLONG, /* [TUVLONG] */ BFLOAT, /* [TFLOAT] */ BDOUBLE, /* [TDOUBLE] */ BLONG|BULONG|BIND, /* [TIND] */ 0, /* [TFUNC] */ 0, /* [TARRAY] */ 0, /* [TVOID] */ BSTRUCT, /* [TSTRUCT] */ BUNION, /* [TUNION] */ 0, /* [TENUM] */ }; case TSHORT: a = AMOVH; break; case TUSHORT: a = AMOVHU; break; } if(typechlp[ft] && typeilp[tt]) regal