0

我很有趣,如果我在现代 C++ 中使用内联汇编和现代编译器(如 GCC 4.7 和 VS12),我现在会有什么好处吗?例如矢量化和一些小的优化?或者这只是顽皮,现代优化编译器在任何范围内使用它都没有给我什么?

4

4 回答 4

3

内联汇编的使用使您的代码架构特定。即使对于类似的东西vectorization,您现在也依赖于执行此代码的目标需要支持这些特殊/增强指令集的事实。

假设有人试图将您的代码从 移植x86ARM,他们将很难处理。

我建议有一种机制,您可以通过该机制检测目标是否支持 SSE2 或 SSE3 等向量指令集,并执行优化的代码,并在不支持增强指令集的目标上运行故障安全代码。

例如,Linux 内核将arch目录下的所有体系结构特定代码抽象出来,并且针对不同体系结构存在相同功能的实现。如果您知道您的代码可能会在多个不同的架构上执行,您可以通过提出自己的抽象来做类似的事情。

于 2013-03-02T23:47:50.113 回答
2

与许多事情一样,这取决于。

对于您可能编写的大多数代码,内联汇编不太可能有帮助。现代编译器相当聪明,并且通常会生成至少与您可以编写的任何代码一样好的代码。(而且它们生成它的速度也比你编写和调试它的速度要快得多。)

正如您所猜到的,例外是编写某些矢量代码。虽然一些编译器会尝试对某些循环进行矢量化,但它们的工作不如熟练的人。在某些应用(例如,DSP、视频编码等)中,这可能会产生重大影响。但是,这需要您对所编码的处理器有详细的了解——写得不好的向量代码通常会比编译器提供的标量代码执行得更差!

底线:除非您有充分的理由相信您需要编写内联汇编,否则请避免使用它。

于 2013-03-02T23:49:04.790 回答
1

通常,您要寻找的是对特定指令进行薄包装的内在函数。

这使您可以在不放弃 C++ 的类型安全的情况下访问例如向量指令,同时保留与内联汇编提供的类似程度的控制。本质上,使用内在函数,您可以选择要使用的指令,但编译器会执行寄存器分配。

于 2013-03-02T23:54:46.113 回答
0

这个问题的答案有点像英语表达“一段字符串有多长”——如果不实际展开整段字符串,就无法轻易回答。同样在这里,不知道代码实际上应该做什么,很难说是否有好处。

我的一般做法是使用 C 或 C++ 编写代码,然后看看编译器做了什么。如果它足够快[无论定义为什么],那么就不需要做任何其他事情。如果速度不够,请查看代码,看看是否有任何琐碎的算法优化,或简化,拆分函数以避免代码中间出现 if 语句等。分析代码,看看在哪里它正在花费时间。

在改进的每一步之后[测量并跟踪更改、设置等-我通常有电子表格,其中包含“有了这个改变,它的运行速度提高了 4%”、“有了这个,它的运行速度降低了 2%”]。

一旦你用尽了所有其他选项,那么你就可以开始考虑内联汇编了。有时,如果你“做正确的事”,可能会有很大的改进。在其他时候,根本没有太多收获。

我最近写了一些内存基准测试,使用gcc. 当我使用volatile(强制内存写入实际发生)时,编译器产生了相当垃圾的代码,所以当我在内联汇编器中编写相应的代码时,它快了 3-4 倍。但是,一旦我重新排列代码以在内存写入本身之后的一步中实际使用写入内存,并删除volatile,编译器就和我的 SSE2 代码一样好。

对于复杂的 SSE 代码,我仍然认为编译器在某些情况下会有所欠缺,但它有时会非常聪明——它肯定会将简单循环优化为完整的 SSE2 代码。

我发现的最大收获是当编译器根本不理解你真正想要发生的事情时[或者它不能为你想要的操作生成正确的代码]。非时间移动就是一个例子——你不想在缓存中存储一​​些东西,因为你知道它在缓存中无论如何都不会有用。

于 2013-03-02T23:52:52.427 回答