Extend rewriteresults to handle functions where only some explicit
returns return a local. For example:
func f(x uint64, c bool) [16]byte {
var ret [16]byte
use(ret[:8], x)
if c {
return ret
}
return [16]byte{1}
}
The previous CL handles the case where every explicit return returns the
same local. This CL relaxes that to require only that every direct local
return for a given result slot returns the same local. Other return
expressions for that slot are left alone.
The post-escape placement introduced in the first CL is what keeps
this weaker pattern safe: the pass rejects locals that escape to the
heap. If a local's address escapes, another return path that
overwrites the result slot could otherwise change what the escaped
pointer observes.
The rewrite remains conservative: no defers, no naked returns, explicit
return counts must match the signature, result parameters must be
anonymous, the local must have a normal zeroing declaration, must not be
closure-captured, must not escape to the heap, and must not map to
multiple result slots.
compilecmp results (this CL vs parent, over std cmd):
file before after delta %
addr2line 3956269 3953365 -2904 -0.073%
asm 7237685 7235373 -2312 -0.032%
buildid 3826062 3823646 -2416 -0.063%
cgo 6195346 6192738 -2608 -0.042%
compile 37103491 37095195 -8296 -0.022%
cover 7917704 7910176 -7528 -0.095%
dist 5336503 5333223 -3280 -0.061%
distpack 4040039 4038759 -1280 -0.032%
fix 12721347 12716307 -5040 -0.040%
link 10108535 10106679 -1856 -0.018%
nm 3935967 3932927 -3040 -0.077%
objdump 6581468 6578508 -2960 -0.045%
pack 3266676 3265284 -1392 -0.043%
pprof 20281781 20271101 -10680 -0.053%
test2json 4575312 4572568 -2744 -0.060%
trace 18689578 18675114 -14464 -0.077%
vet 12307501 12302205 -5296 -0.043%
total 176007153 175925057 -82096 -0.047%
Function text size changes over std cmd total -2550 bytes (-0.006%).
Representative changes include:
internal/gover.Parse 1481 -> 1150 (-22.35%)
vendor/golang.org/x/net/dns/dnsmessage.(*Parser).resource 968 -> 741 (-23.45%)
vendor/golang.org/x/net/dns/dnsmessage.(*Parser).resourceHeader 634 -> 523 (-17.51%)
time.tzsetRule 2458 -> 2298 (-6.51%)
crypto/rsa.(*PrivateKey).precompute 3113 -> 2591 (-16.77%)
net.(*Resolver).lookup 1212 -> 1157 (-4.54%)
Overall compilecmp effect of this CL stack (vs master):
file before after delta %
addr2line 3957733 3953365 -4368 -0.110%
asm 7239069 7235373 -3696 -0.051%
buildid 3826382 3823646 -2736 -0.072%
cgo 6197914 6192738 -5176 -0.084%
compile 37100088 37095195 -4893 -0.013%
cover 7920312 7910176 -10136 -0.128%
dist 5338479 5333223 -5256 -0.098%
distpack 4045463 4038759 -6704 -0.166%
fix 12725363 12716307 -9056 -0.071%
link 10112423 10106679 -5744 -0.057%
nm 3937359 3932927 -4432 -0.113%
objdump 6583348 6578508 -4840 -0.074%
pack 3267644 3265284 -2360 -0.072%
pprof 20295357 20271101 -24256 -0.120%
test2json 4576784 4572568 -4216 -0.092%
trace 18698274 18675114 -23160 -0.124%
vet 12311989 12302205 -9784 -0.079%
total 176062230 175925057 -137173 -0.078%
Updates #20859
Change-Id: Ia423f28edc2366f6e01001cb3d05380ee4da5af0
Reviewed-on: https://go-review.googlesource.com/c/go/+/779002
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
64 lines
1.2 KiB
Go
64 lines
1.2 KiB
Go
// 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
|
|
|
|
//go:noinline
|
|
func use16(b []byte, x uint64) {
|
|
b[0] = byte(x)
|
|
}
|
|
|
|
//go:noinline
|
|
func resultSlotArray(x uint64) [16]byte {
|
|
var ret [16]byte
|
|
// amd64:-`.*\.ret\+`
|
|
use16(ret[:8], x)
|
|
// amd64:-`.*\.ret\+`
|
|
use16(ret[8:], x)
|
|
// amd64:-`.*\.ret\+` -`.*MOVUPS.*~r0`
|
|
return ret
|
|
}
|
|
|
|
//go:noinline
|
|
func resultSlotArrayMultipleReturns(x uint64, c bool) [16]byte {
|
|
var ret [16]byte
|
|
// amd64:-`.*\.ret\+`
|
|
use16(ret[:8], x)
|
|
if c {
|
|
// amd64:-`.*\.ret\+` -`.*MOVUPS.*~r0`
|
|
return ret
|
|
}
|
|
// amd64:-`.*\.ret\+`
|
|
use16(ret[8:], x)
|
|
// amd64:-`.*\.ret\+` -`.*MOVUPS.*~r0`
|
|
return ret
|
|
}
|
|
|
|
//go:noinline
|
|
func resultSlotPartialReturn(x uint64, c bool) [16]byte {
|
|
var ret [16]byte
|
|
// amd64:-`.*\.ret\+`
|
|
use16(ret[:8], x)
|
|
if c {
|
|
// amd64:-`.*\.ret\+` -`.*MOVUPS.*~r0`
|
|
return ret
|
|
}
|
|
return [16]byte{1}
|
|
}
|
|
|
|
//go:noinline
|
|
func resultSlotPartialReturnLocal(x uint64, c bool) [16]byte {
|
|
var ret [16]byte
|
|
// amd64:-`.*\.ret\+`
|
|
use16(ret[:8], x)
|
|
if c {
|
|
// amd64:-`.*\.ret\+` -`.*MOVUPS.*~r0`
|
|
return ret
|
|
}
|
|
other := [16]byte{1}
|
|
return other
|
|
}
|