Почему GCC генерирует такие радикально отличающиеся сборки почти для одного и того же кода C?

При написании оптимизированной функции ftolя обнаружил очень странное поведение функции GCC 4.6.1. Позвольте мне сначала показать вам код (для ясности, я отметил различия):

fast _trunc _один, 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 _два, 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. Теперь мой вопрос :, что вызывает это?

183
задан phuclv 19 September 2019 в 23:07
поделиться