Почему GCC не может векторизовать эту функцию и цикл? - PullRequest
0 голосов
/ 11 января 2019

Я пытаюсь включить функцию с поддержкой SIMD и векторизовать цикл с помощью вызова функции.

#include <cmath>

#pragma omp declare simd
double BlackBoxFunction(const double x) {
    return 1.0/sqrt(x);
}

double ComputeIntegral(const int n, const double a, const double b) {
    const double dx = (b - a)/n;
    double I = 0.0;
    #pragma omp simd reduction(+: I)

    for (int i = 0; i < n; i++) {
      const double xip12 = a + dx*(double(i) + 0.5);
      const double yip12 = BlackBoxFunction(xip12);
      const double dI = yip12*dx;
      I += dI; 
  }
  return I;
}

Для кода выше, если я скомпилирую его с icpc:

icpc worker.cc -qopenmp -qopt-report=5 -c

opt-report показывает, что функция и цикл векторизованы. Однако, если я попытаюсь скомпилировать его с g++ 6.5:

g++ worker.cc -O3 -fopenmp -fopt-info-vec-missed -funsafe-math-optimizations -c

Выходные данные показывают note:not vectorized: control flow in loop. и note: bad loop form, и цикл не может быть векторизован.

Как я могу векторизовать цикл с GCC?

РЕДАКТИРОВАТЬ:

Если я запишу функцию в отдельный файл,

worker.cc:

#include "library.h"

double ComputeIntegral(const int n, const double a, const double b) {
    const double dx = (b - a)/n;
    double I = 0.0;
    #pragma omp simd reduction(+: I)

    for (int i = 0; i < n; i++) {
      const double xip12 = a + dx*(double(i) + 0.5);
      const double yip12 = BlackBoxFunction(xip12);
      const double dI = yip12*dx;
      I += dI; 
  }
  return I;
}

library.h

#ifndef __INCLUDED_LIBRARY_H__
#define __INCLUDED_LIBRARY_H__

#pragma omp declare simd
double BlackBoxFunction(const double x); 

#endif

и library.cc:

#include <cmath>

#pragma omp declare simd
double BlackBoxFunction(const double x) {
  return 1.0/sqrt(x);
}

Затем я компилирую его с помощью GCC:

g++ worker.cc library.cc -O3 -fopenmp -fopt-info-vec-missed -funsafe-math-optimizations -c

Показывает:

worker.cc:9:31: note: loop vectorized

но

library.cc:5:18: note:not vectorized: control flow in loop.
library.cc:5:18: note:bad loop form.

Это меня смущает. Интересно, векторизовано ли оно уже?

1 Ответ

0 голосов
/ 11 января 2019

Векторизация возможна с помощью gcc, после небольшого изменения кода:

#include <cmath>

double BlackBoxFunction(const double x) {
    return 1.0/sqrt(x);
}

double ComputeIntegral(const int n, const double a, const double b) {
    const double dx = (b - a)/n;
    double I = 0.0;
    double d_i = 0.0;
    for (int i = 0; i < n; i++) {
      const double xip12 = a + dx*(d_i + 0.5);
      d_i = d_i + 1.0;
      const double yip12 = BlackBoxFunction(xip12);
      const double dI = yip12*dx;
      I += dI; 
  }
  return I;
}

Это было скомпилировано с параметрами компилятора: -Ofast -march=haswell -fopt-info-vec-missed -funsafe-math-optimizations. Основной цикл компилируется в

.L7:
    vaddpd  ymm2, ymm4, ymm7
    inc     eax
    vaddpd  ymm4, ymm4, ymm8
    vfmadd132pd     ymm2, ymm9, ymm5
    vsqrtpd ymm2, ymm2
    vdivpd  ymm2, ymm6, ymm2
    vfmadd231pd     ymm3, ymm5, ymm2
    cmp     eax, edx
    jne     .L7

См. Следующую ссылку Годболт

Я удалил #pragma omp ..., потому что они не улучшили векторизацию, но они также не ухудшили векторизацию.

Обратите внимание, что только изменение параметра компилятора с -O3 на -Ofast достаточно, чтобы включить векторизацию. Тем не менее, более эффективно использовать счетчик double, чем счетчик int, который конвертируется для удвоения каждой итерации.

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

...