एलएलवीएम एक निरर्थक चर क्यों आवंटित करता है?


9

यहाँ एक एनुम परिभाषा और एक mainफ़ंक्शन के साथ एक सरल सी फ़ाइल है:

enum days {MON, TUE, WED, THU};

int main() {
    enum days d;
    d = WED;
    return 0;
}

यह निम्नलिखित एलएलवीएम आईआर को प्रेषित करता है:

define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 2, i32* %2, align 4
  ret i32 0
}

%2स्पष्ट रूप से dचर है, जो इसे 2 को सौंपा गया है। %1यदि शून्य सीधे लौटाया जाता है तो क्या होता है?


1
इस IR को बनाने के लिए आपने किन झंडे का इस्तेमाल किया?
तीर

@arrowd, मैंने नवीनतम स्थिर LLVM सुइट स्थापित किया और भाग गयाclang-9 -S -emit-llvm simple.c
मैकलगिन

1
मुझे लगता है कि इससे पहले main( godbolt.org/z/kEtS-s ) आरंभीकरण के साथ कुछ करना है । लिंक से पता चलता है कि विधानसभा को स्रोत पर कैसे मैप किया जाता है
प्रदीप कुमार

2
@PeepeepKumar: वास्तव में, यदि आप फ़ंक्शन का नाम किसी अन्य चीज़ के अलावा बदलते हैं main, तो रहस्यमय अतिरिक्त चर गायब हो जाता है। दिलचस्प है, यह भी गायब हो जाता है यदि आप returnकथन को पूरी तरह से छोड़ देते हैं (जो कि mainसी के लिए कानूनी है और समकक्ष है return 0;)।
नैट एल्ड्रेडज

1
@macleginn: मुझे इतना यकीन नहीं है। यदि आप घोषणा करते हैं mainकि int main(int argc, char **argv)आप देखते हैं argcऔर argvस्टैक पर प्रतिलिपि बनाई गई है, लेकिन रहस्यमय शून्य चर अभी भी उनके अलावा है।
नैट एल्ड्रेडज

जवाबों:


3

यह %1रजिस्टर एक फ़ंक्शन में कई रिटर्न स्टेटमेंट को संभालने के लिए क्लैंग द्वारा उत्पन्न किया गया था । कल्पना कीजिए कि आपके पास पूर्णांक के भाज्य की गणना करने के लिए एक फ़ंक्शन था। इस तरह लिखने के बजाय

int factorial(int n){
    int result;
    if(n < 2)
      result = 1;
    else{
      result = n * factorial(n-1);
    }
    return result;
}

आप शायद ऐसा करेंगे

int factorial(int n){
    if(n < 2)
      return 1;
    return n * factorial(n-1);
}

क्यों? क्योंकि क्लैंग उस resultचर को सम्मिलित करेगा जो आपके लिए रिटर्न वैल्यू रखता है। वाह। यही इसका सटीक उद्देश्य है %1। अपने कोड के थोड़ा संशोधित संस्करण के लिए इर को देखें।

संशोधित कोड,

enum days {MON, TUE, WED, THU};

int main() {
    enum days d;
    d = WED;
    if(d) return 1;
    return 0;
}

आईआर,

define dso_local i32 @main() #0 !dbg !15 {
    %1 = alloca i32, align 4
    %2 = alloca i32, align 4
    store i32 0, i32* %1, align 4
    store i32 2, i32* %2, align 4, !dbg !22
    %3 = load i32, i32* %2, align 4, !dbg !23
    %4 = icmp ne i32 %3, 0, !dbg !23
    br i1 %4, label %5, label %6, !dbg !25

 5:                                                ; preds = %0
   store i32 1, i32* %1, align 4, !dbg !26
   br label %7, !dbg !26

 6:                                                ; preds = %0
  store i32 0, i32* %1, align 4, !dbg !27
  br label %7, !dbg !27

 7:                                                ; preds = %6, %5
  %8 = load i32, i32* %1, align 4, !dbg !28
  ret i32 %8, !dbg !28
}

अब आप देखते हैं कि %1खुद को उपयोगी बनाना है? जैसा कि अन्य लोगों ने बताया है, केवल एक रिटर्न स्टेटमेंट वाले कार्यों के लिए, यह चर शायद llvm के आशा पास में से एक द्वारा छीन लिया जाएगा।


1

यह क्यों मायने रखता है - वास्तविक समस्या क्या है?

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

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


1

क्योंकि Clang सिंटैक्स विश्लेषण के साथ किया जाता है, लेकिन LLVM ने अनुकूलन के साथ भी शुरू नहीं किया है।

क्लैंग फ्रंट एंड ने IR (इंटरमीडिएट रिप्रेजेंटेशन) जेनरेट किया है और मशीन कोड नहीं। वे चर एसएसएएस (एकल स्टेटिक असाइनमेंट) हैं; वे अभी तक रजिस्टर करने के लिए बाध्य नहीं हुए हैं और वास्तव में अनुकूलन के बाद, कभी नहीं होंगे क्योंकि वे निरर्थक हैं।

यह कोड स्रोत का कुछ हद तक शाब्दिक प्रतिनिधित्व है। यह वही है जो अनुकूलन के लिए एलएलवीएम से जुड़ा हुआ है। मूलतः, LLVM उसी के साथ शुरू होता है और वहां से अनुकूलन करता है। दरअसल, संस्करण 10 और x86_64 के लिए, llc -O2 अंततः उत्पन्न होगा:

main: # @main
  xor eax, eax
  ret

मैं इस स्तर पर प्रक्रिया को समझता हूं। मैं जानना चाहता था कि इस IR को शुरू करने के लिए क्यों उत्पन्न किया गया था।
मैकलिनिन

आप एक संकलक के बारे में सोच रहे होंगे। क्लैंग फ्रंट एंड से शुरू होने वाले पास की एक पाइपलाइन है जो आईआर उत्पन्न करता है। यह इस शाब्दिक IR को उत्पन्न नहीं करता था, जिसके बजाय किसी ने clang -emit-llvm -S file.cpp के साथ अनुरोध किया था। Clang ने वास्तव में IR का एक द्विआधारी क्रमिक बिटकोड संस्करण उत्पन्न किया था। एलएलवीएम को कई पास के रूप में संरचित किया जाता है, जिनमें से प्रत्येक आईआर को लेते और अनुकूलित करते हैं। पहला LLVM पास IR को क्लैंग से लेता है। यह IR लेता है क्योंकि आप उसी ऑप्टिमाइज़र + कोड जनरेटर के साथ किसी अन्य भाषा का समर्थन करने के लिए Clang को Fortran FE के साथ बदल सकते हैं।
ऑलसनिस्ट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.