LINUX.ORG.RU
ФорумTalks

GCC неправильно оптимизирует вызов abs()


0

0

Код (взят с http://lkml.org/lkml/2007/11/19/493):

#include <stdio.h>
#include <stdlib.h>

int main () {
int i=2;
if( -10*abs (i-1) == 10*abs(i-1) ) printf ("OMG,-10==10 in linux!\n");
else printf ("nothing special here\n");
}

GCC заменяет вызов abs() на встроенную версию, после чего применяет неправильную оптимизацию вида -C*ABS<n> -> ABS<-C*n>. В результате программа выше пишет:

OMG,-10==10 in linux!

Ошибка затрагивает все программы, скомпилированные официальными версиями GCC и умножающие на отрицательную константу результат функции abs(), которую GCC догадался заменить на встроенную версию.

Ядро Linux от этой ошибки не страдает, так как там abs() - это макроопределение.

Исправление: пересобрать gcc с патчем по ссылке. Workaround: использовать опцию -fno-builtin при компиляции программ.

★★★★★

И правда работает.

Спасибо, теперь везде буду вставлять #define abs(x) (((x) < 0) ? (-(x)) : (x)), на всякий пожарный.

Sikon ★★★
()
Ответ на: комментарий от Sikon

> теперь везде буду вставлять #define abs(x) (((x) < 0) ? (-(x)) : (x))

А потом напишешь что-то типа abs(a++) и ПРЕВЕД

anonymous
()

Сравните верный код VC7:
 mov	eax, 1
 cdq
 xor	eax, edx
 sub	eax, edx
 lea	ecx, DWORD PTR [eax+eax*4]
 imul	eax, -10
 shl	ecx, 1
 cmp	eax, ecx
 ...
и неверный GCC-4.1.2:
 movl	$2, -8(%ebp)
 movl	-8(%ebp), %edx
 movl	%edx, %eax
 sall	$2, %eax
 addl	%edx, %eax
 addl	%eax, %eax
 negl	%eax
 addl	$10, %eax
 cltd
 movl	%edx, %ecx
 xorl	%eax, %ecx
 subl	%edx, %ecx
 movl	-8(%ebp), %edx
 movl	%edx, %eax
 sall	$2, %eax
 addl	%edx, %eax
 addl	%eax, %eax
 subl	$10, %eax
 cltd
 xorl	%edx, %eax
 subl	%edx, %eax
 cmpl	%eax, %ecx
 ...
GCC не смог определить инвариант в условии, и потому его код
делает лишнюю и к тому же неправильную работу

frame ★★★
()
Ответ на: комментарий от frame

>GCC неправильно оптимизирует

GCC неправильно и не оптимизирует - так ближе к истине

anonymous
()
Ответ на: комментарий от frame

Ты наверное с -O0 компилировал. У меня с -O3 вот что:

.file "test.c" .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .string "OMG,-10==10 in linux!" .text .p2align 4,,15 .globl main .type main, @function main: leal 4(%esp), %ecx andl $-16, %esp pushl -4(%ecx) pushl %ebp movl %esp, %ebp pushl %ecx subl $4, %esp movl $.LC0, (%esp) call puts addl $4, %esp popl %ecx popl %ebp leal -4(%ecx), %esp ret .size main, .-main .ident "GCC: (GNU) 4.2.1 (SUSE Linux)" .section .note.GNU-stack,"",@progbits

Он по ходу модуль даже не вычисляет.

anonymous
()
Ответ на: комментарий от anonymous

ПИЛЯЯЯЯТЬ

        .file   "test.c"
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string "OMG,-10==10 in linux!"
        .text
        .p2align 4,,15
.globl main
        .type   main, @function
main:
        leal    4(%esp), %ecx
        andl    $-16, %esp
        pushl   -4(%ecx)
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %ecx
        subl    $4, %esp
        movl    $.LC0, (%esp)
        call    puts
        addl    $4, %esp
        popl    %ecx
        popl    %ebp
        leal    -4(%ecx), %esp
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 4.2.1 (SUSE Linux)"
        .section        .note.GNU-stack,"",@progbits

anonymous
()
Ответ на: комментарий от anonymous

Усп, я скомпилил с О3, а листинг дал по умолчанию, всё признаю :)

frame ★★★
()
Ответ на: комментарий от anonymous

> А потом напишешь что-то типа abs(a++)

Я так не пишу.

Sikon ★★★
()

Проверил в gcc 2.95.3, (Slackware 8.0). Все работает как надо. Даже с O3

mky ★★★★★
()

> все программы, скомпилированные официальными версиями GCC и умножающие на отрицательную константу результат функции abs(), которую GCC догадался заменить на встроенную версию.

Следует понимать так: "только nethack и кусок мертвого кода в libtheora".

AEP ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.