Go使用SIMD指令——以string转为整数为例

发布于:2024-11-04 ⋅ 阅读:(110) ⋅ 点赞:(0)

本文Go使用SIMD指令采用如下方式:

  1. C编写对应的程序
  2. clang编译成汇编
  3. c2goasm将上述生成的汇编转为go的汇编

准备工具

  1. clang。直接使用apt-get install clang安装即可
  2. c2goasm。 go get -u github.com/minio/c2goasm来进行安装
  3. asm2plan9s。 go get -u github.com/minio/asm2plan9s
  4. 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