本文Go使用SIMD指令采用如下方式:
- C编写对应的程序
- clang编译成汇编
- c2goasm将上述生成的汇编转为go的汇编
准备工具
- clang。直接使用
apt-get install clang
安装即可 - c2goasm。
go get -u github.com/minio/c2goasm
来进行安装 - asm2plan9s。
go get -u github.com/minio/asm2plan9s
- yasm。直接使用功能
apt-get install yasm
,asm2plan9s依赖的工具
示例
// simd.c
#include <immintrin.h>
#include <stdint.h>
void simd_str_to_int(const char *str, size_t len, uint64_t* result) {
__m128i ten = _mm_set1_epi8('0');
__m128i mult=_mm_set_epi8(1,10,1,10,1,10,1,10,1,10,1,10,1,10,1,10);
__m128i data = _mm_loadu_si128((__m128i const *)(str));
data=_mm_sub_epi8(data, ten);
data=_mm_maddubs_epi16(data, mult);
mult=_mm_set_epi16(1,100,1,100,1,100,1,100);
data=_mm_madd_epi16(data,mult);
int32_t da[4];
_mm_storeu_si128((__m128i *)da, data);
*result= da[0]*1000000000000l+da[1]*100000000l+da[2]*10000+da[3];
}
采用如下命令
clang -S -DENABLE_AVX2 -target x86_64-unknown-none -masm=intel -mno-red-zone -mstackrealign -mllvm -inline-threshold=1000 -fno-asynchronous-unwind-tables -fno-exceptions -fno-rtti -O3 -fno-builtin -ffast-math -mavx simd.c -o simd.s
准备文件simd_amd64.go
//go:build !noasm && !appengine
// +build !noasm,!appengine
package main
import (
"reflect"
"unsafe"
)
//go:noescape
func _simd_str_to_int(src unsafe.Pointer, size int64, result unsafe.Pointer)
func SIMDToInt(va string) uint64 {
h := (*reflect.StringHeader)(unsafe.Pointer(&va))
var result uint64
_simd_str_to_int(unsafe.Pointer(h.Data), int64(len(va)), unsafe.Pointer(&result))
return result
}
clang
导出的函数符号是以下划线开头,即_simd_str_to_int
。
开始导出go汇编
c2goasm -a simd.s simd_amd64.s
注意输出文件的名必须和对应声明go文件的名一致。即都为
simd_amd64
参考文献
通过c生成的汇编,生成可供go执行的汇编
如何更快地将string转换成int/long