mirror of
https://github.com/golang/go
synced 2024-11-18 13:14:47 -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 "gc.h"
|
||||||
#include "../../pkg/runtime/funcdata.h"
|
#include "../../pkg/runtime/funcdata.h"
|
||||||
|
|
||||||
|
static int32 pointermap(Sym *gcsym, int32 offset);
|
||||||
|
|
||||||
int
|
int
|
||||||
hasdotdotdot(void)
|
hasdotdotdot(void)
|
||||||
{
|
{
|
||||||
@ -101,7 +103,22 @@ codgen(Node *n, Node *nn)
|
|||||||
|
|
||||||
p = gtext(n1->sym, stkoff);
|
p = gtext(n1->sym, stkoff);
|
||||||
sp = p;
|
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
|
* isolate first argument
|
||||||
*/
|
*/
|
||||||
@ -139,17 +156,6 @@ codgen(Node *n, Node *nn)
|
|||||||
maxargsafe = xround(maxargsafe, 8);
|
maxargsafe = xround(maxargsafe, 8);
|
||||||
sp->to.offset += maxargsafe;
|
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
|
// TODO(rsc): "stkoff" is not right. It does not account for
|
||||||
// the possibility of data stored in .safe variables.
|
// the possibility of data stored in .safe variables.
|
||||||
// Unfortunately those move up and down just like
|
// Unfortunately those move up and down just like
|
||||||
@ -162,8 +168,7 @@ codgen(Node *n, Node *nn)
|
|||||||
off = 0;
|
off = 0;
|
||||||
gextern(gcsym, nodconst(stkoff), off, 4); // locals
|
gextern(gcsym, nodconst(stkoff), off, 4); // locals
|
||||||
off += 4;
|
off += 4;
|
||||||
gextern(gcsym, nodconst(0), off, 4); // nptrs
|
off = pointermap(gcsym, off); // nptrs and ptrs[...]
|
||||||
off += 4;
|
|
||||||
gcsym->type = typ(0, T);
|
gcsym->type = typ(0, T);
|
||||||
gcsym->type->width = off;
|
gcsym->type->width = off;
|
||||||
}
|
}
|
||||||
@ -633,3 +638,105 @@ bcomplex(Node *n, Node *c)
|
|||||||
boolgen(n, 1, Z);
|
boolgen(n, 1, Z);
|
||||||
return 0;
|
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