Skip to content

cmd/compile: Extra bounds checking when using addition in condition/index #76270

@fice-t

Description

@fice-t

Go version

go version go1.26-devel_5241d11 Mon Nov 10 12:48:05 2025 -0800 linux/amd64

Output of go env in your module/workspace:

Workspace is `go.godbolt.org` on `x86-64 gc (tip)` as above.

What did you do?

(Code/output used also found here)

Compile containsDotDot from the standard library:

func containsDotDot(s string) bool {
	if len(s) < 2 {
		return false
	}
	for i := 0; i < len(s)-1; i++ {
		if s[i] == '.' && s[i+1] == '.' {
			return true
		}
	}
	return false
}

What did you see happen?

A bounds check + panic section was generated:

        TEXT    command-line-arguments.containsDotDot(SB), NOSPLIT|ABIInternal, $8-16
        [...]
        CMPQ    BX, $2
        JLT     command-line-arguments_containsDotDot_pc19
        XORL    CX, CX
        JMP     command-line-arguments_containsDotDot_pc26
command-line-arguments_containsDotDot_pc19:
        XORL    AX, AX
        POPQ    BP
        RET
command-line-arguments_containsDotDot_pc23:
        INCQ    CX
command-line-arguments_containsDotDot_pc26:
        LEAQ    -1(BX), DX
        NOP
        CMPQ    CX, DX
        JGE     command-line-arguments_containsDotDot_pc76
        MOVBLZX (AX)(CX*1), DX
        CMPB    DL, $46
        JNE     command-line-arguments_containsDotDot_pc23
        LEAQ    1(CX), DX
        CMPQ    BX, DX
        JLS     command-line-arguments_containsDotDot_pc80 ; <--------------------------
        MOVBLZX 1(CX)(AX*1), DX
        NOP
        CMPB    DL, $46
        JNE     command-line-arguments_containsDotDot_pc23
        MOVL    $1, AX
        POPQ    BP
        RET
command-line-arguments_containsDotDot_pc76:
        XORL    AX, AX
        POPQ    BP
        RET
command-line-arguments_containsDotDot_pc80:
        PCDATA  $1, $1
        PCDATA  $4, $3663
        CALL    runtime.panicBounds(SB)
        XCHGL   AX, AX

What did you expect to see?

No bounds check + panic section should be generated as the condition checks for i < len(s)-1, meaning i+1 < len(s).

There are two cases below illustrating the effects of what should be equivalent assembly output:

Case 1: Change of variable (j := i + 1)

This results in no extra bounds checking:

func containsDotDot(s string) bool {
	if len(s) < 2 {
		return false
	}
	for j := 1; j < len(s); j++ {
		if s[j-1] == '.' && s[j] == '.' {
			return true
		}
	}
	return false
}

Case 2: Move of constant to other side of condition

This results in both index operations having bounds checks:

func containsDotDot(s string) bool {
	if len(s) < 2 {
		return false
	}
	for i := 0; i+1 < len(s); i++ {
		if s[i] == '.' && s[i+1] == '.' {
			return true
		}
	}
	return false
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugReportIssues describing a possible bug in the Go implementation.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

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions