32-बिट रजिस्टरों पर x86-64 निर्देश पूर्ण 64-बिट रजिस्टर के ऊपरी भाग को शून्य क्यों करते हैं?


119

इंटेल नियमावली के x86-64 टूर में , मैंने पढ़ा

शायद सबसे आश्चर्यजनक तथ्य यह है कि एक निर्देश जैसे MOV EAX, EBXस्वचालित रूप से RAXरजिस्टर के ऊपरी 32 बिट्स को शून्य करता है ।

इंटेल प्रलेखन (3.4.1.1 मैनुअल-बेसिक आर्किटेक्चर में 64-बिट मोड में जनरल-पर्पस रजिस्टर), जो एक ही समय पर उद्धृत होता है:

  • 64-बिट ऑपरेंड्स गंतव्य सामान्य-उद्देश्य रजिस्टर में 64-बिट परिणाम उत्पन्न करते हैं।
  • 32-बिट ऑपरेंड्स 32-बिट परिणाम उत्पन्न करते हैं, गंतव्य सामान्य-उद्देश्य रजिस्टर में 64-बिट परिणाम के लिए शून्य-विस्तारित।
  • 8-बिट और 16-बिट ऑपरेंड 8-बिट या 16-बिट परिणाम उत्पन्न करते हैं। गंतव्य सामान्य प्रयोजन रजिस्टर के ऊपरी 56 बिट्स या 48 बिट्स (क्रमशः) ऑपरेशन द्वारा संशोधित नहीं किए जाते हैं। यदि 8-बिट या 16-बिट ऑपरेशन का परिणाम 64-बिट पता गणना के लिए अभिप्रेत है, तो स्पष्ट रूप से रजिस्टर को पूर्ण 64-बिट्स पर हस्ताक्षरित करें।

X86-32 और x86-64 विधानसभा में, 16 बिट निर्देश जैसे

mov ax, bx

इस तरह के "अजीब" व्यवहार को न दिखाएं कि बाज का ऊपरी शब्द शून्य है।

इस प्रकार: इस व्यवहार को पेश करने का क्या कारण है? पहली नज़र में यह अतार्किक लगता है (लेकिन इसका कारण यह हो सकता है कि मुझे x86-32 असेंबली के प्रश्नपत्रों के लिए इस्तेमाल किया जाता है)।


16
यदि आप "आंशिक रजिस्टर स्टाल" के लिए Google, तो आपको उस समस्या के बारे में काफी जानकारी मिल जाएगी जो वे (लगभग निश्चित रूप से) बचने की कोशिश कर रहे थे।
जेरी कॉफिन


4
सिर्फ "सबसे" नहीं। AFAIK, एक गंतव्य ऑपरेंड के साथ सभी निर्देश r32विलय के बजाय उच्च 32 को शून्य करते हैं। उदाहरण के लिए, कुछ कोडर एक REX को बचाने के pmovmskb r64, xmmसाथ बदल देंगे pmovmskb r32, xmm, क्योंकि 64 बिट गंतव्य संस्करण पहचान का व्यवहार करता है। भले ही मैन्युअल के ऑपरेशन खंड में 32/64 बिट के सभी 6 संयोजनों और 64/128 / 256b स्रोत को अलग-अलग सूचीबद्ध किया गया है, लेकिन r32 फॉर्म का अंतर्निहित शून्य-विस्तार r64 फॉर्म के स्पष्ट शून्य-विस्तार को डुप्लिकेट करता है। मैं एचडब्ल्यू कार्यान्वयन के बारे में उत्सुक हूं ...
पीटर कॉर्डेस

2
@ हंसपैंट, परिपत्र संदर्भ शुरू होता है।
कोच्चि १५'१६ को २६:२६

1
संबंधित: xor eax,eaxया xor r8d,r8dRAX या R8 को शून्य करने का सबसे अच्छा तरीका है (RAX के लिए REX उपसर्ग को सहेजना, और 64-बिट XOR को विशेष रूप से सिल्वरमोंट पर भी नियंत्रित नहीं किया गया है)। संबंधित: हसवेल / स्काईलेक पर आंशिक पंजीकरण कैसे ठीक से करते हैं? AL को लिखना RAX पर एक झूठी निर्भरता है, और AH असंगत है
पीटर कॉर्ड्स

जवाबों:


98

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

