C++ SIMD:更通用的洗牌函数
我认为SIMD shuffle功能适用于C++ SIMD:更通用的洗牌函数,c++,intel,simd,intrinsics,avx,C++,Intel,Simd,Intrinsics,Avx,我认为SIMD shuffle功能适用于int32\u t情况,左右部分将分别进行洗牌 我想要一个真正的洗牌函数,如下所示: 假设我们得到了\uuuum256i,我们想洗牌8int32\u 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);
int32\u t
情况,左右部分将分别进行洗牌
我想要一个真正的洗牌函数,如下所示:
假设我们得到了\uuuum256i
,我们想洗牌8int32\u 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,-,-,-,-}
,其中-
表示不相关的值,它们可以是任何值。
因此,我希望设置位为1
的位置处的int
将被置于shuffled
中
(在我们的例子中:17、20、25、26坐在imm8
中带有1
的位置)
这样的功能是由英特尔公司提供的吗 如何有效地实施这一职能
编辑:
-
可以忽略。只需要设置位为1
的int。(我假设您立即向后(17的选择器应该是低位,而不是高位),并且向量实际上是以低位元素的第一顺序写入的)
如何有效地实施这一职能
在这种情况下,使用AVX2vpermd
(\u mm256\u permutevar8x32\u epi32
)。它需要一个控制向量,而不是一个立即数,来为8个输出元素保存8个选择器。因此,您必须加载一个常量并将其用作控制操作数
由于只关心输出向量的下半部分,因此向量常数只能是\uuum128i
,从而节省空间vmovdqa xmm,[mem]
zero扩展到相应的YMM向量中。用C语言编写内部函数可能不太方便,但是\u mm256\u castsi128\u si256
应该可以工作。甚至\u mm256\u broadcastsi128\u si256
,因为广播负载同样便宜。不过,一些编译器可能会通过常量传播将其悲观化为内存中实际的32字节常量。若你们知道汇编,编译器的输出常常令人失望
如果你想在你的源代码中取一个实际的整数位图,你可以使用C++模板将它编译成正确的向量常量。(现在Apache授权的,以前的GPL)有一些相关的东西,像使用C++模板,根据常数和支持什么目标ISA,将整数常量转换成一个混合或一系列混合指令。但是它的洗牌模板是索引列表,而不是位图
但我想你是想问为什么/如何设计x86洗牌。这样的功能是由英特尔公司提供的吗 是,在带有AVX512F的硬件中(加上AVX512VL在256位向量上使用) 您正在寻找,它是与BMI2
pext
等价的向量元素。(但它将控制操作数作为掩码寄存器值,而不是立即数常量。)内在值为\uuuum256i\umm256\uMaskz\uCompress32(\uuuummask8 c,\uuuum256i a)代码>
它也可用于合并到现有向量底部的版本,而不是将顶部元素归零
作为即时洗牌,不需要。
所有x86洗牌都使用一个在源中具有索引的控制操作数,而不是保留哪些元素的位图。(除了vpcompressd/q
和vpexpandd/q
)。或者,它们使用隐式控制,如\u mm256\u unplo\u epi32
,例如,它将来自2个输入的32位元素交错(在低半部和高半部的通道中)
如果您打算提供一个带有控制操作数的洗牌,那么如果任何元素可以在任何位置结束,这通常是最有用的。因此,输出不必与输入的顺序相同。你的压缩洗牌没有那个属性
此外,为每个输出元素提供源索引是shuffle硬件自然想要的。我的理解是,每个输出元素都由它自己的MUX(多路复用器)馈送,其中MUX接受N个输入元素和一个二进制选择器来选择要输出的元素。(当然,宽度与元素宽度相同。)有关构建复用器的更多讨论,请参阅
如果控制操作数的格式不是选择器列表,则需要先进行预处理,然后才能将其送入洗牌硬件。
对于立即数,格式为2x1位或4x2位字段,或为\u mm\u bslli\u si128
和\u mm\u aligner\u epi8
的字节移位计数。或insertps
的索引+调零位掩码。没有立即宽度大于8位的SIMD指令这可能使硬件解码器保持简单。
(或者对于vextractf128 xmm,ymm,0或1
使用1x1位,事后来看,如果根本没有立即数,这会更好。将它与0
一起使用总是比vmovdqa xmm,xmm
更糟糕。虽然AVX512使用相同的操作码,但对于1x2位立即数使用EVEX前缀,因此这可能对解码器的复杂性有一些好处。)y、 无论如何,选择器字段宽度大于2位时不存在立即混洗,因为8x 3位将是24位。)
对于较宽的4x2车道内混洗,如\u mm256\u shuffle\u ps
(vshufps ymm、ymm、ymm、imm8
),相同的4x2位选择器模式可重复用于两条车道。对于较宽的2x1车道内混洗,如\u mm256\u shuffle\u pd
(),我们获得仍在车道中选择的4x1位立即字段
有4个2位选择器、vpermq
和vpermpd
的车道交叉混洗。它们的工作原理与pshufd xmm
(mm\u shuffle\u epi32
)完全相同,但在256位寄存器上有4个qword元素,而不是在128位寄存器上有4个dword元素
就缩小范围/仅关注部分输出而言:
一个普通的立即数需要4个3位选择器来选择每个索引