【问题标题】:How does GCC compile the 80 bit wide 10 byte float __float80 on x86_64?GCC 如何在 x86_64 上编译 80 位宽 10 字节浮点 __float80?
【发布时间】:2018-04-18 22:24:54
【问题描述】:

根据What's A Creel video, "Modern x64 Assembly 4: Data Types" (link to the slide)的视频中的一张幻灯片,

注意:real10 仅与 x87 FPU 一起使用,如今它在很大程度上被忽略了,但提供了惊人的精度!

他说,

“Real10 仅与 x87 浮点单元一起使用。[...] 有趣的是,它为您提供了巨大的精度增益。您会因这种增益而受到性能影响,因为您不能将 real10 与 SSE、打包、SIMD 样式指令一起使用。但是,它有点有趣,因为如果您想要更高的精度,您可以使用 x87 样式的 FPU。现在它几乎从未使用过。”

但是,我在谷歌上搜索并看到GCC supports __float80 and __float128

GCC 中的__float80 是在 x87 上计算的吗?还是像其他浮点操作一样使用 SIMD? __float128呢?

【问题讨论】:

    标签: gcc floating-point x86 precision x87


    【解决方案1】:

    GCC docs for Additional Floating Types:

    ISO/IEC TS 18661-3:2015 定义了 C 对其他浮点类型 _Floatn_Floatnx 的支持

    ... GCC 目前在任何系统上都不支持 _Float128x。

    我认为_Float128x 是 IEEE binary128,即具有巨大指数范围的真正 128 位浮点数。见http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1691.pdf


    __float80 显然是 x87 10 字节类型。在 x86-64 SysV ABI 中,与long double 相同;在该 ABI 中两者都有 16 字节对齐。

    __float80 在 i386、x86_64 和 IA-64 目标上可用,并支持 80 位 (XFmode) 浮点类型。它是这些目标上类型名称 _Float64x 的别名。


    我认为__float128 是使用 SSE2 的扩展精度类型,大概是尾数宽度的两倍但与 64 位 double 相同的指数限制的“双双”格式。 (即小于__float80的指数范围)

    在 i386、x86_64 和 ... 上,__float128 是 _Float128 的别名

    这些可能与 gcc 为您提供的 __float128 相同的 doubledouble。或者也许它是一个纯软件浮点 128 位


    Godbolt compiler explorer 用于 gcc7.3 -O3(与 gcc4.6 相同,显然这些类型不是新的)

    //long double add_ld(long double x) { return x+x; }  // same as __float80
    __float80 add80(__float80 x) { return x+x; }
    
        fld     TBYTE PTR [rsp+8]    # arg on the stack
        fadd    st, st(0)
        ret                          # and returned in st(0)
    
    
    __float128 add128(__float128 x) { return x+x; }
    
              # IDK why not movapd or better movaps, silly compiler
        movdqa  xmm1, xmm0           # x arg in xmm0
        sub     rsp, 8               # align the stack
        call    __addtf3             # args in xmm0, xmm1
        add     rsp, 8
        ret                          # return value in xmm0, I assume
    
    
    int size80 = sizeof(__float80);    // 16
    int sizeld = sizeof(long double);  // 16
    
    int size128 = sizeof(__float128);  // 16
    

    所以 gcc 调用一个 libgcc 函数来进行 __float128 加法,而不是将增量内联到指数或任何类似的聪明东西。

    【讨论】:

    • __float128 是 not double double,至少在 x86_64 上它是 ieee binary128 的软件实现。在 Power 计算机上,long double 传统上是 double-double 类型,但它们正在远离它。
    • @MarcGlisse:我很难找到_Float128_Float128x 的定义。所以_Float128 是ieee binary128,但_Float128x 是什么?如果您有时间,请随时编辑此答案。
    • _Float128x 应该是与 IEEE binary128 关联的扩展格式。 IE。它至少应具有 binary256 的指数宽度(即 emax ≥ 65535)和 binary128 和 binary256 之间的精度(特别是 p 位≥ 128)。有关这些扩展格式的详细信息,请参阅 IEEE 754-2019 的第 3.7 节(2008 年修订版中的相同部分)。 _Float128x_Float128 之间的对应关系几乎与 gcc 上的 __float80double 相同——除了在 __float80 中显式存储的有效数字的 MSB,它不是 IEEE - 兼容。
    【解决方案2】:

    我找到了answer here

    __float80 可用于 i386、x86_64 和 IA-64 目标,并支持 80 位 (XFmode) 浮点类型。它是这些目标上类型名称 _Float64x 的别名。

    查看了XFmode

    “扩展浮点”模式表示 IEEE 扩展浮点数。这种模式只有 80 个有意义的位(十个字节)。一些处理器要求将这些数字填充到 12 个字节,而另一些则需要填充到 16 个字节;此模式用于任何一个。

    还是不完全相信,我编译了一些简单的东西

    int main () {
        __float80 a = 1.445839898;
        return 1;
    }
    

    使用雷达我把它扔了,

    0x00000652      db2dc8000000   fld xword [0x00000720]
    0x00000658      db7df0         fstp xword [local_10h]
    

    我相信fldfstpx87 指令集的一部分。所以它确实被用于__float80 10 字节浮点数,但是在__float128 上,我得到了

    0x000005fe      660f6f05aa00.  movdqa xmm0, xmmword [0x000006b0]
    0x00000606      0f2945f0       movaps xmmword [local_10h], xmm0
    

    所以我们可以在这里看到我们正在使用 SIMD xmmword

    【讨论】:

    • 它可能会使用 SIMD 来移动数据,但这并不意味着它会真正使用它来进行实际操作。
    猜你喜欢
    • 2018-09-13
    • 2012-03-04
    • 2015-07-20
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    • 2021-03-27
    • 2022-01-13
    • 2018-05-02
    相关资源
    最近更新 更多