21#if MOCHI_USE_SIMD && MOCHI_ARCH_ARM_NEON
29class Simd<int64_t, 2> {
34 template <
class U, MOCHI_REQUIRES_NON_BOOL_SCALAR(U, Scalar)>
39 static_assert(i >= 0 && i <
kSize,
"Index out of range");
40 return vgetq_lane_s64(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_s64(v.raw))), 0);
66 if constexpr (N == 1) {
67 return (mask & 0x00000000FFFFFFFFULL) == 0x00000000FFFFFFFFULL;
69 return mask == 0xFFFFFFFFFFFFFFFFULL;
73 template <
int x,
int y>
75 static_assert(x >= 0 && x <= 1 && y >= 0 && y <= 1,
"invalid blend index");
76 if constexpr (x == 0 && y == 0) {
78 }
else if constexpr (x == 1 && y == 1) {
81 auto mask = int64x2_t{x ? (int64_t)0 : (int64_t)-1, y ? (int64_t)0 : (int64_t)-1};
92 static_assert(i >= 0 && i <
kSize,
"Index out of range");
93 return vdupq_laneq_s64(v.raw, i);
98 static_assert(N == 2,
"Unsupported N");
104 static_assert(N == 2,
"Unsupported N");
110 static_assert(N == 2,
"Unsupported N");
111 return vaddvq_s64(a.raw);
114 template <
int N = kSize>
116 static_assert(N >= 0 && N <=
kSize);
117 if constexpr (N == 0) {
119 }
else if constexpr (N == 1) {
120 return Simd{ptr[0], 0};
122 return vld1q_s64(ptr);
136 template <
int kTupleCount = kSize>
139 static_assert(kTupleCount >= 1 && kTupleCount <=
kSize,
"Unsupported kTupleCount");
140 if constexpr (kTupleCount == 1) {
141 out0.raw = int64x2_t{ptr[0], 0};
142 out1.raw = int64x2_t{ptr[1], 0};
143 out2.raw = int64x2_t{ptr[2], 0};
145 int64x2x3_t result = vld3q_s64(ptr);
146 out0.raw = result.val[0];
147 out1.raw = result.val[1];
148 out2.raw = result.val[2];
153 return vbslq_s64(vcltq_s64(a.raw, b.raw), a.raw, b.raw);
157 return vbslq_s64(vcgtq_s64(a.raw, b.raw), a.raw, b.raw);
161 return vbslq_s64(vreinterpretq_u64_s64(mask.raw), a.raw, b.raw);
165 template <
int x = 0,
int y = 1>
167 static_assert(x >= 0 && x < 2,
"Invalid index");
168 static_assert(y >= 0 && y < 2,
"Invalid index");
169 if constexpr (x == 0 && y == 0) {
171 }
else if constexpr (x == 0 && y == 1) {
173 }
else if constexpr (x == 1 && y == 0) {
174 return vcombine_s64(vget_high_s64(v.raw), vget_low_s64(v.raw));
175 }
else if constexpr (x == 1 && y == 1) {
180 template <
int N = kSize>
182 static_assert(N >= 0 && N <=
kSize);
183 if constexpr (N == 0) {
184 }
else if constexpr (N <
kSize) {
185 memcpy(ptr, &v,
sizeof(
Scalar) * N);
187 vst1q_s64(ptr, v.raw);
202 uint64x2_t shifted = vshrq_n_u64(vreinterpretq_u64_s64(condition.raw), 63);
203 uint32_t bit0 = vgetq_lane_u64(shifted, 0);
204 uint32_t bit1 = vgetq_lane_u64(shifted, 1);
205 uint32_t mask = bit0 | (bit1 << 1);
206 uint32_t count = bit0 + bit1;
207 uint8x16_t pattern = vld1q_u8(arm_simd::kStoreSelectedShuffleTableD2[mask]);
208 uint8x16_t packed = vqtbl1q_u8(vreinterpretq_u8_s64(values.raw), pattern);
209 vst1q_s64(ptr, vreinterpretq_s64_u8(packed));
210 return static_cast<int>(count);
213 template <
int kTupleCount = kSize>
215 static_assert(kTupleCount >= 1 && kTupleCount <=
kSize,
"Invalid kTupleCount");
216 if constexpr (kTupleCount == 1) {
221 vst3q_s64(ptr, int64x2x3_t({a.raw, b.raw, c.raw}));
226 return vdupq_n_s64(0);
230 return vreinterpretq_s64_u64(vcltq_s64(this->
raw, rhs.raw));
234 return vreinterpretq_s64_u64(vcgtq_s64(this->
raw, rhs.raw));
238 return vreinterpretq_s64_u64(vcleq_s64(this->
raw, rhs.raw));
242 return vreinterpretq_s64_u64(vcgeq_s64(this->
raw, rhs.raw));
246 return vreinterpretq_s64_u64(vceqq_s64(a.raw, b.raw));
254 return vnegq_s64(
raw);
258 return vaddq_s64(
raw, rhs.raw);
262 return vsubq_s64(
raw, rhs.raw);
269 raw[1] * rhs.raw[1]};
276 raw[1] / rhs.raw[1]};
280 uint32x2_t t = vqmovn_u64(vceqq_s64(
raw, rhs.raw));
281 return vget_lane_u64(vreinterpret_u64_u32(t), 0) == uint64_t(-1);
285 return !(*
this == rhs);
289 return vreinterpretq_s64_u32(vmvnq_u32(vreinterpretq_u32_s64(
raw)));
293 return vandq_s64(
raw, rhs.raw);
297 return vorrq_s64(
raw, rhs.raw);
301 return veorq_s64(
raw, rhs.raw);
308 auto vShift =
Simd(shift);
309 return vshlq_s64(
raw, vShift.raw);
312 template <
int kShift>
314 return vshrq_n_s64(a.raw, kShift);
Simd operator&(Simd rhs) const
bool operator==(Simd rhs) const
Simd operator>(Simd rhs) const
Simd operator<<(int shift) 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,...)
Simd< T, 2 > Shuffle(Simd< T, 2 > a)
constexpr T const & Min(T const &a, T const &b)
constexpr auto Equal(T const &a, T const &b)
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)
Simd< T, N > Blend(Simd< T, N > a, Simd< T, N > b)
constexpr T Select(bool condition, T a, T b)
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)
void StoreTransposed(T *ptr, Simd< T, N > a, Simd< T, N > b, Simd< T, N > c)
void Store(T *ptr, Simd< T, N > a)
int StoreSelected(T *ptr, Simd< MaskT, N > condition, Simd< T, N > values)
V Load(typename V::Scalar const *ptr)
Simd< T, N > ShiftRight(Simd< T, N > a)
#define MOCHI_NATIVE_SIMD_IMPL_BOILERPLATE(T, N, NativeT)