diff --git a/glm/detail/qualifier.hpp b/glm/detail/qualifier.hpp index cb4e108a..1964ad1a 100644 --- a/glm/detail/qualifier.hpp +++ b/glm/detail/qualifier.hpp @@ -108,6 +108,28 @@ namespace detail # endif # if GLM_ARCH & GLM_ARCH_SSE2_BIT +#if defined(__clang__) || defined(__GNUC__) + template + struct storage<2, T, false> + { + typedef T type __attribute__((aligned(sizeof(T)),vector_size(2*sizeof(T)))); + }; + template + struct storage<1, T, false> + { + typedef T type __attribute__((aligned(1),vector_size(sizeof(T)))); + }; + template + struct storage<2, T, true> + { + typedef T type __attribute__((aligned(sizeof(T)),vector_size(2*sizeof(T)))); + }; + template + struct storage<1, T, true> + { + typedef T type __attribute__((aligned(sizeof(T)),vector_size(sizeof(T)))); + }; +#endif template<> struct storage<4, float, true> { diff --git a/glm/detail/setup.hpp b/glm/detail/setup.hpp index 5e94f2dc..30222511 100644 --- a/glm/detail/setup.hpp +++ b/glm/detail/setup.hpp @@ -297,7 +297,7 @@ // N2235 Generalized Constant Expressions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf // N3652 Extended Constant Expressions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3652.html -#if (GLM_ARCH & GLM_ARCH_SIMD_BIT) // Compiler SIMD intrinsics don't support constexpr... +#if (GLM_ARCH & GLM_ARCH_SIMD_BIT) && GLM_SIMD_CONSTEXPR == 0 // Compiler SIMD intrinsics don't support constexpr... # define GLM_HAS_CONSTEXPR 0 #elif (GLM_COMPILER & GLM_COMPILER_CLANG) # define GLM_HAS_CONSTEXPR __has_feature(cxx_relaxed_constexpr) diff --git a/glm/detail/simd_constexpr/element.hpp b/glm/detail/simd_constexpr/element.hpp index 06103770..e5098dd0 100644 --- a/glm/detail/simd_constexpr/element.hpp +++ b/glm/detail/simd_constexpr/element.hpp @@ -2,12 +2,11 @@ namespace glm::detail { consteval bool NotEmpty(length_t I, length_t L) { return I <= L; } - - template + template struct ElementCollection; - template - struct ElementCollection { - using data_t = DataWrapper::data_t; + template + struct ElementCollection { + using data_t = typename detail::storage<4, T, detail::is_aligned::value>::type; union { struct { @@ -20,46 +19,45 @@ namespace glm::detail }; }; - struct Empty {}; - #define G [[no_unique_address]] - template - struct ElementCollection { - using data_t = DataWrapper::data_t; + + template + struct ElementCollection { + using data_t = typename detail::storage<3, T, detail::is_aligned::value>::type; + struct w {}; struct a {}; struct q{}; union { struct { union { T x, r, s; }; union { T y, g, t; }; union { T z, b, p; }; - union { G Empty w, a, q; }; }; data_t data; }; }; - template - struct ElementCollection { - using data_t = DataWrapper::data_t; + template + struct ElementCollection { + using data_t = typename detail::storage<2, T, detail::is_aligned::value>::type; + struct z {}; struct b {}; struct p{}; + struct w {}; struct a {}; struct q{}; union { struct { union { T x, r, s; }; union { T y, g, t; }; - union { G Empty z, b, p; }; - union { G Empty w, a, q; }; }; data_t data; }; }; - template - struct ElementCollection { - using data_t = DataWrapper::data_t; + template + struct ElementCollection { + using data_t = typename detail::storage<1, T, detail::is_aligned::value>::type; + struct y {}; struct g {}; struct t{}; + struct z {}; struct b {}; struct p{}; + struct w {}; struct a {}; struct q{}; union { struct { union { T x, r, s; }; - union { G Empty y, g, t; }; - union { G Empty z, b, p; }; - union { G Empty w, a, q; }; }; data_t data; }; diff --git a/glm/detail/simd_constexpr/simd_helpers.inl b/glm/detail/simd_constexpr/simd_helpers.inl index 9a5ffaa2..f605217e 100644 --- a/glm/detail/simd_constexpr/simd_helpers.inl +++ b/glm/detail/simd_constexpr/simd_helpers.inl @@ -64,8 +64,8 @@ namespace glm::detail //assuming that number of scalars is always the same as the length of the to-be-constructed vector using Tx = typename GetFirstType::FirstTx; using OtherPaddedVec = PaddedVec; - OtherPaddedVec o = {.gcc_vec={Tx(scalars)...}}; - PaddedVec converted = {.gcc_vec=__builtin_convertvector(o.gcc_vec, gcc_vec_t)}; + typename OtherPaddedVec::GccV o = {Tx(scalars)...}; + PaddedVec converted = {.gcc_vec=__builtin_convertvector(o, gcc_vec_t)}; return gcc_vec_to_data(converted); } }; diff --git a/glm/detail/simd_constexpr/vec.hpp b/glm/detail/simd_constexpr/vec.hpp index 613e8c8f..92f45f3e 100644 --- a/glm/detail/simd_constexpr/vec.hpp +++ b/glm/detail/simd_constexpr/vec.hpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace glm { template @@ -40,7 +41,7 @@ namespace glm namespace detail { template - using _ArrT = T[L]; + using _ArrT = std::array; template using _data_t = typename detail::storage::value>::type; @@ -115,9 +116,9 @@ namespace glm using data_t = detail::_data_t; }; template - using EC = detail::ElementCollection, T, L>; + using EC = detail::ElementCollection; template - struct vec : detail::ElementCollection, T, L> + struct vec : detail::ElementCollection { // -- Data -- using EC::x; @@ -142,6 +143,7 @@ namespace glm typedef vec type; typedef vec bool_type; static constexpr qualifier k_qual = Q; + static constexpr length_t k_len = L; enum is_aligned { @@ -247,7 +249,7 @@ namespace glm # endif template - constexpr auto ctor_scalar(ScalarGetter scalar) { + static constexpr auto ctor_scalar(ScalarGetter scalar) { if (std::is_constant_evaluated()) { DataArray a; for (length_t i = 0; i < L; i++) { @@ -260,7 +262,7 @@ namespace glm } template - constexpr auto ctor(VecGetter vecGetter) { + static constexpr auto ctor(VecGetter vecGetter) { if (std::is_constant_evaluated()) { DataArray a = {}; auto v = vecGetter(); @@ -276,44 +278,45 @@ namespace glm return SimdHlp::simd_ctor(vecGetter()); } } + template + using RetArr = T[len]; - typedef struct { - DataArray a; - length_t i; - } RetPair; - static inline auto ctor_mixed_constexpr_single = [](auto&& vs0, length_t index) -> var_t + template + static constexpr length_t ctor_mixed_constexpr_single_get_length() { - DataArray a {}; - using VTX = std::decay_t; - length_t i = 0; - auto&& __restrict__ _vs0 = vs0; + if constexpr ( std::is_integral_v || std::is_floating_point_v ) { + return 1; + } else if constexpr ( ( requires { Vs0::k_len; }) ) { + return Vs0::k_len; + } else { + return 1; + } + } + static inline auto ctor_mixed_constexpr_single = [](auto vs0) -> auto + { + using VTX = decltype(vs0); if constexpr ( std::is_integral_v || std::is_floating_point_v ) { - a.p[index] = _vs0; - i++; - } else if constexpr ( ( requires (VTX v){ VTX::value_type; _vs0.length(); }) ) { + return RetArr<1>{vs0}; + } else if constexpr ( ( requires { VTX::k_len; }) ) { using Tx = VTX::value_type; - using ArrX = VecDataArray<_vs0.length(), Tx, VTX::k_qual>; - ArrX ax = std::bit_cast(_vs0.data); - for (Tx tx : ax.p) { - a.p[index+i++] = (T)tx; - } - } else if constexpr ( requires (VTX v){ VTX::value_type; }) { + using ArrX = VecDataArray; + + ArrX ax = std::bit_cast(vs0.data); + return ax; + } else { using Tx = VTX::value_type; - a.p[index] = (Tx) _vs0; - i++; - } - - return var_t{RetPair{a, i}}; + return RetArr<1>{(Tx)vs0}; + } }; constexpr vec() = default; - constexpr vec(arithmetic auto scalar) : EC{.data= [scalar,this](){ auto s = [scalar](){ return scalar; }; return ctor_scalar(s); }() } {} + constexpr vec(arithmetic auto scalar) : EC{.data= [scalar](){ auto s = [scalar](){ return scalar; }; return ctor_scalar(s); }() } {} template requires (Lx == 1 && NotVec1) - constexpr vec(vec v) : EC{.data= [d=std::bit_cast>(v.data),this](){ auto s = [scalar=d.p[0]](){ return scalar; }; return ctor_scalar(s); }() } {} + constexpr vec(vec v) : EC{.data= [d=std::bit_cast>(v.data)](){ auto s = [scalar=d.p[0]](){ return scalar; }; return ctor_scalar(s); }() } {} template requires (L == 1 || Lx != 1) - constexpr vec(vec v) : EC{.data= [v, this](){ auto vv = [v](){ return v; }; return ctor(vv); }() } {} + constexpr vec(vec v) : EC{.data= [v](){ auto vv = [v](){ return v; }; return ctor(vv); }() } {} template requires (sizeof...(Scalar) == L) constexpr vec(Scalar... scalar) @@ -329,26 +332,38 @@ namespace glm }() } {} - template requires (sizeof...(VecOrScalar) > 1 && NotSameArithmeticTypes()) - constexpr vec(VecOrScalar... vecOrScalar) + template requires (sizeof...(VecOrScalar) >= 1 && NotSameArithmeticTypes()) + constexpr vec(VecOrScalar0 vecOrScalar0, VecOrScalar... vecOrScalar) : EC - {.data= [vecOrScalar...]() -> data_t + {.data= [vecOrScalar0, vecOrScalar...]() -> data_t { //type_vecx.inl never had any simd versions for ctor from mixes of scalars & vectors, //so I don't really need to figure out how I'd make a generic simd version for this ctor - DataArray a {}; - length_t i = 0; - using var_t = std::variant; - for (auto var_vs : std::array{ vecOrScalar... } ) { - auto visitee = [i](auto&& arg) -> var_t { return ctor_mixed_constexpr_single.template operator()(arg, i); }; - RetPair pair = std::get(std::visit(visitee, var_vs)); - for (length_t j = pair.i; j < i+pair.i; j++) { - a.p[j] = pair.a.p[j]; + + constexpr auto i = ctor_mixed_constexpr_single_get_length(); + struct PaddedA { + VecDataArray a; + unsigned char padding[sizeof(VecDataArray) - sizeof(VecDataArray)]; + }; + PaddedA aa = {.a=ctor_mixed_constexpr_single(vecOrScalar0)}; + constexpr std::array lengths = { ctor_mixed_constexpr_single_get_length()...}; + const auto params = std::tuple{vecOrScalar...}; + + const auto arr = ctor_mixed_constexpr_single(std::get<0>(params)); + std::memcpy(aa.a.p.begin()+i, arr, sizeof(T)*lengths[0]); + constexpr auto i2 = i + lengths[0]; + + if constexpr (sizeof...(VecOrScalar) > 1) { + const auto arr2 = ctor_mixed_constexpr_single(std::get<1>(params)); + std::memcpy(aa.a.p.begin()+i2, arr2, sizeof(T)*lengths[1]); + constexpr auto i3 = i2 + lengths[1]; + if constexpr (sizeof...(VecOrScalar) > 2) { + const auto arr3 = ctor_mixed_constexpr_single(std::get<2>(params)); + std::memcpy(aa.a.p.begin()+i3, arr3, sizeof(T)*lengths[2]); } - i+=pair.i; } - return std::bit_cast(a); + return std::bit_cast(aa); }() } {} @@ -363,70 +378,118 @@ namespace glm inline GLM_CONSTEXPR vec& operator+=(arithmetic auto scalar) { - return (*this = detail::compute_vec_add::value>::call(*this, vec(scalar))); + if constexpr (L < 3) { + this->data += scalar; + return *this; + } else + return (*this = detail::compute_vec_add::value>::call(*this, vec(scalar))); } template inline GLM_CONSTEXPR vec & operator+=(vec<1, Tx, Q> v) requires (NotVec1) { - return (*this = detail::compute_vec_add::value>::call(*this, vec(v.x))); + if constexpr (L < 3) { + this->data += v.data; + return *this; + } else + return (*this = detail::compute_vec_add::value>::call(*this, vec(v.x))); } template inline GLM_CONSTEXPR vec & operator+=(vec v) { - return (*this = detail::compute_vec_add::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data += v.data; + return *this; + } else + return (*this = detail::compute_vec_add::value>::call(*this, vec(v))); } inline GLM_CONSTEXPR vec & operator-=(arithmetic auto scalar) { - return (*this = detail::compute_vec_sub::value>::call(*this, vec(scalar))); + if constexpr (L < 3) { + this->data -= scalar; + return *this; + } else + return (*this = detail::compute_vec_sub::value>::call(*this, vec(scalar))); } template inline GLM_CONSTEXPR vec & operator-=(vec<1, Tx, Q> v) requires (NotVec1) { - return (*this = detail::compute_vec_sub::value>::call(*this, vec(v.x))); + if constexpr (L < 3) { + this->data -= v.data; + return *this; + } else + return (*this = detail::compute_vec_sub::value>::call(*this, vec(v.x))); } template inline GLM_CONSTEXPR vec & operator-=(vec v) { - return (*this = detail::compute_vec_sub::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data -= v.data; + return *this; + } else + return (*this = detail::compute_vec_sub::value>::call(*this, vec(v))); } inline GLM_CONSTEXPR vec & operator*=(arithmetic auto scalar) { - return (*this = detail::compute_vec_mul::value>::call(*this, vec(scalar))); + if constexpr (L < 3) { + this->data *= scalar; + return *this; + } else + return (*this = detail::compute_vec_mul::value>::call(*this, vec(scalar))); } template inline GLM_CONSTEXPR vec & operator*=(vec<1, Tx, Q> v) requires (NotVec1) { - return (*this = detail::compute_vec_mul::value>::call(*this, vec(v.x))); + if constexpr (L < 3) { + this->data *= v.data; + return *this; + } else + return (*this = detail::compute_vec_mul::value>::call(*this, vec(v.x))); } template inline GLM_CONSTEXPR vec & operator*=(vec v) { - return (*this = detail::compute_vec_mul::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data *= v.data; + return *this; + } else + return (*this = detail::compute_vec_mul::value>::call(*this, vec(v))); } inline GLM_CONSTEXPR vec & operator/=(arithmetic auto scalar) { + if constexpr (L < 3) { + this->data /= scalar; + return *this; + } else return (*this = detail::compute_vec_div::value>::call(*this, vec(scalar))); } template inline GLM_CONSTEXPR vec & operator/=(vec<1, Tx, Q> v) requires (NotVec1) { - return (*this = detail::compute_vec_div::value>::call(*this, vec(v.x))); + if constexpr (L < 3) { + this->data /= v.data; + return *this; + } else + return (*this = detail::compute_vec_div::value>::call(*this, vec(v.x))); } template inline GLM_CONSTEXPR vec & operator/=(vec v) { - return (*this = detail::compute_vec_div::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data /= v.data; + return *this; + } else + return (*this = detail::compute_vec_div::value>::call(*this, vec(v))); } // -- Increment and decrement operators -- @@ -467,64 +530,108 @@ namespace glm inline GLM_CONSTEXPR vec & operator%=(arithmetic auto scalar) { - return (*this = detail::compute_vec_mod::value>::call(*this, vec(scalar))); + if constexpr (L < 3) { + this->data %= scalar; + return *this; + } else + return (*this = detail::compute_vec_mod::value>::call(*this, vec(scalar))); } template inline GLM_CONSTEXPR vec & operator%=(vec<1, Tx, Q> v) requires (NotVec1) { - return (*this = detail::compute_vec_mod::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data *= v.data; + return *this; + } else + return (*this = detail::compute_vec_mod::value>::call(*this, vec(v))); } template inline GLM_CONSTEXPR vec & operator%=(vec v) { - return (*this = detail::compute_vec_mod::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data %= v.data; + return *this; + } else + return (*this = detail::compute_vec_mod::value>::call(*this, vec(v))); } inline GLM_CONSTEXPR vec & operator&=(arithmetic auto scalar) { - return (*this = detail::compute_vec_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(scalar))); + if constexpr (L < 3) { + this->data &= scalar; + return *this; + } else + return (*this = detail::compute_vec_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(scalar))); } template inline GLM_CONSTEXPR vec & operator&=(vec<1, Tx, Q> v) requires (NotVec1) { - return (*this = detail::compute_vec_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data &= v.data; + return *this; + } else + return (*this = detail::compute_vec_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); } template inline GLM_CONSTEXPR vec & operator&=(vec v) { - return (*this = detail::compute_vec_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data &= v.data; + return *this; + } else + return (*this = detail::compute_vec_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); } inline GLM_CONSTEXPR vec & operator|=(arithmetic auto scalar) { - return (*this = detail::compute_vec_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(scalar))); + if constexpr (L < 3) { + this->data |= scalar; + return *this; + } else + return (*this = detail::compute_vec_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(scalar))); } template inline GLM_CONSTEXPR vec & operator|=(vec<1, Tx, Q> const& v) requires (NotVec1) { - return (*this = detail::compute_vec_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data |= v.data; + return *this; + } else + return (*this = detail::compute_vec_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); } template inline GLM_CONSTEXPR vec & operator|=(vec const& v) { - return (*this = detail::compute_vec_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data |= v.data; + return *this; + } else + return (*this = detail::compute_vec_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); } inline GLM_CONSTEXPR vec & operator^=(arithmetic auto scalar) { - return (*this = detail::compute_vec_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(scalar))); + if constexpr (L < 3) { + this->data ^= scalar; + return *this; + } else + return (*this = detail::compute_vec_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(scalar))); } template inline GLM_CONSTEXPR vec & operator^=(vec<1, Tx, Q> const& v) requires (NotVec1) { - return (*this = detail::compute_vec_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data ^= v.data; + return *this; + } else + return (*this = detail::compute_vec_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); } template @@ -535,36 +642,60 @@ namespace glm inline GLM_CONSTEXPR vec & operator<<=(arithmetic auto scalar) { - return (*this = detail::compute_vec_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(scalar))); + if constexpr (L < 3) { + this->data <<= scalar; + return *this; + } else + return (*this = detail::compute_vec_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(scalar))); } template inline GLM_CONSTEXPR vec & operator<<=(vec<1, Tx, Q> const& v) requires (NotVec1) { - return (*this = detail::compute_vec_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data <<= v.data; + return *this; + } else + return (*this = detail::compute_vec_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); } template inline GLM_CONSTEXPR vec & operator<<=(vec const& v) { - return (*this = detail::compute_vec_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data <<= v.data; + return *this; + } else + return (*this = detail::compute_vec_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); } inline GLM_CONSTEXPR vec & operator>>=(arithmetic auto scalar) { - return (*this = detail::compute_vec_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(scalar))); + if constexpr (L < 3) { + this->data >>= scalar; + return *this; + } else + return (*this = detail::compute_vec_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(scalar))); } template inline GLM_CONSTEXPR vec & operator>>=(vec<1, Tx, Q> const& v) requires (NotVec1) { - return (*this = detail::compute_vec_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data >>= v.data; + return *this; + } else + return (*this = detail::compute_vec_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); } template inline GLM_CONSTEXPR vec & operator>>=(vec const& v) { - return (*this = detail::compute_vec_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); + if constexpr (L < 3) { + this->data >>= v.data; + return *this; + } else + return (*this = detail::compute_vec_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec(v))); } // -- Unary constant operators -- @@ -905,4 +1036,6 @@ namespace glm { return vec(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z, v1.w || v2.w); } -} \ No newline at end of file +} +static_assert( glm::detail::is_aligned<(glm::qualifier)0>::value == false); +static_assert(sizeof(glm::vec<3, float, (glm::qualifier)0>) == 12); \ No newline at end of file