Как оптимизировать вычисление цикла for с использованием SIMD? - PullRequest
1 голос
/ 09 мая 2019

Я пытаюсь ускорить алгоритм стереофонического согласования на платформе ODROID XU4 ARM, используя Neon SIMD.Для этой цели я использую прагмы openMp.

 void StereoMatch:: sadCol(uint8_t* leftRank,uint8_t* rightRank,const int SAD_WIDTH,const int SAD_WIDTH_STEP, const int imgWidth,int j, int d , uint16_t* cost) 
  {

   uint16_t sum = 0;
   int n = 0;
   int m =0;
      for ( n = 0; n < SAD_WIDTH+1; n++)
      {

     #pragma omp simd
     for(  m = 0; m< SAD_WIDTH_STEP; m = m + imgWidth ) 
         {


        sum += abs(leftRank[j+m+n]-rightRank[j+m+n-d]);

         };
         cost[n] = sum;
         sum = 0;



  };

Я довольно новичок в SIMD и openMp, я понял, что использование прагмы SIMD в коде заставит компилятор векторизовать вычитание, но когда я выполнил код, я не заметил никакой разницы.Что я должен добавить к своему коду для его векторизации?

1 Ответ

1 голос
/ 17 июля 2019

Как сказано в комментариях, ARM-Neon имеет инструкцию, которая напрямую выполняет то, что вы хотите, то есть вычисляет абсолютную разницу беззнаковых байтов и накапливает ее в беззнаковые короткие целые числа.

Предполагая SAD_WIDTH+1==8Вот очень простая реализация с использованием встроенных функций (на основе упрощенной версии @nemequ):

void sadCol(uint8_t* leftRank,
            uint8_t* rightRank,
            int j,
            int d ,
            uint16_t* cost) {
    const int SAD_WIDTH = 7;
    const int imgWidth = 320;
    const int SAD_WIDTH_STEP = SAD_WIDTH * imgWidth;

    uint16x8_t cost_8 = {0};
    for(int m = 0; m < SAD_WIDTH_STEP; m = m + imgWidth )  {
        cost_8 = vabal_u8(cost_8, vld1_u8(&leftRank[j+m]), vld1_u8(&rightRank[j+m-d]));
    };
    vst1q_u16(cost, cost_8);
};

vld1_u8 загружает 8 последовательных байтов, vabal_u8 вычисляет абсолютную разницу и накапливает ее до первогорегистр.Наконец, vst1q_u16 сохраняет регистр в памяти.

Вы можете легко настроить imgWidth и SAD_WIDTH_STEP функциональные параметры.Если SAD_WIDTH+1 отличается от кратного 8, вы можете написать для этого еще один цикл.

У меня нет под рукой платформы ARM для его проверки, но "она компилируется": https://godbolt.org/z/vPqiYI (исборка выглядит нормально, на мой взгляд).Если вы оптимизируете с помощью -O3, gcc развернет цикл.

...