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.