2013-01-21 28 views
43

ロックフリーのデータ構造とタイミングコードを実装する場合、コンパイラの最適化を抑止する必要があることがよくあります。通常、人々はasm volatilememoryをclobberリストで使用しますが、時にはasm volatileと表示されるか、まったく平らなasmメモリしか表示されません。asm、asm volatileとclobberingメモリの相違点

これらの異なるステートメントは、コード生成(特にGCCでは移植性が低い可能性があるため)にどのような影響を与えますか? 。。

asm (""); // presumably this has no effect on code generation 
asm volatile (""); 
asm ("" ::: "memory"); 
asm volatile ("" ::: "memory"); 
+0

誰かが周りにあまりにも近いいじりしているようです(@mysticialは不思議な詳細な答えで打ち明けています) –

答えて

39

を生成"Extended Asm" page in the GCC documentationを参照してください。

あなたはasm後にキーワードvolatileを書き込むことによって削除されasm命令を防ぐことができます。 [...] volatileキーワードは、命令に重要な副作用があることを示します。到達可能であれば、GCCはvolatileを削除しません。任意の出力オペランドなしで

asm命令は、揮発性asm命令と同一に扱われます。あなたの例の

なし指定された出力オペランドを持たないので、asmasm volatileフォームが同じように動作:彼らは(到達不能であることが証明されない限り)、削除されないことがあり、コード内のポイントを作成します。

これは何もしないことと全く同じではありません。コード生成を変更するダミーのasmの例については、this questionを参照してください。この例では、ループの周りを1000回進むコードは、ループの16回の反復を一度に計算するコードにベクトル化されます。ループ内にasmが存在すると最適化ができなくなります(asmは1000回に達する必要があります)。

"memory"クロバーはGCCが任意のメモリが任意に読み取りまたはasmブロックによって書かれたので、それを越えロードまたはストアを並べ替えから、コンパイラを防ぐことができますすることができることを前提としています:

これは、GCCは保持しないようになりますアセンブラ命令でレジスタにキャッシュされ、そのメモリへのストアまたはロードを最適化しません。

(それはしかし、別のCPUに対するロードとストアを並べ替えからCPUを防ぐことはできませんが、あなたはそのための実メモリバリア命令を必要とする)

+0

これは実際には非常に興味深いものですが、gccが出力なしで 'asm'ブロックを処理することは、私の知るところでは巨大なギャップであったためです。 – jleahy

+0

したがって、変数(変数またはasm)でどのようなコンテキストが使用されているにもかかわらず、 'volatile' =パフォーマンスを殺します。 'goto'キーワードでファイルしてください - 絶対に必要な場合にのみ使用してください。 – etherice

8

asm ("")何もしない(あるいは、少なくとも、何かを行うことになっていない

asm volatile ("")何もしません

asm ("" ::: "memory")

ただ参考のために、これらは興味深いバリエーションです単純なコンパイラフェンスです

asm volatile ("" ::: "memory") AFAIKは同じです前のように。 volatileキーワードは、このアセンブリブロックの移動が許可されていないことをコンパイラーに通知します。たとえば、コンパイラが入力値がすべての呼び出しで同じであると判断した場合、ループからループを外すことができます。コンパイラがどのような条件の下でアセンブリの配置を最適化しようと十分に理解していると判断するのかはわかりませんが、volatileというキーワードはそれを完全に抑制します。つまり、コンパイラが入力または出力が宣言されていない文のasmを移動しようとすると、私は非常に驚くでしょう。

なお、volatileは、出力値が使用されていないと判断した場合にコンパイラが式を削除しないようにします。これは出力値がある場合にのみ発生する可能性があるため、asm ("" ::: "memory")には適用されません。

+6

Matthew Slatteryの答えは、 'asm volatile(" ")'は何もしないことと全く同じではないことを指摘していますコンパイラの最適化に大きな影響を与えます。 asm volatile( "" ::: "memory") 'をコンパイラフェンスとして使用する場合と同じパフォーマンスの影響があります。 – etherice

+0

コンパイラはアセンブリ言語を理解していません! – curiousguy

+1

@curiousguyいいえ、 'asm'ブロックが入力/出力を宣言したときに、それが依存するレジスタと変更するものをコンパイラに知らせると、コンパイラは特定の計算をシャッフルすることができます。入力/出力に影響しません。 –

1

Visual Studio 2010は、Kevin Ballardの答えを完全に理解するために、_ReadBarrier()、_WriteBarrier()、_ReadWriteBarrier()を使用して同じ処理を行います(VS2010では64ビットアプリケーションのインラインアセンブリは許可されません)。

これらは命令を生成しませんが、コンパイラの動作に影響します。良い例はhere

メモリバリア(ある)lock or DWORD PTR [rsp], 0