क्यों जीसीसी संकलक कुछ कोड को छोड़ रहा है?


9

मुझे समझ नहीं आ रहा है कि जीसीसी संकलक मेरे कोड का हिस्सा क्यों काट रहा है जबकि यह पड़ोस में बिल्कुल एक ही है?

सी कोड:

#define setb_SYNCO do{(PORTA|= (1<<0));} while(0);

ISR(INT0_vect){
    unsigned char i;

    i = 10;
    while(i>0)i--;   // first pause - omitted

    setb_SYNCO;
    setb_GATE;
    i=30;
    clrb_SYNCO;
    while(i>0)i--;  // second pause - preserved
    clrb_GATE;
}

LSS का संगत हिस्सा (कंपाइलर द्वारा बनाई गई कोडांतरक फ़ाइल):

ISR(INT0_vect){
  a4:   1f 92           push    r1
  a6:   0f 92           push    r0
  a8:   0f b6           in  r0, 0x3f    ; 63
  aa:   0f 92           push    r0
  ac:   11 24           eor r1, r1
  ae:   8f 93           push    r24
    unsigned char i;

    i = 10;
    while(i>0)i--;

    setb_SYNCO;
  b0:   d8 9a           sbi 0x1b, 0 ; 27
    setb_GATE;
  b2:   d9 9a           sbi 0x1b, 1 ; 27
    i=30;
    clrb_SYNCO;
  b4:   d8 98           cbi 0x1b, 0 ; 27
  b6:   8e e1           ldi r24, 0x1E   ; 30
  b8:   81 50           subi    r24, 0x01   ; 1
    while(i>0)i--;
  ba:   f1 f7           brne    .-4         ; 0xb8 <__vector_1+0x14>
    clrb_GATE;
  bc:   d9 98           cbi 0x1b, 1 ; 27
}
  be:   8f 91           pop r24
  c0:   0f 90           pop r0
  c2:   0f be           out 0x3f, r0    ; 63
  c4:   0f 90           pop r0
  c6:   1f 90           pop r1
  c8:   18 95           reti

मुझे लगता है कि संकलक यह पता लगा सकता है कि ऐसा कोड डमी है और इसे काट देता है, लेकिन यह कोड के अंत में उसी को संरक्षित क्यों करता है?

क्या इस तरह के अनुकूलन से बचाव के लिए कोई संकलक निर्देश है?


1
आप किसी एकल फ़ंक्शन का अनुकूलन नहीं करने के लिए कंपाइलर को भी बता सकते हैं, हो सकता है कि यह विधि आपके ISR के साथ आज़माए। स्टैकओवरफ़्लो पर यह प्रश्न देखें ।
व्लादिमीर क्रेवरो

2
हे रोमन, मैंने आपके प्रश्न में "c" टैग जोड़ा है जो atmega को हटा रहा है। मुझे एक टैग को हटाना पड़ा क्योंकि एक सीमा (पाँच) है, और जब एक कोड से संबंधित प्रश्न पूछते हैं तो भाषा का नाम एक टैग के रूप में महान होता है क्योंकि सभी कोड (क्यू एंड अस) हाइलाइट हो जाते हैं।
व्लादिमीर क्रैवरो

5
सामान्यतया, उच्च स्तरीय भाषाओं (जैसे सी) को स्पष्ट रूप से उनके परिणामस्वरूप विधानसभा के साथ 1: 1 संबंध के लिए बाध्य नहीं किया जाता है। यदि आपको समय सही पाने के लिए निर्देशों को गिनने की आवश्यकता है, तो आपको हमेशा असेंबली पर निर्भर रहना होगा (जैसा कि कुछ उत्तरों ने किया था)। उच्च स्तर की भाषाओं का संपूर्ण बिंदु यह है कि संकलक को अपने कोड को पहले से अधिक मजबूत-बेहतर बनाने में मदद करने के लिए कुछ स्वतंत्रता है। रजिस्टर आवंटन और शाखा भविष्यवाणियों जैसे विवरण संकलक के लिए बहुत बेहतर हैं ... इस तरह के समय में जहां आप, प्रोग्रामर को छोड़कर, बिल्कुल वही निर्देश जानिए जो आप चाहते हैं।
Cort Ammon

