インラインアセンブラを使用する関数全体のSSEレジスタを維持するためにGCCを取得
-
12-09-2019 - |
質問
私はいくつかの高速な数学の計算を行う必要があるCでプログラムを書いています。私は(浮動小数点数パック倍精度を使用して)いくつかのSIMD動作を取得するには、インラインSSEのアセンブリ命令を使用しています。私は、Linux上でGCCを使用してコンパイルしています。
私はいくつかのデータをループに必要な状況にいるよ、と私は私の計算に一定の係数を使用します。私は、ループの中に安全なレジスタに隠れている要因を維持したいと思いますので、私はそれを再ロードするたびに持っていません。
いくつかのコードを明確にする:
struct vect2 {
fltpt x;
fltpt y;
}__attribute__((aligned(16))); /* Align on 16B boundary for SSE2 instructions */
typedef struct vect2 vect2_t;
void function()
{
/* get a specific value set up in xmm1, and keep it there for the
* rest of the loop. */
for( int i = 0, i<N; i++ ){
asm(
"Some calculations;"
"on an element of;"
"a data set.;"
"The value in xmm1;"
"is needed;"
);
}
}
私は、「登録」のキーワードで何かをやってみました。私は間違っていない場合、私は唯一のの(汎用レジスタで)その構造体へのポインタを保存することができているかのように。しかし、それが見えます。これは、貴重な時間を無駄に、すべての反復をdeferencedする必要があります。
register vect2_t hVect asm("xmm1") = {h, h};
/* Gives error: data type of 'hVect' isn't suitable for a register */
register vect2_t *hVect2 asm("rax");
*hVect2 = (vect2_t){h,h};
/* Seems to work, but not what I'm looking for */
私はGCCが登録XMM1変更されないことを前提として好きではない、それは:-)ものの一種「自分の鼻の外に飛んで鬼」のあまりのです。だから私はこれを行うための適切な方法がある願っています。
解決
私はここに解決策は、あなたのvec2_t
タイプが実際のベクトルであることにはgccを認識することですだと思います。その後、あなただけ(コンパイラがベクトル型であることを知っている除く)ループ不変値を計算し、通常の変数として扱うことができます:
typedef double vec2_t __attribute__ ((vector_size (16)));
void function()
{
/* get a specific value set up, e.g. */
vec2_t invariant;
asm( "some calculations, soring result in invariant."
: "=x" (invariant) );
for( int i = 0; i<N; i++ ){
asm(
"Some calculations;"
"on an element of;"
"a data set.;"
"The value in xmm1;"
"is needed;"
: "x" (invariant) // and other SSE arguments
);
}
}
私は、ループ内の単純な計算でこれをコンパイルし、少なくとも最適化レベル1でinvariant
の値はループ中XMMレジスタに保持されます。
(これは、すべてあなたの明示的XMMレジスタのないの必要性のあなたのループ不変と仮定し、そしてあなたがGCCの通常のレジスタ割り当てを使用することができる)
。他のヒント
私は、アセンブリとCと私はここにするだろう、私はアセンブリ全体の機能を記述していることであると連携するために使用しています。 あなたは柔軟にシステムを持っている場合は、私は別にASM機能を組み立てると、アプリケーションにリンクさせることをおすすめします。これで唯一の問題は、関数は、コンパイラによってインライン化することができないということです。
ボイド関数(ボイド)。 // C
のextern "C" 関数(ボイド)。 // C ++