我们观察到一个奇怪的情况,VS2015 Update3编译器会在没有明显原因的情况下省略部分代码。
我们发现了
我们设法将此代码段的罪魁祸首代码最小化:
#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
在线尝试!
/O2
置于Additional compiler flags
Run executable after compilation
答案 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