cmd/gc: allocate buffers for non-escaping string conversions on stack

Support the following conversions in escape analysis:
[]rune("foo")
[]byte("foo")
string([]rune{})

If the result does not escape, allocate temp buffer on stack
and pass it to runtime functions.

Change-Id: I1d075907eab8b0109ad7ad1878104b02b3d5c690
Reviewed-on: https://go-review.googlesource.com/3590
Reviewed-by: Russ Cox <rsc@golang.org>
diff --git a/test/escape2n.go b/test/escape2n.go
index 31f4ed0..d9d95e8 100644
--- a/test/escape2n.go
+++ b/test/escape2n.go
@@ -212,7 +212,7 @@
 func foo21a() func() int {
 	x := 42             // ERROR "moved to heap: x"
 	return func() int { // ERROR "func literal escapes to heap"
-		x++  // ERROR "&x escapes to heap"
+		x++ // ERROR "&x escapes to heap"
 		return x
 	}
 }
@@ -1560,14 +1560,14 @@
 
 func ptrlitNoEscape2() {
 	// Literal does not escape, but element does.
-	i := 0 // ERROR "moved to heap: i"
+	i := 0        // ERROR "moved to heap: i"
 	x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap"
 	sink = *x
 }
 
 func ptrlitEscape() {
 	// Both literal and element escape.
-	i := 0 // ERROR "moved to heap: i"
+	i := 0        // ERROR "moved to heap: i"
 	x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap"
 	sink = x
 }
@@ -1619,7 +1619,7 @@
 // to just x, and thus &i looks escaping.
 func fieldFlowTracking() {
 	var x StructWithString
-	i := 0 // ERROR "moved to heap: i"
+	i := 0   // ERROR "moved to heap: i"
 	x.p = &i // ERROR "&i escapes to heap"
 	sink = x.s
 }
@@ -1703,3 +1703,51 @@
 	s := string(x) // ERROR "string\(x\) escapes to heap" "moved to heap: s"
 	sink = &s      // ERROR "&s escapes to heap"
 }
+
+func stringtoslicebyte0() {
+	s := "foo"
+	x := []byte(s) // ERROR "\(\[\]byte\)\(s\) does not escape"
+	_ = x
+}
+
+func stringtoslicebyte1() []byte {
+	s := "foo"
+	return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap"
+}
+
+func stringtoslicebyte2() {
+	s := "foo"
+	sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap"
+}
+
+func stringtoslicerune0() {
+	s := "foo"
+	x := []rune(s) // ERROR "\(\[\]rune\)\(s\) does not escape"
+	_ = x
+}
+
+func stringtoslicerune1() []rune {
+	s := "foo"
+	return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap"
+}
+
+func stringtoslicerune2() {
+	s := "foo"
+	sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap"
+}
+
+func slicerunetostring0() {
+	r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
+	s := string(r)       // ERROR "string\(r\) does not escape"
+	_ = s
+}
+
+func slicerunetostring1() string {
+	r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
+	return string(r)     // ERROR "string\(r\) escapes to heap"
+}
+
+func slicerunetostring2() {
+	r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
+	sink = string(r)     // ERROR "string\(r\) escapes to heap"
+}