7

pthreads と __m128 SSE タイプを使用するアプリケーションを構築しようとしています。GCC マニュアルによると、デフォルトのスタック アラインメントは 16 バイトです。__m128 を使用するには、16 バイトのアラインメントが必要です。

私のターゲット CPU は SSE をサポートしています。ランタイム スタックの再配置をサポートしていない GCC コンパイラを使用しています (例: -mstackrealign)。他の GCC コンパイラ バージョンは使用できません。

私のテストアプリケーションは次のようになります:

#include <xmmintrin.h>
#include <pthread.h>
void *f(void *x){
   __m128 y;
   ...
}
int main(void){
  pthread_t p;
  pthread_create(&p, NULL, f, NULL);
}

アプリケーションは例外を生成して終了します。簡単なデバッグ (printf "%p", &y) の後、変数 y が 16 バイトでアラインされていないことがわかりました。

私の質問は、GCC フラグと属性を使用せずに (役に立たない) スタックを適切に (16 バイト) 再調整するにはどうすればよいですか? このスレッド関数 f() 内で GCC インライン アセンブラーを使用する必要がありますか?

4

5 に答える 5

7

よりも 15 バイト大きい配列をスタックに割り当て、sizeof(__m128)その配列の最初にアラインされたアドレスを使用します。複数必要な場合は、アラインメントのために 15 バイトのマージンを 1 つ持つ配列に割り当てます。

配列を割り当てるとunsigned char、コンパイラによる厳密なエイリアシングの最適化から安全になるのか、それとも逆にしか機能しないのかは覚えていません。

#include <stdint.h>

void *f(void *x)
{
   unsigned char y[sizeof(__m128)+15];
   __m128 *py = (__m128*) (((uintptr_t)&y) + 15) & ~(uintptr_t)15);
   ...
}
于 2010-05-04T13:04:53.050 に答える
3

これはそもそも発生するべきではありませんが、問題を回避するために次のことを試すことができます。

void *f(void *x)
{
   __m128 y __attribute__ ((aligned (16)));
   ...
}
于 2010-05-04T12:47:42.997 に答える
2

別の解決策は、最初にスタックを整列させてからを呼び出すパディング関数を使用することfです。fしたがって、直接呼び出す代わりに、を呼び出しますpad。これは、最初にスタックをパディングfooしてから、整列されたスタックで呼び出します。

コードは次のようになります。

#include <xmmintrin.h>
#include <pthread.h>

#define ALIGNMENT 16

void *f(void *x) {
    __m128 y;
    // other stuff
}

void * pad(void *val) {
    unsigned int x; // to get the current address from the stack
    unsigned char pad[ALIGNMENT - ((unsigned int) &x) % ALIGNMENT];
    return f(val);
}

int main(void){
    pthread_t p;
    pthread_create(&p, NULL, pad, NULL);
}
于 2010-05-05T12:47:22.987 に答える
-2

私はこの問題を解決しました。これが私の解決策です:

void another_function(){
   __m128 y;
   ...
}
void *f(void *x){
asm("pushl    %esp");
asm("subl    $16,%esp");
asm("andl    $-0x10,%esp");
another_function();
asm("popl %esp");
}

まず、スタックを 16 バイト増やします。次に、最下位ニブルを 0x0 にします。プッシュ/ポップ オペランドを使用してスタック ポインターを保持します。すべての独自のローカル変数が 16 バイトでアラインされている別の関数を呼び出します。ネストされたすべての関数も、16 バイトでアラインされたローカル変数を持ちます。

そしてそれは動作します!

于 2010-05-04T16:01:04.753 に答える