2011-08-26 24 views
6

पर स्पिलिंग पंजीकरण मैं x86-64 असेंबली के साथ कुछ प्रयोग कर रहा हूं।जीसीसी तर्क पंजीकरण x86-64

long myfunc(long a, long b, long c, long d, 
      long e, long f, long g, long h) 
{ 
    long xx = a * b * c * d * e * f * g * h; 
    long yy = a + b + c + d + e + f + g + h; 
    long zz = utilfunc(xx, yy, xx % yy); 
    return zz + 20; 
} 
gcc -O0 -g मैं समारोह के विधानसभा की शुरुआत में निम्नलिखित आश्चर्य हुआ के साथ

: इस डमी समारोह संकलित करने के बाद

0000000000400520 <myfunc>: 
    400520:  55      push rbp 
    400521:  48 89 e5    mov rbp,rsp 
    400524:  48 83 ec 50    sub rsp,0x50 
    400528:  48 89 7d d8    mov QWORD PTR [rbp-0x28],rdi 
    40052c:  48 89 75 d0    mov QWORD PTR [rbp-0x30],rsi 
    400530:  48 89 55 c8    mov QWORD PTR [rbp-0x38],rdx 
    400534:  48 89 4d c0    mov QWORD PTR [rbp-0x40],rcx 
    400538:  4c 89 45 b8    mov QWORD PTR [rbp-0x48],r8 
    40053c:  4c 89 4d b0    mov QWORD PTR [rbp-0x50],r9 
    400540:  48 8b 45 d8    mov rax,QWORD PTR [rbp-0x28] 
    400544:  48 0f af 45 d0   imul rax,QWORD PTR [rbp-0x30] 
    400549:  48 0f af 45 c8   imul rax,QWORD PTR [rbp-0x38] 
    40054e:  48 0f af 45 c0   imul rax,QWORD PTR [rbp-0x40] 
    400553:  48 0f af 45 b8   imul rax,QWORD PTR [rbp-0x48] 
    400558:  48 0f af 45 b0   imul rax,QWORD PTR [rbp-0x50] 
    40055d:  48 0f af 45 10   imul rax,QWORD PTR [rbp+0x10] 
    400562:  48 0f af 45 18   imul rax,QWORD PTR [rbp+0x18] 

gcc बहुत अजीब फैल सभी तर्क ढेर पर पंजीकृत करता है और उसके बाद ले जाता है उन्हें आगे के संचालन के लिए स्मृति से।

यह केवल -O0 पर होता है (-O1 के साथ कोई समस्या नहीं है), लेकिन फिर भी, क्यों? यह मेरे लिए एंटी-ऑप्टिमाइज़ेशन जैसा दिखता है - gcc ऐसा क्यों करेगा?

+6

मुझे लगता है कि आप इसे पीछे की ओर ले सकते हैं। मुझे पूरा यकीन है कि उपर्युक्त यह है कि जीसीसी हमेशा (प्रारंभिक रूप से) कोड उत्पन्न करता है, यह केवल सामान्य रूप से इसे नहीं देखेगा क्योंकि इसे आसानी से अनुकूलित किया जाता है (लेकिन निश्चित रूप से केवल ऑप्टिमाइज़ेशन सक्षम होने पर ही)। – user786653

+0

यह विरोधी अनुकूलन नहीं है, यह सिर्फ कोई अनुकूलन नहीं है। – hirschhornsalz

+0

मैंने अभी यह उदाहरण कहीं देखा था: http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/ :-) –

उत्तर

7

मैं किसी भी तरह से जीसीसी आंतरिक विशेषज्ञ नहीं हूं, लेकिन मैं इसे एक शॉट दूंगा। दुर्भाग्य से जीसीसी के बारे में अधिकतर जानकारी आवंटन पंजीकृत करती है और स्पिलिंग पुरानी प्रतीत होती है (local-alloc.c जैसी फाइलों का संदर्भ देना जो अब मौजूद नहीं हैं)।

मैं gcc-4.5-20110825 का स्रोत कोड देख रहा हूं।

