2013-07-20 33 views
8

Süzgeçler arası vektörlerin toplam elementlerini nasıl azaltabilirim?SSE şamandıra vektörünün azaltılması

basit seri kodu: Tipik haliyle

void(float *input, float &result, unsigned int NumElems) 
{ 
    result = 0; 
    for(auto i=0; i<NumElems; ++i) 
     result += input[i]; 
} 
+3

Bir şey denediniz mi? – harold

+2

Gerçekten oluşturulan koda baktınız mı? En azından gcc'le ilgili deneyimim, mümkün olduğunda SSE talimatlarının yapılması konusunda oldukça iyi bir iş çıkarmasıdır - ancak -O3 gerektirebilir. –

cevap

14

döngünün 4 kısmi toplam oluşturmak ve daha sonra, sadece döngü sonra, örneğin 4 elemanları yatay olarak özetlemek

#include <cassert> 
#include <cstdint> 
#include <emmintrin.h> 

float vsum(const float *a, int n) 
{ 
    float sum; 
    __m128 vsum = _mm_set1_ps(0.0f); 
    assert((n & 3) == 0); 
    assert(((uintptr_t)a & 15) == 0); 
    for (int i = 0; i < n; i += 4) 
    { 
     __m128 v = _mm_load_ps(&a[i]); 
     vsum = _mm_add_ps(vsum, v); 
    } 
    vsum = _mm_hadd_ps(vsum, vsum); 
    vsum = _mm_hadd_ps(vsum, vsum); 
    _mm_store_ss(&sum, vsum); 
    return sum; 
} 

Not: Yukarıdaki örnekte a 16 bayt hizalanmış olması ve a hizalama sonra _mm_loadu_ps yerine _mm_load_ps kullanımı garanti edilemez ise n 4 bir katı olmalıdır. n'un 4'ün katları olması garanti edilmezse, kalan tüm öğeleri biriktirmek için işlevin sonuna bir skaler döngü ekleyin.

+1

Giriş dizisi potansiyel olarak büyükse, başlangıçta da SSC döngüsü için bir 16B sınırında hizalanana kadar 0-3 kez çalışan bir skaler döngü sahip olmaya değer. Ardından, döngüsünüzü yavaşlatan önbellek/sayfa satırlarını geçen yükleriniz olmaz. Ve 'ADDPS' işlevini, potansiyel olarak mikro sigorta ile yükü azaltan bir bellek işleneni ile birlikte kullanabilir. Ayrıca, birden fazla akümülatör kullanarak 2 veya 4 bağımlılık zinciri elde edebilirsiniz, böylece döngünüz her döngü başına 1 vektör FP eklemesini koruyabilir (“ADDPS' = gecikme süresi = 3). –