X86 什么';什么是cmpgt sd和其他类似方法的要点?

X86 什么';什么是cmpgt sd和其他类似方法的要点?,x86,sse,simd,intrinsics,X86,Sse,Simd,Intrinsics,我正在寻找一个SIMD选项来加速比较,我找到了函数\uuuuum128d\umm\ucmpgt\usd(\uuuuum128d a,\uuuuum128d b) 显然,它比较较低的double,并将较高的double从a复制到输出中。它所做的是有道理的,但有什么意义呢?这是想解决什么问题?重点可能是在非常旧的硬件上,例如英特尔奔腾II和III,\u-mm\u-cmpgt\u-sd()比\u-mm\u-cmpgt\u-pd()快。看阿格纳·福格的。这些处理器(PII和PIII)只有一个64位宽的浮

我正在寻找一个SIMD选项来加速比较,我找到了函数
\uuuuum128d\umm\ucmpgt\usd(\uuuuum128d a,\uuuuum128d b)


显然,它比较较低的double,并将较高的double从
a
复制到输出中。它所做的是有道理的,但有什么意义呢?这是想解决什么问题?

重点可能是在非常旧的硬件上,例如英特尔奔腾II和III,
\u-mm\u-cmpgt\u-sd()
\u-mm\u-cmpgt\u-pd()快。看阿格纳·福格的。这些处理器(PII和PIII)只有一个64位宽的浮点单元。128位宽的SSE指令作为两个64位微操作在这些处理器上执行。在较新的CPU(例如intel Core 2(Merom)和更新版本)上,
\u pd
\u ps
版本与
\u sd
\u ss
版本一样快。因此,如果只需比较单个元素,而不关心结果的高64位,则可能更喜欢
\u sd
\u ss
版本

此外,
\u mm\u cmpgt\u pd()
如果高位垃圾位意外包含
NaN
或低于正常值的数字,则可能引发伪浮点异常或性能下降,请参阅。尽管在实践中,在使用内部函数编程时,应该很容易避免这样的上层垃圾位


如果您想对代码进行矢量化,并且需要一个压缩的双重比较,那么请使用内在的
\u mm\u cmpgt\u pd()
,而不是
\u mm\u cmpgt\u sd()
cmpsd
是一条存在于asm中并在XMM寄存器上运行的指令,因此不通过内在函数公开它是不一致的。

(几乎所有压缩FP指令(除随机/混合指令外)都有标量版本,因此ISA设计也有一个一致性参数;它只是同一操作码的一个额外前缀,可能需要更多的晶体管,以应对操作码不支持标量版本的特殊情况。)

您或设计intrinsics API的人员是否能够想到一个合理的用例根本不是问题所在。在此基础上遗漏一些东西是愚蠢的;当有人提出一个用例时,他们将不得不使用内联asm或编写编译成更多指令的C

也许有一天,有人会发现一个用例,它的下半部分是一个掩码,而上半部分是一个仍然有效的
double
。e、 g.可能
\u mm\u和\u ps
返回到输入,有条件地仅将低元素
归零,而无需在高元素中进行压缩比较即可生成真值

或者认为所有的都是楠的一种模式,所有的零都是<代码> + 0 < /代码>的位模式。


如果任何元素低于正常值(如果您没有在MXCSR中设置DAZ位),IIRC,
cmppd
会减慢速度。至少在ISA设计时存在的一些旧CPU上。因此,对于FP比较而言,对于不关心的元素,使用标量版本对于避免虚假的FP辅助非常重要

也用于避免虚假的FP异常(或者设置异常标志,如果它们被屏蔽),比如在任一向量的上部元素中都有一个NaN

@wim还指出,Core2之前的Intel CPU将128位SIMD指令解码为2个UOP,每64位一半一个UOP。因此,当您不需要高半拍结果时,使用
cmppd
总是会比较慢,即使它不会出错。由于只有一个解码器可以处理多uop指令,因此在没有uop缓存的情况下,许多多uop指令很容易使CPU上的前端解码器出现瓶颈


您通常不会对FP标量指令(如
cmpsd
addsd
)使用内部函数,但它们存在于您需要的情况下(例如,作为水平求和的最后一步)。更常见的情况是,在编译标量代码而不进行自动矢量化时,将指令的标量版本留给编译器使用


对于标量比较,编译器通常希望得到EFLAGS中的结果,因此将使用
ucomisd
而不是创建比较掩码,但对于无分支代码,掩码通常很有用,例如对于
a
cmpsd
和PD
一起使用。(或者实际上是
和ps
,因为它较短,并且与无意义的
和pd
做相同的事情)

IIRC,
cmppd
可以接受FP辅助,如果上面元素中的垃圾表示低于正常的
。有些代码希望避免在比较可能的NAN时出现虚假的FP异常。但是如果您不关心高位,那么为什么不在正常数据类型(例如int、double等)上使用常规的旧比较运算符呢?因为您已经将一些数据(出于任何原因)加载到了一个广泛的寄存器中?我认为,如果您只需要一次比较,较高的目标位将保留其当前值,而不是从
a
@Jimbo复制位:实际上,最高的目标位保留其当前值,它们是未修改的。参见第750页,共:CMPSD(128位传统SSE版本)…
DEST[MAXVL-1:64](未经修改)
@Jimbo:注意,编译器可能会生成
cmpgtsd
cmpltsd
指令,即使是“正常双数据类型上的常规旧比较运算符”。看这个。由于
cmpltsd
指令存在,因此
\u mm\u cmpgt\u sd
也自然存在。此外,SIMD代码通常包含少量不可矢量化的标量代码。在这种情况下,可以方便地使用
\u mm\u cmpgt\u sd
\u mm\u add\u sd
等。Peter Cordes已经提到了
addsd
\u mm\u add\u sd
)作为水平和的最后一步。@wim关于英特尔SDM的一点。现在,如果您想要一个大的pdf来测试性能,那么有一个!Th