native 0.0.1
Vectors, masks and wide register packs for C++26
Loading...
Searching...
No Matches
common.h
Go to the documentation of this file.
1#pragma once
2#include "native/attributes.h"
3#include "native/isa.h"
4#include "native/mask_traits.h"
5#include "native/value_traits.h"
6#include <array>
7#include <span>
8#include <concepts>
9#include <utility>
10#include <cstddef>
11#include <cstdint>
12#include <type_traits>
13#include <limits>
14
41namespace native {
42 static_assert(sizeof(float) == 4 && std::numeric_limits<float>::is_iec559 &&
43 std::numeric_limits<float>::radix == 2 && std::numeric_limits<float>::digits == 24 &&
44 std::numeric_limits<float>::min_exponent == -125 && std::numeric_limits<float>::max_exponent == 128,
45 "native math requires IEEE 754 binary32 float");
46
47 using std::int8_t;
48 using std::int16_t;
49 using std::int32_t;
50 using std::int64_t;
51 using std::uint8_t;
52 using std::uint16_t;
53 using std::uint32_t;
54 using std::uint64_t;
55
56 template <class T> concept simd_integer_element =
57 std::same_as<T,int8_t> || std::same_as<T,int16_t> ||
58 std::same_as<T,int32_t> || std::same_as<T,int64_t> ||
59 std::same_as<T,uint8_t> || std::same_as<T,uint16_t> ||
60 std::same_as<T,uint32_t> || std::same_as<T,uint64_t>;
61
64 template<class V> requires requires { typename V::value_type; } &&
65 (std::same_as<typename V::value_type,float> ||
66 std::same_as<typename V::value_type,std::int32_t> ||
67 std::same_as<typename V::value_type,std::uint32_t>)
69 V value;
70 std::size_t count;
71 };
72
75 template <std::size_t K> struct imm_t {
76 static constexpr std::size_t value = K;
78 native_nodiscard native_inline native_const consteval operator std::size_t() const noexcept { return K; }
79 };
80
82 template <std::size_t K> inline constexpr imm_t<K> imm{};
83
88 template<class U> requires (std::is_unsigned_v<U> && !std::same_as<U,bool> && (sizeof(U)==1 || sizeof(U)==2 || sizeof(U)==4 || sizeof(U)==8))
89 struct mask_lane {
90 using storage_type=U;
92 native_inline constexpr mask_lane() noexcept = default;
94 explicit native_inline constexpr mask_lane(bool value) noexcept : value_(value?U(~U(0)):U(0)) {}
96 native_nodiscard static native_inline native_const constexpr mask_lane from_bits(U value) noexcept { return mask_lane(value!=0); }
98 native_nodiscard native_inline native_pure constexpr U to_bits() const noexcept { return value_; }
100 native_nodiscard native_inline native_pure constexpr bool to_bool() const noexcept { return value_!=0; }
102 native_nodiscard friend native_inline native_const constexpr mask_lane operator!(mask_lane a) noexcept { return mask_lane(!a.to_bool()); }
104 native_nodiscard friend native_inline native_const constexpr mask_lane operator~(mask_lane a) noexcept { return !a; }
106 native_nodiscard friend native_inline native_const constexpr mask_lane operator&(mask_lane a,mask_lane b) noexcept { return mask_lane(a.to_bool()&&b.to_bool()); }
108 native_nodiscard friend native_inline native_const constexpr mask_lane operator|(mask_lane a,mask_lane b) noexcept { return mask_lane(a.to_bool()||b.to_bool()); }
110 native_nodiscard friend native_inline native_const constexpr mask_lane operator^(mask_lane a,mask_lane b) noexcept { return mask_lane(a.to_bool()!=b.to_bool()); }
112 native_nodiscard friend native_inline native_const constexpr bool operator==(mask_lane,mask_lane) noexcept = default;
113 private:
114 U value_=0;
115 };
116 using mask8=mask_lane<std::uint8_t>;
117 using mask16=mask_lane<std::uint16_t>;
118 using mask32=mask_lane<std::uint32_t>;
119 using mask64=mask_lane<std::uint64_t>;
120 template<class T> concept simd_mask_element=detail::is_mask_lane<T>;
121
122 // Custom elements supply their storage register and their own value semantics.
123 // The core never lifts raw arithmetic into a user-defined element implicitly.
127 template <class T> struct simd_traits;
132 template <class T, class Raw, class Self> struct simd_customization;
133 template <class T> concept simd_custom_element = requires {
135 };
136 namespace detail {
137 template<class V,class U,class=void> struct memory_architecture : value_architecture<V> {};
138 template<class V,simd_custom_element U>
139 requires std::same_as<typename V::value_type,typename simd_traits<U>::storage_type> &&
140 value_architecture<V>::known &&
141 value_architecture<typename V::template rebind<U>>::known
142 struct memory_architecture<V,U,std::void_t<typename V::template rebind<U>>> {
143 static constexpr isa<> value=value_architecture_v<V> &
144 value_architecture_v<typename V::template rebind<U>>;
145 static constexpr bool known=true;
146 };
147 template<class V,class U> inline constexpr isa<> memory_architecture_v=memory_architecture<V,U>::value;
148 }
149
150 namespace detail {
151 // Native registers are trivial values: default initialization leaves lanes
152 // unspecified; broadcast, load, or value initialization supplies every lane.
153 // Partial operations touch exactly n lanes (0 <= n <= lanes).
154 template<class V, std::size_t L> struct register_memory;
155 }
171 template<class T, std::size_t N, isa<> Arch> struct simd;
175 template<std::size_t N, isa<> Arch> struct predicate;
176
179 template<class T, std::size_t N, isa<> Arch>
180 requires requires { typename simd<T, N, Arch>::mask_type; }
181 struct mask_traits<simd<T, N, Arch>> {
182 using type = typename simd<T, N, Arch>::mask_type;
183 };
184
187 template<std::size_t N, isa<> Arch>
188 requires requires { typename predicate<N, Arch>::native_type; }
189 struct mask_traits<predicate<N, Arch>> { using type = predicate<N, Arch>; };
190
193 template<class U> requires requires { typename mask_lane<U>; }
194 struct mask_traits<mask_lane<U>> { using type = mask_lane<U>; };
195
196 namespace detail { template<class T,std::size_t N,isa<> Arch> struct swizzle_access {}; }
197
198 // Native-register conversions must not make different architectures mix.
200 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
201 void operator+(simd<T,N,A>,simd<U,M,B>) = delete;
203 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
204 void operator-(simd<T,N,A>,simd<U,M,B>) = delete;
206 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
207 void operator*(simd<T,N,A>,simd<U,M,B>) = delete;
209 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
210 void operator/(simd<T,N,A>,simd<U,M,B>) = delete;
212 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
213 void operator%(simd<T,N,A>,simd<U,M,B>) = delete;
215 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
216 void operator&(simd<T,N,A>,simd<U,M,B>) = delete;
218 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
219 void operator|(simd<T,N,A>,simd<U,M,B>) = delete;
221 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
222 void operator^(simd<T,N,A>,simd<U,M,B>) = delete;
224 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
225 void operator<<(simd<T,N,A>,simd<U,M,B>) = delete;
227 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
228 void operator>>(simd<T,N,A>,simd<U,M,B>) = delete;
230 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
231 void operator==(simd<T,N,A>,simd<U,M,B>) = delete;
233 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
234 void operator!=(simd<T,N,A>,simd<U,M,B>) = delete;
236 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
237 void operator<(simd<T,N,A>,simd<U,M,B>) = delete;
239 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
240 void operator<=(simd<T,N,A>,simd<U,M,B>) = delete;
242 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
243 void operator>(simd<T,N,A>,simd<U,M,B>) = delete;
245 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
246 void operator>=(simd<T,N,A>,simd<U,M,B>) = delete;
248 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
249 void operator+=(simd<T,N,A> &,simd<U,M,B>) = delete;
251 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
252 void operator-=(simd<T,N,A> &,simd<U,M,B>) = delete;
254 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
255 void operator*=(simd<T,N,A> &,simd<U,M,B>) = delete;
257 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
258 void operator/=(simd<T,N,A> &,simd<U,M,B>) = delete;
260 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
261 void operator%=(simd<T,N,A> &,simd<U,M,B>) = delete;
263 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
264 void operator&=(simd<T,N,A> &,simd<U,M,B>) = delete;
266 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
267 void operator|=(simd<T,N,A> &,simd<U,M,B>) = delete;
269 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
270 void operator^=(simd<T,N,A> &,simd<U,M,B>) = delete;
272 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
273 void operator<<=(simd<T,N,A> &,simd<U,M,B>) = delete;
275 template<class T,class U,std::size_t N,std::size_t M,isa<> A,isa<> B> requires(A!=B || (N!=M && (N==2 || N==3 || M==2 || M==3)))
276 void operator>>=(simd<T,N,A> &,simd<U,M,B>) = delete;
277
280 enum class simd_access { ordinary, streaming };
284 template <std::size_t Alignment = 1, simd_access Access = simd_access::ordinary>
285 struct simd_memory {
286 static_assert(Alignment > 0 && (Alignment & (Alignment - 1)) == 0);
287 static constexpr std::size_t alignment = Alignment;
288 static constexpr simd_access requested_access = Access;
289 // Streaming is currently an ordinary-access fallback on every backend.
290 static constexpr bool non_temporal = false;
291 };
292
293}
294
295
296
Compiler attributes for host code, with shader-safe shared modifiers.
#define native_inline
inline [[always_inline]]
Definition attributes.h:212
#define native_nodiscard
C++17 [[nodiscard]].
Definition attributes.h:189
#define native_const
[[const]] is not const
Definition attributes.h:108
#define native_pure
[[pure]]
Definition attributes.h:126
simd_access
Definition common.h:280
constexpr imm_t< K > imm
Definition common.h:82
Architecture-tagged vectors, register packs and supporting value types. Native arithmetic follows its...
Standard-library adaptations documented here for SIMD value types.
static constexpr mask_lane from_bits(U value) noexcept
Normalize nonzero bits to a true, all-one lane.
Definition common.h:96
friend constexpr bool operator==(mask_lane, mask_lane) noexcept=default
Compare the two canonical lane truth values and return bool.
friend constexpr mask_lane operator&(mask_lane a, mask_lane b) noexcept
Bitwise AND of corresponding lane representations.
Definition common.h:106
friend constexpr mask_lane operator|(mask_lane a, mask_lane b) noexcept
Bitwise OR of corresponding lane representations.
Definition common.h:108
friend constexpr mask_lane operator^(mask_lane a, mask_lane b) noexcept
Bitwise XOR of corresponding lane representations.
Definition common.h:110
friend constexpr mask_lane operator~(mask_lane a) noexcept
Invert each lane truth value, preserving the mask representation.
Definition common.h:104
constexpr bool to_bool() const noexcept
Return the lane truth value.
Definition common.h:100
constexpr mask_lane() noexcept=default
Initialize this lane to false.
constexpr U to_bits() const noexcept
Return the canonical zero or all-one representation.
Definition common.h:98
friend constexpr mask_lane operator!(mask_lane a) noexcept
Return the lane-wise logical complement, retaining this mask type.
Definition common.h:102
Omitted architecture arguments use the native.simd provider's baseline.