我目前正在与KNL合作,并试图了解AVX512的新机会。除了扩展寄存器端,AVX512还提供了新的指令集。冲突探测似乎很有希望。内在
_mm512_conflict_epi32(...)创建向量寄存器,其中包含给定源寄存器的无冲突子集:

可以看到,值的第一次出现在结果向量中相应位置的0。如果该值多次出现,则结果寄存器保存一个零扩展值.到目前一切尚好!但我想知道如何利用这一结果进行进一步的汇总或计算。我读到它可以用在前导零点计数上,但我认为这不足以确定子集的值。
有人知道如何利用这个结果吗?
由衷地
发布于 2017-08-23 00:38:09
现在我明白了,您的问题是如何利用VPCONFLICTD/Q的结果来构建用于进一步聚合或计算的子集.
使用您自己的例子:
conflict_input =
[
00000001|00000001|00000001|00000001|
00000002|00000002|00000002|00000002|
00000002|00000002|00000001|00000001|
00000001|00000001|00000001|00000001
]应用VPCONFLICTD
__m512i out = _mm512_conflict_epi32(in);现在我们得到:
conflict_output =
[
00000000|00000001|00000003|00000007|
00000000|00000010|00000030|00000070|
000000f0|000001f0|0000000f|0000040f|
00000c0f|00001c0f|00003c0f|00007c0f
]
bit representation =
[
................|...............1|..............11|.............111|
................|...........1....|..........11....|.........111....|
........1111....|.......11111....|............1111|.....1......1111|
....11......1111|...111......1111|..1111......1111|.11111......1111
]如果您希望根据第一次出现的非重复值获得一个掩码。
const __m512i set1 = _mm512_set1_epi32(0xFFFFFFFF);
const __mmask16 mask = _mm512_testn_epi32_mask(out, set1);现在,您可以使用mmask16完成所有常见的工作。
[1000100000000000]您还可以压缩它:
const __m512i out3 = _mm512_mask_compress_epi32(set0, mask, in);
[00000001|00000002|00000000|00000000|
00000000|00000000|00000000|00000000|
00000000|00000000|00000000|00000000|
00000000|00000000|00000000|00000000]您可以使用这个掩码做很多事情;但是,我注意到有趣的是,vplzcntd,并且不知道我可以在哪里使用它:
const __m512i out1 = _mm512_conflict_epi32(in);
const __m512i out2 = _mm512_lzcnt_epi32(out1);
output2 = [
00000020|0000001f|0000001e|0000001d|
00000020|0000001b|0000001a|00000019|
00000018|00000017|0000001c|00000015|
00000014|00000013|00000012|00000011
]
= [
..........1.....|...........11111|...........1111.|...........111.1|
..........1.....|...........11.11|...........11.1.|...........11..1|
...........11...|...........1.111|...........111..|...........1.1.1|
...........1.1..|...........1..11|...........1..1.|...........1...1
]发布于 2017-08-26 03:49:51
也见一些AVX512柱状图链接和信息,我在this answer上挖掘了一段时间。
我认为基本的想法是分散无冲突的元素集,然后重新收集,重新处理,然后再分散下一个无冲突的元素集。重复,直到不再有冲突。
注意,根据vpconflictd的说法,重复索引的第一次出现是一个“无冲突”元素,所以简单的重复循环会向前推进。
这一进程的步骤:
vpconflictd结果转换为一个掩码,您可以使用它与一个集合指令一起使用:针对所有向量的_mm512_testn_epi32_mask (由@veritas建议)看起来不错,因为您需要将其反转。你不能只凭自己来测试它。vpcompressd可能对此很有好处。我们甚至可以用新的元素填充向量中的“空”空间,这样我们就不会用大多数被蒙面的元素重新运行道集/进程/分散循环。例如,如果我做得对,这可能是一个直方图循环:
// probably slow, since it assumes conflicts and has a long loop-carried dep chain
// TOTALLY untested.
__m512i all_ones = _mm512_set1_epi32(-1); // easy to gen on the fly (vpternlogd)
__m512i indices = _mm512_loadu_si512(p);
p += 16;
// pessimistic loop that assumes conflicts
while (p < endp) {
// unmasked gather, so it can run in parallel with conflict detection
__m512i v = _mm512_i32gather_epi32(indices, base, 4);
v = _mm512_sub_epi32(gather, all_ones); // -= -1 to reuse the constant.
// scatter the no-conflict elements
__m512i conflicts = _mm512_conflict_epi32(indices);
__mmask16 knoconflict = _mm512_testn_epi32_mask(conflicts, all_ones);
_mm512_mask_i32scatter_epi32(base, knoconflict, indices, v, 4);
// if(knoconflict == 0xffff) { goto optimistic_loop; }
// keep the conflicting elements and merge in new indices to refill the vector
size_t done = _popcnt32(knoconflict);
p += done; // the elements that overlap will be replaced with the conflicts from last time
__m512i newidx = _mm512_loadu_si512(p);
// merge-mask into the bottom of the newly-loaded index vector
indices = _mm512_mask_compress_epi32(newidx, ~knoconflict, indices);
}我们最终都需要掩码(knoconflict和~knoconflict)。最好使用_mm512_test_epi32_mask(same,same),并避免对testn使用向量常量。这可能会从mask_compress中的索引中缩短循环携带的依赖链,方法是将掩码反转到scatter依赖链上。如果不存在冲突(包括迭代之间的冲突),则散射是独立的。
如果冲突很少,最好在它上分支,。这种对冲突的无分支处理有点像在循环中使用cmov:它创建一个长的循环携带依赖链。
分支预测+投机执行将打破这些链,并允许多个聚集/分散器同时运行。(避免在没有冲突时运行popcnt / vpcompressd )。
还请注意,vpconflictd在Skylake- not 512(但不是在KNL上)上是缓慢的。当您期望冲突非常罕见时,您甚至可以使用一个快速的any_conflicts()检查,在运行冲突处理之前不知道它们在哪里。
请参阅Fallback implementation for conflict detection in AVX2的ymm AVX2实现,它应该比Skylake-AVX2 512的微编码vpconflictd ymm更快。将其扩展到512 b zmm向量并不困难(如果您可以利用AVX512蒙面比较到掩码来替换两个比较结果之间的布尔运算,则可能会更有效)。也许和AVX512 with a NEQ predicate在一起。
https://stackoverflow.com/questions/45803140
复制相似问题