GNU C Compiler Internals में यह उल्लेख किया गया है कि प्रारंभिक फ़ंक्शन कोड expand_function_startgcc/function.c में उत्पन्न होता है। है

4462 /* Initialize rtx for parameters and local variables. 
4463  In some cases this requires emitting insns. */ 
4464 assign_parms (subr); 

assign_parms में कोड संभालती है कि जहां प्रत्येक तर्क संग्रहीत किया जाता है निम्नलिखित:: वहाँ हम से निपटने के मापदंडों के लिए निम्नलिखित को खोजने

3207  if (assign_parm_setup_block_p (&data)) 
3208   assign_parm_setup_block (&all, parm, &data); 
3209  else if (data.passed_pointer || use_register_for_decl (parm)) 
    assign_parm_setup_reg (&all, parm, &data); 
3211  else 
3212   assign_parm_setup_stack (&all, parm, &data); 

कुल डेटा प्रकार संभालती है और इस मामले में लागू नहीं है और चूंकि डेटा पॉइंटर जीसीसी के रूप में पारित नहीं किया गया है use_register_for_decl

यहाँ प्रासंगिक हिस्सा है:

1972 if (optimize) 
1973  return true; 
1974 
1975 if (!DECL_REGISTER (decl)) 
1976  return false; 

DECL_REGISTER परीक्षण है कि क्या चर register कीवर्ड के साथ घोषित किया गया। और अब हमारे पास हमारा जवाब है: अनुकूलन सक्षम नहीं होने पर अधिकांश पैरामीटर स्टैक पर रहते हैं, और फिर assign_parm_setup_stack द्वारा प्रबंधित किए जाते हैं। मूल्य को फैलाने से पहले स्रोत कोड के माध्यम से लिया गया मार्ग पॉइंटर तर्कों के लिए थोड़ा अधिक जटिल है, लेकिन यदि आप उत्सुक हैं तो उसी फ़ाइल में खोजा जा सकता है।

जीसीसी सभी तर्कों और स्थानीय चर को अनुकूलन के साथ क्यों अक्षम करता है? डीबगिंग में मदद करने के लिए। इस सरल समारोह पर विचार करें:

1 extern int bar(int); 
2 int foo(int a) { 
3   int b = bar(a | 1); 
4   b += 42; 
5   return b; 
6 } 

gcc -O1 -c साथ संकलित यह मेरा मशीन पर निम्न उत्पन्न करता है:

0: 48 83 ec 08    sub $0x8,%rsp 
4: 83 cf 01    or  $0x1,%edi 
7: e8 00 00 00 00   callq c <foo+0xc> 
c: 83 c0 2a    add $0x2a,%eax 
f: 48 83 c4 08    add $0x8,%rsp 
13: c3      retq 

कौन सा ठीक है, सिवाय अगर आप लाइन 5 पर तोड़ने के लिए और एक के मूल्य में मुद्रित करने के लिए प्रयास करते हैं, आप

(gdb) print a 
$1 = <value optimized out> 

मिल तर्क ओवरराइट हो जाता है, क्योंकि यह bar करने के लिए कॉल के बाद उपयोग नहीं किया जाता है।

6

कारणों में से एक जोड़े:

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

आप सामान्य रूप में -O0 कोड को देख रहे हों, विचार है कि संकलक की शीर्ष प्राथमिकताओं संकलन समय संभव और उच्च गुणवत्ता वाले डिबगिंग जानकारी पैदा करने के रूप में के रूप में ज्यादा कम कर रहे हैं।

+1

हां, और कोई अनुकूलन के साथ, कंपाइलर विशेष रूप से सभी लाइनों को स्वतंत्र बनाता है, हमेशा वास्तविक चर से पुनः लोड होता है और तुरंत भंडारण करता है, जो आपको सीपीयू को दूसरी पंक्ति में स्थानांतरित करने या डीबगर में किसी भी चर के मान को बदलने की अनुमति देता है, और यह सही तरीके से व्यवहार करता है। – doug65536