在clangAArch64上用NEON本征扩展int32x2_t到int32x4_t时,如何用NEON本征扩展新通道?

问题描述 投票:2回答:1

ARM的朋友们,我想用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寄存器的后半部分不被初始化?我想避免使用内联汇编。谢谢你!

arm simd intrinsics arm64 neon
1个回答
2
投票

我不知道有什么好的解决方案,使用通用的 arm_neon.h 但至少在Clang中,可以使用Clang特有的buildins来生成一个矢量,其中一些元素被设置为未定义,这样代码生成就不需要用任何特定的值来填充它们。

一个使用这种方法的设置是这样的。

$ 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

https:/godbolt.orgzN_NsSE

请看 https:/clang.llvm.orgdocsLanguageExtensions.html#builtin-shufflevector。 的文件 __builtin_shufflevector.

EDIT: 在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.orgzTzHuon),而GCC仍然包括一个 mov v0.8b, v0.8b (https:/godbolt.orgzwZTAU9).


0
投票
$ 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

https:/godbolt.orgzATr4D7。

© www.soinside.com 2019 - 2024. All rights reserved.