我们可以使用_mm256_packs_epi32。如下:__m256i e = _mm256_packs_epi32 ( ai, bi);
在调试器中,我看到ai:m256i_i32 = {0, 1, 0, 1, 1, 1, 0, 1}
的值。我还看到bi:m256i_i32 = {1, 1, 1, 1, 0, 0, 0, 1}
的值。包装给了我e:m256i_i16 = {0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1}
。包装是交错的。所以我们有前四个数字在ai中,前四个数字在bi中,最后四个数字在ai中,最后四个数字在bi中按这个顺序排列。
我想知道是否有这样一种指令,就是将ai和bi并排打包,而不需要交织。
包装后的vpermq是可行的,但我想知道是否有一个单一的指令来实现这一点。
发布于 2021-06-15 08:28:50
不幸的是,在AVX-512之前没有顺序交叉车道打包。(即使这样,也只适用于一个寄存器,或者没有饱和。)
像vpacksswd
和vpalignr
这样的混搭在车道上的行为是AVX2的主要缺点之一,这使得这些洗牌的256位版本不如它们的__m128i
版本有用。但是在英特尔和Zen2 CPU上,如果您需要按特定顺序使用__m256i
向量,在最后使用vpermq
是最好的。(或在2级包装后带有向量常数的vpermd
:t)?)
如果您的32位元素来自于解压更窄的元素,而您不关心更宽元素的顺序,那么您可以使用车道内解包扩展,这使您可以重新打包到原来的顺序中。
这对于零扩展解包来说很便宜:_mm256_unpacklo/hi_epi16
(带有_mm256_setzero_si256()
)。这和vpmovzxwd
(_mm256_cvtepu16_epi32
)一样便宜,而且实际上更好,因为您可以对源数据执行256位的加载,并以两种方式解压缩,而不是只在输入寄存器底部的数据上工作的vpmovzx...
。(而且内存源vpmovzx... ymm, [mem]
不能在英特尔CPU上将负载与YMM目标进行微融合,只用于128位XMM版本,因此前端成本与单独的加载和洗牌指令相同。)
但是,对于需要签名扩展的数据,这个技巧不太管用。vpcmpgtw
得到高一半的vpunpckl/hwd
确实有效,但是vpermq
在重新包装时也是一样好的,只是不同的执行端口压力。所以vpmovsxwd
在那里更简单。
将数据分割成奇数/偶数(而不是低/高)也可以工作,例如将16位元素零扩展为32位元素:
auto veven = _mm256_and_si256(v, _mm256_set1_epi32(0x0000FFFF));
auto vodd = _mm256_srli_epi32(v, 16);
经过处理后,可以与shift和vpblendw
进行重组。(英特尔Skylake /冰湖5号端口1 uop )。或者是字节,使用控制向量的vpblendvb
,但这在Intel上要花费2个uop (但任何端口除外),而在Zen2上只需1uop。(这些uop计数不包括将奇数元素与其起点对齐的vpslld ymm, ymm, 16
移位。)
,即使使用AVX-512,情况也不是很好。仍然可以使用单个洗牌uop将两个向量组合到相同宽度的一个。
对于任何一对元素大小,如vpmovzx
/ sx
的逆值,都有非常好的单矢量截断或符号或无符号饱和的缩小。例如vpmov[su]qb
,有一个可选的内存目的地。
(有趣的事实:vpmovdm [rdi]{k1}, zmm0
是Xeon (缺乏AVX-512 be和AVX-512 in )对内存进行字节屏蔽存储的唯一方法;这可能就是这些存储以内存目的地形式存在的原因。在像Skylake-X /Skylake这样的主流英特尔上,内存目的地版本并不比单独打包到寄存器中存储更便宜。https://uops.info/)
AVX-512也有一个很好的2输入洗牌和一个控制向量,所以对于dword到word截断您可以使用vpermt2w zmm1, zmm2, zmm3
。但这需要一个洗牌控制向量,而vpermt2w
是SKX和IceLake上的3 uop。(t2d
和t2q
为1 uop)。vpermt2b
只在AVX-512VBMI (冰湖)提供,在那里也有3个uops。
(不像vpermb
在冰湖上是1 uop,而AVX-512 is vpermw
是冰湖上还有2英尺。因此,它们没有降低向后兼容指令的前端成本,但ICL可以在端口0或1上运行它的2个uop中的一个,而不是在端口5上的洗牌单元上运行两个uop。也许ICL有一个uop将洗牌控件预处理成vpermb控件或什么的,这也可以解释为什么延迟会有所改善:数据的3个周期->数据,控制>数据的4个周期->数据。对于2p5 uops,SKX上有6个周期,显然是从控件和数据向量开始的串行依赖。)
https://stackoverflow.com/questions/67979078
复制相似问题