【问题标题】:Shuffle AVX 256 Vector elements by 1 position left/right - C intrinsics将 AVX 256 向量元素按左/右 1 个位置随机播放 - C 内在函数
【发布时间】:2017-04-09 20:40:13
【问题描述】:

我正在尝试找到一种更有效的方法来“旋转”或将 avx _m256 向量中的 32 位浮点值向右或向左移动一个位置。

这样:

a7、a6、a5、a4、a3、a2、a1、a0

变成

0、a7、a6、a5、a4、a3、a2、a1

(我不介意在我更换单元格时数据是否会丢失。)

我已经看过这个帖子:Emulating shifts on 32 bytes with AVX 但我不太明白发生了什么,也没有解释 _MM_SHUFFLE(0, 0, 3, 0) 作为输入参数的作用。


我正在尝试优化这段代码:

_mm256_store_ps(temp, array[POS(ii, jj)]);
_mm256_store_ps(left, array[POS(ii, jj-1)]);

tmp_array[POS(ii, jj)] = _mm256_set_ps(left[0], temp[7], temp[6], temp[5], temp[4], temp[3], temp[2], temp[1]);

我知道一旦换档到位,我可以使用插入来替换剩余的单元格。我觉得这会比解包到 float[8] 数组并重建更有效。

-- 我还希望能够左右移动,因为我需要在其他地方执行类似的操作。

非常感谢任何帮助!谢谢!

【问题讨论】:

  • 我们称其为随机播放,因为您是在四处移动元素,而不是在元素内移动或旋转位。
  • 感谢术语更正,问题已适当重命名!
  • 前面的代码是什么,它填充了将要移位的内容,紧随其后的代码是什么,它将使用移位的结果?也许外部部分可以集成到优化工作中。
  • 您需要这个的非 AVX2 版本吗?对于 AVX2,只需在寄存器中使用带有随机掩码的 VPERMPS。它可以进行任意的车道交叉洗牌。
  • 之前唯一的后续代码是 mm256_store_ps 使用的几个浮点数组的定义。 (attribute ((aligned (32))) float temp[8], up[8], down[8], left[8], right[8];) 后面的代码挺长的,但它是一系列数学表达式。该代码执行晶格 Boltzman 流体动力学的模拟。最初它是在每个单元格的基础上执行的(每个单元格都是一个浮点数)。我通过使用 AVX 指令同时执行 8 次迭代来优化这一点。这个阶段正在转移来自相邻细胞的流量。

标签: c sse hpc intrinsics avx


【解决方案1】:

对于 AVX2

使用VPERMPS 在一个车道交叉洗牌指令中完成。

rotated_right = _mm256_permutevar8x32_ps(src, _mm256_set_epi32(0,7,6,5,4,3,2,1));

对于 AVX(无 AVX2)

既然你说数据已经来自内存,这可能很好:

  • 使用未对齐的负载将 7 个元素放置到正确的位置,从而解决所有的车道交叉问题。
  • 然后将环绕的元素混合到其他 7 个的向量中。
  • 要获得就地包裹以进行混合的元素,可以使用广播负载将其置于高位。 AVX 可以在一条VBROADCASTPS 指令中进行广播加载(因此set1() 很便宜),尽管它确实需要英特尔 SnB 和 IvB 上的随机端口(英特尔仅有的两个具有 AVX 而不是 AVX2 的微架构)。 (请参阅 标签 wiki 中的性能链接。

INSERTPS 仅适用于 XMM 目的地,无法到达上车道。

您也许可以使用 VINSERTF128 进行另一个未对齐的加载,最终将您想要的元素作为高元素放在上车道(在低车道有一些无关向量)。

这可以编译,但未经测试。

__m256 load_rotr(float *src)
{
#ifdef __AVX2__
    __m256 orig = _mm256_loadu_ps(src);
    __m256 rotated_right = _mm256_permutevar8x32_ps(orig, _mm256_set_epi32(0,7,6,5,4,3,2,1));
    return rotated_right;
#else
    __m256 shifted = _mm256_loadu_ps(src + 1);
    __m256 bcast = _mm256_set1_ps(*src);
    return _mm256_blend_ps(shifted, bcast, 0b10000000);
#endif
}

the code + asm on Godbolt

【讨论】:

  • 再次感谢您的帮助!我尝试了 AVX2 方法,它在我自己的机器上本地运行得非常好。不幸的是,我意识到我的分发环境只有常规的 AVX。使用 loadu 的另一种方法有效,但是它比我在实施时已经做的慢 30% 左右。虽然我从您的回复中学到了很多,但还是感谢您的宝贵时间:)!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-26
  • 1970-01-01
  • 2020-01-22
  • 1970-01-01
  • 2021-06-26
  • 1970-01-01
相关资源
最近更新 更多