Не удалось определить, почему следующий фрагмент кода не был векторизован

Я какое-то время боролся с векторизацией конкретного приложения, и я пробовал все. От автовекторизации до написанных вручную встроенных функций SSE. Но почему-то я не могу получить ускорение в своем приложении на основе трафарета.

Ниже приведен фрагмент моего текущего кода, который я векторизовал с помощью встроенных функций SSE. Когда я компилирую (Intel icc) с помощью -vec-report3, я постоянно получаю это сообщение:
примечание: цикл не был векторизован: оператор не может быть векторизован.

  #pragma ivdep
  for ( i = STENCIL; i < z - STENCIL; i+=4 )
  {
    it = it2 + i;

    __m128 tmp2i = _mm_mul_ps(_mm_add_ps(_mm_load_ps(&p2[i+j*it_j-it_j4+k*it_k]),_mm_load_ps(&p2[i+j*it_j+it_j4+k*it_k])),X4_i); //loop was not vectorized: statement cannot be vectorized
    __m128 tmp3 = _mm_mul_ps(_mm_add_ps(_mm_load_ps(&p2[i+j*it_j-it_j3+k*it_k]),_mm_load_ps(&p2[i+j*it_j+it_j3+k*it_k])),X3_i);
    __m128 tmp4 = _mm_mul_ps(_mm_add_ps(_mm_load_ps(&p2[i+j*it_j-it_j2+k*it_k]),_mm_load_ps(&p2[i+j*it_j+it_j2+k*it_k])),X2_i);
    __m128 tmp5 = _mm_mul_ps(_mm_add_ps(_mm_load_ps(&p2[i+j*it_j-it_j +k*it_k]),_mm_load_ps(&p2[i+j*it_j+it_j +k*it_k])),X1_i);

    __m128 tmp6 = _mm_add_ps(_mm_add_ps(_mm_add_ps(tmp2i,tmp3),_mm_add_ps(tmp4,tmp5)), _mm_mul_ps(_mm_load_ps(&p2[it]),C00_i));

    _mm_store_ps(&tmp2[i],tmp6);

   }

Я упускаю что-то важное? Поскольку в сообщении не уточняется, почему его нельзя векторизовать, мне трудно определить узкое место.

ОБНОВЛЕНИЕ: после тщательного рассмотрения предложений я изменил код следующим образом. Я подумал, что лучше разбить его дальше, чтобы определить утверждения, которые на самом деле ответственны за векторную зависимость.

//#pragma ivdep
  for ( i = STENCIL; i < z - STENCIL; i+=4 )
  {
    it = it2 + i;
    __m128 center = _mm_mul_ps(_mm_load_ps(&p2[it]),C00_i);

    u_j4 = _mm_load_ps(&p2[i+j*it_j-it_j4+k*it_k]); //Line 180
    u_j3 = _mm_load_ps(&p2[i+j*it_j-it_j3+k*it_k]);
    u_j2 = _mm_load_ps(&p2[i+j*it_j-it_j2+k*it_k]);
    u_j1 = _mm_load_ps(&p2[i+j*it_j-it_j +k*it_k]);
    u_j8 = _mm_load_ps(&p2[i+j*it_j+it_j4+k*it_k]);
    u_j7 = _mm_load_ps(&p2[i+j*it_j+it_j3+k*it_k]);
    u_j6 = _mm_load_ps(&p2[i+j*it_j+it_j2+k*it_k]);
    u_j5 = _mm_load_ps(&p2[i+j*it_j+it_j +k*it_k]);

    __m128 tmp2i = _mm_mul_ps(_mm_add_ps(u_j4,u_j8),X4_i);
    __m128 tmp3 = _mm_mul_ps(_mm_add_ps(u_j3,u_j7),X3_i);
    __m128 tmp4 = _mm_mul_ps(_mm_add_ps(u_j2,u_j6),X2_i);
    __m128 tmp5 = _mm_mul_ps(_mm_add_ps(u_j1,u_j5),X1_i);

    __m128 tmp6 = _mm_add_ps(_mm_add_ps(tmp2i,tmp3),_mm_add_ps(tmp4,tmp5));
    __m128 tmp7 = _mm_add_ps(tmp6,center);

    _mm_store_ps(&tmp2[i],tmp7);  //Line 196

   }

Когда я компилирую (icc) приведенный выше код без #pragma ivdep, я получаю следующее сообщение:

