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 <drchase@google.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Keith Randall 2025-11-20 09:42:16 -08:00
parent efe9ad501d
commit 3c6bf6fbf3
2 changed files with 53 additions and 1 deletions

View file

@ -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)

View file

@ -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) {
}