From ad5cd931d8f7738752fbd471081b15e9931e7d2b Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 25 Jul 2013 17:51:33 -0700 Subject: [PATCH] undo CL 11788043 / 62d06cccc261 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Reason for breakage fixed with CL 11888043. ««« original CL description undo CL 11683043 / bb75d03e6ccb Broke arm build. R=dave ««« original CL description cc: generate argument pointer maps for C functions. R=golang-dev, rsc CC=golang-dev https://golang.org/cl/11683043 »»» R=golang-dev CC=golang-dev https://golang.org/cl/11788043 »»» TBR=dave CC=golang-dev https://golang.org/cl/11789043 --- src/cmd/cc/pgen.c | 134 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 120 insertions(+), 14 deletions(-) diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c index 27022d54e8..a6b0f947e1 100644 --- a/src/cmd/cc/pgen.c +++ b/src/cmd/cc/pgen.c @@ -31,6 +31,8 @@ #include "gc.h" #include "../../pkg/runtime/funcdata.h" +static int32 pointermap(Sym *gcsym, int32 offset); + int hasdotdotdot(void) { @@ -101,7 +103,21 @@ codgen(Node *n, Node *nn) p = gtext(n1->sym, stkoff); sp = p; - + + /* + * generate funcdata symbol for this function. + * data is filled in at the end of codgen(). + */ + snprint(namebuf, sizeof namebuf, "gc·%d", ngcsym++); + gcsym = slookup(namebuf); + gcsym->class = CSTATIC; + + memset(&nod, 0, sizeof nod); + nod.op = ONAME; + nod.sym = gcsym; + nod.class = CSTATIC; + gins(AFUNCDATA, nodconst(FUNCDATA_GC), &nod); + /* * isolate first argument */ @@ -139,17 +155,6 @@ codgen(Node *n, Node *nn) maxargsafe = xround(maxargsafe, 8); sp->to.offset += maxargsafe; - snprint(namebuf, sizeof namebuf, "gc·%d", ngcsym++); - gcsym = slookup(namebuf); - gcsym->class = CSTATIC; - - memset(&nod, 0, sizeof nod); - nod.op = ONAME; - nod.sym = gcsym; - nod.class = CSTATIC; - - gins(AFUNCDATA, nodconst(FUNCDATA_GC), &nod); - // TODO(rsc): "stkoff" is not right. It does not account for // the possibility of data stored in .safe variables. // Unfortunately those move up and down just like @@ -162,8 +167,7 @@ codgen(Node *n, Node *nn) off = 0; gextern(gcsym, nodconst(stkoff), off, 4); // locals off += 4; - gextern(gcsym, nodconst(0), off, 4); // nptrs - off += 4; + off = pointermap(gcsym, off); // nptrs and ptrs[...] gcsym->type = typ(0, T); gcsym->type->width = off; } @@ -633,3 +637,105 @@ bcomplex(Node *n, Node *c) boolgen(n, 1, Z); return 0; } + +// Makes a bitmap marking the the pointers in t. t starts at the given byte +// offset in the argument list. The returned bitmap should be for pointer +// indexes (relative to offset 0) between baseidx and baseidx+32. +static int32 +pointermap_type(Type *t, int32 offset, int32 baseidx) +{ + Type *t1; + int32 idx; + int32 m; + + switch(t->etype) { + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TFLOAT: + case TDOUBLE: + // non-pointer types + return 0; + case TIND: + case TARRAY: // unlike Go, C passes arrays by reference + // pointer types + if((offset + t->offset) % ewidth[TIND] != 0) + yyerror("unaligned pointer"); + idx = (offset + t->offset) / ewidth[TIND]; + if(idx >= baseidx && idx < baseidx + 32) + return 1 << (idx - baseidx); + return 0; + case TSTRUCT: + // build map recursively + m = 0; + for(t1=t->link; t1; t1=t1->down) + m |= pointermap_type(t1, offset, baseidx); + return m; + case TUNION: + // We require that all elements of the union have the same pointer map. + m = pointermap_type(t->link, offset, baseidx); + for(t1=t->link->down; t1; t1=t1->down) { + if(pointermap_type(t1, offset, baseidx) != m) + yyerror("invalid union in argument list - pointer maps differ"); + } + return m; + default: + yyerror("can't handle arg type %s\n", tnames[t->etype]); + return 0; + } +} + +// Compute a bit vector to describe the pointer containing locations +// in the argument list. Adds the data to gcsym and returns the offset +// of end of the bit vector. +static int32 +pointermap(Sym *gcsym, int32 off) +{ + int32 nptrs; + int32 i; + int32 s; // offset in argument list (in bytes) + int32 m; // current ptrs[i/32] + Type *t; + + if(hasdotdotdot()) { + // give up for C vararg functions. + // TODO: maybe make a map just for the args we do know? + gextern(gcsym, nodconst(0), off, 4); // nptrs=0 + return off + 4; + } + nptrs = (argsize() + ewidth[TIND] - 1) / ewidth[TIND]; + gextern(gcsym, nodconst(nptrs), off, 4); + off += 4; + + for(i = 0; i < nptrs; i += 32) { + // generate mask for ptrs at offsets i ... i+31 + m = 0; + s = align(0, thisfn->link, Aarg0, nil); + if(s > 0 && i == 0) { + // C Calling convention returns structs by copying + // them to a location pointed to by a hidden first + // argument. This first argument is a pointer. + if(s != ewidth[TIND]) + yyerror("passbyptr arg not the right size"); + m = 1; + } + for(t=thisfn->down; t!=T; t=t->down) { + if(t->etype == TVOID) + continue; + s = align(s, t, Aarg1, nil); + m |= pointermap_type(t, s, i); + s = align(s, t, Aarg2, nil); + } + gextern(gcsym, nodconst(m), off, 4); + off += 4; + } + return off; + // TODO: needs a test for nptrs>32 +} -- 2.48.1