Commit 2db5e4bb authored by Carl Shapiro's avatar Carl Shapiro

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
parent 14903f65
// 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; ...@@ -52,6 +52,7 @@ typedef struct Hist Hist;
typedef struct Term Term; typedef struct Term Term;
typedef struct Init Init; typedef struct Init Init;
typedef struct Bits Bits; typedef struct Bits Bits;
typedef struct Bvec Bvec;
typedef struct Dynimp Dynimp; typedef struct Dynimp Dynimp;
typedef struct Dynexp Dynexp; typedef struct Dynexp Dynexp;
...@@ -76,6 +77,12 @@ struct Bits ...@@ -76,6 +77,12 @@ struct Bits
uint32 b[BITS]; uint32 b[BITS];
}; };
struct Bvec
{
int32 n; // number of bits
uint32 b[];
};
struct Node struct Node
{ {
Node* left; Node* left;
...@@ -750,6 +757,12 @@ Bits blsh(uint); ...@@ -750,6 +757,12 @@ Bits blsh(uint);
int beq(Bits, Bits); int beq(Bits, Bits);
int bset(Bits, uint); int bset(Bits, uint);
/*
* bv.c
*/
Bvec* bvalloc(int32 n);
void bvset(Bvec *bv, int32 i);
/* /*
* dpchk.c * dpchk.c
*/ */
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#include "gc.h" #include "gc.h"
#include "../../pkg/runtime/funcdata.h" #include "../../pkg/runtime/funcdata.h"
static int32 pointermap(Sym *gcsym, int32 offset); static void dumpgcargs(Type *fn, Sym *sym);
int int
hasdotdotdot(void) hasdotdotdot(void)
...@@ -82,7 +82,6 @@ codgen(Node *n, Node *nn) ...@@ -82,7 +82,6 @@ codgen(Node *n, Node *nn)
Sym *gcsym, *gclocalssym; Sym *gcsym, *gclocalssym;
static int ngcsym, ngclocalssym; static int ngcsym, ngclocalssym;
static char namebuf[40]; static char namebuf[40];
int32 off;
cursafe = 0; cursafe = 0;
curarg = 0; curarg = 0;
...@@ -164,7 +163,9 @@ codgen(Node *n, Node *nn) ...@@ -164,7 +163,9 @@ codgen(Node *n, Node *nn)
if(thechar=='6' || thechar=='7') /* [sic] */ if(thechar=='6' || thechar=='7') /* [sic] */
maxargsafe = xround(maxargsafe, 8); maxargsafe = xround(maxargsafe, 8);
sp->to.offset += maxargsafe; sp->to.offset += maxargsafe;
dumpgcargs(thisfn, gcsym);
// 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
...@@ -174,16 +175,9 @@ codgen(Node *n, Node *nn) ...@@ -174,16 +175,9 @@ codgen(Node *n, Node *nn)
// area its own section. // area its own section.
// That said, we've been using stkoff for months // That said, we've been using stkoff for months
// and nothing too terrible has happened. // and nothing too terrible has happened.
off = 0; gextern(gclocalssym, nodconst(-stkoff), 0, 4); // locals
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;
gclocalssym->type = typ(0, T); gclocalssym->type = typ(0, T);
gclocalssym->type->width = off; gclocalssym->type->width = 4;
} }
void void
...@@ -652,15 +646,12 @@ bcomplex(Node *n, Node *c) ...@@ -652,15 +646,12 @@ bcomplex(Node *n, Node *c)
return 0; return 0;
} }
// Makes a bitmap marking the the pointers in t. t starts at the given byte // Updates the bitvector with a set bit for each pointer containing
// offset in the argument list. The returned bitmap should be for pointer // value in the type description starting at offset.
// indexes (relative to offset 0) between baseidx and baseidx+32. static void
static int32 walktype1(Type *t, int32 offset, Bvec *bv)
pointermap_type(Type *t, int32 offset, int32 baseidx)
{ {
Type *t1; Type *t1;
int32 idx;
int32 m;
switch(t->etype) { switch(t->etype) {
case TCHAR: case TCHAR:
...@@ -676,80 +667,74 @@ pointermap_type(Type *t, int32 offset, int32 baseidx) ...@@ -676,80 +667,74 @@ pointermap_type(Type *t, int32 offset, int32 baseidx)
case TFLOAT: case TFLOAT:
case TDOUBLE: case TDOUBLE:
// non-pointer types // non-pointer types
return 0; break;
case TIND: case TIND:
case TARRAY: // unlike Go, C passes arrays by reference case TARRAY: // unlike Go, C passes arrays by reference
// pointer types // pointer types
if((offset + t->offset) % ewidth[TIND] != 0) if((offset + t->offset) % ewidth[TIND] != 0)
yyerror("unaligned pointer"); yyerror("unaligned pointer");
idx = (offset + t->offset) / ewidth[TIND]; bvset(bv, (offset + t->offset) / ewidth[TIND]);
if(idx >= baseidx && idx < baseidx + 32) break;
return 1 << (idx - baseidx);
return 0;
case TSTRUCT: case TSTRUCT:
// build map recursively // build map recursively
m = 0; for(t1 = t->link; t1 != T; t1 = t1->down)
for(t1=t->link; t1; t1=t1->down) walktype1(t1, offset, bv);
m |= pointermap_type(t1, offset, baseidx); break;
return m;
case TUNION: case TUNION:
// We require that all elements of the union have the same pointer map. walktype1(t->link, offset, bv);
m = pointermap_type(t->link, offset, baseidx); break;
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: default:
yyerror("can't handle arg type %s\n", tnames[t->etype]); yyerror("can't handle arg type %s\n", tnames[t->etype]);
return 0;
} }
} }
// Compute a bit vector to describe the pointer containing locations // Compute a bit vector to describe the pointer containing locations
// in the argument list. Adds the data to gcsym and returns the offset // in the argument list. Adds the data to gcsym and returns the offset
// of end of the bit vector. // of end of the bit vector.
static int32 static void
pointermap(Sym *gcsym, int32 off) dumpgcargs(Type *fn, Sym *sym)
{ {
int32 nptrs; Bvec *bv;
int32 i;
int32 s; // offset in argument list (in bytes)
int32 m; // current ptrs[i/32]
Type *t; Type *t;
int32 i;
int32 symoffset, argoffset;
if(hasdotdotdot()) { if(hasdotdotdot()) {
// give up for C vararg functions. // give up for C vararg functions.
// TODO: maybe make a map just for the args we do know? // TODO: maybe make a map just for the args we do know?
gextern(gcsym, nodconst(0), off, 4); // nptrs=0 gextern(sym, nodconst(0), 0, 4); // nptrs=0
return off + 4; symoffset = 4;
} } else {
nptrs = (argsize() + ewidth[TIND] - 1) / ewidth[TIND]; bv = bvalloc((argsize() + ewidth[TIND] - 1) / ewidth[TIND]);
gextern(gcsym, nodconst(nptrs), off, 4); argoffset = align(0, fn->link, Aarg0, nil);
off += 4; if(argoffset > 0) {
// The C calling convention returns structs by
for(i = 0; i < nptrs; i += 32) { // copying them to a location pointed to by a
// generate mask for ptrs at offsets i ... i+31 // hidden first argument. This first argument
m = 0; // is a pointer.
s = align(0, thisfn->link, Aarg0, nil); if(argoffset != ewidth[TIND])
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"); 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) if(t->etype == TVOID)
continue; continue;
s = align(s, t, Aarg1, nil); argoffset = align(argoffset, t, Aarg1, nil);
m |= pointermap_type(t, s, i); walktype1(t, argoffset, bv);
s = align(s, t, Aarg2, nil); argoffset = align(argoffset, t, Aarg2, nil);
}
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;
} }
gextern(gcsym, nodconst(m), off, 4); free(bv);
off += 4;
} }
return off; sym->type = typ(0, T);
// TODO: needs a test for nptrs>32 sym->type->width = symoffset;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment