최적화 된 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는 동의하지 않는다. 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