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


 

下面我們用具有SSE特性的C++代碼重寫上面這個函數。為了查詢使用SSE指令C++函數的方法,我參考了Intel軟體說明書(Intel Software manuals)中有關SSE匯編指令的說明,首先我是在第一卷的第九章找到的相關SSE指令,然后在第二卷找到了這些SSE指令的詳細說明,這些說明有一部分涉及了與其特性相關的C++函數。然后我通過這些SSE指令對應的C++函數搜尋了MSDN中與其相關的說明。搜索的結果見下表:


 

實現的功能

對應的SSE匯編指令

Visual C++.NET中的SSE函數

432位浮點數放進一個128位的存儲單元。

movss shufps

_mm_set_ps1

432位浮點數同時進行相乘操作。這432位浮點數來自兩個128位的存儲單元,再把計算結果(乘積)賦給一個128位的存儲單元。

mulps

_mm_mul_ps

432位浮點數同時進行相加操作。這432位浮點數來自兩個128位的存儲單元,再把計算結果(相加之和)賦給一個128位的存儲單元。

addps

_mm_add_ps

對一個128位存儲單元中的432位浮點數同時進行求平方根操作。

sqrtps

_mm_sqrt_ps


 

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

void CSSETestDlg::ComputeArrayCPlusPlusSSE(
           float* pArray1,                    // [
輸入] 源數組1
           float* pArray2,                    // [
輸入] 源數組2
           float* pResult,                    // [
輸出] 用來存放結果的數組
           int nSize)                         // [
輸入] 數組的大小
{
     int nLoop = nSize/ 4;

     __m 128 m 1, m2, m3, m4;

     __m128* pSrc1 = (__m128*) pArray1;
     __m128* pSrc2 = (__m128*) pArray2;
     __m128* pDest = (__m128*) pResult;


     __m 128 m 0_5 = _mm_set_ps1( 0.5f );         // m0_5[0, 1, 2, 3] = 0.5

     for ( int i = 0; i < nLoop; i++ )
     {
         m1 = _mm_mul_ps(*pSrc1, *pSrc1);         // m1 = *pSrc1 * *pSrc1
         m2 = _mm_mul_ps(*pSrc2, *pSrc2);         // m2 = *pSrc2 * *pSrc2
         m3 = _mm_add_ps(m1, m2);                 // m3 = m1 + m2
         m4 = _mm_sqrt_ps(m3);                    // m4 = sqrt(m3)
         *pDest = _mm_add_ps(m4, m0_5);           // *pDest = m4 + 0.5
        
         pSrc1++;
         pSrc2++;
         pDest++;
     }
}


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

void CSSETestDlg::ComputeArrayAssemblySSE(
           float* pArray1,                    // [
輸入] 源數組1
           float* pArray2,                    // [
輸入] 源數組2
           float* pResult,                    // [
輸出] 用來存放結果的數組
           int nSize)                         // [
輸入] 數組的大小
{
     int nLoop = nSize/4;
     float f = 0.5f ;

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

         mov          esi, pArray1                 // 輸入的源數組1的地址送往esi
         mov          edx, pArray2                 //
輸入的源數組2的地址送往edx

         mov          edi, pResult                 // 輸出結果數組的地址保存在edi
         mov          ecx, nLoop                   //
循環次數送往ecx

start_loop:
         movaps       xmm0, [esi]                  // xmm0 = [esi]
         mulps        xmm0, xmm0                   // xmm0 = xmm0 * xmm0

         movaps       xmm1, [edx]                  // xmm1 = [edx]
         mulps        xmm1, xmm1                   // xmm1 = xmm1 * xmm1

         addps        xmm0, xmm1                   // xmm0 = xmm0 + xmm1
         sqrtps       xmm0, xmm0                   // xmm0 = sqrt(xmm0)

         addps        xmm0, xmm2                   // xmm0 = xmm1 + xmm2

         movaps       [edi], xmm0                  // [edi] = xmm0

         add          esi, 16                      // esi += 16
         add          edx, 16                      // edx += 16
         add          edi, 16                      // edi += 16

         dec          ecx                          // ecx--
         jnz          start_loop                 //
如果不為0則轉向start_loop
     }
}

最后,在我的電腦上運行計算測試的結果:

C++代碼計算所用的時間是26 毫秒
使用SSEC++ 函數計算所用的時間是 9 毫秒
包含SSE匯編指令的C++代碼計算所用的時間是 9 毫秒

以上的時間結果是在Release優化編譯后執行程序得出的。

arrow
arrow
    全站熱搜

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