IDK क्यों कोई कभी उचित जवाब यह है कि टिप्पणी में कई बार आ गया है पोस्ट, लेकिन यहाँ यह है:
प्रत्येक बाइट, एक पूरे डबल के लिए मुखौटा है तो PMOVSXBQ
है कि वास्तव में क्या हम की जरूरत है: लोड दो m16
पॉइंटर से बाइट्स, और उन्हें xmm रजिस्टर के दो 64 बिट (qword) हिस्सों में साइन-इन करें।
# UNTESTED CODE
(loop setup stuff)
# RSI: double pointer
# RDI: mask pointer
# RCX: loop conter = mask byte-count
LEA RDI, [RDI + RCX*1]
LEA RSI, [RSI + RCX*8] ; sizeof(double) = 8
NEG RCX ; point to the end and count up
XORPD XMM0, XMM0 ; clear accumulator
ALIGN 16
.loop:
PMOVSXBQ XMM1, [RDI + RCX]
ANDPD XMM1, [RSI + RCX * 8]
ADDPD XMM0, XMM1
ADD RCX, 2 ; 2 bytes/doubles per iter
JL .loop
HADDPD XMM0, XMM0 ; combine the two parallel sums
ret
इंट्रिनिक्स के साथ इसे लिखना आसान होना चाहिए। जैसा कि अन्य ने इंगित किया है, केवल अंतर्निहित पॉइंटर्स का उपयोग इंट्रिनिक्स के तर्क के रूप में करें।
Sandybridge पर और बाद में, राम से PMOVSXBQ का उपयोग कर शायद अच्छा है:
अपने प्रश्न, चारों ओर डेटा शिफ्ट करने के लिए कि यह कैसे को पंक्तिबद्ध करने PMOVSX
के लिए के बारे में के अन्य भाग का उत्तर दें। पिछले सीपीयू पर जो प्रति चक्र दो लोड को संभाल नहीं सकता है, एक समय में 16 बी मास्क डेटा लोड कर रहा है, और PSRLDQ xmm1, 2
के साथ 2 बाइट्स द्वारा इसे स्थानांतरित करने से रजिस्टर के कम 2 बाइट्स में मास्क डेटा के 2 बाइट डाले जाएंगे। या शायद PUNPCKHQDQ
, या PSHUFD
उच्च निर्भरता श्रृंखला को 64 से दूसरे 64 के निम्न 64 तक ले जाकर दो निर्भरता श्रृंखलाएं प्राप्त करने के लिए। आपको यह जांचना होगा कि किस पोर्ट का उपयोग किस निर्देश (शिफ्ट बनाम शफल/निकालने) द्वारा किया जाता है, और देखें कि PMOVSX
और ADDPD
के साथ कौन से संघर्ष कम हैं।
punpck
और pshufd
दोनों एसएनबी पर पी 1/पी 5 का उपयोग करते हैं, तो pmovsx
करता है। addpd
केवल पी 1 पर चल सकता है। andpd
केवल पी 5 पर चल सकता है। हम्म, शायद PAND
बेहतर होगा, क्योंकि यह पी 0 (और पी 1/पी 5) पर चल सकता है। अन्यथा लूप में कुछ भी निष्पादन बंदरगाह 0 का उपयोग नहीं करेगा। अगर पूर्णांक से एफपी डोमेन तक डेटा ले जाने के लिए विलंबता जुर्माना है, तो हम PMOVSX
का उपयोग करते हुए अपरिहार्य है, क्योंकि इसे int डोमेन में मास्क डेटा प्राप्त होगा। सबसे लंबी निर्भरता श्रृंखला से लूप को लंबा बनाने के लिए अधिक accumulators का उपयोग करने के लिए बेहतर है। लेकिन यह सुनिश्चित करने के लिए कि 4 यूपीएस प्रति चक्र जारी कर सकते हैं, लूप बफर में फिट करने के लिए 28uops या इससे कम रखें।
और पूरी चीज़ को अनुकूलित करने के बारे में अधिक जानकारी: लूप को संरेखित करना वास्तव में आवश्यक नहीं है, क्योंकि नेहलेम पर और बाद में यह लूप बफर में फिट होगा।
आपको लूप को 2 या 4 से अनलोल करना चाहिए, क्योंकि प्री-हैसवेल इंटेल CPU में एक ही चक्र में सभी 4 (फ़्यूज्ड) यूओप्स को संभालने के लिए पर्याप्त निष्पादन इकाइयां नहीं हैं। (3 वेक्टर और एक फ़्यूज्ड add
/jl
। वेक्टर यूप्स के साथ दो लोड फ़्यूज़ का हिस्सा हैं।) सैंड्रिब्रिज और बाद में दोनों चक्रों को लोड कर सकते हैं, इसलिए लूप ओवरहेड को छोड़कर प्रति चक्र एक पुनरावृत्ति करने योग्य है।
ओह, ADDPD
में 3 चक्रों की विलम्ब है। इसलिए आपको लूप-ले जाने वाली निर्भरता श्रृंखला को बाधा से बचने के लिए एकाधिक accumulators को अनलॉक और उपयोग करने की आवश्यकता है। शायद 4 से अनलॉक करें, और फिर अंत में 4 जमाकर्ताओं को जोड़ दें। आपको स्रोत कोड में भी इंट्रिनिक्स के साथ ऐसा करना होगा, क्योंकि इससे एफपी गणित के लिए संचालन का क्रम बदल जाएगा, इसलिए संकलक अनलोल करते समय ऐसा करने के इच्छुक नहीं हो सकता है।
तो प्रत्येक अनियंत्रित-बाय -4 लूप में 4 घड़ी चक्र लगेगा, साथ ही लूप ओवरहेड के लिए 1 यूओपी भी होगा। नेहलेम पर, जहां आपके पास एक छोटा पाश-कैश है लेकिन कोई यूओपी कैश नहीं है, तो अनलॉकिंग का मतलब हो सकता है कि आपको डिकोडर थ्रूपुट के बारे में देखभाल करना शुरू करना है। पूर्व-रेतीलेब्रिज पर, हालांकि प्रति घड़ी एक लोड शायद बाधा होगी।
डिकोडर थ्रूपुट के लिए, आप ANDPD
के बजाय ANDPS
का उपयोग कर सकते हैं, जो एन्कोड करने के लिए एक कम बाइट लेता है। आईडीके अगर इससे मदद मिलेगी।
इसे 256b ymm
रजिस्टरों को विस्तारित करने के लिए सबसे सरल कार्यान्वयन के लिए AVX2 की आवश्यकता होगी (VPMOVSXBQ ymm
के लिए)। आपको AVX-केवल दो VPMOVSXBQ xmm
करके एक गति प्राप्त हो सकती है और उन्हें VINSERTF128
या कुछ के साथ संयोजित किया जा सकता है।
'pmovsxbq' वास्तव में एक मेमोरी ऑपरेंड ले सकता है और स्मृति से उन दो बाइटों को सीधे लोड कर सकता है।लेकिन निश्चित रूप से एमएसवीसी टीम की परवाह नहीं है। – harold
@harold हां, इंटेल द्वारा दिए गए इंट्रिनिक्स के लिए वास्तव में एक पता मोड गुम है। तो वास्तव में इंटेल को दोष देना है, एमएस नहीं (जैसा कि मुझे यह कहना नफरत है ;-))। आसान समाधान इनलाइन असेंबली में 'pmovsxbq' का उपयोग कर रहा है। अन्यथा बाइट्स को सही जगहों पर प्राप्त करने के लिए एक बार में 16 बाइट पढ़ना और कुछ 'pshufb' पढ़ना होगा। – hirschhornsalz
@drhirsch अच्छी तरह से अप्रत्याशित है .. मुझे – harold