From 3c6bf6fbf38062b24a7cf0390f1e617d733851b3 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 20 Nov 2025 09:42:16 -0800 Subject: [PATCH] cmd/compile: handle loops better during stack allocation of slices Don't use the move2heap optimization if the move2heap is inside a loop deeper than the declaration of the slice. We really only want to do the move2heap operation once. Change-Id: I4a68d01609c2c9d4e0abe4580839e70059393a81 Reviewed-on: https://go-review.googlesource.com/c/go/+/722440 Reviewed-by: David Chase Reviewed-by: Junyang Shao LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/slice/slice.go | 22 ++++++++++++++++- test/codegen/append.go | 32 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/slice/slice.go b/src/cmd/compile/internal/slice/slice.go index 7a32e7adbd..17eba5b772 100644 --- a/src/cmd/compile/internal/slice/slice.go +++ b/src/cmd/compile/internal/slice/slice.go @@ -152,6 +152,11 @@ func analyze(fn *ir.Func) { // least weight 2. (Note: appends in loops have weight >= 2.) appendWeight int + // Loop depth at declaration point. + // Use for heuristics only, it is not guaranteed to be correct + // in the presence of gotos. + declDepth int + // Whether we ever do cap(s), or other operations that use cap(s) // (possibly implicitly), like s[i:j]. capUsed bool @@ -209,6 +214,20 @@ func analyze(fn *ir.Func) { i.s.Opt = nil return } + if loopDepth > i.declDepth { + // Conservatively, we disable this optimization when the + // transition is inside a loop. This can result in adding + // overhead unnecessarily in cases like: + // func f(n int, p *[]byte) { + // var s []byte + // for i := range n { + // *p = s + // s = append(s, 0) + // } + // } + i.s.Opt = nil + return + } i.transition = loc } @@ -237,7 +256,7 @@ func analyze(fn *ir.Func) { // s = append(s, ...) is ok i.okUses += 2 i.appends = append(i.appends, y) - i.appendWeight += 1 + loopDepth + i.appendWeight += 1 + (loopDepth - i.declDepth) } // TODO: s = append(nil, ...)? } @@ -277,6 +296,7 @@ func analyze(fn *ir.Func) { n := n.(*ir.Decl) if i := tracking(n.X); i != nil { i.okUses++ + i.declDepth = loopDepth } case ir.OINDEX: n := n.(*ir.IndexExpr) diff --git a/test/codegen/append.go b/test/codegen/append.go index 0e58a48c45..e90fa87ed2 100644 --- a/test/codegen/append.go +++ b/test/codegen/append.go @@ -185,6 +185,38 @@ func Append17(n int) []int { return r } +func Append18(n int, p *[]int) { + var r []int + for i := range n { + // amd64:-`.*moveSliceNoCapNoScan` + *p = r + // amd64:`.*growslice` + r = append(r, i) + } +} + +func Append19(n int, p [][]int) { + for j := range p { + var r []int + for i := range n { + // amd64:`.*growslice` + r = append(r, i) + } + // amd64:`.*moveSliceNoCapNoScan` + p[j] = r + } +} + +func Append20(n int, p [][]int) { + for j := range p { + var r []int + // amd64:`.*growslice` + r = append(r, 0) + // amd64:-`.*moveSliceNoCapNoScan` + p[j] = r + } +} + //go:noinline func useSlice(s []int) { } -- 2.52.0