[我认为对于not real shuffle,SIMD混洗功能为int32_t
,左右部分将分别混洗。
我想要一个真正的随机播放功能,如下所示:
假设我们得到了__m256i
,我们想将8 int32_t
改组。
__m256i to_shuffle = _mm256_set_epi32(17, 18, 20, 21, 25, 26, 29, 31);
const int imm8 = 0b10101100;
__m256i shuffled _mm256_shuffle(to_shuffle, imm8);
我希望shuffled = {17, 20, 25, 26, -, -, -, -}
,其中-
代表无关的值,它们可以是任何值。因此,我希望将int
设置位置的1
放置在shuffled
中。
(在我们的情况下:17、20、25、26坐在1
中带有imm8
的位置上。
英特尔提供了这种功能吗?如何有效地实现这种功能?
编辑:-
可以忽略。仅需要设置位1
的int。
(我假设您立即倒退(17
的选择器应该是低位,而不是高位,并且您的向量实际上是以低元素优先顺序写入的。)
如何有效地实现这种功能?
在这种情况下,使用AVX2 vpermd
(_mm256_permutevar8x32_epi32
)。它需要一个不是立即数的控制向量,才能为8个输出元素保留8个选择器。因此,您必须加载一个常数并将其用作控制操作数。
由于您仅关心输出矢量的下半部分,因此矢量常量只能为__m128i
,从而节省了空间。 vmovdqa xmm, [mem]
零扩展到相应的YMM向量。用内在函数用C编写此代码可能很不方便,但是_mm256_castsi128_si256
应该可以工作。甚至_mm256_broadcastsi128_si256
,因为广播负载同样便宜。不过,有些编译器可能会通过进行常量传播将其简化为内存中的实际32字节常量。如果您知道汇编语言,则编译器输出经常令人失望。
如果要在源代码中获取实际的整数位图,则可以使用C ++模板在编译时将其转换为正确的向量常量。 Agner Fog's Vector Class Library(现在是Apache许可的,以前是GPL)具有一些相关的功能,例如,使用C ++模板,根据常量和支持的目标ISA将整数常量转换为单个混合或混合指令序列。但是其随机播放模板采用的是索引列表,而不是位图。
但是我认为您正在尝试询问为什么/如何按原样设计x86洗牌。
英特尔提供了这种功能吗?
是,在带有AVX512F的硬件中(加上AVX512VL以便在256位向量上使用它)。
您正在寻找vpcompressd
,它是BMI2 vpcompressd
的向量元素等效项。 (但是它将控制操作数作为掩码寄存器值,而不是立即数。)内在函数是pext
也可以使用合并到现有向量底部而不是将顶部元素清零的版本。
作为[[立即随机播放,编号
所有x86随机播放都使用一个控件操作数,该操作数具有指向源的索引,而不是保留哪些元素的位图。 (__m256i _mm256_maskz_compress_epi32( __mmask8 c, __m256i a);
和vpcompressd/q
除外)。或者,他们使用隐式控件,例如vpexpandd/q
,它从2个输入(低和高半部分的车道内)交错32位元素。如果您要完全提供带有控制操作数的随机播放,那么任何元素都可以在任何位置结束通常是最有用的。因此,输出不必与输入顺序相同。您的压缩随机播放不具有该属性。
此外,随机播放硬件自然需要每个输出元素都有一个源索引。我的理解是,每个输出元素都由其自己的MUX(多路复用器)馈送,其中MUX需要N个输入元素和一个二进制选择器来选择要输出的那个。 (并且宽度当然与元素的宽度一样。)有关构建复用器的更多讨论,请参见_mm256_unpacklo_epi32
。
具有选择器列表以外的某种格式的控制操作数,在将其馈送到随机播放硬件之前,需要进行预处理。
[立即,格式为2x1位或4x2位字段,或Where is VPERMB in AVX2?和_mm_bslli_si128
的字节移位计数。或_mm_alignr_epi8
的索引+调零位掩码。没有立即宽度大于8位的SIMD指令。 大概使硬件解码器保持简单。
(或insertps
为1x1位,这在事后看来会更好,根本不立即使用。与vextractf128 xmm, ymm, 0 or 1
一起使用总是比0
差。尽管AVX512确实对vmovdqa xmm, xmm
使用与vextractf32x4
相同的操作码1x2位立即数的EVEX前缀,所以这可能对解码器的复杂性有所帮助。无论如何,选择器字段不超过2位的立即混洗
,因为8x 3位将是24位。]] >对于像vextractf32x4
(_mm256_shuffle_ps
)这样的较宽的4x2通道内混洗,相同的4x2位选择器模式将重新用于两个通道。对于像vshufps ymm, ymm, ymm, imm8
(_mm256_shuffle_pd
)这样的2x1较宽的通道内混洗,我们得到4个1位立即数字段,这些字段仍选择通道内。[具有4个2位选择器vshufpd ymm, ymm, ymm, imm8
和vshufpd ymm, ymm, ymm, imm8
的横穿混洗。它们的工作原理与vpermq
(vpermpd
)完全相同,但是在256位寄存器中使用4个qword元素,而不在128位寄存器中使用4x dword元素。
普通立即数将需要4个3位选择器来为8个32位源元素之一的每个索引。但是更有可能是8个3位选择器= 24位,因为为什么要设计一个只能写一半半宽度输出的混洗指令? (pshufd xmm
除外)。
一般来说,更细粒度的混洗的范例是采用控制向量,
而不是一些时髦的立即编码。[AVX512确实添加了一些变窄的改组,例如_mm_shuffle_epi32
,可将32位元素截断(或使有符号/无符号饱和)降至8位。 (并且所有其他尺寸的组合都可用)。它们很有趣,因为它们可与内存
目标
一起使用。可能这是由于某些不具有AVX512VL的CPU(例如至强融核KNL / KNM)引起的,因此它们可以[仅]将AVX512指令与ZMM向量一起使用。它们仍然具有AVX1和2,因此您可以压缩为xmm reg,并使用常规的VEX编码存储。但这确实允许使用AVX512F进行窄字节掩码存储,只有将打包数据存储在XMM寄存器中的情况下,AVX512BW才可能进行存储。[有一些2输入混洗,例如vextractf128 xmm, ymm, 1
,它们分别处理输出的下半部分和上半部分,例如输出的低半部分可以从第一源的元素中选择,输出的高半部分可以从第二源寄存器的元素中选择。