厳密なエイリアシング ルールと関数の最適化
次の関数を考えてみましょう:
inline u64 Swap_64(u64 x) { u64 tmp; (*(u32*)&tmp) = Swap_32(*(((u32*)&x)+1)); (*(((u32*)&tmp)+1)) = Swap_32(*(u32*) &x); return tmp; }
無害に見えるかもしれませんが、このコードは、最適化が有効になっている場合に不審な動作を示します。コンパイラは、一時変数 tmp への割り当てを「最適化して取り除く」ようです。なぜこれが起こるのかを理解するには、「厳密なエイリアシング ルール」を詳しく調べる必要があります。
厳密なエイリアシング
厳密なエイリアシング ルールでは、オブジェクトのポインタを介してオブジェクトにアクセスすることが規定されています。ポインタが同じメモリを指している場合でも、異なる型は不正です。これにより、コンパイラーは、異なる型のポインターがエイリアス (重複) しないと想定し、それに応じて最適化することができます。質問に示されている例を考えてみましょう。
Swap_64 では、tmp のタイプは u64 ですが、x のタイプは u32 です。コンパイラは、&x を u32 オブジェクトへのポインタとして解釈します。厳密なエイリアス規則によれば、u64 オブジェクト (&tmp) へのポインターを介してそのメモリにアクセスすることは違法です。
最適化と未定義の動作
高レベルの場合最適化が有効になっている場合、コンパイラは、tmp が指すメモリが実際には割り当てられていないため、tmp への割り当てが最適化される可能性があることに気づきます。変更されました。厳密なエイリアス規則により、&x と &tmp が異なるメモリを指していると想定できるため、この最適化はコンパイラの権限内にあります。
ただし、この最適化は、メモリが によって指されているという前提に依存しています。 &x には、別の型のポインターを介してアクセスすることはできません。厳密なエイリアス規則に違反すると、コードに未定義の動作が導入されます。このようなシナリオでは、コンパイラは、割り当てを最適化して削除するなど、一見無害に見える操作を含め、やりたいことを自由に実行できます。したがって、最適化を有効にすると、コードは期待どおりに機能しなくなります。
解決策
この問題を解決するには、厳密なエイリアシング ルールに違反していないことを確認する必要があります。 1 つのアプローチは、共用体を使用して x のビットを u64 として再解釈することです。これにより、適切な型を介して同じメモリにアクセスできるようになり、厳密なエイリアシング ルールの違反が回避され、最適化が有効になっている場合でもコードが正しく機能できるようになります。
以上が厳密なエイリアシング ルールは C/C コードのコンパイラの最適化にどのような影響を与えますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。