c - 为什么 GCC -Ofast 使程序出错,但仅在它打印两次结果时才出错?

标签 c gcc

重新编译旧程序使其输出错误结果。 我想知道为什么 .

我知道-Ofast可能“无视严格的标准合规性”,但我很好奇引擎盖下会发生什么。

我将程序简化为这个 最小示例 foo1.c :

#include <stdio.h>

double my_pow(double x, unsigned n)
{ /* returns x^n */
        double y = 1;

        while(n--) y *= x;
        return y;
}

void foo(double small)
{ /* prints small^19 */
        double x = my_pow(small,19);

        printf("%E\n",x);
        printf("%E\n",x);

}

int main(void)
{
        foo(1-0.8-0.2);

        return 0;
}

使用 -Ofast 编译时它提供与任何其他优化级别不同的输出。
gcc -Ofast foo1.c && ./a.out :
-0.000000E+00
-0.000000E+00
gcc foo1.c && ./a.out :
-1.390671E-309
-1.390671E-309

一个奇怪的事实是,当其中一个 printf被注释掉(文件 foo2.c)这种行为不会复制,使其成为一种 heisenbug。
gcc -Ofast foo2.c && ./a.out :
-1.390671E-309
gcc foo2.c && ./a.out :
-1.390671E-309

可能有用的信息:
gcc -v :
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
gcc -Ofast foo1.c -S -o - :
    .file   "foo1.c"
    .text
    .p2align 4,,15
    .globl  my_pow
    .type   my_pow, @function
my_pow:
.LFB11:
    .cfi_startproc
    testl   %edi, %edi
    leal    -1(%rdi), %edx
    je  .L10
    movl    %edi, %ecx
    shrl    %ecx
    movl    %ecx, %esi
    addl    %esi, %esi
    je  .L11
    cmpl    $9, %edi
    jbe .L11
    movapd  %xmm0, %xmm1
    movapd  .LC0(%rip), %xmm2
    xorl    %eax, %eax
    unpcklpd    %xmm1, %xmm1
.L9:
    addl    $1, %eax
    mulpd   %xmm1, %xmm2
    cmpl    %eax, %ecx
    ja  .L9
    movapd  %xmm2, -24(%rsp)
    subl    %esi, %edx
    cmpl    %esi, %edi
    movsd   -16(%rsp), %xmm1
    mulsd   %xmm2, %xmm1
    je  .L2
    testl   %edx, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
.L35:
    cmpl    $1, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    cmpl    $2, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    cmpl    $3, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    cmpl    $4, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    cmpl    $5, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    cmpl    $6, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    cmpl    $7, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    mulsd   %xmm0, %xmm1
    .p2align 4,,10
    .p2align 3
.L2:
    movapd  %xmm1, %xmm0
    ret
    .p2align 4,,10
    .p2align 3
.L11:
    movsd   .LC1(%rip), %xmm1
    testl   %edx, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    jmp .L35
    .p2align 4,,10
    .p2align 3
.L10:
    movsd   .LC1(%rip), %xmm1
    jmp .L2
    .cfi_endproc
.LFE11:
    .size   my_pow, .-my_pow
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC2:
    .string "%E\n"
    .text
    .p2align 4,,15
    .globl  foo
    .type   foo, @function
foo:
.LFB12:
    .cfi_startproc
    movapd  %xmm0, %xmm2
    subq    $24, %rsp
    .cfi_def_cfa_offset 32
    movl    $.LC2, %edi
    movl    $1, %eax
    unpcklpd    %xmm2, %xmm2
    movapd  %xmm2, %xmm1
    mulpd   %xmm2, %xmm1
    mulpd   %xmm1, %xmm1
    mulpd   %xmm1, %xmm1
    mulpd   %xmm2, %xmm1
    movapd  %xmm1, %xmm2
    unpckhpd    %xmm1, %xmm1
    mulsd   %xmm1, %xmm2
    mulsd   %xmm0, %xmm2
    movapd  %xmm2, %xmm0
    movsd   %xmm2, 8(%rsp)
    call    printf
    movsd   8(%rsp), %xmm2
    movl    $.LC2, %edi
    movl    $1, %eax
    addq    $24, %rsp
    .cfi_def_cfa_offset 8
    movapd  %xmm2, %xmm0
    jmp printf
    .cfi_endproc
.LFE12:
    .size   foo, .-foo
    .section    .text.startup,"ax",@progbits
    .p2align 4,,15
    .globl  main
    .type   main, @function
main:
.LFB13:
    .cfi_startproc
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    movsd   .LC3(%rip), %xmm0
    call    foo
    xorl    %eax, %eax
    addq    $8, %rsp
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc
.LFE13:
    .size   main, .-main
    .section    .rodata.cst16,"aM",@progbits,16
    .align 16
.LC0:
    .long   0
    .long   1072693248
    .long   0
    .long   1072693248
    .section    .rodata.cst8,"aM",@progbits,8
    .align 8
.LC1:
    .long   0
    .long   1072693248
    .align 8
.LC3:
    .long   0
    .long   -1131413504
    .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-39)"
    .section    .note.GNU-stack,"",@progbits
gcc foo1.c -S -o - :
    .file   "foo1.c"
    .text
    .globl  my_pow
    .type   my_pow, @function
my_pow:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movsd   %xmm0, -24(%rbp)
    movl    %edi, -28(%rbp)
    movabsq $4607182418800017408, %rax
    movq    %rax, -8(%rbp)
    jmp .L2
.L3:
    movsd   -8(%rbp), %xmm0
    mulsd   -24(%rbp), %xmm0
    movsd   %xmm0, -8(%rbp)
.L2:
    movl    -28(%rbp), %eax
    leal    -1(%rax), %edx
    movl    %edx, -28(%rbp)
    testl   %eax, %eax
    jne .L3
    movq    -8(%rbp), %rax
    movq    %rax, -40(%rbp)
    movsd   -40(%rbp), %xmm0
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   my_pow, .-my_pow
    .section    .rodata
.LC1:
    .string "%E\n"
    .text
    .globl  foo
    .type   foo, @function
foo:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $32, %rsp
    movsd   %xmm0, -24(%rbp)
    movq    -24(%rbp), %rax
    movl    $19, %edi
    movq    %rax, -32(%rbp)
    movsd   -32(%rbp), %xmm0
    call    my_pow
    movsd   %xmm0, -32(%rbp)
    movq    -32(%rbp), %rax
    movq    %rax, -8(%rbp)
    movq    -8(%rbp), %rax
    movq    %rax, -32(%rbp)
    movsd   -32(%rbp), %xmm0
    movl    $.LC1, %edi
    movl    $1, %eax
    call    printf
    movq    -8(%rbp), %rax
    movq    %rax, -32(%rbp)
    movsd   -32(%rbp), %xmm0
    movl    $.LC1, %edi
    movl    $1, %eax
    call    printf
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size   foo, .-foo
    .globl  main
    .type   main, @function
main:
.LFB2:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movabsq $-4859383997932765184, %rax
    movq    %rax, -8(%rbp)
    movsd   -8(%rbp), %xmm0
    call    foo
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE2:
    .size   main, .-main
    .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-39)"
    .section    .note.GNU-stack,"",@progbits
gcc -Ofast foo2.c -S -o - :
    .file   "foo2.c"
    .text
    .p2align 4,,15
    .globl  my_pow
    .type   my_pow, @function
my_pow:
.LFB11:
    .cfi_startproc
    testl   %edi, %edi
    leal    -1(%rdi), %edx
    je  .L10
    movl    %edi, %ecx
    shrl    %ecx
    movl    %ecx, %esi
    addl    %esi, %esi
    je  .L11
    cmpl    $9, %edi
    jbe .L11
    movapd  %xmm0, %xmm1
    movapd  .LC0(%rip), %xmm2
    xorl    %eax, %eax
    unpcklpd    %xmm1, %xmm1
.L9:
    addl    $1, %eax
    mulpd   %xmm1, %xmm2
    cmpl    %eax, %ecx
    ja  .L9
    movapd  %xmm2, -24(%rsp)
    subl    %esi, %edx
    cmpl    %esi, %edi
    movsd   -16(%rsp), %xmm1
    mulsd   %xmm2, %xmm1
    je  .L2
    testl   %edx, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
.L35:
    cmpl    $1, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    cmpl    $2, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    cmpl    $3, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    cmpl    $4, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    cmpl    $5, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    cmpl    $6, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    cmpl    $7, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    mulsd   %xmm0, %xmm1
    .p2align 4,,10
    .p2align 3
.L2:
    movapd  %xmm1, %xmm0
    ret
    .p2align 4,,10
    .p2align 3
.L11:
    movsd   .LC1(%rip), %xmm1
    testl   %edx, %edx
    mulsd   %xmm0, %xmm1
    je  .L2
    jmp .L35
    .p2align 4,,10
    .p2align 3
.L10:
    movsd   .LC1(%rip), %xmm1
    jmp .L2
    .cfi_endproc
.LFE11:
    .size   my_pow, .-my_pow
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC2:
    .string "%E\n"
    .text
    .p2align 4,,15
    .globl  foo
    .type   foo, @function
