cmd/compile: don't use statictmps for small object in slice literal

Fixes #21561

Change-Id: I89c59752060dd9570d17d73acbbaceaefce5d8ce
Reviewed-on: https://go-review.googlesource.com/c/go/+/197560
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index f36e271..bfd2ce2 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -29,6 +29,12 @@
 	//   s := []byte("...")   allocating [n]byte on the stack
 	// Note: the flag smallframes can update this value.
 	maxImplicitStackVarSize = int64(64 * 1024)
+
+	// smallArrayBytes is the maximum size of an array which is considered small.
+	// Small arrays will be initialized directly with a sequence of constant stores.
+	// Large arrays will be initialized by copying from a static temp.
+	// 256 bytes was chosen to minimize generated code + statictmp size.
+	smallArrayBytes = int64(256)
 )
 
 // isRuntimePkg reports whether p is package runtime.
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index a6d13d1..96b3430 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -582,6 +582,16 @@
 	}
 }
 
+func isSmallSliceLit(n *Node) bool {
+	if n.Op != OSLICELIT {
+		return false
+	}
+
+	r := n.Right
+
+	return smallintconst(r) && (n.Type.Elem().Width == 0 || r.Int64() <= smallArrayBytes/n.Type.Elem().Width)
+}
+
 func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
 	// make an array type corresponding the number of elements we have
 	t := types.NewArray(n.Type.Elem(), n.Right.Int64())
@@ -639,7 +649,7 @@
 	var vstat *Node
 
 	mode := getdyn(n, true)
-	if mode&initConst != 0 {
+	if mode&initConst != 0 && !isSmallSliceLit(n) {
 		vstat = staticname(t)
 		if ctxt == inInitFunction {
 			vstat.Name.SetReadonly(true)
diff --git a/test/codegen/slices.go b/test/codegen/slices.go
index fccd711..cf569e2 100644
--- a/test/codegen/slices.go
+++ b/test/codegen/slices.go
@@ -113,3 +113,54 @@
 	// amd64:-`TESTB`
 	_ = *p
 }
+
+// ---------------------- //
+//   Init slice literal   //
+// ---------------------- //
+// See issue 21561
+func InitSmallSliceLiteral() []int {
+	// amd64:`MOVQ\t[$]42`
+	return []int{42}
+}
+
+func InitNotSmallSliceLiteral() []int {
+	// amd64:`MOVQ\t.*autotmp_`
+	return []int{
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+		42,
+	}
+}