remark: loop was not vectorized: existence of vector dependence.
vector dependence: assumed FLOW dependence between tmp2 line 196 and tmp2 line 196.
vector dependence: assumed ANTI dependence between tmp2 line 196 and tmp2 line 196.

Когда я компилирую (icc) его с #pragma ivdep, я получаю следующее сообщение:

remark: loop was not vectorized: unsupported data type. //Line 180

Почему для строки 196 предлагается зависимость? Как я могу устранить предложенную векторную зависимость?


person PGOnTheGo    schedule 16.07.2012    source источник
comment
Упростите конструкцию for, предварительно вычислив конечное значение и количество циклов.   -  person David Schwartz    schedule 16.07.2012
comment
Он не может векторизовать его, потому что вы уже его векторизовали. Вы не получаете никакого ускорения, потому что соотношение вычислений/доступа к памяти слишком низкое.   -  person Mysticial    schedule 16.07.2012
comment
Моей первой мыслью было не выравнивание (Mysticial поправил меня), но определенно стоит начать с упрощения выражений для смещений массива.   -  person Viktor Latypov    schedule 17.07.2012
comment
@Mystical: это только фрагмент моего кода. Фактический код представляет собой трехмерный шаблон, и я тестировал данные размером от 512 до 1024. Это означает, что общее количество операций с плавающей запятой должно быть (512) ^ 3 * 31 * 200. 200 - это количество итераций. . Я ожидал некоторого улучшения при совместном планировании 4 плавающих операций (при использовании встроенных функций SSE) по сравнению с 1 за один тактовый цикл.   -  person PGOnTheGo    schedule 17.07.2012
comment
Это не проблема. У вас есть 10 доступов к памяти только для 13 операций. Это слишком много. ЦП, скорее всего, будет узким местом из-за нагрузки, а не из-за вычислений. По моему опыту, вам действительно нужно иметь соотношение вычислений/доступа к памяти как минимум 3 к 1.   -  person Mysticial    schedule 17.07.2012
comment
Кроме того, ваше тело цикла, похоже, имеет довольно длинную цепочку зависимостей. Я бы рассмотрел возможность вручную развернуть его на 2-4 итерации.   -  person Mysticial    schedule 17.07.2012
comment
@Mystical: я пытался реализовать развертывание цикла вручную с коэффициентом 2,4,8. Однако, поскольку этот цикл является самым внутренним (самым быстрым измерением в 3D-шаблоне) при развертывании, я всегда получал снижение производительности. Но когда я развернул самый внешний цикл, я увидел некоторое улучшение.   -  person PGOnTheGo    schedule 17.07.2012
comment
@Mystical: Не могли бы вы предложить способы уменьшить количество обращений к памяти в моем коде. Я выполняю операции перетасовки в своем i-м измерении, чтобы уменьшить количество загрузок, но я не могу понять, как это будет возможно для j-го и k-го измерений, поскольку они не являются смежными в памяти (в отличие от измерения i) и связаны шаги 'dx' и 'dx*dy' соответственно.   -  person PGOnTheGo    schedule 17.07.2012
comment
Я должен афк. Но я вернусь к этому позже.   -  person Mysticial    schedule 17.07.2012
comment
Единственный способ уменьшить доступ к памяти — изменить способ обработки данных. Если вы выполняете несколько проходов по одним и тем же данным, попробуйте сгруппировать их вместе. Больше я не могу здесь сказать. Вы можете взглянуть на: en.wikipedia.org/wiki/Loop_tiling   -  person Mysticial    schedule 17.07.2012
comment
Попробуйте скомпилировать с -guide. Возможно, это даст вам совет, что делать, чтобы включить векторизацию цикла. Вы также можете попробовать прагмы simd и vector.   -  person Hristo Iliev    schedule 19.07.2012


Ответы (1)


Проблема в том, что вы пытаетесь использовать автоматическую векторизацию вместе с ручным векторизованным кодом. Компилятор говорит, что линия не может быть векторизована, потому что вы не можете векторизовать векторную функцию.

Либо позвольте компилятору автоматически векторизовать его, либо отключите автоматическую векторизацию и вручную векторизуйте свой код. Как уже отмечалось, автоматический векторизатор рассчитает рентабельность векторизации: он проверит, стоит ли векторизовать ваш код.

person hdante    schedule 26.02.2013