我正在尝试使功能启用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.
这让我感到困惑。我想知道它是否已经矢量化了。
答案 0 :(得分:7)
在稍微修改一下代码之后,可以使用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
请参阅以下Godbolt link
我删除了#pragma omp ...
,因为它们没有改善向量化,但也没有使向量化恶化。
请注意,仅将编译器选项从-O3
更改为-Ofast
是
足以实现矢量化。但是,使用double
计数器比int
计数器要有效,后者每次转换都会翻倍。
还请注意,矢量化报告具有很大的误导性。检查生成的汇编代码,以查看矢量化是否成功。