Strange / fp浮点模型标志行为

时间:2013-04-03 04:55:47

标签: c visual-studio-2010 visual-studio-2012 floating-point sse

我正在检查一些使用/fp:precise/fp:fast标记的代码。

根据/fp:precise的{​​{3}}:

  

使用/ fp:精确地在x86处理器上,编译器将对float类型的变量执行舍入,以便为赋值和强制转换以及将参数传递给函数时具有适当的精度。这种舍入保证了数据不会保留大于其类型容量的任何重要性。使用/ fp:precise编译的程序可以比没有/ fp:precise编译的程序更慢更大。 / fp:exact禁用内在函数;而是使用标准的运行时库例程。有关更多信息,请参阅/ Oi(生成内部函数)。

查看对sqrtf的调用的反汇编(使用/arch:SSE2调用,定位x86/Win32平台):

0033185D  cvtss2sd    xmm0,xmm1  
00331861  call        __libm_sse2_sqrt_precise (0333370h)  
00331866  cvtsd2ss    xmm0,xmm0  

来自MSDN documentation我相信现代的x86 / x64处理器不使用80位寄存器(或者至少不鼓励使用它们),所以编译器做了我认为是下一个最好的事情,并用64位双打。因为内在函数被禁用,所以调用了一个库sqrtf函数。

好的,相当公平,这似乎符合文档所说的内容。

然而,当我为x64 arch编译时,会发生一些奇怪的事情:

000000013F2B199E  movups      xmm0,xmm1  
000000013F2B19A1  sqrtps      xmm1,xmm1  
000000013F2B19A4  movups      xmmword ptr [rcx+rax],xmm1  

不使用64位双精度执行计算,并且正在使用内在函数。据我所知,结果与使用/fp:fast标志的结果完全相同。

为什么两者之间存在差异? /fp:precise根本不适用于x64平台吗?

现在,作为一项完整性检查,我使用/fp:precise/arch:SSE2在VS2010 x86中测试了相同的代码。令人惊讶的是,正在使用sqrtpd内在函数!

00AF14C7  cvtps2pd    xmm0,xmm0  
00AF14CA  sqrtsd      xmm0,xmm0  
00AF14CE  cvtpd2ps    xmm0,xmm0 

这里发生了什么?为什么VS2010在VS2012调用系统库时使用内在函数?

针对x64平台测试VS2010的结果与VS2012类似(/fp:precise似乎被忽略)。

我无法访问任何旧版本的VS,因此我无法在这些平台上进行任何测试。

作为参考,我正在使用Intel i5-m430处理器在Windows 7 64位中进行测试。

1 个答案:

答案 0 :(得分:3)

首先,你应该阅读关于中间浮点精度的this非常好的博文。这篇文章只处理visual studio生成的代码(但这就是你的问题所在)。现在举例来说:

0033185D  cvtss2sd    xmm0,xmm1  
00331861  call        __libm_sse2_sqrt_precise (0333370h)  
00331866  cvtsd2ss    xmm0,xmm0  

此汇编代码已使用/fp:precise /arch:SSE2为x86平台生成。根据{{​​3}},精确浮点模型可以促进所有计算在x86平台上内部加强 。它还可以防止使用内在函数(我认为你已经阅读了documentation)。因此,代码以从float到double的转换开始,然后是双精度sqrt调用,最后将结果转换回float。

000000013F2B199E  movups      xmm0,xmm1  
000000013F2B19A1  sqrtps      xmm1,xmm1  
000000013F2B19A4  movups      xmmword ptr [rcx+rax],xmm1

第二个示例是针对x64(amd64)平台编译的,这个平台的行为完全不同!根据文件:

  

出于性能原因,中间运算是以任一操作数的最宽精度计算的,而不是以最宽的精度计算。

因此,计算将在内部以单精度完成。我认为他们也决定尽可能使用内在函数,因此/fp:precise/fp:fast之间的差异在x64平台上稍微 。新行为导致更快的代码它使程序员能够更好地控制究竟发生了什么(他们能够改变游戏规则,因为兼容性问题与新的x64平台无关)。遗憾的是,这些更改/差异未在文档中明确说明。

00AF14C7  cvtps2pd    xmm0,xmm0  
00AF14CA  sqrtsd      xmm0,xmm0  
00AF14CE  cvtpd2ps    xmm0,xmm0 

最后,最后一个示例是使用Visual Studio 2010编译器编译的,我认为他们不应该使用sqrt的内在函数,因为他们最好不要(至少在/fp:precise模式下),但他们决定改变/再次在Visual Studio 2012中修复此行为(请参阅this information)。