【问题标题】:How to avoid floating point exceptions in unused SIMD lanes如何避免未使用的 SIMD 通道中的浮点异常
【发布时间】:2020-11-17 09:49:55
【问题描述】:

我喜欢在启用浮点异常的情况下运行我的代码。 我在 Linux 下使用:

feenableexcept( FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW );

到目前为止一切顺利。

我遇到的问题是,有时编译器(我使用 clang8)决定使用 SIMD 指令进行标量除法。好吧,如果这样更快,即使是单个标量,为什么不呢。

但结果是 SIMD 寄存器中未使用的通道可以包含零。

并且在执行SIMD除法时,会抛出一个浮点异常。

这是否意味着如果您允许编译器使用 sse/avx 扩展,浮点异常就根本无法使用?

就我而言,这行 C 代码:

float a0, min, a, d;
...
a0 = (min - a) / (d);

...被执行为:

divps  %xmm2,%xmm3

然后抛出一个:

Thread 1 "noisetuner" received signal SIGFPE, Arithmetic exception.

【问题讨论】:

  • clang 是否有 GCC 的 -ftrapping-math 等效项以使 FP 异常成为可见的副作用? (请注意,默认情况下,GCC 的该选项版本是打开的,但实际上已损坏:它无法阻止 GCC 进行一些优化,这些优化会更改 FP 异常的数量或类型,可能包括从 0 到非零 IIRC。)
  • 当我喂它 -ftrapping-math 时,clang 没有抱怨,但它没有解决它。要停止 FPE,我必须提供 -mno-mmx -mno-sse 参数。
  • 提交错误报告。
  • 您确定它生成的是divps 而不是divss?你能提供一个minimal reproducible example吗?
  • @chtz 不是 OP,但很容易复制,请参见:godbolt.org/z/Wd98eG

标签: floating-point clang simd floating-point-exceptions sigfpe


【解决方案1】:

我认为您在 clang 或 llvm 中发现了一个错误。

Here’s how I have reproduced,clang 10.0 发出相同的代码,即也有这个错误。显然,vdivps 指令仅在向量的前 2 个通道中具有有效数据,而在较高的 2 个通道中它将运行 0.0 / 0.0,因此如果您在 mxcsr 中启用这些中断,您将获得运行时异常像你一样注册。

Microsoft、Intel 和 gcc 不会为该代码发出 divps。如果可以的话,切换到gcc,应该不错。

更新: Clang 10+ 有一个选项控制此类优化,-ffp-exception-behavior=maytrap,看看:https://godbolt.org/z/WG7bEE

【讨论】:

  • 请注意,即使使用 -fno-trapping-math#pragma STDC FENV_ACCESS OFF godbolt.org/z/bGoe1n,gcc 也会错过优化。所以不幸的是,即使您确实想要优化,也无法通过 GCC 获得它。 (即使是-ffast-math,实际上)。具有讽刺意味的是,将 x 和 y 存储到 dst[0]dst[1] 输出数组(使 divps 成为更好的优化,不需要 shuffle)会破坏 clang 和 GCC 的自动矢量化器。
  • 看起来clang可以通过将movsd替换为movddup来轻松避免这种情况(至少在不太旧的架构上使用相同的端口)。
  • @chtz:哦,好点,是的,在 Nehalem 和更高版本(以及我认为/希望的一些 AMD)上,movddup 是纯负载,广播由负载端口处理,没有向量 ALU。这将需要特殊的异常安全向量化支持来寻找,这可能没有足够的时间来值得寻找(考虑到编译时间的成本)。
  • -ffp-exception-behavior=maytrap 标志使这个问题在 clang-10 上消失。谢谢。
猜你喜欢
  • 1970-01-01
  • 2020-12-29
  • 2015-10-02
  • 2011-09-27
  • 2015-10-26
  • 1970-01-01
  • 1970-01-01
  • 2012-11-26
  • 1970-01-01
相关资源
最近更新 更多