これが本当の質問でない場合は、お気軽に閉じてください ;)
3 に答える
コンパイラーが (主に最適化のために) 実行を並べ替えることができるだけでなく、ほとんどの最新のプロセッサーもそうします。実行の並べ替えとメモリ バリアについて詳しくは、こちらをご覧ください。
コンパイラーは、最適化の目的に適していると判断した場合、およびそのような変更によってコードの観察可能な動作が変更されない場合に、ステートメントの実行順序を変更できます。
非常に簡単な例-
int func (int value)
{
int result = value*2;
if (value > 10)
{
return result;
}
else
{
return 0;
}
}
ナイーブなコンパイラーは、このためのコードを示されている順序で正確に生成できます。最初に「結果」を計算し、元の値が10より大きい場合にのみ返します(そうでない場合、「結果」は無視されます-不必要に計算されます)。
ただし、正常なコンパイラでは、「結果」の計算は「値」が10より大きい場合にのみ必要であることがわかるため、計算「値* 2」を最初の中括弧内に簡単に移動し、「値」の場合にのみ実行できます。実際には10よりも大きいです(言うまでもなく、コンパイラーは最適化時にCコードを実際には調べません-それはより低いレベルで機能します)。
これは単純な例にすぎません。より複雑な例を作成できます。十分に積極的な最適化を行うと、C関数がコンパイルされた形式のC表現とほとんど同じように見えなくなる可能性が非常に高くなります。
多くのコンパイラは、「共通部分式除去」と呼ばれるものを使用します。たとえば、次のコードがある場合:
for(int i=0; i<100; i++) {
x += y * i * 15;
}
コンパイラーは、y * 15が不変であることに気付くでしょう(その値は変更されません)。したがって、y * 15を計算し、結果をレジスタに貼り付けて、ループステートメントを「x + = r0*i」に変更します。これは一種の不自然な例ですが、配列インデックスやその他のベース+オフセットタイプの状況で作業する場合、このような式がよく見られます。