2012-10-17 36 views
8

Tôi đã tình cờ gặp vấn đề sau. Đoạn mã dưới đây không liên kết trên Mac OS X với bất kỳ Xcode nào mà tôi đã thử (4.4, 4.5)Biên dịch không thành công với OpenMP trên Mac OS X Lion (bản ghi nhớ và bản chất SSE)

#include <stdlib.h> 
#include <string.h> 
#include <emmintrin.h> 

int main(int argc, char *argv[]) 
{ 
    char *temp; 
#pragma omp parallel 
    { 
    __m128d v_a, v_ar; 
    memcpy(temp, argv[0], 10); 
    v_ar = _mm_shuffle_pd(v_a, v_a, _MM_SHUFFLE2 (0,1)); 
    } 
} 

Mã này chỉ được cung cấp làm ví dụ và sẽ phân đoạn khi bạn chạy. Vấn đề là nó không biên dịch. Việc lập được thực hiện bằng cách sử dụng dòng sau

/Applications/Xcode.app/Contents/Developer/usr/bin/gcc test.c -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk -mmacosx-version-min=10.7 -fopenmp 

Undefined symbols for architecture x86_64: 
"___builtin_ia32_shufpd", referenced from: 
    _main.omp_fn.0 in ccJM7RAw.o 
"___builtin_object_size", referenced from: 
    _main.omp_fn.0 in ccJM7RAw.o 
ld: symbol(s) not found for architecture x86_64 
collect2: ld returned 1 exit status 

mã biên dịch chỉ tốt khi không sử dụng -fopenmp cờ để gcc. Bây giờ, tôi googled xung quanh và tìm thấy một giải pháp cho vấn đề đầu tiên kết nối với memcpy, mà là thêm -fno-builtin, hoặc -D_FORTIFY_SOURCE=0 đến gcc danh sách đối số. Tôi đã không giải quyết được vấn đề thứ hai (sse nội tại).

Có ai có thể giúp tôi giải quyết vấn đề này không? Các câu hỏi:

  • quan trọng nhất: làm thế nào để thoát khỏi lỗi "___builtin_ia32_shufpd"?
  • lý do chính xác cho vấn đề memcpy là gì và cờ -D_FORTIFY_SOURCE=0 cuối cùng sẽ làm gì?
+0

biên dịch tốt cho tôi (OSX10.8.2, Xcode 4.5, macports gcc 4.7.1) khi sử dụng -fopenmp -O1 (hoặc cao hơn, nhưng không -O0: điều này cho lỗi liên kết bị thiếu '___ gxx_personality_v0'). Tuy nhiên mã sản xuất segfault khi chạy. Khi biên dịch mà không có -fopenmp, mã biên dịch cho bất kỳ -O, nhưng một lần nữa segfaults (ngoại trừ -O0: bus error). – Walter

+0

@Walter Cảm ơn. segfault không phải là một vấn đề, mã chỉ là một ví dụ - tất nhiên nó là sai. Bạn đang sử dụng gcc 4.7.1, vì vậy không phải trình biên dịch Xcode, phải không? Bạn có thể biên dịch với dòng lệnh mà tôi đã đưa ra không? Thay đổi mức tối ưu hóa không giúp được gì ở đây .. – angainor

+1

Đây là lỗi trong trình biên dịch 'llvm-gcc' mà Xcode giao với. Nó là một trình biên dịch LLVM với lối vào GCC. Giai đoạn OpenMP tạo ra một số nội trang mà backend không thể nhận ra. Khi Xcode đang dần chuyển sang hướng thay thế hoàn toàn GCC bằng 'clang', lỗi này có thể sẽ không bao giờ được sửa chữa. Chỉ cần cài đặt GCC thực từ nguồn hoặc thông qua một số phương pháp khác và sử dụng nó để biên dịch mã OpenMP. –

Trả lời

15

