随机/置换内在函数对于256位pd如何工作?

时间:2018-08-08 12:26:08

标签: c++ intrinsics avx

我正在努力解决_mm256_shuffle_pd和_mm256_permute_pd内部函数的工作方式。 我似乎无法预测其中一项操作的结果。

首先,对于_mm_shuffle_ps来说一切都很好。我得到的结果是我期望的结果。例如:

float b[4] = { 1.12, 2.22, 3.33, 4.44 };

__m128 a = _mm_load_ps(&b[0]);
a = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 1, 2));
_mm_store_ps(&b[0], a);
// 3.33 2.22 1.12 4.44

所以一切都在这里。现在,我想使用__m256d尝试此操作,这是我当前在代码中使用的。 根据我发现_mm256_shuffle_ps / pd内部函数的工作方式有所不同。

我在这里的理解是,两次应用了控制遮罩。第一次是在128位的前半部分,第二次是在最后128位。 前两对控制位用于从第一个向量中选择(并将值存储在结果向量的第一个和第二个字以及第五个和第六个字中),而最高的位对则从第二个向量中进行选择。 例如:

float b[8] = { 1.12, 2.22, 3.33, 4.44, 5.55, 6.66, 7.77, 8.88 };

__m256 a = _mm256_load_ps(&b[0]);
a = _mm256_shuffle_ps(a, a, 0b00000111);
_mm256_store_ps(&b[0], a);
// 4.44 2.22 1.12 1.12 8.88 6.66 5.55 5.55

在这里,我期望的结果(实际上是我得到的)是{ 4.44, 2.22, 1.12, 1.12, 8.88, 6.66, 5.55, 5.55 }

这应该如下:

enter image description here

(对不起,我不好画)。 对于第二个向量(在本例中为a),使用最高的两对(即00 00)并填充缺失的空间也是如此。

我认为_mm256_shuffle_pd的工作方式相同。因此,如果我想要第一个双精度数,则必须移动00空间和01空间以正确构造它。

例如:

__m256d a = _mm256_load_pd(&b[0]);
a = _mm256_shuffle_pd(a, a, 0b01000100);
_mm256_store_pd(&b[0], a);
// 1.12 1.12 4.44 3.33

我希望它能输出{1.12,1.12,3.33,3.33}。 在我的脑海里,我从第一个向量取00 01(1.12)和00 01 {3.33},从第二个向量取00 01 {3.33},因为它是相同的向量且全部。

我已经尝试过多种组合的控制面罩,但是我只是无法将其包裹在使用方法上,也无法找到以我能理解的方式解释它的地方。

所以我的问题是:_mm256_shuffle_pd如何工作?以及如何获得与_mm_shuffle_ps(a,a,_MM_SHUFFLE(3,0,2,1))具有四个双打和一个随机播放(如果可能)相同的结果?

1 个答案:

答案 0 :(得分:5)

shufps仅需要4个元素的立即数的所有8位,每个元素有4个可能的来源。因此,它没有空间可以扩展到256位,并且唯一的选择是在两个通道中复制相同的随机播放。

但是128位shufpd只有2个元素,每个元素具有2个源,因此为2 x 1位。因此,AVX版本总共使用4位,每个通道2位。 (这不是 交叉路口,因此不如128位shufps 强大。)


http://felixcloutier.com/x86/SHUFPD.html包含带图表的完整文档,以及详细的伪代码。英特尔的_mm256_shuffle_pd内部函数指南具有相同的伪代码。

AVX2 http://felixcloutier.com/x86/VPERMPD.html_mm256_permute_pd,又名_mm256_permute4x64_pd)横穿车道,并以与128位shufps完全相同的方式使用其立即数:四个2位选择器


直到vperm2f128 (_mm256_permute2f128_pd),直到AVX512F引入更细粒度的vpermt2pdvpermt2ps(以及等效的整数洗牌),才是唯一跨越两线的洗牌。

AVX1没有粒度小于128位的甚至小于1源版本的任何通道交叉改组。如果需要一个,则必须使用vinsertf128vperm2f128 +车内混洗来构建。


因此,与使用128位向量的float相比,使用AVX将3D向量保留在SIMD向量中更加糟糕。 http://fastcpp.blogspot.com/2011/04/vector-cross-product-using-sse-code.html可能比标量要快,但是比为SIMD设计数据布局要糟糕得多。

使用连续的x[]y[]z[]的单独数组,这样您就可以并行进行4x叉积运算,而不会混洗,并利用FMA指令。< / strong>使用SIMD并行处理多个矢量,而不是加快单个矢量的速度。

请参阅https://stackoverflow.com/tags/sse/info中的链接,尤其是https://deplinenoise.wordpress.com/2015/03/06/slides-simd-at-insomniac-games-gdc-2015/中的链接,该链接很好地解释了数据布局问题,以及使用SIMD向量化的循环级别。