我正在使用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?
答案 0 :(得分:3)
如果您的mask
对于整个32位元素(例如vpcmpgtd
结果)已经全为零/全部,请使用_mm256_blendv_epi8
直接
我的代码仅依赖于blendv检查最高位。
然后你有两个不错的选择:
使用算术右移31来广播每个元素中的高位,以设置VPBLENDVB (_mm256_blendv_epi8
)。即VPSRAD: mask=_mm256_srai_epi32(mask, 31)
。
对于port0,VPSRAD在Intel Haswell上为1-uop。 (Skylake的吞吐量更高:p01)。如果你的算法在端口0上遇到瓶颈(例如整数乘法和移位),那就不太好了。
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
尝试双向和基准。无论哪种方式都可以更好,取决于周围的代码。
与uop吞吐量/指令数相比,延迟可能无关紧要。另请注意,如果您只是将结果存储到内存中,那么存储说明并不关心数据来自哪个域。
但是如果你使用它作为长依赖链的一部分,那么可能值得额外的指令来避免混合数据的额外2个周期的延迟。
请注意,如果掩码生成位于关键路径上,那么VPSRAD的1个周期延迟相当于旁路延迟延迟,因此使用FP混合仅为掩模的额外延迟周期 - >结果链,相对于数据 - >结果链的2个额外周期。
例如,当整数位模式碰巧表示浮点NAN?
时会发生什么
BLENDVPS并不在意。英特尔的insn ref manual fully documents everything an instruction can/can't do和 SIMD浮点异常:无意味着这不是问题。另请参阅x86代码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
的下溢视为否定)。