排列 AVX 寄存器的内容
Permute content of AVX register
我有一个带有四个双精度值的AVX寄存器。现在我需要对每个元素单独执行一些算术。我需要做的一个例子如下。
Situation:
a = [a4 a3 a2 a1]
w = [ 0 0 0 w1]
x = [ 0 0 0 x1]
y = [ 0 0 0 y1]
z = [ 0 0 0 z1]
Desired result:
w = [-- -- -- w1+a1]
x = [-- -- -- x1+a2]
y = [-- -- -- y1+a3]
z = [-- -- -- z1+a4]
除了期望的结果不仅仅是两个值的总和,而是它们更复杂的算术表达式。我把--
放在哪里,我的意思是我不在乎那些价值,这些价值观将被丢弃。
我想出我可以使用排列操作来排列寄存器a
(例如,参见使用单个AVX内联函数反转包含双精度的AVX寄存器(。我唯一的问题是这些内部函数需要一个即时的,即编译时值,而我需要动态地执行此操作。
我发现了排列内联函数,它们对其他寄存器(如_mm256_permutevar_pd(中包含的整数进行操作,但它们都没有跨通道排列(例如,使用这些指令首先不可能有a3
。使用这些说明执行我想要的操作的唯一方法是使用 if
,我宁愿避免这样做。
我是否应该在受if
条件约束的 128 位通道上进行排列,然后在通道内进行动态排列?还是有更好的解决方案?我对性能和可维护性都感兴趣。我最多可以使用AVX2指令。组装是一种选择,但我更喜欢内在。
理想情况下,您可以将[ z y x w ]
打包到矢量中后,使用 SIMD 运算执行+
所表示的任何操作。 但如果没有:
以正常方式将所有 4 个元素提取到标量double
,然后执行任何您想要的操作:
void unpack_256_to_scalar(__m256d a) {
// unpack to two 128b halves
__m128d a01 = _mm256_castpd256_pd128(a); // extractf128_pd(a, 0) should also compile the same way, if you like more-consistent C instead of code that matches the asm you expect
__m128d a23 = _mm256_extractf128_pd(a, 1);
// and then halves of each 128b vector
double a0 = _mm_cvtsd_f64(a01);
double a1 = _mm_cvtsd_f64(_mm_unpackhi_pd(a01,a01));
double a2 = _mm_cvtsd_f64(a23);
double a3 = _mm_cvtsd_f64(_mm_unpackhi_pd(a23,a23));
...
// use the results
}
这(在 Godbolt 编译器资源管理器上(编译为只有 3 条带有 clang 的指令,或者使用 gcc 编译为 4 条指令,因为它在寄存器分配方面很愚蠢:
unpack_256_to_scalar(double __vector(4)):
vextractf128 xmm1, ymm0, 0x1
vunpckhpd xmm2, xmm0, xmm0
vmovapd xmm3, xmm1 # gcc should have use vunpckhpd xmm3, xmm1,xmm1. This wasted mov is a missed-optimization bug.
vunpckhpd xmm1, xmm1, xmm1
# the empty asm statement emitted the empty string here.
vzeroupper
ret
三个指令中的每一个都会产生一个不同的元素作为其向量结果的低元素。 不需要常量,甚至不需要即时常量(这就是为什么我选择了 unpackhi_pd
而不是 clang 在从其内部表示数据移动生成随机播放时使用的shufpd
或vpermilpd
。
使用需要向量作为控制掩码的变量洗牌在这里是疯狂的。 这似乎不需要任何动态/变量洗牌或提取。
顺便说一句,请参阅 x86 标签 wiki 以获取有关编写高性能代码的一些链接。
- 本质:使用__128寄存器
- 将寄存器设计成可由C和C++访问的外设的最佳实践
- 在模拟器中使用并集来模拟CPU寄存器有多合适
- 使用英特尔 PIN 修改寄存器
- AVX 指令中寄存器和指针之间的客观差异
- 如何确定我的处理器有多少个 AVX 寄存器?
- 除非使用某些寄存器,否则函数挂钩会崩溃
- 寄存器上的管道计算
- 其中关于内存和寄存器的左值和右值
- 有没有办法强制C++编译器将变量存储在寄存器中?
- "变量":函数中函数作用域不允许初始化的自动或寄存器变量'naked'
- Atmel Studio:返回一个包含数组的寄存器
- 使用 AVX 对两个 zmm(512 位)寄存器进行异或运算
- 在英特尔x86体系结构上使用非AVX指令修改xmm整数寄存器值
- 有4位,如何为AVX寄存器产生口罩
- 如何从AVX寄存器中获取数据
- SSE/AVX 寄存器的非零字节索引
- 是阻塞xmm/ymm寄存器的静态/静态本地SSE/AVX变量
- 用AVX寄存器联合类成员以减少内存访问
- 排列 AVX 寄存器的内容