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
+}