2012-03-19 13 views
12

Ho un vettore compresso di quattro valori a virgola mobile a 64 bit.
Vorrei ottenere la somma degli elementi del vettore.Il modo più veloce per eseguire la somma vettoriale orizzontale con le istruzioni AVX

Con SSE (e usando carri a 32-bit) ho potuto solo effettuare le seguenti operazioni:

v_sum = _mm_hadd_ps(v_sum, v_sum); 
v_sum = _mm_hadd_ps(v_sum, v_sum); 

Purtroppo, anche se AVX presenta un'istruzione _mm256_hadd_pd, si differenzia nel risultato dalla versione SSE. Credo che ciò sia dovuto al fatto che la maggior parte delle istruzioni AVX funzionano come istruzioni SSE per ogni minimo e alto 128 bit separatamente, senza mai superare il limite di 128 bit.

Idealmente, la soluzione che sto cercando dovrebbe seguire le seguenti linee guida:
1) utilizzare solo le istruzioni AVX/AVX2. (no SSE)
2) eseguirlo in non più di 2-3 istruzioni.

Tuttavia, qualsiasi modo efficiente/elegante per farlo (anche senza seguire le linee guida di cui sopra) è sempre ben accettato.

Grazie mille per qualsiasi aiuto.

-Luigi Castelli

+0

Inizia con '_mm256_extractf128_ps',' _mm_add_ps' le due metà, quindi utilizzare [i metodi esistenti per ridurre un vettore 128b] (http://stackoverflow.com/questions/6996764/fastest-way-to -do-orizzontale-flottante somma vettoriale-on-x86). –

risposta

17

Se si dispone di due vettori __m256dx1 e x2 che contengono ciascuno quattro double s che si desidera in orizzontale somma, si potrebbe fare:

__m256d x1, x2; 
// calculate 4 two-element horizontal sums: 
// lower 64 bits contain x1[0] + x1[1] 
// next 64 bits contain x2[0] + x2[1] 
// next 64 bits contain x1[2] + x1[3] 
// next 64 bits contain x2[2] + x2[3] 
__m256d sum = _mm256_hadd_pd(x1, x2); 
// extract upper 128 bits of result 
__m128d sum_high = _mm256_extractf128_pd(sum1, 1); 
// add upper 128 bits of sum to its lower 128 bits 
__m128d result = _mm_add_pd(sum_high, _mm256_castpd256_pd128(sum)); 
// lower 64 bits of result contain the sum of x1[0], x1[1], x1[2], x1[3] 
// upper 64 bits of result contain the sum of x2[0], x2[1], x2[2], x2[3] 

modo che appaia come 3 istruzioni farà 2 delle somme orizzontali di cui hai bisogno. Quanto sopra non è stato verificato, ma dovresti ottenere il concetto.

+0

Sì, ottima soluzione. Grazie Jason. @jason –

+0

Invece di usare il cast con (__m128d) penso che dovresti usare _mm256_castpd256_pd128 (somma). –

+0

Che compilatore hai usato per questo? Ho fatto una domanda sul tuo cast qui [c-style-cast-versus-intrinsic-cast] (http://stackoverflow.com/questions/20401413/c-style-cast-versus-intrinsic-cast). Non ho accesso al sistema per testarlo adesso. –

5

Se si desidera solo la somma, e un po 'di codice di scalare è accettabile:

__m256d x; 
__m256d s = _mm256_hadd_pd(x,x); 
return ((double*)&s)[0] + ((double*)&s)[2]; 
3

Assumendo quanto segue, che si dispone di un vettore __m256d contenente 4 doppie imballati e volete calcolare la somma di i suoi componenti, vale a dire a0, a1, a2, a3 è ogni componente doppia volete a0 + a1 + a2 + a3 poi heres un'altra soluzione AVX:

// goal to calculate a0 + a1 + a2 + a3 
__m256d values = _mm256_set_pd(23211.24, -123.421, 1224.123, 413.231); 

// assuming _mm256_hadd_pd(a, b) == a0 + a1, b0 + b1, a2 + a3, b2 + b3 (5 cycles) ... 
values = _mm256_hadd_pd(values, _mm256_permute2f128_pd(values, values, 1)); 
// ^^^^^^^^^^^^^^^^^^^^ a0 + a1, a2 + a3, a2 + a3, a0 + a1 

values = _mm256_hadd_pd(values, values); 
// ^^^^^^^^^^^^^^^^^^^^ (a0 + a1 + a2 + a3), (a0 + a1 + a2 + a3), (a2 + a3 + a0 + a1), (a2 + a3 + a0 + a1) 

// Being that addition is associative then each component of values contains the sum of all its initial components (11 cycles) to calculate, (1-2 cycles) to extract, total (12-13 cycles) 
double got = _mm_cvtsd_f64(_mm256_castpd256_pd128(values)), exp = (23211.24 + -123.421 + 1224.123 + 413.231); 

if (got != exp || _mm256_movemask_pd(_mm256_cmp_pd(values, _mm256_set1_pd(exp), _CMP_EQ_OS)) != 0b1111) 
    printf("Failed to sum double components, exp: %f, got %f\n", exp, got); 
else 
    printf("ok\n"); 

Questa soluzione ha trasmesso la somma che forse utile ...

012.

Se ho interpretato erroneamente il problema, mi scuso.

$ uname -a 
Darwin Samys-MacBook-Pro.local 13.3.0 Darwin Kernel Version 13.3.0: Tue Jun 3 21:27:35 PDT 2014; root:xnu-2422.110.17~1/RELEASE_X86_64 x86_64 

$ gcc --version 
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn) 
Target: x86_64-apple-darwin13.3.0 
Thread model: posix 
Problemi correlati