【发布时间】:2013-04-03 04:55:47
【问题描述】:
我正在检查一些使用 /fp:precise 和 /fp:fast 标志的代码。
根据MSDN documentation为/fp:precise:
在 x86 处理器上使用 /fp:precise 时,编译器将对 float 类型的变量执行舍入,以达到赋值和强制转换以及将参数传递给函数时的正确精度。这种舍入保证数据不会保留任何大于其类型容量的意义。使用 /fp:precise 编译的程序可能比没有 /fp:precise 编译的程序更慢和更大。 /fp:precise 禁用内在函数;而是使用标准运行时库例程。有关详细信息,请参阅 /Oi(生成内部函数)。
查看对sqrtf的调用的反汇编(使用/arch:SSE2调用,目标x86/Win32平台):
0033185D cvtss2sd xmm0,xmm1
00331861 call __libm_sse2_sqrt_precise (0333370h)
00331866 cvtsd2ss xmm0,xmm0
来自this question 我相信现代 x86/x64 处理器不使用 80 位寄存器(或至少不鼓励使用它们),因此编译器执行我认为是次优的操作并使用 64- 进行计算位双打。由于内部函数被禁用,因此调用了库 sqrtf 函数。
好的,很公平,这似乎符合文档所说的内容。
但是,当我为 x64 架构编译时,发生了一些奇怪的事情:
000000013F2B199E movups xmm0,xmm1
000000013F2B19A1 sqrtps xmm1,xmm1
000000013F2B19A4 movups xmmword ptr [rcx+rax],xmm1
不使用 64 位双精度执行计算,而是使用内部函数。据我所知,结果与使用/fp:fast 标志完全相同。
为什么两者之间存在差异? /fp:precise 是否根本不适用于 x64 平台?
现在,作为健全性检查,我在 VS2010 x86 中使用 /fp:precise 和 /arch:SSE2 测试了相同的代码。令人惊讶的是,sqrtpd 内部函数正在被使用!
00AF14C7 cvtps2pd xmm0,xmm0
00AF14CA sqrtsd xmm0,xmm0
00AF14CE cvtpd2ps xmm0,xmm0
这里发生了什么?为什么VS2010使用intrinsic而VS2012调用系统库?
针对 x64 平台的 VS2010 测试结果与 VS2012 相似(/fp:precise 似乎被忽略了)。
我无法访问任何旧版本的 VS,因此无法在这些平台上进行任何测试。
作为参考,我正在使用 Intel i5-m430 处理器的 Windows 7 64 位进行测试。
【问题讨论】:
-
这真的很奇怪。我知道
/fp:precise有时会导致编译器酌情将中间体提升到更高的精度。但这并不能解释这里的完全不一致。 -
“从这个问题我相信 x86 架构没有 80 位寄存器”再来一次?
-
是的,奇怪的措辞。更新以阐明反对使用它们的一般建议。
-
@PascalCuoq 回复对您(已删除)答案的评论。有 3 种模式,
precise、fast和strict。 AFAIK,precise表示编译器将尝试生成尽可能精确的结果。 (可能以性能为代价)fast是不言自明的,与 GCC 的ffast-math相同。strict严格遵循 IEEE。
标签: c visual-studio-2010 visual-studio-2012 floating-point sse