native 0.0.1
Vectors, masks and wide register packs for C++26
Loading...
Searching...
No Matches
rdm.h
1// SPDX-FileCopyrightText: 2026 Edward Kmett <ekmett@gmail.com>
2// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0
3#pragma once
5#include "native/config.h"
6#include "native/attributes.h"
7#include "native/isa.h"
8#if NATIVE_HOST_NEON
9#include <arm_neon.h>
10#endif
11#if NATIVE_HOST_NEON || defined(NATIVE_DOXYGEN)
12
13namespace native::detail {
14 // Clang lowers 128-bit inline-asm operands through byte vectors. On a
15 // big-endian target that changes byte order within 16/32-bit lanes.
16 // Its 64-bit/scalar register operands already preserve the required bits.
17 template<class V> native_inline V rdm_register_order(V value) noexcept {
18#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
19 if constexpr (requires { value[0]; }) {
20 if constexpr (sizeof(V) == 16) {
21 auto bytes = __builtin_bit_cast(int8x16_t, value);
22 if constexpr (sizeof(value[0]) == 2)
23 return __builtin_bit_cast(V, __builtin_shufflevector(bytes, bytes,
24 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14));
25 else
26 return __builtin_bit_cast(V, __builtin_shufflevector(bytes, bytes,
27 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12));
28 }
29 }
30#endif
31 return value;
32 }
33
34 template<isa<arm> Arch> requires(Arch.has(arm_feature::rdm))
35 native_nodiscard native_inline __attribute__((target("rdm")))
36 int16_t sqrdmlah(int16_t accumulator, int16_t lhs, int16_t rhs) noexcept {
37 auto result = detail::rdm_register_order(accumulator);
38 auto left = detail::rdm_register_order(lhs);
39 auto right = detail::rdm_register_order(rhs);
40 asm volatile("sqrdmlah %h0, %h1, %h2"
41 : "+w"(result) : "w"(left), "w"(right));
42 return detail::rdm_register_order(result);
43 }
44
45 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 4)
46 native_nodiscard native_inline __attribute__((target("rdm")))
47 int16_t sqrdmlah_lane(int16_t accumulator, int16_t lhs, int16x4_t rhs) noexcept {
48 auto result = detail::rdm_register_order(accumulator);
49 auto left = detail::rdm_register_order(lhs);
50 auto right = detail::rdm_register_order(rhs);
51 // The restricted V0-V15 constraint accepts a full 128-bit register.
52 auto source = detail::rdm_register_order(
53 __builtin_shufflevector(right, right, 0, 1, 2, 3, -1, -1, -1, -1));
54#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
55 constexpr int index = 3 - Lane;
56#else
57 constexpr int index = Lane;
58#endif
59 asm volatile("sqrdmlah %h0, %h1, %2.h[%c3]"
60 : "+w"(result) : "w"(left), "x"(source), "i"(index));
61 return detail::rdm_register_order(result);
62 }
63
64 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 8)
65 native_nodiscard native_inline __attribute__((target("rdm")))
66 int16_t sqrdmlah_lane(int16_t accumulator, int16_t lhs, int16x8_t rhs) noexcept {
67 auto result = detail::rdm_register_order(accumulator);
68 auto left = detail::rdm_register_order(lhs);
69 auto right = detail::rdm_register_order(rhs);
70#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
71 constexpr int index = 7 - Lane;
72#else
73 constexpr int index = Lane;
74#endif
75 asm volatile("sqrdmlah %h0, %h1, %2.h[%c3]"
76 : "+w"(result) : "w"(left), "x"(right), "i"(index));
77 return detail::rdm_register_order(result);
78 }
79
80 template<isa<arm> Arch> requires(Arch.has(arm_feature::rdm))
81 native_nodiscard native_inline __attribute__((target("rdm")))
82 int16x4_t sqrdmlah(int16x4_t accumulator, int16x4_t lhs, int16x4_t rhs) noexcept {
83 auto result = detail::rdm_register_order(accumulator);
84 auto left = detail::rdm_register_order(lhs);
85 auto right = detail::rdm_register_order(rhs);
86 asm volatile("sqrdmlah %0.4h, %1.4h, %2.4h"
87 : "+w"(result) : "w"(left), "w"(right));
88 return detail::rdm_register_order(result);
89 }
90
91 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 4)
92 native_nodiscard native_inline __attribute__((target("rdm")))
93 int16x4_t sqrdmlah_lane(int16x4_t accumulator, int16x4_t lhs, int16x4_t rhs) noexcept {
94 auto result = detail::rdm_register_order(accumulator);
95 auto left = detail::rdm_register_order(lhs);
96 auto right = detail::rdm_register_order(rhs);
97 // The restricted V0-V15 constraint accepts a full 128-bit register.
98 auto source = detail::rdm_register_order(
99 __builtin_shufflevector(right, right, 0, 1, 2, 3, -1, -1, -1, -1));
100#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
101 constexpr int index = 3 - Lane;
102#else
103 constexpr int index = Lane;
104#endif
105 asm volatile("sqrdmlah %0.4h, %1.4h, %2.h[%c3]"
106 : "+w"(result) : "w"(left), "x"(source), "i"(index));
107 return detail::rdm_register_order(result);
108 }
109
110 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 8)
111 native_nodiscard native_inline __attribute__((target("rdm")))
112 int16x4_t sqrdmlah_lane(int16x4_t accumulator, int16x4_t lhs, int16x8_t rhs) noexcept {
113 auto result = detail::rdm_register_order(accumulator);
114 auto left = detail::rdm_register_order(lhs);
115 auto right = detail::rdm_register_order(rhs);
116#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
117 constexpr int index = 7 - Lane;
118#else
119 constexpr int index = Lane;
120#endif
121 asm volatile("sqrdmlah %0.4h, %1.4h, %2.h[%c3]"
122 : "+w"(result) : "w"(left), "x"(right), "i"(index));
123 return detail::rdm_register_order(result);
124 }
125
126 template<isa<arm> Arch> requires(Arch.has(arm_feature::rdm))
127 native_nodiscard native_inline __attribute__((target("rdm")))
128 int16x8_t sqrdmlah(int16x8_t accumulator, int16x8_t lhs, int16x8_t rhs) noexcept {
129 auto result = detail::rdm_register_order(accumulator);
130 auto left = detail::rdm_register_order(lhs);
131 auto right = detail::rdm_register_order(rhs);
132 asm volatile("sqrdmlah %0.8h, %1.8h, %2.8h"
133 : "+w"(result) : "w"(left), "w"(right));
134 return detail::rdm_register_order(result);
135 }
136
137 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 4)
138 native_nodiscard native_inline __attribute__((target("rdm")))
139 int16x8_t sqrdmlah_lane(int16x8_t accumulator, int16x8_t lhs, int16x4_t rhs) noexcept {
140 auto result = detail::rdm_register_order(accumulator);
141 auto left = detail::rdm_register_order(lhs);
142 auto right = detail::rdm_register_order(rhs);
143 // The restricted V0-V15 constraint accepts a full 128-bit register.
144 auto source = detail::rdm_register_order(
145 __builtin_shufflevector(right, right, 0, 1, 2, 3, -1, -1, -1, -1));
146#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
147 constexpr int index = 3 - Lane;
148#else
149 constexpr int index = Lane;
150#endif
151 asm volatile("sqrdmlah %0.8h, %1.8h, %2.h[%c3]"
152 : "+w"(result) : "w"(left), "x"(source), "i"(index));
153 return detail::rdm_register_order(result);
154 }
155
156 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 8)
157 native_nodiscard native_inline __attribute__((target("rdm")))
158 int16x8_t sqrdmlah_lane(int16x8_t accumulator, int16x8_t lhs, int16x8_t rhs) noexcept {
159 auto result = detail::rdm_register_order(accumulator);
160 auto left = detail::rdm_register_order(lhs);
161 auto right = detail::rdm_register_order(rhs);
162#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
163 constexpr int index = 7 - Lane;
164#else
165 constexpr int index = Lane;
166#endif
167 asm volatile("sqrdmlah %0.8h, %1.8h, %2.h[%c3]"
168 : "+w"(result) : "w"(left), "x"(right), "i"(index));
169 return detail::rdm_register_order(result);
170 }
171
172 template<isa<arm> Arch> requires(Arch.has(arm_feature::rdm))
173 native_nodiscard native_inline __attribute__((target("rdm")))
174 int32_t sqrdmlah(int32_t accumulator, int32_t lhs, int32_t rhs) noexcept {
175 auto result = detail::rdm_register_order(accumulator);
176 auto left = detail::rdm_register_order(lhs);
177 auto right = detail::rdm_register_order(rhs);
178 asm volatile("sqrdmlah %s0, %s1, %s2"
179 : "+w"(result) : "w"(left), "w"(right));
180 return detail::rdm_register_order(result);
181 }
182
183 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 2)
184 native_nodiscard native_inline __attribute__((target("rdm")))
185 int32_t sqrdmlah_lane(int32_t accumulator, int32_t lhs, int32x2_t rhs) noexcept {
186 auto result = detail::rdm_register_order(accumulator);
187 auto left = detail::rdm_register_order(lhs);
188 auto right = detail::rdm_register_order(rhs);
189 constexpr int index = Lane;
190 asm volatile("sqrdmlah %s0, %s1, %2.s[%c3]"
191 : "+w"(result) : "w"(left), "w"(right), "i"(index));
192 return detail::rdm_register_order(result);
193 }
194
195 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 4)
196 native_nodiscard native_inline __attribute__((target("rdm")))
197 int32_t sqrdmlah_lane(int32_t accumulator, int32_t lhs, int32x4_t rhs) noexcept {
198 auto result = detail::rdm_register_order(accumulator);
199 auto left = detail::rdm_register_order(lhs);
200 auto right = detail::rdm_register_order(rhs);
201#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
202 constexpr int index = 3 - Lane;
203#else
204 constexpr int index = Lane;
205#endif
206 asm volatile("sqrdmlah %s0, %s1, %2.s[%c3]"
207 : "+w"(result) : "w"(left), "w"(right), "i"(index));
208 return detail::rdm_register_order(result);
209 }
210
211 template<isa<arm> Arch> requires(Arch.has(arm_feature::rdm))
212 native_nodiscard native_inline __attribute__((target("rdm")))
213 int32x2_t sqrdmlah(int32x2_t accumulator, int32x2_t lhs, int32x2_t rhs) noexcept {
214 auto result = detail::rdm_register_order(accumulator);
215 auto left = detail::rdm_register_order(lhs);
216 auto right = detail::rdm_register_order(rhs);
217 asm volatile("sqrdmlah %0.2s, %1.2s, %2.2s"
218 : "+w"(result) : "w"(left), "w"(right));
219 return detail::rdm_register_order(result);
220 }
221
222 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 2)
223 native_nodiscard native_inline __attribute__((target("rdm")))
224 int32x2_t sqrdmlah_lane(int32x2_t accumulator, int32x2_t lhs, int32x2_t rhs) noexcept {
225 auto result = detail::rdm_register_order(accumulator);
226 auto left = detail::rdm_register_order(lhs);
227 auto right = detail::rdm_register_order(rhs);
228 constexpr int index = Lane;
229 asm volatile("sqrdmlah %0.2s, %1.2s, %2.s[%c3]"
230 : "+w"(result) : "w"(left), "w"(right), "i"(index));
231 return detail::rdm_register_order(result);
232 }
233
234 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 4)
235 native_nodiscard native_inline __attribute__((target("rdm")))
236 int32x2_t sqrdmlah_lane(int32x2_t accumulator, int32x2_t lhs, int32x4_t rhs) noexcept {
237 auto result = detail::rdm_register_order(accumulator);
238 auto left = detail::rdm_register_order(lhs);
239 auto right = detail::rdm_register_order(rhs);
240#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
241 constexpr int index = 3 - Lane;
242#else
243 constexpr int index = Lane;
244#endif
245 asm volatile("sqrdmlah %0.2s, %1.2s, %2.s[%c3]"
246 : "+w"(result) : "w"(left), "w"(right), "i"(index));
247 return detail::rdm_register_order(result);
248 }
249
250 template<isa<arm> Arch> requires(Arch.has(arm_feature::rdm))
251 native_nodiscard native_inline __attribute__((target("rdm")))
252 int32x4_t sqrdmlah(int32x4_t accumulator, int32x4_t lhs, int32x4_t rhs) noexcept {
253 auto result = detail::rdm_register_order(accumulator);
254 auto left = detail::rdm_register_order(lhs);
255 auto right = detail::rdm_register_order(rhs);
256 asm volatile("sqrdmlah %0.4s, %1.4s, %2.4s"
257 : "+w"(result) : "w"(left), "w"(right));
258 return detail::rdm_register_order(result);
259 }
260
261 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 2)
262 native_nodiscard native_inline __attribute__((target("rdm")))
263 int32x4_t sqrdmlah_lane(int32x4_t accumulator, int32x4_t lhs, int32x2_t rhs) noexcept {
264 auto result = detail::rdm_register_order(accumulator);
265 auto left = detail::rdm_register_order(lhs);
266 auto right = detail::rdm_register_order(rhs);
267 constexpr int index = Lane;
268 asm volatile("sqrdmlah %0.4s, %1.4s, %2.s[%c3]"
269 : "+w"(result) : "w"(left), "w"(right), "i"(index));
270 return detail::rdm_register_order(result);
271 }
272
273 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 4)
274 native_nodiscard native_inline __attribute__((target("rdm")))
275 int32x4_t sqrdmlah_lane(int32x4_t accumulator, int32x4_t lhs, int32x4_t rhs) noexcept {
276 auto result = detail::rdm_register_order(accumulator);
277 auto left = detail::rdm_register_order(lhs);
278 auto right = detail::rdm_register_order(rhs);
279#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
280 constexpr int index = 3 - Lane;
281#else
282 constexpr int index = Lane;
283#endif
284 asm volatile("sqrdmlah %0.4s, %1.4s, %2.s[%c3]"
285 : "+w"(result) : "w"(left), "w"(right), "i"(index));
286 return detail::rdm_register_order(result);
287 }
288
289 template<isa<arm> Arch> requires(Arch.has(arm_feature::rdm))
290 native_nodiscard native_inline __attribute__((target("rdm")))
291 int16_t sqrdmlsh(int16_t accumulator, int16_t lhs, int16_t rhs) noexcept {
292 auto result = detail::rdm_register_order(accumulator);
293 auto left = detail::rdm_register_order(lhs);
294 auto right = detail::rdm_register_order(rhs);
295 asm volatile("sqrdmlsh %h0, %h1, %h2"
296 : "+w"(result) : "w"(left), "w"(right));
297 return detail::rdm_register_order(result);
298 }
299
300 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 4)
301 native_nodiscard native_inline __attribute__((target("rdm")))
302 int16_t sqrdmlsh_lane(int16_t accumulator, int16_t lhs, int16x4_t rhs) noexcept {
303 auto result = detail::rdm_register_order(accumulator);
304 auto left = detail::rdm_register_order(lhs);
305 auto right = detail::rdm_register_order(rhs);
306 // The restricted V0-V15 constraint accepts a full 128-bit register.
307 auto source = detail::rdm_register_order(
308 __builtin_shufflevector(right, right, 0, 1, 2, 3, -1, -1, -1, -1));
309#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
310 constexpr int index = 3 - Lane;
311#else
312 constexpr int index = Lane;
313#endif
314 asm volatile("sqrdmlsh %h0, %h1, %2.h[%c3]"
315 : "+w"(result) : "w"(left), "x"(source), "i"(index));
316 return detail::rdm_register_order(result);
317 }
318
319 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 8)
320 native_nodiscard native_inline __attribute__((target("rdm")))
321 int16_t sqrdmlsh_lane(int16_t accumulator, int16_t lhs, int16x8_t rhs) noexcept {
322 auto result = detail::rdm_register_order(accumulator);
323 auto left = detail::rdm_register_order(lhs);
324 auto right = detail::rdm_register_order(rhs);
325#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
326 constexpr int index = 7 - Lane;
327#else
328 constexpr int index = Lane;
329#endif
330 asm volatile("sqrdmlsh %h0, %h1, %2.h[%c3]"
331 : "+w"(result) : "w"(left), "x"(right), "i"(index));
332 return detail::rdm_register_order(result);
333 }
334
335 template<isa<arm> Arch> requires(Arch.has(arm_feature::rdm))
336 native_nodiscard native_inline __attribute__((target("rdm")))
337 int16x4_t sqrdmlsh(int16x4_t accumulator, int16x4_t lhs, int16x4_t rhs) noexcept {
338 auto result = detail::rdm_register_order(accumulator);
339 auto left = detail::rdm_register_order(lhs);
340 auto right = detail::rdm_register_order(rhs);
341 asm volatile("sqrdmlsh %0.4h, %1.4h, %2.4h"
342 : "+w"(result) : "w"(left), "w"(right));
343 return detail::rdm_register_order(result);
344 }
345
346 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 4)
347 native_nodiscard native_inline __attribute__((target("rdm")))
348 int16x4_t sqrdmlsh_lane(int16x4_t accumulator, int16x4_t lhs, int16x4_t rhs) noexcept {
349 auto result = detail::rdm_register_order(accumulator);
350 auto left = detail::rdm_register_order(lhs);
351 auto right = detail::rdm_register_order(rhs);
352 // The restricted V0-V15 constraint accepts a full 128-bit register.
353 auto source = detail::rdm_register_order(
354 __builtin_shufflevector(right, right, 0, 1, 2, 3, -1, -1, -1, -1));
355#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
356 constexpr int index = 3 - Lane;
357#else
358 constexpr int index = Lane;
359#endif
360 asm volatile("sqrdmlsh %0.4h, %1.4h, %2.h[%c3]"
361 : "+w"(result) : "w"(left), "x"(source), "i"(index));
362 return detail::rdm_register_order(result);
363 }
364
365 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 8)
366 native_nodiscard native_inline __attribute__((target("rdm")))
367 int16x4_t sqrdmlsh_lane(int16x4_t accumulator, int16x4_t lhs, int16x8_t rhs) noexcept {
368 auto result = detail::rdm_register_order(accumulator);
369 auto left = detail::rdm_register_order(lhs);
370 auto right = detail::rdm_register_order(rhs);
371#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
372 constexpr int index = 7 - Lane;
373#else
374 constexpr int index = Lane;
375#endif
376 asm volatile("sqrdmlsh %0.4h, %1.4h, %2.h[%c3]"
377 : "+w"(result) : "w"(left), "x"(right), "i"(index));
378 return detail::rdm_register_order(result);
379 }
380
381 template<isa<arm> Arch> requires(Arch.has(arm_feature::rdm))
382 native_nodiscard native_inline __attribute__((target("rdm")))
383 int16x8_t sqrdmlsh(int16x8_t accumulator, int16x8_t lhs, int16x8_t rhs) noexcept {
384 auto result = detail::rdm_register_order(accumulator);
385 auto left = detail::rdm_register_order(lhs);
386 auto right = detail::rdm_register_order(rhs);
387 asm volatile("sqrdmlsh %0.8h, %1.8h, %2.8h"
388 : "+w"(result) : "w"(left), "w"(right));
389 return detail::rdm_register_order(result);
390 }
391
392 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 4)
393 native_nodiscard native_inline __attribute__((target("rdm")))
394 int16x8_t sqrdmlsh_lane(int16x8_t accumulator, int16x8_t lhs, int16x4_t rhs) noexcept {
395 auto result = detail::rdm_register_order(accumulator);
396 auto left = detail::rdm_register_order(lhs);
397 auto right = detail::rdm_register_order(rhs);
398 // The restricted V0-V15 constraint accepts a full 128-bit register.
399 auto source = detail::rdm_register_order(
400 __builtin_shufflevector(right, right, 0, 1, 2, 3, -1, -1, -1, -1));
401#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
402 constexpr int index = 3 - Lane;
403#else
404 constexpr int index = Lane;
405#endif
406 asm volatile("sqrdmlsh %0.8h, %1.8h, %2.h[%c3]"
407 : "+w"(result) : "w"(left), "x"(source), "i"(index));
408 return detail::rdm_register_order(result);
409 }
410
411 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 8)
412 native_nodiscard native_inline __attribute__((target("rdm")))
413 int16x8_t sqrdmlsh_lane(int16x8_t accumulator, int16x8_t lhs, int16x8_t rhs) noexcept {
414 auto result = detail::rdm_register_order(accumulator);
415 auto left = detail::rdm_register_order(lhs);
416 auto right = detail::rdm_register_order(rhs);
417#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
418 constexpr int index = 7 - Lane;
419#else
420 constexpr int index = Lane;
421#endif
422 asm volatile("sqrdmlsh %0.8h, %1.8h, %2.h[%c3]"
423 : "+w"(result) : "w"(left), "x"(right), "i"(index));
424 return detail::rdm_register_order(result);
425 }
426
427 template<isa<arm> Arch> requires(Arch.has(arm_feature::rdm))
428 native_nodiscard native_inline __attribute__((target("rdm")))
429 int32_t sqrdmlsh(int32_t accumulator, int32_t lhs, int32_t rhs) noexcept {
430 auto result = detail::rdm_register_order(accumulator);
431 auto left = detail::rdm_register_order(lhs);
432 auto right = detail::rdm_register_order(rhs);
433 asm volatile("sqrdmlsh %s0, %s1, %s2"
434 : "+w"(result) : "w"(left), "w"(right));
435 return detail::rdm_register_order(result);
436 }
437
438 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 2)
439 native_nodiscard native_inline __attribute__((target("rdm")))
440 int32_t sqrdmlsh_lane(int32_t accumulator, int32_t lhs, int32x2_t rhs) noexcept {
441 auto result = detail::rdm_register_order(accumulator);
442 auto left = detail::rdm_register_order(lhs);
443 auto right = detail::rdm_register_order(rhs);
444 constexpr int index = Lane;
445 asm volatile("sqrdmlsh %s0, %s1, %2.s[%c3]"
446 : "+w"(result) : "w"(left), "w"(right), "i"(index));
447 return detail::rdm_register_order(result);
448 }
449
450 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 4)
451 native_nodiscard native_inline __attribute__((target("rdm")))
452 int32_t sqrdmlsh_lane(int32_t accumulator, int32_t lhs, int32x4_t rhs) noexcept {
453 auto result = detail::rdm_register_order(accumulator);
454 auto left = detail::rdm_register_order(lhs);
455 auto right = detail::rdm_register_order(rhs);
456#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
457 constexpr int index = 3 - Lane;
458#else
459 constexpr int index = Lane;
460#endif
461 asm volatile("sqrdmlsh %s0, %s1, %2.s[%c3]"
462 : "+w"(result) : "w"(left), "w"(right), "i"(index));
463 return detail::rdm_register_order(result);
464 }
465
466 template<isa<arm> Arch> requires(Arch.has(arm_feature::rdm))
467 native_nodiscard native_inline __attribute__((target("rdm")))
468 int32x2_t sqrdmlsh(int32x2_t accumulator, int32x2_t lhs, int32x2_t rhs) noexcept {
469 auto result = detail::rdm_register_order(accumulator);
470 auto left = detail::rdm_register_order(lhs);
471 auto right = detail::rdm_register_order(rhs);
472 asm volatile("sqrdmlsh %0.2s, %1.2s, %2.2s"
473 : "+w"(result) : "w"(left), "w"(right));
474 return detail::rdm_register_order(result);
475 }
476
477 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 2)
478 native_nodiscard native_inline __attribute__((target("rdm")))
479 int32x2_t sqrdmlsh_lane(int32x2_t accumulator, int32x2_t lhs, int32x2_t rhs) noexcept {
480 auto result = detail::rdm_register_order(accumulator);
481 auto left = detail::rdm_register_order(lhs);
482 auto right = detail::rdm_register_order(rhs);
483 constexpr int index = Lane;
484 asm volatile("sqrdmlsh %0.2s, %1.2s, %2.s[%c3]"
485 : "+w"(result) : "w"(left), "w"(right), "i"(index));
486 return detail::rdm_register_order(result);
487 }
488
489 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 4)
490 native_nodiscard native_inline __attribute__((target("rdm")))
491 int32x2_t sqrdmlsh_lane(int32x2_t accumulator, int32x2_t lhs, int32x4_t rhs) noexcept {
492 auto result = detail::rdm_register_order(accumulator);
493 auto left = detail::rdm_register_order(lhs);
494 auto right = detail::rdm_register_order(rhs);
495#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
496 constexpr int index = 3 - Lane;
497#else
498 constexpr int index = Lane;
499#endif
500 asm volatile("sqrdmlsh %0.2s, %1.2s, %2.s[%c3]"
501 : "+w"(result) : "w"(left), "w"(right), "i"(index));
502 return detail::rdm_register_order(result);
503 }
504
505 template<isa<arm> Arch> requires(Arch.has(arm_feature::rdm))
506 native_nodiscard native_inline __attribute__((target("rdm")))
507 int32x4_t sqrdmlsh(int32x4_t accumulator, int32x4_t lhs, int32x4_t rhs) noexcept {
508 auto result = detail::rdm_register_order(accumulator);
509 auto left = detail::rdm_register_order(lhs);
510 auto right = detail::rdm_register_order(rhs);
511 asm volatile("sqrdmlsh %0.4s, %1.4s, %2.4s"
512 : "+w"(result) : "w"(left), "w"(right));
513 return detail::rdm_register_order(result);
514 }
515
516 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 2)
517 native_nodiscard native_inline __attribute__((target("rdm")))
518 int32x4_t sqrdmlsh_lane(int32x4_t accumulator, int32x4_t lhs, int32x2_t rhs) noexcept {
519 auto result = detail::rdm_register_order(accumulator);
520 auto left = detail::rdm_register_order(lhs);
521 auto right = detail::rdm_register_order(rhs);
522 constexpr int index = Lane;
523 asm volatile("sqrdmlsh %0.4s, %1.4s, %2.s[%c3]"
524 : "+w"(result) : "w"(left), "w"(right), "i"(index));
525 return detail::rdm_register_order(result);
526 }
527
528 template<isa<arm> Arch, int Lane> requires(Arch.has(arm_feature::rdm) && Lane >= 0 && Lane < 4)
529 native_nodiscard native_inline __attribute__((target("rdm")))
530 int32x4_t sqrdmlsh_lane(int32x4_t accumulator, int32x4_t lhs, int32x4_t rhs) noexcept {
531 auto result = detail::rdm_register_order(accumulator);
532 auto left = detail::rdm_register_order(lhs);
533 auto right = detail::rdm_register_order(rhs);
534#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
535 constexpr int index = 3 - Lane;
536#else
537 constexpr int index = Lane;
538#endif
539 asm volatile("sqrdmlsh %0.4s, %1.4s, %2.s[%c3]"
540 : "+w"(result) : "w"(left), "w"(right), "i"(index));
541 return detail::rdm_register_order(result);
542 }
543
544 // Reject Clang's lax vector conversions and scalar narrowing when an exact
545 // instruction shape or immediate lane is unavailable.
546
547 template<isa<arm> Arch, class A, class B, class C>
548 void sqrdmlah(A, B, C) = delete;
549 template<isa<arm> Arch, int Lane, class A, class B, class C>
550 void sqrdmlah_lane(A, B, C) = delete;
551 template<isa<arm> Arch, class A, class B, class C>
552 void sqrdmlsh(A, B, C) = delete;
553 template<isa<arm> Arch, int Lane, class A, class B, class C>
554 void sqrdmlsh_lane(A, B, C) = delete;
555
556
557}
558#endif
Compiler attributes for host code, with shader-safe shared modifiers.
constexpr int16_t sqrdmlah(int16_t accumulator, int16_t lhs, int16_t rhs) noexcept
SQRDMLAH: signed 16-bit rounding saturating add.
constexpr int16_t sqrdmlah_lane(int16_t accumulator, int16_t lhs, simd< std::int16_t, 4, Arch > rhs) noexcept
SQRDMLAH by element: broadcast rhs[Lane] before rounding and saturation.
constexpr int16_t sqrdmlsh_lane(int16_t accumulator, int16_t lhs, simd< std::int16_t, 4, Arch > rhs) noexcept
SQRDMLSH by element: broadcast rhs[Lane] before rounding and saturation.
constexpr int16_t sqrdmlsh(int16_t accumulator, int16_t lhs, int16_t rhs) noexcept
SQRDMLSH: signed 16-bit rounding saturating subtract.
#define native_inline
inline [[always_inline]]
Definition attributes.h:212
#define native_nodiscard
C++17 [[nodiscard]].
Definition attributes.h:189
constexpr int target
First matching requirement, with every later choice checked for shadowing.
Definition isa.h:396