3

我只是想知道 MSVC++ 编译器如何优化代码(带有代码示例)或者他不能优化什么以及为什么。

例如,我使用了类似这样的 SSE-intrinsics(var 是一个 __m128 值)(它用于截头体剔除测试):

if( var.m128_f32[0] > 0.0f && var.m128_f32[1] > 0.0f && var.m128_f32[2] > 0.0f && var.m128_f32[3] > 0.0f ) {
    ...
}

当我查看 asm 输出时,我看到它确实编译成一个丑陋的非常跳跃的版本(而且我知道 CPU 只是讨厌快速跳跃)而且我也知道我可以使用 SSE4.1 PTEST 指令对其进行优化,但是为什么编译器不这样做(即使编译器编写者定义了 PTEST 内在函数,所以他们知道指令)?

它也不能做哪些优化(直到现在)。

这是否意味着我使用当今的技术被迫使用内在函数和内联 ASM 以及链接的 ASM 函数,并且编译器会找到这样的东西(我不这么认为)?

我在哪里可以阅读更多关于 MSVC++ 编译器优化的信息?

(编辑 1): 我使用了 SSE2 开关和 FP:fast 开关

4

5 回答 5

4

编译器的默认设置被设置为生成将在“最低公分母”CPU 上运行的代码——即没有 SSE 4.1 指令的代码。

您可以通过仅在构建选项中针对以后的 CPU 来更改它。

也就是说,在SSE 优化方面,MS 编译器传统上并不是“最好的” 。我什至不确定它是否支持 SSE 4。该链接在 SSE 优化方面对 GCC 给予了很好的评价:

作为关于 GCC 在代码生成方面近乎完美的旁注——看到它甚至超过了英特尔自己的编译器,我感到非常惊讶

也许您需要更改编译器!

于 2010-07-14T23:04:05.783 回答
2

您可能想尝试英特尔的 ICC 编译器 - 根据我的经验,它生成的代码比 Visual C++ 好得多,尤其是对于 SSE 代码。您可以从 intel.com 获得 30 天免费评估许可证。

于 2010-07-14T22:28:46.323 回答
1

您可以激活编译代码的 asm 视图并查看自己生成的内容。

于 2010-07-14T22:29:40.753 回答
0

在http://lambda-the-ultimate.org/node/3674查看演示文稿

总结:编译器现在通常会做很多令人惊叹的技巧,甚至是看起来通常与命令式编程无关的事情,比如尾调用优化。MSVC++ 不是最好的,但看起来还不错。

于 2010-07-14T22:46:44.500 回答
0

除非您可以使用条件移动,否则 Ïf 语句会生成条件跳转,但这更有可能是在手写汇编中完成的。有一些规则可以控制 CPU 的条件跳转假设(分支预测),因此按照规则运行的条件跳转的惩罚是可以接受的。然后是乱序执行使事情变得更加复杂:)。底线是,如果您的代码是直截了当的,那么最终发生的跳转不会影响性能。您可以查看 Agner Fog 的优化页面

C 代码的非调试编译特别应该生成四个条件跳转。逻辑与 (&&) 和括号的使用将导致从左到右的测试,因此一个 C 优化可能是首先测试最有可能大于 0.0f 的 f32(如果可以确定这样的概率)。您有五种可能的执行变体:test1 true 采用分支 (t1tbt)、test1 false 无分支 (t1fnb) test2 true 分支采用 (t2tbt) 等,给出以下可能的序列

t1tbt                      ; var.m128_f32[0] <= 0.0f
t1fnb t2tbt                ; var.m128_f32[0] >  0.0f, var.m128_f32[1] <= 0.0f
t1fnb t2fnb t3tbt          ; var.m128_f32[0] >  0.0f, var.m128_f32[1] >  0.0f,
                           ; var.m128_f32[2] <= 0.0f
t1fnb t2fnb t3fnb t4tbt    ; var.m128_f32[0] >  0.0f, var.m128_f32[1] >  0.0f,
                           ; var.m128_f32[2] >  0.0f, var.m128_f32[3] <= 0.0f
t1fnb t2fnb t3fnb t4fnb    ; var.m128_f32[0] >  0.0f, var.m128_f32[1] >  0.0f
                           ; var.m128_f32[2] >  0.0f, var.m128_f32[3] >  0.0f

只有采用的分支会导致流水线中断,分支预测将尽可能减少中断。

假设浮点数的测试成本很高(它们是),如果 var 是一个联合并且您精通浮点输入和输出,您可能会考虑对重叠类型进行整数测试。例如,存储值 1.0f 占用存储为 0x00、0x00、0x80、0x3f (x86/little-endian) 的四个字节。将此值读取为长整数将给出 0x3f800000 或 +1065353216。0.0f 是 0x00、0x00、0x00、0x00 或 0x00000000(长)。负浮点值与正浮点值具有完全相同的格式,除了设置了最高位 (0x80000000)。

于 2011-04-14T08:23:32.237 回答