wip: constexpr vec (constructors) when using simd

This commit is contained in:
sharkautarch 2024-09-10 23:12:03 -04:00
parent 33b4a621a6
commit 9806342de0
No known key found for this signature in database
GPG Key ID: F270CA9462164405
5 changed files with 751 additions and 3 deletions

View File

@ -0,0 +1,394 @@
#include <iostream>
namespace glm::detail
{
consteval bool NotEmpty(length_t I, length_t L) { return I <= L; }
template <bool IsEmpty, typename T, length_t I, length_t L>
struct Element
{
constexpr operator auto() {
return 0;
}
constexpr decltype(auto) operator=(auto thing) {
return *this;
}
constexpr std::ostream& operator<<(std::ostream& os)
{
return os;
}
// prefix increment
constexpr decltype(auto) operator++() requires requires (T first) { first++; }
{
return *this; // return new value by reference
}
// postfix increment
constexpr decltype(auto) operator++(auto) requires requires (T first) { first++; }
{
return *this;
}
// prefix decrement
constexpr decltype(auto) operator--() requires requires (T first) { first--; }
{
return *this; // return new value by reference
}
// postfix decrement
constexpr decltype(auto) operator--(auto) requires requires (T first) { first--; }
{
return *this;
}
constexpr decltype(auto) operator+=(auto a) requires requires (T first, decltype(rhs) r) { first + r; }
{
return *this;
}
constexpr decltype(auto) operator-=(auto a) requires requires (T first, decltype(rhs) r) { first - r; }
{
return *this;
}
constexpr decltype(auto) operator*=(auto a) requires requires (T first, decltype(rhs) r) { first * r; }
{
return *this;
}
constexpr decltype(auto) operator/=(auto a) requires requires (T first, decltype(rhs) r) { first / r; }
{
return *this;
}
constexpr decltype(auto) operator%=(auto a) requires requires (T first, decltype(rhs) r) { first % r; }
{
return *this;
}
constexpr decltype(auto) operator&=(auto a) requires requires (T first, decltype(rhs) r) { first & r; }
{
return *this;
}
constexpr decltype(auto) operator|=(auto a) requires requires (T first, decltype(rhs) r) { first | r; }
{
return *this;
}
constexpr decltype(auto) operator^=(auto a) requires requires (T first, decltype(rhs) r) { first ^ r; }
{
return *this;
}
constexpr decltype(auto) operator<<=(auto a) requires requires (T first, decltype(rhs) r) { first << r; }
{
return *this;
}
constexpr decltype(auto) operator>>=(auto a) requires requires (T first, decltype(rhs) r) { first >> r; }
{
return *this;
}
constexpr decltype(auto) operator+(auto rhs) requires requires (T first, decltype(rhs) r) { first + r; }
{
return rhs;
}
constexpr decltype(auto) operator-(auto rhs) requires requires (T first, decltype(rhs) r) { first - r; }
{
return -rhs;
}
constexpr decltype(auto) operator*(auto rhs) requires requires (T first, decltype(rhs) r) { first * r; }
{
return 0;
}
constexpr decltype(auto) operator/(auto rhs) requires requires (T first, decltype(rhs) r) { first / r; }
{
return 0;
}
constexpr decltype(auto) operator%(auto rhs) requires requires (T first, decltype(rhs) r) { first % r; }
{
return 0;
}
constexpr decltype(auto) operator&(auto rhs) requires requires (T first, decltype(rhs) r) { first & r; }
{
return 0;
}
constexpr decltype(auto) operator|(auto rhs) requires requires (T first, decltype(rhs) r) { first | r; }
{
return rhs;
}
constexpr decltype(auto) operator^(auto rhs) requires requires (T first, decltype(rhs) r) { first ^ r; }
{
return 0^rhs;
}
constexpr decltype(auto) operator<<(auto rhs) requires requires (T first, decltype(rhs) r) { first << r; }
{
return 0;
}
constexpr decltype(auto) operator>>(auto rhs) requires requires (T first, decltype(rhs) r) { first >> r; }
{
return 0;
}
constexpr decltype(auto) operator~() requires requires (T first) { ~first; }
{
return 0;
}
constexpr decltype(auto) operator||(auto rhs) requires requires (T first, decltype(rhs) r) { first + r; }
{
return false || rhs;
}
constexpr decltype(auto) operator&&(auto rhs) requires requires (T first, decltype(rhs) r) { first + r; }
{
return false;
}
constexpr decltype(auto) operator!(auto rhs) requires requires (T first) { !first; }
{
return false;
}
constexpr decltype(auto) operator bool() requires requires (T first) { !!first; }
{
return false;
}
constexpr decltype(auto) operator +() requires requires (T first) { +first; }
{
return 0;
}
constexpr decltype(auto) operator -() requires requires (T first) { -first; }
{
return 0;
}
constexpr decltype(auto) operator&(); requires requires (T first) { &first; }
{
return nullptr;
}
constexpr decltype(auto) operator<=>(auto rhs) requires requires (T first, decltype(rhs) r) { first <=> r; }
{
return (T)false <=> rhs;
}
};
template <typename T, length_t I, length_t L> requires (NotEmpty(I, L))
struct Element<true, T, I, L>
{
T t;
constexpr operator auto()
{
return t;
}
constexpr decltype(auto) operator=(auto thing)
{
t=(T)thing;
return *this;
}
constexpr std::ostream& operator<<(std::ostream& os)
{
return os << t;
}
// prefix increment
constexpr decltype(auto) operator++() requires requires (T first) { first++; }
{
t++;
return *this; // return new value by reference
}
// postfix increment
constexpr decltype(auto) operator++(auto) requires requires (T first) { first++; }
{
auto old = *this; // copy old value
operator++(); // prefix increment
return old; // return old value
}
// prefix decrement
constexpr decltype(auto) operator--() requires requires (T first) { first--; }
{
t--;
return *this; // return new value by reference
}
// postfix decrement
constexpr decltype(auto) operator--(auto) requires requires (T first) { first--; }
{
auto old = *this; // copy old value
operator--(); // prefix decrement
return old; // return old value
}
constexpr decltype(auto) operator+=(auto a) requires requires (T first, decltype(rhs) r) { first + r; }
{
t+=a;
return *this;
}
constexpr decltype(auto) operator-=(auto a) requires requires (T first, decltype(rhs) r) { first - r; }
{
t-=a;
return *this;
}
constexpr decltype(auto) operator*=(auto a) requires requires (T first, decltype(rhs) r) { first * r; }
{
t*=a;
return *this;
}
constexpr decltype(auto) operator/=(auto a) requires requires (T first, decltype(rhs) r) { first / r; }
{
t/=a;
return *this;
}
constexpr decltype(auto) operator%=(auto a) requires requires (T first, decltype(rhs) r) { first % r; }
{
t%=a;
return *this;
}
constexpr decltype(auto) operator&=(auto a) requires requires (T first, decltype(rhs) r) { first & r; }
{
t&=a;
return *this;
}
constexpr decltype(auto) operator|=(auto a) requires requires (T first, decltype(rhs) r) { first | r; }
{
t|=a;
return *this;
}
constexpr decltype(auto) operator^=(auto a) requires requires (T first, decltype(rhs) r) { first ^ r; }
{
t^=a;
return *this;
}
constexpr decltype(auto) operator<<=(auto a) requires requires (T first, decltype(rhs) r) { first << r; }
{
t<<=a;
return *this;
}
constexpr decltype(auto) operator>>=(auto a) requires requires (T first, decltype(rhs) r) { first >> r; }
{
t>>=a;
return *this;
}
constexpr decltype(auto) operator+(auto rhs) requires requires (T first, decltype(rhs) r) { first + r; }
{
auto lhs = *this;
lhs+=rhs;
return lhs.t;
}
constexpr decltype(auto) operator-(auto rhs) requires requires (T first, decltype(rhs) r) { first - r; }
{
auto lhs = *this;
lhs-=rhs;
return lhs.t;
}
constexpr decltype(auto) operator*(auto rhs) requires requires (T first, decltype(rhs) r) { first * r; }
{
auto lhs = *this;
lhs*=rhs;
return lhs.t;
}
constexpr decltype(auto) operator/(auto rhs) requires requires (T first, decltype(rhs) r) { first / r; }
{
auto lhs = *this;
lhs/=rhs;
return lhs.t;
}
constexpr decltype(auto) operator%(auto rhs) requires requires (T first, decltype(rhs) r) { first % r; }
{
auto lhs = *this;
lhs%=rhs;
return lhs.t;
}
constexpr decltype(auto) operator&(auto rhs) requires requires (T first, decltype(rhs) r) { first & r; }
{
auto lhs = *this;
lhs&=rhs;
return lhs.t;
}
constexpr decltype(auto) operator|(auto rhs) requires requires (T first, decltype(rhs) r) { first | r; }
{
auto lhs = *this;
lhs|=rhs;
return lhs.t;
}
constexpr decltype(auto) operator^(auto rhs) requires requires (T first, decltype(rhs) r) { first ^ r; }
{
auto lhs = *this;
lhs^=rhs;
return lhs.t;
}
constexpr decltype(auto) operator<<(auto rhs) requires requires (T first, decltype(rhs) r) { first << r; }
{
auto lhs = *this;
lhs<<=rhs;
return lhs.t;
}
constexpr decltype(auto) operator>>(auto rhs) requires requires (T first, decltype(rhs) r) { first >> r; }
{
auto lhs = *this;
lhs>>=rhs;
return lhs.t;
}
constexpr decltype(auto) operator~() requires requires (T first) { ~first; }
{
auto lhs = *this;
lhs.t = ~(lhs.t);
return lhs.t;
}
constexpr decltype(auto) operator||(auto rhs) requires requires (T first, decltype(rhs) r) { first || r; }
{
auto lhs = *this;
lhs.t = lhs.t || rhs.t;
return lhs.t;
}
constexpr decltype(auto) operator&&(auto rhs) requires requires (T first, decltype(rhs) r) { first && r; }
{
auto lhs = *this;
lhs.t = lhs.t && rhs.t;
return lhs.t;
}
constexpr decltype(auto) operator!() requires requires (T first) { !first; }
{
auto lhs = *this;
return !lhs.t;
}
constexpr decltype(auto) operator bool() requires requires (T first) { !!first; }
{
auto lhs = *this;
return !!lhs.t;
}
constexpr decltype(auto) operator +() requires requires (T first) { +first; }
{
auto lhs = *this;
return +lhs.t;
}
constexpr decltype(auto) operator -() requires requires (T first) { -first; }
{
auto lhs = *this;
return -lhs.t;
}
constexpr decltype(auto) operator&(); requires requires (T first) { &first; }
{
return &(this->t);
}
constexpr decltype(auto) operator<=>(auto rhs) requires requires (T first, decltype(rhs) r) { first <=> r; }
{
return t <=> rhs;
}
};
}