5
बेहतर सवाल यह है कि जीसीसी उन दोनों छोरों का अनुकूलन क्यों नहीं कर रहा है ?
इल्मरी करोनें

5
Gcc पहले लूप को अनियंत्रित करता है और केवल तब ही नोटिस करता है कि संबंधित कोड बेकार है। 30 के लूप साइज के साथ, अनरोल करना मूर्खतापूर्ण होगा और gcc ऐसा नहीं करता है। उच्च अनुकूलन स्तर पर दोनों को अनुकूलित किया जाता है।
मार्क ग्लिसे

जवाबों:


9

चूंकि एक टिप्पणी में आप कहते हैं कि "प्रत्येक सीपीयू टिक योग्य है" तो मैं सुझाव देता हूं कि आप जिस तरह से चाहते हैं, वैसे ही आपके विलंब लूप को बनाने के लिए कुछ इनलाइन असेंबली का उपयोग करें। यह समाधान विभिन्न से बेहतर है volatileया -O0क्योंकि यह स्पष्ट करता है कि आपका इरादा क्या है।

unsigned char i = 10;
__asm__ volatile ( "loop: subi    %0, 0x01\n\t"
                   "      brne    loop"
                   : "+rm" (i)
                   : /* no inputs */
                   : /* no dirty registers to decleare*/);

यह ट्रिक काम आना चाहिए। संकलक को यह बताने के लिए अस्थिरता है "मुझे पता है कि यह कुछ भी नहीं करता है, बस इसे बनाए रखें और मुझ पर विश्वास करें"। तीन asm "स्टेटमेंट" काफी आत्म व्याख्यात्मक हैं, आप r24 के बजाय किसी भी रजिस्टर का उपयोग कर सकते हैं, मेरा मानना ​​है कि कंपाइलर कम रजिस्टरों को पसंद करता है इसलिए आप एक उच्च का उपयोग करना चाह सकते हैं। पहले के बाद :आपको c वेरिएबल्स में आउटपुट (पढ़ना और लिखना) सूचीबद्ध करना चाहिए, और कोई नहीं है, दूसरे के बाद :आपको इनपुट (रॉनली) c वेरिएबल्स को सूचीबद्ध करना चाहिए, फिर से, कोई नहीं है, और तीसरा पैरामीटर संशोधित रजिस्टरों की अल्पविराम से अलग की गई सूची है , इस मामले में r24। मुझे यकीन नहीं है कि यदि आप निश्चित रूप से ZEROध्वज परिवर्तन के बाद से स्थिति रजिस्टर को भी शामिल करना चाहिए , तो मैंने इसे शामिल नहीं किया।

संपादित उत्तर को ओपी अनुरोध के रूप में संपादित करें । कुछ नोट।

"+rm"पहले (i)का मतलब है कि आप संकलक दे रहे हैं में मैं जगह का फैसला मीटर एमोरी या एक में आर egister। यह ज्यादातर मामलों में एक अच्छी बात है क्योंकि कंपाइलर मुफ्त में बेहतर कर सकता है। आपके मामले में मेरा मानना ​​है कि आप मुझे रजिस्टर करने के लिए बाध्य करने के लिए केवल आर बाधा रखना चाहते हैं।


लगता है कि यह एक ऐसी चीज है जिसकी मुझे वास्तव में जरूरत है। लेकिन क्या आप मूल उत्तर में उल्लिखित cशाब्दिक के बजाय किसी भी चर को स्वीकार करने के लिए अपने उत्तर को संशोधित कर सकते हैं 10? मैं asm निर्माण के उचित उपयोग के बारे में GCC मैनुअल पढ़ने की कोशिश कर रहा हूँ, लेकिन यह अब मेरे लिए थोड़ा अस्पष्ट है। मैं बहुत सराहना करूंगा!
रोमन मटेव

