使用 AVX2 C++ 的选择性加载

Posted

技术标签:

【中文标题】使用 AVX2 C++ 的选择性加载【英文标题】:Selective load using AVX2 C++ 【发布时间】:2019-12-04 13:16:50 【问题描述】:

我正在尝试使用 AVX2 实现以下目标,但花了半天时间却无法做到。 我尝试使用 maskload 和其他东西,但未能解决问题。

我有两个双精度数组,a 和 b。

double a[] = -1000.00, 0.00, 2000.00, 3500.00;
double b[] = 1.25, 1.636, -2.50, 3.25;

我只想将b 中的那些值加载到__m256d 中,a 中的对应值不为零,否则设置为 0。

类似:

double c[4];
for(int i=0; i<4; ++i)

    if a[i] == 0
        c[i] = 0;
    else
        c[i] = b[i];

有人可以帮忙吗?

编辑:这是一个更大问题的一部分,不只有 4 个值,因此我不想像这里一样计算另一个数组并将该数组加载到寄存器中。

【问题讨论】:

是否允许从b 加载丢弃的条目,还是必须保持原样? 是的,我们可以将它加载到一个临时变量中,然后再删除它们 【参考方案1】:

由于b的条目可以无条件加载,所以应该清零的条目可以用掩码清零:

__m256d zero = _mm256_setzero_pd();
__m256d c = _mm256_and_pd(b, _mm256_cmp_pd(zero, a, _CMP_NEQ_UQ));

使用 _CMP_NEQ_UQ 意味着 a 中的 NaN 不会将条目归零,而使用 _CMP_NEQ_OQ 时,零和 NaN 都会将条目归零。

【讨论】:

在 Skylake 上,_mm256_maskload_pd 应该同样有效,vcmppd 结果与掩码相同。尽管如果掩码必须在加载开始之前准备好,它可能会有更短的延迟。 vmaskmovpd 作为负载是 Skylake 上的 2 个融合域微指令,p23 + p015。它在 Ryzen 上也很有效,只有一个 uop(每 128 位)。但在 Broadwell 或更早的版本上,它是 3 微指令,p23 + 2p5,这与 vandpd 相比很糟糕。

以上是关于使用 AVX2 C++ 的选择性加载的主要内容,如果未能解决你的问题,请参考以下文章

用于灰度到 ARGB 转换的 C++ SSE2 或 AVX2 内在函数

在啥情况下,AVX2 收集指令会比单独加载数据更快?

两个 16 位整数向量与 C++ 中的 AVX2 的内积

加载指令与 AVX 中的 AVX2 __m256i const* mem_addr [关闭]

从填充为 0 的数组加载到 256 位 AVX2 寄存器

SIMD (AVX2) - 将 uint8_t 值加载到多个浮点 __m256 寄存器