当我们考虑对 SSE 浮点使用 DAZ 标志时,"denormal input"在汇编中到底是什么意思



我读过这篇文章,做过非标准化标志,比如非标准化为零,影响了相等性的比较,我了解FTZ和daz标志之间的用法和区别。

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

让我困惑的是,如果设置了FTZ,那么非正规值在程序集视图中从哪里来。我认为它只能是常数值,要么作为立即数操作数,要么来自部分.rodata(通过RIP相对寻址访问(。

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

如果我同时设置DAZ和FTZ,问题就会消失,性能也会变得更好。事实上,我甚至在源代码中都找不到任何非规范化的输入。我真的很困惑,非正规值是从哪里来的?


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

在我的理解中,DAZ会使它以0x9498(%rip)为零,并将0移动到xmm0;FTZ会将0x9498(%rip)移动到xmm0,并发现它是非正规的,所以将xmm0刷新为零。我不确定,这是正确的吗?

非正规(也称为亚正规(是IEEE二进制格式中指数字段为0的值。https://en.wikipedia.org/wiki/Double-precision_floating-point_format

当FP数学指令(非移动或纯逐位布尔(读取这样一个数字作为输入操作数时,当尾数与其他操作数对齐时,以及当应用指数为0或非零所隐含的尾数的隐式高位时,它必须处理这种特殊情况。

是的,由于大多数浮点值都是其他FP计算的结果,所以输出上的FTZ在大多数情况下都是足够的。是的,FTZ是必要的,因为正态数上的mul/div/add/sub可以创建一个次正态结果。(对于加法,输入需要相反的符号(。IEEE的另一个"基本"精确取整运算sqrt无法创建子规范,因为它使数字接近1.0。

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


FTZ设置的非标准化(非详尽(的可能来源,即FP数学运算之外的其他来源:

  • 浮动字符串,用于构建具有扩展精度整数的FP位模式,如Glibc的strtod
  • 如果您正在读取二进制数据,请输入文件/网络
  • 其他线程或通过来自未使用FTZ运行的其他进程的共享内存。(MXCSR中的FTZ/DAZ和舍入模式是每线程的体系结构状态。说到这一点,如果在启动另一个线程后仅在主线程中设置FTZ,则对已启动的线程无效。(
  • 可能是像nextafter这样的FP位模式的整数操作。也可能是exp实现内部的一部分,该实现将整数填充到double的指数字段中
  • 编译时间常量值。不过,它们不必以文字值的形式出现在源代码中。例如CCD_ 14将是编译时的非正规化。但你会在.rodata.data中找到它们。非常数非零静态/全局变量进入.data

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

立即数

x86没有FP立即数;则必须是mov rax, imm64/movq xmm0, rax或类似的。但编译器不这么做,因为从.rodata加载通常更高效。

指令vmovsd 0x9498(%rip),%xmm0

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

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

最新更新