]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/cc: use a temporary bitmap when constructing pointer maps
authorCarl Shapiro <cshapiro@google.com>
Fri, 9 Aug 2013 20:02:33 +0000 (13:02 -0700)
committerCarl Shapiro <cshapiro@google.com>
Fri, 9 Aug 2013 20:02:33 +0000 (13:02 -0700)
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

src/cmd/cc/bv.c [new file with mode: 0644]
src/cmd/cc/cc.h
src/cmd/cc/pgen.c

diff --git a/src/cmd/cc/bv.c b/src/cmd/cc/bv.c
new file mode 100644 (file)
index 0000000..38d9e43
--- /dev/null
@@ -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;
+}
index fe9f9f79854ee8cc1749ed39491d60391c50f799..af2339c976e15bdeec519218e514de5daebbdfc6 100644 (file)
@@ -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
  */
index 29ab49c42eedfa8b8b58778996f99a3ef269c897..4c6859a73364b5c5584e2740639c2cc61bdfb0c2 100644 (file)
@@ -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(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);
-               off += 4;
+               free(bv);
        }
-       return off;
-       // TODO: needs a test for nptrs>32
+       sym->type = typ(0, T);
+       sym->type->width = symoffset;
 }