]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/arm/arm-mve-builtins-shapes.cc
arm: [MVE intrinsics] add ternary_rshift shape
[thirdparty/gcc.git] / gcc / config / arm / arm-mve-builtins-shapes.cc
1 /* ACLE support for Arm MVE (function shapes)
2 Copyright (C) 2023 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 GCC is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
19
20 #include "config.h"
21 #include "system.h"
22 #include "coretypes.h"
23 #include "tm.h"
24 #include "tree.h"
25 #include "rtl.h"
26 #include "memmodel.h"
27 #include "insn-codes.h"
28 #include "optabs.h"
29 #include "arm-mve-builtins.h"
30 #include "arm-mve-builtins-shapes.h"
31
32 /* In the comments below, _t0 represents the first type suffix
33 (e.g. "_s8") and _t1 represents the second. T0/T1 represent the
34 type full names (e.g. int8x16_t). Square brackets enclose
35 characters that are present in only the full name, not the
36 overloaded name. Governing predicate arguments and predicate
37 suffixes are not shown, since they depend on the predication type,
38 which is a separate piece of information from the shape. */
39
40 namespace arm_mve {
41
42 /* If INSTANCE has a predicate, add it to the list of argument types
43 in ARGUMENT_TYPES. RETURN_TYPE is the type returned by the
44 function. */
45 static void
46 apply_predication (const function_instance &instance, tree return_type,
47 vec<tree> &argument_types)
48 {
49 if (instance.pred != PRED_none)
50 {
51 /* When predicate is PRED_m, insert a first argument
52 ("inactive") with the same type as return_type. */
53 if (instance.has_inactive_argument ())
54 argument_types.quick_insert (0, return_type);
55 argument_types.quick_push (get_mve_pred16_t ());
56 }
57 }
58
59 /* Parse and move past an element type in FORMAT and return it as a type
60 suffix. The format is:
61
62 [01] - the element type in type suffix 0 or 1 of INSTANCE.
63 h<elt> - a half-sized version of <elt>
64 s<bits> - a signed type with the given number of bits
65 s[01] - a signed type with the same width as type suffix 0 or 1
66 u<bits> - an unsigned type with the given number of bits
67 u[01] - an unsigned type with the same width as type suffix 0 or 1
68 w<elt> - a double-sized version of <elt>
69 x<bits> - a type with the given number of bits and same signedness
70 as the next argument.
71
72 Future intrinsics will extend this format. */
73 static type_suffix_index
74 parse_element_type (const function_instance &instance, const char *&format)
75 {
76 int ch = *format++;
77
78
79 if (ch == 's' || ch == 'u')
80 {
81 type_class_index tclass = (ch == 'f' ? TYPE_float
82 : ch == 's' ? TYPE_signed
83 : TYPE_unsigned);
84 char *end;
85 unsigned int bits = strtol (format, &end, 10);
86 format = end;
87 if (bits == 0 || bits == 1)
88 bits = instance.type_suffix (bits).element_bits;
89 return find_type_suffix (tclass, bits);
90 }
91
92 if (ch == 'h')
93 {
94 type_suffix_index suffix = parse_element_type (instance, format);
95 return find_type_suffix (type_suffixes[suffix].tclass,
96 type_suffixes[suffix].element_bits / 2);
97 }
98
99 if (ch == 'w')
100 {
101 type_suffix_index suffix = parse_element_type (instance, format);
102 return find_type_suffix (type_suffixes[suffix].tclass,
103 type_suffixes[suffix].element_bits * 2);
104 }
105
106 if (ch == 'x')
107 {
108 const char *next = format;
109 next = strstr (format, ",");
110 next+=2;
111 type_suffix_index suffix = parse_element_type (instance, next);
112 type_class_index tclass = type_suffixes[suffix].tclass;
113 char *end;
114 unsigned int bits = strtol (format, &end, 10);
115 format = end;
116 return find_type_suffix (tclass, bits);
117 }
118
119 if (ch == '0' || ch == '1')
120 return instance.type_suffix_ids[ch - '0'];
121
122 gcc_unreachable ();
123 }
124
125 /* Read and return a type from FORMAT for function INSTANCE. Advance
126 FORMAT beyond the type string. The format is:
127
128 p - predicates with type mve_pred16_t
129 s<elt> - a scalar type with the given element suffix
130 t<elt> - a vector or tuple type with given element suffix [*1]
131 v<elt> - a vector with the given element suffix
132
133 where <elt> has the format described above parse_element_type.
134
135 Future intrinsics will extend this format.
136
137 [*1] the vectors_per_tuple function indicates whether the type should
138 be a tuple, and if so, how many vectors it should contain. */
139 static tree
140 parse_type (const function_instance &instance, const char *&format)
141 {
142 int ch = *format++;
143
144 if (ch == 'p')
145 return get_mve_pred16_t ();
146
147 if (ch == 's')
148 {
149 type_suffix_index suffix = parse_element_type (instance, format);
150 return scalar_types[type_suffixes[suffix].vector_type];
151 }
152
153 if (ch == 't')
154 {
155 type_suffix_index suffix = parse_element_type (instance, format);
156 vector_type_index vector_type = type_suffixes[suffix].vector_type;
157 unsigned int num_vectors = instance.vectors_per_tuple ();
158 return acle_vector_types[num_vectors - 1][vector_type];
159 }
160
161 if (ch == 'v')
162 {
163 type_suffix_index suffix = parse_element_type (instance, format);
164 return acle_vector_types[0][type_suffixes[suffix].vector_type];
165 }
166
167 gcc_unreachable ();
168 }
169
170 /* Read a type signature for INSTANCE from FORMAT. Add the argument
171 types to ARGUMENT_TYPES and return the return type. Assert there
172 are no more than MAX_ARGS arguments.
173
174 The format is a comma-separated list of types (as for parse_type),
175 with the first type being the return type and the rest being the
176 argument types. */
177 static tree
178 parse_signature (const function_instance &instance, const char *format,
179 vec<tree> &argument_types, unsigned int max_args)
180 {
181 tree return_type = parse_type (instance, format);
182 unsigned int args = 0;
183 while (format[0] == ',')
184 {
185 gcc_assert (args < max_args);
186 format += 1;
187 tree argument_type = parse_type (instance, format);
188 argument_types.quick_push (argument_type);
189 args += 1;
190 }
191 gcc_assert (format[0] == 0);
192 return return_type;
193 }
194
195 /* Add one function instance for GROUP, using mode suffix MODE_SUFFIX_ID,
196 the type suffixes at index TI and the predication suffix at index PI.
197 The other arguments are as for build_all. */
198 static void
199 build_one (function_builder &b, const char *signature,
200 const function_group_info &group, mode_suffix_index mode_suffix_id,
201 unsigned int ti, unsigned int pi, bool preserve_user_namespace,
202 bool force_direct_overloads)
203 {
204 /* Current functions take at most five arguments. Match
205 parse_signature parameter below. */
206 auto_vec<tree, 5> argument_types;
207 function_instance instance (group.base_name, *group.base, *group.shape,
208 mode_suffix_id, group.types[ti],
209 group.preds[pi]);
210 tree return_type = parse_signature (instance, signature, argument_types, 5);
211 apply_predication (instance, return_type, argument_types);
212 b.add_unique_function (instance, return_type, argument_types,
213 preserve_user_namespace, group.requires_float,
214 force_direct_overloads);
215 }
216
217 /* Add a function instance for every type and predicate combination in
218 GROUP, except if requested to use only the predicates listed in
219 RESTRICT_TO_PREDS. Take the function base name from GROUP and the
220 mode suffix from MODE_SUFFIX_ID. Use SIGNATURE to construct the
221 function signature, then use apply_predication to add in the
222 predicate. */
223 static void
224 build_all (function_builder &b, const char *signature,
225 const function_group_info &group, mode_suffix_index mode_suffix_id,
226 bool preserve_user_namespace,
227 bool force_direct_overloads = false,
228 const predication_index *restrict_to_preds = NULL)
229 {
230 for (unsigned int pi = 0; group.preds[pi] != NUM_PREDS; ++pi)
231 {
232 unsigned int pi2 = 0;
233
234 if (restrict_to_preds)
235 for (; restrict_to_preds[pi2] != NUM_PREDS; ++pi2)
236 if (restrict_to_preds[pi2] == group.preds[pi])
237 break;
238
239 if (restrict_to_preds == NULL || restrict_to_preds[pi2] != NUM_PREDS)
240 for (unsigned int ti = 0;
241 ti == 0 || group.types[ti][0] != NUM_TYPE_SUFFIXES; ++ti)
242 build_one (b, signature, group, mode_suffix_id, ti, pi,
243 preserve_user_namespace, force_direct_overloads);
244 }
245 }
246
247 /* Add a function instance for every type and predicate combination in
248 GROUP, except if requested to use only the predicates listed in
249 RESTRICT_TO_PREDS, and only for 16-bit and 32-bit integers. Take
250 the function base name from GROUP and the mode suffix from
251 MODE_SUFFIX_ID. Use SIGNATURE to construct the function signature,
252 then use apply_predication to add in the predicate. */
253 static void
254 build_16_32 (function_builder &b, const char *signature,
255 const function_group_info &group, mode_suffix_index mode_suffix_id,
256 bool preserve_user_namespace,
257 bool force_direct_overloads = false,
258 const predication_index *restrict_to_preds = NULL)
259 {
260 for (unsigned int pi = 0; group.preds[pi] != NUM_PREDS; ++pi)
261 {
262 unsigned int pi2 = 0;
263
264 if (restrict_to_preds)
265 for (; restrict_to_preds[pi2] != NUM_PREDS; ++pi2)
266 if (restrict_to_preds[pi2] == group.preds[pi])
267 break;
268
269 if (restrict_to_preds == NULL || restrict_to_preds[pi2] != NUM_PREDS)
270 for (unsigned int ti = 0;
271 ti == 0 || group.types[ti][0] != NUM_TYPE_SUFFIXES; ++ti)
272 {
273 unsigned int element_bits = type_suffixes[group.types[ti][0]].element_bits;
274 type_class_index tclass = type_suffixes[group.types[ti][0]].tclass;
275 if ((tclass == TYPE_signed || tclass == TYPE_unsigned)
276 && (element_bits == 16 || element_bits == 32))
277 build_one (b, signature, group, mode_suffix_id, ti, pi,
278 preserve_user_namespace, force_direct_overloads);
279 }
280 }
281 }
282
283 /* Declare the function shape NAME, pointing it to an instance
284 of class <NAME>_def. */
285 #define SHAPE(NAME) \
286 static CONSTEXPR const NAME##_def NAME##_obj; \
287 namespace shapes { const function_shape *const NAME = &NAME##_obj; }
288
289 /* Base class for functions that are not overloaded. */
290 struct nonoverloaded_base : public function_shape
291 {
292 bool
293 explicit_type_suffix_p (unsigned int, enum predication_index, enum mode_suffix_index) const override
294 {
295 return true;
296 }
297
298 bool
299 explicit_mode_suffix_p (enum predication_index, enum mode_suffix_index) const override
300 {
301 return true;
302 }
303
304 bool
305 skip_overload_p (enum predication_index, enum mode_suffix_index) const override
306 {
307 return false;
308 }
309
310 tree
311 resolve (function_resolver &) const override
312 {
313 gcc_unreachable ();
314 }
315 };
316
317 /* Base class for overloaded functions. Bit N of EXPLICIT_MASK is true
318 if type suffix N appears in the overloaded name. */
319 template<unsigned int EXPLICIT_MASK>
320 struct overloaded_base : public function_shape
321 {
322 bool
323 explicit_type_suffix_p (unsigned int i, enum predication_index, enum mode_suffix_index) const override
324 {
325 return (EXPLICIT_MASK >> i) & 1;
326 }
327
328 bool
329 explicit_mode_suffix_p (enum predication_index, enum mode_suffix_index) const override
330 {
331 return false;
332 }
333
334 bool
335 skip_overload_p (enum predication_index, enum mode_suffix_index) const override
336 {
337 return false;
338 }
339 };
340
341 /* <T0>_t vfoo[_t0](<T0>_t, <T0>_t)
342
343 i.e. the standard shape for binary operations that operate on
344 uniform types.
345
346 Example: vandq.
347 int8x16_t [__arm_]vandq[_s8](int8x16_t a, int8x16_t b)
348 int8x16_t [__arm_]vandq_m[_s8](int8x16_t inactive, int8x16_t a, int8x16_t b, mve_pred16_t p)
349 int8x16_t [__arm_]vandq_x[_s8](int8x16_t a, int8x16_t b, mve_pred16_t p) */
350 struct binary_def : public overloaded_base<0>
351 {
352 void
353 build (function_builder &b, const function_group_info &group,
354 bool preserve_user_namespace) const override
355 {
356 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
357 build_all (b, "v0,v0,v0", group, MODE_none, preserve_user_namespace);
358 }
359
360 tree
361 resolve (function_resolver &r) const override
362 {
363 return r.resolve_uniform (2);
364 }
365 };
366 SHAPE (binary)
367
368 /* <[u]int32>_t vfoo[_<t0>](<T0>_t, <T0>_t)
369
370 i.e. the shape for binary operations that operate on a pair of
371 vectors and produce an int32_t or an uint32_t depending on the
372 signedness of the input elements.
373
374 Example: vmladavq.
375 int32_t [__arm_]vmladavq[_s16](int16x8_t m1, int16x8_t m2)
376 int32_t [__arm_]vmladavq_p[_s16](int16x8_t m1, int16x8_t m2, mve_pred16_t p) */
377 struct binary_acc_int32_def : public overloaded_base<0>
378 {
379 void
380 build (function_builder &b, const function_group_info &group,
381 bool preserve_user_namespace) const override
382 {
383 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
384 build_all (b, "sx32,v0,v0", group, MODE_none, preserve_user_namespace);
385 }
386
387 tree
388 resolve (function_resolver &r) const override
389 {
390 return r.resolve_uniform (2);
391 }
392 };
393 SHAPE (binary_acc_int32)
394
395 /* <[u]int64>_t vfoo[_<t0>](<T0>_t, <T0>_t)
396
397 Example: vmlaldavq.
398 int64_t [__arm_]vmlaldavq[_s16](int16x8_t m1, int16x8_t m2)
399 int64_t [__arm_]vmlaldavq_p[_s16](int16x8_t m1, int16x8_t m2, mve_pred16_t p) */
400 struct binary_acc_int64_def : public overloaded_base<0>
401 {
402 void
403 build (function_builder &b, const function_group_info &group,
404 bool preserve_user_namespace) const override
405 {
406 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
407 build_all (b, "sx64,v0,v0", group, MODE_none, preserve_user_namespace);
408 }
409
410 tree
411 resolve (function_resolver &r) const override
412 {
413 return r.resolve_uniform (2);
414 }
415 };
416 SHAPE (binary_acc_int64)
417
418 /* <[u]int32>_t vfoo[_<t0>]([u]int32_t, <T0>_t, <T0>_t)
419
420 Example: vmladavaq.
421 int32_t [__arm_]vmladavaq[_s16](int32_t add, int16x8_t m1, int16x8_t m2)
422 int32_t [__arm_]vmladavaq_p[_s16](int32_t add, int16x8_t m1, int16x8_t m2, mve_pred16_t p) */
423 struct binary_acca_int32_def : public overloaded_base<0>
424 {
425 void
426 build (function_builder &b, const function_group_info &group,
427 bool preserve_user_namespace) const override
428 {
429 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
430 build_all (b, "sx32,sx32,v0,v0", group, MODE_none, preserve_user_namespace);
431 }
432
433 tree
434 resolve (function_resolver &r) const override
435 {
436 unsigned int i, nargs;
437 type_suffix_index type;
438 if (!r.check_gp_argument (3, i, nargs)
439 || (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES)
440 return error_mark_node;
441
442 unsigned int last_arg = i;
443 for (i = 1; i < last_arg; i++)
444 if (!r.require_matching_vector_type (i, type))
445 return error_mark_node;
446
447 if (!r.require_integer_immediate (0))
448 return error_mark_node;
449
450 return r.resolve_to (r.mode_suffix_id, type);
451 }
452 };
453 SHAPE (binary_acca_int32)
454
455 /* [u]int64_t vfoo[_<t0>]([u]int64_t, <T0>_t, <T0>_t)
456
457 Example: vmlaldavaq.
458 int64_t [__arm_]vmlaldavaq[_s16](int64_t add, int16x8_t m1, int16x8_t m2)
459 int64_t [__arm_]vmlaldavaq_p[_s16](int64_t add, int16x8_t m1, int16x8_t m2, mve_pred16_t p) */
460 struct binary_acca_int64_def : public overloaded_base<0>
461 {
462 void
463 build (function_builder &b, const function_group_info &group,
464 bool preserve_user_namespace) const override
465 {
466 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
467 build_all (b, "sx64,sx64,v0,v0", group, MODE_none, preserve_user_namespace);
468 }
469
470 tree
471 resolve (function_resolver &r) const override
472 {
473 unsigned int i, nargs;
474 type_suffix_index type;
475 if (!r.check_gp_argument (3, i, nargs)
476 || (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES)
477 return error_mark_node;
478
479 unsigned int last_arg = i;
480 for (i = 1; i < last_arg; i++)
481 if (!r.require_matching_vector_type (i, type))
482 return error_mark_node;
483
484 if (!r.require_integer_immediate (0))
485 return error_mark_node;
486
487 return r.resolve_to (r.mode_suffix_id, type);
488 }
489 };
490 SHAPE (binary_acca_int64)
491
492 /* <T0>_t vfoo[_n_t0](<T0>_t, int32_t)
493
494 i.e. the shape for binary operations that operate on
495 a vector and an int32_t.
496
497 Example: vbrsrq.
498 int16x8_t [__arm_]vbrsrq[_n_s16](int16x8_t a, int32_t b)
499 int16x8_t [__arm_]vbrsrq_m[_n_s16](int16x8_t inactive, int16x8_t a, int32_t b, mve_pred16_t p)
500 int16x8_t [__arm_]vbrsrq_x[_n_s16](int16x8_t a, int32_t b, mve_pred16_t p) */
501 struct binary_imm32_def : public overloaded_base<0>
502 {
503 void
504 build (function_builder &b, const function_group_info &group,
505 bool preserve_user_namespace) const override
506 {
507 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
508 build_all (b, "v0,v0,ss32", group, MODE_n, preserve_user_namespace);
509 }
510
511 tree
512 resolve (function_resolver &r) const override
513 {
514 return r.resolve_uniform (1, 1);
515 }
516 };
517 SHAPE (binary_imm32)
518
519 /* <T0>_t vfoo[_n_t0](<T0>_t, const int)
520
521 Shape for vector shift right operations that take a vector first
522 argument and an integer, and produce a vector.
523
524 Check that 'imm' is in the [1..#bits] range.
525
526 Example: vrshrq.
527 int8x16_t [__arm_]vrshrq[_n_s8](int8x16_t a, const int imm)
528 int8x16_t [__arm_]vrshrq_m[_n_s8](int8x16_t inactive, int8x16_t a, const int imm, mve_pred16_t p)
529 int8x16_t [__arm_]vrshrq_x[_n_s8](int8x16_t a, const int imm, mve_pred16_t p) */
530 struct binary_rshift_def : public overloaded_base<0>
531 {
532 void
533 build (function_builder &b, const function_group_info &group,
534 bool preserve_user_namespace) const override
535 {
536 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
537 build_all (b, "v0,v0,ss32", group, MODE_n, preserve_user_namespace);
538 }
539
540 tree
541 resolve (function_resolver &r) const override
542 {
543 return r.resolve_uniform (1, 1);
544 }
545
546 bool
547 check (function_checker &c) const override
548 {
549 unsigned int bits = c.type_suffix (0).element_bits;
550 return c.require_immediate_range (1, 1, bits);
551 }
552 };
553 SHAPE (binary_rshift)
554
555
556 /* <uT0>_t vfoo[_n_t0](<T0>_t, int)
557
558 Shape for vector saturating shift left operations that take a
559 vector of signed elements as first argument and an integer, and
560 produce a vector of unsigned elements.
561
562 Check that 'imm' is in the [0..#bits-1] range.
563
564 Example: vqshluq.
565 uint16x8_t [__arm_]vqshluq[_n_s16](int16x8_t a, const int imm)
566 uint16x8_t [__arm_]vqshluq_m[_n_s16](uint16x8_t inactive, int16x8_t a, const int imm, mve_pred16_t p) */
567 struct binary_lshift_unsigned_def : public overloaded_base<0>
568 {
569 void
570 build (function_builder &b, const function_group_info &group,
571 bool preserve_user_namespace) const override
572 {
573 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
574 build_all (b, "vu0,vs0,ss32", group, MODE_n, preserve_user_namespace);
575 }
576
577 tree
578 resolve (function_resolver &r) const override
579 {
580 unsigned int i, nargs;
581 type_suffix_index type;
582 if (!r.check_gp_argument (2, i, nargs)
583 || (type = r.infer_vector_type (i-1)) == NUM_TYPE_SUFFIXES)
584 return error_mark_node;
585
586 if (r.pred == PRED_m)
587 {
588 /* With PRED_m, check that the 'inactive' first argument has
589 the expeected unsigned type. */
590 type_suffix_index return_type
591 = find_type_suffix (TYPE_unsigned, type_suffixes[type].element_bits);
592
593 if (!r.require_matching_vector_type (0, return_type))
594 return error_mark_node;
595 }
596
597 for (; i < nargs; ++i)
598 if (!r.require_integer_immediate (i))
599 return error_mark_node;
600
601 return r.resolve_to (r.mode_suffix_id, type);
602 }
603
604 bool
605 check (function_checker &c) const override
606 {
607 unsigned int bits = c.type_suffix (0).element_bits;
608 return c.require_immediate_range (1, 0, bits - 1);
609 }
610
611 };
612 SHAPE (binary_lshift_unsigned)
613
614 /* <uT0>_t vfoo[_t0](<uT0>_t, <T0>_t)
615
616 i.e. binary operations that take a vector of unsigned elements as first argument and a
617 vector of signed elements as second argument, and produce a vector of unsigned elements.
618
619 Example: vminaq.
620 uint8x16_t [__arm_]vminaq[_s8](uint8x16_t a, int8x16_t b)
621 uint8x16_t [__arm_]vminaq_m[_s8](uint8x16_t a, int8x16_t b, mve_pred16_t p) */
622 struct binary_maxamina_def : public overloaded_base<0>
623 {
624 void
625 build (function_builder &b, const function_group_info &group,
626 bool preserve_user_namespace) const override
627 {
628 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
629 build_all (b, "vu0,vu0,vs0", group, MODE_none, preserve_user_namespace);
630 }
631
632 tree
633 resolve (function_resolver &r) const override
634 {
635 unsigned int i, nargs;
636 type_suffix_index type;
637 if (!r.check_gp_argument (2, i, nargs)
638 || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES)
639 return error_mark_node;
640
641 /* Check that the first argument has the expeected unsigned
642 type. */
643 type_suffix_index return_type
644 = find_type_suffix (TYPE_unsigned, type_suffixes[type].element_bits);
645 if (!r.require_matching_vector_type (0, return_type))
646 return error_mark_node;
647
648 return r.resolve_to (r.mode_suffix_id, type);
649 }
650 };
651 SHAPE (binary_maxamina)
652
653 /* <uS0>_t vfoo[_<t0>](<uS0>_t, <T0>_t)
654
655 Example: vmaxavq.
656 uint8_t [__arm_]vmaxavq[_s8](uint8_t a, int8x16_t b)
657 uint8_t [__arm_]vmaxavq_p[_s8](uint8_t a, int8x16_t b, mve_pred16_t p) */
658 struct binary_maxavminav_def : public overloaded_base<0>
659 {
660 void
661 build (function_builder &b, const function_group_info &group,
662 bool preserve_user_namespace) const override
663 {
664 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
665 build_all (b, "su0,su0,v0", group, MODE_none, preserve_user_namespace);
666 }
667
668 tree
669 resolve (function_resolver &r) const override
670 {
671 unsigned int i, nargs;
672 type_suffix_index type;
673 if (!r.check_gp_argument (2, i, nargs)
674 || !r.require_derived_scalar_type (0, TYPE_unsigned)
675 || (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES)
676 return error_mark_node;
677
678 return r.resolve_to (r.mode_suffix_id, type);
679 }
680 };
681 SHAPE (binary_maxavminav)
682
683 /* <S0>_t vfoo[_<t0>](<S0>_t, <T0>_t)
684
685 Example: vmaxvq.
686 int8_t [__arm_]vmaxvq[_s8](int8_t a, int8x16_t b)
687 int8_t [__arm_]vmaxvq_p[_s8](int8_t a, int8x16_t b, mve_pred16_t p) */
688 struct binary_maxvminv_def : public overloaded_base<0>
689 {
690 void
691 build (function_builder &b, const function_group_info &group,
692 bool preserve_user_namespace) const override
693 {
694 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
695 build_all (b, "s0,s0,v0", group, MODE_none, preserve_user_namespace);
696 }
697
698 tree
699 resolve (function_resolver &r) const override
700 {
701 unsigned int i, nargs;
702 type_suffix_index type;
703 if (!r.check_gp_argument (2, i, nargs)
704 || !r.require_derived_scalar_type (0, r.SAME_TYPE_CLASS)
705 || (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES)
706 return error_mark_node;
707
708 return r.resolve_to (r.mode_suffix_id, type);
709 }
710 };
711 SHAPE (binary_maxvminv)
712
713 /* <T0:half>_t vfoo[_t0](<T0:half>_t, <T0>_t)
714
715 Example: vmovnbq.
716 int8x16_t [__arm_]vmovnbq[_s16](int8x16_t a, int16x8_t b)
717 int8x16_t [__arm_]vmovnbq_m[_s16](int8x16_t a, int16x8_t b, mve_pred16_t p) */
718 struct binary_move_narrow_def : public overloaded_base<0>
719 {
720 void
721 build (function_builder &b, const function_group_info &group,
722 bool preserve_user_namespace) const override
723 {
724 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
725 build_all (b, "vh0,vh0,v0", group, MODE_none, preserve_user_namespace);
726 }
727
728 tree
729 resolve (function_resolver &r) const override
730 {
731 unsigned int i, nargs;
732 type_suffix_index type;
733 if (!r.check_gp_argument (2, i, nargs)
734 || (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES)
735 return error_mark_node;
736
737 type_suffix_index narrow_suffix
738 = find_type_suffix (type_suffixes[type].tclass,
739 type_suffixes[type].element_bits / 2);
740
741
742 if (!r.require_matching_vector_type (0, narrow_suffix))
743 return error_mark_node;
744
745 return r.resolve_to (r.mode_suffix_id, type);
746 }
747 };
748 SHAPE (binary_move_narrow)
749
750 /* <uT0:half>_t vfoo[_t0](<uT0:half>_t, <T0>_t)
751
752 Example: vqmovunbq.
753 uint8x16_t [__arm_]vqmovunbq[_s16](uint8x16_t a, int16x8_t b)
754 uint8x16_t [__arm_]vqmovunbq_m[_s16](uint8x16_t a, int16x8_t b, mve_pred16_t p) */
755 struct binary_move_narrow_unsigned_def : public overloaded_base<0>
756 {
757 void
758 build (function_builder &b, const function_group_info &group,
759 bool preserve_user_namespace) const override
760 {
761 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
762 build_all (b, "vhu0,vhu0,v0", group, MODE_none, preserve_user_namespace);
763 }
764
765 tree
766 resolve (function_resolver &r) const override
767 {
768 unsigned int i, nargs;
769 type_suffix_index type;
770 if (!r.check_gp_argument (2, i, nargs)
771 || (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES)
772 return error_mark_node;
773
774 type_suffix_index narrow_suffix
775 = find_type_suffix (TYPE_unsigned,
776 type_suffixes[type].element_bits / 2);
777
778 if (!r.require_matching_vector_type (0, narrow_suffix))
779 return error_mark_node;
780
781 return r.resolve_to (r.mode_suffix_id, type);
782 }
783 };
784 SHAPE (binary_move_narrow_unsigned)
785
786 /* <T0>_t vfoo[_t0](<T0>_t, <T0>_t)
787 <T0>_t vfoo[_n_t0](<T0>_t, <S0>_t)
788
789 i.e. the standard shape for binary operations that operate on
790 uniform types.
791
792 Example: vaddq.
793 int8x16_t [__arm_]vaddq[_s8](int8x16_t a, int8x16_t b)
794 int8x16_t [__arm_]vaddq[_n_s8](int8x16_t a, int8_t b)
795 int8x16_t [__arm_]vaddq_m[_s8](int8x16_t inactive, int8x16_t a, int8x16_t b, mve_pred16_t p)
796 int8x16_t [__arm_]vaddq_m[_n_s8](int8x16_t inactive, int8x16_t a, int8_t b, mve_pred16_t p)
797 int8x16_t [__arm_]vaddq_x[_s8](int8x16_t a, int8x16_t b, mve_pred16_t p)
798 int8x16_t [__arm_]vaddq_x[_n_s8](int8x16_t a, int8_t b, mve_pred16_t p) */
799 struct binary_opt_n_def : public overloaded_base<0>
800 {
801 void
802 build (function_builder &b, const function_group_info &group,
803 bool preserve_user_namespace) const override
804 {
805 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
806 build_all (b, "v0,v0,v0", group, MODE_none, preserve_user_namespace);
807 build_all (b, "v0,v0,s0", group, MODE_n, preserve_user_namespace);
808 }
809
810 tree
811 resolve (function_resolver &r) const override
812 {
813 return r.resolve_uniform_opt_n (2);
814 }
815 };
816 SHAPE (binary_opt_n)
817
818 /* <T0>_t vfoo[t0](<T0>_t, <T0>_t)
819 <T0>_t vfoo[_n_t0](<T0>_t, <S0>_t)
820
821 Where the _n form only supports s16/s32/u16/u32 types as for vorrq.
822
823 Example: vorrq.
824 int16x8_t [__arm_]vorrq[_s16](int16x8_t a, int16x8_t b)
825 int16x8_t [__arm_]vorrq_m[_s16](int16x8_t inactive, int16x8_t a, int16x8_t b, mve_pred16_t p)
826 int16x8_t [__arm_]vorrq_x[_s16](int16x8_t a, int16x8_t b, mve_pred16_t p)
827 int16x8_t [__arm_]vorrq[_n_s16](int16x8_t a, const int16_t imm)
828 int16x8_t [__arm_]vorrq_m_n[_s16](int16x8_t a, const int16_t imm, mve_pred16_t p) */
829 struct binary_orrq_def : public overloaded_base<0>
830 {
831 bool
832 explicit_mode_suffix_p (enum predication_index pred, enum mode_suffix_index mode) const override
833 {
834 return (mode == MODE_n
835 && pred == PRED_m);
836 }
837
838 bool
839 skip_overload_p (enum predication_index pred, enum mode_suffix_index mode) const override
840 {
841 switch (mode)
842 {
843 case MODE_none:
844 return false;
845
846 /* For MODE_n, share the overloaded instance with MODE_none, except for PRED_m. */
847 case MODE_n:
848 return pred != PRED_m;
849
850 default:
851 gcc_unreachable ();
852 }
853 }
854
855 void
856 build (function_builder &b, const function_group_info &group,
857 bool preserve_user_namespace) const override
858 {
859 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
860 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
861 build_all (b, "v0,v0,v0", group, MODE_none, preserve_user_namespace);
862 build_16_32 (b, "v0,v0,s0", group, MODE_n, preserve_user_namespace, false, preds_m_or_none);
863 }
864
865 tree
866 resolve (function_resolver &r) const override
867 {
868 unsigned int i, nargs;
869 type_suffix_index type;
870 if (!r.check_gp_argument (2, i, nargs)
871 || (type = r.infer_vector_type (0)) == NUM_TYPE_SUFFIXES)
872 return error_mark_node;
873
874 return r.finish_opt_n_resolution (i, 0, type);
875 }
876 };
877 SHAPE (binary_orrq)
878
879 /* <T0>_t vfoo[t0](<T0>_t, <T0>_t)
880 <T0>_t vfoo[_n_t0](<T0>_t, int32_t)
881
882 Shape for rounding shift left operations.
883
884 Example: vrshlq.
885 int8x16_t [__arm_]vrshlq[_n_s8](int8x16_t a, int32_t b)
886 int8x16_t [__arm_]vrshlq_m_n[_s8](int8x16_t a, int32_t b, mve_pred16_t p)
887 int8x16_t [__arm_]vrshlq[_s8](int8x16_t a, int8x16_t b)
888 int8x16_t [__arm_]vrshlq_m[_s8](int8x16_t inactive, int8x16_t a, int8x16_t b, mve_pred16_t p)
889 int8x16_t [__arm_]vrshlq_x[_s8](int8x16_t a, int8x16_t b, mve_pred16_t p) */
890 struct binary_round_lshift_def : public overloaded_base<0>
891 {
892 bool
893 explicit_mode_suffix_p (enum predication_index pred, enum mode_suffix_index mode) const override
894 {
895 return ((mode == MODE_n)
896 && (pred == PRED_m));
897 }
898
899 bool
900 skip_overload_p (enum predication_index pred, enum mode_suffix_index mode) const override
901 {
902 switch (mode)
903 {
904 case MODE_none:
905 return false;
906
907 /* For MODE_n, share the overloaded instance with MODE_none, except for PRED_m. */
908 case MODE_n:
909 return pred != PRED_m;
910
911 default:
912 gcc_unreachable ();
913 }
914 }
915
916 void
917 build (function_builder &b, const function_group_info &group,
918 bool preserve_user_namespace) const override
919 {
920 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
921 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
922 build_all (b, "v0,v0,vs0", group, MODE_none, preserve_user_namespace);
923 build_all (b, "v0,v0,ss32", group, MODE_n, preserve_user_namespace, false, preds_m_or_none);
924 }
925
926 tree
927 resolve (function_resolver &r) const override
928 {
929 unsigned int i, nargs;
930 type_suffix_index type;
931 if (!r.check_gp_argument (2, i, nargs)
932 || (type = r.infer_vector_type (0)) == NUM_TYPE_SUFFIXES)
933 return error_mark_node;
934
935 return r.finish_opt_n_resolution (i, 0, type, TYPE_signed);
936 }
937 };
938 SHAPE (binary_round_lshift)
939
940 /* <T0>_t vfoo[_t0](<T0>_t, <T0>_t)
941 <T0>_t vfoo_n[_t0](<T0>_t, const int)
942
943 i.e. the standard shape for left shift operations that operate on
944 vector types.
945
946 For the MODE_n versions, check that 'imm' is in the [0..#bits-1] range.
947
948 Example: vshlq.
949 int8x16_t [__arm_]vshlq[_s8](int8x16_t a, int8x16_t b)
950 int8x16_t [__arm_]vshlq_m[_s8](int8x16_t inactive, int8x16_t a, int8x16_t b, mve_pred16_t p)
951 int8x16_t [__arm_]vshlq_x[_s8](int8x16_t a, int8x16_t b, mve_pred16_t p)
952 int8x16_t [__arm_]vshlq_n[_s8](int8x16_t a, const int imm)
953 int8x16_t [__arm_]vshlq_m_n[_s8](int8x16_t inactive, int8x16_t a, const int imm, mve_pred16_t p)
954 int8x16_t [__arm_]vshlq_x_n[_s8](int8x16_t a, const int imm, mve_pred16_t p) */
955 struct binary_lshift_def : public overloaded_base<0>
956 {
957 bool
958 explicit_mode_suffix_p (enum predication_index, enum mode_suffix_index) const override
959 {
960 return true;
961 }
962
963 void
964 build (function_builder &b, const function_group_info &group,
965 bool preserve_user_namespace) const override
966 {
967 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
968 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
969 build_all (b, "v0,v0,vs0", group, MODE_none, preserve_user_namespace);
970 build_all (b, "v0,v0,ss32", group, MODE_n, preserve_user_namespace);
971 }
972
973 tree
974 resolve (function_resolver &r) const override
975 {
976 unsigned int i, nargs;
977 type_suffix_index type;
978 if (!r.check_gp_argument (2, i, nargs)
979 || (type = r.infer_vector_type (0)) == NUM_TYPE_SUFFIXES)
980 return error_mark_node;
981
982 return r.finish_opt_n_resolution (i, 0, type, TYPE_signed);
983 }
984
985 bool
986 check (function_checker &c) const override
987 {
988 if (c.mode_suffix_id != MODE_n)
989 return true;
990
991 unsigned int bits = c.type_suffix (0).element_bits;
992 return c.require_immediate_range (1, 0, bits - 1);
993 }
994 };
995 SHAPE (binary_lshift)
996
997 /* Used with the above form, but only for the MODE_r case which does
998 not always support the same set of predicates as MODE_none and
999 MODE_n. For vqshlq they are the same, but for vshlq they are not.
1000
1001 <T0>_t vfoo_r[_t0](<T0>_t, int32_t)
1002
1003 i.e. the standard shape for shift operations that operate on
1004 vector types.
1005 Example: vshlq.
1006 int8x16_t [__arm_]vshlq_r[_s8](int8x16_t a, int32_t b)
1007 int8x16_t [__arm_]vshlq_m_r[_s8](int8x16_t a, int32_t b, mve_pred16_t p) */
1008 struct binary_lshift_r_def : public overloaded_base<0>
1009 {
1010 bool
1011 explicit_mode_suffix_p (enum predication_index, enum mode_suffix_index) const override
1012 {
1013 return true;
1014 }
1015
1016 void
1017 build (function_builder &b, const function_group_info &group,
1018 bool preserve_user_namespace) const override
1019 {
1020 b.add_overloaded_functions (group, MODE_r, preserve_user_namespace);
1021 build_all (b, "v0,v0,ss32", group, MODE_r, preserve_user_namespace, false, preds_m_or_none);
1022 }
1023
1024 tree
1025 resolve (function_resolver &r) const override
1026 {
1027 unsigned int i, nargs;
1028 type_suffix_index type;
1029 if (!r.check_gp_argument (2, i, nargs)
1030 || (type = r.infer_vector_type (0)) == NUM_TYPE_SUFFIXES)
1031 return error_mark_node;
1032
1033 return r.finish_opt_n_resolution (i, 0, type, TYPE_signed);
1034 }
1035 };
1036 SHAPE (binary_lshift_r)
1037
1038 /* <T0:half>_t vfoo[_n_t0](<T0:half>_t, <T0>_t, const int)
1039
1040 Narrowing right shifts.
1041 Check that 'imm' is in the [1..#bits/2] range.
1042
1043 Example: vqrshrnbq.
1044 int8x16_t [__arm_]vqrshrnbq[_n_s16](int8x16_t a, int16x8_t b, const int imm)
1045 int8x16_t [__arm_]vqrshrnbq_m[_n_s16](int8x16_t a, int16x8_t b, const int imm, mve_pred16_t p) */
1046 struct binary_rshift_narrow_def : public overloaded_base<0>
1047 {
1048 void
1049 build (function_builder &b, const function_group_info &group,
1050 bool preserve_user_namespace) const override
1051 {
1052 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
1053 build_all (b, "vh0,vh0,v0,ss32", group, MODE_n, preserve_user_namespace);
1054 }
1055
1056 tree
1057 resolve (function_resolver &r) const override
1058 {
1059 unsigned int i, nargs;
1060 type_suffix_index type;
1061 if (!r.check_gp_argument (3, i, nargs)
1062 || (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES
1063 || !r.require_integer_immediate (i))
1064 return error_mark_node;
1065
1066 type_suffix_index narrow_suffix
1067 = find_type_suffix (type_suffixes[type].tclass,
1068 type_suffixes[type].element_bits / 2);
1069
1070 if (!r.require_matching_vector_type (0, narrow_suffix))
1071 return error_mark_node;
1072
1073 return r.resolve_to (r.mode_suffix_id, type);
1074 }
1075
1076 bool
1077 check (function_checker &c) const override
1078 {
1079 unsigned int bits = c.type_suffix (0).element_bits;
1080 return c.require_immediate_range (2, 1, bits / 2);
1081 }
1082 };
1083 SHAPE (binary_rshift_narrow)
1084
1085 /* <uT0:half>_t vfoo[_n_t0](<uT0:half>_t, <T0>_t, const int)
1086
1087 Vector saturating rounding shift right and narrow.
1088 Check that 'imm' is in the [1..#bits/2] range.
1089
1090 Example: vqshrunbq.
1091 uint8x16_t [__arm_]vqshrunbq[_n_s16](uint8x16_t a, int16x8_t b, const int imm)
1092 uint8x16_t [__arm_]vqshrunbq_m[_n_s16](uint8x16_t a, int16x8_t b, const int imm, mve_pred16_t p) */
1093 struct binary_rshift_narrow_unsigned_def : public overloaded_base<0>
1094 {
1095 void
1096 build (function_builder &b, const function_group_info &group,
1097 bool preserve_user_namespace) const override
1098 {
1099 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
1100 build_all (b, "vhu0,vhu0,v0,ss32", group, MODE_n, preserve_user_namespace);
1101 }
1102
1103 tree
1104 resolve (function_resolver &r) const override
1105 {
1106 unsigned int i, nargs;
1107 type_suffix_index type;
1108 if (!r.check_gp_argument (3, i, nargs)
1109 || (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES
1110 || !r.require_integer_immediate (i))
1111 return error_mark_node;
1112
1113 type_suffix_index narrow_suffix
1114 = find_type_suffix (TYPE_unsigned,
1115 type_suffixes[type].element_bits / 2);
1116
1117 if (!r.require_matching_vector_type (0, narrow_suffix))
1118 return error_mark_node;
1119
1120 return r.resolve_to (r.mode_suffix_id, type);
1121 }
1122
1123 bool
1124 check (function_checker &c) const override
1125 {
1126 unsigned int bits = c.type_suffix (0).element_bits;
1127 return c.require_immediate_range (2, 1, bits / 2);
1128 }
1129
1130 };
1131 SHAPE (binary_rshift_narrow_unsigned)
1132
1133 /* <T0:twice>_t vfoo[_n_t0](<T0>_t, const int)
1134
1135 Check that 'imm' is in the [1..#bits] range.
1136
1137 Example: vshllbq.
1138 int16x8_t [__arm_]vshllbq[_n_s8](int8x16_t a, const int imm)
1139 int16x8_t [__arm_]vshllbq_m[_n_s8](int16x8_t inactive, int8x16_t a, const int imm, mve_pred16_t p)
1140 int16x8_t [__arm_]vshllbq_x[_n_s8](int8x16_t a, const int imm, mve_pred16_t p) */
1141 struct binary_widen_n_def : public overloaded_base<0>
1142 {
1143 void
1144 build (function_builder &b, const function_group_info &group,
1145 bool preserve_user_namespace) const override
1146 {
1147 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
1148 build_all (b, "vw0,v0,s0", group, MODE_n, preserve_user_namespace);
1149 }
1150
1151 tree
1152 resolve (function_resolver &r) const override
1153 {
1154 unsigned int i, nargs;
1155 type_suffix_index type;
1156 tree res;
1157 if (!r.check_gp_argument (2, i, nargs)
1158 || (type = r.infer_vector_type (i - 1)) == NUM_TYPE_SUFFIXES
1159 || !r.require_integer_immediate (i))
1160 return error_mark_node;
1161
1162 type_suffix_index wide_suffix
1163 = find_type_suffix (type_suffixes[type].tclass,
1164 type_suffixes[type].element_bits * 2);
1165
1166 /* Check the inactive argument has the wide type. */
1167 if (((r.pred == PRED_m) && (r.infer_vector_type (0) == wide_suffix))
1168 || r.pred == PRED_none
1169 || r.pred == PRED_x)
1170 if ((res = r.lookup_form (r.mode_suffix_id, type)))
1171 return res;
1172
1173 return r.report_no_such_form (type);
1174 }
1175
1176 bool
1177 check (function_checker &c) const override
1178 {
1179 unsigned int bits = c.type_suffix (0).element_bits;
1180 return c.require_immediate_range (1, 1, bits);
1181 }
1182
1183 };
1184 SHAPE (binary_widen_n)
1185
1186 /* <T0:twice>_t vfoo[_t0](<T0>_t, <T0>_t)
1187 <T0:twice>_t vfoo[_n_t0](<T0>_t, <S0>_t)
1188
1189 Example: vqdmullbq.
1190 int32x4_t [__arm_]vqdmulltq[_n_s16](int16x8_t a, int16_t b)
1191 int32x4_t [__arm_]vqdmulltq_m[_n_s16](int32x4_t inactive, int16x8_t a, int16_t b, mve_pred16_t p)
1192 int32x4_t [__arm_]vqdmulltq[_s16](int16x8_t a, int16x8_t b)
1193 int32x4_t [__arm_]vqdmulltq_m[_s16](int32x4_t inactive, int16x8_t a, int16x8_t b, mve_pred16_t p) */
1194 struct binary_widen_opt_n_def : public overloaded_base<0>
1195 {
1196 void
1197 build (function_builder &b, const function_group_info &group,
1198 bool preserve_user_namespace) const override
1199 {
1200 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1201 build_all (b, "vw0,v0,v0", group, MODE_none, preserve_user_namespace);
1202 build_all (b, "vw0,v0,s0", group, MODE_n, preserve_user_namespace);
1203 }
1204
1205 tree
1206 resolve (function_resolver &r) const override
1207 {
1208 unsigned int i, nargs;
1209 type_suffix_index type;
1210 if (!r.check_gp_argument (2, i, nargs)
1211 || (type = r.infer_vector_type (i - 1)) == NUM_TYPE_SUFFIXES)
1212 return error_mark_node;
1213
1214 type_suffix_index wide_suffix
1215 = find_type_suffix (type_suffixes[type].tclass,
1216 type_suffixes[type].element_bits * 2);
1217
1218 /* Skip last argument, may be scalar, will be checked below by
1219 finish_opt_n_resolution. */
1220 unsigned int last_arg = i--;
1221 for (; i > 0; i--)
1222 if (!r.require_matching_vector_type (i, type))
1223 return error_mark_node;
1224
1225 /* Check the inactive argument has the wide type. */
1226 if ((r.pred == PRED_m)
1227 && (r.infer_vector_type (0) != wide_suffix))
1228 return r.report_no_such_form (type);
1229
1230 return r.finish_opt_n_resolution (last_arg, 0, type);
1231 }
1232 };
1233 SHAPE (binary_widen_opt_n)
1234
1235 /* Shape for comparison operations that operate on
1236 uniform types.
1237
1238 Examples: vcmpq.
1239 mve_pred16_t [__arm_]vcmpeqq[_s16](int16x8_t a, int16x8_t b)
1240 mve_pred16_t [__arm_]vcmpeqq[_n_s16](int16x8_t a, int16_t b)
1241 mve_pred16_t [__arm_]vcmpeqq_m[_s16](int16x8_t a, int16x8_t b, mve_pred16_t p)
1242 mve_pred16_t [__arm_]vcmpeqq_m[_n_s16](int16x8_t a, int16_t b, mve_pred16_t p) */
1243 struct cmp_def : public overloaded_base<0>
1244 {
1245 void
1246 build (function_builder &b, const function_group_info &group,
1247 bool preserve_user_namespace) const override
1248 {
1249 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1250 build_all (b, "p,v0,v0", group, MODE_none, preserve_user_namespace);
1251 build_all (b, "p,v0,s0", group, MODE_n, preserve_user_namespace);
1252 }
1253
1254 tree
1255 resolve (function_resolver &r) const override
1256 {
1257 return r.resolve_uniform_opt_n (2);
1258 }
1259 };
1260 SHAPE (cmp)
1261
1262 /* <T0>xN_t vfoo[_t0](uint64_t, uint64_t)
1263
1264 where there are N arguments in total.
1265 Example: vcreateq.
1266 int16x8_t [__arm_]vcreateq_s16(uint64_t a, uint64_t b) */
1267 struct create_def : public nonoverloaded_base
1268 {
1269 void
1270 build (function_builder &b, const function_group_info &group,
1271 bool preserve_user_namespace) const override
1272 {
1273 build_all (b, "v0,su64,su64", group, MODE_none, preserve_user_namespace);
1274 }
1275
1276 tree
1277 resolve (function_resolver &r) const override
1278 {
1279 return r.resolve_uniform (0, 2);
1280 }
1281 };
1282 SHAPE (create)
1283
1284 /* <T0>[xN]_t vfoo_t0().
1285
1286 Example: vuninitializedq.
1287 int8x16_t [__arm_]vuninitializedq_s8(void)
1288 int8x16_t [__arm_]vuninitializedq(int8x16_t t) */
1289 struct inherent_def : public nonoverloaded_base
1290 {
1291 void
1292 build (function_builder &b, const function_group_info &group,
1293 bool preserve_user_namespace) const override
1294 {
1295 build_all (b, "t0", group, MODE_none, preserve_user_namespace);
1296 }
1297 };
1298 SHAPE (inherent)
1299
1300 /* <T0>_t vfoo[_t0](<T0>_t)
1301 <T0>_t vfoo_n_t0(<sT0>_t)
1302
1303 For MODE_n, define only the 16 and 32 bits versions.
1304
1305 Example: vmvnq.
1306 int16x8_t [__arm_]vmvnq[_s16](int16x8_t a)
1307 int16x8_t [__arm_]vmvnq_m[_s16](int16x8_t inactive, int16x8_t a, mve_pred16_t p)
1308 int16x8_t [__arm_]vmvnq_x[_s16](int16x8_t a, mve_pred16_t p)
1309 int16x8_t [__arm_]vmvnq_n_s16(const int16_t imm)
1310 int16x8_t [__arm_]vmvnq_m[_n_s16](int16x8_t inactive, const int16_t imm, mve_pred16_t p)
1311 int16x8_t [__arm_]vmvnq_x_n_s16(const int16_t imm, mve_pred16_t p) */
1312 struct mvn_def : public overloaded_base<0>
1313 {
1314 void
1315 build (function_builder &b, const function_group_info &group,
1316 bool preserve_user_namespace) const override
1317 {
1318 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1319 /* Do not build a separate instance for MODE_n, since we want to
1320 share vmvnq_m[_n_s16] with vmvnq_m[_s16]. */
1321 build_all (b, "v0,v0", group, MODE_none, preserve_user_namespace);
1322 build_16_32 (b, "v0,s0", group, MODE_n, preserve_user_namespace);
1323 }
1324
1325 tree
1326 resolve (function_resolver &r) const override
1327 {
1328 unsigned int i, nargs;
1329 type_suffix_index type;
1330 if (!r.check_gp_argument (1, i, nargs)
1331 /* Same type for arg 0 and 1 if _m, so using 0 is OK */
1332 || (type = r.infer_vector_type (0)) == NUM_TYPE_SUFFIXES)
1333 return error_mark_node;
1334
1335 /* Skip last argument, may be scalar. */
1336 unsigned int last_arg = i;
1337 for (i = 0; i < last_arg; i++)
1338 if (!r.require_matching_vector_type (i, type))
1339 return error_mark_node;
1340
1341 if (last_arg == 0)
1342 return r.resolve_to (r.mode_suffix_id, type);
1343
1344 return r.finish_opt_n_resolution (last_arg, 0, type);
1345 }
1346 };
1347 SHAPE (mvn)
1348
1349 /* <T0>_t vfoo[_t0](<T0>_t, <T0>_t, <T0>_t)
1350
1351 i.e. the standard shape for ternary operations that operate on
1352 uniform types.
1353
1354 Example: vqrdmlsdhxq.
1355 int8x16_t [__arm_]vqrdmlsdhxq[_s8](int8x16_t inactive, int8x16_t a, int8x16_t b)
1356 int8x16_t [__arm_]vqrdmlsdhxq_m[_s8](int8x16_t inactive, int8x16_t a, int8x16_t b, mve_pred16_t p) */
1357 struct ternary_def : public overloaded_base<0>
1358 {
1359 void
1360 build (function_builder &b, const function_group_info &group,
1361 bool preserve_user_namespace) const override
1362 {
1363 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1364 build_all (b, "v0,v0,v0,v0", group, MODE_none, preserve_user_namespace);
1365 }
1366
1367 tree
1368 resolve (function_resolver &r) const override
1369 {
1370 return r.resolve_uniform_opt_n (3);
1371 }
1372 };
1373 SHAPE (ternary)
1374
1375 /* <T0>_t vfoo[_t0](<T0>_t, <T0>_t, const int)
1376
1377 i.e. ternary operations that operate on a pair of vectors of the
1378 same type as the destination, and take a third integer argument.
1379
1380 Check that 'imm' is in the [0..#bits-1] range.
1381
1382 Example: vsliq.
1383 int16x8_t [__arm_]vsliq[_n_s16](int16x8_t a, int16x8_t b, const int imm)
1384 int16x8_t [__arm_]vsliq_m[_n_s16](int16x8_t a, int16x8_t b, const int imm, mve_pred16_t p) */
1385 struct ternary_lshift_def : public overloaded_base<0>
1386 {
1387 void
1388 build (function_builder &b, const function_group_info &group,
1389 bool preserve_user_namespace) const override
1390 {
1391 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
1392 build_all (b, "v0,v0,v0,ss32", group, MODE_n, preserve_user_namespace);
1393 }
1394
1395 tree
1396 resolve (function_resolver &r) const override
1397 {
1398 return r.resolve_uniform (2, 1);
1399 }
1400
1401 bool
1402 check (function_checker &c) const override
1403 {
1404 if (c.mode_suffix_id != MODE_n)
1405 return true;
1406
1407 unsigned int bits = c.type_suffix (0).element_bits;
1408 return c.require_immediate_range (2, 0, bits - 1);
1409 }
1410 };
1411 SHAPE (ternary_lshift)
1412
1413 /* <T0>_t vfoo[_n_t0](<T0>_t, <T0>_t, <S0>_t)
1414
1415 i.e. the standard shape for ternary operations that operate on a
1416 pair of vectors of the same type as the destination, and take a
1417 third scalar argument of the same type as the vector elements.
1418
1419 Example: vmlaq.
1420 int8x16_t [__arm_]vmlaq[_n_s8](int8x16_t add, int8x16_t m1, int8_t m2)
1421 int8x16_t [__arm_]vmlaq_m[_n_s8](int8x16_t add, int8x16_t m1, int8_t m2, mve_pred16_t p) */
1422 struct ternary_n_def : public overloaded_base<0>
1423 {
1424 void
1425 build (function_builder &b, const function_group_info &group,
1426 bool preserve_user_namespace) const override
1427 {
1428 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
1429 build_all (b, "v0,v0,v0,s0", group, MODE_n, preserve_user_namespace);
1430 }
1431
1432 tree
1433 resolve (function_resolver &r) const override
1434 {
1435 return r.resolve_uniform (2, 1);
1436 }
1437 };
1438 SHAPE (ternary_n)
1439
1440 /* <T0>_t vfoo[_t0](<T0>_t, <T0>_t, <T0>_t)
1441 <T0>_t vfoo[_n_t0](<T0>_t, <T0>_t, <S0>_t)
1442
1443 i.e. the standard shape for ternary operations that operate on
1444 uniform types.
1445
1446 Example: vfmaq.
1447 float16x8_t [__arm_]vfmaq[_n_f16](float16x8_t add, float16x8_t m1, float16_t m2)
1448 float16x8_t [__arm_]vfmaq_m[_n_f16](float16x8_t add, float16x8_t m1, float16_t m2, mve_pred16_t p)
1449 float16x8_t [__arm_]vfmaq[_f16](float16x8_t add, float16x8_t m1, float16x8_t m2)
1450 float16x8_t [__arm_]vfmaq_m[_f16](float16x8_t add, float16x8_t m1, float16x8_t m2, mve_pred16_t p) */
1451 struct ternary_opt_n_def : public overloaded_base<0>
1452 {
1453 void
1454 build (function_builder &b, const function_group_info &group,
1455 bool preserve_user_namespace) const override
1456 {
1457 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1458 build_all (b, "v0,v0,v0,v0", group, MODE_none, preserve_user_namespace);
1459 build_all (b, "v0,v0,v0,s0", group, MODE_n, preserve_user_namespace);
1460 }
1461
1462 tree
1463 resolve (function_resolver &r) const override
1464 {
1465 return r.resolve_uniform_opt_n (3);
1466 }
1467 };
1468 SHAPE (ternary_opt_n)
1469
1470 /* <T0>_t vfoo[_t0](<T0>_t, <T0>_t, const int)
1471
1472 i.e. ternary operations that operate on a pair of vectors of the
1473 same type as the destination, and take a third integer argument.
1474
1475 Check that 'imm' is in the [1..#bits] range.
1476
1477 Example: vsriq.
1478 int8x16_t [__arm_]vsriq[_n_s8](int8x16_t a, int8x16_t b, const int imm)
1479 int8x16_t [__arm_]vsriq_m[_n_s8](int8x16_t a, int8x16_t b, const int imm, mve_pred16_t p) */
1480 struct ternary_rshift_def : public overloaded_base<0>
1481 {
1482 void
1483 build (function_builder &b, const function_group_info &group,
1484 bool preserve_user_namespace) const override
1485 {
1486 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
1487 build_all (b, "v0,v0,v0,ss32", group, MODE_n, preserve_user_namespace);
1488 }
1489
1490 tree
1491 resolve (function_resolver &r) const override
1492 {
1493 return r.resolve_uniform (2, 1);
1494 }
1495
1496 bool
1497 check (function_checker &c) const override
1498 {
1499 if (c.mode_suffix_id != MODE_n)
1500 return true;
1501
1502 unsigned int bits = c.type_suffix (0).element_bits;
1503 return c.require_immediate_range (2, 1, bits);
1504 }
1505 };
1506 SHAPE (ternary_rshift)
1507
1508 /* <T0>_t vfoo[_t0](<T0>_t)
1509
1510 i.e. the standard shape for unary operations that operate on
1511 uniform types.
1512
1513 Example: vabsq.
1514 int8x16_t [__arm_]vabsq[_s8](int8x16_t a)
1515 int8x16_t [__arm_]vabsq_m[_s8](int8x16_t inactive, int8x16_t a, mve_pred16_t p)
1516 int8x16_t [__arm_]vabsq_x[_s8](int8x16_t a, mve_pred16_t p) */
1517 struct unary_def : public overloaded_base<0>
1518 {
1519 void
1520 build (function_builder &b, const function_group_info &group,
1521 bool preserve_user_namespace) const override
1522 {
1523 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1524 build_all (b, "v0,v0", group, MODE_none, preserve_user_namespace);
1525 }
1526
1527 tree
1528 resolve (function_resolver &r) const override
1529 {
1530 return r.resolve_unary ();
1531 }
1532 };
1533 SHAPE (unary)
1534
1535 /* <S0:twice>_t vfoo[_<t0>](<T0>_t)
1536
1537 i.e. a version of "unary" in which the source elements are half the
1538 size of the destination scalar, but have the same type class.
1539
1540 Example: vaddlvq.
1541 int64_t [__arm_]vaddlvq[_s32](int32x4_t a)
1542 int64_t [__arm_]vaddlvq_p[_s32](int32x4_t a, mve_pred16_t p) */
1543 struct unary_acc_def : public overloaded_base<0>
1544 {
1545 void
1546 build (function_builder &b, const function_group_info &group,
1547 bool preserve_user_namespace) const override
1548 {
1549 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1550 build_all (b, "sw0,v0", group, MODE_none, preserve_user_namespace);
1551 }
1552
1553 tree
1554 resolve (function_resolver &r) const override
1555 {
1556 /* FIXME: check that the return value is actually
1557 twice as wide as arg 0. */
1558 return r.resolve_unary ();
1559 }
1560 };
1561 SHAPE (unary_acc)
1562
1563 /* <T0>_t foo_t0[_t1](<T1>_t)
1564
1565 where the target type <t0> must be specified explicitly but the source
1566 type <t1> can be inferred.
1567
1568 Example: vreinterpretq.
1569 int16x8_t [__arm_]vreinterpretq_s16[_s8](int8x16_t a)
1570 int32x4_t [__arm_]vreinterpretq_s32[_s8](int8x16_t a)
1571 int8x16_t [__arm_]vreinterpretq_s8[_s16](int16x8_t a)
1572 int8x16_t [__arm_]vreinterpretq_s8[_s32](int32x4_t a) */
1573 struct unary_convert_def : public overloaded_base<1>
1574 {
1575 void
1576 build (function_builder &b, const function_group_info &group,
1577 bool preserve_user_namespace) const override
1578 {
1579 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1580 build_all (b, "v0,v1", group, MODE_none, preserve_user_namespace);
1581 }
1582
1583 tree
1584 resolve (function_resolver &r) const override
1585 {
1586 return r.resolve_unary ();
1587 }
1588 };
1589 SHAPE (unary_convert)
1590
1591 /* [u]int32_t vfoo[_<t0>](<T0>_t)
1592
1593 i.e. a version of "unary" which generates a scalar of type int32_t
1594 or uint32_t depending on the signedness of the elements of of input
1595 vector.
1596
1597 Example: vaddvq
1598 int32_t [__arm_]vaddvq[_s16](int16x8_t a)
1599 int32_t [__arm_]vaddvq_p[_s16](int16x8_t a, mve_pred16_t p) */
1600 struct unary_int32_def : public overloaded_base<0>
1601 {
1602 void
1603 build (function_builder &b, const function_group_info &group,
1604 bool preserve_user_namespace) const override
1605 {
1606 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1607 build_all (b, "sx32,v0", group, MODE_none, preserve_user_namespace);
1608 }
1609
1610 tree
1611 resolve (function_resolver &r) const override
1612 {
1613 return r.resolve_uniform (1);
1614 }
1615 };
1616 SHAPE (unary_int32)
1617
1618 /* [u]int32_t vfoo[_<t0>]([u]int32_t, <T0>_t)
1619
1620 i.e. a version of "unary" which accumulates into scalar of type
1621 int32_t or uint32_t depending on the signedness of the elements of
1622 of input vector.
1623
1624 Example: vaddvaq.
1625 int32_t [__arm_]vaddvaq[_s16](int32_t a, int16x8_t b)
1626 int32_t [__arm_]vaddvaq_p[_s16](int32_t a, int16x8_t b, mve_pred16_t p) */
1627 struct unary_int32_acc_def : public overloaded_base<0>
1628 {
1629 void
1630 build (function_builder &b, const function_group_info &group,
1631 bool preserve_user_namespace) const override
1632 {
1633 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1634 build_all (b, "sx32,sx32,v0", group, MODE_none, preserve_user_namespace);
1635 }
1636
1637 tree
1638 resolve (function_resolver &r) const override
1639 {
1640 unsigned int i, nargs;
1641 type_suffix_index type;
1642 if (!r.check_gp_argument (2, i, nargs)
1643 || !r.require_integer_immediate (0)
1644 || (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES)
1645 return error_mark_node;
1646
1647 return r.resolve_to (r.mode_suffix_id, type);
1648 }
1649 };
1650 SHAPE (unary_int32_acc)
1651
1652 /* <T0>_t vfoo[_n]_t0(<S0>_t)
1653
1654 Example: vdupq.
1655 int16x8_t [__arm_]vdupq_n_s16(int16_t a)
1656 int16x8_t [__arm_]vdupq_m[_n_s16](int16x8_t inactive, int16_t a, mve_pred16_t p)
1657 int16x8_t [__arm_]vdupq_x_n_s16(int16_t a, mve_pred16_t p) */
1658 struct unary_n_def : public overloaded_base<0>
1659 {
1660 bool
1661 explicit_type_suffix_p (unsigned int, enum predication_index pred,
1662 enum mode_suffix_index) const override
1663 {
1664 return pred != PRED_m;
1665 }
1666
1667 bool
1668 explicit_mode_suffix_p (enum predication_index pred,
1669 enum mode_suffix_index mode) const override
1670 {
1671 return ((mode == MODE_n)
1672 && (pred != PRED_m));
1673 }
1674
1675 bool
1676 skip_overload_p (enum predication_index pred, enum mode_suffix_index mode)
1677 const override
1678 {
1679 switch (mode)
1680 {
1681 case MODE_n:
1682 return pred != PRED_m;
1683
1684 default:
1685 gcc_unreachable ();
1686 }
1687 }
1688
1689 void
1690 build (function_builder &b, const function_group_info &group,
1691 bool preserve_user_namespace) const override
1692 {
1693 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
1694 build_all (b, "v0,s0", group, MODE_n, preserve_user_namespace);
1695 }
1696
1697 tree
1698 resolve (function_resolver &r) const override
1699 {
1700 return r.resolve_unary_n ();
1701 }
1702 };
1703 SHAPE (unary_n)
1704
1705 /* <T0:twice>_t vfoo[_t0](<T0>_t)
1706
1707 i.e. a version of "unary" in which the source elements are half the
1708 size of the destination, but have the same type class.
1709
1710 Example: vmovlbq.
1711 int32x4_t [__arm_]vmovlbq[_s16](int16x8_t a)
1712 int32x4_t [__arm_]vmovlbq_m[_s16](int32x4_t inactive, int16x8_t a, mve_pred16_t p)
1713 int32x4_t [__arm_]vmovlbq_x[_s16](int16x8_t a, mve_pred16_t p) */
1714 struct unary_widen_def : public overloaded_base<0>
1715 {
1716 void
1717 build (function_builder &b, const function_group_info &group,
1718 bool preserve_user_namespace) const override
1719 {
1720 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1721 build_all (b, "vw0,v0", group, MODE_none, preserve_user_namespace);
1722 }
1723
1724 tree
1725 resolve (function_resolver &r) const override
1726 {
1727 unsigned int i, nargs;
1728 type_suffix_index type;
1729 tree res;
1730 if (!r.check_gp_argument (1, i, nargs)
1731 || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES)
1732 return error_mark_node;
1733
1734 type_suffix_index wide_suffix
1735 = find_type_suffix (type_suffixes[type].tclass,
1736 type_suffixes[type].element_bits * 2);
1737
1738 /* Check the inactive argument has the wide type. */
1739 if ((r.pred == PRED_m)
1740 && (r.infer_vector_type (0) != wide_suffix))
1741 return r.report_no_such_form (type);
1742
1743 if ((res = r.lookup_form (r.mode_suffix_id, type)))
1744 return res;
1745
1746 return r.report_no_such_form (type);
1747 }
1748 };
1749 SHAPE (unary_widen)
1750
1751 /* <S0:twice>_t vfoo[_<t0>](<S0:twice>_t, <T0>_t)
1752
1753 i.e. a version of "unary" in which the source elements are half the
1754 size of the destination scalar and accumulator, but have the same
1755 type class.
1756
1757 Example: vaddlvaq.
1758 int64_t [__arm_]vaddlvaq[_s32](int64_t a, int32x4_t b)
1759 int64_t [__arm_]vaddlvaq_p[_s32](int64_t a, int32x4_t b, mve_pred16_t p) */
1760 struct unary_widen_acc_def : public overloaded_base<0>
1761 {
1762 void
1763 build (function_builder &b, const function_group_info &group,
1764 bool preserve_user_namespace) const override
1765 {
1766 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1767 build_all (b, "sw0,sw0,v0", group, MODE_none, preserve_user_namespace);
1768 }
1769
1770 tree
1771 resolve (function_resolver &r) const override
1772 {
1773 unsigned int i, nargs;
1774 type_suffix_index type;
1775 if (!r.check_gp_argument (2, i, nargs)
1776 || !r.require_derived_scalar_type (0, r.SAME_TYPE_CLASS)
1777 || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES)
1778 return error_mark_node;
1779
1780 return r.resolve_to (r.mode_suffix_id, type);
1781 }
1782 };
1783 SHAPE (unary_widen_acc)
1784
1785 /* <T0>_t vfoo[_t0](<T0>_t, <T0>_t, mve_pred16_t)
1786
1787 i.e. a version of the standard ternary shape in which
1788 the final argument is always a set of predicates.
1789
1790 Example: vpselq.
1791 int16x8_t [__arm_]vpselq[_s16](int16x8_t a, int16x8_t b, mve_pred16_t p) */
1792 struct vpsel_def : public overloaded_base<0>
1793 {
1794 void
1795 build (function_builder &b, const function_group_info &group,
1796 bool preserve_user_namespace) const override
1797 {
1798 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1799 build_all (b, "v0,v0,v0,p", group, MODE_none, preserve_user_namespace);
1800 }
1801
1802 tree
1803 resolve (function_resolver &r) const override
1804 {
1805 unsigned int i, nargs;
1806 type_suffix_index type;
1807 if (!r.check_gp_argument (3, i, nargs)
1808 || (type = r.infer_vector_type (0)) == NUM_TYPE_SUFFIXES)
1809 return error_mark_node;
1810
1811 unsigned int last_arg = i;
1812 for (i = 0; i < last_arg; i++)
1813 if (!r.require_matching_vector_type (i, type))
1814 return error_mark_node;
1815
1816 if (!r.require_vector_type (2 , VECTOR_TYPE_mve_pred16_t))
1817 return error_mark_node;
1818
1819 return r.resolve_to (r.mode_suffix_id, type);
1820 }
1821 };
1822 SHAPE (vpsel)
1823
1824 } /* end namespace arm_mve */
1825
1826 #undef SHAPE