cmd/6g: handle very wide offsets.
Fixes #6036.
R=golang-dev, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/12992043
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index d08caf6..fd79c09 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -937,6 +937,7 @@
igen(n->left, a, res);
a->xoffset += n->xoffset;
a->type = n->type;
+ fixlargeoffset(a);
return;
case ODOTPTR:
@@ -945,6 +946,7 @@
a->op = OINDREG;
a->xoffset += n->xoffset;
a->type = n->type;
+ fixlargeoffset(a);
return;
case OCALLFUNC:
@@ -993,6 +995,7 @@
// Compute &a[i] as &a + i*width.
a->type = n->type;
a->xoffset += mpgetfix(n->right->val.u.xval)*n->type->width;
+ fixlargeoffset(a);
return;
}
}
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
index f2f3ac1..3ef59c7 100644
--- a/src/cmd/6g/gg.h
+++ b/src/cmd/6g/gg.h
@@ -132,6 +132,7 @@
void nodfconst(Node*, Type*, Mpflt*);
void gtrack(Sym*);
void gargsize(vlong);
+void fixlargeoffset(Node *n);
/*
* cplx.c
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index 9e8a2b2..0e45cc0 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -1067,6 +1067,29 @@
return p;
}
+void
+fixlargeoffset(Node *n)
+{
+ Node a;
+
+ if(n == N)
+ return;
+ if(n->op != OINDREG)
+ return;
+ if(n->val.u.reg == D_SP) // stack offset cannot be large
+ return;
+ if(n->xoffset != (int32)n->xoffset) {
+ // offset too large, add to register instead.
+ a = *n;
+ a.op = OREGISTER;
+ a.type = types[tptr];
+ a.xoffset = 0;
+ cgen_checknil(&a);
+ ginscon(optoas(OADD, types[tptr]), n->xoffset, &a);
+ n->xoffset = 0;
+ }
+}
+
/*
* generate code to compute n;
* make a refer to result.
@@ -2015,6 +2038,7 @@
a->type = D_NONE;
a->index = D_NONE;
+ fixlargeoffset(&n1);
naddr(&n1, a, 1);
goto yes;
@@ -2176,6 +2200,7 @@
n2 = *reg;
n2.op = OINDREG;
n2.xoffset = v*w;
+ fixlargeoffset(&n2);
a->type = D_NONE;
a->index = D_NONE;
naddr(&n2, a, 1);
@@ -2188,6 +2213,7 @@
reg->op = OREGISTER;
}
n1.xoffset += v*w;
+ fixlargeoffset(&n1);
a->type = D_NONE;
a->index= D_NONE;
naddr(&n1, a, 1);
@@ -2223,6 +2249,7 @@
n2 = *reg;
n2.op = OINDREG;
n2.xoffset = v*w;
+ fixlargeoffset(&n2);
a->type = D_NONE;
a->index = D_NONE;
naddr(&n2, a, 1);
diff --git a/test/fixedbugs/issue6036.go b/test/fixedbugs/issue6036.go
new file mode 100644
index 0000000..5f787c5
--- /dev/null
+++ b/test/fixedbugs/issue6036.go
@@ -0,0 +1,44 @@
+// +build amd64
+// compile
+
+// 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.
+
+// Issue 6036: 6g's backend generates OINDREG with
+// offsets larger than 32-bit.
+
+package main
+
+type T struct {
+ Large [1 << 31]byte
+ A int
+ B int
+}
+
+func F(t *T) {
+ t.B = t.A
+}
+
+type T2 [1<<31 + 2]byte
+
+func F2(t *T2) {
+ t[1<<31+1] = 42
+}
+
+type T3 [1<<15 + 1][1<<15 + 1]int
+
+func F3(t *T3) {
+ t[1<<15][1<<15] = 42
+}
+
+type S struct {
+ A int32
+ B int32
+}
+
+type T4 [1<<29 + 1]S
+
+func F4(t *T4) {
+ t[1<<29].B = 42
+}