एक अनुकूलित ftol
फ़ंक्शन लिखते समय मुझे कुछ बहुत ही अजीब व्यवहार मिला GCC 4.6.1
। मैं आपको पहले कोड दिखाऊंगा (स्पष्टता के लिए मैंने अंतर चिह्नित किया है):
fast_trunc_one, C:
int fast_trunc_one(int i) {
int mantissa, exponent, sign, r;
mantissa = (i & 0x07fffff) | 0x800000;
exponent = 150 - ((i >> 23) & 0xff);
sign = i & 0x80000000;
if (exponent < 0) {
r = mantissa << -exponent; /* diff */
} else {
r = mantissa >> exponent; /* diff */
}
return (r ^ -sign) + sign; /* diff */
}
fast_trunc_two, C:
int fast_trunc_two(int i) {
int mantissa, exponent, sign, r;
mantissa = (i & 0x07fffff) | 0x800000;
exponent = 150 - ((i >> 23) & 0xff);
sign = i & 0x80000000;
if (exponent < 0) {
r = (mantissa << -exponent) ^ -sign; /* diff */
} else {
r = (mantissa >> exponent) ^ -sign; /* diff */
}
return r + sign; /* diff */
}
एक ही सही लगता है? खैर जीसीसी असहमत है। gcc -O3 -S -Wall -o test.s test.c
इस के साथ संकलन के बाद विधानसभा उत्पादन है:
fast_trunc_one, उत्पन्न:
_fast_trunc_one:
LFB0:
.cfi_startproc
movl 4(%esp), %eax
movl $150, %ecx
movl %eax, %edx
andl $8388607, %edx
sarl $23, %eax
orl $8388608, %edx
andl $255, %eax
subl %eax, %ecx
movl %edx, %eax
sarl %cl, %eax
testl %ecx, %ecx
js L5
rep
ret
.p2align 4,,7
L5:
negl %ecx
movl %edx, %eax
sall %cl, %eax
ret
.cfi_endproc
fast_trunc_two, उत्पन्न:
_fast_trunc_two:
LFB1:
.cfi_startproc
pushl %ebx
.cfi_def_cfa_offset 8
.cfi_offset 3, -8
movl 8(%esp), %eax
movl $150, %ecx
movl %eax, %ebx
movl %eax, %edx
sarl $23, %ebx
andl $8388607, %edx
andl $255, %ebx
orl $8388608, %edx
andl $-2147483648, %eax
subl %ebx, %ecx
js L9
sarl %cl, %edx
movl %eax, %ecx
negl %ecx
xorl %ecx, %edx
addl %edx, %eax
popl %ebx
.cfi_remember_state
.cfi_def_cfa_offset 4
.cfi_restore 3
ret
.p2align 4,,7
L9:
.cfi_restore_state
negl %ecx
sall %cl, %edx
movl %eax, %ecx
negl %ecx
xorl %ecx, %edx
addl %edx, %eax
popl %ebx
.cfi_restore 3
.cfi_def_cfa_offset 4
ret
.cfi_endproc
यह एक चरम अंतर है। यह वास्तव में प्रोफ़ाइल पर भी दिखाता है, fast_trunc_one
की तुलना में लगभग 30% तेज है fast_trunc_two
। अब मेरा सवाल: यह क्या कारण है?
-S -O3 -da -fdump-tree-all
। यह मध्यवर्ती प्रतिनिधित्व के कई स्नैपशॉट बनाएगा। उनके माध्यम से चलें (वे क्रमांकित हैं) कंधे से कंधा मिलाकर चल रहे हैं और आपको पहले मामले में लापता अनुकूलन खोजने में सक्षम होना चाहिए।
int
को बदलो unsigned int
और देखो कि क्या अंतर गायब हो जाता है।
(r + shifted) ^ sign
समान नहीं है r + (shifted ^ sign)
। मुझे लगता है कि आशावादी को भ्रमित कर रहा है? FWIW, MSVC 2010 (16.00.40219.01) लिस्टिंग का उत्पादन करता है जो लगभग एक दूसरे के समान होते हैं: gist.github.com/2430454