对整数向量使用 _mm_shuffle_ps 的影响

2024-04-13

SSE内在函数包括_mm_shuffle_ps xmm1 xmm2 immx它允许人们从中选择 2 个元素xmm1与 2 个元素连接xmm2。然而,这是针对浮点数的,(由_ps,单个包装)。但是,如果你转换你的压缩整数__m128i,那么你可以使用_mm_shuffle_ps还有:

#include <iostream>
#include <immintrin.h>
#include <sstream>

using namespace std;

template <typename T>
std::string __m128i_toString(const __m128i var) {
    std::stringstream sstr;
    const T* values = (const T*) &var;
    if (sizeof(T) == 1) {
        for (unsigned int i = 0; i < sizeof(__m128i); i++) {
            sstr << (int) values[i] << " ";
        }
    } else {
        for (unsigned int i = 0; i < sizeof(__m128i) / sizeof(T); i++) {
            sstr << values[i] << " ";
        }
    }
    return sstr.str();
}



int main(){

  cout << "Starting SSE test" << endl;
  cout << "integer shuffle" << endl;

 int A[] = {1,  -2147483648, 3, 5};
 int B[] = {4, 6, 7, 8};

  __m128i pC;

  __m128i* pA = (__m128i*) A;
  __m128i* pB = (__m128i*) B;

  *pA = (__m128i)_mm_shuffle_ps((__m128)*pA, (__m128)*pB, _MM_SHUFFLE(3, 2, 1 ,0));
  pC = _mm_add_epi32(*pA,*pB);

  cout << "A[0] = " << A[0] << endl;
  cout << "A[1] = " << A[1] << endl;
  cout << "A[2] = " << A[2] << endl;
  cout << "A[3] = " << A[3] << endl;

  cout << "B[0] = " << B[0] << endl;
  cout << "B[1] = " << B[1] << endl;
  cout << "B[2] = " << B[2] << endl;
  cout << "B[3] = " << B[3] << endl;

  cout << "pA = " << __m128i_toString<int>(*pA) << endl;
  cout << "pC = " << __m128i_toString<int>(pC) << endl;
}

相关相应程序集的片段(mac osx、macports gcc 4.8、ivybridge CPU 上的 -march=native):

vshufps $228, 16(%rsp), %xmm1, %xmm0
vpaddd  16(%rsp), %xmm0, %xmm2
vmovdqa %xmm0, 32(%rsp)
vmovaps %xmm0, (%rsp)
vmovdqa %xmm2, 16(%rsp)
call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
....

因此,它似乎在整数上工作得很好,这是我所期望的,因为寄存器与类型无关,但是文档说该指令仅适用于浮点数一定是有原因的。有人知道我错过的任何缺点或影响吗?


没有等同于_mm_shuffle_ps对于整数。为了在这种情况下达到相同的效果,你可以这样做

SSE2

*pA = _mm_shuffle_epi32(_mm_unpacklo_epi32(*pA, _mm_shuffle_epi32(*pB, 0xe)),0xd8);

SSE4.1

*pA = _mm_blend_epi16(*pA, *pB, 0xf0);

or 更改为浮点域 https://stackoverflow.com/questions/13153584/mm-shuffle-ps-equivalent-for-integer-vectors-m128i像这样

*pA = _mm_castps_si128( 
        _mm_shuffle_ps(_mm_castsi128_ps(*pA), 
                       _mm_castsi128_ps(*pB), _MM_SHUFFLE(3, 2, 1 ,0)));

但更改域可能会导致绕过延迟延迟 https://stackoverflow.com/questions/19543590/bypass-delays-when-switching-execution-unit-domains在某些 CPU 上。请记住,根据阿格纳的说法

旁路延迟在延迟是瓶颈的长依赖链中很重要,但是 不是吞吐量而不是延迟重要的地方。

您必须测试您的代码并查看上面哪种方法更有效。

幸运的是,在大多数 Intel/AMD CPU 上,使用通常不会受到任何惩罚shufps大多数整数向量指令之间。阿格纳 说:

例如,我发现混合时没有延迟PADDD and SHUFPS[在桑迪布里奇]。

Nehalem 确实有 2 个往返延迟SHUFPS,但即便如此,单个SHUFPS通常仍然比多个其他指令更快。额外的指令也会带来延迟,并且会降低吞吐量。


相反(FP 数学指令之间的整数洗牌)则不那么安全:

In Agner Fog 的微架构 http://www.agner.org/optimize/microarchitecture.pdf在第 112 页的例 8.3a 中,他表明使用PSHUFD (_mm_shuffle_epi32) 代替SHUFPS (_mm_shuffle_ps)在浮点域中时会导致四个时钟周期的旁路延迟。在示例 8.3b 中,他使用 SHUFPS 来消除延迟(这在他的示例中有效)。

尼黑勒姆上实际上有五个域。纳哈勒姆 (Nahalem) 似乎受到的影响最大(纳哈勒姆 (Nahalem) 之前不存在旁路延误)。在桑迪桥,延误不太严重。在 Haswell 上更是如此。事实上,哈斯韦尔·阿格纳(Haswell Agner)表示,他发现之间没有任何延误SHUFPS or PSHUFD(参见第 140 页)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对整数向量使用 _mm_shuffle_ps 的影响 的相关文章

随机推荐