2011-02-16 25 views
5

Tôi đã chương trình C sau (đơn giản hóa các trường hợp sử dụng thực tế của tôi trưng bày các hành vi tương tự)Tại sao GCC không tự động vector hóa vòng lặp này?

#include <stdlib.h> 
#include <math.h> 
int main(int argc, char ** argv) { 
    const float * __restrict__ const input = malloc(20000*sizeof(float)); 
    float * __restrict__ const output = malloc(20000*sizeof(float)); 

    unsigned int pos=0; 
    while(1) { 
      unsigned int rest=100; 
      for(unsigned int i=pos;i<pos+rest; i++) { 
        output[i] = input[i] * 0.1; 
      } 

      pos+=rest;    
      if(pos>10000) { 
        break; 
      } 
    } 
} 

Khi tôi biên dịch với

-O3 -g -Wall -ftree-vectorizer-verbose=5 -msse -msse2 -msse3 -march=native -mtune=native --std=c99 -fPIC -ffast-math 

tôi nhận được đầu ra

main.c:10: note: not vectorized: unhandled data-ref 

trong đó 10 là đường bên trong của vòng lặp. Khi tôi nhìn lên lý do tại sao nó có thể nói điều này, nó dường như nói rằng các con trỏ có thể được đặt bí danh, nhưng chúng không thể có trong mã của tôi, vì tôi có từ khóa __restrict. Họ cũng đề xuất bao gồm các cờ -msse, nhưng họ dường như không làm bất cứ điều gì cả. Bất kỳ giúp đỡ?

+0

Phiên bản gcc nào? Một ví dụ làm việc có thể hữu ích là tốt, như là một phiên bản hacked lên vectorized khi tôi đã thử nó với 4.4.5 – ergosys

+0

bạn có thể gửi mã ví dụ biên dịch? khi tôi điền vào một số giá trị giả, vòng lặp đã được vector hóa ... – Christoph

+0

@ergosys: những gì anh ấy nói;) – Christoph

Trả lời

3

Chắc chắn nó có vẻ giống như một lỗi. Trong, chức năng tương đương sau, foo() được vectorised nhưng bar() không phải là, khi biên dịch cho một mục tiêu x86-64:

void foo(const float * restrict input, float * restrict output) 
{ 
    unsigned int pos; 
    for (pos = 0; pos < 10100; pos++) 
     output[pos] = input[pos] * 0.1; 
} 

void bar(const float * restrict input, float * restrict output) 
{ 
    unsigned int pos; 
    unsigned int i; 
    for (pos = 0; pos <= 10000; pos += 100) 
     for (i = 0; i < 100; i++) 
      output[pos + i] = input[pos + i] * 0.1; 
} 

Thêm -m32 cờ, để biên dịch cho một mục tiêu x86 thay vào đó, gây ra cả hai chức năng được vectorised .

+1

Cảm ơn bạn! Tôi đang ở trên nền tảng 64 bit! làm -m32 làm cho nó hoạt động hoàn hảo. Tôi đang nộp báo cáo lỗi ngay bây giờ. Các câu trả lời khác là tuyệt vời, nhưng thực sự chỉ là cách giải quyết, vì điều này sẽ làm việc mà không có sửa đổi. –

+0

Lưu ý rằng thực thi 32 bit có thể chậm hơn nhiều so với 64 không được vector hóa, vì vậy trừ khi mục tiêu của bạn hoàn toàn là "sử dụng SSE", bạn nên lập hồ sơ cho toàn bộ ứng dụng của mình. –

+0

Cảm ơn Ben, tôi thực sự không sử dụng điều này để biên dịch mã của tôi, nhưng chỉ để gửi báo cáo lỗi. Tôi có thể làm cho nó để vectorize một cách chính xác trên 64 bit bằng cách sắp xếp lại những thứ một chút. –

1

thử:

const float * __restrict__ input = ...; 
float * __restrict__ output = ...; 

thí nghiệm một chút bằng cách thay đổi những thứ xung quanh:

