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