如果你需要编译-O0
,然后在一条语句中执行尽可能多的操作。在正常代码中,int a=foo(); bar(a);
将编译为与以下相同的 asmbar(foo())
, 但在-O0
代码,第二个版本可能会更快,因为它不会将结果存储到内存中,然后为下一条语句重新加载它。
-O0
旨在通过调试提供最可预测的结果,这就是为什么在每个语句之后所有内容都存储到内存中的原因。这对于性能来说显然是可怕的。
I wrote 前段时间有个大回答 https://stackoverflow.com/a/32001196/224132对于像您这样的愚蠢任务的其他人提出的不同问题,需要他们进行优化-O0
。其中一些可能会有所帮助。
不要在这项任务上太努力。可能您发现的大多数“技巧”可以使您的代码运行得更快-O0
只会对-O0
,但启用优化后没有区别。
在现实生活中,代码通常使用 clang 或 gcc 编译-O2
至少,有时-O3 -march=haswell
或任何自动矢量化的东西。 (调试完成后,您就可以进行优化了。)
回复:您的更新:
现在它可以编译了,可以看到 SSE 版本中可怕的 asm。我把它在 godbolt 上以及实际编译的标量代码版本 http://gcc.godbolt.org/#compilers:!((compiler:g530,options:%27-xc+-O0+-Wall+-fno-verbose-asm%27,sourcez:MQSwdgxgNgrgJgUwAQB4QFt3gC4CdwB0AFgHwBQoksiq6AhtkceZdPMigGZQD2DzZMjiQBzBNgD6nXAgCOEgM4Q6UOrgAUEHmAXYk3PtgBUSenhAAPADT7eDJADcVMBDYUKQALwQS9IiQhQCOgIYNgKAJRIAN6CSPFIwtJySAC8SAAMANxxCZw8uEjq7l4%2BeiBpmVmJqKIBQSFhCtUgANStUbEJ3YmcRZx0AEYKnOpm%2BBYA2iAAukgAtI7OCFEo6QBiADIAKhIAogAKAMoAkpsA8gBynWQ9d/oysu0590gAvrcJH5/xMtgwuDADzkOW%2BwEQnHAyAA4ntthcAIIAEXUYCiEgk6AAjAAmAAcSDscGAwCB6Ux6AkRIkAAcFOoAGTjSzTJCtJAAFiQJjAMwiFAhUKQsO2ewAigBVVHozG4gkQIgICAAaxJZKQFIkdDAcFp9M1EHQNLkevURLVNicsBWNm1uqtLn54IQkLAMLhAGFzhLLttpUgtDAwpVNXQ4Lq6ZoeEHsDYFUrVaT%2BT9EsGxJJkrIozo9AYGCZmdZbIZRCAHKEAGrLNweby%2BOqBYKhcI3FPdJKPSrZNsJYQgHI9%2BIY7H4pbWkOYRTiLGmkRlyvLCIve7DuUB6PB8mThTiby4HimpeDjWy0d2iQO5Bbyk77AzyMZCwZZ8vjJYo%2B5O75QrqCrpbI1OyWIAKy1P4jaNOELRsukWIAGw3K83QioiKIZEuwpwqh6jvtUKHnMi6g4hh%2BGEQAzEeSEJCK4pSuh1SYaKko4RhjG0URrE0cxFHLlRIpej6fr0fx3q%2BixWQiYJHESZ6ol%2Bjxx7fK8q6jgoRAwJw3A%2BHQE43upmlBKagZhHGG6xhqACyFkSEcAASErrFsew4TYGQ2GRNjEZR9zGXo15auGRlmW4%2BlaVq3l3CpBJqRpYWDLpiihYZka%2BaZMY2BIVk2fZjmbM5OLua5NjvhFPS%2BQlYYRvSqVIDFBk%2BIMpXdJmCUQA44QKIoIBkTiUYxh%2Bx7fkU0EoA2DTNs0iTtIhVG9P0QwjGMDATNMcyLHO5ZgFW1qrBsOz7McZxXDNs15I8zzHt0HyvEp9x/ACQKZrx7xAAAA%3D%3D)),filterAsm:(commentOnly:!t,directives:!t,intel:!t,labels:!t),version:3。内在函数通常在禁用优化的情况下编译得非常糟糕,内联函数仍然具有参数和返回值,从而导致实际加载/存储往返 https://stackoverflow.com/questions/54073295/why-is-this-c-wrapper-class-not-being-inlined-away(存储转发延迟)即使__attribute__((always_inline))
. See 禁用优化后,演示代码未能显示出 4 倍快的 SIMD 速度 https://stackoverflow.com/questions/27075540/demonstrator-code-failing-to-show-4-times-faster-simd-speed-with-optimization-di例如。
标量版本的结果要好得多。它的源在一个表达式中完成所有操作,因此临时值保留在寄存器中。不过,循环计数器仍然在内存中,例如,在 Haswell 上,它的瓶颈最多为每 6 个周期一次迭代。 (参见x86 /questions/tagged/x86标记 wiki 以获取优化资源。)
顺便说一句,矢量化fabsf()
很容易,看使用 SSE 计算绝对值的最快方法 https://stackoverflow.com/questions/32408665/fastest-absolute-value-calculator-using-sse/32422471#32422471。与小于的 SSE 比较应该可以为您提供与标量代码相同的语义。 (但更难获得-O0
为了不吸)。
您可能会做得更好,只需手动展开标量版本一两次,因为-O0
太糟糕了。