View File

@ -0,0 +1,53 @@
namespace glm::detail
{
template<length_t L, typename T, qualifier Q>
struct SimdHelpers
{
using PaddedVec = PaddedGccVec<L, T, Q>;
using gcc_vec_t = PaddedVec::GccV;
using data_t = typename detail::storage<L, T, detail::is_aligned<Q>::value>::type;
static inline auto simd_ctor_scalar(arithmetic auto scalar) {
PaddedVec v = {};
v.gcc_vec = v.gcc_vec + ( (T)scalar );
return std::bit_cast<data_t>(v);
}
template <length_t Lx, typename Tx, qualifier Qx> requires (Lx == L)
static inline auto simd_ctor(::glm::vec<Lx, Tx, Qx> v)
{
using OtherPaddedVec = PaddedGccVec<Lx, Tx, Qx>;
OtherPaddedVec o = std::bit_cast<OtherPaddedVec>(v.data);
PaddedVec converted = {.gcc_vec=__builtin_convertvector(o.gcc_vec, gcc_vec_t)};
return std::bit_cast<data_t>(converted);
}
template <length_t Lx, typename Tx, qualifier Qx> requires (Lx != L && Lx < L)
static inline auto simd_ctor(::glm::vec<Lx, Tx, Qx> v)
{
using OtherPaddedVec = PaddedGccVec<Lx, Tx, Qx>;
using OurSizeTheirType = PaddedGccVec<L, Tx, Qx>;
OtherPaddedVec o = std::bit_cast<OtherPaddedVec>(v.data);
OurSizeTheirType oExpanded = {};
for (length_t i = 0; i < Lx; i++) {
oExpanded.gcc_vec[i] = o.gcc_vec[i];
}
PaddedVec converted = {.gcc_vec=__builtin_convertvector(oExpanded.gcc_vec, gcc_vec_t)};
return std::bit_cast<data_t>(converted);
}
static consteval bool isLengthOfVector(arithmetic auto... scalars) {
return sizeof...(scalars) == L;
}
template <arithmetic... A>
static inline auto simd_ctor_multi_scalars(A... scalars) requires ( isLengthOfVector(scalars...) && SameArithmeticTypes<A...>())
{
//assuming that number of scalars is always the same as the length of the to-be-constructed vector
using OtherPaddedVec = PaddedGccVec<L, A, Q>;
OtherPaddedVec o = {.gcc_vec={scalars...}};
PaddedVec converted = {.gcc_vec=__builtin_convertvector(o, gcc_vec_t)};
return std::bit_cast<data_t>(converted);
}
};
}

