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

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)