How to initialize experimental/simd vector?

206 Views Asked by At

This page https://en.cppreference.com/w/cpp/experimental/simd shows only these two initialization methods of a SIMD vector:

  1. All elements to the same value: native_simd<int> a = 1
  2. Using a lambda: fixed_size_simd<float, 8> a([](int i) {return i;});

Is there another option? I would like this to work:

const fixed_size_simd<int, 4> a{3, 1, 4, 1};
1

There are 1 best solutions below

3
Maxim Egorushkin On

This library doesn't provide a convenient constructor from elements at the moment, it seems.

It is worth noticing, that generator constructor #4 you mention receives a std::integral_constant<std::size_t, i> argument, which can be used to index an array, std::tuple or a variadic function template argument at compile time. to_simd function below does the latter:

#include <experimental/simd>
#include <type_traits>

namespace stdx = std::experimental;

//
// Boilerplate. C++20 Pack indexing supercedes nth_arg.
//
template<size_t N, class T0, class... Ts>
constexpr decltype(auto) nth_arg(T0&& a0, Ts&&... as) noexcept {
    if constexpr(N)
        return nth_arg<N - 1>(std::forward<Ts>(as)...);
    else
        return std::forward<T0>(a0);
}

template<class T0, class... Ts>
constexpr auto to_simd(T0 a0, Ts... as) noexcept {
    using V = stdx::simd<T0, stdx::simd_abi::deduce_t<T0, 1 + sizeof...(as)>>;
    auto generator = [&](auto i) { return nth_arg<i.value>(a0, as...); };
    return V{generator};
}

// 
// Unit-test to_simd return types.
// 
static_assert(std::is_same_v<decltype(to_simd(0.)), stdx::simd<double, stdx::simd_abi::deduce_t<double, 1>>>);
static_assert(std::is_same_v<decltype(to_simd(0., 0.)), stdx::simd<double, stdx::simd_abi::deduce_t<double, 2>>>);
static_assert(std::is_same_v<decltype(to_simd(0., 0., 0., 0.)), stdx::simd<double, stdx::simd_abi::deduce_t<double, 4>>>);

//
// Usage.
//
auto f_sse(double a0, double a1) {
    auto v = to_simd(a0, a1);
    return v;
}

auto f_sse0() {
    auto v = to_simd(0., 0.);
    return v;
}

auto f_avx(double a0, double a1, double a2, double a3) {
    auto v = to_simd(a0, a1, a2, a3);
    return v;
}

auto f_avx0() {
    auto v = to_simd(0., 0., 0., 0.);
    return v;
}

Generated assembly is identical to hand-coded initialization using CPU-specific vector intrinsic functions.