如果检查vs sse操作的成本?

时间:2012-04-02 19:50:54

标签: 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左移指令所需的时间或周期数相对)。

1 个答案:

答案 0 :(得分:1)

使用microbenchmark回答,使用如下代码:

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)shift == 64:

带有if的

~2.5s(避免无操作移位)。

~2.8s执行无操作班次。

2)with shift == 65:

~2.8s有或没有if。

Timings是在“Intel(R)Xeon(R)CPU X5570 @ 2.93GHz”(/ proc / cpuinfo)上制作的,并且相对一致。

即使分支完全冗余(shift == 65),我也没有看到进行操作所需的时间差别很大,但它肯定有助于避免执行SSE no-op shift的指令当(shift == 64)。