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/
- 把示例代码放到编辑器中
- 将
/O2
到Additional 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