3#include "native/arm/detail/constant_lanes.h"
6namespace native::detail::arm_neon_constant {
7 template<
class T>
constexpr T add(T a, T b)
noexcept {
8 constexpr auto lo = std::numeric_limits<T>::min();
9 constexpr auto hi = std::numeric_limits<T>::max();
10 if constexpr (std::is_signed_v<T>) {
11 if (b > 0 && a > hi - b)
13 if (b < 0 && a < lo - b)
15 }
else if (a > hi - b) {
21 template<
class T>
constexpr T sub(T a, T b)
noexcept {
22 constexpr auto lo = std::numeric_limits<T>::min();
23 constexpr auto hi = std::numeric_limits<T>::max();
24 if constexpr (std::is_signed_v<T>) {
25 if (b < 0 && a > hi + b)
27 if (b > 0 && a < lo + b)
35 template<
class To,
class From>
constexpr To narrow(From a)
noexcept {
36 if (a < From(std::numeric_limits<To>::min()))
37 return std::numeric_limits<To>::min();
38 if (a > From(std::numeric_limits<To>::max()))
39 return std::numeric_limits<To>::max();
43 template<
bool Round,
class T>
constexpr T multiply_high(T a, T b)
noexcept {
44 constexpr unsigned width =
sizeof(T) * 8;
45 auto product = std::int64_t(a) * b;
47 product += std::int64_t{1} << (width - 2);
48 return narrow<T>(product >> (width - 1));
51 template<
bool Round,
bool Saturate,
class T,
class S>
52 constexpr T shift(T value, S count)
noexcept {
53 using U = std::make_unsigned_t<T>;
54 constexpr unsigned width =
sizeof(T) * 8;
56 int amount = std::bit_cast<std::int8_t>(std::uint8_t(count));
58 unsigned left = unsigned(amount);
60 if constexpr (Saturate) {
62 return value < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::
max();
66 if constexpr (Saturate) {
67 if (value > (std::numeric_limits<T>::max() >> left))
68 return std::numeric_limits<T>::max();
69 if constexpr (std::is_signed_v<T>)
70 if (value < (std::numeric_limits<T>::min() >> left))
71 return std::numeric_limits<T>::min();
73 return std::bit_cast<T>(U(std::uint64_t(U(value)) << left));
75 unsigned right = unsigned(-amount);
77 if constexpr (Round) {
78 if constexpr (std::is_unsigned_v<T>)
80 return T(value >> (width - 1));
83 return value < 0 ? T(-1) : T(0);
86 T result = T(value >> right);
88 result = T(result + T((U(value) >> (right - 1)) & 1));
92 template<
class V,
class W,
class F>
constexpr V binary(V a, W b, F operation)
noexcept {
93 auto left = arm_constant::lanes(a);
94 auto right = arm_constant::lanes(b);
95 for (
unsigned i = 0; i < V::lanes; ++i)
96 left[i] = operation(left[i], right[i]);
97 return arm_constant::pack<V>(left);
100 template<
class Result,
class V>
constexpr Result narrow_low(V input)
noexcept {
101 auto source = arm_constant::lanes(input);
102 std::array<typename Result::value_type, Result::lanes> result{};
103 for (
unsigned i = 0; i < Result::lanes; ++i)
104 result[i] = narrow<typename Result::value_type>(source[i]);
105 return arm_constant::pack<Result>(result);
108 template<
class Result,
class Low,
class V>
109 constexpr Result narrow_high(Low low, V input)
noexcept {
110 auto bottom = arm_constant::lanes(low);
111 auto source = arm_constant::lanes(input);
112 std::array<typename Result::value_type, Result::lanes> result{};
113 for (
unsigned i = 0; i < Low::lanes; ++i) {
114 result[i] = bottom[i];
115 result[i + Low::lanes] = narrow<typename Result::value_type>(source[i]);
117 return arm_constant::pack<Result>(result);
constexpr simd< T, N, A > max(simd< T, N, A > a, simd< T, N, A > b) noexcept
Minimum/maximum; floating NaNs propagate and signed zeros follow WebAssembly rules.