go cmd/asm: ARM64 NEON浮点指令(VFABD VFMAX, VFMAXNM, VFMINNM VFMIN VFADD, VFSUB VFMUL, VFDIV VFMLA, VFMLS VCVT*)

kzmpq1sx  于 6个月前  发布在  Go
关注(0)|答案(8)|浏览(54)

你正在使用哪个版本的Go( go version )?

$ go version
go version go1.15 linux/arm64

这个问题在最新版本中是否重现?

是的

你正在使用什么操作系统和处理器架构( go env )?

go env 输出

$ go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/home/ubuntu/.cache/go-build"
GOENV="/home/ubuntu/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/ubuntu/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/ubuntu/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/home/ubuntu/xx/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/ubuntu/xx/go/pkg/tool/linux_arm64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build141213394=/tmp/go-build -gno-record-gcc-switches"

你做了什么?

当我编写一些NEON代码时,我发现自己需要在NEON中进行浮点运算。我可以将数据加载到 V* 寄存器(并将其写出来!),但当我尝试使用 VF* 指令,如 VFADDVFMUL 时,这些操作码尚未被arm64上的任何勇敢的工程师实现。

你期望看到什么?

向量化的浮点加法或乘法。

你看到了什么?

unrecognized instruction "VFADD"

测试代码

neon.go
package fptest
func AddFloat([]float32, []float32, []float32)
neon_test.go
package fptest_test

import (
        "testing"
        fptest "."

        "github.com/stretchr/testify/assert"
)

func TestAddFloat(t *testing.T) {
        dst := make([]float32, 4)
        fptest.AddFloat([]float32{1, 2, 3, 4}, []float32{10, 20, 30, 40}, dst)
        assert.Equal(t, []float32{11, 22, 33, 44}, dst)
}
neon_arm64.s
// func AddFloat(a []int32, b []int32, dst []int32)
TEXT ·AddFloat(SB), $0-72
    // For the sake of simplicity, this only does the first 4.

    // Load a, b and dst's addresses to R8, 9, 10.
    MOVD a+0(FP),    R8
    MOVD b+24(FP),   R9
    MOVD dst+48(FP), R10

    // Load [4]int32 from a, b to v1, v2.
    VLD1 (R8), [V1.S4]
    VLD1 (R9), [V2.S4]

    VFADD V1.S4, V2.S4, V1.S4
    // WORD $0x4e21d441;

    // Write [4]int32 to dst.
    VST1 [V1.S4], (R10)

    RET
ni65a41a

ni65a41a2#

(我认为上面的评论是针对以下评论的参考:)
请不要把这当作批评,而是作为一个观察者,对这类请求进行观察。当OP(在这种情况下是你)能够精确地列出要添加的指令时,可以获得最佳结果。我无法解释为什么所有XXX指令的请求都未成功,但鼓励你列出想要添加的确切指令,因为有轶事证据表明,以这种方式形成的请求解决得更快。
我会去购物找opcodes,感谢@davecheney。我本来打算尝试整理一个与此问题相关的更改集,但觉得还是先在这里列出我需要的opcodes,看看能否产生一个更改集(著名的最后一条错误报告词)。

fkvaft9z

fkvaft9z3#

在查看了一些类似的添加arm64操作码的变化后,我怀疑自己力不从心。我仍然会尝试为纯粹的乐趣而改变set,但如果有能力的人遇到这个问题,请不要阻止我。

以下是我遇到的一些最紧迫的操作码,以帮助解决一些瓶颈问题:

  • VFABD
  • VFMAX , VFMAXNM , VFMINNMVFMIN
  • VFADD , VFSUB
  • VFMUL , VFDIV
  • VFMLA , VFMLS
  • VCVT (不确定在习惯性的Go汇编中正确的指令操作码是什么,我想要的是"浮点数转无符号整数","浮点数转有符号整数","有符号整数转浮点数"和"无符号整数转浮点数"变体)
yrdbyhpb

yrdbyhpb5#

@cherrymui 有什么我可以帮忙的吗?我也对此感兴趣。只是不知道从何开始。

lpwwtiir

lpwwtiir6#

对于阅读此文但无法等待实施的人,可以按照以下步骤操作:

  • 用C/C++或其他让你能做的语言编写内联汇编。例如,对于VFADD 32x4:
float32x4_t t;

t = vaddq_f32(t, t);
  • 使用otool或objdump编译并反汇编二进制文件。例如,对于otool:
$ gcc main.c
$ otool -tvj a.out
...
...        4e20d420        fadd.4s v0, v1, v0
...

-j选项会打印操作码字节

  • 将操作码与WORD指令加载到你的汇编代码中:
WORD $0x4e20d420 // fadd.4s v0, v1, v0

⚠️ 注意操作数的顺序!

vu8f3i0k

vu8f3i0k7#

我完全忘记了在完成工作后发布类似的内容 - 我最终发布了我正在研究的代码,这里是供未来旅行者参考的链接(尽管我最终使用Python编写了一个简单的汇编器来处理arm64操作码PDF,但代码在几年前丢失了,而且它并不是特别聪明,这种编译方法更好) - 谢谢@Clement-Jean的分享和提醒。

https://github.com/hztools/go-sdr/blob/9809d5729f372dde16038710b13f70ff484baaf8/internal/simd/mult_simd_arm64.s#L89

u0sqgete

u0sqgete8#

感谢Clement-Jean对贡献的关注!ARM64汇编器后端的源代码位于https://cs.opensource.google/go/go/+/master:src/cmd/internal/obj/arm64/。鉴于我们已经支持了类似的指令,不难为新指令添加支持。谢谢。

相关问题