2011-12-15 20 views
7

SSE3 में, PALIGNR अनुदेश निम्नलिखित प्रदर्शन 128 बिट। नैवली, मुझे विश्वास था कि अंतर्निहित कार्य _mm256_alignr_epi8 (VPALIGNR) उसी ऑपरेशन को _mm_alignr_epi8 केवल 256 बिट रजिस्टरों पर करता है। अफसोस की बात है, हालांकि, यह बिल्कुल मामला नहीं है। वास्तव में, _mm256_alignr_epi8 256 बिट रजिस्टर को 2 128 बिट रजिस्ट्रार के रूप में मानता है और दो पड़ोसी 128 बिट रजिस्टरों पर 2 "संरेखण" संचालन करता है। _mm_alignr_epi8 के रूप में एक ही ऑपरेशन को प्रभावी ढंग से प्रदर्शन करना, लेकिन एक बार में 2 रजिस्टरों पर। यह सबसे स्पष्ट रूप से यहाँ सचित्र है: _mm256_alignr_epi8_mm_alignr_epi8 (PALIGNR) AVX2 में बराबर

वर्तमान में मेरे समाधान है _mm_alignr_epi8 का उपयोग कर रखने के लिए YMM (256 बिट) पंजीकृत करता विभाजित करके दो XMM (128 बिट) रजिस्टरों (हाई और लो) में है, इसलिए जैसे:

__m128i xmm_ymm1_hi = _mm256_extractf128_si256(ymm1, 0); 
__m128i xmm_ymm1_lo = _mm256_extractf128_si256(ymm1, 1); 
__m128i xmm_ymm2_hi = _mm256_extractf128_si256(ymm2, 0); 
__m128i xmm_ymm_aligned_lo = _mm_alignr_epi8(xmm_ymm1_lo, xmm_ymm1_hi, 1); 
__m128i xmm_ymm_aligned_hi = _mm_alignr_epi8(xmm_ymm2_hi, xmm_ymm1_lo, 1); 
__m256i xmm_ymm_aligned = _mm256_set_m128i(xmm_ymm_aligned_lo, xmm_ymm_aligned_hi); 

यह काम करता है, लेकिन एक बेहतर तरीका होना चाहिए, है ना? क्या कोई और अधिक "सामान्य" AVX2 निर्देश है जिसका उपयोग एक ही परिणाम प्राप्त करने के लिए किया जाना चाहिए?

उत्तर

2

एकमात्र समाधान मैं के लिए यह है साथ आने के लिए सक्षम था:

static inline __m256i _mm256_alignr_epi8(const __m256i v0, const __m256i v1, const int n) 
{ 
    if (n < 16) 
    { 
    __m128i v0h = _mm256_extractf128_si256(v0, 0); 
    __m128i v0l = _mm256_extractf128_si256(v0, 1); 
    __m128i v1h = _mm256_extractf128_si256(v1, 0); 
    __m128i vouth = _mm_alignr_epi8(v0l, v0h, n); 
    __m128i voutl = _mm_alignr_epi8(v1h, v0l, n); 
    __m256i vout = _mm256_set_m128i(voutl, vouth); 
    return vout; 
    } 
    else 
    { 
    __m128i v0h = _mm256_extractf128_si256(v0, 1); 
    __m128i v0l = _mm256_extractf128_si256(v1, 0); 
    __m128i v1h = _mm256_extractf128_si256(v1, 1); 
    __m128i vouth = _mm_alignr_epi8(v0l, v0h, n - 16); 
    __m128i voutl = _mm_alignr_epi8(v1h, v0l, n - 16); 
    __m256i vout = _mm256_set_m128i(voutl, vouth); 
    return vout; 
    } 
} 

जो मुझे लगता है कि काफी अपने समाधान के समान को छोड़कर यह भी> = 16 बाइट्स की पाली संभालती है।

+0

yup, यह वही समाधान है। लेकिन अगर यह एकमात्र तरीका है तो यह AVX2 निर्देश – eladidan

+0

