如何混合32位整数?或者:为什么没有_mm256混合_epi32?

问题描述 投票:2回答:1

我正在使用AVX2 x86 256位SIMD扩展。我想做一个32位整数组件if-then-else指令。在英特尔文档中,这样的指令称为vblend。

Intel内部指南包含函数_mm256_blendv_epi8。这个功能几乎可以满足我的需求。唯一的问题是它适用于8位整数。遗憾的是,文档中没有_mm256_blendv_epi32。我的第一个问题是:为什么这个功能不存在?我的第二个问题是:如何模仿它?

经过一番搜索,我找到了_mm256_blendv_ps,它可以满足我对32位浮点的需求。此外,我发现了转换函数_mm256_castsi256_ps和_mm256_castps_si256,它们从整数转换为32位浮点数并返回。将这些放在一起给出:

inline __m256i _mm256_blendv_epi32 (__m256i a, __m256i b, __m256i mask){
    return _mm256_castps_si256( 
        _mm256_blendv_ps(
            _mm256_castsi256_ps(a),
            _mm256_castsi256_ps(b),
            _mm256_castsi256_ps(mask)
        ) 
    );
}

虽然这看起来像5个函数,但其​​中4个只是美化的强制转换,而另一个直接映射到处理器指令。因此,整个功能归结为一个处理器指令。

因此,真正尴尬的部分是似乎有一个32位的blendv,除了相应的内在缺失。

是否有一些边境案例,这将失败?例如,当整数位模式碰巧表示浮点NAN时会发生什么? blendv会忽略这个还是会引发一些信号?

如果这是有效的:我是否正确,有一个8位,32位和64位blendv但是缺少16位blendv?

c++ c sse intrinsics avx2
1个回答
3
投票

如果你的mask已经为整个32位元素全部为零/全部(如vpcmpgtd结果),请直接使用_mm256_blendv_epi8

我的代码依赖于blendv只检查最高位。

那你有两个不错的选择:

  • 使用VBLENDVPS。你是正确的,所有演员表只是为了让编译器满意,VBLENDVPS将在一条指令中完全按照你的意愿行事。
static inline
__m256i blendvps_si256(__m256i a, __m256i b, __m256i mask) {
    __m256 res = _mm256_blendv_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b), _mm256_castsi256_ps(mask));
    return _mm256_castps_si256(res);
}

但是,当将整数结果转发到FP混合单元时,Intel SnB系列CPU的旁路延迟延迟为1个周期,而将混合结果转发给其他整数指令时则具有另外1c延迟。如果延迟不是瓶颈,这可能不会影响吞吐量。

有关旁路延迟延迟的更多信息,请参阅Agner Fog's microach guide。这就是他们不为FP指令制作__m256i内在函数的原因,反之亦然。请注意,由于Sandybridge,FP shuffle没有额外的延迟来转发/转发到PADDD之类的指令。因此,如果PUNPCK *或PALIGNR没有完全符合您的要求,SHUFPS是组合来自两个整数向量的数据的好方法。 (即使在Nehalem上,整数上的SHUFPS也是值得的,如果吞吐量是你的瓶颈,那么它在两方面都会有2c的惩罚)。

尝试两种方式和基准。无论哪种方式都可能更好,具体取决于周围的代码。

与uop吞吐量/指令计数相比,延迟可能无关紧要。另请注意,如果您只是将结果存储到内存中,则存储指令不关心数据来自哪个域。

但是,如果您将此作为长依赖链的一部分使用,那么可能值得额外的指令来避免混合数据的额外2个周期的延迟。

请注意,如果掩码生成位于关键路径上,那么VPSRAD的1个周期延迟等于旁路延迟延迟,因此使用FP混合只是掩码 - >结果链的1个额外延迟周期,而2数据 - >结果链的额外周期。


例如,当整数位模式碰巧表示浮点NAN时会发生什么?

BLENDVPS不关心。英特尔的insn ref manual fully documents everything an instruction can/can't do和SIMD浮点异常:无意味着这不是问题。另请参阅标签wiki以获取文档链接。

FP blend / shuffle / bitwise-boolean / load / store指令不关心NaN。只有执行实际FP数学运算的指令(包括CMPPS,MINPS和类似的东西)才会引发FP异常,或者可能会因非正规性而减速。


我是否正确,有一个8位,一个32位和一个64位的blendv但是缺少一个16位的blendv?

是。但是有32位和16位算术移位,因此使用8位粒度混合最多需要一条额外的指令。 (没有PSRAQ,因此64位整数的混合通常最好用BLENDVPD完成,除非掩模生成偏离关键路径和/或相同的掩码将在关键路径上重复使用多次。)

最常见的用例是比较掩码,其中每个元素都是全1或全0,因此您可以与PAND / PANDN => POR混合。当然,巧妙的技巧只会使掩码的符号位与真值保持一致,可以节省指令和延迟,特别是因为变量混合比三个布尔按位指令快一些。 (例如,ORPS两个浮点向量,看看它们是否都是非负的,而不是2x CMPPS和ORing蒙版。如果你不关心负零,这可以很好用,或者你很乐意将下溢对待-0.0作为消极)。

© www.soinside.com 2019 - 2024. All rights reserved.