アセンブリコードをC/C ++プログラムに埋め込む場合、プッシュ命令でレジスタを保存することで(または、サポートされているコンパイラのclobberリストを指定して)レジスタのクロバリングを回避できます。
アセンブリをインラインに含めていて、クラバリングされたレジスタをプッシュおよびポップするオーバーヘッドを回避したい場合、gccにレジスタを選択させる方法はありますか(たとえば、有用な情報がないことがわかっているレジスタ)。
アセンブリコードをC/C ++プログラムに埋め込む場合、プッシュ命令でレジスタを保存することで(または、サポートされているコンパイラのclobberリストを指定して)レジスタのクロバリングを回避できます。
アセンブリをインラインに含めていて、クラバリングされたレジスタをプッシュおよびポップするオーバーヘッドを回避したい場合、gccにレジスタを選択させる方法はありますか(たとえば、有用な情報がないことがわかっているレジスタ)。
はい。特定の変数(入力または出力)をレジスターに保管するように指定できますが、レジスターを指定する必要はありません。詳細な説明については、このドキュメントを参照してください。基本的に、インラインアセンブリは次のようになります。
asm("your assembly instructions"
: output1("=a"), // I want output1 in the eax register
output2("=r"), // output2 can be in any general-purpose register
output3("=q"), // output3 can be in eax, ebx, ecx, or edx
output4("=A") // output4 can be in eax or edx
: /* inputs */
: /* clobbered registers */
);
わかりましたので、上記にコメントを残すことはできませんが、正しい構文 (上記のものとは異なります) は次のとおりであると確信しています。
asm ( "your assembly instructions"
: "=a"(output1),
"=r"(output2),
"=q"(output3),
"=A"(output4)
: /* inputs */
: /* clobbered registers */
);
入力レジスタと出力レジスタの割り当てをコンパイラに任せることはできますが、スクラッチ/一時レジスタ (つまり、入力または出力ではなく中間値に使用されるレジスタ) の割り当てをコンパイラに任せる明白な方法はありません。歴史的には、単にそれらを clobber リスト (例: "%xmm1"、"%rcx") に明示的にリストしていましたが、コンパイラーがそれらを選択できるようにするために、それらを出力としてリストする方がよいのではないかと考えています。この問題に明確に対処している情報源を私は知りません。
コンパイラ組み込み関数は、アセンブリと C/C++ コードを混在させる非常に便利な方法です。これらは関数のように見える宣言ですが、実際には個々のネイティブ命令に直接コンパイルされます (コンパイラ内の特別なケースを介して)。これにより、アセンブリでの作業の多くを制御できますが、レジスタの色付けとスケジューリングはコンパイラに任せます。
利点は、通常の C 変数を組み込み関数に渡すことができ、コンパイラーがそれをレジスターにロードし、その周りの他の操作をスケジュールすることを処理できることです。例えば、
struct TwoVectors
{
__m128 a; __m128b;
}
// adds two vectors A += B using the native SSE opcode
inline void SimdADD( TwoVectors *v )
{
v->a = _mm_add_ps( v->a , v->b ); // compiles directly to ADDSS opcode
}