Intel 上的 gcc / clang / msvc:为什么 QNAN == QNAN 的 ucomiss预期,但 QNAN <= QNAN意外的 comiss?

问题描述

示例代码 (t2.c):

#include <fenv.h>
#include <stdio.h>
#include <math.h>

#if _MSC_VER && ! __clang__ /*&& ! __INTEL_COMPILER*/
#pragma fenv_access (on)
#else
#pragma STDC FENV_ACCESS ON
#endif

int main(void)
{
    volatile _Bool b;
    volatile float f = NAN;  // quiet NaN per C11

    feclearexcept(FE_ALL_EXCEPT);
//  b = f == f;  // leads to ucomiss (signals Invalid if operand is SNaN)
    b = f <= f;  // leads to comiss  (signals Invalid if operand is QNaN or SNaN)
    if (fetestexcept(FE_INVALID))
    {
        printf("FE_INVALID\n");
    }
    return b ? 1 : 0;
}

b = f <= f 生成的汇编代码

clang t2.c -std=c11 -ffp-model=strict -S

    callq   feclearexcept
    movss   44(%rsp),%xmm1                 # xmm1 = mem[0],zero,zero
    movss   44(%rsp),%xmm0                 # xmm0 = mem[0],zero
    comiss  %xmm1,%xmm0
    setae   %al
    andb    $1,%al
    movb    %al,51(%rsp)
    movl    $16,%ecx
    callq   fetestexcept

gcc t2.c -std=c11 -S

    call    feclearexcept
    movss   -8(%rbp),%xmm1
    movss   -8(%rbp),%xmm0
    comiss  %xmm1,%xmm0
    setnb   %al
    movb    %al,-1(%rbp)
    movl    $1,%ecx
    call    fetestexcept

cl t2.c /std:c11 /fp:strict /Za /Fa

    call    feclearexcept
; Line 18
    movss   xmm0,DWORD PTR f$[rsp]
    movss   xmm1,DWORD PTR f$[rsp]
    comiss  xmm1,xmm0
    jb  SHORT $LN4@main
    mov DWORD PTR tv76[rsp],1
    jmp SHORT $LN5@main
$LN4@main:
    mov DWORD PTR tv76[rsp],0
$LN5@main:
    cmp DWORD PTR tv76[rsp],0
    jne SHORT $LN6@main
    mov DWORD PTR tv78[rsp],0
    jmp SHORT $LN7@main
$LN6@main:
    mov DWORD PTR tv78[rsp],1
$LN7@main:
    movzx   eax,BYTE PTR tv78[rsp]
    mov BYTE PTR b$[rsp],al
; Line 19
    mov ecx,16
    call    fetestexcept

注意:这里有 clang 和 gcc:

  • 正在使实现符合版本 201112 或不符合实现但 __STDC__ 具有 1 的定义
  • 符合附件 F 中的规范(__STDC_IEC_559__ 具有 1 的定义)

注意:comissucomiss 的说明:

IEEE 754-2008,5.11,p4(强调):

明确考虑quiet NaN 操作数可能性的程序可以使用 表 5.3 中的无序安静谓词不会发出这种无效操作异常的信号

IEEE 754-2008,Table 5.3

这里我们看到无序安静谓词LT EQ<=是C)在表5.3中,因此QNAN <= QNAN不会导致无效操作异常。我错过了什么吗?为什么 QNAN <= QNAN 编译器生成 comiss 而不是 ucomiss

工具版本:

$ gcc --version
gcc (Ubuntu 10.2.0-5ubuntu1~20.04) 10.2.0

$ clang --version
Ubuntu clang version 11.0.0-2~ubuntu20.04.1

$ cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29913 for x64

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)