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

我们观察到一个奇怪的情况,在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)
  • 只有打开优化时才会发生这种情况(例如,在默认的“发行”configuration中)
  • 在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; } 

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


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

 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 

testing项目: http : //dropmefiles.com/S7mwT


在线试用!

  • 转到http://webcompiler.cloudapp.net/
  • 把示例代码放到编辑器中
  • /O2Additional compiler flags
  • Run executable after compilation检查Run executable after compilation

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

是的,这是一个错误。 具体来说,这是VS2015 Update 3中引入的新SSA优化器中的一个错误。未-d2SSAOptimizer-命令行选项-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; } 

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


来自Codeguard的补充 (我决定Casey的答案应该是答案):我已经收到微软的回复(Gratian Lup,博客文章的作者介绍一个新的,先进的Visual C ++代码优化器 ):

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

这是一个小select。 如果没有溢出,它会尝试删除看起来像(a – Const1)CMP(a – Const2)的比较。 问题是你的代码有(1 – indexOffset)CMP(2 – indexOffset),当然减法是不可交换的,但是优化器代码会忽略它并像(indexOffset – 1)一样处理(1 – indexOffset)。

此问题的修复将在VS2017的下一个更大的更新中发布。 在此之前,禁用SSA优化器将是一个体面的解决方法。 只有这个function禁用优化可能是一个更好的方法,如果它不放慢事情太多。 这可以通过#pragma optimize(“”,off)来完成: https : //msdn.microsoft.com/en-us/library/chh3fb0k.aspx