-Ofast 的 GCC 问题?

Posted

技术标签:

【中文标题】-Ofast 的 GCC 问题?【英文标题】:GCC issue with -Ofast? 【发布时间】:2020-06-17 14:27:17 【问题描述】:

我对使用此代码的最新 GCC 编译器(版本 >= 5)有疑问:

#include <math.h>

void test_nan (
    const float * const __restrict__ in,
    const int n,
    char * const __restrict__ out )

    for (int i = 0; i < n; ++i)
        out[i] = isnan(in[i]);

来自 GCC 的程序集清单:

test_nan:
        movq    %rdx, %rdi
        testl   %esi, %esi
        jle     .L1
        movslq  %esi, %rdx
        xorl    %esi, %esi
        jmp     memset
.L1:
        ret

这看起来像memset(out, 0, n)。 为什么 GCC 假设 -Ofast 没有条目可以是 NaN ? 使用相同的编译选项,ICC 不会显示此问题。 使用 GCC,“-O3”问题就消失了。

请注意,使用“-O3”时,此查询 gcc -c -Q -O3 --help=optimizers | egrep -i nan 会给出 -fsignaling-nans [disabled]

我在本地和godbolt 上都验证了这一点,并使用了附加选项“-std=c99”。

编辑:按照下面的有用答案,我可以确认-Ofast -std=c99 -fno-finite-math-only 正确解决了这个问题。

【问题讨论】:

这正是 -Ofast 的文档记录。 一般来说,几乎任何时候你发现自己认为这是一个编译器错误,它不是。 man gcc, /-Ofast。不是很复杂。 @n.'pronouns'm。公平地说,在您了解有关 NaN 的详细信息之前,有一个对其他选项的引用树。 【参考方案1】:

来自 GCC Options That Control Optimizations 文档。

-Ofast 除了-O3 之外,还启用了以下优化:

它会打开 -ffast-math、-fallow-store-data-races 和 Fortran 特定的 -fstack-arrays,除非指定了 -fmax-stack-var-size,并且 - fno-protect-parens。

-ffast-math 启用以下功能:

-fno-math-errno、-funsafe-math-optimizations、-ffinite-math-only、-fno-rounding-math、-fno-signaling-nans、-fcx-limited-范围和 -fexcess-precision=fast。

-ffinite-math-only 执行以下操作:

允许对假设参数和结果不是 NaN 或 +-Infs 的浮点算术进行优化。

这允许它假设isnan() 总是返回0

【讨论】:

【参考方案2】:

Barmar's answer 解释了为什么-Ofast 导致编译器假定 NaN 永远不会发生。我有两件事要补充。

首先,您谈到在--help=optimize 输出中看到-fsignaling-nans [disabled]信令 NaN 是所有 NaN 位模式的子类别。 CPU 将在使用时触发浮点异常(请参阅架构手册以了解“使用时”的确切含义)。通常人们只使用另一种类型,quiet NaN,因为处理浮点异常很痛苦;因此,默认情况下,GCC 生成的代码可以处理安静的 NaN(和 ±Inf),但 发出信号 NaN。 isnan 对安静和信令 NaN 都是正确的。简而言之,-fsignaling-nans 是一条红鲱鱼;直接控制你不喜欢的行为的选项是-ffinite-math-only

其次,如果您使用-Ofast 是因为您希望此函数被矢量化,请尝试使用-O3 -march=native。循环向量化在-O3 启用,-march=native 指示 GCC 对其运行的 CPU 的全部功能进行优化。如果没有任何-march 开关,GCC 将假定它只能使用 psABI 保证可用的 CPU 功能;对于 x86-64(看起来你有),那是 SSE2,但之后没有,这遗漏了大部分矢量功能。在我正在输入的计算机上,-O3 -march=native 为您的示例函数生成代码,其大小只有 -O3 的一半可能大约是 -O3 的四倍。

【讨论】:

以上是关于-Ofast 的 GCC 问题?的主要内容,如果未能解决你的问题,请参考以下文章

Mac OSX 上的 GCC——多个版本的 gcc

VMware安装的Linux Fedora , 关于gcc 的问题

GCC:在 GCC 版本之间伪装

VMware安装的Linux Fedora , 关于gcc 的问题

gcc 和 g++/gcc-c++ 有啥区别?

GCC 向量扩展的内存对齐问题