पूंछ कॉल अनुकूलन (TCO) के साथ प्रयोग, मैं निम्नलिखित उत्सुक उदाहरण पर ठोकर खाई:जीसीसी एक संस्करण के लिए पूंछ कॉल अनुकूलन क्यों करता है लेकिन दूसरे के लिए नहीं?
unsigned long long int fac1(unsigned long long int n){
if (n==0)
return 1;
return n*fac1(n-1);
}
वास्तव में, मैं बहुत प्रभावित थे, कि gcc was able (-O2
ध्वज के साथ) यहाँ TCO प्रदर्शन करने के लिए है, क्योंकि यह नहीं है कि सीधे आगे:
fac1(unsigned long long):
testq %rdi, %rdi
movl $1, %eax
je .L4
.L3:
imulq %rdi, %rax
subq $1, %rdi
jne .L3
rep ret
.L4:
rep ret
हालांकि, unsigned long long int
unsigned int
करने से वापसी प्रकार में परिवर्तन के बाद जीसीसी नहीं Tlo प्रदर्शन करने में सक्षम था
हम स्पष्ट रूप से resulting assembly में पुनरावर्ती कॉल देख सकते हैं:
fac2(unsigned long long):
testq %rdi, %rdi
jne .L16
movl $1, %eax
ret
.L16:
pushq %rbx
movq %rdi, %rbx
leaq -1(%rdi), %rdi
call fac2(unsigned long long)
imull %ebx, %eax
popq %rbx
ret
सबसे पहले, मैं एक चूक अनुकूलन के रूप में इस को खारिज कर दिया, लेकिन अब मैं, कि यकीन नहीं है क्योंकि clang isn't able रूप में अच्छी तरह इस अनुकूलन प्रदर्शन करने के लिए । तो हो सकता है कि उस भाषा की सूक्ष्मताएं हैं जिनके बारे में मुझे पता नहीं है, इस अनुकूलन को रोकें।
फ़ंक्शन fac2
फ़ंक्शन के लिए पूंछ-कॉल-ऑप्टिमाइज़ेशन क्यों नहीं करता है, लेकिन केवल fac1
के लिए?
यह मेरे लिए स्पष्ट है, कि दूसरे संस्करण में, परिणाम downcasted किया जाना चाहिए। जाहिर है यह एकमात्र अंतर है। लेकिन यह एक समस्या क्यों होनी चाहिए और टलो को रोकना चाहिए?
उदाहरण के लिए, अगर मैं संकलक मदद और एक क्लासिक पूंछ-प्रत्यावर्तन के रूप में मेरे समारोह को फिर से लिखने (संस्करण fac2
के समान परिणाम चाहिए):
unsigned int tlo_fac(unsigned long long int n, unsigned long long int cur){
if (n==0)
return cur;
return tlo_fac(n-1, n*cur);
}
unsigned int fac(unsigned long long int n){
return tlo_fac(n,1);
}
मैं एक Tlo-अनुकूलित संस्करण जो identical to fac1
है मिल (उच्च 32 बिट allowed to contain garbage हैं, इसलिए imulq
इनलाइनिंग के बाद इस्तेमाल किया जा सकता):
fac(unsigned long long):
testq %rdi, %rdi
movl $1, %eax
je .L10
.L11:
imulq %rdi, %rax
subq $1, %rdi
jne .L11
.L10:
rep ret
हो सकता है क्योंकि वहाँ डाली है 'बदले में की जरूरत n * fac2 (n-1),' 'fact2 करने के लिए कॉल के बाद (n-1) ' –
@ गौरावसेगल लेकिन यह कलाकार क्यों रोक देगा? – ead
क्योंकि रिकर्सन गहराई का विश्लेषण करने के बाद कास्ट किया जाएगा। अगर आप पैरामीटर को 'fact2 (unisnged int n)' में बदलते हैं, तो आपको ऑप्टिमाइज़ेशन मिल जाएगा। –