2010-09-22 9 views
6

मैं एक कोर्स के लिए एक कंपाइलर लिख रहा हूं। मैंने कुछ ऑप्टिमाइज़ेशन मुद्दों में भाग लिया है जिनमें से मुझे यकीन है कि कैसे बेहतर तरीके से संभालना है। मान लें कि इनपुट भाषा से थोड़ी देर लूप है जो एन स्थानीय चर का उपयोग करता है जो रजिस्टरों में आयोजित किया जाना चाहिए (या, तेजी से गणना के लिए होना चाहिए)। मान लीजिए एन> के, रजिस्टरों की संख्या। जबकि लूप के अंत में सशर्त रजिस्टर बदलना एक मौका है।कंपाइलर कोड पीढ़ी - सशर्त ब्लॉक के अंदर आवंटन पंजीकृत करें

उदाहरण के लिए, एक्स के लिए रजिस्टर लगता से पहले निर्धारित किया गया था निम्न कथन (मान लीजिए कि i386 पर% eax हैं):

while (x) { x = x - 1 ; /* more statements */ } 

अधिक बयानों कोड में, यह संभव है x गिरा किए जाने के लिए ढेर पर वापस। जब कोड एक्स का फिर से मूल्यांकन करने के लिए लूप की शुरुआत में वापस कूदता है, तो यह% eax का उपयोग करने का प्रयास करेगा - लेकिन यह अब x का मान भी नहीं रख सकता है। तो हम जैसे

 movl -8(%ebp), %eax  # eax <- x 
     ....      # do stuff but let x stay in %eax 
_LOOP1: cmpl $0, %eax 
     .... 
     movl -12(%ebp), %eax  #eax now holds something else 
     .... 
     jmp _LOOP1 

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

 movl -8(%ebp), %eax  # eax <- x 
     ....      # do stuff but let x stay in %eax 
     movl %eax, -8(%ebp)  # spilling and clearing all registers 
_LOOP1: movl -8(%ebp), %eax  # get a register for x again 
     cmpl $0, %eax 
     .... 
     movl -12(%ebp), %eax  # eax now holds something else 
     .... 
     movl %eax, -8(%ebp)  # spill to prevent overwrite 
     jmp _LOOP1 

ऐसा लगता है मेरी समाधान की तरह एक छोटे से बाहरी या अनावश्यक है:

मेरे समाधान कुछ इस तरह है। क्या कोई सामान्य अनुकूलन चाल है जो मैं यहां भूल रहा हूं?

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

उत्तर

4

सामान्य तकनीक जिसे आप यहां खोज रहे हैं उसे आमतौर पर "लाइव रेंज स्प्लिटिंग" कहा जाता है। उस अवधि के लिए Google Search आपको विभिन्न कागजात के समूह को पॉइंटर्स देगा। असल में विचार यह है कि आप अलग-अलग चर में एक एकल चर (आपके उदाहरण में एक्स) को विभाजित करना चाहते हैं, जिसमें अलग-अलग लाइव श्रेणियां होती हैं जिनमें से प्रत्येक को विभाजन बिंदु पर अगली बार कॉपी किया जाता है। तो आपके पास लूप से पहले x.0 होगा, जिसे while से पहले x.1 में कॉपी किया गया है और लूप में इसका उपयोग किया जाता है। फिर लूप के ठीक बाद, आप x.1 को x.2 में कॉपी करेंगे और लूप के बाद इसका उपयोग करेंगे। प्रत्येक स्प्लिट वर्र्स को संभावित रूप से एक अलग रजिस्टर (या स्टैक स्लॉट) में आवंटित किया जाएगा।

यहां बहुत सारे ट्रेडऑफ हैं - कोड में बहुत अधिक विभाजन (कई) अधिक चर होते हैं, जिससे पंजीकरण आवंटन बहुत धीमा हो जाता है, और संभावित रूप से अनावश्यक प्रतियां होती हैं।

+0

मेरे पास अभी तक देखने के लिए अधिक समय नहीं है, लेकिन ऐसा लगता है कि अतिरिक्त जटिलता की लागत पर प्रदर्शन में बहुत कम लाभ है? – Kizaru

+0

संकलित किए जाने वाले कोड (सभी कंपाइलर अनुकूलन के साथ) के आधार पर होने वाला लाभ काफी भिन्न होता है। बहुत कम अनुकूलन कुल मिलाकर कुछ प्रतिशत से अधिक कोड की गति को प्रभावित करते हैं। –

+0

धन्यवाद। मैंने बक्षीस से सम्मानित किया। मेरा मतलब था कि जब मैंने अपनी पहली टिप्पणी पोस्ट की। कुछ परीक्षण मामलों के बाद, अनुकूलन वास्तव में न्यूनतम है (i386 के लिए)। मुझे उम्मीद है कि यह एमआईपीएस जैसे आर्किटेक्चर पर उपयोगी होगा। – Kizaru