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