Cya*_*yan 3 c gcc arm intrinsics neon
我正在尝试使用 NEON 向量指令做一些相对简单的事情:给定uint64x2_t,我想交换 64 位成员的位置。
又名,如果这是一个简单的普通代码:
typedef struct {
U64 u[2];
} u64x2;
u64x2 swap(u64x2 in)
{
u64x2 out;
out.u[0] = in.u[1];
out.u[1] = in.u[0];
return out;
}
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,我找不到内在的东西。显然有一个汇编指令 ( VSWP) 但没有相应的内在指令。
这很奇怪。这是一个尽可能微不足道的操作,所以它必须是可能的。问题是:如何?
编辑:作为参考,godbolt结果使用@Jake 回答:https ://godbolt.org/z/ueJ6nB
。不vswp,但vext效果很好。
您是对的,NEON 内在函数不支持该VSWP指令。
但是,您可以VEXT改用内在函数中也提供的指令。
out = vextq_u64(in, in, 1);
或者,您可以使用vcombine(并祈祷编译器不会把它搞砸):
out = vcombine_U64(vget_high_u64(in), vget_low_u64(in));
但请注意,编译器在看到vcombine和/或vget.
坚持前者,这是我的建议。
表达这种随机播放的另一种方法是使用GNU C 本机向量内置函数,它提供与目标无关的方式来执行给定的操作。根据目标支持的内容,编译时常量洗牌掩码可以优化为立即洗牌。但运行时变量洗牌可能效率低下,具体取决于目标 ISA 支持。
#include <arm_neon.h>
#ifndef __clang__
uint64x2_t swap_GNU_shuffle(uint64x2_t in)
{
uint64x2_t mask = {1,0};
uint64x2_t out = __builtin_shuffle (in, mask);
return out;
}
#endif
Run Code Online (Sandbox Code Playgroud)
Godbolt 上的 AArch64 gcc8.2实际上编译为 Jake 建议的相同 shuffle,而不是 SWP:
swap_GNU_shuffle:
ext v0.16b, v0.16b, v0.16b, #8
ret
Run Code Online (Sandbox Code Playgroud)
Clang 还优化了我们对指令的大多数纯 C 尝试ext,包括用于memcpy将类型双关语转换为普通结构并返回的指令。与 GCC 不同,GCC 没有那么好的随机优化器。(在 Godbolt 上,使用clang带有 .clang 的下拉列表中的任何一个-O3 -target arm64。默认情况下,clang 通常支持多个目标 ISA,这与 GCC 不同。)
因此,要么所有这些编译器都错过了对uneric=generic and -mcpu=cortex-a53、a57、 and的优化,a75要么ext实际上是一个不错的选择,也许比swp必须写入2个输出寄存器而不是逻辑上写入一个全角寄存器更好。但通常这对 ARM 来说不是问题;很多指令都可以做到这一点,并且通常会提高效率。
Cortex-A8 的 ARM 时序信息具有相同的vext和数字(两者从到输出vswp都有 1 个周期延迟,但从到输出有 2 个周期)。我尚未检查较新的核心(或任何 64 位核心)。QnQQmQ
| 归档时间: |
|
| 查看次数: |
460 次 |
| 最近记录: |