SuperDex Physics C++ API
Loading...
Searching...
No Matches
simd.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
22
23#include <type_traits>
24#include <utility>
25
26namespace superdex {
27
28// Forward declaration for use in composite StaticCast (full definition is in half.h)
29struct Half;
30
31// Number of values of type T that fit in a native SIMD register
32template <class T>
34
35// Type used with enable_if_t that can be used to select a Simd specialization based on type traits
36struct SimdConcept {};
37
38/***********************************************************************************************
39 Simd<T, N>
40
41 A SIMD vector storing N values of type T.
42
43 This generic template must be fully specialized for supported sizes and types.
44 There currently is no reference implementation.
45*/
46template <class T, int N = kSimdDefaultSize<T>, class Concept = SimdConcept>
47class Simd;
48
49// clang-format off
50namespace details {
51template <class T> constexpr bool IsSimdDef = false;
52template <class T, int N> constexpr bool IsSimdDef<Simd<T, N>> = true;
53template <class T> constexpr bool IsSimdSupportedTypeDef = false;
54template <> inline constexpr bool IsSimdSupportedTypeDef<float> = true;
55template <> inline constexpr bool IsSimdSupportedTypeDef<double> = true;
56template <> inline constexpr bool IsSimdSupportedTypeDef<int> = true;
57template <> inline constexpr bool IsSimdSupportedTypeDef<int64_t> = true;
58template <class T> constexpr bool IsHalfDef = false; // Specialized in half.h
59} // namespace details
60// clang-format on
61
62// Compile-time type traits:
63// - IsSimd<T> is true T is an instantiation of the Simd template class.
64// - IsSimdSupportedType<T> is true if Simd<T, N> is supported for some integer N.
65// - IsHalf<T> is true if T is Half (from half.h).
66#if MOCHI_LANGUAGE_CPP20
67template <class T>
68concept IsSimd = details::IsSimdDef<std::decay_t<T>>;
69template <class T>
70concept IsSimdSupportedType = details::IsSimdSupportedTypeDef<T>;
71template <class T>
72concept IsHalf = details::IsHalfDef<std::decay_t<T>>;
73#else
74template <class T>
75inline constexpr bool IsSimd = details::IsSimdDef<std::decay_t<T>>;
76template <class T>
77inline constexpr bool IsSimdSupportedType = details::IsSimdSupportedTypeDef<T>;
78template <class T>
79inline constexpr bool IsHalf = details::IsHalfDef<std::decay_t<T>>;
80#endif
81
82/***********************************************************************************************
83 Simd<T, N>
84
85 A SIMD vector storing N values of type T.
86
87 This generic template must be fully specialized for supported sizes and types.
88 There currently is no reference implementation.
89*/
90template <class T, int N, class Concept>
91class Simd {
92 public:
93 struct NotSupported {};
95 using Scalar = T;
96 static constexpr int kSize = N;
97 static constexpr bool kIsSupported = false; // Can this combination of T and N function
98 static constexpr bool kIsComposite = false; // Is this type a composite of native sizes
99 static constexpr bool kIsEmulated = false; // Whether it emulates SIMD instructions (if true) or
100 // uses actual native SIMD instructions (if false).
101
102 // Check to prevent misuse of Simd<T>::kIsSupported if queried with a const T.
103 static_assert(!std::is_const_v<T>, "Scalar type must not be const");
104
106 static_assert(std::is_same_v<T, void>, "The requested SIMD size or type is not supported");
107 }
108
109 Simd(Simd const& rhs) = default;
110
111 // Implicit conversion from native storage type.
112 Simd(NativeType rhs) : raw(rhs) {};
113
114 // Broadcast scalar
116
117 // Init from 2 or more scalars. Remaining values will be zero.
118 template <class... Ts>
119 Simd(Scalar a, Scalar b, Ts... vals);
120
121 // Lower-case for compatibility with std::size
122 static constexpr size_t size() {
123 return kSize;
124 }
125
126 // Assignment
129
130 // Comparison operators
131 bool operator==(Simd rhs) const;
132 bool operator!=(Simd rhs) const;
133 Simd operator<(Simd rhs) const;
134 Simd operator<=(Simd rhs) const;
135 Simd operator>(Simd rhs) const;
136 Simd operator>=(Simd rhs) const;
137
138 // Math operators
140 Simd operator+(Simd rhs) const;
141 Simd operator-(Simd rhs) const;
142 Simd operator*(Simd rhs) const;
143 Simd operator/(Simd rhs) const;
152
153 // Bitwise operators
155 Simd operator&(Simd rhs) const;
156 Simd operator|(Simd rhs) const;
157 Simd operator^(Simd rhs) const;
161
162 // Logical operators
163 // Each lane must have all-bits-0 (logical false) or all-bits-1 (logical true).
164 Simd operator&&(Simd rhs) const;
165 Simd operator||(Simd rhs) const;
166
167 // Left shift
168 Simd operator<<(int shift) const;
169
170 // Indexing (read only)
171 Scalar operator[](int i) const;
172
173 // Storage type is implementation specific (e.g. __m256)
175};
176
177/// @brief Reinterpret the bits of one Simd type to another of the same binary size.
178/// @note Example: ReinterpretCast<Vec2d>(myVec4i);
179/// @note The generic version of ReinterpretCast is not valid, but specializations
180/// can be provided for specific pairs of types.
181template <class VecTo, class VecFrom, MOCHI_CONCEPT(IsSimd<VecTo>&& IsSimd<VecFrom>)>
182MOCHI_ANY MOCHI_FORCE_INLINE VecTo ReinterpretCast(VecFrom const& a) {
183 static_assert(
184 std::is_same_v<std::decay_t<VecTo>, std::decay_t<VecFrom>>,
185 "ReinterpretCast not supported for these types.");
186 return a;
187}
188
189/// @brief StaticCast from one Simd type to another of the same size.
190/// @note The generic version is a fallback.
191/// Specializations are provided for specific pairs of types.
192template <class VecTo, class VecFrom, MOCHI_CONCEPT(IsSimd<VecTo>&& IsSimd<VecFrom>)>
194
195} // namespace superdex
197namespace superdex {
198
199// Aliases
212
213// clang-format off
214/***********************************************************************************************
215 Native SIMD Function Support Matrix (please keep up-to-date)
216 Functions supporting Simd<T, N> also support Simd<T, MultipleOfN>
217
218 For Simd<Half, N> (Vec8h, Vec16h), include half.h.
219
220************************************************************************************************
221
222 | Vec2d | Vec2l | Vec4d | Vec4f | Vec4i | Vec4l | Vec8f | Vec8i | Vec8h | Vec16h |
223 Abs | x | | x | x | | | x | | | |
224 ACos | x | | x | x | | | x | | | |
225 AllTrue | x | x | x | x | x | x | x | x | x | x |
226 AnyTrue | x | | x | x | x | | x | x | x | x |
227 ASin | x | | x | x | | | x | | | |
228 ATan | x | | x | x | | | x | | | |
229 Blend | x | x | x | x | x | | | | | |
230 Broadcast | x | x | x | x | x | x | x | x | | |
231 Clamp | x | | x | x | | | x | | | |
232 Cos | x | | x | x | | | x | | | |
233 Cross3 | | | x | x | | | | | | |
234 Dot | x | | x | x | | | x | | | |
235 (V)Equal | x | x | x | x | x | x | x | x | x | x |
236 Exp | x | | x | x | | | x | | | |
237 FastRound | x | | x | x | | | x | | | |
238 Floor | x | | x | x | | | x | | | |
239 Get | x | x | x | x | x | x | x | x | x | x |
240 Get0 | x | x | x | x | x | x | x | x | x | x |
241 GetHalf | | | x | | | x | x | x | | x |
242 HMax | x | x | x | x | x | x | x | x | | |
243 HMin | x | x | x | x | x | x | x | x | | |
244 HProd | x | | x | x | | | | | | |
245 HSum | x | x | x | x | x | x | x | x | | |
246 (V)IsFinite | x | | x | x | | | x | | | |
247 IsTrue | x | | x | x | x | | x | x | | |
248 Lerp | x | | x | x | | | x | | | |
249 Ln | x | | x | x | | | x | | | |
250 Load | x | x | x | x | x | x | x | x | x | x |
251 LoadIndexed | x | | x | x | | | x | | | |
252 LoadTransposed | x | x | x | x | x | x | x | x | | |
253 Max | x | x | x | x | x | x | x | x | | |
254 Min | x | x | x | x | x | x | x | x | | |
255 MulAdd | x | | x | x | | | x | | | |
256 MulSub | x | | x | x | | | x | | | |
257 (V)NearEqual | x | | x | x | | | x | | | |
258 (V)NearZero | x | | x | x | | | x | | | |
259 Neg (4 bools) | | | x | x | | | | | | |
260 NegMulAdd | x | | x | x | | | x | | | |
261 NegMulSub | x | | x | x | | | x | | | |
262 (V)Norm | x | | x | x | | | x | | | |
263 Normalize | x | | x | x | | | x | | | |
264 (V)NotEqual | x | x | x | x | x | x | x | x | x | x |
265 OrthogonalVector3 | | | x | x | | | | | | |
266 RcpApprox | x | | x | x | | | x | | | |
267 RcpSqrtApprox | x | | x | x | | | x | | | |
268 Select | x | x | x | x | x | x | x | x | | |
269 Set | x | | x | x | x | | x | x | | |
270 Sequence | | x | | | x | x | | x | | |
271 ShiftRight | | x | | | x | x | | x | | |
272 Shuffle (1 arg) | x | x | x | x | x | x | | | | |
273 Shuffle (2 arg) | | | x | x | x | x | | | | |
274 Sign | x | | x | x | | | x | | | |
275 SignedSqrt | x | | x | x | | | x | | | |
276 SimdBasisVector | | | x | x | | | | | | |
277 SimdMask | x | | x | x | x | | x | x | | |
278 SimdZero | x | x | x | x | x | x | x | x | x | x |
279 Sin | x | | x | x | | | x | | | |
280 SinCos | x | | x | x | | | x | | | |
281 Sqr | x | x | x | x | x | x | x | x | | |
282 Sqrt | x | | x | x | | | | | | |
283 Store | x | x | x | x | x | x | x | x | x | x |
284 StoreSelected | x | x | x | x | x | x | x | x | | |
285 StoreTransposed | x | x | x | x | x | x | x | x | | |
286 Tan | x | | x | x | | | x | | | |
287 Tanh | x | | x | x | | | x | | | |
288 ToSimd | x | | x | x | x | | x | x | | |
289 ToSimdDirection | | | x | x | | | | | | |
290 ToSimdPoint | | | x | x | | | | | | |
291
292***********************************************************************************************/
293// clang-format on
294
295// Make kDefaultNearEqualEpsilon<T> "just work" when T is a Simd type
296template <class T, int N>
298
299// Broadcast a single value to all elements of the result
300template <class V, MOCHI_CONCEPT(IsSimd<V>)>
301MOCHI_ANY MOCHI_FORCE_INLINE V Broadcast(typename V::Scalar a);
302
303// Broadcast a single value at address ptr to all elements of the result
304template <class V, MOCHI_CONCEPT(IsSimd<V>)>
305MOCHI_ANY MOCHI_FORCE_INLINE V Broadcast(typename V::Scalar const* ptr);
306
307// Broadcast the ith element of a vector to all elements of the result
308template <int i, class T, int N>
309MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Broadcast(Simd<T, N> v);
310
311// Broadcast the ith element of a vector to all elements of the result.
312// Prefer Broadcast<i> if index is known at compile time.
313template <class T, int N>
314MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Broadcast(Simd<T, N> v, int i);
315
316// Return V{b0 ? TRUE : FALSE, b1 ? TRUE : FALSE, ...} where TRUE is represented by all bits set
317// to 1 (e.g. 0xFFFFFFFF) and FALSE is represented by all bits set to 0 (e.g. 0x00000000). This is
318// the same type of mask returned by comparison operators like <, <=, >, and >=. It can be used with
319// functions like AllTrue, AnyTrue, and Select.
320// Example: SimdMask<Vec4r>(true, false, true, false)
321template <class V, class... MoreBools>
322MOCHI_ANY MOCHI_FORCE_INLINE V SimdMask(bool b0, bool b1, MoreBools... bs);
323
324// Return 0 value
325//
326// The function is templated on the return type.
327template <class V = Vec4r>
329
330// Return a vector with a single component set to 1, and the rest to 0.
331template <int i, class V = Vec4r>
333
334// Return a vector with a single component set to 1, and the rest to 0.
335template <class V = Vec4r>
337
338// Return {a[0], a[1], a[2], 1}. Used for positions that can be both rotated & translated.
339template <class V>
341
342// Return {a[0], a[1], a[2], 0}. Used for direction vectors that can only be rotated.
343template <class V>
345
346// Read V::kSize scalars from the specified address into a vector
347template <class V, MOCHI_CONCEPT(IsSimd<V>)>
348MOCHI_ANY MOCHI_FORCE_INLINE V Load(typename V::Scalar const* ptr);
349
350// Read N scalars from the specified address into a vector.
351template <int N, class V, MOCHI_CONCEPT(IsSimd<V>)>
352MOCHI_ANY MOCHI_FORCE_INLINE V Load(typename V::Scalar const* ptr);
353
354// Read n scalars from the specified address into a vector.
355// Prefer Load<N, V> if the number is a constexpr.
356template <class V, MOCHI_CONCEPT(IsSimd<V>)>
357MOCHI_ANY MOCHI_FORCE_INLINE V Load(typename V::Scalar const* ptr, int n);
358
359// Read V::kSize scalars from an unaligned address offset by Simd<I, kSize>, where I is an integer
360// type.
361template <class V, class I, MOCHI_CONCEPT(IsSimd<V>)>
363LoadIndexed(typename V::Scalar const* ptr, Simd<I, V::kSize> indices);
364
365// Load (kTupleCount * 3) values from memory. Deinterleave into 3 output vectors.
366// By default (kTupleCount == N).
367//
368// If the memory order was:
369// {x0, y0, z0, x1, y1, z1, x2, y2, z2, x3, y3, z3}
370//
371// ...then the output vectors will be:
372// {x0, x1, x2, x3}, {y0, y1, y2, y3}, {z0, z1, z2, z3}
373//
374template <int kTupleCount = -1, class T, int N>
376LoadTransposed(T const* ptr, Simd<T, N>& out0, Simd<T, N>& out1, Simd<T, N>& out2);
377
378// Return the first component of a vector (e.g. a[0])
379template <class T, int N>
380MOCHI_ANY MOCHI_FORCE_INLINE T Get0(Simd<T, N> v);
381
382// Return the ith component of a vector (e.g a[i]), when the index is a constexpr
383template <int i, class T, int N>
384MOCHI_ANY MOCHI_FORCE_INLINE T Get(Simd<T, N> v);
385
386// Return the ith component of a vector (e.g. a[i]).
387template <class T, int N>
388MOCHI_ANY MOCHI_FORCE_INLINE T Get(Simd<T, N> v, int i);
389
390// Return the low or high half of a vector via GetHalf<0>(a) or GetHalf<1>(a)
391template <int iHalf, class T, int N>
392MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N / 2> GetHalf(Simd<T, N> a);
393
394// Return a copy of the vector with the ith component replaced with a new value.
395template <int i, class T, int N>
396[[nodiscard]] MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Set(Simd<T, N> a, T value);
397
398// Return a copy of the vector with the ith component replaced with a new value.
399template <class T, int N>
400[[nodiscard]] MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Set(Simd<T, N> a, int i, T value);
401
402// Returns a vector with integer values [0, 1, 2, 3, ...].
403// If you want a different starting value, then add an integer to the result.
404// Example: (Sequence<V>() + 1) results in the sequence [1, 2, 3, ...]
405template <class V>
406[[nodiscard]] MOCHI_ANY MOCHI_FORCE_INLINE V Sequence();
407
408// Write COUNT scalars from a vector to the specified address. A COUNT of -1 means "all".
409template <int COUNT = -1, class T, int N>
410MOCHI_ANY MOCHI_FORCE_INLINE void Store(T* ptr, Simd<T, N> a);
411
412// Write count scalars from a vector to the specified address.
413// Prefer Store<N> if the number is a constexpr.
414template <class T, int N>
415MOCHI_ANY MOCHI_FORCE_INLINE void Store(T* ptr, Simd<T, N> a, int count);
416
417// Write each value for which condition[i] is true. It may then write unspecified values for a total
418// of N values written, so the destination buffer must be large enough. Returns the number of
419// values for which condition[i] was true.
420//
421// Example - Store all the positive values (branchless):
422// int count = 0;
423// for (int i = 0; i + N <= isize(src); i += N) {
424// auto values = Load<Simd<T, N>>(&src[i]);
425// count += StoreSelected(&dst[count], values >= 0, values);
426// }
427//
428// Warning: If the condition is somewhat predictable (e.g. many false values in a row), then a
429// traditional branching algorithm may be faster. You should always profile it.
430//
431template <class T, int N, class MaskT>
432MOCHI_ANY MOCHI_FORCE_INLINE int StoreSelected(T* ptr, Simd<MaskT, N> condition, Simd<T, N> values);
433
434// Interleave the values of 3 input vectors. Store those (kTupleCount * 3) values to memory.
435// By default (kTupleCount == N).
436//
437// If the input vectors are:
438// {x0, x1, x2, x3}, {y0, y1, y2, y3}, {z0, z1, z2, z3}
439//
440// ...then the order written to memory will be:
441// {x0, y0, z0, x1, y1, z1, x2, y2, z2, x3, y3, z3}
442//
443template <int kTupleCount = -1, class T, int N>
444MOCHI_ANY MOCHI_FORCE_INLINE void StoreTransposed(T* ptr, Simd<T, N> a, Simd<T, N> b, Simd<T, N> c);
445
446// Return result[i] = conditionalMask[i] ? a[i] : b[i]
447// where conditionMask[i] is 0x00000000 (false) or 0xFFFFFFFF (true).
448// Example: Select(a <= b, a, b) is equivalent to Min(a, b)
449template <class T, int N, class MaskT>
451Select(Simd<MaskT, N> conditionMask, Simd<T, N> a, Simd<T, N> b);
452
453// Special bit shift operations
454template <int kShift, class T, int N>
455MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> ShiftRight(Simd<T, N> a); // return (a >> kShift)
456
457// Shuffle elements in a vector. Returns: {a[i0], a[i1], ... }
458template <int x = 0, int y = 1, class T>
459MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, 2> Shuffle(Simd<T, 2> a);
460template <int x = 0, int y = 1, int z = 2, int w = 3, class T>
461MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, 4> Shuffle(Simd<T, 4> a);
462
463// Shuffle elements between two vectors. Returns: { a[x], a[y], b[z], b[w] }
464template <int x, int y, int z, int w, class T>
465MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, 4> Shuffle(Simd<T, 4> a, Simd<T, 4> b);
466
467// Blend returns { (x ? b[0] : a[0]), (y ? b[1] : a[1]) }
468template <int x, int y, class T, int N>
469MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Blend(Simd<T, N> a, Simd<T, N> b);
470
471// Blend returns { (x ? b[0] : a[0]), (y ? b[1] : a[1]), (z ? b[2] : a[2]), (w ? b[3] : a[3]) }
472template <int x, int y, int z, int w, class T, int N>
473MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Blend(Simd<T, N> a, Simd<T, N> b);
474
475// Math Operations:
476template <bool x, bool y, bool z, bool w, class T, int N>
478 Simd<T, N> a); // { x ? -a[0] : a[0], y ? -a[1] : a[1], z ? -a[2] : a[2], w ? -a[3] : a[3] }
479template <class T, int N>
480MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Sqrt(Simd<T, N> a); // sqrt(a)
481template <class T, int N>
482MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> RcpApprox(Simd<T, N> a); // Fast approximation of 1/a
483template <class T, int N>
485 Simd<T, N> a); // Fast approximation of 1/sqrt(a)
486template <class T, int N>
487MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Abs(Simd<T, N> a); // abs(a)
488
489// NOTE: NaN behavior of Min/Max is undefined (platform-dependent and operand-order-dependent).
490template <class T, int N>
491MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Min(Simd<T, N> a, Simd<T, N> b); // min(a, b)
492template <class T, int N>
493MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Max(Simd<T, N> a, Simd<T, N> b); // max(a, b)
494template <class T, int N>
495MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Floor(Simd<T, N> a); // floor(a)
496
497// Round to the nearest integer. On ARM, exact ties are rounded away from zero, just like with
498// std::round. However, on x64 ties are rounded to the nearest even integer. Use only in situations
499// where this discrepancy is not an issue.
500template <class T, int N>
501MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> FastRound(Simd<T, N> a);
502
503// NOT FAST: Horizontal sum of first COUNT elements of a vector. COUNT of -1 means "all".
504template <int COUNT = -1, class T, int N>
505MOCHI_ANY MOCHI_FORCE_INLINE T HSum(Simd<T, N> a);
506
507// NOT FAST: Horizontal product of first COUNT elements of a vector. COUNT of -1 means "all".
508template <int COUNT = -1, class T, int N>
509MOCHI_ANY MOCHI_FORCE_INLINE T HProd(Simd<T, N> a);
510
511// NOT FAST: Horizontal minimum of first COUNT elements of a vector. COUNT of -1 means "all".
512template <int COUNT = -1, class T, int N>
513MOCHI_ANY MOCHI_FORCE_INLINE T HMin(Simd<T, N> a);
514
515// NOT FAST: Horizontal maximum of first COUNT elements of a vector. COUNT of -1 means "all".
516template <int COUNT = -1, class T, int N>
517MOCHI_ANY MOCHI_FORCE_INLINE T HMax(Simd<T, N> a);
518
519// We have a custom implementation of cosine for single-precision floats. It matches the precision
520// of std::cos to within than 6.0e-8. Performance is a little slower than a single call to std::cos,
521// but faster than 2 calls, and much faster than N calls. For double-precision, we fall back on SVML
522// intrinsics (no faster than our implementation), or std::cos if SVML is not available.
523template <class T, int N>
524MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Cos(Simd<T, N> a);
525
526// We have a custom implementation of sine for single-precision floats. Performance and precision is
527// nearly identical to Cos (see notes above).
528template <class T, int N>
529MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Sin(Simd<T, N> a);
530
531// If you need both the sine and the cosine of an angle, then this function can compute both at the
532// same time. It is faster than calling std::sin + std::cos for a single float. In that time, it
533// computes sine and cosine for all N vector components. Precision matches the standard library
534// functions to within 6.0e-8 for single-precision floats. For double-precision, we fall back on
535// SVML or scalar functions (more precision, but slower).
536template <class T, int N>
537MOCHI_ANY MOCHI_FORCE_INLINE std::pair<Simd<T, N>, Simd<T, N>> SinCos(Simd<T, N> a);
538
539// These trig functions are implemented with intrinsics with the SVML extension is available on x64
540// platforms. Otherwise, these functions are quite slow because they simply call the corresponding
541// std library functions N times.
542template <class T, int N>
543MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Tan(Simd<T, N> a);
544template <class T, int N>
545MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Tanh(Simd<T, N> a);
546template <class T, int N>
547MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> ACos(Simd<T, N> a);
548template <class T, int N>
549MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> ASin(Simd<T, N> a);
550template <class T, int N>
551MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> ATan(Simd<T, N> a);
552
553// Math functions
554template <class T, int N>
555MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Exp(Simd<T, N> a);
556template <class T, int N>
557MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Ln(Simd<T, N> a);
558
559// Simd Comparisons:
560// Comparisons are performed for each Simd elements. They return a Simd mask where result[i] has
561// all bits set to 0 to signify "false" or all bits set to 1 to signify "true". This is true for
562// Simd operators <, <=, >, and >= as well as Simd functions with a "V" prefix.
563//
564// Exception:
565// Simd operator== and operator!= return a bool to match typical user expectation. Specifically
566// operator== returns true if all Simd elements are equal, while operator!= returns true if any
567// Simd elements are not equal.
568//
569// Example:
570// auto a = VEqual(Vec4i{1,2,3,4}, Vec4i{1,0,3,0});
571// MOCHI_ASSERT(a == Vec4i{0xFFFFFFFF, 0, 0xFFFFFFFF, 0});
572//
573
574// Return true if ALL of the first COUNT elements have a non-zero bit pattern. COUNT of -1 means
575// "all". Example: AllTrue<2>(a < b) returns true iff ((a[0] < b[0]) && (a[1] < b[1]))
576template <int COUNT = -1, class T, int N>
577MOCHI_ANY MOCHI_FORCE_INLINE bool AllTrue(Simd<T, N> a);
578
579// Return true if ANY of the first COUNT elements have a non-zero bit pattern. COUNT of -1 means
580// "all". Example: AnyTrue<2>(a < b) returns true iff ((a[0] < b[0]) || (a[1] < b[1]))
581template <int COUNT = -1, class T, int N>
582MOCHI_ANY MOCHI_FORCE_INLINE bool AnyTrue(Simd<T, N> a);
583
584// Returns result[i] = (a[i] == b[i]) ? 0xFFFFFFFF : 0x00000000;
585// See note above regarding Simd comparisons.
586template <class V>
588
589// Return true if (a[i] == b[i]) for ALL of the first COUNT elements. Count of -1 means "all".
590template <int COUNT = -1, class T, int N>
591MOCHI_ANY MOCHI_FORCE_INLINE bool Equal(Simd<T, N> a, Simd<T, N> b);
592
593// Returns result[i] = (a[i] != b[i]) ? 0xFFFFFFFF : 0x00000000;
594// See note above regarding Simd comparisons.
595template <class V>
597
598// Return true if (a[i] != b[i]) for ANY of the first COUNT lanes. Count of -1 means "all".
599template <int COUNT = -1, class T, int N>
600MOCHI_ANY MOCHI_FORCE_INLINE bool NotEqual(Simd<T, N> a, Simd<T, N> b);
601
602// Like NearEqual except that it takes a Simd epsilon and returns a Simd bit mask.
603// Returns result[i] = (Abs(a[i] - b[i]) <= epsilon[i]) ? 0xFFFFFFFF : 0x00000000;
604// See note above regarding Simd comparisons.
605template <class V>
606MOCHI_ANY MOCHI_FORCE_INLINE V VNearEqual(V a, V b, V epsilon);
607
608// Return true if (Abs(a[i] - b[i]) <= epsilon) for ALL of the first N lanes.
609// Count of -1 means "all".
610template <int COUNT = -1, class T, int N, class Eps = T>
613 return AllTrue<COUNT>(VNearEqual(a, b, Simd<T, N>{epsilon}));
614}
615
616// Like NearZero except that it takes a Simd epsilon and returns a Simd bit mask.
617// Returns result[i] = (Abs(a[i]) <= epsilon[i]) ? 0xFFFFFFFF : 0x00000000;
618// See note above regarding Simd comparisons.
619template <class V>
620MOCHI_ANY MOCHI_FORCE_INLINE V VNearZero(V a, V epsilon);
621
622// Return true if (Abs(a[i]) <= epsilon) for ALL of the first N lanes. Count of -1 means "all".
623template <int COUNT = -1, class T, int N, class Eps = T>
629
630// Returns result[i] = IsFinite(a[i]) ? 0xFFFFFFFF : 0x00000000;
631template <class T, int N>
632MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> VIsFinite(Simd<T, N> a);
633
634// Return true if all elements of the Simd vector are finite (not +inf, -inf, nor NaN).
635template <class T, int N>
639
640// Return a non-zero integer if component i of the vector is considered "true" (see AnyTrue,
641// AllTrue). Example: "if (IsTrue<i>(a < b))" is like writing "if (a[i] < b[i])".
642template <int i, class T, int N>
643MOCHI_ANY MOCHI_FORCE_INLINE int IsTrue(Simd<T, N> mask);
644
645// Fused Math Operations:
646template <class T, int N>
648MulAdd(Simd<T, N> a, Simd<T, N> b, Simd<T, N> c); // (a * b) + c
649template <class T, int N>
651MulSub(Simd<T, N> a, Simd<T, N> b, Simd<T, N> c); // (a * b) - c
652template <class T, int N>
654NegMulAdd(Simd<T, N> a, Simd<T, N> b, Simd<T, N> c); // -(a * b) + c
655template <class T, int N>
657NegMulSub(Simd<T, N> a, Simd<T, N> b, Simd<T, N> c); // -(a * b) - c
658
659// Dot product of the first COUNT elements. Count of -1 means "all". Broadcasts the result to all
660// elements. Use "Dot" (not "VDot") if you want a single scalar result.
661template <int COUNT = -1, class V>
663
664// Dot product of the first COUNT elements. Count of -1 means "all".
665template <int COUNT = -1, class T, int N>
669
670// Cross Product (3 component)
671template <class T, int N>
672MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Cross3(Simd<T, N> a, Simd<T, N> b);
673
674// Compute the square of the norm using the first COUNT elements of a Simd vector. A count of -1
675// means "all". The result will be broadcasted to a new vector. Use NormSqr instead if you want a
676// scalar result.
677template <int COUNT = -1, class T, int N>
678MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> VNormSqr(Simd<T, N> a);
679
680// Compute the norm using the first COUNT elements of a Simd vector. A count of -1 means "all". The
681// result will be broadcasted to a new vector. Use Norm instead if you want a scalar result.
682template <int COUNT = -1, class T, int N>
683MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> VNorm(Simd<T, N> a);
684
685// Compute the square of the norm using the first COUNT elements of a Simd vector. A count of -1
686// means "all".
687template <int COUNT = -1, class T, int N>
688MOCHI_ANY MOCHI_FORCE_INLINE T NormSqr(Simd<T, N> a);
689
690// Compute the norm using the first COUNT elements of a Simd vector. Count of -1 means "all".
691template <int COUNT = -1, class T, int N>
692MOCHI_ANY MOCHI_FORCE_INLINE T Norm(Simd<T, N> a);
693
694// Normalizes Simd<T, N> elements introducing an epsilon term (to avoid divide-by-zero).
695// Returns (x / (√n₀ + ε), y / (√n₁ + ε), z / (√n₂ + ε), w / (√n₃ + ε))
696template <int COUNT = -1, class T, int N>
697[[nodiscard]] MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Normalize(Simd<T, N> a);
698
699// Use this overload if you have the square of the norm as a Simd vector.
700template <class T, int N>
701[[nodiscard]] MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Normalize(Simd<T, N> a, Simd<T, N> normSqr);
702
703// Use this overload if you have the square of the norm as a scalar.
704template <class T, int N>
705[[nodiscard]] MOCHI_ANY MOCHI_FORCE_INLINE Simd<T, N> Normalize(Simd<T, N> a, T normSqr);
706
707// Builds an arbitrary vector that is orthogonal to the given one.
708template <typename T, int N>
710
711} // namespace superdex
712
713#include "simd/simd_inl.h"
Simd operator-(Simd rhs) const
Simd(NativeType rhs)
Definition simd.h:112
Simd operator&(Simd rhs) const
Simd & operator^=(Simd rhs)
Simd & operator&=(Simd rhs)
Simd & operator/=(T rhs)
bool operator==(Simd rhs) const
Simd operator&&(Simd rhs) const
Simd operator>(Simd rhs) const
Simd operator<<(int shift) const
Simd operator*(Simd rhs) const
Simd & operator-=(T rhs)
Simd operator^(Simd rhs) const
Simd operator-() const
Simd & operator=(Scalar rhs)
Simd & operator-=(Simd rhs)
Simd(Scalar a, Scalar b, Ts... vals)
Simd(Scalar a)
Simd(Simd const &rhs)=default
Simd operator||(Simd rhs) const
Simd operator>=(Simd rhs) const
static constexpr bool kIsComposite
Definition simd.h:98
Simd operator<(Simd rhs) const
Simd & operator*=(T rhs)
Simd & operator|=(Simd rhs)
bool operator!=(Simd rhs) const
Simd & operator*=(Simd rhs)
static constexpr size_t size()
Definition simd.h:122
static constexpr bool kIsEmulated
Definition simd.h:99
Simd & operator=(Simd rhs)
Simd operator|(Simd rhs) const
static constexpr int kSize
Definition simd.h:96
Simd operator+(Simd rhs) const
static constexpr bool kIsSupported
Definition simd.h:97
NotSupported NativeType
Definition simd.h:94
Simd & operator+=(T rhs)
Simd operator~() const
Simd operator/(Simd rhs) const
Simd & operator/=(Simd rhs)
Simd operator<=(Simd rhs) const
Simd & operator+=(Simd rhs)
Scalar operator[](int i) const
#define MOCHI_SIMD_REGISTER_SIZE_BYTES
#define MOCHI_FORCE_INLINE
#define MOCHI_ANY
T Dot(Simd< T, N > a, Simd< T, N > b)
Definition simd.h:666
constexpr T ACos(T a)
Simd< T, N > VIsFinite(Simd< T, N > a)
Definition simd_inl.h:755
Simd< T, 2 > Shuffle(Simd< T, 2 > a)
Definition simd_inl.h:270
constexpr int kSimdDefaultSize
Definition simd.h:33
V LoadIndexed(typename V::Scalar const *ptr, Simd< I, V::kSize > indices)
Definition simd_inl.h:200
constexpr T const & Min(T const &a, T const &b)
Simd< int, 4 > Vec4i
Definition simd.h:204
T NormSqr(Simd< T, N > a)
Definition simd_inl.h:849
constexpr auto Equal(T const &a, T const &b)
Simd< T, N > Cross3(Simd< T, N > a, Simd< T, N > b)
Definition simd_inl.h:832
constexpr T Sin(T a)
T HSum(Simd< T, N > a)
Definition simd_inl.h:379
constexpr To StaticCast(From const &a)
Definition basic_utils.h:79
constexpr T kDefaultNearEqualEpsilon
V VDot(V a, V b)
Definition simd_inl.h:826
T HMin(Simd< T, N > a)
Definition simd_inl.h:391
T Norm(Simd< T, N > a)
Definition simd_inl.h:854
bool AllTrue(T const &a)
Definition basic_utils.h:60
constexpr auto MulAdd(A a, B b, C c)
V SimdBasisVector()
Definition simd_inl.h:151
Simd< T, N > Tanh(Simd< T, N > a)
Definition simd_inl.h:688
Simd< int64_t, 2 > Vec2l
Definition simd.h:201
V VEqual(V a, V b)
Definition simd_inl.h:700
V ToSimdDirection(V a)
Definition simd_inl.h:179
Simd< T, N > Set(Simd< T, N > a, T value)
Definition simd_inl.h:315
V Sequence()
Definition simd_inl.h:325
Simd< double, 8 > Vec8d
Definition simd.h:207
constexpr auto NotEqual(T const &a, T const &b)
constexpr T Exp(T a)
Simd< real, 4 > Vec4r
Definition simd.h:206
constexpr T Cos(T a)
V VNearEqual(V a, V b, V epsilon)
Definition simd_inl.h:733
Simd< int, 8 > Vec8i
Definition simd.h:209
V SimdZero()
Definition simd_inl.h:146
T HMax(Simd< T, N > a)
Definition simd_inl.h:397
Simd< T, N > VNormSqr(Simd< T, N > a)
Definition simd_inl.h:837
int IsTrue(Simd< T, N > mask)
Definition simd_inl.h:796
Simd< int64_t, 4 > Vec4l
Definition simd.h:205
V Broadcast(typename V::Scalar a)
Definition simd_inl.h:115
constexpr T Abs(T a)
Definition basic_utils.h:50
V VNotEqual(V a, V b)
Definition simd_inl.h:705
constexpr auto MulSub(A a, B b, C c)
Simd< T, N > Normalize(Simd< T, N > a)
Definition simd_inl.h:859
Simd< real, 8 > Vec8r
Definition simd.h:211
Simd< float, 4 > Vec4f
Definition simd.h:203
Simd< T, N > Blend(Simd< T, N > a, Simd< T, N > b)
Definition simd_inl.h:285
constexpr T Tan(T a)
bool AnyTrue(T const &a)
Definition basic_utils.h:66
Simd< double, 4 > Vec4d
Definition simd.h:202
constexpr T Select(bool condition, T a, T b)
constexpr T Sqrt(T a)
constexpr T ATan(T a)
Simd< T, N > Ln(Simd< T, N > a)
Definition simd_inl.h:678
std::pair< Simd< T, N >, Simd< T, N > > SinCos(Simd< T, N > a)
Definition simd_inl.h:502
constexpr auto NegMulAdd(A a, B b, C c)
T Get(Simd< T, N > v)
Definition simd_inl.h:300
constexpr T Floor(T a)
constexpr T ASin(T a)
V SimdMask(bool b0, bool b1, MoreBools... bs)
Definition simd_inl.h:137
Simd< T, N/2 > GetHalf(Simd< T, N > a)
Definition simd_inl.h:310
T HProd(Simd< T, N > a)
Definition simd_inl.h:385
Simd< T, 4 > OrthogonalVector3(Simd< T, 4 > a)
T Get0(Simd< T, N > v)
Definition simd_inl.h:295
Simd< T, N > VNorm(Simd< T, N > a)
Definition simd_inl.h:844
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)
Definition simd_inl.h:207
Simd< T, N > FastRound(Simd< T, N > a)
Definition simd_inl.h:416
void StoreTransposed(T *ptr, Simd< T, N > a, Simd< T, N > b, Simd< T, N > c)
Definition simd_inl.h:245
void Store(T *ptr, Simd< T, N > a)
Definition simd_inl.h:213
Simd< T, N > RcpSqrtApprox(Simd< T, N > a)
Definition simd_inl.h:359
constexpr T RcpApprox(T a)
Simd< int64_t, 8 > Vec8l
Definition simd.h:210
bool NearEqual(TransformRT const &a, TransformRT const &b, real epsilon=kDefaultNearEqualEpsilon< real >)
constexpr auto NegMulSub(A a, B b, C c)
V VNearZero(V a, V epsilon)
Definition simd_inl.h:738
int StoreSelected(T *ptr, Simd< MaskT, N > condition, Simd< T, N > values)
Definition simd_inl.h:225
V Load(typename V::Scalar const *ptr)
Definition simd_inl.h:184
Simd< T, N > Neg(Simd< T, N > a)
Definition simd_inl.h:340
Simd< float, 8 > Vec8f
Definition simd.h:208
V ToSimdPoint(V a)
Definition simd_inl.h:174
Simd< double, 2 > Vec2d
Definition simd.h:200
bool IsFinite(TransformRT const &a)
constexpr auto NearZero(T const &a, T epsilon=kDefaultNearEqualEpsilon< T >)
Simd< T, N > ShiftRight(Simd< T, N > a)
Definition simd_inl.h:260