gcc/testsuite/:
[official-gcc.git] / gcc / config / aarch64 / aarch64-builtins.c
blob6df42fde8e84106486d2a57e61672131adfca96b
1 /* Builtins' description for AArch64 SIMD architecture.
2 Copyright (C) 2011-2014 Free Software Foundation, Inc.
3 Contributed by ARM Ltd.
5 This file is part of GCC.
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.
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.
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/>. */
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 "insn-codes.h"
36 #include "optabs.h"
37 #include "hash-table.h"
38 #include "vec.h"
39 #include "ggc.h"
40 #include "predict.h"
41 #include "hashtab.h"
42 #include "hash-set.h"
43 #include "machmode.h"
44 #include "hard-reg-set.h"
45 #include "input.h"
46 #include "function.h"
47 #include "dominance.h"
48 #include "cfg.h"
49 #include "cfgrtl.h"
50 #include "cfganal.h"
51 #include "lcm.h"
52 #include "cfgbuild.h"
53 #include "cfgcleanup.h"
54 #include "basic-block.h"
55 #include "tree-ssa-alias.h"
56 #include "internal-fn.h"
57 #include "gimple-fold.h"
58 #include "tree-eh.h"
59 #include "gimple-expr.h"
60 #include "is-a.h"
61 #include "gimple.h"
62 #include "gimple-iterator.h"
64 #define v8qi_UP V8QImode
65 #define v4hi_UP V4HImode
66 #define v2si_UP V2SImode
67 #define v2sf_UP V2SFmode
68 #define v1df_UP V1DFmode
69 #define di_UP DImode
70 #define df_UP DFmode
71 #define v16qi_UP V16QImode
72 #define v8hi_UP V8HImode
73 #define v4si_UP V4SImode
74 #define v4sf_UP V4SFmode
75 #define v2di_UP V2DImode
76 #define v2df_UP V2DFmode
77 #define ti_UP TImode
78 #define ei_UP EImode
79 #define oi_UP OImode
80 #define ci_UP CImode
81 #define xi_UP XImode
82 #define si_UP SImode
83 #define sf_UP SFmode
84 #define hi_UP HImode
85 #define qi_UP QImode
86 #define UP(X) X##_UP
88 #define SIMD_MAX_BUILTIN_ARGS 5
90 enum aarch64_type_qualifiers
92 /* T foo. */
93 qualifier_none = 0x0,
94 /* unsigned T foo. */
95 qualifier_unsigned = 0x1, /* 1 << 0 */
96 /* const T foo. */
97 qualifier_const = 0x2, /* 1 << 1 */
98 /* T *foo. */
99 qualifier_pointer = 0x4, /* 1 << 2 */
100 /* Used when expanding arguments if an operand could
101 be an immediate. */
102 qualifier_immediate = 0x8, /* 1 << 3 */
103 qualifier_maybe_immediate = 0x10, /* 1 << 4 */
104 /* void foo (...). */
105 qualifier_void = 0x20, /* 1 << 5 */
106 /* Some patterns may have internal operands, this qualifier is an
107 instruction to the initialisation code to skip this operand. */
108 qualifier_internal = 0x40, /* 1 << 6 */
109 /* Some builtins should use the T_*mode* encoded in a simd_builtin_datum
110 rather than using the type of the operand. */
111 qualifier_map_mode = 0x80, /* 1 << 7 */
112 /* qualifier_pointer | qualifier_map_mode */
113 qualifier_pointer_map_mode = 0x84,
114 /* qualifier_const | qualifier_pointer | qualifier_map_mode */
115 qualifier_const_pointer_map_mode = 0x86,
116 /* Polynomial types. */
117 qualifier_poly = 0x100,
118 /* Lane indices - must be in range, and flipped for bigendian. */
119 qualifier_lane_index = 0x200
122 typedef struct
124 const char *name;
125 machine_mode mode;
126 const enum insn_code code;
127 unsigned int fcode;
128 enum aarch64_type_qualifiers *qualifiers;
129 } aarch64_simd_builtin_datum;
131 static enum aarch64_type_qualifiers
132 aarch64_types_unop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
133 = { qualifier_none, qualifier_none };
134 #define TYPES_UNOP (aarch64_types_unop_qualifiers)
135 static enum aarch64_type_qualifiers
136 aarch64_types_unopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
137 = { qualifier_unsigned, qualifier_unsigned };
138 #define TYPES_UNOPU (aarch64_types_unopu_qualifiers)
139 static enum aarch64_type_qualifiers
140 aarch64_types_binop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
141 = { qualifier_none, qualifier_none, qualifier_maybe_immediate };
142 #define TYPES_BINOP (aarch64_types_binop_qualifiers)
143 static enum aarch64_type_qualifiers
144 aarch64_types_binopv_qualifiers[SIMD_MAX_BUILTIN_ARGS]
145 = { qualifier_void, qualifier_none, qualifier_none };
146 #define TYPES_BINOPV (aarch64_types_binopv_qualifiers)
147 static enum aarch64_type_qualifiers
148 aarch64_types_binopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
149 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned };
150 #define TYPES_BINOPU (aarch64_types_binopu_qualifiers)
151 static enum aarch64_type_qualifiers
152 aarch64_types_binop_uus_qualifiers[SIMD_MAX_BUILTIN_ARGS]
153 = { qualifier_unsigned, qualifier_unsigned, qualifier_none };
154 #define TYPES_BINOP_UUS (aarch64_types_binop_uus_qualifiers)
155 static enum aarch64_type_qualifiers
156 aarch64_types_binop_ssu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
157 = { qualifier_none, qualifier_none, qualifier_unsigned };
158 #define TYPES_BINOP_SSU (aarch64_types_binop_ssu_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)
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_ternop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
170 = { qualifier_none, qualifier_none, qualifier_none, qualifier_lane_index };
171 #define TYPES_TERNOP_LANE (aarch64_types_ternop_lane_qualifiers)
172 static enum aarch64_type_qualifiers
173 aarch64_types_ternopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
174 = { qualifier_unsigned, qualifier_unsigned,
175 qualifier_unsigned, qualifier_unsigned };
176 #define TYPES_TERNOPU (aarch64_types_ternopu_qualifiers)
178 static enum aarch64_type_qualifiers
179 aarch64_types_quadop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
180 = { qualifier_none, qualifier_none, qualifier_none,
181 qualifier_none, qualifier_lane_index };
182 #define TYPES_QUADOP_LANE (aarch64_types_quadop_lane_qualifiers)
184 static enum aarch64_type_qualifiers
185 aarch64_types_binop_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
186 = { qualifier_none, qualifier_none, qualifier_immediate };
187 #define TYPES_GETREG (aarch64_types_binop_imm_qualifiers)
188 #define TYPES_SHIFTIMM (aarch64_types_binop_imm_qualifiers)
189 static enum aarch64_type_qualifiers
190 aarch64_types_shift_to_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS]
191 = { qualifier_unsigned, qualifier_none, qualifier_immediate };
192 #define TYPES_SHIFTIMM_USS (aarch64_types_shift_to_unsigned_qualifiers)
193 static enum aarch64_type_qualifiers
194 aarch64_types_unsigned_shift_qualifiers[SIMD_MAX_BUILTIN_ARGS]
195 = { qualifier_unsigned, qualifier_unsigned, qualifier_immediate };
196 #define TYPES_USHIFTIMM (aarch64_types_unsigned_shift_qualifiers)
198 static enum aarch64_type_qualifiers
199 aarch64_types_ternop_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
200 = { qualifier_none, qualifier_none, qualifier_none, qualifier_immediate };
201 #define TYPES_SETREG (aarch64_types_ternop_imm_qualifiers)
202 #define TYPES_SHIFTINSERT (aarch64_types_ternop_imm_qualifiers)
203 #define TYPES_SHIFTACC (aarch64_types_ternop_imm_qualifiers)
205 static enum aarch64_type_qualifiers
206 aarch64_types_unsigned_shiftacc_qualifiers[SIMD_MAX_BUILTIN_ARGS]
207 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
208 qualifier_immediate };
209 #define TYPES_USHIFTACC (aarch64_types_unsigned_shiftacc_qualifiers)
212 static enum aarch64_type_qualifiers
213 aarch64_types_combine_qualifiers[SIMD_MAX_BUILTIN_ARGS]
214 = { qualifier_none, qualifier_none, qualifier_none };
215 #define TYPES_COMBINE (aarch64_types_combine_qualifiers)
217 static enum aarch64_type_qualifiers
218 aarch64_types_load1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
219 = { qualifier_none, qualifier_const_pointer_map_mode };
220 #define TYPES_LOAD1 (aarch64_types_load1_qualifiers)
221 #define TYPES_LOADSTRUCT (aarch64_types_load1_qualifiers)
222 static enum aarch64_type_qualifiers
223 aarch64_types_loadstruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
224 = { qualifier_none, qualifier_const_pointer_map_mode,
225 qualifier_none, qualifier_none };
226 #define TYPES_LOADSTRUCT_LANE (aarch64_types_loadstruct_lane_qualifiers)
228 static enum aarch64_type_qualifiers
229 aarch64_types_bsl_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
230 = { qualifier_poly, qualifier_unsigned,
231 qualifier_poly, qualifier_poly };
232 #define TYPES_BSL_P (aarch64_types_bsl_p_qualifiers)
233 static enum aarch64_type_qualifiers
234 aarch64_types_bsl_s_qualifiers[SIMD_MAX_BUILTIN_ARGS]
235 = { qualifier_none, qualifier_unsigned,
236 qualifier_none, qualifier_none };
237 #define TYPES_BSL_S (aarch64_types_bsl_s_qualifiers)
238 static enum aarch64_type_qualifiers
239 aarch64_types_bsl_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
240 = { qualifier_unsigned, qualifier_unsigned,
241 qualifier_unsigned, qualifier_unsigned };
242 #define TYPES_BSL_U (aarch64_types_bsl_u_qualifiers)
244 /* The first argument (return type) of a store should be void type,
245 which we represent with qualifier_void. Their first operand will be
246 a DImode pointer to the location to store to, so we must use
247 qualifier_map_mode | qualifier_pointer to build a pointer to the
248 element type of the vector. */
249 static enum aarch64_type_qualifiers
250 aarch64_types_store1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
251 = { qualifier_void, qualifier_pointer_map_mode, qualifier_none };
252 #define TYPES_STORE1 (aarch64_types_store1_qualifiers)
253 #define TYPES_STORESTRUCT (aarch64_types_store1_qualifiers)
254 static enum aarch64_type_qualifiers
255 aarch64_types_storestruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
256 = { qualifier_void, qualifier_pointer_map_mode,
257 qualifier_none, qualifier_none };
258 #define TYPES_STORESTRUCT_LANE (aarch64_types_storestruct_lane_qualifiers)
260 #define CF0(N, X) CODE_FOR_aarch64_##N##X
261 #define CF1(N, X) CODE_FOR_##N##X##1
262 #define CF2(N, X) CODE_FOR_##N##X##2
263 #define CF3(N, X) CODE_FOR_##N##X##3
264 #define CF4(N, X) CODE_FOR_##N##X##4
265 #define CF10(N, X) CODE_FOR_##N##X
267 #define VAR1(T, N, MAP, A) \
268 {#N #A, UP (A), CF##MAP (N, A), 0, TYPES_##T},
269 #define VAR2(T, N, MAP, A, B) \
270 VAR1 (T, N, MAP, A) \
271 VAR1 (T, N, MAP, B)
272 #define VAR3(T, N, MAP, A, B, C) \
273 VAR2 (T, N, MAP, A, B) \
274 VAR1 (T, N, MAP, C)
275 #define VAR4(T, N, MAP, A, B, C, D) \
276 VAR3 (T, N, MAP, A, B, C) \
277 VAR1 (T, N, MAP, D)
278 #define VAR5(T, N, MAP, A, B, C, D, E) \
279 VAR4 (T, N, MAP, A, B, C, D) \
280 VAR1 (T, N, MAP, E)
281 #define VAR6(T, N, MAP, A, B, C, D, E, F) \
282 VAR5 (T, N, MAP, A, B, C, D, E) \
283 VAR1 (T, N, MAP, F)
284 #define VAR7(T, N, MAP, A, B, C, D, E, F, G) \
285 VAR6 (T, N, MAP, A, B, C, D, E, F) \
286 VAR1 (T, N, MAP, G)
287 #define VAR8(T, N, MAP, A, B, C, D, E, F, G, H) \
288 VAR7 (T, N, MAP, A, B, C, D, E, F, G) \
289 VAR1 (T, N, MAP, H)
290 #define VAR9(T, N, MAP, A, B, C, D, E, F, G, H, I) \
291 VAR8 (T, N, MAP, A, B, C, D, E, F, G, H) \
292 VAR1 (T, N, MAP, I)
293 #define VAR10(T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
294 VAR9 (T, N, MAP, A, B, C, D, E, F, G, H, I) \
295 VAR1 (T, N, MAP, J)
296 #define VAR11(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
297 VAR10 (T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
298 VAR1 (T, N, MAP, K)
299 #define VAR12(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K, L) \
300 VAR11 (T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
301 VAR1 (T, N, MAP, L)
303 #include "aarch64-builtin-iterators.h"
305 static aarch64_simd_builtin_datum aarch64_simd_builtin_data[] = {
306 #include "aarch64-simd-builtins.def"
309 /* There's only 8 CRC32 builtins. Probably not worth their own .def file. */
310 #define AARCH64_CRC32_BUILTINS \
311 CRC32_BUILTIN (crc32b, QI) \
312 CRC32_BUILTIN (crc32h, HI) \
313 CRC32_BUILTIN (crc32w, SI) \
314 CRC32_BUILTIN (crc32x, DI) \
315 CRC32_BUILTIN (crc32cb, QI) \
316 CRC32_BUILTIN (crc32ch, HI) \
317 CRC32_BUILTIN (crc32cw, SI) \
318 CRC32_BUILTIN (crc32cx, DI)
320 typedef struct
322 const char *name;
323 machine_mode mode;
324 const enum insn_code icode;
325 unsigned int fcode;
326 } aarch64_crc_builtin_datum;
328 #define CRC32_BUILTIN(N, M) \
329 AARCH64_BUILTIN_##N,
331 #undef VAR1
332 #define VAR1(T, N, MAP, A) \
333 AARCH64_SIMD_BUILTIN_##T##_##N##A,
335 enum aarch64_builtins
337 AARCH64_BUILTIN_MIN,
339 AARCH64_BUILTIN_GET_FPCR,
340 AARCH64_BUILTIN_SET_FPCR,
341 AARCH64_BUILTIN_GET_FPSR,
342 AARCH64_BUILTIN_SET_FPSR,
344 AARCH64_SIMD_BUILTIN_BASE,
345 #include "aarch64-simd-builtins.def"
346 AARCH64_SIMD_BUILTIN_MAX = AARCH64_SIMD_BUILTIN_BASE
347 + ARRAY_SIZE (aarch64_simd_builtin_data),
348 AARCH64_CRC32_BUILTIN_BASE,
349 AARCH64_CRC32_BUILTINS
350 AARCH64_CRC32_BUILTIN_MAX,
351 AARCH64_BUILTIN_MAX
354 #undef CRC32_BUILTIN
355 #define CRC32_BUILTIN(N, M) \
356 {"__builtin_aarch64_"#N, M##mode, CODE_FOR_aarch64_##N, AARCH64_BUILTIN_##N},
358 static aarch64_crc_builtin_datum aarch64_crc_builtin_data[] = {
359 AARCH64_CRC32_BUILTINS
362 #undef CRC32_BUILTIN
364 static GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX];
366 #define NUM_DREG_TYPES 6
367 #define NUM_QREG_TYPES 6
369 /* Internal scalar builtin types. These types are used to support
370 neon intrinsic builtins. They are _not_ user-visible types. Therefore
371 the mangling for these types are implementation defined. */
372 const char *aarch64_scalar_builtin_types[] = {
373 "__builtin_aarch64_simd_qi",
374 "__builtin_aarch64_simd_hi",
375 "__builtin_aarch64_simd_si",
376 "__builtin_aarch64_simd_sf",
377 "__builtin_aarch64_simd_di",
378 "__builtin_aarch64_simd_df",
379 "__builtin_aarch64_simd_poly8",
380 "__builtin_aarch64_simd_poly16",
381 "__builtin_aarch64_simd_poly64",
382 "__builtin_aarch64_simd_poly128",
383 "__builtin_aarch64_simd_ti",
384 "__builtin_aarch64_simd_uqi",
385 "__builtin_aarch64_simd_uhi",
386 "__builtin_aarch64_simd_usi",
387 "__builtin_aarch64_simd_udi",
388 "__builtin_aarch64_simd_ei",
389 "__builtin_aarch64_simd_oi",
390 "__builtin_aarch64_simd_ci",
391 "__builtin_aarch64_simd_xi",
392 NULL
395 #define ENTRY(E, M, Q, G) E,
396 enum aarch64_simd_type
398 #include "aarch64-simd-builtin-types.def"
399 ARM_NEON_H_TYPES_LAST
401 #undef ENTRY
403 struct aarch64_simd_type_info
405 enum aarch64_simd_type type;
407 /* Internal type name. */
408 const char *name;
410 /* Internal type name(mangled). The mangled names conform to the
411 AAPCS64 (see "Procedure Call Standard for the ARM 64-bit Architecture",
412 Appendix A). To qualify for emission with the mangled names defined in
413 that document, a vector type must not only be of the correct mode but also
414 be of the correct internal AdvSIMD vector type (e.g. __Int8x8_t); these
415 types are registered by aarch64_init_simd_builtin_types (). In other
416 words, vector types defined in other ways e.g. via vector_size attribute
417 will get default mangled names. */
418 const char *mangle;
420 /* Internal type. */
421 tree itype;
423 /* Element type. */
424 tree eltype;
426 /* Machine mode the internal type maps to. */
427 enum machine_mode mode;
429 /* Qualifiers. */
430 enum aarch64_type_qualifiers q;
433 #define ENTRY(E, M, Q, G) \
434 {E, "__" #E, #G "__" #E, NULL_TREE, NULL_TREE, M##mode, qualifier_##Q},
435 static struct aarch64_simd_type_info aarch64_simd_types [] = {
436 #include "aarch64-simd-builtin-types.def"
438 #undef ENTRY
440 static tree aarch64_simd_intOI_type_node = NULL_TREE;
441 static tree aarch64_simd_intEI_type_node = NULL_TREE;
442 static tree aarch64_simd_intCI_type_node = NULL_TREE;
443 static tree aarch64_simd_intXI_type_node = NULL_TREE;
445 static const char *
446 aarch64_mangle_builtin_scalar_type (const_tree type)
448 int i = 0;
450 while (aarch64_scalar_builtin_types[i] != NULL)
452 const char *name = aarch64_scalar_builtin_types[i];
454 if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
455 && DECL_NAME (TYPE_NAME (type))
456 && !strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), name))
457 return aarch64_scalar_builtin_types[i];
458 i++;
460 return NULL;
463 static const char *
464 aarch64_mangle_builtin_vector_type (const_tree type)
466 int i;
467 int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
469 for (i = 0; i < nelts; i++)
470 if (aarch64_simd_types[i].mode == TYPE_MODE (type)
471 && TYPE_NAME (type)
472 && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
473 && DECL_NAME (TYPE_NAME (type))
474 && !strcmp
475 (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))),
476 aarch64_simd_types[i].name))
477 return aarch64_simd_types[i].mangle;
479 return NULL;
482 const char *
483 aarch64_mangle_builtin_type (const_tree type)
485 const char *mangle;
486 /* Walk through all the AArch64 builtins types tables to filter out the
487 incoming type. */
488 if ((mangle = aarch64_mangle_builtin_vector_type (type))
489 || (mangle = aarch64_mangle_builtin_scalar_type (type)))
490 return mangle;
492 return NULL;
495 static tree
496 aarch64_simd_builtin_std_type (enum machine_mode mode,
497 enum aarch64_type_qualifiers q)
499 #define QUAL_TYPE(M) \
500 ((q == qualifier_none) ? int##M##_type_node : unsigned_int##M##_type_node);
501 switch (mode)
503 case QImode:
504 return QUAL_TYPE (QI);
505 case HImode:
506 return QUAL_TYPE (HI);
507 case SImode:
508 return QUAL_TYPE (SI);
509 case DImode:
510 return QUAL_TYPE (DI);
511 case TImode:
512 return QUAL_TYPE (TI);
513 case OImode:
514 return aarch64_simd_intOI_type_node;
515 case EImode:
516 return aarch64_simd_intEI_type_node;
517 case CImode:
518 return aarch64_simd_intCI_type_node;
519 case XImode:
520 return aarch64_simd_intXI_type_node;
521 case SFmode:
522 return float_type_node;
523 case DFmode:
524 return double_type_node;
525 default:
526 gcc_unreachable ();
528 #undef QUAL_TYPE
531 static tree
532 aarch64_lookup_simd_builtin_type (enum machine_mode mode,
533 enum aarch64_type_qualifiers q)
535 int i;
536 int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
538 /* Non-poly scalar modes map to standard types not in the table. */
539 if (q != qualifier_poly && !VECTOR_MODE_P (mode))
540 return aarch64_simd_builtin_std_type (mode, q);
542 for (i = 0; i < nelts; i++)
543 if (aarch64_simd_types[i].mode == mode
544 && aarch64_simd_types[i].q == q)
545 return aarch64_simd_types[i].itype;
547 return NULL_TREE;
550 static tree
551 aarch64_simd_builtin_type (enum machine_mode mode,
552 bool unsigned_p, bool poly_p)
554 if (poly_p)
555 return aarch64_lookup_simd_builtin_type (mode, qualifier_poly);
556 else if (unsigned_p)
557 return aarch64_lookup_simd_builtin_type (mode, qualifier_unsigned);
558 else
559 return aarch64_lookup_simd_builtin_type (mode, qualifier_none);
562 static void
563 aarch64_init_simd_builtin_types (void)
565 int i;
566 int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
567 tree tdecl;
569 /* Init all the element types built by the front-end. */
570 aarch64_simd_types[Int8x8_t].eltype = intQI_type_node;
571 aarch64_simd_types[Int8x16_t].eltype = intQI_type_node;
572 aarch64_simd_types[Int16x4_t].eltype = intHI_type_node;
573 aarch64_simd_types[Int16x8_t].eltype = intHI_type_node;
574 aarch64_simd_types[Int32x2_t].eltype = intSI_type_node;
575 aarch64_simd_types[Int32x4_t].eltype = intSI_type_node;
576 aarch64_simd_types[Int64x1_t].eltype = intDI_type_node;
577 aarch64_simd_types[Int64x2_t].eltype = intDI_type_node;
578 aarch64_simd_types[Uint8x8_t].eltype = unsigned_intQI_type_node;
579 aarch64_simd_types[Uint8x16_t].eltype = unsigned_intQI_type_node;
580 aarch64_simd_types[Uint16x4_t].eltype = unsigned_intHI_type_node;
581 aarch64_simd_types[Uint16x8_t].eltype = unsigned_intHI_type_node;
582 aarch64_simd_types[Uint32x2_t].eltype = unsigned_intSI_type_node;
583 aarch64_simd_types[Uint32x4_t].eltype = unsigned_intSI_type_node;
584 aarch64_simd_types[Uint64x1_t].eltype = unsigned_intDI_type_node;
585 aarch64_simd_types[Uint64x2_t].eltype = unsigned_intDI_type_node;
587 /* Poly types are a world of their own. */
588 aarch64_simd_types[Poly8_t].eltype = aarch64_simd_types[Poly8_t].itype =
589 build_distinct_type_copy (unsigned_intQI_type_node);
590 aarch64_simd_types[Poly16_t].eltype = aarch64_simd_types[Poly16_t].itype =
591 build_distinct_type_copy (unsigned_intHI_type_node);
592 aarch64_simd_types[Poly64_t].eltype = aarch64_simd_types[Poly64_t].itype =
593 build_distinct_type_copy (unsigned_intDI_type_node);
594 aarch64_simd_types[Poly128_t].eltype = aarch64_simd_types[Poly128_t].itype =
595 build_distinct_type_copy (unsigned_intTI_type_node);
596 /* Init poly vector element types with scalar poly types. */
597 aarch64_simd_types[Poly8x8_t].eltype = aarch64_simd_types[Poly8_t].itype;
598 aarch64_simd_types[Poly8x16_t].eltype = aarch64_simd_types[Poly8_t].itype;
599 aarch64_simd_types[Poly16x4_t].eltype = aarch64_simd_types[Poly16_t].itype;
600 aarch64_simd_types[Poly16x8_t].eltype = aarch64_simd_types[Poly16_t].itype;
601 aarch64_simd_types[Poly64x1_t].eltype = aarch64_simd_types[Poly64_t].itype;
602 aarch64_simd_types[Poly64x2_t].eltype = aarch64_simd_types[Poly64_t].itype;
604 /* Continue with standard types. */
605 aarch64_simd_types[Float32x2_t].eltype = float_type_node;
606 aarch64_simd_types[Float32x4_t].eltype = float_type_node;
607 aarch64_simd_types[Float64x1_t].eltype = double_type_node;
608 aarch64_simd_types[Float64x2_t].eltype = double_type_node;
610 for (i = 0; i < nelts; i++)
612 tree eltype = aarch64_simd_types[i].eltype;
613 enum machine_mode mode = aarch64_simd_types[i].mode;
615 if (aarch64_simd_types[i].itype == NULL)
616 aarch64_simd_types[i].itype =
617 build_distinct_type_copy
618 (build_vector_type (eltype, GET_MODE_NUNITS (mode)));
620 tdecl = add_builtin_type (aarch64_simd_types[i].name,
621 aarch64_simd_types[i].itype);
622 TYPE_NAME (aarch64_simd_types[i].itype) = tdecl;
623 SET_TYPE_STRUCTURAL_EQUALITY (aarch64_simd_types[i].itype);
626 #define AARCH64_BUILD_SIGNED_TYPE(mode) \
627 make_signed_type (GET_MODE_PRECISION (mode));
628 aarch64_simd_intOI_type_node = AARCH64_BUILD_SIGNED_TYPE (OImode);
629 aarch64_simd_intEI_type_node = AARCH64_BUILD_SIGNED_TYPE (EImode);
630 aarch64_simd_intCI_type_node = AARCH64_BUILD_SIGNED_TYPE (CImode);
631 aarch64_simd_intXI_type_node = AARCH64_BUILD_SIGNED_TYPE (XImode);
632 #undef AARCH64_BUILD_SIGNED_TYPE
634 tdecl = add_builtin_type
635 ("__builtin_aarch64_simd_ei" , aarch64_simd_intEI_type_node);
636 TYPE_NAME (aarch64_simd_intEI_type_node) = tdecl;
637 tdecl = add_builtin_type
638 ("__builtin_aarch64_simd_oi" , aarch64_simd_intOI_type_node);
639 TYPE_NAME (aarch64_simd_intOI_type_node) = tdecl;
640 tdecl = add_builtin_type
641 ("__builtin_aarch64_simd_ci" , aarch64_simd_intCI_type_node);
642 TYPE_NAME (aarch64_simd_intCI_type_node) = tdecl;
643 tdecl = add_builtin_type
644 ("__builtin_aarch64_simd_xi" , aarch64_simd_intXI_type_node);
645 TYPE_NAME (aarch64_simd_intXI_type_node) = tdecl;
648 static void
649 aarch64_init_simd_builtin_scalar_types (void)
651 /* Define typedefs for all the standard scalar types. */
652 (*lang_hooks.types.register_builtin_type) (intQI_type_node,
653 "__builtin_aarch64_simd_qi");
654 (*lang_hooks.types.register_builtin_type) (intHI_type_node,
655 "__builtin_aarch64_simd_hi");
656 (*lang_hooks.types.register_builtin_type) (intSI_type_node,
657 "__builtin_aarch64_simd_si");
658 (*lang_hooks.types.register_builtin_type) (float_type_node,
659 "__builtin_aarch64_simd_sf");
660 (*lang_hooks.types.register_builtin_type) (intDI_type_node,
661 "__builtin_aarch64_simd_di");
662 (*lang_hooks.types.register_builtin_type) (double_type_node,
663 "__builtin_aarch64_simd_df");
664 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
665 "__builtin_aarch64_simd_poly8");
666 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
667 "__builtin_aarch64_simd_poly16");
668 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
669 "__builtin_aarch64_simd_poly64");
670 (*lang_hooks.types.register_builtin_type) (unsigned_intTI_type_node,
671 "__builtin_aarch64_simd_poly128");
672 (*lang_hooks.types.register_builtin_type) (intTI_type_node,
673 "__builtin_aarch64_simd_ti");
674 /* Unsigned integer types for various mode sizes. */
675 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
676 "__builtin_aarch64_simd_uqi");
677 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
678 "__builtin_aarch64_simd_uhi");
679 (*lang_hooks.types.register_builtin_type) (unsigned_intSI_type_node,
680 "__builtin_aarch64_simd_usi");
681 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
682 "__builtin_aarch64_simd_udi");
685 static void
686 aarch64_init_simd_builtins (void)
688 unsigned int i, fcode = AARCH64_SIMD_BUILTIN_BASE + 1;
690 aarch64_init_simd_builtin_types ();
692 /* Strong-typing hasn't been implemented for all AdvSIMD builtin intrinsics.
693 Therefore we need to preserve the old __builtin scalar types. It can be
694 removed once all the intrinsics become strongly typed using the qualifier
695 system. */
696 aarch64_init_simd_builtin_scalar_types ();
698 for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++)
700 bool print_type_signature_p = false;
701 char type_signature[SIMD_MAX_BUILTIN_ARGS] = { 0 };
702 aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i];
703 char namebuf[60];
704 tree ftype = NULL;
705 tree fndecl = NULL;
707 d->fcode = fcode;
709 /* We must track two variables here. op_num is
710 the operand number as in the RTL pattern. This is
711 required to access the mode (e.g. V4SF mode) of the
712 argument, from which the base type can be derived.
713 arg_num is an index in to the qualifiers data, which
714 gives qualifiers to the type (e.g. const unsigned).
715 The reason these two variables may differ by one is the
716 void return type. While all return types take the 0th entry
717 in the qualifiers array, there is no operand for them in the
718 RTL pattern. */
719 int op_num = insn_data[d->code].n_operands - 1;
720 int arg_num = d->qualifiers[0] & qualifier_void
721 ? op_num + 1
722 : op_num;
723 tree return_type = void_type_node, args = void_list_node;
724 tree eltype;
726 /* Build a function type directly from the insn_data for this
727 builtin. The build_function_type () function takes care of
728 removing duplicates for us. */
729 for (; op_num >= 0; arg_num--, op_num--)
731 machine_mode op_mode = insn_data[d->code].operand[op_num].mode;
732 enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num];
734 if (qualifiers & qualifier_unsigned)
736 type_signature[arg_num] = 'u';
737 print_type_signature_p = true;
739 else if (qualifiers & qualifier_poly)
741 type_signature[arg_num] = 'p';
742 print_type_signature_p = true;
744 else
745 type_signature[arg_num] = 's';
747 /* Skip an internal operand for vget_{low, high}. */
748 if (qualifiers & qualifier_internal)
749 continue;
751 /* Some builtins have different user-facing types
752 for certain arguments, encoded in d->mode. */
753 if (qualifiers & qualifier_map_mode)
754 op_mode = d->mode;
756 /* For pointers, we want a pointer to the basic type
757 of the vector. */
758 if (qualifiers & qualifier_pointer && VECTOR_MODE_P (op_mode))
759 op_mode = GET_MODE_INNER (op_mode);
761 eltype = aarch64_simd_builtin_type
762 (op_mode,
763 (qualifiers & qualifier_unsigned) != 0,
764 (qualifiers & qualifier_poly) != 0);
765 gcc_assert (eltype != NULL);
767 /* Add qualifiers. */
768 if (qualifiers & qualifier_const)
769 eltype = build_qualified_type (eltype, TYPE_QUAL_CONST);
771 if (qualifiers & qualifier_pointer)
772 eltype = build_pointer_type (eltype);
774 /* If we have reached arg_num == 0, we are at a non-void
775 return type. Otherwise, we are still processing
776 arguments. */
777 if (arg_num == 0)
778 return_type = eltype;
779 else
780 args = tree_cons (NULL_TREE, eltype, args);
783 ftype = build_function_type (return_type, args);
785 gcc_assert (ftype != NULL);
787 if (print_type_signature_p)
788 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s_%s",
789 d->name, type_signature);
790 else
791 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s",
792 d->name);
794 fndecl = add_builtin_function (namebuf, ftype, fcode, BUILT_IN_MD,
795 NULL, NULL_TREE);
796 aarch64_builtin_decls[fcode] = fndecl;
800 static void
801 aarch64_init_crc32_builtins ()
803 tree usi_type = aarch64_simd_builtin_std_type (SImode, qualifier_unsigned);
804 unsigned int i = 0;
806 for (i = 0; i < ARRAY_SIZE (aarch64_crc_builtin_data); ++i)
808 aarch64_crc_builtin_datum* d = &aarch64_crc_builtin_data[i];
809 tree argtype = aarch64_simd_builtin_std_type (d->mode,
810 qualifier_unsigned);
811 tree ftype = build_function_type_list (usi_type, usi_type, argtype, NULL_TREE);
812 tree fndecl = add_builtin_function (d->name, ftype, d->fcode,
813 BUILT_IN_MD, NULL, NULL_TREE);
815 aarch64_builtin_decls[d->fcode] = fndecl;
819 void
820 aarch64_init_builtins (void)
822 tree ftype_set_fpr
823 = build_function_type_list (void_type_node, unsigned_type_node, NULL);
824 tree ftype_get_fpr
825 = build_function_type_list (unsigned_type_node, NULL);
827 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR]
828 = add_builtin_function ("__builtin_aarch64_get_fpcr", ftype_get_fpr,
829 AARCH64_BUILTIN_GET_FPCR, BUILT_IN_MD, NULL, NULL_TREE);
830 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR]
831 = add_builtin_function ("__builtin_aarch64_set_fpcr", ftype_set_fpr,
832 AARCH64_BUILTIN_SET_FPCR, BUILT_IN_MD, NULL, NULL_TREE);
833 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR]
834 = add_builtin_function ("__builtin_aarch64_get_fpsr", ftype_get_fpr,
835 AARCH64_BUILTIN_GET_FPSR, BUILT_IN_MD, NULL, NULL_TREE);
836 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR]
837 = add_builtin_function ("__builtin_aarch64_set_fpsr", ftype_set_fpr,
838 AARCH64_BUILTIN_SET_FPSR, BUILT_IN_MD, NULL, NULL_TREE);
840 if (TARGET_SIMD)
841 aarch64_init_simd_builtins ();
842 if (TARGET_CRC32)
843 aarch64_init_crc32_builtins ();
846 tree
847 aarch64_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
849 if (code >= AARCH64_BUILTIN_MAX)
850 return error_mark_node;
852 return aarch64_builtin_decls[code];
855 typedef enum
857 SIMD_ARG_COPY_TO_REG,
858 SIMD_ARG_CONSTANT,
859 SIMD_ARG_LANE_INDEX,
860 SIMD_ARG_STOP
861 } builtin_simd_arg;
863 static rtx
864 aarch64_simd_expand_args (rtx target, int icode, int have_retval,
865 tree exp, builtin_simd_arg *args)
867 rtx pat;
868 rtx op[SIMD_MAX_BUILTIN_ARGS + 1]; /* First element for result operand. */
869 int opc = 0;
871 if (have_retval)
873 machine_mode tmode = insn_data[icode].operand[0].mode;
874 if (!target
875 || GET_MODE (target) != tmode
876 || !(*insn_data[icode].operand[0].predicate) (target, tmode))
877 target = gen_reg_rtx (tmode);
878 op[opc++] = target;
881 for (;;)
883 builtin_simd_arg thisarg = args[opc - have_retval];
885 if (thisarg == SIMD_ARG_STOP)
886 break;
887 else
889 tree arg = CALL_EXPR_ARG (exp, opc - have_retval);
890 enum machine_mode mode = insn_data[icode].operand[opc].mode;
891 op[opc] = expand_normal (arg);
893 switch (thisarg)
895 case SIMD_ARG_COPY_TO_REG:
896 if (POINTER_TYPE_P (TREE_TYPE (arg)))
897 op[opc] = convert_memory_address (Pmode, op[opc]);
898 /*gcc_assert (GET_MODE (op[opc]) == mode); */
899 if (!(*insn_data[icode].operand[opc].predicate)
900 (op[opc], mode))
901 op[opc] = copy_to_mode_reg (mode, op[opc]);
902 break;
904 case SIMD_ARG_LANE_INDEX:
905 /* Must be a previous operand into which this is an index. */
906 gcc_assert (opc > 0);
907 if (CONST_INT_P (op[opc]))
909 machine_mode vmode = insn_data[icode].operand[opc - 1].mode;
910 aarch64_simd_lane_bounds (op[opc],
911 0, GET_MODE_NUNITS (vmode), exp);
912 /* Keep to GCC-vector-extension lane indices in the RTL. */
913 op[opc] = GEN_INT (ENDIAN_LANE_N (vmode, INTVAL (op[opc])));
915 /* Fall through - if the lane index isn't a constant then
916 the next case will error. */
917 case SIMD_ARG_CONSTANT:
918 if (!(*insn_data[icode].operand[opc].predicate)
919 (op[opc], mode))
921 error_at (EXPR_LOCATION (exp), "incompatible type for argument %d, "
922 "expected %<const int%>", opc + 1);
923 return const0_rtx;
925 break;
927 case SIMD_ARG_STOP:
928 gcc_unreachable ();
931 opc++;
935 switch (opc)
937 case 1:
938 pat = GEN_FCN (icode) (op[0]);
939 break;
941 case 2:
942 pat = GEN_FCN (icode) (op[0], op[1]);
943 break;
945 case 3:
946 pat = GEN_FCN (icode) (op[0], op[1], op[2]);
947 break;
949 case 4:
950 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
951 break;
953 case 5:
954 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
955 break;
957 case 6:
958 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]);
959 break;
961 default:
962 gcc_unreachable ();
965 if (!pat)
966 return NULL_RTX;
968 emit_insn (pat);
970 return target;
973 /* Expand an AArch64 AdvSIMD builtin(intrinsic). */
975 aarch64_simd_expand_builtin (int fcode, tree exp, rtx target)
977 aarch64_simd_builtin_datum *d =
978 &aarch64_simd_builtin_data[fcode - (AARCH64_SIMD_BUILTIN_BASE + 1)];
979 enum insn_code icode = d->code;
980 builtin_simd_arg args[SIMD_MAX_BUILTIN_ARGS];
981 int num_args = insn_data[d->code].n_operands;
982 int is_void = 0;
983 int k;
985 is_void = !!(d->qualifiers[0] & qualifier_void);
987 num_args += is_void;
989 for (k = 1; k < num_args; k++)
991 /* We have four arrays of data, each indexed in a different fashion.
992 qualifiers - element 0 always describes the function return type.
993 operands - element 0 is either the operand for return value (if
994 the function has a non-void return type) or the operand for the
995 first argument.
996 expr_args - element 0 always holds the first argument.
997 args - element 0 is always used for the return type. */
998 int qualifiers_k = k;
999 int operands_k = k - is_void;
1000 int expr_args_k = k - 1;
1002 if (d->qualifiers[qualifiers_k] & qualifier_lane_index)
1003 args[k] = SIMD_ARG_LANE_INDEX;
1004 else if (d->qualifiers[qualifiers_k] & qualifier_immediate)
1005 args[k] = SIMD_ARG_CONSTANT;
1006 else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate)
1008 rtx arg
1009 = expand_normal (CALL_EXPR_ARG (exp,
1010 (expr_args_k)));
1011 /* Handle constants only if the predicate allows it. */
1012 bool op_const_int_p =
1013 (CONST_INT_P (arg)
1014 && (*insn_data[icode].operand[operands_k].predicate)
1015 (arg, insn_data[icode].operand[operands_k].mode));
1016 args[k] = op_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG;
1018 else
1019 args[k] = SIMD_ARG_COPY_TO_REG;
1022 args[k] = SIMD_ARG_STOP;
1024 /* The interface to aarch64_simd_expand_args expects a 0 if
1025 the function is void, and a 1 if it is not. */
1026 return aarch64_simd_expand_args
1027 (target, icode, !is_void, exp, &args[1]);
1031 aarch64_crc32_expand_builtin (int fcode, tree exp, rtx target)
1033 rtx pat;
1034 aarch64_crc_builtin_datum *d
1035 = &aarch64_crc_builtin_data[fcode - (AARCH64_CRC32_BUILTIN_BASE + 1)];
1036 enum insn_code icode = d->icode;
1037 tree arg0 = CALL_EXPR_ARG (exp, 0);
1038 tree arg1 = CALL_EXPR_ARG (exp, 1);
1039 rtx op0 = expand_normal (arg0);
1040 rtx op1 = expand_normal (arg1);
1041 machine_mode tmode = insn_data[icode].operand[0].mode;
1042 machine_mode mode0 = insn_data[icode].operand[1].mode;
1043 machine_mode mode1 = insn_data[icode].operand[2].mode;
1045 if (! target
1046 || GET_MODE (target) != tmode
1047 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1048 target = gen_reg_rtx (tmode);
1050 gcc_assert ((GET_MODE (op0) == mode0 || GET_MODE (op0) == VOIDmode)
1051 && (GET_MODE (op1) == mode1 || GET_MODE (op1) == VOIDmode));
1053 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1054 op0 = copy_to_mode_reg (mode0, op0);
1055 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
1056 op1 = copy_to_mode_reg (mode1, op1);
1058 pat = GEN_FCN (icode) (target, op0, op1);
1059 if (!pat)
1060 return NULL_RTX;
1062 emit_insn (pat);
1063 return target;
1066 /* Expand an expression EXP that calls a built-in function,
1067 with result going to TARGET if that's convenient. */
1069 aarch64_expand_builtin (tree exp,
1070 rtx target,
1071 rtx subtarget ATTRIBUTE_UNUSED,
1072 machine_mode mode ATTRIBUTE_UNUSED,
1073 int ignore ATTRIBUTE_UNUSED)
1075 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
1076 int fcode = DECL_FUNCTION_CODE (fndecl);
1077 int icode;
1078 rtx pat, op0;
1079 tree arg0;
1081 switch (fcode)
1083 case AARCH64_BUILTIN_GET_FPCR:
1084 case AARCH64_BUILTIN_SET_FPCR:
1085 case AARCH64_BUILTIN_GET_FPSR:
1086 case AARCH64_BUILTIN_SET_FPSR:
1087 if ((fcode == AARCH64_BUILTIN_GET_FPCR)
1088 || (fcode == AARCH64_BUILTIN_GET_FPSR))
1090 icode = (fcode == AARCH64_BUILTIN_GET_FPSR) ?
1091 CODE_FOR_get_fpsr : CODE_FOR_get_fpcr;
1092 target = gen_reg_rtx (SImode);
1093 pat = GEN_FCN (icode) (target);
1095 else
1097 target = NULL_RTX;
1098 icode = (fcode == AARCH64_BUILTIN_SET_FPSR) ?
1099 CODE_FOR_set_fpsr : CODE_FOR_set_fpcr;
1100 arg0 = CALL_EXPR_ARG (exp, 0);
1101 op0 = expand_normal (arg0);
1102 pat = GEN_FCN (icode) (op0);
1104 emit_insn (pat);
1105 return target;
1108 if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
1109 return aarch64_simd_expand_builtin (fcode, exp, target);
1110 else if (fcode >= AARCH64_CRC32_BUILTIN_BASE && fcode <= AARCH64_CRC32_BUILTIN_MAX)
1111 return aarch64_crc32_expand_builtin (fcode, exp, target);
1113 gcc_unreachable ();
1116 tree
1117 aarch64_builtin_vectorized_function (tree fndecl, tree type_out, tree type_in)
1119 machine_mode in_mode, out_mode;
1120 int in_n, out_n;
1122 if (TREE_CODE (type_out) != VECTOR_TYPE
1123 || TREE_CODE (type_in) != VECTOR_TYPE)
1124 return NULL_TREE;
1126 out_mode = TYPE_MODE (TREE_TYPE (type_out));
1127 out_n = TYPE_VECTOR_SUBPARTS (type_out);
1128 in_mode = TYPE_MODE (TREE_TYPE (type_in));
1129 in_n = TYPE_VECTOR_SUBPARTS (type_in);
1131 #undef AARCH64_CHECK_BUILTIN_MODE
1132 #define AARCH64_CHECK_BUILTIN_MODE(C, N) 1
1133 #define AARCH64_FIND_FRINT_VARIANT(N) \
1134 (AARCH64_CHECK_BUILTIN_MODE (2, D) \
1135 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2df] \
1136 : (AARCH64_CHECK_BUILTIN_MODE (4, S) \
1137 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v4sf] \
1138 : (AARCH64_CHECK_BUILTIN_MODE (2, S) \
1139 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2sf] \
1140 : NULL_TREE)))
1141 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
1143 enum built_in_function fn = DECL_FUNCTION_CODE (fndecl);
1144 switch (fn)
1146 #undef AARCH64_CHECK_BUILTIN_MODE
1147 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1148 (out_mode == N##Fmode && out_n == C \
1149 && in_mode == N##Fmode && in_n == C)
1150 case BUILT_IN_FLOOR:
1151 case BUILT_IN_FLOORF:
1152 return AARCH64_FIND_FRINT_VARIANT (floor);
1153 case BUILT_IN_CEIL:
1154 case BUILT_IN_CEILF:
1155 return AARCH64_FIND_FRINT_VARIANT (ceil);
1156 case BUILT_IN_TRUNC:
1157 case BUILT_IN_TRUNCF:
1158 return AARCH64_FIND_FRINT_VARIANT (btrunc);
1159 case BUILT_IN_ROUND:
1160 case BUILT_IN_ROUNDF:
1161 return AARCH64_FIND_FRINT_VARIANT (round);
1162 case BUILT_IN_NEARBYINT:
1163 case BUILT_IN_NEARBYINTF:
1164 return AARCH64_FIND_FRINT_VARIANT (nearbyint);
1165 case BUILT_IN_SQRT:
1166 case BUILT_IN_SQRTF:
1167 return AARCH64_FIND_FRINT_VARIANT (sqrt);
1168 #undef AARCH64_CHECK_BUILTIN_MODE
1169 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1170 (out_mode == SImode && out_n == C \
1171 && in_mode == N##Imode && in_n == C)
1172 case BUILT_IN_CLZ:
1174 if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1175 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_clzv4si];
1176 return NULL_TREE;
1178 case BUILT_IN_CTZ:
1180 if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1181 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv2si];
1182 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1183 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv4si];
1184 return NULL_TREE;
1186 #undef AARCH64_CHECK_BUILTIN_MODE
1187 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1188 (out_mode == N##Imode && out_n == C \
1189 && in_mode == N##Fmode && in_n == C)
1190 case BUILT_IN_LFLOOR:
1191 case BUILT_IN_LFLOORF:
1192 case BUILT_IN_LLFLOOR:
1193 case BUILT_IN_IFLOORF:
1195 enum aarch64_builtins builtin;
1196 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1197 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2dfv2di;
1198 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1199 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv4sfv4si;
1200 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1201 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2sfv2si;
1202 else
1203 return NULL_TREE;
1205 return aarch64_builtin_decls[builtin];
1207 case BUILT_IN_LCEIL:
1208 case BUILT_IN_LCEILF:
1209 case BUILT_IN_LLCEIL:
1210 case BUILT_IN_ICEILF:
1212 enum aarch64_builtins builtin;
1213 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1214 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2dfv2di;
1215 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1216 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv4sfv4si;
1217 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1218 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2sfv2si;
1219 else
1220 return NULL_TREE;
1222 return aarch64_builtin_decls[builtin];
1224 case BUILT_IN_LROUND:
1225 case BUILT_IN_IROUNDF:
1227 enum aarch64_builtins builtin;
1228 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1229 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2dfv2di;
1230 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1231 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv4sfv4si;
1232 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1233 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2sfv2si;
1234 else
1235 return NULL_TREE;
1237 return aarch64_builtin_decls[builtin];
1239 case BUILT_IN_BSWAP16:
1240 #undef AARCH64_CHECK_BUILTIN_MODE
1241 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1242 (out_mode == N##Imode && out_n == C \
1243 && in_mode == N##Imode && in_n == C)
1244 if (AARCH64_CHECK_BUILTIN_MODE (4, H))
1245 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4hi];
1246 else if (AARCH64_CHECK_BUILTIN_MODE (8, H))
1247 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv8hi];
1248 else
1249 return NULL_TREE;
1250 case BUILT_IN_BSWAP32:
1251 if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1252 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2si];
1253 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1254 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4si];
1255 else
1256 return NULL_TREE;
1257 case BUILT_IN_BSWAP64:
1258 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1259 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2di];
1260 else
1261 return NULL_TREE;
1262 default:
1263 return NULL_TREE;
1267 return NULL_TREE;
1270 #undef VAR1
1271 #define VAR1(T, N, MAP, A) \
1272 case AARCH64_SIMD_BUILTIN_##T##_##N##A:
1274 tree
1275 aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args,
1276 bool ignore ATTRIBUTE_UNUSED)
1278 int fcode = DECL_FUNCTION_CODE (fndecl);
1279 tree type = TREE_TYPE (TREE_TYPE (fndecl));
1281 switch (fcode)
1283 BUILTIN_VDQF (UNOP, abs, 2)
1284 return fold_build1 (ABS_EXPR, type, args[0]);
1285 break;
1286 VAR1 (UNOP, floatv2si, 2, v2sf)
1287 VAR1 (UNOP, floatv4si, 2, v4sf)
1288 VAR1 (UNOP, floatv2di, 2, v2df)
1289 return fold_build1 (FLOAT_EXPR, type, args[0]);
1290 default:
1291 break;
1294 return NULL_TREE;
1297 bool
1298 aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi)
1300 bool changed = false;
1301 gimple stmt = gsi_stmt (*gsi);
1302 tree call = gimple_call_fn (stmt);
1303 tree fndecl;
1304 gimple new_stmt = NULL;
1306 if (call)
1308 fndecl = gimple_call_fndecl (stmt);
1309 if (fndecl)
1311 int fcode = DECL_FUNCTION_CODE (fndecl);
1312 int nargs = gimple_call_num_args (stmt);
1313 tree *args = (nargs > 0
1314 ? gimple_call_arg_ptr (stmt, 0)
1315 : &error_mark_node);
1317 /* We use gimple's REDUC_(PLUS|MIN|MAX)_EXPRs for float, signed int
1318 and unsigned int; it will distinguish according to the types of
1319 the arguments to the __builtin. */
1320 switch (fcode)
1322 BUILTIN_VALL (UNOP, reduc_plus_scal_, 10)
1323 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
1324 REDUC_PLUS_EXPR, args[0]);
1325 break;
1326 BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10)
1327 BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10)
1328 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
1329 REDUC_MAX_EXPR, args[0]);
1330 break;
1331 BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10)
1332 BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10)
1333 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
1334 REDUC_MIN_EXPR, args[0]);
1335 break;
1337 default:
1338 break;
1343 if (new_stmt)
1345 gsi_replace (gsi, new_stmt, true);
1346 changed = true;
1349 return changed;
1352 void
1353 aarch64_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
1355 const unsigned AARCH64_FE_INVALID = 1;
1356 const unsigned AARCH64_FE_DIVBYZERO = 2;
1357 const unsigned AARCH64_FE_OVERFLOW = 4;
1358 const unsigned AARCH64_FE_UNDERFLOW = 8;
1359 const unsigned AARCH64_FE_INEXACT = 16;
1360 const unsigned HOST_WIDE_INT AARCH64_FE_ALL_EXCEPT = (AARCH64_FE_INVALID
1361 | AARCH64_FE_DIVBYZERO
1362 | AARCH64_FE_OVERFLOW
1363 | AARCH64_FE_UNDERFLOW
1364 | AARCH64_FE_INEXACT);
1365 const unsigned HOST_WIDE_INT AARCH64_FE_EXCEPT_SHIFT = 8;
1366 tree fenv_cr, fenv_sr, get_fpcr, set_fpcr, mask_cr, mask_sr;
1367 tree ld_fenv_cr, ld_fenv_sr, masked_fenv_cr, masked_fenv_sr, hold_fnclex_cr;
1368 tree hold_fnclex_sr, new_fenv_var, reload_fenv, restore_fnenv, get_fpsr, set_fpsr;
1369 tree update_call, atomic_feraiseexcept, hold_fnclex, masked_fenv, ld_fenv;
1371 /* Generate the equivalence of :
1372 unsigned int fenv_cr;
1373 fenv_cr = __builtin_aarch64_get_fpcr ();
1375 unsigned int fenv_sr;
1376 fenv_sr = __builtin_aarch64_get_fpsr ();
1378 Now set all exceptions to non-stop
1379 unsigned int mask_cr
1380 = ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT);
1381 unsigned int masked_cr;
1382 masked_cr = fenv_cr & mask_cr;
1384 And clear all exception flags
1385 unsigned int maske_sr = ~AARCH64_FE_ALL_EXCEPT;
1386 unsigned int masked_cr;
1387 masked_sr = fenv_sr & mask_sr;
1389 __builtin_aarch64_set_cr (masked_cr);
1390 __builtin_aarch64_set_sr (masked_sr); */
1392 fenv_cr = create_tmp_var (unsigned_type_node);
1393 fenv_sr = create_tmp_var (unsigned_type_node);
1395 get_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR];
1396 set_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR];
1397 get_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR];
1398 set_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR];
1400 mask_cr = build_int_cst (unsigned_type_node,
1401 ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT));
1402 mask_sr = build_int_cst (unsigned_type_node,
1403 ~(AARCH64_FE_ALL_EXCEPT));
1405 ld_fenv_cr = build2 (MODIFY_EXPR, unsigned_type_node,
1406 fenv_cr, build_call_expr (get_fpcr, 0));
1407 ld_fenv_sr = build2 (MODIFY_EXPR, unsigned_type_node,
1408 fenv_sr, build_call_expr (get_fpsr, 0));
1410 masked_fenv_cr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_cr, mask_cr);
1411 masked_fenv_sr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_sr, mask_sr);
1413 hold_fnclex_cr = build_call_expr (set_fpcr, 1, masked_fenv_cr);
1414 hold_fnclex_sr = build_call_expr (set_fpsr, 1, masked_fenv_sr);
1416 hold_fnclex = build2 (COMPOUND_EXPR, void_type_node, hold_fnclex_cr,
1417 hold_fnclex_sr);
1418 masked_fenv = build2 (COMPOUND_EXPR, void_type_node, masked_fenv_cr,
1419 masked_fenv_sr);
1420 ld_fenv = build2 (COMPOUND_EXPR, void_type_node, ld_fenv_cr, ld_fenv_sr);
1422 *hold = build2 (COMPOUND_EXPR, void_type_node,
1423 build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv),
1424 hold_fnclex);
1426 /* Store the value of masked_fenv to clear the exceptions:
1427 __builtin_aarch64_set_fpsr (masked_fenv_sr); */
1429 *clear = build_call_expr (set_fpsr, 1, masked_fenv_sr);
1431 /* Generate the equivalent of :
1432 unsigned int new_fenv_var;
1433 new_fenv_var = __builtin_aarch64_get_fpsr ();
1435 __builtin_aarch64_set_fpsr (fenv_sr);
1437 __atomic_feraiseexcept (new_fenv_var); */
1439 new_fenv_var = create_tmp_var (unsigned_type_node);
1440 reload_fenv = build2 (MODIFY_EXPR, unsigned_type_node,
1441 new_fenv_var, build_call_expr (get_fpsr, 0));
1442 restore_fnenv = build_call_expr (set_fpsr, 1, fenv_sr);
1443 atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT);
1444 update_call = build_call_expr (atomic_feraiseexcept, 1,
1445 fold_convert (integer_type_node, new_fenv_var));
1446 *update = build2 (COMPOUND_EXPR, void_type_node,
1447 build2 (COMPOUND_EXPR, void_type_node,
1448 reload_fenv, restore_fnenv), update_call);
1452 #undef AARCH64_CHECK_BUILTIN_MODE
1453 #undef AARCH64_FIND_FRINT_VARIANT
1454 #undef CF0
1455 #undef CF1
1456 #undef CF2
1457 #undef CF3
1458 #undef CF4
1459 #undef CF10
1460 #undef VAR1
1461 #undef VAR2
1462 #undef VAR3
1463 #undef VAR4
1464 #undef VAR5
1465 #undef VAR6
1466 #undef VAR7
1467 #undef VAR8
1468 #undef VAR9
1469 #undef VAR10
1470 #undef VAR11
1472 #include "gt-aarch64-builtins.h"