C++错误:在此作用域中未声明'_mm_sin_ps'。

6
我正在尝试对将函数应用到数组的不同方式进行基准测试。
为什么我的范围内不知道_mm_sin_ps,但却知道_mm_sqrt_ps
如何使其被识别,并在编译时不出现错误?同时请参考https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=3260,2124,4779,4779&cats=Trigonometry&text=_sin
#include <random>
#include <iostream>
#include <cmath>
#include <chrono>
#include <algorithm>
#include <valarray>
#include "immintrin.h"
#include <array>
int main()
{
    std::cout<<"start\n";
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<> dis(-1000, 1000);
    int N=100;
    while(N--)
    {   
        std::cout<<"\nN: "<<N;

    const int T1=4E6;
      { 
        int T=T1,T0=T1/4;
        std::array<float,T1> array;
        while(T--)
        {
            array[T]=dis(gen);
        }
        auto start_time = std::chrono::high_resolution_clock::now();
        auto it =array.begin();
        while(T0--)
        {
            __m128 X = _mm_loadu_ps(it);
            __m128 result = _mm_sin_ps(X);
            _mm_storeu_ps(it, result);
            it+=4;
        }
        auto time2=std::chrono::high_resolution_clock::now()-start_time;
            std::cout<<"\nintr1: "<<std::chrono::duration_cast<std::chrono::microseconds>(time2).count();
        }
  }
    std::cout<<"\nfin\n";
    return 0;
}

compiler

g++ -v

Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu      4.8.2-19ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs   --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable- plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu  --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) 

如果你自己声明 extern __m128 _mm_sin_ps(__m128 v1);,那么它会编译吗? - Anthony
1
我的机器可能根本不知道_mm_sin_ps内在函数吗?你的机器上代码能编译吗? - Philipp
1
好的,所以你得到了一个链接器错误,这意味着内置函数对你的编译器不可用。 - Anthony
编译器:gcc 4.8.2。我将g++ -v的输出放在了问题中。 - Philipp
1
我有gcc 4.9.2,但没有_mm_sin_ps函数。此外,在英特尔页面上,该函数位于SVML部分,没有机器指令。请查看此项目,使用SSE三角函数库或自己实现。 - Youka
显示剩余7条评论
3个回答

7

_mm_sin_psSVML库的一部分,仅随Intel编译器一起发布。GCC开发人员专注于包装机器指令和简单任务,因此目前在immintrin.h中没有SVML。

您需要使用库或自己编写代码。 正弦实现:


谢谢,我认为CORDIC不能与SSE一起使用,因为需要进行表查找。我将使用min {int_0_pi / 2 ((P_n(x)-sin(x))^ 2)dx,其中P_n(0)= 0; P_n(pi / 2)= 1; 对于n = 2,这应该是二次曲线。 - Philipp
Windows 8 SDK或更高版本中的DirectXMath还包括超越函数的SIMD实现。 - Chuck Walbourn

4
正如已经指出的那样,您正在尝试使用英特尔的SVML库。
然而,在免费开源的sse_mathfun库中有几个SIMD超越函数。原始版本仅使用SSE2,位于此处:http://gruntthepeon.free.fr/ssemath/,但这里有一个更新的版本,已经更新为SSE3/SSE4:https://github.com/RJVB/sse_mathfun 您需要的函数名为sin_ps
v4sf sin_ps(v4sf x);

这里的v4sf只是__m128的一个typedef。

原始的sse_mathfun还包括cos_pslog_psexp_ps,而更新的(RJVB)版本则为单精度和双精度提供了一些额外的函数。

我已经成功地在gcc、clang和英特尔的ICC上使用了这个库(对于后者进行了一些小修改)。


1
可以使用英特尔的SVML与其他编译器,但这是未记录的。函数原型如下: extern __m128 __vectorcall __svml_expf4 (__m128); extern __m128d __vectorcall __svml_exp2 (__m128d); 非官方的函数原型列在https://github.com/vectorclass/version2/blob/master/vectormath_lib.h中。 - A Fog

4

__mm_sin_ps是用于调用已提到的SVML库的内置函数。

在GCC中,SVML作为libmvec的一部分在glibc中可用。

函数的命名根据上面链接中描述的向量ABI。可用的函数包括sin、cos、exp、sincos、log、pow。这里是一个__m128的示例:

#include <x86intrin.h>
#include <stdio.h>

typedef union
{
  __m128  x;
  float a[4];
} union128;

__m128 _ZGVbN4v_sinf_sse4(__m128);

void main()
{
  union128 s1, res;
  s1.x = _mm_set_ps (0, 0.523599, 1.0472 , 1.5708);
  res.x =_ZGVbN4v_sinf_sse4(s1.x);
  fprintf(stderr, "%f %f %f %f\n", res.a[0], res.a[1], res.a[2], res.a[3]);
}

有没有什么原因,内在函数比直接使用SVML函数更好?


libmvec和SVML不是同一个库。 - A Fog

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接