mirror of
https://github.com/chai2010/advanced-go-programming-book.git
synced 2025-05-24 04:22:22 +00:00
ch3: 准备例子
This commit is contained in:
parent
ef944c68fe
commit
93aa027f21
17
examples/ch3-xx/add/add.go
Normal file
17
examples/ch3-xx/add/add.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// Go版本, 支持内联优化
|
||||||
|
|
||||||
|
package add
|
||||||
|
|
||||||
|
func Add(a, b int) int {
|
||||||
|
return a + b
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddSlice(dst, a, b []int) {
|
||||||
|
for i := 0; i < len(dst) && i < len(a) && i < len(b); i++ {
|
||||||
|
dst[i] = a[i] + b[i]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
16
examples/ch3-xx/add/add_asm.go
Normal file
16
examples/ch3-xx/add/add_asm.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// +build amd64
|
||||||
|
|
||||||
|
// 汇编版本, 不支持内联优化
|
||||||
|
|
||||||
|
package add
|
||||||
|
|
||||||
|
func AsmAdd(a, b int) int
|
||||||
|
|
||||||
|
func AsmAddSlice(dst, a, b []int) {
|
||||||
|
AddSlice(dst, a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AsmAddSlice__todo(dst, a, b []int)
|
23
examples/ch3-xx/add/add_asm_amd64.s
Normal file
23
examples/ch3-xx/add/add_asm_amd64.s
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// func AsmAdd(a, b int) int
|
||||||
|
TEXT ·AsmAdd(SB), NOSPLIT, $0-24
|
||||||
|
MOVQ a+0(FP), AX // a
|
||||||
|
MOVQ b+8(FP), BX // b
|
||||||
|
ADDQ AX, BX // a+b
|
||||||
|
MOVQ BX, ret+16(FP) // return a+b
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func AsmAddSlice(dst, a, b []int)
|
||||||
|
TEXT ·AsmAddSlice__todo(SB), NOSPLIT, $0-72
|
||||||
|
MOVQ dst+0(FP), AX // AX: dst
|
||||||
|
MOVQ a+24(FP), BX // BX: &a
|
||||||
|
MOVQ b+48(FP), CX // CX: &b
|
||||||
|
MOVQ dst_len+8(FP), DX // DX: len(dst)
|
||||||
|
MOVQ a_len+32(FP), R8 // R8: len(a)
|
||||||
|
MOVQ b_len+56(FP), R9 // R9: len(b)
|
||||||
|
// TODO: DX = min(DX,R8,R9)
|
||||||
|
RET
|
16
examples/ch3-xx/add/add_asm_generic.go
Normal file
16
examples/ch3-xx/add/add_asm_generic.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// +build !amd64
|
||||||
|
|
||||||
|
// 对于没有汇编实现的环境, 临时采用Go版本代替
|
||||||
|
|
||||||
|
package add
|
||||||
|
|
||||||
|
func AsmAdd(a, b int) int {
|
||||||
|
return Add(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AsmAddSlice(dst, a, b []int) {
|
||||||
|
AddSlice(dst, a, b)
|
||||||
|
}
|
97
examples/ch3-xx/add/add_test.go
Normal file
97
examples/ch3-xx/add/add_test.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// go test -bench=.
|
||||||
|
|
||||||
|
package add
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAdd(t *testing.T) {
|
||||||
|
t.Run("go", func(t *testing.T) {
|
||||||
|
if x := Add(1, 2); x != 3 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 3, x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("asm", func(t *testing.T) {
|
||||||
|
if x := AsmAdd(1, 2); x != 3 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 3, x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddSlice(t *testing.T) {
|
||||||
|
a := []int{1, 2, 3, 4, 5}
|
||||||
|
b := []int{10, 20, 30, 40, 50, 60}
|
||||||
|
|
||||||
|
t.Run("go", func(t *testing.T) {
|
||||||
|
x := make([]int, len(a))
|
||||||
|
AddSlice(x, a, b)
|
||||||
|
|
||||||
|
for i := 0; i < len(x) && i < len(a) && i < len(b); i++ {
|
||||||
|
if x[i] != a[i]+b[i] {
|
||||||
|
t.Fatalf("expect = %d, got = %d", x[i], a[i]+b[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("asm", func(t *testing.T) {
|
||||||
|
x := make([]int, len(a))
|
||||||
|
AsmAddSlice(x, a, b)
|
||||||
|
|
||||||
|
for i := 0; i < len(x) && i < len(a) && i < len(b); i++ {
|
||||||
|
if x[i] != a[i]+b[i] {
|
||||||
|
t.Fatalf("expect = %d, got = %d", x[i], a[i]+b[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAdd(b *testing.B) {
|
||||||
|
b.Run("go", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Add(1, 2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("asm", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AsmAdd(1, 2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAddSlice(b *testing.B) {
|
||||||
|
s0 := make([]int, 10<<10)
|
||||||
|
s1 := make([]int, 10<<10)
|
||||||
|
dst := make([]int, 10<<10)
|
||||||
|
|
||||||
|
b.Run("len=10", func(b *testing.B) {
|
||||||
|
dst := dst[:10]
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AddSlice(dst, s0, s1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("len=50", func(b *testing.B) {
|
||||||
|
dst := dst[:50]
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AddSlice(dst, s0, s1)
|
||||||
|
_ = dst
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("len=100", func(b *testing.B) {
|
||||||
|
dst := dst[:100]
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AddSlice(dst, s0, s1)
|
||||||
|
_ = dst
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("len=1000", func(b *testing.B) {
|
||||||
|
dst := dst[:1000]
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AddSlice(dst, s0, s1)
|
||||||
|
_ = dst
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
14
examples/ch3-xx/add/runme.go
Normal file
14
examples/ch3-xx/add/runme.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "."
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println("Add(1+2) =", Add(1, 2))
|
||||||
|
}
|
6
examples/ch3-xx/binary_search/binary_search.go
Normal file
6
examples/ch3-xx/binary_search/binary_search.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package bsearch
|
||||||
|
|
||||||
|
func BinarySearch(arr []int, num int) bool
|
45
examples/ch3-xx/binary_search/binary_search_amd64.s
Normal file
45
examples/ch3-xx/binary_search/binary_search_amd64.s
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
TEXT ·BinarySearch+0(SB),$0
|
||||||
|
|
||||||
|
start:
|
||||||
|
MOVQ arr+0(FP), CX
|
||||||
|
MOVQ len+8(FP), AX
|
||||||
|
JMP find_index
|
||||||
|
|
||||||
|
find_index:
|
||||||
|
XORQ DX, DX
|
||||||
|
MOVQ $2, BX
|
||||||
|
IDIVQ BX
|
||||||
|
JMP comp
|
||||||
|
|
||||||
|
comp:
|
||||||
|
LEAQ (AX * 8), BX
|
||||||
|
ADDQ BX, CX
|
||||||
|
MOVQ num+24(FP), DX
|
||||||
|
CMPQ DX, (CX)
|
||||||
|
JE found
|
||||||
|
JG right
|
||||||
|
JL left
|
||||||
|
JMP not_found
|
||||||
|
|
||||||
|
left:
|
||||||
|
CMPQ len+8(FP), $1
|
||||||
|
JE not_found
|
||||||
|
MOVQ AX, len+8(FP)
|
||||||
|
JMP start
|
||||||
|
|
||||||
|
right:
|
||||||
|
CMPQ len+8(FP), $1
|
||||||
|
JE not_found
|
||||||
|
MOVQ CX, arr+0(FP)
|
||||||
|
JMP start
|
||||||
|
|
||||||
|
not_found:
|
||||||
|
MOVQ $0, ret+32(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
found:
|
||||||
|
MOVQ $1, ret+32(FP)
|
||||||
|
RET
|
26
examples/ch3-xx/binary_search/binary_search_test.go
Normal file
26
examples/ch3-xx/binary_search/binary_search_test.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package bsearch
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestBinarySearch(t *testing.T) {
|
||||||
|
data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||||
|
|
||||||
|
if result := BinarySearch(data, 8); result != true {
|
||||||
|
t.Errorf("Expected true value for binary search.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := BinarySearch(data, 1); result != true {
|
||||||
|
t.Errorf("Expected true value for binary search.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := BinarySearch(data, 10); result != true {
|
||||||
|
t.Errorf("Expected true value for binary search.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := BinarySearch(data, 12); result != false {
|
||||||
|
t.Errorf("Expected false value for binary search.")
|
||||||
|
}
|
||||||
|
}
|
26
examples/ch3-xx/globalvar/asm_amd64.s
Normal file
26
examples/ch3-xx/globalvar/asm_amd64.s
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// func GetPkgValue() int
|
||||||
|
TEXT ·GetPkgValue(SB), NOSPLIT, $0-8
|
||||||
|
MOVQ ·gopkgValue(SB), AX
|
||||||
|
MOVQ AX, ret+0(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func GetPkgInfo() PkgInfo
|
||||||
|
TEXT ·GetPkgInfo(SB), NOSPLIT, $0-24
|
||||||
|
MOVBLZX ·gInfo+0(SB), AX // .V0 byte
|
||||||
|
MOVQ AX, ret+0(FP)
|
||||||
|
MOVWLZX ·gInfo+2(SB), AX // .V1 uint16
|
||||||
|
MOVQ AX, ret+2(FP)
|
||||||
|
MOVLQZX ·gInfo+4(SB), AX // .V2 int32
|
||||||
|
MOVQ AX, ret+4(FP)
|
||||||
|
MOVQ ·gInfo+8(SB), AX // .V3 int32
|
||||||
|
MOVQ AX, ret+8(FP)
|
||||||
|
MOVBLZX ·gInfo+(16+0)(SB), AX // .V4 bool
|
||||||
|
MOVQ AX, ret+(16+0)(FP)
|
||||||
|
MOVBLZX ·gInfo+(16+1)(SB), AX // .V5 bool
|
||||||
|
MOVQ AX, ret+(16+1)(FP)
|
||||||
|
RET
|
32
examples/ch3-xx/globalvar/globalvar.go
Normal file
32
examples/ch3-xx/globalvar/globalvar.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// 汇编中访问Go中定义的全局变量
|
||||||
|
|
||||||
|
package globalvar
|
||||||
|
|
||||||
|
var gopkgValue int = 42
|
||||||
|
|
||||||
|
type PkgInfo struct {
|
||||||
|
V0 byte
|
||||||
|
V1 uint16
|
||||||
|
V2 int32
|
||||||
|
V3 int64
|
||||||
|
V4 bool
|
||||||
|
V5 bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var gInfo PkgInfo
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
gInfo.V0 = 101
|
||||||
|
gInfo.V1 = 102
|
||||||
|
gInfo.V2 = 103
|
||||||
|
gInfo.V3 = 104
|
||||||
|
gInfo.V4 = true
|
||||||
|
gInfo.V5 = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPkgValue() int
|
||||||
|
|
||||||
|
func GetPkgInfo() PkgInfo
|
17
examples/ch3-xx/globalvar/runme.go
Normal file
17
examples/ch3-xx/globalvar/runme.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
. "."
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println(GetPkgValue())
|
||||||
|
fmt.Println(GetPkgInfo())
|
||||||
|
}
|
10
examples/ch3-xx/hello/hello.go
Normal file
10
examples/ch3-xx/hello/hello.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package hello
|
||||||
|
|
||||||
|
var text = "你好, 世界, 包变量\n"
|
||||||
|
|
||||||
|
func PrintHelloWorld()
|
||||||
|
func PrintHelloWorld_zh()
|
||||||
|
func PrintHelloWorld_var()
|
51
examples/ch3-xx/hello/hello_amd64.s
Normal file
51
examples/ch3-xx/hello/hello_amd64.s
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
#include "funcdata.h"
|
||||||
|
|
||||||
|
// "Hello World!\n"
|
||||||
|
DATA text<>+0(SB)/8,$"Hello Wo"
|
||||||
|
DATA text<>+8(SB)/8,$"rld!\n"
|
||||||
|
GLOBL text<>(SB),NOPTR,$16
|
||||||
|
|
||||||
|
// utf8: "你好, 世界!\n"
|
||||||
|
// hex: e4bda0e5a5bd2c20 e4b896e7958c210a
|
||||||
|
// len: 16
|
||||||
|
DATA text_zh<>+0(SB)/8,$"\xe4\xbd\xa0\xe5\xa5\xbd\x2c\x20"
|
||||||
|
DATA text_zh<>+8(SB)/8,$"\xe4\xb8\x96\xe7\x95\x8c\x21\x0a"
|
||||||
|
GLOBL text_zh<>(SB),NOPTR,$16
|
||||||
|
|
||||||
|
// func PrintHelloWorld_var()
|
||||||
|
TEXT ·PrintHelloWorld_var(SB), $16-0
|
||||||
|
NO_LOCAL_POINTERS
|
||||||
|
CALL runtime·printlock(SB)
|
||||||
|
MOVQ ·text+0(SB), AX
|
||||||
|
MOVQ AX, (SP)
|
||||||
|
MOVQ ·text+8(SB), AX
|
||||||
|
MOVQ AX, 8(SP)
|
||||||
|
CALL runtime·printstring(SB)
|
||||||
|
CALL runtime·printunlock(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func PrintHelloWorld()
|
||||||
|
TEXT ·PrintHelloWorld(SB), $16-0
|
||||||
|
NO_LOCAL_POINTERS
|
||||||
|
CALL runtime·printlock(SB)
|
||||||
|
MOVQ $text<>+0(SB), AX
|
||||||
|
MOVQ AX, (SP)
|
||||||
|
MOVQ $16, 8(SP)
|
||||||
|
CALL runtime·printstring(SB)
|
||||||
|
CALL runtime·printunlock(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func PrintHelloWorld_zh()
|
||||||
|
TEXT ·PrintHelloWorld_zh(SB), $16-0
|
||||||
|
NO_LOCAL_POINTERS
|
||||||
|
CALL runtime·printlock(SB)
|
||||||
|
MOVQ $text_zh<>+0(SB), AX
|
||||||
|
MOVQ AX, (SP)
|
||||||
|
MOVQ $16, 8(SP)
|
||||||
|
CALL runtime·printstring(SB)
|
||||||
|
CALL runtime·printunlock(SB)
|
||||||
|
RET
|
20
examples/ch3-xx/hello/runme.go
Normal file
20
examples/ch3-xx/hello/runme.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
. "."
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := "你好, 世界!\n"
|
||||||
|
fmt.Printf("%d: %x\n", len(s), s)
|
||||||
|
PrintHelloWorld()
|
||||||
|
PrintHelloWorld_zh()
|
||||||
|
PrintHelloWorld_var()
|
||||||
|
}
|
15
examples/ch3-xx/ifelse/ifelse.go
Normal file
15
examples/ch3-xx/ifelse/ifelse.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// Go版本, 支持内联优化
|
||||||
|
|
||||||
|
package ifelse
|
||||||
|
|
||||||
|
func If(ok bool, a, b int) int {
|
||||||
|
if ok {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func AsmIf(ok bool, a, b int) int
|
31
examples/ch3-xx/ifelse/ifelse_ams_amd64.s
Normal file
31
examples/ch3-xx/ifelse/ifelse_ams_amd64.s
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// https://github.com/golang/go/issues/14288
|
||||||
|
//
|
||||||
|
// from rsc:
|
||||||
|
// But expanding what I said yesterday just a bit:
|
||||||
|
// never use MOVB or MOVW with a register destination,
|
||||||
|
// since it's inefficient (it's a read-modify-write on the target register).
|
||||||
|
// Instead use MOVL for reg->reg and use MOVBLZX or MOVWLZX for mem->reg;
|
||||||
|
// those are pure writes on the target register.
|
||||||
|
//
|
||||||
|
// 因此, 加载bool型参数到寄存器时, 建议使用 MOVBLZX.
|
||||||
|
// 如果使用 MOVB 的话, go test 虽然通过了,
|
||||||
|
// 但是 go run runme.go 则出现错误结果.
|
||||||
|
//
|
||||||
|
|
||||||
|
// func AsmIf(ok bool, a, b int) int
|
||||||
|
TEXT ·AsmIf(SB), NOSPLIT, $0-32
|
||||||
|
MOVBQZX ok+0(FP), AX // ok
|
||||||
|
MOVQ a+8(FP), BX // a
|
||||||
|
MOVQ b+16(FP), CX // b
|
||||||
|
CMPQ AX, $0 // test ok
|
||||||
|
JEQ 3(PC) // if !ok, skip 2 line
|
||||||
|
MOVQ BX, ret+24(FP) // return a
|
||||||
|
RET
|
||||||
|
MOVQ CX, ret+24(FP) // return b
|
||||||
|
RET
|
32
examples/ch3-xx/ifelse/ifelse_test.go
Normal file
32
examples/ch3-xx/ifelse/ifelse_test.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// go test -bench=.
|
||||||
|
|
||||||
|
package ifelse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMin(t *testing.T) {
|
||||||
|
t.Run("go", func(t *testing.T) {
|
||||||
|
if x := If(true, 1, 2); x != 1 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 1, x)
|
||||||
|
}
|
||||||
|
if x := If(false, 1, 2); x != 2 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 2, x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("asm", func(t *testing.T) {
|
||||||
|
if x := AsmIf(true, 1, 2); x != 1 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 1, x)
|
||||||
|
}
|
||||||
|
if x := AsmIf(false, 1, 2); x != 2 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 2, x)
|
||||||
|
}
|
||||||
|
if x := AsmIf(false, 2, 1); x != 1 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 1, x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
18
examples/ch3-xx/ifelse/runme.go
Normal file
18
examples/ch3-xx/ifelse/runme.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "."
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println("If(true, 1, 2) =", If(true, 1, 2))
|
||||||
|
println("If(false, 1, 2) =", If(false, 1, 2))
|
||||||
|
println("AsmIf(true, 1, 2) =", AsmIf(true, 1, 2))
|
||||||
|
println("AsmIf(false, 1, 2) =", AsmIf(false, 1, 2))
|
||||||
|
println("AsmIf(false, 2, 1) =", AsmIf(false, 2, 1))
|
||||||
|
}
|
22
examples/ch3-xx/instr/bench_test.go
Executable file
22
examples/ch3-xx/instr/bench_test.go
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package instr
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
var g int64
|
||||||
|
|
||||||
|
func BenchmarkSum(b *testing.B) {
|
||||||
|
ns := []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
g = Sum(ns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSum2(b *testing.B) {
|
||||||
|
ns := []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
g = Sum2(ns)
|
||||||
|
}
|
||||||
|
}
|
26
examples/ch3-xx/instr/instr.go
Executable file
26
examples/ch3-xx/instr/instr.go
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package instr
|
||||||
|
|
||||||
|
func Add(n, m int64) int64 {
|
||||||
|
return n + m
|
||||||
|
}
|
||||||
|
|
||||||
|
func Add2(n, m int64) int64
|
||||||
|
|
||||||
|
// BSF returns the index of the least significant set bit,
|
||||||
|
// or -1 if the input contains no set bits.
|
||||||
|
func BSF(n int64) int
|
||||||
|
|
||||||
|
func BSF32(n int32) int32
|
||||||
|
|
||||||
|
func Sum(s []int64) int64 {
|
||||||
|
var ss int64
|
||||||
|
for _, n := range s {
|
||||||
|
ss += n
|
||||||
|
}
|
||||||
|
return ss
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sum2(s []int64) int64
|
57
examples/ch3-xx/instr/instr_amd64.s
Executable file
57
examples/ch3-xx/instr/instr_amd64.s
Executable file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// func Add2(n, m int64) int32
|
||||||
|
TEXT ·Add2(SB), NOSPLIT, $0-24
|
||||||
|
MOVQ n+0(FP), AX
|
||||||
|
MOVQ m+8(FP), BX
|
||||||
|
ADDQ AX, BX
|
||||||
|
MOVQ BX, ret+16(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func BSF(n int64) int
|
||||||
|
TEXT ·BSF(SB), NOSPLIT, $0
|
||||||
|
BSFQ n+0(FP), AX
|
||||||
|
JEQ allZero
|
||||||
|
MOVQ AX, ret+8(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
allZero:
|
||||||
|
MOVQ $-1, ret+8(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func BSF32(n int32) int32
|
||||||
|
TEXT ·BSF32(SB), NOSPLIT, $0
|
||||||
|
BSFL n+0(FP), AX
|
||||||
|
JEQ allZero32
|
||||||
|
MOVL AX, ret+8(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
allZero32:
|
||||||
|
MOVL $-1, ret+8(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func Sum2(s []int64) int64
|
||||||
|
TEXT ·Sum2(SB), NOSPLIT, $0
|
||||||
|
MOVQ $0, DX
|
||||||
|
MOVQ s_base+0(FP), AX
|
||||||
|
MOVQ s_len+8(FP), DI
|
||||||
|
MOVQ $0, CX
|
||||||
|
CMPQ CX, DI
|
||||||
|
JGE Sum2End
|
||||||
|
|
||||||
|
Sum2Loop:
|
||||||
|
MOVQ (AX), BP
|
||||||
|
ADDQ BP, DX
|
||||||
|
ADDQ $8, AX
|
||||||
|
INCQ CX
|
||||||
|
CMPQ CX, DI
|
||||||
|
JL Sum2Loop
|
||||||
|
|
||||||
|
Sum2End:
|
||||||
|
MOVQ DX, ret+24(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// vim: set ft=txt:
|
16
examples/ch3-xx/loop/loop.go
Normal file
16
examples/ch3-xx/loop/loop.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// Go版本, 支持内联优化
|
||||||
|
|
||||||
|
package loop
|
||||||
|
|
||||||
|
func LoopAdd(cnt, v0, step int) int {
|
||||||
|
result := v0
|
||||||
|
for i := 0; i < cnt; i++ {
|
||||||
|
result += step
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func AsmLoopAdd(cnt, v0, step int) int
|
21
examples/ch3-xx/loop/loop_asm_amd64.s
Normal file
21
examples/ch3-xx/loop/loop_asm_amd64.s
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// func AsmLoopAdd(cnt, v0, step int) int
|
||||||
|
TEXT ·AsmLoopAdd(SB), NOSPLIT, $0-32
|
||||||
|
MOVQ cnt+0(FP), AX // cnt
|
||||||
|
MOVQ v0+8(FP), BX // v0
|
||||||
|
MOVQ step+16(FP), CX // step
|
||||||
|
|
||||||
|
loop:
|
||||||
|
CMPQ AX, $0 // compare cnt,0
|
||||||
|
JLE end // if cnt <= 0: go end
|
||||||
|
DECQ AX // cnt--
|
||||||
|
ADDQ CX, BX // v0 += step
|
||||||
|
JMP loop // goto loop
|
||||||
|
|
||||||
|
end:
|
||||||
|
MOVQ BX, ret+24(FP) // return v0
|
||||||
|
RET
|
54
examples/ch3-xx/loop/loop_test.go
Normal file
54
examples/ch3-xx/loop/loop_test.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// go test -bench=.
|
||||||
|
|
||||||
|
package loop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLoopAdd(t *testing.T) {
|
||||||
|
t.Run("go", func(t *testing.T) {
|
||||||
|
if x := LoopAdd(100, 0, 1); x != 100 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 100, x)
|
||||||
|
}
|
||||||
|
if x := LoopAdd(100, 0, 2); x != 200 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 200, x)
|
||||||
|
}
|
||||||
|
if x := LoopAdd(100, 0, -1); x != -100 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", -100, x)
|
||||||
|
}
|
||||||
|
if x := LoopAdd(100, 50, 1); x != 150 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 150, x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("asm", func(t *testing.T) {
|
||||||
|
if x := AsmLoopAdd(100, 0, 1); x != 100 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 100, x)
|
||||||
|
}
|
||||||
|
if x := AsmLoopAdd(100, 0, 2); x != 200 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 200, x)
|
||||||
|
}
|
||||||
|
if x := AsmLoopAdd(100, 0, -1); x != -100 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", -100, x)
|
||||||
|
}
|
||||||
|
if x := AsmLoopAdd(100, 50, 1); x != 150 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 150, x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLoopAdd(b *testing.B) {
|
||||||
|
b.Run("go", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
LoopAdd(1000, 0, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("asm", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AsmLoopAdd(1000, 0, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
17
examples/ch3-xx/loop/runme.go
Normal file
17
examples/ch3-xx/loop/runme.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "."
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println("LoopAdd(100,0,1) =", LoopAdd(100, 0, 1))
|
||||||
|
println("LoopAdd(100,0,2) =", LoopAdd(100, 0, 2))
|
||||||
|
println("LoopAdd(100,200,-1) =", LoopAdd(100, 200, -1))
|
||||||
|
println("LoopAdd(100,0,-1) =", LoopAdd(100, 0, -1))
|
||||||
|
}
|
31
examples/ch3-xx/min/min.go
Normal file
31
examples/ch3-xx/min/min.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// Go版本, 支持内联优化
|
||||||
|
|
||||||
|
package min
|
||||||
|
|
||||||
|
func Min(a, b int) int {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func MinNoInline(a, b int) int {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func Max(a, b int) int {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func AsmMin(a, b int) int
|
||||||
|
func AsmMax(a, b int) int
|
26
examples/ch3-xx/min/min_asm_amd64.s
Normal file
26
examples/ch3-xx/min/min_asm_amd64.s
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// func AsmMin(a, b int) int
|
||||||
|
TEXT ·AsmMin(SB), NOSPLIT, $0-24
|
||||||
|
MOVQ a+0(FP), AX // a
|
||||||
|
MOVQ b+8(FP), BX // b
|
||||||
|
CMPQ AX, BX // compare a, b
|
||||||
|
JGT 3(PC) // if a>b, skip 2 line
|
||||||
|
MOVQ AX, ret+16(FP) // return a
|
||||||
|
RET
|
||||||
|
MOVQ BX, ret+16(FP) // return b
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func AsmMax(a, b int) int
|
||||||
|
TEXT ·AsmMax(SB), NOSPLIT, $0-24
|
||||||
|
MOVQ a+0(FP), AX // a
|
||||||
|
MOVQ b+8(FP), BX // b
|
||||||
|
CMPQ AX, BX // compare a, b
|
||||||
|
JLT 3(PC) // if a<b, skip 2 line
|
||||||
|
MOVQ AX, ret+16(FP) // return a
|
||||||
|
RET
|
||||||
|
MOVQ BX, ret+16(FP) // return b
|
||||||
|
RET
|
65
examples/ch3-xx/min/min_test.go
Normal file
65
examples/ch3-xx/min/min_test.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// go test -bench=.
|
||||||
|
|
||||||
|
package min
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMin(t *testing.T) {
|
||||||
|
t.Run("go", func(t *testing.T) {
|
||||||
|
if x := Min(1, 2); x != 1 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 1, x)
|
||||||
|
}
|
||||||
|
if x := Min(2, 1); x != 1 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 1, x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("asm", func(t *testing.T) {
|
||||||
|
if x := AsmMin(1, 2); x != 1 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 1, x)
|
||||||
|
}
|
||||||
|
if x := AsmMin(2, 1); x != 1 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 1, x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func TestMax(t *testing.T) {
|
||||||
|
t.Run("go", func(t *testing.T) {
|
||||||
|
if x := Max(1, 2); x != 2 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 2, x)
|
||||||
|
}
|
||||||
|
if x := Max(2, 1); x != 2 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 2, x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("asm", func(t *testing.T) {
|
||||||
|
if x := AsmMax(1, 2); x != 2 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 2, x)
|
||||||
|
}
|
||||||
|
if x := AsmMax(2, 1); x != 2 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 2, x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMin(b *testing.B) {
|
||||||
|
b.Run("go", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Min(1, 2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("go.noinline", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
MinNoInline(1, 2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("asm", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AsmMin(1, 2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
14
examples/ch3-xx/min/runme.go
Normal file
14
examples/ch3-xx/min/runme.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "."
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println("Min(1,2) =", Min(1, 2))
|
||||||
|
}
|
15
examples/ch3-xx/slice/runme.go
Normal file
15
examples/ch3-xx/slice/runme.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "."
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println("SumIntSlice([]int{1,2,3}) =", SumIntSlice([]int{1, 2, 3}))
|
||||||
|
println("AsmSumIntSlice([]int{1,2,3}) =", AsmSumIntSlice([]int{1, 2, 3}))
|
||||||
|
}
|
35
examples/ch3-xx/slice/slice.go
Normal file
35
examples/ch3-xx/slice/slice.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// Go版本, 支持内联优化
|
||||||
|
|
||||||
|
package slice
|
||||||
|
|
||||||
|
func SumIntSlice(s []int) int {
|
||||||
|
var sum int
|
||||||
|
for _, v := range s {
|
||||||
|
sum += v
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
func SumFloat32Slice(s []float32) float32 {
|
||||||
|
var sum float32
|
||||||
|
for _, v := range s {
|
||||||
|
sum += v
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
func SumFloat64Slice(s []float64) float64 {
|
||||||
|
var sum float64
|
||||||
|
for _, v := range s {
|
||||||
|
sum += v
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
func AsmSumInt16Slice(v []int16) int16
|
||||||
|
|
||||||
|
func AsmSumIntSlice(s []int) int
|
||||||
|
func AsmSumIntSliceV2(s []int) int
|
59
examples/ch3-xx/slice/slice_asm_amd64.s
Normal file
59
examples/ch3-xx/slice/slice_asm_amd64.s
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// func AsmSumInt16Slice(v []int16) int16
|
||||||
|
TEXT ·AsmSumInt16Slice(SB), NOSPLIT, $0-26
|
||||||
|
MOVQ v_base+0(FP), R8
|
||||||
|
MOVQ v_len+8(FP), R9
|
||||||
|
SHLQ $1, R9
|
||||||
|
ADDQ R8, R9
|
||||||
|
MOVQ $0, R10
|
||||||
|
|
||||||
|
loop:
|
||||||
|
CMPQ R8, R9
|
||||||
|
JE end
|
||||||
|
ADDW (R8), R10
|
||||||
|
ADDQ $2, R8
|
||||||
|
JMP loop
|
||||||
|
|
||||||
|
end:
|
||||||
|
MOVW R10, ret+24(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func AsmSumIntSlice(s []int) int
|
||||||
|
TEXT ·AsmSumIntSlice(SB), NOSPLIT, $0-32
|
||||||
|
MOVQ s+0(FP), AX // &s[0]
|
||||||
|
MOVQ s_len+8(FP), BX // len(s)
|
||||||
|
MOVQ $0, CX // sum = 0
|
||||||
|
|
||||||
|
loop:
|
||||||
|
CMPQ BX, $0 // compare cnt,0
|
||||||
|
JLE end // if cnt <= 0: goto end
|
||||||
|
DECQ BX // cnt--
|
||||||
|
ADDQ (AX), CX // sum += s[i]
|
||||||
|
ADDQ $8, AX // i++
|
||||||
|
JMP loop // goto loop
|
||||||
|
|
||||||
|
end:
|
||||||
|
MOVQ CX, ret+24(FP) // return sum
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func AsmSumIntSliceV2(s []int) int
|
||||||
|
TEXT ·AsmSumIntSliceV2(SB), NOSPLIT, $0-32
|
||||||
|
MOVQ s+0(FP), AX // p := &s[0]
|
||||||
|
MOVQ s_len+8(FP), BX
|
||||||
|
LEAQ 0(AX)(BX*8), BX // p_end := &s[len(s)]
|
||||||
|
MOVQ $0, CX // sum = 0
|
||||||
|
|
||||||
|
loop:
|
||||||
|
CMPQ AX, BX // compare p,p_end
|
||||||
|
JGE end // if p >= p_end: goto end
|
||||||
|
ADDQ (AX), CX // sum += s[i]
|
||||||
|
ADDQ $8, AX // p++
|
||||||
|
JMP loop // goto loop
|
||||||
|
|
||||||
|
end:
|
||||||
|
MOVQ CX, ret+24(FP) // return sum
|
||||||
|
RET
|
82
examples/ch3-xx/slice/slice_test.go
Normal file
82
examples/ch3-xx/slice/slice_test.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
// go test -bench=.
|
||||||
|
|
||||||
|
package slice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLoopAdd(t *testing.T) {
|
||||||
|
t.Run("go", func(t *testing.T) {
|
||||||
|
if x := SumIntSlice([]int{1, 2, 3}); x != 6 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 6, x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("asm", func(t *testing.T) {
|
||||||
|
if x := AsmSumIntSlice([]int{1, 2, 3}); x != 6 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 6, x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("asm.v2", func(t *testing.T) {
|
||||||
|
if x := AsmSumIntSliceV2([]int{1, 2, 3}); x != 6 {
|
||||||
|
t.Fatalf("expect = %d, got = %d", 6, x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLoopAdd(b *testing.B) {
|
||||||
|
s10 := make([]int, 10)
|
||||||
|
s100 := make([]int, 100)
|
||||||
|
s1000 := make([]int, 1000)
|
||||||
|
|
||||||
|
b.Run("go/len=10", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
SumIntSlice(s10)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("asm/len=10", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AsmSumIntSlice(s10)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("asm.v2/len=10", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AsmSumIntSliceV2(s10)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("go/len=100", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
SumIntSlice(s100)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("asm/len=100", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AsmSumIntSlice(s100)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("asm.v2/len=100", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AsmSumIntSliceV2(s100)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("go/len=1000", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
SumIntSlice(s1000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("asm/len=1000", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AsmSumIntSlice(s1000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("asm.v2/len=1000", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AsmSumIntSliceV2(s1000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
25
examples/ch3-xx/stackmap/stackmap.go
Executable file
25
examples/ch3-xx/stackmap/stackmap.go
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package stackmap
|
||||||
|
|
||||||
|
func X(b []byte) []byte
|
||||||
|
|
||||||
|
//func X(b []byte) []byte {
|
||||||
|
// if len(b) == cap(b) {
|
||||||
|
// b = growSlice(b)
|
||||||
|
// }
|
||||||
|
// b = b[:len(b)+1]
|
||||||
|
// b[len(b)-1] = 3
|
||||||
|
// return b
|
||||||
|
//}
|
||||||
|
|
||||||
|
func growSlice(b []byte) []byte {
|
||||||
|
newCap := 10
|
||||||
|
if cap(b) > 5 {
|
||||||
|
newCap = cap(b) * 2
|
||||||
|
}
|
||||||
|
b1 := make([]byte, len(b), newCap)
|
||||||
|
copy(b1, b)
|
||||||
|
return b1
|
||||||
|
}
|
44
examples/ch3-xx/stackmap/stackmap_amd64.s
Executable file
44
examples/ch3-xx/stackmap/stackmap_amd64.s
Executable file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
#include "funcdata.h"
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// func X(b []byte) []byte
|
||||||
|
TEXT ·X(SB), $48-48
|
||||||
|
MOVQ b_base+0(FP), BX
|
||||||
|
MOVQ b_len+8(FP), CX
|
||||||
|
MOVQ b_cap+16(FP), DX
|
||||||
|
|
||||||
|
CMPQ CX, DX
|
||||||
|
JL afterGrow
|
||||||
|
|
||||||
|
// Set up the growSlice call.
|
||||||
|
MOVQ BX, gs_base-48(SP)
|
||||||
|
MOVQ CX, gs_len-40(SP)
|
||||||
|
MOVQ DX, gs_cap-32(SP)
|
||||||
|
|
||||||
|
CALL ·growSlice(SB)
|
||||||
|
|
||||||
|
MOVQ gs_base-24(SP), BX
|
||||||
|
MOVQ gs_len-16(SP), CX
|
||||||
|
MOVQ gs_cap-8(SP), DX
|
||||||
|
|
||||||
|
afterGrow:
|
||||||
|
// At this point, we have adequate capacity to increase len + 1 and the
|
||||||
|
// following register scheme:
|
||||||
|
// BX - b_base
|
||||||
|
// CX - b_len
|
||||||
|
// DX - b_cap
|
||||||
|
|
||||||
|
// Write base/cap results.
|
||||||
|
MOVQ BX, ret_base+24(FP)
|
||||||
|
MOVQ DX, ret_cap+40(FP)
|
||||||
|
|
||||||
|
// Write new element to b and increment the length.
|
||||||
|
LEAQ (BX)(CX*1), BX
|
||||||
|
MOVB $3, (BX)
|
||||||
|
ADDQ $1, CX
|
||||||
|
MOVQ CX, ret_len+32(FP)
|
||||||
|
|
||||||
|
RET
|
47
examples/ch3-xx/stackmap/stackmap_test.go
Executable file
47
examples/ch3-xx/stackmap/stackmap_test.go
Executable file
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package stackmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestX(t *testing.T) {
|
||||||
|
b := make([]byte, 0, 3)
|
||||||
|
|
||||||
|
for _, want := range [][]byte{
|
||||||
|
mkSlice(3, 3),
|
||||||
|
mkSlice(3, 3, 3),
|
||||||
|
mkSlice(3, 3, 3, 3),
|
||||||
|
mkSlice(10, 3, 3, 3, 3),
|
||||||
|
mkSlice(10, 3, 3, 3, 3, 3),
|
||||||
|
mkSlice(10, 3, 3, 3, 3, 3, 3),
|
||||||
|
mkSlice(10, 3, 3, 3, 3, 3, 3, 3),
|
||||||
|
mkSlice(10, 3, 3, 3, 3, 3, 3, 3, 3),
|
||||||
|
mkSlice(10, 3, 3, 3, 3, 3, 3, 3, 3, 3),
|
||||||
|
mkSlice(10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
|
||||||
|
mkSlice(20, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
|
||||||
|
} {
|
||||||
|
b = X(b)
|
||||||
|
if !slicesEqual(b, want) {
|
||||||
|
t.Fatalf("got %v[cap=%d]; want %v[cap=%d]",
|
||||||
|
b, cap(b), want, cap(want))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mkSlice(cap int, vs ...byte) []byte {
|
||||||
|
b1 := make([]byte, 0, cap)
|
||||||
|
for _, v := range vs {
|
||||||
|
b1 = append(b1, v)
|
||||||
|
}
|
||||||
|
return b1
|
||||||
|
}
|
||||||
|
func slicesEqual(b0, b1 []byte) bool {
|
||||||
|
if cap(b0) != cap(b1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return bytes.Equal(b0, b1)
|
||||||
|
}
|
6
examples/ch3-xx/sum/sum.go
Normal file
6
examples/ch3-xx/sum/sum.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package sum
|
||||||
|
|
||||||
|
func Sum(a int, b int) int
|
9
examples/ch3-xx/sum/sum_amd64.s
Normal file
9
examples/ch3-xx/sum/sum_amd64.s
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
TEXT ·Sum+0(SB),$0
|
||||||
|
MOVQ a+0(FP), BX
|
||||||
|
MOVQ b+8(FP), BP
|
||||||
|
ADDQ BP, BX
|
||||||
|
MOVQ BX, return+16(FP)
|
||||||
|
RET
|
14
examples/ch3-xx/sum/sum_test.go
Normal file
14
examples/ch3-xx/sum/sum_test.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package sum
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestSum(t *testing.T) {
|
||||||
|
result := Sum(1, 1)
|
||||||
|
|
||||||
|
if result != 2 {
|
||||||
|
t.Errorf("%d does not equal 2", result)
|
||||||
|
}
|
||||||
|
}
|
11
examples/ch3-xx/vector/sum_amd64.s
Normal file
11
examples/ch3-xx/vector/sum_amd64.s
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
TEXT ·SumVec+0(SB), $0
|
||||||
|
MOVQ vec1+0(FP), BX // Move the first vector into BX
|
||||||
|
MOVQ vec2+24(FP), CX // Move the second vector into BX
|
||||||
|
MOVUPS (BX), X0
|
||||||
|
MOVUPS (CX), X1
|
||||||
|
ADDPS X0, X1
|
||||||
|
MOVUPS X1, result+48(FP)
|
||||||
|
RET
|
8
examples/ch3-xx/vector/vector.go
Normal file
8
examples/ch3-xx/vector/vector.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package vector
|
||||||
|
|
||||||
|
func Find(vec []int, num int) bool
|
||||||
|
|
||||||
|
func SumVec(vec1 []int32, vec2 []int32) [4]int32
|
28
examples/ch3-xx/vector/vector_amd64.s
Normal file
28
examples/ch3-xx/vector/vector_amd64.s
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
TEXT ·Find+0(SB),$0
|
||||||
|
MOVQ $0, SI // zero the iterator
|
||||||
|
MOVQ vec+0(FP), BX // BX = &vec[0]
|
||||||
|
MOVQ vec+8(FP), CX // len(vec)
|
||||||
|
MOVQ num+24(FP), DX
|
||||||
|
|
||||||
|
start:
|
||||||
|
CMPQ SI, CX
|
||||||
|
JG notfound
|
||||||
|
CMPQ (BX), DX
|
||||||
|
JNE notequal
|
||||||
|
JE found
|
||||||
|
|
||||||
|
found:
|
||||||
|
MOVQ $1, return+32(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
notequal:
|
||||||
|
INCQ SI
|
||||||
|
LEAQ +8(BX), BX
|
||||||
|
JMP start
|
||||||
|
|
||||||
|
notfound:
|
||||||
|
MOVQ $0, return+32(FP)
|
||||||
|
RET
|
40
examples/ch3-xx/vector/vector_test.go
Normal file
40
examples/ch3-xx/vector/vector_test.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright © 2017 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package vector
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestFind(t *testing.T) {
|
||||||
|
vec := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||||
|
if result := Find(vec, 5); result != true {
|
||||||
|
t.Errorf("Could not find number in vector, got: %v", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := Find(vec, 10); result != false {
|
||||||
|
t.Errorf("Returned true when false was expected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSum(t *testing.T) {
|
||||||
|
vec1 := []int32{1, 2, 3, 5}
|
||||||
|
vec2 := []int32{1, 2, 3, 5}
|
||||||
|
|
||||||
|
result := SumVec(vec1, vec2)
|
||||||
|
|
||||||
|
if result[0] != 2 {
|
||||||
|
t.Errorf("Expected 2, got %v, result was: %v", result[0], result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result[1] != 4 {
|
||||||
|
t.Errorf("Expected 4, got %v, result was: %v", result[0], result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result[2] != 6 {
|
||||||
|
t.Errorf("Expected 6, got %v, result was: %v", result[0], result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result[3] != 10 {
|
||||||
|
t.Errorf("Expected 10, got %v, result was: %v", result[0], result)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user