VCTR
Loading...
Searching...
No Matches
NeonRegister.h
1/*
2 ==============================================================================
3 DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
5 Copyright 2022- by sonible GmbH.
6
7 This file is part of VCTR - Versatile Container Templates Reconceptualized.
8
9 VCTR is free software: you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License version 3
11 only, as published by the Free Software Foundation.
12
13 VCTR is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License version 3 for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 version 3 along with VCTR. If not, see <https://www.gnu.org/licenses/>.
20 ==============================================================================
21*/
22
23namespace vctr
24{
25
26template <class T>
28{
29 static constexpr NeonRegister broadcast (const T&) { return {}; }
30};
31
32#if VCTR_ARM
33
34namespace detail
35{
36
37// clang-format off
38template <CompareOp, class>
39struct NeonCompare {};
40
41template <> struct NeonCompare<CompareOp::less, float> { static auto cmp (float32x4_t a, float32x4_t b) { return vcltq_f32 (a, b); } };
42template <> struct NeonCompare<CompareOp::less, double> { static auto cmp (float64x2_t a, float64x2_t b) { return vcltq_f64 (a, b); } };
43template <> struct NeonCompare<CompareOp::lessOrEqual, float> { static auto cmp (float32x4_t a, float32x4_t b) { return vcleq_f32 (a, b); } };
44template <> struct NeonCompare<CompareOp::lessOrEqual, double> { static auto cmp (float64x2_t a, float64x2_t b) { return vcleq_f64 (a, b); } };
45template <> struct NeonCompare<CompareOp::greater, float> { static auto cmp (float32x4_t a, float32x4_t b) { return vcgtq_f32 (a, b); } };
46template <> struct NeonCompare<CompareOp::greater, double> { static auto cmp (float64x2_t a, float64x2_t b) { return vcgtq_f64 (a, b); } };
47template <> struct NeonCompare<CompareOp::greaterOrEqual, float> { static auto cmp (float32x4_t a, float32x4_t b) { return vcgeq_f32 (a, b); } };
48template <> struct NeonCompare<CompareOp::greaterOrEqual, double> { static auto cmp (float64x2_t a, float64x2_t b) { return vcgeq_f64 (a, b); } };
49template <> struct NeonCompare<CompareOp::equal, float> { static auto cmp (float32x4_t a, float32x4_t b) { return vceqq_f32 (a, b); } };
50template <> struct NeonCompare<CompareOp::equal, double> { static auto cmp (float64x2_t a, float64x2_t b) { return vceqq_f64 (a, b); } };
51template <> struct NeonCompare<CompareOp::notEqual, float> { static auto cmp (float32x4_t a, float32x4_t b) { return vmvnq_u32 (vceqq_f32 (a, b)); } };
52template <> struct NeonCompare<CompareOp::notEqual, double> { static auto cmp (float64x2_t a, float64x2_t b) { return vreinterpretq_u64_u32 (vmvnq_u32 (vreinterpretq_u32_u64 (vceqq_f64 (a, b)))); } };
53// clang-format on
54}
55
56template <>
57struct NeonRegister<float>
58{
59 static constexpr size_t numElements = 4;
60
61 using NativeType = float32x4_t;
62 float32x4_t value;
63
64 //==============================================================================
65 // Loading
66 // clang-format off
67 static NeonRegister load (const float* d) { return { vld1q_f32 (d) }; }
68 static NeonRegister broadcast (float x) { return { vdupq_n_f32 (x) }; }
69
70 //==============================================================================
71 // Storing
72 void store (float* d) const { vst1q_f32 (d, value); }
73
74 //==============================================================================
75 // Generate Compare Masks
76 template <CompareOp op>
77 static NeonRegister compare (NeonRegister a, NeonRegister b) { return { vreinterpretq_f32_u32 (detail::NeonCompare<op, float>::cmp (a.value, b.value)) }; }
78
79 //==============================================================================
80 // Bit Operations
82 static NeonRegister bitwiseAndNot (NeonRegister a, NeonRegister b) { return { vreinterpretq_f32_u32 (vandq_u32 (vreinterpretq_u32_f32 (a.value), vmvnq_u32 (vreinterpretq_u32_f32 (b.value)))) }; }
83 static NeonRegister bitwiseAnd (NeonRegister a, NeonRegister b) { return { vreinterpretq_f32_u32 (vandq_u32 (vreinterpretq_u32_f32 (a.value), vreinterpretq_u32_f32 (b.value))) }; }
84 static NeonRegister bitwiseBlend (NeonRegister a, NeonRegister b, NeonRegister mask) { return { vbslq_f32 (vreinterpretq_u32_f32 (mask.value), b.value, a.value) }; }
85
86 //==============================================================================
87 // Math
88 static NeonRegister abs (NeonRegister x) { return { vabsq_f32 (x.value) }; }
89 static NeonRegister floor (NeonRegister x) { return { vrndmq_f32 (x.value) }; }
90 static NeonRegister ceil (NeonRegister x) { return { vrndpq_f32 (x.value) }; }
91 static NeonRegister mul (NeonRegister a, NeonRegister b) { return { vmulq_f32 (a.value, b.value) }; }
92 static NeonRegister div (NeonRegister a, NeonRegister b) { return { vdivq_f32 (a.value, b.value) }; }
93 static NeonRegister add (NeonRegister a, NeonRegister b) { return { vaddq_f32 (a.value, b.value) }; }
94 static NeonRegister sub (NeonRegister a, NeonRegister b) { return { vsubq_f32 (a.value, b.value) }; }
95 static NeonRegister max (NeonRegister a, NeonRegister b) { return { vmaxq_f32 (a.value, b.value) }; }
96 static NeonRegister min (NeonRegister a, NeonRegister b) { return { vminq_f32 (a.value, b.value) }; }
97 static NeonRegister fma (NeonRegister a, NeonRegister b, NeonRegister c) { return { vfmaq_f32 (c.value, a.value, b.value) }; }
98 static NeonRegister fms (NeonRegister a, NeonRegister b, NeonRegister c) { return { vfmsq_f32 (c.value, a.value, b.value) }; }
99
100 //==============================================================================
101 // Type conversion
102 static NeonRegister<int32_t> convertToInt (NeonRegister x);
103 static NeonRegister<int32_t> reinterpretAsInt (NeonRegister x);
104 // clang-format on
105};
106
107template <>
108struct NeonRegister<double>
109{
110 static constexpr size_t numElements = 2;
111
112 using NativeType = float64x2_t;
113 float64x2_t value;
114
115 //==============================================================================
116 // Loading
117 // clang-format off
118 static NeonRegister load (const double* d) { return { vld1q_f64 (d) }; }
119 static NeonRegister broadcast (double x) { return { vdupq_n_f64 (x) }; }
120
121 //==============================================================================
122 // Storing
123 void store (double* d) const { vst1q_f64 (d, value); }
124
125 //==============================================================================
126 // Generate Compare Masks
127 template <CompareOp op>
128 static NeonRegister compare (NeonRegister a, NeonRegister b) { return { vreinterpretq_f64_u64 (detail::NeonCompare<op, double>::cmp (a.value, b.value)) }; }
129
130 //==============================================================================
131 // Bit Operations
133 static NeonRegister bitwiseAndNot (NeonRegister a, NeonRegister b) { return { vreinterpretq_f64_u32 (vandq_u32 (vreinterpretq_u32_f64 (a.value), vmvnq_u32 (vreinterpretq_u32_f64 (b.value)))) }; }
134 static NeonRegister bitwiseAnd (NeonRegister a, NeonRegister b) { return { vreinterpretq_f64_u32 (vandq_u32 (vreinterpretq_u32_f64 (a.value), vreinterpretq_u32_f64 (b.value))) }; }
135 static NeonRegister bitwiseBlend (NeonRegister a, NeonRegister b, NeonRegister mask) { return { vbslq_f64 (vreinterpretq_u64_f64 (mask.value), b.value, a.value) }; }
136
137 //==============================================================================
138 // Math
139 static NeonRegister abs (NeonRegister x) { return { vabsq_f64 (x.value) }; }
140 static NeonRegister floor (NeonRegister x) { return { vrndmq_f64 (x.value) }; }
141 static NeonRegister ceil (NeonRegister x) { return { vrndpq_f64 (x.value) }; }
142 static NeonRegister mul (NeonRegister a, NeonRegister b) { return { vmulq_f64 (a.value, b.value) }; }
143 static NeonRegister div (NeonRegister a, NeonRegister b) { return { vdivq_f64 (a.value, b.value) }; }
144 static NeonRegister add (NeonRegister a, NeonRegister b) { return { vaddq_f64 (a.value, b.value) }; }
145 static NeonRegister sub (NeonRegister a, NeonRegister b) { return { vsubq_f64 (a.value, b.value) }; }
146 static NeonRegister max (NeonRegister a, NeonRegister b) { return { vmaxq_f64 (a.value, b.value) }; }
147 static NeonRegister min (NeonRegister a, NeonRegister b) { return { vminq_f64 (a.value, b.value) }; }
148 static NeonRegister fma (NeonRegister a, NeonRegister b, NeonRegister c) { return { vfmaq_f64 (c.value, a.value, b.value) }; }
149 static NeonRegister fms (NeonRegister a, NeonRegister b, NeonRegister c) { return { vfmsq_f64 (c.value, a.value, b.value) }; }
150
151 //==============================================================================
152 // Type conversion
153 static NeonRegister<int64_t> convertToInt (NeonRegister x);
154 static NeonRegister<int64_t> reinterpretAsInt (NeonRegister x);
155 // clang-format on
156};
157
158template <>
159struct NeonRegister<int32_t>
160{
161 static constexpr size_t numElements = 4;
162
163 using NativeType = int32x4_t;
164 int32x4_t value;
165
166 //==============================================================================
167 // Loading
168 // clang-format off
169 static NeonRegister load (const int32_t* d) { return { vld1q_s32 (d) }; }
170 static NeonRegister broadcast (int32_t x) { return { vdupq_n_s32 (x) }; }
171
172 //==============================================================================
173 // Storing
174 void store (int32_t* d) const { vst1q_s32 (d, value); }
175
176 //==============================================================================
177 // Bit Operations
178 static NeonRegister bitwiseAnd (NeonRegister a, NeonRegister b) { return { vandq_s32 (a.value, b.value) }; }
179 static NeonRegister bitwiseOr (NeonRegister a, NeonRegister b) { return { vorrq_s32 (a.value, b.value) }; }
180
181 //==============================================================================
182 // Math
183 static NeonRegister abs (NeonRegister x) { return { vabsq_s32 (x.value) }; }
184 static NeonRegister mul (NeonRegister a, NeonRegister b) { return { vmulq_s32 (a.value, b.value) }; }
185 static NeonRegister add (NeonRegister a, NeonRegister b) { return { vaddq_s32 (a.value, b.value) }; }
186 static NeonRegister sub (NeonRegister a, NeonRegister b) { return { vsubq_s32 (a.value, b.value) }; }
187 static NeonRegister max (NeonRegister a, NeonRegister b) { return { vmaxq_s32 (a.value, b.value) }; }
188 static NeonRegister min (NeonRegister a, NeonRegister b) { return { vminq_s32 (a.value, b.value) }; }
189
190 //==============================================================================
191 // Type conversion
192 static NeonRegister<float> convertToFp (NeonRegister x) { return { vcvtq_f32_s32 (x.value) }; }
193 static NeonRegister<float> reinterpretAsFp (NeonRegister x) { return { vreinterpretq_f32_s32 (x.value) }; }
194 // clang-format on
195};
196
197template <>
198struct NeonRegister<uint32_t>
199{
200 static constexpr size_t numElements = 4;
201
202 using NativeType = uint32x4_t;
203 uint32x4_t value;
204
205 //==============================================================================
206 // Loading
207 // clang-format off
208 static NeonRegister load (const uint32_t* d) { return { vld1q_u32 (d) }; }
209 static NeonRegister broadcast (uint32_t x) { return { vdupq_n_u32 (x) }; }
210
211 //==============================================================================
212 // Storing
213 void store (uint32_t* d) const { vst1q_u32 (d, value); }
214
215 //==============================================================================
216 // Bit Operations
217 static NeonRegister bitwiseAnd (NeonRegister a, NeonRegister b) { return { vandq_u32 (a.value, b.value) }; }
218 static NeonRegister bitwiseOr (NeonRegister a, NeonRegister b) { return { vorrq_u32 (a.value, b.value) }; }
219
220 //==============================================================================
221 // Math
222 static NeonRegister mul (NeonRegister a, NeonRegister b) { return { vmulq_u32 (a.value, b.value) }; }
223 static NeonRegister add (NeonRegister a, NeonRegister b) { return { vaddq_u32 (a.value, b.value) }; }
224 static NeonRegister sub (NeonRegister a, NeonRegister b) { return { vsubq_u32 (a.value, b.value) }; }
225 static NeonRegister max (NeonRegister a, NeonRegister b) { return { vmaxq_u32 (a.value, b.value) }; }
226 static NeonRegister min (NeonRegister a, NeonRegister b) { return { vminq_u32 (a.value, b.value) }; }
227 // clang-format on
228};
229
230template <>
231struct NeonRegister<int64_t>
232{
233 static constexpr size_t numElements = 2;
234
235 using NativeType = int64x2_t;
236 int64x2_t value;
237
238 //==============================================================================
239 // Loading
240 // clang-format off
241 static NeonRegister load (const int64_t* d) { return { vld1q_s64 (d) }; }
242 static NeonRegister broadcast (int64_t x) { return { vdupq_n_s64 (x) }; }
243
244 //==============================================================================
245 // Storing
246 void store (int64_t* d) const { vst1q_s64 (d, value); }
247
248 //==============================================================================
249 // Bit Operations
250 static NeonRegister bitwiseAnd (NeonRegister a, NeonRegister b) { return { vandq_s64 (a.value, b.value) }; }
251 static NeonRegister bitwiseOr (NeonRegister a, NeonRegister b) { return { vorrq_s64 (a.value, b.value) }; }
252
253 //==============================================================================
254 // Math
255 static NeonRegister abs (NeonRegister x) { return { vabsq_s64 (x.value) }; }
256 static NeonRegister add (NeonRegister a, NeonRegister b) { return { vaddq_s64 (a.value, b.value) }; }
257 static NeonRegister sub (NeonRegister a, NeonRegister b) { return { vsubq_s64 (a.value, b.value) }; }
258
259 //==============================================================================
260 // Type conversion
261 static NeonRegister<double> convertToFp (NeonRegister x) { return { vcvtq_f64_s64 (x.value) }; }
262 static NeonRegister<double> reinterpretAsFp (NeonRegister x) { return { vreinterpretq_f64_s64 (x.value) }; }
263 // clang-format on
264};
265
266template <>
267struct NeonRegister<uint64_t>
268{
269 static constexpr size_t numElements = 2;
270
271 using NativeType = uint64x2_t;
272 uint64x2_t value;
273
274 //==============================================================================
275 // Loading
276 // clang-format off
277 static NeonRegister load (const uint64_t* d) { return { vld1q_u64 (d) }; }
278 static NeonRegister broadcast (uint64_t x) { return { vdupq_n_u64 (x) }; }
279
280 //==============================================================================
281 // Storing
282 void store (uint64_t* d) const { vst1q_u64 (d, value); }
283
284 //==============================================================================
285 // Bit Operations
286 static NeonRegister bitwiseAnd (NeonRegister a, NeonRegister b) { return { vandq_u64 (a.value, b.value) }; }
287 static NeonRegister bitwiseOr (NeonRegister a, NeonRegister b) { return { vorrq_u64 (a.value, b.value) }; }
288
289 //==============================================================================
290 // Math
291 static NeonRegister add (NeonRegister a, NeonRegister b) { return { vaddq_u64 (a.value, b.value) }; }
292 static NeonRegister sub (NeonRegister a, NeonRegister b) { return { vsubq_u64 (a.value, b.value) }; }
293 // clang-format on
294};
295
296inline NeonRegister<int32_t> NeonRegister<float>::convertToInt (NeonRegister<float> x) { return { vcvtq_s32_f32 (x.value) }; }
297inline NeonRegister<int32_t> NeonRegister<float>::reinterpretAsInt (NeonRegister<float> x) { return { vreinterpretq_s32_f32 (x.value) }; }
298inline NeonRegister<int64_t> NeonRegister<double>::convertToInt (NeonRegister<double> x) { return { vcvtq_s64_f64 (x.value) }; }
299inline NeonRegister<int64_t> NeonRegister<double>::reinterpretAsInt (NeonRegister<double> x) { return { vreinterpretq_s64_f64 (x.value) }; }
300
301#endif
302
303} // namespace vctr
constexpr ExpressionChainBuilder< expressions::Max > max
Computes the maximum value of the source values.
Definition: Max.h:198
constexpr ExpressionChainBuilder< expressions::Abs > abs
Computes the absolute value of the source values.
Definition: Abs.h:135
constexpr ExpressionChainBuilder< expressions::Min > min
Computes the minimum value of the source values.
Definition: Min.h:198
The main namespace of the VCTR project.
Definition: Array.h:24
CompareOp
Possible types of (SIMD) compare operations.
Definition: SIMDHelpers.h:63
Definition: NeonRegister.h:28