【发布时间】:2016-11-22 01:31:43
【问题描述】:
我有一个具有四个双精度值的 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(参见例如Reverse a AVX register containing doubles using a single AVX intrinsic)。我唯一的问题是这些内在函数需要立即数,即编译时值,而我需要动态执行此操作。
我发现了对包含在其他寄存器中的整数进行操作的置换内在函数,例如 _mm256_permutevar_pd,但它们都不会跨通道置换(例如,使用这些指令首先不可能有 a3。唯一的方法使用这些说明做我想做的事情是使用if,我宁愿避免这样做。
我是否应该在 128 位通道上进行排列,以符合 if 条件,然后在通道内进行动态排列?还是有更好的解决方案?我对性能和可维护性都感兴趣。我最多可以使用 AVX2 指令。组装是一种选择,但我更喜欢内在。
【问题讨论】:
-
作为向量存储在内存中,作为标量读回?
-
当我放弃这样的解决方案时,我的应用程序得到了巨大的加速。我已经实现了“存储在内存中”的解决方案。现在我想看看整个操作在寄存器中完成时的区别。
-
所以你需要你的结果作为 4 个单独的标量双精度数? (这与将它放在向量的低元素中而其他元素无关)是一样的)。非编译时间常数洗牌从哪里来?我不明白为什么你不能只用
vextractf128解包,然后用vmovhlps或其他东西将每个__m128d的高半部分转换为标量double。你知道哪个向量元素与哪个变量名搭配... -
正确,我需要将这些值视为单独的标量。指令
vextractf128(用于像_mm256_extractf128_pd这样的内在函数)要求索引是静态值。我需要索引是动态的。我无法在编译时知道取值的顺序。 [另一个用例是当我使用for循环遍历这些值时。由于我同时支持float和double作为基本类型,因此我不能手动展开循环for (int i = 0; i < packSize; ++i),因为它需要针对不同类型进行不同的迭代。] -
我有点错过了这个问题 - 你不是总是需要相同的 3 个排列吗?即把第 2、3、4 个值降到第 1 位?
标签: c++ c intrinsics avx avx2