mirror of
https://github.com/golang/go
synced 2024-11-22 03:54:39 -07:00
cmd/cc: use a temporary bitmap when constructing pointer maps
This change makes the way cc constructs pointer maps closer to what gc does and is being done in preparation for changes to the internal content of the pointer map such as a change to distinguish interface pointers from ordinary pointers. R=golang-dev, rsc CC=golang-dev https://golang.org/cl/12692043
This commit is contained in:
parent
14903f6598
commit
2db5e4bb0b
46
src/cmd/cc/bv.c
Normal file
46
src/cmd/cc/bv.c
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "cc.h"
|
||||
|
||||
enum {
|
||||
WORDSIZE = sizeof(uint32),
|
||||
WORDBITS = 32,
|
||||
};
|
||||
|
||||
uintptr
|
||||
bvsize(uintptr n)
|
||||
{
|
||||
return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE;
|
||||
}
|
||||
|
||||
Bvec*
|
||||
bvalloc(int32 n)
|
||||
{
|
||||
Bvec *bv;
|
||||
uintptr nbytes;
|
||||
|
||||
if(n < 0)
|
||||
fatal(Z, "bvalloc: initial size is negative\n");
|
||||
nbytes = sizeof(Bvec) + bvsize(n);
|
||||
bv = malloc(nbytes);
|
||||
if(bv == nil)
|
||||
fatal(Z, "bvalloc: malloc failed\n");
|
||||
memset(bv, 0, nbytes);
|
||||
bv->n = n;
|
||||
return bv;
|
||||
}
|
||||
|
||||
void
|
||||
bvset(Bvec *bv, int32 i)
|
||||
{
|
||||
uint32 mask;
|
||||
|
||||
if(i < 0 || i >= bv->n)
|
||||
fatal(Z, "bvset: index %d is out of bounds with length %d\n", i, bv->n);
|
||||
mask = 1 << (i % WORDBITS);
|
||||
bv->b[i / WORDBITS] |= mask;
|
||||
}
|
@ -52,6 +52,7 @@ typedef struct Hist Hist;
|
||||
typedef struct Term Term;
|
||||
typedef struct Init Init;
|
||||
typedef struct Bits Bits;
|
||||
typedef struct Bvec Bvec;
|
||||
typedef struct Dynimp Dynimp;
|
||||
typedef struct Dynexp Dynexp;
|
||||
|
||||
@ -76,6 +77,12 @@ struct Bits
|
||||
uint32 b[BITS];
|
||||
};
|
||||
|
||||
struct Bvec
|
||||
{
|
||||
int32 n; // number of bits
|
||||
uint32 b[];
|
||||
};
|
||||
|
||||
struct Node
|
||||
{
|
||||
Node* left;
|
||||
@ -750,6 +757,12 @@ Bits blsh(uint);
|
||||
int beq(Bits, Bits);
|
||||
int bset(Bits, uint);
|
||||
|
||||
/*
|
||||
* bv.c
|
||||
*/
|
||||
Bvec* bvalloc(int32 n);
|
||||
void bvset(Bvec *bv, int32 i);
|
||||
|
||||
/*
|
||||
* dpchk.c
|
||||
*/
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "gc.h"
|
||||
#include "../../pkg/runtime/funcdata.h"
|
||||
|
||||
static int32 pointermap(Sym *gcsym, int32 offset);
|
||||
static void dumpgcargs(Type *fn, Sym *sym);
|
||||
|
||||
int
|
||||
hasdotdotdot(void)
|
||||
@ -82,7 +82,6 @@ codgen(Node *n, Node *nn)
|
||||
Sym *gcsym, *gclocalssym;
|
||||
static int ngcsym, ngclocalssym;
|
||||
static char namebuf[40];
|
||||
int32 off;
|
||||
|
||||
cursafe = 0;
|
||||
curarg = 0;
|
||||
@ -164,7 +163,9 @@ codgen(Node *n, Node *nn)
|
||||
if(thechar=='6' || thechar=='7') /* [sic] */
|
||||
maxargsafe = xround(maxargsafe, 8);
|
||||
sp->to.offset += maxargsafe;
|
||||
|
||||
|
||||
dumpgcargs(thisfn, gcsym);
|
||||
|
||||
// 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
|
||||
@ -174,16 +175,9 @@ codgen(Node *n, Node *nn)
|
||||
// area its own section.
|
||||
// That said, we've been using stkoff for months
|
||||
// and nothing too terrible has happened.
|
||||
off = 0;
|
||||
off = pointermap(gcsym, off); // nptrs and ptrs[...]
|
||||
gcsym->type = typ(0, T);
|
||||
gcsym->type->width = off;
|
||||
|
||||
off = 0;
|
||||
gextern(gclocalssym, nodconst(-stkoff), off, 4); // locals
|
||||
off += 4;
|
||||
gextern(gclocalssym, nodconst(-stkoff), 0, 4); // locals
|
||||
gclocalssym->type = typ(0, T);
|
||||
gclocalssym->type->width = off;
|
||||
gclocalssym->type->width = 4;
|
||||
}
|
||||
|
||||
void
|
||||
@ -652,15 +646,12 @@ bcomplex(Node *n, Node *c)
|
||||
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)
|
||||
// Updates the bitvector with a set bit for each pointer containing
|
||||
// value in the type description starting at offset.
|
||||
static void
|
||||
walktype1(Type *t, int32 offset, Bvec *bv)
|
||||
{
|
||||
Type *t1;
|
||||
int32 idx;
|
||||
int32 m;
|
||||
|
||||
switch(t->etype) {
|
||||
case TCHAR:
|
||||
@ -676,80 +667,74 @@ pointermap_type(Type *t, int32 offset, int32 baseidx)
|
||||
case TFLOAT:
|
||||
case TDOUBLE:
|
||||
// non-pointer types
|
||||
return 0;
|
||||
break;
|
||||
|
||||
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;
|
||||
bvset(bv, (offset + t->offset) / ewidth[TIND]);
|
||||
break;
|
||||
|
||||
case TSTRUCT:
|
||||
// build map recursively
|
||||
m = 0;
|
||||
for(t1=t->link; t1; t1=t1->down)
|
||||
m |= pointermap_type(t1, offset, baseidx);
|
||||
return m;
|
||||
for(t1 = t->link; t1 != T; t1 = t1->down)
|
||||
walktype1(t1, offset, bv);
|
||||
break;
|
||||
|
||||
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;
|
||||
walktype1(t->link, offset, bv);
|
||||
break;
|
||||
|
||||
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)
|
||||
static void
|
||||
dumpgcargs(Type *fn, Sym *sym)
|
||||
{
|
||||
int32 nptrs;
|
||||
int32 i;
|
||||
int32 s; // offset in argument list (in bytes)
|
||||
int32 m; // current ptrs[i/32]
|
||||
Bvec *bv;
|
||||
Type *t;
|
||||
int32 i;
|
||||
int32 symoffset, argoffset;
|
||||
|
||||
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])
|
||||
gextern(sym, nodconst(0), 0, 4); // nptrs=0
|
||||
symoffset = 4;
|
||||
} else {
|
||||
bv = bvalloc((argsize() + ewidth[TIND] - 1) / ewidth[TIND]);
|
||||
argoffset = align(0, fn->link, Aarg0, nil);
|
||||
if(argoffset > 0) {
|
||||
// The 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(argoffset != ewidth[TIND])
|
||||
yyerror("passbyptr arg not the right size");
|
||||
m = 1;
|
||||
bvset(bv, 0);
|
||||
}
|
||||
for(t=thisfn->down; t!=T; t=t->down) {
|
||||
for(t = fn->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);
|
||||
argoffset = align(argoffset, t, Aarg1, nil);
|
||||
walktype1(t, argoffset, bv);
|
||||
argoffset = align(argoffset, t, Aarg2, nil);
|
||||
}
|
||||
gextern(gcsym, nodconst(m), off, 4);
|
||||
off += 4;
|
||||
gextern(sym, nodconst(bv->n), 0, 4);
|
||||
symoffset = 4;
|
||||
for(i = 0; i < bv->n; i += 32) {
|
||||
gextern(sym, nodconst(bv->b[i/32]), symoffset, 4);
|
||||
symoffset += 4;
|
||||
}
|
||||
free(bv);
|
||||
}
|
||||
return off;
|
||||
// TODO: needs a test for nptrs>32
|
||||
sym->type = typ(0, T);
|
||||
sym->type->width = symoffset;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user