2015-01-14 6 views
5

मैं विजुअल सी ++ 2010 और मैसम ('फास्ट कॉल' कॉलिंग कन्वेंशन) के साथ कुछ x64 असेंबली कर रहा हूं।डुप्लिकेट बाइट मानों के साथ 64 बिट रजिस्टर को कैसे पॉप्युलेट करें

तो चलो कहते हैं कि मैं C++ एक समारोह डालते हैं:

extern "C" void fillArray(unsigned char* byteArray, unsigned char value); 

सरणी सूचक RCX में होगा और चार मूल्य डीएल में हो जाएगा

मैं कैसे RAX मूल्यों के साथ डीएल इस तरह का उपयोग कर भर सकते हैं कि अगर मैं mov qword ptr [RCX], RAX पर था और बाइटएरे प्रिंट करता हूं, तो सभी मान 'char value' के बराबर होंगे?

कृपया ध्यान दें कि मैं अपने कंपाइलर को आउट-कोड करने की कोशिश नहीं कर रहा हूं, मैं बस सीख रहा हूं।

+0

यदि आप कुछ एमएमएक्स/एसएसई सीखना चाहते हैं तो ऐसे निर्देश हैं। लेकिन इस मामले में यह शायद धीमा हो जाएगा क्योंकि यह सिर्फ एक मूल्य के लिए है। अगर आप कई मूल्यों पर गणना करते हैं तो एसएसई बहुत बेहतर प्रदर्शन करता है। –

उत्तर

6

क्योंकि आपने अपनी प्रक्रिया 'fillArray' कहा है, मुझे लगता है कि आप एक बाइट वैल्यू के साथ एक संपूर्ण मेमोरी ब्लॉक भरना चाहते हैं। तो मैंने विभिन्न दृष्टिकोणों पर तुलना की। यह 32 बिट मैस्म कोड है, लेकिन परिणाम 64 बिट मोड में समान होना चाहिए। प्रत्येक दृष्टिकोण दोनों गठबंधन और unaligned बफर के साथ परीक्षण किया जाता है। यहाँ परिणाम हैं:

Simple REP STOSB - aligned....: 192 
Simple REP STOSB - not aligned: 192 
Simple REP STOSD - aligned....: 191 
Simple REP STOSD - not aligned: 222 
Simple while loop - aligned....: 267 
Simple while loop - not aligned: 261 
Simple while loop with different addressing - aligned....: 271 
Simple while loop with different addressing - not aligned: 262 
Loop with 16-byte SSE write - aligned....: 192 
Loop with 16-byte SSE write - not aligned: 205 
Loop with 16-byte SSE write non-temporal hint - aligned....: 126 (EDIT) 

सबसे अनुभवहीन संस्करण निम्न कोड दोनों स्थितियों में सबसे अच्छा प्रदर्शन करने के लिए लगता है और सबसे छोटा कोड आकार के रूप में अच्छी तरह से है का उपयोग करते हुए:

cld 
mov al, 44h ; byte value 
mov edi, lpDst 
mov ecx, 256000*4 ; buf size 
rep stosb 

संपादित करें: यह नहीं करने के लिए सबसे तेजी से है गठबंधन डेटा। जोड़ा गया MOVNTDQ संस्करण जो सबसे अच्छा प्रदर्शन करता है, नीचे देखें।

पूर्णता के लिए के लिए, यहाँ अन्य दिनचर्या के अंश हैं - मूल्य से पहले EAX में विस्तार किया जा करने के लिए माना जाता है:

निरसित Stosd:

mov edi, lpDst 
mov ecx, 256000 
rep stosd 

सरल जबकि:

mov edi, lpDst 
mov ecx, 256000 
.while ecx>0 
    mov [edi],eax 
    add edi,4 
    dec ecx 
.endw 

विभिन्न सरल करते हुए:

mov edi, lpDst 
xor ecx, ecx 
.while ecx<256000 
    mov [edi+ecx*4],eax 
    inc ecx 
.endw 

SSE (दोनों):

movd xmm0,eax 
punpckldq xmm0,xmm0 ; xxxxxxxxGGGGHHHH -> xxxxxxxxHHHHHHHH 
punpcklqdq xmm0,xmm0 ; xxxxxxxxHHHHHHHH -> HHHHHHHHHHHHHHHH 
mov ecx, 256000/4 ; 16 byte 
mov edi, lpDst 
.while ecx>0 
    movdqa xmmword ptr [edi],xmm0 ; movdqu for unaligned 
    add edi,16 
    dec ecx 
