VCV Rack API v2
Loading...
Searching...
No Matches
Vector.hpp
Go to the documentation of this file.
1#pragma once
2#include <cstring>
3#include "common.hpp"
4
5
6namespace rack {
7
8
11namespace simd {
12
13
26template <typename TYPE, int SIZE>
27struct Vector;
28
29
32template <>
33struct Vector<float, 4> {
34 using type = float;
35 constexpr static int size = 4;
36
37 union {
38 __m128 v;
41 float s[4];
42 };
43
45 Vector() = default;
46
48 Vector(__m128 v) : v(v) {}
49
51 Vector(float x) {
52 v = _mm_set1_ps(x);
53 }
54
56 Vector(float x1, float x2, float x3, float x4) {
57 v = _mm_setr_ps(x1, x2, x3, x4);
58 }
59
61 static Vector zero() {
62 return Vector(_mm_setzero_ps());
63 }
64
66 static Vector mask() {
67 return Vector(_mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())));
68 }
69
73 static Vector load(const float* x) {
74 /*
75 My benchmarks show that _mm_loadu_ps() performs equally as fast as _mm_load_ps() when data is actually aligned.
76 This post seems to agree. https://stackoverflow.com/a/20265193/272642
77 I therefore use _mm_loadu_ps() for generality, so you can load unaligned arrays using the same function (although load aligned arrays if you can for best performance).
78 */
79 return Vector(_mm_loadu_ps(x));
80 }
81
85 void store(float* x) {
86 _mm_storeu_ps(x, v);
87 }
88
92 float& operator[](int i) {
93 return s[i];
94 }
95 const float& operator[](int i) const {
96 return s[i];
97 }
98
99 // Conversions
101 // Casts
102 static Vector cast(Vector<int32_t, 4> a);
103};
104
105
106template <>
107struct Vector<int32_t, 4> {
108 using type = int32_t;
109 constexpr static int size = 4;
110
111 union {
112 __m128i v;
113 int32_t s[4];
114 };
115
116 Vector() = default;
117 Vector(__m128i v) : v(v) {}
118 Vector(int32_t x) {
119 v = _mm_set1_epi32(x);
120 }
121 Vector(int32_t x1, int32_t x2, int32_t x3, int32_t x4) {
122 v = _mm_setr_epi32(x1, x2, x3, x4);
123 }
124 static Vector zero() {
125 return Vector(_mm_setzero_si128());
126 }
127 static Vector mask() {
128 return Vector(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128()));
129 }
130 static Vector load(const int32_t* x) {
131 // HACK
132 // Use _mm_loadu_si128() because GCC doesn't support _mm_loadu_si32()
133 return Vector(_mm_loadu_si128((const __m128i*) x));
134 }
135 void store(int32_t* x) {
136 // HACK
137 // Use _mm_storeu_si128() because GCC doesn't support _mm_storeu_si32()
138 _mm_storeu_si128((__m128i*) x, v);
139 }
140 int32_t& operator[](int i) {
141 return s[i];
142 }
143 const int32_t& operator[](int i) const {
144 return s[i];
145 }
147 static Vector cast(Vector<float, 4> a);
148};
149
150
151// Conversions and casts
152
153
155 v = _mm_cvtepi32_ps(a.v);
156}
157
159 v = _mm_cvttps_epi32(a.v);
160}
161
163 return Vector(_mm_castsi128_ps(a.v));
164}
165
167 return Vector(_mm_castps_si128(a.v));
168}
169
170
171// Operator overloads
172
173
175#define DECLARE_VECTOR_OPERATOR_INFIX(t, s, operator, func) \
176 inline Vector<t, s> operator(const Vector<t, s>& a, const Vector<t, s>& b) { \
177 return Vector<t, s>(func(a.v, b.v)); \
178 }
179
181#define DECLARE_VECTOR_OPERATOR_INCREMENT(t, s, operator, opfunc) \
182 inline Vector<t, s>& operator(Vector<t, s>& a, const Vector<t, s>& b) { \
183 return a = opfunc(a, b); \
184 }
185
186DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator+, _mm_add_ps)
187DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator+, _mm_add_epi32)
188
189DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator-, _mm_sub_ps)
190DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator-, _mm_sub_epi32)
191
192DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator*, _mm_mul_ps)
193// DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator*, NOT AVAILABLE IN SSE3)
194
195DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator/, _mm_div_ps)
196// DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator/, NOT AVAILABLE IN SSE3)
197
198/* Use these to apply logic, bit masks, and conditions to elements.
199Boolean operators on vectors give 0x00000000 for false and 0xffffffff for true, for each vector element.
200
201Examples:
202
203Subtract 1 from value if greater than or equal to 1.
204
205 x -= (x >= 1.f) & 1.f;
206*/
207DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator^, _mm_xor_ps)
208DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator^, _mm_xor_si128)
209
210DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator&, _mm_and_ps)
211DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator&, _mm_and_si128)
212
213DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator|, _mm_or_ps)
214DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator|, _mm_or_si128)
215
216DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator+=, operator+)
217DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator+=, operator+)
218
219DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator-=, operator-)
220DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator-=, operator-)
221
222DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator*=, operator*)
223// DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator*=, NOT AVAILABLE IN SSE3)
224
225DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator/=, operator/)
226// DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator/=, NOT AVAILABLE IN SSE3)
227
228DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator^=, operator^)
229DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator^=, operator^)
230
231DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator&=, operator&)
232DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator&=, operator&)
233
234DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator|=, operator|)
235DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator|=, operator|)
236
237DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator==, _mm_cmpeq_ps)
238DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator==, _mm_cmpeq_epi32)
239
240DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator>=, _mm_cmpge_ps)
241inline Vector<int32_t, 4> operator>=(const Vector<int32_t, 4>& a, const Vector<int32_t, 4>& b) {
242 return Vector<int32_t, 4>(_mm_cmpgt_epi32(a.v, b.v)) ^ Vector<int32_t, 4>::mask();
243}
244
245DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator>, _mm_cmpgt_ps)
246DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator>, _mm_cmpgt_epi32)
247
248DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator<=, _mm_cmple_ps)
249inline Vector<int32_t, 4> operator<=(const Vector<int32_t, 4>& a, const Vector<int32_t, 4>& b) {
250 return Vector<int32_t, 4>(_mm_cmplt_epi32(a.v, b.v)) ^ Vector<int32_t, 4>::mask();
251}
252
253DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator<, _mm_cmplt_ps)
254DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator<, _mm_cmplt_epi32)
255
256DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator!=, _mm_cmpneq_ps)
257inline Vector<int32_t, 4> operator!=(const Vector<int32_t, 4>& a, const Vector<int32_t, 4>& b) {
258 return Vector<int32_t, 4>(_mm_cmpeq_epi32(a.v, b.v)) ^ Vector<int32_t, 4>::mask();
259}
260
263 return a;
264}
266 return a;
267}
268
271 return 0.f - a;
272}
274 return 0 - a;
275}
276
279 return a += 1.f;
280}
282 return a += 1;
283}
284
287 return a -= 1.f;
288}
290 return a -= 1;
291}
292
295 Vector<float, 4> b = a;
296 ++a;
297 return b;
298}
300 Vector<int32_t, 4> b = a;
301 ++a;
302 return b;
303}
304
307 Vector<float, 4> b = a;
308 --a;
309 return b;
310}
312 Vector<int32_t, 4> b = a;
313 --a;
314 return b;
315}
316
319 return a ^ Vector<float, 4>::mask();
320}
322 return a ^ Vector<int32_t, 4>::mask();
323}
324
326inline Vector<int32_t, 4> operator<<(const Vector<int32_t, 4>& a, const int& b) {
327 return Vector<int32_t, 4>(_mm_sll_epi32(a.v, _mm_cvtsi32_si128(b)));
328}
329
331inline Vector<int32_t, 4> operator>>(const Vector<int32_t, 4>& a, const int& b) {
332 return Vector<int32_t, 4>(_mm_srl_epi32(a.v, _mm_cvtsi32_si128(b)));
333}
334
335
336// Typedefs
337
338
341
342
343} // namespace simd
344} // namespace rack
#define DECLARE_VECTOR_OPERATOR_INFIX(t, s, operator,func)
a @ b
Definition Vector.hpp:175
#define DECLARE_VECTOR_OPERATOR_INCREMENT(t, s, operator,opfunc)
a @= b
Definition Vector.hpp:181
Vector< int32_t, 4 > operator<=(const Vector< int32_t, 4 > &a, const Vector< int32_t, 4 > &b)
Definition Vector.hpp:249
Vector< int32_t, 4 > operator>>(const Vector< int32_t, 4 > &a, const int &b)
a >> b
Definition Vector.hpp:331
Vector< int32_t, 4 > operator<<(const Vector< int32_t, 4 > &a, const int &b)
a << b
Definition Vector.hpp:326
Vector< float, 4 > operator-(const Vector< float, 4 > &a)
-a
Definition Vector.hpp:270
Vector< float, 4 > & operator++(Vector< float, 4 > &a)
++a
Definition Vector.hpp:278
Vector< float, 4 > & operator--(Vector< float, 4 > &a)
--a
Definition Vector.hpp:286
Vector< float, 4 > operator~(const Vector< float, 4 > &a)
~a
Definition Vector.hpp:318
Vector< float, 4 > operator+(const Vector< float, 4 > &a)
+a
Definition Vector.hpp:262
Root namespace for the Rack API.
Definition AudioDisplay.hpp:9
Wrapper for __m128 representing an aligned vector of 4 single-precision float values.
Definition Vector.hpp:33
static Vector mask()
Returns a vector with all 1 bits.
Definition Vector.hpp:66
void store(float *x)
Writes an array of 4 values.
Definition Vector.hpp:85
Vector(float x1, float x2, float x3, float x4)
Constructs a vector from four scalars.
Definition Vector.hpp:56
float & operator[](int i)
Accessing vector elements individually is slow and defeats the purpose of vectorizing.
Definition Vector.hpp:92
Vector(__m128 v)
Constructs a vector from a native __m128 type.
Definition Vector.hpp:48
Vector(float x)
Constructs a vector with all elements set to x.
Definition Vector.hpp:51
Vector()=default
Constructs an uninitialized vector.
static Vector load(const float *x)
Reads an array of 4 values.
Definition Vector.hpp:73
const float & operator[](int i) const
Definition Vector.hpp:95
float type
Definition Vector.hpp:34
static Vector zero()
Returns a vector with all 0 bits.
Definition Vector.hpp:61
__m128 v
Definition Vector.hpp:38
Definition Vector.hpp:107
Vector(int32_t x1, int32_t x2, int32_t x3, int32_t x4)
Definition Vector.hpp:121
static Vector zero()
Definition Vector.hpp:124
Vector(__m128i v)
Definition Vector.hpp:117
__m128i v
Definition Vector.hpp:112
Vector(int32_t x)
Definition Vector.hpp:118
const int32_t & operator[](int i) const
Definition Vector.hpp:143
int32_t type
Definition Vector.hpp:108
static Vector mask()
Definition Vector.hpp:127
static Vector load(const int32_t *x)
Definition Vector.hpp:130
int32_t & operator[](int i)
Definition Vector.hpp:140
void store(int32_t *x)
Definition Vector.hpp:135
Generic class for vector types.
Definition Vector.hpp:27