parent: 17086:2879112bff3d tip, linux/amd64
The program is:
package main
import "sync"
func main() {
println(foo(0))
}
func foo(x int) int {
// fast path
if x != 42 {
return x
}
// slow path
mu.Lock()
defer mu.Unlock()
seq++
return seq
}
var (
mu sync.Mutex
seq int
)
The generated code for fast path is:
func foo(x int) int {
400c40: 64 48 8b 0c 25 f0 ff mov %fs:0xfffffffffffffff0,%rcx
400c47: ff ff
400c49: 48 3b 21 cmp (%rcx),%rsp
400c4c: 77 05 ja 400c53 <main.foo+0x13>
400c4e: e8 bd 81 01 00 callq 418e10 <runtime.morestack16>
400c53: 48 83 ec 08 sub $0x8,%rsp
400c57: 48 8b 44 24 10 mov 0x10(%rsp),%rax
400c5c: 48 c7 44 24 18 00 00 movq $0x0,0x18(%rsp)
400c63: 00 00
if x != 42 {
400c65: 48 83 f8 2a cmp $0x2a,%rax
400c69: 74 0f je 400c7a <main.foo+0x3a>
return x
400c6b: 48 89 44 24 18 mov %rax,0x18(%rsp)
}
mu.Lock()
defer mu.Unlock()
seq++
return seq
}
400c70: e8 eb b7 00 00 callq 40c460 <runtime.deferreturn>
400c75: 48 83 c4 08 add $0x8,%rsp
400c79: c3 retq
If the compiler performs some CFG analysis, it can figure out that 'callq
runtime.deferreturn' is unnecessary in this case.
Comment From: DanielMorsing
We have some other issues that could use dataflow analysis to solve them, For example issue #5364. It would be a good idea to have a general way of doing DFA. Maybe roll in escape analysis.
Comment From: bradfitz
Labels changed: removed priority-triage.
Status changed to Accepted.
Comment From: rsc
The analysis here can be pretty basic. If the return is above the defer and not in a loop or after a goto'ed label, it doesn't need the deferreturn.
Labels changed: added go1.2maybe.
Comment From: rsc
Labels changed: added feature.
Comment From: robpike
Not for 1.2.
Labels changed: removed go1.2maybe.
Comment From: rsc
Labels changed: added go1.3maybe.
Comment From: rsc
Labels changed: removed feature.
Comment From: rsc
Labels changed: added release-none, removed go1.3maybe.
Comment From: rsc
Labels changed: added repo-main.
Comment From: linsite
building with go 1.24 shows that unnecessray deferreturn is no longer there. can you confirm this can be closed? @dvyukov
$ go version go version go1.24.0 linux/amd64
0x0000000000469847 <+39>: cmp $0x2a,%rax
0x000000000046984b <+43>: jne 0x4698cf
0x00000000004698ce <+174>: retq
0x00000000004698cf <+175>: mov %rax,0x10(%rsp)
0x00000000004698d4 <+180>: add $0x30,%rsp
0x00000000004698d8 <+184>: pop %rbp
0x00000000004698d9 <+185>: retq
0x00000000004698da <+186>: callq 0x430100
Comment From: dvyukov
Please confirm on your end. I've lost all context of this.
Comment From: linsite
Please confirm on your end. I've lost all context of this.
OK, I see it as fixed. cc @seankhliao
Comment From: randall77
Yes, this is fixed. Or maybe more correctly, no longer relevant. We don't have a deferreturn call at each return point any more. There is a single one per function.