これは、AppleのLLVM対応GCC(llvm-gcc
)がOpenMP領域を変換し、その内部の組み込み関数への呼び出しを処理する方法のバグです。この問題は、中間ツリーダンプを調べることで診断できます(引数に-fdump-tree-all
引数を渡すことで取得できます)。 OpenMPのがなければ、次の最終的なコードの表現は(test.c.016t.fap
から)生成された有効:
main (argc, argv)
{
D.6544 = __builtin_object_size (temp, 0);
D.6545 = __builtin_object_size (temp, 0);
D.6547 = __builtin___memcpy_chk (temp, D.6546, 10, D.6545);
D.6550 = __builtin_ia32_shufpd (v_a, v_a, 1);
}
これは、コンパイラがすべての変換後、内部のコードを見ているかのCのような表現です。これがアセンブリ命令に変換されます。 のOpenMPで
は、並列領域は、自身の機能にmain.omp_fn.0
抽出する有効(ビルトインを参照する行のみがここに示されている):再び
main.omp_fn.0 (.omp_data_i)
{
void * (*<T4f6>) (void *, const <unnamed type> *, long unsigned int, long unsigned int) __builtin___memcpy_chk.21;
long unsigned int (*<T4f5>) (const <unnamed type> *, int) __builtin_object_size.20;
vector double (*<T6b5>) (vector double, vector double, int) __builtin_ia32_shufpd.23;
long unsigned int (*<T4f5>) (const <unnamed type> *, int) __builtin_object_size.19;
__builtin_object_size.19 = __builtin_object_size;
D.6587 = __builtin_object_size.19 (D.6603, 0);
__builtin_ia32_shufpd.23 = __builtin_ia32_shufpd;
D.6593 = __builtin_ia32_shufpd.23 (v_a, v_a, 1);
__builtin_object_size.20 = __builtin_object_size;
D.6588 = __builtin_object_size.20 (D.6605, 0);
__builtin___memcpy_chk.21 = __builtin___memcpy_chk;
D.6590 = __builtin___memcpy_chk.21 (D.6609, D.6589, 10, D.6588);
}
私はコードのみを残していること組み込み関数を指します。明らかなことは(しかし、それはすぐにわかりません)というのは、OpenMPコードtrasnformerが実際には、がすべての組み込み関数を関数ポインタで呼び出すことを主張しているからです。これらのポインタasignments:
実際にはシンボルではなくむしろコンパイラによって特別な扱いを受ける名前のシンボルへの外部参照を生成します。リンカーは、それらを解決しようとしますが、コードがリンクされているオブジェクトファイルのいずれかにある__builtin_*
の名前を見つけることはできません。と、1つの%xmm0
で%eax
二XMM引数の整数と%xmm1
:これは基本的に3つの引数を取る関数呼び出しがある
LBB2_1:
movapd -48(%rbp), %xmm0
movl $1, %eax
movaps %xmm0, -80(%rbp)
movaps -80(%rbp), %xmm1
movl %eax, %edi
callq ___builtin_ia32_shufpd
movapd %xmm0, -32(%rbp)
:これはまた、一つ-S
gcc
に通過させることによって得ることができるアセンブリコードで観察されますその結果は%xmm0
に返されます(SysV AMD64 ABI関数呼び出し規約に従って)。起こることになっているよう対照的に、-fopenmp
せずに生成されたコードは、固有の命令レベルの展開は次のとおりです。
LBB1_3:
movapd -64(%rbp), %xmm0
shufpd $1, %xmm0, %xmm0
movapd %xmm0, -80(%rbp)
何が-D_FORTIFY_SOURCE=0
はmemcpy
は「強化」、バージョンチェックに置き換えされていないということである渡すときに発生代わりにmemcpy
への通常の呼び出しが使用されます。これにより、object_size
および__memcpy_chk
への参照は削除されますが、ia32_shufpd
ビルトインへのコールは削除できません。
これは明らかにコンパイラのバグです。
void func(char *temp, char *argv0)
{
__m128d v_a, v_ar;
memcpy(temp, argv0, 10);
v_ar = _mm_shuffle_pd(v_a, v_a, _MM_SHUFFLE2 (0,1));
}
int main(int argc, char *argv[])
{
char *temp;
#pragma omp parallel
{
func(temp, argv[0]);
}
}
:あなたは本当に、本当に、本当にコードをコンパイルするために、AppleのGCCを使用しなければならない場合は、暫定的な解決策は、バグが明らかにのみparallel
た領域から抽出された取得するコードに影響を与える外部関数に問題のコードを移動することです1つの追加の関数呼び出しのオーバーヘッドは、parallel
領域への出入りのオーバーヘッドに比べて無視できません。 func
の中でOpenMPプラグマを使うことができます - parallel
領域の動的スコープのために動作します。
将来的にAppleが固定コンパイラを提供するかもしれないが、GCCをClangに置き換えるコミットメントを考えれば、そうでないかもしれない。
は、-fopenmp -O1(またはそれ以上、-O0ではなく、 '___ gxx_personality_v0'が見つからないというリンカエラー)を使用すると、私にとってうまくコンパイルできます(OSX10.8.2、Xcode 4.5、macports gcc 4.7.1)。しかし、コードは実行時にsegfaultを生成します。 -fopenmpを指定せずにコンパイルすると、-Oはコンパイルされますが、segfaults(-O0:バスエラーは例外です)。 – Walter
@Walterありがとうございます。 segfaultは問題ではなく、コードは単なる例に過ぎず、もちろん間違っています。あなたはgcc 4.7.1を使用していますので、Xcodeコンパイラではありません。私が与えたコマンドラインでコンパイルできますか?最適化レベルの変更はここでは役に立たなかった。 – angainor
これは、Xcodeが提供する 'llvm-gcc'コンパイラのバグです。これはGCCフロントエンドを持つLLVMコンパイラです。 OpenMP段階では、バックエンドが認識できない組み込み関数が生成されています。 XcodeはGCCを 'clang'に完全に置き換えるように着実に進んでいるので、バグは決して解決されないでしょう。実際のGCCをソースか他の方法でインストールしてOpenMPコードをコンパイルするだけです。 –