2011-02-16 5 views
5

я следующую программу C (упрощение моего фактического использования случай, который имеет такое же поведение)Почему GCC не автогенерирует этот цикл?

#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; 
      } 
    } 
} 

Когда я компилирую с

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

я получить выход

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

где 10 - линия внутренней петли. Когда я посмотрел, почему это может сказать это, казалось, было сказано, что указатели могут быть сглажены, но они не могут быть в моем коде, поскольку у меня есть ключевое слово __restrict. Они также предложили включить в себя -msse флаги, но они, похоже, тоже ничего не делают. Любая помощь?

+0

Какая версия gcc? Рабочий пример также может быть полезен, так как взломанная версия, векторизованная, когда я пробовал ее с 4.4.5 – ergosys

+0

, мог бы опубликовать пример кода, который компилируется? когда я заполнил некоторые фиктивные значения, цикл был векторизован ... – Christoph

+0

@ergosys: что он сказал;) – Christoph

ответ

3

Это, безусловно, похоже на ошибку. В следующих, эквивалентных функциях, foo() является vectorised, но bar() нет, при компиляции для целевой 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; 
} 

Добавление -m32 флага, чтобы собрать для цели x86 вместо этого, вызывает обе функции, чтобы быть vectorised ,

+1

Спасибо! Я на 64-битной платформе! Выполнение -m32 заставляет его работать отлично. Сейчас я отправляю отчет об ошибке. Другие ответы велики, но на самом деле это всего лишь обходные пути, так как это должно работать без каких-либо изменений. –

+0

Обратите внимание, что 32-разрядный исполняемый файл может быть намного медленнее, чем не-векторизованный 64, поэтому, если ваша цель не является исключительно «использованием SSE», вы должны профилировать все свое приложение. –

+0

Спасибо, Бен, я на самом деле не использую это, чтобы скомпилировать мой код, но просто чтобы записать отчет об ошибке. Я могу заставить его правильно нарисовать на 64 бит, просто немного изменив ситуацию. –

1

попробовать:

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

эксперимент немного изменив вещи вокруг:

#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

В чем причина? –

+0

@ Oli просто догадаться, может быть, его компилятор не любит дополнительную const или '__restrict' форму – Anycorn

+0

ничего не меняет. –

2

Это не нравится внешний формат цикла, который предотвращает его от понимания внутреннего цикла. Я могу получить его векторизации, если я просто сложить его в одну петлю:

#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; 
    } 
} 

(обратите внимание, что я не думаю, что слишком трудно о том, как правильно перевести поз + ограничение остальное в один для условия цикла, это может быть неверно)

Возможно, вы сможете воспользоваться этим, поставив упрощенный внутренний цикл в функцию, которую вы вызываете с помощью указателей и счетчика. Даже когда он снова встроен, он может работать нормально. Это предполагает, что вы удалили части вашего цикла while(), который я только что упростил, но вам нужно сохранить.