diff options
Diffstat (limited to 'src/cmd/gc')
-rw-r--r-- | src/cmd/gc/bits.c | 34 | ||||
-rw-r--r-- | src/cmd/gc/export.c | 41 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 19 | ||||
-rw-r--r-- | src/cmd/gc/lex.c | 200 | ||||
-rw-r--r-- | src/cmd/gc/obj.c | 12 | ||||
-rw-r--r-- | src/cmd/gc/pgen.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/plive.c | 19 | ||||
-rw-r--r-- | src/cmd/gc/reflect.c | 14 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 46 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 8 |
10 files changed, 324 insertions, 73 deletions
diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c index 2e79f6f1d..fe9a168dc 100644 --- a/src/cmd/gc/bits.c +++ b/src/cmd/gc/bits.c @@ -95,11 +95,11 @@ int bnum(Bits a) { int i; - int32 b; + uint64 b; for(i=0; i<BITS; i++) if(b = a.b[i]) - return 32*i + bitno(b); + return 64*i + bitno(b); fatal("bad in bnum"); return 0; } @@ -110,27 +110,35 @@ blsh(uint n) Bits c; c = zbits; - c.b[n/32] = 1L << (n%32); + c.b[n/64] = 1LL << (n%64); return c; } -/* int -bset(Bits a, uint n) +btest(Bits *a, uint n) { - if(a.b[n/32] & (1L << (n%32))) - return 1; - return 0; + return (a->b[n/64] & (1LL << (n%64))) != 0; +} + +void +biset(Bits *a, uint n) +{ + a->b[n/64] |= 1LL << (n%64); +} + +void +biclr(Bits *a, uint n) +{ + a->b[n/64] &= ~(1LL << (n%64)); } -*/ int -bitno(int32 b) +bitno(uint64 b) { int i; - for(i=0; i<32; i++) - if(b & (1L<<i)) + for(i=0; i<64; i++) + if(b & (1LL<<i)) return i; fatal("bad in bitno"); return 0; @@ -157,7 +165,7 @@ Qconv(Fmt *fp) if(var[i].offset != 0) fmtprint(fp, "%+lld", (vlong)var[i].offset); } - bits.b[i/32] &= ~(1L << (i%32)); + biclr(&bits, i); } return 0; } diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c index da5984ceb..aeee55236 100644 --- a/src/cmd/gc/export.c +++ b/src/cmd/gc/export.c @@ -7,6 +7,8 @@ #include "go.h" #include "y.tab.h" +static NodeList *asmlist; + static void dumpexporttype(Type *t); // Mark n's symbol as exported @@ -68,6 +70,11 @@ autoexport(Node *n, int ctxt) // -A is for cmd/gc/mkbuiltin script, so export everything if(debug['A'] || exportname(n->sym->name) || initname(n->sym->name)) exportsym(n); + if(asmhdr && n->sym->pkg == localpkg && !(n->sym->flags & SymAsm)) { + n->sym->flags |= SymAsm; + asmlist = list(asmlist, n); + } + } static void @@ -519,3 +526,37 @@ importtype(Type *pt, Type *t) if(debug['E']) print("import type %T %lT\n", pt, t); } + +void +dumpasmhdr(void) +{ + Biobuf *b; + NodeList *l; + Node *n; + Type *t; + + b = Bopen(asmhdr, OWRITE); + if(b == nil) + fatal("open %s: %r", asmhdr); + Bprint(b, "// generated by %cg -asmhdr from package %s\n\n", thechar, localpkg->name); + for(l=asmlist; l; l=l->next) { + n = l->n; + if(isblanksym(n->sym)) + continue; + switch(n->op) { + case OLITERAL: + Bprint(b, "#define const_%s %#V\n", n->sym->name, &n->val); + break; + case OTYPE: + t = n->type; + if(t->etype != TSTRUCT || t->map != T || t->funarg) + break; + for(t=t->type; t != T; t=t->down) + if(!isblanksym(t->sym)) + Bprint(b, "#define %s_%s %d\n", n->sym->name, t->sym->name, (int)t->width); + break; + } + } + + Bterm(b); +} diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 965a0550d..6e326961d 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -382,6 +382,7 @@ enum SymExported = 1<<2, // already written out by export SymUniq = 1<<3, SymSiggen = 1<<4, + SymAsm = 1<<5, }; struct Sym @@ -393,6 +394,7 @@ struct Sym int32 npkg; // number of imported packages with this name uint32 uniqgen; Pkg* importdef; // where imported definition was found + char* linkname; // link name // saved and restored by dcopy Pkg* pkg; @@ -704,13 +706,13 @@ enum Ecomplit = 1<<11, // type in composite literal }; -#define BITS 5 -#define NVAR (BITS*sizeof(uint32)*8) +#define BITS 3 +#define NVAR (BITS*sizeof(uint64)*8) typedef struct Bits Bits; struct Bits { - uint32 b[BITS]; + uint64 b[BITS]; }; EXTERN Bits zbits; @@ -860,6 +862,8 @@ EXTERN int32 lexlineno; EXTERN int32 lineno; EXTERN int32 prevlineno; +EXTERN Fmt pragcgobuf; + EXTERN char* infile; EXTERN char* outfile; EXTERN Biobuf* bout; @@ -890,6 +894,7 @@ EXTERN Pkg* typelinkpkg; // fake package for runtime type info (data) EXTERN Pkg* weaktypepkg; // weak references to runtime type info EXTERN Pkg* unsafepkg; // package unsafe EXTERN Pkg* trackpkg; // fake package for field tracking +EXTERN Pkg* rawpkg; // fake package for raw symbol names EXTERN Pkg* phash[128]; EXTERN int tptr; // either TPTR32 or TPTR64 extern char* runtimeimport; @@ -897,6 +902,7 @@ extern char* unsafeimport; EXTERN char* myimportpath; EXTERN Idir* idirs; EXTERN char* localimport; +EXTERN char* asmhdr; EXTERN Type* types[NTYPE]; EXTERN Type* idealstring; @@ -1027,12 +1033,14 @@ int Qconv(Fmt *fp); Bits band(Bits a, Bits b); int bany(Bits *a); int beq(Bits a, Bits b); -int bitno(int32 b); +int bitno(uint64 b); Bits blsh(uint n); Bits bnot(Bits a); int bnum(Bits a); Bits bor(Bits a, Bits b); -int bset(Bits a, uint n); +int btest(Bits *a, uint n); +void biset(Bits *a, uint n); +void biclr(Bits *a, uint n); /* * bv.c @@ -1145,6 +1153,7 @@ void escapes(NodeList*); */ void autoexport(Node *n, int ctxt); void dumpexport(void); +void dumpasmhdr(void); int exportname(char *s); void exportsym(Node *n); void importconst(Sym *s, Type *t, Node *n); diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index 523ba37aa..2bd7adfb6 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -17,6 +17,8 @@ extern int yychar; int yyprev; int yylast; +static int imported_unsafe; + static void lexinit(void); static void lexinit1(void); static void lexfini(void); @@ -271,6 +273,9 @@ main(int argc, char *argv[]) flag_largemodel = 1; setexp(); + + fmtstrinit(&pragcgobuf); + quotefmtinstall(); outfile = nil; flagcount("+", "compiling runtime", &compiling_runtime); @@ -289,6 +294,7 @@ main(int argc, char *argv[]) flagcount("S", "print assembly listing", &debug['S']); flagfn0("V", "print compiler version", doversion); flagcount("W", "debug parse tree after type checking", &debug['W']); + flagstr("asmhdr", "file: write assembly header to named file", &asmhdr); flagcount("complete", "compiling complete package (no C or assembly)", &pure_go); flagstr("d", "list: print debug information about items in list", &debugstr); flagcount("e", "no limit on number of errors reported", &debug['e']); @@ -403,6 +409,8 @@ main(int argc, char *argv[]) block = 1; iota = -1000000; + + imported_unsafe = 0; yyparse(); if(nsyntaxerrors != 0) @@ -509,6 +517,9 @@ main(int argc, char *argv[]) errorexit(); dumpobj(); + + if(asmhdr) + dumpasmhdr(); if(nerrors+nsavederrors) errorexit(); @@ -724,6 +735,7 @@ importfile(Val *f, int line) } importpkg = mkpkg(f->u.sval); cannedimports("unsafe.6", unsafeimport); + imported_unsafe = 1; return; } @@ -1501,6 +1513,20 @@ caseout: return LLITERAL; } +static void pragcgo(char*); + +static int +more(char **pp) +{ + char *p; + + p = *pp; + while(yy_isspace(*p)) + p++; + *pp = p; + return *p != '\0'; +} + /* * read and interpret syntax that looks like * //line parse.y:15 @@ -1583,9 +1609,39 @@ go: *cp++ = c; } *cp = 0; + + if(strncmp(lexbuf, "go:cgo_", 7) == 0) + pragcgo(lexbuf); + ep = strchr(lexbuf, ' '); if(ep != nil) *ep = 0; + + if(strcmp(lexbuf, "go:linkname") == 0) { + if(!imported_unsafe) + yyerror("//go:linkname only allowed in Go files that import \"unsafe\""); + if(ep == nil) { + yyerror("usage: //go:linkname localname linkname"); + goto out; + } + cp = ep+1; + while(yy_isspace(*cp)) + cp++; + ep = strchr(cp, ' '); + if(ep == nil) { + yyerror("usage: //go:linkname localname linkname"); + goto out; + } + *ep++ = 0; + while(yy_isspace(*ep)) + ep++; + if(*ep == 0) { + yyerror("usage: //go:linkname localname linkname"); + goto out; + } + lookup(cp)->linkname = strdup(ep); + goto out; + } if(strcmp(lexbuf, "go:nointerface") == 0 && fieldtrack_enabled) { nointerface = 1; @@ -1604,6 +1660,150 @@ out: return c; } +static char* +getimpsym(char **pp) +{ + char *p, *start; + + more(pp); // skip spaces + + p = *pp; + if(*p == '\0' || *p == '"') + return nil; + + start = p; + while(*p != '\0' && !yy_isspace(*p) && *p != '"') + p++; + if(*p != '\0') + *p++ = '\0'; + + *pp = p; + return start; +} + +static char* +getquoted(char **pp) +{ + char *p, *start; + + more(pp); // skip spaces + + p = *pp; + if(*p != '"') + return nil; + p++; + + start = p; + while(*p != '"') { + if(*p == '\0') + return nil; + p++; + } + *p++ = '\0'; + *pp = p; + return start; +} + +// Copied nearly verbatim from the C compiler's #pragma parser. +// TODO: Rewrite more cleanly once the compiler is written in Go. +static void +pragcgo(char *text) +{ + char *local, *remote, *p, *q, *verb; + + for(q=text; *q != '\0' && *q != ' '; q++) + ; + if(*q == ' ') + *q++ = '\0'; + + verb = text+3; // skip "go:" + + if(strcmp(verb, "cgo_dynamic_linker") == 0 || strcmp(verb, "dynlinker") == 0) { + p = getquoted(&q); + if(p == nil) + goto err1; + fmtprint(&pragcgobuf, "cgo_dynamic_linker %q\n", p); + goto out; + + err1: + yyerror("usage: //go:cgo_dynamic_linker \"path\""); + goto out; + } + + if(strcmp(verb, "dynexport") == 0) + verb = "cgo_export_dynamic"; + if(strcmp(verb, "cgo_export_static") == 0 || strcmp(verb, "cgo_export_dynamic") == 0) { + local = getimpsym(&q); + if(local == nil) + goto err2; + if(!more(&q)) { + fmtprint(&pragcgobuf, "%s %q\n", verb, local); + goto out; + } + remote = getimpsym(&q); + if(remote == nil) + goto err2; + fmtprint(&pragcgobuf, "%s %q %q\n", verb, local, remote); + goto out; + + err2: + yyerror("usage: //go:%s local [remote]", verb); + goto out; + } + + if(strcmp(verb, "cgo_import_dynamic") == 0 || strcmp(verb, "dynimport") == 0) { + local = getimpsym(&q); + if(local == nil) + goto err3; + if(!more(&q)) { + fmtprint(&pragcgobuf, "cgo_import_dynamic %q\n", local); + goto out; + } + remote = getimpsym(&q); + if(remote == nil) + goto err3; + if(!more(&q)) { + fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q\n", local, remote); + goto out; + } + p = getquoted(&q); + if(p == nil) + goto err3; + fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q %q\n", local, remote, p); + goto out; + + err3: + yyerror("usage: //go:cgo_import_dynamic local [remote [\"library\"]]"); + goto out; + } + + if(strcmp(verb, "cgo_import_static") == 0) { + local = getimpsym(&q); + if(local == nil || more(&q)) + goto err4; + fmtprint(&pragcgobuf, "cgo_import_static %q\n", local); + goto out; + + err4: + yyerror("usage: //go:cgo_import_static local"); + goto out; + } + + if(strcmp(verb, "cgo_ldflag") == 0) { + p = getquoted(&q); + if(p == nil) + goto err5; + fmtprint(&pragcgobuf, "cgo_ldflag %q\n", p); + goto out; + + err5: + yyerror("usage: //go:cgo_ldflag \"arg\""); + goto out; + } + +out:; +} + int32 yylex(void) { diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c index b752a13ce..7e4e97854 100644 --- a/src/cmd/gc/obj.c +++ b/src/cmd/gc/obj.c @@ -67,6 +67,16 @@ dumpobj(void) startobj = Boffset(bout); Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring()); } + + if(pragcgobuf.to > pragcgobuf.start) { + if(writearchive) { + // write empty export section; must be before cgo section + Bprint(bout, "\n$$\n\n$$\n\n"); + } + Bprint(bout, "\n$$ // cgo\n"); + Bprint(bout, "%s\n$$\n\n", fmtstrflush(&pragcgobuf)); + } + Bprint(bout, "\n!\n"); @@ -153,6 +163,8 @@ linksym(Sym *s) return s->lsym; if(isblanksym(s)) s->lsym = linklookup(ctxt, "_", 0); + else if(s->linkname != nil) + s->lsym = linklookup(ctxt, s->linkname, 0); else { p = smprint("%s.%s", s->pkg->prefix, s->name); s->lsym = linklookup(ctxt, p, 0); diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c index 39028e3f8..259cec85a 100644 --- a/src/cmd/gc/pgen.c +++ b/src/cmd/gc/pgen.c @@ -471,7 +471,7 @@ allocauto(Prog* ptxt) stksize = rnd(stksize, n->type->align); if(haspointers(n->type)) stkptrsize = stksize; - if(thechar == '5') + if(thechar == '5' || thechar == '9') stksize = rnd(stksize, widthptr); if(stksize >= (1ULL<<31)) { setlineno(curfn); @@ -528,7 +528,7 @@ cgen_checknil(Node *n) dump("checknil", n); fatal("bad checknil"); } - if((thechar == '5' && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) { + if(((thechar == '5' || thechar == '9') && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) { regalloc(®, types[tptr], n); cgen(n, ®); gins(ACHECKNIL, ®, N); diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c index 0feb2c710..3bfa69b1f 100644 --- a/src/cmd/gc/plive.c +++ b/src/cmd/gc/plive.c @@ -1092,7 +1092,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv) case TCOMPLEX64: case TCOMPLEX128: for(i = 0; i < t->width; i++) { - bvset(bv, ((*xoffset + i) / widthptr) * BitsPerPointer); // 1 = live scalar + bvset(bv, ((*xoffset + i) / widthptr) * BitsPerPointer); // 1 = live scalar (BitsScalar) } *xoffset += t->width; break; @@ -1105,7 +1105,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv) case TMAP: if((*xoffset & (widthptr-1)) != 0) fatal("twobitwalktype1: invalid alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr (BitsPointer) *xoffset += t->width; break; @@ -1113,7 +1113,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv) // struct { byte *str; intgo len; } if((*xoffset & (widthptr-1)) != 0) fatal("twobitwalktype1: invalid alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot (BitsPointer) *xoffset += t->width; break; @@ -1123,15 +1123,8 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv) // struct { Type *type; union { void *ptr, uintptr val } data; } if((*xoffset & (widthptr-1)) != 0) fatal("twobitwalktype1: invalid alignment, %T", t); - bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 0); - bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 1); // 3 = multiword - // next word contains 2 = Iface, 3 = Eface - if(isnilinter(t)) { - bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 2); - bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 3); - } else { - bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 3); - } + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot (BitsPointer) + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 3); // 2 = live ptr in second slot (BitsPointer) *xoffset += t->width; break; @@ -1144,7 +1137,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv) // struct { byte *array; uintgo len; uintgo cap; } if((*xoffset & (widthptr-1)) != 0) fatal("twobitwalktype1: invalid TARRAY alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot (BitsPointer) *xoffset += t->width; } else for(i = 0; i < t->bound; i++) diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index b2ff2fbc5..4155953be 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -1318,7 +1318,7 @@ gengcmask(Type *t, uint8 gcmask[16]) { Bvec *vec; vlong xoffset, nptr, i, j; - int half, mw; + int half; uint8 bits, *pos; memset(gcmask, 0, 16); @@ -1335,7 +1335,6 @@ gengcmask(Type *t, uint8 gcmask[16]) pos = (uint8*)gcmask; nptr = (t->width+widthptr-1)/widthptr; half = 0; - mw = 0; // If number of words is odd, repeat the mask. // This makes simpler handling of arrays in runtime. for(j=0; j<=(nptr%2); j++) { @@ -1344,9 +1343,8 @@ gengcmask(Type *t, uint8 gcmask[16]) // Some fake types (e.g. Hmap) has missing fileds. // twobitwalktype1 generates BitsDead for that holes, // replace BitsDead with BitsScalar. - if(!mw && bits == BitsDead) + if(bits == BitsDead) bits = BitsScalar; - mw = !mw && bits == BitsMultiWord; bits <<= 2; if(half) bits <<= 4; @@ -1525,11 +1523,9 @@ gengcprog1(ProgGen *g, Type *t, vlong *xoffset) *xoffset += t->width; break; case TINTER: - proggendata(g, BitsMultiWord); - if(isnilinter(t)) - proggendata(g, BitsEface); - else - proggendata(g, BitsIface); + // Assuming IfacePointerOnly=1. + proggendata(g, BitsPointer); + proggendata(g, BitsPointer); *xoffset += t->width; break; case TARRAY: diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index c3bc5af3b..5e369b695 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -3802,39 +3802,25 @@ checknil(Node *x, NodeList **init) /* * Can this type be stored directly in an interface word? + * Yes, if the representation is a single pointer. */ int isdirectiface(Type *t) { - // Setting IfacePointerOnly = 1 changes the - // interface representation so that the data word - // in an interface value must always be a pointer. - // Setting it to 0 uses the original representation, - // where the data word can hold a pointer or any - // non-pointer value no bigger than a pointer. - enum { - IfacePointerOnly = 1, - }; - - if(IfacePointerOnly) { - switch(t->etype) { - case TPTR32: - case TPTR64: - case TCHAN: - case TMAP: - case TFUNC: - case TUNSAFEPTR: - return 1; - case TARRAY: - // Array of 1 direct iface type can be direct. - return t->bound == 1 && isdirectiface(t->type); - case TSTRUCT: - // Struct with 1 field of direct iface type can be direct. - return t->type != T && t->type->down == T && isdirectiface(t->type->type); - } - return 0; + switch(t->etype) { + case TPTR32: + case TPTR64: + case TCHAN: + case TMAP: + case TFUNC: + case TUNSAFEPTR: + return 1; + case TARRAY: + // Array of 1 direct iface type can be direct. + return t->bound == 1 && isdirectiface(t->type); + case TSTRUCT: + // Struct with 1 field of direct iface type can be direct. + return t->type != T && t->type->down == T && isdirectiface(t->type->type); } - - dowidth(t); - return t->width <= widthptr; + return 0; } diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index ff9b36208..77f9c80f9 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -1766,7 +1766,6 @@ walkprint(Node *nn, NodeList **init) int notfirst, et, op; NodeList *calls; - on = nil; op = nn->op; all = nn->list; calls = nil; @@ -3301,6 +3300,9 @@ walkrotate(Node **np) int w, sl, sr, s; Node *l, *r; Node *n; + + if(thechar == '9') + return; n = *np; @@ -3426,6 +3428,10 @@ walkdiv(Node **np, NodeList **init) Type *twide; Magic m; + // TODO(minux) + if(thechar == '9') + return; + n = *np; if(n->right->op != OLITERAL) return; |