if 检查与 sse 操作的成本?

标签 c sse

这里有两种不同的方法,我可以使用 SSE 内在函数左移 >= 64 位。第二种变体专门处理 (shift == 64) 情况,并避免一条 SSE 指令,但增加了 if 检查的成本:

inline __m128i shiftLeftGte64ByBits( const __m128i & a, const unsigned shift )
{
   __m128i r ;

   r = _mm_slli_si128( a, 8 ) ; // a << 64

   r = _mm_sll_epi64( r, _mm_set_epi32( 0, 0, 0, shift - 64 ) ) ;

   return r ;
}

inline __m128i shiftLeftGte64ByBits( const __m128i & a, const unsigned shift )
{
   __m128i r ;

   r = _mm_slli_si128( a, 8 ) ; // a << 64

   if ( shift > 64 )
   {
      r = _mm_sll_epi64( r, _mm_set_epi32( 0, 0, 0, shift - 64 ) ) ;
   }

   return r ;
}

我(大致)想知道这个 if() 检查的成本与移位指令本身的成本相比如何(可能相对于正常 ALU 左移指令所需的时间或周期数)。

最佳答案

使用微基准进行回答,使用如下代码:

void timingWithIf( volatile __m128i * pA, volatile unsigned long * pShift, unsigned long n )
{
   __m128i r = *pA ;

   for ( unsigned long i = 0 ; i < n ; i++ )
   {
      r = _mm_slli_si128( r, 8 ) ; // a << 64

      unsigned long shift = *pShift ;

      // does it hurt more to do the check, or just do the operation?
      if ( shift > 64 )
      {
         r = _mm_sll_epi64( r, _mm_set_epi32( 0, 0, 0, shift - 64 ) ) ;
      }
   }

   *pA = r ;
}

这生成了以下代码:

    xor    %eax,%eax
    movdqa (%rdi),%xmm0
    test   %rdx,%rdx
    movdqa %xmm0,0xffffffffffffffe8(%rsp)
    jbe    F0
    pxor   %xmm0,%xmm0
B0: movdqa 0xffffffffffffffe8(%rsp),%xmm2
    pslldq $0x8,%xmm2
    movdqa %xmm2,0xffffffffffffffe8(%rsp)
    mov    (%rsi),%rcx
    cmp    $0x40,%rcx
    jbe    F1
    add    $0xffffffffffffffc0,%rcx
    movd   %ecx,%xmm1
    punpckldq %xmm0,%xmm1
    punpcklqdq %xmm0,%xmm1
    psllq  %xmm1,%xmm2
    movdqa %xmm2,0xffffffffffffffe8(%rsp)
F1: inc    %rax
    cmp    %rdx,%rax
    jb     B0
F0: movdqa 0xffffffffffffffe8(%rsp),%xmm0
    movdqa %xmm0,(%rdi)
    retq
    nopl   0x0(%rax)

观察分支避免的移位实际上需要三个 SSE 指令(如果可以 ALU -> XMM reg 移动则需要四个指令),再加上一个 ALU 添加操作:

    add    $0xffffffffffffffc0,%rcx
    movd   %ecx,%xmm1
    punpckldq %xmm0,%xmm1
    punpcklqdq %xmm0,%xmm1
    psllq  %xmm1,%xmm2

我测量了 10 亿个循环:

1) 移位 == 64:

使用 if 约​​ 2.5 秒(避免无操作移位)。

~2.8s 执行无操作移位。

2) 移位 == 65:

~2.8s,无论是否有 if。

计时是在“Intel(R) Xeon(R) CPU X5570 @ 2.93GHz”(/proc/cpuinfo) 上进行的,并且相对一致。

即使分支完全冗余(shift == 65),我也看不出执行操作所需的时间有太大差异,但这绝对有助于避免执行 SSE 无操作左移的指令当(shift == 64)时。

关于if 检查与 sse 操作的成本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9982878/

相关文章:

c - 为什么 odd * even 在 C 中不返回精确值?

c - C中一行输入不同的值

c - 在函数内使用 fopen() 的奇怪错误

c - 找出C中的整数比较

x86 - 4 个 32 位整数的 SSE 乘法

c - 使用 SSE4 向量化点积计算

x86 - 支持SSE的x86处理器上有多少个XMM寄存器可用?

c - 阻止 Linux 将 usb 条形码扫描器字符发送到控制台

c++ - 是否有与 Sse2 _mm_unpackhi/lo_epi32/64 和 _mm_shuffle_epi8/32 等效的 Neon?

c - 学习在 Intel/AMD 64 位上用 C 语言预取缓冲区的最佳资源