2012-01-31 4 views
17

Un'operazione comune che faccio nel mio programma è ridimensionare i vettori con uno scalare (V * s, ad es. [1,2,3,4] * 2 == [2,4, 6,8]). Esiste un'istruzione SSE (o AVX) per fare ciò, a parte il primo caricamento dello scalare in ogni posizione in un vettore (ad es. _mm_set_ps (2,2,2,2)) e quindi moltiplicando?SSE (SIMD): moltiplicare il vettore per scalare

Questo è quello che faccio ora:

__m128 _scalar = _mm_set_ps(s,s,s,s); 
__m128 _result = _mm_mul_ps(_vector, _scalar); 

Sto cercando qualcosa di simile ...

__m128 _result = _mm_scale_ps(_vector, s); 

risposta

13

a seconda del vostro compilatore si può essere in grado di migliorare la generazione di codice un po 'utilizzando _mm_set1_ps:

const __m128 scalar = _mm_set1_ps(s); 
__m128 result = _mm_mul_ps(vector, scalar); 

costanti Tuttavia scalari come questo dovrebbe solo bisogno di essere inizializzato una volta, fuori di qualsiasi loop, quindi le prestazioni il costo dovrebbe essere irrilevante. (A meno che il valore scalare non cambi nel loop?)

Come sempre, dovresti esaminare il codice generato dal compilatore e anche provare a eseguire il codice con un profiler decente per vedere dove sono realmente gli hotspot.

0

Non so di ogni singolo insegnamento che fa quello che si vuole. L'operazione impostata è davvero un collo di bottiglia? Se si sta moltiplicando un vettore grande con la stessa costante, il tempo necessario per riempire un registro XMM/YMM con quattro copie della costante dovrebbe essere una frazione molto piccola del tempo complessivo impiegato.

Come semplice ottimizzazione, se la costante è 2 come era nell'esempio, è possibile sostituire il multiplo con un'istruzione add, anziché richiedere alcuna costante.

4

Non ci sono istruzioni per la moltiplicazione di un vettore per uno scalare. Esistono tuttavia alcune istruzioni per caricare gli stessi valori scalari in tutte le posizioni in un registro vettoriale.

AVX set di istruzioni fornisce _mm_broadcast_ss/_mm256_broadcast_ss/_mm256_broadcast_sd intrinseci per la compilazione SSE e AVX registra con lo stesso galleggiante/valore doppio.

Nel set di istruzioni SSE3 è possibile trovare _mm_loaddup_pd intrinseco che compila il registro SSE con lo stesso valore doppio.

In altre versioni di SSE genere l'opzione migliore è quella di caricare un valore scalare usando _mm_load_ss/_mm_load_sd e quindi copiarlo a tutti gli elementi di un registro vettore con _mm_shuffle_ps/_mm_unpacklo_pd.