के डिजाइनरों द्वारा बड़ी निगरानी की तरह लगता है, मैं इसे संकलित करने के लिए नहीं मिला ... मुझे संकलन त्रुटि मिलती है: "आपदात्मक त्रुटि: आंतरिक पैरामीटर तत्काल मान होना चाहिए" निम्नलिखित पंक्ति पर: "__m128i vouth = _mm_alignr_epi8 (v0l, v0h, n);"। जाहिर है, क्योंकि एन एक immidiate नहीं है। आप इसे कैसे बाईपास करने में सक्षम थे? मैं इंटेल सी ++ कंपाइलर – eladidan

+0

का उपयोग कर रहा हूं, यह मेरे लिए काम करता है, जब तक कि एन संकलन-समय स्थिर रहता है - मैं भी इंटेल आईसीसी कंपाइलर का उपयोग कर रहा हूं, लेकिन सी ++ के बजाय सी के रूप में संकलित करता हूं यदि इससे कोई फर्क पड़ता है, और यह भी जीसीसी के साथ मेरे लिए काम करता है। –

4

आप palignr का उपयोग कर रहे हैं? यदि यह केवल डेटा मिसाइलमेंट को संभालने के लिए है, तो इसके बजाय गलत तरीके से लोड किए गए लोड का उपयोग करें; वे आम तौर पर आधुनिक इंटेल μ-architectures पर "तेज़ पर्याप्त" होते हैं (और आपको बहुत सारे कोड आकार को बचाएंगे)।

यदि आपको किसी अन्य कारण के लिए palignr जैसा व्यवहार की आवश्यकता है, तो आप इसे शाखा-मुक्त तरीके से करने के लिए असाइन किए गए लोड समर्थन का लाभ उठा सकते हैं। जब तक कि आप पूरी तरह से लोड-स्टोर बाध्य न हों, यह शायद पसंदीदा मुहावरे है।

static inline __m256i _mm256_alignr_epi8(const __m256i v0, const __m256i v1, const int n) 
{ 
    // Do whatever your compiler needs to make this buffer 64-byte aligned. 
    // You want to avoid the possibility of a page-boundary crossing load. 
    char buffer[64]; 

    // Two aligned stores to fill the buffer. 
    _mm256_store_si256((__m256i *)&buffer[0], v0); 
    _mm256_store_si256((__m256i *)&buffer[32], v1); 

    // Misaligned load to get the data we want. 
    return _mm256_loadu_si256((__m256i *)&buffer[n]); 
} 

आप बारे में अधिक जानकारी प्रदान कर सकते हैं कि कैसे वास्तव में आप palignr उपयोग कर रहे हैं, मैं शायद और अधिक उपयोगी हो सकता है।

+0

विलंबता बहुत अच्छी नहीं होगी, क्योंकि लोड में इंटेल CPUs पर स्टोर-फ़ॉरवर्डिंग स्टॉल से विलंबता का अतिरिक्त ~ 10 चक्र होगा। यदि स्टोर-फ़ॉरवर्डिंग स्टाल एक थ्रूपुट समस्या है, तो आईडीके। वे नहीं हो सकते हैं। –

+1

@ पीटरकॉर्ड: कोई थ्रूपुट खतरे नहीं है, केवल विलंबता है। यहां स्केच किए गए दृष्टिकोण परिस्थितियों में समझ में आता है जहां स्टोर को विलंबता को छिपाने के लिए फहराया जा सकता है या संग्रहीत डेटा को विभिन्न संरेखणों को निकालने के लिए फिर से उपयोग किया जा सकता है। बेशक, हमारे पास AVX-512 में दो-स्रोत शफल हैं, जो आमतौर पर एक बेहतर समाधान होते हैं। –

+0

ओह अच्छा बिंदु, यह एक ही दो वैक्टरों पर विभिन्न खिड़कियां उत्पन्न करने के लिए उत्कृष्ट है। यह रनटाइम-परिवर्तनीय शिफ्ट गणना के लिए भी अच्छा है। –