【问题标题】:Visual Studio 2015 Update 3 - C++ Compiler bug?Visual Studio 2015 更新 3 - C++ 编译器错误?
【发布时间】:2017-11-25 22:36:57
【问题描述】:

我们观察到一个奇怪的情况,在 VS2015 Update3 编译器会无缘无故地省略部分代码。

我们发现

  • 这发生在 VS2015 Update3 中(帮助|关于说 14.0.25431.01 Update 3,cl.exe 版本 19.00.24215.1)
  • 这在 VS2015 Update2 中不会发生(帮助|关于说 14.0.25123.00 Update 2,cl.exe 版本 19.00.23918)
  • 只有在开启优化时才会发生这种情况(例如,在默认发布配置中)
  • 在 x86 和 x64 中都发生
  • 将代码 sn-p 插入全新的“Win32 控制台应用程序”时发生(我的意思是,不需要花哨的命令行选项)

我们设法最小化了这个 sn-p 的罪魁祸首代码:

#include <stdio.h>
#include <tchar.h>
#include <stdlib.h>

int _tmain(int, _TCHAR*[])
{
    volatile int someVar = 1;

    const int indexOffset = someVar ? 0 : 1;    // Loop omitted
    // const int indexOffset = !someVar;        // Loop omitted
    // const int indexOffset = 0;               // Good
    // const int indexOffset = 1;               // Good
    // const int indexOffset = someVar;         // Good
    // const int indexOffset = someVar + 1;     // Good

    for (int i = 1 - indexOffset; i < 2 - indexOffset; ++i)
    {
        printf("Test passed\n");
    }

    return 0;
}

对于说“省略循环”的行,编译器会省略整个循环体。为什么?据我所知,不涉及未定义的行为。


第一个“省略循环”的反汇编:

int _tmain(int, _TCHAR*[])
{
01151010  push        ebp  
01151011  mov         ebp,esp  
01151013  push        ecx  
    volatile int someVar = 1;
01151014  mov         dword ptr [ebp-4],1  

    const int indexOffset = someVar ? 0 : 1;    // Loop omitted
0115101B  mov         eax,dword ptr [someVar]  
    // const int indexOffset = !someVar;        // Loop omitted
    // const int indexOffset = 0;               // Good
    // const int indexOffset = 1;               // Good
    // const int indexOffset = someVar;         // Good
    // const int indexOffset = someVar + 1;     // Good

    for (int i = 1 - indexOffset; i < 2 - indexOffset; ++i)
    {
        printf("Test passed\n");
    }

    system("pause");
0115101E  push        offset string "pause" (011520F8h)  
01151023  call        dword ptr [__imp__system (0115205Ch)]  
01151029  add         esp,4  
    return 0;
0115102C  xor         eax,eax  
}
0115102E  mov         esp,ebp  
01151030  pop         ebp  
01151031  ret

测试项目:http://dropmefiles.com/S7mwT


在线试用!


错误报告:https://developercommunity.visualstudio.com/content/problem/71906/compiler-optimization-code-generation-bug.html

【问题讨论】:

  • 能否给出编译代码的命令行?我想试试最新的 MSVC 版本。也就是说,它绝对看起来像一个错误。您似乎也缺少包含。
  • “不工作”意味着没有打印消息,或者断点没有触发? FWIW,第一个“不起作用”情况的 main 汇编代码是什么?
  • 您缺少一些包含。 tchar.hwindows.hcstdio。这绝对是一个编译器错误 - 它适用于 MSVC x64 19.10.25019 (VS15 RTM) 和 19.11.25325 (VS15.3 Preview)。您应该升级您的编译器 - 不支持 MSVC 19.0。
  • @Codeguard -- 您正在查看 Visual Studio 本身的版本,而不是编译器版本。要获取编译器版本,请在命令行输入cl /?
  • 很多人声称发现了编译器错误,而实际上它是他们自己代码中的错误。看到一个可能编译器错误的,真是令人耳目一新!

标签: c++ visual-studio-2015 compiler-errors compiler-optimization


【解决方案1】:

是的,这是一个错误。具体来说,这是 VS2015 Update 3 中引入的新 SSA 优化器中的一个错误。The undocumented command line option -d2SSAOptimizer- tells the compiler backend to use the old optimizer instead, which causes the bug to not manifest

仅供参考,您可以将复制减少到:

int main()
{
    volatile int someVar = 1;

    const int indexOffset = someVar ? 0 : 1;

    for (int i = 1 - indexOffset; i < 2 - indexOffset; ++i)
    {
        return 0;
    }
    return 1;
}

这将有助于编译器开发人员更快地定位问题。


Codeguard 的补充(我认为 Casey 的答案应该是 THE 答案): 我收到了微软的回复(Gratian Lup,博文作者Introducing a new, advanced Visual C++ code optimizer):

是的,这确实是 SSA 优化器本身的一个错误 - 通常是大多数 报告为在新优化器中的错误在其他部分, 有时会在 20 年后暴露出来。

这是一个小选项。试图删除看起来像(a - Const1) CMP (a - Const2),如果没有溢出。问题是您的代码具有 (1 - indexOffset) CMP (2 - indexOffset) 和减法 当然,它不是可交换的——但优化器代码忽略了 并将 (1 - indexOffset) 当作 (indexOffset - 1) 处理。

此问题的修复将在下一次较大的更新中发布 VS2017。在那之前,禁用 SSA 优化器将是一个不错的选择 解决方法。仅禁用此功能的优化可能是 如果它不会使事情减慢太多,则更好的方法。这可以是 使用#pragma optimize("", off) 完成: https://msdn.microsoft.com/en-us/library/chh3fb0k.aspx

【讨论】:

  • 我相信编译器开发人员最终会想出如何进一步最小化自己... :)
  • 哇 - 我很惊讶你这么快就从 MS 开发人员那里得到了如此详细的答复。好问题,@Casey 的好回答和 MS 的好回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-25
相关资源
最近更新 更多