如何强制 GCC 假定浮点表达式为非负?

2024-01-08

在某些情况下,您知道某个浮点表达式始终为非负数。例如,当计算向量的长度时,sqrt(a[0]*a[0] + ... + a[N-1]*a[N-1]) (NB: I am意识到std::hypot,这与问题无关),并且平方根下的表达式显然是非负的。然而,海湾合作委员会outputs https://godbolt.org/z/SsrYUu以下程序集用于sqrt(x*x):

        mulss   xmm0, xmm0
        pxor    xmm1, xmm1
        ucomiss xmm1, xmm0
        ja      .L10
        sqrtss  xmm0, xmm0
        ret
.L10:
        jmp     sqrtf

也就是说,它比较的结果x*x为零,如果结果非负,则执行sqrtss指令,否则调用sqrtf.

所以,我的问题是:我怎样才能迫使海湾合作委员会假设x*x始终为非负数,因此它会跳过比较和sqrtf调用,而不编写内联汇编?

我想强调的是,我对本地解决方案感兴趣,而不是做类似的事情-ffast-math, -fno-math-errno, or -ffinite-math-only(尽管这些确实解决了问题,感谢评论中的 ks1322、harold 和 Eric Postpischil)。

此外,“迫使海湾合作委员会假设x*x是非负的”应该解释为assert(x*x >= 0.f),所以这也排除了以下情况x*x为 NaN。

我对特定于编译器、特定于平台、特定于 CPU 等的解决方案很满意。


你可以写assert(x*x >= 0.f)在 GNU C 中作为编译时承诺而不是运行时检查,如下所示:

#include <cmath>

float test1 (float x)
{
    float tmp = x*x;
    if (!(tmp >= 0.0f)) 
        __builtin_unreachable();    
    return std::sqrt(tmp);
}

(有关的:__builtin_unreachable 有助于哪些优化? https://stackoverflow.com/questions/54764535/what-optimizations-does-builtin-unreachable-facilitate你也可以包裹if(!x)__builtin_unreachable()在宏中并调用它promise()或者其他的东西。)

但海湾合作委员会不知道如何利用这一承诺tmp是非 NaN 且非负。我们仍然得到(Godbolt https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,lang:c%2B%2B,source:%27%23include+%3Ccmath%3E%0A%0Afloat+test1+(float+x)%0A%7B%0A++++float+tmp+%3D+x*x%3B%0A++++if+(!!(tmp+%3E%3D+0.0f))+%0A++++++++__builtin_unreachable()%3B++++%0A++++return+std::sqrt(tmp)%3B%0A%7D%0A%0Afloat+test2+(float+x)%0A%7B%0A++++return+std::sqrt(x*x)%3B%0A%7D%0A%27),l:%275%27,n:%270%27,o:%27C%2B%2B+source+%231%27,t:%270%27)),k:36.64524356415925,l:%274%27,m:100,n:%270%27,o:%27%27,s:0,t:%270%27),(g:!((h:compiler,i:(compiler:g92,filters:(b:%270%27,binary:%271%27,commentOnly:%270%27,demangle:%270%27,directives:%270%27,execute:%271%27,intel:%270%27,libraryCode:%271%27,trim:%271%27),lang:c%2B%2B,libs:!((name:rangesv3,ver:%27036%27)),options:%27-fno-math-errno+-std%3Dgnu%2B%2B17+-O3%27,source:1),l:%275%27,n:%270%27,o:%27x86-64+gcc+9.2+(Editor+%231,+Compiler+%231)+C%2B%2B%27,t:%270%27)),header:(),k:30.021423102507427,l:%274%27,m:100,n:%270%27,o:%27%27,s:0,t:%270%27),(g:!((h:compiler,i:(compiler:gsnapshot,filters:(b:%270%27,binary:%271%27,commentOnly:%270%27,demangle:%270%27,directives:%270%27,execute:%271%27,intel:%270%27,libraryCode:%271%27,trim:%271%27),lang:c%2B%2B,libs:!((name:rangesv3,ver:%27036%27)),options:%27-std%3Dgnu%2B%2B17+-O3+-fno-trapping-math%27,source:1),l:%275%27,n:%270%27,o:%27x86-64+gcc+(trunk)+(Editor+%231,+Compiler+%232)+C%2B%2B%27,t:%270%27)),k:33.33333333333333,l:%274%27,n:%270%27,o:%27%27,s:0,t:%270%27)),l:%272%27,m:100,n:%270%27,o:%27%27,t:%270%27)),version:4) 检查的相同的固定 asm 序列x>=0并以其他方式调用sqrtf to set errno. 据推测,扩展为比较和分支是在其他优化过程之后发生的,所以编译器了解更多信息并没有帮助。

这是推测性内联逻辑中的一个错过的优化sqrt when -fmath-errno已启用(不幸的是默认情况下启用)。

你想要的是-fno-math-errno,这在全球范围内都是安全的

