2017-03-07 74 views
2

Xeon-Phi騎士登陸核心有一個快速exp2指令vexp2pd(內部_mm512_exp2a23_pd)。英特爾C++編譯器可以使用編譯器附帶的短矢量數學庫(SVML)矢量化exp函數。具體而言,它稱爲功能__svml_exp8從SVML覆蓋函數調用

然而,當我通過調試步驟我沒有看到__svml_exp8使用vexp2pd指令。這是許多FMA操作的複雜功能。據我所知,vexp2pdexp不太準確,但如果我用-fp-model fast=1(默認值)或fp-model fast=2我期望編譯器使用該指令,但事實並非如此。

我有兩個問題。

  1. 有沒有辦法讓編譯器使用vexp2pd
  2. 我如何安全地重寫調用__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); 
} 
+0

你問的編譯器使用'vexp2pd'扔的精度有30位。即使快速數學也不會這樣做。 – Mysticial

+0

@Mysticial我很確定我注意到編譯器使用'vrcp28pd'(實際上你可以在這裏看到它(https://godbolt.org/g/Wya9Ic))。所以如果它使用快速互惠爲什麼不是一個快速的'exp'?看看這個代碼的倒數,它看起來可能是在做一次牛頓迭代或其他事情(否則,所有FMA都會出現這種情況)。這可以解釋爲什麼它使用快速倒數而不是快速的'exp'。 –

+0

我從來沒有聽說過'vfixupimmpd'。奇怪的指示。內在指導說它需要AVXVL,但是共享者爲沒有AVXVL的KNL生成它。 –

回答

4

ICC會產生vexp2pd但只有在非常寬鬆的數學要求,通過有針對性的-fimf *交換機指定。

#include <math.h> 

void vfoo(int n, double * a, double * r) 
{ 
    int i; 
    #pragma simd 
    for (i = 0; i < n; i++) 
    { 
     r[i] = exp(a[i]); 
    } 
} 

例如,與-xMIC-AVX512 -fimf域排阻編譯= 1 -fimf精度位= 22

..B1.12: 
     vmovups (%rsi,%rax,8), %zmm0 
     vmulpd .L_2il0floatpacket.2(%rip){1to8}, %zmm0, %zmm1 
     vexp2pd %zmm1, %zmm2 
     vmovupd %zmm2, (%rcx,%rax,8) 
     addq  $8, %rax 
     cmpq  %r8, %rax 
     jb  ..B1.12 

請一定要了解的準確性影響,因爲不僅最終的結果是隻有大約22位準確,但是vexp2pd也會刷新到任何非規格化結果爲零,而不管MXCSR中設置的FTZ/DAZ位。

對第二個問題:「我如何安全地重寫調用__svml_exp8?」 您的方法通常不安全。 SVML例程是英特爾編譯器的內部函數,並且依賴於自定義調用約定,因此與庫例程相比,具有相同名稱的泛型例程可能會更多地註冊更多的寄存器,並且最終會導致難以調試的ABI不匹配。

提供自己的載體功能,更好的辦法是利用OMP的#pragma聲明SIMD,例如請參閱https://software.intel.com/en-us/node/524514,如果喜歡使用intrinsics進行編碼,請參閱https://software.intel.com/en-us/node/523350,可能還有vector_variant屬性。只是不要試圖覆蓋標準的數學名稱,否則你會得到一個錯誤。

+0

您的代碼不會爲ICC 17生成'vexp2pd'。我嘗試了很多變體。但是如果我在你的答案的代碼中用'exp2'替換'exp',那麼它確實會產生'vexp2pd'。 –

+1

請試用18.0(目前處於測試階段) – NikitaA