29#if defined(JPL_USE_SSE)
33#if defined (JPL_USE_SSE4_1)
36#elif defined(JPL_USE_NEON)
37#ifdef JPL_COMPILER_MSVC
39#include <arm64_neon.h>
59 struct [[nodiscard]] alignas(JPL_VECTOR_ALIGNMENT)
simd
62#if defined(JPL_USE_SSE)
64#elif defined(JPL_USE_NEON)
65 using Type = float32x4_t;
67 using Type = std::array<float, 4>;
72 simd& operator=(const
simd&) noexcept = default;
73 JPL_INLINE
simd(
Type value) noexcept : mNative(value) {}
74 JPL_INLINE
simd(
float value)
noexcept;
75 JPL_INLINE
simd(
float v0,
float v1,
float v2,
float v3)
noexcept;
76 JPL_INLINE
simd(
const float* mem);
80 static JPL_INLINE
simd gather(
const float* base,
const simd_mask& offsets);
83 static JPL_INLINE
simd zero() noexcept;
86 static JPL_INLINE
simd nan() noexcept;
88 static JPL_INLINE
simd inf() noexcept;
91 static JPL_INLINE
simd c_0() noexcept;
92 static JPL_INLINE
simd c_1() noexcept;
93 static JPL_INLINE
simd c_0p5() noexcept;
94 static JPL_INLINE
simd c_pi() noexcept;
97 static constexpr
std::
size_t size() noexcept {
return 4; }
100 JPL_INLINE
void load(
const float* mem);
103 JPL_INLINE
void store(
float* mem)
const;
106 JPL_INLINE
float operator [] (
uint32 index)
const noexcept;
109 template<u
int32 LaneIndex>
requires (LaneIndex < 4)
110 JPL_INLINE
float get_lane()
const noexcept;
113 JPL_INLINE
simd operator * (
const simd& other)
const noexcept;
116 JPL_INLINE
simd operator * (
float value)
const noexcept;
119 friend JPL_INLINE
simd operator * (
float value,
const simd& other)
noexcept;
122 JPL_INLINE
simd operator / (
float value)
const noexcept;
125 JPL_INLINE
simd& operator *= (
float value)
noexcept;
128 JPL_INLINE
simd& operator *= (
const simd& other)
noexcept;
131 JPL_INLINE
simd& operator /= (
float value)
noexcept;
134 JPL_INLINE
simd& operator /= (
const simd& other)
noexcept;
137 JPL_INLINE
simd operator + (
const simd& other)
const noexcept;
140 JPL_INLINE
simd& operator += (
const simd& other)
noexcept;
143 JPL_INLINE
simd operator - () const noexcept;
146 JPL_INLINE
simd operator - (const
simd& other) const noexcept;
149 JPL_INLINE
simd& operator -= (const
simd& other) noexcept;
152 JPL_INLINE
simd operator / (const
simd& other) const noexcept;
155 JPL_INLINE
void operator |= (const
simd& other) noexcept;
158 JPL_INLINE
void operator ^= (const
simd& other) noexcept;
161 JPL_INLINE
void operator &= (const
simd& other) noexcept;
164 template<
uint32 LaneIndex> requires (LaneIndex < 4)
165 JPL_INLINE
simd splat() const;
168 JPL_INLINE
float reduce() const noexcept;
171 JPL_INLINE
float reduce_max() const noexcept;
174 JPL_INLINE
float reduce_min() const noexcept;
177 JPL_INLINE
float reduce_mean() const noexcept {
return reduce() * 0.25f; };
179 JPL_INLINE
operator Type() const noexcept {
return mNative; }
182 JPL_INLINE
simd_mask to_mask() const noexcept;
185 JPL_INLINE
simd_mask as_mask() const noexcept;
191 static JPL_INLINE
simd reciprocal(const
simd& vec) noexcept;
193 inline friend
std::ostream& operator << (
std::ostream& inStream, const
simd& vec)
197 inStream << data[0] <<
", " << data[1] <<
", " << data[2] <<
", " << data[3];
203 static_assert(std::is_trivial<simd>(),
"simd supposed to be a trivial type.");
206 struct [[nodiscard]] alignas(JPL_VECTOR_ALIGNMENT)
simd_mask
209#if defined(JPL_USE_SSE)
210 using Type = __m128i;
211#elif defined(JPL_USE_NEON)
212 using Type = uint32x4_t;
214 using Type = std::array<uint32,4>;
225 static JPL_INLINE
simd_mask replicate(
int value)
noexcept;
228 static JPL_INLINE
simd_mask zero() noexcept;
231 static constexpr
std::
size_t size() noexcept {
return 4; }
234 inline static constexpr uint32 cTrueValue = 0xffffffffu;
237 JPL_INLINE
void load(
const uint32* mem);
240 JPL_INLINE
void store(
uint32* mem)
const;
243 template<u
int32 LaneIndex>
requires (LaneIndex < 4)
244 JPL_INLINE
uint32 get_lane()
const noexcept;
247 JPL_INLINE
bool all_of() const noexcept;
250 JPL_INLINE
bool any_of() const noexcept;
253 JPL_INLINE
bool none_of() const noexcept;
256 JPL_INLINE
int reduce_count() const noexcept;
259 JPL_INLINE
int reduce_min_index() const noexcept;
261 JPL_INLINE
int reduce_max_index() const noexcept;
264 JPL_INLINE
int GetTrues() const noexcept;
285 JPL_INLINE
simd_mask operator ~ () const noexcept;
288 JPL_INLINE
void operator |= (const
simd_mask& other) noexcept;
291 JPL_INLINE
void operator ^= (const
simd_mask& other) noexcept;
294 JPL_INLINE
void operator &= (const
simd_mask& other) noexcept;
299 template<
uint Count> requires(Count <= 31)
300 JPL_INLINE
simd_mask shr() const noexcept;
302 template<
uint Count> requires(Count <= 31)
303 JPL_INLINE
simd_mask shl() const noexcept;
305 template<
uint Count> requires(Count <= 31)
306 JPL_INLINE
simd_mask ashr() const noexcept;
311 JPL_INLINE operator
Type() const noexcept {
return mNative; };
314 JPL_INLINE
simd to_simd() const noexcept;
317 JPL_INLINE
simd as_simd() const noexcept;
319 inline friend
std::ostream& operator << (
std::ostream& inStream, const
simd_mask& vec)
323 inStream << data[0] <<
", " << data[1] <<
", " << data[2] <<
", " << data[3];
329 static_assert(std::is_trivial<simd_mask>(),
"simd_mask supposed to be a trivial type.");
343 JPL_INLINE simd_mask
operator < (
const simd& a,
const simd& b)
noexcept;
344 JPL_INLINE simd_mask
operator <= (
const simd& a,
const simd& b)
noexcept;
345 JPL_INLINE simd_mask
operator > (
const simd& a,
const simd& b)
noexcept;
346 JPL_INLINE simd_mask
operator >= (
const simd& a,
const simd& b)
noexcept;
349 JPL_INLINE simd_mask
operator == (
const simd_mask& a,
const simd_mask& b)
noexcept;
353 JPL_INLINE simd_mask
operator | (
const simd_mask& a,
const simd_mask& b)
noexcept;
355 JPL_INLINE simd_mask
operator ^ (
const simd_mask& a,
const simd_mask& b)
noexcept;
357 JPL_INLINE simd_mask
operator & (
const simd_mask& a,
const simd_mask& b)
noexcept;
363 [[nodiscard]] JPL_INLINE simd
Sqrt(
const simd& vec)
noexcept;
366 [[nodiscard]] JPL_INLINE simd
InvSqrt(
const simd& vec)
noexcept;
370 [[nodiscard]] JPL_INLINE simd
Sign2(
const simd& vec)
noexcept;
373 [[nodiscard]] JPL_INLINE simd_mask
IsNearlyZero(
const simd& vec,
float tolerance = JPL_FLOAT_EPS)
noexcept;
377 JPL_INLINE simd
max(
const simd& a,
const simd& b)
noexcept;
380 JPL_INLINE simd
min(
const simd& a,
const simd& b)
noexcept;
382 JPL_INLINE simd
abs(
const simd& vec)
noexcept;
385 JPL_INLINE simd
clamp(
const simd& value,
const simd& minV,
const simd& maxV)
noexcept;
388 JPL_INLINE simd
fma(
const simd& mul1,
const simd& mul2,
const simd& addV)
noexcept;
398 JPL_INLINE simd
floor(
const simd& vec)
noexcept;
401 JPL_INLINE simd
ceil(
const simd& vec)
noexcept;
404 JPL_INLINE simd
round(
const simd& vec)
noexcept;
410 JPL_INLINE simd
combine_lo(
const simd& a,
const simd& b)
noexcept;
413 JPL_INLINE simd
combine_hi(
const simd& a,
const simd& b)
noexcept;
416 JPL_INLINE simd
combine_lohi(
const simd& a,
const simd& b)
noexcept;
419 JPL_INLINE simd
reverse(
const simd& vec)
noexcept;
422 JPL_INLINE simd_mask
max(
const simd_mask& a,
const simd_mask& b)
noexcept;
425 JPL_INLINE simd_mask
min(
const simd_mask& a,
const simd_mask& b)
noexcept;
428 JPL_INLINE simd_mask
clamp(
const simd_mask& value,
const simd_mask& minV,
const simd_mask& maxV)
noexcept;
431 JPL_INLINE simd_mask
maxs(
const simd_mask& a,
const simd_mask& b)
noexcept;
434 JPL_INLINE simd_mask
mins(
const simd_mask& a,
const simd_mask& b)
noexcept;
437 JPL_INLINE simd_mask
clamps(
const simd_mask& value,
const simd_mask& minV,
const simd_mask& maxV)
noexcept;
443struct std::equal_to<
JPL::simd>
479#if defined(JPL_USE_SSE)
480 mNative = _mm_set1_ps(value);
481#elif defined(JPL_USE_NEON)
482 mNative = vdupq_n_f32(value);
491 JPL_INLINE
simd::simd(
float v0,
float v1,
float v2,
float v3)
noexcept
493#if defined(JPL_USE_SSE)
494 mNative = _mm_set_ps(v3, v2, v1, v0);
495#elif defined(JPL_USE_NEON)
496 mNative = vdupq_n_f32(0);
497 mNative = vsetq_lane_f32(v0, mNative, 0);
498 mNative = vsetq_lane_f32(v1, mNative, 1);
499 mNative = vsetq_lane_f32(v2, mNative, 2);
500 mNative = vsetq_lane_f32(v3, mNative, 3);
517#if defined(JPL_USE_SSE)
519 return _mm_i32gather_ps(inBase, offsets.
mNative, Scale);
521 const uint8* base =
reinterpret_cast<const uint8*
>(inBase);
522 Type x = _mm_load_ss(
reinterpret_cast<const float*
>(base + offsets.
get_lane<0>() * Scale));
523 Type y = _mm_load_ss(
reinterpret_cast<const float*
>(base + offsets.
get_lane<1>() * Scale));
524 Type xy = _mm_unpacklo_ps(x, y);
525 Type z = _mm_load_ss(
reinterpret_cast<const float*
>(base + offsets.
get_lane<2>() * Scale));
526 Type w = _mm_load_ss(
reinterpret_cast<const float*
>(base + offsets.
get_lane<3>() * Scale));
527 Type zw = _mm_unpacklo_ps(z, w);
528 return _mm_movelh_ps(xy, zw);
531 const uint8* base =
reinterpret_cast<const uint8*
>(inBase);
532 float x = *
reinterpret_cast<const float*
>(base + offsets.
get_lane<0>() * Scale);
533 float y = *
reinterpret_cast<const float*
>(base + offsets.
get_lane<1>() * Scale);
534 float z = *
reinterpret_cast<const float*
>(base + offsets.
get_lane<2>() * Scale);
535 float w = *
reinterpret_cast<const float*
>(base + offsets.
get_lane<3>() * Scale);
536 return { x, y, z, w };
543#if defined(JPL_USE_SSE)
544 return _mm_setzero_ps();
545#elif defined(JPL_USE_NEON)
546 return vdupq_n_f32(0);
548 return simd(0, 0, 0, 0);
554 return simd(std::numeric_limits<float>::quiet_NaN());
559 return simd(std::numeric_limits<float>::infinity());
564#if defined(JPL_USE_SSE)
566#elif defined(JPL_USE_NEON)
569 mNative = { mem[0], mem[1], mem[2], mem[3] };
575#if defined(JPL_USE_SSE)
577#elif defined(JPL_USE_NEON)
590#if defined(JPL_USE_SSE)
591#if defined(JPL_USE_AVX)
592 __m128i sel = _mm_set1_epi32(
static_cast<int>(index));
593 __m128 p = _mm_permutevar_ps(mNative, sel);
594 return _mm_cvtss_f32(p);
596 alignas(16)
float temp[4];
597 _mm_store_ps(temp, mNative);
600#elif defined(JPL_USE_NEON)
601 alignas(16)
float temp[4];
602 vst1q_f32(temp, mNative);
605 return mNative[index];
609 template<u
int32 LaneIndex>
requires (LaneIndex < 4)
612#if defined(JPL_USE_SSE)
613 return _mm_cvtss_f32(_mm_shuffle_ps(mNative, mNative, _MM_SHUFFLE(0, 0, 0, LaneIndex)));
614#elif defined(JPL_USE_NEON)
615 return vgetq_lane_f32(mNative, LaneIndex);
617 return mNative[LaneIndex];
623#if defined(JPL_USE_SSE)
624 return _mm_mul_ps(mNative, other.mNative);
625#elif defined(JPL_USE_NEON)
626 return vmulq_f32(mNative, other.mNative);
629 mNative[0] * other.mNative[0],
630 mNative[1] * other.mNative[1],
631 mNative[2] * other.mNative[2],
632 mNative[3] * other.mNative[3]
639#if defined(JPL_USE_SSE)
640 return _mm_mul_ps(mNative, _mm_set1_ps(value));
641#elif defined(JPL_USE_NEON)
642 return vmulq_n_f32(mNative, value);
644 return simd(mNative[0] * value, mNative[1] * value, mNative[2] * value, mNative[3] * value);
650#if defined(JPL_USE_SSE)
651 return _mm_mul_ps(_mm_set1_ps(value), vec.mNative);
652#elif defined(JPL_USE_NEON)
653 return vmulq_n_f32(vec.mNative, value);
656 value * vec.mNative[0],
657 value * vec.mNative[1],
658 value * vec.mNative[2],
659 value * vec.mNative[3]
666#if defined(JPL_USE_SSE)
667 return _mm_div_ps(mNative, _mm_set1_ps(value));
668#elif defined(JPL_USE_NEON)
669 return vdivq_f32(mNative, vdupq_n_f32(value));
682#if defined(JPL_USE_SSE)
683 mNative = _mm_mul_ps(mNative, _mm_set1_ps(value));
684#elif defined(JPL_USE_NEON)
685 mNative = vmulq_n_f32(mNative, value);
687 for (
int i = 0; i < 4; ++i)
695#if defined(JPL_USE_SSE)
696 mNative = _mm_mul_ps(mNative, other.mNative);
697#elif defined(JPL_USE_NEON)
698 mNative = vmulq_f32(mNative, other.mNative);
700 for (
int i = 0; i < 4; ++i)
701 mNative[i] *= other.mNative[i];
708#if defined(JPL_USE_SSE)
709 mNative = _mm_div_ps(mNative, _mm_set1_ps(value));
710#elif defined(JPL_USE_NEON)
711 mNative = vdivq_f32(mNative, vdupq_n_f32(value));
713 for (
int i = 0; i < 4; ++i)
721#if defined(JPL_USE_SSE)
722 mNative = _mm_div_ps(mNative, other);
723#elif defined(JPL_USE_NEON)
724 mNative = vdivq_f32(mNative, other);
726 for (
int i = 0; i < 4; ++i)
727 mNative[i] /= other.mNative[i];
734#if defined(JPL_USE_SSE)
735 return _mm_add_ps(mNative, other.mNative);
736#elif defined(JPL_USE_NEON)
737 return vaddq_f32(mNative, other.mNative);
740 mNative[0] + other.mNative[0],
741 mNative[1] + other.mNative[1],
742 mNative[2] + other.mNative[2],
743 mNative[3] + other.mNative[3]
750#if defined(JPL_USE_SSE)
751 mNative = _mm_add_ps(mNative, other.mNative);
752#elif defined(JPL_USE_NEON)
753 mNative = vaddq_f32(mNative, other.mNative);
755 for (
int i = 0; i < 4; ++i)
756 mNative[i] += other.mNative[i];
763#if defined(JPL_USE_SSE)
764 return _mm_sub_ps(_mm_setzero_ps(),
mNative);
765#elif defined(JPL_USE_NEON)
767 return vsubq_f32(vdupq_n_f32(0),
mNative);
787#if defined(JPL_USE_SSE)
788 return _mm_sub_ps(mNative, other.mNative);
789#elif defined(JPL_USE_NEON)
790 return vsubq_f32(mNative, other.mNative);
793 mNative[0] - other.mNative[0],
794 mNative[1] - other.mNative[1],
795 mNative[2] - other.mNative[2],
796 mNative[3] - other.mNative[3]
803#if defined(JPL_USE_SSE)
804 mNative = _mm_sub_ps(mNative, other.mNative);
805#elif defined(JPL_USE_NEON)
806 mNative = vsubq_f32(mNative, other.mNative);
808 for (
int i = 0; i < 4; ++i)
809 mNative[i] -= other.mNative[i];
816#if defined(JPL_USE_SSE)
817 return _mm_div_ps(mNative, other.mNative);
818#elif defined(JPL_USE_NEON)
819 return vdivq_f32(mNative, other.mNative);
822 mNative[0] / other.mNative[0],
823 mNative[1] / other.mNative[1],
824 mNative[2] / other.mNative[2],
825 mNative[3] / other.mNative[3]
832#if defined(JPL_USE_SSE)
833 mNative = _mm_or_ps(mNative, other.mNative);
834#elif defined(JPL_USE_NEON)
835 mNative = vreinterpretq_f32_u32(
837 vreinterpretq_u32_f32(mNative),
838 vreinterpretq_u32_f32(other.mNative)
842 *
this = (as_mask() | other.as_mask()).as_simd();
848#if defined(JPL_USE_SSE)
849 mNative = _mm_xor_ps(mNative, other.mNative);
850#elif defined(JPL_USE_NEON)
851 mNative = vreinterpretq_f32_u32(
853 vreinterpretq_u32_f32(mNative),
854 vreinterpretq_u32_f32(other.mNative)
858 *
this = (as_mask() ^ other.as_mask()).as_simd();
864#if defined(JPL_USE_SSE)
865 mNative = _mm_and_ps(mNative, other.mNative);
866#elif defined(JPL_USE_NEON)
867 mNative = vreinterpretq_f32_u32(
869 vreinterpretq_u32_f32(mNative),
870 vreinterpretq_u32_f32(other.mNative)
874 *
this = (as_mask() & other.as_mask()).as_simd();
880#if defined(JPL_USE_SSE)
881 return _mm_or_ps(a.mNative, b.mNative);
882#elif defined(JPL_USE_NEON)
883 return vreinterpretq_f32_u32(
885 vreinterpretq_u32_f32(a.mNative),
886 vreinterpretq_u32_f32(b.mNative)
890 return (a.as_mask() | b.as_mask()).as_simd();
896#if defined(JPL_USE_SSE)
897 return _mm_xor_ps(a.mNative, b.mNative);
898#elif defined(JPL_USE_NEON)
899 return vreinterpretq_f32_u32(
901 vreinterpretq_u32_f32(a.mNative),
902 vreinterpretq_u32_f32(b.mNative)
906 return (a.as_mask() ^ b.as_mask()).as_simd();
912#if defined(JPL_USE_SSE)
913 return _mm_and_ps(a.mNative, b.mNative);
914#elif defined(JPL_USE_NEON)
915 return vreinterpretq_f32_u32(
917 vreinterpretq_u32_f32(a.mNative),
918 vreinterpretq_u32_f32(b.mNative)
922 return (a.as_mask() & b.as_mask()).as_simd();
926 template<u
int32 LaneIndex>
requires(LaneIndex < 4)
929#if defined(JPL_USE_SSE)
930 return _mm_shuffle_ps(mNative, mNative, _MM_SHUFFLE(LaneIndex, LaneIndex, LaneIndex, LaneIndex));
931#elif defined(JPL_USE_NEON)
932 return vdupq_laneq_f32(mNative, LaneIndex);
934 return { mNative[LaneIndex], mNative[LaneIndex], mNative[LaneIndex], mNative[LaneIndex] };
940#if defined(JPL_USE_SSE)
943 shuf = _mm_movehl_ps(shuf, sums);
944 sums = _mm_add_ss(sums, shuf);
945 return _mm_cvtss_f32(sums);
946#elif defined (JPL_USE_NEON)
955#if defined(JPL_USE_SSE)
958 Type shuf2 = _mm_shuffle_ps(max1, max1, _MM_SHUFFLE(1, 0, 3, 2));
959 max1 = _mm_max_ps(max1, shuf2);
960 return _mm_cvtss_f32(max1);
961#elif defined (JPL_USE_NEON)
962 float32x2_t v_pair = vpmax_f32(vget_low_f32(
mNative), vget_high_f32(
mNative));
963 float32x2_t max_pair = vpmax_f32(v_pair, v_pair);
964 return vget_lane_f32(max_pair, 0);
972#if defined(JPL_USE_SSE)
975 Type shuf2 = _mm_shuffle_ps(min1, min1, _MM_SHUFFLE(1, 0, 3, 2));
976 min1 = _mm_min_ps(min1, shuf2);
977 return _mm_cvtss_f32(min1);
978#elif defined (JPL_USE_NEON)
979 float32x2_t v_pair = vpmin_f32(vget_low_f32(
mNative), vget_high_f32(
mNative));
980 float32x2_t min_pair = vpmin_f32(v_pair, v_pair);
981 return vget_lane_f32(min_pair, 0);
989#if defined(JPL_USE_SSE)
990 return _mm_cvttps_epi32(
mNative);
991#elif defined(JPL_USE_NEON)
993 auto _sse2neon_cvtps_epi32_fixup = [](float32x4_t f, int32x4_t cvt)
996 float32x4_t max_f = vdupq_n_f32(2147483648.0f);
997 uint32x4_t overflow = vcgeq_f32(f, max_f);
1000 uint32x4_t is_nan = vmvnq_u32(vceqq_f32(f, f));
1003 uint32x4_t need_indefinite = vorrq_u32(overflow, is_nan);
1006 int32x4_t indefinite = vdupq_n_s32(INT32_MIN);
1007 return vbslq_s32(need_indefinite, indefinite, cvt);
1010 int32x4_t cvt = vcvtq_s32_f32(
mNative);
1011 return vreinterpretq_u32_s32(_sse2neon_cvtps_epi32_fixup(
mNative, cvt));
1025#if defined(JPL_USE_SSE)
1026 return _mm_castps_si128(
mNative);
1027#elif defined(JPL_USE_NEON)
1028 return vreinterpretq_u32_f32(
mNative);
1030 return std::bit_cast<simd_mask>(*
this);
1036#if defined(JPL_USE_SSE4_1)
1037 return _mm_blendv_ps(b.mNative, a.mNative, _mm_castsi128_ps(mask.mNative));
1038#elif defined(JPL_USE_SSE)
1039 Type mf = _mm_castsi128_ps(mask.mNative);
1040 Type t0 = _mm_andnot_ps(mf, b.mNative);
1041 Type t1 = _mm_and_ps(mf, a.mNative);
1042 return _mm_or_ps(t0, t1);
1043#elif defined(JPL_USE_NEON)
1045 vreinterpretq_u32_s32(vshrq_n_s32(vreinterpretq_s32_u32(mask.mNative), 31)),
1050 mask.mNative[0] ? a.mNative[0] : b.mNative[0],
1051 mask.mNative[1] ? a.mNative[1] : b.mNative[1],
1052 mask.mNative[2] ? a.mNative[2] : b.mNative[2],
1053 mask.mNative[3] ? a.mNative[3] : b.mNative[3]
1060 return simd(1.0f) / vec;
1066#if defined(JPL_USE_SSE)
1067 mNative = _mm_set1_epi32(
static_cast<int>(value));
1068#elif defined(JPL_USE_NEON)
1069 mNative = vdupq_n_u32(value);
1080#if defined(JPL_USE_SSE)
1081 mNative = _mm_set_epi32(
1082 static_cast<int>(v3),
1083 static_cast<int>(v2),
1084 static_cast<int>(v1),
1085 static_cast<int>(v0)
1087#elif defined(JPL_USE_NEON)
1088 mNative = vdupq_n_u32(0);
1089 mNative = vsetq_lane_u32(v0, mNative, 0);
1090 mNative = vsetq_lane_u32(v1, mNative, 1);
1091 mNative = vsetq_lane_u32(v2, mNative, 2);
1092 mNative = vsetq_lane_u32(v3, mNative, 3);
1108#if defined(JPL_USE_NEON)
1109 return vreinterpretq_u32_s32(vdupq_n_s32(value));
1123#if defined(JPL_USE_SSE)
1124 return _mm_setzero_si128();
1125#elif defined(JPL_USE_NEON)
1126 return vdupq_n_u32(0);
1134#if defined(JPL_USE_SSE)
1136#elif defined(JPL_USE_NEON)
1139 mNative = { mem[0], mem[1], mem[2], mem[3] };
1145#if defined(JPL_USE_SSE)
1147#elif defined(JPL_USE_NEON)
1157 template<u
int32 LaneIndex>
requires (LaneIndex < 4)
1160#if defined(JPL_USE_SSE)
1161 return static_cast<uint32>(_mm_cvtsi128_si32(_mm_shuffle_epi32(mNative, _MM_SHUFFLE(0, 0, 0, LaneIndex))));
1162#elif defined(JPL_USE_NEON)
1163 return vgetq_lane_u32(mNative, LaneIndex);
1165 return mNative[LaneIndex];
1186#if defined(JPL_USE_SSE)
1187 return std::popcount(
static_cast<uint32>(_mm_movemask_ps(_mm_castsi128_ps(
mNative))));
1188#elif defined(JPL_USE_NEON)
1189 return vaddvq_u32(vshrq_n_u32(
mNative, 31));
1199 return m ?
static_cast<int>(std::countr_zero(m)) : -1;
1206 return 31 -
static_cast<int>(std::countl_zero(m));
1211#if defined(JPL_USE_SSE)
1212 return _mm_movemask_ps(_mm_castsi128_ps(
mNative));
1213#elif defined(JPL_USE_NEON)
1214 static_assert(JPL_CPU_ADDRESS_BITS == 64 &&
"32-bit arm doesn't support this.");
1215 uint32x4_t bits = vshrq_n_u32(
mNative, 31);
1216#if defined(JPL_COMPILER_MSVC)
1217 const uint32x4_t w = { .n128_u32 = { 1u, 2u, 4u, 8u } };
1219 const uint32x4_t w = { 1u, 2u, 4u, 8u };
1221 return static_cast<int>(vaddvq_u32(vmulq_u32(bits, w)));
1232#if defined(JPL_USE_SSE4_1)
1233 return _mm_mullo_epi32(mNative, other.mNative);
1234#elif defined(JPL_USE_SSE)
1235 Type tmp1 = _mm_mul_epu32(mNative, other.mNative);
1236 Type tmp2 = _mm_mul_epu32(_mm_srli_si128(mNative, 4), _mm_srli_si128(other.mNative, 4));
1237 return _mm_unpacklo_epi32(
1238 _mm_shuffle_epi32(tmp1, _MM_SHUFFLE(0, 0, 2, 0)),
1239 _mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 2, 0))
1241#elif defined(JPL_USE_NEON)
1242 return vmulq_u32(mNative, other.mNative);
1245 mNative[0] * other.mNative[0],
1246 mNative[1] * other.mNative[1],
1247 mNative[2] * other.mNative[2],
1248 mNative[3] * other.mNative[3]
1255#if defined(JPL_USE_SSE4_1)
1256 mNative = _mm_mullo_epi32(mNative, other.mNative);
1257#elif defined(JPL_USE_SSE)
1258 Type tmp1 = _mm_mul_epu32(mNative, other.mNative);
1259 Type tmp2 = _mm_mul_epu32(_mm_srli_si128(mNative, 4), _mm_srli_si128(other.mNative, 4));
1260 mNative = _mm_unpacklo_epi32(
1261 _mm_shuffle_epi32(tmp1, _MM_SHUFFLE(0, 0, 2, 0)),
1262 _mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 2, 0))
1264#elif defined(JPL_USE_NEON)
1265 mNative = vmulq_u32(mNative, other.mNative);
1267 mNative[0] *= other.mNative[0];
1268 mNative[1] *= other.mNative[1];
1269 mNative[2] *= other.mNative[2];
1270 mNative[3] *= other.mNative[3];
1277#if defined(JPL_USE_SSE)
1278 return _mm_add_epi32(mNative, other.mNative);
1279#elif defined(JPL_USE_NEON)
1280 return vaddq_u32(mNative, other.mNative);
1283 mNative[0] + other.mNative[0],
1284 mNative[1] + other.mNative[1],
1285 mNative[2] + other.mNative[2],
1286 mNative[3] + other.mNative[3]
1293#if defined(JPL_USE_SSE)
1294 mNative = _mm_add_epi32(mNative, other.mNative);
1295#elif defined(JPL_USE_NEON)
1296 mNative = vaddq_u32(mNative, other.mNative);
1298 mNative[0] += other.mNative[0];
1299 mNative[1] += other.mNative[1];
1300 mNative[2] += other.mNative[2];
1301 mNative[3] += other.mNative[3];
1308#if defined(JPL_USE_SSE)
1309 return _mm_sub_epi32(mNative, other.mNative);
1310#elif defined(JPL_USE_NEON)
1311 return vsubq_u32(mNative, other.mNative);
1314 mNative[0] - other.mNative[0],
1315 mNative[1] - other.mNative[1],
1316 mNative[2] - other.mNative[2],
1317 mNative[3] - other.mNative[3]
1324#if defined(JPL_USE_SSE)
1326 mNative = _mm_sub_epi32(mNative, other.mNative);
1327#elif defined(JPL_USE_NEON)
1328 mNative = vsubq_u32(mNative, other.mNative);
1330 mNative[0] -= other.mNative[0];
1331 mNative[1] -= other.mNative[1];
1332 mNative[2] -= other.mNative[2];
1333 mNative[3] -= other.mNative[3];
1340#if defined(JPL_USE_SSE)
1341 return _mm_castps_si128(_mm_cmpeq_ps(a.mNative, b.mNative));
1342#elif defined(JPL_USE_NEON)
1343 return vceqq_f32(a.mNative, b.mNative);
1346 a.mNative[0] == b.mNative[0] ? cTrueValue : 0,
1347 a.mNative[1] == b.mNative[1] ? cTrueValue : 0,
1348 a.mNative[2] == b.mNative[2] ? cTrueValue : 0,
1349 a.mNative[3] == b.mNative[3] ? cTrueValue : 0
1356#if defined(JPL_USE_SSE)
1357 return _mm_castps_si128(_mm_cmplt_ps(a.mNative, b.mNative));
1358#elif defined(JPL_USE_NEON)
1359 return vcltq_f32(a.mNative, b.mNative);
1362 a.mNative[0] < b.mNative[0] ? cTrueValue : 0,
1363 a.mNative[1] < b.mNative[1] ? cTrueValue : 0,
1364 a.mNative[2] < b.mNative[2] ? cTrueValue : 0,
1365 a.mNative[3] < b.mNative[3] ? cTrueValue : 0
1372#if defined(JPL_USE_SSE)
1373 return _mm_castps_si128(_mm_cmple_ps(a.mNative, b.mNative));
1374#elif defined(JPL_USE_NEON)
1375 return vcleq_f32(a.mNative, b.mNative);
1378 a.mNative[0] <= b.mNative[0] ? cTrueValue : 0,
1379 a.mNative[1] <= b.mNative[1] ? cTrueValue : 0,
1380 a.mNative[2] <= b.mNative[2] ? cTrueValue : 0,
1381 a.mNative[3] <= b.mNative[3] ? cTrueValue : 0
1388#if defined(JPL_USE_SSE)
1389 return _mm_castps_si128(_mm_cmpgt_ps(a.mNative, b.mNative));
1390#elif defined(JPL_USE_NEON)
1391 return vcgtq_f32(a.mNative, b.mNative);
1394 a.mNative[0] > b.mNative[0] ? cTrueValue : 0,
1395 a.mNative[1] > b.mNative[1] ? cTrueValue : 0,
1396 a.mNative[2] > b.mNative[2] ? cTrueValue : 0,
1397 a.mNative[3] > b.mNative[3] ? cTrueValue : 0
1404#if defined(JPL_USE_SSE)
1405 return _mm_castps_si128(_mm_cmpge_ps(a.mNative, b.mNative));
1406#elif defined(JPL_USE_NEON)
1407 return vcgeq_f32(a.mNative, b.mNative);
1410 a.mNative[0] >= b.mNative[0] ? cTrueValue : 0,
1411 a.mNative[1] >= b.mNative[1] ? cTrueValue : 0,
1412 a.mNative[2] >= b.mNative[2] ? cTrueValue : 0,
1413 a.mNative[3] >= b.mNative[3] ? cTrueValue : 0
1420#if defined(JPL_USE_SSE)
1421 return _mm_cmpeq_epi32(a.mNative, b.mNative);
1422#elif defined(JPL_USE_NEON)
1423 return vceqq_u32(a.mNative, b.mNative);
1426 a.mNative[0] == b.mNative[0] ? cTrueValue : 0,
1427 a.mNative[1] == b.mNative[1] ? cTrueValue : 0,
1428 a.mNative[2] == b.mNative[2] ? cTrueValue : 0,
1429 a.mNative[3] == b.mNative[3] ? cTrueValue : 0
1436#if defined(JPL_USE_AVX512)
1438#elif defined(JPL_USE_SSE)
1440#elif defined(JPL_USE_NEON)
1443 return { ~mNative[0], ~mNative[1], ~mNative[2], ~mNative[3] };
1449#if defined(JPL_USE_SSE)
1450 mNative = _mm_or_si128(mNative, other.mNative);
1451#elif defined(JPL_USE_NEON)
1452 mNative = vorrq_u32(mNative, other.mNative);
1454 mNative[0] |= other.mNative[0];
1455 mNative[1] |= other.mNative[1];
1456 mNative[2] |= other.mNative[2];
1457 mNative[3] |= other.mNative[3];
1463#if defined(JPL_USE_SSE)
1464 mNative = _mm_xor_si128(mNative, other.mNative);
1465#elif defined(JPL_USE_NEON)
1466 mNative = veorq_u32(mNative, other.mNative);
1468 mNative[0] ^= other.mNative[0];
1469 mNative[1] ^= other.mNative[1];
1470 mNative[2] ^= other.mNative[2];
1471 mNative[3] ^= other.mNative[3];
1477#if defined(JPL_USE_SSE)
1478 mNative = _mm_and_si128(mNative, other.mNative);
1479#elif defined(JPL_USE_NEON)
1480 mNative = vandq_u32(mNative, other.mNative);
1482 mNative[0] &= other.mNative[0];
1483 mNative[1] &= other.mNative[1];
1484 mNative[2] &= other.mNative[2];
1485 mNative[3] &= other.mNative[3];
1492#if defined(JPL_USE_SSE)
1493 __m128i c = _mm_cvtsi32_si128(
static_cast<int>(count));
1494 return _mm_srl_epi32(mNative, c);
1495#elif defined(JPL_USE_NEON)
1496 int32x4_t sh = vdupq_n_s32(-
static_cast<int32_t
>(count));
1497 return vshlq_u32(mNative, sh);
1500 mNative[0] >> count,
1501 mNative[1] >> count,
1502 mNative[2] >> count,
1511#if defined(JPL_USE_SSE)
1512 __m128i c = _mm_cvtsi32_si128(
static_cast<int>(count));
1513 return _mm_sll_epi32(mNative, c);
1514#elif defined(JPL_USE_NEON)
1515 int32x4_t sh = vdupq_n_s32(
static_cast<int32_t
>(count));
1516 return vshlq_u32(mNative, sh);
1519 mNative[0] << count,
1520 mNative[1] << count,
1521 mNative[2] << count,
1527 template<u
int Count>
requires(Count <= 31)
1530#if defined(JPL_USE_SSE)
1531 return _mm_srli_epi32(mNative, Count);
1532#elif defined(JPL_USE_NEON)
1533 return vshrq_n_u32(mNative, Count);
1536 mNative[0] >> Count,
1537 mNative[1] >> Count,
1538 mNative[2] >> Count,
1544 template<u
int Count>
requires(Count <= 31)
1547#if defined(JPL_USE_SSE)
1548 return _mm_slli_epi32(mNative, Count);
1549#elif defined(JPL_USE_NEON)
1550 return vshlq_n_u32(mNative, Count);
1553 mNative[0] << Count,
1554 mNative[1] << Count,
1555 mNative[2] << Count,
1561 template<u
int Count>
requires(Count <= 31)
1564#if defined(JPL_USE_SSE)
1565 return _mm_srai_epi32(mNative, Count);
1566#elif defined(JPL_USE_NEON)
1567 return vreinterpretq_u32_s32(vshrq_n_s32(vreinterpretq_s32_u32(mNative), Count));
1570 static_cast<uint32>(
static_cast<int32>(mNative[0]) >> Count),
1571 static_cast<uint32>(
static_cast<int32>(mNative[1]) >> Count),
1572 static_cast<uint32>(
static_cast<int32>(mNative[2]) >> Count),
1573 static_cast<uint32>(
static_cast<int32>(mNative[3]) >> Count)
1580#if defined(JPL_USE_SSE)
1581 return _mm_add_epi32(mNative, other.mNative);
1582#elif defined(JPL_USE_NEON)
1583 return vreinterpretq_u32_s32(vaddq_s32(
1584 vreinterpretq_s32_u32(mNative),
1585 vreinterpretq_s32_u32(other.mNative)));
1587 return simd_mask(mNative[0] + other.mNative[0],
1588 mNative[1] + other.mNative[1],
1589 mNative[2] + other.mNative[2],
1590 mNative[3] + other.mNative[3]);
1596#if defined(JPL_USE_SSE)
1597 return _mm_sub_epi32(mNative, other.mNative);
1598#elif defined(JPL_USE_NEON)
1599 return vreinterpretq_u32_s32(vsubq_s32(
1600 vreinterpretq_s32_u32(mNative),
1601 vreinterpretq_s32_u32(other.mNative)));
1603 return simd_mask(mNative[0] - other.mNative[0],
1604 mNative[1] - other.mNative[1],
1605 mNative[2] - other.mNative[2],
1606 mNative[3] - other.mNative[3]);
1612#if defined(JPL_USE_SSE)
1613 return _mm_cvtepi32_ps(
mNative);
1614#elif defined(JPL_USE_NEON)
1615 return vcvtq_f32_s32(vreinterpretq_s32_u32(
mNative));
1619 static_cast<float>(mU32[0]),
1620 static_cast<float>(mU32[1]),
1621 static_cast<float>(mU32[2]),
1622 static_cast<float>(mU32[3])
1629#if defined(JPL_USE_SSE)
1630 return _mm_castsi128_ps(
mNative);
1631#elif defined(JPL_USE_NEON)
1632 return vreinterpretq_f32_u32(
mNative);
1634 return std::bit_cast<simd>(*
this);
1640#if defined(JPL_USE_SSE)
1641 return _mm_or_si128(a.mNative, b.mNative);
1642#elif defined(JPL_USE_NEON)
1643 return vorrq_u32(a.mNative, b.mNative);
1646 a.mNative[0] | b.mNative[0],
1647 a.mNative[1] | b.mNative[1],
1648 a.mNative[2] | b.mNative[2],
1649 a.mNative[3] | b.mNative[3]
1656#if defined(JPL_USE_SSE)
1657 return _mm_xor_si128(a.mNative, b.mNative);
1658#elif defined(JPL_USE_NEON)
1659 return veorq_u32(a.mNative, b.mNative);
1662 a.mNative[0] ^ b.mNative[0],
1663 a.mNative[1] ^ b.mNative[1],
1664 a.mNative[2] ^ b.mNative[2],
1665 a.mNative[3] ^ b.mNative[3]
1672#if defined(JPL_USE_SSE)
1673 return _mm_and_si128(a.mNative, b.mNative);
1674#elif defined(JPL_USE_NEON)
1675 return vandq_u32(a.mNative, b.mNative);
1678 a.mNative[0] & b.mNative[0],
1679 a.mNative[1] & b.mNative[1],
1680 a.mNative[2] & b.mNative[2],
1681 a.mNative[3] & b.mNative[3]
1691#if defined(JPL_USE_SSE)
1692 return _mm_sqrt_ps(vec.mNative);
1693#elif defined(JPL_USE_NEON)
1694 return vsqrtq_f32(vec.mNative);
1696 return simd(std::sqrt(mNative[0]), std::sqrt(mNative[1]), std::sqrt(mNative[2]), std::sqrt(mNative[3]));
1702 template<
int NR>
requires(NR > 0 && NR <= 2)
1707#if defined(JPL_USE_SSE)
1709 Type y = _mm_rsqrt_ps(vec);
1711 auto newton = [](
const Type& x,
const Type& y)
1713 static const Type half = _mm_set1_ps(0.5f);
1714 static const Type thal = _mm_set1_ps(1.5f);
1715#if defined(JPL_USE_FMADD)
1717 Type xy = _mm_mul_ps(x, y);
1718 Type xy2 = _mm_mul_ps(xy, y);
1719 Type term = _mm_fnmadd_ps(half, xy2, thal);
1720 return _mm_mul_ps(y, term);
1722 Type y2 = _mm_mul_ps(y, y);
1723 Type term = _mm_sub_ps(thal, _mm_mul_ps(_mm_mul_ps(half, x), y2));
1724 return _mm_mul_ps(y, term);
1728 if constexpr (NR >= 1)
1732 if constexpr (NR >= 2)
1738#elif defined (JPL_USE_NEON)
1739 Type y = vrsqrteq_f32(vec);
1741 auto newton = [](
const Type& x,
const Type& y)
1745 Type y2 = vmulq_f32(y, y);
1746 Type xy2 = vmulq_f32(x, y2);
1747 Type term = vrsqrtsq_f32(xy2, y);
1749 static const Type half = vdupq_n_f32(0.5f);
1750 static const Type thal = vdupq_n_f32(1.5f);
1751 Type xy = vmulq_f32(x, y);
1752 Type xy2 = vmulq_f32(xy, y);
1753 Type term = vfmsq_f32(thal, half, xy2);
1755 return vmulq_f32(y, term);
1758 if constexpr (NR >= 1)
1762 if constexpr (NR >= 2)
1770 1.0f / std::sqrt(vec.
mNative[0]),
1771 1.0f / std::sqrt(vec.
mNative[1]),
1772 1.0f / std::sqrt(vec.
mNative[2]),
1773 1.0f / std::sqrt(vec.
mNative[3])
1795 return abs(vec) <= tolerance;
1801#if defined(JPL_USE_SSE)
1802 return _mm_max_ps(a.mNative, b.mNative);
1803#elif defined(JPL_USE_NEON)
1804 return vmaxq_f32(a.mNative, b.mNative);
1806 return simd(std::max(a.mNative[0], b.mNative[0]),
1807 std::max(a.mNative[1], b.mNative[1]),
1808 std::max(a.mNative[2], b.mNative[2]),
1809 std::max(a.mNative[3], b.mNative[3]));
1815#if defined(JPL_USE_SSE)
1816 return _mm_min_ps(a.mNative, b.mNative);
1817#elif defined(JPL_USE_NEON)
1818 return vminq_f32(a.mNative, b.mNative);
1820 return simd(std::min(a.mNative[0], b.mNative[0]),
1821 std::min(a.mNative[1], b.mNative[1]),
1822 std::min(a.mNative[2], b.mNative[2]),
1823 std::min(a.mNative[3], b.mNative[3]));
1829#if defined(JPL_USE_SSE)
1830 return _mm_and_ps(vec.mNative,
simd_mask(0x7fffffff).as_simd());
1831#elif defined(JPL_USE_NEON)
1832 return vabsq_f32(vec.mNative);
1834 return {
abs(vec.mNative[0]),
abs(vec.mNative[1]),
abs(vec.mNative[2]),
abs(vec.mNative[3]) };
1840 return max(
min(value, maxV), minV);
1845#if defined(JPL_USE_SSE)
1847 return _mm_fmadd_ps(mul1.mNative, mul2.mNative, addV.mNative);
1849 return _mm_add_ps(_mm_mul_ps(mul1.mNative, mul2.mNative), addV.mNative);
1851#elif defined(JPL_USE_NEON)
1852 return vmlaq_f32(addV.mNative, mul1.mNative, mul2.mNative);
1854 return Vec3(mul1.mNative[0] * mul2.mNative[0] + addV.mNative[0],
1855 mul1.mNative[1] * mul2.mNative[1] + addV.mNative[1],
1856 mul1.mNative[2] * mul2.mNative[2] + addV.mNative[2],
1857 mul1.mNative[3] * mul2.mNative[3] + addV.mNative[3]);
1864 const simd vec_abs =
abs(vec);
1869#if defined (JPL_USE_SSE)
1870#if defined (JPL_USE_SSE4_1)
1871 simd floored = _mm_floor_ps(vec.mNative);
1876 simd mask = (truncated > vec).as_simd() &
simd(1.0f);
1877 simd floored = truncated - mask;
1879 return simd::select(is_nan | is_inf | is_zero, vec, floored);
1880#elif defined (JPL_USE_NEON)
1881 auto floored = vrndmq_f32(vec.mNative);
1882 return simd::select(is_nan | is_inf | is_zero, vec, floored);
1885 std::floorf(vec.mNative[0]),
1886 std::floorf(vec.mNative[1]),
1887 std::floorf(vec.mNative[2]),
1888 std::floorf(vec.mNative[3])
1896 const simd vec_abs =
abs(vec);
1901#if defined (JPL_USE_SSE)
1902 const simd_mask requires_rounding = vec_abs <
simd(8'388'608.0f);
1903#if defined (JPL_USE_SSE4_1)
1904 simd ceiled = _mm_ceil_ps(vec.mNative);
1911 const simd increment = (truncated < vec).as_simd() &
simd(1.0f);
1912 simd ceiled = truncated + increment;
1914 ceiled = ceiled | (vec &
simd(-0.0f));
1917#elif defined (JPL_USE_NEON)
1918 auto ceiled = vrndpq_f32(vec.mNative);
1919 return simd::select(is_nan | is_inf | is_zero, vec, ceiled);
1922 std::ceilf(vec.mNative[0]),
1923 std::ceilf(vec.mNative[1]),
1924 std::ceilf(vec.mNative[2]),
1925 std::ceilf(vec.mNative[3])
1932#if defined(JPL_USE_SSE4_1)
1933 return _mm_round_ps(vec, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
1934#elif defined(JPL_USE_SSE)
1937 return (vec + (
simd(0.5f) | sign.as_simd())).to_mask().to_simd();
1938#elif defined(JPL_USE_NEON)
1939 return vrndnq_f32(vec.mNative);
1942 std::roundf(vec.mNative[0]),
1943 std::roundf(vec.mNative[1]),
1944 std::roundf(vec.mNative[2]),
1945 std::roundf(vec.mNative[3])
1952#if defined(JPL_USE_SSE)
1953 return _mm_shuffle_ps(vec.mNative, vec.mNative, _MM_SHUFFLE(3, 1, 2, 0));
1954#elif defined(JPL_USE_NEON)
1955 auto vecs = vzip_f32(vget_low_f32(vec.mNative), vget_high_f32(vec.mNative));
1956 return vcombine_f32(vecs.val[0], vecs.val[1]);
1958 return { vec.mNative[0], vec.mNative[2], vec.mNative[1], vec.mNative[3] };
1964#if defined(JPL_USE_SSE)
1965 return _mm_castsi128_ps(
1967 _mm_castps_si128(a.mNative),
1968 _mm_castps_si128(b.mNative)
1971#elif defined(JPL_USE_NEON)
1972 return vcombine_f32(vget_low_f32(a.mNative), vget_low_f32(b.mNative));
1974 return { a.mNative[0], a.mNative[1], b.mNative[0], b.mNative[1] };
1980#if defined(JPL_USE_SSE)
1981 return _mm_castsi128_ps(
1983 _mm_castps_si128(a.mNative),
1984 _mm_castps_si128(b.mNative)
1987#elif defined(JPL_USE_NEON)
1988 return vcombine_f32(vget_high_f32(a.mNative), vget_high_f32(b.mNative));
1990 return { a.mNative[2], a.mNative[3], b.mNative[2], b.mNative[3] };
1996#if defined(JPL_USE_SSE)
1997 return _mm_shuffle_ps(a.mNative, b.mNative, _MM_SHUFFLE(3, 2, 1, 0));
1998#elif defined(JPL_USE_NEON)
1999 return vcombine_f32(vget_low_f32(a.mNative), vget_high_f32(b.mNative));
2001 return { a.mNative[0], a.mNative[1], b.mNative[2], b.mNative[3] };
2007#if defined(JPL_USE_SSE)
2008 return _mm_shuffle_ps(vec.mNative, vec.mNative, _MM_SHUFFLE(0, 1, 2, 3));
2009#elif defined(JPL_USE_NEON)
2011 float32x4_t rev64 = vrev64q_f32(vec.mNative);
2013 return vcombine_f32(vget_high_f32(rev64), vget_low_f32(rev64));
2015 return { vec.mNative[3], vec.mNative[2], vec.mNative[1], vec.mNative[0] };
2022#if defined(JPL_USE_SSE4_1)
2023 return _mm_max_epu32(a.mNative, b.mNative);
2024#elif defined(JPL_USE_SSE)
2026 __m128i offset = _mm_set1_epi32(0x80000000);
2027 __m128i a_signed = _mm_xor_si128(a, offset);
2028 __m128i b_signed = _mm_xor_si128(b, offset);
2030 __m128i mask = _mm_cmpgt_epi32(a_signed, b_signed);
2033 return _mm_or_si128(_mm_and_si128(mask, a), _mm_andnot_si128(mask, b));
2034#elif defined(JPL_USE_NEON)
2035 return vmaxq_u32(a.mNative, b.mNative);
2037 return simd_mask(std::max(a.mNative[0], b.mNative[0]),
2038 std::max(a.mNative[1], b.mNative[1]),
2039 std::max(a.mNative[2], b.mNative[2]),
2040 std::max(a.mNative[3], b.mNative[3]));
2046#if defined(JPL_USE_SSE4_1)
2047 return _mm_min_epu32(a.mNative, b.mNative);
2048#elif defined(JPL_USE_SSE)
2050 __m128i offset = _mm_set1_epi32(0x80000000);
2051 __m128i a_signed = _mm_xor_si128(a, offset);
2052 __m128i b_signed = _mm_xor_si128(b, offset);
2054 __m128i mask = _mm_cmpgt_epi32(a_signed, b_signed);
2056 return _mm_or_si128(_mm_and_si128(mask, b), _mm_andnot_si128(mask, a));
2057#elif defined(JPL_USE_NEON)
2058 return vminq_u32(a.mNative, b.mNative);
2060 return simd_mask(std::min(a.mNative[0], b.mNative[0]),
2061 std::min(a.mNative[1], b.mNative[1]),
2062 std::min(a.mNative[2], b.mNative[2]),
2063 std::min(a.mNative[3], b.mNative[3]));
2069 return max(
min(value, maxV), minV);
2074#if defined(JPL_USE_SSE4_1)
2075 return _mm_max_epi32(a.mNative, b.mNative);
2076#elif defined(JPL_USE_SSE)
2079 return _mm_or_si128(_mm_and_si128(gt, a.mNative),
2080 _mm_andnot_si128(gt, b.mNative));
2081#elif defined(JPL_USE_NEON)
2082 return vreinterpretq_u32_s32(vmaxq_s32(
2083 vreinterpretq_s32_u32(a.mNative),
2084 vreinterpretq_s32_u32(b.mNative)));
2087 static_cast<uint32>(std::max(
static_cast<int32>(a.mNative[0]),
static_cast<int32>(b.mNative[0]))),
2088 static_cast<uint32>(std::max(
static_cast<int32>(a.mNative[1]),
static_cast<int32>(b.mNative[1]))),
2089 static_cast<uint32>(std::max(
static_cast<int32>(a.mNative[2]),
static_cast<int32>(b.mNative[2]))),
2090 static_cast<uint32>(std::max(
static_cast<int32>(a.mNative[3]),
static_cast<int32>(b.mNative[3]))));
2096#if defined(JPL_USE_SSE4_1)
2097 return _mm_min_epi32(a.mNative, b.mNative);
2098#elif defined(JPL_USE_SSE)
2101 return _mm_or_si128(_mm_and_si128(gt, b.mNative),
2102 _mm_andnot_si128(gt, a.mNative));
2103#elif defined(JPL_USE_NEON)
2104 return vreinterpretq_u32_s32(vminq_s32(
2105 vreinterpretq_s32_u32(a.mNative),
2106 vreinterpretq_s32_u32(b.mNative)));
2109 static_cast<uint32>(std::min(
static_cast<int32>(a.mNative[0]),
static_cast<int32>(b.mNative[0]))),
2110 static_cast<uint32>(std::min(
static_cast<int32>(a.mNative[1]),
static_cast<int32>(b.mNative[1]))),
2111 static_cast<uint32>(std::min(
static_cast<int32>(a.mNative[2]),
static_cast<int32>(b.mNative[2]))),
2112 static_cast<uint32>(std::min(
static_cast<int32>(a.mNative[3]),
static_cast<int32>(b.mNative[3]))));
2118 return maxs(
mins(value, maxV), minV);
#define JPL_ASSERT(inExpression,...)
Main assert macro, usage: JPL_ASSERT(condition, message) or JPL_ASSERT(condition)
Definition ErrorReporting.h:80
JPL_INLINE constexpr T FMA(T a, T b, T c) noexcept
Inlined fuse multiply-add. Compiler in some circumstances is more eager to optimize this than std::fm...
Definition Math.h:186
JPL_INLINE constexpr T InvSqrt(T x) noexcept
Definition Math.h:283
JPL_INLINE constexpr T Lerp(const T &v0, const T &v1, T t) noexcept
Linearly interpolate v0 towards v1.
Definition Math.h:172
JPL_INLINE constexpr T Sqrt(T x) noexcept
Definition Math.h:269
JPL_INLINE constexpr bool IsNearlyZero(T value, T errorTolerance=JPL_FLOAT_EPS_V< T >) noexcept
Definition Math.h:146
JPL_INLINE simd InvSqrtImpl(const simd &vec) noexcept
Definition SIMD.h:1703
JPL_INLINE simd InvSqrtFast(const simd &vec) noexcept
Definition SIMD.h:1783
JPL_INLINE constexpr T Sign2(T value) noexcept
Sign2 returns -1 for negative values, 1 otherwise.
Definition Math.h:131
Definition AcousticMaterial.h:36
JPL_INLINE simd clamp(const simd &value, const simd &minV, const simd &maxV) noexcept
Element-wise clamp.
Definition SIMD.h:1838
std::uint32_t uint32
Definition Core.h:311
JPL_INLINE simd_mask clamps(const simd_mask &value, const simd_mask &minV, const simd_mask &maxV) noexcept
Element-wise clamp, signed.
Definition SIMD.h:2116
JPL_INLINE simd_mask operator!=(const simd &a, const simd &b) noexcept
Definition SIMD.h:341
JPL_INLINE simd_mask mins(const simd_mask &a, const simd_mask &b) noexcept
Element-wise min, signed.
Definition SIMD.h:2094
JPL_INLINE simd_mask operator>=(const simd &a, const simd &b) noexcept
Definition SIMD.h:1402
JPL_INLINE simd operator|(const simd &a, const simd &b) noexcept
Component-wise logical OR.
Definition SIMD.h:878
JPL_INLINE simd_mask operator<=(const simd &a, const simd &b) noexcept
Definition SIMD.h:1370
JPL_INLINE simd_mask operator<(const simd &a, const simd &b) noexcept
Definition SIMD.h:1354
std::uint8_t uint8
Definition Core.h:309
std::int32_t int32
Definition Core.h:316
JPL_INLINE simd combine_hi(const simd &a, const simd &b) noexcept
Combine two high lanes of input a and b as { a2, a3, b2, b3 }.
Definition SIMD.h:1978
JPL_INLINE simd_mask maxs(const simd_mask &a, const simd_mask &b) noexcept
Element-wise max, signed.
Definition SIMD.h:2072
JPL_INLINE simd reverse(const simd &vec) noexcept
Reverse the order of the lanes.
Definition SIMD.h:2005
JPL_INLINE simd operator^(const simd &a, const simd &b) noexcept
Component-wise logical XOR.
Definition SIMD.h:894
unsigned int uint
Definition Core.h:308
JPL_INLINE simd combine_lohi(const simd &a, const simd &b) noexcept
Combine two low lanes of a and two high lanes from b as { a0, a1, b2, b3 }.
Definition SIMD.h:1994
JPL_INLINE constexpr bool operator==(const Vec2 &A, const Vec2 &B) noexcept
Definition MinimalVec2.h:59
JPL_INLINE simd operator&(const simd &a, const simd &b) noexcept
Component-wise logical AND.
Definition SIMD.h:910
JPL_INLINE simd_mask operator>(const simd &a, const simd &b) noexcept
Definition SIMD.h:1386
JPL_INLINE simd round(const simd &vec) noexcept
Element-wise round to nearest integer value.
Definition SIMD.h:1930
JPL_INLINE simd floor(const simd &vec) noexcept
Element-wise floor.
Definition SIMD.h:1861
JPL_INLINE simd max(const simd &a, const simd &b) noexcept
Element-wise max.
Definition SIMD.h:1799
JPL_INLINE simd ceil(const simd &vec) noexcept
Element-wise ceil.
Definition SIMD.h:1893
JPL_INLINE simd fma(const simd &mul1, const simd &mul2, const simd &addV) noexcept
Element-wise fused multiply-add.
Definition SIMD.h:1843
JPL_INLINE constexpr Vec2 operator*(T Scale, const JPL::Vec2 &V) noexcept
Definition MinimalVec2.h:62
JPL_INLINE simd interleave_lohi(const simd &vec) noexcept
Interleave two low lanes with the two high lanes (e.g. { 0, 1, 2, 3 } -> { 0, 2, 1,...
Definition SIMD.h:1950
JPL_INLINE simd min(const simd &a, const simd &b) noexcept
Element-wise min.
Definition SIMD.h:1813
JPL_INLINE simd abs(const simd &vec) noexcept
Definition SIMD.h:1827
JPL_INLINE simd combine_lo(const simd &a, const simd &b) noexcept
Combine two low lanes of input a and b as { a0, a1, b0, b1 }.
Definition SIMD.h:1962
Definition ChannelMap.h:272
JPL_INLINE void store(uint32 *mem) const
Store values from simd to provided memory location.
Definition SIMD.h:1143
JPL_INLINE simd_mask & operator-=(const simd_mask &other) noexcept
Component-wise subtract two simd_mask vectors.
Definition SIMD.h:1322
JPL_INLINE bool all_of() const noexcept
Test if all of the components are true.
Definition SIMD.h:1169
JPL_INLINE simd_mask operator*(const simd_mask &other) const noexcept
Component-wise multiplies each of the 4 integer components with an integer (discards any overflow)
Definition SIMD.h:1230
Type mNative
Definition SIMD.h:327
JPL_INLINE bool any_of() const noexcept
Test if any of the components are true.
Definition SIMD.h:1174
JPL_INLINE simd_mask ashr() const noexcept
Definition SIMD.h:1562
JPL_INLINE simd_mask & operator*=(const simd_mask &other) noexcept
Component-wise multiplies each of the 4 integer components with an integer (discards any overflow)
Definition SIMD.h:1253
JPL_INLINE simd_mask operator-(const simd_mask &other) const noexcept
Component-wise subtract two simd_mask vectors.
Definition SIMD.h:1306
friend std::ostream & operator<<(std::ostream &inStream, const simd_mask &vec)
Definition SIMD.h:319
JPL_INLINE void operator^=(const simd_mask &other) noexcept
Component-wise logical XOR.
Definition SIMD.h:1461
JPL_INLINE int reduce_count() const noexcept
Count the number of components that are true.
Definition SIMD.h:1184
JPL_INLINE int reduce_max_index() const noexcept
Get index of the last component that is true.
Definition SIMD.h:1202
simd_mask() noexcept=default
JPL_INLINE simd_mask operator+(const simd_mask &other) const noexcept
Component-wise add an integer value to all integer components (discards any overflow)
Definition SIMD.h:1275
std::array< uint32, 4 > Type
Definition SIMD.h:214
JPL_INLINE simd as_simd() const noexcept
Reinterpret simd_mask as a simd (doesn't change the bits)
Definition SIMD.h:1627
JPL_INLINE uint32 get_lane() const noexcept
Get float component by index known at compile-time.
Definition SIMD.h:1158
JPL_INLINE simd_mask shr() const noexcept
Definition SIMD.h:1528
JPL_INLINE int reduce_min_index() const noexcept
Get index of the first component that is true.
Definition SIMD.h:1195
JPL_INLINE simd_mask & operator+=(const simd_mask &other) noexcept
Component-wise add two integer vectors (component wise)
Definition SIMD.h:1291
JPL_INLINE simd_mask operator>>(const uint32 count) const noexcept
Definition SIMD.h:1489
static JPL_INLINE simd_mask zero() noexcept
Definition SIMD.h:1121
JPL_INLINE simd_mask subs(const simd_mask &other) const noexcept
Definition SIMD.h:1594
JPL_INLINE int GetTrues() const noexcept
Store if [0] is true in bit 0, [1] in bit 1, [2] in bit 2 and [3] in bit 3.
Definition SIMD.h:1209
JPL_INLINE void operator&=(const simd_mask &other) noexcept
Component-wise logical AND.
Definition SIMD.h:1475
JPL_INLINE void load(const uint32 *mem)
Load values from memory into simd, 'mem' should point to memory with at least size() number of uint32...
Definition SIMD.h:1132
JPL_INLINE simd to_simd() const noexcept
Convert each component from an int to a float.
Definition SIMD.h:1610
JPL_INLINE void operator|=(const simd_mask &other) noexcept
Component-wise logical OR.
Definition SIMD.h:1447
JPL_INLINE bool none_of() const noexcept
Test if none of the components are true.
Definition SIMD.h:1179
JPL_INLINE simd_mask adds(const simd_mask &other) const noexcept
Definition SIMD.h:1578
JPL_INLINE simd_mask shl() const noexcept
Definition SIMD.h:1545
static JPL_INLINE simd_mask replicate(int value) noexcept
Definition SIMD.h:1106
JPL_INLINE simd_mask operator~() const noexcept
Component-wise logical NOT.
Definition SIMD.h:1434
Minimal 4-wide 32-bit float vector implementation for SIMD.
Definition SIMD.h:60
static JPL_INLINE simd c_0() noexcept
Frequently used constants.
Definition SIMD.h:456
JPL_INLINE float operator[](uint32 index) const noexcept
Get float component by index.
Definition SIMD.h:587
static JPL_INLINE simd c_1() noexcept
Definition SIMD.h:461
JPL_INLINE simd_mask to_mask() const noexcept
Convert each component from a float to an int.
Definition SIMD.h:987
JPL_INLINE simd operator/(float value) const noexcept
Divide vector by float.
Definition SIMD.h:664
JPL_INLINE simd & operator-=(const simd &other) noexcept
Subtract two float vectors (component wise)
Definition SIMD.h:801
JPL_INLINE simd_mask as_mask() const noexcept
Reinterpret simd as a simd_mask (doesn't change the bits)
Definition SIMD.h:1023
Type mNative
Definition SIMD.h:201
JPL_INLINE simd splat() const
Replicate component at LaneIndex to all components.
Definition SIMD.h:927
JPL_INLINE void operator|=(const simd &other) noexcept
Component-wise logical OR.
Definition SIMD.h:830
JPL_INLINE void load(const float *mem)
Load values from memory into simd, 'mem' should point to memory with at least size() number of floats...
Definition SIMD.h:562
static JPL_INLINE simd c_0p5() noexcept
Definition SIMD.h:466
static JPL_INLINE simd reciprocal(const simd &vec) noexcept
Reciprocal vector (1 / value) for each of the components.
Definition SIMD.h:1058
JPL_INLINE simd & operator+=(const simd &other) noexcept
Add two float vectors (component wise)
Definition SIMD.h:748
friend JPL_INLINE simd operator*(float value, const simd &other) noexcept
Multiply vector with float.
Definition SIMD.h:648
static JPL_INLINE simd zero() noexcept
Vector with all zeros.
Definition SIMD.h:541
std::array< float, 4 > Type
Definition SIMD.h:67
JPL_INLINE float reduce_min() const noexcept
Returns min component.
Definition SIMD.h:970
static JPL_INLINE simd c_pi() noexcept
Definition SIMD.h:471
JPL_INLINE simd & operator*=(float value) noexcept
Multiply vector with float.
Definition SIMD.h:680
JPL_INLINE void operator^=(const simd &other) noexcept
Component-wise logical XOR.
Definition SIMD.h:846
static JPL_INLINE simd inf() noexcept
Definition SIMD.h:557
JPL_INLINE float reduce_max() const noexcept
Returns max component.
Definition SIMD.h:953
static JPL_INLINE simd select(const simd_mask &mask, const simd &a, const simd &b) noexcept
Component-wise select, returns 'a' if mask is true, 'b' otherwise.
Definition SIMD.h:1034
JPL_INLINE void operator&=(const simd &other) noexcept
Component-wise logical AND.
Definition SIMD.h:862
JPL_INLINE float reduce() const noexcept
Returns sum of all components.
Definition SIMD.h:938
JPL_INLINE simd operator-() const noexcept
Negate.
Definition SIMD.h:761
JPL_INLINE simd operator+(const simd &other) const noexcept
Add two float vectors (component wise)
Definition SIMD.h:732
JPL_INLINE float get_lane() const noexcept
Get float component by index known at compile-time.
Definition SIMD.h:610
JPL_INLINE simd & operator/=(float value) noexcept
Divide vector by float.
Definition SIMD.h:706
JPL_INLINE void store(float *mem) const
Store values from simd to provided memory location.
Definition SIMD.h:573
static JPL_INLINE simd nan() noexcept
Vector with all NaN's.
Definition SIMD.h:552
static JPL_INLINE simd gather(const float *base, const simd_mask &offsets)
Gather 4 floats from memory at base + offsets[i] * Scale.
Definition SIMD.h:515
JPL_INLINE bool operator()(const JPL::simd &a, const JPL::simd &b) const
Definition SIMD.h:445