5#include "native/config.h"
9#include <wasm_simd128.h>
11namespace native::detail::wasm_relaxed {
12 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
14 v128_t i8x16_relaxed_swizzle(v128_t a, v128_t b) noexcept {
15 return wasm_i8x16_relaxed_swizzle(a, b);
18 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
20 v128_t i32x4_relaxed_trunc_f32x4(v128_t a) noexcept {
21 return wasm_i32x4_relaxed_trunc_f32x4(a);
24 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
26 v128_t u32x4_relaxed_trunc_f32x4(v128_t a) noexcept {
27 return wasm_u32x4_relaxed_trunc_f32x4(a);
30 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
32 v128_t i32x4_relaxed_trunc_f64x2_zero(v128_t a) noexcept {
33 return wasm_i32x4_relaxed_trunc_f64x2_zero(a);
36 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
38 v128_t u32x4_relaxed_trunc_f64x2_zero(v128_t a) noexcept {
39 return wasm_u32x4_relaxed_trunc_f64x2_zero(a);
42 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
44 v128_t f32x4_relaxed_madd(v128_t a, v128_t b, v128_t c) noexcept {
45 return wasm_f32x4_relaxed_madd(a, b, c);
48 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
50 v128_t f32x4_relaxed_nmadd(v128_t a, v128_t b, v128_t c) noexcept {
51 return wasm_f32x4_relaxed_nmadd(a, b, c);
54 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
56 v128_t f64x2_relaxed_madd(v128_t a, v128_t b, v128_t c) noexcept {
57 return wasm_f64x2_relaxed_madd(a, b, c);
60 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
62 v128_t f64x2_relaxed_nmadd(v128_t a, v128_t b, v128_t c) noexcept {
63 return wasm_f64x2_relaxed_nmadd(a, b, c);
66 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
68 v128_t i8x16_relaxed_laneselect(v128_t a, v128_t b, v128_t c) noexcept {
69 return wasm_i8x16_relaxed_laneselect(a, b, c);
72 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
74 v128_t i16x8_relaxed_laneselect(v128_t a, v128_t b, v128_t c) noexcept {
75 return wasm_i16x8_relaxed_laneselect(a, b, c);
78 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
80 v128_t i32x4_relaxed_laneselect(v128_t a, v128_t b, v128_t c) noexcept {
81 return wasm_i32x4_relaxed_laneselect(a, b, c);
84 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
86 v128_t i64x2_relaxed_laneselect(v128_t a, v128_t b, v128_t c) noexcept {
87 return wasm_i64x2_relaxed_laneselect(a, b, c);
90 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
92 v128_t f32x4_relaxed_min(v128_t a, v128_t b) noexcept {
93 return wasm_f32x4_relaxed_min(a, b);
96 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
98 v128_t f32x4_relaxed_max(v128_t a, v128_t b) noexcept {
99 return wasm_f32x4_relaxed_max(a, b);
102 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
104 v128_t f64x2_relaxed_min(v128_t a, v128_t b) noexcept {
105 return wasm_f64x2_relaxed_min(a, b);
108 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
110 v128_t f64x2_relaxed_max(v128_t a, v128_t b) noexcept {
111 return wasm_f64x2_relaxed_max(a, b);
114 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
116 v128_t i16x8_relaxed_q15mulr(v128_t a, v128_t b) noexcept {
117 return wasm_i16x8_relaxed_q15mulr(a, b);
120 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
122 v128_t i16x8_relaxed_dot_i8x16_i7x16(v128_t a, v128_t b) noexcept {
123 return wasm_i16x8_relaxed_dot_i8x16_i7x16(a, b);
126 template<isa<wasm> Arch>
requires(Arch.has(wasm_feature::relaxed_simd))
128 v128_t i32x4_relaxed_dot_i8x16_i7x16_add(v128_t a, v128_t b, v128_t c) noexcept {
129 return wasm_i32x4_relaxed_dot_i8x16_i7x16_add(a, b, c);
135#include "native/detail/constexpr_float.h"
138namespace native::detail::wasm_relaxed_constant {
140 constexpr auto lanes(V value)
noexcept {
141 std::array<typename V::value_type, V::lanes> result{};
142 value.store(result.data());
147 using format = std::conditional_t<
sizeof(T) == 4,
148 constexpr_float::binary32, constexpr_float::binary64>;
151 constexpr V swizzle(V value, V indices)
noexcept {
152 auto input = lanes(value);
153 auto result = lanes(indices);
154 for (
auto & index : result) {
155 index = index < 16 ? input[index] : 0;
157 return V::load(result.data());
162 template<
class To,
class From>
163 constexpr To truncate(From value)
noexcept {
164 using format_type = format<From>;
165 auto bits = std::bit_cast<typename format_type::bits_type>(value);
166 if (constexpr_float::is_nan<format_type>(bits)) {
169 constexpr bool signed_result = std::is_signed_v<To>;
170 constexpr std::uint64_t positive_limit = std::numeric_limits<To>::max();
171 constexpr std::uint64_t negative_limit = signed_result ? std::uint64_t{1} << 31 : 0;
172 auto parts = constexpr_float::unpack<format_type>(bits);
173 auto limit = parts.sign ? negative_limit : positive_limit;
174 std::uint64_t magnitude = 0;
175 if (constexpr_float::is_infinite<format_type>(bits) || parts.exponent > 32) {
177 }
else if (parts.exponent >= 0) {
178 magnitude = parts.significand > (limit >> parts.exponent)
179 ? limit : parts.significand << parts.exponent;
180 }
else if (parts.exponent > -64) {
181 magnitude = parts.significand >> -parts.exponent;
182 if (magnitude > limit) {
186 if constexpr (signed_result) {
187 return static_cast<To
>(parts.sign ? -
static_cast<std::int64_t
>(magnitude)
188 :
static_cast<std::int64_t
>(magnitude));
190 return static_cast<To
>(magnitude);
194 template<
class R,
class V>
195 constexpr R truncation(V value)
noexcept {
196 auto input = lanes(value);
197 std::array<typename R::value_type, R::lanes> result{};
198 for (std::size_t i = 0; i < V::lanes; ++i) {
199 result[i] = truncate<typename R::value_type>(input[i]);
201 return R::load(result.data());
205 template<
bool Negative,
class V>
206 constexpr V multiply_add(V a, V b, V c)
noexcept {
207 using lane_type =
typename V::value_type;
208 using format_type = format<lane_type>;
209 using word_type =
typename format_type::bits_type;
213 for (std::size_t i = 0; i < V::lanes; ++i) {
214 auto x = std::bit_cast<word_type>(av[i]);
215 if constexpr (Negative) {
216 x ^= format_type::sign_mask;
218 cv[i] = std::bit_cast<lane_type>(constexpr_float::fma_bits<format_type>(
219 x, std::bit_cast<word_type>(bv[i]), std::bit_cast<word_type>(cv[i])));
221 return V::load(cv.data());
225 constexpr V lane_select(V a, V b, V
mask)
noexcept {
228 auto mv = lanes(
mask);
229 for (std::size_t i = 0; i < V::lanes; ++i) {
230 av[i] = (av[i] & mv[i]) | (bv[i] & ~mv[i]);
232 return V::load(av.data());
237 template<
bool Maximum,
class V>
238 constexpr V minimum_maximum(V a, V b)
noexcept {
239 using lane_type =
typename V::value_type;
240 using format_type = format<lane_type>;
241 using word_type =
typename format_type::bits_type;
244 for (std::size_t i = 0; i < V::lanes; ++i) {
245 auto x = std::bit_cast<word_type>(av[i]);
246 auto y = std::bit_cast<word_type>(bv[i]);
248 if (constexpr_float::is_nan<format_type>(x) || constexpr_float::is_nan<format_type>(y)) {
249 result = constexpr_float::default_nan<format_type>();
250 }
else if (constexpr_float::is_zero<format_type>(x) && constexpr_float::is_zero<format_type>(y)) {
251 result = Maximum ? x & y : x | y;
253 result = constexpr_float::less_bits<format_type>(x, y) != Maximum ? x : y;
255 av[i] = std::bit_cast<lane_type>(result);
257 return V::load(av.data());
261 constexpr V q15_multiply(V a, V b)
noexcept {
264 for (std::size_t i = 0; i < V::lanes; ++i) {
265 auto result = (std::int32_t{av[i]} * bv[i] + 0x4000) >> 15;
266 av[i] =
static_cast<std::int16_t
>(result > 32767 ? 32767 : result);
268 return V::load(av.data());
271 template<
class V,
class W>
272 constexpr auto dot_pairs(V a, W b)
noexcept {
275 std::array<std::int16_t, 8> result{};
276 for (std::size_t i = 0; i < result.size(); ++i) {
277 auto first = std::int32_t{av[2 * i]} * std::bit_cast<std::int8_t>(bv[2 * i]);
278 auto second = std::int32_t{av[2 * i + 1]} * std::bit_cast<std::int8_t>(bv[2 * i + 1]);
279 auto sum = first + second;
280 result[i] =
static_cast<std::int16_t
>(sum > 32767 ? 32767 : sum < -32768 ? -32768 : sum);
285 template<
class R,
class V,
class W>
286 constexpr R dot(V a, W b)
noexcept {
287 auto result = dot_pairs(a, b);
288 return R::load(result.data());
291 template<
class V,
class W,
class R>
292 constexpr R dot_add(V a, W b, R c)
noexcept {
293 auto pairs = dot_pairs(a, b);
294 auto result = lanes(c);
295 for (std::size_t i = 0; i < result.size(); ++i) {
296 auto sum = std::int32_t{pairs[2 * i]} + pairs[2 * i + 1];
297 result[i] = std::bit_cast<std::int32_t>(
298 std::bit_cast<std::uint32_t>(result[i]) +
static_cast<std::uint32_t
>(sum));
300 return R::load(result.data());
Compiler attributes for host code, with shader-safe shared modifiers.
#define native_inline
inline [[always_inline]]
#define native_nodiscard
C++17 [[nodiscard]].
#define native_target(x)
this indicates a required feature set for the current multiversioned function.
typename mask_traits< std::remove_cvref_t< T > >::type mask