Xeon-Phi Knights Landing核心具有快速的exp2指令vexp2pd(本征_mm512_exp2a23_pd)。英特尔C++编译器可以使用编译器随附的短 vector 数学库(SVML)对exp函数进行矢量化处理。具体来说,它称为功能__svml_exp8

但是,当我逐步调试程序时,看不到__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);
    }
    

    最佳答案

    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-domain-exclusion = 1 -fimf-accuracy-bits = 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例程是Intel Compiler的内部组件,并依赖于自定义调用约定,因此,与库例程相比,具有相同名称的泛型例程可能会浪费更多的寄存器,并且您可能最终难以调试ABI不匹配。

    提供您自己的 vector 函数的更好方法是利用#pragma omp声明simd,例如如果更喜欢使用内在函数进行编码,请参见https://software.intel.com/en-us/node/524514以及可能的vector_variant属性,请参见https://software.intel.com/en-us/node/523350。只是不要尝试覆盖标准数学名称,否则会出现错误。

    关于c++ - 覆盖来自SVML的函数调用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42644794/

    10-10 11:22