簡體   English   中英

將SSE代碼轉換為AVX-_mm256_and_ps的成本

[英]converting SSE code to AVX - cost of _mm256_and_ps

我正在將SSE2正弦和余弦函數(來自Julien Pommier的sse_mathfun.h;基於CEPHES sinf函數)轉換為使用AVX,以便接受8個浮點矢量或4個雙精度數。

因此,朱利安函數sin_ps變為sin_ps8(對於8個浮點數),而sin_pd4變為4個雙精度數。 (此處的“高級”編輯器無法接受我的代碼,因此請訪問http://arstechnica.com/civis/viewtopic.php?f=20&t=1227375進行查看。)

在2011 Core2 i7 @ 2.7Ghz上運行的Mac OS X 10.6.8下使用clang 3.3進行測試,基准測試結果如下所示:

  • sinf ..->在5.56e + 07 iter上每秒進行2770萬次向量評估(標准,標量sinf()函數)

    sin_ps ..->在8.22e + 07 iters上每秒進行4100萬次矢量評估

    sin_pd4 ..->在8.06e + 07 iters上每秒進行4020萬次矢量評估

    sin_ps8 ..->在5.1e + 06 iter上每秒進行250萬次矢量評估

sin_ps8的成本令人震驚,這似乎是由於使用_mm256_castsi256_ps造成的。 實際上,注釋掉“ poly_mask = _mm256_castsi256_ps(emmm2);”這一行。 導致更正常的性能。 sin_pd4使用_mm_castsi128_pd,但似乎(不是)在sin_ps8中咬住我的SSE和AVX指令的混合:當我模擬_mm256_castsi256_ps調用和對_mm_castsi128_ps的2次調用時,性能沒有提高。 emm2和emm0是兩個v8si實例的emmm2和emmm0的指針,因此(先驗)正確對齊到32位邊界。

有關可編譯代碼,請參見sse_mathfun.hsse_mathfun_test.c

有沒有一種簡單的方法可以避免我看到的懲罰?

將寄存器中的內容轉移到內存通常不是一個好主意。 每次將其存儲到指針中時,您就需要執行此操作。

代替這個:

{ ALIGN32_BEG v4sf *yy ALIGN32_END = (v4sf*) &y;
         emm2[0] = _mm_and_si128(_mm_add_epi32( _mm_cvttps_epi32( yy[0] ), _v4si_pi32_1), _v4si_pi32_inv1),
         emm2[1] = _mm_and_si128(_mm_add_epi32( _mm_cvttps_epi32( yy[1] ), _v4si_pi32_1), _v4si_pi32_inv1);
         yy[0] = _mm_cvtepi32_ps(emm2[0]),
         yy[1] = _mm_cvtepi32_ps(emm2[1]);
      }

/* get the swap sign flag */
emm0[0] = _mm_slli_epi32(_mm_and_si128(emm2[0], _v4si_pi32_4), 29),
emm0[1] = _mm_slli_epi32(_mm_and_si128(emm2[1], _v4si_pi32_4), 29);

/* get the polynom selection mask
there is one polynom for 0 <= x <= Pi/4
and another one for Pi/4<x<=Pi/2

Both branches will be computed.
*/
emm2[0] = _mm_cmpeq_epi32(_mm_and_si128(emm2[0], _v4si_pi32_2), _mm_setzero_si128()),
emm2[1] = _mm_cmpeq_epi32(_mm_and_si128(emm2[1], _v4si_pi32_2), _mm_setzero_si128());

((v4sf*)&poly_mask)[0] = _mm_castsi128_ps(emm2[0]);
((v4sf*)&poly_mask)[1] = _mm_castsi128_ps(emm2[1]);
swap_sign_bit = _mm256_castsi256_ps(emmm0);

嘗試這樣的事情:

__m128i emm2a = _mm_and_si128(_mm_add_epi32( _mm256_castps256_ps128(y), _v4si_pi32_1), _v4si_pi32_inv1);
__m128i emm2b = _mm_and_si128(_mm_add_epi32( _mm256_extractf128_ps(y, 1), _v4si_pi32_1), _v4si_pi32_inv1);

y = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_cvtepi32_ps(emm2a)), _mm_cvtepi32_ps(emm2b), 1);

/* get the swap sign flag */
__m128i emm0a = _mm_slli_epi32(_mm_and_si128(emm2a, _v4si_pi32_4), 29),
__m128i emm0b = _mm_slli_epi32(_mm_and_si128(emm2b, _v4si_pi32_4), 29);

swap_sign_bit = _mm256_castsi256_ps(_mm256_insertf128_si256(_mm256_castsi128_si256(emm0a), emm0b, 1));

/* get the polynom selection mask
there is one polynom for 0 <= x <= Pi/4
and another one for Pi/4<x<=Pi/2

Both branches will be computed.
*/
emm2a = _mm_cmpeq_epi32(_mm_and_si128(emm2a, _v4si_pi32_2), _mm_setzero_si128()),
emm2b = _mm_cmpeq_epi32(_mm_and_si128(emm2b, _v4si_pi32_2), _mm_setzero_si128());

poly_mask = _mm256_castsi256_ps(_mm256_insertf128_si256(_mm256_castsi128_si256(emm2a), emm2b, 1));

如注釋中所述, cast內在函數純粹是編譯時的,不發出指令。

也許您可以將您的代碼與Julien Pommier SSE數學函數的已在工作的AVX擴展進行比較?

http://software-lisc.fbk.eu/avx_mathfun/

該代碼在GCC中有效,但在MSVC中不起作用,並且僅支持浮點數(float8),但我認為您可以輕松地將其擴展為使用double(double4)。 sin函數的快速比較顯示,除了SSE2整數部分外,它們非常相似。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM