1 /* Builtins' description for AArch64 SIMD architecture.
2    Copyright (C) 2011-2014 Free Software Foundation, Inc.
3    Contributed by ARM Ltd.
4 
5    This file is part of GCC.
6 
7    GCC is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3, or (at your option)
10    any later version.
11 
12    GCC is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with GCC; see the file COPYING3.  If not see
19    <http://www.gnu.org/licenses/>.  */
20 
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "rtl.h"
26 #include "tree.h"
27 #include "stor-layout.h"
28 #include "stringpool.h"
29 #include "calls.h"
30 #include "expr.h"
31 #include "tm_p.h"
32 #include "recog.h"
33 #include "langhooks.h"
34 #include "diagnostic-core.h"
35 #include "optabs.h"
36 #include "pointer-set.h"
37 #include "hash-table.h"
38 #include "vec.h"
39 #include "ggc.h"
40 #include "basic-block.h"
41 #include "tree-ssa-alias.h"
42 #include "internal-fn.h"
43 #include "gimple-fold.h"
44 #include "tree-eh.h"
45 #include "gimple-expr.h"
46 #include "is-a.h"
47 #include "gimple.h"
48 #include "gimple-iterator.h"
49 
50 enum aarch64_simd_builtin_type_mode
51 {
52   T_V8QI,
53   T_V4HI,
54   T_V2SI,
55   T_V2SF,
56   T_DI,
57   T_DF,
58   T_V16QI,
59   T_V8HI,
60   T_V4SI,
61   T_V4SF,
62   T_V2DI,
63   T_V2DF,
64   T_TI,
65   T_EI,
66   T_OI,
67   T_XI,
68   T_SI,
69   T_SF,
70   T_HI,
71   T_QI,
72   T_MAX
73 };
74 
75 #define v8qi_UP  T_V8QI
76 #define v4hi_UP  T_V4HI
77 #define v2si_UP  T_V2SI
78 #define v2sf_UP  T_V2SF
79 #define di_UP    T_DI
80 #define df_UP    T_DF
81 #define v16qi_UP T_V16QI
82 #define v8hi_UP  T_V8HI
83 #define v4si_UP  T_V4SI
84 #define v4sf_UP  T_V4SF
85 #define v2di_UP  T_V2DI
86 #define v2df_UP  T_V2DF
87 #define ti_UP	 T_TI
88 #define ei_UP	 T_EI
89 #define oi_UP	 T_OI
90 #define xi_UP	 T_XI
91 #define si_UP    T_SI
92 #define sf_UP    T_SF
93 #define hi_UP    T_HI
94 #define qi_UP    T_QI
95 
96 #define UP(X) X##_UP
97 
98 #define SIMD_MAX_BUILTIN_ARGS 5
99 
100 enum aarch64_type_qualifiers
101 {
102   /* T foo.  */
103   qualifier_none = 0x0,
104   /* unsigned T foo.  */
105   qualifier_unsigned = 0x1, /* 1 << 0  */
106   /* const T foo.  */
107   qualifier_const = 0x2, /* 1 << 1  */
108   /* T *foo.  */
109   qualifier_pointer = 0x4, /* 1 << 2  */
110   /* const T *foo.  */
111   qualifier_const_pointer = 0x6, /* qualifier_const | qualifier_pointer  */
112   /* Used when expanding arguments if an operand could
113      be an immediate.  */
114   qualifier_immediate = 0x8, /* 1 << 3  */
115   qualifier_maybe_immediate = 0x10, /* 1 << 4  */
116   /* void foo (...).  */
117   qualifier_void = 0x20, /* 1 << 5  */
118   /* Some patterns may have internal operands, this qualifier is an
119      instruction to the initialisation code to skip this operand.  */
120   qualifier_internal = 0x40, /* 1 << 6  */
121   /* Some builtins should use the T_*mode* encoded in a simd_builtin_datum
122      rather than using the type of the operand.  */
123   qualifier_map_mode = 0x80, /* 1 << 7  */
124   /* qualifier_pointer | qualifier_map_mode  */
125   qualifier_pointer_map_mode = 0x84,
126   /* qualifier_const_pointer | qualifier_map_mode  */
127   qualifier_const_pointer_map_mode = 0x86,
128   /* Polynomial types.  */
129   qualifier_poly = 0x100
130 };
131 
132 typedef struct
133 {
134   const char *name;
135   enum aarch64_simd_builtin_type_mode mode;
136   const enum insn_code code;
137   unsigned int fcode;
138   enum aarch64_type_qualifiers *qualifiers;
139 } aarch64_simd_builtin_datum;
140 
141 static enum aarch64_type_qualifiers
142 aarch64_types_unop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
143   = { qualifier_none, qualifier_none };
144 #define TYPES_UNOP (aarch64_types_unop_qualifiers)
145 static enum aarch64_type_qualifiers
146 aarch64_types_unopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
147   = { qualifier_unsigned, qualifier_unsigned };
148 #define TYPES_UNOPU (aarch64_types_unopu_qualifiers)
149 #define TYPES_CREATE (aarch64_types_unop_qualifiers)
150 #define TYPES_REINTERP (aarch64_types_unop_qualifiers)
151 static enum aarch64_type_qualifiers
152 aarch64_types_binop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
153   = { qualifier_none, qualifier_none, qualifier_maybe_immediate };
154 #define TYPES_BINOP (aarch64_types_binop_qualifiers)
155 static enum aarch64_type_qualifiers
156 aarch64_types_binopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
157   = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned };
158 #define TYPES_BINOPU (aarch64_types_binopu_qualifiers)
159 static enum aarch64_type_qualifiers
160 aarch64_types_binopp_qualifiers[SIMD_MAX_BUILTIN_ARGS]
161   = { qualifier_poly, qualifier_poly, qualifier_poly };
162 #define TYPES_BINOPP (aarch64_types_binopp_qualifiers)
163 
164 static enum aarch64_type_qualifiers
165 aarch64_types_ternop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
166   = { qualifier_none, qualifier_none, qualifier_none, qualifier_none };
167 #define TYPES_TERNOP (aarch64_types_ternop_qualifiers)
168 static enum aarch64_type_qualifiers
169 aarch64_types_ternopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
170   = { qualifier_unsigned, qualifier_unsigned,
171       qualifier_unsigned, qualifier_unsigned };
172 #define TYPES_TERNOPU (aarch64_types_ternopu_qualifiers)
173 
174 static enum aarch64_type_qualifiers
175 aarch64_types_quadop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
176   = { qualifier_none, qualifier_none, qualifier_none,
177       qualifier_none, qualifier_none };
178 #define TYPES_QUADOP (aarch64_types_quadop_qualifiers)
179 
180 static enum aarch64_type_qualifiers
181 aarch64_types_getlane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
182   = { qualifier_none, qualifier_none, qualifier_immediate };
183 #define TYPES_GETLANE (aarch64_types_getlane_qualifiers)
184 #define TYPES_SHIFTIMM (aarch64_types_getlane_qualifiers)
185 static enum aarch64_type_qualifiers
186 aarch64_types_unsigned_shift_qualifiers[SIMD_MAX_BUILTIN_ARGS]
187   = { qualifier_unsigned, qualifier_unsigned, qualifier_immediate };
188 #define TYPES_USHIFTIMM (aarch64_types_unsigned_shift_qualifiers)
189 static enum aarch64_type_qualifiers
190 aarch64_types_setlane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
191   = { qualifier_none, qualifier_none, qualifier_none, qualifier_immediate };
192 #define TYPES_SETLANE (aarch64_types_setlane_qualifiers)
193 #define TYPES_SHIFTINSERT (aarch64_types_setlane_qualifiers)
194 #define TYPES_SHIFTACC (aarch64_types_setlane_qualifiers)
195 
196 static enum aarch64_type_qualifiers
197 aarch64_types_combine_qualifiers[SIMD_MAX_BUILTIN_ARGS]
198   = { qualifier_none, qualifier_none, qualifier_none };
199 #define TYPES_COMBINE (aarch64_types_combine_qualifiers)
200 
201 static enum aarch64_type_qualifiers
202 aarch64_types_load1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
203   = { qualifier_none, qualifier_const_pointer_map_mode };
204 #define TYPES_LOAD1 (aarch64_types_load1_qualifiers)
205 #define TYPES_LOADSTRUCT (aarch64_types_load1_qualifiers)
206 
207 static enum aarch64_type_qualifiers
208 aarch64_types_bsl_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
209   = { qualifier_poly, qualifier_unsigned,
210       qualifier_poly, qualifier_poly };
211 #define TYPES_BSL_P (aarch64_types_bsl_p_qualifiers)
212 static enum aarch64_type_qualifiers
213 aarch64_types_bsl_s_qualifiers[SIMD_MAX_BUILTIN_ARGS]
214   = { qualifier_none, qualifier_unsigned,
215       qualifier_none, qualifier_none };
216 #define TYPES_BSL_S (aarch64_types_bsl_s_qualifiers)
217 static enum aarch64_type_qualifiers
218 aarch64_types_bsl_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
219   = { qualifier_unsigned, qualifier_unsigned,
220       qualifier_unsigned, qualifier_unsigned };
221 #define TYPES_BSL_U (aarch64_types_bsl_u_qualifiers)
222 
223 /* The first argument (return type) of a store should be void type,
224    which we represent with qualifier_void.  Their first operand will be
225    a DImode pointer to the location to store to, so we must use
226    qualifier_map_mode | qualifier_pointer to build a pointer to the
227    element type of the vector.  */
228 static enum aarch64_type_qualifiers
229 aarch64_types_store1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
230   = { qualifier_void, qualifier_pointer_map_mode, qualifier_none };
231 #define TYPES_STORE1 (aarch64_types_store1_qualifiers)
232 #define TYPES_STORESTRUCT (aarch64_types_store1_qualifiers)
233 
234 #define CF0(N, X) CODE_FOR_aarch64_##N##X
235 #define CF1(N, X) CODE_FOR_##N##X##1
236 #define CF2(N, X) CODE_FOR_##N##X##2
237 #define CF3(N, X) CODE_FOR_##N##X##3
238 #define CF4(N, X) CODE_FOR_##N##X##4
239 #define CF10(N, X) CODE_FOR_##N##X
240 
241 #define VAR1(T, N, MAP, A) \
242   {#N, UP (A), CF##MAP (N, A), 0, TYPES_##T},
243 #define VAR2(T, N, MAP, A, B) \
244   VAR1 (T, N, MAP, A) \
245   VAR1 (T, N, MAP, B)
246 #define VAR3(T, N, MAP, A, B, C) \
247   VAR2 (T, N, MAP, A, B) \
248   VAR1 (T, N, MAP, C)
249 #define VAR4(T, N, MAP, A, B, C, D) \
250   VAR3 (T, N, MAP, A, B, C) \
251   VAR1 (T, N, MAP, D)
252 #define VAR5(T, N, MAP, A, B, C, D, E) \
253   VAR4 (T, N, MAP, A, B, C, D) \
254   VAR1 (T, N, MAP, E)
255 #define VAR6(T, N, MAP, A, B, C, D, E, F) \
256   VAR5 (T, N, MAP, A, B, C, D, E) \
257   VAR1 (T, N, MAP, F)
258 #define VAR7(T, N, MAP, A, B, C, D, E, F, G) \
259   VAR6 (T, N, MAP, A, B, C, D, E, F) \
260   VAR1 (T, N, MAP, G)
261 #define VAR8(T, N, MAP, A, B, C, D, E, F, G, H) \
262   VAR7 (T, N, MAP, A, B, C, D, E, F, G) \
263   VAR1 (T, N, MAP, H)
264 #define VAR9(T, N, MAP, A, B, C, D, E, F, G, H, I) \
265   VAR8 (T, N, MAP, A, B, C, D, E, F, G, H) \
266   VAR1 (T, N, MAP, I)
267 #define VAR10(T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
268   VAR9 (T, N, MAP, A, B, C, D, E, F, G, H, I) \
269   VAR1 (T, N, MAP, J)
270 #define VAR11(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
271   VAR10 (T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
272   VAR1 (T, N, MAP, K)
273 #define VAR12(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K, L) \
274   VAR11 (T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
275   VAR1 (T, N, MAP, L)
276 
277 /* BUILTIN_<ITERATOR> macros should expand to cover the same range of
278    modes as is given for each define_mode_iterator in
279    config/aarch64/iterators.md.  */
280 
281 #define BUILTIN_DX(T, N, MAP) \
282   VAR2 (T, N, MAP, di, df)
283 #define BUILTIN_GPF(T, N, MAP) \
284   VAR2 (T, N, MAP, sf, df)
285 #define BUILTIN_SDQ_I(T, N, MAP) \
286   VAR4 (T, N, MAP, qi, hi, si, di)
287 #define BUILTIN_SD_HSI(T, N, MAP) \
288   VAR2 (T, N, MAP, hi, si)
289 #define BUILTIN_V2F(T, N, MAP) \
290   VAR2 (T, N, MAP, v2sf, v2df)
291 #define BUILTIN_VALL(T, N, MAP) \
292   VAR10 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, \
293 	 v4si, v2di, v2sf, v4sf, v2df)
294 #define BUILTIN_VALLDI(T, N, MAP) \
295   VAR11 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, \
296 	 v4si, v2di, v2sf, v4sf, v2df, di)
297 #define BUILTIN_VALLDIF(T, N, MAP) \
298   VAR12 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, \
299 	 v4si, v2di, v2sf, v4sf, v2df, di, df)
300 #define BUILTIN_VB(T, N, MAP) \
301   VAR2 (T, N, MAP, v8qi, v16qi)
302 #define BUILTIN_VD(T, N, MAP) \
303   VAR4 (T, N, MAP, v8qi, v4hi, v2si, v2sf)
304 #define BUILTIN_VDC(T, N, MAP) \
305   VAR6 (T, N, MAP, v8qi, v4hi, v2si, v2sf, di, df)
306 #define BUILTIN_VDIC(T, N, MAP) \
307   VAR3 (T, N, MAP, v8qi, v4hi, v2si)
308 #define BUILTIN_VDN(T, N, MAP) \
309   VAR3 (T, N, MAP, v4hi, v2si, di)
310 #define BUILTIN_VDQ(T, N, MAP) \
311   VAR7 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di)
312 #define BUILTIN_VDQF(T, N, MAP) \
313   VAR3 (T, N, MAP, v2sf, v4sf, v2df)
314 #define BUILTIN_VDQH(T, N, MAP) \
315   VAR2 (T, N, MAP, v4hi, v8hi)
316 #define BUILTIN_VDQHS(T, N, MAP) \
317   VAR4 (T, N, MAP, v4hi, v8hi, v2si, v4si)
318 #define BUILTIN_VDQIF(T, N, MAP) \
319   VAR9 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2sf, v4sf, v2df)
320 #define BUILTIN_VDQM(T, N, MAP) \
321   VAR6 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si)
322 #define BUILTIN_VDQV(T, N, MAP) \
323   VAR5 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v4si)
324 #define BUILTIN_VDQQH(T, N, MAP) \
325   VAR4 (T, N, MAP, v8qi, v16qi, v4hi, v8hi)
326 #define BUILTIN_VDQ_BHSI(T, N, MAP) \
327   VAR6 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si)
328 #define BUILTIN_VDQ_I(T, N, MAP) \
329   VAR7 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di)
330 #define BUILTIN_VDW(T, N, MAP) \
331   VAR3 (T, N, MAP, v8qi, v4hi, v2si)
332 #define BUILTIN_VD_BHSI(T, N, MAP) \
333   VAR3 (T, N, MAP, v8qi, v4hi, v2si)
334 #define BUILTIN_VD_HSI(T, N, MAP) \
335   VAR2 (T, N, MAP, v4hi, v2si)
336 #define BUILTIN_VD_RE(T, N, MAP) \
337   VAR6 (T, N, MAP, v8qi, v4hi, v2si, v2sf, di, df)
338 #define BUILTIN_VQ(T, N, MAP) \
339   VAR6 (T, N, MAP, v16qi, v8hi, v4si, v2di, v4sf, v2df)
340 #define BUILTIN_VQN(T, N, MAP) \
341   VAR3 (T, N, MAP, v8hi, v4si, v2di)
342 #define BUILTIN_VQW(T, N, MAP) \
343   VAR3 (T, N, MAP, v16qi, v8hi, v4si)
344 #define BUILTIN_VQ_HSI(T, N, MAP) \
345   VAR2 (T, N, MAP, v8hi, v4si)
346 #define BUILTIN_VQ_S(T, N, MAP) \
347   VAR6 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si)
348 #define BUILTIN_VSDQ_HSI(T, N, MAP) \
349   VAR6 (T, N, MAP, v4hi, v8hi, v2si, v4si, hi, si)
350 #define BUILTIN_VSDQ_I(T, N, MAP) \
351   VAR11 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di, qi, hi, si, di)
352 #define BUILTIN_VSDQ_I_BHSI(T, N, MAP) \
353   VAR10 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di, qi, hi, si)
354 #define BUILTIN_VSDQ_I_DI(T, N, MAP) \
355   VAR8 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di, di)
356 #define BUILTIN_VSD_HSI(T, N, MAP) \
357   VAR4 (T, N, MAP, v4hi, v2si, hi, si)
358 #define BUILTIN_VSQN_HSDI(T, N, MAP) \
359   VAR6 (T, N, MAP, v8hi, v4si, v2di, hi, si, di)
360 #define BUILTIN_VSTRUCT(T, N, MAP) \
361   VAR3 (T, N, MAP, oi, ci, xi)
362 
363 static aarch64_simd_builtin_datum aarch64_simd_builtin_data[] = {
364 #include "aarch64-simd-builtins.def"
365 };
366 
367 #undef VAR1
368 #define VAR1(T, N, MAP, A) \
369   AARCH64_SIMD_BUILTIN_##T##_##N##A,
370 
371 enum aarch64_builtins
372 {
373   AARCH64_BUILTIN_MIN,
374   AARCH64_SIMD_BUILTIN_BASE,
375 #include "aarch64-simd-builtins.def"
376   AARCH64_SIMD_BUILTIN_MAX = AARCH64_SIMD_BUILTIN_BASE
377 			      + ARRAY_SIZE (aarch64_simd_builtin_data),
378   AARCH64_BUILTIN_MAX
379 };
380 
381 static GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX];
382 
383 #define NUM_DREG_TYPES 6
384 #define NUM_QREG_TYPES 6
385 
386 /* Return a tree for a signed or unsigned argument of either
387    the mode specified by MODE, or the inner mode of MODE.  */
388 tree
aarch64_build_scalar_type(enum machine_mode mode,bool unsigned_p,bool poly_p)389 aarch64_build_scalar_type (enum machine_mode mode,
390 			   bool unsigned_p,
391 			   bool poly_p)
392 {
393 #undef INT_TYPES
394 #define INT_TYPES \
395   AARCH64_TYPE_BUILDER (QI) \
396   AARCH64_TYPE_BUILDER (HI) \
397   AARCH64_TYPE_BUILDER (SI) \
398   AARCH64_TYPE_BUILDER (DI) \
399   AARCH64_TYPE_BUILDER (EI) \
400   AARCH64_TYPE_BUILDER (OI) \
401   AARCH64_TYPE_BUILDER (CI) \
402   AARCH64_TYPE_BUILDER (XI) \
403   AARCH64_TYPE_BUILDER (TI) \
404 
405 /* Statically declare all the possible types we might need.  */
406 #undef AARCH64_TYPE_BUILDER
407 #define AARCH64_TYPE_BUILDER(X) \
408   static tree X##_aarch64_type_node_p = NULL; \
409   static tree X##_aarch64_type_node_s = NULL; \
410   static tree X##_aarch64_type_node_u = NULL;
411 
412   INT_TYPES
413 
414   static tree float_aarch64_type_node = NULL;
415   static tree double_aarch64_type_node = NULL;
416 
417   gcc_assert (!VECTOR_MODE_P (mode));
418 
419 /* If we've already initialised this type, don't initialise it again,
420    otherwise ask for a new type of the correct size.  */
421 #undef AARCH64_TYPE_BUILDER
422 #define AARCH64_TYPE_BUILDER(X) \
423   case X##mode: \
424     if (unsigned_p) \
425       return (X##_aarch64_type_node_u \
426 	      ? X##_aarch64_type_node_u \
427 	      : X##_aarch64_type_node_u \
428 		  = make_unsigned_type (GET_MODE_PRECISION (mode))); \
429     else if (poly_p) \
430        return (X##_aarch64_type_node_p \
431 	      ? X##_aarch64_type_node_p \
432 	      : X##_aarch64_type_node_p \
433 		  = make_unsigned_type (GET_MODE_PRECISION (mode))); \
434     else \
435        return (X##_aarch64_type_node_s \
436 	      ? X##_aarch64_type_node_s \
437 	      : X##_aarch64_type_node_s \
438 		  = make_signed_type (GET_MODE_PRECISION (mode))); \
439     break;
440 
441   switch (mode)
442     {
443       INT_TYPES
444       case SFmode:
445 	if (!float_aarch64_type_node)
446 	  {
447 	    float_aarch64_type_node = make_node (REAL_TYPE);
448 	    TYPE_PRECISION (float_aarch64_type_node) = FLOAT_TYPE_SIZE;
449 	    layout_type (float_aarch64_type_node);
450 	  }
451 	return float_aarch64_type_node;
452 	break;
453       case DFmode:
454 	if (!double_aarch64_type_node)
455 	  {
456 	    double_aarch64_type_node = make_node (REAL_TYPE);
457 	    TYPE_PRECISION (double_aarch64_type_node) = DOUBLE_TYPE_SIZE;
458 	    layout_type (double_aarch64_type_node);
459 	  }
460 	return double_aarch64_type_node;
461 	break;
462       default:
463 	gcc_unreachable ();
464     }
465 }
466 
467 tree
aarch64_build_vector_type(enum machine_mode mode,bool unsigned_p,bool poly_p)468 aarch64_build_vector_type (enum machine_mode mode,
469 			   bool unsigned_p,
470 			   bool poly_p)
471 {
472   tree eltype;
473 
474 #define VECTOR_TYPES \
475   AARCH64_TYPE_BUILDER (V16QI) \
476   AARCH64_TYPE_BUILDER (V8HI) \
477   AARCH64_TYPE_BUILDER (V4SI) \
478   AARCH64_TYPE_BUILDER (V2DI) \
479   AARCH64_TYPE_BUILDER (V8QI) \
480   AARCH64_TYPE_BUILDER (V4HI) \
481   AARCH64_TYPE_BUILDER (V2SI) \
482   \
483   AARCH64_TYPE_BUILDER (V4SF) \
484   AARCH64_TYPE_BUILDER (V2DF) \
485   AARCH64_TYPE_BUILDER (V2SF) \
486 /* Declare our "cache" of values.  */
487 #undef AARCH64_TYPE_BUILDER
488 #define AARCH64_TYPE_BUILDER(X) \
489   static tree X##_aarch64_type_node_s = NULL; \
490   static tree X##_aarch64_type_node_u = NULL; \
491   static tree X##_aarch64_type_node_p = NULL;
492 
493   VECTOR_TYPES
494 
495   gcc_assert (VECTOR_MODE_P (mode));
496 
497 #undef AARCH64_TYPE_BUILDER
498 #define AARCH64_TYPE_BUILDER(X) \
499   case X##mode: \
500     if (unsigned_p) \
501       return X##_aarch64_type_node_u \
502 	     ? X##_aarch64_type_node_u \
503 	     : X##_aarch64_type_node_u \
504 		= build_vector_type_for_mode (aarch64_build_scalar_type \
505 						(GET_MODE_INNER (mode), \
506 						 unsigned_p, poly_p), mode); \
507     else if (poly_p) \
508        return X##_aarch64_type_node_p \
509 	      ? X##_aarch64_type_node_p \
510 	      : X##_aarch64_type_node_p \
511 		= build_vector_type_for_mode (aarch64_build_scalar_type \
512 						(GET_MODE_INNER (mode), \
513 						 unsigned_p, poly_p), mode); \
514     else \
515        return X##_aarch64_type_node_s \
516 	      ? X##_aarch64_type_node_s \
517 	      : X##_aarch64_type_node_s \
518 		= build_vector_type_for_mode (aarch64_build_scalar_type \
519 						(GET_MODE_INNER (mode), \
520 						 unsigned_p, poly_p), mode); \
521     break;
522 
523   switch (mode)
524     {
525       default:
526 	eltype = aarch64_build_scalar_type (GET_MODE_INNER (mode),
527 					    unsigned_p, poly_p);
528 	return build_vector_type_for_mode (eltype, mode);
529 	break;
530       VECTOR_TYPES
531    }
532 }
533 
534 tree
aarch64_build_type(enum machine_mode mode,bool unsigned_p,bool poly_p)535 aarch64_build_type (enum machine_mode mode, bool unsigned_p, bool poly_p)
536 {
537   if (VECTOR_MODE_P (mode))
538     return aarch64_build_vector_type (mode, unsigned_p, poly_p);
539   else
540     return aarch64_build_scalar_type (mode, unsigned_p, poly_p);
541 }
542 
543 tree
aarch64_build_signed_type(enum machine_mode mode)544 aarch64_build_signed_type (enum machine_mode mode)
545 {
546   return aarch64_build_type (mode, false, false);
547 }
548 
549 tree
aarch64_build_unsigned_type(enum machine_mode mode)550 aarch64_build_unsigned_type (enum machine_mode mode)
551 {
552   return aarch64_build_type (mode, true, false);
553 }
554 
555 tree
aarch64_build_poly_type(enum machine_mode mode)556 aarch64_build_poly_type (enum machine_mode mode)
557 {
558   return aarch64_build_type (mode, false, true);
559 }
560 
561 static void
aarch64_init_simd_builtins(void)562 aarch64_init_simd_builtins (void)
563 {
564   unsigned int i, fcode = AARCH64_SIMD_BUILTIN_BASE + 1;
565 
566   /* Signed scalar type nodes.  */
567   tree aarch64_simd_intQI_type_node = aarch64_build_signed_type (QImode);
568   tree aarch64_simd_intHI_type_node = aarch64_build_signed_type (HImode);
569   tree aarch64_simd_intSI_type_node = aarch64_build_signed_type (SImode);
570   tree aarch64_simd_intDI_type_node = aarch64_build_signed_type (DImode);
571   tree aarch64_simd_intTI_type_node = aarch64_build_signed_type (TImode);
572   tree aarch64_simd_intEI_type_node = aarch64_build_signed_type (EImode);
573   tree aarch64_simd_intOI_type_node = aarch64_build_signed_type (OImode);
574   tree aarch64_simd_intCI_type_node = aarch64_build_signed_type (CImode);
575   tree aarch64_simd_intXI_type_node = aarch64_build_signed_type (XImode);
576 
577   /* Unsigned scalar type nodes.  */
578   tree aarch64_simd_intUQI_type_node = aarch64_build_unsigned_type (QImode);
579   tree aarch64_simd_intUHI_type_node = aarch64_build_unsigned_type (HImode);
580   tree aarch64_simd_intUSI_type_node = aarch64_build_unsigned_type (SImode);
581   tree aarch64_simd_intUDI_type_node = aarch64_build_unsigned_type (DImode);
582 
583   /* Poly scalar type nodes.  */
584   tree aarch64_simd_polyQI_type_node = aarch64_build_poly_type (QImode);
585   tree aarch64_simd_polyHI_type_node = aarch64_build_poly_type (HImode);
586   tree aarch64_simd_polyDI_type_node = aarch64_build_poly_type (DImode);
587   tree aarch64_simd_polyTI_type_node = aarch64_build_poly_type (TImode);
588 
589   /* Float type nodes.  */
590   tree aarch64_simd_float_type_node = aarch64_build_signed_type (SFmode);
591   tree aarch64_simd_double_type_node = aarch64_build_signed_type (DFmode);
592 
593   /* Define typedefs which exactly correspond to the modes we are basing vector
594      types on.  If you change these names you'll need to change
595      the table used by aarch64_mangle_type too.  */
596   (*lang_hooks.types.register_builtin_type) (aarch64_simd_intQI_type_node,
597 					     "__builtin_aarch64_simd_qi");
598   (*lang_hooks.types.register_builtin_type) (aarch64_simd_intHI_type_node,
599 					     "__builtin_aarch64_simd_hi");
600   (*lang_hooks.types.register_builtin_type) (aarch64_simd_intSI_type_node,
601 					     "__builtin_aarch64_simd_si");
602   (*lang_hooks.types.register_builtin_type) (aarch64_simd_float_type_node,
603 					     "__builtin_aarch64_simd_sf");
604   (*lang_hooks.types.register_builtin_type) (aarch64_simd_intDI_type_node,
605 					     "__builtin_aarch64_simd_di");
606   (*lang_hooks.types.register_builtin_type) (aarch64_simd_double_type_node,
607 					     "__builtin_aarch64_simd_df");
608   (*lang_hooks.types.register_builtin_type) (aarch64_simd_polyQI_type_node,
609 					     "__builtin_aarch64_simd_poly8");
610   (*lang_hooks.types.register_builtin_type) (aarch64_simd_polyHI_type_node,
611 					     "__builtin_aarch64_simd_poly16");
612   (*lang_hooks.types.register_builtin_type) (aarch64_simd_polyDI_type_node,
613 					     "__builtin_aarch64_simd_poly64");
614   (*lang_hooks.types.register_builtin_type) (aarch64_simd_polyTI_type_node,
615 					     "__builtin_aarch64_simd_poly128");
616   (*lang_hooks.types.register_builtin_type) (aarch64_simd_intTI_type_node,
617 					     "__builtin_aarch64_simd_ti");
618   (*lang_hooks.types.register_builtin_type) (aarch64_simd_intEI_type_node,
619 					     "__builtin_aarch64_simd_ei");
620   (*lang_hooks.types.register_builtin_type) (aarch64_simd_intOI_type_node,
621 					     "__builtin_aarch64_simd_oi");
622   (*lang_hooks.types.register_builtin_type) (aarch64_simd_intCI_type_node,
623 					     "__builtin_aarch64_simd_ci");
624   (*lang_hooks.types.register_builtin_type) (aarch64_simd_intXI_type_node,
625 					     "__builtin_aarch64_simd_xi");
626 
627   /* Unsigned integer types for various mode sizes.  */
628   (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUQI_type_node,
629 					     "__builtin_aarch64_simd_uqi");
630   (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUHI_type_node,
631 					     "__builtin_aarch64_simd_uhi");
632   (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUSI_type_node,
633 					     "__builtin_aarch64_simd_usi");
634   (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUDI_type_node,
635 					     "__builtin_aarch64_simd_udi");
636 
637   for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++)
638     {
639       bool print_type_signature_p = false;
640       char type_signature[SIMD_MAX_BUILTIN_ARGS] = { 0 };
641       aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i];
642       const char *const modenames[] =
643 	{
644 	  "v8qi", "v4hi", "v2si", "v2sf", "di", "df",
645 	  "v16qi", "v8hi", "v4si", "v4sf", "v2di", "v2df",
646 	  "ti", "ei", "oi", "xi", "si", "sf", "hi", "qi"
647 	};
648       const enum machine_mode modes[] =
649 	{
650 	  V8QImode, V4HImode, V2SImode, V2SFmode, DImode, DFmode,
651 	  V16QImode, V8HImode, V4SImode, V4SFmode, V2DImode,
652 	  V2DFmode, TImode, EImode, OImode, XImode, SImode,
653 	  SFmode, HImode, QImode
654 	};
655       char namebuf[60];
656       tree ftype = NULL;
657       tree fndecl = NULL;
658 
659       gcc_assert (ARRAY_SIZE (modenames) == T_MAX);
660 
661       d->fcode = fcode;
662 
663       /* We must track two variables here.  op_num is
664 	 the operand number as in the RTL pattern.  This is
665 	 required to access the mode (e.g. V4SF mode) of the
666 	 argument, from which the base type can be derived.
667 	 arg_num is an index in to the qualifiers data, which
668 	 gives qualifiers to the type (e.g. const unsigned).
669 	 The reason these two variables may differ by one is the
670 	 void return type.  While all return types take the 0th entry
671 	 in the qualifiers array, there is no operand for them in the
672 	 RTL pattern.  */
673       int op_num = insn_data[d->code].n_operands - 1;
674       int arg_num = d->qualifiers[0] & qualifier_void
675 		      ? op_num + 1
676 		      : op_num;
677       tree return_type = void_type_node, args = void_list_node;
678       tree eltype;
679 
680       /* Build a function type directly from the insn_data for this
681 	 builtin.  The build_function_type () function takes care of
682 	 removing duplicates for us.  */
683       for (; op_num >= 0; arg_num--, op_num--)
684 	{
685 	  enum machine_mode op_mode = insn_data[d->code].operand[op_num].mode;
686 	  enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num];
687 
688 	  if (qualifiers & qualifier_unsigned)
689 	    {
690 	      type_signature[arg_num] = 'u';
691 	      print_type_signature_p = true;
692 	    }
693 	  else if (qualifiers & qualifier_poly)
694 	    {
695 	      type_signature[arg_num] = 'p';
696 	      print_type_signature_p = true;
697 	    }
698 	  else
699 	    type_signature[arg_num] = 's';
700 
701 	  /* Skip an internal operand for vget_{low, high}.  */
702 	  if (qualifiers & qualifier_internal)
703 	    continue;
704 
705 	  /* Some builtins have different user-facing types
706 	     for certain arguments, encoded in d->mode.  */
707 	  if (qualifiers & qualifier_map_mode)
708 	      op_mode = modes[d->mode];
709 
710 	  /* For pointers, we want a pointer to the basic type
711 	     of the vector.  */
712 	  if (qualifiers & qualifier_pointer && VECTOR_MODE_P (op_mode))
713 	    op_mode = GET_MODE_INNER (op_mode);
714 
715 	  eltype = aarch64_build_type (op_mode,
716 				       qualifiers & qualifier_unsigned,
717 				       qualifiers & qualifier_poly);
718 
719 	  /* Add qualifiers.  */
720 	  if (qualifiers & qualifier_const)
721 	    eltype = build_qualified_type (eltype, TYPE_QUAL_CONST);
722 
723 	  if (qualifiers & qualifier_pointer)
724 	      eltype = build_pointer_type (eltype);
725 
726 	  /* If we have reached arg_num == 0, we are at a non-void
727 	     return type.  Otherwise, we are still processing
728 	     arguments.  */
729 	  if (arg_num == 0)
730 	    return_type = eltype;
731 	  else
732 	    args = tree_cons (NULL_TREE, eltype, args);
733 	}
734 
735       ftype = build_function_type (return_type, args);
736 
737       gcc_assert (ftype != NULL);
738 
739       if (print_type_signature_p)
740 	snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s%s_%s",
741 		  d->name, modenames[d->mode], type_signature);
742       else
743 	snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s%s",
744 		  d->name, modenames[d->mode]);
745 
746       fndecl = add_builtin_function (namebuf, ftype, fcode, BUILT_IN_MD,
747 				     NULL, NULL_TREE);
748       aarch64_builtin_decls[fcode] = fndecl;
749     }
750 }
751 
752 void
aarch64_init_builtins(void)753 aarch64_init_builtins (void)
754 {
755   if (TARGET_SIMD)
756     aarch64_init_simd_builtins ();
757 }
758 
759 tree
aarch64_builtin_decl(unsigned code,bool initialize_p ATTRIBUTE_UNUSED)760 aarch64_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
761 {
762   if (code >= AARCH64_BUILTIN_MAX)
763     return error_mark_node;
764 
765   return aarch64_builtin_decls[code];
766 }
767 
768 typedef enum
769 {
770   SIMD_ARG_COPY_TO_REG,
771   SIMD_ARG_CONSTANT,
772   SIMD_ARG_STOP
773 } builtin_simd_arg;
774 
775 static rtx
aarch64_simd_expand_args(rtx target,int icode,int have_retval,tree exp,...)776 aarch64_simd_expand_args (rtx target, int icode, int have_retval,
777 			  tree exp, ...)
778 {
779   va_list ap;
780   rtx pat;
781   tree arg[SIMD_MAX_BUILTIN_ARGS];
782   rtx op[SIMD_MAX_BUILTIN_ARGS];
783   enum machine_mode tmode = insn_data[icode].operand[0].mode;
784   enum machine_mode mode[SIMD_MAX_BUILTIN_ARGS];
785   int argc = 0;
786 
787   if (have_retval
788       && (!target
789 	  || GET_MODE (target) != tmode
790 	  || !(*insn_data[icode].operand[0].predicate) (target, tmode)))
791     target = gen_reg_rtx (tmode);
792 
793   va_start (ap, exp);
794 
795   for (;;)
796     {
797       builtin_simd_arg thisarg = (builtin_simd_arg) va_arg (ap, int);
798 
799       if (thisarg == SIMD_ARG_STOP)
800 	break;
801       else
802 	{
803 	  arg[argc] = CALL_EXPR_ARG (exp, argc);
804 	  op[argc] = expand_normal (arg[argc]);
805 	  mode[argc] = insn_data[icode].operand[argc + have_retval].mode;
806 
807 	  switch (thisarg)
808 	    {
809 	    case SIMD_ARG_COPY_TO_REG:
810 	      if (POINTER_TYPE_P (TREE_TYPE (arg[argc])))
811 		op[argc] = convert_memory_address (Pmode, op[argc]);
812 	      /*gcc_assert (GET_MODE (op[argc]) == mode[argc]); */
813 	      if (!(*insn_data[icode].operand[argc + have_retval].predicate)
814 		  (op[argc], mode[argc]))
815 		op[argc] = copy_to_mode_reg (mode[argc], op[argc]);
816 	      break;
817 
818 	    case SIMD_ARG_CONSTANT:
819 	      if (!(*insn_data[icode].operand[argc + have_retval].predicate)
820 		  (op[argc], mode[argc]))
821 		error_at (EXPR_LOCATION (exp), "incompatible type for argument %d, "
822 		       "expected %<const int%>", argc + 1);
823 	      break;
824 
825 	    case SIMD_ARG_STOP:
826 	      gcc_unreachable ();
827 	    }
828 
829 	  argc++;
830 	}
831     }
832 
833   va_end (ap);
834 
835   if (have_retval)
836     switch (argc)
837       {
838       case 1:
839 	pat = GEN_FCN (icode) (target, op[0]);
840 	break;
841 
842       case 2:
843 	pat = GEN_FCN (icode) (target, op[0], op[1]);
844 	break;
845 
846       case 3:
847 	pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
848 	break;
849 
850       case 4:
851 	pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
852 	break;
853 
854       case 5:
855 	pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
856 	break;
857 
858       default:
859 	gcc_unreachable ();
860       }
861   else
862     switch (argc)
863       {
864       case 1:
865 	pat = GEN_FCN (icode) (op[0]);
866 	break;
867 
868       case 2:
869 	pat = GEN_FCN (icode) (op[0], op[1]);
870 	break;
871 
872       case 3:
873 	pat = GEN_FCN (icode) (op[0], op[1], op[2]);
874 	break;
875 
876       case 4:
877 	pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
878 	break;
879 
880       case 5:
881 	pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
882 	break;
883 
884       default:
885 	gcc_unreachable ();
886       }
887 
888   if (!pat)
889     return 0;
890 
891   emit_insn (pat);
892 
893   return target;
894 }
895 
896 /* Expand an AArch64 AdvSIMD builtin(intrinsic).  */
897 rtx
aarch64_simd_expand_builtin(int fcode,tree exp,rtx target)898 aarch64_simd_expand_builtin (int fcode, tree exp, rtx target)
899 {
900   aarch64_simd_builtin_datum *d =
901 		&aarch64_simd_builtin_data[fcode - (AARCH64_SIMD_BUILTIN_BASE + 1)];
902   enum insn_code icode = d->code;
903   builtin_simd_arg args[SIMD_MAX_BUILTIN_ARGS];
904   int num_args = insn_data[d->code].n_operands;
905   int is_void = 0;
906   int k;
907 
908   is_void = !!(d->qualifiers[0] & qualifier_void);
909 
910   num_args += is_void;
911 
912   for (k = 1; k < num_args; k++)
913     {
914       /* We have four arrays of data, each indexed in a different fashion.
915 	 qualifiers - element 0 always describes the function return type.
916 	 operands - element 0 is either the operand for return value (if
917 	   the function has a non-void return type) or the operand for the
918 	   first argument.
919 	 expr_args - element 0 always holds the first argument.
920 	 args - element 0 is always used for the return type.  */
921       int qualifiers_k = k;
922       int operands_k = k - is_void;
923       int expr_args_k = k - 1;
924 
925       if (d->qualifiers[qualifiers_k] & qualifier_immediate)
926 	args[k] = SIMD_ARG_CONSTANT;
927       else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate)
928 	{
929 	  rtx arg
930 	    = expand_normal (CALL_EXPR_ARG (exp,
931 					    (expr_args_k)));
932 	  /* Handle constants only if the predicate allows it.  */
933 	  bool op_const_int_p =
934 	    (CONST_INT_P (arg)
935 	     && (*insn_data[icode].operand[operands_k].predicate)
936 		(arg, insn_data[icode].operand[operands_k].mode));
937 	  args[k] = op_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG;
938 	}
939       else
940 	args[k] = SIMD_ARG_COPY_TO_REG;
941 
942     }
943   args[k] = SIMD_ARG_STOP;
944 
945   /* The interface to aarch64_simd_expand_args expects a 0 if
946      the function is void, and a 1 if it is not.  */
947   return aarch64_simd_expand_args
948 	  (target, icode, !is_void, exp,
949 	   args[1],
950 	   args[2],
951 	   args[3],
952 	   args[4],
953 	   SIMD_ARG_STOP);
954 }
955 
956 /* Expand an expression EXP that calls a built-in function,
957    with result going to TARGET if that's convenient.  */
958 rtx
aarch64_expand_builtin(tree exp,rtx target,rtx subtarget ATTRIBUTE_UNUSED,enum machine_mode mode ATTRIBUTE_UNUSED,int ignore ATTRIBUTE_UNUSED)959 aarch64_expand_builtin (tree exp,
960 		     rtx target,
961 		     rtx subtarget ATTRIBUTE_UNUSED,
962 		     enum machine_mode mode ATTRIBUTE_UNUSED,
963 		     int ignore ATTRIBUTE_UNUSED)
964 {
965   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
966   int fcode = DECL_FUNCTION_CODE (fndecl);
967 
968   if (fcode >= AARCH64_SIMD_BUILTIN_BASE)
969     return aarch64_simd_expand_builtin (fcode, exp, target);
970 
971   return NULL_RTX;
972 }
973 
974 tree
aarch64_builtin_vectorized_function(tree fndecl,tree type_out,tree type_in)975 aarch64_builtin_vectorized_function (tree fndecl, tree type_out, tree type_in)
976 {
977   enum machine_mode in_mode, out_mode;
978   int in_n, out_n;
979 
980   if (TREE_CODE (type_out) != VECTOR_TYPE
981       || TREE_CODE (type_in) != VECTOR_TYPE)
982     return NULL_TREE;
983 
984   out_mode = TYPE_MODE (TREE_TYPE (type_out));
985   out_n = TYPE_VECTOR_SUBPARTS (type_out);
986   in_mode = TYPE_MODE (TREE_TYPE (type_in));
987   in_n = TYPE_VECTOR_SUBPARTS (type_in);
988 
989 #undef AARCH64_CHECK_BUILTIN_MODE
990 #define AARCH64_CHECK_BUILTIN_MODE(C, N) 1
991 #define AARCH64_FIND_FRINT_VARIANT(N) \
992   (AARCH64_CHECK_BUILTIN_MODE (2, D) \
993     ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2df] \
994     : (AARCH64_CHECK_BUILTIN_MODE (4, S) \
995 	? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v4sf] \
996 	: (AARCH64_CHECK_BUILTIN_MODE (2, S) \
997 	   ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2sf] \
998 	   : NULL_TREE)))
999   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
1000     {
1001       enum built_in_function fn = DECL_FUNCTION_CODE (fndecl);
1002       switch (fn)
1003 	{
1004 #undef AARCH64_CHECK_BUILTIN_MODE
1005 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1006   (out_mode == N##Fmode && out_n == C \
1007    && in_mode == N##Fmode && in_n == C)
1008 	case BUILT_IN_FLOOR:
1009 	case BUILT_IN_FLOORF:
1010 	  return AARCH64_FIND_FRINT_VARIANT (floor);
1011 	case BUILT_IN_CEIL:
1012 	case BUILT_IN_CEILF:
1013 	  return AARCH64_FIND_FRINT_VARIANT (ceil);
1014 	case BUILT_IN_TRUNC:
1015 	case BUILT_IN_TRUNCF:
1016 	  return AARCH64_FIND_FRINT_VARIANT (btrunc);
1017 	case BUILT_IN_ROUND:
1018 	case BUILT_IN_ROUNDF:
1019 	  return AARCH64_FIND_FRINT_VARIANT (round);
1020 	case BUILT_IN_NEARBYINT:
1021 	case BUILT_IN_NEARBYINTF:
1022 	  return AARCH64_FIND_FRINT_VARIANT (nearbyint);
1023 	case BUILT_IN_SQRT:
1024 	case BUILT_IN_SQRTF:
1025 	  return AARCH64_FIND_FRINT_VARIANT (sqrt);
1026 #undef AARCH64_CHECK_BUILTIN_MODE
1027 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1028   (out_mode == SImode && out_n == C \
1029    && in_mode == N##Imode && in_n == C)
1030         case BUILT_IN_CLZ:
1031           {
1032             if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1033               return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_clzv4si];
1034             return NULL_TREE;
1035           }
1036 #undef AARCH64_CHECK_BUILTIN_MODE
1037 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1038   (out_mode == N##Imode && out_n == C \
1039    && in_mode == N##Fmode && in_n == C)
1040 	case BUILT_IN_LFLOOR:
1041 	case BUILT_IN_LFLOORF:
1042 	case BUILT_IN_LLFLOOR:
1043 	case BUILT_IN_IFLOORF:
1044 	  {
1045 	    enum aarch64_builtins builtin;
1046 	    if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1047 	      builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2dfv2di;
1048 	    else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1049 	      builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv4sfv4si;
1050 	    else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1051 	      builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2sfv2si;
1052 	    else
1053 	      return NULL_TREE;
1054 
1055 	    return aarch64_builtin_decls[builtin];
1056 	  }
1057 	case BUILT_IN_LCEIL:
1058 	case BUILT_IN_LCEILF:
1059 	case BUILT_IN_LLCEIL:
1060 	case BUILT_IN_ICEILF:
1061 	  {
1062 	    enum aarch64_builtins builtin;
1063 	    if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1064 	      builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2dfv2di;
1065 	    else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1066 	      builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv4sfv4si;
1067 	    else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1068 	      builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2sfv2si;
1069 	    else
1070 	      return NULL_TREE;
1071 
1072 	    return aarch64_builtin_decls[builtin];
1073 	  }
1074 	case BUILT_IN_LROUND:
1075 	case BUILT_IN_IROUNDF:
1076 	  {
1077 	    enum aarch64_builtins builtin;
1078 	    if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1079 	      builtin =	AARCH64_SIMD_BUILTIN_UNOP_lroundv2dfv2di;
1080 	    else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1081 	      builtin =	AARCH64_SIMD_BUILTIN_UNOP_lroundv4sfv4si;
1082 	    else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1083 	      builtin =	AARCH64_SIMD_BUILTIN_UNOP_lroundv2sfv2si;
1084 	    else
1085 	      return NULL_TREE;
1086 
1087 	    return aarch64_builtin_decls[builtin];
1088 	  }
1089 
1090 	default:
1091 	  return NULL_TREE;
1092       }
1093     }
1094 
1095   return NULL_TREE;
1096 }
1097 
1098 #undef VAR1
1099 #define VAR1(T, N, MAP, A) \
1100   case AARCH64_SIMD_BUILTIN_##T##_##N##A:
1101 
1102 tree
aarch64_fold_builtin(tree fndecl,int n_args ATTRIBUTE_UNUSED,tree * args,bool ignore ATTRIBUTE_UNUSED)1103 aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args,
1104 		      bool ignore ATTRIBUTE_UNUSED)
1105 {
1106   int fcode = DECL_FUNCTION_CODE (fndecl);
1107   tree type = TREE_TYPE (TREE_TYPE (fndecl));
1108 
1109   switch (fcode)
1110     {
1111       BUILTIN_VALLDI (UNOP, abs, 2)
1112 	return fold_build1 (ABS_EXPR, type, args[0]);
1113 	break;
1114       BUILTIN_VALLDI (BINOP, cmge, 0)
1115 	return fold_build2 (GE_EXPR, type, args[0], args[1]);
1116 	break;
1117       BUILTIN_VALLDI (BINOP, cmgt, 0)
1118 	return fold_build2 (GT_EXPR, type, args[0], args[1]);
1119 	break;
1120       BUILTIN_VALLDI (BINOP, cmeq, 0)
1121 	return fold_build2 (EQ_EXPR, type, args[0], args[1]);
1122 	break;
1123       BUILTIN_VSDQ_I_DI (BINOP, cmtst, 0)
1124 	{
1125 	  tree and_node = fold_build2 (BIT_AND_EXPR, type, args[0], args[1]);
1126 	  tree vec_zero_node = build_zero_cst (type);
1127 	  return fold_build2 (NE_EXPR, type, and_node, vec_zero_node);
1128 	  break;
1129 	}
1130       VAR1 (UNOP, floatv2si, 2, v2sf)
1131       VAR1 (UNOP, floatv4si, 2, v4sf)
1132       VAR1 (UNOP, floatv2di, 2, v2df)
1133 	return fold_build1 (FLOAT_EXPR, type, args[0]);
1134       default:
1135 	break;
1136     }
1137 
1138   return NULL_TREE;
1139 }
1140 
1141 bool
aarch64_gimple_fold_builtin(gimple_stmt_iterator * gsi)1142 aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi)
1143 {
1144   bool changed = false;
1145   gimple stmt = gsi_stmt (*gsi);
1146   tree call = gimple_call_fn (stmt);
1147   tree fndecl;
1148   gimple new_stmt = NULL;
1149   if (call)
1150     {
1151       fndecl = gimple_call_fndecl (stmt);
1152       if (fndecl)
1153 	{
1154 	  int fcode = DECL_FUNCTION_CODE (fndecl);
1155 	  int nargs = gimple_call_num_args (stmt);
1156 	  tree *args = (nargs > 0
1157 			? gimple_call_arg_ptr (stmt, 0)
1158 			: &error_mark_node);
1159 
1160 	  switch (fcode)
1161 	    {
1162 	      BUILTIN_VALL (UNOP, reduc_splus_, 10)
1163 		new_stmt = gimple_build_assign_with_ops (
1164 						REDUC_PLUS_EXPR,
1165 						gimple_call_lhs (stmt),
1166 						args[0],
1167 						NULL_TREE);
1168 		break;
1169 	      BUILTIN_VDQIF (UNOP, reduc_smax_, 10)
1170 		new_stmt = gimple_build_assign_with_ops (
1171 						REDUC_MAX_EXPR,
1172 						gimple_call_lhs (stmt),
1173 						args[0],
1174 						NULL_TREE);
1175 		break;
1176 	      BUILTIN_VDQIF (UNOP, reduc_smin_, 10)
1177 		new_stmt = gimple_build_assign_with_ops (
1178 						REDUC_MIN_EXPR,
1179 						gimple_call_lhs (stmt),
1180 						args[0],
1181 						NULL_TREE);
1182 		break;
1183 
1184 	    default:
1185 	      break;
1186 	    }
1187 	}
1188     }
1189 
1190   if (new_stmt)
1191     {
1192       gsi_replace (gsi, new_stmt, true);
1193       changed = true;
1194     }
1195 
1196   return changed;
1197 }
1198 
1199 #undef AARCH64_CHECK_BUILTIN_MODE
1200 #undef AARCH64_FIND_FRINT_VARIANT
1201 #undef BUILTIN_DX
1202 #undef BUILTIN_SDQ_I
1203 #undef BUILTIN_SD_HSI
1204 #undef BUILTIN_V2F
1205 #undef BUILTIN_VALL
1206 #undef BUILTIN_VB
1207 #undef BUILTIN_VD
1208 #undef BUILTIN_VDC
1209 #undef BUILTIN_VDIC
1210 #undef BUILTIN_VDN
1211 #undef BUILTIN_VDQ
1212 #undef BUILTIN_VDQF
1213 #undef BUILTIN_VDQH
1214 #undef BUILTIN_VDQHS
1215 #undef BUILTIN_VDQIF
1216 #undef BUILTIN_VDQM
1217 #undef BUILTIN_VDQV
1218 #undef BUILTIN_VDQ_BHSI
1219 #undef BUILTIN_VDQ_I
1220 #undef BUILTIN_VDW
1221 #undef BUILTIN_VD_BHSI
1222 #undef BUILTIN_VD_HSI
1223 #undef BUILTIN_VD_RE
1224 #undef BUILTIN_VQ
1225 #undef BUILTIN_VQN
1226 #undef BUILTIN_VQW
1227 #undef BUILTIN_VQ_HSI
1228 #undef BUILTIN_VQ_S
1229 #undef BUILTIN_VSDQ_HSI
1230 #undef BUILTIN_VSDQ_I
1231 #undef BUILTIN_VSDQ_I_BHSI
1232 #undef BUILTIN_VSDQ_I_DI
1233 #undef BUILTIN_VSD_HSI
1234 #undef BUILTIN_VSQN_HSDI
1235 #undef BUILTIN_VSTRUCT
1236 #undef CF0
1237 #undef CF1
1238 #undef CF2
1239 #undef CF3
1240 #undef CF4
1241 #undef CF10
1242 #undef VAR1
1243 #undef VAR2
1244 #undef VAR3
1245 #undef VAR4
1246 #undef VAR5
1247 #undef VAR6
1248 #undef VAR7
1249 #undef VAR8
1250 #undef VAR9
1251 #undef VAR10
1252 #undef VAR11
1253 
1254