我有一个简单的c代码如下
void calculate_exp(float *out, float *in, int size) {
for(int i = 0; i < size; i++) {
out[i] = exp(in[i]);
}
}
我想使用 open-mp simd 对其进行优化。我是 open-mp 的新手,使用了一些编译指示,如“omp simd”、“omp simd safelen”等。但我无法生成 simd 代码。有人可以帮忙吗?
最佳答案
您可以使用以下四种替代方法之一来矢量化 exp
函数。
请注意,我使用了 expf
(浮点)而不是 exp
,它是一个 double
函数。
这个Godbolt link显示这些函数已向量化:在编译器生成的代码中搜索 call _ZGVdN8v___expf_finite
。
#include<math.h>
int exp_vect_a(float* x, float* y, int N) {
/* Inform the compiler that N is a multiple of 8, this leads to shorter code */
N = N & 0xFFFFFFF8;
x = (float*)__builtin_assume_aligned(x, 32); /* gcc 8.2 doesn't need aligned x and y to generate `nice` code */
y = (float*)__builtin_assume_aligned(y, 32); /* with gcc 7.3 it improves the generated code */
#pragma omp simd
for(int i=0; i<N; i++) y[i] = expf(x[i]);
return 0;
}
int exp_vect_b(float* restrict x, float* restrict y, int N) {
N = N & 0xFFFFFFF8;
x = (float*)__builtin_assume_aligned(x, 32); /* gcc 8.2 doesn't need aligned x and y to generate `nice` code */
y = (float*)__builtin_assume_aligned(y, 32); /* with gcc 7.3 it improves the generated code */
for(int i=0; i<N; i++) y[i] = expf(x[i]);
return 0;
}
/* This also vectorizes, but it doesn't lead to `nice` code */
int exp_vect_c(float* restrict x, float* restrict y, int N) {
for(int i=0; i<N; i++) y[i] = expf(x[i]);
return 0;
}
/* This also vectorizes, but it doesn't lead to `nice` code */
int exp_vect_d(float* x, float* y, int N) {
#pragma omp simd
for(int i=0; i<N; i++) y[i] = expf(x[i]);
return 0;
}
请注意Peter Cordes' comment在这里非常相关:
函数 _ZGVdN8v___expf_finite
给出的结果可能与 expf
略有不同
因为它的重点是速度,而不是特殊情况,例如输入
无限、次正规或不是数字。
而且,精度为4-ulp最大相对误差,
这可能比标准 expf
函数的准确度稍低。
因此,您需要优化级别 -Ofast
(这允许不太准确的代码)
而不是 -O3
来使用 gcc 获取代码矢量化。
参见this libmvec page了解更多详情。
以下测试代码在 gcc 7.3 上编译并成功运行:
#include <math.h>
#include <stdio.h>
/* gcc expv.c -m64 -Ofast -std=c99 -march=skylake -fopenmp -lm */
int exp_vect_d(float* x, float* y, int N) {
#pragma omp simd
for(int i=0; i<N; i++) y[i] = expf(x[i]);
return 0;
}
int main(){
float x[32];
float y[32];
int i;
int N = 32;
for(i = 0; i < N; i++) x[i] = i/100.0f;
x[10]=-89.0f; /* exp(-89.0f)=2.227e-39 which is a subnormal number */
x[11]=-1000.0f; /* output: 0.0 */
x[12]=1000.0f; /* output: Inf. */
x[13]=0.0f/0.0f; /* input: NaN: Not a number */
x[14]=1e20f*1e20f; /* input: Infinity */
x[15]=-1e20f*1e20f; /* input: -Infinity */
x[16]=2.3025850929940f; /* exp(2.3025850929940f)=10.0... */
exp_vect_d(x, y, N);
for(i = 0; i < N; i++) printf("x=%11.8e, y=%11.8e\n", x[i], y[i]);
return 0;
}
关于openmp - 如何使用 openmp 生成数学函数 "exp"的 simd 代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53280563/