Howto vblend 32位整数?或者:为什么没有_mm256_blendv_epi32?

时间:2016-11-22 16:13:01

标签: c++ c sse intrinsics avx2

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

英特尔内部指南包含函数_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?

1 个答案:

答案 0 :(得分: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);
}

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

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

尝试双向和基准。无论哪种方式都可以更好,取决于周围的代码。

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

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

请注意,如果掩码生成位于关键路径上,那么VPSRAD的1个周期延迟相当于旁路延迟延迟,因此使用FP混合仅为掩模的额外延迟周期 - >结果链,相对于数据 - >结果链的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的下溢视为否定)。