2

我已经阅读了这篇文章do-denormal-flags-like-denormals-are-zero-daz-affect-comparisons-for-equality,我了解 FTZ 和 DAZ 标志之间的用法和区别。

DAZ 适用于输入,FTZ 适用于 FP 操作的输出。

让我感到困惑的是,如果设置了 FTZ,那么汇编视图中的非规范值来自哪里。我认为它只能是常量值,既可以是直接操作数,也可以是节.rodata(通过 RIP 相对寻址访问)。

但是我在我的二进制文件中发现,这些地方没有异常值,但它仍然存在 FP-ASSIST 问题,导致性能不佳。

如果我同时设置 DAZ 和 FTZ,问题就会消失并且性能会变得更好。实际上,我什至在我的源代码中都没有找到任何非正规输入。我真的很困惑,异常值来自哪里?


另外一个问题,对于指令vmovsd 0x9498(%rip),%xmm0,假设0x9498(%rip)是一个非正规值,xmm0如果我们分别设置 FTZ 或 DAZ,这条指令执行后会发生什么?

据我了解,DAZ 会将其0x9498(%rip)设为零并0移至 xmm0;FTZ 将移动0x9498(%rip)到 xmm0 并发现它是非正规的,因此刷新xmm0为零。我不确定,是否正确?

4

1 回答 1

2

非正规又名次正规是 IEEE 二进制格式中指数字段 = 0 的值。 https://en.wikipedia.org/wiki/Double-precision_floating-point_format

当 FP 数学指令(不是移动或纯按位布尔值)读取这样的数字作为输入操作数时,它必须在将尾数与另一个操作数对齐时处理这种特殊情况,以及应用尾数的隐式最高位时指数暗示为 0 或非零。

是的,大多数时候输出上的 FTZ 就足够了,因为大多数浮点值是其他 FP 计算的结果。是的,FTZ 是必要的,因为正常数字上的 mul/div/add/sub 会产生不正常的结果。(添加输入需要相反的符号)。另一个 IEEE “基本” 精确舍入运算 sqrt 不能创建次正规,因为它使数字更接近 1.0。

显而易见的事情是用来perf record找出你在哪里获得 FP 辅助,并在那里添加一些额外的检查以打印或当你在那里发现异常时添加一些东西。(然后在该分支中设置断点,以便检查情况。)


设置 FTZ 的非规范化可能来源(并非详尽无遗),即除 FP 数学运算之外:

  • 使用扩展精度整数构建 FP 位模式的字符串到浮点数,如 Glibc 的strtod
  • 如果您正在读取二进制数据,请输入文件/网络。
  • 其他线程或通过没有 FTZ 运行的其他进程的共享内存。(MXCSR中的FTZ/DAZ和取整模式是per-thread架构状态。话说回来,如果在启动另一个线程只在主线程中设置FTZ,对已经启动的线程是无效的。)
  • 可能对 FP 位模式进行整数操作,例如nextafter. 也可能作为exp实现内部的一部分,将整数填充到 a 的指数字段中double
  • 编译时常量值。不过,它们不必作为文字值出现在源代码中。例如static double foo = DBL_MIN / 4.0;将是编译时非规范化。但是你会在.rodataor中找到它们.data。非常量非零静态/全局变量进入.data.

显然,任何使用整数的 FP 位模式的手动操作也可以做到这一点。 如何在没有 AVX2 的情况下使用字节中的位在 ymm 寄存器中设置 dwords?(vmovmskps 的倒数)如果我没有花费额外的指令来避免它,可能会产生比较的非正规输入,但这是编译器不会为你做的不寻常的手动向量化技巧。

立即数

x86 没有 FP 立即数;你必须mov rax, imm64/movq xmm0, rax或类似的。但是编译器不会这样做,因为从.rodata.

用于指导vmovsd 0x9498(%rip),%xmm0

vmovsd只是一个负载,并且总是准确地复制 64 位;在架构上等效于vmovqSIMD 整数负载。

它不通过 ALU 运行该值,因此没有 MXCSR 位对vmovsdFP shuffle 等有任何影响。只有执行实际 FP 数学运算并可能引发 FP 异常的指令才会受到影响。您可以通过查看 asm 手册条目的异常部分来判断。例如,在根据指定模式四舍五入之前roundsd,确实服从 DAZ 可能将输入四舍五入为零。

于 2020-04-27T12:30:51.430 回答