Xeon-Phi骑士登陆核心有一个快速exp2
指令vexp2pd
(内部_mm512_exp2a23_pd
)。英特尔C++编译器可以使用编译器附带的短矢量数学库(SVML)矢量化exp
函数。具体而言,它称为功能__svml_exp8
。从SVML覆盖函数调用
然而,当我通过调试步骤我没有看到__svml_exp8
使用vexp2pd
指令。这是许多FMA操作的复杂功能。据我所知,vexp2pd
比exp
不太准确,但如果我用-fp-model fast=1
(默认值)或fp-model fast=2
我期望编译器使用该指令,但事实并非如此。
我有两个问题。
- 有没有办法让编译器使用
vexp2pd
? - 我如何安全地重写调用
__svml_exp8
?
至于第二个问题,这是我迄今所做的。
//exp(x) = exp2(log2(e)*x)
extern "C" __m512d __svml_exp8(__m512d x) {
return _mm512_exp2a23_pd(_mm512_mul_pd(_mm512_set1_pd(M_LOG2E), x));
}
这是安全吗?有没有更好的解决方案一个内联函数?在下面的测试代码中,这比不覆盖时大约快3倍。
//https://godbolt.org/g/adI11c
//icpc -O3 -xMIC-AVX512 foo.cpp
#include <math.h>
#include <stdio.h>
#include <x86intrin.h>
extern "C" __m512d __svml_exp8(__m512d x) {
//exp(x) = exp2(log2(e)*x)
return _mm512_exp2a23_pd(_mm512_mul_pd(_mm512_set1_pd(M_LOG2E), x));
}
void foo(double * __restrict x, double * __restrict y) {
__assume_aligned(x, 64);
__assume_aligned(y, 64);
for(int i=0; i<1024; i++) y[i] = exp(x[i]);
}
int main(void) {
double x[1024], y[1024];
for(int i=0; i<1024; i++) x[i] = 1.0*i;
for(int r=0; r<1000000; r++) foo(x,y);
double sum=0;
//for(int i=0; i<1024; i++) sum+=y[i];
for(int i=0; i<8; i++) printf("%f ", y[i]); puts("");
//printf("%lf",sum);
}
你问的编译器使用'vexp2pd'扔的精度有30位。即使快速数学也不会这样做。 – Mysticial
@Mysticial我很确定我注意到编译器使用'vrcp28pd'(实际上你可以在这里看到它(https://godbolt.org/g/Wya9Ic))。所以如果它使用快速互惠为什么不是一个快速的'exp'?看看这个代码的倒数,它看起来可能是在做一次牛顿迭代或其他事情(否则,所有FMA都会出现这种情况)。这可以解释为什么它使用快速倒数而不是快速的'exp'。 –
我从来没有听说过'vfixupimmpd'。奇怪的指示。内在指导说它需要AVXVL,但是共享者为没有AVXVL的KNL生成它。 –