.endw 

SSE (NT, गठबंधन, संपादित करें):

movd xmm0,eax 
punpckldq xmm0,xmm0 ; xxxxxxxxGGGGHHHH -> xxxxxxxxHHHHHHHH 
punpcklqdq xmm0,xmm0 ; xxxxxxxxHHHHHHHH -> HHHHHHHHHHHHHHHH 
mov ecx, 256000/4 ; 16 byte 
mov edi, lpDst 
.while ecx>0 
    movntdq xmmword ptr [edi],xmm0 
    add edi,16 
    dec ecx 
.endw 

मैं पूरी कोड यहाँ http://pastie.org/9831404 अपलोड --- हच से MASM पैकेज कोडांतरण के लिए आवश्यक है ।

+0

ब्याज से आपने सीपीयू को इन बेंचमार्क पर कैसे चलाया? मुझे यह जानने में दिलचस्पी है कि क्या एसबी/आईबी/हैसवेल गैर-अस्थायी स्टोरों का उपयोग करने से समान लाभ देखेंगे? –

+0

मैंने 1333 पर डीडीआर 3-रैम के साथ एएमडी एक्स 4 640 सीपीयू का इस्तेमाल किया। – zx485

+0

धन्यवाद - मैं हैसवेल पर अपना कोड चलाने की कोशिश करूंगा और देख सकता हूं कि यह समान परिणाम देता है या नहीं। –

9

आप 0x0101010101010101 से गुणा सभी अन्य बाइट्स में सबसे कम बाइट प्रतिलिपि करने के लिए (बाकी संभालने सब शून्य के साथ शुरू हो गया था) कर सकते हैं, यह थोड़ा कष्टप्रद है वहाँ कोई imul r64, r64, imm64 लेकिन आप ऐसा कर सकता है कर सकते हैं क्योंकि:

mov rax, 0x0101010101010101 
mul rdx 

कुछ प्रोसेसर पर, mul rdx के बजाय imul rax, rdx का उपयोग करना थोड़ा तेज़ है।

तो rdx (दूसरे शब्दों में, अगर यह सेट के लिए कुछ अतिरिक्त बिट्स है) आवश्यक प्रपत्र की नहीं है, बस सामने एक
movzx rdx, dl जोड़ें।

यदि आपको कोड आकार पसंद नहीं है (mov r64, imm64 पहले से ही 10 बाइट्स है), तो बस अपने डेटा सेगमेंट में स्थिर रहें।

+0

निरंतर गुणा के बारे में वह बिट बिल्कुल वही चीज़ है जिसे मैं ढूंढ रहा था। – Dziugas

+1

क्यू/ए के भावी पाठकों के लिए: एक एसईएस रजिस्टर में बाइट प्रसारित करना एक मेमसेट (उर्फ fillArray) के लिए सेट अप करने के लिए एक बेहतर विकल्प हो सकता है। इसे 32 बी रजिस्टर में प्रसारित करने के लिए पूर्णांक निर्देशों का उपयोग करना (उदाहरण के लिए इस 'imul' चाल के साथ), और फिर' movd' करने से समझ में आ सकता है, या फिर सभी शून्य नियंत्रण मास्क के साथ pshufb का उपयोग करें (जिसे आप pxor के साथ कुशलता से उत्पन्न कर सकते हैं उर्फ '_mm_setzero()')। –

2

अनुभवहीन रास्ता

xor rbx, rbx 
mov bl, dl 
mov bh, dl 
mov rax, rbx 
shl rbx, 16 
or rbx, rax 
mov rax, rbx 
shl rax, 32 
or rax, rbx 

तो यह हेरोल्ड के रास्ते की तुलना में काफी धीमी हो सकती है

आप निम्न कोड

int64_t s; 
s = (s << 8) | s; 
s = (s << 16) | s; 
s = (s << 32) | s; 

जीसीसी 4.9.0 के लिए संकलक विधानसभा उत्पादन देख सकते हैं आरएसआई

mov rsi, rax 
sal rsi, 8 
or rsi, rax 
mov rax, rsi 
sal rax, 16 
or rsi, rax 
mov rax, rsi 
sal rax, 32 
or rsi, rax 
01 के परिणामस्वरूप the following output उत्पन्न करता है
संबंधित मुद्दे