समस्या आपको लगता है कि कोड के अनुकूलन के साथ मिलता है:
08000328 <mul_test01>:
8000328: f04f 5000 mov.w r0, #536870912 ; 0x20000000
800032c: 4770 bx lr
800032e: bf00 nop
अपने कोड does not कुछ क्रम ऐसा अनुकूलक सिर्फ अंतिम जवाब की गणना कर सकते हैं।
इस:
.thumb_func
.globl mul_test02
mul_test02:
smull r2,r3,r0,r1
mov r0,r3
bx lr
इस के साथ कहा जाता है:
c = mul_test02(0x40000000,0x40000000);
देता 0x10000000
UMULL ही परिणाम है क्योंकि आप सकारात्मक संख्या ऑपरेंड उपयोग कर रहे हैं, देता है और परिणाम इतना सब सकारात्मक रहे हैं यह हस्ताक्षरित/हस्ताक्षरित मतभेदों में नहीं मिलता है।
हम्म, ठीक है आप मुझे इस पर मिला है। मैं आपके कोड को 64 बिट तक गुणा करने के लिए संकलक कहने के रूप में पढ़ूंगा। स्मॉल दो 32 बिट ऑपरेशंस है जो 64 बिट परिणाम दे रहा है, जो आपके कोड के लिए नहीं पूछ रहा है .... लेकिन जीसीसी और क्लैंग दोनों ने धुंध का उपयोग किया, भले ही मैंने इसे एक अनिश्चित कार्य के रूप में छोड़ा, तो यह नहीं पता था समय संकलित करें कि ऑपरेटरों के पास 32 से ऊपर कोई महत्वपूर्ण अंक नहीं था, फिर भी उन्होंने धुंध का उपयोग किया।
शायद शिफ्ट कारण था।
यूप, यह था ..
int mul_test04 (int a, int b)
{
int c;
c = ((long long)a*b) >> 31;
return(c);
}
दोनों जीसीसी और बजना देता
08000340 <mul_test04>:
8000340: fb81 2300 smull r2, r3, r1, r0
8000344: 0fd0 lsrs r0, r2, #31
8000346: ea40 0043 orr.w r0, r0, r3, lsl #1
800034a: 4770 bx lr
(अच्छी तरह बजना बजाय R2 और R3 का उपयोग करने का r0 और r1 recycles) लेकिन इस
int mul_test04 (int a, int b)
{
int c;
c = ((long long)a*b);
return(c);
}
इस
देता है
जीसीसी:
08000340 <mul_test04>:
8000340: fb00 f001 mul.w r0, r0, r1
8000344: 4770 bx lr
8000346: bf00 nop
बजना: बिट
0800048c <mul_test04>:
800048c: 4348 muls r0, r1
800048e: 4770 bx lr
तो साथ बदलाव compilers महसूस करते हैं कि आप केवल परिणाम के ऊपरी हिस्से में रुचि रखते हैं तो वे ऑपरेंड के ऊपरी भाग को निरस्त कर सकते हैं जिसका अर्थ है smull कर सकते हैं इस्तेमाल किया गया।
अब आप ऐसा करते हैं, तो:
int mul_test04 (int a, int b)
{
int c;
c = ((long long)a*b) >> 32;
return(c);
}
दोनों compilers विशेष बजना में, यहां तक कि बेहतर हो जाते हैं:
0800048c <mul_test04>:
800048c: fb81 1000 smull r1, r0, r1, r0
8000490: 4770 bx lr
जीसीसी:
08000340 <mul_test04>:
8000340: fb81 0100 smull r0, r1, r1, r0
8000344: 4608 mov r0, r1
8000346: 4770 bx lr
मुझे लगता है कि के रूप में माना 0x40000000 देख सकते हैं एक फ्लोट जहां आप दशमलव स्थान का ट्रैक रखते हैं, और वह स्थान एक निश्चित स्थान है। 0x20000000 उत्तर के रूप में समझ में आता है। मैं अभी तक तय नहीं कर सकता कि 31 बिट शिफ्ट सार्वभौमिक रूप से काम करती है या सिर्फ इस मामले के लिए।
एक पूरा ऊपर के लिए इस्तेमाल किया उदाहरण यहाँ है
https://github.com/dwelch67/stm32vld/tree/master/stm32f4d/sample01
और मैं यह काम करता है और परिणामों की पुष्टि करने के लिए एक stm32f4 पर चला था।
संपादित करें:
आप के बजाय समारोह के भीतर उन्हें हार्डकोड के समारोह में पैरामीटर पास हैं:
int myfun (int a, int b)
{
return(a+b);
}
संकलक क्रम कोड के बजाय अनुकूलन संकलन समय पर जवाब बनाने के लिए मजबूर कर रहा है।
अब अगर आप हार्डकोडेड संख्या के साथ एक और समारोह से कि फ़ंक्शन को कॉल करें: इस बुला समारोह में
...
c=myfun(0x1234,0x5678);
...
संकलक जवाब गणना करने के लिए और बस संकलन समय पर वहाँ यह जगह चुन सकते हैं। यदि myfun() फ़ंक्शन वैश्विक है (स्थैतिक के रूप में घोषित नहीं किया गया है) तो संकलक को पता नहीं है कि बाद में कुछ अन्य कोड लिंक किए जाएंगे, इसलिए इस फ़ाइल में कॉल पॉइंट के पास भी यह एक उत्तर को अनुकूलित करता है जिसे अभी भी वास्तविक फ़ंक्शन का उत्पादन करना है और कॉल करने के लिए अन्य फ़ाइलों में अन्य कोड के लिए ऑब्जेक्ट में छोड़ दें, ताकि आप अभी भी जांच सकें कि उस सी कोड के साथ कंपाइलर/ऑप्टिमाइज़र क्या करता है। जब तक आप llvm का उपयोग उदाहरण के लिए नहीं करते हैं, जहां आप संपूर्ण प्रोजेक्ट (फाइलों में) को अनुकूलित कर सकते हैं, बाहरी कोड को कॉल करने से यह फ़ंक्शन वास्तविक फ़ंक्शन का उपयोग करेगा और संकलन समय गणना गणना नहीं करेगा।
दोनों जीसीसी और क्लैंग ने जो किया है, वह एक वैश्विक कार्य के रूप में फ़ंक्शन के लिए बाएं रनटाइम कोड है, लेकिन फ़ाइल के भीतर यह संकलन समय पर उत्तर की गणना करता है और फ़ंक्शन को कॉल करने के बजाय कोड में हार्डकोडेड उत्तर डालता है:
int mul_test04 (int a, int b)
{
int c;
c = ((long long)a*b) >> 31;
return(c);
}
एक ही फाइल में एक और समारोह में
:
hexstring(mul_test04(0x40000000,0x40000000),1);
समारोह में ही कोड में कार्यान्वित किया जाता है:
0800048c <mul_test04>:
800048c: fb81 1000 smull r1, r0, r1, r0
8000490: 0fc9 lsrs r1, r1, #31
8000492: ea41 0040 orr.w r0, r1, r0, lsl #1
8000496: 4770 bx lr
लेकिन जहां यह कहा जाता है कि वे इस सवाल का जवाब hardcoded है, क्योंकि वे सभी जानकारी ऐसा करने के लिए की जरूरत थी:
8000520: f04f 5000 mov.w r0, #536870912 ; 0x20000000
8000524: 2101 movs r1, #1
8000526: f7ff fe73 bl 8000210 <hexstring>
आप हार्डकोडेड जवाब आप एक समारोह है कि में नहीं है उपयोग करने की आवश्यकता नहीं चाहते हैं एक ही अनुकूलन पास।
कंपाइलर और ऑप्टिमाइज़र में हेरफेर करना बहुत अभ्यास में आता है और यह सटीक विज्ञान नहीं है क्योंकि कंपेलर और ऑप्टिमाइज़र लगातार विकसित होते हैं (बेहतर या बदतर के लिए)।
किसी फ़ंक्शन में कोड का एक छोटा सा कोड अलग करके आप किसी अन्य तरीके से समस्याएं पैदा कर रहे हैं, बड़े कार्यों को स्टैक फ्रेम की आवश्यकता होती है और रजिस्टरों से स्टैक तक वैरिएबल को बेदखल कर दिया जाता है, छोटे कार्यों को ऐसा करने की आवश्यकता नहीं होती है और अनुकूलक बदल सकते हैं कि परिणामस्वरूप कोड कैसे लागू किया जाता है। आप कोड खंड को एक तरीका देखने के लिए जांचते हैं कि संकलक क्या कर रहा है, फिर इसे एक बड़े फ़ंक्शन में उपयोग करें और नतीजे न प्राप्त करें। यदि निर्देशों का एक सटीक निर्देश या अनुक्रम है जिसे आप कार्यान्वित करना चाहते हैं .... उन्हें असेंबलर में लागू करें। यदि आप एक विशिष्ट निर्देश सेट/प्रोसेसर में निर्देशों के एक विशिष्ट सेट को लक्षित कर रहे थे तो गेम से बचें, जब आप कंप्यूटर/कंपाइलर्स/आदि बदलते हैं तो अपने कोड को बदलने से बचें, और उस लक्ष्य के लिए केवल असेंबलर का उपयोग करें। यदि आवश्यक हो तो ifdef या अन्यथा असेंबलर के बिना अलग-अलग लक्ष्यों के निर्माण के लिए सशर्त संकलन विकल्पों का उपयोग करें।
क्या आप ऑप्टिमाइज़ेशन के साथ संकलित हैं? यदि आपका कंपाइलर इष्टतम कोड उत्पन्न नहीं कर रहा है, तो आप एक छोटे असेंबली फ़ंक्शन को लिख सकते हैं या सी – TJD