2013-07-20 11 views
8

एसएसई कमी एसएसई इंट्रिनिक्स का उपयोग कर फ्लोट वेक्टर के योग तत्व (कमी) कैसे प्राप्त कर सकता हूं?फ्लोट वेक्टर

सरल सीरियल कोड:

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

क्या आपने कुछ भी कोशिश की? – harold

+2

क्या आप वास्तव में जेनरेट कोड देखते हैं? जीसीसी के साथ कम से कम मेरा अनुभव यह है कि जब संभव हो तो एसएसई निर्देशों को करने में यह बहुत अच्छा काम करता है - लेकिन इसकी आवश्यकता हो सकती है -ओ 3। –

उत्तर

14

आमतौर पर आप अपने पाश में 4 आंशिक योग पैदा करते हैं और फिर बस पाश के बाद, उदाहरण के लिए 4 तत्वों भर में क्षैतिज योग

#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; 
} 

नोट: ऊपर के उदाहरण a के लिए 16 बाइट गठबंधन होना चाहिए और n 4. की एक बहु होना चाहिए a के संरेखण की गारंटी नहीं हो सकते हैं तो _mm_load_ps के बजाय _mm_loadu_ps का उपयोग करें। यदि n 4 के एकाधिक होने की गारंटी नहीं है तो किसी भी शेष तत्वों को जमा करने के लिए फ़ंक्शन के अंत में एक स्केलर पाश जोड़ें।

+1

यदि इनपुट सरणी संभावित रूप से बड़ी है, तो शुरुआत में स्केलर लूप होने के लायक भी है, जो एसएसई लूप के लिए 16 बी सीमा पर इनपुट गठबंधन होने तक 0-3 बार चलता है। तब आपके पास लोड नहीं होंगे जो आपके लूप को धीमा कर कैश/पेज लाइनों को पार करते हैं। और यह एक मेमोरी ऑपरेंड के साथ 'एडीडीपीएस' का उपयोग कर सकता है, जो संभावित रूप से माइक्रो-फ्यूज, ओवरहेड को कम कर सकता है। इसके अलावा, आप एकाधिक संचयकों का उपयोग करके 2 या 4 निर्भरता श्रृंखलाएं प्राप्त कर सकते हैं, इसलिए आपका लूप 1 प्रति (1 ADDPS' = 3 की विलंबता) के बजाय प्रति चक्र 1 वेक्टर एफपी जोड़ सकता है। –