C++ Visual Studio 2015更新3-C++;编译器错误?

C++ Visual Studio 2015更新3-C++;编译器错误?,c++,visual-studio-2015,compiler-errors,compiler-optimization,C++,Visual Studio 2015,Compiler Errors,Compiler Optimization,我们观察到一个奇怪的情况,在VS2015 Update3中,编译器会无明显原因地省略部分代码 我们发现 这种情况发生在VS2015更新3中(帮助| About表示14.0.25431.01更新3,cl.exe版本19.00.24215.1) 这在VS2015 Update2中不会发生(Help | About说的是14.0.25123.00 Update 2,cl.exe版本19.00.23918) 这仅在启用优化时发生(例如,在默认版本配置中) 发生在x86和x64中 当代码片段插入到全新的

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

我们发现

  • 这种情况发生在VS2015更新3中(帮助| About表示14.0.25431.01更新3,cl.exe版本19.00.24215.1)
  • 这在VS2015 Update2中不会发生(Help | About说的是14.0.25123.00 Update 2,cl.exe版本19.00.23918)
  • 这仅在启用优化时发生(例如,在默认版本配置中)
  • 发生在x86和x64中
  • 当代码片段插入到全新的“Win32 Console应用程序”中时发生(我的意思是,不需要花哨的命令行选项)
我们设法将罪魁祸首代码减少到这个片段:

#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*[])
{
volatile int-someVar=1;
const int indexOffset=someVar?0:1;//省略循环
//const int indexOffset=!someVar;//省略循环
//const int indexOffset=0;//良好
//const int indexOffset=1;//良好
//const int indexOffset=someVar;//很好
//const int indexOffset=someVar+1;//很好
对于(int i=1-indexOffset;i<2-indexOffset;++i)
{
printf(“测试通过\n”);
}
返回0;
}
对于表示“Loop省略”的行,编译器将省略整个循环体。为什么?据我所知,没有未定义的行为


第一个“省略循环”的拆解:

int\u tmain(int,\u TCHAR*[])
{
0115100推式ebp
01151011电动制动踏板,esp
01151013推动ecx
volatile int-someVar=1;
01151014 mov德沃德ptr[ebp-4],1
const int indexOffset=someVar?0:1;//省略循环
011510B mov eax,dword ptr[someVar]
//const int indexOffset=!someVar;//省略循环
//const int indexOffset=0;//良好
//const int indexOffset=1;//良好
//const int indexOffset=someVar;//很好
//const int indexOffset=someVar+1;//很好
对于(int i=1-indexOffset;i<2-indexOffset;++i)
{
printf(“测试通过\n”);
}
系统(“暂停”);
0115101E推送偏置串“暂停”(011520F8h)
01151023呼叫dword ptr[\uuuuu imp\uuuuu系统(0115205Ch)]
01151029添加esp,4
返回0;
0115102C异或eax,eax
}
0115102E mov esp,ebp
011510030波普ebp
01151031 ret

测试项目:


在线试试吧

  • 将示例代码放到编辑器中
  • /O2
    添加到
    其他编译器标志中
  • 检查
    编译后运行可执行文件


错误报告:

是的,这是一个错误。具体来说,这是VS2015更新3中引入的新SSA优化器中的一个缺陷

仅供参考,您可以将复制最小化为:

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;
}
intmain()
{
volatile int-someVar=1;
const int indexOffset=someVar?0:1;
对于(int i=1-indexOffset;i<2-indexOffset;++i)
{
返回0;
}
返回1;
}
这将帮助编译器开发人员更快地定位问题


来自Codeguard的添加(我决定Casey的答案应该是答案): 我收到了微软的回复(Gratian Lup,博客文章的作者):

是的,这确实是SSA优化器本身的一个缺陷——通常是最常见的 新优化器中报告的bug在其他部分, 20年后有时会暴露

这是在一个小的选择。它试图删除类似(a)的比较 -常数1)CMP(a-常数2),如果没有溢出。问题是代码有(1-indexOffset)CMP(2-indexOffset)和减法 当然不是可交换的,但是优化器代码忽略了这一点 并将(1-indexOffset)处理为(indexOffset-1)

此问题的修复程序将在下一次更大的更新中发布 VS2017。在此之前,禁用SSA优化器将是一个不错的选择 变通办法。仅禁用此函数的优化可能是一个错误 如果不太慢的话,更好的方法。这可能是 使用#pragma optimize(“,off)”完成:


你能给出编译代码的命令行吗?我想试试最新的MSVC版本。也就是说,它看起来确实像一只虫子。您似乎还缺少include。“不工作”表示消息未打印,或者断点未触发?FWIW,对于第一个“不工作”的情况,
main
汇编程序代码是什么?您缺少一些包含
tchar.h
windows.h
cstdio
。这肯定是一个编译器错误-它与MSVC x64 19.10.25019(VS15 RTM)和19.11.25325(VS15.3预览)一起工作。您应该升级您的编译器-不支持MSVC 19.0。@Codeguard-您看到的是Visual Studio本身的版本,而不是编译器版本。要获取编译器版本,请在命令行中输入
cl/?
。许多人声称发现了编译器错误,而实际上这是他们自己代码中的错误。看到一个很可能是编译器错误,真是令人耳目一新!我相信编译器开发人员最终会想出如何进一步最小化他们自己…:)哇-我很惊讶你这么快就从微软开发者那里得到了如此详细的答案。好问题,@Casey的回答很好,MS。
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;
}