這是蘋果LLVM支持的GCC(llvm-gcc
)轉換OpenMP區域並處理對其內置插件的調用的一種錯誤。可以通過檢查中間樹轉儲(可通過將-fdump-tree-all
參數傳遞給gcc
來獲得)來診斷問題。如果沒有啓用的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_object_size.19 = __builtin_object_size;
__builtin_ia32_shufpd.23 = __builtin_ia32_shufpd;
__builtin_object_size.20 = __builtin_object_size;
__builtin___memcpy_chk.21 = __builtin___memcpy_chk;
產生到不是真的得到由編譯器特別處理符號,而是名稱的符號外部引用。鏈接器然後嘗試解析它們,但無法找到代碼鏈接到的任何對象文件中的任何__builtin_*
名稱。這也是在彙編代碼,人們可以通過使-S
到gcc
獲得可觀察到的:
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)
這基本上是一個函數調用需要3個參數:在%eax
和兩個XMM參數之一整數%xmm0
和%xmm1
,與結果在%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
的調用。
這顯然是一個編譯器錯誤。如果你真的真的真的必須使用蘋果的GCC編譯代碼,然後一個臨時的解決辦法是有問題的代碼移動到外部功能的bug顯然隻影響會從parallel
地區抽出代碼:
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]);
}
}
一個附加函數調用的開銷與進入和退出parallel
區域的開銷相比是可忽略的。您可以在func
內使用OpenMP pragmas - 由於parallel
區域的動態範圍限定,它們可以工作。
可能蘋果將來會提供一個固定的編譯器,他們可能不會,因爲他們承諾用Clang代替GCC。
當使用-fopenmp -O1(或更高,但不是-O0:這會導致鏈接器錯誤,缺少___ gxx_personality_v0)時,適合我編譯(OSX10.8.2,Xcode 4.5,macports gcc 4.7.1)。但是,代碼在運行時會產生段錯誤。在沒有-fopenmp的情況下編譯時,代碼針對任何-O進行編譯,但是又是段錯誤(除了-O0:總線錯誤)。 – Walter
@Walter謝謝。 segfault不是問題,代碼只是一個例子 - 當然這是錯誤的。你使用的是gcc 4.7.1,所以不是Xcode編譯器,對不對?你能用我給的命令行進行編譯嗎?更改優化級別對此沒有幫助。 – angainor
這是Xcode附帶的'llvm-gcc'編譯器中的一個錯誤。它是一個帶有GCC前端的LLVM編譯器。 OpenMP階段正在生成一些後端無法識別的內置內存。由於Xcode正在穩步地用'clang'完全替代GCC,這個bug可能永遠不會被修復。只需從源代碼或其他方法安裝真正的GCC,並使用它來編譯OpenMP代碼。 –