1
@RomanMatveev ने आपके अनुरोध के अनुसार संपादन किया
व्लादिमीर क्रावेरो

13

आप पाश बनाने की कोशिश कर सकते हैं वास्तव में कुछ करते हैं। जैसा कि यह खड़ा है संकलक काफी सही कह रहा है "यह लूप कुछ नहीं कर रहा है - मैं इससे छुटकारा पाऊंगा"।

तो आप एक निर्माण की कोशिश कर सकते हैं जिसका मैं अक्सर उपयोग करता हूं:

int i;
for (i = 0; i < 10; i++) {
    asm volatile ("nop");
}

नोट: gcc संकलक के लिए सभी लक्ष्य समान इनलाइन असेंबली सिंटैक्स का उपयोग नहीं करते हैं - आपको इसे अपने लक्ष्य के लिए ट्वीक करने की आवश्यकता हो सकती है।


आपका समाधान मेरी तुलना में अधिक सुरुचिपूर्ण लगता है ... शायद मेरा बेहतर है जब PRECISE चक्र गणना की आवश्यकता होती है? मेरा मतलब है, पूरी चीज़ को एक निश्चित तरीके से संकलित करने की गारंटी नहीं है, क्या यह है?
व्लादिमीर क्रेवरो

8
C का उपयोग करने वाला साधारण तथ्य यह है कि आप साइकिल की गारंटी नहीं दे सकते। यदि आपको सटीक चक्र गणना की आवश्यकता है, तो एएसएम एकमात्र रास्ता है। मेरा मतलब है, अगर आपके पास -Funroll-loops से सक्षम नहीं है, तो आप C आदि के साथ अलग-अलग समय प्राप्त करते हैं, आदि
Majenko

हां मैंने भी यही सोचा था। जब एचडब्ल्यू पर्याप्त रूप से उच्च मान के साथ देरी करता है (100 या अधिक) मुझे लगता है कि आपके समाधान से पठनीयता को बढ़ाते हुए लगभग समान परिणाम मिलते हैं।
व्लादिमीर क्रैवेरो

6

हाँ आप मान सकते हैं। यदि आप वैरिएबल के रूप में वैरिएबल घोषित करते हैं, तो आप संकलक को बताते हैं कि मैं इस पर अनुकूलन नहीं करता।


1
यह मेरी राय में पूरी तरह से सच नहीं है।
व्लादिमीर क्रैवेरो

1
@ व्लादिमीरक्रावेरो, आपके कहने का क्या मतलब है? क्या आप और अधिक स्पष्ट कर सकते हैं?
रोमन मतवेव

2
मेरे कहने का मतलब यह है कि मैं इस बात को लेकर निश्चित नहीं हूं कि एक कंपाइलर क्या करता है। एक चर अस्थिर घोषित करते हुए संकलक को बताता है कि यह कहीं और बदल सकता है इसलिए इसे वास्तव में ऐसा करना चाहिए।
व्लादिमीर क्रेवरो

1
@ रोमान माटवेव register unsigned char volatile i __asm__("r1");शायद?
a3f

2
iअस्थिर के रूप में घोषणा करना सब कुछ हल करता है। यह सी मानक 5.1.2.3 द्वारा गारंटीकृत है। एक अनुरूप संकलक उन छोरों को अनुकूलित नहीं करना चाहिए यदि iअस्थिर है। सौभाग्य से, जीसीसी एक अनुरूप संकलक है। दुर्भाग्य से कई सी-कंपाइलर होंगे जो मानक के अनुरूप नहीं हैं, लेकिन इस विशेष प्रश्न के लिए यह अप्रासंगिक है। इनलाइन असेंबलर की बिल्कुल जरूरत नहीं है।
लुंडिन

1

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

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

मुझे लगता है कि जीसीसी iविशुद्ध रूप से इस कारण से है कि आप एक (अपारदर्शी) पोर्ट का उपयोग प्रभावित कर सकते हैं i

उपयोग

asm volatile ("nop");

GCC को यह विश्वास दिलाने के लिए कि पाश कुछ करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.