close
from 
作者:Alex Farber
http://www.codeproject.com/cpp/sseintro.asphttp://blog.csdn.net/showlong/archive/2010/02/11/5306989.aspx
 

SSESample 示例項目

SSESample項目是一個基於對話框的應用程序,其中它用下面的浮點數數組進行計算:

fResult[i] = sqrt(fSource[i]*2.8)

其中i = 0, 1, 2 ... ARRAY_SIZE-1

這個程序同時計算了數組中的最大值和最小值。ARRAY_SIZE被定義為100000,數組中的計算結果在列表框中顯示出來。其中在我的機子上用下面三種方法計算所需的時間是:
 
C++代碼計算                    6 毫秒
使用SSEC++ 函數計算      3 毫秒
使用SSE匯編指令計算          2 毫秒

大家看到,使用SSE匯編指令計算的結果會好一些,因為使用了效率增強了的SSX寄存器組。但是在通常情況下,用SSEC++函數計算會比匯編代碼計算的效率更高一些,因為C++編譯器的優化后的代碼有很高的運算效率,若要使匯編代碼比優化后的代碼運算效率更高,這通常是很難做到的。

C++代碼:

// 輸入: m_fInitialArray
//
輸出: m_fResultArray, m_fMin, m_fMax
void CSSESampleDlg::OnBnClickedButtonCplusplus()
{
     m_fMin = FLT_MAX;
     m_fMax = FLT_MIN;

     int i;

     for ( i = 0; i < ARRAY_SIZE; i++ )
     {
         m_fResultArray[i] = sqrt(m_fInitialArray[i]   * 2.8f );

         if ( m_fResultArray[i] < m_fMin )
             m_fMin = m_fResultArray[i];

         if ( m_fResultArray[i] > m_fMax )
             m_fMax = m_fResultArray[i];
     }
}

使用Visual C++.NET SSE指令函數的代碼:

// 輸入: m_fInitialArray
//
輸出: m_fResultArray, m_fMin, m_fMax
void CSSESampleDlg::OnBnClickedButtonSseC()
{
     __m128 coeff = _mm_set_ps1( 2.8f );       // coeff[0, 1, 2, 3] = 2.8
     __m128 tmp;

     __m128 min128 = _mm_set_ps1(FLT_MAX);   // min128[0, 1, 2, 3] = FLT_MAX
     __m128 max128 = _mm_set_ps1(FLT_MIN);   // max128[0, 1, 2, 3] = FLT_MIN

     __m128* pSource = (__m128*) m_fInitialArray;
     __m128* pDest = (__m128*) m_fResultArray;

     for ( int i = 0; i < ARRAY_SIZE/4; i++ )
     {
         tmp = _mm_mul_ps(*pSource, coeff);       // tmp = *pSource * coeff
         *pDest = _mm_sqrt_ps(tmp);               // *pDest = sqrt(tmp)

         min128 =   _mm_min_ps(*pDest, min128);
         max128 =   _mm_max_ps(*pDest, max128);

         pSource++;
         pDest++;
     }

     // 計算max128的最大值和min128的最小值
     union u
     {
         __m 128 m ;
         float f[4];
     } x;

     x.m = min128;
     m_fMin = min(x.f[0], min(x.f[1], min(x.f[2], x.f[3])));

     x.m = max128;
     m_fMax = max(x.f[0], max(x.f[1], max(x.f[2], x.f[3])));
}

使用SSE匯編指令的C++函數代碼:

// 輸入: m_fInitialArray
//
輸出: m_fResultArray, m_fMin, m_fMax
void CSSESampleDlg::OnBnClickedButtonSseAssembly()
{
   
     float* pIn = m_fInitialArray;
     float* pOut = m_fResultArray;

     float f = 2.8f ;
     float flt_min = FLT_MIN;
     float flt_max = FLT_MAX;

     __m128 min128;
     __m128 max128;

     // 使用以下的附加寄存器:xmm2xmm3xmm4:
     // xmm2 –
相乘系數
     // xmm3 –
最小值
     // xmm4 –
最大值

     _asm
     {
         movss    xmm2, f                          // xmm2[0] = 2.8
         shufps   xmm2, xmm2, 0                    // xmm2[1, 2, 3] = xmm2[0]

         movss    xmm3, flt_max                    // xmm3 = FLT_MAX
         shufps   xmm3, xmm3, 0                    // xmm3[1, 2, 3] = xmm3[0]

         movss    xmm4, flt_min                    // xmm4 = FLT_MIN
         shufps   xmm4, xmm4, 0                    // xmm3[1, 2, 3] = xmm3[0]

         mov          esi, pIn                     // 輸入數組的地址送往esi
         mov          edi, pOut                    //
輸出數組的地址送往edi
         mov          ecx, ARRAY_SIZE/4            //
循環計數器初始化

start_loop:
         movaps       xmm1, [esi]                  // xmm1 = [esi]
         mulps        xmm1, xmm2                   // xmm1 = xmm1 * xmm2
         sqrtps       xmm1, xmm1                   // xmm1 = sqrt(xmm1)
         movaps       [edi], xmm1                  // [edi] = xmm1

         minps        xmm3, xmm1
         maxps        xmm4, xmm1

         add          esi, 16
         add          edi, 16

         dec          ecx
         jnz          start_loop


         movaps       min128, xmm3
         movaps       max128, xmm4
     }

     union u
     {
         __m 128 m ;
         float f[4];
     } x;

     x.m = min128;
     m_fMin = min(x.f[0], min(x.f[1], min(x.f[2], x.f[3])));

     x.m = max128;
     m_fMax = max(x.f[0], max(x.f[1], max(x.f[2], x.f[3])));

}

 
arrow
arrow
    全站熱搜

    chunyuan 發表在 痞客邦 留言(2) 人氣()