作者: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函數 |
將4個32位浮點數放進一個128位的存儲單元。 |
movss 和 shufps |
_mm_set_ps1 |
將4對32位浮點數同時進行相乘操作。這4對32位浮點數來自兩個128位的存儲單元,再把計算結果(乘積)賦給一個128位的存儲單元。 |
mulps |
_mm_mul_ps |
將4對32位浮點數同時進行相加操作。這4對32位浮點數來自兩個128位的存儲單元,再把計算結果(相加之和)賦給一個128位的存儲單元。 |
addps |
_mm_add_ps |
對一個128位存儲單元中的4個32位浮點數同時進行求平方根操作。 |
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
{
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 毫秒
使用SSE的C++ 函數計算所用的時間是 9 毫秒
包含SSE匯編指令的C++代碼計算所用的時間是 9 毫秒
以上的時間結果是在Release優化編譯后執行程序得出的。