कंपाइलर डिज़ाइन - कोड जनरेशन
कोड पीढ़ी को संकलन के अंतिम चरण के रूप में माना जा सकता है। पोस्ट कोड जेनरेशन के माध्यम से, कोड पर ऑप्टिमाइज़ेशन प्रक्रिया लागू की जा सकती है, लेकिन इसे कोड जनरेशन चरण के एक भाग के रूप में ही देखा जा सकता है। संकलक द्वारा उत्पन्न कोड कुछ निचले स्तर की प्रोग्रामिंग भाषा का एक उदाहरण है, उदाहरण के लिए, असेंबली भाषा। हमने देखा है कि उच्च-स्तरीय भाषा में लिखा गया स्रोत कोड एक निम्न-स्तरीय भाषा में बदल जाता है, जिसके परिणामस्वरूप निम्न-स्तरीय ऑब्जेक्ट कोड होता है, जिसमें निम्न न्यूनतम गुण होने चाहिए:
- इसे स्रोत कोड का सही अर्थ होना चाहिए।
- यह CPU उपयोग और मेमोरी प्रबंधन के संदर्भ में कुशल होना चाहिए।
अब हम देखेंगे कि मध्यवर्ती कोड को लक्ष्य वस्तु कोड (असेंबली कोड, इस मामले में) में कैसे बदल दिया जाता है।
निर्देशित अचक्रीय ग्राफ
डाइरेक्टेड एसाइक्लिक ग्राफ (डीएजी) एक ऐसा उपकरण है जो बुनियादी ब्लॉकों की संरचना को दर्शाता है, बुनियादी ब्लॉकों के बीच मूल्यों के प्रवाह को देखने में मदद करता है, और अनुकूलन भी प्रदान करता है। डीएजी बुनियादी ब्लॉकों पर आसान परिवर्तन प्रदान करता है। डीएजी को यहां समझा जा सकता है:
लीफ नोड्स पहचानकर्ता, नाम या स्थिरांक का प्रतिनिधित्व करते हैं।
आंतरिक नोड्स ऑपरेटरों का प्रतिनिधित्व करते हैं।
आंतरिक नोड भी अभिव्यक्तियों या पहचानकर्ताओं / नाम के परिणामों का प्रतिनिधित्व करते हैं जहां मूल्यों को संग्रहीत या सौंपा जाना है।
Example:
t0 = a + b
t1 = t0 + c
d = t0 + t1
[t 0 = a + b] |
[t 1 = t 0 + c] |
[डी = टी ० + टी १ ] |
पीपहोल अनुकूलन
यह अनुकूलन तकनीक स्थानीय रूप से स्रोत कोड पर काम करती है ताकि इसे एक अनुकूलित कोड में बदल सके। स्थानीय स्तर पर, हमारा मतलब कोड ब्लॉक का एक छोटा सा हिस्सा है। इन विधियों को मध्यवर्ती कोड के साथ-साथ लक्ष्य कोड पर भी लागू किया जा सकता है। बयानों के एक समूह का विश्लेषण किया जाता है और निम्नलिखित संभावित अनुकूलन के लिए जाँच की जाती है:
निरर्थक निर्देश उन्मूलन
स्रोत कोड स्तर पर, उपयोगकर्ता द्वारा निम्नलिखित किया जा सकता है:
|
|
|
|
संकलन के स्तर पर, कंपाइलर प्रकृति में निरर्थक निर्देशों की खोज करता है। निर्देशों का एकाधिक लोडिंग और भंडारण एक ही अर्थ ले जा सकता है, भले ही उनमें से कुछ को हटा दिया जाए। उदाहरण के लिए:
- MOV x, R0
- MOV R0, R1
हम पहले निर्देश को हटा सकते हैं और इस वाक्य को फिर से लिख सकते हैं:
MOV x, R1
अगम्य संकेत
अगम्य कोड प्रोग्राम कोड का एक हिस्सा है जो प्रोग्रामिंग कंस्ट्रक्शन के कारण कभी एक्सेस नहीं किया जाता है। प्रोग्रामर ने अकस्मात कोड का एक टुकड़ा लिखा हो सकता है जो कभी नहीं पहुंच सकता है।
Example:
void add_ten(int x)
{
return x + 10;
printf(“value of x is %d”, x);
}
इस कोड सेगमेंट में, printf बयान को कभी भी निष्पादित नहीं किया जाएगा क्योंकि इससे पहले कि कार्यक्रम नियंत्रण वापस आ जाए, इसलिए printf हटाया जा सकता है।
नियंत्रण अनुकूलन का प्रवाह
ऐसे कोड में उदाहरण हैं जहां प्रोग्राम नियंत्रण किसी भी महत्वपूर्ण कार्य को निष्पादित किए बिना आगे और पीछे कूदता है। इन जंपों को हटाया जा सकता है। कोड के निम्नलिखित भाग पर विचार करें:
...
MOV R1, R2
GOTO L1
...
L1 : GOTO L2
L2 : INC R1
इस कोड में, लेबल L1 को हटाया जा सकता है क्योंकि यह L2 पर नियंत्रण से गुजरता है। इसलिए L1 और फिर L2 पर जाने के बजाय नियंत्रण सीधे L2 तक पहुंच सकता है, जैसा कि नीचे दिखाया गया है:
...
MOV R1, R2
GOTO L2
...
L2 : INC R1
बीजगणितीय अभिव्यक्ति सरलीकरण
ऐसे अवसर हैं जहां बीजीय अभिव्यक्तियों को सरल बनाया जा सकता है। उदाहरण के लिए, अभिव्यक्तिa = a + 0 द्वारा प्रतिस्थापित किया जा सकता है a खुद और अभिव्यक्ति a = a + 1 को केवल INC a द्वारा प्रतिस्थापित किया जा सकता है।
ताकत में कमी
ऐसे ऑपरेशन होते हैं जो अधिक समय और स्थान का उपभोग करते हैं। कम समय और स्थान का उपभोग करने वाले अन्य कार्यों के साथ प्रतिस्थापित करके उनकी 'शक्ति' को कम किया जा सकता है, लेकिन वही परिणाम उत्पन्न करते हैं।
उदाहरण के लिए, x * 2 द्वारा प्रतिस्थापित किया जा सकता है x << 1, जिसमें केवल एक ही बाईं पारी शामिल है। यद्यपि एक * a और 2 का आउटपुट समान है, एक 2 को लागू करने के लिए बहुत अधिक कुशल है।
पहुँच मशीन निर्देश
लक्ष्य मशीन अधिक परिष्कृत निर्देशों को तैनात कर सकती है, जिसमें विशिष्ट संचालन को बहुत कुशलता से करने की क्षमता हो सकती है। यदि लक्ष्य कोड उन निर्देशों को सीधे समायोजित कर सकता है, जो न केवल कोड की गुणवत्ता में सुधार करेगा, बल्कि अधिक कुशल परिणाम भी देगा।
कोड जनरेटर
एक कोड जनरेटर से लक्ष्य मशीन के रनटाइम वातावरण और उसके अनुदेश सेट की समझ होनी चाहिए। कोड जनरेटर को कोड उत्पन्न करने के लिए निम्नलिखित बातों पर ध्यान देना चाहिए:
Target language: कोड जनरेटर को लक्ष्य भाषा की प्रकृति के बारे में पता होना चाहिए जिसके लिए कोड को बदलना है। वह भाषा कुछ मशीन-विशिष्ट निर्देशों की सुविधा दे सकती है ताकि कंपाइलर को अधिक सुविधाजनक तरीके से कोड उत्पन्न करने में मदद मिल सके। लक्ष्य मशीन में CISC या RISC प्रोसेसर आर्किटेक्चर हो सकते हैं।
IR Type: मध्यवर्ती प्रतिनिधित्व के विभिन्न रूप हैं। यह सार सिंटेक्स ट्री (एएसटी) संरचना, रिवर्स पोलिश नोटेशन, या 3-एड्रेस कोड में हो सकता है।
Selection of instruction: कोड जनरेटर इंटरमीडिएट रिप्रजेंटेशन को इनपुट के रूप में लेता है और इसे (मैप्स) टारगेट मशीन के इंस्ट्रक्शन सेट में बदल देता है। एक निरूपण में इसे परिवर्तित करने के कई तरीके (निर्देश) हो सकते हैं, इसलिए कोड जनरेटर की जिम्मेदारी बन जाती है कि वह उचित निर्देशों को समझदारी से चुनें।
Register allocation: एक कार्यक्रम में निष्पादन के दौरान बनाए जाने वाले मूल्यों की संख्या होती है। लक्ष्य मशीन की वास्तुकला सीपीयू मेमोरी या रजिस्टरों में सभी मूल्यों को रखने की अनुमति नहीं दे सकती है। रजिस्टर जनरेटर तय करता है कि रजिस्टर में क्या मान रखें। इसके अलावा, यह इन मूल्यों को बनाए रखने के लिए उपयोग किए जाने वाले रजिस्टरों को तय करता है।
Ordering of instructions: अंत में, कोड जनरेटर उस क्रम को तय करता है जिसमें अनुदेश निष्पादित किया जाएगा। यह उन्हें निष्पादित करने के निर्देशों के लिए कार्यक्रम बनाता है।
वर्णनकर्ता
कोड जनरेटर को कोड जनरेट करते समय रजिस्टर (उपलब्धता के लिए) और पते (मूल्यों का स्थान) दोनों को ट्रैक करना होता है। उन दोनों के लिए, निम्नलिखित दो विवरणों का उपयोग किया जाता है:
Register descriptor: रजिस्टर विवरणक का उपयोग रजिस्टरों की उपलब्धता के बारे में कोड जनरेटर को सूचित करने के लिए किया जाता है। रजिस्टर डिस्क्रिप्टर प्रत्येक रजिस्टर में संग्रहीत मूल्यों का ट्रैक रखता है। जब भी कोड पीढ़ी के दौरान एक नया रजिस्टर आवश्यक होता है, तो यह विवरणक रजिस्टर उपलब्धता के लिए परामर्श किया जाता है।
Address descriptor: कार्यक्रम में उपयोग किए जाने वाले नामों (पहचानकर्ताओं) के मूल्यों को निष्पादन के समय विभिन्न स्थानों पर संग्रहीत किया जा सकता है। पता विवरणों का उपयोग मेमोरी स्थानों का ट्रैक रखने के लिए किया जाता है जहां पहचानकर्ताओं के मान संग्रहीत किए जाते हैं। इन स्थानों में सीपीयू रजिस्टर, ढेर, ढेर, मेमोरी या उल्लिखित स्थानों का संयोजन शामिल हो सकता है।
कोड जनरेटर वास्तविक समय में अपडेट किए गए दोनों डिस्क्रिप्टर को रखता है। लोड स्टेटमेंट के लिए, LD R1, x, कोड जनरेटर:
- x का मान दर्ज करने वाले डेस्क्रिप्टर R1 को अपडेट करता है और
- पता डिस्क्रिप्टर (x) को अद्यतन करने के लिए दिखाता है कि x का एक उदाहरण R1 में है।
कोड जनरेशन
बुनियादी ब्लॉकों में तीन-पते के निर्देशों का एक अनुक्रम शामिल है। कोड जनरेटर इन निर्देशों को इनपुट के रूप में लेता है।
Note: यदि किसी नाम का मान एक से अधिक स्थानों (रजिस्टर, कैश या मेमोरी) में पाया जाता है, तो रजिस्टर का मूल्य कैश और मुख्य मेमोरी के ऊपर पसंद किया जाएगा। इसी तरह कैशे का मूल्य मुख्य मेमोरी पर पसंद किया जाएगा। मुख्य मेमोरी को मुश्किल से कोई वरीयता दी जाती है।
getReg: कोड जनरेटर उपलब्ध रजिस्टरों की स्थिति और नाम मूल्यों के स्थान को निर्धारित करने के लिए getReg फ़ंक्शन का उपयोग करता है । getReg निम्नानुसार काम करता है:
यदि चर Y पहले से ही R रजिस्टर में है, तो यह उस रजिस्टर का उपयोग करता है।
कुछ रजिस्टर R उपलब्ध होने पर, यह उस रजिस्टर का उपयोग करता है।
वरना यदि उपरोक्त दोनों विकल्प संभव नहीं हैं, तो यह एक रजिस्टर चुनता है जिसमें न्यूनतम संख्या में लोड और स्टोर निर्देशों की आवश्यकता होती है।
एक निर्देश x = y OP z के लिए, कोड जनरेटर निम्नलिखित क्रियाएं कर सकता है। आइए मान लेते हैं कि L वह स्थान है (अधिमानतः रजिस्टर) जहां y OP z का आउटपुट सहेजा जाना है:
कॉल फ़ंक्शन getReg, L का स्थान तय करने के लिए।
वर्तमान स्थान (रजिस्टर या मेमोरी) का निर्धारण करें y के एड्रेस डिस्क्रिप्टर से परामर्श करके y। अगरy वर्तमान में रजिस्टर में नहीं है L, तब के मूल्य को कॉपी करने के लिए निम्न निर्देश उत्पन्न करें y सेवा L:
एमओवी वाई ', एल
कहाँ पे y’ के कॉपी किए गए मूल्य का प्रतिनिधित्व करता है y।
का वर्तमान स्थान निर्धारित करें z उसी विधि का उपयोग करने के लिए चरण 2 में उपयोग किया जाता है y और निम्नलिखित निर्देश उत्पन्न करें:
ओपी z ', एल
कहाँ पे z’ के कॉपी किए गए मूल्य का प्रतिनिधित्व करता है z।
अब L में y ओपी z का मान सम्मिलित है, जिसका उद्देश्य असाइन किया जाना है x। इसलिए, यदि L एक रजिस्टर है, तो उसके डिस्क्रिप्टर को यह इंगित करने के लिए अपडेट करें कि उसमें मूल्य हैx। के डिस्क्रिप्टर को अपडेट करेंx यह इंगित करने के लिए कि यह स्थान पर संग्रहीत है L।
यदि y और z का कोई और उपयोग नहीं है, तो उन्हें सिस्टम में वापस दिया जा सकता है।
अन्य कोड निर्माण जैसे छोरों और सशर्त बयानों को सामान्य भाषा में विधानसभा भाषा में रूपांतरित किया जाता है।