Repository: go
Issue: cmd/compile: some problems on optimization when takes care about of arrays in struct
Labels: Performance,help wanted,NeedsFix,compiler/runtime

As @ianlancetaylor and @ALTree mentioned, I changed the version from 1.7.4 to 1.8.1 to show the bug clearly.
### What version of Go are you using (`go version`)?
```go
go version go1.8.1 linux/amd64
```

### What operating system and processor architecture are you using (`go env`)?
```go
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH=""
GORACE=""
GOROOT="/home/zhaozq/src/go"
GOTOOLDIR="/home/zhaozq/src/go/pkg/tool/linux_amd64"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build701526462=/tmp/go-build"
CXX="g++"
CGO_ENABLED="1"
```

### What did you do?
I test several examples to test the performance of iterating an array. All of the version are compile by `go build`
#### version I
I put the array into a struct 
```go
package main

const NUM = 100

type T struct {
     arr [NUM]int
}

func sub(t *T) {
     for i := 0; i < NUM; i++ {
         t.arr[i] = 3
     }
}

func main() {
     var t T
     sub(&t)
}
```

The assemble of function sub is

```go
000000000044d5b0 <main.sub>:
  44d5b0:       48 8b 44 24 08          mov    0x8(%rsp),%rax
  44d5b5:       31 c9                   xor    %ecx,%ecx
  44d5b7:       48 83 f9 64             cmp    $0x64,%rcx
  44d5bb:       7d 13                   jge    44d5d0 <main.sub+0x20>
  44d5bd:       84 00                   test   %al,(%rax)
  44d5bf:       48 c7 04 c8 03 00 00    movq   $0x3,(%rax,%rcx,8)
  44d5c6:       00
  44d5c7:       48 ff c1                inc    %rcx
  44d5ca:       48 83 f9 64             cmp    $0x64,%rcx
  44d5ce:       7c ed                   jl     44d5bd <main.sub+0xd>
  44d5d0:       c3                      retq
```

And the loop is

```go
  44d5bd:       84 00                   test   %al,(%rax)
  44d5bf:       48 c7 04 c8 03 00 00    movq   $0x3,(%rax,%rcx,8)
  44d5c6:       00
  44d5c7:       48 ff c1                inc    %rcx
  44d5ca:       48 83 f9 64             cmp    $0x64,%rcx
  44d5ce:       7c ed                   jl     44d5bd <main.sub+0xd>
```

The line `44d5bd`is quite strange. What's the usage of `test` here?? I think it's useless, and it will waste a cycle. We care about it, because we will use this kind of function a lot.



#### version II

We use a way to make the compiler do not what we are passing.

```go
package main

import "unsafe"

const NUM = 100

type T struct {
     arr [NUM]int
}

func sub(p unsafe.Pointer) {
     for i := 0; i < NUM; i++ {
         *(*int)(p) = 3
         p = unsafe.Pointer(uintptr(p) + 8)
     }
}

func main() {
     var t T
     sub(unsafe.Pointer(&t))
}
```

The assembler of function sub

```go
000000000044d5b0 <main.sub>:
  44d5b0:       48 8b 44 24 08          mov    0x8(%rsp),%rax
  44d5b5:       31 c9                   xor    %ecx,%ecx
  44d5b7:       48 83 f9 64             cmp    $0x64,%rcx
  44d5bb:       7d 14                   jge    44d5d1 <main.sub+0x21>
  44d5bd:       48 c7 00 03 00 00 00    movq   $0x3,(%rax)
  44d5c4:       48 ff c1                inc    %rcx
  44d5c7:       48 83 c0 08             add    $0x8,%rax
  44d5cb:       48 83 f9 64             cmp    $0x64,%rcx
  44d5cf:       7c ec                   jl     44d5bd <main.sub+0xd>
  44d5d1:       c3                      retq
```

The loop is

```go
  44d5bd:       48 c7 00 03 00 00 00    movq   $0x3,(%rax)
  44d5c4:       48 ff c1                inc    %rcx
  44d5c7:       48 83 c0 08             add    $0x8,%rax
  44d5cb:       48 83 f9 64             cmp    $0x64,%rcx
  44d5cf:       7c ec                   jl     44d5bd <main.sub+0xd>
```

The number of operations in version II is the same as version I, but memory read times have been reduced, so this kind of version is faster.

#### version III

To reduce the numbers of operations in version II, I changed again.

```go
package main

import "unsafe"

const NUM = 100

type T struct {
     arr [NUM]int
}

func sub(p unsafe.Pointer) {
     maxp := uintptr(p) + 8 * NUM
     for ; uintptr(p) < maxp; {
         *(*int)(p) = 3
         p = unsafe.Pointer(uintptr(p) + 8)
     }
}

func main() {
     var t T
     sub(unsafe.Pointer(&t))
}
```

The assemble of function sub

```go
000000000044d5b0 <main.sub>:
  44d5b0:       48 8b 44 24 08          mov    0x8(%rsp),%rax
  44d5b5:       48 89 c1                mov    %rax,%rcx
  44d5b8:       48 81 c1 20 03 00 00    add    $0x320,%rcx
  44d5bf:       48 89 c2                mov    %rax,%rdx
  44d5c2:       48 39 ca                cmp    %rcx,%rdx
  44d5c5:       73 13                   jae    44d5da <main.sub+0x2a>
  44d5c7:       48 c7 00 03 00 00 00    movq   $0x3,(%rax)
  44d5ce:       48 83 c0 08             add    $0x8,%rax
  44d5d2:       48 89 c2                mov    %rax,%rdx
  44d5d5:       48 39 ca                cmp    %rcx,%rdx
  44d5d8:       72 ed                   jb     44d5c7 <main.sub+0x17>
  44d5da:       c3                      retq
```

The loop is

```go
  44d5c7:       48 c7 00 03 00 00 00    movq   $0x3,(%rax)
  44d5ce:       48 83 c0 08             add    $0x8,%rax
  44d5d2:       48 89 c2                mov    %rax,%rdx
  44d5d5:       48 39 ca                cmp    %rcx,%rdx
  44d5d8:       72 ed                   jb     44d5c7 <main.sub+0x17>
```

The number of operations are not reduced. The reason is `44d5d2` and `44d5d2`.

```go
  44d5d2:       48 89 c2                mov    %rax,%rdx
  44d5d5:       48 39 ca                cmp    %rcx,%rdx```

Why not `cmp %rcx %rax`? Why introduce `%rdx`....?

### What did you expect to see?

Please focus version I and version III.