इस तरह आप 64-बिट मोड में 32-बिट मानों का उपयोग करते हुए तेजी से कोड लिख सकते हैं, यह स्पष्ट रूप से हर समय निर्भरता को तोड़ने के बिना है। इस व्यवहार के बिना, 64-बिट मोड में हर एक 32-बिट निर्देश को उस चीज पर इंतजार करना होगा जो पहले हुआ था, भले ही उस उच्च भाग का उपयोग लगभग कभी नहीं किया जाएगा। ( int64-बिट कैश फ़ुटप्रिंट और मेमोरी बैंडविड्थ को बर्बाद करना; x86-64 सबसे कुशलता से 32 और 64-बिट ऑपरेंड आकार का समर्थन करता है )

8 और 16-बिट ऑपरेंड आकारों के लिए व्यवहार अजीब है। निर्भरता पागलपन एक कारण है कि 16-बिट निर्देशों से बचा जाता है। x86-64 को यह 80-बिट के लिए 886 और 386 के लिए 1686 से विरासत में मिला है, और 8 और 16-बिट रजिस्टरों के 64-बिट मोड में उसी तरह काम करने का फैसला किया है जैसा कि वे 32-बिट मोड में करते हैं।


यह भी देखें कि जीसीसी आंशिक रजिस्टरों का उपयोग क्यों नहीं करता है? 8 और 16-बिट आंशिक रजिस्टरों को कैसे लिखते हैं (और बाद में पूर्ण रजिस्टर की रीडिंग) के व्यावहारिक विवरणों को वास्तविक सीपीयू द्वारा नियंत्रित किया जाता है।


8
मुझे नहीं लगता कि यह अजीब है, मुझे लगता है कि वे बहुत ज्यादा तोड़ना नहीं चाहते थे और पुराने व्यवहार को बनाए रखा था।
एलेक्सी फ्रुंज़े

5
@ एलेक्स जब उन्होंने 32 बिट मोड की शुरुआत की, तो उच्च भाग के लिए कोई पुराना व्यवहार नहीं था। पहले कोई ऊंचा हिस्सा नहीं था .. बेशक उसके बाद इसे अब और नहीं बदला जा सकता।
हेरोल्ड

1
मैं 16-बिट ऑपरेंड्स के बारे में बोल रहा था, क्यों उस मामले में शीर्ष बिट्स शून्य नहीं मिलता है। वे गैर-64-बिट मोड में नहीं हैं। और यह 64-बिट मोड में भी रखा गया है।
एलेक्सी फ्रुंज़े

3
मैंने आपके "16 बिट निर्देशों के लिए व्यवहार अजीब है" की व्याख्या की "जैसा कि यह अजीब है कि शून्य-विस्तार 64-बिट मोड में 16-बिट ऑपरेंड के साथ नहीं होता है"। इसलिए बेहतर संगतता के लिए इसे 64-बिट मोड में उसी तरह रखने के बारे में मेरी टिप्पणी।
एलेक्सी फ्रुंज़े

8
@ एलेक्स ओह, मैं देख रहा हूं। ठीक। मुझे नहीं लगता कि यह उस दृष्टिकोण से अजीब है। बस "पीछे मुड़कर देखना, शायद यह इतना अच्छा विचार नहीं था" -perspective। मुझे लगता है कि मैं स्पष्ट होना चाहिए था :)
हेरोल्ड

9

यह बस निर्देशों और निर्देश सेट में जगह बचाता है। आप मौजूदा (32-बिट) निर्देशों का उपयोग करके छोटे तात्कालिक मानों को 64-बिट रजिस्टर में स्थानांतरित कर सकते हैं।

यह आपको 8 बाइट मान के लिए एनकोड करने से भी बचाता है MOV RAX, 42, जब MOV EAX, 42इसका पुन: उपयोग किया जा सकता है।

यह अनुकूलन 8 और 16 बिट ऑप्स के लिए उतना महत्वपूर्ण नहीं है (क्योंकि वे छोटे हैं), और नियमों को बदलने से पुराना कोड भी टूट जाएगा।


7
अगर यह सही है, तो क्या इसके लिए 0 विस्तार के बजाय साइन-एक्सटेंशन करना अधिक समझदारी नहीं होगी?
डेमियन___बेलिवर