foo:
.LFB12:
    .cfi_startproc
    movapd  %xmm0, %xmm2
    movl    $.LC2, %edi
    movl    $1, %eax
    unpcklpd    %xmm2, %xmm2
    movapd  %xmm2, %xmm1
    mulpd   %xmm2, %xmm1
    mulpd   %xmm1, %xmm1
    mulpd   %xmm1, %xmm1
    mulpd   %xmm2, %xmm1
    movapd  %xmm1, %xmm2
    unpckhpd    %xmm1, %xmm1
    mulsd   %xmm1, %xmm2
    mulsd   %xmm0, %xmm2
    movapd  %xmm2, %xmm0
    jmp printf
    .cfi_endproc
.LFE12:
    .size   foo, .-foo
    .section    .text.startup,"ax",@progbits
    .p2align 4,,15
    .globl  main
    .type   main, @function
main:
.LFB13:
    .cfi_startproc
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    movl    $.LC2, %edi
    movl    $1, %eax
    movsd   .LC3(%rip), %xmm0
    call    printf
    xorl    %eax, %eax
    addq    $8, %rsp
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc
.LFE13:
    .size   main, .-main
    .section    .rodata.cst16,"aM",@progbits,16
    .align 16
.LC0:
    .long   0
    .long   1072693248
    .long   0
    .long   1072693248
    .section    .rodata.cst8,"aM",@progbits,8
    .align 8
.LC1:
    .long   0
    .long   1072693248
    .align 8
.LC3:
    .long   0
    .long   -2147418112
    .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-39)"
    .section    .note.GNU-stack,"",@progbits
gcc foo2.c -S -o - :
    .file   "foo2.c"
    .text
    .globl  my_pow
    .type   my_pow, @function
my_pow:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movsd   %xmm0, -24(%rbp)
    movl    %edi, -28(%rbp)
    movabsq $4607182418800017408, %rax
    movq    %rax, -8(%rbp)
    jmp .L2
.L3:
    movsd   -8(%rbp), %xmm0
    mulsd   -24(%rbp), %xmm0
    movsd   %xmm0, -8(%rbp)
.L2:
    movl    -28(%rbp), %eax
    leal    -1(%rax), %edx
    movl    %edx, -28(%rbp)
    testl   %eax, %eax
    jne .L3
    movq    -8(%rbp), %rax
    movq    %rax, -40(%rbp)
    movsd   -40(%rbp), %xmm0
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   my_pow, .-my_pow
    .section    .rodata
.LC1:
    .string "%E\n"
    .text
    .globl  foo
    .type   foo, @function
foo:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $32, %rsp
    movsd   %xmm0, -24(%rbp)
    movq    -24(%rbp), %rax
    movl    $19, %edi
    movq    %rax, -32(%rbp)
    movsd   -32(%rbp), %xmm0
    call    my_pow
    movsd   %xmm0, -32(%rbp)
    movq    -32(%rbp), %rax
    movq    %rax, -8(%rbp)
    movq    -8(%rbp), %rax
    movq    %rax, -32(%rbp)
    movsd   -32(%rbp), %xmm0
    movl    $.LC1, %edi
    movl    $1, %eax
    call    printf
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size   foo, .-foo
    .globl  main
    .type   main, @function
main:
.LFB2:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movabsq $-4859383997932765184, %rax
    movq    %rax, -8(%rbp)
    movsd   -8(%rbp), %xmm0
    call    foo
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE2:
    .size   main, .-main
    .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-39)"
    .section    .note.GNU-stack,"",@progbits

最佳答案

-ffast-math (它是类似 -Ofast 的兄弟)gcc 将您的应用与 crtfastmath.c 中的特殊启动代码链接起来。设置清零标志:

static void __attribute__((constructor))
set_fast_math (void)
{
#ifndef __x86_64__
...
#else
  unsigned int mxcsr = __builtin_ia32_stmxcsr ();
  mxcsr |= MXCSR_DAZ | MXCSR_FTZ;
  __builtin_ia32_ldmxcsr (mxcsr);
#endif
}

(来自 here)。

关于c - 为什么 GCC -Ofast 使程序出错,但仅在它打印两次结果时才出错?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58904139/

相关文章:

c - 指向字符串数组的指针是否为 CONST?

c - 指定文件扩展名

c - 如果 LONG_MAX 为 2147483647,strtol ("-2147483648", 0, 0) 是否溢出?

c++ - C程序生成运行时日志

c++ - 没有匹配功能 - 专门的签名隐藏通用?

c++ - GCC 构建问题 (#include_next limits.h)

c++ - 运算符重载在 Visual Studio 2013 中编译但不是 gcc

c - 是否可以提示在多个 scanf 函数中使用单个用户输入?

C程序在while循环中不保存到文件

在命令提示符下找不到exe