2010-09-22 8 views
13

मैं वर्तमान में compiler लिखने की प्रक्रिया में हूं और मुझे लगता है कि यह एक सभ्य समय सीमा में निष्पादित आउटपुट कोड को प्राप्त करने में कुछ समस्याएं चला रहा है।एक कंपाइलर द्वारा उत्पन्न असेंबली कोड को अनुकूलित करने के लिए कुछ सुझाव क्या हैं?

संकलक का एक संक्षिप्त अवलोकन:

7Basic एक संकलक है कि लक्ष्य वास्तुकला/प्लेटफ़ॉर्म की मशीन कोड में सीधे 7Basic कोड संकलित करने के लिए करना है। वर्तमान में 7 बेसिक x86 असेंबली को स्रोत फ़ाइल प्रदान करता है।

समस्या यह है कि विधानसभा संकलक द्वारा बनाया गया कोड धीमी और अक्षम है।

उदाहरण के लिए, this कोड (जो this असेंबली कोड तक संकलित करता है) the equivalent C code से निष्पादित करने के लिए लगभग 80.47 गुना अधिक समय लेता है। समस्या का

भाग कि संकलक निम्नलिखित की तरह कोड पैदा कर रहा है है:

push eax 
push 5000000 
pop ebx 
pop eax 
अधिक तार्किक के बजाय

:

mov ebx,5000000 

... जो एक ही बात पूरा करता है।

मेरा प्रश्न है: इस तरह की समस्या से बचने के लिए कुछ तकनीक क्या हैं? पार्सर मूल रूप से अभिव्यक्तियों को पार्स करने के लिए रिकर्सन का उपयोग करता है, इसलिए उत्पन्न कोड इस पर प्रतिबिंबित करता है।

+13

अपने संकलक कमांड लाइन ;-) – hirschhornsalz

+0

+1 @drhirsch LOL – karlphillip

+3

"... एक ** पार मंच ** बेसिक संकलक कि देशी ** Win32 उत्पन्न करता है ** निष्पादनयोग्य।" करने के लिए -O3 जोड़े रुको क्या? –

उत्तर

14

एक तकनीक को peephole optimisation कहा जाता है। असेंबली कोड को साफ करने के लिए यह एक पुनरावृत्ति दृष्टिकोण लेता है। अनिवार्य रूप से आप असेंबली कोड के माध्यम से स्कैन करते हैं, एक समय में केवल दो या तीन निर्देशों को देखते हुए देखते हैं कि आप उन्हें सरल में कम कर सकते हैं या नहीं। उदाहरण के लिए,

push eax  ; 1 
push 5000000 ; 2 
pop ebx   ; 3 
pop eax   ; 4 

पहला कदम लाइनों 2 और 3 पर विचार करेंगे, और की जगह उस के साथ:

push eax  ; 1 
mov ebx,5000000 ; 2a 
pop eax   ; 4 

दूसरे, आप 1 और 4, पर विचार हो सकता है और अगर eax में छुआ नहीं है बीच शिक्षा, उन दोनों को निकालने के लिए, छोड़ने आप क्या चाहते हैं:

mov ebx,5000000 ; 2a 
+0

+1: मुझे इसे हराया ... –

+0

ठीक है, क्या यह कोड बनने के बाद किया जा सकता है? ये अच्छा रहेगा। –

+0

आमतौर पर पेफोल ऑप्टिमाइज़ेशन एक इंटरमीडिएट असेंबली आउटपुट उत्पन्न करने के बाद एक अलग पास के रूप में चलाया जाता है। यदि आप एकाधिक आर्किटेक्चर के लिए संकलित कर रहे हैं, तो आपको * आईएल फॉर्म में संकलित करने के बाद * और फिर अपनी लक्षित असेंबली भाषा में * चलाने के लिए जरूरी होगा। –

5

आप विधानसभा सी कोड जनरेट करने के बजाय विचार करना चाह सकते हैं और फिर एक सी संकलक जाने (जैसे जीसीसी) संभाल कोड जी आपके लिए उत्साह पहिया को फिर से आविष्कार करने का कोई मतलब नहीं है।

+0

आखिरकार संकलक मशीन कोड उत्पन्न करने जा रहा है, इसलिए यह एक विकल्प नहीं है। –

+2

आखिर में सी कंपाइलर भी मशीन कोड उत्पन्न करने जा रहा है। –

+0

मेरा मतलब था कि अंत में संकलक सीधे मशीन कोड उत्पन्न करेगा। –

2

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

उत्सर्जित कोड का यह पैटर्न मुझे बताता है कि आपके कोड जनरेटर को यह नहीं पता है कि x86 में "तत्काल चलें" निर्देश हैं जो सीधे निर्देश स्ट्रीम में निरंतर मान एम्बेड करते हैं। तत्काल मूल्यों के साथ ऑपकोड के लिए x86 एन्कोडिंग थोड़ा जटिल (परिवर्तनीय लंबाई आर/एम बाइट्स) प्राप्त कर सकती है लेकिन यदि आप कई x86 निर्देशों का उपयोग करना चाहते हैं तो यह पहले से ही आवश्यक है।

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

