Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch case order not adhered #17470

Closed
tdewolff opened this issue Oct 16, 2016 · 1 comment
Closed

Switch case order not adhered #17470

tdewolff opened this issue Oct 16, 2016 · 1 comment

Comments

@tdewolff
Copy link

tdewolff commented Oct 16, 2016

What version of Go are you using (go version)?

go version go1.7 windows/amd64

What operating system and processor architecture are you using (go env)?

set GOARCH=amd64
set GOBIN=
set GOEXE=.exe
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=windows
set GOPATH=D:\Go
set GORACE=
set GOROOT=D:\Go1.7
set GOTOOLDIR=D:\Go1.7\pkg\tool\windows_amd64
set CC=gcc
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0 -fdebug-prefix-map=C:\Users\Taco\AppData\Local\Temp\go-build651913466=/tmp/go-build -gno-record-gcc-switches
set CXX=g++
set CGO_ENABLED=1

What did you do?

A switch statement of an integer will order the cases such that the integer is tested by increasing values. The following example would be expected to test first for 2, then 3 and then 1.

package main

var c int

func test(i int) {
    switch i {
    case 2:
        c++
    case 3:
        c++
    case 1:
        c++
    }
}

Instead, the ASM output shows:

        0x0000 00000 (test.go:5)        TEXT    "".test(SB), $0-8
        0x0000 00000 (test.go:5)        NOP
        0x0000 00000 (test.go:5)        NOP
        0x0000 00000 (test.go:5)        FUNCDATA        $0, gclocals·5184031d3a32a42d85027f073f873668(SB)
        0x0000 00000 (test.go:5)        FUNCDATA        $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
        0x0000 00000 (test.go:11)       MOVQ    "".h+8(FP), AX
-->     0x0005 00005 (test.go:11)       CMPQ    AX, $1
        0x0009 00009 (test.go:11)       JNE     29
        0x000b 00011 (test.go:12)       MOVQ    "".c(SB), AX
        0x0012 00018 (test.go:12)       INCQ    AX
        0x0015 00021 (test.go:12)       MOVQ    AX, "".c(SB)
        0x001c 00028 (test.go:14)       RET
-->     0x001d 00029 (test.go:7)        CMPQ    AX, $2
        0x0021 00033 (test.go:7)        JNE     54
        0x0023 00035 (test.go:8)        MOVQ    "".c(SB), AX
        0x002a 00042 (test.go:8)        INCQ    AX
        0x002d 00045 (test.go:8)        MOVQ    AX, "".c(SB)
        0x0034 00052 (test.go:14)       JMP     28
-->     0x0036 00054 (test.go:9)        CMPQ    AX, $3
        0x003a 00058 (test.go:9)        JNE     28
        0x003c 00060 (test.go:10)       MOVQ    "".c(SB), AX
        0x0043 00067 (test.go:10)       INCQ    AX
        0x0046 00070 (test.go:10)       MOVQ    AX, "".c(SB)
        0x004d 00077 (test.go:14)       JMP     28

Here i is tested against 1, then 2 and then 3. A different order in the source code will lead to the same output, it looks like the compiler orders the integer checks by increasing value. This is unexpected, because the docs say that switch will evaluate from top-to-bottom, left-to-right.

I encountered this while rewriting if-else statements to switch statements. I saw a drop in performance because the tests were reordered. Now the most occurring case wasn't the first check...see tdewolff/minify#102

@bradfitz
Copy link
Contributor

The language spec makes no guarantees about the generated code. The spec only guarantees the behaviors.

There is no observable difference in this case, except for performance, as you've noticed. But that is #5496.

I'm going to close this as a dup of #5496.

@golang golang locked and limited conversation to collaborators Oct 16, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants