Visual Studio 2015 Update 3 - C ++编译器错误?

时间:2017-06-22 14:56:40

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

我们观察到一个奇怪的情况,VS2015 Update3编译器会在没有明显原因的情况下省略部分代码。

我们发现了

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

我们设法将此代码段的罪魁祸首代码最小化:

#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

1 个答案:

答案 0 :(得分:24)

是的,这是一个错误。具体来说,这是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

仅供参考,您可以将您的repro最小化为:

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 的回答应该是答案): 我收到了微软的回复(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优化器将是一个不错的选择   解决方法。仅对此功能禁用优化可能是a   更好的方法,如果它不会减慢太多的东西。这可以   完成#pragma optimize(“”,off):   https://msdn.microsoft.com/en-us/library/chh3fb0k.aspx