[dev.ssa] cmd/compile/internal/ssa: fix string index

Change-Id: I984d3e0410ac38c4e42ae8e3670ea47e2140de76
Reviewed-on: https://go-review.googlesource.com/14466
Reviewed-by: Alexandru Moșoi <alexandru@mosoi.ro>
Reviewed-by: Todd Neal <todd@tneal.org>
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 70350e0..0551ddb 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -1693,19 +1693,22 @@
 			a := s.expr(n.Left)
 			i := s.expr(n.Right)
 			i = s.extendIndex(i)
-			var elemtype *Type
-			var len *ssa.Value
 			if n.Left.Type.IsString() {
-				len = s.newValue1(ssa.OpStringLen, Types[TINT], a)
-				elemtype = Types[TUINT8]
+				if !n.Bounded {
+					len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
+					s.boundsCheck(i, len)
+				}
+				ptrtyp := Ptrto(Types[TUINT8])
+				ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
+				ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
+				return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
 			} else {
-				len = s.constInt(Types[TINT], n.Left.Type.Bound)
-				elemtype = n.Left.Type.Type
+				if !n.Bounded {
+					len := s.constInt(Types[TINT], n.Left.Type.Bound)
+					s.boundsCheck(i, len)
+				}
+				return s.newValue2(ssa.OpArrayIndex, n.Left.Type.Type, a, i)
 			}
-			if !n.Bounded {
-				s.boundsCheck(i, len)
-			}
-			return s.newValue2(ssa.OpArrayIndex, elemtype, a, i)
 		} else { // slice
 			p := s.addr(n)
 			return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
diff --git a/src/cmd/compile/internal/gc/testdata/string_ssa.go b/src/cmd/compile/internal/gc/testdata/string_ssa.go
index 448433a..0ff6ce1 100644
--- a/src/cmd/compile/internal/gc/testdata/string_ssa.go
+++ b/src/cmd/compile/internal/gc/testdata/string_ssa.go
@@ -70,6 +70,7 @@
 	p.slice_ssa()
 	if "pre" != p.prefix {
 		println("wrong field slice: wanted %s got %s", "pre", p.prefix)
+		failed = true
 	}
 }
 
@@ -114,11 +115,51 @@
 	}
 }
 
+func testStringElem_ssa(s string, i int) byte {
+	switch { // prevent inlining
+	}
+	return s[i]
+}
+
+func testStringElem() {
+	tests := []struct {
+		s string
+		i int
+		n byte
+	}{
+		{"foobar", 3, 98},
+		{"foobar", 0, 102},
+		{"foobar", 5, 114},
+	}
+	for _, t := range tests {
+		if got := testStringElem_ssa(t.s, t.i); got != t.n {
+			print("testStringElem \"", t.s, "\"[", t.i, "]=", got, ", wanted ", t.n, "\n")
+			failed = true
+		}
+	}
+}
+
+func testStringElemConst_ssa(i int) byte {
+	switch { // prevent inlining
+	}
+	s := "foobar"
+	return s[i]
+}
+
+func testStringElemConst() {
+	if got := testStringElemConst_ssa(3); got != 98 {
+		println("testStringElemConst=", got, ", wanted 98")
+		failed = true
+	}
+}
+
 func main() {
 	testStringSlice()
 	testStringSlicePanic()
 	testStructSlice()
 	testSmallIndexType()
+	testStringElem()
+	testStringElemConst()
 
 	if failed {
 		panic("failed")