3

我目前正在试验GCC 矢量扩展。但是,我想知道如何sqrt(vec)按预期工作。

如:

typedef double v4d __attribute__ ((vector_size (16)));
v4d myfunc(v4d in)
{
    return some_sqrt(in);
}

并且至少在最近的 x86 系统上,它会发出对相关固有 sqrtpd 的调用。是否有适用于矢量类型的 sqrt 内置 GCC,或者是否需要降级到内在级别才能完成此操作?

4

3 回答 3

0

看起来这是一个错误:http ://gcc.gnu.org/bugzilla/show_bug.cgi?id= 54408 除了按组件进行之外,我不知道任何解决方法。无论如何,向量扩展从来都不是要替换特定于平台的内在函数。

为此效果的一些时髦代码:

#include <cmath>

#include <utility>

template <::std::size_t...> struct indices { };

template <::std::size_t M, ::std::size_t... Is>
struct make_indices : make_indices<M - 1, M - 1, Is...> {};

template <::std::size_t... Is>
struct make_indices<0, Is...> : indices<Is...> {};

typedef float vec_type __attribute__ ((vector_size(4 * sizeof(float))));

template <::std::size_t ...Is>
vec_type sqrt_(vec_type const& v, indices<Is...> const)
{
  vec_type r;

  ::std::initializer_list<int>{(r[Is] = ::std::sqrt(v[Is]), 0)...};

  return r;
}

vec_type sqrt(vec_type const& v)
{
  return sqrt_(v, make_indices<4>());
}

int main()
{
  vec_type v;

  return sqrt(v)[0];
}

您还可以尝试使用与矢量扩展分开的自动矢量化来碰碰运气。

于 2013-10-22T16:28:36.250 回答
0

我对这个问题的解读是,您想要 4 个打包双精度值的平方根……那是32字节。使用适当的 AVX 内在函数:

#include <x86intrin.h>

typedef double v4d __attribute__ ((vector_size (32)));
v4d myfunc (v4d v) {
    return _mm256_sqrt_pd(v);
}

x86-64 gcc 10.2 和 x86-64 clang 10.0.1 使用-O3 -march=skylake

myfunc:
  vsqrtpd %ymm0, %ymm0 # (or just `ymm0` for Intel syntax)
  ret

ymm0是返回值寄存器。

也就是说,碰巧有一个内置的: __builtin_ia32_sqrtpd256,它不需要内在的标头。但是,我肯定会阻止它的使用。

于 2018-01-18T14:13:31.350 回答
0

您可以直接遍历向量

#include <math.h>
typedef double v2d __attribute__ ((vector_size (16)));   
v2d myfunc(v2d in) {
    v2d out;
    for(int i=0; i<2; i++) out[i] = sqrt(in[i]);
    return out;
}

sqrt函数必须捕获带符号的零和 NAN,但如果您使用-OfastClang 和 GCC 避免这些,则生成简单sqrtpd的 . https://godbolt.org/g/aCuovX

GCC 可能有一个错误,因为即使只有 2 个元素才能获得最佳代码,我也必须循环到 4。

但是对于 AVX 和 AVX512,GCC 和 Clang 是理想的

AVX https://godbolt.org/g/qdTxyp

AVX512 https://godbolt.org/g/MJP1n7

于 2018-01-17T15:02:41.180 回答