【问题标题】:C++ error: ‘_mm_sin_ps’ was not declared in this scopeC++ 错误:“_mm_sin_ps”未在此范围内声明
【发布时间】:2022-01-07 01:50:49
【问题描述】:

我正在尝试对将函数应用于数组的不同方法进行基准测试。

为什么是https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=3260,2124,4779,4779&cats=Trigonometry&text=_sin

_mm_sin_ps 在我的范围内未知,但 _mm_sqrt_ps 是?

我如何让它知道?并且编译没有错误。

#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;
}

编译器

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);,会编译吗?
  • 是的,但随后收集器在构建时抱怨 undef。参考 _mm_sin_ps(float __vector)'
  • 会不会是我的机器根本不知道 _mm_sin_ps 内在函数?代码可以在你的机器上编译吗?
  • 好的,所以你得到一个链接器错误,这意味着你的编译器不能使用内在函数。
  • 我有 gcc 4.9.2 并且没有函数_mm_sin_ps,而且在 Intel 页面上,这个函数在 SVML 部分并且没有机器指令。看看this project,使用 SSE 三角函数库或自己实现。

标签: c++ optimization sse simd intrinsics


【解决方案1】:

_mm_sin_psSVML 库的一部分,仅随英特尔编译器一起提供。 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 这应该是二次曲线
  • DirectXMath 在 Windows 8 SDK 或更高版本中还包括超越函数的 SIMD 实现。
【解决方案2】:

正如已经指出的那样,您正在尝试使用英特尔的 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 的类型定义。

原来的sse_mathfun还有cos_pslog_psexp_ps,新的(RJVB)版本有一些额外的单精度和双精度功能。

我已经成功地将这个库的两个版本与 gcc、clang 和 Intel 的 ICC 一起使用(对后者进行了一些小修改)。

【讨论】:

    【解决方案3】:

    __mm_sin_ps 是调用 SVML 库的内在函数(已经提到过)。

    在 GCC 中,SVML 作为libmvec 的一部分提供 在 glibc 中。

    函数根据上面链接中描述的 Vector 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]);
    }
    

    有什么原因,为什么intrinsic比直接使用SVML函数更好?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多