当您不关心新车道时,如何使用 clang/AArch64 上的 NEON 内在函数将 int32x2_t 扩展到 int32x4_t?
How to extend a int32x2_t to a int32x4_t with NEON intrinsics on clang/AArch64 when you don't care about the new lanes?
各位 ARMists,
我想用 NEON 代码缩小和饱和 2 s32 到 2 s16,并将它们打包在 GPR 中。
我需要符合某个API,所以请不要在这里讨论效率或设计:)
这是片段:
int32x2_t stuff32 = ...;
int16x4_t stuff16 = vqmovn_s32(vcombine_s32(stuff32, stuff32));
return vget_lane_u32(stuff16, 0)
生成
mov v0.d[1], v0.d[0]
sqxtn v0.4h, v0.4s
fmov w0, s0
ret
有人知道保持类型系统正常运行并使 d 寄存器的后半部分未初始化的方法吗?我想避免内联汇编。
谢谢!
$ cat a.c
#include <arm_neon.h>
int32_t narrow_saturate(int32x2_t stuff32) {
int32x2_t zero = {0, 0};
int16x4_t stuff16 = vqmovn_s32(vcombine_s32(stuff32, zero));
return vget_lane_s32(vreinterpret_s32_s16(stuff16), 0);
}
$ gcc -O2 a.c -S -o-
[...]
narrow_saturate:
mov v0.8b, v0.8b
sqxtn v0.4h, v0.4s
umov w0, v0.s[0]
ret
我不知道使用一般 arm_neon.h
内在函数有什么好的解决方案,但至少对于 Clang,有可能使用 Clang 特定的内置函数来生成一个向量,其中某些元素被设置为未定义,因此代码生成器不需要特别为它们填充任何值。
使用它的设置如下所示:
$ cat test.c
#include <arm_neon.h>
int32_t narrow_saturate(int32x2_t stuff32) {
int16x4_t stuff16 = vqmovn_s32(__builtin_shufflevector(stuff32, stuff32, 0, 1, -1, -1));
return vget_lane_s32(vreinterpret_s32_s16(stuff16), 0);
}
$ clang -target aarch64-linux-gnu test.c -S -o - -O2
[...]
narrow_saturate:
sqxtn v0.4h, v0.4s
fmov w0, s0
ret
有关 __builtin_shufflevector
的文档,请参阅 https://clang.llvm.org/docs/LanguageExtensions.html#builtin-shufflevector。
编辑:似乎也可以通过使用未初始化的变量在 Clang 中实现同样的效果(尽管这会通过 `-Wuninitialized 生成警告):
$ cat test.c
#include <arm_neon.h>
int32_t narrow_saturate(int32x2_t stuff32) {
int32x2_t uninitialized;
int16x4_t stuff16 = vqmovn_s32(vcombine_s32(stuff32, uninitialized));
return vget_lane_s32(vreinterpret_s32_s16(stuff16), 0);
}
Clang 生成与上面相同的内容 (https://godbolt.org/z/TzHuon), while GCC still includes a mov v0.8b, v0.8b
(https://godbolt.org/z/wZTAU9)。
各位 ARMists,
我想用 NEON 代码缩小和饱和 2 s32 到 2 s16,并将它们打包在 GPR 中。
我需要符合某个API,所以请不要在这里讨论效率或设计:)
这是片段:
int32x2_t stuff32 = ...;
int16x4_t stuff16 = vqmovn_s32(vcombine_s32(stuff32, stuff32));
return vget_lane_u32(stuff16, 0)
生成
mov v0.d[1], v0.d[0]
sqxtn v0.4h, v0.4s
fmov w0, s0
ret
有人知道保持类型系统正常运行并使 d 寄存器的后半部分未初始化的方法吗?我想避免内联汇编。
谢谢!
$ cat a.c
#include <arm_neon.h>
int32_t narrow_saturate(int32x2_t stuff32) {
int32x2_t zero = {0, 0};
int16x4_t stuff16 = vqmovn_s32(vcombine_s32(stuff32, zero));
return vget_lane_s32(vreinterpret_s32_s16(stuff16), 0);
}
$ gcc -O2 a.c -S -o-
[...]
narrow_saturate:
mov v0.8b, v0.8b
sqxtn v0.4h, v0.4s
umov w0, v0.s[0]
ret
我不知道使用一般 arm_neon.h
内在函数有什么好的解决方案,但至少对于 Clang,有可能使用 Clang 特定的内置函数来生成一个向量,其中某些元素被设置为未定义,因此代码生成器不需要特别为它们填充任何值。
使用它的设置如下所示:
$ cat test.c
#include <arm_neon.h>
int32_t narrow_saturate(int32x2_t stuff32) {
int16x4_t stuff16 = vqmovn_s32(__builtin_shufflevector(stuff32, stuff32, 0, 1, -1, -1));
return vget_lane_s32(vreinterpret_s32_s16(stuff16), 0);
}
$ clang -target aarch64-linux-gnu test.c -S -o - -O2
[...]
narrow_saturate:
sqxtn v0.4h, v0.4s
fmov w0, s0
ret
有关 __builtin_shufflevector
的文档,请参阅 https://clang.llvm.org/docs/LanguageExtensions.html#builtin-shufflevector。
编辑:似乎也可以通过使用未初始化的变量在 Clang 中实现同样的效果(尽管这会通过 `-Wuninitialized 生成警告):
$ cat test.c
#include <arm_neon.h>
int32_t narrow_saturate(int32x2_t stuff32) {
int32x2_t uninitialized;
int16x4_t stuff16 = vqmovn_s32(vcombine_s32(stuff32, uninitialized));
return vget_lane_s32(vreinterpret_s32_s16(stuff16), 0);
}
Clang 生成与上面相同的内容 (https://godbolt.org/z/TzHuon), while GCC still includes a mov v0.8b, v0.8b
(https://godbolt.org/z/wZTAU9)。