xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/aarch64/aarch64-sve-builtins-functions.h (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1 /* ACLE support for AArch64 SVE (function_base classes)
2    Copyright (C) 2018-2020 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 #ifndef GCC_AARCH64_SVE_BUILTINS_FUNCTIONS_H
21 #define GCC_AARCH64_SVE_BUILTINS_FUNCTIONS_H
22 
23 namespace aarch64_sve {
24 
25 /* Wrap T, which is derived from function_base, and indicate that the
26    function never has side effects.  It is only necessary to use this
27    wrapper on functions that might have floating-point suffixes, since
28    otherwise we assume by default that the function has no side effects.  */
29 template<typename T>
30 class quiet : public T
31 {
32 public:
quiet()33   CONSTEXPR quiet () : T () {}
34 
35   /* Unfortunately we can't use parameter packs yet.  */
36   template<typename T1>
quiet(const T1 & t1)37   CONSTEXPR quiet (const T1 &t1) : T (t1) {}
38 
39   template<typename T1, typename T2>
quiet(const T1 & t1,const T2 & t2)40   CONSTEXPR quiet (const T1 &t1, const T2 &t2) : T (t1, t2) {}
41 
42   template<typename T1, typename T2, typename T3>
quiet(const T1 & t1,const T2 & t2,const T3 & t3)43   CONSTEXPR quiet (const T1 &t1, const T2 &t2, const T3 &t3)
44     : T (t1, t2, t3) {}
45 
46   unsigned int
call_properties(const function_instance &)47   call_properties (const function_instance &) const OVERRIDE
48   {
49     return 0;
50   }
51 };
52 
53 /* A function_base that sometimes or always operates on tuples of
54    vectors.  */
55 class multi_vector_function : public function_base
56 {
57 public:
multi_vector_function(unsigned int vectors_per_tuple)58   CONSTEXPR multi_vector_function (unsigned int vectors_per_tuple)
59     : m_vectors_per_tuple (vectors_per_tuple) {}
60 
61   unsigned int
vectors_per_tuple()62   vectors_per_tuple () const OVERRIDE
63   {
64     return m_vectors_per_tuple;
65   }
66 
67   /* The number of vectors in a tuple, or 1 if the function only operates
68      on single vectors.  */
69   unsigned int m_vectors_per_tuple;
70 };
71 
72 /* A function_base that loads or stores contiguous memory elements
73    without extending or truncating them.  */
74 class full_width_access : public multi_vector_function
75 {
76 public:
77   CONSTEXPR full_width_access (unsigned int vectors_per_tuple = 1)
multi_vector_function(vectors_per_tuple)78     : multi_vector_function (vectors_per_tuple) {}
79 
80   tree
memory_scalar_type(const function_instance & fi)81   memory_scalar_type (const function_instance &fi) const OVERRIDE
82   {
83     return fi.scalar_type (0);
84   }
85 
86   machine_mode
memory_vector_mode(const function_instance & fi)87   memory_vector_mode (const function_instance &fi) const OVERRIDE
88   {
89     machine_mode mode = fi.vector_mode (0);
90     if (m_vectors_per_tuple != 1)
91       mode = targetm.array_mode (mode, m_vectors_per_tuple).require ();
92     return mode;
93   }
94 };
95 
96 /* A function_base that loads elements from memory and extends them
97    to a wider element.  The memory element type is a fixed part of
98    the function base name.  */
99 class extending_load : public function_base
100 {
101 public:
extending_load(type_suffix_index memory_type)102   CONSTEXPR extending_load (type_suffix_index memory_type)
103     : m_memory_type (memory_type) {}
104 
105   unsigned int
call_properties(const function_instance &)106   call_properties (const function_instance &) const OVERRIDE
107   {
108     return CP_READ_MEMORY;
109   }
110 
111   tree
memory_scalar_type(const function_instance &)112   memory_scalar_type (const function_instance &) const OVERRIDE
113   {
114     return scalar_types[type_suffixes[m_memory_type].vector_type];
115   }
116 
117   machine_mode
memory_vector_mode(const function_instance & fi)118   memory_vector_mode (const function_instance &fi) const OVERRIDE
119   {
120     machine_mode mem_mode = type_suffixes[m_memory_type].vector_mode;
121     machine_mode reg_mode = fi.vector_mode (0);
122     return aarch64_sve_data_mode (GET_MODE_INNER (mem_mode),
123 				  GET_MODE_NUNITS (reg_mode)).require ();
124   }
125 
126   /* Return the rtx code associated with the kind of extension that
127      the load performs.  */
128   rtx_code
extend_rtx_code()129   extend_rtx_code () const
130   {
131     return (type_suffixes[m_memory_type].unsigned_p
132 	    ? ZERO_EXTEND : SIGN_EXTEND);
133   }
134 
135   /* The type of the memory elements.  This is part of the function base
136      name rather than a true type suffix.  */
137   type_suffix_index m_memory_type;
138 };
139 
140 /* A function_base that truncates vector elements and stores them to memory.
141    The memory element width is a fixed part of the function base name.  */
142 class truncating_store : public function_base
143 {
144 public:
truncating_store(scalar_int_mode to_mode)145   CONSTEXPR truncating_store (scalar_int_mode to_mode) : m_to_mode (to_mode) {}
146 
147   unsigned int
call_properties(const function_instance &)148   call_properties (const function_instance &) const OVERRIDE
149   {
150     return CP_WRITE_MEMORY;
151   }
152 
153   tree
memory_scalar_type(const function_instance & fi)154   memory_scalar_type (const function_instance &fi) const OVERRIDE
155   {
156     /* In truncating stores, the signedness of the memory element is defined
157        to be the same as the signedness of the vector element.  The signedness
158        doesn't make any difference to the behavior of the function.  */
159     type_class_index tclass = fi.type_suffix (0).tclass;
160     unsigned int element_bits = GET_MODE_BITSIZE (m_to_mode);
161     type_suffix_index suffix = find_type_suffix (tclass, element_bits);
162     return scalar_types[type_suffixes[suffix].vector_type];
163   }
164 
165   machine_mode
memory_vector_mode(const function_instance & fi)166   memory_vector_mode (const function_instance &fi) const OVERRIDE
167   {
168     poly_uint64 nunits = GET_MODE_NUNITS (fi.vector_mode (0));
169     return aarch64_sve_data_mode (m_to_mode, nunits).require ();
170   }
171 
172   /* The mode of a single memory element.  */
173   scalar_int_mode m_to_mode;
174 };
175 
176 /* An incomplete function_base for functions that have an associated rtx code.
177    It simply records information about the mapping for derived classes
178    to use.  */
179 class rtx_code_function_base : public function_base
180 {
181 public:
182   CONSTEXPR rtx_code_function_base (rtx_code code_for_sint,
183 				    rtx_code code_for_uint,
184 				    int unspec_for_fp = -1)
m_code_for_sint(code_for_sint)185     : m_code_for_sint (code_for_sint), m_code_for_uint (code_for_uint),
186       m_unspec_for_fp (unspec_for_fp) {}
187 
188   /* The rtx code to use for signed and unsigned integers respectively.
189      Can be UNKNOWN for functions that don't have integer forms.  */
190   rtx_code m_code_for_sint;
191   rtx_code m_code_for_uint;
192 
193   /* The UNSPEC_COND_* to use for floating-point operations.  Can be -1
194      for functions that only operate on integers.  */
195   int m_unspec_for_fp;
196 };
197 
198 /* A function_base for functions that have an associated rtx code.
199    It supports all forms of predication except PRED_implicit.  */
200 class rtx_code_function : public rtx_code_function_base
201 {
202 public:
203   CONSTEXPR rtx_code_function (rtx_code code_for_sint, rtx_code code_for_uint,
204 			       int unspec_for_fp = -1)
rtx_code_function_base(code_for_sint,code_for_uint,unspec_for_fp)205     : rtx_code_function_base (code_for_sint, code_for_uint, unspec_for_fp) {}
206 
207   rtx
expand(function_expander & e)208   expand (function_expander &e) const OVERRIDE
209   {
210     return e.map_to_rtx_codes (m_code_for_sint, m_code_for_uint,
211 			       m_unspec_for_fp);
212   }
213 };
214 
215 /* Like rtx_code_function, but for functions that take what is normally
216    the final argument first.  One use of this class is to handle binary
217    reversed operations; another is to handle MLA-style operations that
218    are normally expressed in GCC as MAD-style operations.  */
219 class rtx_code_function_rotated : public rtx_code_function_base
220 {
221 public:
222   CONSTEXPR rtx_code_function_rotated (rtx_code code_for_sint,
223 				       rtx_code code_for_uint,
224 				       int unspec_for_fp = -1)
rtx_code_function_base(code_for_sint,code_for_uint,unspec_for_fp)225     : rtx_code_function_base (code_for_sint, code_for_uint, unspec_for_fp) {}
226 
227   rtx
expand(function_expander & e)228   expand (function_expander &e) const OVERRIDE
229   {
230     /* Rotate the inputs into their normal order, but continue to make _m
231        functions merge with what was originally the first vector argument.  */
232     unsigned int nargs = e.args.length ();
233     e.rotate_inputs_left (e.pred != PRED_none ? 1 : 0, nargs);
234     return e.map_to_rtx_codes (m_code_for_sint, m_code_for_uint,
235 			       m_unspec_for_fp, nargs - 1);
236   }
237 };
238 
239 /* An incomplete function_base for functions that have an associated
240    unspec code, with separate codes for signed integers, unsigned
241    integers and floating-point values.  The class simply records
242    information about the mapping for derived classes to use.  */
243 class unspec_based_function_base : public function_base
244 {
245 public:
unspec_based_function_base(int unspec_for_sint,int unspec_for_uint,int unspec_for_fp)246   CONSTEXPR unspec_based_function_base (int unspec_for_sint,
247 					int unspec_for_uint,
248 					int unspec_for_fp)
249     : m_unspec_for_sint (unspec_for_sint),
250       m_unspec_for_uint (unspec_for_uint),
251       m_unspec_for_fp (unspec_for_fp)
252   {}
253 
254   /* Return the unspec code to use for INSTANCE, based on type suffix 0.  */
255   int
unspec_for(const function_instance & instance)256   unspec_for (const function_instance &instance) const
257   {
258     return (!instance.type_suffix (0).integer_p ? m_unspec_for_fp
259 	    : instance.type_suffix (0).unsigned_p ? m_unspec_for_uint
260 	    : m_unspec_for_sint);
261   }
262 
263   /* The unspec code associated with signed-integer, unsigned-integer
264      and floating-point operations respectively.  */
265   int m_unspec_for_sint;
266   int m_unspec_for_uint;
267   int m_unspec_for_fp;
268 };
269 
270 /* A function_base for functions that have an associated unspec code.
271    It supports all forms of predication except PRED_implicit.  */
272 class unspec_based_function : public unspec_based_function_base
273 {
274 public:
unspec_based_function(int unspec_for_sint,int unspec_for_uint,int unspec_for_fp)275   CONSTEXPR unspec_based_function (int unspec_for_sint, int unspec_for_uint,
276 				   int unspec_for_fp)
277     : unspec_based_function_base (unspec_for_sint, unspec_for_uint,
278 				  unspec_for_fp)
279   {}
280 
281   rtx
expand(function_expander & e)282   expand (function_expander &e) const OVERRIDE
283   {
284     return e.map_to_unspecs (m_unspec_for_sint, m_unspec_for_uint,
285 			     m_unspec_for_fp);
286   }
287 };
288 
289 /* Like unspec_based_function, but for functions that take what is normally
290    the final argument first.  One use of this class is to handle binary
291    reversed operations; another is to handle MLA-style operations that
292    are normally expressed in GCC as MAD-style operations.  */
293 class unspec_based_function_rotated : public unspec_based_function_base
294 {
295 public:
unspec_based_function_rotated(int unspec_for_sint,int unspec_for_uint,int unspec_for_fp)296   CONSTEXPR unspec_based_function_rotated (int unspec_for_sint,
297 					   int unspec_for_uint,
298 					   int unspec_for_fp)
299     : unspec_based_function_base (unspec_for_sint, unspec_for_uint,
300 				  unspec_for_fp)
301   {}
302 
303   rtx
expand(function_expander & e)304   expand (function_expander &e) const OVERRIDE
305   {
306     /* Rotate the inputs into their normal order, but continue to make _m
307        functions merge with what was originally the first vector argument.  */
308     unsigned int nargs = e.args.length ();
309     e.rotate_inputs_left (e.pred != PRED_none ? 1 : 0, nargs);
310     return e.map_to_unspecs (m_unspec_for_sint, m_unspec_for_uint,
311 			     m_unspec_for_fp, nargs - 1);
312   }
313 };
314 
315 /* Like unspec_based_function, but map the function directly to
316    CODE (UNSPEC, M) instead of using the generic predication-based
317    expansion. where M is the vector mode associated with type suffix 0.
318    This is useful if the unspec doesn't describe the full operation or
319    if the usual predication rules don't apply for some reason.  */
320 template<insn_code (*CODE) (int, machine_mode)>
321 class unspec_based_function_exact_insn : public unspec_based_function_base
322 {
323 public:
unspec_based_function_exact_insn(int unspec_for_sint,int unspec_for_uint,int unspec_for_fp)324   CONSTEXPR unspec_based_function_exact_insn (int unspec_for_sint,
325 					      int unspec_for_uint,
326 					      int unspec_for_fp)
327     : unspec_based_function_base (unspec_for_sint, unspec_for_uint,
328 				  unspec_for_fp)
329   {}
330 
331   rtx
expand(function_expander & e)332   expand (function_expander &e) const OVERRIDE
333   {
334     return e.use_exact_insn (CODE (unspec_for (e), e.vector_mode (0)));
335   }
336 };
337 
338 /* A function that performs an unspec and then adds it to another value.  */
339 typedef unspec_based_function_exact_insn<code_for_aarch64_sve_add>
340   unspec_based_add_function;
341 typedef unspec_based_function_exact_insn<code_for_aarch64_sve_add_lane>
342   unspec_based_add_lane_function;
343 
344 /* Generic unspec-based _lane function.  */
345 typedef unspec_based_function_exact_insn<code_for_aarch64_sve_lane>
346   unspec_based_lane_function;
347 
348 /* A functon that uses aarch64_pred* patterns regardless of the
349    predication type.  */
350 typedef unspec_based_function_exact_insn<code_for_aarch64_pred>
351   unspec_based_pred_function;
352 
353 /* Like unspec_based_add_function and unspec_based_add_lane_function,
354    but using saturating addition.  */
355 typedef unspec_based_function_exact_insn<code_for_aarch64_sve_qadd>
356   unspec_based_qadd_function;
357 typedef unspec_based_function_exact_insn<code_for_aarch64_sve_qadd_lane>
358   unspec_based_qadd_lane_function;
359 
360 /* Like unspec_based_sub_function and unspec_based_sub_lane_function,
361    but using saturating subtraction.  */
362 typedef unspec_based_function_exact_insn<code_for_aarch64_sve_qsub>
363   unspec_based_qsub_function;
364 typedef unspec_based_function_exact_insn<code_for_aarch64_sve_qsub_lane>
365   unspec_based_qsub_lane_function;
366 
367 /* A function that performs an unspec and then subtracts it from
368    another value.  */
369 typedef unspec_based_function_exact_insn<code_for_aarch64_sve_sub>
370   unspec_based_sub_function;
371 typedef unspec_based_function_exact_insn<code_for_aarch64_sve_sub_lane>
372   unspec_based_sub_lane_function;
373 
374 /* A function that acts like unspec_based_function_exact_insn<INT_CODE>
375    when operating on integers, but that expands to an (fma ...)-style
376    aarch64_sve* operation when applied to floats.  */
377 template<insn_code (*INT_CODE) (int, machine_mode)>
378 class unspec_based_fused_function : public unspec_based_function_base
379 {
380 public:
unspec_based_fused_function(int unspec_for_sint,int unspec_for_uint,int unspec_for_fp)381   CONSTEXPR unspec_based_fused_function (int unspec_for_sint,
382 					 int unspec_for_uint,
383 					 int unspec_for_fp)
384     : unspec_based_function_base (unspec_for_sint, unspec_for_uint,
385 				  unspec_for_fp)
386   {}
387 
388   rtx
expand(function_expander & e)389   expand (function_expander &e) const OVERRIDE
390   {
391     int unspec = unspec_for (e);
392     insn_code icode;
393     if (e.type_suffix (0).float_p)
394       {
395 	/* Put the operands in the normal (fma ...) order, with the accumulator
396 	   last.  This fits naturally since that's also the unprinted operand
397 	   in the asm output.  */
398 	e.rotate_inputs_left (0, e.pred != PRED_none ? 4 : 3);
399 	icode = code_for_aarch64_sve (unspec, e.vector_mode (0));
400       }
401     else
402       icode = INT_CODE (unspec, e.vector_mode (0));
403     return e.use_exact_insn (icode);
404   }
405 };
406 typedef unspec_based_fused_function<code_for_aarch64_sve_add>
407   unspec_based_mla_function;
408 typedef unspec_based_fused_function<code_for_aarch64_sve_sub>
409   unspec_based_mls_function;
410 
411 /* Like unspec_based_fused_function, but for _lane functions.  */
412 template<insn_code (*INT_CODE) (int, machine_mode)>
413 class unspec_based_fused_lane_function : public unspec_based_function_base
414 {
415 public:
unspec_based_fused_lane_function(int unspec_for_sint,int unspec_for_uint,int unspec_for_fp)416   CONSTEXPR unspec_based_fused_lane_function (int unspec_for_sint,
417 					      int unspec_for_uint,
418 					      int unspec_for_fp)
419     : unspec_based_function_base (unspec_for_sint, unspec_for_uint,
420 				  unspec_for_fp)
421   {}
422 
423   rtx
expand(function_expander & e)424   expand (function_expander &e) const OVERRIDE
425   {
426     int unspec = unspec_for (e);
427     insn_code icode;
428     if (e.type_suffix (0).float_p)
429       {
430 	/* Put the operands in the normal (fma ...) order, with the accumulator
431 	   last.  This fits naturally since that's also the unprinted operand
432 	   in the asm output.  */
433 	e.rotate_inputs_left (0, e.pred != PRED_none ? 5 : 4);
434 	icode = code_for_aarch64_lane (unspec, e.vector_mode (0));
435       }
436     else
437       icode = INT_CODE (unspec, e.vector_mode (0));
438     return e.use_exact_insn (icode);
439   }
440 };
441 typedef unspec_based_fused_lane_function<code_for_aarch64_sve_add_lane>
442   unspec_based_mla_lane_function;
443 typedef unspec_based_fused_lane_function<code_for_aarch64_sve_sub_lane>
444   unspec_based_mls_lane_function;
445 
446 /* A function_base that uses CODE_FOR_MODE (M) to get the associated
447    instruction code, where M is the vector mode associated with type
448    suffix N.  */
449 template<insn_code (*CODE_FOR_MODE) (machine_mode), unsigned int N>
450 class code_for_mode_function : public function_base
451 {
452 public:
453   rtx
expand(function_expander & e)454   expand (function_expander &e) const OVERRIDE
455   {
456     return e.use_exact_insn (CODE_FOR_MODE (e.vector_mode (N)));
457   }
458 };
459 
460 /* A function that uses code_for_<PATTERN> (M), where M is the vector
461    mode associated with the first type suffix.  */
462 #define CODE_FOR_MODE0(PATTERN) code_for_mode_function<code_for_##PATTERN, 0>
463 
464 /* Likewise for the second type suffix.  */
465 #define CODE_FOR_MODE1(PATTERN) code_for_mode_function<code_for_##PATTERN, 1>
466 
467 /* Like CODE_FOR_MODE0, but the function doesn't raise exceptions when
468    operating on floating-point data.  */
469 #define QUIET_CODE_FOR_MODE0(PATTERN) \
470   quiet< code_for_mode_function<code_for_##PATTERN, 0> >
471 
472 /* A function_base for functions that always expand to a fixed insn pattern,
473    regardless of what the suffixes are.  */
474 class fixed_insn_function : public function_base
475 {
476 public:
fixed_insn_function(insn_code code)477   CONSTEXPR fixed_insn_function (insn_code code) : m_code (code) {}
478 
479   rtx
expand(function_expander & e)480   expand (function_expander &e) const OVERRIDE
481   {
482     return e.use_exact_insn (m_code);
483   }
484 
485   /* The instruction to use.  */
486   insn_code m_code;
487 };
488 
489 /* A function_base for functions that permute their arguments.  */
490 class permute : public quiet<function_base>
491 {
492 public:
493   /* Fold a unary or binary permute with the permute vector given by
494      BUILDER.  */
495   gimple *
fold_permute(const gimple_folder & f,const vec_perm_builder & builder)496   fold_permute (const gimple_folder &f, const vec_perm_builder &builder) const
497   {
498     /* Punt for now on _b16 and wider; we'd need more complex evpc logic
499        to rerecognize the result.  */
500     if (f.type_suffix (0).bool_p && f.type_suffix (0).element_bits > 8)
501       return NULL;
502 
503     unsigned int nargs = gimple_call_num_args (f.call);
504     poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (f.lhs));
505     vec_perm_indices indices (builder, nargs, nelts);
506     tree perm_type = build_vector_type (ssizetype, nelts);
507     return gimple_build_assign (f.lhs, VEC_PERM_EXPR,
508 				gimple_call_arg (f.call, 0),
509 				gimple_call_arg (f.call, nargs - 1),
510 				vec_perm_indices_to_tree (perm_type, indices));
511   }
512 };
513 
514 /* A function_base for functions that permute two vectors using a fixed
515    choice of indices.  */
516 class binary_permute : public permute
517 {
518 public:
binary_permute(int unspec)519   CONSTEXPR binary_permute (int unspec) : m_unspec (unspec) {}
520 
521   rtx
expand(function_expander & e)522   expand (function_expander &e) const OVERRIDE
523   {
524     insn_code icode = code_for_aarch64_sve (m_unspec, e.vector_mode (0));
525     return e.use_exact_insn (icode);
526   }
527 
528   /* The unspec code associated with the operation.  */
529   int m_unspec;
530 };
531 
532 /* A function_base for functions that reduce a vector to a scalar.  */
533 class reduction : public function_base
534 {
535 public:
reduction(int unspec)536   CONSTEXPR reduction (int unspec)
537     : m_unspec_for_sint (unspec),
538       m_unspec_for_uint (unspec),
539       m_unspec_for_fp (unspec)
540   {}
541 
reduction(int unspec_for_sint,int unspec_for_uint,int unspec_for_fp)542   CONSTEXPR reduction (int unspec_for_sint, int unspec_for_uint,
543 		       int unspec_for_fp)
544     : m_unspec_for_sint (unspec_for_sint),
545       m_unspec_for_uint (unspec_for_uint),
546       m_unspec_for_fp (unspec_for_fp)
547   {}
548 
549   rtx
expand(function_expander & e)550   expand (function_expander &e) const OVERRIDE
551   {
552     machine_mode mode = e.vector_mode (0);
553     int unspec = (!e.type_suffix (0).integer_p ? m_unspec_for_fp
554 		  : e.type_suffix (0).unsigned_p ? m_unspec_for_uint
555 		  : m_unspec_for_sint);
556     /* There's no distinction between SADDV and UADDV for 64-bit elements;
557        the signed versions only exist for narrower elements.  */
558     if (GET_MODE_UNIT_BITSIZE (mode) == 64 && unspec == UNSPEC_SADDV)
559       unspec = UNSPEC_UADDV;
560     return e.use_exact_insn (code_for_aarch64_pred_reduc (unspec, mode));
561   }
562 
563   /* The unspec code associated with signed-integer, unsigned-integer
564      and floating-point operations respectively.  */
565   int m_unspec_for_sint;
566   int m_unspec_for_uint;
567   int m_unspec_for_fp;
568 };
569 
570 /* A function_base for functions that shift narrower-than-64-bit values
571    by 64-bit amounts.  */
572 class shift_wide : public function_base
573 {
574 public:
shift_wide(rtx_code code,int wide_unspec)575   CONSTEXPR shift_wide (rtx_code code, int wide_unspec)
576     : m_code (code), m_wide_unspec (wide_unspec) {}
577 
578   rtx
expand(function_expander & e)579   expand (function_expander &e) const OVERRIDE
580   {
581     machine_mode mode = e.vector_mode (0);
582     machine_mode elem_mode = GET_MODE_INNER (mode);
583 
584     /* If the argument is a constant that the normal shifts can handle
585        directly, use them instead.  */
586     rtx shift = unwrap_const_vec_duplicate (e.args.last ());
587     if (aarch64_simd_shift_imm_p (shift, elem_mode, m_code == ASHIFT))
588       {
589 	e.args.last () = shift;
590 	return e.map_to_rtx_codes (m_code, m_code, -1);
591       }
592 
593     if (e.pred == PRED_x)
594       return e.use_unpred_insn (code_for_aarch64_sve (m_wide_unspec, mode));
595 
596     return e.use_cond_insn (code_for_cond (m_wide_unspec, mode));
597   }
598 
599   /* The rtx code associated with a "normal" shift.  */
600   rtx_code m_code;
601 
602   /* The unspec code associated with the wide shift.  */
603   int m_wide_unspec;
604 };
605 
606 /* A function_base for unary functions that count bits.  */
607 class unary_count : public quiet<function_base>
608 {
609 public:
unary_count(rtx_code code)610   CONSTEXPR unary_count (rtx_code code) : m_code (code) {}
611 
612   rtx
expand(function_expander & e)613   expand (function_expander &e) const OVERRIDE
614   {
615     /* The md patterns treat the operand as an integer.  */
616     machine_mode mode = aarch64_sve_int_mode (e.vector_mode (0));
617     e.args.last () = gen_lowpart (mode, e.args.last ());
618 
619     if (e.pred == PRED_x)
620       return e.use_pred_x_insn (code_for_aarch64_pred (m_code, mode));
621 
622     return e.use_cond_insn (code_for_cond (m_code, mode));
623   }
624 
625   /* The rtx code associated with the operation.  */
626   rtx_code m_code;
627 };
628 
629 /* A function_base for svwhile* functions.  */
630 class while_comparison : public function_base
631 {
632 public:
while_comparison(int unspec_for_sint,int unspec_for_uint)633   CONSTEXPR while_comparison (int unspec_for_sint, int unspec_for_uint)
634     : m_unspec_for_sint (unspec_for_sint),
635       m_unspec_for_uint (unspec_for_uint)
636   {}
637 
638   rtx
expand(function_expander & e)639   expand (function_expander &e) const OVERRIDE
640   {
641     /* Suffix 0 determines the predicate mode, suffix 1 determines the
642        scalar mode and signedness.  */
643     int unspec = (e.type_suffix (1).unsigned_p
644 		  ? m_unspec_for_uint
645 		  : m_unspec_for_sint);
646     machine_mode pred_mode = e.vector_mode (0);
647     scalar_mode reg_mode = GET_MODE_INNER (e.vector_mode (1));
648     return e.use_exact_insn (code_for_while (unspec, reg_mode, pred_mode));
649   }
650 
651   /* The unspec codes associated with signed and unsigned operations
652      respectively.  */
653   int m_unspec_for_sint;
654   int m_unspec_for_uint;
655 };
656 
657 }
658 
659 /* Declare the global function base NAME, creating it from an instance
660    of class CLASS with constructor arguments ARGS.  */
661 #define FUNCTION(NAME, CLASS, ARGS) \
662   namespace { static CONSTEXPR const CLASS NAME##_obj ARGS; } \
663   namespace functions { const function_base *const NAME = &NAME##_obj; }
664 
665 #endif
666