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
はい、それはバグです。具体的には、VS2015 Update 3で導入された新しいSSAオプティマイザーのバグです。 文書化されていないコマンドラインオプション-d2SSAOptimizer-
は、代わりに古いオプティマイザを使用するようにコンパイラバックエンドに指示します。これにより、バグは顕在化しません 。
参考までに、再現を最小限に抑えることができます。
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の答えはTHEであると判断しました回答):Microsoftから返信を受け取りました(ブログ投稿の作成者であるGratian Lup 新しい高度なVisual C++コードオプティマイザーの紹介 ):
はい、これは確かにSSAオプティマイザー自体のバグです。通常、新しいオプティマイザーにあると報告されているバグのほとんどは他の部分にあり、20年後に明らかになることもあります。
それは小さな選択です。オーバーフローがない場合、(a --Const1)CMP(a --Const2)のように見える比較を削除しようとします。問題は、コードに(1-indexOffset)CMP(2-indexOffset)があり、減算はもちろん可換ではないことです-しかし、オプティマイザーコードはそれを無視し、(1-indexOffset)を(indexOffset-1)のように処理します。
この問題の修正は、VS2017の次の大きなアップデートでリリースされます。それまでは、SSAオプティマイザーを無効にすることは適切な回避策です。この関数のみの最適化を無効にすることは、物事をそれほど遅くしないのであれば、より良いアプローチかもしれません。これは#pragmaoptimize( ""、off)で実行できます: https://msdn.Microsoft.com/en-us/library/chh3fb0k.aspx