【问题标题】:Intel x86_64 assembly compare signed double precision floatsIntel x86_64 程序集比较有符号双精度浮点数
【发布时间】:2016-06-11 16:37:16
【问题描述】:

根据主题,我遇到了问题。

在 xmm0 寄存器中,我有一个值,例如-512.000000
在 xmm4 中:0.000000.

我尝试将第一个值与零进行比较,但我无法真正做到这一点。

comisd xmm0, xmm4

COMISD 指令以一种奇怪的方式设置标志,只有 jnz 之后才能在我的代码中正常工作。

我该如何进行这种比较?

【问题讨论】:

    标签: assembly x86-64 intel precision sse


    【解决方案1】:

    英特尔的手册记录了COMISD 如何设置标志。

    首先,使用jp 检查无序(如果您希望代码对 NaN 输入正常工作)。

    然后你可以使用ja/jae/jb/jbe(上/下)条件或其否定(jna等)或je/jne (等于/不等于)。这些条件与无符号整数比较的条件相同。显然 cmovcc 和 setcc 也可以。

    这些条件具有类似 jc 的同义词(如果 CF==1 则跳转),但上方/下方具有正确的语义含义,因此可以减少使您的代码具有人类可读性所需的 cmets 数量。

    您可以在ja 等条件之前跳过jp,因为CF=0 意味着PF=0。 (即,如果操作数是无序的,a 条件将为假)。

    其他一些条件,例如b(以下:CF=1)或be(CF=1 或 ZF=1),对于无序操作数将成立,因此您需要在 jp 之前或jb / jbe 之后,如果您需要排除 NaN 输入。

    如果我的逻辑正确,您可以反转比较操作数以允许使用 ja 而不是 jbe(例如)并将无序大小写与其他“方式”分组。


    历史兴趣/为什么这样设计:

    请注意,comisd 的标志设置与您从 x87 获得的 fcom / fnstsw ax / sahf 匹配。另见this x87 tutorial/guide for an example of using that sequence。但仅出于历史兴趣! fcomi,它也以同样的方式设置标志,已经存在了 20 多年 (P6),而且速度更快。 (有关更多链接,请参阅 标签 wiki)。

    x87 仅对 80 位扩展精度有用,因为假设 SSE2 可用通常是安全的,即使在 32 位模式下也是如此。

    另请参阅Why do x86 FP compares set CF like unsigned integers, instead of using signed conditions?,以更详细地了解 x87 使用这些标志的原因,fcomi 和 SSE 保持兼容。

    【讨论】:

    • 我的理解是:jae=jnc(它只测试CF=0),所以如果操作数是nan,那就是假的。 ja 等价于 CF=0 和 ZF=0,所以在 nan 的情况下也是 false。所以我们可以同时使用这两种方法并遵守 IEEE754 标准。对于 jb 和 jbe,我们可以交换参数并替换为 ja 和 jae (a b > a) 从而避免 a jp。
    • @aka.nice。谢谢你抓住那个。我认为反转比较操作数确实允许将无序的情况与其他“方式”分组,所以也提到了这一点。
    【解决方案2】:

    这里有Intel's IA-32 manual。 在第 689 页上是 COMISD 描述,它指出:

    RESULT ← OrderedCompare(DEST[63:0] ≠ SRC[63:0]) {
    (* Set EFLAGS *) CASE (RESULT) OF
        UNORDERED:    ZF,PF,CF ← 111;
        GREATER_THAN: ZF,PF,CF ← 000;
        LESS_THAN:    ZF,PF,CF ← 001;
        EQUAL:        ZF,PF,CF ← 100;
    ESAC;
    OF, AF, SF ← 0; }
    

    在第 178 页也有描述哪个跳转指令基于 EFLAGS 寄存器的哪个标志(EFLAGS 在第 78 页描述)。

    JC (jump if carry) 仅在设置了 CF 标志时检查 - 如果是,则它可以是 less then 关系或 unordered

    编辑: - 删除错误答案以免误导任何人留下手册链接。

    【讨论】:

    • 在投票之前我并没有仔细阅读此内容。您将 EFLAGS 移至 EAX 的建议是一个坏主意,而且您的代码甚至无法正常工作。您不能 mov 与 EFLAGS 往来。有lahf(从标志中加载啊),它包括除了溢出之外的所有条件标志。但是如果你要使用多个指令来测试标志,只需jp 排除NaN,然后​​使用正常条件。
    • @Peter 我必须同意你的看法。您的解决方案在概念和进行比较的正确方法上更加清晰。作为我错误答案的借口,我只能说我是在半夜写的。给大家带来的不便很抱歉。也许有人会使用完整的手册链接。
    • 您仍然可以对其进行编辑以改进它!也许只保留手册中的引号和一些文字。 (即取出所有错误的部分)。我之前写过一些完全错误的答案,不得不进行重大修改来修复它们:P
    【解决方案3】:

    COMISD 的一个常见问题是它设置标志的方式与普通比较略有不同。因此,COMISD 将设置如下:

    大于:ZF:0, PF:0, CF:0

    等于:ZF:1, PF:0, CF:0

    小于:ZF:0, PF:0, CF:1

    因此,要衡量XMM0是否小于XMM4,需要做一个JC。

    相信这会有所帮助。

    【讨论】:

    • 写成ja/jb比较正常,就像一个无符号整数比较。看我的回答。
    猜你喜欢
    • 1970-01-01
    • 2016-06-30
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 2014-04-25
    • 1970-01-01
    • 2015-10-22
    • 1970-01-01
    相关资源
    最近更新 更多