इस प्रकार का कोडेजन तब होता है जब संकलक के आंतरिक मध्यवर्ती प्रतिनिधित्व लक्ष्य आर्किटेक्चर के सभी पहलुओं का प्रतिनिधित्व करने के लिए पर्याप्त विस्तृत नहीं होते हैं। यह विशेष रूप से सच है यदि कोड जेनरेटर आर्किटेक्चर मूल रूप से आरआईएससी निर्देश सेट के लिए डिज़ाइन किया गया था लेकिन x86 निर्देशों को उत्सर्जित करने के लिए पुनर्निर्मित किया गया है। आरआईएससी आर्किटेक्चर में बहुत कम और बहुत ही सरल लोड, स्टोर, और रेग/रेग निर्देशों का संचालन होता है, जबकि x86 निर्देश सेट ने दशकों से व्यवस्थित रूप से विकसित किया है जिसमें विभिन्न प्रकार के ऑपकोड शामिल हैं जो सीधे स्मृति पर संचालित होते हैं, निर्देशों में इनलाइन स्थिरांक, और अन्य सामान की एक पूरी गड़बड़। यदि आरआईएससी के लिए कंपाइलर का इंटरमीडिएट प्रतिनिधित्व (अभिव्यक्ति ग्राफ) वायर्ड किया गया है, तो इसे x86 की विस्तृत विविधता और सूक्ष्मता को ग्रोक करना मुश्किल होगा।

+0

असल में मैंने कोड जनरेटर लिखा था :) –

+0

कूल। फिर उम्मीद है कि इस कोडेजन में सुधार किया जा सकता है। ;> चरण 1: अपने मध्यवर्ती प्रतिनिधित्व में निरंतर मूल्य भार को पहचानने के तरीके को समझें और उन्हें mov reg, imm। चरण 2: यह पता लगाएं कि क्यों आपका कोड जेनरेटर इस उदाहरण में ईएक्स को दबा रहा है और पॉप कर रहा है, क्योंकि यह कोर ऑपरेशन के लिए प्रासंगिक नहीं है। बग की बदबू आ रही है। – dthorpe

+0

यह एक बग नहीं है। ऐसा लगता है कि अभिव्यक्तियों का मूल्यांकन करने के तरीके के कारण ऐसा करना चाहिए। यही कारण है कि मैंने सवाल पूछा। –

3

मैं इस समय एक कंपाइलर कोर्स ले रहा हूं। मैंने कुशल कोड आउटपुट में कुछ बड़ी प्रगति की है, लेकिन आपको ड्रैगन पुस्तक में देखना चाहिए। यह मार्ग का एक संस्कार है। आपको जेरेमी बेनेट की पुस्तक, से संकलन तकनीक का परिचय लेना चाहिए: एएनएसआई सी, LEX, और YACC का उपयोग करने वाला पहला कोर्स। पुस्तक बहुत मुश्किल है, लेकिन आप से

http://www.jeremybennett.com/publications/download.html

कोड जनरेटर फ़ाइल (cg.c) संकलक मुक्त करने के लिए स्रोत कोड डाउनलोड कर सकते हैं काफी अनुकूलित कोड पैदा करने के लिए कुछ कार्य करती है। लक्षित भाषा i386 नहीं है, लेकिन आपको यह देखना चाहिए कि वह रजिस्टरों का वर्णन कैसे करता है और यह ट्रैक रखता है कि प्रतीक तालिका प्रविष्टियां कहाँ संग्रहित की जाती हैं। उनकी आउटपुट असेंबली को और अनुकूलित किया जा सकता है, लेकिन यह कोड बनाने के लिए एक बड़ा आधार प्रदान करता है जो कुछ मामलों में जीसीसी-एस से उत्पादन को प्रतिद्वंद्वी बना सकता है।

एक सामान्य अनुकूलन एक समारोह में प्रवेश करने पर सभी स्थानीय और अस्थायी चर के लिए स्थान आरक्षित करने के लिए स्टैक पॉइंटर को घटाना होगा। फिर बस लगातार धक्का/पॉपिंग के बजाय ऑफ़सेट का संदर्भ लें।

उदाहरण के लिए, यदि आपका इंटरमीडिएट कोड चौगुनी की सूची है, तो आपको प्रत्येक फंक्शन के लिए बस इसके माध्यम से इसे पुनरावर्तक करना चाहिए और अधिकतम ऑफसेट का ट्रैक रखना चाहिए। फिर स्टैक पर अंतरिक्ष की मात्रा घटाने के लिए लाइन आउटपुट करें। यह इतने सारे चर को चालू और बंद करने की आवश्यकता को हटा देता है। उन्हें पॉप करने की आवश्यकता को हटाने के लिए, आप अपने मूल्य को अपने ऑफसेट से स्टैक पर एक रजिस्टर में चला सकते हैं। यह प्रदर्शन में काफी सुधार करेगा।

+0

महान सलाह - भाषा में अभी तक दायरे की अवधारणा नहीं है, न ही इसमें कार्य/सबराउटिन हैं। एक काम अभी भी प्रगति में है। लेकिन जब ऐसा होता है, तो मुझे यकीन है कि स्थानीय चर ढेर पर चलेंगे। –

+0

आपका इंटरमीडिएट कोड प्रतिनिधित्व क्या है? टीएसी/quadruples? – Kizaru

+0

एक नहीं है :) संकलक आउटपुट मॉड्यूल में 'छद्म-आदेश' भेजता है जो सटीक असेंबली निर्देश उत्पन्न करता है। –

2

Peephole अनुकूलन मदद करेगा, लेकिन एक स्पष्ट मुद्दा यह है कि आपका कंपाइलर पंजीकरण आवंटन नहीं करता है!

http://en.wikipedia.org/wiki/Register_allocation

आप गंभीर प्रदर्शन के स्तर को प्राप्त करना चाहते हैं, तो आप उस पर गौर करने के लिए कर रहे हैं। यह एक ही पास में किया जा सकता है यदि आप इसे "फ्लाई पर" लालच से करते हैं।

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

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