如果您不依赖数学函数设置,那么这是 100% 安全的errno。没有人想要这样,这就是 NaN 传播和/或记录屏蔽 FP 异常的粘性标志的用途。例如C99/C++11fenv https://en.cppreference.com/w/cpp/numeric/fenv通过访问#pragma STDC FENV_ACCESS ON然后像这样的函数fetestexcept() https://en.cppreference.com/w/cpp/numeric/fenv/fetestexcept。请参阅中的示例feclearexcept https://en.cppreference.com/w/cpp/numeric/fenv/feclearexcept它显示了使用它来检测除零。

FP 环境是线程上下文的一部分,而errno是全球性的。

对这个过时的错误功能的支持不是免费的;您应该将其关闭,除非您有编写使用它的旧代码。不要在新代码中使用它:使用fenv。理想情况下支持-fmath-errno会尽可能便宜,但实际使用的人很少__builtin_unreachable()或其他排除 NaN 输入的因素可能会让开发人员不值得花时间来实现优化。不过,如果您愿意,您可以报告错过优化的错误。

事实上,现实世界的 FPU 硬件确实有这些粘性标志,这些标志在清除之前一直保持设置状态,例如x86's mxcsr http://softpixel.com/%7Ecwright/programming/simd/sse.php用于 SSE/AVX 数学的状态/控制寄存器,或其他 ISA 中的硬件 FPU。在 FPU 可以检测异常的硬件上,高质量的 C++ 实现将支持诸如fetestexcept()。如果没有,那么数学-errno可能也不起作用。

errnofor math 是一个过时的设计,C / C++ 默认情况下仍然沿用它,现在被广泛认为是一个坏主意。它使编译器更难有效地内联数学函数。或者也许我们并不像我想象的那样坚持下去:为什么 errno 没有设置为 EDOM,即使 sqrt 取出域参数? https://stackoverflow.com/questions/56243525/why-errno-is-not-set-to-edom-even-sqrt-takes-out-of-domain-arguement解释说在数学函数中设置 errno 是optional在 ISO C11 中,实现可以表明他们是否这样做。大概在 C++ 中也是如此。

结块是个大错误-fno-math-errno进行价值改变的优化,例如-ffast-math or -ffinite-math-only.您应该强烈考虑在全局启用它,或者至少对于包含此函数的整个文件启用它。

float test2 (float x)
{
    return std::sqrt(x*x);
}
# g++ -fno-math-errno -std=gnu++17 -O3
test2(float):   # and test1 is the same
        mulss   xmm0, xmm0
        sqrtss  xmm0, xmm0
        ret

你不妨使用-fno-trapping-math同样,如果您不打算使用以下方法揭露任何 FP 异常feenableexcept()。 (虽然此优化不需要该选项,但它只是errno- 设置废话,这是一个问题。)。

-fno-trapping-math不假设 no-NaN 或任何东西,它只假设像 Invalid 或 Inexact 这样的 FP 异常不会实际调用信号处理程序,而不是产生 NaN 或舍入结果。-ftrapping-math是默认值,但是根据 GCC 开发者 Marc Glisse 的说法,它已经损坏并且“从未工作过” https://stackoverflow.com/questions/56670132/simd-for-float-threshold-operation#comment99952463_56681744。 (即使打开了它,GCC 也会进行一些优化,这些优化可以将引发的异常数量从零更改为非零,反之亦然。并且它会阻止一些安全优化)。但不幸的是,https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54192 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54192(默认关闭)仍然打开。

如果您确实曾经揭露过异常,那么最好-ftrapping-math,但同样,您很少会希望这样做,而不是在一些数学运算后检查标志或检查 NaN。而且它实际上并没有保留精确的异常语义。

See 用于浮点阈值操作的 SIMD https://stackoverflow.com/questions/56670132/simd-for-float-threshold-operation对于这样的情况-ftrapping-math默认错误地阻止了安全优化。 (即使在提升潜在陷阱操作以便 C 无条件执行此操作之后,gcc 也会生成有条件执行此操作的非向量化汇编!因此,GCC 不仅会阻止向量化,而且还会更改与 C 抽象机相比的异常语义。)-fno-trapping-math实现预期的优化。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何强制 GCC 假定浮点表达式为非负? 的相关文章

