1
0
mirror of https://github.com/chai2010/advanced-go-programming-book.git synced 2025-05-24 12:32:21 +00:00

ch3: 准备例子

This commit is contained in:
chai2010 2018-01-13 15:51:22 +08:00
parent ef944c68fe
commit 93aa027f21
44 changed files with 1284 additions and 0 deletions

View 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
}

View 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)

View 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

View 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)
}

View 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
}
})
}

View 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))
}

View 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

View 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

View 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.")
}
}

View 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

View 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

View 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())
}

View 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()

View 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

View 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()
}

View 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

View 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

View 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)
}
})
}

View 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))
}

View 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
View 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

View 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:

View 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

View 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

View 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)
}
})
}

View 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))
}

View 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

View 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

View 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)
}
})
}

View 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))
}

View 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}))
}

View 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

View 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

View 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)
}
})
}

View 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
}

View 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

View 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)
}

View 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

View 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

View 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)
}
}

View 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

View 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

View 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

View 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)
}
}