tml*_*len 6 bit-manipulation simd avx avx2 avx512
使用AVX512,有一个internal函数_mm256_lzcnt_epi32,该函数返回一个向量,该向量对于8个32位元素中的每个元素,包含输入向量元素中前导零位的数量。
是否有仅使用AVX和AVX2指令来实现此目标的有效方法?
目前,我正在使用一个循环,该循环提取每个元素并应用该_lzcnt_u32函数。
相关:要对一个大位图进行位扫描,请参见__m256i字中的前导零计数,该字使用pmovmskb->位扫描以找到要执行标量位扫描的字节。
这个问题是关于当您实际上要使用全部8个结果而不仅仅是选择一个时,对8个单独的32位元素执行8个单独的lzcnts。
float 代表指数格式的数字,因此int-> FP转换为我们提供了在指数字段中编码的最高置位位的位置。
我们希望int- > float震级四舍五入下降(截断向0值),最近的不是默认四舍五入。那可能会四舍五入,0x3FFFFFFF看起来像0x40000000。如果您在不进行任何FP数学运算的情况下进行了大量此类转换,则可以将MXCSR 1中的舍入模式设置为截断,然后在完成后将其设置回去。
否则,您可以v & ~(v>>8)用来保留8个最高有效位,并使某些或所有较低位保持为零,包括MSB下方的一个可能置位的位8。这足以确保所有舍入模式都不会舍入到2的下一个幂。它始终保持8个最高有效位,因为v>>8移位了8个零,所以倒数为8个。在低位位置,无论MSB处于什么位置,都会从高位开始经过8个零,因此它将永远不会清除任何整数的最高有效位。根据MSB队列下方的置位方式,它可能会或可能不会清除以下8个最高有效位。
转换后,我们在位模式上使用整数移位将指数(和符号位)移至底部,并使用饱和减法消除偏置。min如果在原始32位输入中未设置任何位,则我们将结果设置为32。
__m256i avx2_lzcnt_epi32 (__m256i v) {
// prevent value from being rounded up to the next power of two
v = _mm256_andnot_si256(_mm256_srli_epi32(v, 8), v); // keep 8 MSB
v = _mm256_castps_si256(_mm256_cvtepi32_ps(v)); // convert an integer to float
v = _mm256_srli_epi32(v, 23); // shift down the exponent
v = _mm256_subs_epu16(_mm256_set1_epi32(158), v); // undo bias
v = _mm256_min_epi16(v, _mm256_set1_epi32(32)); // clamp at 32
return v;
}
Run Code Online (Sandbox Code Playgroud)
脚注1:fp-> int转换可用于截断(cvtt),但int-> fp转换仅可用于默认舍入(取决于MXCSR)。
AVX512F为512位向量引入了舍入模式替代,可以解决此问题__m512 _mm512_cvt_roundepi32_ps( __m512i a, int r);。但是所有带有AVX512F的CPU也都支持AVX512CD,因此您可以使用_mm512_lzcnt_epi32。加上AVX512VL,_mm256_lzcnt_epi32