21#if MOCHI_USE_SIMD && MOCHI_ARCH_ARM_NEON
29class Simd<double, 2> {
34 template <
class U, MOCHI_REQUIRES_NON_BOOL_SCALAR(U, Scalar)>
39 static_assert(i >= 0 && i < 2,
"Index out of range");
40 return vgetq_lane_f64(v.raw, i);
51 result.raw[i] = value;
57 static_assert(i >= 0 && i <
kSize,
"Index out of range");
58 return Set(v, i, value);
63 static_assert(N == 1 || N == 2,
"Invalid N");
65 vget_lane_u64(vreinterpret_u64_u16(vqmovn_u32(vreinterpretq_u32_f64(v.raw))), 0);
66 if constexpr (N == 1) {
67 return (mask & 0x00000000FFFFFFFFULL) == 0x00000000FFFFFFFFULL;
69 return mask == 0xFFFFFFFFFFFFFFFFULL;
75 static_assert(N == 1 || N == 2,
"Invalid N");
77 vget_lane_u64(vreinterpret_u64_u16(vqmovn_u32(vreinterpretq_u32_f64(v.raw))), 0);
78 if constexpr (N == 1) {
79 return (mask & 0x00000000FFFFFFFFULL) == 0x00000000FFFFFFFFULL;
85 template <
int x,
int y>
87 static_assert(x >= 0 && x <= 1 && y >= 0 && y <= 1,
"invalid blend index");
88 if constexpr (x == 0 && y == 0) {
90 }
else if constexpr (x == 1 && y == 1) {
93 auto mask = vreinterpretq_f64_s64(
94 int64x2_t{x ? (int64_t)0 : (int64_t)-1, y ? (int64_t)0 : (int64_t)-1});
105 static_assert(i >= 0 && i < 2,
"Index out of range");
106 return vdupq_laneq_f64(v.raw, i);
109 template <
int N = kSize>
111 static_assert(N >= 0 && N <=
kSize);
112 if constexpr (N == 0) {
114 }
else if constexpr (N == 1) {
115 return Simd{*ptr, 0.0};
117 return vld1q_f64(ptr);
137 template <
int kTupleCount = kSize>
140 static_assert(kTupleCount >= 1 && kTupleCount <=
kSize,
"Unsupported kTupleCount");
141 if constexpr (kTupleCount == 1) {
142 out0.raw = float64x2_t{ptr[0], 0.0};
143 out1.raw = float64x2_t{ptr[1], 0.0};
144 out2.raw = float64x2_t{ptr[2], 0.0};
146 float64x2x3_t result = vld3q_f64(ptr);
147 out0.raw = result.val[0];
148 out1.raw = result.val[1];
149 out2.raw = result.val[2];
153 template <
int N = kSize>
154 static void Store([[maybe_unused]]
double* ptr, [[maybe_unused]]
Simd v) {
155 static_assert(N >= 0 && N <=
kSize);
156 if constexpr (N == 0) {
157 }
else if constexpr (N == 1) {
160 vst1q_f64(ptr, v.raw);
175 uint64x2_t shifted = vshrq_n_u64(vreinterpretq_u64_f64(condition.raw), 63);
176 uint32_t bit0 = vgetq_lane_u64(shifted, 0);
177 uint32_t bit1 = vgetq_lane_u64(shifted, 1);
178 uint32_t mask = bit0 | (bit1 << 1);
179 uint32_t count = bit0 + bit1;
180 uint8x16_t pattern = vld1q_u8(arm_simd::kStoreSelectedShuffleTableD2[mask]);
181 uint8x16_t packed = vqtbl1q_u8(vreinterpretq_u8_f64(values.raw), pattern);
182 vst1q_f64(ptr, vreinterpretq_f64_u8(packed));
183 return static_cast<int>(count);
186 template <
int kTupleCount = kSize>
188 static_assert(kTupleCount >= 1 && kTupleCount <=
kSize,
"Invalid kTupleCount");
189 if constexpr (kTupleCount == 1) {
194 vst3q_f64(ptr, float64x2x3_t({a.raw, b.raw, c.raw}));
199 return vbslq_f64(vreinterpretq_u64_f64(mask.raw), a.raw, b.raw);
203 template <
int x = 0,
int y = 1>
205 static_assert(x >= 0 && x < 2,
"Invalid index");
206 static_assert(y >= 0 && y < 2,
"Invalid index");
207 if constexpr (x == 0 && y == 0) {
209 }
else if constexpr (x == 0 && y == 1) {
211 }
else if constexpr (x == 1 && y == 0) {
212 return vcombine_f64(vget_high_f64(v.raw), vget_low_f64(v.raw));
213 }
else if constexpr (x == 1 && y == 1) {
219 return vreinterpretq_f64_s64(vdupq_n_s64((int64_t)0x8000000000000000LL));
223 return vsqrtq_f64(v.raw);
227 return vrecpeq_f64(v.raw);
231 return vrsqrteq_f64(v.raw);
235 return vabsq_f64(v.raw);
239 return vminq_f64(a.raw, b.raw);
243 return vmaxq_f64(a.raw, b.raw);
247 return vrndmq_f64(a.raw);
251 return vrndaq_f64(v.raw);
255 return vfmaq_f64(c.raw, b.raw, a.raw);
263 return vfmsq_f64(c.raw, b.raw, a.raw);
272 static_assert(N == 2,
"Unsupported N");
273 return vminvq_f64(a.raw);
278 static_assert(N == 2,
"Unsupported N");
279 return vmaxvq_f64(a.raw);
284 static_assert(N == 2,
"Unsupported N");
285 return vaddvq_f64(a.raw);
290 static_assert(N == 2,
"Unsupported N");
296 static_assert(N == 2,
"Unsupported N");
301 return vreinterpretq_f64_u64(vcltq_f64(this->
raw, rhs.raw));
305 return vreinterpretq_f64_u64(vcgtq_f64(this->
raw, rhs.raw));
309 return vreinterpretq_f64_u64(vcleq_f64(this->
raw, rhs.raw));
313 return vreinterpretq_f64_u64(vcgeq_f64(this->
raw, rhs.raw));
317 return vreinterpretq_f64_u64(vceqq_f64(a.raw, b.raw));
325 return vdupq_n_f64(0);
333 return !(*
this == rhs);
337 return vreinterpretq_f64_u32(vmvnq_u32(vreinterpretq_u32_f64(
raw)));
341 return vnegq_f64(
raw);
345 return vaddq_f64(
raw, rhs.raw);
349 return vsubq_f64(
raw, rhs.raw);
353 return vmulq_f64(
raw, rhs.raw);
357 return vdivq_f64(
raw, rhs.raw);
361 return vreinterpretq_f64_s64(
362 vandq_s64(vreinterpretq_s64_f64(
raw), vreinterpretq_s64_f64(rhs.raw)));
366 return vreinterpretq_f64_s64(
367 vorrq_s64(vreinterpretq_s64_f64(
raw), vreinterpretq_s64_f64(rhs.raw)));
371 return vreinterpretq_f64_s64(
372 veorq_s64(vreinterpretq_s64_f64(
raw), vreinterpretq_s64_f64(rhs.raw)));
Simd operator&(Simd rhs) const
bool operator==(Simd rhs) const
Simd operator>(Simd rhs) const
Simd operator*(Simd rhs) const
Simd operator^(Simd rhs) const
Simd operator>=(Simd rhs) const
Simd operator<(Simd rhs) const
bool operator!=(Simd rhs) const
Simd operator|(Simd rhs) const
static constexpr int kSize
Simd operator+(Simd rhs) const
Simd operator/(Simd rhs) const
Simd operator<=(Simd rhs) const
#define MOCHI_ASSERT_VERBOSE(condition_without_side_effects,...)
T Dot(Simd< T, N > a, Simd< T, N > b)
Simd< T, 2 > Shuffle(Simd< T, 2 > a)
V LoadIndexed(typename V::Scalar const *ptr, Simd< I, V::kSize > indices)
constexpr T const & Min(T const &a, T const &b)
constexpr auto Equal(T const &a, T const &b)
constexpr auto MulAdd(A a, B b, C c)
Simd< T, N > Set(Simd< T, N > a, T value)
constexpr auto NotEqual(T const &a, T const &b)
V Broadcast(typename V::Scalar a)
constexpr auto MulSub(A a, B b, C c)
Simd< T, N > Blend(Simd< T, N > a, Simd< T, N > b)
constexpr T Select(bool condition, T a, T b)
constexpr auto NegMulAdd(A a, B b, C c)
constexpr T const & Max(T const &a, T const &b)
void LoadTransposed(T const *ptr, Simd< T, N > &out0, Simd< T, N > &out1, Simd< T, N > &out2)
Simd< T, N > FastRound(Simd< T, N > a)
void StoreTransposed(T *ptr, Simd< T, N > a, Simd< T, N > b, Simd< T, N > c)
void Store(T *ptr, Simd< T, N > a)
Simd< T, N > RcpSqrtApprox(Simd< T, N > a)
constexpr T RcpApprox(T a)
constexpr auto NegMulSub(A a, B b, C c)
int StoreSelected(T *ptr, Simd< MaskT, N > condition, Simd< T, N > values)
V Load(typename V::Scalar const *ptr)
#define MOCHI_NATIVE_SIMD_IMPL_BOILERPLATE(T, N, NativeT)