随机推荐

  • 从 Angular 前端调用 Azure AD 安全 Web API

    我目前正在开发一个 Angular 前端 它使用 MSAL 来对用户进行身份验证 该前端应调用 Web API 也托管在 Azure 中 该 API 由 Azure Active Directory 保护 虽然我轻松地设法使用 Angula
  • 如何停止 SwingWorker?

    我怎样才能阻止SwingWorker做他的工作吗 我知道有cancel 方法 但我最多能做的就是匿名创建一个新的SwingWorker这就是工作 这是供参考的代码 public void mostrarResultado final Res
  • .Net Core 3 Worker 集成测试

    对于集成测试 Asp Net Core 应用程序 我们有Web应用程序工厂 https learn microsoft com en us aspnet core test integration tests view aspnetcore
  • 使用 JNDI 获取 DNS SRV 记录

    我正在尝试使用 JNDI 从 DNS 服务器获取 SRV 记录 Hashtable
  • 哪个更好? Qt Creator 或 Visual Studio IDE [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我目前在我的 Qt 应用程序中使用 Qt Creator 1 3 我知道它使用jom for make当我们拥有多核处理器时 这一步会更好 但除
  • Twig 标签包含与函数包含

    Twig 的文档标签包括 http twig symfony com doc tags include html看起来非常相似功能包括 http twig symfony com doc functions include html 标签包
  • 如何从java中的JSON文件中删除键值对

    我想知道是否有人可以帮助我或提示我如何用 Java 编辑附加的虚拟 JSON 文件 正如您所看到的 我有一个头对象 其中包含许多遵循相同模式的值和子对象 我想知道是否有办法删除所有值为 1的键 以下是我根据许多网站使用的尝试jackson
  • 根据javascript中的文本行数更改文本区域的高度[重复]

    这个问题在这里已经有答案了 可能的重复 使用原型自动调整文本区域大小 https stackoverflow com questions 7477 autosizing textarea using prototype 如何根据用户放入文本
  • JWT 不记名令牌流程

    我想要的是 ASP NET Core 中 JWT 生成和 JWT 消耗的方法 没有 OAuth2 流程 我确实有 IdentityServerv3 与 OAuth2 配合使用 但当我拥有双方时 对于访问 API 的单个应用程序来说 这有点过
  • Slick Slider slickGoTo 方法打破轮播

    我正在开发一个新闻文章页面 该页面也有一个图像库 我在用着光滑的滑块 http kenwheeler github io slick 用于画廊上的缩略图 图库中的每张图片都有自己的网址 用于广告查看目的 不太好 但我对此无能为力 例如 ou
  • 如何在flutter中定义自定义文本主题?

    如何制作自己的文字主题风格 我只找到这样的默认文本主题 但这还不够 textTheme TextTheme body1 TextStyle body2 TextStyle button TextStyle caption TextStyle
  • Python字典和集合内存分配

    I found 这个优秀的资源 https www safaribooksonline com library view high performance python 9781449361747 ch04 html讨论 python 字典
  • 如何在 Cypress 中存储图像的 src 并将其与另一个图像进行比较?

    测试目标是确认如果用户上传新图像 则上传图像的 src 属性会发生更改 这意味着图像已更改 我尝试使用几种方法 概述如下 第一种方法 cy get img then img gt store the src const source img
  • Chrome 会混淆使用 SVG 格式的网络字体设计的文本(有时)

    Demo http jsbin com onixik 2 http jsbin com onixik 2 内容如下 如果您在 Windows 上的 Chrome 中检查该演示 它可能看起来不错 也可能不太好 我所说的 OK 是指它并不引人注
  • 更改 tkinter 中的输入框背景颜色

    所以我一直在研究这个程序 但我发现很难找出问题所在 我对 tkinter 还很陌生 所以这可能很小 我试图让程序在按下复选按钮时更改输入框的背景颜色 或者更好的是 如果我可以动态地改变它 那就更好了 这是我目前的代码 TodayReadin
  • 在Java中无损JPEG旋转(90/180/270度)?

    是否有一个 Java 库可以以 90 度的增量旋转 JPEG 文件 而不会导致图像质量下降 我找到了这个 http mediachest sourceforge net mediautil http mediachest sourcefor
  • 使用 Azure 管道在特定的自托管服务器上运行

    在 Azure git 中 我正在运行一些自托管代理 它们位于名为 默认 的池中 在 Azure 管道 yml 文件 中 我可以告诉作业它必须在特定代理中运行 如下所示 pool name Default demands Agent Nam
  • 假装电报机器人正在打字?

    如何让机器人假装正在输入消息 当机器人假装打字时 聊天中会出现以下文本 我用的是蟒蛇aiogram https github com aiogram aiogram框架 但对原生 Telegram API 的建议也会有所帮助 我认真建议使用
  • MySQL CSV 导入 - 如果时间戳有毫秒,则日期输入为 0000-00-00 00:00:00?

    我目前有大量 CSV 需要导入到 MySQL 数据库中 这些文件包含每条记录的时间戳 其格式如下 例如 2011 10 13 09 36 02 297000000 我知道 MySQL 错误 8523 它表明不支持在日期时间字段中存储毫秒 尽
  • 如何强制 GCC 假定浮点表达式为非负?

    在某些情况下 您知道某个浮点表达式始终为非负数 例如 当计算向量的长度时 sqrt a 0 a 0 a N 1 a N 1 NB I am意识到std hypot 这与问题无关 并且平方根下的表达式显然是非负的 然而 海湾合作委员会outp