#include <stdlib.h> 
#include <math.h> 

int main(int argc, char ** argv) { 

    const float * __restrict__ input = new float[20000]; 
    float * __restrict__ output = new float[20000]; 

    unsigned int pos=0; 
    while(1) { 
     unsigned int rest=100; 
     output += pos; 
     input += pos; 
     for(unsigned int i=0;i<rest; ++i) { 
      output[i] = input[i] * 0.1; 
     } 

     pos+=rest; 
     if(pos>10000) { 
      break; 
     } 
    } 
} 

g++ -O3 -g -Wall -ftree-vectorizer-verbose=7 -msse -msse2 -msse3 -c test.cpp 

test.cpp:14: note: versioning for alias required: can't determine dependence between *D.4096_24 and *D.4095_21 
test.cpp:14: note: mark for run-time aliasing test between *D.4096_24 and *D.4095_21 
test.cpp:14: note: Alignment of access forced using versioning. 
test.cpp:14: note: Vectorizing an unaligned access. 
test.cpp:14: note: vect_model_load_cost: unaligned supported by hardware. 
test.cpp:14: note: vect_model_load_cost: inside_cost = 2, outside_cost = 0 . 
test.cpp:14: note: vect_model_simple_cost: inside_cost = 2, outside_cost = 0 . 
test.cpp:14: note: vect_model_simple_cost: inside_cost = 2, outside_cost = 1 . 
test.cpp:14: note: vect_model_simple_cost: inside_cost = 1, outside_cost = 0 . 
test.cpp:14: note: vect_model_store_cost: inside_cost = 1, outside_cost = 0 . 
test.cpp:14: note: cost model: Adding cost of checks for loop versioning to treat misalignment. 

test.cpp:14: note: cost model: Adding cost of checks for loop versioning aliasing. 

test.cpp:14: note: Cost model analysis: 
    Vector inside of loop cost: 8 
    Vector outside of loop cost: 6 
    Scalar iteration cost: 5 
    Scalar outside cost: 1 
    prologue iterations: 0 
    epilogue iterations: 0 
    Calculated minimum iters for profitability: 2 

test.cpp:14: note: Profitability threshold = 3 

test.cpp:14: note: Vectorization may not be profitable. 
test.cpp:14: note: create runtime check for data references *D.4096_24 and *D.4095_21 
test.cpp:14: note: created 1 versioning for alias checks. 

test.cpp:14: note: LOOP VECTORIZED. 
test.cpp:4: note: vectorized 1 loops in function. 

Compilation finished at Wed Feb 16 19:17:59 
+0

Lý do cho điều này là gì? –

+0

@Oli chỉ là một đoán, có thể trình biên dịch của mình không giống như thêm const hoặc '__restrict' hình thức – Anycorn

+0

Không thay đổi bất cứ điều gì. –

2

Nó không giống như định dạng vòng ngoài được ngăn chặn nó từ sự hiểu biết các vòng trong. Tôi có thể lấy nó để vectorize nếu tôi chỉ gấp nó thành một vòng duy nhất:

#include <stdlib.h> 
#include <math.h> 
int main(int argc, char ** argv) { 
    const float * __restrict__ input = malloc(20000*sizeof(float)); 
    float * __restrict__ output = malloc(20000*sizeof(float)); 

    for(unsigned int i=0; i<=10100; i++) { 
      output[i] = input[i] * 0.1f; 
    } 
} 

(lưu ý rằng tôi đã không nghĩ rằng quá khó về cách dịch đúng hạn còn lại pos + thành một duy nhất cho tình trạng vòng lặp, có thể sai)

Bạn có thể tận dụng điều này bằng cách đặt vòng lặp bên trong đơn giản vào một hàm mà bạn gọi với con trỏ và số đếm. Ngay cả khi nó được inline một lần nữa nó có thể làm việc tốt. Điều này giả định rằng bạn đã xóa các phần của vòng lặp while() mà tôi đã đơn giản hóa nhưng bạn cần giữ lại.

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