#pragma once //////////////////////////////////////////////////////////////////////////////// // The MIT License (MIT) // // Copyright (c) 2018 Nicholas Frechette & Realtime Math contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //////////////////////////////////////////////////////////////////////////////// #include "rtm/types.h" #include "rtm/impl/compiler_utils.h" #include "rtm/scalarf.h" #include "rtm/scalard.h" #include #include RTM_IMPL_FILE_PRAGMA_PUSH namespace rtm { ////////////////////////////////////////////////////////////////////////// // Creates a vector4 from all 4 components. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE vector4f RTM_SIMD_CALL vector_set(float x, float y, float z, float w) RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) return _mm_set_ps(w, z, y, x); #elif defined(RTM_NEON_INTRINSICS) #if 1 float32x2_t V0 = vcreate_f32(((uint64_t)*(const uint32_t*)&x) | ((uint64_t)(*(const uint32_t*)&y) << 32)); float32x2_t V1 = vcreate_f32(((uint64_t)*(const uint32_t*)&z) | ((uint64_t)(*(const uint32_t*)&w) << 32)); return vcombine_f32(V0, V1); #else float __attribute__((aligned(16))) data[4] = { x, y, z, w }; return vld1q_f32(data); #endif #else return vector4f{ x, y, z, w }; #endif } ////////////////////////////////////////////////////////////////////////// // Creates a vector4 from the [xyz] components and sets [w] to 0.0. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE vector4f RTM_SIMD_CALL vector_set(float x, float y, float z) RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) return _mm_set_ps(0.0F, z, y, x); #elif defined(RTM_NEON_INTRINSICS) #if 1 float32x2_t V0 = vcreate_f32(((uint64_t)*(const uint32_t*)&x) | ((uint64_t)(*(const uint32_t*)&y) << 32)); float32x2_t V1 = vcreate_f32((uint64_t)*(const uint32_t*)&z); return vcombine_f32(V0, V1); #else float __attribute__((aligned(16))) data[4] = { x, y, z }; return vld1q_f32(data); #endif #else return vector4f{ x, y, z, 0.0f }; #endif } ////////////////////////////////////////////////////////////////////////// // Creates a vector4 from a single value for all 4 components. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE vector4f RTM_SIMD_CALL vector_set(float xyzw) RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) return _mm_set_ps1(xyzw); #elif defined(RTM_NEON_INTRINSICS) return vdupq_n_f32(xyzw); #else return vector4f{ xyzw, xyzw, xyzw, xyzw }; #endif } #if defined(RTM_SSE2_INTRINSICS) ////////////////////////////////////////////////////////////////////////// // Creates a vector4 from all 4 components. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE vector4f RTM_SIMD_CALL vector_set(scalarf_arg0 x, scalarf_arg1 y, scalarf_arg2 z, scalarf_arg3 w) RTM_NO_EXCEPT { const __m128 xy = _mm_unpacklo_ps(x.value, y.value); const __m128 zw = _mm_unpacklo_ps(z.value, w.value); return _mm_shuffle_ps(xy, zw, _MM_SHUFFLE(1, 0, 1, 0)); } ////////////////////////////////////////////////////////////////////////// // Creates a vector4 from the [xyz] components and sets [w] to 0.0. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE vector4f RTM_SIMD_CALL vector_set(scalarf_arg0 x, scalarf_arg1 y, scalarf_arg2 z) RTM_NO_EXCEPT { const __m128 xy = _mm_unpacklo_ps(x.value, y.value); const __m128 zw = _mm_unpacklo_ps(z.value, _mm_setzero_ps()); return _mm_shuffle_ps(xy, zw, _MM_SHUFFLE(1, 0, 1, 0)); } ////////////////////////////////////////////////////////////////////////// // Creates a vector4 from a single value for all 4 components. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE vector4f RTM_SIMD_CALL vector_set(scalarf_arg0 xyzw) RTM_NO_EXCEPT { return _mm_shuffle_ps(xyzw.value, xyzw.value, _MM_SHUFFLE(0, 0, 0, 0)); } #endif ////////////////////////////////////////////////////////////////////////// // Creates a vector4 from all 4 components. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE vector4d vector_set(double x, double y, double z, double w) RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) return vector4d{ _mm_set_pd(y, x), _mm_set_pd(w, z) }; #else return vector4d{ x, y, z, w }; #endif } ////////////////////////////////////////////////////////////////////////// // Creates a vector4 from the [xyz] components and sets [w] to 0.0. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE vector4d vector_set(double x, double y, double z) RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) return vector4d{ _mm_set_pd(y, x), _mm_set_pd(0.0, z) }; #else return vector4d{ x, y, z, 0.0 }; #endif } ////////////////////////////////////////////////////////////////////////// // Creates a vector4 from a single value for all 4 components. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE vector4d vector_set(double xyzw) RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) const __m128d xyzw_pd = _mm_set1_pd(xyzw); return vector4d{ xyzw_pd, xyzw_pd }; #else return vector4d{ xyzw, xyzw, xyzw, xyzw }; #endif } #if defined(RTM_SSE2_INTRINSICS) ////////////////////////////////////////////////////////////////////////// // Creates a vector4 from all 4 components. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE vector4d RTM_SIMD_CALL vector_set(scalard x, scalard y, scalard z, scalard w) RTM_NO_EXCEPT { const __m128d xy = _mm_unpacklo_pd(x.value, y.value); const __m128d zw = _mm_unpacklo_pd(z.value, w.value); return vector4d{ xy, zw }; } ////////////////////////////////////////////////////////////////////////// // Creates a vector4 from the [xyz] components and sets [w] to 0.0. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE vector4d RTM_SIMD_CALL vector_set(scalard x, scalard y, scalard z) RTM_NO_EXCEPT { const __m128d xy = _mm_unpacklo_pd(x.value, y.value); const __m128d zw = _mm_unpacklo_pd(z.value, _mm_setzero_pd()); return vector4d{ xy, zw }; } ////////////////////////////////////////////////////////////////////////// // Creates a vector4 from a single value for all 4 components. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE vector4d RTM_SIMD_CALL vector_set(scalard xyzw) RTM_NO_EXCEPT { const __m128d xyzw_pd = _mm_shuffle_pd(xyzw.value, xyzw.value, 0); return vector4d{ xyzw_pd, xyzw_pd }; } #endif namespace rtm_impl { ////////////////////////////////////////////////////////////////////////// // Returns true if mix4 component is one of [xyzw] ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr bool is_mix_xyzw(mix4 arg) RTM_NO_EXCEPT { return uint32_t(arg) <= uint32_t(mix4::w); } ////////////////////////////////////////////////////////////////////////// // Returns true if mix4 component is one of [abcd] ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr bool is_mix_abcd(mix4 arg) RTM_NO_EXCEPT { return uint32_t(arg) >= uint32_t(mix4::a); } ////////////////////////////////////////////////////////////////////////// // This is a helper struct to help manipulate SIMD masks. ////////////////////////////////////////////////////////////////////////// union mask_converter { uint64_t u64; uint32_t u32[2]; RTM_DISABLE_SECURITY_COOKIE_CHECK explicit RTM_FORCE_INLINE constexpr mask_converter(uint64_t value) RTM_NO_EXCEPT : u64(value) {} RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr operator uint32_t() const RTM_NO_EXCEPT { return u32[0]; } RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr operator uint64_t() const RTM_NO_EXCEPT { return u64; } }; ////////////////////////////////////////////////////////////////////////// // Returns a SIMD mask value from a boolean. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr mask_converter get_mask_value(bool is_true) RTM_NO_EXCEPT { return mask_converter(is_true ? uint64_t(0xFFFFFFFFFFFFFFFFULL) : uint64_t(0)); } ////////////////////////////////////////////////////////////////////////// // Selects if_false if the SIMD mask value is 0, otherwise if_true. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr double select(uint64_t mask, double if_true, double if_false) RTM_NO_EXCEPT { return mask == 0 ? if_false : if_true; } ////////////////////////////////////////////////////////////////////////// // Selects if_false if the SIMD mask value is 0, otherwise if_true. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr float select(uint32_t mask, float if_true, float if_false) RTM_NO_EXCEPT { return mask == 0 ? if_false : if_true; } ////////////////////////////////////////////////////////////////////////// // This is a helper struct to allow a single consistent API between // various vector types when the semantics are identical but the return // type differs. Implicit coercion is used to return the desired value // at the call site. ////////////////////////////////////////////////////////////////////////// struct vector_zero_impl { RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator vector4d() const RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) const __m128d zero_pd = _mm_setzero_pd(); return vector4d{ zero_pd, zero_pd }; #else return vector_set(0.0); #endif } RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator vector4f() const RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) return _mm_setzero_ps(); #else return vector_set(0.0F); #endif } }; ////////////////////////////////////////////////////////////////////////// // Various vector widths we can load ////////////////////////////////////////////////////////////////////////// enum class vector_unaligned_loader_width { vec1, vec2, vec3, vec4, }; ////////////////////////////////////////////////////////////////////////// // This is a helper struct to allow a single consistent API between // various vector types when the semantics are identical but the return // type differs. Implicit coercion is used to return the desired value // at the call site. ////////////////////////////////////////////////////////////////////////// template struct vector_unaligned_loader { RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator vector4d() const RTM_NO_EXCEPT { switch (width) { case vector_unaligned_loader_width::vec1: { double data[1]; std::memcpy(&data[0], ptr, sizeof(double) * 1); return vector_set(data[0], 0.0, 0.0, 0.0); } case vector_unaligned_loader_width::vec2: { double data[2]; std::memcpy(&data[0], ptr, sizeof(double) * 2); return vector_set(data[0], data[1], 0.0, 0.0); } case vector_unaligned_loader_width::vec3: { double data[3]; std::memcpy(&data[0], ptr, sizeof(double) * 3); return vector_set(data[0], data[1], data[2], 0.0); } case vector_unaligned_loader_width::vec4: default: { vector4d result; std::memcpy(&result, ptr, sizeof(vector4d)); return result; } } } RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator vector4f() const RTM_NO_EXCEPT { switch (width) { case vector_unaligned_loader_width::vec1: { float data[1]; std::memcpy(&data[0], ptr, sizeof(float) * 1); return vector_set(data[0], 0.0F, 0.0F, 0.0F); } case vector_unaligned_loader_width::vec2: { float data[2]; std::memcpy(&data[0], ptr, sizeof(float) * 2); return vector_set(data[0], data[1], 0.0F, 0.0F); } case vector_unaligned_loader_width::vec3: { float data[3]; std::memcpy(&data[0], ptr, sizeof(float) * 3); return vector_set(data[0], data[1], data[2], 0.0F); } case vector_unaligned_loader_width::vec4: default: { #if defined(RTM_SSE2_INTRINSICS) return _mm_loadu_ps((const float*)ptr); #elif defined(RTM_NEON_INTRINSICS) return vreinterpretq_f32_u8(vld1q_u8(ptr)); #else vector4f result; std::memcpy(&result, ptr, sizeof(vector4f)); return result; #endif } } } const uint8_t* ptr; }; ////////////////////////////////////////////////////////////////////////// // This is a helper struct to allow a single consistent API between // various vector types when the semantics are identical but the return // type differs. Implicit coercion is used to return the desired value // at the call site. ////////////////////////////////////////////////////////////////////////// struct vector4f_to_scalarf { RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator float() const RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) return _mm_cvtss_f32(value); #elif defined(RTM_NEON_INTRINSICS) return vgetq_lane_f32(value, 0); #else return value.x; #endif } #if defined(RTM_SSE2_INTRINSICS) RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator scalarf() const RTM_NO_EXCEPT { return scalarf{ value }; } #endif vector4f value; }; ////////////////////////////////////////////////////////////////////////// // This is a helper struct to allow a single consistent API between // various vector types when the semantics are identical but the return // type differs. Implicit coercion is used to return the desired value // at the call site. ////////////////////////////////////////////////////////////////////////// struct vector4d_to_scalard { RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator double() const RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) return _mm_cvtsd_f64(value.xy); #else return value.x; #endif } #if defined(RTM_SSE2_INTRINSICS) RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator scalard() const RTM_NO_EXCEPT { return scalard{ value.xy }; } #endif vector4d value; }; ////////////////////////////////////////////////////////////////////////// // This is a helper struct to allow a single consistent API between // various vector types when the semantics are identical but the return // type differs. Implicit coercion is used to return the desired value // at the call site. ////////////////////////////////////////////////////////////////////////// struct vector4f_get_min_component { RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator float() const RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) __m128 zwzw = _mm_movehl_ps(value, value); __m128 xz_yw_zz_ww = _mm_min_ps(value, zwzw); __m128 yw_yw_yw_yw = _mm_shuffle_ps(xz_yw_zz_ww, xz_yw_zz_ww, _MM_SHUFFLE(1, 1, 1, 1)); return _mm_cvtss_f32(_mm_min_ps(xz_yw_zz_ww, yw_yw_yw_yw)); #elif defined(RTM_NEON_INTRINSICS) float32x2_t xy_zw = vpmin_f32(vget_low_f32(value), vget_high_f32(value)); return vget_lane_f32(vpmin_f32(xy_zw, xy_zw), 0); #else return scalar_min(scalar_min(value.x, value.y), scalar_min(value.z, value.w)); #endif } #if defined(RTM_SSE2_INTRINSICS) RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator scalarf() const RTM_NO_EXCEPT { __m128 zwzw = _mm_movehl_ps(value, value); __m128 xz_yw_zz_ww = _mm_min_ps(value, zwzw); __m128 yw_yw_yw_yw = _mm_shuffle_ps(xz_yw_zz_ww, xz_yw_zz_ww, _MM_SHUFFLE(1, 1, 1, 1)); return scalarf{ _mm_min_ps(xz_yw_zz_ww, yw_yw_yw_yw) }; } #endif vector4f value; }; ////////////////////////////////////////////////////////////////////////// // This is a helper struct to allow a single consistent API between // various vector types when the semantics are identical but the return // type differs. Implicit coercion is used to return the desired value // at the call site. ////////////////////////////////////////////////////////////////////////// struct vector4f_get_max_component { RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator float() const RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) __m128 zwzw = _mm_movehl_ps(value, value); __m128 xz_yw_zz_ww = _mm_max_ps(value, zwzw); __m128 yw_yw_yw_yw = _mm_shuffle_ps(xz_yw_zz_ww, xz_yw_zz_ww, _MM_SHUFFLE(1, 1, 1, 1)); return _mm_cvtss_f32(_mm_max_ps(xz_yw_zz_ww, yw_yw_yw_yw)); #elif defined(RTM_NEON_INTRINSICS) float32x2_t xy_zw = vpmax_f32(vget_low_f32(value), vget_high_f32(value)); return vget_lane_f32(vpmax_f32(xy_zw, xy_zw), 0); #else return scalar_max(scalar_max(value.x, value.y), scalar_max(value.z, value.w)); #endif } #if defined(RTM_SSE2_INTRINSICS) RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator scalarf() const RTM_NO_EXCEPT { __m128 zwzw = _mm_movehl_ps(value, value); __m128 xz_yw_zz_ww = _mm_max_ps(value, zwzw); __m128 yw_yw_yw_yw = _mm_shuffle_ps(xz_yw_zz_ww, xz_yw_zz_ww, _MM_SHUFFLE(1, 1, 1, 1)); return scalarf{ _mm_max_ps(xz_yw_zz_ww, yw_yw_yw_yw) }; } #endif vector4f value; }; ////////////////////////////////////////////////////////////////////////// // This is a helper struct to allow a single consistent API between // various vector types when the semantics are identical but the return // type differs. Implicit coercion is used to return the desired value // at the call site. ////////////////////////////////////////////////////////////////////////// struct vector4d_get_min_component { RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator double() const RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) __m128d xz_yw = _mm_min_pd(value.xy, value.zw); __m128d yw_yw = _mm_shuffle_pd(xz_yw, xz_yw, 1); return _mm_cvtsd_f64(_mm_min_pd(xz_yw, yw_yw)); #else return scalar_min(scalar_min(value.x, value.y), scalar_min(value.z, value.w)); #endif } #if defined(RTM_SSE2_INTRINSICS) RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator scalard() const RTM_NO_EXCEPT { __m128d xz_yw = _mm_min_pd(value.xy, value.zw); __m128d yw_yw = _mm_shuffle_pd(xz_yw, xz_yw, 1); return scalard{ _mm_min_pd(xz_yw, yw_yw) }; } #endif vector4d value; }; ////////////////////////////////////////////////////////////////////////// // This is a helper struct to allow a single consistent API between // various vector types when the semantics are identical but the return // type differs. Implicit coercion is used to return the desired value // at the call site. ////////////////////////////////////////////////////////////////////////// struct vector4d_get_max_component { RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator double() const RTM_NO_EXCEPT { #if defined(RTM_SSE2_INTRINSICS) __m128d xz_yw = _mm_max_pd(value.xy, value.zw); __m128d yw_yw = _mm_shuffle_pd(xz_yw, xz_yw, 1); return _mm_cvtsd_f64(_mm_max_pd(xz_yw, yw_yw)); #else return scalar_max(scalar_max(value.x, value.y), scalar_max(value.z, value.w)); #endif } #if defined(RTM_SSE2_INTRINSICS) RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE RTM_SIMD_CALL operator scalard() const RTM_NO_EXCEPT { __m128d xz_yw = _mm_max_pd(value.xy, value.zw); __m128d yw_yw = _mm_shuffle_pd(xz_yw, xz_yw, 1); return scalard{ _mm_max_pd(xz_yw, yw_yw) }; } #endif vector4d value; }; } ////////////////////////////////////////////////////////////////////////// // Returns a vector consisting of all zeros. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr rtm_impl::vector_zero_impl RTM_SIMD_CALL vector_zero() RTM_NO_EXCEPT { return rtm_impl::vector_zero_impl(); } ////////////////////////////////////////////////////////////////////////// // Loads an unaligned vector4 from memory. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr rtm_impl::vector_unaligned_loader RTM_SIMD_CALL vector_load(const uint8_t* input) RTM_NO_EXCEPT { return rtm_impl::vector_unaligned_loader{ input }; } ////////////////////////////////////////////////////////////////////////// // Loads an unaligned vector1 from memory and sets the [yzw] components to zero. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr rtm_impl::vector_unaligned_loader RTM_SIMD_CALL vector_load1(const uint8_t* input) RTM_NO_EXCEPT { return rtm_impl::vector_unaligned_loader{ input }; } ////////////////////////////////////////////////////////////////////////// // Loads an unaligned vector2 from memory and sets the [zw] components to zero. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr rtm_impl::vector_unaligned_loader RTM_SIMD_CALL vector_load2(const uint8_t* input) RTM_NO_EXCEPT { return rtm_impl::vector_unaligned_loader{ input }; } ////////////////////////////////////////////////////////////////////////// // Loads an unaligned vector3 from memory and sets the [w] component to zero. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr rtm_impl::vector_unaligned_loader RTM_SIMD_CALL vector_load3(const uint8_t* input) RTM_NO_EXCEPT { return rtm_impl::vector_unaligned_loader{ input }; } ////////////////////////////////////////////////////////////////////////// // Coerces an vector4 input into a scalar by grabbing the first SIMD lane. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr rtm_impl::vector4f_to_scalarf RTM_SIMD_CALL vector_as_scalar(vector4f_arg0 input) RTM_NO_EXCEPT { return rtm_impl::vector4f_to_scalarf{ input }; } ////////////////////////////////////////////////////////////////////////// // Coerces an vector4 input into a scalar by grabbing the first SIMD lane. ////////////////////////////////////////////////////////////////////////// RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr rtm_impl::vector4d_to_scalard RTM_SIMD_CALL vector_as_scalar(const vector4d& input) RTM_NO_EXCEPT { return rtm_impl::vector4d_to_scalard{ input }; } } RTM_IMPL_FILE_PRAGMA_POP