2015-04-15 15 views
5

Spesso sono costretto a scrivere due implementazioni di funzione che utilizza le istruzioni SSE a causa buffer di input e output possono essere allineati o meno gli indirizzi allineati:Caricamento e archiviazione allineati e non allineati dei vettori SSE: come ridurre la duplicazione del codice?

void some_function_aligned(const float * src, size_t size, float * dst) 
{ 
    for(size_t i = 0; i < size; i += 4) 
    { 
     __m128 a = _mm_load_ps(src + i); 
     // do something... 
     _mm_store_ps(dst + i, a); 
    } 
} 

e

void some_function_unaligned(const float * src, size_t size, float * dst) 
{ 
    for(size_t i = 0; i < size; i += 4) 
    { 
     __m128 a = _mm_loadu_ps(src + i); 
     // do something... 
     _mm_storeu_ps(dst + i, a); 
    } 
} 

e non v'è una domanda: Come ridurre la duplicazione del codice, perché queste funzioni sono quasi uguali?

+1

Non preoccuparti di allineamento processori più recenti. Dopo che l'allineamento della serie nehalem (i serie) ha meno impatto rispetto a prima e utilizzando le istruzioni non allineate con dati allineati non ha penalità. Ad esempio MSVC 2013 non emetterà le istruzioni allineate (anche se si utilizza l'intrinseco allineato) – Mgetz

+1

Lo so, ma ci sono CPU più vecchie di Nehalem. E sono costretto a supportarli nel mio codice. –

risposta

5

C'è una soluzione di questo problema che è ampiamente utilizzato qui (http://simd.sourceforge.net/). Essa si basa sulla specializzazione delle funzioni template per il caricamento e il salvataggio di SSE vettori:

template <bool align> __m128 load(const float * p); 

template <> inline __m128 load<false>(const float * p) 
{ 
    return _mm_loadu_ps(p); 
} 

template <> inline __m128 load<true>(const float * p) 
{ 
    return _mm_load_ps(p); 
} 

template <bool align> void store(float * p, __m128 a); 

template <> inline void Store<false>(float * p, __m128 a) 
{ 
    _mm_storeu_ps(p, a); 
} 

template <> inline void Store<true>(float * p, __m128 a) 
{ 
    _mm_store_ps(p, a); 
} 

E ora possiamo scrivere solo un'implementazione della funzione di modello:

template <bool align> void some_function(const float * src, size_t size, float * dst) 
{ 
    for(size_t i = 0; i < size; i += 4) 
    { 
     __m128 a = load<align>(src + i); 
     // do something... 
     store<align>(dst + i, a); 
    } 
} 
+1

Sì, questa è una tecnica utile. Puoi anche fare qualcosa di simile per il codice C, dove usi le funzioni inline e poi "specializzi" tramite i parametri delle funzioni hard-coded (il compilatore ottimizza i rami). –

Problemi correlati