如何确保在gcc中内联lrint函数?

12

阅读相关文献后,有大量证据表明,在英特尔处理器上使用标准的C或C++强制类型转换将浮点数转换为整数非常缓慢。为了符合ANSI / ISO规范,英特尔CPU需要执行大量指令,包括需要切换FPU硬件的舍入模式。

有许多解决方法在各种文档中描述,但最清晰和最通用的方法似乎是在C99和C++ 0x标准中添加的lrint()函数调用。许多文档说,启用优化时编译器应该内联展开这些函数,从而产生比传统类型转换或函数调用更快的代码。

我甚至找到了有关gcc特性跟踪包以将此内联扩展添加到gcc优化器的参考资料,但在我的性能测试中,我无法使其正常工作。所有尝试都显示lrint性能比简单的C或C++风格强制类型转换要慢得多。检查编译器的汇编输出和反汇编编译的对象总是显示对外部lrint()或lrintf()函数的显式调用。

我正在使用的gcc版本是4.4.3和4.6.1,并且我已经尝试了许多针对32位和64位x86目标的标志组合,包括显式启用SSE的选项。

如何让gcc内联展开lrint并为我提供快速转换?


1
你是否实际进行了分析并确认使用明显的转换会占用程序运行时的大量时间? - Mark B
2
性能分析显示,使用从一篇文章中提取的手写汇编宏,我可以获得2-4%的速度差异。由于计算是在3D渲染应用程序的帧之间进行的,因此这是值得的。 - Al Riddoch
1
你设置了-fno-math-errno吗?你还应该考虑使用-ffast-math,但如果你依赖于特定的浮点语义,这并不总是一个选项... - Christoph
-fno-math-errno 看来就是解决问题的办法!谢谢Christoph。可以将其作为答案。 - Al Riddoch
2个回答

10

lrint()函数可能会引发域和范围错误。GNU C库处理此类错误的一种方式是设置errno(参见C99/C11第7.12.1节)。错误检查的开销可能相当显著,在这种特殊情况下,它似乎足以使优化器决定不进行内联。

使用gcc标志-fno-math-errno(这是-ffast-math的一部分)将禁用这些检查。如果您不依赖于符合标准的浮点语义处理,特别是NaN和无穷大,则探索-ffast-math可能是一个不错的主意...


0

你尝试过使用-finline-functions标志来编译gcc吗?

你还可以使用选项-finline-functions让GCC尝试将所有“足够简单”的函数集成到它们的调用者中。

请参见http://gcc.gnu.org/onlinedocs/gcc/Inline.html

在这里,你可以让gcc将所有函数都转换为内联函数,但并不是所有函数都会被转换为内联函数。编译器使用一些启发式方法来确定函数是否足够小以便内联。另外,递归函数也不会在此处内联。


我已经尝试了-finline-functions,但对编译器输出没有任何影响。 - Al Riddoch
如果您在代码中使用math库的lrint()函数,并通过gcc编译,则lrint()函数不会被内联,因为在这种情况下它将来自二进制链接库。这里的lrint()函数的代码不会被内联。 - Jeegar Patel
这份文件表明:http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html“ISO C99函数..... lrintf,lrintl,lrint ......被视为内置函数,除非在严格的ISO C90模式下(-ansi或-std=c90)。”文档更上面说:“许多这些函数只在某些情况下进行优化;如果它们在特定情况下没有被优化,则会发出对库函数的调用。”但我一直无法找出它们被优化的情况。 - Al Riddoch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接