Skip to content

cmd/compile: bounds check elision cannot reason through non-dominating blocks #78946

Description

@mcy

Consider the following program:

//go:nosplit
func use(z, x []int) int {
    if len(x) == 0 {
        return 0
    } else if len(x) > cap(z) {
        z = make([]int, len(x))
    } else {
        z = z[:len(x)]
    }
    return z[len(x)-1]
}

There is no input which can make it panic, but it emits a bounds check for z[len(x)-1], despite len(z) == len(x) > 0:

        TEXT    .use(SB), NOSPLIT|ABIInternal, $64-48
        PUSHQ   BP
        MOVQ    SP, BP
        SUBQ    $56, SP
        MOVQ    AX, 72(FP)
        MOVQ    DI, 96(FP)
        TESTQ   SI, SI
        JEQ     pc112
        CMPQ    CX, SI
        JGE     pc87
        NOP
        CMPQ    SI, $4
        JHI    pc59
        LEAQ    24(SP), CX
        MOVUPS  X15, (CX)
        MOVUPS  X15, 16(CX)
        LEAQ    24(SP), AX
        JMP     pc87
pc59:
        MOVQ    SI, 104(SP)
        LEAQ    type:int(SB), AX
        MOVQ    SI, BX
        MOVQ    BX, CX
        CALL    runtime.makeslice(SB)
        MOVQ    104(SP), SI
pc87:
        LEAQ    -1(SI), CX
        NOP
        CMPQ    SI, CX
        JLS     pc120
        MOVQ    -8(AX)(SI*8), AX
        ADDQ    $56, SP
        POPQ    BP
        RET
pc112:
        XORL    AX, AX
        ADDQ    $56, SP
        POPQ    BP
        RET
pc120:
        CALL    runtime.panicBounds(SB)

After much poking at the structure of this code, I've concluded that the issue is the fact that the bounds information comes from non-dominating blocks which collectively dominate the load. This is unfortunate, because this notably affects math/big.nat.make, which wants to be append(z[:0], make(nat, n)), but in the case where n <= cap(z) results in a redundant call to memclr. This has the knock-on effect that other code in math/big needs to (redundantly) teach the optimizer about bounds checks in the "usual way".

Maybe I'm getting something wrong here, but it looks like a genuine missed optimization to me.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FeatureRequestIssues asking for a new feature that does not need a proposal.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

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Todo

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions