提问人:Serge Rogatch 提问时间:8/20/2023 更新时间:8/21/2023 访问量:152
如何将 8 个打包的 32 位整数(在一个 __m256i)的 +-1 个符号打包成 64 位整数的字节?
How to pack +-1 signs of 8 packed 32-bit integers (in an __m256i) into bytes of a 64-bit integer?
问:
给定一个打包的 32 位有符号整数,如果原始的相应 32 位有符号整数大于或等于 0,如何获得每个字节的单个 64 位数字,如果该 32 位整数为负数?__m256i
1
__m256i
-1
AVX2(可能还有 AVX512)值得关注。
答:
1赞
Alex Guteniev
8/21/2023
#1
您可以将结果转换为 +1 / -1 作为向量,然后使用一系列包对其进行压缩。__m256i
第一步可以完成:
- 使用后跟 with ,正如 Peter Cordes 所建议的那样
_mm256_srai_epi32(val, 31)
or
_mm256_set1_epi32(1)
- 正如 Harold 所建议的那样使用 ,然后是 with 正如 Peter Cordes 所观察到的那样
_mm256_sign_epi32(_mm256_set1_epi32(1), values)
or
_mm256_set1_epi32(1)
- 像这样,知道符号和掩码位 和 处于同一位置:
float
int32_t
__m256i plus_or_minus_pi32 = _mm256_castps_si256(_mm256_blendv_ps(
_mm256_castsi256_ps(_mm256_set1_epi32(+1)),
_mm256_castsi256_ps(_mm256_set1_epi32(-1))
_mm256_castsi256_ps(val)));
然后是随机播放,然后另一个可以将其压缩到向量。_mm256_packs_epi32
_mm256_packs_epi16
int8_t
最后,如果需要,使用零参数转换为 GRP。_mm256_extract_epi64
评论
1赞
Peter Cordes
8/21/2023
另一种策略是从算术右移 31 () 开始,得到 0 / -1 值,然后是 OR 和 After Packing。由于在 Intel CPU 上花费 2 uops,因此这是领先的(特别是如果将多个向量打包为一个,或者您可以在标量中执行 OR)。它还避免了向量常量。请注意,AVX2 打包说明不是跨车道的,因此您需要在两轮车道内打包后进行洗牌。_mm256_srai_epi32(v, 1)
set1_epi8(1)
blendv
0赞
Peter Cordes
8/21/2023
@harold:vpsignd
将 input = 0 时的值归零。在这种情况下,OP 需要,所以我们仍然必须在末尾标量 OR with 将任何零变成 1,并保持任何 -1 不变。移位产生 0 / -1,无需向量常数。1
0x0101010101010101
1赞
Peter Cordes
8/21/2023
@harold:您使用的标量策略可以用 OR 和 来固定,编译器在寄存器中已经需要相同的常量,因此它是有效的(Zen 2 及更早版本除外)。我认为,如果你只有一个向量,这在总 uop 计数上实际上是相当不错的。pdep
0x01...
pdep
3赞
Soonts
8/21/2023
#2
这是另一种方法。
它需要 BMI2 支持 PDEP 指令,仅在 Intel 和 AMD 上快速,从 Zen 3 微架构开始。
// Convert sign bits of 8 int32 lanes into -1 / +1 bytes
uint64_t packSigns( __m256i vec )
{
// Bitcast to FP32 vector, compiles into no instructions
__m256 fv = _mm256_castsi256_ps( vec );
// Move sign bits to general-purpose register
uint64_t bits = (uint32_t)_mm256_movemask_ps( fv );
// Expand bits into bytes
constexpr uint64_t lowBits = 0x0101010101010101ull;
bits = _pdep_u64( bits, lowBits );
// Convert 0 / +1 bytes into +1 / -1 bytes
return ( bits * 0xFF ) | lowBits;
}
评论
0赞
Soonts
8/21/2023
@harold 问得好。查看编辑,保存了一条指令。
评论
int64_t
__m256i
_mm256_srai_epi32(v, 31)
(-1, 0, 1)
__m256i
pmaddubsw
int8_t
0
-1
-x = ~x + 1
(x ^ signs) - signs
-x
_mm256_packs_epi32(v0,v1)
_mm256_srai_epi16(tmp, 15)
_mm256_cmpgt_epi8( _mm256_setzero_si256(), tmp)
0 > v
vpblendvb
0 - x
vpshufb