mirror of
https://github.com/golang/go
synced 2024-11-18 11:14:39 -07:00
cc: generate argument pointer maps for C functions.
R=golang-dev, rsc CC=golang-dev https://golang.org/cl/11683043
This commit is contained in:
parent
8f746af65d
commit
9b1f1833de
@ -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,22 @@ 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 +156,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 +168,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 +638,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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user