Consider the following program:
package x
func z(x int) (*int, int) {
switch x := any(x).(type) {
case *int:
return x, 0
case int:
return nil, x
default:
return nil, 0
}
}
One might imagine this compiles to the following:
TEXT x.z
MOVD R0, R1
MOVD ZR, R0
RET
Unfortunately, it actually performs an allocation:
TEXT x.z(SB), ABIInternal, $32-8
MOVD 16(g), R16
CMP R16, RSP
BLS ...
PCDATA $0, $-1
MOVD.W R30, -32(RSP)
MOVD R29, -8(RSP)
SUB $8, RSP, R29
CALL runtime.convT64(SB)
MOVD (R0), R1
MOVD ZR, R0
MOVD -8(RSP), R29
MOVD.P 32(RSP), R30
RET (R30)
It is fair to argue that this is a duplicate of https://github.com/golang/go/issues/74364, since it's ultimately because the compiler does not perform flow-sensitive escape analysis. However, I believe this case is more egregious and actually represents a compiler phase ordering problem. Once we lower the type switch into a series of branches (presumably in SSA) and delete all of the unreachable branches, we have already decided that any(x)
escapes, and must be heap-allocated.
My original reproduction was about a function containing such a type switch (consider protoreflect.ValueOf()
) unconditionally escaping its any
argument, which is unfortunately common in pre-generic code:
package x
func y(x any) (*int, int) {
switch x := x.(type) {
case *int:
return x, 0
case int:
return nil, x
default:
return nil, 0
}
}
func z(x int) (*int, int) {
return y(x)
}
I was originally planning to argue that inlining should be able to provide a discount to the inlining budget when the callee contains a type switch that, if inlined, could be devirtualized by the callee, since I believed this would eliminate the allocation, side-stepping any inter-procedural escape analysis issues.
Unfortunately, I hit this escape analysis miss, and I don't think that the above inlining suggestion makes sense until this bug is fixed. That said, I'm happy to file an issue about the optimization I suggest above on request.
Comment From: gabyhelp
Related Issues
- cmd/compile: missed devirtualization #51554
- cmd/compile: support conditional escapes by splitting variables #74364
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)