2014-02-26 80 views
2

我乘四捨五入32位浮點數,然後將其轉換爲四個16位整數與SSE內在函數。我想將四個整數結果存儲到一個數組中。漂浮物很容易:_mm_store_ps(float_ptr, m128value)。但是,我還沒有找到任何指令來做16位(__m64)整數。存儲四個16位整數與SSE內在函數

void process(float *fptr, int16_t *sptr, __m128 factor) 
{ 
    __m128 a = _mm_load_ps(fptr); 
    __m128 b = _mm_mul_ps(a, factor); 
    __m128 c = _mm_round_ps(b, _MM_FROUND_TO_NEAREST_INT); 
    __m64 s =_mm_cvtps_pi16(c); 
    // now store the values to sptr 
} 

任何幫助,將不勝感激。

回答

3

我個人會避免使用MMX。此外,我會使用明確的存儲而不是隱式的,這往往只對某些編譯器有效。以下代碼可在MSVC2012和SSE 4.1中找到。

請注意,fptr需要16字節對齊。如果您在64位模式下進行編譯,但在32位模式下進行編譯,則應確保其對齊。

#include <stdio.h> 
#include <stdint.h> 
#include <smmintrin.h> 

void process(float *fptr, int16_t *sptr, __m128 factor) 
{ 
    __m128 a = _mm_load_ps(fptr); 
    __m128 b = _mm_mul_ps(a, factor); 
    __m128i c = _mm_cvttps_epi32(b); 
    __m128i d = _mm_packs_epi32(c,c); 
    _mm_storel_epi64((__m128i*)sptr, d); 
} 

int main() { 
    float x[] = {1.0, 2.0, 3.0, 4.0}; 
    int16_t y[4]; 
    __m128 factor = _mm_set1_ps(3.14159f); 
    process(x, y, factor); 
    printf("%d %d %d %d\n", y[0], y[1], y[2], y[3]); 
} 

注意_mm_cvtps_pi16不是一個簡單的稟英特爾內在指南說,「這內在創建的兩個或多個指令序列,並可能比原生指令執行差。考慮這種內在的性能影響。」

下面是使用MMX版本

mulps (%rdi), %xmm0 
roundps $0, %xmm0, %xmm0 
movaps %xmm0, %xmm1 
cvtps2pi %xmm0, %mm0 
movhlps %xmm0, %xmm1 
cvtps2pi %xmm1, %mm1 
packssdw %mm1, %mm0 
movq %mm0, (%rsi) 
ret 

這裏裝配輸出裝配輸出尤斯上交所唯一版本

mulps (%rdi), %xmm0 
cvttps2dq %xmm0, %xmm0 
packssdw %xmm0, %xmm0 
movq %xmm0, (%rsi) 
ret 
+0

這正是我想要的!但是應該使用_mm_packs_epi32來代替_mm_packus_epi32來保留有符號的值,或者我錯了嗎? – plasmacel

+0

是的,我糾正了我的答案。 –

+3

除了SSE速度更快之外,使用MMX可以使您找到省略EMMS的錯誤(如本例中所示),這是一個嚴重的錯誤(當一些顯然無關的FP計算數百萬個週期後,嚴重的診斷非常難以診斷開始行爲不端)。只要對MMX說不。 –

2

隨着__m64類型,你可以適當地投的目標指針:

void process(float *fptr, int16_t *sptr, __m128 factor) 
{ 
    __m128 a = _mm_load_ps(fptr); 
    __m128 b = _mm_mul_ps(a, factor); 
    __m128 c = _mm_round_ps(b, _MM_FROUND_TO_NEAREST_INT); 
    __m64 s =_mm_cvtps_pi16(c); 
    *((__m64 *) sptr) = s; 
} 

沒有與MMX指令對齊和未對齊的店鋪沒有區別就像有一個與SSE/AVX;因此,您不需要內部函數來執行商店。

+0

MSDN說__m64類型不支持x64處理器。這究竟意味着什麼?根據http://msdn.microsoft.com/en-us/library/08x3t697.aspx – plasmacel

+4

@plasmacel:我相信這只是Visual Studio的64位編譯器的一個限制(不確定它是否是任何類型的Windows限制) 。我現在使用的生產代碼在x86-64架構機器上使用MMX指令(在Linux上,使用gcc或Intel C++構建)。 –

+1

你可以簡單地用'__m128'和'_mm_storel_epi64'('MOVQ')來存儲低64位,而不是使用'__m64'。今天使用MMX沒有任何真正的理由。 –

1

我認爲你是安全的運動,爲通用64位寄存器(long long將用於Linux LLP64和Windows LP64都可以),然後自己複製它。

從我讀到的xmmintrin.h中,gcc將把__m64中的演員完美地處理爲long long。 可以肯定,您可以使用_mm_cvtsi64_si64x

short* f; 
long long b = _mm_cvtsi64_si64x(s); 
f[0] = b >> 48; 
f[1] = b >> 32 & 0x0000FFFFLL; 
f[2] = b >> 16 & 0x000000000FFFFLL; 
f[3] = b & 0x000000000000FFFFLL; 

你可以用聯合鍵入pune,使它看起來更好,但我想這會落入未定義的行爲。

+0

我還沒有找到關於_mm_cvtsi64_si64x的任何參考。也不在http://software.intel.com/sites/landingpage/IntrinsicsGuide – plasmacel

+0

正如我在自定義頭文件中看到的,它只是實現爲一個強制轉換:_mm_cvtsi64_si64x(__ m64 __i){return(long long)__ i; } – plasmacel