C11標準は、定数制御式を含む反復ステートメントを最適化してはならないことを示唆しているようです。私は この答え からアドバイスを取っています。これは、ドラフト標準のセクション6.8.5を具体的に引用しています。
制御式が定数式ではない反復文...は、実装によって終了するものと想定されます。
その答えでは、while(1) ;
のようなループは最適化の対象とすべきではないと述べています。
では、なぜClang/LLVMは(cc -O2 -std=c11 test.c -o test
でコンパイルされた)以下のループを最適化するのですか?
#include <stdio.h>
static void die() {
while(1)
;
}
int main() {
printf("begin\n");
die();
printf("unreachable\n");
}
私のマシンでは、これはbegin
を出力し、次にが不正な命令でクラッシュします(die()
の後に配置されたud2
トラップ)。 godboltの場合 、puts
の呼び出し後に何も生成されないことがわかります。
Clangに-O2
の下で無限ループを出力させるのは驚くほど難しい作業でしたが、volatile
変数を繰り返しテストすることはできましたが、これには不要なメモリ読み取りが含まれています。そして、私がこのようなことをした場合:
#include <stdio.h>
static void die() {
while(1)
;
}
int main() {
printf("begin\n");
volatile int x = 1;
if(x)
die();
printf("unreachable\n");
}
... Clangはbegin
とそれに続くunreachable
を出力して、無限ループが存在しないかのように出力します。
最適化をオンにして、Clangに適切なメモリアクセスなしの無限ループを出力させるにはどうすればよいですか?
準拠する実装は、多くの実際的な実装がプログラムを実行できる時間または実行する命令の数に任意の制限を課し、それらの制限に違反した場合、または「as-if」ルールの下で任意の方法で動作する場合があります。 -違反が避けられないと判断した場合。実装が、N1570 5.2.4.1にリストされているすべての制限を名目上実行する少なくとも1つのプログラムを正常に処理できる場合、変換制限、制限の存在、それらが文書化されている範囲、およびそれらを超えた場合の影響はありません。規格の管轄外のすべての実装品質の問題。
標準の意図は、コンパイラが副作用もbreak
ステートメントもないwhile(1) {}
ループが終了することを想定してはならないことは非常に明白だと思います。一部の人々が考えるかもしれないこととは反対に、標準の作成者は、コンパイラー作成者を愚かで鈍感なものにするように勧めていませんでした。適合する実装は、中断されない場合、宇宙に存在するアトムよりも副作用のない命令を実行するプログラムを終了することを決定するのに役立つかもしれませんが、品質の実装は、あらゆる仮定に基づいてそのようなアクションを実行すべきではありません終了ではなく、そうすることは有用であり、(clangの動作とは異なり)役に立たないよりも悪くはないということに基づいています。