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