16
साइन एक्सटेंशन हार्डवेयर में भी धीमा है। शून्य विस्तार समानांतर में किया जा सकता है जो भी संगणना कम आधे का उत्पादन करता है, लेकिन साइन एक्सटेंशन तब तक नहीं किया जा सकता है जब तक कि कम से कम आधे हिस्से की गणना नहीं की गई हो।
जेरी कॉफिन

13
एक अन्य संबंधित चाल का उपयोग करना है XOR EAX, EAXक्योंकि XOR RAX, RAXएक आरईएक्स उपसर्ग की आवश्यकता होगी।
नील

3
@ नबूक: ज़रूर, वे movzx / movsx का एक एन्कोडिंग जोड़ सकते थे जो एक तत्काल तर्क लेता है। अधिकांश समय यह ऊपरी बिट्स शून्य होने के लिए अधिक सुविधाजनक है, इसलिए आप एक सरणी इंडेक्स के रूप में एक मान का उपयोग कर सकते हैं (क्योंकि सभी regs को एक प्रभावी पते में समान आकार होना चाहिए: [rsi + edx]अनुमति नहीं है)। बेशक झूठी निर्भरता / आंशिक-रजिस्टर स्टालों (अन्य जवाब) से बचना एक और प्रमुख कारण है।
पीटर कॉर्ड्स

4
और नियमों को बदलने से पुराना कोड भी टूट जाएगा। पुराना कोड वैसे भी 64-बिट मोड में नहीं चल सकता (उदाहरण के लिए 1-बाइट इंक / डीईसी आरईएक्स उपसर्ग हैं); यह अप्रासंगिक है। X86 के मौसा की सफाई करने का कारण लॉन्ग मोड और कम्प्रेशन / लीगेसी मोड के बीच कम अंतर है, इसलिए मोड के आधार पर कम निर्देशों को अलग तरीके से डिकोड करना पड़ता है। AMD को नहीं पता था कि AMD64 पकड़ने वाला है, और दुर्भाग्य से बहुत रूढ़िवादी था इसलिए इसे समर्थन करने के लिए कम ट्रांजिस्टर लगेगा। लंबे समय तक, यह ठीक होता अगर कंपाइलर्स और इंसानों को यह याद रखना होता कि कौन सी चीजें 64-बिट मोड में अलग तरह से काम करती हैं।
पीटर कॉर्डेस

1

शून्य को 64 बिट्स तक विस्तारित किए बिना, इसका मतलब होगा कि एक निर्देश पढ़ने से raxइसके raxऑपरेंड के लिए 2 निर्भरताएं होंगी (यह निर्देश जो लिखता है eaxऔर जो निर्देश raxइससे पहले लिखता है ), इसका मतलब यह है कि 1) आरओबी के लिए प्रविष्टियां होनी चाहिए एक एकल ऑपरेंड के लिए कई निर्भरताएं, जिसका अर्थ है कि आरओबी को अधिक तर्क और ट्रांजिस्टर की आवश्यकता होगी और अधिक स्थान लेगा, और निष्पादन धीमी गति से एक अनावश्यक दूसरी निर्भरता पर इंतजार कर रहा होगा जिसे निष्पादित करने में उम्र लग सकती है; या वैकल्पिक रूप से 2), जो मैं अनुमान लगा रहा हूं कि 16 बिट निर्देशों के साथ होता है, आवंटन चरण संभवतः स्टॉल (यानी यदि आरएटी के पास एक axलिखने के लिए एक सक्रिय आवंटन है और एक eaxरीड दिखाई देता है, तो यह तब तक स्टाल होता है जब तक कि axरिटायर न हो जाए)।

mov rdx, 1
mov rax, 6
imul rax, rdx
mov rbx, rax
mov eax, 7 //retires before add rax, 6
mov rdx, rax // has to wait for both imul rax, rdx and mov eax, 7 to finish before dispatch to the execution units, even though the higher order bits are identical anyway

