作者: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 毫秒
使用SSE的C++ 函數計算 3 毫秒
使用SSE匯編指令計算
2 毫秒
大家看到,使用SSE匯編指令計算的結果會好一些,因為使用了效率增強了的SSX寄存器組。但是在通常情況下,用SSE的C++函數計算會比匯編代碼計算的效率更高一些,因為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;
// 使用以下的附加寄存器:xmm2、xmm3、xmm4:
// 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])));
}
留言列表