最適化によりこの関数が劣化する理由
大学のプログラミング専門講義で、講師が学生を困惑させる関数を提示しました。
inline u64 Swap_64(u64 x) { u64 tmp; (*(u32*)&tmp) = Swap_32(*(((u32*)&x)+1)); (*(((u32*)&tmp)+1)) = Swap_32(*(u32*) &x); return tmp; }
当初、この関数はスムーズに動作していましたが、高い最適化レベルを有効にすると、不活性な。この動作の背後にある理由は、厳密なエイリアシング ルールの概念にあります。
厳密なエイリアシング違反
提供されたコードは、オブジェクトが互換性のあるポインタ型を通じてアクセスされます。この場合、u32 および u64 ポインターは重複する可能性のあるメモリーを指しますが、コンパイラーはそれらが別個のオブジェクトを表すものと想定します。この仮定により、一時変数 tmp への代入が最適化され、関数が無効になります。
最適化が発生する理由
コンパイラは、仮定に基づいてコードを最適化できます。ポインタの動作について。 u32 と u64 は異なる型であるため、コンパイラはそれらが同じメモリを指しておらず、u32 ポインタを介して行われた変更は tmp の値に影響を与えないと想定します。この最適化により、観察される動作が生じます。
関数の動作を保持するための解決策
コードが最適化されないようにするには、ポインターの型がアクセスされたデータ型と一致する必要があります。 1 つのアプローチは、共用体を使用してビットに直接アクセスすることです。
typedef union { uint32_t u32; uint16_t u16[2]; } U32; uint32_t swap_words(uint32_t arg) { U32 in; uint16_t lo; uint16_t hi; in.u32 = arg; hi = in.u16[0]; lo = in.u16[1]; in.u16[0] = lo; in.u16[1] = hi; return (in.u32); }
共用体を使用することで、ポインタとデータ型に互換性が確保され、コンパイラが意図した変更を最適化するのを防ぎます。
以上がコンパイラの最適化によってこの 64 ビット スワップ機能が無効になるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。