View File

@ -0,0 +1,265 @@
/// @ref core
/// @file glm/detail/simd_constexpr/vec.hpp
#pragma once
#ifdef GLM_CONFIG_ALIGNED_GENTYPES
# undef GLM_CONFIG_ALIGNED_GENTYPES
#endif
#ifdef GLM_FORCE_DEFAULT_ALIGNED_GENTYPES
# undef GLM_FORCE_DEFAULT_ALIGNED_GENTYPES
#endif
#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES 1
#define GLM_CONFIG_ALIGNED_GENTYPES 1
#include "../qualifier.hpp"
#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR
# include "../_swizzle.hpp"
#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION
# include "../_swizzle_func.hpp"
#endif
#include <cstddef>
#include <array>
#include <variant>
namespace glm
{
template <typename T>
concept arithmetic = std::integral<T> || std::floating_point<T>;
template <typename T0, typename... T>
consteval bool SameArithmeticTypes() {
return (std::is_same_v<T0, T> && ...);
}
template <typename... T>
consteval bool NotSameArithmeticTypes() {
return ( (!(std::is_integral_v<T> || std::floating_point_v<T>) || ...) || !(SameArithmeticTypes<T...>()) );
}
namespace detail
{
template <length_t L, typename T, qualifier Q>
using ArrT = T[L];
template <length_t L, typename T, qualifier Q>
using _data_t = typename detail::storage<L, T, detail::is_aligned<Q>::value>::type;
template <length_t L, typename T, qualifier Q>
using GccV = T __attribute__((vector_size(sizeof(T)*L)));
template <length_t L, typename T, qualifier Q>
consteval bool BDataNeedsPadding() {
return sizeof(_data_t<L,T,Q>) > sizeof(ArrT<L,T,Q>);
}
template <length_t L, typename T, qualifier Q>
consteval bool BVecNeedsPadding() {
return sizeof(_data_t<L,T,Q>) > sizeof(GccV<L,T,Q>);
}
template <length_t L, typename T, qualifier Q, bool NeedsPadding>
struct VecDataArray;
template <length_t L, typename T, qualifier Q>
struct VecDataArray<L, T, Q, true> {
using ArrT = ArrT<L, T, Q>;
using data_t = _data_t<L,T,Q>;
ArrT p;
std::byte padding[sizeof(data_t) - sizeof(ArrT)];
};
template <length_t L, typename T, qualifier Q>
struct VecDataArray<L, T, Q, false> {
using ArrT = ArrT<L, T, Q>;
ArrT p;
};
template <length_t L, typename T, qualifier Q, bool NeedsPadding>
struct PaddedGccVec;
template <length_t L, typename T, qualifier Q>
struct PaddedGccVec<L, T, Q, true> {
using GccV = GccV<L, T,Q>;
using data_t = _data_t<L, T, Q>;
GccV gcc_vec;
std::byte padding[sizeof(data_t) - sizeof(GccV)];
};
template <length_t L, typename T, qualifier Q>
struct PaddedGccVec<L, T, Q, false> {
using GccV = GccV<L, T,Q>;
GccV gcc_vec;
};
}
template <length_t L, typename T, qualifier Q>
using PaddedGccVec = detail::PaddedGccVec<L, T, Q, detail::BVecNeedsPadding<L, T, Q>()>;
template <length_t L, typename T, qualifier Q>
using VecDataArray = detail::VecDataArray<L, T, Q, detail::BDataNeedsPadding<L, T, Q>()>;
}
#include "element.hpp"
#include "simd_helpers.inl"
namespace glm
{
template<length_t L, typename T, qualifier Q> requires (Q != packed_highp && Q != packed_mediump && Q != packed_lowp && Q != packed)
struct vec
{
using SimdHlp = detail::SimdHelpers<L, T, Q>;
using DataArray = VecDataArray<L, T, Q>;
using data_t = typename detail::storage<L, T, detail::is_aligned<Q>::value>::type;
// -- Implementation detail --
typedef T value_type;
typedef vec<L, T, Q> type;
typedef vec<L, bool, Q> bool_type;
enum is_aligned
{
value = detail::is_aligned<Q>::value
};
static constexpr length_t length(){return L;}
// -- Data --
#define GLM_N [[no_unique_address]]
template <length_t I>
using E = detail::Element<detail::NotEmpty(I,L),T,I,L>;
union
{
struct {
union { E<1> x, r, s; };
GLM_N union { GLM_N E<2> y; GLM_N E<2> g; GLM_N E<2> t; };
GLM_N union { GLM_N E<3> z; GLM_N E<3> b; GLM_N E<3> p; };
GLM_N union { GLM_N E<4> w; GLM_N E<4> a; GLM_N E<4> q; };
};
data_t data;
};
#undef GLM_N
# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR
GLM_SWIZZLE4_2_MEMBERS(T, Q, x, y, z, w)
GLM_SWIZZLE4_2_MEMBERS(T, Q, r, g, b, a)
GLM_SWIZZLE4_2_MEMBERS(T, Q, s, t, p, q)
GLM_SWIZZLE4_3_MEMBERS(T, Q, x, y, z, w)
GLM_SWIZZLE4_3_MEMBERS(T, Q, r, g, b, a)
GLM_SWIZZLE4_3_MEMBERS(T, Q, s, t, p, q)
GLM_SWIZZLE4_4_MEMBERS(T, Q, x, y, z, w)
GLM_SWIZZLE4_4_MEMBERS(T, Q, r, g, b, a)
GLM_SWIZZLE4_4_MEMBERS(T, Q, s, t, p, q)
GLM_SWIZZLE3_2_MEMBERS(T, Q, x, y, z)
GLM_SWIZZLE3_2_MEMBERS(T, Q, r, g, b)
GLM_SWIZZLE3_2_MEMBERS(T, Q, s, t, p)
GLM_SWIZZLE3_3_MEMBERS(T, Q, x, y, z)
GLM_SWIZZLE3_3_MEMBERS(T, Q, r, g, b)
GLM_SWIZZLE3_3_MEMBERS(T, Q, s, t, p)
GLM_SWIZZLE3_4_MEMBERS(T, Q, x, y, z)
GLM_SWIZZLE3_4_MEMBERS(T, Q, r, g, b)
GLM_SWIZZLE3_4_MEMBERS(T, Q, s, t, p)
GLM_SWIZZLE2_2_MEMBERS(T, Q, x, y)
GLM_SWIZZLE2_2_MEMBERS(T, Q, r, g)
GLM_SWIZZLE2_2_MEMBERS(T, Q, s, t)
GLM_SWIZZLE2_3_MEMBERS(T, Q, x, y)
GLM_SWIZZLE2_3_MEMBERS(T, Q, r, g)
GLM_SWIZZLE2_3_MEMBERS(T, Q, s, t)
GLM_SWIZZLE2_4_MEMBERS(T, Q, x, y)
GLM_SWIZZLE2_4_MEMBERS(T, Q, r, g)
GLM_SWIZZLE2_4_MEMBERS(T, Q, s, t)
# endif
template <typename ScalarGetter>
constexpr auto ctor_scalar(ScalarGetter scalar) {
if (std::is_constant_evaluated()) {
DataArray a;
for (length_t i = 0; i < L; i++) {
a.p[i]=scalar();
}
return std::bit_cast<data_t>(a);
} else {
return SimdHlp::simd_ctor_scalar(scalar());
}
}
template <typename VecGetter>
constexpr auto ctor(VecGetter vecGetter) {
if (std::is_constant_evaluated()) {
DataArray a = {};
constexpr auto v = vecGetter();
constexpr length_t vL = v.length();
using ArrX = VecDataArray<vL, decltype(v)::value_type, Q>;
ArrX ax = std::bit_cast<ArrX>(v.data);
for (length_t i = 0; i < v.length(); i++) {
a.p[i] = (T)ax.p[i];
}
return std::bit_cast<data_t>(a);
} else {
return SimdHlp::simd_ctor(vecGetter());
}
}
typedef struct {
DataArray a;
length_t i;
} RetPair;
static inline auto ctor_mixed_constexpr_single = []<typename var_t>(auto&& vs0, length_t index) -> var_t
{
DataArray a {};
using VTX = std::decay_t<decltype(vs0)>;
length_t i = 0;
auto&& __restrict__ _vs0 = vs0;
if constexpr ( std::is_integral_v<VTX> || std::is_floating_point_v<VTX> ) {
a.p[index] = _vs0;
i++;
} else {
using Tx = VTX::value_type;
using ArrX = VecDataArray<_vs0.length(), Tx, Q>;
ArrX ax = std::bit_cast<ArrX>(_vs0.data);
for (Tx tx : ax.p) {
a.p[index+i++] = (T)tx;
}
}
return var_t{RetPair{a, i}};
}
constexpr vec(arithmetic auto scalar) : data{ [scalar](){ auto s = [scalar](){ return scalar; }; return ctor_scalar(s); }() } {}
template <length_t Lx, typename Tx, qualifier Qx>
constexpr vec(vec<Lx, Tx, Qx> v) : data{ [v](){ auto vv = [v](){ return v; }; return ctor(vv); }() } {}
template <arithmetic... Scalar> requires (sizeof...(Scalar) == L)
constexpr vec(Scalar... scalar)
: data
{ [scalar...]() -> data_t
{
if (std::is_constant_evaluated()) {
DataArray a = {.p={ T(scalar)... }};
return std::bit_cast<data_t>(a);
} else {
return SimdHlp::simd_ctor_multi_scalars(scalar...);
}
}()
} {}
template <typename... VecOrScalar> requires (sizeof...(VecOrScalar) > 1 && NotSameArithmeticTypes<VecOrScalar...>())
constexpr vec(VecOrScalar... vecOrScalar)
: data
{ [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<RetPair, VecOrScalar...>;
for (auto var_vs : std::array<var_t, sizeof...(vecOrScalar)>{ vecOrScalar... } ) {
auto visitee = [i](auto&& arg) -> var_t { return ctor_mixed_constexpr_single<var_t>(arg, i); };
RetPair pair = std::get<RetPair>(std::visit(visitee, var_vs));
for (length_t j = pair.i; j < i+pair.i; j++) {
a.p[j] = pair.a.p[j];
}
i+=pair.i;
}
return std::bit_cast<data_t>(a);
}()
} {}
};
}