Đây là lỗi trong cách GCC của LLVM được hỗ trợ (llvm-gcc) chuyển đổi vùng OpenMP và xử lý cuộc gọi đến bên trong. Vấn đề có thể được chẩn đoán bằng cách kiểm tra các bãi cây trung gian (có thể đạt được bằng cách chuyển đối số -fdump-tree-all đến gcc). Nếu không có OpenMP kích hoạt các mã đại diện chính thức sau đây được tạo (từ 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); 
} 

Đây là một đại diện C-như thế nào trình biên dịch thấy mã nội bộ sau khi tất cả biến đổi. Đây là những gì sau đó được chuyển thành hướng dẫn lắp ráp. (chỉ những dòng tham khảo các built-in được hiển thị ở đây)

Với OpenMP kích hoạt các khu vực song song được chiết xuất vào chức năng riêng, 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); 
} 

Một lần nữa tôi đã chỉ còn lại các mã mà đề cập đến nội trang. Điều rõ ràng (nhưng lý do cho điều đó là không rõ ràng ngay với tôi) là mã trasnformer mã OpenMP thực sự khẳng định khi gọi tất cả các thông tin được tích hợp thông qua các con trỏ hàm. Các ký hiệu con trỏ này:

__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; 

tạo các tham chiếu bên ngoài cho các ký hiệu không phải là ký hiệu thực sự mà là các tên được trình biên dịch đặc biệt xử lý. Sau đó, trình liên kết cố gắng giải quyết chúng nhưng không thể tìm thấy bất kỳ tên __builtin_* nào trong bất kỳ tệp đối tượng nào mà mã được liên kết.Đây cũng là quan sát được trong các mã lắp ráp mà người ta có thể có được bằng cách đi qua -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) 

này về cơ bản là một chức năng gọi là mất 3 đối số: một số nguyên trong %eax và hai đối XMM trong %xmm0%xmm1, với kết quả được trả lại trong %xmm0 (theo quy ước gọi hàm SysV AMD64 ABI). Ngược lại, các mã được tạo mà không -fopenmp là một mở rộng hướng dẫn cấp của nội tại vì nó là vụ xảy ra:

LBB1_3: 
    movapd -64(%rbp), %xmm0 
    shufpd $1, %xmm0, %xmm0 
    movapd %xmm0, -80(%rbp) 

gì xảy ra khi bạn vượt qua -D_FORTIFY_SOURCE=0memcpy không được thay thế bởi phiên bản kiểm tra "củng cố" và một cuộc gọi thông thường đến memcpy được sử dụng thay thế. Điều này giúp loại bỏ các tham chiếu đến object_size__memcpy_chk nhưng không thể xóa cuộc gọi đến số ia32_shufpd được tích hợp sẵn.

Đây rõ ràng là lỗi trình biên dịch. Nếu bạn thực sự thực sự thực sự phải sử dụng GCC của Apple để biên dịch mã, sau đó là một giải pháp tạm thời sẽ được di chuyển mã vi phạm đến một chức năng bên ngoài như các lỗi dường như chỉ ảnh hưởng đến mã đó được chiết xuất từ ​​parallel vùng:

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]); 
    } 
} 

Các chi phí của một cuộc gọi chức năng bổ sung là neglegible so với chi phí của việc nhập và thoát khỏi khu vực parallel. Bạn có thể sử dụng các pragmas OpenMP bên trong func - chúng sẽ hoạt động vì phạm vi động của vùng parallel.

Có thể Apple sẽ cung cấp trình biên dịch cố định trong tương lai, có thể họ sẽ không, với cam kết thay thế GCC bằng Clang.

+0

Cảm ơn bạn đã giải thích kỹ cho tôi rằng điều này sẽ không hoạt động;) Tôi đã từ bỏ 'Xcode' và cài đặt macports gcc 4.7, như đã đề cập trước đó bởi Walter. Nó hoạt động không có vấn đề gì.Điều khó chịu duy nhất là để sử dụng macports bạn cần cài đặt các công cụ dòng lệnh Xcode ** và **, và bạn sẽ có được một bộ trình biên dịch mới ở trên cùng. chỉ là wow. – angainor

Các vấn đề liên quan