2016-07-05 7 views
6

मेरे पास इंडेक्स I0, I1, I2, I3 युक्त मेमोरी में पूर्णांक का एक गठबंधन सरणी है। मेरा लक्ष्य उन्हें I0, I0 + 1, I1, I1 + 1, I2, I2 + 1, I3, I3 + 1 युक्त __m256i रजिस्टर में प्राप्त करना है। कठिन हिस्सा उन्हें 256 बिट रजिस्टर में I0, I0 के रूप में प्राप्त कर रहा है , I1, I1, I2, I2, I3, I3, जिसके बाद मैं 0, 1, 0, 1, 0, 1, 0, 1.AVX2, 256 बिट रजिस्टर के सूचकांक और अजीब इंडेक्स में कॉपी करने के लिए चार इंटीग्रेट्स को कुशलतापूर्वक लोड कैसे करें?

में एक रजिस्टर जोड़ सकता हूं, मुझे आंतरिक, _mm256_castsi128_si256 मिला, जो कि मुझे 25 पूर्ण बिट रजिस्टर के निचले 128 बिट्स में 4 पूर्णांक लोड करने देता है, लेकिन मैं वहां से उपयोग करने के लिए सर्वोत्तम इंट्रिनिक्स खोजने के लिए संघर्ष कर रहा हूं।

किसी भी मदद की सराहना की जाएगी। मेरे पास सभी एसएसई संस्करणों, एवीएक्स, और एवीएक्स 2 तक पहुंच है और केवल इंट्रिनिक्स का उपयोग करके ऐसा करना चाहूंगा।

संपादित करें:

मैं इस काम करता है लगता है, लेकिन मैं इसे नहीं कैसे कुशल है ... यह परीक्षण करने की प्रक्रिया में हूँ।

// _mm128_load_si128: Loads 4 integer values into a temporary 128bit register. 
// _mm256_broadcastsi128_si256: Copies 4 integer values in the 128 bit register to the low and high 128 bits of the 256 bit register. 
__m256i tmpStuff = _mm256_broadcastsi128_si256 ((_mm_load_si128((__m128i*) indicesArray))); 

// _mm256_unpacklo_epi32: Interleaves the integer values of source0 and source1. 
__m256i indices = _mm256_unpacklo_epi32(tmpStuff, tmpStuff); 

__m256i regToAdd = _mm256_set_epi32 (0, 1, 0, 1, 0, 1, 0, 1); 
indices = _mm256_add_epi32(indices, regToAdd); 

EDIT2: क्योंकि _mm256_unpacklo_epi32 तरह से मैंने सोचा था कि व्यवहार न करे इसके बाद के संस्करण कोड काम नहीं करता। उपरोक्त कोड के परिणामस्वरूप I0, I0 + 1, I1, I1 + 1, I0, I0 + 1, I1, I1 + 1 होगा।

Edit3: निम्नलिखित कोड काम करता है, हालांकि फिर से मुझे यकीन है कि अगर यह सबसे कारगर है नहीं कर रहा हूँ:

__m256i tmpStuff = _mm256_castsi128_si256(_mm_loadu_si128((__m128i*) indicesArray)); 
__m256i mask = _mm256_set_epi32 (3, 3, 2, 2, 1, 1, 0, 0); 
__m256i indices= _mm256_permutevar8x32_epi32(tmpStuff, mask); 
__m256i regToAdd = _mm256_set_epi32 (1, 0, 1, 0, 1, 0, 1, 0); // Set in reverse order. 
indices= _mm256_add_epi32(indices, regToAdd); 

उत्तर

6

आपका 2 संस्करण, के रूप में कुशल के रूप में यह संभव हो सका है जब तक कि मैं एक तरह से याद कर रहा हूँ जो एक 128 बी लोड में शफल को फोल्ड कर सकता है। इससे फ़्यूज्ड-डोमेन यूओपी थ्रूपुट के लिए थोड़ा सा मदद मिल सकती है, लेकिन अप्रयुक्त डोमेन के लिए नहीं।

1 लोड (vmovdqa), 1 फेरबदल (vpermd, उर्फ ​​_mm256_permutevar8x32_epi32) और 1 ऐड (vpaddd) बहुत हल्के वजन है। जब तक आप तत्व 1 और 2 के बीच विभाजन के साथ एक unaligned 256b लोड नहीं करते हैं, तब तक ऊपरी 2 तत्व ऊपरी 128 बी में प्राप्त करने के लिए आपको किसी प्रकार के लेन-क्रॉसिंग शफल की आवश्यकता होती है।

चूंकि आप AVX2 का उपयोग कर सकते हैं, तो vpermd के लिए शफल मास्क लोड करने में आपका समाधान बहुत अच्छा है, कोई समस्या नहीं है। (रजिस्टर दबाव/कैश मिस)।


एक वैकल्पिक कि एक फेरबदल-मुखौटा वेक्टर निरंतर से बचा जाता है, लेकिन बदतर अन्यथा है:

vpmovzxdq ऊपरी 128bit लेन में ऊपरी दो तत्व प्राप्त करने के लिए एक और विकल्प है।

vpmovzxdq ymm0, [src] 
vpshufd ymm1, ymm0, _MM_SHUFFLE(2,2, 0,0) ; duplicate elements 
vpaddd  ... 

या, संभवतः उच्च throughput अगर फेरबदल बंदरगाह पूरे पाश के लिए एक अड़चन है। (फिर भी प्रश्न में vpermd संस्करण से भी बदतर है, हालांकि।)

vpmovzxdq ymm0, [src] 
vpsrlq  ymm1, ymm0,32  ; left shift by 32 
vpaddd  ...     ; ymm1 +=1 in odd elements only 
vpor  ...     ; OR the incremented odd elements with the original even elements 

पारी और या में लेन फेरबदल की जगह।

संबंधित मुद्दे