View File

@ -101,6 +101,10 @@
/// included a specific file. /// included a specific file.
/// ///
#ifndef GLM_SIMD_CONSTEXPR
#define GLM_SIMD_CONSTEXPR 0
#endif
#include "detail/_fixes.hpp" #include "detail/_fixes.hpp"
#include "detail/setup.hpp" #include "detail/setup.hpp"
@ -114,9 +118,14 @@
#include <cassert> #include <cassert>
#include "fwd.hpp" #include "fwd.hpp"
#if GLM_SIMD_CONSTEXPR == 0
# include "vec2.hpp" # include "vec2.hpp"
# include "vec3.hpp" # include "vec3.hpp"
# include "vec4.hpp" # include "vec4.hpp"
#else
# include "simd_constexpr/vec.hpp"
#endif
#include "mat2x2.hpp" #include "mat2x2.hpp"
#include "mat2x3.hpp" #include "mat2x3.hpp"
#include "mat2x4.hpp" #include "mat2x4.hpp"

View File

@ -0,0 +1,27 @@
/// @ref core
/// @file glm/simd_constexpr/vec4.hpp
#pragma once
namespace glm
{
typedef vec<1, float, defaultp> vec1;
typedef vec<2, float, defaultp> vec2;
typedef vec<3, float, defaultp> vec3;
typedef vec<4, float, defaultp> vec4;
typedef vec<1, int, defaultp> ivec1;
typedef vec<2, int, defaultp> ivec2;
typedef vec<3, int, defaultp> ivec3;
typedef vec<4, int, defaultp> ivec4;
typedef vec<1, unsigned int, defaultp> uvec1;
typedef vec<2, unsigned int, defaultp> uvec2;
typedef vec<3, unsigned int, defaultp> uvec3;
typedef vec<4, unsigned int, defaultp> uvec4;
typedef vec<1, bool, defaultp> bvec1;
typedef vec<2, bool, defaultp> bvec2;
typedef vec<3, bool, defaultp> bvec3;
typedef vec<4, bool, defaultp> bvec4;
}
#include "../detail/simd_constexpr/type_vec.hpp"