]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/arm/arm-mve-builtins-shapes.cc
arm: [MVE intrinsics] add vpsel shape
[thirdparty/gcc.git] / gcc / config / arm / arm-mve-builtins-shapes.cc
CommitLineData
6f59caf1
CL
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
40namespace 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. */
45static void
46apply_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. */
73static type_suffix_index
74parse_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. */
139static tree
140parse_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. */
177static tree
178parse_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. */
198static void
199build_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. */
223static void
224build_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. */
253static void
254build_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. */
290struct 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. */
319template<unsigned int EXPLICIT_MASK>
320struct 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
45dbb66f
CL
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) */
350struct 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};
366SHAPE (binary)
367
93597d92
CL
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) */
377struct 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};
393SHAPE (binary_acc_int32)
394
80b97e0b
CL
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) */
400struct 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};
416SHAPE (binary_acc_int64)
417
018aa0db
CL
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) */
423struct 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};
453SHAPE (binary_acca_int32)
454
4d97b9ca
CL
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) */
460struct 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};
490SHAPE (binary_acca_int64)
491
2d262f5f
CL
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) */
501struct 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};
517SHAPE (binary_imm32)
518
66330ec9
CL
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) */
530struct 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};
553SHAPE (binary_rshift)
554
f7590912 555
992b3be2
CL
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) */
567struct 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};
612SHAPE (binary_lshift_unsigned)
613
f7590912
CL
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) */
622struct 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};
651SHAPE (binary_maxamina)
652
2bf22a1e
CL
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) */
658struct 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};
681SHAPE (binary_maxavminav)
682
c66ed9e7
CL
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) */
688struct 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};
711SHAPE (binary_maxvminv)
712
75e9f264
CL
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) */
718struct 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};
748SHAPE (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) */
755struct 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};
784SHAPE (binary_move_narrow_unsigned)
785
fc4cbe8f
CL
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) */
799struct 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};
816SHAPE (binary_opt_n)
817
56609474
CL
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) */
829struct 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};
877SHAPE (binary_orrq)
878
00c76a62
CL
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) */
890struct 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};
938SHAPE (binary_round_lshift)
939
02888679
CL
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) */
955struct 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};
995SHAPE (binary_lshift)
996
55b0c42e
CL
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) */
1008struct 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};
1036SHAPE (binary_lshift_r)
1037
b0915fca
CL
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) */
1046struct 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};
1083SHAPE (binary_rshift_narrow)
1084
27b1bf82
CL
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) */
1093struct 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};
1131SHAPE (binary_rshift_narrow_unsigned)
1132
828e91cf
CL
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) */
1141struct 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};
1184SHAPE (binary_widen_n)
1185
9b926766
CL
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) */
1194struct 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};
1233SHAPE (binary_widen_opt_n)
1234
8e217600
CL
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) */
1243struct 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};
1260SHAPE (cmp)
1261
4545ca8b
CL
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) */
1267struct 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};
1282SHAPE (create)
1283
937ac2cd
CL
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) */
1289struct 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};
1298SHAPE (inherent)
1299
aae9dfd3
CL
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) */
1312struct 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};
1347SHAPE (mvn)
1348
17c4f632
CL
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) */
1357struct 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};
1373SHAPE (ternary)
1374
129a59c6
CL
1375/* <T0>_t vfoo[_n_t0](<T0>_t, <T0>_t, <S0>_t)
1376
1377 i.e. the standard shape for ternary operations that operate on a
1378 pair of vectors of the same type as the destination, and take a
1379 third scalar argument of the same type as the vector elements.
1380
1381 Example: vmlaq.
1382 int8x16_t [__arm_]vmlaq[_n_s8](int8x16_t add, int8x16_t m1, int8_t m2)
1383 int8x16_t [__arm_]vmlaq_m[_n_s8](int8x16_t add, int8x16_t m1, int8_t m2, mve_pred16_t p) */
1384struct ternary_n_def : public overloaded_base<0>
1385{
1386 void
1387 build (function_builder &b, const function_group_info &group,
1388 bool preserve_user_namespace) const override
1389 {
1390 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
1391 build_all (b, "v0,v0,v0,s0", group, MODE_n, preserve_user_namespace);
1392 }
1393
1394 tree
1395 resolve (function_resolver &r) const override
1396 {
1397 return r.resolve_uniform (2, 1);
1398 }
1399};
1400SHAPE (ternary_n)
1401
b62c9c77
CL
1402/* <T0>_t vfoo[_t0](<T0>_t, <T0>_t, <T0>_t)
1403 <T0>_t vfoo[_n_t0](<T0>_t, <T0>_t, <S0>_t)
1404
1405 i.e. the standard shape for ternary operations that operate on
1406 uniform types.
1407
1408 Example: vfmaq.
1409 float16x8_t [__arm_]vfmaq[_n_f16](float16x8_t add, float16x8_t m1, float16_t m2)
1410 float16x8_t [__arm_]vfmaq_m[_n_f16](float16x8_t add, float16x8_t m1, float16_t m2, mve_pred16_t p)
1411 float16x8_t [__arm_]vfmaq[_f16](float16x8_t add, float16x8_t m1, float16x8_t m2)
1412 float16x8_t [__arm_]vfmaq_m[_f16](float16x8_t add, float16x8_t m1, float16x8_t m2, mve_pred16_t p) */
1413struct ternary_opt_n_def : public overloaded_base<0>
1414{
1415 void
1416 build (function_builder &b, const function_group_info &group,
1417 bool preserve_user_namespace) const override
1418 {
1419 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1420 build_all (b, "v0,v0,v0,v0", group, MODE_none, preserve_user_namespace);
1421 build_all (b, "v0,v0,v0,s0", group, MODE_n, preserve_user_namespace);
1422 }
1423
1424 tree
1425 resolve (function_resolver &r) const override
1426 {
1427 return r.resolve_uniform_opt_n (3);
1428 }
1429};
1430SHAPE (ternary_opt_n)
1431
89567b1f
CL
1432/* <T0>_t vfoo[_t0](<T0>_t)
1433
1434 i.e. the standard shape for unary operations that operate on
1435 uniform types.
1436
1437 Example: vabsq.
1438 int8x16_t [__arm_]vabsq[_s8](int8x16_t a)
1439 int8x16_t [__arm_]vabsq_m[_s8](int8x16_t inactive, int8x16_t a, mve_pred16_t p)
1440 int8x16_t [__arm_]vabsq_x[_s8](int8x16_t a, mve_pred16_t p) */
1441struct unary_def : public overloaded_base<0>
1442{
1443 void
1444 build (function_builder &b, const function_group_info &group,
1445 bool preserve_user_namespace) const override
1446 {
1447 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1448 build_all (b, "v0,v0", group, MODE_none, preserve_user_namespace);
1449 }
1450
1451 tree
1452 resolve (function_resolver &r) const override
1453 {
1454 return r.resolve_unary ();
1455 }
1456};
1457SHAPE (unary)
1458
7e3c2d23
CL
1459/* <S0:twice>_t vfoo[_<t0>](<T0>_t)
1460
1461 i.e. a version of "unary" in which the source elements are half the
1462 size of the destination scalar, but have the same type class.
1463
1464 Example: vaddlvq.
1465 int64_t [__arm_]vaddlvq[_s32](int32x4_t a)
1466 int64_t [__arm_]vaddlvq_p[_s32](int32x4_t a, mve_pred16_t p) */
1467struct unary_acc_def : public overloaded_base<0>
1468{
1469 void
1470 build (function_builder &b, const function_group_info &group,
1471 bool preserve_user_namespace) const override
1472 {
1473 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1474 build_all (b, "sw0,v0", group, MODE_none, preserve_user_namespace);
1475 }
1476
1477 tree
1478 resolve (function_resolver &r) const override
1479 {
1480 /* FIXME: check that the return value is actually
1481 twice as wide as arg 0. */
1482 return r.resolve_unary ();
1483 }
1484};
1485SHAPE (unary_acc)
1486
00d97bf3
CL
1487/* <T0>_t foo_t0[_t1](<T1>_t)
1488
1489 where the target type <t0> must be specified explicitly but the source
1490 type <t1> can be inferred.
1491
1492 Example: vreinterpretq.
1493 int16x8_t [__arm_]vreinterpretq_s16[_s8](int8x16_t a)
1494 int32x4_t [__arm_]vreinterpretq_s32[_s8](int8x16_t a)
1495 int8x16_t [__arm_]vreinterpretq_s8[_s16](int16x8_t a)
1496 int8x16_t [__arm_]vreinterpretq_s8[_s32](int32x4_t a) */
1497struct unary_convert_def : public overloaded_base<1>
1498{
1499 void
1500 build (function_builder &b, const function_group_info &group,
1501 bool preserve_user_namespace) const override
1502 {
1503 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1504 build_all (b, "v0,v1", group, MODE_none, preserve_user_namespace);
1505 }
1506
1507 tree
1508 resolve (function_resolver &r) const override
1509 {
1510 return r.resolve_unary ();
1511 }
1512};
1513SHAPE (unary_convert)
1514
8cb62ff9
CL
1515/* [u]int32_t vfoo[_<t0>](<T0>_t)
1516
1517 i.e. a version of "unary" which generates a scalar of type int32_t
1518 or uint32_t depending on the signedness of the elements of of input
1519 vector.
1520
1521 Example: vaddvq
1522 int32_t [__arm_]vaddvq[_s16](int16x8_t a)
1523 int32_t [__arm_]vaddvq_p[_s16](int16x8_t a, mve_pred16_t p) */
1524struct unary_int32_def : public overloaded_base<0>
1525{
1526 void
1527 build (function_builder &b, const function_group_info &group,
1528 bool preserve_user_namespace) const override
1529 {
1530 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1531 build_all (b, "sx32,v0", group, MODE_none, preserve_user_namespace);
1532 }
1533
1534 tree
1535 resolve (function_resolver &r) const override
1536 {
1537 return r.resolve_uniform (1);
1538 }
1539};
1540SHAPE (unary_int32)
1541
0b81d400
CL
1542/* [u]int32_t vfoo[_<t0>]([u]int32_t, <T0>_t)
1543
1544 i.e. a version of "unary" which accumulates into scalar of type
1545 int32_t or uint32_t depending on the signedness of the elements of
1546 of input vector.
1547
1548 Example: vaddvaq.
1549 int32_t [__arm_]vaddvaq[_s16](int32_t a, int16x8_t b)
1550 int32_t [__arm_]vaddvaq_p[_s16](int32_t a, int16x8_t b, mve_pred16_t p) */
1551struct unary_int32_acc_def : public overloaded_base<0>
1552{
1553 void
1554 build (function_builder &b, const function_group_info &group,
1555 bool preserve_user_namespace) const override
1556 {
1557 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1558 build_all (b, "sx32,sx32,v0", group, MODE_none, preserve_user_namespace);
1559 }
1560
1561 tree
1562 resolve (function_resolver &r) const override
1563 {
1564 unsigned int i, nargs;
1565 type_suffix_index type;
1566 if (!r.check_gp_argument (2, i, nargs)
1567 || !r.require_integer_immediate (0)
1568 || (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES)
1569 return error_mark_node;
1570
1571 return r.resolve_to (r.mode_suffix_id, type);
1572 }
1573};
1574SHAPE (unary_int32_acc)
1575
acf9741c
CL
1576/* <T0>_t vfoo[_n]_t0(<S0>_t)
1577
1578 Example: vdupq.
1579 int16x8_t [__arm_]vdupq_n_s16(int16_t a)
1580 int16x8_t [__arm_]vdupq_m[_n_s16](int16x8_t inactive, int16_t a, mve_pred16_t p)
1581 int16x8_t [__arm_]vdupq_x_n_s16(int16_t a, mve_pred16_t p) */
1582struct unary_n_def : public overloaded_base<0>
1583{
1584 bool
1585 explicit_type_suffix_p (unsigned int, enum predication_index pred,
1586 enum mode_suffix_index) const override
1587 {
1588 return pred != PRED_m;
1589 }
1590
1591 bool
1592 explicit_mode_suffix_p (enum predication_index pred,
1593 enum mode_suffix_index mode) const override
1594 {
1595 return ((mode == MODE_n)
1596 && (pred != PRED_m));
1597 }
1598
1599 bool
1600 skip_overload_p (enum predication_index pred, enum mode_suffix_index mode)
1601 const override
1602 {
1603 switch (mode)
1604 {
1605 case MODE_n:
1606 return pred != PRED_m;
1607
1608 default:
1609 gcc_unreachable ();
1610 }
1611 }
1612
1613 void
1614 build (function_builder &b, const function_group_info &group,
1615 bool preserve_user_namespace) const override
1616 {
1617 b.add_overloaded_functions (group, MODE_n, preserve_user_namespace);
1618 build_all (b, "v0,s0", group, MODE_n, preserve_user_namespace);
1619 }
1620
1621 tree
1622 resolve (function_resolver &r) const override
1623 {
1624 return r.resolve_unary_n ();
1625 }
1626};
1627SHAPE (unary_n)
1628
9d7f7762
CL
1629/* <T0:twice>_t vfoo[_t0](<T0>_t)
1630
1631 i.e. a version of "unary" in which the source elements are half the
1632 size of the destination, but have the same type class.
1633
1634 Example: vmovlbq.
1635 int32x4_t [__arm_]vmovlbq[_s16](int16x8_t a)
1636 int32x4_t [__arm_]vmovlbq_m[_s16](int32x4_t inactive, int16x8_t a, mve_pred16_t p)
1637 int32x4_t [__arm_]vmovlbq_x[_s16](int16x8_t a, mve_pred16_t p) */
1638struct unary_widen_def : public overloaded_base<0>
1639{
1640 void
1641 build (function_builder &b, const function_group_info &group,
1642 bool preserve_user_namespace) const override
1643 {
1644 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1645 build_all (b, "vw0,v0", group, MODE_none, preserve_user_namespace);
1646 }
1647
1648 tree
1649 resolve (function_resolver &r) const override
1650 {
1651 unsigned int i, nargs;
1652 type_suffix_index type;
1653 tree res;
1654 if (!r.check_gp_argument (1, i, nargs)
1655 || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES)
1656 return error_mark_node;
1657
1658 type_suffix_index wide_suffix
1659 = find_type_suffix (type_suffixes[type].tclass,
1660 type_suffixes[type].element_bits * 2);
1661
1662 /* Check the inactive argument has the wide type. */
1663 if ((r.pred == PRED_m)
1664 && (r.infer_vector_type (0) != wide_suffix))
1665 return r.report_no_such_form (type);
1666
1667 if ((res = r.lookup_form (r.mode_suffix_id, type)))
1668 return res;
1669
1670 return r.report_no_such_form (type);
1671 }
1672};
1673SHAPE (unary_widen)
1674
2b46dbc0
CL
1675/* <S0:twice>_t vfoo[_<t0>](<S0:twice>_t, <T0>_t)
1676
1677 i.e. a version of "unary" in which the source elements are half the
1678 size of the destination scalar and accumulator, but have the same
1679 type class.
1680
1681 Example: vaddlvaq.
1682 int64_t [__arm_]vaddlvaq[_s32](int64_t a, int32x4_t b)
1683 int64_t [__arm_]vaddlvaq_p[_s32](int64_t a, int32x4_t b, mve_pred16_t p) */
1684struct unary_widen_acc_def : public overloaded_base<0>
1685{
1686 void
1687 build (function_builder &b, const function_group_info &group,
1688 bool preserve_user_namespace) const override
1689 {
1690 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1691 build_all (b, "sw0,sw0,v0", group, MODE_none, preserve_user_namespace);
1692 }
1693
1694 tree
1695 resolve (function_resolver &r) const override
1696 {
1697 unsigned int i, nargs;
1698 type_suffix_index type;
1699 if (!r.check_gp_argument (2, i, nargs)
1700 || !r.require_derived_scalar_type (0, r.SAME_TYPE_CLASS)
1701 || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES)
1702 return error_mark_node;
1703
1704 return r.resolve_to (r.mode_suffix_id, type);
1705 }
1706};
1707SHAPE (unary_widen_acc)
1708
4be4771b
CL
1709/* <T0>_t vfoo[_t0](<T0>_t, <T0>_t, mve_pred16_t)
1710
1711 i.e. a version of the standard ternary shape in which
1712 the final argument is always a set of predicates.
1713
1714 Example: vpselq.
1715 int16x8_t [__arm_]vpselq[_s16](int16x8_t a, int16x8_t b, mve_pred16_t p) */
1716struct vpsel_def : public overloaded_base<0>
1717{
1718 void
1719 build (function_builder &b, const function_group_info &group,
1720 bool preserve_user_namespace) const override
1721 {
1722 b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
1723 build_all (b, "v0,v0,v0,p", group, MODE_none, preserve_user_namespace);
1724 }
1725
1726 tree
1727 resolve (function_resolver &r) const override
1728 {
1729 unsigned int i, nargs;
1730 type_suffix_index type;
1731 if (!r.check_gp_argument (3, i, nargs)
1732 || (type = r.infer_vector_type (0)) == NUM_TYPE_SUFFIXES)
1733 return error_mark_node;
1734
1735 unsigned int last_arg = i;
1736 for (i = 0; i < last_arg; i++)
1737 if (!r.require_matching_vector_type (i, type))
1738 return error_mark_node;
1739
1740 if (!r.require_vector_type (2 , VECTOR_TYPE_mve_pred16_t))
1741 return error_mark_node;
1742
1743 return r.resolve_to (r.mode_suffix_id, type);
1744 }
1745};
1746SHAPE (vpsel)
1747
6f59caf1
CL
1748} /* end namespace arm_mve */
1749
1750#undef SHAPE