cmd/compile: some problems on optimization when takes care about of arrays in struct
#20,022 opened on Apr 18, 2017
Repository metrics
- Stars
- (133,883 stars)
- PR merge metrics
- (No merged PRs in 30d)
Description
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 version go1.8.1 linux/amd64
What operating system and processor architecture are you using (go env)?
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
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
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
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 44d5bdis 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.
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
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
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.
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
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
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.
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.