शून्य विस्तार न करने का एकमात्र लाभ यह सुनिश्चित करना है कि उच्च क्रम के बिट्स raxशामिल हैं, उदाहरण के लिए, यदि इसमें मूल रूप से 0xffffffffffffff शामिल है, तो परिणाम 0xffffff000000007 होगा, लेकिन ISA के लिए इस तरह के खर्च पर यह गारंटी देने का बहुत कम कारण है, और यह अधिक संभावना है कि शून्य विस्तार का लाभ वास्तव में अधिक की आवश्यकता होगी, इसलिए यह कोड की अतिरिक्त रेखा को बचाता है mov rax, 0। यह गारंटी देकर कि यह हमेशा शून्य से 64 बिट्स तक विस्तारित होगा, कंपाइलर इस एक्सलोम को ध्यान में रखते हुए काम कर सकते हैं mov rdx, rax, raxकेवल इसकी एकल निर्भरता के लिए इंतजार करना होगा, जिसका अर्थ है कि यह निष्पादन जल्दी और रिटायर हो सकता है, निष्पादन इकाइयों को मुक्त कर सकता है। इसके अलावा, यह REX बाइट की आवश्यकता के बिना xor eax, eaxशून्य की तरह अधिक कुशल शून्य मुहावरों के लिए भी अनुमति देता है rax


स्काइलेक पर आंशिक-झंडे सीएफजेडओ बनाम सीएफ के लिए अलग से इनपुट होने से कम से कम काम करता है। (तो cmovbe2 उफ़ है लेकिन cmovb1 है)। लेकिन कोई भी CPU जो किसी भी आंशिक-पंजीयन का नाम नहीं देता है, यह आपके सुझाव का तरीका है। इसके बजाय वे एक मर्जिंग यूओपी डालते हैं यदि आंशिक रेज को पूर्ण रेज (यानी "गंदा") से अलग किया जाता है। देखें कि जीसीसी आंशिक रजिस्टर का उपयोग क्यों नहीं करता है? और हसवेल / स्काईलेक पर आंशिक पंजीकरण कैसे करते हैं? AL को लिखना RAX पर एक झूठी निर्भरता है, और AH असंगत है
पीटर कॉर्डेस

P6-परिवार CPU या तो विलय करने के लिए ~ 3 चक्रों के लिए रुक गए (मर्ज 2 / Nehalem), या इससे पहले P6-परिवार (PM, PIII, PII, Ppro) केवल (कम से कम?) ~ 6 चक्रों के लिए स्टाल। शायद जैसा कि आपने 2 में सुझाया है, स्थायी / स्थापत्य रजिस्टर फाइल को राइटबैक वैल्यू के लिए उपलब्ध होने के इंतजार में।
पीटर कॉर्डेस

@PeterCordes ओह, मुझे आंशिक ध्वज स्टालों के लिए कम से कम उफ़ विलय करने के बारे में पता था। समझ में आता है, लेकिन मैं भूल गया कि यह एक मिनट के लिए कैसे काम करता है; इसने एक बार क्लिक किया लेकिन मैं नोट्स बनाना भूल गया
लुईस केल्सी

@PeterCordes microaltecture.pdf: This gives a delay of 5 - 6 clocks. The reason is that a temporary register has been assigned to AL to make it independent of AH. The execution unit has to wait until the write to AL has retired before it is possible to combine the value from AL with the value of the rest of EAXमैं 'मर्जिंग यूओपी' का एक उदाहरण नहीं खोज सकता, जिसका उपयोग इसे हल करने के लिए किया जाएगा, हालांकि यह एक आंशिक फ्लैग स्टाल के लिए भी है
लुईस केल्सी

राइट, शुरुआती P6 सिर्फ राइटबैक तक स्टॉल है। Core2 और Nehalem के बाद / पहले एक मर्जिंग यूओपी डालें? केवल एक छोटे समय के लिए सामने के छोर को रोकना। Sandybridge बिना स्टॉप किए मॉपिंग यूप्स को सम्मिलित करता है। (लेकिन एचएच-विलय को एक चक्र में ही जारी करना पड़ता है, जबकि AL विलय एक पूर्ण समूह का हिस्सा हो सकता है।) हैवेल / SKL AL को RAX से बिल्कुल अलग नहीं करता है, इसलिए mov al, [mem]एक माइक्रो-फ्यूज लोड + ALU- है। मर्ज, केवल नाम बदलकर एएच, और एएच-मर्जिंग यूओपी अभी भी अकेले जारी करता है। इन सीपीयू में आंशिक-ध्वज विलय तंत्र भिन्न होते हैं, जैसे Core2 / Nehalem अभी भी आंशिक-झंडे के लिए आंशिक-reg के विपरीत स्टाल करते हैं।
पीटर कॉर्डेस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.