88

ロックフリーのデータ構造とタイミング コードを実装する場合、多くの場合、コンパイラの最適化を抑制する必要があります。通常、人々はclobber リストでasm volatilewithを使用してこれを行いますが、ときどき単なるまたは単純なclobbering メモリが表示されます。memoryasm volatileasm

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

参考までに、これらは興味深いバリエーションです。

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

3 に答える 3

72

GCCドキュメントの「ExtendedAsm」ページを参照してください。

の後にasmキーワードを書き込むことで、命令が削除されないようにすることができます。[...]キーワードは、命令に重要な副作用があることを示します。到達可能である場合、GCCはasmを削除しません。volatileasmvolatilevolatile

出力オペランドのasmない命令は、揮発性asm命令と同じように扱われます。

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

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

"memory"clobberは、GCCに、任意のメモリがブロックによって任意に読み取られたり書き込まれたりする可能性があると想定させます。そのため、コンパイラは、ブロックasm全体でロードまたはストアを並べ替えることができなくなります。

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

(ただし、CPUが別のCPUに関してロードとストアを並べ替えることを妨げることはありません。そのためには、実際のメモリバリア命令が必要です。)

于 2013-01-22T01:10:20.040 に答える
13

asm ("")何もしません(または少なくとも、何もしないはずです。

asm volatile ("")また、何もしません。

asm ("" ::: "memory")単純なコンパイラフェンスです。

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

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

于 2013-01-21T23:41:58.587 に答える
3

Lily Ballard's answerを完全にするために、Visual Studio 2010 は を提供し_ReadBarrier()、同じことを行います (VS2010 は 64 ビット アプリのインライン アセンブリを許可しません)。_WriteBarrier()_ReadWriteBarrier()

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

MemoryBarrier()生成するlock or DWORD PTR [rsp], 0

于 2013-01-22T00:55:41.823 に答える