Skip to content

cmd/compile: devirtualized type switch causes temporary allocation to escape #74383

Open
@mcy

Description

@mcy

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 #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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.Performancecompiler/runtimeIssues related to the Go compiler and/or runtime.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions