2012-03-04 99 views
6

我正在编写一个编译器,我必须输出浮点值分支条件的代码。例如,要编译这种类型的代码:使用Intel SSE执行分支的最佳方式是什么?

if(a <= b){ 
    //1. DO something 
} else { 
    //2. Do something else 
} 

当a和b是浮点型变量时。我只需要跳到2,如果条件不是真的,否则会下降到1.我在这里考虑在编译器级别考虑1和2中的优化。

我需要一些适用于所有比较运算符>,> =,<,< =,==和!=

我发现进行比较的一种方法是使用CMPLTSD(以及其他关系运算符的等效指令)。但是有了这个,我必须使用一个SSE寄存器,特别是结果,然后我必须将它的值移到通用寄存器(例如eax)上,最后将其与0进行比较。

我还看到UCOMISD指令应该正确地设置标志,但显然它不按我想的方式工作。

那么,处理这样的代码的最好方法是什么?是否有比我拥有的第一个解决方案更好的说明?

最好,我的意思是,这个问题的一般解决方案。如果可能的话,我希望代码的行为与整数比较(cmp a,b; jge label)时的行为相同。当然,我宁愿用最快的指令来实现这一点。

+2

最好的办法*取决于你在做什么*。如在里面,'// DO something'块里面是什么? “最好的方式”通常取决于看整张图片,而不是试图逐行翻译你的代码。 – jalf 2012-03-04 19:48:43

+0

我在帖子中添加了详细信息来回答你的两个问题。 – 2012-03-04 19:56:42

+1

如果你真的想分支,UCOMISD(实际上是SSE2)似乎是答案,它有什么问题?无序的结果? – harold 2012-03-04 20:02:21

回答

7

ucomisd的条件代码不对应于有符号整数比较代码,但不对应于无符号整数(在奇偶标志中带有“无序”)。我承认这有点奇怪,但都清楚地记录在案。 的代码,如果你真的想分支可能是这样的<=

ucomisd a,b 
    ja else  ; greater 
    jp else  ; unordered 
    ; code for //1 goes here 
    jmp end 
else: 
    ; code for //2 goes here 
end: 

对于<

jae else ; greater or equal 
jp else ; unordered 

我可以列出所有这些,如果你真的想,但你可以看看ucomisd的条件代码并将它们匹配到您需要的跳转。

+0

这确实很奇怪......但我想我会将它与文档结合起来。非常感谢。 – 2012-03-04 20:28:05

1

重要:@哈罗德的回答几乎是完全正确的,但有一个微妙的错误方面,这可能会让你发疯了非常重要的边缘情况以后 - NaN的治疗是向后从大多数语言(如C++)。

正如@harold所说的,无序比较结果存储在奇偶标志中。

但是,无序比较在任何操作数是NaN时为真,详见this stack overflow post。这意味着NaN将小于,等于和大于绝对每个数字包括NaN

所以,如果你希望你的语言以匹配C++的,其中与南任何比较返回假行为,你想:

对于<=

ucomisd xmm0, xmm1 
jbe else_label 

对于<

ucomisd xmm0, xmm1 
jb else_label 

在以下gcc反汇编中确认,其中I return a >= b

144e:  66 0f 2e c8    ucomisd %xmm0,%xmm1 
1452:  0f 93 c0    setae %al 

这里它使用setae这是修改注册等效于jae。然后立即返回而不检查奇偶标志。

为什么它的ja而不是jg,@哈罗德的回答仍然是一个清晰和正确的解释。

当然,你不必使用有序的比较,你可以用无序在以前的答案比较如图所示,如果你想绝对是每个数比小于,大于等于NaN在你的程序/语言(即使NaN < NaN是真的!)。当然,正如你所看到的,它可能会慢一点,因为它需要额外的检查。

相关问题