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

Cod*_*ard 35 c++ compiler-errors compiler-optimization visual-studio-2015

我们观察到一个奇怪的情况,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;
}
Run Code Online (Sandbox Code Playgroud)

对于说"循环省略"的行,编译器省略整个循环体.为什么?据我所知,没有涉及未定义的行为.


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

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
Run Code Online (Sandbox Code Playgroud)

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


在线尝试!


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

Cas*_*sey 24

是的,这是一个错误.具体来说,这是VS2015 Update 3中引入的新SSA优化器中的一个错误.未记录的命令行选项-d2SSAOptimizer-告诉编译器后端使用旧的优化器,这会导致错误无法显示.

仅供参考,您可以将您的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;
}
Run Code Online (Sandbox Code Playgroud)

这将有助于编译器开发人员更快地本地化问题.


来自Codeguard的加法(我认为Casey的回答应该是答案):我收到了微软的回复(Gratian Lup,博客文章的作者介绍了一个新的,高级的Visual C++代码优化器):

是的,这确实是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 Dev那里得到了如此详细的答案.不错的问题,来自@Casey的精彩回答以及MS的精彩回应. (4认同)
  • 我相信编译器开发人员最终会想出如何进一步减少自己...... :) (3认同)