用c++写汇编代码

writing assembly code in c++

我在 C++ 中有以下代码:

inline void armMultiply(const float* __restrict__ src1,
                        const float* __restrict__ src2,
                        float* __restrict__ dst)
{
    __asm volatile(
                 "vld1.f32 {q0}, [%[src1]:128]!      \n\t"
                 :
                 :[dst] "r" (dst), [src1] "r" (src1), [src2] "r" (src2)
                 );
}

为什么我得到了预期的错误向量寄存器?

假设我们谈论的是 GCC,文档说您应该使用 "w" ("Floating point or SIMD vector register") 而不是 "r" ("register operand is allowed provided that it is in a general register") 作为约束.

https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/Machine-Constraints.html#Machine-Constraints

https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/Simple-Constraints.html#Simple-Constraints

您收到此错误是因为您的内联汇编适用于 32 位 arm,但您正在为 64 位 arm 编译(使用 clang - 使用 gcc 您会得到不同的错误)。

(内联)汇编在 32 位和 64 位 arm 之间是不同的,所以你需要用例如保护它。 #if defined(__ARM_NEON__) && !defined(__aarch64__),或者如果你想为 64 位和 32 位使用不同的程序集:#ifdef __aarch64__ .. #elif defined(__ARM_NEON__),等等

正如其他人评论的那样,除非您真的需要手动调整生成的程序集,否则内在函数可能同样好(在某些情况下,比您自己生成的更好)。你可以例如通过内部函数执行两个 vld1_f32 调用,一个 vmul_f32 和一个 vst1_f32 就好了。

编辑:

加载到 64 位 SIMD 寄存器的相应内联汇编是:

"ld1 {v0.4s}, [%[src1]], #16      \n\t"

要同时支持两者,您的函数可能如下所示:

inline void armMultiply(const float* __restrict__ src1,
                        const float* __restrict__ src2,
                        float* __restrict__ dst)
{
#ifdef __aarch64__
    __asm volatile(
                 "ld1 {v0.4s}, [%[src1]], #16      \n\t"
                 :
                 :[dst] "r" (dst), [src1] "r" (src1), [src2] "r" (src2)
                 );
#elif defined(__ARM_NEON__)
    __asm volatile(
                 "vld1.f32 {q0}, [%[src1]:128]!      \n\t"
                 :
                 :[dst] "r" (dst), [src1] "r" (src1), [src2] "r" (src2)
                 );
#else
#error this requires neon
#endif
}