我正在编写一个性能关键、数字运算的 C++ 项目,其中 200 行核心模块使用了 70% 的时间。
我想使用内联汇编优化核心,但我对此完全陌生。但是,我确实知道一些 x86 汇编语言,包括 GCC 和 NASM 使用的那种。
据我所知:
我必须将汇编指令放在_asm{}
我想要的位置。
问题:
- 我不知道从哪里开始。在我的内联汇编开始起作用的那一刻,哪个寄存器是什么?
我正在编写一个性能关键、数字运算的 C++ 项目,其中 200 行核心模块使用了 70% 的时间。
我想使用内联汇编优化核心,但我对此完全陌生。但是,我确实知道一些 x86 汇编语言,包括 GCC 和 NASM 使用的那种。
据我所知:
我必须将汇编指令放在_asm{}
我想要的位置。
问题:
您可以按名称访问变量并将它们复制到寄存器中。这是来自 MSDN 的示例:
int power2( int num, int power )
{
__asm
{
mov eax, num ; Get first argument
mov ecx, power ; Get second argument
shl eax, cl ; EAX = EAX * ( 2 to the power of CL )
}
// Return with result in EAX
}
在 ASM 块中使用 C 或 C++可能对您来说也很有趣。
当涉及内联汇编时,微软编译器的优化非常差。它必须备份寄存器,因为如果您使用 eax,那么它不会将 eax 移动到另一个空闲寄存器,它将继续使用 eax。GCC 汇编器在这方面要先进得多。
为了解决这个问题,微软开始提供内在函数。这些是进行优化的更好方法,因为它允许编译器与您一起工作。正如克里斯提到的那样,内联汇编在 x64 下与 MS 编译器也不起作用,所以在那个平台上,你真的最好只使用内在函数。
它们易于使用并具有良好的性能。我承认我经常可以通过使用外部汇编器来挤出更多的周期,但它们对于它们提供的生产力提高非常有好处
寄存器中没有任何内容。随着 _asm 块的执行。你需要把东西移到寄存器中。如果有一个变量:'a',那么你需要
__asm {
mov eax, [a]
}
值得指出的是,VS2010 自带了微软的汇编器。右键单击一个项目,转到构建规则并打开汇编程序构建规则,然后 IDE 将处理 .asm 文件。
这是一个更好的解决方案,因为 VS2010 支持 32 位和 64 位项目,而 __asm 关键字在 64 位版本中不起作用。对于 64 位代码,您必须使用外部汇编程序:/
我更喜欢在汇编中编写整个函数而不是使用inline
汇编。这使您可以在构建过程中将高级语言函数替换为汇编语言函数。此外,您不必担心编译器优化会妨碍您。
在你写一行汇编之前,打印出你的函数的汇编语言列表。这为您提供了构建或修改的基础。另一个有用的工具是汇编与源代码的交织。这将告诉您编译器如何对特定语句进行编码。
如果您需要为大型函数插入内联汇编,请为需要内联的代码创建一个新函数。在构建期间再次替换为 C++ 或程序集。
这些是我的建议,您的里程可能会有所不同 (YMMV)。
我真的很喜欢组装,所以我不会在这里反对。您似乎已经分析了您的代码并找到了“热点”,这是正确的开始方式。我还假设有问题的 200 行不使用很多高级结构,例如vector
.
我必须给出一点警告:如果数字运算涉及浮点数学,那么您将进入一个痛苦的世界,特别是一整套专门的指令,以及大学学期的算法学习。
所有这一切:如果我是你,我会在 VS 调试器中使用反汇编视图逐步检查有问题的代码。如果您在阅读代码时感觉很舒服,那是一个好兆头。之后,进行发布编译(调试关闭优化)并为该模块生成 ASM 列表。然后,如果你认为你看到了改进的空间......你有一个开始的地方。其他人的答案已链接到 MSDN 文档,该文档确实非常简陋,但仍然是一个合理的开始。
先去寻找低垂的果实...
正如其他人所说,微软编译器在优化方面很差。只需投资一个体面的编译器(例如英特尔的 ICC)并“按原样”重新编译代码,您就可以为自己节省很多精力。您可以从英特尔获得 30 天免费评估许可证并试用。
此外,如果您可以选择构建 64 位可执行文件,那么在 64 位模式下运行可以提高 30% 的性能,因为可用寄存器的数量增加了 2 倍。