constexpr simd vec: various improvements

This commit is contained in:
sharkautarch 2024-09-13 21:45:08 -04:00
parent 6b6f0e4cc5
commit 012df5e3cc
No known key found for this signature in database
GPG Key ID: F270CA9462164405
5 changed files with 251 additions and 98 deletions

View File

@ -108,6 +108,28 @@ namespace detail
# endif # endif
# if GLM_ARCH & GLM_ARCH_SSE2_BIT # if GLM_ARCH & GLM_ARCH_SSE2_BIT
#if defined(__clang__) || defined(__GNUC__)
template<typename T>
struct storage<2, T, false>
{
typedef T type __attribute__((aligned(sizeof(T)),vector_size(2*sizeof(T))));
};
template<typename T>
struct storage<1, T, false>
{
typedef T type __attribute__((aligned(1),vector_size(sizeof(T))));
};
template<typename T>
struct storage<2, T, true>
{
typedef T type __attribute__((aligned(sizeof(T)),vector_size(2*sizeof(T))));
};
template<typename T>
struct storage<1, T, true>
{
typedef T type __attribute__((aligned(sizeof(T)),vector_size(sizeof(T))));
};
#endif
template<> template<>
struct storage<4, float, true> struct storage<4, float, true>
{ {

View File

@ -297,7 +297,7 @@
// N2235 Generalized Constant Expressions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf // 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 // 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 # define GLM_HAS_CONSTEXPR 0
#elif (GLM_COMPILER & GLM_COMPILER_CLANG) #elif (GLM_COMPILER & GLM_COMPILER_CLANG)
# define GLM_HAS_CONSTEXPR __has_feature(cxx_relaxed_constexpr) # define GLM_HAS_CONSTEXPR __has_feature(cxx_relaxed_constexpr)

View File

@ -2,12 +2,11 @@
namespace glm::detail namespace glm::detail
{ {
consteval bool NotEmpty(length_t I, length_t L) { return I <= L; } consteval bool NotEmpty(length_t I, length_t L) { return I <= L; }
template <qualifier Q, typename T, length_t L>
template <typename DataWrapper, typename T, length_t L>
struct ElementCollection; struct ElementCollection;
template <typename DataWrapper, typename T> template <qualifier Q, typename T>
struct ElementCollection<DataWrapper, T, 4> { struct ElementCollection<Q, T, 4> {
using data_t = DataWrapper::data_t; using data_t = typename detail::storage<4, T, detail::is_aligned<Q>::value>::type;
union union
{ {
struct { struct {
@ -20,46 +19,45 @@ namespace glm::detail
}; };
}; };
struct Empty {};
#define G [[no_unique_address]] template <qualifier Q, typename T>
template <typename DataWrapper, typename T> struct ElementCollection<Q, T, 3> {
struct ElementCollection<DataWrapper, T, 3> { using data_t = typename detail::storage<3, T, detail::is_aligned<Q>::value>::type;
using data_t = DataWrapper::data_t; struct w {}; struct a {}; struct q{};
union union
{ {
struct { struct {
union { T x, r, s; }; union { T x, r, s; };
union { T y, g, t; }; union { T y, g, t; };
union { T z, b, p; }; union { T z, b, p; };
union { G Empty w, a, q; };
}; };
data_t data; data_t data;
}; };
}; };
template <typename DataWrapper, typename T> template <qualifier Q, typename T>
struct ElementCollection<DataWrapper, T, 2> { struct ElementCollection<Q, T, 2> {
using data_t = DataWrapper::data_t; using data_t = typename detail::storage<2, T, detail::is_aligned<Q>::value>::type;
struct z {}; struct b {}; struct p{};
struct w {}; struct a {}; struct q{};
union union
{ {
struct { struct {
union { T x, r, s; }; union { T x, r, s; };
union { T y, g, t; }; union { T y, g, t; };
union { G Empty z, b, p; };
union { G Empty w, a, q; };
}; };
data_t data; data_t data;
}; };
}; };
template <typename DataWrapper, typename T> template <qualifier Q, typename T>
struct ElementCollection<DataWrapper, T, 1> { struct ElementCollection<Q, T, 1> {
using data_t = DataWrapper::data_t; using data_t = typename detail::storage<1, T, detail::is_aligned<Q>::value>::type;
struct y {}; struct g {}; struct t{};
struct z {}; struct b {}; struct p{};
struct w {}; struct a {}; struct q{};
union union
{ {
struct { struct {
union { T x, r, s; }; 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; data_t data;
}; };

View File

@ -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 //assuming that number of scalars is always the same as the length of the to-be-constructed vector
using Tx = typename GetFirstType<A...>::FirstTx; using Tx = typename GetFirstType<A...>::FirstTx;
using OtherPaddedVec = PaddedVec<L, Tx, Q>; using OtherPaddedVec = PaddedVec<L, Tx, Q>;
OtherPaddedVec o = {.gcc_vec={Tx(scalars)...}}; typename OtherPaddedVec::GccV o = {Tx(scalars)...};
PaddedVec<L, T, Q> converted = {.gcc_vec=__builtin_convertvector(o.gcc_vec, gcc_vec_t)}; PaddedVec<L, T, Q> converted = {.gcc_vec=__builtin_convertvector(o, gcc_vec_t)};
return gcc_vec_to_data(converted); return gcc_vec_to_data(converted);
} }
}; };

View File

@ -13,6 +13,7 @@
#include <array> #include <array>
#include <variant> #include <variant>
#include <cstring> #include <cstring>
#include <ranges>
namespace glm namespace glm
{ {
template <length_t L> template <length_t L>
@ -40,7 +41,7 @@ namespace glm
namespace detail namespace detail
{ {
template <length_t L, typename T, qualifier Q> template <length_t L, typename T, qualifier Q>
using _ArrT = T[L]; using _ArrT = std::array<T,L>;
template <length_t L, typename T, qualifier Q> template <length_t L, typename T, qualifier Q>
using _data_t = typename detail::storage<L, T, detail::is_aligned<Q>::value>::type; using _data_t = typename detail::storage<L, T, detail::is_aligned<Q>::value>::type;
@ -115,9 +116,9 @@ namespace glm
using data_t = detail::_data_t<L, T, Q>; using data_t = detail::_data_t<L, T, Q>;
}; };
template <length_t L, typename T, qualifier Q> template <length_t L, typename T, qualifier Q>
using EC = detail::ElementCollection<DataWrapper<L, T, Q>, T, L>; using EC = detail::ElementCollection<Q, T, L>;
template<length_t L, typename T, qualifier Q> template<length_t L, typename T, qualifier Q>
struct vec : detail::ElementCollection<DataWrapper<L, T, Q>, T, L> struct vec : detail::ElementCollection<Q, T, L>
{ {
// -- Data -- // -- Data --
using EC<L, T, Q>::x; using EC<L, T, Q>::x;
@ -142,6 +143,7 @@ namespace glm
typedef vec<L, T, Q> type; typedef vec<L, T, Q> type;
typedef vec<L, bool, Q> bool_type; typedef vec<L, bool, Q> bool_type;
static constexpr qualifier k_qual = Q; static constexpr qualifier k_qual = Q;
static constexpr length_t k_len = L;
enum is_aligned enum is_aligned
{ {
@ -247,7 +249,7 @@ namespace glm
# endif # endif
template <typename ScalarGetter> template <typename ScalarGetter>
constexpr auto ctor_scalar(ScalarGetter scalar) { static constexpr auto ctor_scalar(ScalarGetter scalar) {
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
DataArray a; DataArray a;
for (length_t i = 0; i < L; i++) { for (length_t i = 0; i < L; i++) {
@ -260,7 +262,7 @@ namespace glm
} }
template <typename VecGetter> template <typename VecGetter>
constexpr auto ctor(VecGetter vecGetter) { static constexpr auto ctor(VecGetter vecGetter) {
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
DataArray a = {}; DataArray a = {};
auto v = vecGetter(); auto v = vecGetter();
@ -276,44 +278,45 @@ namespace glm
return SimdHlp::simd_ctor(vecGetter()); return SimdHlp::simd_ctor(vecGetter());
} }
} }
template <length_t len>
using RetArr = T[len];
typedef struct { template <typename Vs0>
DataArray a; static constexpr length_t ctor_mixed_constexpr_single_get_length()
length_t i;
} RetPair;
static inline auto ctor_mixed_constexpr_single = []<typename var_t>(auto&& vs0, length_t index) -> var_t
{ {
DataArray a {}; if constexpr ( std::is_integral_v<Vs0> || std::is_floating_point_v<Vs0> ) {
using VTX = std::decay_t<decltype(vs0)>; return 1;
length_t i = 0; } else if constexpr ( ( requires { Vs0::k_len; }) ) {
auto&& __restrict__ _vs0 = vs0; 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<VTX> || std::is_floating_point_v<VTX> ) { if constexpr ( std::is_integral_v<VTX> || std::is_floating_point_v<VTX> ) {
a.p[index] = _vs0; return RetArr<1>{vs0};
i++; } else if constexpr ( ( requires { VTX::k_len; }) ) {
} else if constexpr ( ( requires (VTX v){ VTX::value_type; _vs0.length(); }) ) {
using Tx = VTX::value_type; using Tx = VTX::value_type;
using ArrX = VecDataArray<_vs0.length(), Tx, VTX::k_qual>; using ArrX = VecDataArray<VTX::k_len, Tx, VTX::k_qual>;
ArrX ax = std::bit_cast<ArrX>(_vs0.data);
for (Tx tx : ax.p) { ArrX ax = std::bit_cast<ArrX>(vs0.data);
a.p[index+i++] = (T)tx; return ax;
} } else {
} else if constexpr ( requires (VTX v){ VTX::value_type; }) {
using Tx = VTX::value_type; using Tx = VTX::value_type;
a.p[index] = (Tx) _vs0; return RetArr<1>{(Tx)vs0};
i++; }
}
return var_t{RetPair{a, i}};
}; };
constexpr vec() = default; constexpr vec() = default;
constexpr vec(arithmetic auto scalar) : EC<L, T, Q>{.data= [scalar,this](){ auto s = [scalar](){ return scalar; }; return ctor_scalar(s); }() } {} constexpr vec(arithmetic auto scalar) : EC<L, T, Q>{.data= [scalar](){ auto s = [scalar](){ return scalar; }; return ctor_scalar(s); }() } {}
template <length_t Lx, typename Tx, qualifier Qx> requires (Lx == 1 && NotVec1<L>) template <length_t Lx, typename Tx, qualifier Qx> requires (Lx == 1 && NotVec1<L>)
constexpr vec(vec<Lx, Tx, Qx> v) : EC<L, T, Q>{.data= [d=std::bit_cast<VecDataArray<Lx, Tx, Qx>>(v.data),this](){ auto s = [scalar=d.p[0]](){ return scalar; }; return ctor_scalar(s); }() } {} constexpr vec(vec<Lx, Tx, Qx> v) : EC<L, T, Q>{.data= [d=std::bit_cast<VecDataArray<Lx, Tx, Qx>>(v.data)](){ auto s = [scalar=d.p[0]](){ return scalar; }; return ctor_scalar(s); }() } {}
template <length_t Lx, typename Tx, qualifier Qx> requires (L == 1 || Lx != 1) template <length_t Lx, typename Tx, qualifier Qx> requires (L == 1 || Lx != 1)
constexpr vec(vec<Lx, Tx, Qx> v) : EC<L, T, Q>{.data= [v, this](){ auto vv = [v](){ return v; }; return ctor(vv); }() } {} constexpr vec(vec<Lx, Tx, Qx> v) : EC<L, T, Q>{.data= [v](){ auto vv = [v](){ return v; }; return ctor(vv); }() } {}
template <arithmetic... Scalar> requires (sizeof...(Scalar) == L) template <arithmetic... Scalar> requires (sizeof...(Scalar) == L)
constexpr vec(Scalar... scalar) constexpr vec(Scalar... scalar)
@ -329,26 +332,38 @@ namespace glm
}() }()
} {} } {}
template <typename... VecOrScalar> requires (sizeof...(VecOrScalar) > 1 && NotSameArithmeticTypes<VecOrScalar...>()) template <typename VecOrScalar0, typename... VecOrScalar> requires (sizeof...(VecOrScalar) >= 1 && NotSameArithmeticTypes<VecOrScalar0, VecOrScalar...>())
constexpr vec(VecOrScalar... vecOrScalar) constexpr vec(VecOrScalar0 vecOrScalar0, VecOrScalar... vecOrScalar)
: EC<L, T, Q> : EC<L, T, Q>
{.data= [vecOrScalar...]() -> data_t {.data= [vecOrScalar0, vecOrScalar...]() -> data_t
{ {
//type_vecx.inl never had any simd versions for ctor from mixes of scalars & vectors, //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 //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; constexpr auto i = ctor_mixed_constexpr_single_get_length<VecOrScalar0>();
using var_t = std::variant<VecOrScalar..., RetPair>; struct PaddedA {
for (auto var_vs : std::array<var_t, sizeof...(vecOrScalar)>{ vecOrScalar... } ) { VecDataArray<i, T, Q> a;
auto visitee = [i](auto&& arg) -> var_t { return ctor_mixed_constexpr_single.template operator()<var_t>(arg, i); }; unsigned char padding[sizeof(VecDataArray<L, T, Q>) - sizeof(VecDataArray<i, T, Q>)];
RetPair pair = std::get<RetPair>(std::visit(visitee, var_vs)); };
for (length_t j = pair.i; j < i+pair.i; j++) { PaddedA aa = {.a=ctor_mixed_constexpr_single(vecOrScalar0)};
a.p[j] = pair.a.p[j]; constexpr std::array<length_t, sizeof...(VecOrScalar)> lengths = { ctor_mixed_constexpr_single_get_length<VecOrScalar>()...};
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<data_t>(a); return std::bit_cast<data_t>(aa);
}() }()
} {} } {}
@ -363,70 +378,118 @@ namespace glm
inline GLM_CONSTEXPR vec<L, T, Q>& operator+=(arithmetic auto scalar) inline GLM_CONSTEXPR vec<L, T, Q>& operator+=(arithmetic auto scalar)
{ {
return (*this = detail::compute_vec_add<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar))); if constexpr (L < 3) {
this->data += scalar;
return *this;
} else
return (*this = detail::compute_vec_add<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator+=(vec<1, Tx, Q> v) requires (NotVec1<L>) inline GLM_CONSTEXPR vec<L, T, Q> & operator+=(vec<1, Tx, Q> v) requires (NotVec1<L>)
{ {
return (*this = detail::compute_vec_add<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v.x))); if constexpr (L < 3) {
this->data += v.data;
return *this;
} else
return (*this = detail::compute_vec_add<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v.x)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator+=(vec<L, Tx, Q> v) inline GLM_CONSTEXPR vec<L, T, Q> & operator+=(vec<L, Tx, Q> v)
{ {
return (*this = detail::compute_vec_add<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data += v.data;
return *this;
} else
return (*this = detail::compute_vec_add<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
inline GLM_CONSTEXPR vec<L, T, Q> & operator-=(arithmetic auto scalar) inline GLM_CONSTEXPR vec<L, T, Q> & operator-=(arithmetic auto scalar)
{ {
return (*this = detail::compute_vec_sub<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar))); if constexpr (L < 3) {
this->data -= scalar;
return *this;
} else
return (*this = detail::compute_vec_sub<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator-=(vec<1, Tx, Q> v) requires (NotVec1<L>) inline GLM_CONSTEXPR vec<L, T, Q> & operator-=(vec<1, Tx, Q> v) requires (NotVec1<L>)
{ {
return (*this = detail::compute_vec_sub<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v.x))); if constexpr (L < 3) {
this->data -= v.data;
return *this;
} else
return (*this = detail::compute_vec_sub<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v.x)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator-=(vec<L, Tx, Q> v) inline GLM_CONSTEXPR vec<L, T, Q> & operator-=(vec<L, Tx, Q> v)
{ {
return (*this = detail::compute_vec_sub<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data -= v.data;
return *this;
} else
return (*this = detail::compute_vec_sub<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
inline GLM_CONSTEXPR vec<L, T, Q> & operator*=(arithmetic auto scalar) inline GLM_CONSTEXPR vec<L, T, Q> & operator*=(arithmetic auto scalar)
{ {
return (*this = detail::compute_vec_mul<L,T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar))); if constexpr (L < 3) {
this->data *= scalar;
return *this;
} else
return (*this = detail::compute_vec_mul<L,T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator*=(vec<1, Tx, Q> v) requires (NotVec1<L>) inline GLM_CONSTEXPR vec<L, T, Q> & operator*=(vec<1, Tx, Q> v) requires (NotVec1<L>)
{ {
return (*this = detail::compute_vec_mul<L,T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v.x))); if constexpr (L < 3) {
this->data *= v.data;
return *this;
} else
return (*this = detail::compute_vec_mul<L,T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v.x)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator*=(vec<L, Tx, Q> v) inline GLM_CONSTEXPR vec<L, T, Q> & operator*=(vec<L, Tx, Q> v)
{ {
return (*this = detail::compute_vec_mul<L,T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data *= v.data;
return *this;
} else
return (*this = detail::compute_vec_mul<L,T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
inline GLM_CONSTEXPR vec<L, T, Q> & operator/=(arithmetic auto scalar) inline GLM_CONSTEXPR vec<L, T, Q> & operator/=(arithmetic auto scalar)
{ {
if constexpr (L < 3) {
this->data /= scalar;
return *this;
} else
return (*this = detail::compute_vec_div<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar))); return (*this = detail::compute_vec_div<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator/=(vec<1, Tx, Q> v) requires (NotVec1<L>) inline GLM_CONSTEXPR vec<L, T, Q> & operator/=(vec<1, Tx, Q> v) requires (NotVec1<L>)
{ {
return (*this = detail::compute_vec_div<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v.x))); if constexpr (L < 3) {
this->data /= v.data;
return *this;
} else
return (*this = detail::compute_vec_div<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v.x)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator/=(vec<L, Tx, Q> v) inline GLM_CONSTEXPR vec<L, T, Q> & operator/=(vec<L, Tx, Q> v)
{ {
return (*this = detail::compute_vec_div<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data /= v.data;
return *this;
} else
return (*this = detail::compute_vec_div<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
// -- Increment and decrement operators -- // -- Increment and decrement operators --
@ -467,64 +530,108 @@ namespace glm
inline GLM_CONSTEXPR vec<L, T, Q> & operator%=(arithmetic auto scalar) inline GLM_CONSTEXPR vec<L, T, Q> & operator%=(arithmetic auto scalar)
{ {
return (*this = detail::compute_vec_mod<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar))); if constexpr (L < 3) {
this->data %= scalar;
return *this;
} else
return (*this = detail::compute_vec_mod<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator%=(vec<1, Tx, Q> v) requires (NotVec1<L>) inline GLM_CONSTEXPR vec<L, T, Q> & operator%=(vec<1, Tx, Q> v) requires (NotVec1<L>)
{ {
return (*this = detail::compute_vec_mod<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data *= v.data;
return *this;
} else
return (*this = detail::compute_vec_mod<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator%=(vec<L, Tx, Q> v) inline GLM_CONSTEXPR vec<L, T, Q> & operator%=(vec<L, Tx, Q> v)
{ {
return (*this = detail::compute_vec_mod<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data %= v.data;
return *this;
} else
return (*this = detail::compute_vec_mod<L, T, Q, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
inline GLM_CONSTEXPR vec<L, T, Q> & operator&=(arithmetic auto scalar) inline GLM_CONSTEXPR vec<L, T, Q> & operator&=(arithmetic auto scalar)
{ {
return (*this = detail::compute_vec_and<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar))); if constexpr (L < 3) {
this->data &= scalar;
return *this;
} else
return (*this = detail::compute_vec_and<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator&=(vec<1, Tx, Q> v) requires (NotVec1<L>) inline GLM_CONSTEXPR vec<L, T, Q> & operator&=(vec<1, Tx, Q> v) requires (NotVec1<L>)
{ {
return (*this = detail::compute_vec_and<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data &= v.data;
return *this;
} else
return (*this = detail::compute_vec_and<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator&=(vec<L, Tx, Q> v) inline GLM_CONSTEXPR vec<L, T, Q> & operator&=(vec<L, Tx, Q> v)
{ {
return (*this = detail::compute_vec_and<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data &= v.data;
return *this;
} else
return (*this = detail::compute_vec_and<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
inline GLM_CONSTEXPR vec<L, T, Q> & operator|=(arithmetic auto scalar) inline GLM_CONSTEXPR vec<L, T, Q> & operator|=(arithmetic auto scalar)
{ {
return (*this = detail::compute_vec_or<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar))); if constexpr (L < 3) {
this->data |= scalar;
return *this;
} else
return (*this = detail::compute_vec_or<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator|=(vec<1, Tx, Q> const& v) requires (NotVec1<L>) inline GLM_CONSTEXPR vec<L, T, Q> & operator|=(vec<1, Tx, Q> const& v) requires (NotVec1<L>)
{ {
return (*this = detail::compute_vec_or<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data |= v.data;
return *this;
} else
return (*this = detail::compute_vec_or<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator|=(vec<L, Tx, Q> const& v) inline GLM_CONSTEXPR vec<L, T, Q> & operator|=(vec<L, Tx, Q> const& v)
{ {
return (*this = detail::compute_vec_or<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data |= v.data;
return *this;
} else
return (*this = detail::compute_vec_or<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
inline GLM_CONSTEXPR vec<L, T, Q> & operator^=(arithmetic auto scalar) inline GLM_CONSTEXPR vec<L, T, Q> & operator^=(arithmetic auto scalar)
{ {
return (*this = detail::compute_vec_xor<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar))); if constexpr (L < 3) {
this->data ^= scalar;
return *this;
} else
return (*this = detail::compute_vec_xor<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator^=(vec<1, Tx, Q> const& v) requires (NotVec1<L>) inline GLM_CONSTEXPR vec<L, T, Q> & operator^=(vec<1, Tx, Q> const& v) requires (NotVec1<L>)
{ {
return (*this = detail::compute_vec_xor<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data ^= v.data;
return *this;
} else
return (*this = detail::compute_vec_xor<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
template<typename Tx> template<typename Tx>
@ -535,36 +642,60 @@ namespace glm
inline GLM_CONSTEXPR vec<L, T, Q> & operator<<=(arithmetic auto scalar) inline GLM_CONSTEXPR vec<L, T, Q> & operator<<=(arithmetic auto scalar)
{ {
return (*this = detail::compute_vec_shift_left<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar))); if constexpr (L < 3) {
this->data <<= scalar;
return *this;
} else
return (*this = detail::compute_vec_shift_left<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator<<=(vec<1, Tx, Q> const& v) requires (NotVec1<L>) inline GLM_CONSTEXPR vec<L, T, Q> & operator<<=(vec<1, Tx, Q> const& v) requires (NotVec1<L>)
{ {
return (*this = detail::compute_vec_shift_left<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data <<= v.data;
return *this;
} else
return (*this = detail::compute_vec_shift_left<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator<<=(vec<L, Tx, Q> const& v) inline GLM_CONSTEXPR vec<L, T, Q> & operator<<=(vec<L, Tx, Q> const& v)
{ {
return (*this = detail::compute_vec_shift_left<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data <<= v.data;
return *this;
} else
return (*this = detail::compute_vec_shift_left<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
inline GLM_CONSTEXPR vec<L, T, Q> & operator>>=(arithmetic auto scalar) inline GLM_CONSTEXPR vec<L, T, Q> & operator>>=(arithmetic auto scalar)
{ {
return (*this = detail::compute_vec_shift_right<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar))); if constexpr (L < 3) {
this->data >>= scalar;
return *this;
} else
return (*this = detail::compute_vec_shift_right<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(scalar)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator>>=(vec<1, Tx, Q> const& v) requires (NotVec1<L>) inline GLM_CONSTEXPR vec<L, T, Q> & operator>>=(vec<1, Tx, Q> const& v) requires (NotVec1<L>)
{ {
return (*this = detail::compute_vec_shift_right<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data >>= v.data;
return *this;
} else
return (*this = detail::compute_vec_shift_right<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
template<typename Tx> template<typename Tx>
inline GLM_CONSTEXPR vec<L, T, Q> & operator>>=(vec<L, Tx, Q> const& v) inline GLM_CONSTEXPR vec<L, T, Q> & operator>>=(vec<L, Tx, Q> const& v)
{ {
return (*this = detail::compute_vec_shift_right<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v))); if constexpr (L < 3) {
this->data >>= v.data;
return *this;
} else
return (*this = detail::compute_vec_shift_right<L, T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<L, T, Q>(v)));
} }
// -- Unary constant operators -- // -- Unary constant operators --
@ -905,4 +1036,6 @@ namespace glm
{ {
return vec<Lx, bool, Qx>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z, v1.w || v2.w); return vec<Lx, bool, Qx>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z, v1.w || v2.w);
} }
} }
static_assert( glm::detail::is_aligned<(glm::qualifier)0>::value == false);
static_assert(sizeof(glm::vec<3, float, (glm::qualifier)0>) == 12);