From: Youlin Feng Date: Sat, 31 Jan 2026 03:23:41 +0000 (+0800) Subject: cmd/compile: fix slice bounds check elimination after function inlining X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=2a1d605e7f5a0f8870abb9cc26edf27db3ad5452;p=gostls13.git cmd/compile: fix slice bounds check elimination after function inlining When creating a dynamically-sized slice, the compiler attempts to use a stack-allocated buffer if the slice does not escape and its buffer size is ≤ 32 bytes. In this case, the SSA will contain a (OpPhi (OpSliceMake) (OpSliceMake)) value: one OpSliceMake uses the stack-allocated buffer, and the other uses the heap-allocated buffer. The len and cap arguments for these two OpSliceMake values are expected to be identical. This CL enables the prove pass to recognize this scenario and handle OpSliceLen and OpSliceCap as intended. Fixes #77375 Change-Id: Id77a2473caf66d366f5c94108aa6cb6d3df5b887 Reviewed-on: https://go-review.googlesource.com/c/go/+/740840 Reviewed-by: Keith Randall Reviewed-by: Junyang Shao LUCI-TryBot-Result: Go LUCI Auto-Submit: Keith Randall Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules index b34fee095e..495a8d9dbf 100644 --- a/src/cmd/compile/internal/ssa/_gen/generic.rules +++ b/src/cmd/compile/internal/ssa/_gen/generic.rules @@ -1017,6 +1017,8 @@ (ConstNil ) (Const64 [0]) (Const64 [0])) +(SliceLen (Phi (SliceMake _ x _) (SliceMake _ x _))) => x +(SliceCap (Phi (SliceMake _ _ x) (SliceMake _ _ x))) => x // Special rule to help constant slicing; len > 0 implies cap > 0 implies Slicemask is all 1 (SliceMake (AddPtr x (And64 y (Slicemask _))) w:(Const64 [c]) z) && c > 0 => (SliceMake (AddPtr x y) w z) diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go index 0bc97db73c..27234b4f93 100644 --- a/src/cmd/compile/internal/ssa/prove.go +++ b/src/cmd/compile/internal/ssa/prove.go @@ -3063,7 +3063,7 @@ func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) { func removeBranch(b *Block, branch branch) { c := b.Controls[0] - if b.Func.pass.debug > 0 { + if c != nil && b.Func.pass.debug > 0 { verb := "Proved" if branch == positive { verb = "Disproved" diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index ee74d7c971..4e8f7039d7 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -30705,6 +30705,29 @@ func rewriteValuegeneric_OpSliceCap(v *Value) bool { v.AddArg(x) return true } + // match: (SliceCap (Phi (SliceMake _ _ x) (SliceMake _ _ x))) + // result: x + for { + if v_0.Op != OpPhi || len(v_0.Args) != 2 { + break + } + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + if v_0_0.Op != OpSliceMake { + break + } + x := v_0_0.Args[2] + v_0_1 := v_0.Args[1] + if v_0_1.Op != OpSliceMake { + break + } + _ = v_0_1.Args[2] + if x != v_0_1.Args[2] { + break + } + v.copyOf(x) + return true + } return false } func rewriteValuegeneric_OpSliceLen(v *Value) bool { @@ -30761,6 +30784,29 @@ func rewriteValuegeneric_OpSliceLen(v *Value) bool { v.AddArg(x) return true } + // match: (SliceLen (Phi (SliceMake _ x _) (SliceMake _ x _))) + // result: x + for { + if v_0.Op != OpPhi || len(v_0.Args) != 2 { + break + } + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + if v_0_0.Op != OpSliceMake { + break + } + x := v_0_0.Args[1] + v_0_1 := v_0.Args[1] + if v_0_1.Op != OpSliceMake { + break + } + _ = v_0_1.Args[1] + if x != v_0_1.Args[1] { + break + } + v.copyOf(x) + return true + } // match: (SliceLen (SelectN [0] (StaticLECall {sym} _ newLen:(Const64) _ _ _ _))) // cond: (isSameCall(sym, "runtime.growslice") || isSameCall(sym, "runtime.growsliceNoAlias")) // result: newLen diff --git a/test/codegen/issue77375.go b/test/codegen/issue77375.go new file mode 100644 index 0000000000..f74ce399fa --- /dev/null +++ b/test/codegen/issue77375.go @@ -0,0 +1,39 @@ +// asmcheck + +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package codegen + +func Range(n int) []int { + m := make([]int, n) + + for i := 0; i < n; i++ { + m[i] = i + } + + for i := range n { + m[i] = i + } + + for i := range len(m) { + m[i] = i + } + + for i := range m { + m[i] = i + } + + return m +} + +func F(size int) { + // amd64:-`.*panicBounds` + // arm64:-`.*panicBounds` + Range(size) +} + +func main() { + F(-1) +}