summaryrefslogtreecommitdiff
path: root/src/cmd/gc
diff options
context:
space:
mode:
authorMichael Stapelberg <stapelberg@debian.org>2014-06-19 09:22:53 +0200
committerMichael Stapelberg <stapelberg@debian.org>2014-06-19 09:22:53 +0200
commit8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1 (patch)
tree4449f2036cccf162e8417cc5841a35815b3e7ac5 /src/cmd/gc
parentc8bf49ef8a92e2337b69c14b9b88396efe498600 (diff)
downloadgolang-51f2ca399fb8da86b2e7b3a0582e083fab731a98.tar.gz
Imported Upstream version 1.3upstream/1.3
Diffstat (limited to 'src/cmd/gc')
-rw-r--r--src/cmd/gc/align.c10
-rw-r--r--src/cmd/gc/array.c129
-rw-r--r--src/cmd/gc/bits.c2
-rw-r--r--src/cmd/gc/builtin.c30
-rw-r--r--src/cmd/gc/bv.c134
-rw-r--r--src/cmd/gc/closure.c20
-rw-r--r--src/cmd/gc/const.c92
-rw-r--r--src/cmd/gc/dcl.c28
-rw-r--r--src/cmd/gc/doc.go6
-rw-r--r--src/cmd/gc/esc.c190
-rw-r--r--src/cmd/gc/export.c5
-rw-r--r--src/cmd/gc/fmt.c115
-rw-r--r--src/cmd/gc/gen.c95
-rw-r--r--src/cmd/gc/go.h126
-rw-r--r--src/cmd/gc/go.y6
-rw-r--r--src/cmd/gc/inl.c3
-rw-r--r--src/cmd/gc/lex.c97
-rw-r--r--src/cmd/gc/md5.c4
-rw-r--r--src/cmd/gc/md5.h2
-rw-r--r--src/cmd/gc/mparith1.c44
-rw-r--r--src/cmd/gc/mparith2.c10
-rw-r--r--src/cmd/gc/mparith3.c115
-rw-r--r--src/cmd/gc/obj.c281
-rw-r--r--src/cmd/gc/order.c930
-rw-r--r--src/cmd/gc/pgen.c398
-rw-r--r--src/cmd/gc/plive.c1985
-rw-r--r--src/cmd/gc/popt.c79
-rw-r--r--src/cmd/gc/racewalk.c3
-rw-r--r--src/cmd/gc/range.c77
-rw-r--r--src/cmd/gc/reflect.c149
-rw-r--r--src/cmd/gc/runtime.go31
-rw-r--r--src/cmd/gc/select.c116
-rw-r--r--src/cmd/gc/sinit.c98
-rw-r--r--src/cmd/gc/subr.c63
-rw-r--r--src/cmd/gc/swt.c2
-rw-r--r--src/cmd/gc/typecheck.c255
-rw-r--r--src/cmd/gc/walk.c453
-rw-r--r--src/cmd/gc/y.tab.c1762
-rw-r--r--src/cmd/gc/y.tab.h46
39 files changed, 5453 insertions, 2538 deletions
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index 8e9677e75..b809640e4 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -175,11 +175,11 @@ dowidth(Type *t)
case TFLOAT64:
case TCOMPLEX64:
w = 8;
- t->align = widthptr;
+ t->align = widthreg;
break;
case TCOMPLEX128:
w = 16;
- t->align = widthptr;
+ t->align = widthreg;
break;
case TPTR32:
w = 4;
@@ -288,10 +288,10 @@ dowidth(Type *t)
// compute their widths as side-effect.
t1 = t->type;
w = widstruct(t->type, *getthis(t1), 0, 0);
- w = widstruct(t->type, *getinarg(t1), w, widthptr);
- w = widstruct(t->type, *getoutarg(t1), w, widthptr);
+ w = widstruct(t->type, *getinarg(t1), w, widthreg);
+ w = widstruct(t->type, *getoutarg(t1), w, widthreg);
t1->argwid = w;
- if(w%widthptr)
+ if(w%widthreg)
warn("bad type %T %d\n", t1, w);
t->align = 1;
break;
diff --git a/src/cmd/gc/array.c b/src/cmd/gc/array.c
new file mode 100644
index 000000000..5e53c1ff0
--- /dev/null
+++ b/src/cmd/gc/array.c
@@ -0,0 +1,129 @@
+// 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 "go.h"
+
+enum {
+ DEFAULTCAPACITY = 16,
+};
+
+struct Array
+{
+ int32 length; // number of elements
+ int32 size; // element size
+ int32 capacity; // size of data in elements
+ char *data; // element storage
+};
+
+Array*
+arraynew(int32 capacity, int32 size)
+{
+ Array *result;
+
+ if(capacity < 0)
+ fatal("arraynew: capacity %d is not positive", capacity);
+ if(size < 0)
+ fatal("arraynew: size %d is not positive\n", size);
+ result = malloc(sizeof(*result));
+ if(result == nil)
+ fatal("arraynew: malloc failed\n");
+ result->length = 0;
+ result->size = size;
+ result->capacity = capacity == 0 ? DEFAULTCAPACITY : capacity;
+ result->data = malloc(result->capacity * result->size);
+ if(result->data == nil)
+ fatal("arraynew: malloc failed\n");
+ return result;
+}
+
+void
+arrayfree(Array *array)
+{
+ if(array == nil)
+ return;
+ free(array->data);
+ free(array);
+}
+
+int32
+arraylength(Array *array)
+{
+ return array->length;
+}
+
+void*
+arrayget(Array *array, int32 index)
+{
+ if(array == nil)
+ fatal("arrayget: array is nil\n");
+ if(index < 0 || index >= array->length)
+ fatal("arrayget: index %d is out of bounds for length %d\n", index, array->length);
+ return array->data + index * array->size;
+}
+
+void
+arrayset(Array *array, int32 index, void *element)
+{
+ if(array == nil)
+ fatal("arrayset: array is nil\n");
+ if(element == nil)
+ fatal("arrayset: element is nil\n");
+ if(index < 0 || index >= array->length)
+ fatal("arrayget: index %d is out of bounds for length %d\n", index, array->length);
+ memmove(array->data + index * array->size, element, array->size);
+}
+
+static void
+ensurecapacity(Array *array, int32 capacity)
+{
+ int32 newcapacity;
+ char *newdata;
+
+ if(array == nil)
+ fatal("ensurecapacity: array is nil\n");
+ if(capacity < 0)
+ fatal("ensurecapacity: capacity %d is not positive", capacity);
+ if(capacity >= array->capacity) {
+ newcapacity = capacity + (capacity >> 1);
+ newdata = realloc(array->data, newcapacity * array->size);
+ if(newdata == nil)
+ fatal("ensurecapacity: realloc failed\n");
+ array->capacity = newcapacity;
+ array->data = newdata;
+ }
+}
+
+void
+arrayadd(Array *array, void *element)
+{
+ if(array == nil)
+ fatal("arrayset: array is nil\n");
+ if(element == nil)
+ fatal("arrayset: element is nil\n");
+ ensurecapacity(array, array->length + 1);
+ array->length++;
+ arrayset(array, array->length - 1, element);
+}
+
+int32
+arrayindexof(Array *array, void *element)
+{
+ void *p;
+ int32 i;
+
+ for(i = 0; i < array->length; i++) {
+ p = arrayget(array, i);
+ if(memcmp(p, &element, array->size) == 0)
+ return i;
+ }
+ return -1;
+}
+
+void
+arraysort(Array *array, int (*cmp)(const void*, const void*))
+{
+ qsort(array->data, array->length, array->size, cmp);
+}
diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c
index c0fd4d85e..2e79f6f1d 100644
--- a/src/cmd/gc/bits.c
+++ b/src/cmd/gc/bits.c
@@ -153,7 +153,7 @@ Qconv(Fmt *fp)
if(var[i].node == N || var[i].node->sym == S)
fmtprint(fp, "$%d", i);
else {
- fmtprint(fp, "%s", var[i].node->sym->name);
+ fmtprint(fp, "%s(%d)", var[i].node->sym->name, i);
if(var[i].offset != 0)
fmtprint(fp, "%+lld", (vlong)var[i].offset);
}
diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c
index 309dc1ea0..5ca5aeb77 100644
--- a/src/cmd/gc/builtin.c
+++ b/src/cmd/gc/builtin.c
@@ -5,6 +5,7 @@ char *runtimeimport =
"func @\"\".new (@\"\".typ·2 *byte) (? *any)\n"
"func @\"\".panicindex ()\n"
"func @\"\".panicslice ()\n"
+ "func @\"\".panicdivide ()\n"
"func @\"\".throwreturn ()\n"
"func @\"\".throwinit ()\n"
"func @\"\".panicwrap (? string, ? string, ? string)\n"
@@ -23,11 +24,16 @@ char *runtimeimport =
"func @\"\".printnl ()\n"
"func @\"\".printsp ()\n"
"func @\"\".goprintf ()\n"
- "func @\"\".concatstring ()\n"
+ "func @\"\".concatstring2 (? string, ? string) (? string)\n"
+ "func @\"\".concatstring3 (? string, ? string, ? string) (? string)\n"
+ "func @\"\".concatstring4 (? string, ? string, ? string, ? string) (? string)\n"
+ "func @\"\".concatstring5 (? string, ? string, ? string, ? string, ? string) (? string)\n"
+ "func @\"\".concatstrings (? []string) (? string)\n"
"func @\"\".cmpstring (? string, ? string) (? int)\n"
"func @\"\".eqstring (? string, ? string) (? bool)\n"
"func @\"\".intstring (? int64) (? string)\n"
"func @\"\".slicebytetostring (? []byte) (? string)\n"
+ "func @\"\".slicebytetostringtmp (? []byte) (? string)\n"
"func @\"\".slicerunetostring (? []rune) (? string)\n"
"func @\"\".stringtoslicebyte (? string) (? []byte)\n"
"func @\"\".stringtoslicerune (? string) (? []rune)\n"
@@ -38,8 +44,8 @@ char *runtimeimport =
"func @\"\".typ2Itab (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte) (@\"\".ret·1 *byte)\n"
"func @\"\".convI2E (@\"\".elem·2 any) (@\"\".ret·1 any)\n"
"func @\"\".convI2I (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n"
- "func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n"
- "func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 any) (@\"\".ret·1 any)\n"
+ "func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any) (@\"\".ret·1 any)\n"
+ "func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 *any) (@\"\".ret·1 any)\n"
"func @\"\".assertE2E (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
"func @\"\".assertE2E2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n"
"func @\"\".assertE2I (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
@@ -60,26 +66,24 @@ char *runtimeimport =
"func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n"
"func @\"\".equal (@\"\".typ·2 *byte, @\"\".x1·3 any, @\"\".x2·4 any) (@\"\".ret·1 bool)\n"
"func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64) (@\"\".hmap·1 map[any]any)\n"
- "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 any)\n"
+ "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n"
"func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
"func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
"func @\"\".mapaccess1_faststr (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
- "func @\"\".mapaccess2 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 any, @\"\".pres·2 bool)\n"
+ "func @\"\".mapaccess2 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 *any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
"func @\"\".mapaccess2_fast32 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
"func @\"\".mapaccess2_fast64 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
"func @\"\".mapaccess2_faststr (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
- "func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 any, @\"\".val·4 any)\n"
+ "func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any, @\"\".val·4 *any)\n"
"func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *any)\n"
- "func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 any)\n"
+ "func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any)\n"
"func @\"\".mapiternext (@\"\".hiter·1 *any)\n"
- "func @\"\".mapiter1 (@\"\".hiter·2 *any) (@\"\".key·1 any)\n"
- "func @\"\".mapiter2 (@\"\".hiter·3 *any) (@\"\".key·1 any, @\"\".val·2 any)\n"
"func @\"\".makechan (@\"\".chanType·2 *byte, @\"\".hint·3 int64) (@\"\".hchan·1 chan any)\n"
- "func @\"\".chanrecv1 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any) (@\"\".elem·1 any)\n"
- "func @\"\".chanrecv2 (@\"\".chanType·3 *byte, @\"\".hchan·4 <-chan any) (@\"\".elem·1 any, @\"\".received·2 bool)\n"
- "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 any)\n"
+ "func @\"\".chanrecv1 (@\"\".chanType·1 *byte, @\"\".hchan·2 <-chan any, @\"\".elem·3 *any)\n"
+ "func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n"
+ "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n"
"func @\"\".closechan (@\"\".hchan·1 any)\n"
- "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 any) (? bool)\n"
+ "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n"
"func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n"
"func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n"
"func @\"\".newselect (@\"\".size·2 int32) (@\"\".sel·1 *byte)\n"
diff --git a/src/cmd/gc/bv.c b/src/cmd/gc/bv.c
index 92834a97b..2efbbc565 100644
--- a/src/cmd/gc/bv.c
+++ b/src/cmd/gc/bv.c
@@ -11,12 +11,24 @@ enum {
WORDBITS = 32,
};
-uintptr
+static uintptr
bvsize(uintptr n)
{
return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE;
}
+int32
+bvbits(Bvec *bv)
+{
+ return bv->n;
+}
+
+int32
+bvwords(Bvec *bv)
+{
+ return (bv->n + WORDBITS - 1) / WORDBITS;
+}
+
Bvec*
bvalloc(int32 n)
{
@@ -34,26 +46,49 @@ bvalloc(int32 n)
return bv;
}
+/* difference */
void
-bvset(Bvec *bv, int32 i)
+bvandnot(Bvec *dst, Bvec *src1, Bvec *src2)
{
- uint32 mask;
+ int32 i, w;
- if(i < 0 || i >= bv->n)
- fatal("bvset: index %d is out of bounds with length %d\n", i, bv->n);
- mask = 1U << (i % WORDBITS);
- bv->b[i / WORDBITS] |= mask;
+ if(dst->n != src1->n || dst->n != src2->n)
+ fatal("bvand: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n);
+ for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++)
+ dst->b[w] = src1->b[w] & ~src2->b[w];
+}
+
+int
+bvcmp(Bvec *bv1, Bvec *bv2)
+{
+ uintptr nbytes;
+
+ if(bv1->n != bv2->n)
+ fatal("bvequal: lengths %d and %d are not equal", bv1->n, bv2->n);
+ nbytes = bvsize(bv1->n);
+ return memcmp(bv1->b, bv2->b, nbytes);
}
void
-bvres(Bvec *bv, int32 i)
+bvcopy(Bvec *dst, Bvec *src)
{
- uint32 mask;
+ memmove(dst->b, src->b, bvsize(dst->n));
+}
- if(i < 0 || i >= bv->n)
- fatal("bvres: index %d is out of bounds with length %d\n", i, bv->n);
- mask = ~(1 << (i % WORDBITS));
- bv->b[i / WORDBITS] &= mask;
+Bvec*
+bvconcat(Bvec *src1, Bvec *src2)
+{
+ Bvec *dst;
+ int32 i;
+
+ dst = bvalloc(src1->n + src2->n);
+ for(i = 0; i < src1->n; i++)
+ if(bvget(src1, i))
+ bvset(dst, i);
+ for(i = 0; i < src2->n; i++)
+ if(bvget(src2, i))
+ bvset(dst, i + src1->n);
+ return dst;
}
int
@@ -63,7 +98,7 @@ bvget(Bvec *bv, int32 i)
if(i < 0 || i >= bv->n)
fatal("bvget: index %d is out of bounds with length %d\n", i, bv->n);
- mask = 1 << (i % WORDBITS);
+ mask = 1U << (i % WORDBITS);
word = bv->b[i / WORDBITS] & mask;
return word ? 1 : 0;
}
@@ -78,3 +113,74 @@ bvisempty(Bvec *bv)
return 0;
return 1;
}
+
+void
+bvnot(Bvec *bv)
+{
+ int32 i, w;
+
+ for(i = 0, w = 0; i < bv->n; i += WORDBITS, w++)
+ bv->b[w] = ~bv->b[w];
+}
+
+/* union */
+void
+bvor(Bvec *dst, Bvec *src1, Bvec *src2)
+{
+ int32 i, w;
+
+ if(dst->n != src1->n || dst->n != src2->n)
+ fatal("bvor: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n);
+ for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++)
+ dst->b[w] = src1->b[w] | src2->b[w];
+}
+
+/* intersection */
+void
+bvand(Bvec *dst, Bvec *src1, Bvec *src2)
+{
+ int32 i, w;
+
+ if(dst->n != src1->n || dst->n != src2->n)
+ fatal("bvor: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n);
+ for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++)
+ dst->b[w] = src1->b[w] & src2->b[w];
+}
+
+void
+bvprint(Bvec *bv)
+{
+ int32 i;
+
+ print("#*");
+ for(i = 0; i < bv->n; i++)
+ print("%d", bvget(bv, i));
+}
+
+void
+bvreset(Bvec *bv, int32 i)
+{
+ uint32 mask;
+
+ if(i < 0 || i >= bv->n)
+ fatal("bvreset: index %d is out of bounds with length %d\n", i, bv->n);
+ mask = ~(1 << (i % WORDBITS));
+ bv->b[i / WORDBITS] &= mask;
+}
+
+void
+bvresetall(Bvec *bv)
+{
+ memset(bv->b, 0x00, bvsize(bv->n));
+}
+
+void
+bvset(Bvec *bv, int32 i)
+{
+ uint32 mask;
+
+ if(i < 0 || i >= bv->n)
+ fatal("bvset: index %d is out of bounds with length %d\n", i, bv->n);
+ mask = 1U << (i % WORDBITS);
+ bv->b[i / WORDBITS] |= mask;
+}
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
index 5a84dfb1b..ad4e5bd02 100644
--- a/src/cmd/gc/closure.c
+++ b/src/cmd/gc/closure.c
@@ -161,6 +161,7 @@ makeclosure(Node *func)
// and initialize in entry prologue.
body = nil;
offset = widthptr;
+ xfunc->needctxt = func->cvars != nil;
for(l=func->cvars; l; l=l->next) {
v = l->n;
if(v->op == 0)
@@ -252,6 +253,14 @@ walkclosure(Node *func, NodeList **init)
// typecheck will insert a PTRLIT node under CONVNOP,
// tag it with escape analysis result.
clos->left->esc = func->esc;
+ // non-escaping temp to use, if any.
+ // orderexpr did not compute the type; fill it in now.
+ if(func->alloc != N) {
+ func->alloc->type = clos->left->left->type;
+ func->alloc->orig->type = func->alloc->type;
+ clos->left->right = func->alloc;
+ func->alloc = N;
+ }
walkexpr(&clos, init);
return clos;
@@ -361,9 +370,12 @@ makepartialcall(Node *fn, Type *t0, Node *meth)
// Declare and initialize variable holding receiver.
body = nil;
+ xfunc->needctxt = 1;
cv = nod(OCLOSUREVAR, N, N);
cv->xoffset = widthptr;
cv->type = rcvrtype;
+ if(cv->type->align > widthptr)
+ cv->xoffset = cv->type->align;
ptr = nod(ONAME, N, N);
ptr->sym = lookup("rcvr");
ptr->class = PAUTO;
@@ -441,6 +453,14 @@ walkpartialcall(Node *n, NodeList **init)
// typecheck will insert a PTRLIT node under CONVNOP,
// tag it with escape analysis result.
clos->left->esc = n->esc;
+ // non-escaping temp to use, if any.
+ // orderexpr did not compute the type; fill it in now.
+ if(n->alloc != N) {
+ n->alloc->type = clos->left->left->type;
+ n->alloc->orig->type = n->alloc->type;
+ clos->left->right = n->alloc;
+ n->alloc = N;
+ }
walkexpr(&clos, init);
return clos;
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index cfb1f0ade..143c1730d 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -22,19 +22,22 @@ Mpflt*
truncfltlit(Mpflt *oldv, Type *t)
{
double d;
- float f;
Mpflt *fv;
+ Val v;
if(t == T)
return oldv;
+ memset(&v, 0, sizeof v);
+ v.ctype = CTFLT;
+ v.u.fval = oldv;
+ overflow(v, t);
+
fv = mal(sizeof *fv);
*fv = *oldv;
// convert large precision literal floating
// into limited precision (float64 or float32)
- // botch -- this assumes that compiler fp
- // has same precision as runtime fp
switch(t->etype) {
case TFLOAT64:
d = mpgetflt(fv);
@@ -42,10 +45,9 @@ truncfltlit(Mpflt *oldv, Type *t)
break;
case TFLOAT32:
- d = mpgetflt(fv);
- f = d;
- d = f;
+ d = mpgetflt32(fv);
mpmovecflt(fv, d);
+
break;
}
return fv;
@@ -235,7 +237,6 @@ convlit1(Node **np, Type *t, int explicit)
n->val = toflt(n->val);
// flowthrough
case CTFLT:
- overflow(n->val, t);
n->val.u.fval = truncfltlit(n->val.u.fval, t);
break;
}
@@ -521,6 +522,7 @@ evconst(Node *n)
int wl, wr, lno, et;
Val v, rv;
Mpint b;
+ NodeList *l1, *l2;
// pick off just the opcodes that can be
// constant evaluated.
@@ -528,7 +530,6 @@ evconst(Node *n)
default:
return;
case OADD:
- case OADDSTR:
case OAND:
case OANDAND:
case OANDNOT:
@@ -559,6 +560,47 @@ evconst(Node *n)
if(!okforconst[n->type->etype] && n->type->etype != TNIL)
return;
break;
+
+ case OADDSTR:
+ // merge adjacent constants in the argument list.
+ for(l1=n->list; l1 != nil; l1= l1->next) {
+ if(isconst(l1->n, CTSTR) && l1->next != nil && isconst(l1->next->n, CTSTR)) {
+ l2 = l1;
+ len = 0;
+ while(l2 != nil && isconst(l2->n, CTSTR)) {
+ nr = l2->n;
+ len += nr->val.u.sval->len;
+ l2 = l2->next;
+ }
+ // merge from l1 up to but not including l2
+ str = mal(sizeof(*str) + len);
+ str->len = len;
+ len = 0;
+ l2 = l1;
+ while(l2 != nil && isconst(l2->n, CTSTR)) {
+ nr = l2->n;
+ memmove(str->s+len, nr->val.u.sval->s, nr->val.u.sval->len);
+ len += nr->val.u.sval->len;
+ l2 = l2->next;
+ }
+ nl = nod(OXXX, N, N);
+ *nl = *l1->n;
+ nl->orig = nl;
+ nl->val.ctype = CTSTR;
+ nl->val.u.sval = str;
+ l1->n = nl;
+ l1->next = l2;
+ }
+ }
+ // fix list end pointer.
+ for(l2=n->list; l2 != nil; l2=l2->next)
+ n->list->end = l2;
+ // collapse single-constant list to single constant.
+ if(count(n->list) == 1 && isconst(n->list->n, CTSTR)) {
+ n->op = OLITERAL;
+ n->val = n->list->n->val;
+ }
+ return;
}
nl = n->left;
@@ -861,15 +903,6 @@ evconst(Node *n)
if(cmpslit(nl, nr) > 0)
goto settrue;
goto setfalse;
- case TUP(OADDSTR, CTSTR):
- len = v.u.sval->len + rv.u.sval->len;
- str = mal(sizeof(*str) + len);
- str->len = len;
- memcpy(str->s, v.u.sval->s, v.u.sval->len);
- memcpy(str->s+v.u.sval->len, rv.u.sval->s, rv.u.sval->len);
- str->len = len;
- v.u.sval = str;
- break;
case TUP(OOROR, CTBOOL):
if(v.u.bval || rv.u.bval)
@@ -918,6 +951,7 @@ unary:
case TUP(OCONV, CTFLT):
case TUP(OCONV, CTSTR):
convlit1(&nl, n->type, 1);
+ v = nl->val;
break;
case TUP(OPLUS, CTINT):
@@ -1144,7 +1178,10 @@ defaultlit(Node **np, Type *t)
}
if(n->val.ctype == CTNIL) {
lineno = lno;
- yyerror("use of untyped nil");
+ if(!n->diag) {
+ yyerror("use of untyped nil");
+ n->diag = 1;
+ }
n->type = T;
break;
}
@@ -1559,7 +1596,7 @@ isgoconst(Node *n)
case ONAME:
l = n->sym->def;
- if(l->op == OLITERAL && n->val.ctype != CTNIL)
+ if(l && l->op == OLITERAL && n->val.ctype != CTNIL)
return 1;
break;
@@ -1594,10 +1631,25 @@ hascallchan(Node *n)
if(n == N)
return 0;
switch(n->op) {
+ case OAPPEND:
case OCALL:
case OCALLFUNC:
- case OCALLMETH:
case OCALLINTER:
+ case OCALLMETH:
+ case OCAP:
+ case OCLOSE:
+ case OCOMPLEX:
+ case OCOPY:
+ case ODELETE:
+ case OIMAG:
+ case OLEN:
+ case OMAKE:
+ case ONEW:
+ case OPANIC:
+ case OPRINT:
+ case OPRINTN:
+ case OREAL:
+ case ORECOVER:
case ORECV:
return 1;
}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index c7d13ef06..73c2581be 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -130,7 +130,7 @@ dumpdcl(char *st)
}
print(" '%s'", d->name);
s = pkglookup(d->name, d->pkg);
- print(" %lS\n", s);
+ print(" %S\n", s);
}
}
@@ -643,8 +643,8 @@ funcargs(Node *nt)
fatal("funcargs out %O", n->op);
if(n->left == N) {
- // give it a name so escape analysis has nodes to work with
- snprint(namebuf, sizeof(namebuf), "~anon%d", gen++);
+ // Name so that escape analysis can track it. ~r stands for 'result'.
+ snprint(namebuf, sizeof(namebuf), "~r%d", gen++);
n->left = newname(lookup(namebuf));
// TODO: n->left->missing = 1;
}
@@ -652,14 +652,20 @@ funcargs(Node *nt)
n->left->op = ONAME;
if(isblank(n->left)) {
- // Give it a name so we can assign to it during return.
- // preserve the original in ->orig
+ // Give it a name so we can assign to it during return. ~b stands for 'blank'.
+ // The name must be different from ~r above because if you have
+ // func f() (_ int)
+ // func g() int
+ // f is allowed to use a plain 'return' with no arguments, while g is not.
+ // So the two cases must be distinguished.
+ // We do not record a pointer to the original node (n->orig).
+ // Having multiple names causes too much confusion in later passes.
nn = nod(OXXX, N, N);
*nn = *n->left;
+ nn->orig = nn;
+ snprint(namebuf, sizeof(namebuf), "~b%d", gen++);
+ nn->sym = lookup(namebuf);
n->left = nn;
-
- snprint(namebuf, sizeof(namebuf), "~anon%d", gen++);
- n->left->sym = lookup(namebuf);
}
n->left->ntype = n->right;
@@ -941,8 +947,6 @@ interfacefield(Node *n)
f->nname = n->left;
f->embedded = n->embedded;
f->sym = f->nname->sym;
- if(importpkg && !exportname(f->sym->name))
- f->sym = pkglookup(f->sym->name, structpkg);
}
} else {
@@ -1211,7 +1215,7 @@ functype(Node *this, NodeList *in, NodeList *out)
t->outnamed = 0;
if(t->outtuple > 0 && out->n->left != N && out->n->left->orig != N) {
s = out->n->left->orig->sym;
- if(s != S && s->name[0] != '~')
+ if(s != S && (s->name[0] != '~' || s->name[1] != 'r')) // ~r%d is the name invented for an unnamed result
t->outnamed = 1;
}
@@ -1434,6 +1438,8 @@ funccompile(Node *n, int isclosure)
// record offset to actual frame pointer.
// for closure, have to skip over leading pointers and PC slot.
+ // TODO(rsc): this is the old jit closure handling code.
+ // with the new closures, isclosure is always 0; delete this block.
nodfp->xoffset = 0;
if(isclosure) {
NodeList *l;
diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go
index 791967708..03df93a3e 100644
--- a/src/cmd/gc/doc.go
+++ b/src/cmd/gc/doc.go
@@ -37,6 +37,8 @@ Substitute 6g with 8g or 5g where appropriate.
Flags:
-o file
output file, default file.6 for 6g, etc.
+ -pack
+ write an archive file rather than an object file
-e
normally the compiler quits after 10 errors; -e prints all errors
-p path
@@ -50,12 +52,14 @@ Flags:
add dir1 and dir2 to the list of paths to check for imported packages
-N
disable optimizations
+ -nolocalimports
+ disallow local (relative) imports
-S
write assembly language text to standard output (code only)
-S -S
write assembly language text to standard output (code and data)
-u
- disallow importing packages not marked as safe
+ disallow importing packages not marked as safe; implies -nolocalimports
-V
print the compiler version
-race
diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c
index b84b66ef1..78624d7cb 100644
--- a/src/cmd/gc/esc.c
+++ b/src/cmd/gc/esc.c
@@ -185,12 +185,12 @@ visitcode(Node *n, uint32 min)
typedef struct EscState EscState;
static void escfunc(EscState*, Node *func);
-static void esclist(EscState*, NodeList *l);
-static void esc(EscState*, Node *n);
+static void esclist(EscState*, NodeList *l, Node *up);
+static void esc(EscState*, Node *n, Node *up);
static void escloopdepthlist(EscState*, NodeList *l);
static void escloopdepth(EscState*, Node *n);
static void escassign(EscState*, Node *dst, Node *src);
-static void esccall(EscState*, Node*);
+static void esccall(EscState*, Node*, Node *up);
static void escflows(EscState*, Node *dst, Node *src);
static void escflood(EscState*, Node *dst);
static void escwalk(EscState*, int level, Node *dst, Node *src);
@@ -204,6 +204,13 @@ struct EscState {
// flow to.
Node theSink;
+ // If an analyzed function is recorded to return
+ // pieces obtained via indirection from a parameter,
+ // and later there is a call f(x) to that function,
+ // we create a link funcParam <- x to record that fact.
+ // The funcParam node is handled specially in escflood.
+ Node funcParam;
+
NodeList* dsts; // all dst nodes
int loopdepth; // for detecting nested loop scopes
int pdepth; // for debug printing in recursions.
@@ -269,7 +276,13 @@ analyze(NodeList *all, int recursive)
e->theSink.sym = lookup(".sink");
e->theSink.escloopdepth = -1;
e->recursive = recursive;
-
+
+ e->funcParam.op = ONAME;
+ e->funcParam.orig = &e->funcParam;
+ e->funcParam.class = PAUTO;
+ e->funcParam.sym = lookup(".param");
+ e->funcParam.escloopdepth = 10000000;
+
for(l=all; l; l=l->next)
if(l->n->op == ODCLFUNC)
l->n->esc = EscFuncPlanned;
@@ -328,6 +341,7 @@ escfunc(EscState *e, Node *func)
ll->n->escloopdepth = 0;
break;
case PPARAM:
+ ll->n->escloopdepth = 1;
if(ll->n->type && !haspointers(ll->n->type))
break;
if(curfn->nbody == nil && !curfn->noescape)
@@ -335,7 +349,6 @@ escfunc(EscState *e, Node *func)
else
ll->n->esc = EscNone; // prime for escflood later
e->noesc = list(e->noesc, ll->n);
- ll->n->escloopdepth = 1;
break;
}
}
@@ -347,7 +360,7 @@ escfunc(EscState *e, Node *func)
escflows(e, &e->theSink, ll->n);
escloopdepthlist(e, curfn->nbody);
- esclist(e, curfn->nbody);
+ esclist(e, curfn->nbody, curfn);
curfn = savefn;
e->loopdepth = saveld;
}
@@ -405,14 +418,14 @@ escloopdepth(EscState *e, Node *n)
}
static void
-esclist(EscState *e, NodeList *l)
+esclist(EscState *e, NodeList *l, Node *up)
{
for(; l; l=l->next)
- esc(e, l->n);
+ esc(e, l->n, up);
}
static void
-esc(EscState *e, Node *n)
+esc(EscState *e, Node *n, Node *up)
{
int lno;
NodeList *ll, *lr;
@@ -423,18 +436,32 @@ esc(EscState *e, Node *n)
lno = setlineno(n);
+ // ninit logically runs at a different loopdepth than the rest of the for loop.
+ esclist(e, n->ninit, n);
+
if(n->op == OFOR || n->op == ORANGE)
e->loopdepth++;
- esc(e, n->left);
- esc(e, n->right);
- esc(e, n->ntest);
- esc(e, n->nincr);
- esclist(e, n->ninit);
- esclist(e, n->nbody);
- esclist(e, n->nelse);
- esclist(e, n->list);
- esclist(e, n->rlist);
+ // type switch variables have no ODCL.
+ // process type switch as declaration.
+ // must happen before processing of switch body,
+ // so before recursion.
+ if(n->op == OSWITCH && n->ntest && n->ntest->op == OTYPESW) {
+ for(ll=n->list; ll; ll=ll->next) { // cases
+ // ll->n->nname is the variable per case
+ if(ll->n->nname)
+ ll->n->nname->escloopdepth = e->loopdepth;
+ }
+ }
+
+ esc(e, n->left, n);
+ esc(e, n->right, n);
+ esc(e, n->ntest, n);
+ esc(e, n->nincr, n);
+ esclist(e, n->nbody, n);
+ esclist(e, n->nelse, n);
+ esclist(e, n->list, n);
+ esclist(e, n->rlist, n);
if(n->op == OFOR || n->op == ORANGE)
e->loopdepth--;
@@ -520,7 +547,7 @@ esc(EscState *e, Node *n)
case OCALLMETH:
case OCALLFUNC:
case OCALLINTER:
- esccall(e, n);
+ esccall(e, n, up);
break;
case OAS2FUNC: // x,y = f()
@@ -628,7 +655,6 @@ esc(EscState *e, Node *n)
escassign(e, n, a);
}
// fallthrough
- case OADDR:
case OMAKECHAN:
case OMAKEMAP:
case OMAKESLICE:
@@ -637,6 +663,35 @@ esc(EscState *e, Node *n)
n->esc = EscNone; // until proven otherwise
e->noesc = list(e->noesc, n);
break;
+
+ case OADDR:
+ n->esc = EscNone; // until proven otherwise
+ e->noesc = list(e->noesc, n);
+ // current loop depth is an upper bound on actual loop depth
+ // of addressed value.
+ n->escloopdepth = e->loopdepth;
+ // for &x, use loop depth of x if known.
+ // it should always be known, but if not, be conservative
+ // and keep the current loop depth.
+ if(n->left->op == ONAME) {
+ switch(n->left->class) {
+ case PAUTO:
+ if(n->left->escloopdepth != 0)
+ n->escloopdepth = n->left->escloopdepth;
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ // PPARAM is loop depth 1 always.
+ // PPARAMOUT is loop depth 0 for writes
+ // but considered loop depth 1 for address-of,
+ // so that writing the address of one result
+ // to another (or the same) result makes the
+ // first result move to the heap.
+ n->escloopdepth = 1;
+ break;
+ }
+ }
+ break;
}
lineno = lno;
@@ -748,8 +803,8 @@ escassign(EscState *e, Node *dst, Node *src)
case ODOTTYPE:
case ODOTTYPE2:
case OSLICE:
- case OSLICEARR:
case OSLICE3:
+ case OSLICEARR:
case OSLICE3ARR:
// Conversions, field access, slice all preserve the input value.
escassign(e, dst, src->left);
@@ -792,24 +847,34 @@ escassign(EscState *e, Node *dst, Node *src)
lineno = lno;
}
-static void
+static int
escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src)
{
- int em;
+ int em, em0;
em = parsetag(note);
-
+
if(em == EscUnknown) {
escassign(e, &e->theSink, src);
- return;
+ return em;
}
-
- for(em >>= EscBits; em && dsts; em >>= 1, dsts=dsts->next)
+
+ if(em == EscNone)
+ return em;
+
+ // If content inside parameter (reached via indirection)
+ // escapes back to results, mark as such.
+ if(em & EscContentEscapes)
+ escassign(e, &e->funcParam, src);
+
+ em0 = em;
+ for(em >>= EscReturnBits; em && dsts; em >>= 1, dsts=dsts->next)
if(em & 1)
escassign(e, dsts->n, src);
if (em != 0 && dsts == nil)
fatal("corrupt esc tag %Z or messed up escretval list\n", note);
+ return em0;
}
// This is a bit messier than fortunate, pulled out of esc's big
@@ -819,7 +884,7 @@ escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src)
// different for methods vs plain functions and for imported vs
// this-package
static void
-esccall(EscState *e, Node *n)
+esccall(EscState *e, Node *n, Node *up)
{
NodeList *ll, *lr;
Node *a, *fn, *src;
@@ -856,7 +921,7 @@ esccall(EscState *e, Node *n)
if(a->type->etype == TSTRUCT && a->type->funarg) // f(g()).
ll = a->escretval;
}
-
+
if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype && fn->defn->esc < EscFuncTagged) {
// function in same mutually recursive group. Incorporate into flow graph.
// print("esc local fn: %N\n", fn->ntype);
@@ -876,6 +941,10 @@ esccall(EscState *e, Node *n)
if(lr->n->isddd && !n->isddd) {
// Introduce ODDDARG node to represent ... allocation.
src = nod(ODDDARG, N, N);
+ src->type = typ(TARRAY);
+ src->type->type = lr->n->type->type;
+ src->type->bound = count(ll);
+ src->type = ptrto(src->type); // make pointer so it will be tracked
src->escloopdepth = e->loopdepth;
src->lineno = n->lineno;
src->esc = EscNone; // until we find otherwise
@@ -916,8 +985,12 @@ esccall(EscState *e, Node *n)
// print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
// Receiver.
- if(n->op != OCALLFUNC)
- escassignfromtag(e, getthisx(fntype)->type->note, n->escretval, n->left->left);
+ if(n->op != OCALLFUNC) {
+ t = getthisx(fntype)->type;
+ src = n->left->left;
+ if(haspointers(t->type))
+ escassignfromtag(e, t->note, n->escretval, src);
+ }
for(t=getinargx(fntype)->type; ll; ll=ll->next) {
src = ll->n;
@@ -926,11 +999,40 @@ esccall(EscState *e, Node *n)
src = nod(ODDDARG, N, N);
src->escloopdepth = e->loopdepth;
src->lineno = n->lineno;
+ src->type = typ(TARRAY);
+ src->type->type = t->type->type;
+ src->type->bound = count(ll);
+ src->type = ptrto(src->type); // make pointer so it will be tracked
src->esc = EscNone; // until we find otherwise
e->noesc = list(e->noesc, src);
n->right = src;
}
- escassignfromtag(e, t->note, n->escretval, src);
+ if(haspointers(t->type)) {
+ if(escassignfromtag(e, t->note, n->escretval, src) == EscNone && up->op != ODEFER && up->op != OPROC) {
+ a = src;
+ while(a->op == OCONVNOP)
+ a = a->left;
+ switch(a->op) {
+ case OCALLPART:
+ case OCLOSURE:
+ case ODDDARG:
+ case OARRAYLIT:
+ case OPTRLIT:
+ case OSTRUCTLIT:
+ // The callee has already been analyzed, so its arguments have esc tags.
+ // The argument is marked as not escaping at all.
+ // Record that fact so that any temporary used for
+ // synthesizing this expression can be reclaimed when
+ // the function returns.
+ // This 'noescape' is even stronger than the usual esc == EscNone.
+ // src->esc == EscNone means that src does not escape the current function.
+ // src->noescape = 1 here means that src does not escape this statement
+ // in the current function.
+ a->noescape = 1;
+ break;
+ }
+ }
+ }
if(src != ll->n)
break;
t = t->down;
@@ -1029,19 +1131,30 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
// Input parameter flowing to output parameter?
if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen <= 20) {
- if(src->op == ONAME && src->class == PPARAM && level == 0 && src->curfn == dst->curfn) {
- if(src->esc != EscScope && src->esc != EscHeap) {
+ if(src->op == ONAME && src->class == PPARAM && src->curfn == dst->curfn && src->esc != EscScope && src->esc != EscHeap) {
+ if(level == 0) {
if(debug['m'])
warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym);
if((src->esc&EscMask) != EscReturn)
src->esc = EscReturn;
- src->esc |= 1<<((dst->vargen-1) + EscBits);
+ src->esc |= 1<<((dst->vargen-1) + EscReturnBits);
+ goto recurse;
+ } else if(level > 0) {
+ if(debug['m'])
+ warnl(src->lineno, "%N leaking param %hN content to result %S", src->curfn->nname, src, dst->sym);
+ if((src->esc&EscMask) != EscReturn)
+ src->esc = EscReturn;
+ src->esc |= EscContentEscapes;
goto recurse;
}
}
}
- leaks = (level <= 0) && (dst->escloopdepth < src->escloopdepth);
+ // The second clause is for values pointed at by an object passed to a call
+ // that returns something reached via indirect from the object.
+ // We don't know which result it is or how many indirects, so we treat it as leaking.
+ leaks = level <= 0 && dst->escloopdepth < src->escloopdepth ||
+ level < 0 && dst == &e->funcParam && haspointers(src->type);
switch(src->op) {
case ONAME:
@@ -1094,6 +1207,10 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
break;
case ODOT:
+ case OSLICE:
+ case OSLICEARR:
+ case OSLICE3:
+ case OSLICE3ARR:
escwalk(e, level, dst, src->left);
break;
@@ -1103,7 +1220,6 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
break;
}
// fall through
- case OSLICE:
case ODOTPTR:
case OINDEXMAP:
case OIND:
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
index 31bcdf8e7..da5984ceb 100644
--- a/src/cmd/gc/export.c
+++ b/src/cmd/gc/export.c
@@ -354,7 +354,7 @@ dumpexport(void)
lno = lineno;
- Bprint(bout, "\n$$ // exports\n package %s", localpkg->name);
+ Bprint(bout, "\n$$\npackage %s", localpkg->name);
if(safemode)
Bprint(bout, " safe");
Bprint(bout, "\n");
@@ -369,8 +369,7 @@ dumpexport(void)
dumpsym(l->n->sym);
}
- Bprint(bout, "\n$$ // local types\n\n$$\n"); // 6l expects this. (see ld/go.c)
-
+ Bprint(bout, "\n$$\n");
lineno = lno;
}
diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c
index 9cd344870..b5f8a834f 100644
--- a/src/cmd/gc/fmt.c
+++ b/src/cmd/gc/fmt.c
@@ -17,7 +17,7 @@
// Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg)
//
// %J Node* Node details
-// Flags: "%hJ" supresses things not relevant until walk.
+// Flags: "%hJ" suppresses things not relevant until walk.
//
// %V Val* Constant values
//
@@ -102,75 +102,7 @@ setfmode(unsigned long *flags)
static int
Lconv(Fmt *fp)
{
- struct
- {
- Hist* incl; /* start of this include file */
- int32 idel; /* delta line number to apply to include */
- Hist* line; /* start of this #line directive */
- int32 ldel; /* delta line number to apply to #line */
- } a[HISTSZ];
- int32 lno, d;
- int i, n;
- Hist *h;
-
- lno = va_arg(fp->args, int32);
-
- n = 0;
- for(h=hist; h!=H; h=h->link) {
- if(h->offset < 0)
- continue;
- if(lno < h->line)
- break;
- if(h->name) {
- if(h->offset > 0) {
- // #line directive
- if(n > 0 && n < HISTSZ) {
- a[n-1].line = h;
- a[n-1].ldel = h->line - h->offset + 1;
- }
- } else {
- // beginning of file
- if(n < HISTSZ) {
- a[n].incl = h;
- a[n].idel = h->line;
- a[n].line = 0;
- }
- n++;
- }
- continue;
- }
- n--;
- if(n > 0 && n < HISTSZ) {
- d = h->line - a[n].incl->line;
- a[n-1].ldel += d;
- a[n-1].idel += d;
- }
- }
-
- if(n > HISTSZ)
- n = HISTSZ;
-
- for(i=n-1; i>=0; i--) {
- if(i != n-1) {
- if(fp->flags & ~(FmtWidth|FmtPrec))
- break;
- fmtprint(fp, " ");
- }
- if(debug['L'] || (fp->flags&FmtLong))
- fmtprint(fp, "%s/", pathname);
- if(a[i].line)
- fmtprint(fp, "%s:%d[%s:%d]",
- a[i].line->name, lno-a[i].ldel+1,
- a[i].incl->name, lno-a[i].idel+1);
- else
- fmtprint(fp, "%s:%d",
- a[i].incl->name, lno-a[i].idel+1);
- lno = a[i].incl->line - 1; // now print out start of this file
- }
- if(n == 0)
- fmtprint(fp, "<unknown line number>");
-
- return 0;
+ return linklinefmt(ctxt, fp);
}
static char*
@@ -702,9 +634,17 @@ typefmt(Fmt *fp, Type *t)
case TSTRUCT:
// Format the bucket struct for map[x]y as map.bucket[x]y.
// This avoids a recursive print that generates very long names.
- if(t->hmap != T) {
- t = t->hmap;
- return fmtprint(fp, "map.bucket[%T]%T", t->down, t->type);
+ if(t->map != T) {
+ if(t->map->bucket == t) {
+ return fmtprint(fp, "map.bucket[%T]%T", t->map->down, t->map->type);
+ }
+ if(t->map->hmap == t) {
+ return fmtprint(fp, "map.hdr[%T]%T", t->map->down, t->map->type);
+ }
+ if(t->map->hiter == t) {
+ return fmtprint(fp, "map.iter[%T]%T", t->map->down, t->map->type);
+ }
+ yyerror("unknown internal map type");
}
if(t->funarg) {
@@ -738,12 +678,17 @@ typefmt(Fmt *fp, Type *t)
if(!(fp->flags&FmtShort)) {
s = t->sym;
- // Take the name from the original, lest we substituted it with ~anon%d
+ // Take the name from the original, lest we substituted it with ~r%d or ~b%d.
+ // ~r%d is a (formerly) unnamed result.
if ((fmtmode == FErr || fmtmode == FExp) && t->nname != N) {
if(t->nname->orig != N) {
s = t->nname->orig->sym;
- if(s != S && s->name[0] == '~')
- s = S;
+ if(s != S && s->name[0] == '~') {
+ if(s->name[1] == 'r') // originally an unnamed result
+ s = S;
+ else if(s->name[1] == 'b') // originally the blank identifier _
+ s = lookup("_");
+ }
} else
s = S;
}
@@ -1099,6 +1044,7 @@ static int opprec[] = {
[OEMPTY] = -1,
[OFALL] = -1,
[OFOR] = -1,
+ [OGOTO] = -1,
[OIF] = -1,
[OLABEL] = -1,
[OPROC] = -1,
@@ -1163,7 +1109,10 @@ exprfmt(Fmt *f, Node *n, int prec)
case PAUTO:
case PPARAM:
case PPARAMOUT:
- if(fmtmode == FExp && n->sym && !isblanksym(n->sym) && n->vargen > 0)
+ // _ becomes ~b%d internally; print as _ for export
+ if(fmtmode == FExp && n->sym && n->sym->name[0] == '~' && n->sym->name[1] == 'b')
+ return fmtprint(f, "_");
+ if(fmtmode == FExp && n->sym && !isblank(n) && n->vargen > 0)
return fmtprint(f, "%S·%d", n->sym, n->vargen);
}
@@ -1390,7 +1339,6 @@ exprfmt(Fmt *f, Node *n, int prec)
// Binary
case OADD:
- case OADDSTR:
case OAND:
case OANDAND:
case OANDNOT:
@@ -1415,6 +1363,14 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->right, nprec+1);
return 0;
+ case OADDSTR:
+ for(l=n->list; l; l=l->next) {
+ if(l != n->list)
+ fmtprint(f, " + ");
+ exprfmt(f, l->n, nprec);
+ }
+ return 0;
+
case OCMPSTR:
case OCMPIFACE:
exprfmt(f, n->left, nprec);
@@ -1572,6 +1528,9 @@ Sconv(Fmt *fp)
int r, sm;
unsigned long sf;
+ if(fp->flags&FmtLong)
+ return linksymfmt(fp);
+
s = va_arg(fp->args, Sym*);
if(s == S)
return fmtstrcpy(fp, "<S>");
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index ada16eacc..cf630f348 100644
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -301,6 +301,9 @@ gen(Node *n)
break;
case OLABEL:
+ if(isblanksym(n->left->sym))
+ break;
+
lab = newlab(n);
// if there are pending gotos, resolve them all to the current pc.
@@ -495,6 +498,11 @@ gen(Node *n)
case OCHECKNIL:
cgen_checknil(n->left);
+ break;
+
+ case OVARKILL:
+ gvarkill(n->left);
+ break;
}
ret:
@@ -562,8 +570,7 @@ cgen_proc(Node *n, int proc)
/*
* generate declaration.
- * nothing to do for on-stack automatics,
- * but might have to allocate heap copy
+ * have to allocate heap copy
* for escaped variables.
*/
static void
@@ -739,6 +746,8 @@ cgen_as(Node *nl, Node *nr)
if(tl == T)
return;
if(isfat(tl)) {
+ if(nl->op == ONAME)
+ gvardef(nl);
clearfat(nl);
return;
}
@@ -767,10 +776,18 @@ cgen_eface(Node *n, Node *res)
* so it's important that it is done first
*/
Node dst;
+ Node *tmp;
+
+ tmp = temp(types[tptr]);
+ cgen(n->right, tmp);
+
+ gvardef(res);
+
dst = *res;
dst.type = types[tptr];
dst.xoffset += widthptr;
- cgen(n->right, &dst);
+ cgen(tmp, &dst);
+
dst.xoffset -= widthptr;
cgen(n->left, &dst);
}
@@ -787,7 +804,7 @@ cgen_eface(Node *n, Node *res)
void
cgen_slice(Node *n, Node *res)
{
- Node src, dst, *cap, *len, *offs, *add;
+ Node src, dst, *cap, *len, *offs, *add, *base;
cap = n->list->n;
len = n->list->next->n;
@@ -795,24 +812,15 @@ cgen_slice(Node *n, Node *res)
if(n->list->next->next)
offs = n->list->next->next->n;
- // dst.len = hi [ - lo ]
- dst = *res;
- dst.xoffset += Array_nel;
- dst.type = types[simtype[TUINT]];
- cgen(len, &dst);
-
- if(n->op != OSLICESTR) {
- // dst.cap = cap [ - lo ]
- dst = *res;
- dst.xoffset += Array_cap;
- dst.type = types[simtype[TUINT]];
- cgen(cap, &dst);
- }
-
- // dst.array = src.array [ + lo *width ]
- dst = *res;
- dst.xoffset += Array_array;
- dst.type = types[TUINTPTR];
+ // evaluate base pointer first, because it is the only
+ // possibly complex expression. once that is evaluated
+ // and stored, updating the len and cap can be done
+ // without making any calls, so without doing anything that
+ // might cause preemption or garbage collection.
+ // this makes the whole slice update atomic as far as the
+ // garbage collector can see.
+
+ base = temp(types[TUINTPTR]);
if(isnil(n->left)) {
tempname(&src, n->left->type);
@@ -821,24 +829,49 @@ cgen_slice(Node *n, Node *res)
src = *n->left;
if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR)
src.xoffset += Array_array;
- src.type = types[TUINTPTR];
if(n->op == OSLICEARR || n->op == OSLICE3ARR) {
if(!isptr[n->left->type->etype])
fatal("slicearr is supposed to work on pointer: %+N\n", n);
- cgen(&src, &dst);
- cgen_checknil(&dst);
+ cgen(&src, base);
+ cgen_checknil(base);
if(offs != N) {
- add = nod(OADD, &dst, offs);
+ add = nod(OADD, base, offs);
typecheck(&add, Erv);
- cgen(add, &dst);
+ cgen(add, base);
}
} else if(offs == N) {
- cgen(&src, &dst);
+ src.type = types[tptr];
+ cgen(&src, base);
} else {
- add = nod(OADD, &src, offs);
+ src.type = types[tptr];
+ add = nod(OADDPTR, &src, offs);
typecheck(&add, Erv);
- cgen(add, &dst);
+ cgen(add, base);
+ }
+
+ // committed to the update
+ gvardef(res);
+
+ // dst.array = src.array [ + lo *width ]
+ dst = *res;
+ dst.xoffset += Array_array;
+ dst.type = types[tptr];
+
+ cgen(base, &dst);
+
+ // dst.len = hi [ - lo ]
+ dst = *res;
+ dst.xoffset += Array_nel;
+ dst.type = types[simtype[TUINT]];
+ cgen(len, &dst);
+
+ if(n->op != OSLICESTR) {
+ // dst.cap = cap [ - lo ]
+ dst = *res;
+ dst.xoffset += Array_cap;
+ dst.type = types[simtype[TUINT]];
+ cgen(cap, &dst);
}
}
@@ -935,5 +968,5 @@ temp(Type *t)
n = nod(OXXX, N, N);
tempname(n, t);
n->sym->def->used = 1;
- return n;
+ return n->orig;
}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 562f16890..413e71069 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
#include <bio.h>
+#include <link.h>
#undef OAPPEND
@@ -31,7 +32,6 @@ enum
STRINGSZ = 200,
MAXALIGN = 7,
UINF = 100,
- HISTSZ = 10,
PRIME1 = 3,
@@ -129,6 +129,10 @@ struct Val
} u;
};
+// prevent incompatible type signatures between libgc and 8g on Plan 9
+#pragma incomplete struct Array
+
+typedef struct Array Array;
typedef struct Bvec Bvec;
typedef struct Pkg Pkg;
typedef struct Sym Sym;
@@ -190,6 +194,8 @@ struct Type
// TMAP
Type* bucket; // internal type representing a hash bucket
Type* hmap; // internal type representing a Hmap (map header object)
+ Type* hiter; // internal type representing hash iterator state
+ Type* map; // link from the above 3 internal types back to the map type.
int32 maplineno; // first use of TFORW as map key
int32 embedlineno; // first use of TFORW as embedded type
@@ -230,8 +236,10 @@ enum
EscNone,
EscReturn,
EscNever,
- EscBits = 4,
+ EscBits = 3,
EscMask = (1<<EscBits) - 1,
+ EscContentEscapes = 1<<EscBits, // value obtained by indirect of parameter escapes to some returned result
+ EscReturnBits = EscBits+1,
};
struct Node
@@ -277,6 +285,7 @@ struct Node
schar likely; // likeliness of if statement
uchar hasbreak; // has break statement
uchar needzero; // if it contains pointers, needs to be zeroed on function entry
+ uchar needctxt; // function uses context register (has closure variables)
uint esc; // EscXXX
int funcdepth;
@@ -392,6 +401,7 @@ struct Sym
int32 block; // blocknumber to catch redeclaration
int32 lastlineno; // last declaration for diagnostic
Pkg* origpkg; // original package for . import
+ LSym* lsym;
};
#define S ((Sym*)0)
@@ -420,16 +430,6 @@ struct Iter
Node* n;
};
-typedef struct Hist Hist;
-struct Hist
-{
- Hist* link;
- char* name;
- int32 line;
- int32 offset;
-};
-#define H ((Hist*)0)
-
// Node ops.
enum
{
@@ -447,11 +447,13 @@ enum
OSUB, // x - y
OOR, // x | y
OXOR, // x ^ y
+ OADDPTR, // ptr + uintptr, inserted by compiler only, used to avoid unsafe type changes during codegen
OADDSTR, // s + "foo"
OADDR, // &x
OANDAND, // b0 && b1
OAPPEND, // append
OARRAYBYTESTR, // string(bytes)
+ OARRAYBYTESTRTMP, // string(bytes) ephemeral
OARRAYRUNESTR, // string(runes)
OSTRARRAYBYTE, // []byte(s)
OSTRARRAYRUNE, // []rune(s)
@@ -506,7 +508,7 @@ enum
OKEY, // The x:3 in t{x:3, y:4}, the 1:2 in a[1:2], the 2:20 in [3]int{2:20}, etc.
OPARAM, // The on-stack copy of a parameter or return value that escapes.
OLEN, // len
- OMAKE, // make, typechecking may convert to a more specfic OMAKEXXX.
+ OMAKE, // make, typechecking may convert to a more specific OMAKEXXX.
OMAKECHAN, // make(chan int)
OMAKEMAP, // make(map[string]int)
OMAKESLICE, // make([]int, 0)
@@ -528,7 +530,7 @@ enum
OPRINTN, // println
OPAREN, // (x)
OSEND, // c <- x
- OSLICE, // v[1:2], typechecking may convert to a more specfic OSLICEXXX.
+ OSLICE, // v[1:2], typechecking may convert to a more specific OSLICEXXX.
OSLICEARR, // a[1:2]
OSLICESTR, // s[1:2]
OSLICE3, // v[1:2:3], typechecking may convert to OSLICE3ARR.
@@ -583,6 +585,7 @@ enum
OCLOSUREVAR, // variable reference at beginning of closure function
OCFUNC, // reference to c function pointer (not go func value)
OCHECKNIL, // emit code to ensure pointer/interface not nil
+ OVARKILL, // variable is dead
// arch-specific registers
OREGISTER, // a register, such as AX.
@@ -724,6 +727,7 @@ struct Var
{
vlong offset;
Node* node;
+ Var* nextinnode;
int width;
char name;
char etype;
@@ -804,9 +808,6 @@ struct Magic
int ua; // output - adder
};
-typedef struct Prog Prog;
-#pragma incomplete Prog
-
struct Label
{
uchar used;
@@ -859,9 +860,6 @@ EXTERN Io pushedio;
EXTERN int32 lexlineno;
EXTERN int32 lineno;
EXTERN int32 prevlineno;
-EXTERN char* pathname;
-EXTERN Hist* hist;
-EXTERN Hist* ehist;
EXTERN char* infile;
EXTERN char* outfile;
@@ -870,6 +868,7 @@ EXTERN int nerrors;
EXTERN int nsavederrors;
EXTERN int nsyntaxerrors;
EXTERN int safemode;
+EXTERN int nolocalimports;
EXTERN char namebuf[NSYMB];
EXTERN char lexbuf[NSYMB];
EXTERN char litbuf[NSYMB];
@@ -950,7 +949,6 @@ EXTERN Node* lasttype;
EXTERN vlong maxarg;
EXTERN vlong stksize; // stack size for current frame
EXTERN vlong stkptrsize; // prefix of stack containing pointers
-EXTERN vlong stkzerosize; // prefix of stack that must be zeroed on entry
EXTERN int32 blockgen; // max block number
EXTERN int32 block; // current block number
EXTERN int hasdefer; // flag that curfn has defer statetment
@@ -959,12 +957,14 @@ EXTERN Node* curfn;
EXTERN int widthptr;
EXTERN int widthint;
+EXTERN int widthreg;
EXTERN Node* typesw;
EXTERN Node* nblank;
extern int thechar;
extern char* thestring;
+extern LinkArch* thelinkarch;
EXTERN int use_sse;
EXTERN char* hunk;
@@ -980,10 +980,17 @@ EXTERN char* flag_installsuffix;
EXTERN int flag_race;
EXTERN int flag_largemodel;
EXTERN int noescape;
+EXTERN int debuglive;
+EXTERN Link* ctxt;
EXTERN int nointerface;
EXTERN int fieldtrack_enabled;
EXTERN int precisestack_enabled;
+EXTERN int writearchive;
+
+EXTERN Biobuf bstdout;
+
+EXTERN int nacl;
/*
* y.tab.c
@@ -1002,6 +1009,18 @@ vlong rnd(vlong o, vlong r);
void typeinit(void);
/*
+ * array.c
+ */
+Array* arraynew(int32 capacity, int32 size);
+void arrayfree(Array *array);
+int32 arraylength(Array *array);
+void* arrayget(Array *array, int32 index);
+void arrayset(Array *array, int32 index, void *element);
+void arrayadd(Array *array, void *element);
+int32 arrayindexof(Array* array, void *element);
+void arraysort(Array* array, int (*cmp)(const void*, const void*));
+
+/*
* bits.c
*/
int Qconv(Fmt *fp);
@@ -1019,11 +1038,19 @@ int bset(Bits a, uint n);
* bv.c
*/
Bvec* bvalloc(int32 n);
-void bvset(Bvec *bv, int32 i);
-void bvres(Bvec *bv, int32 i);
+void bvandnot(Bvec *dst, Bvec *src1, Bvec *src2);
+int bvcmp(Bvec *bv1, Bvec *bv2);
+void bvcopy(Bvec *dst, Bvec *src);
+Bvec* bvconcat(Bvec *src1, Bvec *src2);
int bvget(Bvec *bv, int32 i);
int bvisempty(Bvec *bv);
-int bvcmp(Bvec *bv1, Bvec *bv2);
+void bvnot(Bvec *bv);
+void bvor(Bvec *dst, Bvec *src1, Bvec *src2);
+void bvand(Bvec *dst, Bvec *src1, Bvec *src2);
+void bvprint(Bvec *bv);
+void bvreset(Bvec *bv, int32 i);
+void bvresetall(Bvec *bv);
+void bvset(Bvec *bv, int32 i);
/*
* closure.c
@@ -1173,7 +1200,6 @@ char* expstring(void);
void mkpackage(char* pkgname);
void unimportfile(void);
int32 yylex(void);
-extern int windows;
extern int yylast;
extern int yyprev;
@@ -1230,17 +1256,19 @@ void mpxorfixfix(Mpint *a, Mpint *b);
void mpaddfltflt(Mpflt *a, Mpflt *b);
void mpdivfltflt(Mpflt *a, Mpflt *b);
double mpgetflt(Mpflt *a);
+double mpgetflt32(Mpflt *a);
void mpmovecflt(Mpflt *a, double c);
void mpmulfltflt(Mpflt *a, Mpflt *b);
void mpnegflt(Mpflt *a);
void mpnorm(Mpflt *a);
+void mpsetexp(Mpflt *a, int exp);
int mptestflt(Mpflt *a);
int sigfig(Mpflt *a);
/*
* obj.c
*/
-void Bputname(Biobuf *b, Sym *s);
+void Bputname(Biobuf *b, LSym *s);
int duint16(Sym *s, int off, uint16 v);
int duint32(Sym *s, int off, uint32 v);
int duint64(Sym *s, int off, uint64 v);
@@ -1248,8 +1276,9 @@ int duint8(Sym *s, int off, uint8 v);
int duintptr(Sym *s, int off, uint64 v);
int dsname(Sym *s, int off, char *dat, int ndat);
void dumpobj(void);
-void ieeedtod(uint64 *ieee, double native);
Sym* stringsym(char*, int);
+void slicebytes(Node*, char*, int);
+LSym* linksym(Sym*);
/*
* order.c
@@ -1274,6 +1303,7 @@ Sym* tracksym(Type *t);
Sym* typesymprefix(char *prefix, Type *t);
int haspointers(Type *t);
void usefield(Node*);
+Type* hiter(Type* t);
/*
* select.c
@@ -1434,32 +1464,21 @@ void walkstmt(Node **np);
void walkstmtlist(NodeList *l);
Node* conv(Node*, Type*);
int candiscard(Node*);
+Node* outervalue(Node*);
/*
- * arch-specific ggen.c/gsubr.c/gobj.c/pgen.c
+ * arch-specific ggen.c/gsubr.c/gobj.c/pgen.c/plive.c
*/
#define P ((Prog*)0)
-typedef struct Plist Plist;
-struct Plist
-{
- Node* name;
- Prog* firstpc;
- int recur;
- Plist* link;
-};
-
-EXTERN Plist* plist;
-EXTERN Plist* plast;
-
EXTERN Prog* continpc;
EXTERN Prog* breakpc;
EXTERN Prog* pc;
EXTERN Prog* firstpc;
-EXTERN Prog* retpc;
EXTERN Node* nodfp;
EXTERN int disable_checknil;
+EXTERN vlong zerosize;
int anyregalloc(void);
void betypeinit(void);
@@ -1474,59 +1493,52 @@ void cgen_checknil(Node*);
void cgen_ret(Node *n);
void clearfat(Node *n);
void compile(Node*);
-void defframe(Prog*, Bvec*);
+void defframe(Prog*);
int dgostringptr(Sym*, int off, char *str);
int dgostrlitptr(Sym*, int off, Strlit*);
int dstringptr(Sym *s, int off, char *str);
int dsymptr(Sym *s, int off, Sym *x, int xoff);
int duintxx(Sym *s, int off, uint64 v, int wid);
void dumpdata(void);
-void dumpfuncs(void);
void fixautoused(Prog*);
void gdata(Node*, Node*, int);
void gdatacomplex(Node*, Mpcplx*);
void gdatastring(Node*, Strlit*);
void ggloblnod(Node *nam);
void ggloblsym(Sym *s, int32 width, int dupok, int rodata);
+void gvardef(Node*);
+void gvarkill(Node*);
Prog* gjmp(Prog*);
void gused(Node*);
void movelarge(NodeList*);
int isfat(Type*);
+void linkarchinit(void);
+void liveness(Node*, Prog*, Sym*, Sym*);
void markautoused(Prog*);
Plist* newplist(void);
Node* nodarg(Type*, int);
void nopout(Prog*);
void patch(Prog*, Prog*);
Prog* unpatch(Prog*);
-void zfile(Biobuf *b, char *p, int n);
-void zhist(Biobuf *b, int line, vlong offset);
-void zname(Biobuf *b, Sym *s, int t);
-#pragma varargck type "A" int
#pragma varargck type "B" Mpint*
-#pragma varargck type "D" Addr*
-#pragma varargck type "lD" Addr*
#pragma varargck type "E" int
#pragma varargck type "E" uint
#pragma varargck type "F" Mpflt*
#pragma varargck type "H" NodeList*
#pragma varargck type "J" Node*
-#pragma varargck type "lL" int
-#pragma varargck type "lL" uint
-#pragma varargck type "L" int
-#pragma varargck type "L" uint
+#pragma varargck type "lL" int32
+#pragma varargck type "L" int32
#pragma varargck type "N" Node*
#pragma varargck type "lN" Node*
+#pragma varargck type "O" int
#pragma varargck type "O" uint
-#pragma varargck type "P" Prog*
#pragma varargck type "Q" Bits
-#pragma varargck type "R" int
#pragma varargck type "S" Sym*
-#pragma varargck type "lS" Sym*
+#pragma varargck type "lS" LSym*
#pragma varargck type "T" Type*
#pragma varargck type "lT" Type*
#pragma varargck type "V" Val*
-#pragma varargck type "Y" char*
#pragma varargck type "Z" Strlit*
/*
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 5432eca85..2f354f723 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -557,6 +557,7 @@ caseblock:
// This is so that the stmt_list action doesn't look at
// the case tokens if the stmt_list is empty.
yylast = yychar;
+ $1->xoffset = block;
}
stmt_list
{
@@ -1730,6 +1731,7 @@ non_dcl_stmt:
{
// will be converted to OFALL
$$ = nod(OXFALL, N, N);
+ $$->xoffset = block;
}
| LBREAK onew_name
{
@@ -2138,6 +2140,10 @@ hidden_literal:
case CTFLT:
mpnegflt($$->val.u.fval);
break;
+ case CTCPLX:
+ mpnegflt(&$$->val.u.cval->real);
+ mpnegflt(&$$->val.u.cval->imag);
+ break;
default:
yyerror("bad negated constant");
}
diff --git a/src/cmd/gc/inl.c b/src/cmd/gc/inl.c
index 6800884a0..cf89b0090 100644
--- a/src/cmd/gc/inl.c
+++ b/src/cmd/gc/inl.c
@@ -392,6 +392,8 @@ inlnode(Node **np)
case OCALLFUNC:
case OCALLMETH:
case OCALLINTER:
+ case OAPPEND:
+ case OCOMPLEX:
// if we just replaced arg in f(arg()) or return arg with an inlined call
// and arg returns multiple values, glue as list
if(count(n->list) == 1 && n->list->n->op == OINLCALL && count(n->list->n->rlist) > 1) {
@@ -800,6 +802,7 @@ inlvar(Node *var)
n->class = PAUTO;
n->used = 1;
n->curfn = curfn; // the calling function, not the called one
+ n->addrtaken = var->addrtaken;
// esc pass wont run if we're inlining into a iface wrapper
// luckily, we can steal the results from the target func
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 8c739391a..a50101c42 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -14,7 +14,6 @@
#define ungetc ccungetc
extern int yychar;
-int windows;
int yyprev;
int yylast;
@@ -61,7 +60,7 @@ static void
addexp(char *s)
{
int i;
-
+
for(i=0; exper[i].name != nil; i++) {
if(strcmp(exper[i].name, s) == 0) {
*exper[i].val = 1;
@@ -78,8 +77,10 @@ setexp(void)
{
char *f[20];
int i, nf;
-
- // The makefile #defines GOEXPERIMENT for us.
+
+ precisestack_enabled = 1; // on by default
+
+ // cmd/dist #defines GOEXPERIMENT for us.
nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ",");
for(i=0; i<nf; i++)
addexp(f[i]);
@@ -165,6 +166,21 @@ fault(int s)
fatal("fault");
}
+#ifdef PLAN9
+void
+catcher(void *v, char *s)
+{
+ USED(v);
+
+ if(strncmp(s, "sys: trap: fault read", 21) == 0) {
+ if(nsavederrors + nerrors > 0)
+ errorexit();
+ fatal("fault");
+ }
+ noted(NDFLT);
+}
+#endif
+
void
doversion(void)
{
@@ -189,6 +205,24 @@ main(int argc, char *argv[])
signal(SIGSEGV, fault);
#endif
+#ifdef PLAN9
+ notify(catcher);
+ // Tell the FPU to handle all exceptions.
+ setfcr(FPPDBL|FPRNR);
+#endif
+ // Allow GOARCH=thestring or GOARCH=thestringsuffix,
+ // but not other values.
+ p = getgoarch();
+ if(strncmp(p, thestring, strlen(thestring)) != 0)
+ sysfatal("cannot use %cg with GOARCH=%s", thechar, p);
+ goarch = p;
+
+ linkarchinit();
+ ctxt = linknew(thelinkarch);
+ ctxt->diag = yyerror;
+ ctxt->bso = &bstdout;
+ Binit(&bstdout, 1, OWRITE);
+
localpkg = mkpkg(strlit(""));
localpkg->prefix = "\"\"";
@@ -229,8 +263,11 @@ main(int argc, char *argv[])
goroot = getgoroot();
goos = getgoos();
- goarch = thestring;
-
+
+ nacl = strcmp(goos, "nacl") == 0;
+ if(nacl)
+ flag_largemodel = 1;
+
setexp();
outfile = nil;
@@ -260,12 +297,16 @@ main(int argc, char *argv[])
flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix);
flagcount("j", "debug runtime-initialized variables", &debug['j']);
flagcount("l", "disable inlining", &debug['l']);
+ flagcount("live", "debug liveness analysis", &debuglive);
flagcount("m", "print optimization decisions", &debug['m']);
+ flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports);
flagstr("o", "obj: set output file", &outfile);
flagstr("p", "path: set expected package import path", &myimportpath);
+ flagcount("pack", "write package file instead of object file", &writearchive);
flagcount("r", "debug generated wrappers", &debug['r']);
flagcount("race", "enable race detector", &flag_race);
flagcount("s", "warn about composite literals that can be simplified", &debug['s']);
+ flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
flagcount("u", "reject unsafe code", &safemode);
flagcount("v", "increase debug verbosity", &debug['v']);
flagcount("w", "debug type checking", &debug['w']);
@@ -275,6 +316,7 @@ main(int argc, char *argv[])
flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel);
flagparse(&argc, &argv, usage);
+ ctxt->debugasm = debug['S'];
if(argc < 1)
usage();
@@ -319,20 +361,6 @@ main(int argc, char *argv[])
sysfatal("unsupported setting GO386=%s", p);
}
- pathname = mal(1000);
- if(getwd(pathname, 999) == 0)
- strcpy(pathname, "/???");
-
- if(yy_isalpha(pathname[0]) && pathname[1] == ':') {
- // On Windows.
- windows = 1;
-
- // Canonicalize path by converting \ to / (Windows accepts both).
- for(p=pathname; *p; p++)
- if(*p == '\\')
- *p = '/';
- }
-
fmtinstallgo();
betypeinit();
if(widthptr == 0)
@@ -527,12 +555,13 @@ skiptopkgdef(Biobuf *b)
return 0;
if(memcmp(p, "!<arch>\n", 8) != 0)
return 0;
- /* symbol table is first; skip it */
+ /* symbol table may be first; skip it */
sz = arsize(b, "__.GOSYMDEF");
- if(sz < 0)
- return 0;
- Bseek(b, sz, 1);
- /* package export block is second */
+ if(sz >= 0)
+ Bseek(b, sz, 1);
+ else
+ Bseek(b, 8, 0);
+ /* package export block is next */
sz = arsize(b, "__.PKGDEF");
if(sz <= 0)
return 0;
@@ -560,7 +589,7 @@ islocalname(Strlit *name)
{
if(name->len >= 1 && name->s[0] == '/')
return 1;
- if(windows && name->len >= 3 &&
+ if(ctxt->windows && name->len >= 3 &&
yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
return 1;
if(name->len >= 2 && strncmp(name->s, "./", 2) == 0)
@@ -581,7 +610,7 @@ findpkg(Strlit *name)
char *q, *suffix, *suffixsep;
if(islocalname(name)) {
- if(safemode)
+ if(safemode || nolocalimports)
return 0;
// try .a before .6. important for building libraries:
// if there is an array.6 in the array.a library,
@@ -702,7 +731,7 @@ importfile(Val *f, int line)
fakeimport();
return;
}
- prefix = pathname;
+ prefix = ctxt->pathname;
if(localimport != nil)
prefix = localimport;
cleanbuf = mal(strlen(prefix) + strlen(path->s) + 2);
@@ -760,7 +789,7 @@ importfile(Val *f, int line)
yyerror("import %s: not a go object file", file);
errorexit();
}
- q = smprint("%s %s %s %s", getgoos(), thestring, getgoversion(), expstring());
+ q = smprint("%s %s %s %s", getgoos(), getgoarch(), getgoversion(), expstring());
if(strcmp(p+10, q) != 0) {
yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
errorexit();
@@ -1528,7 +1557,7 @@ getlinepragma(void)
goto out;
// try to avoid allocating file name over and over
- for(h=hist; h!=H; h=h->link) {
+ for(h=ctxt->hist; h!=nil; h=h->link) {
if(h->name != nil && strcmp(h->name, lexbuf) == 0) {
linehist(h->name, n, 0);
goto out;
@@ -2143,14 +2172,18 @@ struct
} lexn[] =
{
LANDAND, "ANDAND",
+ LANDNOT, "ANDNOT",
LASOP, "ASOP",
LBREAK, "BREAK",
LCASE, "CASE",
LCHAN, "CHAN",
LCOLAS, "COLAS",
+ LCOMM, "<-",
LCONST, "CONST",
LCONTINUE, "CONTINUE",
+ LDDD, "...",
LDEC, "DEC",
+ LDEFAULT, "DEFAULT",
LDEFER, "DEFER",
LELSE, "ELSE",
LEQ, "EQ",
@@ -2177,6 +2210,7 @@ struct
LRANGE, "RANGE",
LRETURN, "RETURN",
LRSH, "RSH",
+ LSELECT, "SELECT",
LSTRUCT, "STRUCT",
LSWITCH, "SWITCH",
LTYPE, "TYPE",
@@ -2207,6 +2241,7 @@ struct
"LASOP", "op=",
"LBREAK", "break",
"LCASE", "case",
+ "LCHAN", "chan",
"LCOLAS", ":=",
"LCONST", "const",
"LCONTINUE", "continue",
@@ -2354,7 +2389,7 @@ mkpackage(char* pkgname)
if(outfile == nil) {
p = strrchr(infile, '/');
- if(windows) {
+ if(ctxt->windows) {
q = strrchr(infile, '\\');
if(q > p)
p = q;
diff --git a/src/cmd/gc/md5.c b/src/cmd/gc/md5.c
index bbd4e298f..0051ac964 100644
--- a/src/cmd/gc/md5.c
+++ b/src/cmd/gc/md5.c
@@ -63,7 +63,7 @@ md5write(MD5 *d, uchar *p, int nn)
}
uint64
-md5sum(MD5 *d)
+md5sum(MD5 *d, uint64 *hi)
{
uchar tmp[64];
int i;
@@ -87,6 +87,8 @@ md5sum(MD5 *d)
if(d->nx != 0)
fatal("md5sum");
+ if(hi != nil)
+ *hi = d->s[2] | ((uint64)d->s[3]<<32);
return d->s[0] | ((uint64)d->s[1]<<32);
}
diff --git a/src/cmd/gc/md5.h b/src/cmd/gc/md5.h
index f153e30f2..5a60106b2 100644
--- a/src/cmd/gc/md5.h
+++ b/src/cmd/gc/md5.h
@@ -13,4 +13,4 @@ struct MD5
void md5reset(MD5*);
void md5write(MD5*, uchar*, int);
-uint64 md5sum(MD5*);
+uint64 md5sum(MD5*, uint64*);
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
index e25044a8b..1519caec7 100644
--- a/src/cmd/gc/mparith1.c
+++ b/src/cmd/gc/mparith1.c
@@ -65,7 +65,7 @@ mpcmpfltc(Mpflt *b, double c)
Mpflt a;
mpmovecflt(&a, c);
- return mpcmpfltflt(&a, b);
+ return mpcmpfltflt(b, &a);
}
void
@@ -416,7 +416,7 @@ mpatoflt(Mpflt *a, char *as)
if(eb) {
if(dp)
goto bad;
- a->exp += ex;
+ mpsetexp(a, a->exp+ex);
goto out;
}
@@ -427,8 +427,14 @@ mpatoflt(Mpflt *a, char *as)
mppow10flt(&b, ex-dp);
mpmulfltflt(a, &b);
} else {
- mppow10flt(&b, dp-ex);
- mpdivfltflt(a, &b);
+ // 4 approximates least_upper_bound(log2(10)).
+ if(dp-ex >= (1<<(8*sizeof(dp)-3)) || (short)(4*(dp-ex)) != 4*(dp-ex)) {
+ mpmovecflt(a, 0.0);
+ }
+ else {
+ mppow10flt(&b, dp-ex);
+ mpdivfltflt(a, &b);
+ }
}
}
@@ -573,20 +579,40 @@ Fconv(Fmt *fp)
{
char buf[500];
Mpflt *fvp, fv;
- double d;
+ double d, dexp;
+ int exp;
fvp = va_arg(fp->args, Mpflt*);
if(fp->flags & FmtSharp) {
// alternate form - decimal for error messages.
// for well in range, convert to double and use print's %g
- if(-900 < fvp->exp && fvp->exp < 900) {
+ exp = fvp->exp + sigfig(fvp)*Mpscale;
+ if(-900 < exp && exp < 900) {
d = mpgetflt(fvp);
if(d >= 0 && (fp->flags & FmtSign))
fmtprint(fp, "+");
- return fmtprint(fp, "%g", d);
+ return fmtprint(fp, "%g", d, exp, fvp);
+ }
+
+ // very out of range. compute decimal approximation by hand.
+ // decimal exponent
+ dexp = fvp->exp * 0.301029995663981195; // log_10(2)
+ exp = (int)dexp;
+ // decimal mantissa
+ fv = *fvp;
+ fv.val.neg = 0;
+ fv.exp = 0;
+ d = mpgetflt(&fv);
+ d *= pow(10, dexp-exp);
+ while(d >= 9.99995) {
+ d /= 10;
+ exp++;
}
- // TODO(rsc): for well out of range, print
- // an approximation like 1.234e1000
+ if(fvp->val.neg)
+ fmtprint(fp, "-");
+ else if(fp->flags & FmtSign)
+ fmtprint(fp, "+");
+ return fmtprint(fp, "%.5fe+%d", d, exp);
}
if(sigfig(fvp) == 0) {
diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c
index 9b2f664f7..5cf98c62c 100644
--- a/src/cmd/gc/mparith2.c
+++ b/src/cmd/gc/mparith2.c
@@ -300,13 +300,21 @@ mpmulfixfix(Mpint *a, Mpint *b)
for(i=0; i<na; i++) {
x = *a1++;
for(j=0; j<Mpscale; j++) {
- if(x & 1)
+ if(x & 1) {
+ if(s.ovf) {
+ q.ovf = 1;
+ goto out;
+ }
mpaddfixfix(&q, &s, 1);
+ if(q.ovf)
+ goto out;
+ }
mplsh(&s, 1);
x >>= 1;
}
}
+out:
q.neg = a->neg ^ b->neg;
mpmovefixfix(a, &q);
if(a->ovf)
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
index f8344c9b4..95618f1c6 100644
--- a/src/cmd/gc/mparith3.c
+++ b/src/cmd/gc/mparith3.c
@@ -23,6 +23,27 @@ sigfig(Mpflt *a)
}
/*
+ * sets the exponent.
+ * a too large exponent is an error.
+ * a too small exponent rounds the number to zero.
+ */
+void
+mpsetexp(Mpflt *a, int exp) {
+ if((short)exp != exp) {
+ if(exp > 0) {
+ yyerror("float constant is too large");
+ a->exp = 0x7fff;
+ }
+ else {
+ mpmovecflt(a, 0);
+ }
+ }
+ else {
+ a->exp = exp;
+ }
+}
+
+/*
* shifts the leading non-zero
* word of the number to Mpnorm
*/
@@ -60,7 +81,7 @@ mpnorm(Mpflt *a)
}
mpshiftfix(&a->val, s);
- a->exp -= s;
+ mpsetexp(a, a->exp-s);
}
/// implements float arihmetic
@@ -95,7 +116,7 @@ mpaddfltflt(Mpflt *a, Mpflt *b)
if(s < 0) {
// b is larger, shift a right
mpshiftfix(&a->val, s);
- a->exp -= s;
+ mpsetexp(a, a->exp-s);
mpaddfixfix(&a->val, &b->val, 0);
goto out;
}
@@ -131,7 +152,7 @@ mpmulfltflt(Mpflt *a, Mpflt *b)
}
mpmulfract(&a->val, &b->val);
- a->exp = (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1;
+ mpsetexp(a, (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1);
mpnorm(a);
if(Mpdebug)
@@ -171,18 +192,18 @@ mpdivfltflt(Mpflt *a, Mpflt *b)
// divide
mpdivfract(&a->val, &c.val);
- a->exp = (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1;
+ mpsetexp(a, (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1);
mpnorm(a);
if(Mpdebug)
print(" = %F\n\n", a);
}
-double
-mpgetflt(Mpflt *a)
+static double
+mpgetfltN(Mpflt *a, int prec, int bias)
{
- int s, i, e;
- uvlong v, vm;
+ int s, i, e, minexp;
+ uvlong v;
double f;
if(a->val.ovf && nsavederrors+nerrors == 0)
@@ -199,59 +220,69 @@ mpgetflt(Mpflt *a)
while((a->val.a[Mpnorm-1] & Mpsign) == 0) {
mpshiftfix(&a->val, 1);
- a->exp -= 1;
+ mpsetexp(a, a->exp-1); // can set 'a' to zero
+ s = sigfig(a);
+ if(s == 0)
+ return 0;
}
- // the magic numbers (64, 63, 53, 10, -1074) are
- // IEEE specific. this should be done machine
- // independently or in the 6g half of the compiler
-
- // pick up the mantissa and a rounding bit in a uvlong
- s = 53+1;
+ // pick up the mantissa, a rounding bit, and a tie-breaking bit in a uvlong
+ s = prec+2;
v = 0;
for(i=Mpnorm-1; s>=Mpscale; i--) {
v = (v<<Mpscale) | a->val.a[i];
s -= Mpscale;
}
- vm = v;
- if(s > 0)
- vm = (vm<<s) | (a->val.a[i]>>(Mpscale-s));
-
- // continue with 64 more bits
- s += 64;
- for(; s>=Mpscale; i--) {
- v = (v<<Mpscale) | a->val.a[i];
- s -= Mpscale;
- }
- if(s > 0)
+ if(s > 0) {
v = (v<<s) | (a->val.a[i]>>(Mpscale-s));
+ if((a->val.a[i]&((1<<(Mpscale-s))-1)) != 0)
+ v |= 1;
+ i--;
+ }
+ for(; i >= 0; i--) {
+ if(a->val.a[i] != 0)
+ v |= 1;
+ }
// gradual underflow
- e = Mpnorm*Mpscale + a->exp - 53;
- if(e < -1074) {
- s = -e - 1074;
- if(s > 54)
- s = 54;
- v |= vm & ((1ULL<<s) - 1);
- vm >>= s;
- e = -1074;
+ e = Mpnorm*Mpscale + a->exp - prec;
+ minexp = bias+1-prec+1;
+ if(e < minexp) {
+ s = minexp - e;
+ if(s > prec+1)
+ s = prec+1;
+ if((v & ((1<<s)-1)) != 0)
+ v |= 1<<s;
+ v >>= s;
+ e = minexp;
}
+
+ // round to even
+ v |= (v&4)>>2;
+ v += v&1;
+ v >>= 2;
-//print("vm=%.16llux v=%.16llux\n", vm, v);
- // round toward even
- if(v != 0 || (vm&2ULL) != 0)
- vm = (vm>>1) + (vm&1ULL);
- else
- vm >>= 1;
-
- f = (double)(vm);
+ f = (double)(v);
f = ldexp(f, e);
if(a->val.neg)
f = -f;
+
return f;
}
+double
+mpgetflt(Mpflt *a)
+{
+ return mpgetfltN(a, 53, -1023);
+}
+
+double
+mpgetflt32(Mpflt *a)
+{
+ return mpgetfltN(a, 24, -127);
+}
+
void
mpmovecflt(Mpflt *a, double c)
{
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index 4cad08924..4eeb03aa8 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -10,13 +10,28 @@
* architecture-independent object file output
*/
-static void outhist(Biobuf *b);
static void dumpglobls(void);
+enum
+{
+ ArhdrSize = 60
+};
+
+static void
+formathdr(char *arhdr, char *name, vlong size)
+{
+ snprint(arhdr, ArhdrSize, "%-16s%-12d%-6d%-6d%-8o%-10lld`",
+ name, 0, 0, 0, 0644, size);
+ arhdr[ArhdrSize-1] = '\n'; // overwrite \0 written by snprint
+}
+
void
dumpobj(void)
{
NodeList *externs, *tmp;
+ char arhdr[ArhdrSize];
+ vlong startobj, size;
+ Sym *zero;
bout = Bopen(outfile, OWRITE);
if(bout == nil) {
@@ -25,13 +40,34 @@ dumpobj(void)
errorexit();
}
- Bprint(bout, "go object %s %s %s %s\n", getgoos(), thestring, getgoversion(), expstring());
- Bprint(bout, " exports automatically generated from\n");
- Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name);
+ startobj = 0;
+ if(writearchive) {
+ Bwrite(bout, "!<arch>\n", 8);
+ memset(arhdr, 0, sizeof arhdr);
+ Bwrite(bout, arhdr, sizeof arhdr);
+ startobj = Boffset(bout);
+ }
+ Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
dumpexport();
- Bprint(bout, "\n!\n");
+
+ if(writearchive) {
+ Bflush(bout);
+ size = Boffset(bout) - startobj;
+ if(size&1)
+ Bputc(bout, 0);
+ Bseek(bout, startobj - ArhdrSize, 0);
+ formathdr(arhdr, "__.PKGDEF", size);
+ Bwrite(bout, arhdr, ArhdrSize);
+ Bflush(bout);
+
+ Bseek(bout, startobj + size + (size&1), 0);
+ memset(arhdr, 0, ArhdrSize);
+ Bwrite(bout, arhdr, ArhdrSize);
+ startobj = Boffset(bout);
+ Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
+ }
- outhist(bout);
+ Bprint(bout, "\n!\n");
externs = nil;
if(externdcl != nil)
@@ -47,9 +83,22 @@ dumpobj(void)
dumpglobls();
externdcl = tmp;
- dumpdata();
- dumpfuncs();
+ zero = pkglookup("zerovalue", runtimepkg);
+ ggloblsym(zero, zerosize, 1, 1);
+ dumpdata();
+ writeobj(ctxt, bout);
+
+ if(writearchive) {
+ Bflush(bout);
+ size = Boffset(bout) - startobj;
+ if(size&1)
+ Bputc(bout, 0);
+ Bseek(bout, startobj - ArhdrSize, 0);
+ snprint(namebuf, sizeof namebuf, "_go_.%c", thechar);
+ formathdr(arhdr, namebuf, size);
+ Bwrite(bout, arhdr, ArhdrSize);
+ }
Bterm(bout);
}
@@ -75,184 +124,50 @@ dumpglobls(void)
ggloblnod(n);
}
-
+
for(l=funcsyms; l; l=l->next) {
n = l->n;
dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0);
ggloblsym(n->sym, widthptr, 1, 1);
}
+
+ // Do not reprocess funcsyms on next dumpglobls call.
+ funcsyms = nil;
}
void
-Bputname(Biobuf *b, Sym *s)
+Bputname(Biobuf *b, LSym *s)
{
- Bprint(b, "%s", s->pkg->prefix);
- BPUTC(b, '.');
Bwrite(b, s->name, strlen(s->name)+1);
}
-static void
-outzfile(Biobuf *b, char *p)
-{
- char *q, *q2;
-
- while(p) {
- q = utfrune(p, '/');
- if(windows) {
- q2 = utfrune(p, '\\');
- if(q2 && (!q || q2 < q))
- q = q2;
- }
- if(!q) {
- zfile(b, p, strlen(p));
- return;
- }
- if(q > p)
- zfile(b, p, q-p);
- p = q + 1;
- }
-}
-
-#define isdelim(c) (c == '/' || c == '\\')
-
-static void
-outwinname(Biobuf *b, Hist *h, char *ds, char *p)
+LSym*
+linksym(Sym *s)
{
- if(isdelim(p[0])) {
- // full rooted name
- zfile(b, ds, 3); // leading "c:/"
- outzfile(b, p+1);
- } else {
- // relative name
- if(h->offset >= 0 && pathname && pathname[1] == ':') {
- if(tolowerrune(ds[0]) == tolowerrune(pathname[0])) {
- // using current drive
- zfile(b, pathname, 3); // leading "c:/"
- outzfile(b, pathname+3);
- } else {
- // using drive other then current,
- // we don't have any simple way to
- // determine current working directory
- // there, therefore will output name as is
- zfile(b, ds, 2); // leading "c:"
- }
- }
- outzfile(b, p);
+ char *p;
+
+ if(s == nil)
+ return nil;
+ if(s->lsym != nil)
+ return s->lsym;
+ if(isblanksym(s))
+ s->lsym = linklookup(ctxt, "_", 0);
+ else {
+ p = smprint("%s.%s", s->pkg->prefix, s->name);
+ s->lsym = linklookup(ctxt, p, 0);
+ free(p);
}
+ return s->lsym;
}
-static void
-outhist(Biobuf *b)
-{
- Hist *h;
- char *p, ds[] = {'c', ':', '/', 0};
- char *tofree;
- int n;
- static int first = 1;
- static char *goroot, *goroot_final;
-
- if(first) {
- // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
- first = 0;
- goroot = getenv("GOROOT");
- goroot_final = getenv("GOROOT_FINAL");
- if(goroot == nil)
- goroot = "";
- if(goroot_final == nil)
- goroot_final = goroot;
- if(strcmp(goroot, goroot_final) == 0) {
- goroot = nil;
- goroot_final = nil;
- }
- }
-
- tofree = nil;
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- if(p) {
- if(goroot != nil) {
- n = strlen(goroot);
- if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
- tofree = smprint("%s%s", goroot_final, p+n);
- p = tofree;
- }
- }
- if(windows) {
- // if windows variable is set, then, we know already,
- // pathname is started with windows drive specifier
- // and all '\' were replaced with '/' (see lex.c)
- if(isdelim(p[0]) && isdelim(p[1])) {
- // file name has network name in it,
- // like \\server\share\dir\file.go
- zfile(b, "//", 2); // leading "//"
- outzfile(b, p+2);
- } else if(p[1] == ':') {
- // file name has drive letter in it
- ds[0] = p[0];
- outwinname(b, h, ds, p+2);
- } else {
- // no drive letter in file name
- outwinname(b, h, pathname, p);
- }
- } else {
- if(p[0] == '/') {
- // full rooted name, like /home/rsc/dir/file.go
- zfile(b, "/", 1); // leading "/"
- outzfile(b, p+1);
- } else {
- // relative name, like dir/file.go
- if(h->offset >= 0 && pathname && pathname[0] == '/') {
- zfile(b, "/", 1); // leading "/"
- outzfile(b, pathname+1);
- }
- outzfile(b, p);
- }
- }
- }
- zhist(b, h->line, h->offset);
- if(tofree) {
- free(tofree);
- tofree = nil;
- }
- }
-}
-
-void
-ieeedtod(uint64 *ieee, double native)
+int
+duintxx(Sym *s, int off, uint64 v, int wid)
{
- double fr, ho, f;
- int exp;
- uint32 h, l;
- uint64 bits;
-
- if(native < 0) {
- ieeedtod(ieee, -native);
- *ieee |= 1ULL<<63;
- return;
- }
- if(native == 0) {
- *ieee = 0;
- return;
- }
- fr = frexp(native, &exp);
- f = 2097152L; /* shouldn't use fp constants here */
- fr = modf(fr*f, &ho);
- h = ho;
- h &= 0xfffffL;
- f = 65536L;
- fr = modf(fr*f, &ho);
- l = ho;
- l <<= 16;
- l |= (int32)(fr*f);
- bits = ((uint64)h<<32) | l;
- if(exp < -1021) {
- // gradual underflow
- bits |= 1LL<<52;
- bits >>= -1021 - exp;
- exp = -1022;
- }
- bits |= (uint64)(exp+1022L) << 52;
- *ieee = bits;
+ // Update symbol data directly instead of generating a
+ // DATA instruction that liblink will have to interpret later.
+ // This reduces compilation time and memory usage.
+ off = rnd(off, wid);
+ return setuintxx(ctxt, linksym(s), off, v, wid);
}
int
@@ -338,3 +253,31 @@ stringsym(char *s, int len)
return sym;
}
+
+void
+slicebytes(Node *nam, char *s, int len)
+{
+ int off, n, m;
+ static int gen;
+ Sym *sym;
+
+ snprint(namebuf, sizeof(namebuf), ".gobytes.%d", ++gen);
+ sym = pkglookup(namebuf, localpkg);
+ sym->def = newname(sym);
+
+ off = 0;
+ for(n=0; n<len; n+=m) {
+ m = 8;
+ if(m > len-n)
+ m = len-n;
+ off = dsname(sym, off, s+n, m);
+ }
+ ggloblsym(sym, off, 0, 0);
+
+ if(nam->op != ONAME)
+ fatal("slicebytes %N", nam);
+ off = nam->xoffset;
+ off = dsymptr(nam->sym, off, sym, 0);
+ off = duintxx(nam->sym, off, len, widthint);
+ duintxx(nam->sym, off, len, widthint);
+}
diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c
index 7552510e9..30dbc7dac 100644
--- a/src/cmd/gc/order.c
+++ b/src/cmd/gc/order.c
@@ -5,79 +5,343 @@
// Rewrite tree to use separate statements to enforce
// order of evaluation. Makes walk easier, because it
// can (after this runs) reorder at will within an expression.
+//
+// Rewrite x op= y into x = x op y.
+//
+// Introduce temporaries as needed by runtime routines.
+// For example, the map runtime routines take the map key
+// by reference, so make sure all map keys are addressable
+// by copying them to temporaries as needed.
+// The same is true for channel operations.
+//
+// Arrange that map index expressions only appear in direct
+// assignments x = m[k] or m[k] = x, never in larger expressions.
+//
+// Arrange that receive expressions only appear in direct assignments
+// x = <-c or as standalone statements <-c, never in larger expressions.
+
+// TODO(rsc): The temporary introduction during multiple assignments
+// should be moved into this file, so that the temporaries can be cleaned
+// and so that conversions implicit in the OAS2FUNC and OAS2RECV
+// nodes can be made explicit and then have their temporaries cleaned.
+
+// TODO(rsc): Goto and multilevel break/continue can jump over
+// inserted VARKILL annotations. Work out a way to handle these.
+// The current implementation is safe, in that it will execute correctly.
+// But it won't reuse temporaries as aggressively as it might, and
+// it can result in unnecessary zeroing of those variables in the function
+// prologue.
#include <u.h>
#include <libc.h>
#include "go.h"
-static void orderstmt(Node*, NodeList**);
-static void orderstmtlist(NodeList*, NodeList**);
+// Order holds state during the ordering process.
+typedef struct Order Order;
+struct Order
+{
+ NodeList *out; // list of generated statements
+ NodeList *temp; // head of stack of temporary variables
+ NodeList *free; // free list of NodeList* structs (for use in temp)
+};
+
+static void orderstmt(Node*, Order*);
+static void orderstmtlist(NodeList*, Order*);
static void orderblock(NodeList **l);
-static void orderexpr(Node**, NodeList**);
-static void orderexprlist(NodeList*, NodeList**);
+static void orderexpr(Node**, Order*);
+static void orderexprinplace(Node**, Order*);
+static void orderexprlist(NodeList*, Order*);
+static void orderexprlistinplace(NodeList*, Order*);
+// Order rewrites fn->nbody to apply the ordering constraints
+// described in the comment at the top of the file.
void
order(Node *fn)
{
orderblock(&fn->nbody);
}
+// Ordertemp allocates a new temporary with the given type,
+// pushes it onto the temp stack, and returns it.
+// If clear is true, ordertemp emits code to zero the temporary.
+static Node*
+ordertemp(Type *t, Order *order, int clear)
+{
+ Node *var, *a;
+ NodeList *l;
+
+ var = temp(t);
+ if(clear) {
+ a = nod(OAS, var, N);
+ typecheck(&a, Etop);
+ order->out = list(order->out, a);
+ }
+ if((l = order->free) == nil)
+ l = mal(sizeof *l);
+ order->free = l->next;
+ l->next = order->temp;
+ l->n = var;
+ order->temp = l;
+ return var;
+}
+
+// Ordercopyexpr behaves like ordertemp but also emits
+// code to initialize the temporary to the value n.
+//
+// The clear argument is provided for use when the evaluation
+// of tmp = n turns into a function call that is passed a pointer
+// to the temporary as the output space. If the call blocks before
+// tmp has been written, the garbage collector will still treat the
+// temporary as live, so we must zero it before entering that call.
+// Today, this only happens for channel receive operations.
+// (The other candidate would be map access, but map access
+// returns a pointer to the result data instead of taking a pointer
+// to be filled in.)
+static Node*
+ordercopyexpr(Node *n, Type *t, Order *order, int clear)
+{
+ Node *a, *var;
+
+ var = ordertemp(t, order, clear);
+ a = nod(OAS, var, n);
+ typecheck(&a, Etop);
+ order->out = list(order->out, a);
+ return var;
+}
+
+// Ordercheapexpr returns a cheap version of n.
+// The definition of cheap is that n is a variable or constant.
+// If not, ordercheapexpr allocates a new tmp, emits tmp = n,
+// and then returns tmp.
+static Node*
+ordercheapexpr(Node *n, Order *order)
+{
+ switch(n->op) {
+ case ONAME:
+ case OLITERAL:
+ return n;
+ }
+ return ordercopyexpr(n, n->type, order, 0);
+}
+
+// Ordersafeexpr returns a safe version of n.
+// The definition of safe is that n can appear multiple times
+// without violating the semantics of the original program,
+// and that assigning to the safe version has the same effect
+// as assigning to the original n.
+//
+// The intended use is to apply to x when rewriting x += y into x = x + y.
+static Node*
+ordersafeexpr(Node *n, Order *order)
+{
+ Node *l, *r, *a;
+
+ switch(n->op) {
+ default:
+ fatal("ordersafeexpr %O", n->op);
+
+ case ONAME:
+ case OLITERAL:
+ return n;
+
+ case ODOT:
+ l = ordersafeexpr(n->left, order);
+ if(l == n->left)
+ return n;
+ a = nod(OXXX, N, N);
+ *a = *n;
+ a->orig = a;
+ a->left = l;
+ typecheck(&a, Erv);
+ return a;
+
+ case ODOTPTR:
+ case OIND:
+ l = ordercheapexpr(n->left, order);
+ if(l == n->left)
+ return n;
+ a = nod(OXXX, N, N);
+ *a = *n;
+ a->orig = a;
+ a->left = l;
+ typecheck(&a, Erv);
+ return a;
+
+ case OINDEX:
+ case OINDEXMAP:
+ if(isfixedarray(n->left->type))
+ l = ordersafeexpr(n->left, order);
+ else
+ l = ordercheapexpr(n->left, order);
+ r = ordercheapexpr(n->right, order);
+ if(l == n->left && r == n->right)
+ return n;
+ a = nod(OXXX, N, N);
+ *a = *n;
+ a->orig = a;
+ a->left = l;
+ a->right = r;
+ typecheck(&a, Erv);
+ return a;
+ }
+}
+
+// Istemp reports whether n is a temporary variable.
+static int
+istemp(Node *n)
+{
+ if(n->op != ONAME)
+ return 0;
+ return strncmp(n->sym->name, "autotmp_", 8) == 0;
+}
+
+// Isaddrokay reports whether it is okay to pass n's address to runtime routines.
+// Taking the address of a variable makes the liveness and optimization analyses
+// lose track of where the variable's lifetime ends. To avoid hurting the analyses
+// of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay,
+// because we emit explicit VARKILL instructions marking the end of those
+// temporaries' lifetimes.
+static int
+isaddrokay(Node *n)
+{
+ return islvalue(n) && (n->op != ONAME || n->class == PEXTERN || istemp(n));
+}
+
+// Orderaddrtemp ensures that *np is okay to pass by address to runtime routines.
+// If the original argument *np is not okay, orderaddrtemp creates a tmp, emits
+// tmp = *np, and then sets *np to the tmp variable.
static void
-orderstmtlist(NodeList *l, NodeList **out)
+orderaddrtemp(Node **np, Order *order)
+{
+ Node *n;
+
+ n = *np;
+ if(isaddrokay(n))
+ return;
+ *np = ordercopyexpr(n, n->type, order, 0);
+}
+
+// Marktemp returns the top of the temporary variable stack.
+static NodeList*
+marktemp(Order *order)
+{
+ return order->temp;
+}
+
+// Poptemp pops temporaries off the stack until reaching the mark,
+// which must have been returned by marktemp.
+static void
+poptemp(NodeList *mark, Order *order)
+{
+ NodeList *l;
+
+ while((l = order->temp) != mark) {
+ order->temp = l->next;
+ l->next = order->free;
+ order->free = l;
+ }
+}
+
+// Cleantempnopop emits to *out VARKILL instructions for each temporary
+// above the mark on the temporary stack, but it does not pop them
+// from the stack.
+static void
+cleantempnopop(NodeList *mark, Order *order, NodeList **out)
+{
+ NodeList *l;
+ Node *kill;
+
+ for(l=order->temp; l != mark; l=l->next) {
+ kill = nod(OVARKILL, l->n, N);
+ typecheck(&kill, Etop);
+ *out = list(*out, kill);
+ }
+}
+
+// Cleantemp emits VARKILL instructions for each temporary above the
+// mark on the temporary stack and removes them from the stack.
+static void
+cleantemp(NodeList *top, Order *order)
+{
+ cleantempnopop(top, order, &order->out);
+ poptemp(top, order);
+}
+
+// Orderstmtlist orders each of the statements in the list.
+static void
+orderstmtlist(NodeList *l, Order *order)
{
for(; l; l=l->next)
- orderstmt(l->n, out);
+ orderstmt(l->n, order);
}
-// Order the block of statements *l onto a new list,
-// and then replace *l with that list.
+// Orderblock orders the block of statements *l onto a new list,
+// and then replaces *l with that list.
static void
orderblock(NodeList **l)
{
- NodeList *out;
+ Order order;
+ NodeList *mark;
- out = nil;
- orderstmtlist(*l, &out);
- *l = out;
+ memset(&order, 0, sizeof order);
+ mark = marktemp(&order);
+ orderstmtlist(*l, &order);
+ cleantemp(mark, &order);
+ *l = order.out;
}
-// Order the side effects in *np and leave them as
-// the init list of the final *np.
+// Orderexprinplace orders the side effects in *np and
+// leaves them as the init list of the final *np.
static void
-orderexprinplace(Node **np)
+orderexprinplace(Node **np, Order *outer)
{
Node *n;
- NodeList *out;
+ NodeList **lp;
+ Order order;
n = *np;
- out = nil;
- orderexpr(&n, &out);
- addinit(&n, out);
+ memset(&order, 0, sizeof order);
+ orderexpr(&n, &order);
+ addinit(&n, order.out);
+
+ // insert new temporaries from order
+ // at head of outer list.
+ lp = &order.temp;
+ while(*lp != nil)
+ lp = &(*lp)->next;
+ *lp = outer->temp;
+ outer->temp = order.temp;
+
*np = n;
}
-// Like orderblock, but applied to a single statement.
+// Orderstmtinplace orders the side effects of the single statement *np
+// and replaces it with the resulting statement list.
static void
orderstmtinplace(Node **np)
{
Node *n;
- NodeList *out;
-
+ Order order;
+ NodeList *mark;
+
n = *np;
- out = nil;
- orderstmt(n, &out);
- *np = liststmt(out);
+ memset(&order, 0, sizeof order);
+ mark = marktemp(&order);
+ orderstmt(n, &order);
+ cleantemp(mark, &order);
+ *np = liststmt(order.out);
}
-// Move n's init list to *out.
+// Orderinit moves n's init list to order->out.
static void
-orderinit(Node *n, NodeList **out)
+orderinit(Node *n, Order *order)
{
- orderstmtlist(n->ninit, out);
+ orderstmtlist(n->ninit, order);
n->ninit = nil;
}
-// Is the list l actually just f() for a multi-value function?
+// Ismulticall reports whether the list l is f() for a multi-value function.
+// Such an f() could appear as the lone argument to a multi-arg function.
static int
ismulticall(NodeList *l)
{
@@ -102,10 +366,10 @@ ismulticall(NodeList *l)
return n->left->type->outtuple > 1;
}
-// n is a multi-value function call. Add t1, t2, .. = n to out
-// and return the list t1, t2, ...
+// Copyret emits t1, t2, ... = n, where n is a function call,
+// and then returns the list t1, t2, ....
static NodeList*
-copyret(Node *n, NodeList **out)
+copyret(Node *n, Order *order)
{
Type *t;
Node *tmp, *as;
@@ -127,86 +391,224 @@ copyret(Node *n, NodeList **out)
as->list = l1;
as->rlist = list1(n);
typecheck(&as, Etop);
- orderstmt(as, out);
+ orderstmt(as, order);
return l2;
}
+// Ordercallargs orders the list of call arguments *l.
static void
-ordercallargs(NodeList **l, NodeList **out)
+ordercallargs(NodeList **l, Order *order)
{
if(ismulticall(*l)) {
// return f() where f() is multiple values.
- *l = copyret((*l)->n, out);
+ *l = copyret((*l)->n, order);
} else {
- orderexprlist(*l, out);
+ orderexprlist(*l, order);
}
}
+// Ordercall orders the call expression n.
+// n->op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
static void
-ordercall(Node *n, NodeList **out)
+ordercall(Node *n, Order *order)
{
- orderexpr(&n->left, out);
- ordercallargs(&n->list, out);
+ orderexpr(&n->left, order);
+ orderexpr(&n->right, order); // ODDDARG temp
+ ordercallargs(&n->list, order);
}
+// Ordermapassign appends n to order->out, introducing temporaries
+// to make sure that all map assignments have the form m[k] = x,
+// where x is adressable.
+// (Orderexpr has already been called on n, so we know k is addressable.)
+//
+// If n is m[k] = x where x is not addressable, the rewrite is:
+// tmp = x
+// m[k] = tmp
+//
+// If n is the multiple assignment form ..., m[k], ... = ..., the rewrite is
+// t1 = m
+// t2 = k
+// ...., t3, ... = x
+// t1[t2] = t3
+//
+// The temporaries t1, t2 are needed in case the ... being assigned
+// contain m or k. They are usually unnecessary, but in the unnecessary
+// cases they are also typically registerizable, so not much harm done.
+// And this only applies to the multiple-assignment form.
+// We could do a more precise analysis if needed, like in walk.c.
static void
-orderstmt(Node *n, NodeList **out)
+ordermapassign(Node *n, Order *order)
{
- int lno;
+ Node *m, *a;
NodeList *l;
- Node *r;
+ NodeList *post;
+
+ switch(n->op) {
+ default:
+ fatal("ordermapassign %O", n->op);
+
+ case OAS:
+ order->out = list(order->out, n);
+ if(n->left->op == OINDEXMAP && !isaddrokay(n->right)) {
+ m = n->left;
+ n->left = ordertemp(m->type, order, 0);
+ a = nod(OAS, m, n->left);
+ typecheck(&a, Etop);
+ order->out = list(order->out, a);
+ }
+ break;
+
+ case OAS2:
+ case OAS2DOTTYPE:
+ case OAS2MAPR:
+ case OAS2FUNC:
+ post = nil;
+ for(l=n->list; l != nil; l=l->next) {
+ if(l->n->op == OINDEXMAP) {
+ m = l->n;
+ if(!istemp(m->left))
+ m->left = ordercopyexpr(m->left, m->left->type, order, 0);
+ if(!istemp(m->right))
+ m->right = ordercopyexpr(m->right, m->right->type, order, 0);
+ l->n = ordertemp(m->type, order, 0);
+ a = nod(OAS, m, l->n);
+ typecheck(&a, Etop);
+ post = list(post, a);
+ }
+ }
+ order->out = list(order->out, n);
+ order->out = concat(order->out, post);
+ break;
+ }
+}
+
+// Orderstmt orders the statement n, appending to order->out.
+// Temporaries created during the statement are cleaned
+// up using VARKILL instructions as possible.
+static void
+orderstmt(Node *n, Order *order)
+{
+ int lno;
+ NodeList *l, *t, *t1;
+ Node *r, *tmp1, *tmp2, **np;
+ Type *ch;
if(n == N)
return;
lno = setlineno(n);
- orderinit(n, out);
+ orderinit(n, order);
switch(n->op) {
default:
fatal("orderstmt %O", n->op);
+ case OVARKILL:
+ order->out = list(order->out, n);
+ break;
+
+ case OAS:
case OAS2:
case OAS2DOTTYPE:
- case OAS2MAPR:
- case OAS:
- case OASOP:
case OCLOSE:
case OCOPY:
- case ODELETE:
- case OPANIC:
case OPRINT:
case OPRINTN:
case ORECOVER:
case ORECV:
- case OSEND:
- orderexpr(&n->left, out);
- orderexpr(&n->right, out);
- orderexprlist(n->list, out);
- orderexprlist(n->rlist, out);
- *out = list(*out, n);
+ t = marktemp(order);
+ orderexpr(&n->left, order);
+ orderexpr(&n->right, order);
+ orderexprlist(n->list, order);
+ orderexprlist(n->rlist, order);
+ switch(n->op) {
+ case OAS:
+ case OAS2:
+ case OAS2DOTTYPE:
+ ordermapassign(n, order);
+ break;
+ default:
+ order->out = list(order->out, n);
+ break;
+ }
+ cleantemp(t, order);
break;
-
+
+ case OASOP:
+ // Special: rewrite l op= r into l = l op r.
+ // This simplies quite a few operations;
+ // most important is that it lets us separate
+ // out map read from map write when l is
+ // a map index expression.
+ t = marktemp(order);
+ orderexpr(&n->left, order);
+ n->left = ordersafeexpr(n->left, order);
+ tmp1 = treecopy(n->left);
+ if(tmp1->op == OINDEXMAP)
+ tmp1->etype = 0; // now an rvalue not an lvalue
+ tmp1 = ordercopyexpr(tmp1, n->left->type, order, 0);
+ n->right = nod(n->etype, tmp1, n->right);
+ typecheck(&n->right, Erv);
+ orderexpr(&n->right, order);
+ n->etype = 0;
+ n->op = OAS;
+ ordermapassign(n, order);
+ cleantemp(t, order);
+ break;
+
+ case OAS2MAPR:
+ // Special: make sure key is addressable,
+ // and make sure OINDEXMAP is not copied out.
+ t = marktemp(order);
+ orderexprlist(n->list, order);
+ r = n->rlist->n;
+ orderexpr(&r->left, order);
+ orderexpr(&r->right, order);
+ // See case OINDEXMAP below.
+ if(r->right->op == OARRAYBYTESTR)
+ r->right->op = OARRAYBYTESTRTMP;
+ orderaddrtemp(&r->right, order);
+ ordermapassign(n, order);
+ cleantemp(t, order);
+ break;
+
case OAS2FUNC:
// Special: avoid copy of func call n->rlist->n.
- orderexprlist(n->list, out);
- ordercall(n->rlist->n, out);
- *out = list(*out, n);
+ t = marktemp(order);
+ orderexprlist(n->list, order);
+ ordercall(n->rlist->n, order);
+ ordermapassign(n, order);
+ cleantemp(t, order);
break;
case OAS2RECV:
// Special: avoid copy of receive.
- orderexprlist(n->list, out);
- orderexpr(&n->rlist->n->left, out); // arg to recv
- *out = list(*out, n);
+ // Use temporary variables to hold result,
+ // so that chanrecv can take address of temporary.
+ t = marktemp(order);
+ orderexprlist(n->list, order);
+ orderexpr(&n->rlist->n->left, order); // arg to recv
+ ch = n->rlist->n->left->type;
+ tmp1 = ordertemp(ch->type, order, haspointers(ch->type));
+ tmp2 = ordertemp(types[TBOOL], order, 0);
+ order->out = list(order->out, n);
+ r = nod(OAS, n->list->n, tmp1);
+ typecheck(&r, Etop);
+ ordermapassign(r, order);
+ r = nod(OAS, n->list->next->n, tmp2);
+ typecheck(&r, Etop);
+ ordermapassign(r, order);
+ n->list = list(list1(tmp1), tmp2);
+ cleantemp(t, order);
break;
case OBLOCK:
case OEMPTY:
// Special: does not save n onto out.
- orderstmtlist(n->list, out);
+ orderstmtlist(n->list, order);
break;
case OBREAK:
@@ -215,109 +617,329 @@ orderstmt(Node *n, NodeList **out)
case ODCLCONST:
case ODCLTYPE:
case OFALL:
- case_OFALL:
+ case OXFALL:
case OGOTO:
case OLABEL:
case ORETJMP:
// Special: n->left is not an expression; save as is.
- *out = list(*out, n);
+ order->out = list(order->out, n);
break;
case OCALLFUNC:
case OCALLINTER:
case OCALLMETH:
// Special: handle call arguments.
- ordercall(n, out);
- *out = list(*out, n);
+ t = marktemp(order);
+ ordercall(n, order);
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
case ODEFER:
case OPROC:
// Special: order arguments to inner call but not call itself.
- ordercall(n->left, out);
- *out = list(*out, n);
+ t = marktemp(order);
+ switch(n->left->op) {
+ case ODELETE:
+ // Delete will take the address of the key.
+ // Copy key into new temp and do not clean it
+ // (it persists beyond the statement).
+ orderexprlist(n->left->list, order);
+ t1 = marktemp(order);
+ np = &n->left->list->next->n; // map key
+ *np = ordercopyexpr(*np, (*np)->type, order, 0);
+ poptemp(t1, order);
+ break;
+ default:
+ ordercall(n->left, order);
+ break;
+ }
+ order->out = list(order->out, n);
+ cleantemp(t, order);
+ break;
+
+ case ODELETE:
+ t = marktemp(order);
+ orderexpr(&n->list->n, order);
+ orderexpr(&n->list->next->n, order);
+ orderaddrtemp(&n->list->next->n, order); // map key
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
case OFOR:
- orderexprinplace(&n->ntest);
- orderstmtinplace(&n->nincr);
+ // Clean temporaries from condition evaluation at
+ // beginning of loop body and after for statement.
+ t = marktemp(order);
+ orderexprinplace(&n->ntest, order);
+ l = nil;
+ cleantempnopop(t, order, &l);
+ n->nbody = concat(l, n->nbody);
orderblock(&n->nbody);
- *out = list(*out, n);
+ orderstmtinplace(&n->nincr);
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
case OIF:
- orderexprinplace(&n->ntest);
+ // Clean temporaries from condition at
+ // beginning of both branches.
+ t = marktemp(order);
+ orderexprinplace(&n->ntest, order);
+ l = nil;
+ cleantempnopop(t, order, &l);
+ n->nbody = concat(l, n->nbody);
+ l = nil;
+ cleantempnopop(t, order, &l);
+ n->nelse = concat(l, n->nelse);
+ poptemp(t, order);
orderblock(&n->nbody);
orderblock(&n->nelse);
- *out = list(*out, n);
+ order->out = list(order->out, n);
+ break;
+
+ case OPANIC:
+ // Special: argument will be converted to interface using convT2E
+ // so make sure it is an addressable temporary.
+ t = marktemp(order);
+ orderexpr(&n->left, order);
+ if(!isinter(n->left->type))
+ orderaddrtemp(&n->left, order);
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
case ORANGE:
- orderexpr(&n->right, out);
+ // n->right is the expression being ranged over.
+ // order it, and then make a copy if we need one.
+ // We almost always do, to ensure that we don't
+ // see any value changes made during the loop.
+ // Usually the copy is cheap (e.g., array pointer, chan, slice, string are all tiny).
+ // The exception is ranging over an array value (not a slice, not a pointer to array),
+ // which must make a copy to avoid seeing updates made during
+ // the range body. Ranging over an array value is uncommon though.
+ t = marktemp(order);
+ orderexpr(&n->right, order);
+ switch(n->type->etype) {
+ default:
+ fatal("orderstmt range %T", n->type);
+ case TARRAY:
+ if(count(n->list) < 2 || isblank(n->list->next->n)) {
+ // for i := range x will only use x once, to compute len(x).
+ // No need to copy it.
+ break;
+ }
+ // fall through
+ case TCHAN:
+ case TSTRING:
+ // chan, string, slice, array ranges use value multiple times.
+ // make copy.
+ r = n->right;
+ if(r->type->etype == TSTRING && r->type != types[TSTRING]) {
+ r = nod(OCONV, r, N);
+ r->type = types[TSTRING];
+ typecheck(&r, Erv);
+ }
+ n->right = ordercopyexpr(r, r->type, order, 0);
+ break;
+ case TMAP:
+ // copy the map value in case it is a map literal.
+ // TODO(rsc): Make tmp = literal expressions reuse tmp.
+ // For maps tmp is just one word so it hardly matters.
+ r = n->right;
+ n->right = ordercopyexpr(r, r->type, order, 0);
+ // n->alloc is the temp for the iterator.
+ n->alloc = ordertemp(types[TUINT8], order, 1);
+ break;
+ }
for(l=n->list; l; l=l->next)
- orderexprinplace(&l->n);
+ orderexprinplace(&l->n, order);
orderblock(&n->nbody);
- *out = list(*out, n);
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
case ORETURN:
- ordercallargs(&n->list, out);
- *out = list(*out, n);
+ ordercallargs(&n->list, order);
+ order->out = list(order->out, n);
break;
case OSELECT:
+ // Special: clean case temporaries in each block entry.
+ // Select must enter one of its blocks, so there is no
+ // need for a cleaning at the end.
+ t = marktemp(order);
for(l=n->list; l; l=l->next) {
if(l->n->op != OXCASE)
fatal("order select case %O", l->n->op);
r = l->n->left;
- if(r == nil)
- continue;
- switch(r->op) {
- case OSELRECV:
- case OSELRECV2:
- orderexprinplace(&r->left);
- orderexprinplace(&r->ntest);
- orderexpr(&r->right->left, &l->n->ninit);
- break;
- case OSEND:
- orderexpr(&r->left, &l->n->ninit);
- orderexpr(&r->right, &l->n->ninit);
- break;
+ setlineno(l->n);
+ // Append any new body prologue to ninit.
+ // The next loop will insert ninit into nbody.
+ if(l->n->ninit != nil)
+ fatal("order select ninit");
+ if(r != nil) {
+ switch(r->op) {
+ default:
+ yyerror("unknown op in select %O", r->op);
+ dump("select case", r);
+ break;
+
+ case OSELRECV:
+ case OSELRECV2:
+ // If this is case x := <-ch or case x, y := <-ch, the case has
+ // the ODCL nodes to declare x and y. We want to delay that
+ // declaration (and possible allocation) until inside the case body.
+ // Delete the ODCL nodes here and recreate them inside the body below.
+ if(r->colas) {
+ t = r->ninit;
+ if(t != nil && t->n->op == ODCL && t->n->left == r->left)
+ t = t->next;
+ if(t != nil && t->n->op == ODCL && t->n->left == r->ntest)
+ t = t->next;
+ if(t == nil)
+ r->ninit = nil;
+ }
+ if(r->ninit != nil) {
+ yyerror("ninit on select recv");
+ dumplist("ninit", r->ninit);
+ }
+ // case x = <-c
+ // case x, ok = <-c
+ // r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c.
+ // r->left == N means 'case <-c'.
+ // c is always evaluated; x and ok are only evaluated when assigned.
+ orderexpr(&r->right->left, order);
+
+ // Introduce temporary for receive and move actual copy into case body.
+ // avoids problems with target being addressed, as usual.
+ // NOTE: If we wanted to be clever, we could arrange for just one
+ // temporary per distinct type, sharing the temp among all receives
+ // with that temp. Similarly one ok bool could be shared among all
+ // the x,ok receives. Not worth doing until there's a clear need.
+ if(r->left != N && isblank(r->left))
+ r->left = N;
+ if(r->left != N) {
+ // use channel element type for temporary to avoid conversions,
+ // such as in case interfacevalue = <-intchan.
+ // the conversion happens in the OAS instead.
+ tmp1 = r->left;
+ if(r->colas) {
+ tmp2 = nod(ODCL, tmp1, N);
+ typecheck(&tmp2, Etop);
+ l->n->ninit = list(l->n->ninit, tmp2);
+ }
+ r->left = ordertemp(r->right->left->type->type, order, haspointers(r->right->left->type->type));
+ tmp2 = nod(OAS, tmp1, r->left);
+ typecheck(&tmp2, Etop);
+ l->n->ninit = list(l->n->ninit, tmp2);
+ }
+ if(r->ntest != N && isblank(r->ntest))
+ r->ntest = N;
+ if(r->ntest != N) {
+ tmp1 = r->ntest;
+ if(r->colas) {
+ tmp2 = nod(ODCL, tmp1, N);
+ typecheck(&tmp2, Etop);
+ l->n->ninit = list(l->n->ninit, tmp2);
+ }
+ r->ntest = ordertemp(tmp1->type, order, 0);
+ tmp2 = nod(OAS, tmp1, r->ntest);
+ typecheck(&tmp2, Etop);
+ l->n->ninit = list(l->n->ninit, tmp2);
+ }
+ orderblock(&l->n->ninit);
+ break;
+
+ case OSEND:
+ if(r->ninit != nil) {
+ yyerror("ninit on select send");
+ dumplist("ninit", r->ninit);
+ }
+ // case c <- x
+ // r->left is c, r->right is x, both are always evaluated.
+ orderexpr(&r->left, order);
+ if(!istemp(r->left))
+ r->left = ordercopyexpr(r->left, r->left->type, order, 0);
+ orderexpr(&r->right, order);
+ if(!istemp(r->right))
+ r->right = ordercopyexpr(r->right, r->right->type, order, 0);
+ break;
+ }
}
+ orderblock(&l->n->nbody);
}
- *out = list(*out, n);
+ // Now that we have accumulated all the temporaries, clean them.
+ // Also insert any ninit queued during the previous loop.
+ // (The temporary cleaning must follow that ninit work.)
+ for(l=n->list; l; l=l->next) {
+ cleantempnopop(t, order, &l->n->ninit);
+ l->n->nbody = concat(l->n->ninit, l->n->nbody);
+ l->n->ninit = nil;
+ }
+ order->out = list(order->out, n);
+ poptemp(t, order);
+ break;
+
+ case OSEND:
+ // Special: value being sent is passed as a pointer; make it addressable.
+ t = marktemp(order);
+ orderexpr(&n->left, order);
+ orderexpr(&n->right, order);
+ orderaddrtemp(&n->right, order);
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
case OSWITCH:
- orderexpr(&n->ntest, out);
+ // TODO(rsc): Clean temporaries more aggressively.
+ // Note that because walkswitch will rewrite some of the
+ // switch into a binary search, this is not as easy as it looks.
+ // (If we ran that code here we could invoke orderstmt on
+ // the if-else chain instead.)
+ // For now just clean all the temporaries at the end.
+ // In practice that's fine.
+ t = marktemp(order);
+ orderexpr(&n->ntest, order);
for(l=n->list; l; l=l->next) {
if(l->n->op != OXCASE)
fatal("order switch case %O", l->n->op);
- orderexpr(&l->n->left, &l->n->ninit);
+ orderexprlistinplace(l->n->list, order);
+ orderblock(&l->n->nbody);
}
- *out = list(*out, n);
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
-
- case OXFALL:
- yyerror("fallthrough statement out of place");
- n->op = OFALL;
- goto case_OFALL;
}
lineno = lno;
}
+// Orderexprlist orders the expression list l into order.
+static void
+orderexprlist(NodeList *l, Order *order)
+{
+ for(; l; l=l->next)
+ orderexpr(&l->n, order);
+}
+
+// Orderexprlist orders the expression list l but saves
+// the side effects on the individual expression ninit lists.
static void
-orderexprlist(NodeList *l, NodeList **out)
+orderexprlistinplace(NodeList *l, Order *order)
{
for(; l; l=l->next)
- orderexpr(&l->n, out);
+ orderexprinplace(&l->n, order);
}
+// Orderexpr orders a single expression, appending side
+// effects to order->out as needed.
static void
-orderexpr(Node **np, NodeList **out)
+orderexpr(Node **np, Order *order)
{
Node *n;
+ NodeList *mark, *l;
+ Type *t;
int lno;
n = *np;
@@ -325,31 +947,113 @@ orderexpr(Node **np, NodeList **out)
return;
lno = setlineno(n);
- orderinit(n, out);
+ orderinit(n, order);
switch(n->op) {
default:
- orderexpr(&n->left, out);
- orderexpr(&n->right, out);
- orderexprlist(n->list, out);
- orderexprlist(n->rlist, out);
+ orderexpr(&n->left, order);
+ orderexpr(&n->right, order);
+ orderexprlist(n->list, order);
+ orderexprlist(n->rlist, order);
+ break;
+
+ case OADDSTR:
+ // Addition of strings turns into a function call.
+ // Allocate a temporary to hold the strings.
+ // Fewer than 5 strings use direct runtime helpers.
+ orderexprlist(n->list, order);
+ if(count(n->list) > 5) {
+ t = typ(TARRAY);
+ t->bound = count(n->list);
+ t->type = types[TSTRING];
+ n->alloc = ordertemp(t, order, 0);
+ }
+ break;
+
+ case OINDEXMAP:
+ // key must be addressable
+ orderexpr(&n->left, order);
+ orderexpr(&n->right, order);
+
+ // For x = m[string(k)] where k is []byte, the allocation of
+ // backing bytes for the string can be avoided by reusing
+ // the []byte backing array. This is a special case that it
+ // would be nice to handle more generally, but because
+ // there are no []byte-keyed maps, this specific case comes
+ // up in important cases in practice. See issue 3512.
+ // Nothing can change the []byte we are not copying before
+ // the map index, because the map access is going to
+ // be forced to happen immediately following this
+ // conversion (by the ordercopyexpr a few lines below).
+ if(n->etype == 0 && n->right->op == OARRAYBYTESTR)
+ n->right->op = OARRAYBYTESTRTMP;
+
+ orderaddrtemp(&n->right, order);
+ if(n->etype == 0) {
+ // use of value (not being assigned);
+ // make copy in temporary.
+ n = ordercopyexpr(n, n->type, order, 0);
+ }
+ break;
+
+ case OCONVIFACE:
+ // concrete type (not interface) argument must be addressable
+ // temporary to pass to runtime.
+ orderexpr(&n->left, order);
+ if(!isinter(n->left->type))
+ orderaddrtemp(&n->left, order);
break;
case OANDAND:
case OOROR:
- orderexpr(&n->left, out);
- orderexprinplace(&n->right);
+ mark = marktemp(order);
+ orderexpr(&n->left, order);
+ // Clean temporaries from first branch at beginning of second.
+ // Leave them on the stack so that they can be killed in the outer
+ // context in case the short circuit is taken.
+ l = nil;
+ cleantempnopop(mark, order, &l);
+ n->right->ninit = concat(l, n->right->ninit);
+ orderexprinplace(&n->right, order);
break;
case OCALLFUNC:
case OCALLMETH:
case OCALLINTER:
- ordercall(n, out);
- n = copyexpr(n, n->type, out);
+ case OAPPEND:
+ case OCOMPLEX:
+ ordercall(n, order);
+ n = ordercopyexpr(n, n->type, order, 0);
+ break;
+
+ case OCLOSURE:
+ if(n->noescape && n->cvars != nil)
+ n->alloc = ordertemp(types[TUINT8], order, 0); // walk will fill in correct type
+ break;
+
+ case OARRAYLIT:
+ case OCALLPART:
+ orderexpr(&n->left, order);
+ orderexpr(&n->right, order);
+ orderexprlist(n->list, order);
+ orderexprlist(n->rlist, order);
+ if(n->noescape)
+ n->alloc = ordertemp(types[TUINT8], order, 0); // walk will fill in correct type
+ break;
+
+ case ODDDARG:
+ if(n->noescape) {
+ // The ddd argument does not live beyond the call it is created for.
+ // Allocate a temporary that will be cleaned up when this statement
+ // completes. We could be more aggressive and try to arrange for it
+ // to be cleaned up when the call completes.
+ n->alloc = ordertemp(n->type->type, order, 0);
+ }
break;
case ORECV:
- n = copyexpr(n, n->type, out);
+ orderexpr(&n->left, order);
+ n = ordercopyexpr(n, n->type, order, 1);
break;
}
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
index 2850af6bb..40620c3da 100644
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -8,30 +8,159 @@
#include <u.h>
#include <libc.h>
+#include "md5.h"
#include "gg.h"
#include "opt.h"
#include "../../pkg/runtime/funcdata.h"
-enum { BitsPerPointer = 2 };
-
static void allocauto(Prog* p);
-static void dumpgcargs(Node*, Sym*);
-static Bvec* dumpgclocals(Node*, Sym*);
+
+static Sym*
+makefuncdatasym(char *namefmt, int64 funcdatakind)
+{
+ Node nod;
+ Node *pnod;
+ Sym *sym;
+ static int32 nsym;
+
+ snprint(namebuf, sizeof(namebuf), namefmt, nsym++);
+ sym = lookup(namebuf);
+ pnod = newname(sym);
+ pnod->class = PEXTERN;
+ nodconst(&nod, types[TINT32], funcdatakind);
+ gins(AFUNCDATA, &nod, pnod);
+ return sym;
+}
+
+// gvardef inserts a VARDEF for n into the instruction stream.
+// VARDEF is an annotation for the liveness analysis, marking a place
+// where a complete initialization (definition) of a variable begins.
+// Since the liveness analysis can see initialization of single-word
+// variables quite easy, gvardef is usually only called for multi-word
+// or 'fat' variables, those satisfying isfat(n->type).
+// However, gvardef is also called when a non-fat variable is initialized
+// via a block move; the only time this happens is when you have
+// return f()
+// for a function with multiple return values exactly matching the return
+// types of the current function.
+//
+// A 'VARDEF x' annotation in the instruction stream tells the liveness
+// analysis to behave as though the variable x is being initialized at that
+// point in the instruction stream. The VARDEF must appear before the
+// actual (multi-instruction) initialization, and it must also appear after
+// any uses of the previous value, if any. For example, if compiling:
+//
+// x = x[1:]
+//
+// it is important to generate code like:
+//
+// base, len, cap = pieces of x[1:]
+// VARDEF x
+// x = {base, len, cap}
+//
+// If instead the generated code looked like:
+//
+// VARDEF x
+// base, len, cap = pieces of x[1:]
+// x = {base, len, cap}
+//
+// then the liveness analysis would decide the previous value of x was
+// unnecessary even though it is about to be used by the x[1:] computation.
+// Similarly, if the generated code looked like:
+//
+// base, len, cap = pieces of x[1:]
+// x = {base, len, cap}
+// VARDEF x
+//
+// then the liveness analysis will not preserve the new value of x, because
+// the VARDEF appears to have "overwritten" it.
+//
+// VARDEF is a bit of a kludge to work around the fact that the instruction
+// stream is working on single-word values but the liveness analysis
+// wants to work on individual variables, which might be multi-word
+// aggregates. It might make sense at some point to look into letting
+// the liveness analysis work on single-word values as well, although
+// there are complications around interface values, slices, and strings,
+// all of which cannot be treated as individual words.
+//
+// VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
+// even if its address has been taken. That is, a VARKILL annotation asserts
+// that its argument is certainly dead, for use when the liveness analysis
+// would not otherwise be able to deduce that fact.
+
+static void
+gvardefx(Node *n, int as)
+{
+ if(n == N)
+ fatal("gvardef nil");
+ if(n->op != ONAME) {
+ yyerror("gvardef %#O; %N", n->op, n);
+ return;
+ }
+ switch(n->class) {
+ case PAUTO:
+ case PPARAM:
+ case PPARAMOUT:
+ gins(as, N, n);
+ }
+}
+
+void
+gvardef(Node *n)
+{
+ gvardefx(n, AVARDEF);
+}
+
+void
+gvarkill(Node *n)
+{
+ gvardefx(n, AVARKILL);
+}
+
+static void
+removevardef(Prog *firstp)
+{
+ Prog *p;
+
+ for(p = firstp; p != P; p = p->link) {
+ while(p->link != P && (p->link->as == AVARDEF || p->link->as == AVARKILL))
+ p->link = p->link->link;
+ if(p->to.type == D_BRANCH)
+ while(p->to.u.branch != P && (p->to.u.branch->as == AVARDEF || p->to.u.branch->as == AVARKILL))
+ p->to.u.branch = p->to.u.branch->link;
+ }
+}
+
+static void
+gcsymdup(Sym *s)
+{
+ LSym *ls;
+ uint64 lo, hi;
+
+ ls = linksym(s);
+ if(ls->nr > 0)
+ fatal("cannot rosymdup %s with relocations", ls->name);
+ MD5 d;
+ md5reset(&d);
+ md5write(&d, ls->p, ls->np);
+ lo = md5sum(&d, &hi);
+ ls->name = smprint("gclocals·%016llux%016llux", lo, hi);
+ ls->dupok = 1;
+}
void
compile(Node *fn)
{
- Bvec *bv;
Plist *pl;
- Node nod1, *n, *gcargsnod, *gclocalsnod;
- Prog *ptxt, *p, *p1;
+ Node nod1, *n;
+ Prog *ptxt, *p;
int32 lno;
Type *t;
Iter save;
vlong oldstksize;
NodeList *l;
- Sym *gcargssym, *gclocalssym;
- static int ngcargs, ngclocals;
+ Sym *gcargs;
+ Sym *gclocals;
if(newproc == N) {
newproc = sysfunc("newproc");
@@ -45,7 +174,7 @@ compile(Node *fn)
lno = setlineno(fn);
if(fn->nbody == nil) {
- if(pure_go || memcmp(fn->nname->sym->name, "init·", 6) == 0)
+ if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0)
yyerror("missing function body", fn);
goto ret;
}
@@ -88,7 +217,7 @@ compile(Node *fn)
breakpc = P;
pl = newplist();
- pl->name = curfn->nname;
+ pl->name = linksym(curfn->nname->sym);
setlineno(curfn);
@@ -98,6 +227,8 @@ compile(Node *fn)
ptxt->TEXTFLAG |= DUPOK;
if(fn->wrapper)
ptxt->TEXTFLAG |= WRAPPER;
+ if(fn->needctxt)
+ ptxt->TEXTFLAG |= NEEDCTXT;
// Clumsy but important.
// See test/recover.go for test cases and src/pkg/reflect/value.go
@@ -111,21 +242,8 @@ compile(Node *fn)
ginit();
- snprint(namebuf, sizeof namebuf, "gcargs·%d", ngcargs++);
- gcargssym = lookup(namebuf);
- gcargsnod = newname(gcargssym);
- gcargsnod->class = PEXTERN;
-
- nodconst(&nod1, types[TINT32], FUNCDATA_GCArgs);
- gins(AFUNCDATA, &nod1, gcargsnod);
-
- snprint(namebuf, sizeof(namebuf), "gclocals·%d", ngclocals++);
- gclocalssym = lookup(namebuf);
- gclocalsnod = newname(gclocalssym);
- gclocalsnod->class = PEXTERN;
-
- nodconst(&nod1, types[TINT32], FUNCDATA_GCLocals);
- gins(AFUNCDATA, &nod1, gclocalsnod);
+ gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
+ gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps);
for(t=curfn->paramfld; t; t=t->down)
gtrack(tracksym(t->type));
@@ -140,20 +258,12 @@ compile(Node *fn)
case PPARAMOUT:
nodconst(&nod1, types[TUINTPTR], l->n->type->width);
p = gins(ATYPE, l->n, &nod1);
- p->from.gotype = ngotype(l->n);
+ p->from.gotype = linksym(ngotype(l->n));
break;
}
}
genlist(curfn->enter);
-
- retpc = nil;
- if(hasdefer || curfn->exit) {
- p1 = gjmp(nil);
- retpc = gjmp(nil);
- patch(p1, pc);
- }
-
genlist(curfn->nbody);
gclean();
checklabels();
@@ -165,13 +275,15 @@ compile(Node *fn)
if(curfn->type->outtuple != 0)
ginscall(throwreturn, 0);
- if(retpc)
- patch(retpc, pc);
ginit();
- if(hasdefer)
- ginscall(deferreturn, 0);
- if(curfn->exit)
- genlist(curfn->exit);
+ // TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
+ cgen_ret(nil);
+ if(hasdefer) {
+ // deferreturn pretends to have one uintptr argument.
+ // Reserve space for it so stack scanner is happy.
+ if(maxarg < widthptr)
+ maxarg = widthptr;
+ }
gclean();
if(nerrors != 0)
goto ret;
@@ -179,6 +291,7 @@ compile(Node *fn)
pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
+ fixjmp(ptxt);
if(!debug['N'] || debug['R'] || debug['P']) {
regopt(ptxt);
nilopt(ptxt);
@@ -190,6 +303,7 @@ compile(Node *fn)
if(0)
print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
+ USED(oldstksize);
setlineno(curfn);
if((int64)stksize+maxarg > (1ULL<<31)) {
@@ -198,184 +312,21 @@ compile(Node *fn)
}
// Emit garbage collection symbols.
- dumpgcargs(fn, gcargssym);
- bv = dumpgclocals(curfn, gclocalssym);
+ liveness(curfn, ptxt, gcargs, gclocals);
+ gcsymdup(gcargs);
+ gcsymdup(gclocals);
- defframe(ptxt, bv);
- free(bv);
+ defframe(ptxt);
if(0)
frame(0);
+ // Remove leftover instrumentation from the instruction stream.
+ removevardef(ptxt);
ret:
lineno = lno;
}
-static void
-walktype1(Type *t, vlong *xoffset, Bvec *bv)
-{
- vlong fieldoffset, i, o;
- Type *t1;
-
- if(t->align > 0 && (*xoffset % t->align) != 0)
- fatal("walktype1: invalid initial alignment, %T", t);
-
- switch(t->etype) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TBOOL:
- case TFLOAT32:
- case TFLOAT64:
- case TCOMPLEX64:
- case TCOMPLEX128:
- *xoffset += t->width;
- break;
-
- case TPTR32:
- case TPTR64:
- case TUNSAFEPTR:
- case TFUNC:
- case TCHAN:
- case TMAP:
- if(*xoffset % widthptr != 0)
- fatal("walktype1: invalid alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer);
- *xoffset += t->width;
- break;
-
- case TSTRING:
- // struct { byte *str; intgo len; }
- if(*xoffset % widthptr != 0)
- fatal("walktype1: invalid alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer);
- *xoffset += t->width;
- break;
-
- case TINTER:
- // struct { Itab* tab; union { void* ptr, uintptr val } data; }
- // or, when isnilinter(t)==true:
- // struct { Type* type; union { void* ptr, uintptr val } data; }
- if(*xoffset % widthptr != 0)
- fatal("walktype1: invalid alignment, %T", t);
- bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 1);
- if(isnilinter(t))
- bvset(bv, ((*xoffset / widthptr) * BitsPerPointer));
- *xoffset += t->width;
- break;
-
- case TARRAY:
- // The value of t->bound is -1 for slices types and >0 for
- // for fixed array types. All other values are invalid.
- if(t->bound < -1)
- fatal("walktype1: invalid bound, %T", t);
- if(isslice(t)) {
- // struct { byte* array; uintgo len; uintgo cap; }
- if(*xoffset % widthptr != 0)
- fatal("walktype1: invalid TARRAY alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer);
- *xoffset += t->width;
- } else if(!haspointers(t->type))
- *xoffset += t->width;
- else
- for(i = 0; i < t->bound; ++i)
- walktype1(t->type, xoffset, bv);
- break;
-
- case TSTRUCT:
- o = 0;
- for(t1 = t->type; t1 != T; t1 = t1->down) {
- fieldoffset = t1->width;
- *xoffset += fieldoffset - o;
- walktype1(t1->type, xoffset, bv);
- o = fieldoffset + t1->type->width;
- }
- *xoffset += t->width - o;
- break;
-
- default:
- fatal("walktype1: unexpected type, %T", t);
- }
-}
-
-static void
-walktype(Type *type, Bvec *bv)
-{
- vlong xoffset;
-
- // Start the walk at offset 0. The correct offset will be
- // filled in by the first type encountered during the walk.
- xoffset = 0;
- walktype1(type, &xoffset, bv);
-}
-
-// Compute a bit vector to describe the pointer-containing locations
-// in the in and out argument list and dump the bitvector length and
-// data to the provided symbol.
-static void
-dumpgcargs(Node *fn, Sym *sym)
-{
- Type *thistype, *inargtype, *outargtype;
- Bvec *bv;
- int32 i;
- int off;
-
- thistype = getthisx(fn->type);
- inargtype = getinargx(fn->type);
- outargtype = getoutargx(fn->type);
- bv = bvalloc((fn->type->argwid / widthptr) * BitsPerPointer);
- if(thistype != nil)
- walktype(thistype, bv);
- if(inargtype != nil)
- walktype(inargtype, bv);
- if(outargtype != nil)
- walktype(outargtype, bv);
- off = duint32(sym, 0, bv->n);
- for(i = 0; i < bv->n; i += 32)
- off = duint32(sym, off, bv->b[i/32]);
- free(bv);
- ggloblsym(sym, off, 0, 1);
-}
-
-// Compute a bit vector to describe the pointer-containing locations
-// in local variables and dump the bitvector length and data out to
-// the provided symbol. Return the vector for use and freeing by caller.
-static Bvec*
-dumpgclocals(Node* fn, Sym *sym)
-{
- Bvec *bv;
- NodeList *ll;
- Node *node;
- vlong xoffset;
- int32 i;
- int off;
-
- bv = bvalloc((stkptrsize / widthptr) * BitsPerPointer);
- for(ll = fn->dcl; ll != nil; ll = ll->next) {
- node = ll->n;
- if(node->class == PAUTO && node->op == ONAME) {
- if(haspointers(node->type)) {
- xoffset = node->xoffset + stkptrsize;
- walktype1(node->type, &xoffset, bv);
- }
- }
- }
- off = duint32(sym, 0, bv->n);
- for(i = 0; i < bv->n; i += 32) {
- off = duint32(sym, off, bv->b[i/32]);
- }
- ggloblsym(sym, off, 0, 1);
- return bv;
-}
-
// Sort the list of stack variables. Autos after anything else,
// within autos, unused after used, within used, things with
// pointers first, zeroed things first, and then decreasing size.
@@ -415,7 +366,8 @@ cmpstackvar(Node *a, Node *b)
return +1;
if(a->type->width > b->type->width)
return -1;
- return 0;
+
+ return strcmp(a->sym->name, b->sym->name);
}
// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
@@ -428,7 +380,6 @@ allocauto(Prog* ptxt)
stksize = 0;
stkptrsize = 0;
- stkzerosize = 0;
if(curfn->dcl == nil)
return;
@@ -440,13 +391,6 @@ allocauto(Prog* ptxt)
markautoused(ptxt);
- if(precisestack_enabled) {
- // TODO: Remove when liveness analysis sets needzero instead.
- for(ll=curfn->dcl; ll != nil; ll=ll->next)
- if(ll->n->class == PAUTO)
- ll->n->needzero = 1; // ll->n->addrtaken;
- }
-
listsort(&curfn->dcl, cmpstackvar);
// Unused autos are at the end, chop 'em off.
@@ -480,11 +424,8 @@ allocauto(Prog* ptxt)
fatal("bad width");
stksize += w;
stksize = rnd(stksize, n->type->align);
- if(haspointers(n->type)) {
+ if(haspointers(n->type))
stkptrsize = stksize;
- if(n->needzero)
- stkzerosize = stksize;
- }
if(thechar == '5')
stksize = rnd(stksize, widthptr);
if(stksize >= (1ULL<<31)) {
@@ -493,9 +434,8 @@ allocauto(Prog* ptxt)
}
n->stkdelta = -stksize - n->xoffset;
}
- stksize = rnd(stksize, widthptr);
- stkptrsize = rnd(stkptrsize, widthptr);
- stkzerosize = rnd(stkzerosize, widthptr);
+ stksize = rnd(stksize, widthreg);
+ stkptrsize = rnd(stkptrsize, widthreg);
fixautoused(ptxt);
@@ -538,12 +478,12 @@ cgen_checknil(Node *n)
if(disable_checknil)
return;
- // Ideally we wouldn't see any TUINTPTR here, but we do.
- if(n->type == T || (!isptr[n->type->etype] && n->type->etype != TUINTPTR && n->type->etype != TUNSAFEPTR)) {
+ // Ideally we wouldn't see any integer types here, but we do.
+ if(n->type == T || (!isptr[n->type->etype] && !isint[n->type->etype] && n->type->etype != TUNSAFEPTR)) {
dump("checknil", n);
fatal("bad checknil");
}
- if((thechar == '5' && n->op != OREGISTER) || !n->addable) {
+ if((thechar == '5' && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) {
regalloc(&reg, types[tptr], n);
cgen(n, &reg);
gins(ACHECKNIL, &reg, N);
diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c
new file mode 100644
index 000000000..eb8901733
--- /dev/null
+++ b/src/cmd/gc/plive.c
@@ -0,0 +1,1985 @@
+// 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.
+
+// Garbage collector liveness bitmap generation.
+
+// The command line flag -live causes this code to print debug information.
+// The levels are:
+//
+// -live (aka -live=1): print liveness lists as code warnings at safe points
+// -live=2: print an assembly listing with liveness annotations
+// -live=3: print information during each computation phase (much chattier)
+//
+// Each level includes the earlier output as well.
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "opt.h"
+#include "../../pkg/runtime/funcdata.h"
+
+enum { BitsPerPointer = 2 };
+
+enum {
+ UNVISITED = 0,
+ VISITED = 1,
+};
+
+// An ordinary basic block.
+//
+// Instructions are threaded together in a doubly-linked list. To iterate in
+// program order follow the link pointer from the first node and stop after the
+// last node has been visited
+//
+// for(p = bb->first;; p = p->link) {
+// ...
+// if(p == bb->last)
+// break;
+// }
+//
+// To iterate in reverse program order by following the opt pointer from the
+// last node
+//
+// for(p = bb->last; p != nil; p = p->opt) {
+// ...
+// }
+typedef struct BasicBlock BasicBlock;
+struct BasicBlock {
+ // An array of preceding blocks. If the length of this array is 0 the
+ // block is probably the start block of the CFG.
+ Array *pred;
+
+ // An array out succeeding blocks. If the length of this array is zero,
+ // the block probably ends in a return instruction.
+ Array *succ;
+
+ // First instruction in the block. When part of a fully initialized
+ // control flow graph, the opt member will be nil.
+ Prog *first;
+
+ // Last instruction in the basic block.
+ Prog *last;
+
+ // The reverse post order number. This value is initialized to -1 and
+ // will be replaced by a non-negative value when the CFG is constructed.
+ // After CFG construction, if rpo is -1 this block is unreachable.
+ int rpo;
+
+ // State to denote whether the block has been visited during a
+ // traversal.
+ int mark;
+
+ // For use during livenessepilogue.
+ int lastbitmapindex;
+};
+
+// A collection of global state used by liveness analysis.
+typedef struct Liveness Liveness;
+struct Liveness {
+ // A pointer to the node corresponding to the function being analyzed.
+ Node *fn;
+
+ // A linked list of instructions for this function.
+ Prog *ptxt;
+
+ // A list of arguments and local variables in this function.
+ Array *vars;
+
+ // A list of basic blocks that are overlayed on the instruction list.
+ // The blocks are roughly in the same order as the instructions
+ // in the function (first block has TEXT instruction, and so on).
+ Array *cfg;
+
+ // Summary sets of block effects.
+ // The Bvec** is indexed by bb->rpo to yield a single Bvec*.
+ // That bit vector is indexed by variable number (same as lv->vars).
+ //
+ // Computed during livenessprologue using only the content of
+ // individual blocks:
+ //
+ // uevar: upward exposed variables (used before set in block)
+ // varkill: killed variables (set in block)
+ // avarinit: addrtaken variables set or used (proof of initialization)
+ //
+ // Computed during livenesssolve using control flow information:
+ //
+ // livein: variables live at block entry
+ // liveout: variables live at block exit
+ // avarinitany: addrtaken variables possibly initialized at block exit
+ // (initialized in block or at exit from any predecessor block)
+ // avarinitall: addrtaken variables certainly initialized at block exit
+ // (initialized in block or at exit from all predecessor blocks)
+ Bvec **uevar;
+ Bvec **varkill;
+ Bvec **livein;
+ Bvec **liveout;
+ Bvec **avarinit;
+ Bvec **avarinitany;
+ Bvec **avarinitall;
+
+ // An array with a bit vector for each safe point tracking live pointers
+ // in the arguments and locals area, indexed by bb->rpo.
+ Array *argslivepointers;
+ Array *livepointers;
+};
+
+static void*
+xmalloc(uintptr size)
+{
+ void *result;
+
+ result = malloc(size);
+ if(result == nil)
+ fatal("malloc failed");
+ return result;
+}
+
+// Constructs a new basic block containing a single instruction.
+static BasicBlock*
+newblock(Prog *prog)
+{
+ BasicBlock *result;
+
+ if(prog == nil)
+ fatal("newblock: prog cannot be nil");
+ result = xmalloc(sizeof(*result));
+ result->rpo = -1;
+ result->mark = UNVISITED;
+ result->first = prog;
+ result->last = prog;
+ result->pred = arraynew(2, sizeof(BasicBlock*));
+ result->succ = arraynew(2, sizeof(BasicBlock*));
+ return result;
+}
+
+// Frees a basic block and all of its leaf data structures.
+static void
+freeblock(BasicBlock *bb)
+{
+ if(bb == nil)
+ fatal("freeblock: cannot free nil");
+ arrayfree(bb->pred);
+ arrayfree(bb->succ);
+ free(bb);
+}
+
+// Adds an edge between two basic blocks by making from a predecessor of to and
+// to a successor of from.
+static void
+addedge(BasicBlock *from, BasicBlock *to)
+{
+ if(from == nil)
+ fatal("addedge: from is nil");
+ if(to == nil)
+ fatal("addedge: to is nil");
+ arrayadd(from->succ, &to);
+ arrayadd(to->pred, &from);
+}
+
+// Inserts prev before curr in the instruction
+// stream. Any control flow, such as branches or fall throughs, that target the
+// existing instruction are adjusted to target the new instruction.
+static void
+splicebefore(Liveness *lv, BasicBlock *bb, Prog *prev, Prog *curr)
+{
+ Prog *next, tmp;
+
+ USED(lv);
+
+ // There may be other instructions pointing at curr,
+ // and we want them to now point at prev. Instead of
+ // trying to find all such instructions, swap the contents
+ // so that the problem becomes inserting next after curr.
+ // The "opt" field is the backward link in the linked list.
+
+ // Overwrite curr's data with prev, but keep the list links.
+ tmp = *curr;
+ *curr = *prev;
+ curr->opt = tmp.opt;
+ curr->link = tmp.link;
+
+ // Overwrite prev (now next) with curr's old data.
+ next = prev;
+ *next = tmp;
+ next->opt = nil;
+ next->link = nil;
+
+ // Now insert next after curr.
+ next->link = curr->link;
+ next->opt = curr;
+ curr->link = next;
+ if(next->link && next->link->opt == curr)
+ next->link->opt = next;
+
+ if(bb->last == curr)
+ bb->last = next;
+}
+
+// A pretty printer for basic blocks.
+static void
+printblock(BasicBlock *bb)
+{
+ BasicBlock *pred;
+ BasicBlock *succ;
+ Prog *prog;
+ int i;
+
+ print("basic block %d\n", bb->rpo);
+ print("\tpred:");
+ for(i = 0; i < arraylength(bb->pred); i++) {
+ pred = *(BasicBlock**)arrayget(bb->pred, i);
+ print(" %d", pred->rpo);
+ }
+ print("\n");
+ print("\tsucc:");
+ for(i = 0; i < arraylength(bb->succ); i++) {
+ succ = *(BasicBlock**)arrayget(bb->succ, i);
+ print(" %d", succ->rpo);
+ }
+ print("\n");
+ print("\tprog:\n");
+ for(prog = bb->first;; prog=prog->link) {
+ print("\t\t%P\n", prog);
+ if(prog == bb->last)
+ break;
+ }
+}
+
+
+// Iterates over a basic block applying a callback to each instruction. There
+// are two criteria for termination. If the end of basic block is reached a
+// value of zero is returned. If the callback returns a non-zero value, the
+// iteration is stopped and the value of the callback is returned.
+static int
+blockany(BasicBlock *bb, int (*callback)(Prog*))
+{
+ Prog *p;
+ int result;
+
+ for(p = bb->last; p != nil; p = p->opt) {
+ result = (*callback)(p);
+ if(result != 0)
+ return result;
+ }
+ return 0;
+}
+
+// Collects and returns and array of Node*s for functions arguments and local
+// variables.
+static Array*
+getvariables(Node *fn)
+{
+ Array *result;
+ NodeList *ll;
+
+ result = arraynew(0, sizeof(Node*));
+ for(ll = fn->dcl; ll != nil; ll = ll->next) {
+ if(ll->n->op == ONAME) {
+ // In order for GODEBUG=gcdead=1 to work, each bitmap needs
+ // to contain information about all variables covered by the bitmap.
+ // For local variables, the bitmap only covers the stkptrsize
+ // bytes in the frame where variables containing pointers live.
+ // For arguments and results, the bitmap covers all variables,
+ // so we must include all the variables, even the ones without
+ // pointers.
+ switch(ll->n->class) {
+ case PAUTO:
+ if(haspointers(ll->n->type))
+ arrayadd(result, &ll->n);
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ arrayadd(result, &ll->n);
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+// A pretty printer for control flow graphs. Takes an array of BasicBlock*s.
+static void
+printcfg(Array *cfg)
+{
+ BasicBlock *bb;
+ int32 i;
+
+ for(i = 0; i < arraylength(cfg); i++) {
+ bb = *(BasicBlock**)arrayget(cfg, i);
+ printblock(bb);
+ }
+}
+
+// Assigns a reverse post order number to each connected basic block using the
+// standard algorithm. Unconnected blocks will not be affected.
+static void
+reversepostorder(BasicBlock *root, int32 *rpo)
+{
+ BasicBlock *bb;
+ int i;
+
+ root->mark = VISITED;
+ for(i = 0; i < arraylength(root->succ); i++) {
+ bb = *(BasicBlock**)arrayget(root->succ, i);
+ if(bb->mark == UNVISITED)
+ reversepostorder(bb, rpo);
+ }
+ *rpo -= 1;
+ root->rpo = *rpo;
+}
+
+// Comparison predicate used for sorting basic blocks by their rpo in ascending
+// order.
+static int
+blockrpocmp(const void *p1, const void *p2)
+{
+ BasicBlock *bb1;
+ BasicBlock *bb2;
+
+ bb1 = *(BasicBlock**)p1;
+ bb2 = *(BasicBlock**)p2;
+ if(bb1->rpo < bb2->rpo)
+ return -1;
+ if(bb1->rpo > bb2->rpo)
+ return 1;
+ return 0;
+}
+
+// A pattern matcher for call instructions. Returns true when the instruction
+// is a call to a specific package qualified function name.
+static int
+iscall(Prog *prog, LSym *name)
+{
+ if(prog == nil)
+ fatal("iscall: prog is nil");
+ if(name == nil)
+ fatal("iscall: function name is nil");
+ if(prog->as != ACALL)
+ return 0;
+ return name == prog->to.sym;
+}
+
+// Returns true for instructions that call a runtime function implementing a
+// select communication clause.
+static int
+isselectcommcasecall(Prog *prog)
+{
+ static LSym* names[5];
+ int32 i;
+
+ if(names[0] == nil) {
+ names[0] = linksym(pkglookup("selectsend", runtimepkg));
+ names[1] = linksym(pkglookup("selectrecv", runtimepkg));
+ names[2] = linksym(pkglookup("selectrecv2", runtimepkg));
+ names[3] = linksym(pkglookup("selectdefault", runtimepkg));
+ }
+ for(i = 0; names[i] != nil; i++)
+ if(iscall(prog, names[i]))
+ return 1;
+ return 0;
+}
+
+// Returns true for call instructions that target runtime·newselect.
+static int
+isnewselect(Prog *prog)
+{
+ static LSym *sym;
+
+ if(sym == nil)
+ sym = linksym(pkglookup("newselect", runtimepkg));
+ return iscall(prog, sym);
+}
+
+// Returns true for call instructions that target runtime·selectgo.
+static int
+isselectgocall(Prog *prog)
+{
+ static LSym *sym;
+
+ if(sym == nil)
+ sym = linksym(pkglookup("selectgo", runtimepkg));
+ return iscall(prog, sym);
+}
+
+static int
+isdeferreturn(Prog *prog)
+{
+ static LSym *sym;
+
+ if(sym == nil)
+ sym = linksym(pkglookup("deferreturn", runtimepkg));
+ return iscall(prog, sym);
+}
+
+// Walk backwards from a runtime·selectgo call up to its immediately dominating
+// runtime·newselect call. Any successor nodes of communication clause nodes
+// are implicit successors of the runtime·selectgo call node. The goal of this
+// analysis is to add these missing edges to complete the control flow graph.
+static void
+addselectgosucc(BasicBlock *selectgo)
+{
+ BasicBlock *pred;
+ BasicBlock *succ;
+
+ pred = selectgo;
+ for(;;) {
+ if(arraylength(pred->pred) == 0)
+ fatal("selectgo does not have a newselect");
+ pred = *(BasicBlock**)arrayget(pred->pred, 0);
+ if(blockany(pred, isselectcommcasecall)) {
+ // A select comm case block should have exactly one
+ // successor.
+ if(arraylength(pred->succ) != 1)
+ fatal("select comm case has too many successors");
+ succ = *(BasicBlock**)arrayget(pred->succ, 0);
+ // Its successor should have exactly two successors.
+ // The drop through should flow to the selectgo block
+ // and the branch should lead to the select case
+ // statements block.
+ if(arraylength(succ->succ) != 2)
+ fatal("select comm case successor has too many successors");
+ // Add the block as a successor of the selectgo block.
+ addedge(selectgo, succ);
+ }
+ if(blockany(pred, isnewselect)) {
+ // Reached the matching newselect.
+ break;
+ }
+ }
+}
+
+// The entry point for the missing selectgo control flow algorithm. Takes an
+// array of BasicBlock*s containing selectgo calls.
+static void
+fixselectgo(Array *selectgo)
+{
+ BasicBlock *bb;
+ int32 i;
+
+ for(i = 0; i < arraylength(selectgo); i++) {
+ bb = *(BasicBlock**)arrayget(selectgo, i);
+ addselectgosucc(bb);
+ }
+}
+
+// Constructs a control flow graph from a sequence of instructions. This
+// procedure is complicated by various sources of implicit control flow that are
+// not accounted for using the standard cfg construction algorithm. Returns an
+// array of BasicBlock*s in control flow graph form (basic blocks ordered by
+// their RPO number).
+static Array*
+newcfg(Prog *firstp)
+{
+ Prog *p;
+ Prog *prev;
+ BasicBlock *bb;
+ Array *cfg;
+ Array *selectgo;
+ int32 i;
+ int32 rpo;
+
+ // Reset the opt field of each prog to nil. In the first and second
+ // passes, instructions that are labels temporarily use the opt field to
+ // point to their basic block. In the third pass, the opt field reset
+ // to point to the predecessor of an instruction in its basic block.
+ for(p = firstp; p != P; p = p->link)
+ p->opt = nil;
+
+ // Allocate an array to remember where we have seen selectgo calls.
+ // These blocks will be revisited to add successor control flow edges.
+ selectgo = arraynew(0, sizeof(BasicBlock*));
+
+ // Loop through all instructions identifying branch targets
+ // and fall-throughs and allocate basic blocks.
+ cfg = arraynew(0, sizeof(BasicBlock*));
+ bb = newblock(firstp);
+ arrayadd(cfg, &bb);
+ for(p = firstp; p != P; p = p->link) {
+ if(p->to.type == D_BRANCH) {
+ if(p->to.u.branch == nil)
+ fatal("prog branch to nil");
+ if(p->to.u.branch->opt == nil) {
+ p->to.u.branch->opt = newblock(p->to.u.branch);
+ arrayadd(cfg, &p->to.u.branch->opt);
+ }
+ if(p->as != AJMP && p->link != nil && p->link->opt == nil) {
+ p->link->opt = newblock(p->link);
+ arrayadd(cfg, &p->link->opt);
+ }
+ } else if(isselectcommcasecall(p) || isselectgocall(p)) {
+ // Accommodate implicit selectgo control flow.
+ if(p->link->opt == nil) {
+ p->link->opt = newblock(p->link);
+ arrayadd(cfg, &p->link->opt);
+ }
+ }
+ }
+
+ // Loop through all basic blocks maximally growing the list of
+ // contained instructions until a label is reached. Add edges
+ // for branches and fall-through instructions.
+ for(i = 0; i < arraylength(cfg); i++) {
+ bb = *(BasicBlock**)arrayget(cfg, i);
+ for(p = bb->last; p != nil; p = p->link) {
+ if(p->opt != nil && p != bb->last)
+ break;
+ bb->last = p;
+
+ // Stop before an unreachable RET, to avoid creating
+ // unreachable control flow nodes.
+ if(p->link != nil && p->link->as == ARET && p->link->mode == 1)
+ break;
+
+ // Collect basic blocks with selectgo calls.
+ if(isselectgocall(p))
+ arrayadd(selectgo, &bb);
+ }
+ if(bb->last->to.type == D_BRANCH)
+ addedge(bb, bb->last->to.u.branch->opt);
+ if(bb->last->link != nil) {
+ // Add a fall-through when the instruction is
+ // not an unconditional control transfer.
+ switch(bb->last->as) {
+ case AJMP:
+ case ARET:
+ case AUNDEF:
+ break;
+ default:
+ addedge(bb, bb->last->link->opt);
+ }
+ }
+ }
+
+ // Add back links so the instructions in a basic block can be traversed
+ // backward. This is the final state of the instruction opt field.
+ for(i = 0; i < arraylength(cfg); i++) {
+ bb = *(BasicBlock**)arrayget(cfg, i);
+ p = bb->first;
+ prev = nil;
+ for(;;) {
+ p->opt = prev;
+ if(p == bb->last)
+ break;
+ prev = p;
+ p = p->link;
+ }
+ }
+
+ // Add missing successor edges to the selectgo blocks.
+ if(arraylength(selectgo))
+ fixselectgo(selectgo);
+ arrayfree(selectgo);
+
+ // Find a depth-first order and assign a depth-first number to
+ // all basic blocks.
+ for(i = 0; i < arraylength(cfg); i++) {
+ bb = *(BasicBlock**)arrayget(cfg, i);
+ bb->mark = UNVISITED;
+ }
+ bb = *(BasicBlock**)arrayget(cfg, 0);
+ rpo = arraylength(cfg);
+ reversepostorder(bb, &rpo);
+
+ // Sort the basic blocks by their depth first number. The
+ // array is now a depth-first spanning tree with the first
+ // node being the root.
+ arraysort(cfg, blockrpocmp);
+ bb = *(BasicBlock**)arrayget(cfg, 0);
+
+ // Unreachable control flow nodes are indicated by a -1 in the rpo
+ // field. If we see these nodes something must have gone wrong in an
+ // upstream compilation phase.
+ if(bb->rpo == -1) {
+ print("newcfg: unreachable basic block for %P\n", bb->last);
+ printcfg(cfg);
+ fatal("newcfg: invalid control flow graph");
+ }
+
+ return cfg;
+}
+
+// Frees a control flow graph (an array of BasicBlock*s) and all of its leaf
+// data structures.
+static void
+freecfg(Array *cfg)
+{
+ BasicBlock *bb;
+ BasicBlock *bb0;
+ Prog *p;
+ int32 i;
+ int32 len;
+
+ len = arraylength(cfg);
+ if(len > 0) {
+ bb0 = *(BasicBlock**)arrayget(cfg, 0);
+ for(p = bb0->first; p != P; p = p->link) {
+ p->opt = nil;
+ }
+ for(i = 0; i < len; i++) {
+ bb = *(BasicBlock**)arrayget(cfg, i);
+ freeblock(bb);
+ }
+ }
+ arrayfree(cfg);
+}
+
+// Returns true if the node names a variable that is otherwise uninteresting to
+// the liveness computation.
+static int
+isfunny(Node *node)
+{
+ char *names[] = { ".fp", ".args", nil };
+ int i;
+
+ if(node->sym != nil && node->sym->name != nil)
+ for(i = 0; names[i] != nil; i++)
+ if(strcmp(node->sym->name, names[i]) == 0)
+ return 1;
+ return 0;
+}
+
+// Computes the effects of an instruction on a set of
+// variables. The vars argument is an array of Node*s.
+//
+// The output vectors give bits for variables:
+// uevar - used by this instruction
+// varkill - killed by this instruction
+// for variables without address taken, means variable was set
+// for variables with address taken, means variable was marked dead
+// avarinit - initialized or referred to by this instruction,
+// only for variables with address taken but not escaping to heap
+//
+// The avarinit output serves as a signal that the data has been
+// initialized, because any use of a variable must come after its
+// initialization.
+static void
+progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
+{
+ ProgInfo info;
+ Adr *from;
+ Adr *to;
+ Node *node;
+ int32 i;
+ int32 pos;
+
+ bvresetall(uevar);
+ bvresetall(varkill);
+ bvresetall(avarinit);
+
+ proginfo(&info, prog);
+ if(prog->as == ARET) {
+ // Return instructions implicitly read all the arguments. For
+ // the sake of correctness, out arguments must be read. For the
+ // sake of backtrace quality, we read in arguments as well.
+ //
+ // A return instruction with a p->to is a tail return, which brings
+ // the stack pointer back up (if it ever went down) and then jumps
+ // to a new function entirely. That form of instruction must read
+ // all the parameters for correctness, and similarly it must not
+ // read the out arguments - they won't be set until the new
+ // function runs.
+ for(i = 0; i < arraylength(vars); i++) {
+ node = *(Node**)arrayget(vars, i);
+ switch(node->class & ~PHEAP) {
+ case PPARAM:
+ bvset(uevar, i);
+ break;
+ case PPARAMOUT:
+ // If the result had its address taken, it is being tracked
+ // by the avarinit code, which does not use uevar.
+ // If we added it to uevar too, we'd not see any kill
+ // and decide that the varible was live entry, which it is not.
+ // So only use uevar in the non-addrtaken case.
+ // The p->to.type == D_NONE limits the bvset to
+ // non-tail-call return instructions; see note above
+ // the for loop for details.
+ if(!node->addrtaken && prog->to.type == D_NONE)
+ bvset(uevar, i);
+ break;
+ }
+ }
+ return;
+ }
+ if(prog->as == ATEXT) {
+ // A text instruction marks the entry point to a function and
+ // the definition point of all in arguments.
+ for(i = 0; i < arraylength(vars); i++) {
+ node = *(Node**)arrayget(vars, i);
+ switch(node->class & ~PHEAP) {
+ case PPARAM:
+ if(node->addrtaken)
+ bvset(avarinit, i);
+ bvset(varkill, i);
+ break;
+ }
+ }
+ return;
+ }
+ if(info.flags & (LeftRead | LeftWrite | LeftAddr)) {
+ from = &prog->from;
+ if (from->node != nil && from->sym != nil) {
+ switch(from->node->class & ~PHEAP) {
+ case PAUTO:
+ case PPARAM:
+ case PPARAMOUT:
+ pos = arrayindexof(vars, from->node);
+ if(pos == -1)
+ goto Next;
+ if(from->node->addrtaken) {
+ bvset(avarinit, pos);
+ } else {
+ if(info.flags & (LeftRead | LeftAddr))
+ bvset(uevar, pos);
+ if(info.flags & LeftWrite)
+ if(from->node != nil && !isfat(from->node->type))
+ bvset(varkill, pos);
+ }
+ }
+ }
+ }
+Next:
+ if(info.flags & (RightRead | RightWrite | RightAddr)) {
+ to = &prog->to;
+ if (to->node != nil && to->sym != nil) {
+ switch(to->node->class & ~PHEAP) {
+ case PAUTO:
+ case PPARAM:
+ case PPARAMOUT:
+ pos = arrayindexof(vars, to->node);
+ if(pos == -1)
+ goto Next1;
+ if(to->node->addrtaken) {
+ if(prog->as != AVARKILL)
+ bvset(avarinit, pos);
+ if(prog->as == AVARDEF || prog->as == AVARKILL)
+ bvset(varkill, pos);
+ } else {
+ // RightRead is a read, obviously.
+ // RightAddr by itself is also implicitly a read.
+ //
+ // RightAddr|RightWrite means that the address is being taken
+ // but only so that the instruction can write to the value.
+ // It is not a read. It is equivalent to RightWrite except that
+ // having the RightAddr bit set keeps the registerizer from
+ // trying to substitute a register for the memory location.
+ if((info.flags & RightRead) || (info.flags & (RightAddr|RightWrite)) == RightAddr)
+ bvset(uevar, pos);
+ if(info.flags & RightWrite)
+ if(to->node != nil && (!isfat(to->node->type) || prog->as == AVARDEF))
+ bvset(varkill, pos);
+ }
+ }
+ }
+ }
+Next1:;
+}
+
+// Constructs a new liveness structure used to hold the global state of the
+// liveness computation. The cfg argument is an array of BasicBlock*s and the
+// vars argument is an array of Node*s.
+static Liveness*
+newliveness(Node *fn, Prog *ptxt, Array *cfg, Array *vars)
+{
+ Liveness *result;
+ int32 i;
+ int32 nblocks;
+ int32 nvars;
+
+ result = xmalloc(sizeof(*result));
+ result->fn = fn;
+ result->ptxt = ptxt;
+ result->cfg = cfg;
+ result->vars = vars;
+
+ nblocks = arraylength(cfg);
+ result->uevar = xmalloc(sizeof(Bvec*) * nblocks);
+ result->varkill = xmalloc(sizeof(Bvec*) * nblocks);
+ result->livein = xmalloc(sizeof(Bvec*) * nblocks);
+ result->liveout = xmalloc(sizeof(Bvec*) * nblocks);
+ result->avarinit = xmalloc(sizeof(Bvec*) * nblocks);
+ result->avarinitany = xmalloc(sizeof(Bvec*) * nblocks);
+ result->avarinitall = xmalloc(sizeof(Bvec*) * nblocks);
+
+ nvars = arraylength(vars);
+ for(i = 0; i < nblocks; i++) {
+ result->uevar[i] = bvalloc(nvars);
+ result->varkill[i] = bvalloc(nvars);
+ result->livein[i] = bvalloc(nvars);
+ result->liveout[i] = bvalloc(nvars);
+ result->avarinit[i] = bvalloc(nvars);
+ result->avarinitany[i] = bvalloc(nvars);
+ result->avarinitall[i] = bvalloc(nvars);
+ }
+
+ result->livepointers = arraynew(0, sizeof(Bvec*));
+ result->argslivepointers = arraynew(0, sizeof(Bvec*));
+ return result;
+}
+
+// Frees the liveness structure and all of its leaf data structures.
+static void
+freeliveness(Liveness *lv)
+{
+ int32 i;
+
+ if(lv == nil)
+ fatal("freeliveness: cannot free nil");
+
+ for(i = 0; i < arraylength(lv->livepointers); i++)
+ free(*(Bvec**)arrayget(lv->livepointers, i));
+ arrayfree(lv->livepointers);
+
+ for(i = 0; i < arraylength(lv->argslivepointers); i++)
+ free(*(Bvec**)arrayget(lv->argslivepointers, i));
+ arrayfree(lv->argslivepointers);
+
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ free(lv->uevar[i]);
+ free(lv->varkill[i]);
+ free(lv->livein[i]);
+ free(lv->liveout[i]);
+ free(lv->avarinit[i]);
+ free(lv->avarinitany[i]);
+ free(lv->avarinitall[i]);
+ }
+
+ free(lv->uevar);
+ free(lv->varkill);
+ free(lv->livein);
+ free(lv->liveout);
+ free(lv->avarinit);
+ free(lv->avarinitany);
+ free(lv->avarinitall);
+
+ free(lv);
+}
+
+static void
+printeffects(Prog *p, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
+{
+ print("effects of %P", p);
+ print("\nuevar: ");
+ bvprint(uevar);
+ print("\nvarkill: ");
+ bvprint(varkill);
+ print("\navarinit: ");
+ bvprint(avarinit);
+ print("\n");
+}
+
+// Pretty print a variable node. Uses Pascal like conventions for pointers and
+// addresses to avoid confusing the C like conventions used in the node variable
+// names.
+static void
+printnode(Node *node)
+{
+ char *p;
+ char *a;
+
+ p = haspointers(node->type) ? "^" : "";
+ a = node->addrtaken ? "@" : "";
+ print(" %N%s%s", node, p, a);
+}
+
+// Pretty print a list of variables. The vars argument is an array of Node*s.
+static void
+printvars(char *name, Bvec *bv, Array *vars)
+{
+ int32 i;
+
+ print("%s:", name);
+ for(i = 0; i < arraylength(vars); i++)
+ if(bvget(bv, i))
+ printnode(*(Node**)arrayget(vars, i));
+ print("\n");
+}
+
+// Prints a basic block annotated with the information computed by liveness
+// analysis.
+static void
+livenessprintblock(Liveness *lv, BasicBlock *bb)
+{
+ BasicBlock *pred;
+ BasicBlock *succ;
+ Prog *prog;
+ Bvec *live;
+ int i;
+ int32 pos;
+
+ print("basic block %d\n", bb->rpo);
+
+ print("\tpred:");
+ for(i = 0; i < arraylength(bb->pred); i++) {
+ pred = *(BasicBlock**)arrayget(bb->pred, i);
+ print(" %d", pred->rpo);
+ }
+ print("\n");
+
+ print("\tsucc:");
+ for(i = 0; i < arraylength(bb->succ); i++) {
+ succ = *(BasicBlock**)arrayget(bb->succ, i);
+ print(" %d", succ->rpo);
+ }
+ print("\n");
+
+ printvars("\tuevar", lv->uevar[bb->rpo], lv->vars);
+ printvars("\tvarkill", lv->varkill[bb->rpo], lv->vars);
+ printvars("\tlivein", lv->livein[bb->rpo], lv->vars);
+ printvars("\tliveout", lv->liveout[bb->rpo], lv->vars);
+ printvars("\tavarinit", lv->avarinit[bb->rpo], lv->vars);
+ printvars("\tavarinitany", lv->avarinitany[bb->rpo], lv->vars);
+ printvars("\tavarinitall", lv->avarinitall[bb->rpo], lv->vars);
+
+ print("\tprog:\n");
+ for(prog = bb->first;; prog = prog->link) {
+ print("\t\t%P", prog);
+ if(prog->as == APCDATA && prog->from.offset == PCDATA_StackMapIndex) {
+ pos = prog->to.offset;
+ live = *(Bvec**)arrayget(lv->livepointers, pos);
+ print(" ");
+ bvprint(live);
+ }
+ print("\n");
+ if(prog == bb->last)
+ break;
+ }
+}
+
+// Prints a control flow graph annotated with any information computed by
+// liveness analysis.
+static void
+livenessprintcfg(Liveness *lv)
+{
+ BasicBlock *bb;
+ int32 i;
+
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+ livenessprintblock(lv, bb);
+ }
+}
+
+static void
+checkauto(Node *fn, Prog *p, Node *n)
+{
+ NodeList *l;
+
+ for(l = fn->dcl; l != nil; l = l->next)
+ if(l->n->op == ONAME && l->n->class == PAUTO && l->n == n)
+ return;
+
+ print("checkauto %N: %N (%p; class=%d) not found in %P\n", curfn, n, n, n->class, p);
+ for(l = fn->dcl; l != nil; l = l->next)
+ print("\t%N (%p; class=%d)\n", l->n, l->n, l->n->class);
+ yyerror("checkauto: invariant lost");
+}
+
+static void
+checkparam(Node *fn, Prog *p, Node *n)
+{
+ NodeList *l;
+ Node *a;
+ int class;
+
+ if(isfunny(n))
+ return;
+ for(l = fn->dcl; l != nil; l = l->next) {
+ a = l->n;
+ class = a->class & ~PHEAP;
+ if(a->op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n)
+ return;
+ }
+
+ print("checkparam %N: %N (%p; class=%d) not found in %P\n", curfn, n, n, n->class, p);
+ for(l = fn->dcl; l != nil; l = l->next)
+ print("\t%N (%p; class=%d)\n", l->n, l->n, l->n->class);
+ yyerror("checkparam: invariant lost");
+}
+
+static void
+checkprog(Node *fn, Prog *p)
+{
+ if(p->from.type == D_AUTO)
+ checkauto(fn, p, p->from.node);
+ if(p->from.type == D_PARAM)
+ checkparam(fn, p, p->from.node);
+ if(p->to.type == D_AUTO)
+ checkauto(fn, p, p->to.node);
+ if(p->to.type == D_PARAM)
+ checkparam(fn, p, p->to.node);
+}
+
+// Check instruction invariants. We assume that the nodes corresponding to the
+// sources and destinations of memory operations will be declared in the
+// function. This is not strictly true, as is the case for the so-called funny
+// nodes and there are special cases to skip over that stuff. The analysis will
+// fail if this invariant blindly changes.
+static void
+checkptxt(Node *fn, Prog *firstp)
+{
+ Prog *p;
+
+ for(p = firstp; p != P; p = p->link) {
+ if(0)
+ print("analyzing '%P'\n", p);
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ case ATYPE:
+ continue;
+ }
+ checkprog(fn, p);
+ }
+}
+
+// NOTE: The bitmap for a specific type t should be cached in t after the first run
+// and then simply copied into bv at the correct offset on future calls with
+// the same type t. On https://rsc.googlecode.com/hg/testdata/slow.go, twobitwalktype1
+// accounts for 40% of the 6g execution time.
+static void
+twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
+{
+ vlong fieldoffset;
+ vlong i;
+ vlong o;
+ Type *t1;
+
+ if(t->align > 0 && (*xoffset & (t->align - 1)) != 0)
+ fatal("twobitwalktype1: invalid initial alignment, %T", t);
+
+ switch(t->etype) {
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TINT:
+ case TUINT:
+ case TUINTPTR:
+ case TBOOL:
+ case TFLOAT32:
+ case TFLOAT64:
+ case TCOMPLEX64:
+ case TCOMPLEX128:
+ for(i = 0; i < t->width; i++) {
+ bvset(bv, ((*xoffset + i) / widthptr) * BitsPerPointer); // 1 = live scalar
+ }
+ *xoffset += t->width;
+ break;
+
+ case TPTR32:
+ case TPTR64:
+ case TUNSAFEPTR:
+ case TFUNC:
+ case TCHAN:
+ case TMAP:
+ if((*xoffset & (widthptr-1)) != 0)
+ fatal("twobitwalktype1: invalid alignment, %T", t);
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr
+ *xoffset += t->width;
+ break;
+
+ case TSTRING:
+ // struct { byte *str; intgo len; }
+ if((*xoffset & (widthptr-1)) != 0)
+ fatal("twobitwalktype1: invalid alignment, %T", t);
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0);
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 3:0 = multiword:string
+ *xoffset += t->width;
+ break;
+
+ case TINTER:
+ // struct { Itab *tab; union { void *ptr, uintptr val } data; }
+ // or, when isnilinter(t)==true:
+ // struct { Type *type; union { void *ptr, uintptr val } data; }
+ if((*xoffset & (widthptr-1)) != 0)
+ fatal("twobitwalktype1: invalid alignment, %T", t);
+ bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 0);
+ bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 1); // 3 = multiword
+ // next word contains 2 = Iface, 3 = Eface
+ if(isnilinter(t)) {
+ bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 2);
+ bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 3);
+ } else {
+ bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 3);
+ }
+ *xoffset += t->width;
+ break;
+
+ case TARRAY:
+ // The value of t->bound is -1 for slices types and >0 for
+ // for fixed array types. All other values are invalid.
+ if(t->bound < -1)
+ fatal("twobitwalktype1: invalid bound, %T", t);
+ if(isslice(t)) {
+ // struct { byte *array; uintgo len; uintgo cap; }
+ if((*xoffset & (widthptr-1)) != 0)
+ fatal("twobitwalktype1: invalid TARRAY alignment, %T", t);
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0);
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1);
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 2); // 3:1 = multiword/slice
+ *xoffset += t->width;
+ } else
+ for(i = 0; i < t->bound; i++)
+ twobitwalktype1(t->type, xoffset, bv);
+ break;
+
+ case TSTRUCT:
+ o = 0;
+ for(t1 = t->type; t1 != T; t1 = t1->down) {
+ fieldoffset = t1->width;
+ *xoffset += fieldoffset - o;
+ twobitwalktype1(t1->type, xoffset, bv);
+ o = fieldoffset + t1->type->width;
+ }
+ *xoffset += t->width - o;
+ break;
+
+ default:
+ fatal("twobitwalktype1: unexpected type, %T", t);
+ }
+}
+
+// Returns the number of words of local variables.
+static int32
+localswords(void)
+{
+ return stkptrsize / widthptr;
+}
+
+// Returns the number of words of in and out arguments.
+static int32
+argswords(void)
+{
+ return curfn->type->argwid / widthptr;
+}
+
+// Generates live pointer value maps for arguments and local variables. The
+// this argument and the in arguments are always assumed live. The vars
+// argument is an array of Node*s.
+static void
+twobitlivepointermap(Liveness *lv, Bvec *liveout, Array *vars, Bvec *args, Bvec *locals)
+{
+ Node *node;
+ Type *thisargtype;
+ Type *inargtype;
+ vlong xoffset;
+ int32 i;
+
+ for(i = 0; i < arraylength(vars); i++) {
+ node = *(Node**)arrayget(vars, i);
+ switch(node->class) {
+ case PAUTO:
+ if(bvget(liveout, i)) {
+ xoffset = node->xoffset + stkptrsize;
+ twobitwalktype1(node->type, &xoffset, locals);
+ }
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ if(bvget(liveout, i)) {
+ xoffset = node->xoffset;
+ twobitwalktype1(node->type, &xoffset, args);
+ }
+ break;
+ }
+ }
+
+ // The node list only contains declared names.
+ // If the receiver or arguments are unnamed, they will be omitted
+ // from the list above. Preserve those values - even though they are unused -
+ // in order to keep their addresses live for use in stack traces.
+ thisargtype = getthisx(lv->fn->type);
+ if(thisargtype != nil) {
+ xoffset = 0;
+ twobitwalktype1(thisargtype, &xoffset, args);
+ }
+ inargtype = getinargx(lv->fn->type);
+ if(inargtype != nil) {
+ xoffset = 0;
+ twobitwalktype1(inargtype, &xoffset, args);
+ }
+}
+
+// Construct a disembodied instruction.
+static Prog*
+unlinkedprog(int as)
+{
+ Prog *p;
+
+ p = mal(sizeof(*p));
+ clearp(p);
+ p->as = as;
+ return p;
+}
+
+// Construct a new PCDATA instruction associated with and for the purposes of
+// covering an existing instruction.
+static Prog*
+newpcdataprog(Prog *prog, int32 index)
+{
+ Node from, to;
+ Prog *pcdata;
+
+ nodconst(&from, types[TINT32], PCDATA_StackMapIndex);
+ nodconst(&to, types[TINT32], index);
+ pcdata = unlinkedprog(APCDATA);
+ pcdata->lineno = prog->lineno;
+ naddr(&from, &pcdata->from, 0);
+ naddr(&to, &pcdata->to, 0);
+ return pcdata;
+}
+
+// Returns true for instructions that are safe points that must be annotated
+// with liveness information.
+static int
+issafepoint(Prog *prog)
+{
+ return prog->as == ATEXT || prog->as == ACALL;
+}
+
+// Initializes the sets for solving the live variables. Visits all the
+// instructions in each basic block to summarizes the information at each basic
+// block
+static void
+livenessprologue(Liveness *lv)
+{
+ BasicBlock *bb;
+ Bvec *uevar, *varkill, *avarinit;
+ Prog *p;
+ int32 i;
+ int32 nvars;
+
+ nvars = arraylength(lv->vars);
+ uevar = bvalloc(nvars);
+ varkill = bvalloc(nvars);
+ avarinit = bvalloc(nvars);
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+ // Walk the block instructions backward and update the block
+ // effects with the each prog effects.
+ for(p = bb->last; p != nil; p = p->opt) {
+ progeffects(p, lv->vars, uevar, varkill, avarinit);
+ if(debuglive >= 3)
+ printeffects(p, uevar, varkill, avarinit);
+ bvor(lv->varkill[i], lv->varkill[i], varkill);
+ bvandnot(lv->uevar[i], lv->uevar[i], varkill);
+ bvor(lv->uevar[i], lv->uevar[i], uevar);
+ }
+ // Walk the block instructions forward to update avarinit bits.
+ // avarinit describes the effect at the end of the block, not the beginning.
+ bvresetall(varkill);
+ for(p = bb->first;; p = p->link) {
+ progeffects(p, lv->vars, uevar, varkill, avarinit);
+ if(debuglive >= 3)
+ printeffects(p, uevar, varkill, avarinit);
+ bvandnot(lv->avarinit[i], lv->avarinit[i], varkill);
+ bvor(lv->avarinit[i], lv->avarinit[i], avarinit);
+ if(p == bb->last)
+ break;
+ }
+ }
+ free(uevar);
+ free(varkill);
+ free(avarinit);
+}
+
+// Solve the liveness dataflow equations.
+static void
+livenesssolve(Liveness *lv)
+{
+ BasicBlock *bb, *succ, *pred;
+ Bvec *newlivein, *newliveout, *any, *all;
+ int32 rpo, i, j, change;
+
+ // These temporary bitvectors exist to avoid successive allocations and
+ // frees within the loop.
+ newlivein = bvalloc(arraylength(lv->vars));
+ newliveout = bvalloc(arraylength(lv->vars));
+ any = bvalloc(arraylength(lv->vars));
+ all = bvalloc(arraylength(lv->vars));
+
+ // Push avarinitall, avarinitany forward.
+ // avarinitall says the addressed var is initialized along all paths reaching the block exit.
+ // avarinitany says the addressed var is initialized along some path reaching the block exit.
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+ rpo = bb->rpo;
+ if(i == 0)
+ bvcopy(lv->avarinitall[rpo], lv->avarinit[rpo]);
+ else {
+ bvresetall(lv->avarinitall[rpo]);
+ bvnot(lv->avarinitall[rpo]);
+ }
+ bvcopy(lv->avarinitany[rpo], lv->avarinit[rpo]);
+ }
+
+ change = 1;
+ while(change != 0) {
+ change = 0;
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+ rpo = bb->rpo;
+ bvresetall(any);
+ bvresetall(all);
+ for(j = 0; j < arraylength(bb->pred); j++) {
+ pred = *(BasicBlock**)arrayget(bb->pred, j);
+ if(j == 0) {
+ bvcopy(any, lv->avarinitany[pred->rpo]);
+ bvcopy(all, lv->avarinitall[pred->rpo]);
+ } else {
+ bvor(any, any, lv->avarinitany[pred->rpo]);
+ bvand(all, all, lv->avarinitall[pred->rpo]);
+ }
+ }
+ bvandnot(any, any, lv->varkill[rpo]);
+ bvandnot(all, all, lv->varkill[rpo]);
+ bvor(any, any, lv->avarinit[rpo]);
+ bvor(all, all, lv->avarinit[rpo]);
+ if(bvcmp(any, lv->avarinitany[rpo])) {
+ change = 1;
+ bvcopy(lv->avarinitany[rpo], any);
+ }
+ if(bvcmp(all, lv->avarinitall[rpo])) {
+ change = 1;
+ bvcopy(lv->avarinitall[rpo], all);
+ }
+ }
+ }
+
+ // Iterate through the blocks in reverse round-robin fashion. A work
+ // queue might be slightly faster. As is, the number of iterations is
+ // so low that it hardly seems to be worth the complexity.
+ change = 1;
+ while(change != 0) {
+ change = 0;
+ // Walk blocks in the general direction of propagation. This
+ // improves convergence.
+ for(i = arraylength(lv->cfg) - 1; i >= 0; i--) {
+ // A variable is live on output from this block
+ // if it is live on input to some successor.
+ //
+ // out[b] = \bigcup_{s \in succ[b]} in[s]
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+ rpo = bb->rpo;
+ bvresetall(newliveout);
+ for(j = 0; j < arraylength(bb->succ); j++) {
+ succ = *(BasicBlock**)arrayget(bb->succ, j);
+ bvor(newliveout, newliveout, lv->livein[succ->rpo]);
+ }
+ if(bvcmp(lv->liveout[rpo], newliveout)) {
+ change = 1;
+ bvcopy(lv->liveout[rpo], newliveout);
+ }
+
+ // A variable is live on input to this block
+ // if it is live on output from this block and
+ // not set by the code in this block.
+ //
+ // in[b] = uevar[b] \cup (out[b] \setminus varkill[b])
+ bvandnot(newlivein, lv->liveout[rpo], lv->varkill[rpo]);
+ bvor(lv->livein[rpo], newlivein, lv->uevar[rpo]);
+ }
+ }
+
+ free(newlivein);
+ free(newliveout);
+ free(any);
+ free(all);
+}
+
+// This function is slow but it is only used for generating debug prints.
+// Check whether n is marked live in args/locals.
+static int
+islive(Node *n, Bvec *args, Bvec *locals)
+{
+ int i;
+
+ switch(n->class) {
+ case PPARAM:
+ case PPARAMOUT:
+ for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++)
+ if(bvget(args, n->xoffset/widthptr*BitsPerPointer + i))
+ return 1;
+ break;
+ case PAUTO:
+ for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++)
+ if(bvget(locals, (n->xoffset + stkptrsize)/widthptr*BitsPerPointer + i))
+ return 1;
+ break;
+ }
+ return 0;
+}
+
+// Visits all instructions in a basic block and computes a bit vector of live
+// variables at each safe point locations.
+static void
+livenessepilogue(Liveness *lv)
+{
+ BasicBlock *bb, *pred;
+ Bvec *ambig, *livein, *liveout, *uevar, *varkill, *args, *locals, *avarinit, *any, *all;
+ Node *n;
+ Prog *p, *next;
+ int32 i, j, numlive, startmsg, nmsg, nvars, pos;
+ vlong xoffset;
+ char **msg;
+ Fmt fmt;
+
+ nvars = arraylength(lv->vars);
+ livein = bvalloc(nvars);
+ liveout = bvalloc(nvars);
+ uevar = bvalloc(nvars);
+ varkill = bvalloc(nvars);
+ avarinit = bvalloc(nvars);
+ any = bvalloc(nvars);
+ all = bvalloc(nvars);
+ ambig = bvalloc(localswords() * BitsPerPointer);
+ msg = nil;
+ nmsg = 0;
+ startmsg = 0;
+
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+
+ // Compute avarinitany and avarinitall for entry to block.
+ // This duplicates information known during livenesssolve
+ // but avoids storing two more vectors for each block.
+ bvresetall(any);
+ bvresetall(all);
+ for(j = 0; j < arraylength(bb->pred); j++) {
+ pred = *(BasicBlock**)arrayget(bb->pred, j);
+ if(j == 0) {
+ bvcopy(any, lv->avarinitany[pred->rpo]);
+ bvcopy(all, lv->avarinitall[pred->rpo]);
+ } else {
+ bvor(any, any, lv->avarinitany[pred->rpo]);
+ bvand(all, all, lv->avarinitall[pred->rpo]);
+ }
+ }
+
+ // Walk forward through the basic block instructions and
+ // allocate liveness maps for those instructions that need them.
+ // Seed the maps with information about the addrtaken variables.
+ for(p = bb->first;; p = p->link) {
+ progeffects(p, lv->vars, uevar, varkill, avarinit);
+ bvandnot(any, any, varkill);
+ bvandnot(all, all, varkill);
+ bvor(any, any, avarinit);
+ bvor(all, all, avarinit);
+
+ if(issafepoint(p)) {
+ // Annotate ambiguously live variables so that they can
+ // be zeroed at function entry.
+ // livein and liveout are dead here and used as temporaries.
+ // For now, only enabled when using GOEXPERIMENT=precisestack
+ // during make.bash / all.bash.
+ if(precisestack_enabled) {
+ bvresetall(livein);
+ bvandnot(liveout, any, all);
+ if(!bvisempty(liveout)) {
+ for(pos = 0; pos < liveout->n; pos++) {
+ if(!bvget(liveout, pos))
+ continue;
+ bvset(all, pos); // silence future warnings in this block
+ n = *(Node**)arrayget(lv->vars, pos);
+ if(!n->needzero) {
+ n->needzero = 1;
+ if(debuglive >= 1)
+ warnl(p->lineno, "%N: %lN is ambiguously live", curfn->nname, n);
+ // Record in 'ambiguous' bitmap.
+ xoffset = n->xoffset + stkptrsize;
+ twobitwalktype1(n->type, &xoffset, ambig);
+ }
+ }
+ }
+ }
+
+ // Allocate a bit vector for each class and facet of
+ // value we are tracking.
+
+ // Live stuff first.
+ args = bvalloc(argswords() * BitsPerPointer);
+ arrayadd(lv->argslivepointers, &args);
+ locals = bvalloc(localswords() * BitsPerPointer);
+ arrayadd(lv->livepointers, &locals);
+
+ if(debuglive >= 3) {
+ print("%P\n", p);
+ printvars("avarinitany", any, lv->vars);
+ }
+
+ // Record any values with an "address taken" reaching
+ // this code position as live. Must do now instead of below
+ // because the any/all calculation requires walking forward
+ // over the block (as this loop does), while the liveout
+ // requires walking backward (as the next loop does).
+ twobitlivepointermap(lv, any, lv->vars, args, locals);
+ }
+
+ if(p == bb->last)
+ break;
+ }
+ bb->lastbitmapindex = arraylength(lv->livepointers) - 1;
+ }
+
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+
+ if(debuglive >= 1 && strcmp(curfn->nname->sym->name, "init") != 0 && curfn->nname->sym->name[0] != '.') {
+ nmsg = arraylength(lv->livepointers);
+ startmsg = nmsg;
+ msg = xmalloc(nmsg*sizeof msg[0]);
+ for(j=0; j<nmsg; j++)
+ msg[j] = nil;
+ }
+
+ // walk backward, emit pcdata and populate the maps
+ pos = bb->lastbitmapindex;
+ if(pos < 0) {
+ // the first block we encounter should have the ATEXT so
+ // at no point should pos ever be less than zero.
+ fatal("livenessepilogue");
+ }
+
+ bvcopy(livein, lv->liveout[bb->rpo]);
+ for(p = bb->last; p != nil; p = next) {
+ next = p->opt; // splicebefore modifies p->opt
+ // Propagate liveness information
+ progeffects(p, lv->vars, uevar, varkill, avarinit);
+ bvcopy(liveout, livein);
+ bvandnot(livein, liveout, varkill);
+ bvor(livein, livein, uevar);
+ if(debuglive >= 3 && issafepoint(p)){
+ print("%P\n", p);
+ printvars("uevar", uevar, lv->vars);
+ printvars("varkill", varkill, lv->vars);
+ printvars("livein", livein, lv->vars);
+ printvars("liveout", liveout, lv->vars);
+ }
+ if(issafepoint(p)) {
+ // Found an interesting instruction, record the
+ // corresponding liveness information.
+
+ // Useful sanity check: on entry to the function,
+ // the only things that can possibly be live are the
+ // input parameters.
+ if(p->as == ATEXT) {
+ for(j = 0; j < liveout->n; j++) {
+ if(!bvget(liveout, j))
+ continue;
+ n = *(Node**)arrayget(lv->vars, j);
+ if(n->class != PPARAM)
+ yyerrorl(p->lineno, "internal error: %N %lN recorded as live on entry", curfn->nname, n);
+ }
+ }
+
+ // Record live pointers.
+ args = *(Bvec**)arrayget(lv->argslivepointers, pos);
+ locals = *(Bvec**)arrayget(lv->livepointers, pos);
+ twobitlivepointermap(lv, liveout, lv->vars, args, locals);
+
+ // Ambiguously live variables are zeroed immediately after
+ // function entry. Mark them live for all the non-entry bitmaps
+ // so that GODEBUG=gcdead=1 mode does not poison them.
+ if(p->as == ACALL)
+ bvor(locals, locals, ambig);
+
+ // Show live pointer bitmaps.
+ // We're interpreting the args and locals bitmap instead of liveout so that we
+ // include the bits added by the avarinit logic in the
+ // previous loop.
+ if(msg != nil) {
+ fmtstrinit(&fmt);
+ fmtprint(&fmt, "%L: live at ", p->lineno);
+ if(p->as == ACALL && p->to.node)
+ fmtprint(&fmt, "call to %s:", p->to.node->sym->name);
+ else if(p->as == ACALL)
+ fmtprint(&fmt, "indirect call:");
+ else
+ fmtprint(&fmt, "entry to %s:", p->from.node->sym->name);
+ numlive = 0;
+ for(j = 0; j < arraylength(lv->vars); j++) {
+ n = *(Node**)arrayget(lv->vars, j);
+ if(islive(n, args, locals)) {
+ fmtprint(&fmt, " %N", n);
+ numlive++;
+ }
+ }
+ fmtprint(&fmt, "\n");
+ if(numlive == 0) // squelch message
+ free(fmtstrflush(&fmt));
+ else
+ msg[--startmsg] = fmtstrflush(&fmt);
+ }
+
+ // Only CALL instructions need a PCDATA annotation.
+ // The TEXT instruction annotation is implicit.
+ if(p->as == ACALL) {
+ if(isdeferreturn(p)) {
+ // runtime.deferreturn modifies its return address to return
+ // back to the CALL, not to the subsequent instruction.
+ // Because the return comes back one instruction early,
+ // the PCDATA must begin one instruction early too.
+ // The instruction before a call to deferreturn is always a
+ // no-op, to keep PC-specific data unambiguous.
+ splicebefore(lv, bb, newpcdataprog(p->opt, pos), p->opt);
+ } else {
+ splicebefore(lv, bb, newpcdataprog(p, pos), p);
+ }
+ }
+
+ pos--;
+ }
+ }
+ if(msg != nil) {
+ for(j=startmsg; j<nmsg; j++)
+ if(msg[j] != nil)
+ print("%s", msg[j]);
+ free(msg);
+ msg = nil;
+ nmsg = 0;
+ startmsg = 0;
+ }
+ }
+
+ free(livein);
+ free(liveout);
+ free(uevar);
+ free(varkill);
+ free(avarinit);
+ free(any);
+ free(all);
+ free(ambig);
+
+ flusherrors();
+}
+
+// FNV-1 hash function constants.
+#define H0 2166136261UL
+#define Hp 16777619UL
+
+static uint32
+hashbitmap(uint32 h, Bvec *bv)
+{
+ uchar *p, *ep;
+
+ p = (uchar*)bv->b;
+ ep = p + 4*((bv->n+31)/32);
+ while(p < ep)
+ h = (h*Hp) ^ *p++;
+ return h;
+}
+
+// Compact liveness information by coalescing identical per-call-site bitmaps.
+// The merging only happens for a single function, not across the entire binary.
+//
+// There are actually two lists of bitmaps, one list for the local variables and one
+// list for the function arguments. Both lists are indexed by the same PCDATA
+// index, so the corresponding pairs must be considered together when
+// merging duplicates. The argument bitmaps change much less often during
+// function execution than the local variable bitmaps, so it is possible that
+// we could introduce a separate PCDATA index for arguments vs locals and
+// then compact the set of argument bitmaps separately from the set of
+// local variable bitmaps. As of 2014-04-02, doing this to the godoc binary
+// is actually a net loss: we save about 50k of argument bitmaps but the new
+// PCDATA tables cost about 100k. So for now we keep using a single index for
+// both bitmap lists.
+static void
+livenesscompact(Liveness *lv)
+{
+ int *table, *remap, i, j, n, tablesize, uniq;
+ uint32 h;
+ Bvec *local, *arg, *jlocal, *jarg;
+ Prog *p;
+
+ // Linear probing hash table of bitmaps seen so far.
+ // The hash table has 4n entries to keep the linear
+ // scan short. An entry of -1 indicates an empty slot.
+ n = arraylength(lv->livepointers);
+ tablesize = 4*n;
+ table = xmalloc(tablesize*sizeof table[0]);
+ memset(table, 0xff, tablesize*sizeof table[0]);
+
+ // remap[i] = the new index of the old bit vector #i.
+ remap = xmalloc(n*sizeof remap[0]);
+ memset(remap, 0xff, n*sizeof remap[0]);
+ uniq = 0; // unique tables found so far
+
+ // Consider bit vectors in turn.
+ // If new, assign next number using uniq,
+ // record in remap, record in lv->livepointers and lv->argslivepointers
+ // under the new index, and add entry to hash table.
+ // If already seen, record earlier index in remap and free bitmaps.
+ for(i=0; i<n; i++) {
+ local = *(Bvec**)arrayget(lv->livepointers, i);
+ arg = *(Bvec**)arrayget(lv->argslivepointers, i);
+ h = hashbitmap(hashbitmap(H0, local), arg) % tablesize;
+
+ for(;;) {
+ j = table[h];
+ if(j < 0)
+ break;
+ jlocal = *(Bvec**)arrayget(lv->livepointers, j);
+ jarg = *(Bvec**)arrayget(lv->argslivepointers, j);
+ if(bvcmp(local, jlocal) == 0 && bvcmp(arg, jarg) == 0) {
+ free(local);
+ free(arg);
+ remap[i] = j;
+ goto Next;
+ }
+ if(++h == tablesize)
+ h = 0;
+ }
+ table[h] = uniq;
+ remap[i] = uniq;
+ *(Bvec**)arrayget(lv->livepointers, uniq) = local;
+ *(Bvec**)arrayget(lv->argslivepointers, uniq) = arg;
+ uniq++;
+ Next:;
+ }
+
+ // We've already reordered lv->livepointers[0:uniq]
+ // and lv->argslivepointers[0:uniq] and freed the bitmaps
+ // we don't need anymore. Clear the pointers later in the
+ // array so that we can tell where the coalesced bitmaps stop
+ // and so that we don't double-free when cleaning up.
+ for(j=uniq; j<n; j++) {
+ *(Bvec**)arrayget(lv->livepointers, j) = nil;
+ *(Bvec**)arrayget(lv->argslivepointers, j) = nil;
+ }
+
+ // Rewrite PCDATA instructions to use new numbering.
+ for(p=lv->ptxt; p != P; p=p->link) {
+ if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex) {
+ i = p->to.offset;
+ if(i >= 0)
+ p->to.offset = remap[i];
+ }
+ }
+
+ free(table);
+ free(remap);
+}
+
+static int
+printbitset(int printed, char *name, Array *vars, Bvec *bits)
+{
+ int i, started;
+ Node *n;
+
+ started = 0;
+ for(i=0; i<arraylength(vars); i++) {
+ if(!bvget(bits, i))
+ continue;
+ if(!started) {
+ if(!printed)
+ print("\t");
+ else
+ print(" ");
+ started = 1;
+ printed = 1;
+ print("%s=", name);
+ } else {
+ print(",");
+ }
+ n = *(Node**)arrayget(vars, i);
+ print("%s", n->sym->name);
+ }
+ return printed;
+}
+
+// Prints the computed liveness information and inputs, for debugging.
+// This format synthesizes the information used during the multiple passes
+// into a single presentation.
+static void
+livenessprintdebug(Liveness *lv)
+{
+ int i, j, pcdata, printed;
+ BasicBlock *bb;
+ Prog *p;
+ Bvec *uevar, *varkill, *avarinit, *args, *locals;
+ Node *n;
+
+ print("liveness: %s\n", curfn->nname->sym->name);
+
+ uevar = bvalloc(arraylength(lv->vars));
+ varkill = bvalloc(arraylength(lv->vars));
+ avarinit = bvalloc(arraylength(lv->vars));
+
+ pcdata = 0;
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ if(i > 0)
+ print("\n");
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+
+ // bb#0 pred=1,2 succ=3,4
+ print("bb#%d pred=", i);
+ for(j = 0; j < arraylength(bb->pred); j++) {
+ if(j > 0)
+ print(",");
+ print("%d", (*(BasicBlock**)arrayget(bb->pred, j))->rpo);
+ }
+ print(" succ=");
+ for(j = 0; j < arraylength(bb->succ); j++) {
+ if(j > 0)
+ print(",");
+ print("%d", (*(BasicBlock**)arrayget(bb->succ, j))->rpo);
+ }
+ print("\n");
+
+ // initial settings
+ printed = 0;
+ printed = printbitset(printed, "uevar", lv->vars, lv->uevar[bb->rpo]);
+ printed = printbitset(printed, "livein", lv->vars, lv->livein[bb->rpo]);
+ if(printed)
+ print("\n");
+
+ // program listing, with individual effects listed
+ for(p = bb->first;; p = p->link) {
+ print("%P\n", p);
+ if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex)
+ pcdata = p->to.offset;
+ progeffects(p, lv->vars, uevar, varkill, avarinit);
+ printed = 0;
+ printed = printbitset(printed, "uevar", lv->vars, uevar);
+ printed = printbitset(printed, "varkill", lv->vars, varkill);
+ printed = printbitset(printed, "avarinit", lv->vars, avarinit);
+ if(printed)
+ print("\n");
+ if(issafepoint(p)) {
+ args = *(Bvec**)arrayget(lv->argslivepointers, pcdata);
+ locals = *(Bvec**)arrayget(lv->livepointers, pcdata);
+ print("\tlive=");
+ printed = 0;
+ for(j = 0; j < arraylength(lv->vars); j++) {
+ n = *(Node**)arrayget(lv->vars, j);
+ if(islive(n, args, locals)) {
+ if(printed++)
+ print(",");
+ print("%N", n);
+ }
+ }
+ print("\n");
+ }
+ if(p == bb->last)
+ break;
+ }
+
+ // bb bitsets
+ print("end\n");
+ printed = printbitset(printed, "varkill", lv->vars, lv->varkill[bb->rpo]);
+ printed = printbitset(printed, "liveout", lv->vars, lv->liveout[bb->rpo]);
+ printed = printbitset(printed, "avarinit", lv->vars, lv->avarinit[bb->rpo]);
+ printed = printbitset(printed, "avarinitany", lv->vars, lv->avarinitany[bb->rpo]);
+ printed = printbitset(printed, "avarinitall", lv->vars, lv->avarinitall[bb->rpo]);
+ if(printed)
+ print("\n");
+ }
+ print("\n");
+
+ free(uevar);
+ free(varkill);
+ free(avarinit);
+}
+
+// Dumps an array of bitmaps to a symbol as a sequence of uint32 values. The
+// first word dumped is the total number of bitmaps. The second word is the
+// length of the bitmaps. All bitmaps are assumed to be of equal length. The
+// words that are followed are the raw bitmap words. The arr argument is an
+// array of Node*s.
+static void
+twobitwritesymbol(Array *arr, Sym *sym)
+{
+ Bvec *bv;
+ int off, i, j, len;
+ uint32 word;
+
+ len = arraylength(arr);
+ off = 0;
+ off += 4; // number of bitmaps, to fill in later
+ bv = *(Bvec**)arrayget(arr, 0);
+ off = duint32(sym, off, bv->n); // number of bits in each bitmap
+ for(i = 0; i < len; i++) {
+ // bitmap words
+ bv = *(Bvec**)arrayget(arr, i);
+ if(bv == nil)
+ break;
+ for(j = 0; j < bv->n; j += 32) {
+ word = bv->b[j/32];
+ off = duint32(sym, off, word);
+ }
+ }
+ duint32(sym, 0, i); // number of bitmaps
+ ggloblsym(sym, off, 0, 1);
+}
+
+static void
+printprog(Prog *p)
+{
+ while(p != nil) {
+ print("%P\n", p);
+ p = p->link;
+ }
+}
+
+// Entry pointer for liveness analysis. Constructs a complete CFG, solves for
+// the liveness of pointer variables in the function, and emits a runtime data
+// structure read by the garbage collector.
+void
+liveness(Node *fn, Prog *firstp, Sym *argssym, Sym *livesym)
+{
+ Array *cfg, *vars;
+ Liveness *lv;
+ int debugdelta;
+
+ // Change name to dump debugging information only for a specific function.
+ debugdelta = 0;
+ if(strcmp(curfn->nname->sym->name, "!") == 0)
+ debugdelta = 2;
+
+ debuglive += debugdelta;
+ if(debuglive >= 3) {
+ print("liveness: %s\n", curfn->nname->sym->name);
+ printprog(firstp);
+ }
+ checkptxt(fn, firstp);
+
+ // Construct the global liveness state.
+ cfg = newcfg(firstp);
+ if(debuglive >= 3)
+ printcfg(cfg);
+ vars = getvariables(fn);
+ lv = newliveness(fn, firstp, cfg, vars);
+
+ // Run the dataflow framework.
+ livenessprologue(lv);
+ if(debuglive >= 3)
+ livenessprintcfg(lv);
+ livenesssolve(lv);
+ if(debuglive >= 3)
+ livenessprintcfg(lv);
+ livenessepilogue(lv);
+ if(debuglive >= 3)
+ livenessprintcfg(lv);
+ livenesscompact(lv);
+
+ if(debuglive >= 2)
+ livenessprintdebug(lv);
+
+ // Emit the live pointer map data structures
+ twobitwritesymbol(lv->livepointers, livesym);
+ twobitwritesymbol(lv->argslivepointers, argssym);
+
+ // Free everything.
+ freeliveness(lv);
+ arrayfree(vars);
+ freecfg(cfg);
+
+ debuglive -= debugdelta;
+}
diff --git a/src/cmd/gc/popt.c b/src/cmd/gc/popt.c
index 8d7afa011..ea88b94db 100644
--- a/src/cmd/gc/popt.c
+++ b/src/cmd/gc/popt.c
@@ -51,9 +51,14 @@ noreturn(Prog *p)
symlist[2] = pkglookup("throwinit", runtimepkg);
symlist[3] = pkglookup("panic", runtimepkg);
symlist[4] = pkglookup("panicwrap", runtimepkg);
+ symlist[5] = pkglookup("throwreturn", runtimepkg);
+ symlist[6] = pkglookup("selectgo", runtimepkg);
+ symlist[7] = pkglookup("block", runtimepkg);
}
- s = p->to.sym;
+ if(p->to.node == nil)
+ return 0;
+ s = p->to.node->sym;
if(s == S)
return 0;
for(i=0; symlist[i]!=S; i++)
@@ -144,7 +149,13 @@ fixjmp(Prog *firstp)
if(p->opt == dead) {
if(p->link == P && p->as == ARET && last && last->as != ARET) {
// This is the final ARET, and the code so far doesn't have one.
- // Let it stay.
+ // Let it stay. The register allocator assumes that all live code in
+ // the function can be traversed by starting at all the RET instructions
+ // and following predecessor links. If we remove the final RET,
+ // this assumption will not hold in the case of an infinite loop
+ // at the end of a function.
+ // Keep the RET but mark it dead for the liveness analysis.
+ p->mode = 1;
} else {
if(debug['R'] && debug['v'])
print("del %P\n", p);
@@ -489,8 +500,8 @@ struct TempVar
TempFlow *use; // use list, chained through TempFlow.uselink
TempVar *freelink; // next free temp in Type.opt list
TempVar *merge; // merge var with this one
- uint32 start; // smallest Prog.loc in live range
- uint32 end; // largest Prog.loc in live range
+ vlong start; // smallest Prog.pc in live range
+ vlong end; // largest Prog.pc in live range
uchar addr; // address taken - no accurate end
uchar removed; // removed from program
};
@@ -520,10 +531,11 @@ startcmp(const void *va, const void *vb)
static int
canmerge(Node *n)
{
- return n->class == PAUTO && !n->addrtaken && strncmp(n->sym->name, "autotmp", 7) == 0;
+ return n->class == PAUTO && strncmp(n->sym->name, "autotmp", 7) == 0;
}
static void mergewalk(TempVar*, TempFlow*, uint32);
+static void varkillwalk(TempVar*, TempFlow*, uint32);
void
mergetemp(Prog *firstp)
@@ -544,7 +556,7 @@ mergetemp(Prog *firstp)
g = flowstart(firstp, sizeof(TempFlow));
if(g == nil)
return;
-
+
// Build list of all mergeable variables.
nvar = 0;
for(l = curfn->dcl; l != nil; l = l->next)
@@ -640,6 +652,11 @@ mergetemp(Prog *firstp)
gen++;
for(r = v->use; r != nil; r = r->uselink)
mergewalk(v, r, gen);
+ if(v->addr) {
+ gen++;
+ for(r = v->use; r != nil; r = r->uselink)
+ varkillwalk(v, r, gen);
+ }
}
// Sort variables by start.
@@ -659,7 +676,7 @@ mergetemp(Prog *firstp)
nfree = nvar;
for(i=0; i<nvar; i++) {
v = bystart[i];
- if(v->addr || v->removed)
+ if(v->removed)
continue;
// Expire no longer in use.
@@ -672,7 +689,12 @@ mergetemp(Prog *firstp)
t = v->node->type;
for(j=nfree; j<nvar; j++) {
v1 = inuse[j];
- if(eqtype(t, v1->node->type)) {
+ // Require the types to match but also require the addrtaken bits to match.
+ // If a variable's address is taken, that disables registerization for the individual
+ // words of the variable (for example, the base,len,cap of a slice).
+ // We don't want to merge a non-addressed var with an addressed one and
+ // inhibit registerization of the former.
+ if(eqtype(t, v1->node->type) && v->node->addrtaken == v1->node->addrtaken) {
inuse[j] = inuse[nfree++];
if(v1->merge)
v->merge = v1->merge;
@@ -695,7 +717,7 @@ mergetemp(Prog *firstp)
if(Debug) {
print("%S [%d - %d]\n", curfn->nname->sym, nvar, nkill);
for(v=var; v<var+nvar; v++) {
- print("var %#N %T %d-%d", v->node, v->node->type, v->start, v->end);
+ print("var %#N %T %lld-%lld", v->node, v->node->type, v->start, v->end);
if(v->addr)
print(" addr=1");
if(v->removed)
@@ -752,10 +774,10 @@ mergewalk(TempVar *v, TempFlow *r0, uint32 gen)
break;
r1->f.active = gen;
p = r1->f.prog;
- if(v->end < p->loc)
- v->end = p->loc;
+ if(v->end < p->pc)
+ v->end = p->pc;
if(r1 == v->def) {
- v->start = p->loc;
+ v->start = p->pc;
break;
}
}
@@ -765,6 +787,29 @@ mergewalk(TempVar *v, TempFlow *r0, uint32 gen)
mergewalk(v, r2, gen);
}
+static void
+varkillwalk(TempVar *v, TempFlow *r0, uint32 gen)
+{
+ Prog *p;
+ TempFlow *r1, *r;
+
+ for(r1 = r0; r1 != nil; r1 = (TempFlow*)r1->f.s1) {
+ if(r1->f.active == gen)
+ break;
+ r1->f.active = gen;
+ p = r1->f.prog;
+ if(v->end < p->pc)
+ v->end = p->pc;
+ if(v->start > p->pc)
+ v->start = p->pc;
+ if(p->as == ARET || (p->as == AVARKILL && p->to.node == v->node))
+ break;
+ }
+
+ for(r = r0; r != r1; r = (TempFlow*)r->f.s1)
+ varkillwalk(v, (TempFlow*)r->f.s2, gen);
+}
+
// Eliminate redundant nil pointer checks.
//
// The code generation pass emits a CHECKNIL for every possibly nil pointer.
@@ -911,7 +956,7 @@ nilwalkback(NilFlow *rcheck)
static void
nilwalkfwd(NilFlow *rcheck)
{
- NilFlow *r;
+ NilFlow *r, *last;
Prog *p;
ProgInfo info;
@@ -922,6 +967,7 @@ nilwalkfwd(NilFlow *rcheck)
// avoid problems like:
// _ = *x // should panic
// for {} // no writes but infinite loop may be considered visible
+ last = nil;
for(r = (NilFlow*)uniqs(&rcheck->f); r != nil; r = (NilFlow*)uniqs(&r->f)) {
p = r->f.prog;
proginfo(&info, p);
@@ -944,5 +990,12 @@ nilwalkfwd(NilFlow *rcheck)
// Stop if memory write.
if((info.flags & RightWrite) && !regtyp(&p->to))
return;
+ // Stop if we jump backward.
+ // This test is valid because all the NilFlow* are pointers into
+ // a single contiguous array. We will need to add an explicit
+ // numbering when the code is converted to Go.
+ if(last != nil && r <= last)
+ return;
+ last = r;
}
}
diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c
index d6a5b3cce..285bd78a2 100644
--- a/src/cmd/gc/racewalk.c
+++ b/src/cmd/gc/racewalk.c
@@ -166,6 +166,7 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
goto ret;
case OCFUNC:
+ case OVARKILL:
// can't matter
goto ret;
@@ -181,7 +182,7 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
// x, y := f() becomes BLOCK{CALL f, AS x [SP+0], AS y [SP+n]}
// We don't want to instrument between the statements because it will
// smash the results.
- racewalknode(&n->list->n, &n->ninit, 0, 0);
+ racewalknode(&n->list->n, &n->list->n->ninit, 0, 0);
fini = nil;
racewalklist(n->list->next, &fini);
n->list = concat(n->list, fini);
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
index bd271da38..45aa521b3 100644
--- a/src/cmd/gc/range.c
+++ b/src/cmd/gc/range.c
@@ -111,6 +111,8 @@ walkrange(Node *n)
Node *hb; // hidden bool
Node *a, *v1, *v2; // not hidden aggregate, val 1, 2
Node *fn, *tmp;
+ Node *keyname, *valname;
+ Node *key, *val;
NodeList *body, *init;
Type *th, *t;
int lno;
@@ -120,34 +122,23 @@ walkrange(Node *n)
a = n->right;
lno = setlineno(a);
- if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) {
- a = nod(OCONV, n->right, N);
- a->type = types[TSTRING];
- }
v1 = n->list->n;
v2 = N;
- if(n->list->next)
+ if(n->list->next && !isblank(n->list->next->n))
v2 = n->list->next->n;
// n->list has no meaning anymore, clear it
// to avoid erroneous processing by racewalk.
n->list = nil;
hv2 = N;
- if(v2 == N && t->etype == TARRAY) {
- // will have just one reference to argument.
- // no need to make a potentially expensive copy.
- ha = a;
- } else {
- ha = temp(a->type);
- init = list(init, nod(OAS, ha, a));
- }
-
switch(t->etype) {
default:
fatal("walkrange");
case TARRAY:
+ // orderstmt arranged for a copy of the array/slice variable if needed.
+ ha = a;
hv1 = temp(types[TINT]);
hn = temp(types[TINT]);
hp = nil;
@@ -162,8 +153,7 @@ walkrange(Node *n)
}
n->ntest = nod(OLT, hv1, hn);
- n->nincr = nod(OASOP, hv1, nodintconst(1));
- n->nincr->etype = OADD;
+ n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)));
if(v2 == N)
body = list1(nod(OAS, v1, hv1));
else {
@@ -171,54 +161,70 @@ walkrange(Node *n)
a->list = list(list1(v1), v2);
a->rlist = list(list1(hv1), nod(OIND, hp, N));
body = list1(a);
-
+
+ // Advance pointer as part of increment.
+ // We used to advance the pointer before executing the loop body,
+ // but doing so would make the pointer point past the end of the
+ // array during the final iteration, possibly causing another unrelated
+ // piece of memory not to be garbage collected until the loop finished.
+ // Advancing during the increment ensures that the pointer p only points
+ // pass the end of the array during the final "p++; i++; if(i >= len(x)) break;",
+ // after which p is dead, so it cannot confuse the collector.
tmp = nod(OADD, hp, nodintconst(t->type->width));
tmp->type = hp->type;
tmp->typecheck = 1;
tmp->right->type = types[tptr];
tmp->right->typecheck = 1;
- body = list(body, nod(OAS, hp, tmp));
+ a = nod(OAS, hp, tmp);
+ typecheck(&a, Etop);
+ n->nincr->ninit = list1(a);
}
break;
case TMAP:
- th = typ(TARRAY);
- th->type = ptrto(types[TUINT8]);
- // see ../../pkg/runtime/hashmap.c:/hash_iter
- // Size of hash_iter in # of pointers.
- th->bound = 11;
- hit = temp(th);
+ // orderstmt allocated the iterator for us.
+ // we only use a once, so no copy needed.
+ ha = a;
+ th = hiter(t);
+ hit = n->alloc;
+ hit->type = th;
+ n->left = N;
+ keyname = newname(th->type->sym); // depends on layout of iterator struct. See reflect.c:hiter
+ valname = newname(th->type->down->sym); // ditto
fn = syslook("mapiterinit", 1);
argtype(fn, t->down);
argtype(fn, t->type);
argtype(fn, th);
init = list(init, mkcall1(fn, T, nil, typename(t), ha, nod(OADDR, hit, N)));
- n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil());
+ n->ntest = nod(ONE, nod(ODOT, hit, keyname), nodnil());
fn = syslook("mapiternext", 1);
argtype(fn, th);
n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N));
+ key = nod(ODOT, hit, keyname);
+ key = nod(OIND, key, N);
if(v2 == N) {
- fn = syslook("mapiter1", 1);
- argtype(fn, th);
- argtype(fn, t->down);
- a = nod(OAS, v1, mkcall1(fn, t->down, nil, nod(OADDR, hit, N)));
+ a = nod(OAS, v1, key);
} else {
- fn = syslook("mapiter2", 1);
- argtype(fn, th);
- argtype(fn, t->down);
- argtype(fn, t->type);
+ val = nod(ODOT, hit, valname);
+ val = nod(OIND, val, N);
a = nod(OAS2, N, N);
a->list = list(list1(v1), v2);
- a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, nod(OADDR, hit, N)));
+ a->rlist = list(list1(key), val);
}
body = list1(a);
break;
case TCHAN:
+ // orderstmt arranged for a copy of the channel variable.
+ ha = a;
+ n->ntest = N;
+
hv1 = temp(t->type);
+ if(haspointers(t->type))
+ init = list(init, nod(OAS, hv1, N));
hb = temp(types[TBOOL]);
n->ntest = nod(ONE, hb, nodbool(0));
@@ -231,6 +237,9 @@ walkrange(Node *n)
break;
case TSTRING:
+ // orderstmt arranged for a copy of the string variable.
+ ha = a;
+
ohv1 = temp(types[TINT]);
hv1 = temp(types[TINT]);
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index 0a8aa8d7a..dbb447e4e 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -125,6 +125,8 @@ mapbucket(Type *t)
keytype = t->down;
valtype = t->type;
+ dowidth(keytype);
+ dowidth(valtype);
if(keytype->width > MAXKEYSIZE)
keytype = ptrto(keytype);
if(valtype->width > MAXVALSIZE)
@@ -143,6 +145,11 @@ mapbucket(Type *t)
overflowfield->sym = mal(sizeof(Sym)); // not important but needs to be set to give this type a name
overflowfield->sym->name = "overflow";
offset += widthptr;
+
+ // The keys are padded to the native integer alignment.
+ // This is usually the same as widthptr; the exception (as usual) is nacl/amd64.
+ if(widthreg > widthptr)
+ offset += widthreg - widthptr;
keysfield = typ(TFIELD);
keysfield->type = typ(TARRAY);
@@ -173,6 +180,7 @@ mapbucket(Type *t)
bucket->width = offset;
bucket->local = t->local;
t->bucket = bucket;
+ bucket->map = t;
return bucket;
}
@@ -229,10 +237,89 @@ hmap(Type *t)
h->width = offset;
h->local = t->local;
t->hmap = h;
- h->hmap = t;
+ h->map = t;
return h;
}
+Type*
+hiter(Type *t)
+{
+ int32 n, off;
+ Type *field[7];
+ Type *i;
+
+ if(t->hiter != T)
+ return t->hiter;
+
+ // build a struct:
+ // hash_iter {
+ // key *Key
+ // val *Value
+ // t *MapType
+ // h *Hmap
+ // buckets *Bucket
+ // bptr *Bucket
+ // other [4]uintptr
+ // }
+ // must match ../../pkg/runtime/hashmap.c:hash_iter.
+ field[0] = typ(TFIELD);
+ field[0]->type = ptrto(t->down);
+ field[0]->sym = mal(sizeof(Sym));
+ field[0]->sym->name = "key";
+
+ field[1] = typ(TFIELD);
+ field[1]->type = ptrto(t->type);
+ field[1]->sym = mal(sizeof(Sym));
+ field[1]->sym->name = "val";
+
+ field[2] = typ(TFIELD);
+ field[2]->type = ptrto(types[TUINT8]); // TODO: is there a Type type?
+ field[2]->sym = mal(sizeof(Sym));
+ field[2]->sym->name = "t";
+
+ field[3] = typ(TFIELD);
+ field[3]->type = ptrto(hmap(t));
+ field[3]->sym = mal(sizeof(Sym));
+ field[3]->sym->name = "h";
+
+ field[4] = typ(TFIELD);
+ field[4]->type = ptrto(mapbucket(t));
+ field[4]->sym = mal(sizeof(Sym));
+ field[4]->sym->name = "buckets";
+
+ field[5] = typ(TFIELD);
+ field[5]->type = ptrto(mapbucket(t));
+ field[5]->sym = mal(sizeof(Sym));
+ field[5]->sym->name = "bptr";
+
+ // all other non-pointer fields
+ field[6] = typ(TFIELD);
+ field[6]->type = typ(TARRAY);
+ field[6]->type->type = types[TUINTPTR];
+ field[6]->type->bound = 4;
+ field[6]->type->width = 4 * widthptr;
+ field[6]->sym = mal(sizeof(Sym));
+ field[6]->sym->name = "other";
+
+ // build iterator struct holding the above fields
+ i = typ(TSTRUCT);
+ i->noalg = 1;
+ i->type = field[0];
+ off = 0;
+ for(n = 0; n < 6; n++) {
+ field[n]->down = field[n+1];
+ field[n]->width = off;
+ off += field[n]->type->width;
+ }
+ field[6]->down = T;
+ off += field[6]->type->width;
+ if(off != 10 * widthptr)
+ yyerror("hash_iter size not correct %d %d", off, 10 * widthptr);
+ t->hiter = i;
+ i->map = t;
+ return i;
+}
+
/*
* f is method type, with receiver.
* return function type, receiver as first argument (or not).
@@ -396,9 +483,8 @@ imethods(Type *t)
last->link = a;
last = a;
- // Compiler can only refer to wrappers for
- // named interface types and non-blank methods.
- if(t->sym == S || isblanksym(method))
+ // Compiler can only refer to wrappers for non-blank methods.
+ if(isblanksym(method))
continue;
// NOTE(rsc): Perhaps an oversight that
@@ -620,6 +706,10 @@ haspointers(Type *t)
ret = 1;
break;
}
+ if(t->bound == 0) { // empty array
+ ret = 0;
+ break;
+ }
ret = haspointers(t->type);
break;
case TSTRUCT:
@@ -656,7 +746,7 @@ static int
dcommontype(Sym *s, int ot, Type *t)
{
int i, alg, sizeofAlg;
- Sym *sptr, *algsym;
+ Sym *sptr, *algsym, *zero;
static Sym *algarray;
char *p;
@@ -677,6 +767,18 @@ dcommontype(Sym *s, int ot, Type *t)
else
sptr = weaktypesym(ptrto(t));
+ // All (non-reflect-allocated) Types share the same zero object.
+ // Each place in the compiler where a pointer to the zero object
+ // might be returned by a runtime call (map access return value,
+ // 2-arg type cast) declares the size of the zerovalue it needs.
+ // The linker magically takes the max of all the sizes.
+ zero = pkglookup("zerovalue", runtimepkg);
+
+ // We use size 0 here so we get the pointer to the zero value,
+ // but don't allocate space for the zero value unless we need it.
+ // TODO: how do we get this symbol into bss? We really want
+ // a read-only bss, but I don't think such a thing exists.
+
// ../../pkg/reflect/type.go:/^type.commonType
// actual type structure
// type commonType struct {
@@ -691,6 +793,7 @@ dcommontype(Sym *s, int ot, Type *t)
// string *string
// *extraType
// ptrToThis *Type
+ // zero unsafe.Pointer
// }
ot = duintptr(s, ot, t->width);
ot = duint32(s, ot, typehash(t));
@@ -728,6 +831,7 @@ dcommontype(Sym *s, int ot, Type *t)
ot += widthptr;
ot = dsymptr(s, ot, sptr, 0); // ptrto type
+ ot = dsymptr(s, ot, zero, 0); // ptr to zero value
return ot;
}
@@ -893,7 +997,7 @@ ok:
switch(t->etype) {
default:
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
break;
case TARRAY:
@@ -905,7 +1009,7 @@ ok:
t2->bound = -1; // slice
s2 = dtypesym(t2);
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s1, 0);
ot = dsymptr(s, ot, s2, 0);
ot = duintptr(s, ot, t->bound);
@@ -913,7 +1017,7 @@ ok:
// ../../pkg/runtime/type.go:/SliceType
s1 = dtypesym(t->type);
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s1, 0);
}
break;
@@ -922,7 +1026,7 @@ ok:
// ../../pkg/runtime/type.go:/ChanType
s1 = dtypesym(t->type);
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s1, 0);
ot = duintptr(s, ot, t->chan);
break;
@@ -939,7 +1043,7 @@ ok:
dtypesym(t1->type);
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = duint8(s, ot, isddd);
// two slice headers: in and out.
@@ -971,7 +1075,7 @@ ok:
// ../../pkg/runtime/type.go:/InterfaceType
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
ot = duintxx(s, ot, n, widthint);
ot = duintxx(s, ot, n, widthint);
@@ -990,7 +1094,7 @@ ok:
s3 = dtypesym(mapbucket(t));
s4 = dtypesym(hmap(t));
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s1, 0);
ot = dsymptr(s, ot, s2, 0);
ot = dsymptr(s, ot, s3, 0);
@@ -1007,7 +1111,7 @@ ok:
// ../../pkg/runtime/type.go:/PtrType
s1 = dtypesym(t->type);
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s1, 0);
break;
@@ -1020,7 +1124,7 @@ ok:
n++;
}
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
ot = duintxx(s, ot, n, widthint);
ot = duintxx(s, ot, n, widthint);
@@ -1218,7 +1322,22 @@ dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size)
// NOTE: Any changes here need to be made to reflect.PtrTo as well.
if(*off % widthptr != 0)
fatal("dgcsym1: invalid alignment, %T", t);
- if(!haspointers(t->type) || t->type->etype == TUINT8) {
+
+ // NOTE(rsc): Emitting GC_APTR here for *nonptrtype
+ // (pointer to non-pointer-containing type) means that
+ // we do not record 'nonptrtype' and instead tell the
+ // garbage collector to look up the type of the memory in
+ // type information stored in the heap. In effect we are telling
+ // the collector "we don't trust our information - use yours".
+ // It's not completely clear why we want to do this.
+ // It does have the effect that if you have a *SliceHeader and a *[]int
+ // pointing at the same actual slice header, *SliceHeader will not be
+ // used as an authoritative type for the memory, which is good:
+ // if the collector scanned the memory as type *SliceHeader, it would
+ // see no pointers inside but mark the block as scanned, preventing
+ // the seeing of pointers when we followed the *[]int pointer.
+ // Perhaps that kind of situation is the rationale.
+ if(!haspointers(t->type)) {
ot = duintptr(s, ot, GC_APTR);
ot = duintptr(s, ot, *off);
} else {
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index c8d57ab33..fb5c2a150 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -15,6 +15,7 @@ package PACKAGE
func new(typ *byte) *any
func panicindex()
func panicslice()
+func panicdivide()
func throwreturn()
func throwinit()
func panicwrap(string, string, string)
@@ -36,13 +37,17 @@ func printnl()
func printsp()
func goprintf()
-// filled in by compiler: int n, string, string, ...
-func concatstring()
+func concatstring2(string, string) string
+func concatstring3(string, string, string) string
+func concatstring4(string, string, string, string) string
+func concatstring5(string, string, string, string, string) string
+func concatstrings([]string) string
func cmpstring(string, string) int
func eqstring(string, string) bool
func intstring(int64) string
func slicebytetostring([]byte) string
+func slicebytetostringtmp([]byte) string
func slicerunetostring([]rune) string
func stringtoslicebyte(string) []byte
func stringtoslicerune(string) []rune
@@ -55,8 +60,8 @@ func slicestringcopy(to any, fr any) int
func typ2Itab(typ *byte, typ2 *byte, cache **byte) (ret *byte)
func convI2E(elem any) (ret any)
func convI2I(typ *byte, elem any) (ret any)
-func convT2E(typ *byte, elem any) (ret any)
-func convT2I(typ *byte, typ2 *byte, cache **byte, elem any) (ret any)
+func convT2E(typ *byte, elem *any) (ret any)
+func convT2I(typ *byte, typ2 *byte, cache **byte, elem *any) (ret any)
// interface type assertions x.(T)
func assertE2E(typ *byte, iface any) (ret any)
@@ -83,29 +88,27 @@ func equal(typ *byte, x1, x2 any) (ret bool)
// *byte is really *runtime.Type
func makemap(mapType *byte, hint int64) (hmap map[any]any)
-func mapaccess1(mapType *byte, hmap map[any]any, key any) (val any)
+func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any)
func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any)
func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any)
func mapaccess1_faststr(mapType *byte, hmap map[any]any, key any) (val *any)
-func mapaccess2(mapType *byte, hmap map[any]any, key any) (val any, pres bool)
+func mapaccess2(mapType *byte, hmap map[any]any, key *any) (val *any, pres bool)
func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
-func mapassign1(mapType *byte, hmap map[any]any, key any, val any)
+func mapassign1(mapType *byte, hmap map[any]any, key *any, val *any)
func mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
-func mapdelete(mapType *byte, hmap map[any]any, key any)
+func mapdelete(mapType *byte, hmap map[any]any, key *any)
func mapiternext(hiter *any)
-func mapiter1(hiter *any) (key any)
-func mapiter2(hiter *any) (key any, val any)
// *byte is really *runtime.Type
func makechan(chanType *byte, hint int64) (hchan chan any)
-func chanrecv1(chanType *byte, hchan <-chan any) (elem any)
-func chanrecv2(chanType *byte, hchan <-chan any) (elem any, received bool)
-func chansend1(chanType *byte, hchan chan<- any, elem any)
+func chanrecv1(chanType *byte, hchan <-chan any, elem *any)
+func chanrecv2(chanType *byte, hchan <-chan any, elem *any) bool
+func chansend1(chanType *byte, hchan chan<- any, elem *any)
func closechan(hchan any)
-func selectnbsend(chanType *byte, hchan chan<- any, elem any) bool
+func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool
func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool
func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
index cd3de8c7b..58a120674 100644
--- a/src/cmd/gc/select.c
+++ b/src/cmd/gc/select.c
@@ -69,6 +69,7 @@ typecheckselect(Node *sel)
n->op = OSELRECV2;
n->left = n->list->n;
n->ntest = n->list->next->n;
+ n->list = nil;
n->right = n->rlist->n;
n->rlist = nil;
break;
@@ -94,7 +95,7 @@ void
walkselect(Node *sel)
{
int lno, i;
- Node *n, *r, *a, *tmp, *var, *cas, *dflt, *ch;
+ Node *n, *r, *a, *var, *cas, *dflt, *ch;
NodeList *l, *init;
if(sel->list == nil && sel->xoffset != 0)
@@ -110,6 +111,8 @@ walkselect(Node *sel)
}
// optimization: one-case select: single op.
+ // TODO(rsc): Reenable optimization once order.c can handle it.
+ // golang.org/issue/7672.
if(i == 1) {
cas = sel->list->n;
setlineno(cas);
@@ -123,32 +126,34 @@ walkselect(Node *sel)
fatal("select %O", n->op);
case OSEND:
- ch = cheapexpr(n->left, &l);
- n->left = ch;
+ // ok already
+ ch = n->left;
break;
case OSELRECV:
- r = n->right;
- ch = cheapexpr(r->left, &l);
- r->left = ch;
-
+ ch = n->right->left;
+ Selrecv1:
if(n->left == N)
- n = r;
- else {
- n = nod(OAS, n->left, r);
- typecheck(&n, Etop);
- }
+ n = n->right;
+ else
+ n->op = OAS;
break;
case OSELRECV2:
- r = n->right;
- ch = cheapexpr(r->left, &l);
- r->left = ch;
-
- a = nod(OAS2, N, N);
- a->list = n->list;
- a->rlist = list1(n->right);
- n = a;
+ ch = n->right->left;
+ if(n->ntest == N)
+ goto Selrecv1;
+ if(n->left == N) {
+ typecheck(&nblank, Erv | Easgn);
+ n->left = nblank;
+ }
+ n->op = OAS2;
+ n->list = list(list1(n->left), n->ntest);
+ n->rlist = list1(n->right);
+ n->right = N;
+ n->left = N;
+ n->ntest = N;
+ n->typecheck = 0;
typecheck(&n, Etop);
break;
}
@@ -166,7 +171,7 @@ walkselect(Node *sel)
goto out;
}
- // introduce temporary variables for OSELRECV where needed.
+ // convert case value arguments to addresses.
// this rewrite is used by both the general code and the next optimization.
for(l=sel->list; l; l=l->next) {
cas = l->n;
@@ -175,58 +180,24 @@ walkselect(Node *sel)
if(n == N)
continue;
switch(n->op) {
+ case OSEND:
+ n->right = nod(OADDR, n->right, N);
+ typecheck(&n->right, Erv);
+ break;
case OSELRECV:
case OSELRECV2:
- ch = n->right->left;
-
- // If we can use the address of the target without
- // violating addressability or order of operations, do so.
- // Otherwise introduce a temporary.
- // Also introduce a temporary for := variables that escape,
- // so that we can delay the heap allocation until the case
- // is selected.
+ if(n->op == OSELRECV2 && n->ntest == N)
+ n->op = OSELRECV;
if(n->op == OSELRECV2) {
- if(n->ntest == N || isblank(n->ntest))
- n->ntest = nodnil();
- else if(n->ntest->op == ONAME &&
- (!n->colas || (n->ntest->class&PHEAP) == 0) &&
- convertop(types[TBOOL], n->ntest->type, nil) == OCONVNOP) {
- n->ntest = nod(OADDR, n->ntest, N);
- n->ntest->etype = 1; // pointer does not escape
- typecheck(&n->ntest, Erv);
- } else {
- tmp = temp(types[TBOOL]);
- a = nod(OADDR, tmp, N);
- a->etype = 1; // pointer does not escape
- typecheck(&a, Erv);
- r = nod(OAS, n->ntest, tmp);
- typecheck(&r, Etop);
- cas->nbody = concat(list1(r), cas->nbody);
- n->ntest = a;
- }
+ n->ntest = nod(OADDR, n->ntest, N);
+ typecheck(&n->ntest, Erv);
}
-
- if(n->left == N || isblank(n->left))
+ if(n->left == N)
n->left = nodnil();
- else if(n->left->op == ONAME &&
- (!n->colas || (n->left->class&PHEAP) == 0) &&
- convertop(ch->type->type, n->left->type, nil) == OCONVNOP) {
+ else {
n->left = nod(OADDR, n->left, N);
- n->left->etype = 1; // pointer does not escape
typecheck(&n->left, Erv);
- } else {
- tmp = temp(ch->type->type);
- a = nod(OADDR, tmp, N);
- a->etype = 1; // pointer does not escape
- typecheck(&a, Erv);
- r = nod(OAS, n->left, tmp);
- typecheck(&r, Etop);
- cas->nbody = concat(list1(r), cas->nbody);
- n->left = a;
- }
-
- cas->nbody = concat(n->ninit, cas->nbody);
- n->ninit = nil;
+ }
break;
}
}
@@ -250,8 +221,8 @@ walkselect(Node *sel)
fatal("select %O", n->op);
case OSEND:
- // if c != nil && selectnbsend(c, v) { body } else { default body }
- ch = cheapexpr(n->left, &r->ninit);
+ // if selectnbsend(c, v) { body } else { default body }
+ ch = n->left;
r->ntest = mkcall1(chanfn("selectnbsend", 2, ch->type),
types[TBOOL], &r->ninit, typename(ch->type), ch, n->right);
break;
@@ -260,7 +231,7 @@ walkselect(Node *sel)
// if c != nil && selectnbrecv(&v, c) { body } else { default body }
r = nod(OIF, N, N);
r->ninit = cas->ninit;
- ch = cheapexpr(n->right->left, &r->ninit);
+ ch = n->right->left;
r->ntest = mkcall1(chanfn("selectnbrecv", 2, ch->type),
types[TBOOL], &r->ninit, typename(ch->type), n->left, ch);
break;
@@ -269,7 +240,7 @@ walkselect(Node *sel)
// if c != nil && selectnbrecv2(&v, c) { body } else { default body }
r = nod(OIF, N, N);
r->ninit = cas->ninit;
- ch = cheapexpr(n->right->left, &r->ninit);
+ ch = n->right->left;
r->ntest = mkcall1(chanfn("selectnbrecv2", 2, ch->type),
types[TBOOL], &r->ninit, typename(ch->type), n->left, n->ntest, ch);
break;
@@ -313,11 +284,6 @@ walkselect(Node *sel)
case OSEND:
// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
- n->left = localexpr(safeexpr(n->left, &r->ninit), n->left->type, &r->ninit);
- n->right = localexpr(n->right, n->left->type->type, &r->ninit);
- n->right = nod(OADDR, n->right, N);
- n->right->etype = 1; // pointer does not escape
- typecheck(&n->right, Erv);
r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
&r->ninit, var, n->left, n->right);
break;
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index 446b1110a..59804cd8d 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -286,8 +286,8 @@ staticcopy(Node *l, Node *r, NodeList **out)
if(r->op != ONAME || r->class != PEXTERN || r->sym->pkg != localpkg)
return 0;
- if(r->defn == N) // zeroed
- return 1;
+ if(r->defn == N) // probably zeroed but perhaps supplied externally and of unknown value
+ return 0;
if(r->defn->op != OAS)
return 0;
orig = r;
@@ -354,11 +354,13 @@ staticcopy(Node *l, Node *r, NodeList **out)
else {
ll = nod(OXXX, N, N);
*ll = n1;
+ ll->orig = ll; // completely separate copy
if(!staticassign(ll, e->expr, out)) {
// Requires computation, but we're
// copying someone else's computation.
rr = nod(OXXX, N, N);
*rr = *orig;
+ rr->orig = rr; // completely separate copy
rr->type = ll->type;
rr->xoffset += e->xoffset;
*out = list(*out, nod(OAS, ll, rr));
@@ -378,6 +380,7 @@ staticassign(Node *l, Node *r, NodeList **out)
InitPlan *p;
InitEntry *e;
int i;
+ Strlit *sval;
switch(r->op) {
default:
@@ -426,6 +429,14 @@ staticassign(Node *l, Node *r, NodeList **out)
}
break;
+ case OSTRARRAYBYTE:
+ if(l->class == PEXTERN && r->left->op == OLITERAL) {
+ sval = r->left->val.u.sval;
+ slicebytes(l, sval->s, sval->len);
+ return 1;
+ }
+ break;
+
case OARRAYLIT:
initplan(r);
if(isslice(r->type)) {
@@ -459,6 +470,7 @@ staticassign(Node *l, Node *r, NodeList **out)
else {
a = nod(OXXX, N, N);
*a = n1;
+ a->orig = a; // completely separate copy
if(!staticassign(a, e->expr, out))
*out = list(*out, nod(OAS, a, e->expr));
}
@@ -756,11 +768,24 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
vauto = temp(ptrto(t));
// set auto to point at new temp or heap (3 assign)
- if(n->esc == EscNone) {
- a = nod(OAS, temp(t), N);
- typecheck(&a, Etop);
- *init = list(*init, a); // zero new temp
- a = nod(OADDR, a->left, N);
+ if(n->alloc != N) {
+ // temp allocated during order.c for dddarg
+ n->alloc->type = t;
+ if(vstat == N) {
+ a = nod(OAS, n->alloc, N);
+ typecheck(&a, Etop);
+ *init = list(*init, a); // zero new temp
+ }
+ a = nod(OADDR, n->alloc, N);
+ } else if(n->esc == EscNone) {
+ a = temp(t);
+ if(vstat == N) {
+ a = nod(OAS, temp(t), N);
+ typecheck(&a, Etop);
+ *init = list(*init, a); // zero new temp
+ a = a->left;
+ }
+ a = nod(OADDR, a, N);
} else {
a = nod(ONEW, N, N);
a->list = list1(typenod(t));
@@ -827,7 +852,7 @@ maplit(int ctxt, Node *n, Node *var, NodeList **init)
int nerr;
int64 b;
Type *t, *tk, *tv, *t1;
- Node *vstat, *index, *value;
+ Node *vstat, *index, *value, *key, *val;
Sym *syma, *symb;
USED(ctxt);
@@ -846,7 +871,7 @@ ctxt = 0;
r = l->n;
if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
+ fatal("maplit: rhs not OKEY: %N", r);
index = r->left;
value = r->right;
@@ -890,7 +915,7 @@ ctxt = 0;
r = l->n;
if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
+ fatal("maplit: rhs not OKEY: %N", r);
index = r->left;
value = r->right;
@@ -941,8 +966,7 @@ ctxt = 0;
a->ninit = list1(nod(OAS, index, nodintconst(0)));
a->ntest = nod(OLT, index, nodintconst(t->bound));
- a->nincr = nod(OASOP, index, nodintconst(1));
- a->nincr->etype = OADD;
+ a->nincr = nod(OAS, index, nod(OADD, index, nodintconst(1)));
typecheck(&a, Etop);
walkstmt(&a);
@@ -950,25 +974,49 @@ ctxt = 0;
}
// put in dynamic entries one-at-a-time
+ key = nil;
+ val = nil;
for(l=n->list; l; l=l->next) {
r = l->n;
if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
+ fatal("maplit: rhs not OKEY: %N", r);
index = r->left;
value = r->right;
if(isliteral(index) && isliteral(value))
continue;
+
+ // build list of var[c] = expr.
+ // use temporary so that mapassign1 can have addressable key, val.
+ if(key == nil) {
+ key = temp(var->type->down);
+ val = temp(var->type->type);
+ }
+ a = nod(OAS, key, r->left);
+ typecheck(&a, Etop);
+ walkstmt(&a);
+ *init = list(*init, a);
+ a = nod(OAS, val, r->right);
+ typecheck(&a, Etop);
+ walkstmt(&a);
+ *init = list(*init, a);
- // build list of var[c] = expr
- a = nod(OINDEX, var, r->left);
- a = nod(OAS, a, r->right);
+ a = nod(OAS, nod(OINDEX, var, key), val);
typecheck(&a, Etop);
- walkexpr(&a, init);
+ walkstmt(&a);
+ *init = list(*init, a);
+
if(nerr != nerrors)
break;
-
+ }
+
+ if(key != nil) {
+ a = nod(OVARKILL, key, N);
+ typecheck(&a, Etop);
+ *init = list(*init, a);
+ a = nod(OVARKILL, val, N);
+ typecheck(&a, Etop);
*init = list(*init, a);
}
}
@@ -988,12 +1036,16 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
if(!isptr[t->etype])
fatal("anylit: not ptr");
- r = nod(ONEW, N, N);
- r->typecheck = 1;
- r->type = t;
- r->esc = n->esc;
+ if(n->right != N) {
+ r = nod(OADDR, n->right, N);
+ typecheck(&r, Erv);
+ } else {
+ r = nod(ONEW, N, N);
+ r->typecheck = 1;
+ r->type = t;
+ r->esc = n->esc;
+ }
walkexpr(&r, init);
-
a = nod(OAS, var, r);
typecheck(&a, Etop);
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index bea90b87b..72a9ac20c 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -88,6 +88,7 @@ flusherrors(void)
{
int i;
+ Bflush(&bstdout);
if(nerr == 0)
return;
qsort(err, nerr, sizeof err[0], errcmp);
@@ -258,9 +259,6 @@ fatal(char *fmt, ...)
void
linehist(char *file, int32 off, int relative)
{
- Hist *h;
- char *cp;
-
if(debug['i']) {
if(file != nil) {
if(off < 0)
@@ -274,25 +272,10 @@ linehist(char *file, int32 off, int relative)
print("end of import");
print(" at line %L\n", lexlineno);
}
-
- if(off < 0 && file[0] != '/' && !relative) {
- cp = mal(strlen(file) + strlen(pathname) + 2);
- sprint(cp, "%s/%s", pathname, file);
- file = cp;
- }
-
- h = mal(sizeof(Hist));
- h->name = file;
- h->line = lexlineno;
- h->offset = off;
- h->link = H;
- if(ehist == H) {
- hist = h;
- ehist = h;
- return;
- }
- ehist->link = h;
- ehist = h;
+
+ if(off < 0 && file[0] != '/' && !relative)
+ file = smprint("%s/%s", ctxt->pathname, file);
+ linklinehist(ctxt, lexlineno, file, off);
}
int32
@@ -607,8 +590,6 @@ algtype1(Type *t, Type **bad)
*bad = t;
return ANOEQ;
}
- if(t->bound == 0)
- return AMEM;
a = algtype1(t->type, bad);
if(a == ANOEQ || a == AMEM) {
if(a == ANOEQ && bad)
@@ -1242,8 +1223,10 @@ assignop(Type *src, Type *dst, char **why)
// 2. src and dst have identical underlying types
// and either src or dst is not a named type or
- // both are interface types.
- if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || src->etype == TINTER))
+ // both are empty interface types.
+ // For assignable but different non-empty interface types,
+ // we want to recompute the itab.
+ if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || isnilinter(src)))
return OCONVNOP;
// 3. dst is an interface type and src implements dst.
@@ -1251,13 +1234,16 @@ assignop(Type *src, Type *dst, char **why)
if(implements(src, dst, &missing, &have, &ptr))
return OCONVIFACE;
- // we'll have complained about this method anyway, supress spurious messages.
+ // we'll have complained about this method anyway, suppress spurious messages.
if(have && have->sym == missing->sym && (have->type->broke || missing->type->broke))
return OCONVIFACE;
if(why != nil) {
if(isptrto(src, TINTER))
*why = smprint(":\n\t%T is pointer to interface, not interface", src);
+ else if(have && have->sym == missing->sym && have->nointerface)
+ *why = smprint(":\n\t%T does not implement %T (%S method is marked 'nointerface')",
+ src, dst, missing->sym);
else if(have && have->sym == missing->sym)
*why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n"
"\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
@@ -1692,7 +1678,7 @@ typehash(Type *t)
md5reset(&d);
md5write(&d, (uchar*)p, strlen(p));
free(p);
- return md5sum(&d);
+ return md5sum(&d, nil);
}
Type*
@@ -2115,7 +2101,7 @@ cheapexpr(Node *n, NodeList **init)
Node*
localexpr(Node *n, Type *t, NodeList **init)
{
- if(n->op == ONAME && !n->addrtaken &&
+ if(n->op == ONAME && (!n->addrtaken || strncmp(n->sym->name, "autotmp_", 8) == 0) &&
(n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT) &&
convertop(n->type, t, nil) == OCONVNOP)
return n;
@@ -2257,6 +2243,7 @@ adddot(Node *n)
int c, d;
typecheck(&n->left, Etype|Erv);
+ n->diag |= n->left->diag;
t = n->left->type;
if(t == T)
goto ret;
@@ -2506,12 +2493,19 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
Type *tpad, *methodrcvr;
int isddd;
Val v;
+ static int linehistdone = 0;
if(0 && debug['r'])
print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
rcvr, method, newnam);
- lineno = 1; // less confusing than end of input
+ lexlineno++;
+ lineno = lexlineno;
+ if (linehistdone == 0) {
+ // All the wrappers can share the same linehist entry.
+ linehist("<autogenerated>", 0, 0);
+ linehistdone = 1;
+ }
dclcontext = PEXTERN;
markdcl();
@@ -2608,8 +2602,10 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
funcbody(fn);
curfn = fn;
- // wrappers where T is anonymous (struct{ NamedType }) can be duplicated.
- if(rcvr->etype == TSTRUCT || isptr[rcvr->etype] && rcvr->type->etype == TSTRUCT)
+ // wrappers where T is anonymous (struct or interface) can be duplicated.
+ if(rcvr->etype == TSTRUCT ||
+ rcvr->etype == TINTER ||
+ isptr[rcvr->etype] && rcvr->type->etype == TSTRUCT)
fn->dupok = 1;
typecheck(&fn, Etop);
typechecklist(fn->nbody, Etop);
@@ -3631,7 +3627,8 @@ ngotype(Node *n)
* only in the last segment of the path, and it makes for happier
* users if we escape that as little as possible.
*
- * If you edit this, edit ../ld/lib.c:/^pathtoprefix copy too.
+ * If you edit this, edit ../ld/lib.c:/^pathtoprefix too.
+ * If you edit this, edit ../../pkg/debug/goobj/read.go:/importPathToPrefix too.
*/
static char*
pathtoprefix(char *s)
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
index d6aa021a9..ce0190507 100644
--- a/src/cmd/gc/swt.c
+++ b/src/cmd/gc/swt.c
@@ -317,7 +317,7 @@ casebody(Node *sw, Node *typeswvar)
// botch - shouldn't fall thru declaration
last = stat->end->n;
- if(last->op == OXFALL) {
+ if(last->xoffset == n->xoffset && last->op == OXFALL) {
if(typeswvar) {
setlineno(last);
yyerror("cannot fallthrough in type switch");
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 31a2f2c5c..c50b2285b 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -310,7 +310,7 @@ typecheck1(Node **np, int top)
int ok, ntop;
Type *t, *tp, *missing, *have, *badtype;
Val v;
- char *why;
+ char *why, *desc, descbuf[64];
n = *np;
@@ -368,7 +368,7 @@ reswitch:
goto ret;
case OPACK:
- yyerror("use of package %S not in selector", n->sym);
+ yyerror("use of package %S without selector", n->sym);
goto error;
case ODDD:
@@ -535,6 +535,19 @@ reswitch:
op = n->etype;
goto arith;
+ case OADDPTR:
+ ok |= Erv;
+ l = typecheck(&n->left, Erv);
+ r = typecheck(&n->right, Erv);
+ if(l->type == T || r->type == T)
+ goto error;
+ if(l->type->etype != tptr)
+ fatal("bad OADDPTR left type %E for %N", l->type->etype, n->left);
+ if(r->type->etype != TUINTPTR)
+ fatal("bad OADDPTR right type %E for %N", r->type->etype, n->right);
+ n->type = types[tptr];
+ goto ret;
+
case OADD:
case OAND:
case OANDAND:
@@ -654,8 +667,20 @@ reswitch:
if(iscmp[n->op]) {
n->etype = n->op;
n->op = OCMPSTR;
- } else if(n->op == OADD)
+ } else if(n->op == OADD) {
+ // create OADDSTR node with list of strings in x + y + z + (w + v) + ...
n->op = OADDSTR;
+ if(l->op == OADDSTR)
+ n->list = l->list;
+ else
+ n->list = list1(l);
+ if(r->op == OADDSTR)
+ n->list = concat(n->list, r->list);
+ else
+ n->list = list(n->list, r);
+ n->left = N;
+ n->right = N;
+ }
}
if(et == TINTER) {
if(l->op == OLITERAL && l->val.ctype == CTNIL) {
@@ -721,8 +746,11 @@ reswitch:
if(n->left->type == T)
goto error;
checklvalue(n->left, "take the address of");
- for(l=n->left; l->op == ODOT; l=l->left)
+ r = outervalue(n->left);
+ for(l = n->left; l != r; l = l->left)
l->addrtaken = 1;
+ if(l->orig != l && l->op == ONAME)
+ fatal("found non-orig name node %N", l);
l->addrtaken = 1;
defaultlit(&n->left, T);
l = n->left;
@@ -864,7 +892,7 @@ reswitch:
goto error;
switch(t->etype) {
default:
- yyerror("invalid operation: %N (index of type %T)", n, t);
+ yyerror("invalid operation: %N (type %T does not support indexing)", n, t);
goto error;
@@ -947,7 +975,7 @@ reswitch:
r = n->right;
if(r->type == T)
goto error;
- r = assignconv(r, l->type->type, "send");
+ n->right = assignconv(r, l->type->type, "send");
// TODO: more aggressive
n->etype = 0;
n->type = T;
@@ -1062,6 +1090,7 @@ reswitch:
goto reswitch;
}
typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc));
+ n->diag |= n->left->diag;
l = n->left;
if(l->op == ONAME && l->etype != 0) {
if(n->isddd && l->etype != OAPPEND)
@@ -1123,7 +1152,11 @@ reswitch:
}
break;
}
- typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, "function argument");
+ if(snprint(descbuf, sizeof descbuf, "argument to %N", n->left) < sizeof descbuf)
+ desc = descbuf;
+ else
+ desc = "function argument";
+ typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, desc);
ok |= Etop;
if(t->outtuple == 0)
goto ret;
@@ -1209,17 +1242,29 @@ reswitch:
case OCOMPLEX:
ok |= Erv;
- if(twoarg(n) < 0)
- goto error;
- l = typecheck(&n->left, Erv | (top & Eiota));
- r = typecheck(&n->right, Erv | (top & Eiota));
- if(l->type == T || r->type == T)
- goto error;
- defaultlit2(&l, &r, 0);
- if(l->type == T || r->type == T)
- goto error;
- n->left = l;
- n->right = r;
+ if(count(n->list) == 1) {
+ typechecklist(n->list, Efnstruct);
+ t = n->list->n->left->type;
+ if(t->outtuple != 2) {
+ yyerror("invalid operation: complex expects two arguments, %N returns %d results", n->list->n, t->outtuple);
+ goto error;
+ }
+ t = n->list->n->type->type;
+ l = t->nname;
+ r = t->down->nname;
+ } else {
+ if(twoarg(n) < 0)
+ goto error;
+ l = typecheck(&n->left, Erv | (top & Eiota));
+ r = typecheck(&n->right, Erv | (top & Eiota));
+ if(l->type == T || r->type == T)
+ goto error;
+ defaultlit2(&l, &r, 0);
+ if(l->type == T || r->type == T)
+ goto error;
+ n->left = l;
+ n->right = r;
+ }
if(!eqtype(l->type, r->type)) {
yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
goto error;
@@ -1298,9 +1343,22 @@ reswitch:
yyerror("missing arguments to append");
goto error;
}
- typechecklist(args, Erv);
+
+ if(count(args) == 1 && !n->isddd)
+ typecheck(&args->n, Erv | Efnstruct);
+ else
+ typechecklist(args, Erv);
+
if((t = args->n->type) == T)
goto error;
+
+ // Unpack multiple-return result before type-checking.
+ if(istype(t, TSTRUCT)) {
+ t = t->type;
+ if(istype(t, TFIELD))
+ t = t->type;
+ }
+
n->type = t;
if(!isslice(t)) {
if(isconst(args->n, CTNIL)) {
@@ -1355,6 +1413,8 @@ reswitch:
goto error;
defaultlit(&n->left, T);
defaultlit(&n->right, T);
+ if(n->left->type == T || n->right->type == T)
+ goto error;
// copy([]byte, string)
if(isslice(n->left->type) && n->right->type->etype == TSTRING) {
@@ -1406,6 +1466,9 @@ reswitch:
}
break;
case OSTRARRAYBYTE:
+ // do not use stringtoarraylit.
+ // generated code and compiler memory footprint is better without it.
+ break;
case OSTRARRAYRUNE:
if(n->left->op == OLITERAL)
stringtoarraylit(&n);
@@ -1621,6 +1684,7 @@ reswitch:
case OGOTO:
case OLABEL:
case OXFALL:
+ case OVARKILL:
ok |= Etop;
goto ret;
@@ -2116,6 +2180,31 @@ nokeys(NodeList *l)
return 1;
}
+static int
+hasddd(Type *t)
+{
+ Type *tl;
+
+ for(tl=t->type; tl; tl=tl->down) {
+ if(tl->isddd)
+ return 1;
+ }
+ return 0;
+}
+
+static int
+downcount(Type *t)
+{
+ Type *tl;
+ int n;
+
+ n = 0;
+ for(tl=t->type; tl; tl=tl->down) {
+ n++;
+ }
+ return n;
+}
+
/*
* typecheck assignment: type list = expression list
*/
@@ -2126,14 +2215,25 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *
Node *n;
int lno;
char *why;
+ int n1, n2;
lno = lineno;
if(tstruct->broke)
goto out;
+ n = N;
if(nl != nil && nl->next == nil && (n = nl->n)->type != T)
if(n->type->etype == TSTRUCT && n->type->funarg) {
+ if(!hasddd(tstruct)) {
+ n1 = downcount(tstruct);
+ n2 = downcount(n->type);
+ if(n2 > n1)
+ goto toomany;
+ if(n2 < n1)
+ goto notenough;
+ }
+
tn = n->type->type;
for(tl=tstruct->type; tl; tl=tl->down) {
if(tl->isddd) {
@@ -2162,6 +2262,26 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *
goto out;
}
+ n1 = downcount(tstruct);
+ n2 = count(nl);
+ if(!hasddd(tstruct)) {
+ if(n2 > n1)
+ goto toomany;
+ if(n2 < n1)
+ goto notenough;
+ }
+ else {
+ if(!isddd) {
+ if(n2 < n1-1)
+ goto notenough;
+ } else {
+ if(n2 > n1)
+ goto toomany;
+ if(n2 < n1)
+ goto notenough;
+ }
+ }
+
for(tl=tstruct->type; tl; tl=tl->down) {
t = tl->type;
if(tl->isddd) {
@@ -2206,10 +2326,14 @@ out:
return;
notenough:
- if(call != N)
- yyerror("not enough arguments in call to %N", call);
- else
- yyerror("not enough arguments to %O", op);
+ if(n == N || !n->diag) {
+ if(call != N)
+ yyerror("not enough arguments in call to %N", call);
+ else
+ yyerror("not enough arguments to %O", op);
+ if(n != N)
+ n->diag = 1;
+ }
goto out;
toomany:
@@ -2252,10 +2376,13 @@ keydup(Node *n, Node *hash[], ulong nhash)
ulong b;
double d;
int i;
- Node *a;
+ Node *a, *orign;
Node cmp;
char *s;
+ orign = n;
+ if(n->op == OCONVIFACE)
+ n = n->left;
evconst(n);
if(n->op != OLITERAL)
return; // we dont check variables
@@ -2288,17 +2415,25 @@ keydup(Node *n, Node *hash[], ulong nhash)
for(a=hash[h]; a!=N; a=a->ntest) {
cmp.op = OEQ;
cmp.left = n;
- cmp.right = a;
- evconst(&cmp);
- b = cmp.val.u.bval;
+ b = 0;
+ if(a->op == OCONVIFACE && orign->op == OCONVIFACE) {
+ if(eqtype(a->left->type, n->type)) {
+ cmp.right = a->left;
+ evconst(&cmp);
+ b = cmp.val.u.bval;
+ }
+ } else if(eqtype(a->type, n->type)) {
+ cmp.right = a;
+ evconst(&cmp);
+ b = cmp.val.u.bval;
+ }
if(b) {
- // too lazy to print the literal
yyerror("duplicate key %N in map literal", n);
return;
}
}
- n->ntest = hash[h];
- hash[h] = n;
+ orign->ntest = hash[h];
+ hash[h] = orign;
}
static void
@@ -2486,8 +2621,9 @@ typecheckcomplit(Node **np)
typecheck(&l->left, Erv);
evconst(l->left);
i = nonnegconst(l->left);
- if(i < 0) {
+ if(i < 0 && !l->left->diag) {
yyerror("array index must be non-negative integer constant");
+ l->left->diag = 1;
i = -(1<<30); // stay negative for a while
}
if(i >= 0)
@@ -2497,7 +2633,7 @@ typecheckcomplit(Node **np)
len = i;
if(t->bound >= 0 && len > t->bound) {
setlineno(l);
- yyerror("array index %d out of bounds [0:%d]", len, t->bound);
+ yyerror("array index %lld out of bounds [0:%lld]", len-1, t->bound);
t->bound = -1; // no more errors
}
}
@@ -2680,6 +2816,11 @@ checkassign(Node *n)
n->etype = 1;
return;
}
+
+ // have already complained about n being undefined
+ if(n->op == ONONAME)
+ return;
+
yyerror("cannot assign to %N", n);
}
@@ -2804,7 +2945,7 @@ typecheckas2(Node *n)
n->op = OAS2FUNC;
t = structfirst(&s, &r->type);
for(ll=n->list; ll; ll=ll->next) {
- if(ll->n->type != T)
+ if(t->type != T && ll->n->type != T)
checkassignto(t->type, ll->n);
if(ll->n->defn == n && ll->n->ntype == N)
ll->n->type = t->type;
@@ -3130,7 +3271,10 @@ typecheckdef(Node *n)
goto ret;
}
if(e->type != T && e->op != OLITERAL || !isgoconst(e)) {
- yyerror("const initializer %N is not a constant", e);
+ if(!e->diag) {
+ yyerror("const initializer %N is not a constant", e);
+ e->diag = 1;
+ }
goto ret;
}
t = n->type;
@@ -3220,29 +3364,38 @@ static int
checkmake(Type *t, char *arg, Node *n)
{
if(n->op == OLITERAL) {
- n->val = toint(n->val);
- if(mpcmpfixc(n->val.u.xval, 0) < 0) {
- yyerror("negative %s argument in make(%T)", arg, t);
- return -1;
- }
- if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) {
- yyerror("%s argument too large in make(%T)", arg, t);
- return -1;
+ switch(n->val.ctype) {
+ case CTINT:
+ case CTRUNE:
+ case CTFLT:
+ case CTCPLX:
+ n->val = toint(n->val);
+ if(mpcmpfixc(n->val.u.xval, 0) < 0) {
+ yyerror("negative %s argument in make(%T)", arg, t);
+ return -1;
+ }
+ if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) {
+ yyerror("%s argument too large in make(%T)", arg, t);
+ return -1;
+ }
+
+ // Delay defaultlit until after we've checked range, to avoid
+ // a redundant "constant NNN overflows int" error.
+ defaultlit(&n, types[TINT]);
+ return 0;
+ default:
+ break;
}
-
- // Delay defaultlit until after we've checked range, to avoid
- // a redundant "constant NNN overflows int" error.
- defaultlit(&n, types[TINT]);
- return 0;
}
-
- // Defaultlit still necessary for non-constant: n might be 1<<k.
- defaultlit(&n, types[TINT]);
- if(!isint[n->type->etype]) {
+ if(!isint[n->type->etype] && n->type->etype != TIDEAL) {
yyerror("non-integer %s argument in make(%T) - %T", arg, t, n->type);
return -1;
}
+
+ // Defaultlit still necessary for non-constant: n might be 1<<k.
+ defaultlit(&n, types[TINT]);
+
return 0;
}
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 66409d530..1cb25512e 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -21,7 +21,7 @@ static NodeList* reorder3(NodeList*);
static Node* addstr(Node*, NodeList**);
static Node* appendslice(Node*, NodeList**);
static Node* append(Node*, NodeList**);
-static Node* copyany(Node*, NodeList**);
+static Node* copyany(Node*, NodeList**, int);
static Node* sliceany(Node*, NodeList**);
static void walkcompare(Node**, NodeList**);
static void walkrotate(Node**);
@@ -163,7 +163,6 @@ walkstmt(Node **np)
case OCALLFUNC:
case ODELETE:
case OSEND:
- case ORECV:
case OPRINT:
case OPRINTN:
case OPANIC:
@@ -179,6 +178,21 @@ walkstmt(Node **np)
n->op = OEMPTY; // don't leave plain values as statements.
break;
+ case ORECV:
+ // special case for a receive where we throw away
+ // the value received.
+ if(n->typecheck == 0)
+ fatal("missing typecheck: %+N", n);
+ init = n->ninit;
+ n->ninit = nil;
+
+ walkexpr(&n->left, &init);
+ n = mkcall1(chanfn("chanrecv1", 2, n->left->type), T, &init, typename(n->left->type), n->left, nodnil());
+ walkexpr(&n, &init);
+
+ addinit(&n, init);
+ break;
+
case OBREAK:
case ODCL:
case OCONTINUE:
@@ -188,6 +202,7 @@ walkstmt(Node **np)
case ODCLCONST:
case ODCLTYPE:
case OCHECKNIL:
+ case OVARKILL:
break;
case OBLOCK:
@@ -209,6 +224,9 @@ walkstmt(Node **np)
walkexprlist(n->left->list, &n->ninit);
n->left = walkprint(n->left, &n->ninit, 1);
break;
+ case OCOPY:
+ n->left = copyany(n->left, &n->ninit, 1);
+ break;
default:
walkexpr(&n->left, &n->ninit);
break;
@@ -240,6 +258,9 @@ walkstmt(Node **np)
walkexprlist(n->left->list, &n->ninit);
n->left = walkprint(n->left, &n->ninit, 1);
break;
+ case OCOPY:
+ n->left = copyany(n->left, &n->ninit, 1);
+ break;
default:
walkexpr(&n->left, &n->ninit);
break;
@@ -341,7 +362,8 @@ void
walkexpr(Node **np, NodeList **init)
{
Node *r, *l, *var, *a;
- NodeList *ll, *lr, *lpost;
+ Node *map, *key;
+ NodeList *ll, *lr;
Type *t;
int et, old_safemode;
int64 v;
@@ -455,7 +477,6 @@ walkexpr(Node **np, NodeList **init)
case ORSH:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
- shiftwalked:
t = n->left->type;
n->bounded = bounded(n->right, 8*t->width);
if(debug['m'] && n->etype && !isconst(n->right, CTINT))
@@ -472,6 +493,11 @@ walkexpr(Node **np, NodeList **init)
case OADD:
case OCOMPLEX:
case OLROT:
+ // Use results from call expression as arguments for complex.
+ if(n->op == OCOMPLEX && n->left == N && n->right == N) {
+ n->left = n->list->n;
+ n->right = n->list->next->n;
+ }
walkexpr(&n->left, init);
walkexpr(&n->right, init);
goto ret;
@@ -576,13 +602,32 @@ walkexpr(Node **np, NodeList **init)
case OAS:
*init = concat(*init, n->ninit);
n->ninit = nil;
+
walkexpr(&n->left, init);
n->left = safeexpr(n->left, init);
if(oaslit(n, init))
goto ret;
- walkexpr(&n->right, init);
+ if(n->right == N)
+ goto ret;
+
+ switch(n->right->op) {
+ default:
+ walkexpr(&n->right, init);
+ break;
+
+ case ORECV:
+ // x = <-c; n->left is x, n->right->left is c.
+ // orderstmt made sure x is addressable.
+ walkexpr(&n->right->left, init);
+ n1 = nod(OADDR, n->left, N);
+ r = n->right->left; // the channel
+ n = mkcall1(chanfn("chanrecv1", 2, r->type), T, init, typename(r->type), r, n1);
+ walkexpr(&n, init);
+ goto ret;
+ }
+
if(n->left != N && n->right != N) {
r = convas(nod(OAS, n->left, n->right), init);
r->dodata = n->dodata;
@@ -602,53 +647,35 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OAS2FUNC:
- as2func:
// a,b,... = fn()
*init = concat(*init, n->ninit);
n->ninit = nil;
r = n->rlist->n;
walkexprlistsafe(n->list, init);
walkexpr(&r, init);
- l = n->list->n;
-
- // all the really hard stuff - explicit function calls and so on -
- // is gone, but map assignments remain.
- // if there are map assignments here, assign via
- // temporaries, because ascompatet assumes
- // the targets can be addressed without function calls
- // and map index has an implicit one.
- lpost = nil;
- if(l->op == OINDEXMAP) {
- var = temp(l->type);
- n->list->n = var;
- a = nod(OAS, l, var);
- typecheck(&a, Etop);
- lpost = list(lpost, a);
- }
- l = n->list->next->n;
- if(l->op == OINDEXMAP) {
- var = temp(l->type);
- n->list->next->n = var;
- a = nod(OAS, l, var);
- typecheck(&a, Etop);
- lpost = list(lpost, a);
- }
+
ll = ascompatet(n->op, n->list, &r->type, 0, init);
- walkexprlist(lpost, init);
- n = liststmt(concat(concat(list1(r), ll), lpost));
+ n = liststmt(concat(list1(r), ll));
goto ret;
case OAS2RECV:
+ // x, y = <-c
+ // orderstmt made sure x is addressable.
*init = concat(*init, n->ninit);
n->ninit = nil;
r = n->rlist->n;
walkexprlistsafe(n->list, init);
walkexpr(&r->left, init);
+ if(isblank(n->list->n))
+ n1 = nodnil();
+ else
+ n1 = nod(OADDR, n->list->n, N);
+ n1->etype = 1; // addr does not escape
fn = chanfn("chanrecv2", 2, r->left->type);
- r = mkcall1(fn, getoutargx(fn->type), init, typename(r->left->type), r->left);
- n->rlist->n = r;
- n->op = OAS2FUNC;
- goto as2func;
+ r = mkcall1(fn, types[TBOOL], init, typename(r->left->type), r->left, n1);
+ n = nod(OAS, n->list->next->n, r);
+ typecheck(&n, Etop);
+ goto ret;
case OAS2MAPR:
// a,b = m[i];
@@ -657,6 +684,7 @@ walkexpr(Node **np, NodeList **init)
r = n->rlist->n;
walkexprlistsafe(n->list, init);
walkexpr(&r->left, init);
+ walkexpr(&r->right, init);
t = r->left->type;
p = nil;
if(t->type->width <= 128) { // Check ../../pkg/runtime/hashmap.c:MAXVALUESIZE before changing.
@@ -675,41 +703,50 @@ walkexpr(Node **np, NodeList **init)
}
}
if(p != nil) {
- // from:
- // a,b = m[i]
- // to:
- // var,b = mapaccess2_fast*(t, m, i)
- // a = *var
- a = n->list->n;
- var = temp(ptrto(t->type));
- var->typecheck = 1;
-
- fn = mapfn(p, t);
- r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, r->right);
- n->rlist = list1(r);
- n->op = OAS2FUNC;
- n->list->n = var;
- walkexpr(&n, init);
- *init = list(*init, n);
-
- n = nod(OAS, a, nod(OIND, var, N));
- typecheck(&n, Etop);
- walkexpr(&n, init);
- goto ret;
- }
- fn = mapfn("mapaccess2", t);
- r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, r->right);
+ // fast versions take key by value
+ key = r->right;
+ } else {
+ // standard version takes key by reference
+ // orderexpr made sure key is addressable.
+ key = nod(OADDR, r->right, N);
+ p = "mapaccess2";
+ }
+
+ // from:
+ // a,b = m[i]
+ // to:
+ // var,b = mapaccess2*(t, m, i)
+ // a = *var
+ a = n->list->n;
+ var = temp(ptrto(t->type));
+ var->typecheck = 1;
+ fn = mapfn(p, t);
+ r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, key);
n->rlist = list1(r);
n->op = OAS2FUNC;
- goto as2func;
+ n->list->n = var;
+ walkexpr(&n, init);
+ *init = list(*init, n);
+ n = nod(OAS, a, nod(OIND, var, N));
+ typecheck(&n, Etop);
+ walkexpr(&n, init);
+ // mapaccess needs a zero value to be at least this big.
+ if(zerosize < t->type->width)
+ zerosize = t->type->width;
+ // TODO: ptr is always non-nil, so disable nil check for this OIND op.
+ goto ret;
case ODELETE:
*init = concat(*init, n->ninit);
n->ninit = nil;
- l = n->list->n;
- r = n->list->next->n;
- t = l->type;
- n = mkcall1(mapfndel("mapdelete", t), t->down, init, typename(t), l, r);
+ map = n->list->n;
+ key = n->list->next->n;
+ walkexpr(&map, init);
+ walkexpr(&key, init);
+ // orderstmt made sure key is addressable.
+ key = nod(OADDR, key, N);
+ t = map->type;
+ n = mkcall1(mapfndel("mapdelete", t), T, init, typename(t), map, key);
goto ret;
case OAS2DOTTYPE:
@@ -872,7 +909,20 @@ walkexpr(Node **np, NodeList **init)
goto ret;
}
}
- ll = list(ll, n->left);
+ if(isinter(n->left->type)) {
+ ll = list(ll, n->left);
+ } else {
+ // regular types are passed by reference to avoid C vararg calls
+ // orderexpr arranged for n->left to be a temporary for all
+ // the conversions it could see. comparison of an interface
+ // with a non-interface, especially in a switch on interface value
+ // with non-interface cases, is not visible to orderstmt, so we
+ // have to fall back on allocating a temp here.
+ if(islvalue(n->left))
+ ll = list(ll, nod(OADDR, n->left, N));
+ else
+ ll = list(ll, nod(OADDR, copyexpr(n->left, n->left->type, init), N));
+ }
argtype(fn, n->left->type);
argtype(fn, n->type);
dowidth(fn->type);
@@ -909,51 +959,6 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init);
goto ret;
- case OASOP:
- if(n->etype == OANDNOT) {
- n->etype = OAND;
- n->right = nod(OCOM, n->right, N);
- typecheck(&n->right, Erv);
- }
- n->left = safeexpr(n->left, init);
- walkexpr(&n->left, init);
- l = n->left;
- walkexpr(&n->right, init);
-
- /*
- * on 32-bit arch, rewrite 64-bit ops into l = l op r.
- * on 386, rewrite float ops into l = l op r.
- * everywhere, rewrite map ops into l = l op r.
- * everywhere, rewrite string += into l = l op r.
- * everywhere, rewrite integer/complex /= into l = l op r.
- * TODO(rsc): Maybe this rewrite should be done always?
- */
- et = n->left->type->etype;
- if((widthptr == 4 && (et == TUINT64 || et == TINT64)) ||
- (thechar == '8' && isfloat[et]) ||
- l->op == OINDEXMAP ||
- et == TSTRING ||
- (!isfloat[et] && n->etype == ODIV) ||
- n->etype == OMOD) {
- l = safeexpr(n->left, init);
- a = l;
- if(a->op == OINDEXMAP) {
- // map index has "lhs" bit set in a->etype.
- // make a copy so we can clear it on the rhs.
- a = nod(OXXX, N, N);
- *a = *l;
- a->etype = 0;
- }
- r = nod(OAS, l, nod(n->etype, a, n->right));
- typecheck(&r, Etop);
- walkexpr(&r, init);
- n = r;
- goto ret;
- }
- if(n->etype == OLSH || n->etype == ORSH)
- goto shiftwalked;
- goto ret;
-
case OANDNOT:
walkexpr(&n->left, init);
n->op = OAND;
@@ -998,7 +1003,7 @@ walkexpr(Node **np, NodeList **init)
switch(n->op) {
case OMOD:
case ODIV:
- if(widthptr > 4 || (et != TUINT64 && et != TINT64))
+ if(widthreg >= 8 || (et != TUINT64 && et != TINT64))
goto ret;
if(et == TINT64)
strcpy(namebuf, "int64");
@@ -1063,6 +1068,8 @@ walkexpr(Node **np, NodeList **init)
case OINDEXMAP:
if(n->etype == 1)
goto ret;
+ walkexpr(&n->left, init);
+ walkexpr(&n->right, init);
t = n->left->type;
p = nil;
@@ -1082,23 +1089,25 @@ walkexpr(Node **np, NodeList **init)
}
}
if(p != nil) {
- // use fast version. The fast versions return a pointer to the value - we need
- // to dereference it to get the result.
- n = mkcall1(mapfn(p, t), ptrto(t->type), init, typename(t), n->left, n->right);
- n = nod(OIND, n, N);
- n->type = t->type;
- n->typecheck = 1;
+ // fast versions take key by value
+ key = n->right;
} else {
- // no fast version for this key
- n = mkcall1(mapfn("mapaccess1", t), t->type, init, typename(t), n->left, n->right);
- }
+ // standard version takes key by reference.
+ // orderexpr made sure key is addressable.
+ key = nod(OADDR, n->right, N);
+ p = "mapaccess1";
+ }
+ n = mkcall1(mapfn(p, t), ptrto(t->type), init, typename(t), n->left, key);
+ n = nod(OIND, n, N);
+ n->type = t->type;
+ n->typecheck = 1;
+ // mapaccess needs a zero value to be at least this big.
+ if(zerosize < t->type->width)
+ zerosize = t->type->width;
goto ret;
case ORECV:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- n = mkcall1(chanfn("chanrecv1", 2, n->left->type), n->type, init, typename(n->left->type), n->left);
- goto ret;
+ fatal("walkexpr ORECV"); // should see inside OAS only
case OSLICE:
if(n->right != N && n->right->left == N && n->right->right == N) { // noop
@@ -1182,9 +1191,10 @@ walkexpr(Node **np, NodeList **init)
// s + "badgerbadgerbadger" == "badgerbadgerbadger"
if((n->etype == OEQ || n->etype == ONE) &&
isconst(n->right, CTSTR) &&
- n->left->op == OADDSTR && isconst(n->left->right, CTSTR) &&
- cmpslit(n->right, n->left->right) == 0) {
- r = nod(n->etype, nod(OLEN, n->left->left, N), nodintconst(0));
+ n->left->op == OADDSTR && count(n->left->list) == 2 &&
+ isconst(n->left->list->next->n, CTSTR) &&
+ cmpslit(n->right, n->left->list->next->n) == 0) {
+ r = nod(n->etype, nod(OLEN, n->left->list->n, N), nodintconst(0));
typecheck(&r, Erv);
walkexpr(&r, init);
r->type = n->type;
@@ -1238,19 +1248,7 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OCOPY:
- if(flag_race) {
- if(n->right->type->etype == TSTRING)
- fn = syslook("slicestringcopy", 1);
- else
- fn = syslook("copy", 1);
- argtype(fn, n->left->type);
- argtype(fn, n->right->type);
- n = mkcall1(fn, n->type, init,
- n->left, n->right,
- nodintconst(n->left->type->type->width));
- goto ret;
- }
- n = copyany(n, init);
+ n = copyany(n, init, flag_race);
goto ret;
case OCLOSE:
@@ -1321,6 +1319,11 @@ walkexpr(Node **np, NodeList **init)
n = mkcall("slicebytetostring", n->type, init, n->left);
goto ret;
+ case OARRAYBYTESTRTMP:
+ // slicebytetostringtmp([]byte) string;
+ n = mkcall("slicebytetostringtmp", n->type, init, n->left);
+ goto ret;
+
case OARRAYRUNESTR:
// slicerunetostring([]rune) string;
n = mkcall("slicerunetostring", n->type, init, n->left);
@@ -1368,13 +1371,18 @@ walkexpr(Node **np, NodeList **init)
case OMAPLIT:
case OSTRUCTLIT:
case OPTRLIT:
+ // XXX TODO do we need to clear var?
var = temp(n->type);
anylit(0, n, var, init);
n = var;
goto ret;
case OSEND:
- n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n->right);
+ n1 = n->right;
+ n1 = assignconv(n1, n->left->type->type, "chan send");
+ walkexpr(&n1, init);
+ n1 = nod(OADDR, n1, N);
+ n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n1);
goto ret;
case OCLOSURE:
@@ -1534,11 +1542,16 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
* package all the arguments that match a ... T parameter into a []T.
*/
static NodeList*
-mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, int esc)
+mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, Node *ddd)
{
Node *a, *n;
Type *tslice;
-
+ int esc;
+
+ esc = EscUnknown;
+ if(ddd != nil)
+ esc = ddd->esc;
+
tslice = typ(TARRAY);
tslice->type = l->type->type;
tslice->bound = -1;
@@ -1548,6 +1561,8 @@ mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, int
n->type = tslice;
} else {
n = nod(OCOMPLIT, N, typenod(tslice));
+ if(ddd != nil)
+ n->alloc = ddd->alloc; // temporary to use
n->list = lr0;
n->esc = esc;
typecheck(&n, Erv);
@@ -1619,7 +1634,6 @@ dumpnodetypes(NodeList *l, char *what)
static NodeList*
ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
{
- int esc;
Type *l, *ll;
Node *r, *a;
NodeList *nn, *lr0, *alist;
@@ -1638,7 +1652,8 @@ ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeL
// optimization - can do block copy
if(eqtypenoname(r->type, *nl)) {
a = nodarg(*nl, fp);
- a->type = r->type;
+ r = nod(OCONVNOP, r, N);
+ r->type = a->type;
nn = list1(convas(nod(OAS, a, r), init));
goto ret;
}
@@ -1682,10 +1697,7 @@ loop:
// normal case -- make a slice of all
// remaining arguments and pass it to
// the ddd parameter.
- esc = EscUnknown;
- if(call->right)
- esc = call->right->esc;
- nn = mkdotargslice(lr, nn, l, fp, init, esc);
+ nn = mkdotargslice(lr, nn, l, fp, init, call->right);
goto ret;
}
@@ -1911,6 +1923,7 @@ static Node*
convas(Node *n, NodeList **init)
{
Type *lt, *rt;
+ Node *map, *key, *val;
if(n->op != OAS)
fatal("convas: not OAS %O", n->op);
@@ -1931,9 +1944,17 @@ convas(Node *n, NodeList **init)
}
if(n->left->op == OINDEXMAP) {
- n = mkcall1(mapfn("mapassign1", n->left->left->type), T, init,
- typename(n->left->left->type),
- n->left->left, n->left->right, n->right);
+ map = n->left->left;
+ key = n->left->right;
+ val = n->right;
+ walkexpr(&map, init);
+ walkexpr(&key, init);
+ walkexpr(&val, init);
+ // orderexpr made sure key and val are addressable.
+ key = nod(OADDR, key, N);
+ val = nod(OADDR, val, N);
+ n = mkcall1(mapfn("mapassign1", map->type), T, init,
+ typename(map->type), map, key, val);
goto out;
}
@@ -2101,7 +2122,7 @@ reorder3save(Node **np, NodeList *all, NodeList *stop, NodeList **early)
* what's the outer value that a write to n affects?
* outer value means containing struct or array.
*/
-static Node*
+Node*
outervalue(Node *n)
{
for(;;) {
@@ -2320,7 +2341,7 @@ paramstoheap(Type **argin, int out)
nn = nil;
for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
v = t->nname;
- if(v && v->sym && v->sym->name[0] == '~')
+ if(v && v->sym && v->sym->name[0] == '~' && v->sym->name[1] == 'r') // unnamed result
v = N;
// In precisestack mode, the garbage collector assumes results
// are always live, so zero them always.
@@ -2493,33 +2514,38 @@ mapfndel(char *name, Type *t)
static Node*
addstr(Node *n, NodeList **init)
{
- Node *r, *cat, *typstr;
- NodeList *in, *args;
- int i, count;
-
- count = 0;
- for(r=n; r->op == OADDSTR; r=r->left)
- count++; // r->right
- count++; // r
-
- // prepare call of runtime.catstring of type int, string, string, string
- // with as many strings as we have.
- cat = syslook("concatstring", 1);
- cat->type = T;
- cat->ntype = nod(OTFUNC, N, N);
- in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // count
- typstr = typenod(types[TSTRING]);
- for(i=0; i<count; i++)
- in = list(in, nod(ODCLFIELD, N, typstr));
- cat->ntype->list = in;
- cat->ntype->rlist = list1(nod(ODCLFIELD, N, typstr));
+ Node *r, *cat, *slice;
+ NodeList *args, *l;
+ int c;
+ Type *t;
+
+ // orderexpr rewrote OADDSTR to have a list of strings.
+ c = count(n->list);
+ if(c < 2)
+ yyerror("addstr count %d too small", c);
+ // build list of string arguments
args = nil;
- for(r=n; r->op == OADDSTR; r=r->left)
- args = concat(list1(conv(r->right, types[TSTRING])), args);
- args = concat(list1(conv(r, types[TSTRING])), args);
- args = concat(list1(nodintconst(count)), args);
+ for(l=n->list; l != nil; l=l->next)
+ args = list(args, conv(l->n, types[TSTRING]));
+ if(c <= 5) {
+ // small numbers of strings use direct runtime helpers.
+ // note: orderexpr knows this cutoff too.
+ snprint(namebuf, sizeof(namebuf), "concatstring%d", c);
+ } else {
+ // large numbers of strings are passed to the runtime as a slice.
+ strcpy(namebuf, "concatstrings");
+ t = typ(TARRAY);
+ t->type = types[TSTRING];
+ t->bound = -1;
+ slice = nod(OCOMPLIT, N, typenod(t));
+ slice->alloc = n->alloc;
+ slice->list = args;
+ slice->esc = EscNone;
+ args = list1(slice);
+ }
+ cat = syslook(namebuf, 1);
r = nod(OCALL, cat, N);
r->list = args;
typecheck(&r, Erv);
@@ -2597,9 +2623,10 @@ appendslice(Node *n, NodeList **init)
fn = syslook("copy", 1);
argtype(fn, l1->type);
argtype(fn, l2->type);
- l = list(l, mkcall1(fn, types[TINT], init,
+ nt = mkcall1(fn, types[TINT], &l,
nptr1, nptr2,
- nodintconst(s->type->type->width)));
+ nodintconst(s->type->type->width));
+ l = list(l, nt);
} else {
// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
nptr1 = nod(OINDEX, s, nod(OLEN, l1, N));
@@ -2614,7 +2641,8 @@ appendslice(Node *n, NodeList **init)
nwid = cheapexpr(conv(nod(OLEN, l2, N), types[TUINTPTR]), &l);
nwid = nod(OMUL, nwid, nodintconst(s->type->type->width));
- l = list(l, mkcall1(fn, T, init, nptr1, nptr2, nwid));
+ nt = mkcall1(fn, T, &l, nptr1, nptr2, nwid);
+ l = list(l, nt);
}
// s = s[:len(l1)+len(l2)]
@@ -2660,6 +2688,10 @@ append(Node *n, NodeList **init)
l->n = cheapexpr(l->n, init);
nsrc = n->list->n;
+
+ // Resolve slice type of multi-valued return.
+ if(istype(nsrc->type, TSTRUCT))
+ nsrc->type = nsrc->type->type->type;
argc = count(n->list) - 1;
if (argc < 1) {
return nsrc;
@@ -2705,7 +2737,7 @@ append(Node *n, NodeList **init)
return ns;
}
-// Lower copy(a, b) to a memmove call.
+// Lower copy(a, b) to a memmove call or a runtime call.
//
// init {
// n := len(a)
@@ -2717,11 +2749,22 @@ append(Node *n, NodeList **init)
// Also works if b is a string.
//
static Node*
-copyany(Node *n, NodeList **init)
+copyany(Node *n, NodeList **init, int runtimecall)
{
Node *nl, *nr, *nfrm, *nto, *nif, *nlen, *nwid, *fn;
NodeList *l;
+ if(runtimecall) {
+ if(n->right->type->etype == TSTRING)
+ fn = syslook("slicestringcopy", 1);
+ else
+ fn = syslook("copy", 1);
+ argtype(fn, n->left->type);
+ argtype(fn, n->right->type);
+ return mkcall1(fn, n->type, init,
+ n->left, n->right,
+ nodintconst(n->left->type->type->width));
+ }
walkexpr(&n->left, init);
walkexpr(&n->right, init);
nl = temp(n->left->type);
@@ -2802,17 +2845,13 @@ sliceany(Node* n, NodeList **init)
if(isconst(cb, CTINT)) {
cbv = mpgetfix(cb->val.u.xval);
- if(cbv < 0 || cbv > bv) {
+ if(cbv < 0 || cbv > bv)
yyerror("slice index out of bounds");
- cbv = -1;
- }
}
if(isconst(hb, CTINT)) {
hbv = mpgetfix(hb->val.u.xval);
- if(hbv < 0 || hbv > bv) {
+ if(hbv < 0 || hbv > bv)
yyerror("slice index out of bounds");
- hbv = -1;
- }
}
if(isconst(lb, CTINT)) {
lbv = mpgetfix(lb->val.u.xval);
@@ -3052,13 +3091,10 @@ walkcompare(Node **np, NodeList **init)
}
if(expr == N)
expr = nodbool(n->op == OEQ);
- typecheck(&expr, Erv);
- walkexpr(&expr, init);
- expr->type = n->type;
- *np = expr;
- return;
+ r = expr;
+ goto ret;
}
-
+
if(t->etype == TSTRUCT && countfield(t) <= 4) {
// Struct of four or fewer fields.
// Inline comparisons.
@@ -3075,13 +3111,10 @@ walkcompare(Node **np, NodeList **init)
}
if(expr == N)
expr = nodbool(n->op == OEQ);
- typecheck(&expr, Erv);
- walkexpr(&expr, init);
- expr->type = n->type;
- *np = expr;
- return;
+ r = expr;
+ goto ret;
}
-
+
// Chose not to inline, but still have addresses.
// Call equality function directly.
// The equality function requires a bool pointer for
@@ -3114,10 +3147,7 @@ walkcompare(Node **np, NodeList **init)
if(n->op != OEQ)
r = nod(ONOT, r, N);
- typecheck(&r, Erv);
- walkexpr(&r, init);
- *np = r;
- return;
+ goto ret;
hard:
// Cannot take address of one or both of the operands.
@@ -3133,7 +3163,16 @@ hard:
r = mkcall1(fn, n->type, init, typename(n->left->type), l, r);
if(n->op == ONE) {
r = nod(ONOT, r, N);
- typecheck(&r, Erv);
+ }
+ goto ret;
+
+ret:
+ typecheck(&r, Erv);
+ walkexpr(&r, init);
+ if(r->type != n->type) {
+ r = nod(OCONVNOP, r, N);
+ r->type = n->type;
+ r->typecheck = 1;
}
*np = r;
return;
diff --git a/src/cmd/gc/y.tab.c b/src/cmd/gc/y.tab.c
index 390ad80b3..08d8ecff2 100644
--- a/src/cmd/gc/y.tab.c
+++ b/src/cmd/gc/y.tab.c
@@ -1,21 +1,24 @@
-/* A Bison parser, made by GNU Bison 2.5. */
+/* A Bison parser, made by GNU Bison 2.3. */
-/* Bison implementation for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -26,7 +29,7 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
@@ -44,7 +47,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "2.5"
+#define YYBISON_VERSION "2.3"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -52,52 +55,11 @@
/* Pure parsers. */
#define YYPURE 0
-/* Push parsers. */
-#define YYPUSH 0
-
-/* Pull parsers. */
-#define YYPULL 1
-
/* Using locations. */
#define YYLSP_NEEDED 0
-/* Copy the first part of user declarations. */
-
-/* Line 268 of yacc.c */
-#line 20 "go.y"
-
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */
-#include <libc.h>
-#include "go.h"
-
-static void fixlbrace(int);
-
-
-/* Line 268 of yacc.c */
-#line 81 "y.tab.c"
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 1
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -209,36 +171,61 @@ static void fixlbrace(int);
+/* Copy the first part of user declarations. */
+#line 20 "go.y"
+
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */
+#include <libc.h>
+#include "go.h"
+
+static void fixlbrace(int);
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-{
-
-/* Line 293 of yacc.c */
#line 28 "go.y"
-
+{
Node* node;
NodeList* list;
Type* type;
Sym* sym;
struct Val val;
int i;
-
-
-
-/* Line 293 of yacc.c */
-#line 230 "y.tab.c"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
+}
+/* Line 193 of yacc.c. */
+#line 216 "y.tab.c"
+ YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
+
/* Copy the second part of user declarations. */
-/* Line 343 of yacc.c */
-#line 242 "y.tab.c"
+/* Line 216 of yacc.c. */
+#line 229 "y.tab.c"
#ifdef short
# undef short
@@ -313,14 +300,14 @@ typedef short int yytype_int16;
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static int
-YYID (int yyi)
+YYID (int i)
#else
static int
-YYID (yyi)
- int yyi;
+YYID (i)
+ int i;
#endif
{
- return yyi;
+ return i;
}
#endif
@@ -341,11 +328,11 @@ YYID (yyi)
# define alloca _alloca
# else
# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
# endif
# endif
# endif
@@ -368,24 +355,24 @@ YYID (yyi)
# ifndef YYSTACK_ALLOC_MAXIMUM
# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
# endif
-# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+# if (defined __cplusplus && ! defined _STDLIB_H \
&& ! ((defined YYMALLOC || defined malloc) \
&& (defined YYFREE || defined free)))
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
# endif
# endif
# ifndef YYMALLOC
# define YYMALLOC malloc
-# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
# ifndef YYFREE
# define YYFREE free
-# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void free (void *); /* INFRINGES ON USER NAME SPACE */
# endif
@@ -401,9 +388,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
/* A type that is properly aligned for any stack member. */
union yyalloc
{
- yytype_int16 yyss_alloc;
- YYSTYPE yyvs_alloc;
-};
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
/* The size of the maximum gap between one aligned stack and the next. */
# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
@@ -414,27 +401,6 @@ union yyalloc
((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ YYSTACK_GAP_MAXIMUM)
-# define YYCOPY_NEEDED 1
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
- Stack = &yyptr->Stack_alloc; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
/* Copy COUNT objects from FROM to TO. The source and destination do
not overlap. */
# ifndef YYCOPY
@@ -452,7 +418,24 @@ union yyalloc
while (YYID (0))
# endif
# endif
-#endif /* !YYCOPY_NEEDED */
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 4
@@ -681,36 +664,36 @@ static const yytype_uint16 yyrline[] =
308, 312, 316, 322, 328, 334, 339, 343, 347, 353,
359, 363, 367, 373, 377, 383, 384, 388, 394, 403,
409, 427, 432, 444, 460, 465, 472, 492, 510, 519,
- 538, 537, 552, 551, 582, 585, 592, 591, 602, 608,
- 617, 628, 634, 637, 645, 644, 655, 661, 673, 677,
- 682, 672, 703, 702, 715, 718, 724, 727, 739, 743,
- 738, 761, 760, 776, 777, 781, 785, 789, 793, 797,
- 801, 805, 809, 813, 817, 821, 825, 829, 833, 837,
- 841, 845, 849, 854, 860, 861, 865, 876, 880, 884,
- 888, 893, 897, 907, 911, 916, 924, 928, 929, 940,
- 944, 948, 952, 956, 964, 965, 971, 978, 984, 991,
- 994, 1001, 1007, 1024, 1031, 1032, 1039, 1040, 1059, 1060,
- 1063, 1066, 1070, 1081, 1090, 1096, 1099, 1102, 1109, 1110,
- 1116, 1129, 1144, 1152, 1164, 1169, 1175, 1176, 1177, 1178,
- 1179, 1180, 1186, 1187, 1188, 1189, 1195, 1196, 1197, 1198,
- 1199, 1205, 1206, 1209, 1212, 1213, 1214, 1215, 1216, 1219,
- 1220, 1233, 1237, 1242, 1247, 1252, 1256, 1257, 1260, 1266,
- 1273, 1279, 1286, 1292, 1303, 1317, 1346, 1386, 1411, 1429,
- 1438, 1441, 1449, 1453, 1457, 1464, 1470, 1475, 1487, 1490,
- 1500, 1501, 1507, 1508, 1514, 1518, 1524, 1525, 1531, 1535,
- 1541, 1564, 1569, 1575, 1581, 1588, 1597, 1606, 1621, 1627,
- 1632, 1636, 1643, 1656, 1657, 1663, 1669, 1672, 1676, 1682,
- 1685, 1694, 1697, 1698, 1702, 1703, 1709, 1710, 1711, 1712,
- 1713, 1715, 1714, 1729, 1734, 1738, 1742, 1746, 1750, 1755,
- 1774, 1780, 1788, 1792, 1798, 1802, 1808, 1812, 1818, 1822,
- 1831, 1835, 1839, 1843, 1849, 1852, 1860, 1861, 1863, 1864,
- 1867, 1870, 1873, 1876, 1879, 1882, 1885, 1888, 1891, 1894,
- 1897, 1900, 1903, 1906, 1912, 1916, 1920, 1924, 1928, 1932,
- 1952, 1959, 1970, 1971, 1972, 1975, 1976, 1979, 1983, 1993,
- 1997, 2001, 2005, 2009, 2013, 2017, 2023, 2029, 2037, 2045,
- 2051, 2058, 2074, 2096, 2100, 2106, 2109, 2112, 2116, 2126,
- 2130, 2145, 2153, 2154, 2166, 2167, 2170, 2174, 2180, 2184,
- 2190, 2194
+ 538, 537, 552, 551, 583, 586, 593, 592, 603, 609,
+ 618, 629, 635, 638, 646, 645, 656, 662, 674, 678,
+ 683, 673, 704, 703, 716, 719, 725, 728, 740, 744,
+ 739, 762, 761, 777, 778, 782, 786, 790, 794, 798,
+ 802, 806, 810, 814, 818, 822, 826, 830, 834, 838,
+ 842, 846, 850, 855, 861, 862, 866, 877, 881, 885,
+ 889, 894, 898, 908, 912, 917, 925, 929, 930, 941,
+ 945, 949, 953, 957, 965, 966, 972, 979, 985, 992,
+ 995, 1002, 1008, 1025, 1032, 1033, 1040, 1041, 1060, 1061,
+ 1064, 1067, 1071, 1082, 1091, 1097, 1100, 1103, 1110, 1111,
+ 1117, 1130, 1145, 1153, 1165, 1170, 1176, 1177, 1178, 1179,
+ 1180, 1181, 1187, 1188, 1189, 1190, 1196, 1197, 1198, 1199,
+ 1200, 1206, 1207, 1210, 1213, 1214, 1215, 1216, 1217, 1220,
+ 1221, 1234, 1238, 1243, 1248, 1253, 1257, 1258, 1261, 1267,
+ 1274, 1280, 1287, 1293, 1304, 1318, 1347, 1387, 1412, 1430,
+ 1439, 1442, 1450, 1454, 1458, 1465, 1471, 1476, 1488, 1491,
+ 1501, 1502, 1508, 1509, 1515, 1519, 1525, 1526, 1532, 1536,
+ 1542, 1565, 1570, 1576, 1582, 1589, 1598, 1607, 1622, 1628,
+ 1633, 1637, 1644, 1657, 1658, 1664, 1670, 1673, 1677, 1683,
+ 1686, 1695, 1698, 1699, 1703, 1704, 1710, 1711, 1712, 1713,
+ 1714, 1716, 1715, 1730, 1736, 1740, 1744, 1748, 1752, 1757,
+ 1776, 1782, 1790, 1794, 1800, 1804, 1810, 1814, 1820, 1824,
+ 1833, 1837, 1841, 1845, 1851, 1854, 1862, 1863, 1865, 1866,
+ 1869, 1872, 1875, 1878, 1881, 1884, 1887, 1890, 1893, 1896,
+ 1899, 1902, 1905, 1908, 1914, 1918, 1922, 1926, 1930, 1934,
+ 1954, 1961, 1972, 1973, 1974, 1977, 1978, 1981, 1985, 1995,
+ 1999, 2003, 2007, 2011, 2015, 2019, 2025, 2031, 2039, 2047,
+ 2053, 2060, 2076, 2098, 2102, 2108, 2111, 2114, 2118, 2128,
+ 2132, 2151, 2159, 2160, 2172, 2173, 2176, 2180, 2186, 2190,
+ 2196, 2200
};
#endif
@@ -729,16 +712,16 @@ const char *yytname[] =
"'/'", "'%'", "'&'", "NotPackage", "NotParen", "'('", "')'",
"PreferToRightParen", "';'", "'.'", "'$'", "'='", "':'", "'{'", "'}'",
"'!'", "'~'", "'['", "']'", "'?'", "'@'", "','", "$accept", "file",
- "package", "loadsys", "$@1", "imports", "import", "import_stmt",
+ "package", "loadsys", "@1", "imports", "import", "import_stmt",
"import_stmt_list", "import_here", "import_package", "import_safety",
- "import_there", "$@2", "xdcl", "common_dcl", "lconst", "vardcl",
+ "import_there", "@2", "xdcl", "common_dcl", "lconst", "vardcl",
"constdcl", "constdcl1", "typedclname", "typedcl", "simple_stmt", "case",
- "compound_stmt", "$@3", "caseblock", "$@4", "caseblock_list",
- "loop_body", "$@5", "range_stmt", "for_header", "for_body", "for_stmt",
- "$@6", "if_header", "if_stmt", "$@7", "$@8", "$@9", "elseif", "$@10",
- "elseif_list", "else", "switch_stmt", "$@11", "$@12", "select_stmt",
- "$@13", "expr", "uexpr", "pseudocall", "pexpr_no_paren", "start_complit",
- "keyval", "bare_complitexpr", "complitexpr", "pexpr", "expr_or_type",
+ "compound_stmt", "@3", "caseblock", "@4", "caseblock_list", "loop_body",
+ "@5", "range_stmt", "for_header", "for_body", "for_stmt", "@6",
+ "if_header", "if_stmt", "@7", "@8", "@9", "elseif", "@10", "elseif_list",
+ "else", "switch_stmt", "@11", "@12", "select_stmt", "@13", "expr",
+ "uexpr", "pseudocall", "pexpr_no_paren", "start_complit", "keyval",
+ "bare_complitexpr", "complitexpr", "pexpr", "expr_or_type",
"name_or_type", "lbrace", "new_name", "dcl_name", "onew_name", "sym",
"hidden_importsym", "name", "labelname", "dotdotdot", "ntype",
"non_expr_type", "non_recvchantype", "convtype", "comptype",
@@ -748,7 +731,7 @@ const char *yytname[] =
"vardcl_list", "constdcl_list", "typedcl_list", "structdcl_list",
"interfacedcl_list", "structdcl", "packname", "embed", "interfacedcl",
"indcl", "arg_type", "arg_type_list", "oarg_type_list_ocomma", "stmt",
- "non_dcl_stmt", "$@14", "stmt_list", "new_name_list", "dcl_name_list",
+ "non_dcl_stmt", "@14", "stmt_list", "new_name_list", "dcl_name_list",
"expr_list", "expr_or_type_list", "keyval_list", "braced_keyval_list",
"osemi", "ocomma", "oexpr", "oexpr_list", "osimple_stmt",
"ohidden_funarg_list", "ohidden_structdcl_list",
@@ -861,8 +844,8 @@ static const yytype_uint8 yyr2[] =
1, 3
};
-/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
- Performed when YYTABLE doesn't specify something else to do. Zero
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
means the default is an error. */
static const yytype_uint16 yydefact[] =
{
@@ -1051,7 +1034,8 @@ static const yytype_int16 yypgoto[] =
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
positive, shift that token. If negative, reduce the rule which
- number is the opposite. If YYTABLE_NINF, syntax error. */
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
#define YYTABLE_NINF -277
static const yytype_int16 yytable[] =
{
@@ -1285,12 +1269,6 @@ static const yytype_int16 yytable[] =
198
};
-#define yypact_value_is_default(yystate) \
- ((yystate) == (-474))
-
-#define yytable_value_is_error(yytable_value) \
- YYID (0)
-
static const yytype_int16 yycheck[] =
{
37, 37, 61, 143, 67, 37, 37, 202, 324, 251,
@@ -1608,18 +1586,9 @@ static const yytype_uint8 yystos[] =
/* Like YYERROR except do call yyerror. This remains here temporarily
to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. However,
- YYFAIL appears to be in use. Nevertheless, it is formally deprecated
- in Bison 2.4.2's NEWS entry, where a plan to phase it out is
- discussed. */
+ Once GCC version 2 has supplanted version 1, this can go. */
#define YYFAIL goto yyerrlab
-#if defined YYFAIL
- /* This is here to suppress warnings from the GCC cpp's
- -Wunused-macros. Normally we don't worry about that warning, but
- some users do, and we want to make it easy for users to remove
- YYFAIL uses, which will produce warnings from Bison 2.5. */
-#endif
#define YYRECOVERING() (!!yyerrstatus)
@@ -1629,6 +1598,7 @@ do \
{ \
yychar = (Token); \
yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
YYPOPSTACK (1); \
goto yybackup; \
} \
@@ -1670,10 +1640,19 @@ while (YYID (0))
#endif
-/* This macro is provided for backward compatibility. */
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
#endif
@@ -1777,20 +1756,17 @@ yy_symbol_print (yyoutput, yytype, yyvaluep)
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
#else
static void
-yy_stack_print (yybottom, yytop)
- yytype_int16 *yybottom;
- yytype_int16 *yytop;
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
#endif
{
YYFPRINTF (stderr, "Stack now");
- for (; yybottom <= yytop; yybottom++)
- {
- int yybot = *yybottom;
- YYFPRINTF (stderr, " %d", yybot);
- }
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
YYFPRINTF (stderr, "\n");
}
@@ -1824,11 +1800,11 @@ yy_reduce_print (yyvsp, yyrule)
/* The symbols being reduced. */
for (yyi = 0; yyi < yynrhs; yyi++)
{
- YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ fprintf (stderr, " $%d = ", yyi + 1);
yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
&(yyvsp[(yyi + 1) - (yynrhs)])
);
- YYFPRINTF (stderr, "\n");
+ fprintf (stderr, "\n");
}
}
@@ -1865,6 +1841,7 @@ int yydebug;
# define YYMAXDEPTH 10000
#endif
+
#if YYERROR_VERBOSE
@@ -1967,142 +1944,115 @@ yytnamerr (char *yyres, const char *yystr)
}
# endif
-/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
- about the unexpected token YYTOKEN for the state stack whose top is
- YYSSP.
-
- Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
- not large enough to hold the message. In that case, also set
- *YYMSG_ALLOC to the required number of bytes. Return 2 if the
- required number of bytes is too large to store. */
-static int
-yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
- yytype_int16 *yyssp, int yytoken)
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
{
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- /* Internationalized format string. */
- const char *yyformat = 0;
- /* Arguments of yyformat. */
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- /* Number of reported tokens (one for the "unexpected", one per
- "expected"). */
- int yycount = 0;
-
- /* There are many possibilities here to consider:
- - Assume YYFAIL is not used. It's too flawed to consider. See
- <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
- for details. YYERROR is fine as it does not invoke this
- function.
- - If this state is a consistent state with a default action, then
- the only way this function was invoked is if the default action
- is an error action. In that case, don't check for expected
- tokens because there are none.
- - The only way there can be no lookahead present (in yychar) is if
- this state is a consistent state with a default action. Thus,
- detecting the absence of a lookahead is sufficient to determine
- that there is no unexpected or expected token to report. In that
- case, just report a simple "syntax error".
- - Don't assume there isn't a lookahead just because this state is a
- consistent state with a default action. There might have been a
- previous inconsistent state, consistent state with a non-default
- action, or user semantic action that manipulated yychar.
- - Of course, the expected token list depends on states to have
- correct lookahead information, and it depends on the parser not
- to perform extra reductions after fetching a lookahead from the
- scanner and before detecting a syntax error. Thus, state merging
- (from LALR or IELR) and default reductions corrupt the expected
- token list. However, the list is correct for canonical LR with
- one exception: it will still contain any token that will not be
- accepted due to an error action in a later state.
- */
- if (yytoken != YYEMPTY)
- {
- int yyn = yypact[*yyssp];
- yyarg[yycount++] = yytname[yytoken];
- if (!yypact_value_is_default (yyn))
- {
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. In other words, skip the first -YYN actions for
- this state because they are default actions. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yyx;
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
- && !yytable_value_is_error (yytable[yyx + yyn]))
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- if (! (yysize <= yysize1
- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
- }
- }
- }
+ int yyn = yypact[yystate];
- switch (yycount)
- {
-# define YYCASE_(N, S) \
- case N: \
- yyformat = S; \
- break
- YYCASE_(0, YY_("syntax error"));
- YYCASE_(1, YY_("syntax error, unexpected %s"));
- YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
- YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
- YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
- YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-# undef YYCASE_
- }
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
- yysize1 = yysize + yystrlen (yyformat);
- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
- if (*yymsg_alloc < yysize)
- {
- *yymsg_alloc = 2 * yysize;
- if (! (yysize <= *yymsg_alloc
- && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
- *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
- return 1;
- }
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- {
- char *yyp = *yymsg;
- int yyi = 0;
- while ((*yyp = *yyformat) != '\0')
- if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyformat += 2;
- }
- else
- {
- yyp++;
- yyformat++;
- }
- }
- return 0;
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
}
#endif /* YYERROR_VERBOSE */
+
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
@@ -2134,9 +2084,10 @@ yydestruct (yymsg, yytype, yyvaluep)
break;
}
}
-
+
/* Prevent warnings from -Wmissing-prototypes. */
+
#ifdef YYPARSE_PARAM
#if defined __STDC__ || defined __cplusplus
int yyparse (void *YYPARSE_PARAM);
@@ -2152,16 +2103,18 @@ int yyparse ();
#endif /* ! YYPARSE_PARAM */
-/* The lookahead symbol. */
+
+/* The look-ahead symbol. */
int yychar, yystate;
-/* The semantic value of the lookahead symbol. */
+/* The semantic value of the look-ahead symbol. */
YYSTYPE yylval;
/* Number of syntax errors so far. */
int yynerrs;
+
/*----------.
| yyparse. |
`----------*/
@@ -2188,36 +2141,13 @@ yyparse ()
#endif
#endif
{
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
-
- /* The stacks and their tools:
- `yyss': related to states.
- `yyvs': related to semantic values.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs;
- YYSTYPE *yyvsp;
-
- YYSIZE_T yystacksize;
-
+
int yyn;
int yyresult;
- /* Lookahead token as an internal (translated) token number. */
- int yytoken;
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
#if YYERROR_VERBOSE
/* Buffer for error messages, and its allocated size. */
char yymsgbuf[128];
@@ -2225,28 +2155,51 @@ yyparse ()
YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
#endif
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
/* The number of symbols on the RHS of the reduced rule.
Keep to zero when no symbol should be popped. */
int yylen = 0;
- yytoken = 0;
- yyss = yyssa;
- yyvs = yyvsa;
- yystacksize = YYINITDEPTH;
-
YYDPRINTF ((stderr, "Starting parse\n"));
yystate = 0;
yyerrstatus = 0;
yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
+ yychar = YYEMPTY; /* Cause a token to be read. */
/* Initialize stack pointers.
Waste one element of value and location stack
so that they stay on the same level as the state stack.
The wasted elements are never initialized. */
+
yyssp = yyss;
yyvsp = yyvs;
@@ -2276,6 +2229,7 @@ yyparse ()
YYSTYPE *yyvs1 = yyvs;
yytype_int16 *yyss1 = yyss;
+
/* Each stack pointer address is followed by the size of the
data in use in that stack, in bytes. This used to be a
conditional around just the two extra args, but that might
@@ -2283,6 +2237,7 @@ yyparse ()
yyoverflow (YY_("memory exhausted"),
&yyss1, yysize * sizeof (*yyssp),
&yyvs1, yysize * sizeof (*yyvsp),
+
&yystacksize);
yyss = yyss1;
@@ -2305,8 +2260,9 @@ yyparse ()
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
if (! yyptr)
goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss_alloc, yyss);
- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
# undef YYSTACK_RELOCATE
if (yyss1 != yyssa)
YYSTACK_FREE (yyss1);
@@ -2317,6 +2273,7 @@ yyparse ()
yyssp = yyss + yysize - 1;
yyvsp = yyvs + yysize - 1;
+
YYDPRINTF ((stderr, "Stack size increased to %lu\n",
(unsigned long int) yystacksize));
@@ -2326,9 +2283,6 @@ yyparse ()
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
- if (yystate == YYFINAL)
- YYACCEPT;
-
goto yybackup;
/*-----------.
@@ -2337,16 +2291,16 @@ yyparse ()
yybackup:
/* Do appropriate processing given the current state. Read a
- lookahead token if we need one and don't already have one. */
+ look-ahead token if we need one and don't already have one. */
- /* First try to decide what to do without reference to lookahead token. */
+ /* First try to decide what to do without reference to look-ahead token. */
yyn = yypact[yystate];
- if (yypact_value_is_default (yyn))
+ if (yyn == YYPACT_NINF)
goto yydefault;
- /* Not known => get a lookahead token if don't already have one. */
+ /* Not known => get a look-ahead token if don't already have one. */
- /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
if (yychar == YYEMPTY)
{
YYDPRINTF ((stderr, "Reading a token: "));
@@ -2372,22 +2326,26 @@ yybackup:
yyn = yytable[yyn];
if (yyn <= 0)
{
- if (yytable_value_is_error (yyn))
- goto yyerrlab;
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
yyn = -yyn;
goto yyreduce;
}
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
/* Count tokens shifted since error; after three, turn off error
status. */
if (yyerrstatus)
yyerrstatus--;
- /* Shift the lookahead token. */
+ /* Shift the look-ahead token. */
YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
- /* Discard the shifted token. */
- yychar = YYEMPTY;
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
yystate = yyn;
*++yyvsp = yylval;
@@ -2427,8 +2385,6 @@ yyreduce:
switch (yyn)
{
case 2:
-
-/* Line 1806 of yacc.c */
#line 128 "go.y"
{
xtop = concat(xtop, (yyvsp[(4) - (4)].list));
@@ -2436,8 +2392,6 @@ yyreduce:
break;
case 3:
-
-/* Line 1806 of yacc.c */
#line 134 "go.y"
{
prevlineno = lineno;
@@ -2447,8 +2401,6 @@ yyreduce:
break;
case 4:
-
-/* Line 1806 of yacc.c */
#line 140 "go.y"
{
mkpackage((yyvsp[(2) - (3)].sym)->name);
@@ -2456,8 +2408,6 @@ yyreduce:
break;
case 5:
-
-/* Line 1806 of yacc.c */
#line 150 "go.y"
{
importpkg = runtimepkg;
@@ -2471,8 +2421,6 @@ yyreduce:
break;
case 6:
-
-/* Line 1806 of yacc.c */
#line 161 "go.y"
{
importpkg = nil;
@@ -2480,8 +2428,6 @@ yyreduce:
break;
case 12:
-
-/* Line 1806 of yacc.c */
#line 175 "go.y"
{
Pkg *ipkg;
@@ -2522,8 +2468,6 @@ yyreduce:
break;
case 13:
-
-/* Line 1806 of yacc.c */
#line 212 "go.y"
{
// When an invalid import path is passed to importfile,
@@ -2536,8 +2480,6 @@ yyreduce:
break;
case 16:
-
-/* Line 1806 of yacc.c */
#line 227 "go.y"
{
// import with original name
@@ -2548,8 +2490,6 @@ yyreduce:
break;
case 17:
-
-/* Line 1806 of yacc.c */
#line 234 "go.y"
{
// import with given name
@@ -2560,8 +2500,6 @@ yyreduce:
break;
case 18:
-
-/* Line 1806 of yacc.c */
#line 241 "go.y"
{
// import into my name space
@@ -2572,8 +2510,6 @@ yyreduce:
break;
case 19:
-
-/* Line 1806 of yacc.c */
#line 250 "go.y"
{
if(importpkg->name == nil) {
@@ -2590,8 +2526,6 @@ yyreduce:
break;
case 21:
-
-/* Line 1806 of yacc.c */
#line 265 "go.y"
{
if(strcmp((yyvsp[(1) - (1)].sym)->name, "safe") == 0)
@@ -2600,8 +2534,6 @@ yyreduce:
break;
case 22:
-
-/* Line 1806 of yacc.c */
#line 271 "go.y"
{
defercheckwidth();
@@ -2609,8 +2541,6 @@ yyreduce:
break;
case 23:
-
-/* Line 1806 of yacc.c */
#line 275 "go.y"
{
resumecheckwidth();
@@ -2619,8 +2549,6 @@ yyreduce:
break;
case 24:
-
-/* Line 1806 of yacc.c */
#line 284 "go.y"
{
yyerror("empty top-level declaration");
@@ -2629,8 +2557,6 @@ yyreduce:
break;
case 26:
-
-/* Line 1806 of yacc.c */
#line 290 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
@@ -2638,8 +2564,6 @@ yyreduce:
break;
case 27:
-
-/* Line 1806 of yacc.c */
#line 294 "go.y"
{
yyerror("non-declaration statement outside function body");
@@ -2648,8 +2572,6 @@ yyreduce:
break;
case 28:
-
-/* Line 1806 of yacc.c */
#line 299 "go.y"
{
(yyval.list) = nil;
@@ -2657,8 +2579,6 @@ yyreduce:
break;
case 29:
-
-/* Line 1806 of yacc.c */
#line 305 "go.y"
{
(yyval.list) = (yyvsp[(2) - (2)].list);
@@ -2666,8 +2586,6 @@ yyreduce:
break;
case 30:
-
-/* Line 1806 of yacc.c */
#line 309 "go.y"
{
(yyval.list) = (yyvsp[(3) - (5)].list);
@@ -2675,8 +2593,6 @@ yyreduce:
break;
case 31:
-
-/* Line 1806 of yacc.c */
#line 313 "go.y"
{
(yyval.list) = nil;
@@ -2684,8 +2600,6 @@ yyreduce:
break;
case 32:
-
-/* Line 1806 of yacc.c */
#line 317 "go.y"
{
(yyval.list) = (yyvsp[(2) - (2)].list);
@@ -2695,8 +2609,6 @@ yyreduce:
break;
case 33:
-
-/* Line 1806 of yacc.c */
#line 323 "go.y"
{
(yyval.list) = (yyvsp[(3) - (5)].list);
@@ -2706,8 +2618,6 @@ yyreduce:
break;
case 34:
-
-/* Line 1806 of yacc.c */
#line 329 "go.y"
{
(yyval.list) = concat((yyvsp[(3) - (7)].list), (yyvsp[(5) - (7)].list));
@@ -2717,8 +2627,6 @@ yyreduce:
break;
case 35:
-
-/* Line 1806 of yacc.c */
#line 335 "go.y"
{
(yyval.list) = nil;
@@ -2727,8 +2635,6 @@ yyreduce:
break;
case 36:
-
-/* Line 1806 of yacc.c */
#line 340 "go.y"
{
(yyval.list) = list1((yyvsp[(2) - (2)].node));
@@ -2736,8 +2642,6 @@ yyreduce:
break;
case 37:
-
-/* Line 1806 of yacc.c */
#line 344 "go.y"
{
(yyval.list) = (yyvsp[(3) - (5)].list);
@@ -2745,8 +2649,6 @@ yyreduce:
break;
case 38:
-
-/* Line 1806 of yacc.c */
#line 348 "go.y"
{
(yyval.list) = nil;
@@ -2754,8 +2656,6 @@ yyreduce:
break;
case 39:
-
-/* Line 1806 of yacc.c */
#line 354 "go.y"
{
iota = 0;
@@ -2763,8 +2663,6 @@ yyreduce:
break;
case 40:
-
-/* Line 1806 of yacc.c */
#line 360 "go.y"
{
(yyval.list) = variter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
@@ -2772,8 +2670,6 @@ yyreduce:
break;
case 41:
-
-/* Line 1806 of yacc.c */
#line 364 "go.y"
{
(yyval.list) = variter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
@@ -2781,8 +2677,6 @@ yyreduce:
break;
case 42:
-
-/* Line 1806 of yacc.c */
#line 368 "go.y"
{
(yyval.list) = variter((yyvsp[(1) - (3)].list), nil, (yyvsp[(3) - (3)].list));
@@ -2790,8 +2684,6 @@ yyreduce:
break;
case 43:
-
-/* Line 1806 of yacc.c */
#line 374 "go.y"
{
(yyval.list) = constiter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
@@ -2799,8 +2691,6 @@ yyreduce:
break;
case 44:
-
-/* Line 1806 of yacc.c */
#line 378 "go.y"
{
(yyval.list) = constiter((yyvsp[(1) - (3)].list), N, (yyvsp[(3) - (3)].list));
@@ -2808,8 +2698,6 @@ yyreduce:
break;
case 46:
-
-/* Line 1806 of yacc.c */
#line 385 "go.y"
{
(yyval.list) = constiter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
@@ -2817,8 +2705,6 @@ yyreduce:
break;
case 47:
-
-/* Line 1806 of yacc.c */
#line 389 "go.y"
{
(yyval.list) = constiter((yyvsp[(1) - (1)].list), N, nil);
@@ -2826,8 +2712,6 @@ yyreduce:
break;
case 48:
-
-/* Line 1806 of yacc.c */
#line 395 "go.y"
{
// different from dclname because the name
@@ -2838,8 +2722,6 @@ yyreduce:
break;
case 49:
-
-/* Line 1806 of yacc.c */
#line 404 "go.y"
{
(yyval.node) = typedcl1((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node), 1);
@@ -2847,8 +2729,6 @@ yyreduce:
break;
case 50:
-
-/* Line 1806 of yacc.c */
#line 410 "go.y"
{
(yyval.node) = (yyvsp[(1) - (1)].node);
@@ -2870,8 +2750,6 @@ yyreduce:
break;
case 51:
-
-/* Line 1806 of yacc.c */
#line 428 "go.y"
{
(yyval.node) = nod(OASOP, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
@@ -2880,8 +2758,6 @@ yyreduce:
break;
case 52:
-
-/* Line 1806 of yacc.c */
#line 433 "go.y"
{
if((yyvsp[(1) - (3)].list)->next == nil && (yyvsp[(3) - (3)].list)->next == nil) {
@@ -2897,8 +2773,6 @@ yyreduce:
break;
case 53:
-
-/* Line 1806 of yacc.c */
#line 445 "go.y"
{
if((yyvsp[(3) - (3)].list)->n->op == OTYPESW) {
@@ -2918,8 +2792,6 @@ yyreduce:
break;
case 54:
-
-/* Line 1806 of yacc.c */
#line 461 "go.y"
{
(yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
@@ -2928,8 +2800,6 @@ yyreduce:
break;
case 55:
-
-/* Line 1806 of yacc.c */
#line 466 "go.y"
{
(yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
@@ -2938,8 +2808,6 @@ yyreduce:
break;
case 56:
-
-/* Line 1806 of yacc.c */
#line 473 "go.y"
{
Node *n, *nn;
@@ -2963,8 +2831,6 @@ yyreduce:
break;
case 57:
-
-/* Line 1806 of yacc.c */
#line 493 "go.y"
{
Node *n;
@@ -2986,8 +2852,6 @@ yyreduce:
break;
case 58:
-
-/* Line 1806 of yacc.c */
#line 511 "go.y"
{
// will be converted to OCASE
@@ -3000,8 +2864,6 @@ yyreduce:
break;
case 59:
-
-/* Line 1806 of yacc.c */
#line 520 "go.y"
{
Node *n, *nn;
@@ -3021,8 +2883,6 @@ yyreduce:
break;
case 60:
-
-/* Line 1806 of yacc.c */
#line 538 "go.y"
{
markdcl();
@@ -3030,8 +2890,6 @@ yyreduce:
break;
case 61:
-
-/* Line 1806 of yacc.c */
#line 542 "go.y"
{
if((yyvsp[(3) - (4)].list) == nil)
@@ -3043,8 +2901,6 @@ yyreduce:
break;
case 62:
-
-/* Line 1806 of yacc.c */
#line 552 "go.y"
{
// If the last token read by the lexer was consumed
@@ -3054,13 +2910,12 @@ yyreduce:
// This is so that the stmt_list action doesn't look at
// the case tokens if the stmt_list is empty.
yylast = yychar;
+ (yyvsp[(1) - (1)].node)->xoffset = block;
}
break;
case 63:
-
-/* Line 1806 of yacc.c */
-#line 562 "go.y"
+#line 563 "go.y"
{
int last;
@@ -3082,36 +2937,28 @@ yyreduce:
break;
case 64:
-
-/* Line 1806 of yacc.c */
-#line 582 "go.y"
+#line 583 "go.y"
{
(yyval.list) = nil;
}
break;
case 65:
-
-/* Line 1806 of yacc.c */
-#line 586 "go.y"
+#line 587 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node));
}
break;
case 66:
-
-/* Line 1806 of yacc.c */
-#line 592 "go.y"
+#line 593 "go.y"
{
markdcl();
}
break;
case 67:
-
-/* Line 1806 of yacc.c */
-#line 596 "go.y"
+#line 597 "go.y"
{
(yyval.list) = (yyvsp[(3) - (4)].list);
popdcl();
@@ -3119,9 +2966,7 @@ yyreduce:
break;
case 68:
-
-/* Line 1806 of yacc.c */
-#line 603 "go.y"
+#line 604 "go.y"
{
(yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
(yyval.node)->list = (yyvsp[(1) - (4)].list);
@@ -3130,9 +2975,7 @@ yyreduce:
break;
case 69:
-
-/* Line 1806 of yacc.c */
-#line 609 "go.y"
+#line 610 "go.y"
{
(yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
(yyval.node)->list = (yyvsp[(1) - (4)].list);
@@ -3142,9 +2985,7 @@ yyreduce:
break;
case 70:
-
-/* Line 1806 of yacc.c */
-#line 618 "go.y"
+#line 619 "go.y"
{
// init ; test ; incr
if((yyvsp[(5) - (5)].node) != N && (yyvsp[(5) - (5)].node)->colas != 0)
@@ -3158,9 +2999,7 @@ yyreduce:
break;
case 71:
-
-/* Line 1806 of yacc.c */
-#line 629 "go.y"
+#line 630 "go.y"
{
// normal test
(yyval.node) = nod(OFOR, N, N);
@@ -3169,9 +3008,7 @@ yyreduce:
break;
case 73:
-
-/* Line 1806 of yacc.c */
-#line 638 "go.y"
+#line 639 "go.y"
{
(yyval.node) = (yyvsp[(1) - (2)].node);
(yyval.node)->nbody = concat((yyval.node)->nbody, (yyvsp[(2) - (2)].list));
@@ -3179,18 +3016,14 @@ yyreduce:
break;
case 74:
-
-/* Line 1806 of yacc.c */
-#line 645 "go.y"
+#line 646 "go.y"
{
markdcl();
}
break;
case 75:
-
-/* Line 1806 of yacc.c */
-#line 649 "go.y"
+#line 650 "go.y"
{
(yyval.node) = (yyvsp[(3) - (3)].node);
popdcl();
@@ -3198,9 +3031,7 @@ yyreduce:
break;
case 76:
-
-/* Line 1806 of yacc.c */
-#line 656 "go.y"
+#line 657 "go.y"
{
// test
(yyval.node) = nod(OIF, N, N);
@@ -3209,9 +3040,7 @@ yyreduce:
break;
case 77:
-
-/* Line 1806 of yacc.c */
-#line 662 "go.y"
+#line 663 "go.y"
{
// init ; test
(yyval.node) = nod(OIF, N, N);
@@ -3222,18 +3051,14 @@ yyreduce:
break;
case 78:
-
-/* Line 1806 of yacc.c */
-#line 673 "go.y"
+#line 674 "go.y"
{
markdcl();
}
break;
case 79:
-
-/* Line 1806 of yacc.c */
-#line 677 "go.y"
+#line 678 "go.y"
{
if((yyvsp[(3) - (3)].node)->ntest == N)
yyerror("missing condition in if statement");
@@ -3241,18 +3066,14 @@ yyreduce:
break;
case 80:
-
-/* Line 1806 of yacc.c */
-#line 682 "go.y"
+#line 683 "go.y"
{
(yyvsp[(3) - (5)].node)->nbody = (yyvsp[(5) - (5)].list);
}
break;
case 81:
-
-/* Line 1806 of yacc.c */
-#line 686 "go.y"
+#line 687 "go.y"
{
Node *n;
NodeList *nn;
@@ -3270,18 +3091,14 @@ yyreduce:
break;
case 82:
-
-/* Line 1806 of yacc.c */
-#line 703 "go.y"
+#line 704 "go.y"
{
markdcl();
}
break;
case 83:
-
-/* Line 1806 of yacc.c */
-#line 707 "go.y"
+#line 708 "go.y"
{
if((yyvsp[(4) - (5)].node)->ntest == N)
yyerror("missing condition in if statement");
@@ -3291,36 +3108,28 @@ yyreduce:
break;
case 84:
-
-/* Line 1806 of yacc.c */
-#line 715 "go.y"
+#line 716 "go.y"
{
(yyval.list) = nil;
}
break;
case 85:
-
-/* Line 1806 of yacc.c */
-#line 719 "go.y"
+#line 720 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].list));
}
break;
case 86:
-
-/* Line 1806 of yacc.c */
-#line 724 "go.y"
+#line 725 "go.y"
{
(yyval.list) = nil;
}
break;
case 87:
-
-/* Line 1806 of yacc.c */
-#line 728 "go.y"
+#line 729 "go.y"
{
NodeList *node;
@@ -3332,18 +3141,14 @@ yyreduce:
break;
case 88:
-
-/* Line 1806 of yacc.c */
-#line 739 "go.y"
+#line 740 "go.y"
{
markdcl();
}
break;
case 89:
-
-/* Line 1806 of yacc.c */
-#line 743 "go.y"
+#line 744 "go.y"
{
Node *n;
n = (yyvsp[(3) - (3)].node)->ntest;
@@ -3354,9 +3159,7 @@ yyreduce:
break;
case 90:
-
-/* Line 1806 of yacc.c */
-#line 751 "go.y"
+#line 752 "go.y"
{
(yyval.node) = (yyvsp[(3) - (7)].node);
(yyval.node)->op = OSWITCH;
@@ -3367,18 +3170,14 @@ yyreduce:
break;
case 91:
-
-/* Line 1806 of yacc.c */
-#line 761 "go.y"
+#line 762 "go.y"
{
typesw = nod(OXXX, typesw, N);
}
break;
case 92:
-
-/* Line 1806 of yacc.c */
-#line 765 "go.y"
+#line 766 "go.y"
{
(yyval.node) = nod(OSELECT, N, N);
(yyval.node)->lineno = typesw->lineno;
@@ -3388,198 +3187,154 @@ yyreduce:
break;
case 94:
-
-/* Line 1806 of yacc.c */
-#line 778 "go.y"
+#line 779 "go.y"
{
(yyval.node) = nod(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 95:
-
-/* Line 1806 of yacc.c */
-#line 782 "go.y"
+#line 783 "go.y"
{
(yyval.node) = nod(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 96:
-
-/* Line 1806 of yacc.c */
-#line 786 "go.y"
+#line 787 "go.y"
{
(yyval.node) = nod(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 97:
-
-/* Line 1806 of yacc.c */
-#line 790 "go.y"
+#line 791 "go.y"
{
(yyval.node) = nod(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 98:
-
-/* Line 1806 of yacc.c */
-#line 794 "go.y"
+#line 795 "go.y"
{
(yyval.node) = nod(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 99:
-
-/* Line 1806 of yacc.c */
-#line 798 "go.y"
+#line 799 "go.y"
{
(yyval.node) = nod(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 100:
-
-/* Line 1806 of yacc.c */
-#line 802 "go.y"
+#line 803 "go.y"
{
(yyval.node) = nod(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 101:
-
-/* Line 1806 of yacc.c */
-#line 806 "go.y"
+#line 807 "go.y"
{
(yyval.node) = nod(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 102:
-
-/* Line 1806 of yacc.c */
-#line 810 "go.y"
+#line 811 "go.y"
{
(yyval.node) = nod(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 103:
-
-/* Line 1806 of yacc.c */
-#line 814 "go.y"
+#line 815 "go.y"
{
(yyval.node) = nod(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 104:
-
-/* Line 1806 of yacc.c */
-#line 818 "go.y"
+#line 819 "go.y"
{
(yyval.node) = nod(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 105:
-
-/* Line 1806 of yacc.c */
-#line 822 "go.y"
+#line 823 "go.y"
{
(yyval.node) = nod(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 106:
-
-/* Line 1806 of yacc.c */
-#line 826 "go.y"
+#line 827 "go.y"
{
(yyval.node) = nod(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 107:
-
-/* Line 1806 of yacc.c */
-#line 830 "go.y"
+#line 831 "go.y"
{
(yyval.node) = nod(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 108:
-
-/* Line 1806 of yacc.c */
-#line 834 "go.y"
+#line 835 "go.y"
{
(yyval.node) = nod(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 109:
-
-/* Line 1806 of yacc.c */
-#line 838 "go.y"
+#line 839 "go.y"
{
(yyval.node) = nod(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 110:
-
-/* Line 1806 of yacc.c */
-#line 842 "go.y"
+#line 843 "go.y"
{
(yyval.node) = nod(OANDNOT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 111:
-
-/* Line 1806 of yacc.c */
-#line 846 "go.y"
+#line 847 "go.y"
{
(yyval.node) = nod(OLSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 112:
-
-/* Line 1806 of yacc.c */
-#line 850 "go.y"
+#line 851 "go.y"
{
(yyval.node) = nod(ORSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 113:
-
-/* Line 1806 of yacc.c */
-#line 855 "go.y"
+#line 856 "go.y"
{
(yyval.node) = nod(OSEND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 115:
-
-/* Line 1806 of yacc.c */
-#line 862 "go.y"
+#line 863 "go.y"
{
(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
}
break;
case 116:
-
-/* Line 1806 of yacc.c */
-#line 866 "go.y"
+#line 867 "go.y"
{
if((yyvsp[(2) - (2)].node)->op == OCOMPLIT) {
// Special case for &T{...}: turn into (*T){...}.
@@ -3593,36 +3348,28 @@ yyreduce:
break;
case 117:
-
-/* Line 1806 of yacc.c */
-#line 877 "go.y"
+#line 878 "go.y"
{
(yyval.node) = nod(OPLUS, (yyvsp[(2) - (2)].node), N);
}
break;
case 118:
-
-/* Line 1806 of yacc.c */
-#line 881 "go.y"
+#line 882 "go.y"
{
(yyval.node) = nod(OMINUS, (yyvsp[(2) - (2)].node), N);
}
break;
case 119:
-
-/* Line 1806 of yacc.c */
-#line 885 "go.y"
+#line 886 "go.y"
{
(yyval.node) = nod(ONOT, (yyvsp[(2) - (2)].node), N);
}
break;
case 120:
-
-/* Line 1806 of yacc.c */
-#line 889 "go.y"
+#line 890 "go.y"
{
yyerror("the bitwise complement operator is ^");
(yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
@@ -3630,36 +3377,28 @@ yyreduce:
break;
case 121:
-
-/* Line 1806 of yacc.c */
-#line 894 "go.y"
+#line 895 "go.y"
{
(yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
}
break;
case 122:
-
-/* Line 1806 of yacc.c */
-#line 898 "go.y"
+#line 899 "go.y"
{
(yyval.node) = nod(ORECV, (yyvsp[(2) - (2)].node), N);
}
break;
case 123:
-
-/* Line 1806 of yacc.c */
-#line 908 "go.y"
+#line 909 "go.y"
{
(yyval.node) = nod(OCALL, (yyvsp[(1) - (3)].node), N);
}
break;
case 124:
-
-/* Line 1806 of yacc.c */
-#line 912 "go.y"
+#line 913 "go.y"
{
(yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N);
(yyval.node)->list = (yyvsp[(3) - (5)].list);
@@ -3667,9 +3406,7 @@ yyreduce:
break;
case 125:
-
-/* Line 1806 of yacc.c */
-#line 917 "go.y"
+#line 918 "go.y"
{
(yyval.node) = nod(OCALL, (yyvsp[(1) - (6)].node), N);
(yyval.node)->list = (yyvsp[(3) - (6)].list);
@@ -3678,18 +3415,14 @@ yyreduce:
break;
case 126:
-
-/* Line 1806 of yacc.c */
-#line 925 "go.y"
+#line 926 "go.y"
{
(yyval.node) = nodlit((yyvsp[(1) - (1)].val));
}
break;
case 128:
-
-/* Line 1806 of yacc.c */
-#line 930 "go.y"
+#line 931 "go.y"
{
if((yyvsp[(1) - (3)].node)->op == OPACK) {
Sym *s;
@@ -3703,45 +3436,35 @@ yyreduce:
break;
case 129:
-
-/* Line 1806 of yacc.c */
-#line 941 "go.y"
+#line 942 "go.y"
{
(yyval.node) = nod(ODOTTYPE, (yyvsp[(1) - (5)].node), (yyvsp[(4) - (5)].node));
}
break;
case 130:
-
-/* Line 1806 of yacc.c */
-#line 945 "go.y"
+#line 946 "go.y"
{
(yyval.node) = nod(OTYPESW, N, (yyvsp[(1) - (5)].node));
}
break;
case 131:
-
-/* Line 1806 of yacc.c */
-#line 949 "go.y"
+#line 950 "go.y"
{
(yyval.node) = nod(OINDEX, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
}
break;
case 132:
-
-/* Line 1806 of yacc.c */
-#line 953 "go.y"
+#line 954 "go.y"
{
(yyval.node) = nod(OSLICE, (yyvsp[(1) - (6)].node), nod(OKEY, (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node)));
}
break;
case 133:
-
-/* Line 1806 of yacc.c */
-#line 957 "go.y"
+#line 958 "go.y"
{
if((yyvsp[(5) - (8)].node) == N)
yyerror("middle index required in 3-index slice");
@@ -3752,9 +3475,7 @@ yyreduce:
break;
case 135:
-
-/* Line 1806 of yacc.c */
-#line 966 "go.y"
+#line 967 "go.y"
{
// conversion
(yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N);
@@ -3763,9 +3484,7 @@ yyreduce:
break;
case 136:
-
-/* Line 1806 of yacc.c */
-#line 972 "go.y"
+#line 973 "go.y"
{
(yyval.node) = (yyvsp[(3) - (5)].node);
(yyval.node)->right = (yyvsp[(1) - (5)].node);
@@ -3775,9 +3494,7 @@ yyreduce:
break;
case 137:
-
-/* Line 1806 of yacc.c */
-#line 979 "go.y"
+#line 980 "go.y"
{
(yyval.node) = (yyvsp[(3) - (5)].node);
(yyval.node)->right = (yyvsp[(1) - (5)].node);
@@ -3786,9 +3503,7 @@ yyreduce:
break;
case 138:
-
-/* Line 1806 of yacc.c */
-#line 985 "go.y"
+#line 986 "go.y"
{
yyerror("cannot parenthesize type in composite literal");
(yyval.node) = (yyvsp[(5) - (7)].node);
@@ -3798,9 +3513,7 @@ yyreduce:
break;
case 140:
-
-/* Line 1806 of yacc.c */
-#line 994 "go.y"
+#line 995 "go.y"
{
// composite expression.
// make node early so we get the right line number.
@@ -3809,18 +3522,14 @@ yyreduce:
break;
case 141:
-
-/* Line 1806 of yacc.c */
-#line 1002 "go.y"
+#line 1003 "go.y"
{
(yyval.node) = nod(OKEY, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 142:
-
-/* Line 1806 of yacc.c */
-#line 1008 "go.y"
+#line 1009 "go.y"
{
// These nodes do not carry line numbers.
// Since a composite literal commonly spans several lines,
@@ -3840,9 +3549,7 @@ yyreduce:
break;
case 143:
-
-/* Line 1806 of yacc.c */
-#line 1025 "go.y"
+#line 1026 "go.y"
{
(yyval.node) = (yyvsp[(2) - (4)].node);
(yyval.node)->list = (yyvsp[(3) - (4)].list);
@@ -3850,9 +3557,7 @@ yyreduce:
break;
case 145:
-
-/* Line 1806 of yacc.c */
-#line 1033 "go.y"
+#line 1034 "go.y"
{
(yyval.node) = (yyvsp[(2) - (4)].node);
(yyval.node)->list = (yyvsp[(3) - (4)].list);
@@ -3860,9 +3565,7 @@ yyreduce:
break;
case 147:
-
-/* Line 1806 of yacc.c */
-#line 1041 "go.y"
+#line 1042 "go.y"
{
(yyval.node) = (yyvsp[(2) - (3)].node);
@@ -3882,27 +3585,21 @@ yyreduce:
break;
case 151:
-
-/* Line 1806 of yacc.c */
-#line 1067 "go.y"
+#line 1068 "go.y"
{
(yyval.i) = LBODY;
}
break;
case 152:
-
-/* Line 1806 of yacc.c */
-#line 1071 "go.y"
+#line 1072 "go.y"
{
(yyval.i) = '{';
}
break;
case 153:
-
-/* Line 1806 of yacc.c */
-#line 1082 "go.y"
+#line 1083 "go.y"
{
if((yyvsp[(1) - (1)].sym) == S)
(yyval.node) = N;
@@ -3912,27 +3609,21 @@ yyreduce:
break;
case 154:
-
-/* Line 1806 of yacc.c */
-#line 1091 "go.y"
+#line 1092 "go.y"
{
(yyval.node) = dclname((yyvsp[(1) - (1)].sym));
}
break;
case 155:
-
-/* Line 1806 of yacc.c */
-#line 1096 "go.y"
+#line 1097 "go.y"
{
(yyval.node) = N;
}
break;
case 157:
-
-/* Line 1806 of yacc.c */
-#line 1103 "go.y"
+#line 1104 "go.y"
{
(yyval.sym) = (yyvsp[(1) - (1)].sym);
// during imports, unqualified non-exported identifiers are from builtinpkg
@@ -3942,18 +3633,14 @@ yyreduce:
break;
case 159:
-
-/* Line 1806 of yacc.c */
-#line 1111 "go.y"
+#line 1112 "go.y"
{
(yyval.sym) = S;
}
break;
case 160:
-
-/* Line 1806 of yacc.c */
-#line 1117 "go.y"
+#line 1118 "go.y"
{
Pkg *p;
@@ -3969,9 +3656,7 @@ yyreduce:
break;
case 161:
-
-/* Line 1806 of yacc.c */
-#line 1130 "go.y"
+#line 1131 "go.y"
{
Pkg *p;
@@ -3987,9 +3672,7 @@ yyreduce:
break;
case 162:
-
-/* Line 1806 of yacc.c */
-#line 1145 "go.y"
+#line 1146 "go.y"
{
(yyval.node) = oldname((yyvsp[(1) - (1)].sym));
if((yyval.node)->pack != N)
@@ -3998,9 +3681,7 @@ yyreduce:
break;
case 164:
-
-/* Line 1806 of yacc.c */
-#line 1165 "go.y"
+#line 1166 "go.y"
{
yyerror("final argument in variadic function missing type");
(yyval.node) = nod(ODDD, typenod(typ(TINTER)), N);
@@ -4008,45 +3689,35 @@ yyreduce:
break;
case 165:
-
-/* Line 1806 of yacc.c */
-#line 1170 "go.y"
+#line 1171 "go.y"
{
(yyval.node) = nod(ODDD, (yyvsp[(2) - (2)].node), N);
}
break;
case 171:
-
-/* Line 1806 of yacc.c */
-#line 1181 "go.y"
+#line 1182 "go.y"
{
(yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N);
}
break;
case 175:
-
-/* Line 1806 of yacc.c */
-#line 1190 "go.y"
+#line 1191 "go.y"
{
(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
}
break;
case 180:
-
-/* Line 1806 of yacc.c */
-#line 1200 "go.y"
+#line 1201 "go.y"
{
(yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N);
}
break;
case 190:
-
-/* Line 1806 of yacc.c */
-#line 1221 "go.y"
+#line 1222 "go.y"
{
if((yyvsp[(1) - (3)].node)->op == OPACK) {
Sym *s;
@@ -4060,18 +3731,14 @@ yyreduce:
break;
case 191:
-
-/* Line 1806 of yacc.c */
-#line 1234 "go.y"
+#line 1235 "go.y"
{
(yyval.node) = nod(OTARRAY, (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].node));
}
break;
case 192:
-
-/* Line 1806 of yacc.c */
-#line 1238 "go.y"
+#line 1239 "go.y"
{
// array literal of nelem
(yyval.node) = nod(OTARRAY, nod(ODDD, N, N), (yyvsp[(4) - (4)].node));
@@ -4079,9 +3746,7 @@ yyreduce:
break;
case 193:
-
-/* Line 1806 of yacc.c */
-#line 1243 "go.y"
+#line 1244 "go.y"
{
(yyval.node) = nod(OTCHAN, (yyvsp[(2) - (2)].node), N);
(yyval.node)->etype = Cboth;
@@ -4089,9 +3754,7 @@ yyreduce:
break;
case 194:
-
-/* Line 1806 of yacc.c */
-#line 1248 "go.y"
+#line 1249 "go.y"
{
(yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
(yyval.node)->etype = Csend;
@@ -4099,27 +3762,21 @@ yyreduce:
break;
case 195:
-
-/* Line 1806 of yacc.c */
-#line 1253 "go.y"
+#line 1254 "go.y"
{
(yyval.node) = nod(OTMAP, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
}
break;
case 198:
-
-/* Line 1806 of yacc.c */
-#line 1261 "go.y"
+#line 1262 "go.y"
{
(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
}
break;
case 199:
-
-/* Line 1806 of yacc.c */
-#line 1267 "go.y"
+#line 1268 "go.y"
{
(yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
(yyval.node)->etype = Crecv;
@@ -4127,9 +3784,7 @@ yyreduce:
break;
case 200:
-
-/* Line 1806 of yacc.c */
-#line 1274 "go.y"
+#line 1275 "go.y"
{
(yyval.node) = nod(OTSTRUCT, N, N);
(yyval.node)->list = (yyvsp[(3) - (5)].list);
@@ -4138,9 +3793,7 @@ yyreduce:
break;
case 201:
-
-/* Line 1806 of yacc.c */
-#line 1280 "go.y"
+#line 1281 "go.y"
{
(yyval.node) = nod(OTSTRUCT, N, N);
fixlbrace((yyvsp[(2) - (3)].i));
@@ -4148,9 +3801,7 @@ yyreduce:
break;
case 202:
-
-/* Line 1806 of yacc.c */
-#line 1287 "go.y"
+#line 1288 "go.y"
{
(yyval.node) = nod(OTINTER, N, N);
(yyval.node)->list = (yyvsp[(3) - (5)].list);
@@ -4159,9 +3810,7 @@ yyreduce:
break;
case 203:
-
-/* Line 1806 of yacc.c */
-#line 1293 "go.y"
+#line 1294 "go.y"
{
(yyval.node) = nod(OTINTER, N, N);
fixlbrace((yyvsp[(2) - (3)].i));
@@ -4169,9 +3818,7 @@ yyreduce:
break;
case 204:
-
-/* Line 1806 of yacc.c */
-#line 1304 "go.y"
+#line 1305 "go.y"
{
(yyval.node) = (yyvsp[(2) - (3)].node);
if((yyval.node) == N)
@@ -4186,9 +3833,7 @@ yyreduce:
break;
case 205:
-
-/* Line 1806 of yacc.c */
-#line 1318 "go.y"
+#line 1319 "go.y"
{
Node *t;
@@ -4220,9 +3865,7 @@ yyreduce:
break;
case 206:
-
-/* Line 1806 of yacc.c */
-#line 1347 "go.y"
+#line 1348 "go.y"
{
Node *rcvr, *t;
@@ -4263,9 +3906,7 @@ yyreduce:
break;
case 207:
-
-/* Line 1806 of yacc.c */
-#line 1387 "go.y"
+#line 1388 "go.y"
{
Sym *s;
Type *t;
@@ -4293,9 +3934,7 @@ yyreduce:
break;
case 208:
-
-/* Line 1806 of yacc.c */
-#line 1412 "go.y"
+#line 1413 "go.y"
{
(yyval.node) = methodname1(newname((yyvsp[(4) - (8)].sym)), (yyvsp[(2) - (8)].list)->n->right);
(yyval.node)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list));
@@ -4314,9 +3953,7 @@ yyreduce:
break;
case 209:
-
-/* Line 1806 of yacc.c */
-#line 1430 "go.y"
+#line 1431 "go.y"
{
(yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1);
(yyval.node) = nod(OTFUNC, N, N);
@@ -4326,18 +3963,14 @@ yyreduce:
break;
case 210:
-
-/* Line 1806 of yacc.c */
-#line 1438 "go.y"
+#line 1439 "go.y"
{
(yyval.list) = nil;
}
break;
case 211:
-
-/* Line 1806 of yacc.c */
-#line 1442 "go.y"
+#line 1443 "go.y"
{
(yyval.list) = (yyvsp[(2) - (3)].list);
if((yyval.list) == nil)
@@ -4346,27 +3979,21 @@ yyreduce:
break;
case 212:
-
-/* Line 1806 of yacc.c */
-#line 1450 "go.y"
+#line 1451 "go.y"
{
(yyval.list) = nil;
}
break;
case 213:
-
-/* Line 1806 of yacc.c */
-#line 1454 "go.y"
+#line 1455 "go.y"
{
(yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node)));
}
break;
case 214:
-
-/* Line 1806 of yacc.c */
-#line 1458 "go.y"
+#line 1459 "go.y"
{
(yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0);
(yyval.list) = (yyvsp[(2) - (3)].list);
@@ -4374,18 +4001,14 @@ yyreduce:
break;
case 215:
-
-/* Line 1806 of yacc.c */
-#line 1465 "go.y"
+#line 1466 "go.y"
{
closurehdr((yyvsp[(1) - (1)].node));
}
break;
case 216:
-
-/* Line 1806 of yacc.c */
-#line 1471 "go.y"
+#line 1472 "go.y"
{
(yyval.node) = closurebody((yyvsp[(3) - (4)].list));
fixlbrace((yyvsp[(2) - (4)].i));
@@ -4393,27 +4016,21 @@ yyreduce:
break;
case 217:
-
-/* Line 1806 of yacc.c */
-#line 1476 "go.y"
+#line 1477 "go.y"
{
(yyval.node) = closurebody(nil);
}
break;
case 218:
-
-/* Line 1806 of yacc.c */
-#line 1487 "go.y"
+#line 1488 "go.y"
{
(yyval.list) = nil;
}
break;
case 219:
-
-/* Line 1806 of yacc.c */
-#line 1491 "go.y"
+#line 1492 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list));
if(nsyntaxerrors == 0)
@@ -4424,72 +4041,56 @@ yyreduce:
break;
case 221:
-
-/* Line 1806 of yacc.c */
-#line 1502 "go.y"
+#line 1503 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
}
break;
case 223:
-
-/* Line 1806 of yacc.c */
-#line 1509 "go.y"
+#line 1510 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
}
break;
case 224:
-
-/* Line 1806 of yacc.c */
-#line 1515 "go.y"
+#line 1516 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 225:
-
-/* Line 1806 of yacc.c */
-#line 1519 "go.y"
+#line 1520 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 227:
-
-/* Line 1806 of yacc.c */
-#line 1526 "go.y"
+#line 1527 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
}
break;
case 228:
-
-/* Line 1806 of yacc.c */
-#line 1532 "go.y"
+#line 1533 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 229:
-
-/* Line 1806 of yacc.c */
-#line 1536 "go.y"
+#line 1537 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 230:
-
-/* Line 1806 of yacc.c */
-#line 1542 "go.y"
+#line 1543 "go.y"
{
NodeList *l;
@@ -4515,9 +4116,7 @@ yyreduce:
break;
case 231:
-
-/* Line 1806 of yacc.c */
-#line 1565 "go.y"
+#line 1566 "go.y"
{
(yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val);
(yyval.list) = list1((yyvsp[(1) - (2)].node));
@@ -4525,9 +4124,7 @@ yyreduce:
break;
case 232:
-
-/* Line 1806 of yacc.c */
-#line 1570 "go.y"
+#line 1571 "go.y"
{
(yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val);
(yyval.list) = list1((yyvsp[(2) - (4)].node));
@@ -4536,9 +4133,7 @@ yyreduce:
break;
case 233:
-
-/* Line 1806 of yacc.c */
-#line 1576 "go.y"
+#line 1577 "go.y"
{
(yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N);
(yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val);
@@ -4547,9 +4142,7 @@ yyreduce:
break;
case 234:
-
-/* Line 1806 of yacc.c */
-#line 1582 "go.y"
+#line 1583 "go.y"
{
(yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
(yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
@@ -4559,9 +4152,7 @@ yyreduce:
break;
case 235:
-
-/* Line 1806 of yacc.c */
-#line 1589 "go.y"
+#line 1590 "go.y"
{
(yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
(yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
@@ -4571,9 +4162,7 @@ yyreduce:
break;
case 236:
-
-/* Line 1806 of yacc.c */
-#line 1598 "go.y"
+#line 1599 "go.y"
{
Node *n;
@@ -4585,9 +4174,7 @@ yyreduce:
break;
case 237:
-
-/* Line 1806 of yacc.c */
-#line 1607 "go.y"
+#line 1608 "go.y"
{
Pkg *pkg;
@@ -4603,18 +4190,14 @@ yyreduce:
break;
case 238:
-
-/* Line 1806 of yacc.c */
-#line 1622 "go.y"
+#line 1623 "go.y"
{
(yyval.node) = embedded((yyvsp[(1) - (1)].sym), localpkg);
}
break;
case 239:
-
-/* Line 1806 of yacc.c */
-#line 1628 "go.y"
+#line 1629 "go.y"
{
(yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
ifacedcl((yyval.node));
@@ -4622,18 +4205,14 @@ yyreduce:
break;
case 240:
-
-/* Line 1806 of yacc.c */
-#line 1633 "go.y"
+#line 1634 "go.y"
{
(yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym)));
}
break;
case 241:
-
-/* Line 1806 of yacc.c */
-#line 1637 "go.y"
+#line 1638 "go.y"
{
(yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym)));
yyerror("cannot parenthesize embedded type");
@@ -4641,9 +4220,7 @@ yyreduce:
break;
case 242:
-
-/* Line 1806 of yacc.c */
-#line 1644 "go.y"
+#line 1645 "go.y"
{
// without func keyword
(yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1);
@@ -4654,9 +4231,7 @@ yyreduce:
break;
case 244:
-
-/* Line 1806 of yacc.c */
-#line 1658 "go.y"
+#line 1659 "go.y"
{
(yyval.node) = nod(ONONAME, N, N);
(yyval.node)->sym = (yyvsp[(1) - (2)].sym);
@@ -4665,9 +4240,7 @@ yyreduce:
break;
case 245:
-
-/* Line 1806 of yacc.c */
-#line 1664 "go.y"
+#line 1665 "go.y"
{
(yyval.node) = nod(ONONAME, N, N);
(yyval.node)->sym = (yyvsp[(1) - (2)].sym);
@@ -4676,72 +4249,56 @@ yyreduce:
break;
case 247:
-
-/* Line 1806 of yacc.c */
-#line 1673 "go.y"
+#line 1674 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 248:
-
-/* Line 1806 of yacc.c */
-#line 1677 "go.y"
+#line 1678 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 249:
-
-/* Line 1806 of yacc.c */
-#line 1682 "go.y"
+#line 1683 "go.y"
{
(yyval.list) = nil;
}
break;
case 250:
-
-/* Line 1806 of yacc.c */
-#line 1686 "go.y"
+#line 1687 "go.y"
{
(yyval.list) = (yyvsp[(1) - (2)].list);
}
break;
case 251:
-
-/* Line 1806 of yacc.c */
-#line 1694 "go.y"
+#line 1695 "go.y"
{
(yyval.node) = N;
}
break;
case 253:
-
-/* Line 1806 of yacc.c */
-#line 1699 "go.y"
+#line 1700 "go.y"
{
(yyval.node) = liststmt((yyvsp[(1) - (1)].list));
}
break;
case 255:
-
-/* Line 1806 of yacc.c */
-#line 1704 "go.y"
+#line 1705 "go.y"
{
(yyval.node) = N;
}
break;
case 261:
-
-/* Line 1806 of yacc.c */
-#line 1715 "go.y"
+#line 1716 "go.y"
{
(yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N);
(yyvsp[(1) - (2)].node)->sym = dclstack; // context, for goto restrictions
@@ -4749,9 +4306,7 @@ yyreduce:
break;
case 262:
-
-/* Line 1806 of yacc.c */
-#line 1720 "go.y"
+#line 1721 "go.y"
{
NodeList *l;
@@ -4764,55 +4319,44 @@ yyreduce:
break;
case 263:
-
-/* Line 1806 of yacc.c */
-#line 1730 "go.y"
+#line 1731 "go.y"
{
// will be converted to OFALL
(yyval.node) = nod(OXFALL, N, N);
+ (yyval.node)->xoffset = block;
}
break;
case 264:
-
-/* Line 1806 of yacc.c */
-#line 1735 "go.y"
+#line 1737 "go.y"
{
(yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N);
}
break;
case 265:
-
-/* Line 1806 of yacc.c */
-#line 1739 "go.y"
+#line 1741 "go.y"
{
(yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N);
}
break;
case 266:
-
-/* Line 1806 of yacc.c */
-#line 1743 "go.y"
+#line 1745 "go.y"
{
(yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N);
}
break;
case 267:
-
-/* Line 1806 of yacc.c */
-#line 1747 "go.y"
+#line 1749 "go.y"
{
(yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N);
}
break;
case 268:
-
-/* Line 1806 of yacc.c */
-#line 1751 "go.y"
+#line 1753 "go.y"
{
(yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N);
(yyval.node)->sym = dclstack; // context, for goto restrictions
@@ -4820,9 +4364,7 @@ yyreduce:
break;
case 269:
-
-/* Line 1806 of yacc.c */
-#line 1756 "go.y"
+#line 1758 "go.y"
{
(yyval.node) = nod(ORETURN, N, N);
(yyval.node)->list = (yyvsp[(2) - (2)].list);
@@ -4842,9 +4384,7 @@ yyreduce:
break;
case 270:
-
-/* Line 1806 of yacc.c */
-#line 1775 "go.y"
+#line 1777 "go.y"
{
(yyval.list) = nil;
if((yyvsp[(1) - (1)].node) != N)
@@ -4853,9 +4393,7 @@ yyreduce:
break;
case 271:
-
-/* Line 1806 of yacc.c */
-#line 1781 "go.y"
+#line 1783 "go.y"
{
(yyval.list) = (yyvsp[(1) - (3)].list);
if((yyvsp[(3) - (3)].node) != N)
@@ -4864,243 +4402,189 @@ yyreduce:
break;
case 272:
-
-/* Line 1806 of yacc.c */
-#line 1789 "go.y"
+#line 1791 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 273:
-
-/* Line 1806 of yacc.c */
-#line 1793 "go.y"
+#line 1795 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 274:
-
-/* Line 1806 of yacc.c */
-#line 1799 "go.y"
+#line 1801 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 275:
-
-/* Line 1806 of yacc.c */
-#line 1803 "go.y"
+#line 1805 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 276:
-
-/* Line 1806 of yacc.c */
-#line 1809 "go.y"
+#line 1811 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 277:
-
-/* Line 1806 of yacc.c */
-#line 1813 "go.y"
+#line 1815 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 278:
-
-/* Line 1806 of yacc.c */
-#line 1819 "go.y"
+#line 1821 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 279:
-
-/* Line 1806 of yacc.c */
-#line 1823 "go.y"
+#line 1825 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 280:
-
-/* Line 1806 of yacc.c */
-#line 1832 "go.y"
+#line 1834 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 281:
-
-/* Line 1806 of yacc.c */
-#line 1836 "go.y"
+#line 1838 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 282:
-
-/* Line 1806 of yacc.c */
-#line 1840 "go.y"
+#line 1842 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 283:
-
-/* Line 1806 of yacc.c */
-#line 1844 "go.y"
+#line 1846 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 284:
-
-/* Line 1806 of yacc.c */
-#line 1849 "go.y"
+#line 1851 "go.y"
{
(yyval.list) = nil;
}
break;
case 285:
-
-/* Line 1806 of yacc.c */
-#line 1853 "go.y"
+#line 1855 "go.y"
{
(yyval.list) = (yyvsp[(1) - (2)].list);
}
break;
case 290:
-
-/* Line 1806 of yacc.c */
-#line 1867 "go.y"
+#line 1869 "go.y"
{
(yyval.node) = N;
}
break;
case 292:
-
-/* Line 1806 of yacc.c */
-#line 1873 "go.y"
+#line 1875 "go.y"
{
(yyval.list) = nil;
}
break;
case 294:
-
-/* Line 1806 of yacc.c */
-#line 1879 "go.y"
+#line 1881 "go.y"
{
(yyval.node) = N;
}
break;
case 296:
-
-/* Line 1806 of yacc.c */
-#line 1885 "go.y"
+#line 1887 "go.y"
{
(yyval.list) = nil;
}
break;
case 298:
-
-/* Line 1806 of yacc.c */
-#line 1891 "go.y"
+#line 1893 "go.y"
{
(yyval.list) = nil;
}
break;
case 300:
-
-/* Line 1806 of yacc.c */
-#line 1897 "go.y"
+#line 1899 "go.y"
{
(yyval.list) = nil;
}
break;
case 302:
-
-/* Line 1806 of yacc.c */
-#line 1903 "go.y"
+#line 1905 "go.y"
{
(yyval.val).ctype = CTxxx;
}
break;
case 304:
-
-/* Line 1806 of yacc.c */
-#line 1913 "go.y"
+#line 1915 "go.y"
{
importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval);
}
break;
case 305:
-
-/* Line 1806 of yacc.c */
-#line 1917 "go.y"
+#line 1919 "go.y"
{
importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type));
}
break;
case 306:
-
-/* Line 1806 of yacc.c */
-#line 1921 "go.y"
+#line 1923 "go.y"
{
importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node));
}
break;
case 307:
-
-/* Line 1806 of yacc.c */
-#line 1925 "go.y"
+#line 1927 "go.y"
{
importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node));
}
break;
case 308:
-
-/* Line 1806 of yacc.c */
-#line 1929 "go.y"
+#line 1931 "go.y"
{
importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type));
}
break;
case 309:
-
-/* Line 1806 of yacc.c */
-#line 1933 "go.y"
+#line 1935 "go.y"
{
if((yyvsp[(2) - (4)].node) == N) {
dclcontext = PEXTERN; // since we skip the funcbody below
@@ -5121,9 +4605,7 @@ yyreduce:
break;
case 310:
-
-/* Line 1806 of yacc.c */
-#line 1953 "go.y"
+#line 1955 "go.y"
{
(yyval.sym) = (yyvsp[(1) - (1)].sym);
structpkg = (yyval.sym)->pkg;
@@ -5131,9 +4613,7 @@ yyreduce:
break;
case 311:
-
-/* Line 1806 of yacc.c */
-#line 1960 "go.y"
+#line 1962 "go.y"
{
(yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
importsym((yyvsp[(1) - (1)].sym), OTYPE);
@@ -5141,18 +4621,14 @@ yyreduce:
break;
case 317:
-
-/* Line 1806 of yacc.c */
-#line 1980 "go.y"
+#line 1982 "go.y"
{
(yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
}
break;
case 318:
-
-/* Line 1806 of yacc.c */
-#line 1984 "go.y"
+#line 1986 "go.y"
{
// predefined name like uint8
(yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg);
@@ -5165,63 +4641,49 @@ yyreduce:
break;
case 319:
-
-/* Line 1806 of yacc.c */
-#line 1994 "go.y"
+#line 1996 "go.y"
{
(yyval.type) = aindex(N, (yyvsp[(3) - (3)].type));
}
break;
case 320:
-
-/* Line 1806 of yacc.c */
-#line 1998 "go.y"
+#line 2000 "go.y"
{
(yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type));
}
break;
case 321:
-
-/* Line 1806 of yacc.c */
-#line 2002 "go.y"
+#line 2004 "go.y"
{
(yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type));
}
break;
case 322:
-
-/* Line 1806 of yacc.c */
-#line 2006 "go.y"
+#line 2008 "go.y"
{
(yyval.type) = tostruct((yyvsp[(3) - (4)].list));
}
break;
case 323:
-
-/* Line 1806 of yacc.c */
-#line 2010 "go.y"
+#line 2012 "go.y"
{
(yyval.type) = tointerface((yyvsp[(3) - (4)].list));
}
break;
case 324:
-
-/* Line 1806 of yacc.c */
-#line 2014 "go.y"
+#line 2016 "go.y"
{
(yyval.type) = ptrto((yyvsp[(2) - (2)].type));
}
break;
case 325:
-
-/* Line 1806 of yacc.c */
-#line 2018 "go.y"
+#line 2020 "go.y"
{
(yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(2) - (2)].type);
@@ -5230,9 +4692,7 @@ yyreduce:
break;
case 326:
-
-/* Line 1806 of yacc.c */
-#line 2024 "go.y"
+#line 2026 "go.y"
{
(yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(3) - (4)].type);
@@ -5241,9 +4701,7 @@ yyreduce:
break;
case 327:
-
-/* Line 1806 of yacc.c */
-#line 2030 "go.y"
+#line 2032 "go.y"
{
(yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(3) - (3)].type);
@@ -5252,9 +4710,7 @@ yyreduce:
break;
case 328:
-
-/* Line 1806 of yacc.c */
-#line 2038 "go.y"
+#line 2040 "go.y"
{
(yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(3) - (3)].type);
@@ -5263,18 +4719,14 @@ yyreduce:
break;
case 329:
-
-/* Line 1806 of yacc.c */
-#line 2046 "go.y"
+#line 2048 "go.y"
{
(yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list));
}
break;
case 330:
-
-/* Line 1806 of yacc.c */
-#line 2052 "go.y"
+#line 2054 "go.y"
{
(yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type)));
if((yyvsp[(1) - (3)].sym))
@@ -5284,9 +4736,7 @@ yyreduce:
break;
case 331:
-
-/* Line 1806 of yacc.c */
-#line 2059 "go.y"
+#line 2061 "go.y"
{
Type *t;
@@ -5303,9 +4753,7 @@ yyreduce:
break;
case 332:
-
-/* Line 1806 of yacc.c */
-#line 2075 "go.y"
+#line 2077 "go.y"
{
Sym *s;
Pkg *p;
@@ -5328,63 +4776,49 @@ yyreduce:
break;
case 333:
-
-/* Line 1806 of yacc.c */
-#line 2097 "go.y"
+#line 2099 "go.y"
{
(yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list))));
}
break;
case 334:
-
-/* Line 1806 of yacc.c */
-#line 2101 "go.y"
+#line 2103 "go.y"
{
(yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)));
}
break;
case 335:
-
-/* Line 1806 of yacc.c */
-#line 2106 "go.y"
+#line 2108 "go.y"
{
(yyval.list) = nil;
}
break;
case 337:
-
-/* Line 1806 of yacc.c */
-#line 2113 "go.y"
+#line 2115 "go.y"
{
(yyval.list) = (yyvsp[(2) - (3)].list);
}
break;
case 338:
-
-/* Line 1806 of yacc.c */
-#line 2117 "go.y"
+#line 2119 "go.y"
{
(yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))));
}
break;
case 339:
-
-/* Line 1806 of yacc.c */
-#line 2127 "go.y"
+#line 2129 "go.y"
{
(yyval.node) = nodlit((yyvsp[(1) - (1)].val));
}
break;
case 340:
-
-/* Line 1806 of yacc.c */
-#line 2131 "go.y"
+#line 2133 "go.y"
{
(yyval.node) = nodlit((yyvsp[(2) - (2)].val));
switch((yyval.node)->val.ctype){
@@ -5395,6 +4829,10 @@ yyreduce:
case CTFLT:
mpnegflt((yyval.node)->val.u.fval);
break;
+ case CTCPLX:
+ mpnegflt(&(yyval.node)->val.u.cval->real);
+ mpnegflt(&(yyval.node)->val.u.cval->imag);
+ break;
default:
yyerror("bad negated constant");
}
@@ -5402,9 +4840,7 @@ yyreduce:
break;
case 341:
-
-/* Line 1806 of yacc.c */
-#line 2146 "go.y"
+#line 2152 "go.y"
{
(yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg));
if((yyval.node)->op != OLITERAL)
@@ -5413,9 +4849,7 @@ yyreduce:
break;
case 343:
-
-/* Line 1806 of yacc.c */
-#line 2155 "go.y"
+#line 2161 "go.y"
{
if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) {
(yyval.node) = (yyvsp[(2) - (5)].node);
@@ -5429,76 +4863,52 @@ yyreduce:
break;
case 346:
-
-/* Line 1806 of yacc.c */
-#line 2171 "go.y"
+#line 2177 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 347:
-
-/* Line 1806 of yacc.c */
-#line 2175 "go.y"
+#line 2181 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 348:
-
-/* Line 1806 of yacc.c */
-#line 2181 "go.y"
+#line 2187 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 349:
-
-/* Line 1806 of yacc.c */
-#line 2185 "go.y"
+#line 2191 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 350:
-
-/* Line 1806 of yacc.c */
-#line 2191 "go.y"
+#line 2197 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 351:
-
-/* Line 1806 of yacc.c */
-#line 2195 "go.y"
+#line 2201 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
-
-/* Line 1806 of yacc.c */
-#line 5490 "y.tab.c"
+/* Line 1267 of yacc.c. */
+#line 4911 "y.tab.c"
default: break;
}
- /* User semantic actions sometimes alter yychar, and that requires
- that yytoken be updated with the new translation. We take the
- approach of translating immediately before every use of yytoken.
- One alternative is translating here after every semantic action,
- but that translation would be missed if the semantic action invokes
- YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
- if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
- incorrect destructor might then be invoked immediately. In the
- case of YYERROR or YYBACKUP, subsequent parser actions might lead
- to an incorrect destructor call or verbose syntax error message
- before the lookahead is translated. */
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
YYPOPSTACK (yylen);
@@ -5507,6 +4917,7 @@ yyreduce:
*++yyvsp = yyval;
+
/* Now `shift' the result of the reduction. Determine what state
that goes to, based on the state we popped back to and the rule
number reduced by. */
@@ -5526,10 +4937,6 @@ yyreduce:
| yyerrlab -- here on detecting error |
`------------------------------------*/
yyerrlab:
- /* Make sure we have latest lookahead translation. See comments at
- user semantic actions for why this is necessary. */
- yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
-
/* If not already recovering from an error, report this error. */
if (!yyerrstatus)
{
@@ -5537,36 +4944,37 @@ yyerrlab:
#if ! YYERROR_VERBOSE
yyerror (YY_("syntax error"));
#else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
- yyssp, yytoken)
{
- char *yymsgp = YY_("syntax error");
- int yysyntax_error_status;
- yysyntax_error_status = YYSYNTAX_ERROR;
- if (yysyntax_error_status == 0)
- yymsgp = yymsg;
- else if (yysyntax_error_status == 1)
- {
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
- if (!yymsg)
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- yysyntax_error_status = 2;
- }
- else
- {
- yysyntax_error_status = YYSYNTAX_ERROR;
- yymsgp = yymsg;
- }
- }
- yyerror (yymsgp);
- if (yysyntax_error_status == 2)
- goto yyexhaustedlab;
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
}
-# undef YYSYNTAX_ERROR
#endif
}
@@ -5574,7 +4982,7 @@ yyerrlab:
if (yyerrstatus == 3)
{
- /* If just tried and failed to reuse lookahead token after an
+ /* If just tried and failed to reuse look-ahead token after an
error, discard it. */
if (yychar <= YYEOF)
@@ -5591,7 +4999,7 @@ yyerrlab:
}
}
- /* Else will try to reuse lookahead token after shifting the error
+ /* Else will try to reuse look-ahead token after shifting the error
token. */
goto yyerrlab1;
@@ -5625,7 +5033,7 @@ yyerrlab1:
for (;;)
{
yyn = yypact[yystate];
- if (!yypact_value_is_default (yyn))
+ if (yyn != YYPACT_NINF)
{
yyn += YYTERROR;
if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
@@ -5648,6 +5056,9 @@ yyerrlab1:
YY_STACK_PRINT (yyss, yyssp);
}
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
*++yyvsp = yylval;
@@ -5672,7 +5083,7 @@ yyabortlab:
yyresult = 1;
goto yyreturn;
-#if !defined(yyoverflow) || YYERROR_VERBOSE
+#ifndef yyoverflow
/*-------------------------------------------------.
| yyexhaustedlab -- memory exhaustion comes here. |
`-------------------------------------------------*/
@@ -5683,14 +5094,9 @@ yyexhaustedlab:
#endif
yyreturn:
- if (yychar != YYEMPTY)
- {
- /* Make sure we have latest lookahead translation. See comments at
- user semantic actions for why this is necessary. */
- yytoken = YYTRANSLATE (yychar);
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- }
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
/* Do not reclaim the symbols of the rule which action triggered
this YYABORT or YYACCEPT. */
YYPOPSTACK (yylen);
@@ -5714,9 +5120,7 @@ yyreturn:
}
-
-/* Line 2067 of yacc.c */
-#line 2199 "go.y"
+#line 2205 "go.y"
static void
diff --git a/src/cmd/gc/y.tab.h b/src/cmd/gc/y.tab.h
index 6eeb831b2..d01fbe198 100644
--- a/src/cmd/gc/y.tab.h
+++ b/src/cmd/gc/y.tab.h
@@ -1,21 +1,24 @@
-/* A Bison parser, made by GNU Bison 2.5. */
+/* A Bison parser, made by GNU Bison 2.3. */
-/* Bison interface for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -26,11 +29,10 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
-
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -144,28 +146,22 @@
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-{
-
-/* Line 2068 of yacc.c */
#line 28 "go.y"
-
+{
Node* node;
NodeList* list;
Type* type;
Sym* sym;
struct Val val;
int i;
-
-
-
-/* Line 2068 of yacc.c */
-#line 163 "y.tab.h"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
+}
+/* Line 1529 of yacc.c. */
+#line 160 "y.tab.h"
+ YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE yylval;
-