/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * * Martin Renou * * Copyright (c) QuantStack * * Copyright (c) Serge Guelton * * Copyright (c) Anutosh Bhat * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/
#ifndef XSIMD_WASM_HPP #define XSIMD_WASM_HPP
#include <type_traits>
#include"../types/xsimd_wasm_register.hpp"
namespace xsimd
{ template <typename T, class A, bool... Values> struct batch_bool_constant;
template <class T_out, class T_in, class A>
XSIMD_INLINE batch<T_out, A> bitwise_cast(batch<T_in, A> const& x) noexcept;
template <typename T, class A, T... Values> struct batch_constant;
namespace kernel
{ usingnamespace types;
// fwd template <class A, class T, size_t I>
XSIMD_INLINE batch<T, A> insert(batch<T, A> const& self, T val, index<I>, requires_arch<generic>) noexcept; template <class A, typename T, typename ITy, ITy... Indices>
XSIMD_INLINE batch<T, A> shuffle(batch<T, A> const& x, batch<T, A> const& y, batch_constant<ITy, A, Indices...>, requires_arch<generic>) noexcept; template <class A, class T>
XSIMD_INLINE batch<T, A> avg(batch<T, A> const&, batch<T, A> const&, requires_arch<generic>) noexcept; template <class A, class T>
XSIMD_INLINE void transpose(batch<T, A>* matrix_begin, batch<T, A>* matrix_end, requires_arch<generic>) noexcept;
template <class A>
XSIMD_INLINE batch<float, A> add(batch<float, A> const& self, batch<float, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f32x4_add(self, other);
}
template <class A>
XSIMD_INLINE batch<double, A> add(batch<double, A> const& self, batch<double, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f64x2_add(self, other);
}
// avgr template <class A, class T, class = typename std::enable_if<std::is_unsigned<T>::value, void>::type>
XSIMD_INLINE batch<T, A> avgr(batch<T, A> const& self, batch<T, A> const& other, requires_arch<wasm>) noexcept
{
XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
{ return wasm_u8x16_avgr(self, other);
} else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
{ return wasm_u16x8_avgr(self, other);
} else
{ return avgr(self, other, generic {});
}
}
// avg template <class A, class T, class = typename std::enable_if<std::is_unsigned<T>::value, void>::type>
XSIMD_INLINE batch<T, A> avg(batch<T, A> const& self, batch<T, A> const& other, requires_arch<wasm>) noexcept
{
XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
{ auto adj = ((self ^ other) << 7) >> 7; return avgr(self, other, A {}) - adj;
} else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
{ auto adj = ((self ^ other) << 15) >> 15; return avgr(self, other, A {}) - adj;
} else
{ return avg(self, other, generic {});
}
}
// all template <class A>
XSIMD_INLINE bool all(batch_bool<float, A> const& self, requires_arch<wasm>) noexcept
{ return wasm_i32x4_bitmask(self) == 0x0F;
} template <class A>
XSIMD_INLINE bool all(batch_bool<double, A> const& self, requires_arch<wasm>) noexcept
{ return wasm_i64x2_bitmask(self) == 0x03;
} template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE bool all(batch_bool<T, A> const& self, requires_arch<wasm>) noexcept
{ return wasm_i8x16_bitmask(self) == 0xFFFF;
}
// any template <class A>
XSIMD_INLINE bool any(batch_bool<float, A> const& self, requires_arch<wasm>) noexcept
{ return wasm_i32x4_bitmask(self) != 0;
} template <class A>
XSIMD_INLINE bool any(batch_bool<double, A> const& self, requires_arch<wasm>) noexcept
{ return wasm_i64x2_bitmask(self) != 0;
} template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE bool any(batch_bool<T, A> const& self, requires_arch<wasm>) noexcept
{ return wasm_i8x16_bitmask(self) != 0;
}
// batch_bool_cast template <class A, class T_out, class T_in>
XSIMD_INLINE batch_bool<T_out, A> batch_bool_cast(batch_bool<T_in, A> const& self, batch_bool<T_out, A> const&, requires_arch<wasm>) noexcept
{ return { bitwise_cast<T_out>(batch<T_in, A>(self.data)).data };
}
// bitwise_and template <class A, class T>
XSIMD_INLINE batch<T, A> bitwise_and(batch<T, A> const& self, batch<T, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_v128_and(self, other);
}
template <class A, class T>
XSIMD_INLINE batch_bool<T, A> bitwise_and(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_v128_and(self, other);
}
// bitwise_andnot template <class A, class T>
XSIMD_INLINE batch<T, A> bitwise_andnot(batch<T, A> const& self, batch<T, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_v128_andnot(self, other);
}
template <class A, class T>
XSIMD_INLINE batch_bool<T, A> bitwise_andnot(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_v128_andnot(self, other);
}
// bitwise_cast template <class A, class T, class Tp>
XSIMD_INLINE batch<Tp, A> bitwise_cast(batch<T, A> const& self, batch<Tp, A> const&, requires_arch<wasm>) noexcept
{ return batch<Tp, A>(self.data);
}
// bitwise_or template <class A, class T>
XSIMD_INLINE batch<T, A> bitwise_or(batch<T, A> const& self, batch<T, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_v128_or(self, other);
}
template <class A, class T>
XSIMD_INLINE batch_bool<T, A> bitwise_or(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_v128_or(self, other);
}
// bitwise_not template <class A, class T>
XSIMD_INLINE batch<T, A> bitwise_not(batch<T, A> const& self, requires_arch<wasm>) noexcept
{ return wasm_v128_not(self);
}
template <class A, class T>
XSIMD_INLINE batch_bool<T, A> bitwise_not(batch_bool<T, A> const& self, requires_arch<wasm>) noexcept
{ return wasm_v128_not(self);
}
// bitwise_xor template <class A, class T>
XSIMD_INLINE batch<T, A> bitwise_xor(batch<T, A> const& self, batch<T, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_v128_xor(self, other);
}
template <class A, class T>
XSIMD_INLINE batch_bool<T, A> bitwise_xor(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_v128_xor(self, other);
}
// ceil template <class A>
XSIMD_INLINE batch<float, A> ceil(batch<float, A> const& self, requires_arch<wasm>) noexcept
{ return wasm_f32x4_ceil(self);
} template <class A>
XSIMD_INLINE batch<double, A> ceil(batch<double, A> const& self, requires_arch<wasm>) noexcept
{ return wasm_f64x2_ceil(self);
}
// div template <class A>
XSIMD_INLINE batch<float, A> div(batch<float, A> const& self, batch<float, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f32x4_div(self, other);
} template <class A>
XSIMD_INLINE batch<double, A> div(batch<double, A> const& self, batch<double, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f64x2_div(self, other);
}
// eq template <class A>
XSIMD_INLINE batch_bool<float, A> eq(batch<float, A> const& self, batch<float, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f32x4_eq(self, other);
} template <class A>
XSIMD_INLINE batch_bool<float, A> eq(batch_bool<float, A> const& self, batch_bool<float, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_i32x4_eq(self, other);
} template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE batch_bool<T, A> eq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<wasm>) noexcept
{
XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
{ return wasm_i8x16_eq(self, other);
} else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
{ return wasm_i16x8_eq(self, other);
} else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
{ return wasm_i32x4_eq(self, other);
} else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
{ return wasm_i64x2_eq(self, other);
} else
{
assert(false && "unsupported arch/op combination"); return {};
}
} template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE batch_bool<T, A> eq(batch_bool<T, A> const& self, batch_bool<T, A> const& other, requires_arch<wasm>) noexcept
{
XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
{ return wasm_i8x16_eq(self, other);
} else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
{ return wasm_i16x8_eq(self, other);
} else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
{ return wasm_i32x4_eq(self, other);
} else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
{ return wasm_i64x2_eq(self, other);
} else
{
assert(false && "unsupported arch/op combination"); return {};
}
} template <class A>
XSIMD_INLINE batch_bool<double, A> eq(batch<double, A> const& self, batch<double, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f64x2_eq(self, other);
} template <class A>
XSIMD_INLINE batch_bool<double, A> eq(batch_bool<double, A> const& self, batch_bool<double, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_i64x2_eq(self, other);
}
// fast_cast namespace detail
{ template <class A>
XSIMD_INLINE batch<float, A> fast_cast(batch<int32_t, A> const& self, batch<float, A> const&, requires_arch<wasm>) noexcept
{ return wasm_f32x4_convert_i32x4(self);
}
template <class A>
XSIMD_INLINE batch<double, A> fast_cast(batch<uint64_t, A> const& x, batch<double, A> const&, requires_arch<wasm>) noexcept
{ // from https://stackoverflow.com/questions/41144668/how-to-efficiently-perform-double-int64-conversions-with-sse-avx // adapted to wasm
v128_t xH = wasm_u64x2_shr(x, 32);
xH = wasm_v128_or(xH, wasm_f64x2_splat(19342813113834066795298816.)); // 2^84
v128_t mask = wasm_i16x8_make(0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000);
v128_t xL = wasm_v128_or(wasm_v128_and(mask, x), wasm_v128_andnot(wasm_f64x2_splat(0x0010000000000000), mask)); // 2^52
v128_t f = wasm_f64x2_sub(xH, wasm_f64x2_splat(19342813118337666422669312.)); // 2^84 + 2^52 return wasm_f64x2_add(f, xL);
}
// ge template <class A>
XSIMD_INLINE batch_bool<float, A> ge(batch<float, A> const& self, batch<float, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f32x4_ge(self, other);
} template <class A>
XSIMD_INLINE batch_bool<double, A> ge(batch<double, A> const& self, batch<double, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f64x2_ge(self, other);
}
template <class A>
XSIMD_INLINE batch_bool<double, A> gt(batch<double, A> const& self, batch<double, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f64x2_gt(self, other);
}
template <class A, size_t I>
XSIMD_INLINE batch<double, A> insert(batch<double, A> const& self, double val, index<I> pos, requires_arch<wasm>) noexcept
{ return wasm_f64x2_replace_lane(self, pos, val);
}
// isnan template <class A>
XSIMD_INLINE batch_bool<float, A> isnan(batch<float, A> const& self, requires_arch<wasm>) noexcept
{ return wasm_v128_or(wasm_f32x4_ne(self, self), wasm_f32x4_ne(self, self));
} template <class A>
XSIMD_INLINE batch_bool<double, A> isnan(batch<double, A> const& self, requires_arch<wasm>) noexcept
{ return wasm_v128_or(wasm_f64x2_ne(self, self), wasm_f64x2_ne(self, self));
}
// le template <class A>
XSIMD_INLINE batch_bool<float, A> le(batch<float, A> const& self, batch<float, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f32x4_le(self, other);
} template <class A>
XSIMD_INLINE batch_bool<double, A> le(batch<double, A> const& self, batch<double, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f64x2_le(self, other);
}
// load_aligned template <class A>
XSIMD_INLINE batch<float, A> load_aligned(floatconst* mem, convert<float>, requires_arch<wasm>) noexcept
{ return wasm_v128_load(mem);
} template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE batch<T, A> load_aligned(T const* mem, convert<T>, requires_arch<wasm>) noexcept
{ return wasm_v128_load((v128_t const*)mem);
} template <class A>
XSIMD_INLINE batch<double, A> load_aligned(doubleconst* mem, convert<double>, requires_arch<wasm>) noexcept
{ return wasm_v128_load(mem);
}
// load_complex namespace detail
{ template <class A>
XSIMD_INLINE batch<std::complex<float>, A> load_complex(batch<float, A> const& hi, batch<float, A> const& lo, requires_arch<wasm>) noexcept
{ return { wasm_i32x4_shuffle(hi, lo, 0, 2, 4, 6), wasm_i32x4_shuffle(hi, lo, 1, 3, 5, 7) };
} template <class A>
XSIMD_INLINE batch<std::complex<double>, A> load_complex(batch<double, A> const& hi, batch<double, A> const& lo, requires_arch<wasm>) noexcept
{ return { wasm_i64x2_shuffle(hi, lo, 0, 2), wasm_i64x2_shuffle(hi, lo, 1, 3) };
}
}
// load_unaligned template <class A>
XSIMD_INLINE batch<float, A> load_unaligned(floatconst* mem, convert<float>, requires_arch<wasm>) noexcept
{ return wasm_v128_load(mem);
} template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE batch<T, A> load_unaligned(T const* mem, convert<T>, requires_arch<wasm>) noexcept
{ return wasm_v128_load((v128_t const*)mem);
} template <class A>
XSIMD_INLINE batch<double, A> load_unaligned(doubleconst* mem, convert<double>, requires_arch<wasm>) noexcept
{ return wasm_v128_load(mem);
}
template <class A>
XSIMD_INLINE batch_bool<double, A> lt(batch<double, A> const& self, batch<double, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f64x2_lt(self, other);
}
template <class A>
XSIMD_INLINE uint64_t mask(batch_bool<double, A> const& self, requires_arch<wasm>) noexcept
{ return wasm_i64x2_bitmask(self);
}
// max template <class A>
XSIMD_INLINE batch<float, A> max(batch<float, A> const& self, batch<float, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f32x4_pmax(self, other);
} template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE batch<T, A> max(batch<T, A> const& self, batch<T, A> const& other, requires_arch<wasm>) noexcept
{ return select(self > other, self, other);
} template <class A>
XSIMD_INLINE batch<double, A> max(batch<double, A> const& self, batch<double, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f64x2_pmax(self, other);
}
// min template <class A>
XSIMD_INLINE batch<float, A> min(batch<float, A> const& self, batch<float, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f32x4_pmin(self, other);
} template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE batch<T, A> min(batch<T, A> const& self, batch<T, A> const& other, requires_arch<wasm>) noexcept
{ return select(self <= other, self, other);
} template <class A>
XSIMD_INLINE batch<double, A> min(batch<double, A> const& self, batch<double, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f64x2_pmin(self, other);
}
// mul template <class A>
XSIMD_INLINE batch<float, A> mul(batch<float, A> const& self, batch<float, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f32x4_mul(self, other);
} template <class A>
XSIMD_INLINE batch<double, A> mul(batch<double, A> const& self, batch<double, A> const& other, requires_arch<wasm>) noexcept
{ return wasm_f64x2_mul(self, other);
}
// select template <class A>
XSIMD_INLINE batch<float, A> select(batch_bool<float, A> const& cond, batch<float, A> const& true_br, batch<float, A> const& false_br, requires_arch<wasm>) noexcept
{ return wasm_v128_or(wasm_v128_and(cond, true_br), wasm_v128_andnot(false_br, cond));
}
template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE batch<T, A> select(batch_bool<T, A> const& cond, batch<T, A> const& true_br, batch<T, A> const& false_br, requires_arch<wasm>) noexcept
{ return wasm_v128_or(wasm_v128_and(cond, true_br), wasm_v128_andnot(false_br, cond));
} template <class A, class T, bool... Values, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE batch<T, A> select(batch_bool_constant<T, A, Values...> const&, batch<T, A> const& true_br, batch<T, A> const& false_br, requires_arch<wasm>) noexcept
{ return select(batch_bool<T, A> { Values... }, true_br, false_br, wasm {});
} template <class A>
XSIMD_INLINE batch<double, A> select(batch_bool<double, A> const& cond, batch<double, A> const& true_br, batch<double, A> const& false_br, requires_arch<wasm>) noexcept
{ return wasm_v128_or(wasm_v128_and(cond, true_br), wasm_v128_andnot(false_br, cond));
}
// shuffle template <class A, class ITy, ITy I0, ITy I1, ITy I2, ITy I3>
XSIMD_INLINE batch<float, A> shuffle(batch<float, A> const& x, batch<float, A> const& y, batch_constant<ITy, A, I0, I1, I2, I3>, requires_arch<wasm>) noexcept
{ return wasm_i32x4_shuffle(x, y, I0, I1, I2, I3);
}
template <class A, class ITy, ITy I0, ITy I1>
XSIMD_INLINE batch<double, A> shuffle(batch<double, A> const& x, batch<double, A> const& y, batch_constant<ITy, A, I0, I1>, requires_arch<wasm>) noexcept
{ return wasm_i64x2_shuffle(x, y, I0, I1);
}
// set template <class A, class... Values>
XSIMD_INLINE batch<float, A> set(batch<float, A> const&, requires_arch<wasm>, Values... values) noexcept
{
static_assert(sizeof...(Values) == batch<float, A>::size, "consistent init"); return wasm_f32x4_make(values...);
}
template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<wasm>, T v0, T v1) noexcept
{ return wasm_i64x2_make(v0, v1);
}
template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<wasm>, T v0, T v1, T v2, T v3) noexcept
{ return wasm_i32x4_make(v0, v1, v2, v3);
}
template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<wasm>, T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7) noexcept
{ return wasm_i16x8_make(v0, v1, v2, v3, v4, v5, v6, v7);
}
template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE batch<T, A> set(batch<T, A> const&, requires_arch<wasm>, T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7, T v8, T v9, T v10, T v11, T v12, T v13, T v14, T v15) noexcept
{ return wasm_i8x16_make(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15);
}
template <class A, class... Values>
XSIMD_INLINE batch<double, A> set(batch<double, A> const&, requires_arch<wasm>, Values... values) noexcept
{
static_assert(sizeof...(Values) == batch<double, A>::size, "consistent init"); return wasm_f64x2_make(values...);
}
template <class A, class T, class... Values, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
XSIMD_INLINE batch_bool<T, A> set(batch_bool<T, A> const&, requires_arch<wasm>, Values... values) noexcept
{ return set(batch<T, A>(), A {}, static_cast<T>(values ? -1LL : 0LL)...).data;
}
template <class A, class... Values>
XSIMD_INLINE batch_bool<float, A> set(batch_bool<float, A> const&, requires_arch<wasm>, Values... values) noexcept
{
static_assert(sizeof...(Values) == batch_bool<float, A>::size, "consistent init"); return set(batch<int32_t, A>(), A {}, static_cast<int32_t>(values ? -1LL : 0LL)...).data;
}
template <class A, class... Values>
XSIMD_INLINE batch_bool<double, A> set(batch_bool<double, A> const&, requires_arch<wasm>, Values... values) noexcept
{
static_assert(sizeof...(Values) == batch_bool<double, A>::size, "consistent init"); return set(batch<int64_t, A>(), A {}, static_cast<int64_t>(values ? -1LL : 0LL)...).data;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.10Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.