]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/aarch64/aarch64-builtins.c
lto-wrapper: fix memory corruption.
[thirdparty/gcc.git] / gcc / config / aarch64 / aarch64-builtins.c
CommitLineData
43e9d192 1/* Builtins' description for AArch64 SIMD architecture.
99dee823 2 Copyright (C) 2011-2021 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
8fcc61f8
RS
21#define IN_TARGET_CODE 1
22
43e9d192
IB
23#include "config.h"
24#include "system.h"
25#include "coretypes.h"
26#include "tm.h"
c7131fb2 27#include "function.h"
c7131fb2 28#include "basic-block.h"
e11c4407 29#include "rtl.h"
c7131fb2
AM
30#include "tree.h"
31#include "gimple.h"
03312cbd 32#include "ssa.h"
4d0cdd0c 33#include "memmodel.h"
e11c4407
AM
34#include "tm_p.h"
35#include "expmed.h"
36#include "optabs.h"
37#include "recog.h"
38#include "diagnostic-core.h"
40e23961 39#include "fold-const.h"
d8a2d370 40#include "stor-layout.h"
36566b39 41#include "explow.h"
43e9d192 42#include "expr.h"
43e9d192 43#include "langhooks.h"
5be5c238 44#include "gimple-iterator.h"
10766209 45#include "case-cfn-macros.h"
9d63f43b 46#include "emit-rtl.h"
31427b97
RS
47#include "stringpool.h"
48#include "attribs.h"
ad44c6a5 49#include "gimple-fold.h"
43e9d192 50
0d4a1197
RS
51#define v8qi_UP E_V8QImode
52#define v4hi_UP E_V4HImode
53#define v4hf_UP E_V4HFmode
54#define v2si_UP E_V2SImode
55#define v2sf_UP E_V2SFmode
56#define v1df_UP E_V1DFmode
57#define di_UP E_DImode
58#define df_UP E_DFmode
59#define v16qi_UP E_V16QImode
60#define v8hi_UP E_V8HImode
61#define v8hf_UP E_V8HFmode
62#define v4si_UP E_V4SImode
63#define v4sf_UP E_V4SFmode
64#define v2di_UP E_V2DImode
65#define v2df_UP E_V2DFmode
66#define ti_UP E_TImode
67#define oi_UP E_OImode
68#define ci_UP E_CImode
69#define xi_UP E_XImode
70#define si_UP E_SImode
71#define sf_UP E_SFmode
72#define hi_UP E_HImode
73#define hf_UP E_HFmode
74#define qi_UP E_QImode
abbe1ed2
SMW
75#define bf_UP E_BFmode
76#define v4bf_UP E_V4BFmode
77#define v8bf_UP E_V8BFmode
66f206b8
JW
78#define v2x8qi_UP E_V2x8QImode
79#define v2x4hi_UP E_V2x4HImode
80#define v2x4hf_UP E_V2x4HFmode
81#define v2x4bf_UP E_V2x4BFmode
82#define v2x2si_UP E_V2x2SImode
83#define v2x2sf_UP E_V2x2SFmode
84#define v2x1di_UP E_V2x1DImode
85#define v2x1df_UP E_V2x1DFmode
86#define v2x16qi_UP E_V2x16QImode
87#define v2x8hi_UP E_V2x8HImode
88#define v2x8hf_UP E_V2x8HFmode
89#define v2x8bf_UP E_V2x8BFmode
90#define v2x4si_UP E_V2x4SImode
91#define v2x4sf_UP E_V2x4SFmode
92#define v2x2di_UP E_V2x2DImode
93#define v2x2df_UP E_V2x2DFmode
94#define v3x8qi_UP E_V3x8QImode
95#define v3x4hi_UP E_V3x4HImode
96#define v3x4hf_UP E_V3x4HFmode
97#define v3x4bf_UP E_V3x4BFmode
98#define v3x2si_UP E_V3x2SImode
99#define v3x2sf_UP E_V3x2SFmode
100#define v3x1di_UP E_V3x1DImode
101#define v3x1df_UP E_V3x1DFmode
102#define v3x16qi_UP E_V3x16QImode
103#define v3x8hi_UP E_V3x8HImode
104#define v3x8hf_UP E_V3x8HFmode
105#define v3x8bf_UP E_V3x8BFmode
106#define v3x4si_UP E_V3x4SImode
107#define v3x4sf_UP E_V3x4SFmode
108#define v3x2di_UP E_V3x2DImode
109#define v3x2df_UP E_V3x2DFmode
110#define v4x8qi_UP E_V4x8QImode
111#define v4x4hi_UP E_V4x4HImode
112#define v4x4hf_UP E_V4x4HFmode
113#define v4x4bf_UP E_V4x4BFmode
114#define v4x2si_UP E_V4x2SImode
115#define v4x2sf_UP E_V4x2SFmode
116#define v4x1di_UP E_V4x1DImode
117#define v4x1df_UP E_V4x1DFmode
118#define v4x16qi_UP E_V4x16QImode
119#define v4x8hi_UP E_V4x8HImode
120#define v4x8hf_UP E_V4x8HFmode
121#define v4x8bf_UP E_V4x8BFmode
122#define v4x4si_UP E_V4x4SImode
123#define v4x4sf_UP E_V4x4SFmode
124#define v4x2di_UP E_V4x2DImode
125#define v4x2df_UP E_V4x2DFmode
43e9d192
IB
126#define UP(X) X##_UP
127
b5828b4b
JG
128#define SIMD_MAX_BUILTIN_ARGS 5
129
130enum aarch64_type_qualifiers
43e9d192 131{
b5828b4b
JG
132 /* T foo. */
133 qualifier_none = 0x0,
134 /* unsigned T foo. */
135 qualifier_unsigned = 0x1, /* 1 << 0 */
136 /* const T foo. */
137 qualifier_const = 0x2, /* 1 << 1 */
138 /* T *foo. */
139 qualifier_pointer = 0x4, /* 1 << 2 */
b5828b4b
JG
140 /* Used when expanding arguments if an operand could
141 be an immediate. */
142 qualifier_immediate = 0x8, /* 1 << 3 */
143 qualifier_maybe_immediate = 0x10, /* 1 << 4 */
144 /* void foo (...). */
145 qualifier_void = 0x20, /* 1 << 5 */
146 /* Some patterns may have internal operands, this qualifier is an
147 instruction to the initialisation code to skip this operand. */
148 qualifier_internal = 0x40, /* 1 << 6 */
149 /* Some builtins should use the T_*mode* encoded in a simd_builtin_datum
150 rather than using the type of the operand. */
151 qualifier_map_mode = 0x80, /* 1 << 7 */
152 /* qualifier_pointer | qualifier_map_mode */
153 qualifier_pointer_map_mode = 0x84,
e625e715 154 /* qualifier_const | qualifier_pointer | qualifier_map_mode */
6db1ec94
JG
155 qualifier_const_pointer_map_mode = 0x86,
156 /* Polynomial types. */
2a49c16d
AL
157 qualifier_poly = 0x100,
158 /* Lane indices - must be in range, and flipped for bigendian. */
4d0a0237
CB
159 qualifier_lane_index = 0x200,
160 /* Lane indices for single lane structure loads and stores. */
9d63f43b
TC
161 qualifier_struct_load_store_lane_index = 0x400,
162 /* Lane indices selected in pairs. - must be in range, and flipped for
163 bigendian. */
164 qualifier_lane_pair_index = 0x800,
8c197c85
SMW
165 /* Lane indices selected in quadtuplets. - must be in range, and flipped for
166 bigendian. */
167 qualifier_lane_quadtup_index = 0x1000,
b5828b4b 168};
43e9d192 169
bf592b2f 170/* Flags that describe what a function might do. */
171const unsigned int FLAG_NONE = 0U;
172const unsigned int FLAG_READ_FPCR = 1U << 0;
173const unsigned int FLAG_RAISE_FP_EXCEPTIONS = 1U << 1;
174const unsigned int FLAG_READ_MEMORY = 1U << 2;
175const unsigned int FLAG_PREFETCH_MEMORY = 1U << 3;
176const unsigned int FLAG_WRITE_MEMORY = 1U << 4;
177
35ffd4d1 178/* Not all FP intrinsics raise FP exceptions or read FPCR register,
179 use this flag to suppress it. */
180const unsigned int FLAG_AUTO_FP = 1U << 5;
181
bf592b2f 182const unsigned int FLAG_FP = FLAG_READ_FPCR | FLAG_RAISE_FP_EXCEPTIONS;
183const unsigned int FLAG_ALL = FLAG_READ_FPCR | FLAG_RAISE_FP_EXCEPTIONS
184 | FLAG_READ_MEMORY | FLAG_PREFETCH_MEMORY | FLAG_WRITE_MEMORY;
2d5aad69 185const unsigned int FLAG_STORE = FLAG_WRITE_MEMORY | FLAG_AUTO_FP;
e8062ad4 186const unsigned int FLAG_LOAD = FLAG_READ_MEMORY | FLAG_AUTO_FP;
bf592b2f 187
43e9d192
IB
188typedef struct
189{
190 const char *name;
ef4bddc2 191 machine_mode mode;
342be7f7
JG
192 const enum insn_code code;
193 unsigned int fcode;
b5828b4b 194 enum aarch64_type_qualifiers *qualifiers;
bf592b2f 195 unsigned int flags;
43e9d192
IB
196} aarch64_simd_builtin_datum;
197
b5828b4b
JG
198static enum aarch64_type_qualifiers
199aarch64_types_unop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
8f905d69 200 = { qualifier_none, qualifier_none };
b5828b4b 201#define TYPES_UNOP (aarch64_types_unop_qualifiers)
5a7a4e80
TB
202static enum aarch64_type_qualifiers
203aarch64_types_unopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
204 = { qualifier_unsigned, qualifier_unsigned };
205#define TYPES_UNOPU (aarch64_types_unopu_qualifiers)
b5828b4b 206static enum aarch64_type_qualifiers
a579f4c7
JW
207aarch64_types_unopus_qualifiers[SIMD_MAX_BUILTIN_ARGS]
208 = { qualifier_unsigned, qualifier_none };
209#define TYPES_UNOPUS (aarch64_types_unopus_qualifiers)
210static enum aarch64_type_qualifiers
b5828b4b
JG
211aarch64_types_binop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
212 = { qualifier_none, qualifier_none, qualifier_maybe_immediate };
213#define TYPES_BINOP (aarch64_types_binop_qualifiers)
214static enum aarch64_type_qualifiers
5a7a4e80
TB
215aarch64_types_binopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
216 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned };
217#define TYPES_BINOPU (aarch64_types_binopu_qualifiers)
7baa225d 218static enum aarch64_type_qualifiers
de10bcce
AL
219aarch64_types_binop_uus_qualifiers[SIMD_MAX_BUILTIN_ARGS]
220 = { qualifier_unsigned, qualifier_unsigned, qualifier_none };
221#define TYPES_BINOP_UUS (aarch64_types_binop_uus_qualifiers)
222static enum aarch64_type_qualifiers
918621d3
AL
223aarch64_types_binop_ssu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
224 = { qualifier_none, qualifier_none, qualifier_unsigned };
225#define TYPES_BINOP_SSU (aarch64_types_binop_ssu_qualifiers)
226static enum aarch64_type_qualifiers
daef0a8c
JW
227aarch64_types_binop_uss_qualifiers[SIMD_MAX_BUILTIN_ARGS]
228 = { qualifier_unsigned, qualifier_none, qualifier_none };
229#define TYPES_BINOP_USS (aarch64_types_binop_uss_qualifiers)
230static enum aarch64_type_qualifiers
7baa225d
TB
231aarch64_types_binopp_qualifiers[SIMD_MAX_BUILTIN_ARGS]
232 = { qualifier_poly, qualifier_poly, qualifier_poly };
233#define TYPES_BINOPP (aarch64_types_binopp_qualifiers)
3caf7f87
JW
234static enum aarch64_type_qualifiers
235aarch64_types_binop_ppu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
236 = { qualifier_poly, qualifier_poly, qualifier_unsigned };
237#define TYPES_BINOP_PPU (aarch64_types_binop_ppu_qualifiers)
7baa225d 238
5a7a4e80 239static enum aarch64_type_qualifiers
b5828b4b
JG
240aarch64_types_ternop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
241 = { qualifier_none, qualifier_none, qualifier_none, qualifier_none };
242#define TYPES_TERNOP (aarch64_types_ternop_qualifiers)
30442682 243static enum aarch64_type_qualifiers
2a49c16d
AL
244aarch64_types_ternop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
245 = { qualifier_none, qualifier_none, qualifier_none, qualifier_lane_index };
246#define TYPES_TERNOP_LANE (aarch64_types_ternop_lane_qualifiers)
247static enum aarch64_type_qualifiers
30442682
TB
248aarch64_types_ternopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
249 = { qualifier_unsigned, qualifier_unsigned,
250 qualifier_unsigned, qualifier_unsigned };
251#define TYPES_TERNOPU (aarch64_types_ternopu_qualifiers)
27086ea3 252static enum aarch64_type_qualifiers
0b839322
WD
253aarch64_types_ternopu_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
254 = { qualifier_unsigned, qualifier_unsigned,
255 qualifier_unsigned, qualifier_lane_index };
256#define TYPES_TERNOPU_LANE (aarch64_types_ternopu_lane_qualifiers)
257static enum aarch64_type_qualifiers
27086ea3
MC
258aarch64_types_ternopu_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
259 = { qualifier_unsigned, qualifier_unsigned,
260 qualifier_unsigned, qualifier_immediate };
261#define TYPES_TERNOPUI (aarch64_types_ternopu_imm_qualifiers)
8c197c85 262static enum aarch64_type_qualifiers
3caf7f87
JW
263aarch64_types_ternop_sssu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
264 = { qualifier_none, qualifier_none, qualifier_none, qualifier_unsigned };
265#define TYPES_TERNOP_SSSU (aarch64_types_ternop_sssu_qualifiers)
266static enum aarch64_type_qualifiers
8c197c85
SMW
267aarch64_types_ternop_ssus_qualifiers[SIMD_MAX_BUILTIN_ARGS]
268 = { qualifier_none, qualifier_none, qualifier_unsigned, qualifier_none };
269#define TYPES_TERNOP_SSUS (aarch64_types_ternop_ssus_qualifiers)
2050ac1a
TC
270static enum aarch64_type_qualifiers
271aarch64_types_ternop_suss_qualifiers[SIMD_MAX_BUILTIN_ARGS]
272 = { qualifier_none, qualifier_unsigned, qualifier_none, qualifier_none };
273#define TYPES_TERNOP_SUSS (aarch64_types_ternop_suss_qualifiers)
3caf7f87
JW
274static enum aarch64_type_qualifiers
275aarch64_types_binop_pppu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
276 = { qualifier_poly, qualifier_poly, qualifier_poly, qualifier_unsigned };
277#define TYPES_TERNOP_PPPU (aarch64_types_binop_pppu_qualifiers)
27086ea3 278
9d63f43b
TC
279static enum aarch64_type_qualifiers
280aarch64_types_quadop_lane_pair_qualifiers[SIMD_MAX_BUILTIN_ARGS]
281 = { qualifier_none, qualifier_none, qualifier_none,
282 qualifier_none, qualifier_lane_pair_index };
283#define TYPES_QUADOP_LANE_PAIR (aarch64_types_quadop_lane_pair_qualifiers)
b5828b4b 284static enum aarch64_type_qualifiers
2a49c16d 285aarch64_types_quadop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
b5828b4b 286 = { qualifier_none, qualifier_none, qualifier_none,
2a49c16d
AL
287 qualifier_none, qualifier_lane_index };
288#define TYPES_QUADOP_LANE (aarch64_types_quadop_lane_qualifiers)
7a08d813
TC
289static enum aarch64_type_qualifiers
290aarch64_types_quadopu_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
291 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
292 qualifier_unsigned, qualifier_lane_index };
293#define TYPES_QUADOPU_LANE (aarch64_types_quadopu_lane_qualifiers)
b5828b4b 294
8c197c85
SMW
295static enum aarch64_type_qualifiers
296aarch64_types_quadopssus_lane_quadtup_qualifiers[SIMD_MAX_BUILTIN_ARGS]
297 = { qualifier_none, qualifier_none, qualifier_unsigned,
298 qualifier_none, qualifier_lane_quadtup_index };
299#define TYPES_QUADOPSSUS_LANE_QUADTUP \
300 (aarch64_types_quadopssus_lane_quadtup_qualifiers)
301static enum aarch64_type_qualifiers
302aarch64_types_quadopsssu_lane_quadtup_qualifiers[SIMD_MAX_BUILTIN_ARGS]
303 = { qualifier_none, qualifier_none, qualifier_none,
304 qualifier_unsigned, qualifier_lane_quadtup_index };
305#define TYPES_QUADOPSSSU_LANE_QUADTUP \
306 (aarch64_types_quadopsssu_lane_quadtup_qualifiers)
307
27086ea3
MC
308static enum aarch64_type_qualifiers
309aarch64_types_quadopu_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
310 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
311 qualifier_unsigned, qualifier_immediate };
312#define TYPES_QUADOPUI (aarch64_types_quadopu_imm_qualifiers)
313
b5828b4b 314static enum aarch64_type_qualifiers
2a49c16d 315aarch64_types_binop_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
b5828b4b 316 = { qualifier_none, qualifier_none, qualifier_immediate };
2a49c16d
AL
317#define TYPES_GETREG (aarch64_types_binop_imm_qualifiers)
318#define TYPES_SHIFTIMM (aarch64_types_binop_imm_qualifiers)
b5828b4b 319static enum aarch64_type_qualifiers
de10bcce
AL
320aarch64_types_shift_to_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS]
321 = { qualifier_unsigned, qualifier_none, qualifier_immediate };
322#define TYPES_SHIFTIMM_USS (aarch64_types_shift_to_unsigned_qualifiers)
323static enum aarch64_type_qualifiers
1f0e9e34
JG
324aarch64_types_fcvt_from_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS]
325 = { qualifier_none, qualifier_unsigned, qualifier_immediate };
326#define TYPES_FCVTIMM_SUS (aarch64_types_fcvt_from_unsigned_qualifiers)
327static enum aarch64_type_qualifiers
252c7556
AV
328aarch64_types_unsigned_shift_qualifiers[SIMD_MAX_BUILTIN_ARGS]
329 = { qualifier_unsigned, qualifier_unsigned, qualifier_immediate };
330#define TYPES_USHIFTIMM (aarch64_types_unsigned_shift_qualifiers)
05f1883c
DC
331#define TYPES_USHIFT2IMM (aarch64_types_ternopu_imm_qualifiers)
332static enum aarch64_type_qualifiers
333aarch64_types_shift2_to_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS]
334 = { qualifier_unsigned, qualifier_unsigned, qualifier_none, qualifier_immediate };
335#define TYPES_SHIFT2IMM_UUSS (aarch64_types_shift2_to_unsigned_qualifiers)
de10bcce 336
159b8724
TC
337static enum aarch64_type_qualifiers
338aarch64_types_ternop_s_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
339 = { qualifier_none, qualifier_none, qualifier_none, qualifier_immediate};
340#define TYPES_SETREG (aarch64_types_ternop_s_imm_qualifiers)
341#define TYPES_SHIFTINSERT (aarch64_types_ternop_s_imm_qualifiers)
342#define TYPES_SHIFTACC (aarch64_types_ternop_s_imm_qualifiers)
05f1883c 343#define TYPES_SHIFT2IMM (aarch64_types_ternop_s_imm_qualifiers)
159b8724
TC
344
345static enum aarch64_type_qualifiers
346aarch64_types_ternop_p_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
347 = { qualifier_poly, qualifier_poly, qualifier_poly, qualifier_immediate};
348#define TYPES_SHIFTINSERTP (aarch64_types_ternop_p_imm_qualifiers)
b5828b4b 349
de10bcce
AL
350static enum aarch64_type_qualifiers
351aarch64_types_unsigned_shiftacc_qualifiers[SIMD_MAX_BUILTIN_ARGS]
352 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
353 qualifier_immediate };
354#define TYPES_USHIFTACC (aarch64_types_unsigned_shiftacc_qualifiers)
355
356
b5828b4b
JG
357static enum aarch64_type_qualifiers
358aarch64_types_combine_qualifiers[SIMD_MAX_BUILTIN_ARGS]
359 = { qualifier_none, qualifier_none, qualifier_none };
360#define TYPES_COMBINE (aarch64_types_combine_qualifiers)
361
159b8724
TC
362static enum aarch64_type_qualifiers
363aarch64_types_combine_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
364 = { qualifier_poly, qualifier_poly, qualifier_poly };
365#define TYPES_COMBINEP (aarch64_types_combine_p_qualifiers)
366
b5828b4b
JG
367static enum aarch64_type_qualifiers
368aarch64_types_load1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
369 = { qualifier_none, qualifier_const_pointer_map_mode };
370#define TYPES_LOAD1 (aarch64_types_load1_qualifiers)
371#define TYPES_LOADSTRUCT (aarch64_types_load1_qualifiers)
66f206b8
JW
372static enum aarch64_type_qualifiers
373aarch64_types_load1_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
374 = { qualifier_unsigned, qualifier_const_pointer_map_mode };
375#define TYPES_LOADSTRUCT_U (aarch64_types_load1_u_qualifiers)
376static enum aarch64_type_qualifiers
377aarch64_types_load1_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
378 = { qualifier_poly, qualifier_const_pointer_map_mode };
379#define TYPES_LOADSTRUCT_P (aarch64_types_load1_p_qualifiers)
380
3ec1be97
CB
381static enum aarch64_type_qualifiers
382aarch64_types_loadstruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
383 = { qualifier_none, qualifier_const_pointer_map_mode,
4d0a0237 384 qualifier_none, qualifier_struct_load_store_lane_index };
3ec1be97 385#define TYPES_LOADSTRUCT_LANE (aarch64_types_loadstruct_lane_qualifiers)
66f206b8
JW
386static enum aarch64_type_qualifiers
387aarch64_types_loadstruct_lane_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
388 = { qualifier_unsigned, qualifier_const_pointer_map_mode,
389 qualifier_unsigned, qualifier_struct_load_store_lane_index };
390#define TYPES_LOADSTRUCT_LANE_U (aarch64_types_loadstruct_lane_u_qualifiers)
391static enum aarch64_type_qualifiers
392aarch64_types_loadstruct_lane_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
393 = { qualifier_poly, qualifier_const_pointer_map_mode,
394 qualifier_poly, qualifier_struct_load_store_lane_index };
395#define TYPES_LOADSTRUCT_LANE_P (aarch64_types_loadstruct_lane_p_qualifiers)
b5828b4b 396
46e778c4
JG
397static enum aarch64_type_qualifiers
398aarch64_types_bsl_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
399 = { qualifier_poly, qualifier_unsigned,
400 qualifier_poly, qualifier_poly };
401#define TYPES_BSL_P (aarch64_types_bsl_p_qualifiers)
402static enum aarch64_type_qualifiers
403aarch64_types_bsl_s_qualifiers[SIMD_MAX_BUILTIN_ARGS]
404 = { qualifier_none, qualifier_unsigned,
405 qualifier_none, qualifier_none };
406#define TYPES_BSL_S (aarch64_types_bsl_s_qualifiers)
407static enum aarch64_type_qualifiers
408aarch64_types_bsl_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
409 = { qualifier_unsigned, qualifier_unsigned,
410 qualifier_unsigned, qualifier_unsigned };
411#define TYPES_BSL_U (aarch64_types_bsl_u_qualifiers)
412
b5828b4b
JG
413/* The first argument (return type) of a store should be void type,
414 which we represent with qualifier_void. Their first operand will be
415 a DImode pointer to the location to store to, so we must use
416 qualifier_map_mode | qualifier_pointer to build a pointer to the
417 element type of the vector. */
418static enum aarch64_type_qualifiers
419aarch64_types_store1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
420 = { qualifier_void, qualifier_pointer_map_mode, qualifier_none };
421#define TYPES_STORE1 (aarch64_types_store1_qualifiers)
422#define TYPES_STORESTRUCT (aarch64_types_store1_qualifiers)
66f206b8
JW
423static enum aarch64_type_qualifiers
424aarch64_types_store1_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
425 = { qualifier_void, qualifier_pointer_map_mode, qualifier_unsigned };
426#define TYPES_STORESTRUCT_U (aarch64_types_store1_u_qualifiers)
427static enum aarch64_type_qualifiers
428aarch64_types_store1_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
429 = { qualifier_void, qualifier_pointer_map_mode, qualifier_poly };
430#define TYPES_STORE1P (aarch64_types_store1_p_qualifiers)
431#define TYPES_STORESTRUCT_P (aarch64_types_store1_p_qualifiers)
432
ba081b77
JG
433static enum aarch64_type_qualifiers
434aarch64_types_storestruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
435 = { qualifier_void, qualifier_pointer_map_mode,
4d0a0237 436 qualifier_none, qualifier_struct_load_store_lane_index };
ba081b77 437#define TYPES_STORESTRUCT_LANE (aarch64_types_storestruct_lane_qualifiers)
66f206b8
JW
438static enum aarch64_type_qualifiers
439aarch64_types_storestruct_lane_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
440 = { qualifier_void, qualifier_pointer_map_mode,
441 qualifier_unsigned, qualifier_struct_load_store_lane_index };
442#define TYPES_STORESTRUCT_LANE_U (aarch64_types_storestruct_lane_u_qualifiers)
443static enum aarch64_type_qualifiers
444aarch64_types_storestruct_lane_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
445 = { qualifier_void, qualifier_pointer_map_mode,
446 qualifier_poly, qualifier_struct_load_store_lane_index };
447#define TYPES_STORESTRUCT_LANE_P (aarch64_types_storestruct_lane_p_qualifiers)
b5828b4b 448
0ddec79f
JG
449#define CF0(N, X) CODE_FOR_aarch64_##N##X
450#define CF1(N, X) CODE_FOR_##N##X##1
451#define CF2(N, X) CODE_FOR_##N##X##2
452#define CF3(N, X) CODE_FOR_##N##X##3
453#define CF4(N, X) CODE_FOR_##N##X##4
454#define CF10(N, X) CODE_FOR_##N##X
455
bf592b2f 456#define VAR1(T, N, MAP, FLAG, A) \
457 {#N #A, UP (A), CF##MAP (N, A), 0, TYPES_##T, FLAG_##FLAG},
458#define VAR2(T, N, MAP, FLAG, A, B) \
459 VAR1 (T, N, MAP, FLAG, A) \
460 VAR1 (T, N, MAP, FLAG, B)
461#define VAR3(T, N, MAP, FLAG, A, B, C) \
462 VAR2 (T, N, MAP, FLAG, A, B) \
463 VAR1 (T, N, MAP, FLAG, C)
464#define VAR4(T, N, MAP, FLAG, A, B, C, D) \
465 VAR3 (T, N, MAP, FLAG, A, B, C) \
466 VAR1 (T, N, MAP, FLAG, D)
467#define VAR5(T, N, MAP, FLAG, A, B, C, D, E) \
468 VAR4 (T, N, MAP, FLAG, A, B, C, D) \
469 VAR1 (T, N, MAP, FLAG, E)
470#define VAR6(T, N, MAP, FLAG, A, B, C, D, E, F) \
471 VAR5 (T, N, MAP, FLAG, A, B, C, D, E) \
472 VAR1 (T, N, MAP, FLAG, F)
473#define VAR7(T, N, MAP, FLAG, A, B, C, D, E, F, G) \
474 VAR6 (T, N, MAP, FLAG, A, B, C, D, E, F) \
475 VAR1 (T, N, MAP, FLAG, G)
476#define VAR8(T, N, MAP, FLAG, A, B, C, D, E, F, G, H) \
477 VAR7 (T, N, MAP, FLAG, A, B, C, D, E, F, G) \
478 VAR1 (T, N, MAP, FLAG, H)
479#define VAR9(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I) \
480 VAR8 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H) \
481 VAR1 (T, N, MAP, FLAG, I)
482#define VAR10(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J) \
483 VAR9 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I) \
484 VAR1 (T, N, MAP, FLAG, J)
485#define VAR11(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K) \
486 VAR10 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J) \
487 VAR1 (T, N, MAP, FLAG, K)
488#define VAR12(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L) \
489 VAR11 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K) \
490 VAR1 (T, N, MAP, FLAG, L)
491#define VAR13(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M) \
492 VAR12 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L) \
493 VAR1 (T, N, MAP, FLAG, M)
494#define VAR14(T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N) \
495 VAR13 (T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M) \
496 VAR1 (T, X, MAP, FLAG, N)
497#define VAR15(T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) \
498 VAR14 (T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N) \
499 VAR1 (T, X, MAP, FLAG, O)
500#define VAR16(T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) \
501 VAR15 (T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) \
502 VAR1 (T, X, MAP, FLAG, P)
342be7f7 503
f421c516 504#include "aarch64-builtin-iterators.h"
43e9d192
IB
505
506static aarch64_simd_builtin_datum aarch64_simd_builtin_data[] = {
342be7f7
JG
507#include "aarch64-simd-builtins.def"
508};
509
5d357f26
KT
510/* There's only 8 CRC32 builtins. Probably not worth their own .def file. */
511#define AARCH64_CRC32_BUILTINS \
512 CRC32_BUILTIN (crc32b, QI) \
513 CRC32_BUILTIN (crc32h, HI) \
514 CRC32_BUILTIN (crc32w, SI) \
515 CRC32_BUILTIN (crc32x, DI) \
516 CRC32_BUILTIN (crc32cb, QI) \
517 CRC32_BUILTIN (crc32ch, HI) \
518 CRC32_BUILTIN (crc32cw, SI) \
519 CRC32_BUILTIN (crc32cx, DI)
520
9d63f43b
TC
521/* The next 8 FCMLA instrinsics require some special handling compared the
522 normal simd intrinsics. */
523#define AARCH64_SIMD_FCMLA_LANEQ_BUILTINS \
524 FCMLA_LANEQ_BUILTIN (0, v2sf, fcmla, V2SF, false) \
525 FCMLA_LANEQ_BUILTIN (90, v2sf, fcmla, V2SF, false) \
526 FCMLA_LANEQ_BUILTIN (180, v2sf, fcmla, V2SF, false) \
527 FCMLA_LANEQ_BUILTIN (270, v2sf, fcmla, V2SF, false) \
528 FCMLA_LANEQ_BUILTIN (0, v4hf, fcmla_laneq, V4HF, true) \
529 FCMLA_LANEQ_BUILTIN (90, v4hf, fcmla_laneq, V4HF, true) \
530 FCMLA_LANEQ_BUILTIN (180, v4hf, fcmla_laneq, V4HF, true) \
531 FCMLA_LANEQ_BUILTIN (270, v4hf, fcmla_laneq, V4HF, true) \
532
5d357f26
KT
533typedef struct
534{
535 const char *name;
ef4bddc2 536 machine_mode mode;
5d357f26
KT
537 const enum insn_code icode;
538 unsigned int fcode;
539} aarch64_crc_builtin_datum;
540
9d63f43b
TC
541/* Hold information about how to expand the FCMLA_LANEQ builtins. */
542typedef struct
543{
544 const char *name;
545 machine_mode mode;
546 const enum insn_code icode;
547 unsigned int fcode;
548 bool lane;
549} aarch64_fcmla_laneq_builtin_datum;
550
5d357f26
KT
551#define CRC32_BUILTIN(N, M) \
552 AARCH64_BUILTIN_##N,
553
9d63f43b
TC
554#define FCMLA_LANEQ_BUILTIN(I, N, X, M, T) \
555 AARCH64_SIMD_BUILTIN_FCMLA_LANEQ##I##_##M,
556
342be7f7 557#undef VAR1
bf592b2f 558#define VAR1(T, N, MAP, FLAG, A) \
e993fea1 559 AARCH64_SIMD_BUILTIN_##T##_##N##A,
342be7f7
JG
560
561enum aarch64_builtins
562{
563 AARCH64_BUILTIN_MIN,
aa87aced
KV
564
565 AARCH64_BUILTIN_GET_FPCR,
566 AARCH64_BUILTIN_SET_FPCR,
567 AARCH64_BUILTIN_GET_FPSR,
568 AARCH64_BUILTIN_SET_FPSR,
569
0d7e5fa6
AC
570 AARCH64_BUILTIN_GET_FPCR64,
571 AARCH64_BUILTIN_SET_FPCR64,
572 AARCH64_BUILTIN_GET_FPSR64,
573 AARCH64_BUILTIN_SET_FPSR64,
574
a6fc00da
BH
575 AARCH64_BUILTIN_RSQRT_DF,
576 AARCH64_BUILTIN_RSQRT_SF,
577 AARCH64_BUILTIN_RSQRT_V2DF,
578 AARCH64_BUILTIN_RSQRT_V2SF,
579 AARCH64_BUILTIN_RSQRT_V4SF,
342be7f7 580 AARCH64_SIMD_BUILTIN_BASE,
661fce82 581 AARCH64_SIMD_BUILTIN_LANE_CHECK,
342be7f7 582#include "aarch64-simd-builtins.def"
661fce82
AL
583 /* The first enum element which is based on an insn_data pattern. */
584 AARCH64_SIMD_PATTERN_START = AARCH64_SIMD_BUILTIN_LANE_CHECK + 1,
585 AARCH64_SIMD_BUILTIN_MAX = AARCH64_SIMD_PATTERN_START
586 + ARRAY_SIZE (aarch64_simd_builtin_data) - 1,
5d357f26
KT
587 AARCH64_CRC32_BUILTIN_BASE,
588 AARCH64_CRC32_BUILTINS
589 AARCH64_CRC32_BUILTIN_MAX,
312492bd
JW
590 /* ARMv8.3-A Pointer Authentication Builtins. */
591 AARCH64_PAUTH_BUILTIN_AUTIA1716,
592 AARCH64_PAUTH_BUILTIN_PACIA1716,
8fc16d72
ST
593 AARCH64_PAUTH_BUILTIN_AUTIB1716,
594 AARCH64_PAUTH_BUILTIN_PACIB1716,
312492bd 595 AARCH64_PAUTH_BUILTIN_XPACLRI,
9d63f43b
TC
596 /* Special cased Armv8.3-A Complex FMA by Lane quad Builtins. */
597 AARCH64_SIMD_FCMLA_LANEQ_BUILTIN_BASE,
598 AARCH64_SIMD_FCMLA_LANEQ_BUILTINS
e1d5d19e
KT
599 /* Builtin for Arm8.3-a Javascript conversion instruction. */
600 AARCH64_JSCVT,
89626179
SD
601 /* TME builtins. */
602 AARCH64_TME_BUILTIN_TSTART,
603 AARCH64_TME_BUILTIN_TCOMMIT,
604 AARCH64_TME_BUILTIN_TTEST,
605 AARCH64_TME_BUILTIN_TCANCEL,
c5dc215d
KT
606 /* Armv8.5-a RNG instruction builtins. */
607 AARCH64_BUILTIN_RNG_RNDR,
608 AARCH64_BUILTIN_RNG_RNDRRS,
ef01e6bb
DZ
609 /* MEMTAG builtins. */
610 AARCH64_MEMTAG_BUILTIN_START,
611 AARCH64_MEMTAG_BUILTIN_IRG,
612 AARCH64_MEMTAG_BUILTIN_GMI,
613 AARCH64_MEMTAG_BUILTIN_SUBP,
614 AARCH64_MEMTAG_BUILTIN_INC_TAG,
615 AARCH64_MEMTAG_BUILTIN_SET_TAG,
616 AARCH64_MEMTAG_BUILTIN_GET_TAG,
617 AARCH64_MEMTAG_BUILTIN_END,
342be7f7 618 AARCH64_BUILTIN_MAX
43e9d192
IB
619};
620
5d357f26
KT
621#undef CRC32_BUILTIN
622#define CRC32_BUILTIN(N, M) \
0d4a1197 623 {"__builtin_aarch64_"#N, E_##M##mode, CODE_FOR_aarch64_##N, AARCH64_BUILTIN_##N},
5d357f26
KT
624
625static aarch64_crc_builtin_datum aarch64_crc_builtin_data[] = {
626 AARCH64_CRC32_BUILTINS
627};
628
9d63f43b
TC
629
630#undef FCMLA_LANEQ_BUILTIN
631#define FCMLA_LANEQ_BUILTIN(I, N, X, M, T) \
632 {"__builtin_aarch64_fcmla_laneq"#I#N, E_##M##mode, CODE_FOR_aarch64_##X##I##N, \
633 AARCH64_SIMD_BUILTIN_FCMLA_LANEQ##I##_##M, T},
634
635/* This structure contains how to manage the mapping form the builtin to the
636 instruction to generate in the backend and how to invoke the instruction. */
5eb9ac1e 637static aarch64_fcmla_laneq_builtin_datum aarch64_fcmla_lane_builtin_data[] = {
9d63f43b
TC
638 AARCH64_SIMD_FCMLA_LANEQ_BUILTINS
639};
640
5d357f26
KT
641#undef CRC32_BUILTIN
642
119103ca
JG
643static GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX];
644
43e9d192
IB
645#define NUM_DREG_TYPES 6
646#define NUM_QREG_TYPES 6
647
f9d53c27
TB
648/* Internal scalar builtin types. These types are used to support
649 neon intrinsic builtins. They are _not_ user-visible types. Therefore
650 the mangling for these types are implementation defined. */
651const char *aarch64_scalar_builtin_types[] = {
652 "__builtin_aarch64_simd_qi",
653 "__builtin_aarch64_simd_hi",
654 "__builtin_aarch64_simd_si",
7c369485 655 "__builtin_aarch64_simd_hf",
f9d53c27
TB
656 "__builtin_aarch64_simd_sf",
657 "__builtin_aarch64_simd_di",
658 "__builtin_aarch64_simd_df",
659 "__builtin_aarch64_simd_poly8",
660 "__builtin_aarch64_simd_poly16",
661 "__builtin_aarch64_simd_poly64",
662 "__builtin_aarch64_simd_poly128",
663 "__builtin_aarch64_simd_ti",
664 "__builtin_aarch64_simd_uqi",
665 "__builtin_aarch64_simd_uhi",
666 "__builtin_aarch64_simd_usi",
667 "__builtin_aarch64_simd_udi",
668 "__builtin_aarch64_simd_ei",
669 "__builtin_aarch64_simd_oi",
670 "__builtin_aarch64_simd_ci",
671 "__builtin_aarch64_simd_xi",
e603cd43 672 "__builtin_aarch64_simd_bf",
f9d53c27
TB
673 NULL
674};
b5828b4b 675
f9d53c27
TB
676#define ENTRY(E, M, Q, G) E,
677enum aarch64_simd_type
678{
679#include "aarch64-simd-builtin-types.def"
680 ARM_NEON_H_TYPES_LAST
681};
682#undef ENTRY
b5828b4b 683
98f1dd02 684struct GTY(()) aarch64_simd_type_info
b5828b4b 685{
f9d53c27
TB
686 enum aarch64_simd_type type;
687
688 /* Internal type name. */
689 const char *name;
690
691 /* Internal type name(mangled). The mangled names conform to the
692 AAPCS64 (see "Procedure Call Standard for the ARM 64-bit Architecture",
693 Appendix A). To qualify for emission with the mangled names defined in
694 that document, a vector type must not only be of the correct mode but also
695 be of the correct internal AdvSIMD vector type (e.g. __Int8x8_t); these
696 types are registered by aarch64_init_simd_builtin_types (). In other
697 words, vector types defined in other ways e.g. via vector_size attribute
698 will get default mangled names. */
699 const char *mangle;
700
701 /* Internal type. */
702 tree itype;
703
704 /* Element type. */
b5828b4b
JG
705 tree eltype;
706
f9d53c27
TB
707 /* Machine mode the internal type maps to. */
708 enum machine_mode mode;
b5828b4b 709
f9d53c27
TB
710 /* Qualifiers. */
711 enum aarch64_type_qualifiers q;
712};
713
714#define ENTRY(E, M, Q, G) \
0d4a1197 715 {E, "__" #E, #G "__" #E, NULL_TREE, NULL_TREE, E_##M##mode, qualifier_##Q},
98f1dd02 716static GTY(()) struct aarch64_simd_type_info aarch64_simd_types [] = {
f9d53c27
TB
717#include "aarch64-simd-builtin-types.def"
718};
719#undef ENTRY
720
66f206b8
JW
721static GTY(()) tree aarch64_simd_tuple_types[ARM_NEON_H_TYPES_LAST][3];
722
98f1dd02
AP
723static GTY(()) tree aarch64_simd_intOI_type_node = NULL_TREE;
724static GTY(()) tree aarch64_simd_intCI_type_node = NULL_TREE;
725static GTY(()) tree aarch64_simd_intXI_type_node = NULL_TREE;
f9d53c27 726
1b62ed4f
JG
727/* The user-visible __fp16 type, and a pointer to that type. Used
728 across the back-end. */
729tree aarch64_fp16_type_node = NULL_TREE;
730tree aarch64_fp16_ptr_type_node = NULL_TREE;
731
abbe1ed2
SMW
732/* Back-end node type for brain float (bfloat) types. */
733tree aarch64_bf16_type_node = NULL_TREE;
734tree aarch64_bf16_ptr_type_node = NULL_TREE;
735
6d4d616a 736/* Wrapper around add_builtin_function. NAME is the name of the built-in
072a8b8f 737 function, TYPE is the function type, CODE is the function subcode
738 (relative to AARCH64_BUILTIN_GENERAL), and ATTRS is the function
739 attributes. */
6d4d616a 740static tree
072a8b8f 741aarch64_general_add_builtin (const char *name, tree type, unsigned int code,
742 tree attrs = NULL_TREE)
6d4d616a
RS
743{
744 code = (code << AARCH64_BUILTIN_SHIFT) | AARCH64_BUILTIN_GENERAL;
745 return add_builtin_function (name, type, code, BUILT_IN_MD,
072a8b8f 746 NULL, attrs);
6d4d616a
RS
747}
748
f9d53c27
TB
749static const char *
750aarch64_mangle_builtin_scalar_type (const_tree type)
751{
752 int i = 0;
753
754 while (aarch64_scalar_builtin_types[i] != NULL)
b5828b4b 755 {
f9d53c27
TB
756 const char *name = aarch64_scalar_builtin_types[i];
757
758 if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
759 && DECL_NAME (TYPE_NAME (type))
760 && !strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), name))
761 return aarch64_scalar_builtin_types[i];
762 i++;
763 }
764 return NULL;
b5828b4b
JG
765}
766
f9d53c27
TB
767static const char *
768aarch64_mangle_builtin_vector_type (const_tree type)
b5828b4b 769{
31427b97
RS
770 tree attrs = TYPE_ATTRIBUTES (type);
771 if (tree attr = lookup_attribute ("Advanced SIMD type", attrs))
772 {
773 tree mangled_name = TREE_VALUE (TREE_VALUE (attr));
774 return IDENTIFIER_POINTER (mangled_name);
775 }
f9d53c27
TB
776
777 return NULL;
6db1ec94
JG
778}
779
f9d53c27 780const char *
6d4d616a 781aarch64_general_mangle_builtin_type (const_tree type)
6db1ec94 782{
f9d53c27
TB
783 const char *mangle;
784 /* Walk through all the AArch64 builtins types tables to filter out the
785 incoming type. */
786 if ((mangle = aarch64_mangle_builtin_vector_type (type))
787 || (mangle = aarch64_mangle_builtin_scalar_type (type)))
788 return mangle;
789
790 return NULL;
6db1ec94
JG
791}
792
f9d53c27 793static tree
b8506a8a 794aarch64_simd_builtin_std_type (machine_mode mode,
f9d53c27 795 enum aarch64_type_qualifiers q)
6db1ec94 796{
f9d53c27
TB
797#define QUAL_TYPE(M) \
798 ((q == qualifier_none) ? int##M##_type_node : unsigned_int##M##_type_node);
799 switch (mode)
800 {
4e10a5a7 801 case E_QImode:
f9d53c27 802 return QUAL_TYPE (QI);
4e10a5a7 803 case E_HImode:
f9d53c27 804 return QUAL_TYPE (HI);
4e10a5a7 805 case E_SImode:
f9d53c27 806 return QUAL_TYPE (SI);
4e10a5a7 807 case E_DImode:
f9d53c27 808 return QUAL_TYPE (DI);
4e10a5a7 809 case E_TImode:
f9d53c27 810 return QUAL_TYPE (TI);
4e10a5a7 811 case E_OImode:
f9d53c27 812 return aarch64_simd_intOI_type_node;
4e10a5a7 813 case E_CImode:
f9d53c27 814 return aarch64_simd_intCI_type_node;
4e10a5a7 815 case E_XImode:
f9d53c27 816 return aarch64_simd_intXI_type_node;
4e10a5a7 817 case E_HFmode:
71a11456 818 return aarch64_fp16_type_node;
4e10a5a7 819 case E_SFmode:
f9d53c27 820 return float_type_node;
4e10a5a7 821 case E_DFmode:
f9d53c27 822 return double_type_node;
abbe1ed2
SMW
823 case E_BFmode:
824 return aarch64_bf16_type_node;
f9d53c27
TB
825 default:
826 gcc_unreachable ();
827 }
828#undef QUAL_TYPE
6db1ec94
JG
829}
830
f9d53c27 831static tree
b8506a8a 832aarch64_lookup_simd_builtin_type (machine_mode mode,
f9d53c27 833 enum aarch64_type_qualifiers q)
6db1ec94 834{
f9d53c27
TB
835 int i;
836 int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
837
838 /* Non-poly scalar modes map to standard types not in the table. */
839 if (q != qualifier_poly && !VECTOR_MODE_P (mode))
840 return aarch64_simd_builtin_std_type (mode, q);
841
842 for (i = 0; i < nelts; i++)
66f206b8
JW
843 {
844 if (aarch64_simd_types[i].mode == mode
845 && aarch64_simd_types[i].q == q)
846 return aarch64_simd_types[i].itype;
847 if (aarch64_simd_tuple_types[i][0] != NULL_TREE)
848 for (int j = 0; j < 3; j++)
849 if (TYPE_MODE (aarch64_simd_tuple_types[i][j]) == mode
850 && aarch64_simd_types[i].q == q)
851 return aarch64_simd_tuple_types[i][j];
852 }
f9d53c27
TB
853
854 return NULL_TREE;
b5828b4b
JG
855}
856
f9d53c27 857static tree
b8506a8a 858aarch64_simd_builtin_type (machine_mode mode,
f9d53c27
TB
859 bool unsigned_p, bool poly_p)
860{
861 if (poly_p)
862 return aarch64_lookup_simd_builtin_type (mode, qualifier_poly);
863 else if (unsigned_p)
864 return aarch64_lookup_simd_builtin_type (mode, qualifier_unsigned);
865 else
866 return aarch64_lookup_simd_builtin_type (mode, qualifier_none);
867}
868
af55e82d 869static void
f9d53c27 870aarch64_init_simd_builtin_types (void)
43e9d192 871{
f9d53c27
TB
872 int i;
873 int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
874 tree tdecl;
875
876 /* Init all the element types built by the front-end. */
877 aarch64_simd_types[Int8x8_t].eltype = intQI_type_node;
878 aarch64_simd_types[Int8x16_t].eltype = intQI_type_node;
879 aarch64_simd_types[Int16x4_t].eltype = intHI_type_node;
880 aarch64_simd_types[Int16x8_t].eltype = intHI_type_node;
881 aarch64_simd_types[Int32x2_t].eltype = intSI_type_node;
882 aarch64_simd_types[Int32x4_t].eltype = intSI_type_node;
883 aarch64_simd_types[Int64x1_t].eltype = intDI_type_node;
884 aarch64_simd_types[Int64x2_t].eltype = intDI_type_node;
885 aarch64_simd_types[Uint8x8_t].eltype = unsigned_intQI_type_node;
886 aarch64_simd_types[Uint8x16_t].eltype = unsigned_intQI_type_node;
887 aarch64_simd_types[Uint16x4_t].eltype = unsigned_intHI_type_node;
888 aarch64_simd_types[Uint16x8_t].eltype = unsigned_intHI_type_node;
889 aarch64_simd_types[Uint32x2_t].eltype = unsigned_intSI_type_node;
890 aarch64_simd_types[Uint32x4_t].eltype = unsigned_intSI_type_node;
891 aarch64_simd_types[Uint64x1_t].eltype = unsigned_intDI_type_node;
892 aarch64_simd_types[Uint64x2_t].eltype = unsigned_intDI_type_node;
893
894 /* Poly types are a world of their own. */
895 aarch64_simd_types[Poly8_t].eltype = aarch64_simd_types[Poly8_t].itype =
896 build_distinct_type_copy (unsigned_intQI_type_node);
bcee52c4
MS
897 /* Prevent front-ends from transforming Poly8_t arrays into string
898 literals. */
899 TYPE_STRING_FLAG (aarch64_simd_types[Poly8_t].eltype) = false;
900
f9d53c27
TB
901 aarch64_simd_types[Poly16_t].eltype = aarch64_simd_types[Poly16_t].itype =
902 build_distinct_type_copy (unsigned_intHI_type_node);
903 aarch64_simd_types[Poly64_t].eltype = aarch64_simd_types[Poly64_t].itype =
904 build_distinct_type_copy (unsigned_intDI_type_node);
905 aarch64_simd_types[Poly128_t].eltype = aarch64_simd_types[Poly128_t].itype =
906 build_distinct_type_copy (unsigned_intTI_type_node);
907 /* Init poly vector element types with scalar poly types. */
908 aarch64_simd_types[Poly8x8_t].eltype = aarch64_simd_types[Poly8_t].itype;
909 aarch64_simd_types[Poly8x16_t].eltype = aarch64_simd_types[Poly8_t].itype;
910 aarch64_simd_types[Poly16x4_t].eltype = aarch64_simd_types[Poly16_t].itype;
911 aarch64_simd_types[Poly16x8_t].eltype = aarch64_simd_types[Poly16_t].itype;
912 aarch64_simd_types[Poly64x1_t].eltype = aarch64_simd_types[Poly64_t].itype;
913 aarch64_simd_types[Poly64x2_t].eltype = aarch64_simd_types[Poly64_t].itype;
914
915 /* Continue with standard types. */
71a11456
AL
916 aarch64_simd_types[Float16x4_t].eltype = aarch64_fp16_type_node;
917 aarch64_simd_types[Float16x8_t].eltype = aarch64_fp16_type_node;
f9d53c27
TB
918 aarch64_simd_types[Float32x2_t].eltype = float_type_node;
919 aarch64_simd_types[Float32x4_t].eltype = float_type_node;
920 aarch64_simd_types[Float64x1_t].eltype = double_type_node;
921 aarch64_simd_types[Float64x2_t].eltype = double_type_node;
922
abbe1ed2
SMW
923 /* Init Bfloat vector types with underlying __bf16 type. */
924 aarch64_simd_types[Bfloat16x4_t].eltype = aarch64_bf16_type_node;
925 aarch64_simd_types[Bfloat16x8_t].eltype = aarch64_bf16_type_node;
926
f9d53c27
TB
927 for (i = 0; i < nelts; i++)
928 {
929 tree eltype = aarch64_simd_types[i].eltype;
b8506a8a 930 machine_mode mode = aarch64_simd_types[i].mode;
f9d53c27
TB
931
932 if (aarch64_simd_types[i].itype == NULL)
b96824c4 933 {
31427b97
RS
934 tree type = build_vector_type (eltype, GET_MODE_NUNITS (mode));
935 type = build_distinct_type_copy (type);
936 SET_TYPE_STRUCTURAL_EQUALITY (type);
937
938 tree mangled_name = get_identifier (aarch64_simd_types[i].mangle);
939 tree value = tree_cons (NULL_TREE, mangled_name, NULL_TREE);
940 TYPE_ATTRIBUTES (type)
941 = tree_cons (get_identifier ("Advanced SIMD type"), value,
942 TYPE_ATTRIBUTES (type));
943 aarch64_simd_types[i].itype = type;
b96824c4 944 }
f9d53c27
TB
945
946 tdecl = add_builtin_type (aarch64_simd_types[i].name,
947 aarch64_simd_types[i].itype);
948 TYPE_NAME (aarch64_simd_types[i].itype) = tdecl;
f9d53c27 949 }
43e9d192 950
f9d53c27
TB
951#define AARCH64_BUILD_SIGNED_TYPE(mode) \
952 make_signed_type (GET_MODE_PRECISION (mode));
953 aarch64_simd_intOI_type_node = AARCH64_BUILD_SIGNED_TYPE (OImode);
f9d53c27
TB
954 aarch64_simd_intCI_type_node = AARCH64_BUILD_SIGNED_TYPE (CImode);
955 aarch64_simd_intXI_type_node = AARCH64_BUILD_SIGNED_TYPE (XImode);
956#undef AARCH64_BUILD_SIGNED_TYPE
957
f9d53c27
TB
958 tdecl = add_builtin_type
959 ("__builtin_aarch64_simd_oi" , aarch64_simd_intOI_type_node);
960 TYPE_NAME (aarch64_simd_intOI_type_node) = tdecl;
961 tdecl = add_builtin_type
962 ("__builtin_aarch64_simd_ci" , aarch64_simd_intCI_type_node);
963 TYPE_NAME (aarch64_simd_intCI_type_node) = tdecl;
964 tdecl = add_builtin_type
965 ("__builtin_aarch64_simd_xi" , aarch64_simd_intXI_type_node);
966 TYPE_NAME (aarch64_simd_intXI_type_node) = tdecl;
967}
968
969static void
970aarch64_init_simd_builtin_scalar_types (void)
971{
972 /* Define typedefs for all the standard scalar types. */
973 (*lang_hooks.types.register_builtin_type) (intQI_type_node,
43e9d192 974 "__builtin_aarch64_simd_qi");
f9d53c27 975 (*lang_hooks.types.register_builtin_type) (intHI_type_node,
43e9d192 976 "__builtin_aarch64_simd_hi");
7c369485
AL
977 (*lang_hooks.types.register_builtin_type) (aarch64_fp16_type_node,
978 "__builtin_aarch64_simd_hf");
f9d53c27 979 (*lang_hooks.types.register_builtin_type) (intSI_type_node,
43e9d192 980 "__builtin_aarch64_simd_si");
f9d53c27 981 (*lang_hooks.types.register_builtin_type) (float_type_node,
43e9d192 982 "__builtin_aarch64_simd_sf");
f9d53c27 983 (*lang_hooks.types.register_builtin_type) (intDI_type_node,
43e9d192 984 "__builtin_aarch64_simd_di");
f9d53c27 985 (*lang_hooks.types.register_builtin_type) (double_type_node,
43e9d192 986 "__builtin_aarch64_simd_df");
f9d53c27 987 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
43e9d192 988 "__builtin_aarch64_simd_poly8");
f9d53c27 989 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
43e9d192 990 "__builtin_aarch64_simd_poly16");
f9d53c27 991 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
7baa225d 992 "__builtin_aarch64_simd_poly64");
f9d53c27 993 (*lang_hooks.types.register_builtin_type) (unsigned_intTI_type_node,
7baa225d 994 "__builtin_aarch64_simd_poly128");
f9d53c27 995 (*lang_hooks.types.register_builtin_type) (intTI_type_node,
43e9d192 996 "__builtin_aarch64_simd_ti");
e603cd43
MI
997 (*lang_hooks.types.register_builtin_type) (aarch64_bf16_type_node,
998 "__builtin_aarch64_simd_bf");
b5828b4b 999 /* Unsigned integer types for various mode sizes. */
f9d53c27 1000 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
b5828b4b 1001 "__builtin_aarch64_simd_uqi");
f9d53c27 1002 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
b5828b4b 1003 "__builtin_aarch64_simd_uhi");
f9d53c27 1004 (*lang_hooks.types.register_builtin_type) (unsigned_intSI_type_node,
b5828b4b 1005 "__builtin_aarch64_simd_usi");
f9d53c27 1006 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
b5828b4b 1007 "__builtin_aarch64_simd_udi");
f9d53c27
TB
1008}
1009
079c23cf
KT
1010/* Return a set of FLAG_* flags derived from FLAGS
1011 that describe what a function with result MODE could do,
072a8b8f 1012 taking the command-line flags into account. */
1013static unsigned int
079c23cf 1014aarch64_call_properties (unsigned int flags, machine_mode mode)
072a8b8f 1015{
079c23cf 1016 if (!(flags & FLAG_AUTO_FP) && FLOAT_MODE_P (mode))
35ffd4d1 1017 flags |= FLAG_FP;
072a8b8f 1018
1019 /* -fno-trapping-math means that we can assume any FP exceptions
1020 are not user-visible. */
1021 if (!flag_trapping_math)
1022 flags &= ~FLAG_RAISE_FP_EXCEPTIONS;
1023
1024 return flags;
1025}
1026
079c23cf
KT
1027/* Return true if calls to a function with flags F and mode MODE
1028 could modify some form of global state. */
072a8b8f 1029static bool
079c23cf 1030aarch64_modifies_global_state_p (unsigned int f, machine_mode mode)
072a8b8f 1031{
079c23cf 1032 unsigned int flags = aarch64_call_properties (f, mode);
072a8b8f 1033
1034 if (flags & FLAG_RAISE_FP_EXCEPTIONS)
1035 return true;
1036
1037 if (flags & FLAG_PREFETCH_MEMORY)
1038 return true;
1039
1040 return flags & FLAG_WRITE_MEMORY;
1041}
1042
079c23cf
KT
1043/* Return true if calls to a function with flags F and mode MODE
1044 could read some form of global state. */
072a8b8f 1045static bool
079c23cf 1046aarch64_reads_global_state_p (unsigned int f, machine_mode mode)
072a8b8f 1047{
079c23cf 1048 unsigned int flags = aarch64_call_properties (f, mode);
072a8b8f 1049
1050 if (flags & FLAG_READ_FPCR)
1051 return true;
1052
1053 return flags & FLAG_READ_MEMORY;
1054}
1055
079c23cf
KT
1056/* Return true if calls to a function with flags F and mode MODE
1057 could raise a signal. */
072a8b8f 1058static bool
079c23cf 1059aarch64_could_trap_p (unsigned int f, machine_mode mode)
072a8b8f 1060{
079c23cf 1061 unsigned int flags = aarch64_call_properties (f, mode);
072a8b8f 1062
1063 if (flags & FLAG_RAISE_FP_EXCEPTIONS)
1064 return true;
1065
1066 if (flags & (FLAG_READ_MEMORY | FLAG_WRITE_MEMORY))
1067 return true;
1068
1069 return false;
1070}
1071
1072/* Add attribute NAME to ATTRS. */
1073static tree
1074aarch64_add_attribute (const char *name, tree attrs)
1075{
1076 return tree_cons (get_identifier (name), NULL_TREE, attrs);
1077}
1078
079c23cf
KT
1079/* Return the appropriate attributes for a function that has
1080 flags F and mode MODE. */
072a8b8f 1081static tree
079c23cf 1082aarch64_get_attributes (unsigned int f, machine_mode mode)
072a8b8f 1083{
1084 tree attrs = NULL_TREE;
1085
079c23cf 1086 if (!aarch64_modifies_global_state_p (f, mode))
072a8b8f 1087 {
079c23cf 1088 if (aarch64_reads_global_state_p (f, mode))
072a8b8f 1089 attrs = aarch64_add_attribute ("pure", attrs);
1090 else
1091 attrs = aarch64_add_attribute ("const", attrs);
1092 }
1093
079c23cf 1094 if (!flag_non_call_exceptions || !aarch64_could_trap_p (f, mode))
072a8b8f 1095 attrs = aarch64_add_attribute ("nothrow", attrs);
1096
1097 return aarch64_add_attribute ("leaf", attrs);
1098}
1099
e95a988a
KT
1100static bool aarch64_simd_builtins_initialized_p = false;
1101
9d63f43b
TC
1102/* Due to the architecture not providing lane variant of the lane instructions
1103 for fcmla we can't use the standard simd builtin expansion code, but we
1104 still want the majority of the validation that would normally be done. */
1105
1106void
1107aarch64_init_fcmla_laneq_builtins (void)
1108{
1109 unsigned int i = 0;
1110
1111 for (i = 0; i < ARRAY_SIZE (aarch64_fcmla_lane_builtin_data); ++i)
1112 {
1113 aarch64_fcmla_laneq_builtin_datum* d
1114 = &aarch64_fcmla_lane_builtin_data[i];
1115 tree argtype = aarch64_lookup_simd_builtin_type (d->mode, qualifier_none);
1116 machine_mode quadmode = GET_MODE_2XWIDER_MODE (d->mode).require ();
1117 tree quadtype
1118 = aarch64_lookup_simd_builtin_type (quadmode, qualifier_none);
1119 tree lanetype
1120 = aarch64_simd_builtin_std_type (SImode, qualifier_lane_pair_index);
1121 tree ftype = build_function_type_list (argtype, argtype, argtype,
1122 quadtype, lanetype, NULL_TREE);
079c23cf
KT
1123 tree attrs = aarch64_get_attributes (FLAG_FP, d->mode);
1124 tree fndecl
1125 = aarch64_general_add_builtin (d->name, ftype, d->fcode, attrs);
9d63f43b
TC
1126
1127 aarch64_builtin_decls[d->fcode] = fndecl;
1128 }
1129}
1130
e95a988a 1131void
8197ab94 1132aarch64_init_simd_builtin_functions (bool called_from_pragma)
f9d53c27 1133{
661fce82 1134 unsigned int i, fcode = AARCH64_SIMD_PATTERN_START;
f9d53c27 1135
8197ab94
JW
1136 if (!called_from_pragma)
1137 {
1138 tree lane_check_fpr = build_function_type_list (void_type_node,
1139 size_type_node,
1140 size_type_node,
1141 intSI_type_node,
1142 NULL);
1143 aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_LANE_CHECK]
1144 = aarch64_general_add_builtin ("__builtin_aarch64_im_lane_boundsi",
1145 lane_check_fpr,
1146 AARCH64_SIMD_BUILTIN_LANE_CHECK);
1147 }
661fce82 1148
342be7f7 1149 for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++)
43e9d192 1150 {
b5828b4b 1151 bool print_type_signature_p = false;
cae83731 1152 char type_signature[SIMD_MAX_BUILTIN_ARGS + 1] = { 0 };
43e9d192 1153 aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i];
342be7f7
JG
1154 char namebuf[60];
1155 tree ftype = NULL;
119103ca 1156 tree fndecl = NULL;
342be7f7 1157
342be7f7 1158 d->fcode = fcode;
43e9d192 1159
b5828b4b
JG
1160 /* We must track two variables here. op_num is
1161 the operand number as in the RTL pattern. This is
1162 required to access the mode (e.g. V4SF mode) of the
1163 argument, from which the base type can be derived.
1164 arg_num is an index in to the qualifiers data, which
1165 gives qualifiers to the type (e.g. const unsigned).
1166 The reason these two variables may differ by one is the
1167 void return type. While all return types take the 0th entry
1168 in the qualifiers array, there is no operand for them in the
1169 RTL pattern. */
1170 int op_num = insn_data[d->code].n_operands - 1;
1171 int arg_num = d->qualifiers[0] & qualifier_void
1172 ? op_num + 1
1173 : op_num;
1174 tree return_type = void_type_node, args = void_list_node;
1175 tree eltype;
1176
8197ab94
JW
1177 int struct_mode_args = 0;
1178 for (int j = op_num; j >= 0; j--)
1179 {
1180 machine_mode op_mode = insn_data[d->code].operand[j].mode;
1181 if (aarch64_advsimd_struct_mode_p (op_mode))
1182 struct_mode_args++;
1183 }
1184
1185 if ((called_from_pragma && struct_mode_args == 0)
1186 || (!called_from_pragma && struct_mode_args > 0))
1187 continue;
1188
b5828b4b
JG
1189 /* Build a function type directly from the insn_data for this
1190 builtin. The build_function_type () function takes care of
1191 removing duplicates for us. */
1192 for (; op_num >= 0; arg_num--, op_num--)
43e9d192 1193 {
ef4bddc2 1194 machine_mode op_mode = insn_data[d->code].operand[op_num].mode;
b5828b4b 1195 enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num];
43e9d192 1196
b5828b4b
JG
1197 if (qualifiers & qualifier_unsigned)
1198 {
9fd2074d 1199 type_signature[op_num] = 'u';
b5828b4b
JG
1200 print_type_signature_p = true;
1201 }
6db1ec94
JG
1202 else if (qualifiers & qualifier_poly)
1203 {
9fd2074d 1204 type_signature[op_num] = 'p';
6db1ec94
JG
1205 print_type_signature_p = true;
1206 }
b5828b4b 1207 else
9fd2074d 1208 type_signature[op_num] = 's';
b5828b4b
JG
1209
1210 /* Skip an internal operand for vget_{low, high}. */
1211 if (qualifiers & qualifier_internal)
1212 continue;
1213
1214 /* Some builtins have different user-facing types
1215 for certain arguments, encoded in d->mode. */
1216 if (qualifiers & qualifier_map_mode)
bc5e395d 1217 op_mode = d->mode;
b5828b4b
JG
1218
1219 /* For pointers, we want a pointer to the basic type
1220 of the vector. */
1221 if (qualifiers & qualifier_pointer && VECTOR_MODE_P (op_mode))
1222 op_mode = GET_MODE_INNER (op_mode);
1223
f9d53c27
TB
1224 eltype = aarch64_simd_builtin_type
1225 (op_mode,
1226 (qualifiers & qualifier_unsigned) != 0,
1227 (qualifiers & qualifier_poly) != 0);
1228 gcc_assert (eltype != NULL);
b5828b4b
JG
1229
1230 /* Add qualifiers. */
1231 if (qualifiers & qualifier_const)
1232 eltype = build_qualified_type (eltype, TYPE_QUAL_CONST);
1233
1234 if (qualifiers & qualifier_pointer)
1235 eltype = build_pointer_type (eltype);
1236
1237 /* If we have reached arg_num == 0, we are at a non-void
1238 return type. Otherwise, we are still processing
1239 arguments. */
1240 if (arg_num == 0)
1241 return_type = eltype;
1242 else
1243 args = tree_cons (NULL_TREE, eltype, args);
1244 }
342be7f7 1245
b5828b4b 1246 ftype = build_function_type (return_type, args);
43e9d192 1247
342be7f7 1248 gcc_assert (ftype != NULL);
43e9d192 1249
b5828b4b 1250 if (print_type_signature_p)
bc5e395d
JG
1251 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s_%s",
1252 d->name, type_signature);
b5828b4b 1253 else
bc5e395d
JG
1254 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s",
1255 d->name);
43e9d192 1256
079c23cf 1257 tree attrs = aarch64_get_attributes (d->flags, d->mode);
072a8b8f 1258
66f206b8
JW
1259 if (called_from_pragma)
1260 {
1261 unsigned int raw_code
1262 = (fcode << AARCH64_BUILTIN_SHIFT) | AARCH64_BUILTIN_GENERAL;
1263 fndecl = simulate_builtin_function_decl (input_location, namebuf,
1264 ftype, raw_code, NULL,
1265 attrs);
1266 }
1267 else
1268 fndecl = aarch64_general_add_builtin (namebuf, ftype, fcode, attrs);
1269
119103ca 1270 aarch64_builtin_decls[fcode] = fndecl;
43e9d192 1271 }
8197ab94
JW
1272}
1273
1274/* Register the tuple type that contains NUM_VECTORS of the AdvSIMD type
1275 indexed by TYPE_INDEX. */
1276static void
1277register_tuple_type (unsigned int num_vectors, unsigned int type_index)
1278{
1279 aarch64_simd_type_info *type = &aarch64_simd_types[type_index];
1280
1281 /* Synthesize the name of the user-visible vector tuple type. */
1282 const char *vector_type_name = type->name;
1283 char tuple_type_name[sizeof ("bfloat16x4x2_t")];
1284 snprintf (tuple_type_name, sizeof (tuple_type_name), "%.*sx%d_t",
1285 (int) strlen (vector_type_name) - 4, vector_type_name + 2,
1286 num_vectors);
1287 tuple_type_name[0] = TOLOWER (tuple_type_name[0]);
1288
1289 tree vector_type = type->itype;
1290 tree array_type = build_array_type_nelts (vector_type, num_vectors);
66f206b8
JW
1291 if (type->mode == DImode)
1292 {
1293 if (num_vectors == 2)
1294 SET_TYPE_MODE (array_type, V2x1DImode);
1295 else if (num_vectors == 3)
1296 SET_TYPE_MODE (array_type, V3x1DImode);
1297 else if (num_vectors == 4)
1298 SET_TYPE_MODE (array_type, V4x1DImode);
1299 }
1300
8197ab94
JW
1301 unsigned int alignment
1302 = (known_eq (GET_MODE_SIZE (type->mode), 16) ? 128 : 64);
1303 gcc_assert (TYPE_MODE_RAW (array_type) == TYPE_MODE (array_type)
1304 && TYPE_ALIGN (array_type) == alignment);
1305
1306 tree field = build_decl (input_location, FIELD_DECL,
1307 get_identifier ("val"), array_type);
1308
1309 tree t = lang_hooks.types.simulate_record_decl (input_location,
1310 tuple_type_name,
1311 make_array_slice (&field,
1312 1));
1313 gcc_assert (TYPE_MODE_RAW (t) == TYPE_MODE (t)
1314 && TYPE_ALIGN (t) == alignment);
66f206b8
JW
1315
1316 if (num_vectors == 2)
1317 aarch64_simd_tuple_types[type_index][0] = t;
1318 else if (num_vectors == 3)
1319 aarch64_simd_tuple_types[type_index][1] = t;
1320 else if (num_vectors == 4)
1321 aarch64_simd_tuple_types[type_index][2] = t;
8197ab94
JW
1322}
1323
1324static bool
1325aarch64_scalar_builtin_type_p (aarch64_simd_type t)
1326{
1327 return (t == Poly8_t || t == Poly16_t || t == Poly64_t || t == Poly128_t);
1328}
1329
1330/* Implement #pragma GCC aarch64 "arm_neon.h". */
1331void
1332handle_arm_neon_h (void)
1333{
1334 /* Register the AdvSIMD vector tuple types. */
1335 for (unsigned int i = 0; i < ARM_NEON_H_TYPES_LAST; i++)
1336 for (unsigned int count = 2; count <= 4; ++count)
1337 if (!aarch64_scalar_builtin_type_p (aarch64_simd_types[i].type))
1338 register_tuple_type (count, i);
1339
1340 aarch64_init_simd_builtin_functions (true);
1341}
1342
1343void
1344aarch64_init_simd_builtins (void)
1345{
1346 if (aarch64_simd_builtins_initialized_p)
1347 return;
1348
1349 aarch64_simd_builtins_initialized_p = true;
1350
1351 aarch64_init_simd_builtin_types ();
1352
1353 /* Strong-typing hasn't been implemented for all AdvSIMD builtin intrinsics.
1354 Therefore we need to preserve the old __builtin scalar types. It can be
1355 removed once all the intrinsics become strongly typed using the qualifier
1356 system. */
1357 aarch64_init_simd_builtin_scalar_types ();
1358
1359 aarch64_init_simd_builtin_functions (false);
1360 if (in_lto_p)
1361 handle_arm_neon_h ();
280d970b 1362
8197ab94
JW
1363 /* Initialize the remaining fcmla_laneq intrinsics. */
1364 aarch64_init_fcmla_laneq_builtins ();
43e9d192
IB
1365}
1366
5d357f26
KT
1367static void
1368aarch64_init_crc32_builtins ()
1369{
f9d53c27 1370 tree usi_type = aarch64_simd_builtin_std_type (SImode, qualifier_unsigned);
5d357f26
KT
1371 unsigned int i = 0;
1372
1373 for (i = 0; i < ARRAY_SIZE (aarch64_crc_builtin_data); ++i)
1374 {
1375 aarch64_crc_builtin_datum* d = &aarch64_crc_builtin_data[i];
f9d53c27
TB
1376 tree argtype = aarch64_simd_builtin_std_type (d->mode,
1377 qualifier_unsigned);
5d357f26 1378 tree ftype = build_function_type_list (usi_type, usi_type, argtype, NULL_TREE);
079c23cf
KT
1379 tree attrs = aarch64_get_attributes (FLAG_NONE, d->mode);
1380 tree fndecl
1381 = aarch64_general_add_builtin (d->name, ftype, d->fcode, attrs);
5d357f26
KT
1382
1383 aarch64_builtin_decls[d->fcode] = fndecl;
1384 }
1385}
1386
a6fc00da
BH
1387/* Add builtins for reciprocal square root. */
1388
1389void
1390aarch64_init_builtin_rsqrt (void)
1391{
1392 tree fndecl = NULL;
1393 tree ftype = NULL;
1394
1395 tree V2SF_type_node = build_vector_type (float_type_node, 2);
1396 tree V2DF_type_node = build_vector_type (double_type_node, 2);
1397 tree V4SF_type_node = build_vector_type (float_type_node, 4);
1398
1399 struct builtin_decls_data
1400 {
1401 tree type_node;
1402 const char *builtin_name;
1403 int function_code;
1404 };
1405
1406 builtin_decls_data bdda[] =
1407 {
1408 { double_type_node, "__builtin_aarch64_rsqrt_df", AARCH64_BUILTIN_RSQRT_DF },
1409 { float_type_node, "__builtin_aarch64_rsqrt_sf", AARCH64_BUILTIN_RSQRT_SF },
1410 { V2DF_type_node, "__builtin_aarch64_rsqrt_v2df", AARCH64_BUILTIN_RSQRT_V2DF },
1411 { V2SF_type_node, "__builtin_aarch64_rsqrt_v2sf", AARCH64_BUILTIN_RSQRT_V2SF },
1412 { V4SF_type_node, "__builtin_aarch64_rsqrt_v4sf", AARCH64_BUILTIN_RSQRT_V4SF }
1413 };
1414
1415 builtin_decls_data *bdd = bdda;
1416 builtin_decls_data *bdd_end = bdd + (sizeof (bdda) / sizeof (builtin_decls_data));
1417
1418 for (; bdd < bdd_end; bdd++)
1419 {
1420 ftype = build_function_type_list (bdd->type_node, bdd->type_node, NULL_TREE);
079c23cf 1421 tree attrs = aarch64_get_attributes (FLAG_FP, TYPE_MODE (bdd->type_node));
6d4d616a 1422 fndecl = aarch64_general_add_builtin (bdd->builtin_name,
079c23cf 1423 ftype, bdd->function_code, attrs);
a6fc00da
BH
1424 aarch64_builtin_decls[bdd->function_code] = fndecl;
1425 }
1426}
1427
1b62ed4f
JG
1428/* Initialize the backend types that support the user-visible __fp16
1429 type, also initialize a pointer to that type, to be used when
1430 forming HFAs. */
1431
1432static void
1433aarch64_init_fp16_types (void)
1434{
1435 aarch64_fp16_type_node = make_node (REAL_TYPE);
1436 TYPE_PRECISION (aarch64_fp16_type_node) = 16;
1437 layout_type (aarch64_fp16_type_node);
1438
1439 (*lang_hooks.types.register_builtin_type) (aarch64_fp16_type_node, "__fp16");
1440 aarch64_fp16_ptr_type_node = build_pointer_type (aarch64_fp16_type_node);
1441}
1442
abbe1ed2
SMW
1443/* Initialize the backend REAL_TYPE type supporting bfloat types. */
1444static void
1445aarch64_init_bf16_types (void)
1446{
1447 aarch64_bf16_type_node = make_node (REAL_TYPE);
1448 TYPE_PRECISION (aarch64_bf16_type_node) = 16;
1449 SET_TYPE_MODE (aarch64_bf16_type_node, BFmode);
1450 layout_type (aarch64_bf16_type_node);
1451
1452 lang_hooks.types.register_builtin_type (aarch64_bf16_type_node, "__bf16");
1453 aarch64_bf16_ptr_type_node = build_pointer_type (aarch64_bf16_type_node);
1454}
1455
312492bd
JW
1456/* Pointer authentication builtins that will become NOP on legacy platform.
1457 Currently, these builtins are for internal use only (libgcc EH unwinder). */
1458
1459void
1460aarch64_init_pauth_hint_builtins (void)
1461{
1462 /* Pointer Authentication builtins. */
1463 tree ftype_pointer_auth
1464 = build_function_type_list (ptr_type_node, ptr_type_node,
1465 unsigned_intDI_type_node, NULL_TREE);
1466 tree ftype_pointer_strip
1467 = build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE);
1468
1469 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_AUTIA1716]
6d4d616a
RS
1470 = aarch64_general_add_builtin ("__builtin_aarch64_autia1716",
1471 ftype_pointer_auth,
1472 AARCH64_PAUTH_BUILTIN_AUTIA1716);
312492bd 1473 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_PACIA1716]
6d4d616a
RS
1474 = aarch64_general_add_builtin ("__builtin_aarch64_pacia1716",
1475 ftype_pointer_auth,
1476 AARCH64_PAUTH_BUILTIN_PACIA1716);
8fc16d72 1477 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_AUTIB1716]
6d4d616a
RS
1478 = aarch64_general_add_builtin ("__builtin_aarch64_autib1716",
1479 ftype_pointer_auth,
1480 AARCH64_PAUTH_BUILTIN_AUTIB1716);
8fc16d72 1481 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_PACIB1716]
6d4d616a
RS
1482 = aarch64_general_add_builtin ("__builtin_aarch64_pacib1716",
1483 ftype_pointer_auth,
1484 AARCH64_PAUTH_BUILTIN_PACIB1716);
312492bd 1485 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_XPACLRI]
6d4d616a
RS
1486 = aarch64_general_add_builtin ("__builtin_aarch64_xpaclri",
1487 ftype_pointer_strip,
1488 AARCH64_PAUTH_BUILTIN_XPACLRI);
312492bd
JW
1489}
1490
89626179
SD
1491/* Initialize the transactional memory extension (TME) builtins. */
1492static void
1493aarch64_init_tme_builtins (void)
1494{
1495 tree ftype_uint64_void
1496 = build_function_type_list (uint64_type_node, NULL);
1497 tree ftype_void_void
1498 = build_function_type_list (void_type_node, NULL);
1499 tree ftype_void_uint64
1500 = build_function_type_list (void_type_node, uint64_type_node, NULL);
1501
1502 aarch64_builtin_decls[AARCH64_TME_BUILTIN_TSTART]
6d4d616a
RS
1503 = aarch64_general_add_builtin ("__builtin_aarch64_tstart",
1504 ftype_uint64_void,
1505 AARCH64_TME_BUILTIN_TSTART);
89626179 1506 aarch64_builtin_decls[AARCH64_TME_BUILTIN_TTEST]
6d4d616a
RS
1507 = aarch64_general_add_builtin ("__builtin_aarch64_ttest",
1508 ftype_uint64_void,
1509 AARCH64_TME_BUILTIN_TTEST);
89626179 1510 aarch64_builtin_decls[AARCH64_TME_BUILTIN_TCOMMIT]
6d4d616a
RS
1511 = aarch64_general_add_builtin ("__builtin_aarch64_tcommit",
1512 ftype_void_void,
1513 AARCH64_TME_BUILTIN_TCOMMIT);
89626179 1514 aarch64_builtin_decls[AARCH64_TME_BUILTIN_TCANCEL]
6d4d616a
RS
1515 = aarch64_general_add_builtin ("__builtin_aarch64_tcancel",
1516 ftype_void_uint64,
1517 AARCH64_TME_BUILTIN_TCANCEL);
89626179
SD
1518}
1519
c5dc215d
KT
1520/* Add builtins for Random Number instructions. */
1521
1522static void
1523aarch64_init_rng_builtins (void)
1524{
1525 tree unsigned_ptr_type = build_pointer_type (unsigned_intDI_type_node);
1526 tree ftype
1527 = build_function_type_list (integer_type_node, unsigned_ptr_type, NULL);
1528 aarch64_builtin_decls[AARCH64_BUILTIN_RNG_RNDR]
1529 = aarch64_general_add_builtin ("__builtin_aarch64_rndr", ftype,
1530 AARCH64_BUILTIN_RNG_RNDR);
1531 aarch64_builtin_decls[AARCH64_BUILTIN_RNG_RNDRRS]
1532 = aarch64_general_add_builtin ("__builtin_aarch64_rndrrs", ftype,
1533 AARCH64_BUILTIN_RNG_RNDRRS);
1534}
1535
ef01e6bb
DZ
1536/* Initialize the memory tagging extension (MTE) builtins. */
1537struct
1538{
1539 tree ftype;
1540 enum insn_code icode;
1541} aarch64_memtag_builtin_data[AARCH64_MEMTAG_BUILTIN_END -
1542 AARCH64_MEMTAG_BUILTIN_START - 1];
1543
1544static void
1545aarch64_init_memtag_builtins (void)
1546{
1547 tree fntype = NULL;
1548
1549#define AARCH64_INIT_MEMTAG_BUILTINS_DECL(F, N, I, T) \
1550 aarch64_builtin_decls[AARCH64_MEMTAG_BUILTIN_##F] \
1551 = aarch64_general_add_builtin ("__builtin_aarch64_memtag_"#N, \
1552 T, AARCH64_MEMTAG_BUILTIN_##F); \
1553 aarch64_memtag_builtin_data[AARCH64_MEMTAG_BUILTIN_##F - \
1554 AARCH64_MEMTAG_BUILTIN_START - 1] = \
1555 {T, CODE_FOR_##I};
1556
1557 fntype = build_function_type_list (ptr_type_node, ptr_type_node,
1558 uint64_type_node, NULL);
1559 AARCH64_INIT_MEMTAG_BUILTINS_DECL (IRG, irg, irg, fntype);
1560
1561 fntype = build_function_type_list (uint64_type_node, ptr_type_node,
1562 uint64_type_node, NULL);
1563 AARCH64_INIT_MEMTAG_BUILTINS_DECL (GMI, gmi, gmi, fntype);
1564
1565 fntype = build_function_type_list (ptrdiff_type_node, ptr_type_node,
1566 ptr_type_node, NULL);
1567 AARCH64_INIT_MEMTAG_BUILTINS_DECL (SUBP, subp, subp, fntype);
1568
1569 fntype = build_function_type_list (ptr_type_node, ptr_type_node,
1570 unsigned_type_node, NULL);
1571 AARCH64_INIT_MEMTAG_BUILTINS_DECL (INC_TAG, inc_tag, addg, fntype);
1572
1573 fntype = build_function_type_list (void_type_node, ptr_type_node, NULL);
1574 AARCH64_INIT_MEMTAG_BUILTINS_DECL (SET_TAG, set_tag, stg, fntype);
1575
1576 fntype = build_function_type_list (ptr_type_node, ptr_type_node, NULL);
1577 AARCH64_INIT_MEMTAG_BUILTINS_DECL (GET_TAG, get_tag, ldg, fntype);
1578
1579#undef AARCH64_INIT_MEMTAG_BUILTINS_DECL
1580}
c5dc215d 1581
0d7e5fa6 1582/* Initialize fpsr fpcr getters and setters. */
c5dc215d 1583
0d7e5fa6
AC
1584static void
1585aarch64_init_fpsr_fpcr_builtins (void)
43e9d192 1586{
0d7e5fa6 1587 tree ftype_set
aa87aced 1588 = build_function_type_list (void_type_node, unsigned_type_node, NULL);
0d7e5fa6 1589 tree ftype_get
aa87aced
KV
1590 = build_function_type_list (unsigned_type_node, NULL);
1591
1592 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR]
6d4d616a 1593 = aarch64_general_add_builtin ("__builtin_aarch64_get_fpcr",
0d7e5fa6 1594 ftype_get,
6d4d616a 1595 AARCH64_BUILTIN_GET_FPCR);
aa87aced 1596 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR]
6d4d616a 1597 = aarch64_general_add_builtin ("__builtin_aarch64_set_fpcr",
0d7e5fa6 1598 ftype_set,
6d4d616a 1599 AARCH64_BUILTIN_SET_FPCR);
aa87aced 1600 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR]
6d4d616a 1601 = aarch64_general_add_builtin ("__builtin_aarch64_get_fpsr",
0d7e5fa6 1602 ftype_get,
6d4d616a 1603 AARCH64_BUILTIN_GET_FPSR);
aa87aced 1604 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR]
6d4d616a 1605 = aarch64_general_add_builtin ("__builtin_aarch64_set_fpsr",
0d7e5fa6 1606 ftype_set,
6d4d616a 1607 AARCH64_BUILTIN_SET_FPSR);
aa87aced 1608
0d7e5fa6
AC
1609 ftype_set
1610 = build_function_type_list (void_type_node, long_long_unsigned_type_node,
1611 NULL);
1612 ftype_get
1613 = build_function_type_list (long_long_unsigned_type_node, NULL);
1614
1615 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR64]
1616 = aarch64_general_add_builtin ("__builtin_aarch64_get_fpcr64",
1617 ftype_get,
1618 AARCH64_BUILTIN_GET_FPCR64);
1619 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR64]
1620 = aarch64_general_add_builtin ("__builtin_aarch64_set_fpcr64",
1621 ftype_set,
1622 AARCH64_BUILTIN_SET_FPCR64);
1623 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR64]
1624 = aarch64_general_add_builtin ("__builtin_aarch64_get_fpsr64",
1625 ftype_get,
1626 AARCH64_BUILTIN_GET_FPSR64);
1627 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR64]
1628 = aarch64_general_add_builtin ("__builtin_aarch64_set_fpsr64",
1629 ftype_set,
1630 AARCH64_BUILTIN_SET_FPSR64);
1631}
1632
1633/* Initialize all builtins in the AARCH64_BUILTIN_GENERAL group. */
1634
1635void
1636aarch64_general_init_builtins (void)
1637{
1638 aarch64_init_fpsr_fpcr_builtins ();
1639
1b62ed4f 1640 aarch64_init_fp16_types ();
c2ec330c 1641
abbe1ed2
SMW
1642 aarch64_init_bf16_types ();
1643
342be7f7 1644 if (TARGET_SIMD)
280d970b 1645 aarch64_init_simd_builtins ();
e95a988a
KT
1646
1647 aarch64_init_crc32_builtins ();
a6fc00da 1648 aarch64_init_builtin_rsqrt ();
c5dc215d 1649 aarch64_init_rng_builtins ();
312492bd 1650
e1d5d19e
KT
1651 tree ftype_jcvt
1652 = build_function_type_list (intSI_type_node, double_type_node, NULL);
1653 aarch64_builtin_decls[AARCH64_JSCVT]
6d4d616a
RS
1654 = aarch64_general_add_builtin ("__builtin_aarch64_jcvtzs", ftype_jcvt,
1655 AARCH64_JSCVT);
e1d5d19e 1656
a876231c
JW
1657 /* Initialize pointer authentication builtins which are backed by instructions
1658 in NOP encoding space.
1659
1660 NOTE: these builtins are supposed to be used by libgcc unwinder only, as
1661 there is no support on return address signing under ILP32, we don't
1662 register them. */
1663 if (!TARGET_ILP32)
1664 aarch64_init_pauth_hint_builtins ();
89626179
SD
1665
1666 if (TARGET_TME)
1667 aarch64_init_tme_builtins ();
ef01e6bb
DZ
1668
1669 if (TARGET_MEMTAG)
1670 aarch64_init_memtag_builtins ();
43e9d192
IB
1671}
1672
6d4d616a 1673/* Implement TARGET_BUILTIN_DECL for the AARCH64_BUILTIN_GENERAL group. */
119103ca 1674tree
6d4d616a 1675aarch64_general_builtin_decl (unsigned code, bool)
119103ca
JG
1676{
1677 if (code >= AARCH64_BUILTIN_MAX)
1678 return error_mark_node;
1679
1680 return aarch64_builtin_decls[code];
1681}
1682
43e9d192
IB
1683typedef enum
1684{
1685 SIMD_ARG_COPY_TO_REG,
1686 SIMD_ARG_CONSTANT,
2a49c16d 1687 SIMD_ARG_LANE_INDEX,
4d0a0237 1688 SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX,
9d63f43b 1689 SIMD_ARG_LANE_PAIR_INDEX,
8c197c85 1690 SIMD_ARG_LANE_QUADTUP_INDEX,
43e9d192
IB
1691 SIMD_ARG_STOP
1692} builtin_simd_arg;
1693
e95a988a 1694
43e9d192
IB
1695static rtx
1696aarch64_simd_expand_args (rtx target, int icode, int have_retval,
4d0a0237 1697 tree exp, builtin_simd_arg *args,
b8506a8a 1698 machine_mode builtin_mode)
43e9d192 1699{
43e9d192 1700 rtx pat;
d9e80f49
AL
1701 rtx op[SIMD_MAX_BUILTIN_ARGS + 1]; /* First element for result operand. */
1702 int opc = 0;
1703
1704 if (have_retval)
1705 {
1706 machine_mode tmode = insn_data[icode].operand[0].mode;
1707 if (!target
43e9d192 1708 || GET_MODE (target) != tmode
d9e80f49
AL
1709 || !(*insn_data[icode].operand[0].predicate) (target, tmode))
1710 target = gen_reg_rtx (tmode);
1711 op[opc++] = target;
1712 }
43e9d192 1713
43e9d192
IB
1714 for (;;)
1715 {
d9e80f49 1716 builtin_simd_arg thisarg = args[opc - have_retval];
43e9d192
IB
1717
1718 if (thisarg == SIMD_ARG_STOP)
1719 break;
1720 else
1721 {
d9e80f49 1722 tree arg = CALL_EXPR_ARG (exp, opc - have_retval);
b8506a8a 1723 machine_mode mode = insn_data[icode].operand[opc].mode;
d9e80f49 1724 op[opc] = expand_normal (arg);
43e9d192
IB
1725
1726 switch (thisarg)
1727 {
1728 case SIMD_ARG_COPY_TO_REG:
d9e80f49
AL
1729 if (POINTER_TYPE_P (TREE_TYPE (arg)))
1730 op[opc] = convert_memory_address (Pmode, op[opc]);
1731 /*gcc_assert (GET_MODE (op[opc]) == mode); */
1732 if (!(*insn_data[icode].operand[opc].predicate)
1733 (op[opc], mode))
1734 op[opc] = copy_to_mode_reg (mode, op[opc]);
43e9d192
IB
1735 break;
1736
4d0a0237
CB
1737 case SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX:
1738 gcc_assert (opc > 1);
1739 if (CONST_INT_P (op[opc]))
1740 {
6a70badb
RS
1741 unsigned int nunits
1742 = GET_MODE_NUNITS (builtin_mode).to_constant ();
1743 aarch64_simd_lane_bounds (op[opc], 0, nunits, exp);
4d0a0237 1744 /* Keep to GCC-vector-extension lane indices in the RTL. */
7ac29c0f
RS
1745 op[opc] = aarch64_endian_lane_rtx (builtin_mode,
1746 INTVAL (op[opc]));
4d0a0237
CB
1747 }
1748 goto constant_arg;
1749
2a49c16d
AL
1750 case SIMD_ARG_LANE_INDEX:
1751 /* Must be a previous operand into which this is an index. */
d9e80f49
AL
1752 gcc_assert (opc > 0);
1753 if (CONST_INT_P (op[opc]))
2a49c16d 1754 {
d9e80f49 1755 machine_mode vmode = insn_data[icode].operand[opc - 1].mode;
6a70badb
RS
1756 unsigned int nunits
1757 = GET_MODE_NUNITS (vmode).to_constant ();
1758 aarch64_simd_lane_bounds (op[opc], 0, nunits, exp);
2a49c16d 1759 /* Keep to GCC-vector-extension lane indices in the RTL. */
7ac29c0f 1760 op[opc] = aarch64_endian_lane_rtx (vmode, INTVAL (op[opc]));
2a49c16d 1761 }
9d63f43b
TC
1762 /* If the lane index isn't a constant then error out. */
1763 goto constant_arg;
1764
1765 case SIMD_ARG_LANE_PAIR_INDEX:
1766 /* Must be a previous operand into which this is an index and
1767 index is restricted to nunits / 2. */
1768 gcc_assert (opc > 0);
1769 if (CONST_INT_P (op[opc]))
1770 {
1771 machine_mode vmode = insn_data[icode].operand[opc - 1].mode;
1772 unsigned int nunits
1773 = GET_MODE_NUNITS (vmode).to_constant ();
1774 aarch64_simd_lane_bounds (op[opc], 0, nunits / 2, exp);
1775 /* Keep to GCC-vector-extension lane indices in the RTL. */
33b5a38c
TC
1776 int lane = INTVAL (op[opc]);
1777 op[opc] = gen_int_mode (ENDIAN_LANE_N (nunits / 2, lane),
1778 SImode);
9d63f43b 1779 }
8c197c85
SMW
1780 /* If the lane index isn't a constant then error out. */
1781 goto constant_arg;
1782 case SIMD_ARG_LANE_QUADTUP_INDEX:
1783 /* Must be a previous operand into which this is an index and
1784 index is restricted to nunits / 4. */
1785 gcc_assert (opc > 0);
1786 if (CONST_INT_P (op[opc]))
1787 {
1788 machine_mode vmode = insn_data[icode].operand[opc - 1].mode;
1789 unsigned int nunits
1790 = GET_MODE_NUNITS (vmode).to_constant ();
1791 aarch64_simd_lane_bounds (op[opc], 0, nunits / 4, exp);
1792 /* Keep to GCC-vector-extension lane indices in the RTL. */
1793 int lane = INTVAL (op[opc]);
1794 op[opc] = gen_int_mode (ENDIAN_LANE_N (nunits / 4, lane),
1795 SImode);
1796 }
1797 /* If the lane index isn't a constant then error out. */
1798 goto constant_arg;
43e9d192 1799 case SIMD_ARG_CONSTANT:
4d0a0237 1800constant_arg:
d9e80f49
AL
1801 if (!(*insn_data[icode].operand[opc].predicate)
1802 (op[opc], mode))
d5a29419 1803 {
62e43587
MS
1804 error_at (EXPR_LOCATION (exp),
1805 "argument %d must be a constant immediate",
1806 opc + 1 - have_retval);
d5a29419
KT
1807 return const0_rtx;
1808 }
43e9d192
IB
1809 break;
1810
1811 case SIMD_ARG_STOP:
1812 gcc_unreachable ();
1813 }
1814
d9e80f49 1815 opc++;
43e9d192
IB
1816 }
1817 }
1818
d9e80f49
AL
1819 switch (opc)
1820 {
1821 case 1:
1822 pat = GEN_FCN (icode) (op[0]);
1823 break;
43e9d192 1824
d9e80f49
AL
1825 case 2:
1826 pat = GEN_FCN (icode) (op[0], op[1]);
1827 break;
43e9d192 1828
d9e80f49
AL
1829 case 3:
1830 pat = GEN_FCN (icode) (op[0], op[1], op[2]);
1831 break;
43e9d192 1832
d9e80f49
AL
1833 case 4:
1834 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
1835 break;
43e9d192 1836
d9e80f49
AL
1837 case 5:
1838 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
1839 break;
43e9d192 1840
d9e80f49
AL
1841 case 6:
1842 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]);
1843 break;
43e9d192 1844
d9e80f49
AL
1845 default:
1846 gcc_unreachable ();
1847 }
43e9d192
IB
1848
1849 if (!pat)
d5a29419 1850 return NULL_RTX;
43e9d192
IB
1851
1852 emit_insn (pat);
1853
1854 return target;
1855}
1856
1857/* Expand an AArch64 AdvSIMD builtin(intrinsic). */
1858rtx
1859aarch64_simd_expand_builtin (int fcode, tree exp, rtx target)
1860{
661fce82
AL
1861 if (fcode == AARCH64_SIMD_BUILTIN_LANE_CHECK)
1862 {
9c4f25cc
AP
1863 rtx totalsize = expand_normal (CALL_EXPR_ARG (exp, 0));
1864 rtx elementsize = expand_normal (CALL_EXPR_ARG (exp, 1));
1865 if (CONST_INT_P (totalsize) && CONST_INT_P (elementsize)
1866 && UINTVAL (elementsize) != 0
1867 && UINTVAL (totalsize) != 0)
1868 {
1869 rtx lane_idx = expand_normal (CALL_EXPR_ARG (exp, 2));
1870 if (CONST_INT_P (lane_idx))
1871 aarch64_simd_lane_bounds (lane_idx, 0,
1872 UINTVAL (totalsize)
1873 / UINTVAL (elementsize),
1874 exp);
1875 else
62e43587
MS
1876 error_at (EXPR_LOCATION (exp),
1877 "lane index must be a constant immediate");
9c4f25cc 1878 }
661fce82 1879 else
62e43587
MS
1880 error_at (EXPR_LOCATION (exp),
1881 "total size and element size must be a non-zero "
1882 "constant immediate");
661fce82
AL
1883 /* Don't generate any RTL. */
1884 return const0_rtx;
1885 }
342be7f7 1886 aarch64_simd_builtin_datum *d =
661fce82 1887 &aarch64_simd_builtin_data[fcode - AARCH64_SIMD_PATTERN_START];
342be7f7 1888 enum insn_code icode = d->code;
0ff2bf46 1889 builtin_simd_arg args[SIMD_MAX_BUILTIN_ARGS + 1];
b5828b4b
JG
1890 int num_args = insn_data[d->code].n_operands;
1891 int is_void = 0;
1892 int k;
43e9d192 1893
b5828b4b 1894 is_void = !!(d->qualifiers[0] & qualifier_void);
43e9d192 1895
b5828b4b
JG
1896 num_args += is_void;
1897
1898 for (k = 1; k < num_args; k++)
1899 {
1900 /* We have four arrays of data, each indexed in a different fashion.
1901 qualifiers - element 0 always describes the function return type.
1902 operands - element 0 is either the operand for return value (if
1903 the function has a non-void return type) or the operand for the
1904 first argument.
1905 expr_args - element 0 always holds the first argument.
1906 args - element 0 is always used for the return type. */
1907 int qualifiers_k = k;
1908 int operands_k = k - is_void;
1909 int expr_args_k = k - 1;
1910
2a49c16d
AL
1911 if (d->qualifiers[qualifiers_k] & qualifier_lane_index)
1912 args[k] = SIMD_ARG_LANE_INDEX;
9d63f43b
TC
1913 else if (d->qualifiers[qualifiers_k] & qualifier_lane_pair_index)
1914 args[k] = SIMD_ARG_LANE_PAIR_INDEX;
8c197c85
SMW
1915 else if (d->qualifiers[qualifiers_k] & qualifier_lane_quadtup_index)
1916 args[k] = SIMD_ARG_LANE_QUADTUP_INDEX;
4d0a0237
CB
1917 else if (d->qualifiers[qualifiers_k] & qualifier_struct_load_store_lane_index)
1918 args[k] = SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX;
2a49c16d 1919 else if (d->qualifiers[qualifiers_k] & qualifier_immediate)
b5828b4b
JG
1920 args[k] = SIMD_ARG_CONSTANT;
1921 else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate)
1922 {
1923 rtx arg
1924 = expand_normal (CALL_EXPR_ARG (exp,
1925 (expr_args_k)));
1926 /* Handle constants only if the predicate allows it. */
1927 bool op_const_int_p =
1928 (CONST_INT_P (arg)
1929 && (*insn_data[icode].operand[operands_k].predicate)
1930 (arg, insn_data[icode].operand[operands_k].mode));
1931 args[k] = op_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG;
1932 }
1933 else
1934 args[k] = SIMD_ARG_COPY_TO_REG;
43e9d192 1935
43e9d192 1936 }
b5828b4b
JG
1937 args[k] = SIMD_ARG_STOP;
1938
1939 /* The interface to aarch64_simd_expand_args expects a 0 if
1940 the function is void, and a 1 if it is not. */
1941 return aarch64_simd_expand_args
4d0a0237 1942 (target, icode, !is_void, exp, &args[1], d->mode);
43e9d192 1943}
342be7f7 1944
5d357f26
KT
1945rtx
1946aarch64_crc32_expand_builtin (int fcode, tree exp, rtx target)
1947{
1948 rtx pat;
1949 aarch64_crc_builtin_datum *d
1950 = &aarch64_crc_builtin_data[fcode - (AARCH64_CRC32_BUILTIN_BASE + 1)];
1951 enum insn_code icode = d->icode;
1952 tree arg0 = CALL_EXPR_ARG (exp, 0);
1953 tree arg1 = CALL_EXPR_ARG (exp, 1);
1954 rtx op0 = expand_normal (arg0);
1955 rtx op1 = expand_normal (arg1);
ef4bddc2
RS
1956 machine_mode tmode = insn_data[icode].operand[0].mode;
1957 machine_mode mode0 = insn_data[icode].operand[1].mode;
1958 machine_mode mode1 = insn_data[icode].operand[2].mode;
5d357f26
KT
1959
1960 if (! target
1961 || GET_MODE (target) != tmode
1962 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1963 target = gen_reg_rtx (tmode);
1964
1965 gcc_assert ((GET_MODE (op0) == mode0 || GET_MODE (op0) == VOIDmode)
1966 && (GET_MODE (op1) == mode1 || GET_MODE (op1) == VOIDmode));
1967
1968 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1969 op0 = copy_to_mode_reg (mode0, op0);
1970 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
1971 op1 = copy_to_mode_reg (mode1, op1);
1972
1973 pat = GEN_FCN (icode) (target, op0, op1);
d5a29419
KT
1974 if (!pat)
1975 return NULL_RTX;
1976
5d357f26
KT
1977 emit_insn (pat);
1978 return target;
1979}
1980
a6fc00da
BH
1981/* Function to expand reciprocal square root builtins. */
1982
1983static rtx
1984aarch64_expand_builtin_rsqrt (int fcode, tree exp, rtx target)
1985{
1986 tree arg0 = CALL_EXPR_ARG (exp, 0);
1987 rtx op0 = expand_normal (arg0);
1988
1989 rtx (*gen) (rtx, rtx);
1990
1991 switch (fcode)
1992 {
1993 case AARCH64_BUILTIN_RSQRT_DF:
ee62a5a6 1994 gen = gen_rsqrtdf2;
a6fc00da
BH
1995 break;
1996 case AARCH64_BUILTIN_RSQRT_SF:
ee62a5a6 1997 gen = gen_rsqrtsf2;
a6fc00da
BH
1998 break;
1999 case AARCH64_BUILTIN_RSQRT_V2DF:
ee62a5a6 2000 gen = gen_rsqrtv2df2;
a6fc00da
BH
2001 break;
2002 case AARCH64_BUILTIN_RSQRT_V2SF:
ee62a5a6 2003 gen = gen_rsqrtv2sf2;
a6fc00da
BH
2004 break;
2005 case AARCH64_BUILTIN_RSQRT_V4SF:
ee62a5a6 2006 gen = gen_rsqrtv4sf2;
a6fc00da
BH
2007 break;
2008 default: gcc_unreachable ();
2009 }
2010
2011 if (!target)
2012 target = gen_reg_rtx (GET_MODE (op0));
2013
2014 emit_insn (gen (target, op0));
2015
2016 return target;
2017}
2018
9d63f43b
TC
2019/* Expand a FCMLA lane expression EXP with code FCODE and
2020 result going to TARGET if that is convenient. */
2021
2022rtx
2023aarch64_expand_fcmla_builtin (tree exp, rtx target, int fcode)
2024{
2025 int bcode = fcode - AARCH64_SIMD_FCMLA_LANEQ_BUILTIN_BASE - 1;
2026 aarch64_fcmla_laneq_builtin_datum* d
2027 = &aarch64_fcmla_lane_builtin_data[bcode];
2028 machine_mode quadmode = GET_MODE_2XWIDER_MODE (d->mode).require ();
2029 rtx op0 = force_reg (d->mode, expand_normal (CALL_EXPR_ARG (exp, 0)));
2030 rtx op1 = force_reg (d->mode, expand_normal (CALL_EXPR_ARG (exp, 1)));
2031 rtx op2 = force_reg (quadmode, expand_normal (CALL_EXPR_ARG (exp, 2)));
2032 tree tmp = CALL_EXPR_ARG (exp, 3);
2033 rtx lane_idx = expand_expr (tmp, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
2034
2035 /* Validate that the lane index is a constant. */
2036 if (!CONST_INT_P (lane_idx))
2037 {
62e43587
MS
2038 error_at (EXPR_LOCATION (exp),
2039 "argument %d must be a constant immediate", 4);
9d63f43b
TC
2040 return const0_rtx;
2041 }
2042
2043 /* Validate that the index is within the expected range. */
2044 int nunits = GET_MODE_NUNITS (quadmode).to_constant ();
2045 aarch64_simd_lane_bounds (lane_idx, 0, nunits / 2, exp);
2046
9d63f43b
TC
2047 /* Generate the correct register and mode. */
2048 int lane = INTVAL (lane_idx);
2049
2050 if (lane < nunits / 4)
33b5a38c
TC
2051 op2 = simplify_gen_subreg (d->mode, op2, quadmode,
2052 subreg_lowpart_offset (d->mode, quadmode));
9d63f43b
TC
2053 else
2054 {
2055 /* Select the upper 64 bits, either a V2SF or V4HF, this however
2056 is quite messy, as the operation required even though simple
2057 doesn't have a simple RTL pattern, and seems it's quite hard to
2058 define using a single RTL pattern. The target generic version
2059 gen_highpart_mode generates code that isn't optimal. */
2060 rtx temp1 = gen_reg_rtx (d->mode);
2061 rtx temp2 = gen_reg_rtx (DImode);
33b5a38c
TC
2062 temp1 = simplify_gen_subreg (d->mode, op2, quadmode,
2063 subreg_lowpart_offset (d->mode, quadmode));
9d63f43b 2064 temp1 = simplify_gen_subreg (V2DImode, temp1, d->mode, 0);
33b5a38c
TC
2065 if (BYTES_BIG_ENDIAN)
2066 emit_insn (gen_aarch64_get_lanev2di (temp2, temp1, const0_rtx));
2067 else
2068 emit_insn (gen_aarch64_get_lanev2di (temp2, temp1, const1_rtx));
9d63f43b
TC
2069 op2 = simplify_gen_subreg (d->mode, temp2, GET_MODE (temp2), 0);
2070
2071 /* And recalculate the index. */
2072 lane -= nunits / 4;
2073 }
2074
33b5a38c
TC
2075 /* Keep to GCC-vector-extension lane indices in the RTL, only nunits / 4
2076 (max nunits in range check) are valid. Which means only 0-1, so we
2077 only need to know the order in a V2mode. */
2078 lane_idx = aarch64_endian_lane_rtx (V2DImode, lane);
2079
fa59c8dc
AC
2080 if (!target
2081 || !REG_P (target)
2082 || GET_MODE (target) != d->mode)
9d63f43b 2083 target = gen_reg_rtx (d->mode);
9d63f43b
TC
2084
2085 rtx pat = NULL_RTX;
2086
2087 if (d->lane)
33b5a38c 2088 pat = GEN_FCN (d->icode) (target, op0, op1, op2, lane_idx);
9d63f43b
TC
2089 else
2090 pat = GEN_FCN (d->icode) (target, op0, op1, op2);
2091
2092 if (!pat)
2093 return NULL_RTX;
2094
2095 emit_insn (pat);
2096 return target;
2097}
2098
89626179
SD
2099/* Function to expand an expression EXP which calls one of the Transactional
2100 Memory Extension (TME) builtins FCODE with the result going to TARGET. */
2101static rtx
2102aarch64_expand_builtin_tme (int fcode, tree exp, rtx target)
2103{
2104 switch (fcode)
2105 {
2106 case AARCH64_TME_BUILTIN_TSTART:
2107 target = gen_reg_rtx (DImode);
2108 emit_insn (GEN_FCN (CODE_FOR_tstart) (target));
2109 break;
2110
2111 case AARCH64_TME_BUILTIN_TTEST:
2112 target = gen_reg_rtx (DImode);
2113 emit_insn (GEN_FCN (CODE_FOR_ttest) (target));
2114 break;
2115
2116 case AARCH64_TME_BUILTIN_TCOMMIT:
2117 emit_insn (GEN_FCN (CODE_FOR_tcommit) ());
2118 break;
2119
2120 case AARCH64_TME_BUILTIN_TCANCEL:
2121 {
2122 tree arg0 = CALL_EXPR_ARG (exp, 0);
2123 rtx op0 = expand_normal (arg0);
2124 if (CONST_INT_P (op0) && UINTVAL (op0) <= 65536)
2125 emit_insn (GEN_FCN (CODE_FOR_tcancel) (op0));
2126 else
2127 {
62e43587
MS
2128 error_at (EXPR_LOCATION (exp),
2129 "argument must be a 16-bit constant immediate");
89626179
SD
2130 return const0_rtx;
2131 }
2132 }
2133 break;
2134
2135 default :
2136 gcc_unreachable ();
2137 }
2138 return target;
2139}
2140
c5dc215d
KT
2141/* Expand a random number builtin EXP with code FCODE, putting the result
2142 int TARGET. If IGNORE is true the return value is ignored. */
2143
2144rtx
2145aarch64_expand_rng_builtin (tree exp, rtx target, int fcode, int ignore)
2146{
2147 rtx pat;
2148 enum insn_code icode;
2149 if (fcode == AARCH64_BUILTIN_RNG_RNDR)
2150 icode = CODE_FOR_aarch64_rndr;
2151 else if (fcode == AARCH64_BUILTIN_RNG_RNDRRS)
2152 icode = CODE_FOR_aarch64_rndrrs;
2153 else
2154 gcc_unreachable ();
2155
2156 rtx rand = gen_reg_rtx (DImode);
2157 pat = GEN_FCN (icode) (rand);
2158 if (!pat)
2159 return NULL_RTX;
2160
2161 tree arg0 = CALL_EXPR_ARG (exp, 0);
2162 rtx res_addr = expand_normal (arg0);
2163 res_addr = convert_memory_address (Pmode, res_addr);
2164 rtx res_mem = gen_rtx_MEM (DImode, res_addr);
2165 emit_insn (pat);
2166 emit_move_insn (res_mem, rand);
2167 /* If the status result is unused don't generate the CSET code. */
2168 if (ignore)
2169 return target;
2170
2171 rtx cc_reg = gen_rtx_REG (CC_Zmode, CC_REGNUM);
f7581eb3 2172 rtx cmp_rtx = gen_rtx_fmt_ee (EQ, SImode, cc_reg, const0_rtx);
c5dc215d
KT
2173 emit_insn (gen_aarch64_cstoresi (target, cmp_rtx, cc_reg));
2174 return target;
2175}
2176
ef01e6bb
DZ
2177/* Expand an expression EXP that calls a MEMTAG built-in FCODE
2178 with result going to TARGET. */
2179static rtx
2180aarch64_expand_builtin_memtag (int fcode, tree exp, rtx target)
2181{
2182 if (TARGET_ILP32)
2183 {
2184 error ("Memory Tagging Extension does not support %<-mabi=ilp32%>");
2185 return const0_rtx;
2186 }
2187
2188 rtx pat = NULL;
2189 enum insn_code icode = aarch64_memtag_builtin_data[fcode -
2190 AARCH64_MEMTAG_BUILTIN_START - 1].icode;
2191
2192 rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
2193 machine_mode mode0 = GET_MODE (op0);
2194 op0 = force_reg (mode0 == VOIDmode ? DImode : mode0, op0);
2195 op0 = convert_to_mode (DImode, op0, true);
2196
2197 switch (fcode)
2198 {
2199 case AARCH64_MEMTAG_BUILTIN_IRG:
2200 case AARCH64_MEMTAG_BUILTIN_GMI:
2201 case AARCH64_MEMTAG_BUILTIN_SUBP:
2202 case AARCH64_MEMTAG_BUILTIN_INC_TAG:
2203 {
2204 if (! target
2205 || GET_MODE (target) != DImode
2206 || ! (*insn_data[icode].operand[0].predicate) (target, DImode))
2207 target = gen_reg_rtx (DImode);
2208
2209 if (fcode == AARCH64_MEMTAG_BUILTIN_INC_TAG)
2210 {
2211 rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
2212
2213 if ((*insn_data[icode].operand[3].predicate) (op1, QImode))
2214 {
2215 pat = GEN_FCN (icode) (target, op0, const0_rtx, op1);
2216 break;
2217 }
62e43587
MS
2218 error_at (EXPR_LOCATION (exp),
2219 "argument %d must be a constant immediate "
2220 "in range [0,15]", 2);
ef01e6bb
DZ
2221 return const0_rtx;
2222 }
2223 else
2224 {
2225 rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
2226 machine_mode mode1 = GET_MODE (op1);
2227 op1 = force_reg (mode1 == VOIDmode ? DImode : mode1, op1);
2228 op1 = convert_to_mode (DImode, op1, true);
2229 pat = GEN_FCN (icode) (target, op0, op1);
2230 }
2231 break;
2232 }
2233 case AARCH64_MEMTAG_BUILTIN_GET_TAG:
2234 target = op0;
2235 pat = GEN_FCN (icode) (target, op0, const0_rtx);
2236 break;
2237 case AARCH64_MEMTAG_BUILTIN_SET_TAG:
2238 pat = GEN_FCN (icode) (op0, op0, const0_rtx);
2239 break;
2240 default:
2241 gcc_unreachable();
2242 }
2243
2244 if (!pat)
2245 return NULL_RTX;
2246
2247 emit_insn (pat);
2248 return target;
2249}
2250
f5e73de0 2251/* Expand an expression EXP as fpsr or fpcr setter (depending on
0d7e5fa6
AC
2252 UNSPEC) using MODE. */
2253static void
2254aarch64_expand_fpsr_fpcr_setter (int unspec, machine_mode mode, tree exp)
2255{
2256 tree arg = CALL_EXPR_ARG (exp, 0);
2257 rtx op = force_reg (mode, expand_normal (arg));
2258 emit_insn (gen_aarch64_set (unspec, mode, op));
2259}
2260
f5e73de0
AC
2261/* Expand a fpsr or fpcr getter (depending on UNSPEC) using MODE.
2262 Return the target. */
2263static rtx
2264aarch64_expand_fpsr_fpcr_getter (enum insn_code icode, machine_mode mode,
2265 rtx target)
2266{
2267 expand_operand op;
2268 create_output_operand (&op, target, mode);
2269 expand_insn (icode, 1, &op);
2270 return op.value;
2271}
2272
6d4d616a 2273/* Expand an expression EXP that calls built-in function FCODE,
c5dc215d
KT
2274 with result going to TARGET if that's convenient. IGNORE is true
2275 if the result of the builtin is ignored. */
342be7f7 2276rtx
c5dc215d
KT
2277aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target,
2278 int ignore)
342be7f7 2279{
aa87aced 2280 int icode;
0d7e5fa6 2281 rtx op0;
aa87aced
KV
2282 tree arg0;
2283
2284 switch (fcode)
2285 {
2286 case AARCH64_BUILTIN_GET_FPCR:
f5e73de0
AC
2287 return aarch64_expand_fpsr_fpcr_getter (CODE_FOR_aarch64_get_fpcrsi,
2288 SImode, target);
aa87aced 2289 case AARCH64_BUILTIN_SET_FPCR:
0d7e5fa6
AC
2290 aarch64_expand_fpsr_fpcr_setter (UNSPECV_SET_FPCR, SImode, exp);
2291 return target;
aa87aced 2292 case AARCH64_BUILTIN_GET_FPSR:
f5e73de0
AC
2293 return aarch64_expand_fpsr_fpcr_getter (CODE_FOR_aarch64_get_fpsrsi,
2294 SImode, target);
aa87aced 2295 case AARCH64_BUILTIN_SET_FPSR:
0d7e5fa6
AC
2296 aarch64_expand_fpsr_fpcr_setter (UNSPECV_SET_FPSR, SImode, exp);
2297 return target;
2298 case AARCH64_BUILTIN_GET_FPCR64:
f5e73de0
AC
2299 return aarch64_expand_fpsr_fpcr_getter (CODE_FOR_aarch64_get_fpcrdi,
2300 DImode, target);
0d7e5fa6
AC
2301 case AARCH64_BUILTIN_SET_FPCR64:
2302 aarch64_expand_fpsr_fpcr_setter (UNSPECV_SET_FPCR, DImode, exp);
2303 return target;
2304 case AARCH64_BUILTIN_GET_FPSR64:
f5e73de0
AC
2305 return aarch64_expand_fpsr_fpcr_getter (CODE_FOR_aarch64_get_fpsrdi,
2306 DImode, target);
0d7e5fa6
AC
2307 case AARCH64_BUILTIN_SET_FPSR64:
2308 aarch64_expand_fpsr_fpcr_setter (UNSPECV_SET_FPSR, DImode, exp);
aa87aced 2309 return target;
312492bd
JW
2310 case AARCH64_PAUTH_BUILTIN_AUTIA1716:
2311 case AARCH64_PAUTH_BUILTIN_PACIA1716:
8fc16d72
ST
2312 case AARCH64_PAUTH_BUILTIN_AUTIB1716:
2313 case AARCH64_PAUTH_BUILTIN_PACIB1716:
312492bd
JW
2314 case AARCH64_PAUTH_BUILTIN_XPACLRI:
2315 arg0 = CALL_EXPR_ARG (exp, 0);
2316 op0 = force_reg (Pmode, expand_normal (arg0));
2317
312492bd
JW
2318 if (fcode == AARCH64_PAUTH_BUILTIN_XPACLRI)
2319 {
2320 rtx lr = gen_rtx_REG (Pmode, R30_REGNUM);
2321 icode = CODE_FOR_xpaclri;
2322 emit_move_insn (lr, op0);
2323 emit_insn (GEN_FCN (icode) ());
92f0d3d0 2324 return lr;
312492bd
JW
2325 }
2326 else
2327 {
2328 tree arg1 = CALL_EXPR_ARG (exp, 1);
2329 rtx op1 = force_reg (Pmode, expand_normal (arg1));
8fc16d72
ST
2330 switch (fcode)
2331 {
2332 case AARCH64_PAUTH_BUILTIN_AUTIA1716:
2333 icode = CODE_FOR_autia1716;
2334 break;
2335 case AARCH64_PAUTH_BUILTIN_AUTIB1716:
2336 icode = CODE_FOR_autib1716;
2337 break;
2338 case AARCH64_PAUTH_BUILTIN_PACIA1716:
2339 icode = CODE_FOR_pacia1716;
2340 break;
2341 case AARCH64_PAUTH_BUILTIN_PACIB1716:
2342 icode = CODE_FOR_pacib1716;
2343 break;
2344 default:
2345 icode = 0;
2346 gcc_unreachable ();
2347 }
312492bd
JW
2348
2349 rtx x16_reg = gen_rtx_REG (Pmode, R16_REGNUM);
2350 rtx x17_reg = gen_rtx_REG (Pmode, R17_REGNUM);
2351 emit_move_insn (x17_reg, op0);
2352 emit_move_insn (x16_reg, op1);
2353 emit_insn (GEN_FCN (icode) ());
92f0d3d0 2354 return x17_reg;
312492bd
JW
2355 }
2356
e1d5d19e 2357 case AARCH64_JSCVT:
2c62952f
AC
2358 {
2359 expand_operand ops[2];
2360 create_output_operand (&ops[0], target, SImode);
2361 op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
2362 create_input_operand (&ops[1], op0, DFmode);
2363 expand_insn (CODE_FOR_aarch64_fjcvtzs, 2, ops);
2364 return ops[0].value;
2365 }
e1d5d19e 2366
9d63f43b
TC
2367 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ0_V2SF:
2368 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ90_V2SF:
2369 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ180_V2SF:
2370 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ270_V2SF:
2371 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ0_V4HF:
2372 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ90_V4HF:
2373 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ180_V4HF:
2374 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ270_V4HF:
2375 return aarch64_expand_fcmla_builtin (exp, target, fcode);
c5dc215d
KT
2376 case AARCH64_BUILTIN_RNG_RNDR:
2377 case AARCH64_BUILTIN_RNG_RNDRRS:
2378 return aarch64_expand_rng_builtin (exp, target, fcode, ignore);
aa87aced 2379 }
342be7f7 2380
5d357f26 2381 if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
342be7f7 2382 return aarch64_simd_expand_builtin (fcode, exp, target);
5d357f26
KT
2383 else if (fcode >= AARCH64_CRC32_BUILTIN_BASE && fcode <= AARCH64_CRC32_BUILTIN_MAX)
2384 return aarch64_crc32_expand_builtin (fcode, exp, target);
342be7f7 2385
a6fc00da
BH
2386 if (fcode == AARCH64_BUILTIN_RSQRT_DF
2387 || fcode == AARCH64_BUILTIN_RSQRT_SF
2388 || fcode == AARCH64_BUILTIN_RSQRT_V2DF
2389 || fcode == AARCH64_BUILTIN_RSQRT_V2SF
2390 || fcode == AARCH64_BUILTIN_RSQRT_V4SF)
2391 return aarch64_expand_builtin_rsqrt (fcode, exp, target);
2392
89626179
SD
2393 if (fcode == AARCH64_TME_BUILTIN_TSTART
2394 || fcode == AARCH64_TME_BUILTIN_TCOMMIT
2395 || fcode == AARCH64_TME_BUILTIN_TTEST
2396 || fcode == AARCH64_TME_BUILTIN_TCANCEL)
2397 return aarch64_expand_builtin_tme (fcode, exp, target);
2398
ef01e6bb
DZ
2399 if (fcode >= AARCH64_MEMTAG_BUILTIN_START
2400 && fcode <= AARCH64_MEMTAG_BUILTIN_END)
2401 return aarch64_expand_builtin_memtag (fcode, exp, target);
2402
d5a29419 2403 gcc_unreachable ();
342be7f7 2404}
42fc9a7f
JG
2405
2406tree
10766209
RS
2407aarch64_builtin_vectorized_function (unsigned int fn, tree type_out,
2408 tree type_in)
42fc9a7f 2409{
ef4bddc2 2410 machine_mode in_mode, out_mode;
42fc9a7f
JG
2411
2412 if (TREE_CODE (type_out) != VECTOR_TYPE
2413 || TREE_CODE (type_in) != VECTOR_TYPE)
2414 return NULL_TREE;
2415
7cee9637
RS
2416 out_mode = TYPE_MODE (type_out);
2417 in_mode = TYPE_MODE (type_in);
42fc9a7f
JG
2418
2419#undef AARCH64_CHECK_BUILTIN_MODE
2420#define AARCH64_CHECK_BUILTIN_MODE(C, N) 1
2421#define AARCH64_FIND_FRINT_VARIANT(N) \
2422 (AARCH64_CHECK_BUILTIN_MODE (2, D) \
e993fea1 2423 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2df] \
42fc9a7f 2424 : (AARCH64_CHECK_BUILTIN_MODE (4, S) \
e993fea1 2425 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v4sf] \
42fc9a7f 2426 : (AARCH64_CHECK_BUILTIN_MODE (2, S) \
e993fea1 2427 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2sf] \
42fc9a7f 2428 : NULL_TREE)))
10766209 2429 switch (fn)
42fc9a7f 2430 {
42fc9a7f
JG
2431#undef AARCH64_CHECK_BUILTIN_MODE
2432#define AARCH64_CHECK_BUILTIN_MODE(C, N) \
7cee9637 2433 (out_mode == V##C##N##Fmode && in_mode == V##C##N##Fmode)
10766209
RS
2434 CASE_CFN_FLOOR:
2435 return AARCH64_FIND_FRINT_VARIANT (floor);
2436 CASE_CFN_CEIL:
2437 return AARCH64_FIND_FRINT_VARIANT (ceil);
2438 CASE_CFN_TRUNC:
2439 return AARCH64_FIND_FRINT_VARIANT (btrunc);
2440 CASE_CFN_ROUND:
2441 return AARCH64_FIND_FRINT_VARIANT (round);
2442 CASE_CFN_NEARBYINT:
2443 return AARCH64_FIND_FRINT_VARIANT (nearbyint);
2444 CASE_CFN_SQRT:
2445 return AARCH64_FIND_FRINT_VARIANT (sqrt);
42fc9a7f 2446#undef AARCH64_CHECK_BUILTIN_MODE
b5574232 2447#define AARCH64_CHECK_BUILTIN_MODE(C, N) \
7cee9637 2448 (out_mode == V##C##SImode && in_mode == V##C##N##Imode)
10766209
RS
2449 CASE_CFN_CLZ:
2450 {
2451 if (AARCH64_CHECK_BUILTIN_MODE (4, S))
2452 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_clzv4si];
2453 return NULL_TREE;
2454 }
2455 CASE_CFN_CTZ:
2456 {
2457 if (AARCH64_CHECK_BUILTIN_MODE (2, S))
2458 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv2si];
2459 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
2460 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv4si];
2461 return NULL_TREE;
2462 }
b5574232 2463#undef AARCH64_CHECK_BUILTIN_MODE
42fc9a7f 2464#define AARCH64_CHECK_BUILTIN_MODE(C, N) \
7cee9637 2465 (out_mode == V##C##N##Imode && in_mode == V##C##N##Fmode)
10766209
RS
2466 CASE_CFN_IFLOOR:
2467 CASE_CFN_LFLOOR:
2468 CASE_CFN_LLFLOOR:
2469 {
2470 enum aarch64_builtins builtin;
2471 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
2472 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2dfv2di;
2473 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
2474 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv4sfv4si;
2475 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
2476 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2sfv2si;
2477 else
2478 return NULL_TREE;
2479
2480 return aarch64_builtin_decls[builtin];
2481 }
2482 CASE_CFN_ICEIL:
2483 CASE_CFN_LCEIL:
2484 CASE_CFN_LLCEIL:
2485 {
2486 enum aarch64_builtins builtin;
2487 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
2488 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2dfv2di;
2489 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
2490 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv4sfv4si;
2491 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
2492 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2sfv2si;
2493 else
2494 return NULL_TREE;
2495
2496 return aarch64_builtin_decls[builtin];
2497 }
2498 CASE_CFN_IROUND:
2499 CASE_CFN_LROUND:
2500 CASE_CFN_LLROUND:
2501 {
2502 enum aarch64_builtins builtin;
2503 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
2504 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2dfv2di;
2505 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
2506 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv4sfv4si;
2507 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
2508 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2sfv2si;
2509 else
2510 return NULL_TREE;
2511
2512 return aarch64_builtin_decls[builtin];
2513 }
10766209
RS
2514 default:
2515 return NULL_TREE;
42fc9a7f
JG
2516 }
2517
2518 return NULL_TREE;
2519}
0ac198d3 2520
a6fc00da
BH
2521/* Return builtin for reciprocal square root. */
2522
2523tree
6d4d616a 2524aarch64_general_builtin_rsqrt (unsigned int fn)
a6fc00da 2525{
ee62a5a6
RS
2526 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv2df)
2527 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V2DF];
2528 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv2sf)
2529 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V2SF];
2530 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv4sf)
2531 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V4SF];
a6fc00da
BH
2532 return NULL_TREE;
2533}
2534
03312cbd
AP
2535/* Return true if the lane check can be removed as there is no
2536 error going to be emitted. */
2537static bool
2538aarch64_fold_builtin_lane_check (tree arg0, tree arg1, tree arg2)
2539{
2540 if (TREE_CODE (arg0) != INTEGER_CST)
2541 return false;
2542 if (TREE_CODE (arg1) != INTEGER_CST)
2543 return false;
2544 if (TREE_CODE (arg2) != INTEGER_CST)
2545 return false;
2546
2547 auto totalsize = wi::to_widest (arg0);
2548 auto elementsize = wi::to_widest (arg1);
2549 if (totalsize == 0 || elementsize == 0)
2550 return false;
2551 auto lane = wi::to_widest (arg2);
2552 auto high = wi::udiv_trunc (totalsize, elementsize);
2553 return wi::ltu_p (lane, high);
2554}
2555
0ac198d3 2556#undef VAR1
bf592b2f 2557#define VAR1(T, N, MAP, FLAG, A) \
e993fea1 2558 case AARCH64_SIMD_BUILTIN_##T##_##N##A:
0ac198d3 2559
6d4d616a
RS
2560/* Try to fold a call to the built-in function with subcode FCODE. The
2561 function is passed the N_ARGS arguments in ARGS and it returns a value
2562 of type TYPE. Return the new expression on success and NULL_TREE on
2563 failure. */
9697e620 2564tree
6d4d616a
RS
2565aarch64_general_fold_builtin (unsigned int fcode, tree type,
2566 unsigned int n_args ATTRIBUTE_UNUSED, tree *args)
9697e620 2567{
9697e620
JG
2568 switch (fcode)
2569 {
bf592b2f 2570 BUILTIN_VDQF (UNOP, abs, 2, ALL)
9697e620 2571 return fold_build1 (ABS_EXPR, type, args[0]);
bf592b2f 2572 VAR1 (UNOP, floatv2si, 2, ALL, v2sf)
2573 VAR1 (UNOP, floatv4si, 2, ALL, v4sf)
2574 VAR1 (UNOP, floatv2di, 2, ALL, v2df)
1709ff9b 2575 return fold_build1 (FLOAT_EXPR, type, args[0]);
03312cbd
AP
2576 case AARCH64_SIMD_BUILTIN_LANE_CHECK:
2577 gcc_assert (n_args == 3);
2578 if (aarch64_fold_builtin_lane_check (args[0], args[1], args[2]))
2579 return void_node;
2580 break;
9697e620
JG
2581 default:
2582 break;
2583 }
2584
2585 return NULL_TREE;
2586}
2587
ad44c6a5
ASDV
2588enum aarch64_simd_type
2589get_mem_type_for_load_store (unsigned int fcode)
2590{
2591 switch (fcode)
2592 {
2593 VAR1 (LOAD1, ld1 , 0, LOAD, v8qi)
2594 VAR1 (STORE1, st1 , 0, STORE, v8qi)
2595 return Int8x8_t;
2596 VAR1 (LOAD1, ld1 , 0, LOAD, v16qi)
2597 VAR1 (STORE1, st1 , 0, STORE, v16qi)
2598 return Int8x16_t;
2599 VAR1 (LOAD1, ld1 , 0, LOAD, v4hi)
2600 VAR1 (STORE1, st1 , 0, STORE, v4hi)
2601 return Int16x4_t;
2602 VAR1 (LOAD1, ld1 , 0, LOAD, v8hi)
2603 VAR1 (STORE1, st1 , 0, STORE, v8hi)
2604 return Int16x8_t;
2605 VAR1 (LOAD1, ld1 , 0, LOAD, v2si)
2606 VAR1 (STORE1, st1 , 0, STORE, v2si)
2607 return Int32x2_t;
2608 VAR1 (LOAD1, ld1 , 0, LOAD, v4si)
2609 VAR1 (STORE1, st1 , 0, STORE, v4si)
2610 return Int32x4_t;
2611 VAR1 (LOAD1, ld1 , 0, LOAD, v2di)
2612 VAR1 (STORE1, st1 , 0, STORE, v2di)
2613 return Int64x2_t;
2614 VAR1 (LOAD1, ld1 , 0, LOAD, v4hf)
2615 VAR1 (STORE1, st1 , 0, STORE, v4hf)
2616 return Float16x4_t;
2617 VAR1 (LOAD1, ld1 , 0, LOAD, v8hf)
2618 VAR1 (STORE1, st1 , 0, STORE, v8hf)
2619 return Float16x8_t;
2620 VAR1 (LOAD1, ld1 , 0, LOAD, v4bf)
2621 VAR1 (STORE1, st1 , 0, STORE, v4bf)
2622 return Bfloat16x4_t;
2623 VAR1 (LOAD1, ld1 , 0, LOAD, v8bf)
2624 VAR1 (STORE1, st1 , 0, STORE, v8bf)
2625 return Bfloat16x8_t;
2626 VAR1 (LOAD1, ld1 , 0, LOAD, v2sf)
2627 VAR1 (STORE1, st1 , 0, STORE, v2sf)
2628 return Float32x2_t;
2629 VAR1 (LOAD1, ld1 , 0, LOAD, v4sf)
2630 VAR1 (STORE1, st1 , 0, STORE, v4sf)
2631 return Float32x4_t;
2632 VAR1 (LOAD1, ld1 , 0, LOAD, v2df)
2633 VAR1 (STORE1, st1 , 0, STORE, v2df)
2634 return Float64x2_t;
2635 default:
2636 gcc_unreachable ();
2637 break;
2638 }
2639}
2640
6d4d616a
RS
2641/* Try to fold STMT, given that it's a call to the built-in function with
2642 subcode FCODE. Return the new statement on success and null on
2643 failure. */
2644gimple *
ad44c6a5
ASDV
2645aarch64_general_gimple_fold_builtin (unsigned int fcode, gcall *stmt,
2646 gimple_stmt_iterator *gsi)
0ac198d3 2647{
355fe088 2648 gimple *new_stmt = NULL;
6d4d616a
RS
2649 unsigned nargs = gimple_call_num_args (stmt);
2650 tree *args = (nargs > 0
2651 ? gimple_call_arg_ptr (stmt, 0)
2652 : &error_mark_node);
2653
2654 /* We use gimple's IFN_REDUC_(PLUS|MIN|MAX)s for float, signed int
2655 and unsigned int; it will distinguish according to the types of
2656 the arguments to the __builtin. */
2657 switch (fcode)
0ac198d3 2658 {
bf592b2f 2659 BUILTIN_VALL (UNOP, reduc_plus_scal_, 10, ALL)
6d4d616a
RS
2660 new_stmt = gimple_build_call_internal (IFN_REDUC_PLUS,
2661 1, args[0]);
2662 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
2663 break;
ad44c6a5
ASDV
2664
2665 /*lower store and load neon builtins to gimple. */
2666 BUILTIN_VALL_F16 (LOAD1, ld1, 0, LOAD)
2667 if (!BYTES_BIG_ENDIAN)
2668 {
2669 enum aarch64_simd_type mem_type
2670 = get_mem_type_for_load_store(fcode);
2671 aarch64_simd_type_info simd_type
2672 = aarch64_simd_types[mem_type];
0f685601
AV
2673 tree elt_ptr_type = build_pointer_type_for_mode (simd_type.eltype,
2674 VOIDmode, true);
ad44c6a5 2675 tree zero = build_zero_cst (elt_ptr_type);
0f685601
AV
2676 /* Use element type alignment. */
2677 tree access_type
2678 = build_aligned_type (simd_type.itype,
2679 TYPE_ALIGN (simd_type.eltype));
ad44c6a5
ASDV
2680 new_stmt
2681 = gimple_build_assign (gimple_get_lhs (stmt),
2682 fold_build2 (MEM_REF,
0f685601
AV
2683 access_type,
2684 args[0], zero));
ad44c6a5
ASDV
2685 }
2686 break;
2687
2688 BUILTIN_VALL_F16 (STORE1, st1, 0, STORE)
2689 if (!BYTES_BIG_ENDIAN)
2690 {
2691 enum aarch64_simd_type mem_type
2692 = get_mem_type_for_load_store(fcode);
2693 aarch64_simd_type_info simd_type
2694 = aarch64_simd_types[mem_type];
0f685601
AV
2695 tree elt_ptr_type = build_pointer_type_for_mode (simd_type.eltype,
2696 VOIDmode, true);
ad44c6a5 2697 tree zero = build_zero_cst (elt_ptr_type);
0f685601
AV
2698 /* Use element type alignment. */
2699 tree access_type
2700 = build_aligned_type (simd_type.itype,
2701 TYPE_ALIGN (simd_type.eltype));
ad44c6a5 2702 new_stmt
0f685601
AV
2703 = gimple_build_assign (fold_build2 (MEM_REF, access_type,
2704 args[0], zero),
2705 args[1]);
ad44c6a5
ASDV
2706 }
2707 break;
2708
bf592b2f 2709 BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10, ALL)
2710 BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10, ALL)
6d4d616a
RS
2711 new_stmt = gimple_build_call_internal (IFN_REDUC_MAX,
2712 1, args[0]);
2713 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
2714 break;
bf592b2f 2715 BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10, ALL)
2716 BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10, ALL)
6d4d616a
RS
2717 new_stmt = gimple_build_call_internal (IFN_REDUC_MIN,
2718 1, args[0]);
2719 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
2720 break;
1b4a6359
TC
2721 BUILTIN_VSDQ_I_DI (BINOP, ashl, 3, NONE)
2722 if (TREE_CODE (args[1]) == INTEGER_CST
2723 && wi::ltu_p (wi::to_wide (args[1]), element_precision (args[0])))
2724 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
2725 LSHIFT_EXPR, args[0], args[1]);
2726 break;
2727 BUILTIN_VSDQ_I_DI (BINOP, sshl, 0, NONE)
2728 BUILTIN_VSDQ_I_DI (BINOP_UUS, ushl, 0, NONE)
2729 {
2730 tree cst = args[1];
2731 tree ctype = TREE_TYPE (cst);
2732 /* Left shifts can be both scalar or vector, e.g. uint64x1_t is
2733 treated as a scalar type not a vector one. */
2734 if ((cst = uniform_integer_cst_p (cst)) != NULL_TREE)
2735 {
2736 wide_int wcst = wi::to_wide (cst);
2737 tree unit_ty = TREE_TYPE (cst);
2738
2739 wide_int abs_cst = wi::abs (wcst);
2740 if (wi::geu_p (abs_cst, element_precision (args[0])))
2741 break;
2742
2743 if (wi::neg_p (wcst, TYPE_SIGN (ctype)))
2744 {
2745 tree final_cst;
2746 final_cst = wide_int_to_tree (unit_ty, abs_cst);
2747 if (TREE_CODE (cst) != INTEGER_CST)
2748 final_cst = build_uniform_cst (ctype, final_cst);
2749
2750 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
2751 RSHIFT_EXPR, args[0],
2752 final_cst);
2753 }
2754 else
2755 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
2756 LSHIFT_EXPR, args[0], args[1]);
2757 }
2758 }
2759 break;
2760 BUILTIN_VDQ_I (SHIFTIMM, ashr, 3, NONE)
2761 VAR1 (SHIFTIMM, ashr_simd, 0, NONE, di)
2762 BUILTIN_VDQ_I (USHIFTIMM, lshr, 3, NONE)
2763 VAR1 (USHIFTIMM, lshr_simd, 0, NONE, di)
2764 if (TREE_CODE (args[1]) == INTEGER_CST
2765 && wi::ltu_p (wi::to_wide (args[1]), element_precision (args[0])))
2766 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
2767 RSHIFT_EXPR, args[0], args[1]);
2768 break;
bf592b2f 2769 BUILTIN_GPF (BINOP, fmulx, 0, ALL)
0ac198d3 2770 {
6d4d616a
RS
2771 gcc_assert (nargs == 2);
2772 bool a0_cst_p = TREE_CODE (args[0]) == REAL_CST;
2773 bool a1_cst_p = TREE_CODE (args[1]) == REAL_CST;
2774 if (a0_cst_p || a1_cst_p)
0ac198d3 2775 {
6d4d616a 2776 if (a0_cst_p && a1_cst_p)
546e500c 2777 {
6d4d616a
RS
2778 tree t0 = TREE_TYPE (args[0]);
2779 real_value a0 = (TREE_REAL_CST (args[0]));
2780 real_value a1 = (TREE_REAL_CST (args[1]));
2781 if (real_equal (&a1, &dconst0))
2782 std::swap (a0, a1);
2783 /* According to real_equal (), +0 equals -0. */
2784 if (real_equal (&a0, &dconst0) && real_isinf (&a1))
546e500c 2785 {
6d4d616a
RS
2786 real_value res = dconst2;
2787 res.sign = a0.sign ^ a1.sign;
2788 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
2789 REAL_CST,
2790 build_real (t0, res));
546e500c 2791 }
6d4d616a
RS
2792 else
2793 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
2794 MULT_EXPR,
2795 args[0], args[1]);
546e500c 2796 }
6d4d616a
RS
2797 else /* a0_cst_p ^ a1_cst_p. */
2798 {
2799 real_value const_part = a0_cst_p
2800 ? TREE_REAL_CST (args[0]) : TREE_REAL_CST (args[1]);
2801 if (!real_equal (&const_part, &dconst0)
2802 && !real_isinf (&const_part))
2803 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
2804 MULT_EXPR, args[0],
2805 args[1]);
2806 }
2807 }
2808 if (new_stmt)
2809 {
2810 gimple_set_vuse (new_stmt, gimple_vuse (stmt));
2811 gimple_set_vdef (new_stmt, gimple_vdef (stmt));
0ac198d3 2812 }
6d4d616a 2813 break;
0ac198d3 2814 }
03312cbd
AP
2815 case AARCH64_SIMD_BUILTIN_LANE_CHECK:
2816 if (aarch64_fold_builtin_lane_check (args[0], args[1], args[2]))
2817 {
2818 unlink_stmt_vdef (stmt);
2819 release_defs (stmt);
2820 new_stmt = gimple_build_nop ();
2821 }
2822 break;
6d4d616a
RS
2823 default:
2824 break;
0ac198d3 2825 }
6d4d616a 2826 return new_stmt;
0ac198d3
JG
2827}
2828
aa87aced
KV
2829void
2830aarch64_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
2831{
2832 const unsigned AARCH64_FE_INVALID = 1;
2833 const unsigned AARCH64_FE_DIVBYZERO = 2;
2834 const unsigned AARCH64_FE_OVERFLOW = 4;
2835 const unsigned AARCH64_FE_UNDERFLOW = 8;
2836 const unsigned AARCH64_FE_INEXACT = 16;
2837 const unsigned HOST_WIDE_INT AARCH64_FE_ALL_EXCEPT = (AARCH64_FE_INVALID
2838 | AARCH64_FE_DIVBYZERO
2839 | AARCH64_FE_OVERFLOW
2840 | AARCH64_FE_UNDERFLOW
2841 | AARCH64_FE_INEXACT);
2842 const unsigned HOST_WIDE_INT AARCH64_FE_EXCEPT_SHIFT = 8;
2843 tree fenv_cr, fenv_sr, get_fpcr, set_fpcr, mask_cr, mask_sr;
2844 tree ld_fenv_cr, ld_fenv_sr, masked_fenv_cr, masked_fenv_sr, hold_fnclex_cr;
2845 tree hold_fnclex_sr, new_fenv_var, reload_fenv, restore_fnenv, get_fpsr, set_fpsr;
2846 tree update_call, atomic_feraiseexcept, hold_fnclex, masked_fenv, ld_fenv;
2847
2848 /* Generate the equivalence of :
2849 unsigned int fenv_cr;
2850 fenv_cr = __builtin_aarch64_get_fpcr ();
2851
2852 unsigned int fenv_sr;
2853 fenv_sr = __builtin_aarch64_get_fpsr ();
2854
2855 Now set all exceptions to non-stop
2856 unsigned int mask_cr
2857 = ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT);
2858 unsigned int masked_cr;
2859 masked_cr = fenv_cr & mask_cr;
2860
2861 And clear all exception flags
2862 unsigned int maske_sr = ~AARCH64_FE_ALL_EXCEPT;
2863 unsigned int masked_cr;
2864 masked_sr = fenv_sr & mask_sr;
2865
2866 __builtin_aarch64_set_cr (masked_cr);
2867 __builtin_aarch64_set_sr (masked_sr); */
2868
09ba9ef7
RR
2869 fenv_cr = create_tmp_var_raw (unsigned_type_node);
2870 fenv_sr = create_tmp_var_raw (unsigned_type_node);
aa87aced
KV
2871
2872 get_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR];
2873 set_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR];
2874 get_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR];
2875 set_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR];
2876
2877 mask_cr = build_int_cst (unsigned_type_node,
2878 ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT));
2879 mask_sr = build_int_cst (unsigned_type_node,
2880 ~(AARCH64_FE_ALL_EXCEPT));
2881
d81bc2af
HZ
2882 ld_fenv_cr = build4 (TARGET_EXPR, unsigned_type_node,
2883 fenv_cr, build_call_expr (get_fpcr, 0),
2884 NULL_TREE, NULL_TREE);
2885 ld_fenv_sr = build4 (TARGET_EXPR, unsigned_type_node,
2886 fenv_sr, build_call_expr (get_fpsr, 0),
2887 NULL_TREE, NULL_TREE);
aa87aced
KV
2888
2889 masked_fenv_cr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_cr, mask_cr);
2890 masked_fenv_sr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_sr, mask_sr);
2891
2892 hold_fnclex_cr = build_call_expr (set_fpcr, 1, masked_fenv_cr);
2893 hold_fnclex_sr = build_call_expr (set_fpsr, 1, masked_fenv_sr);
2894
2895 hold_fnclex = build2 (COMPOUND_EXPR, void_type_node, hold_fnclex_cr,
2896 hold_fnclex_sr);
2897 masked_fenv = build2 (COMPOUND_EXPR, void_type_node, masked_fenv_cr,
2898 masked_fenv_sr);
2899 ld_fenv = build2 (COMPOUND_EXPR, void_type_node, ld_fenv_cr, ld_fenv_sr);
2900
2901 *hold = build2 (COMPOUND_EXPR, void_type_node,
2902 build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv),
2903 hold_fnclex);
2904
2905 /* Store the value of masked_fenv to clear the exceptions:
2906 __builtin_aarch64_set_fpsr (masked_fenv_sr); */
2907
2908 *clear = build_call_expr (set_fpsr, 1, masked_fenv_sr);
2909
2910 /* Generate the equivalent of :
2911 unsigned int new_fenv_var;
2912 new_fenv_var = __builtin_aarch64_get_fpsr ();
2913
2914 __builtin_aarch64_set_fpsr (fenv_sr);
2915
2916 __atomic_feraiseexcept (new_fenv_var); */
2917
09ba9ef7 2918 new_fenv_var = create_tmp_var_raw (unsigned_type_node);
d81bc2af
HZ
2919 reload_fenv = build4 (TARGET_EXPR, unsigned_type_node,
2920 new_fenv_var, build_call_expr (get_fpsr, 0),
2921 NULL_TREE, NULL_TREE);
aa87aced
KV
2922 restore_fnenv = build_call_expr (set_fpsr, 1, fenv_sr);
2923 atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT);
2924 update_call = build_call_expr (atomic_feraiseexcept, 1,
2925 fold_convert (integer_type_node, new_fenv_var));
2926 *update = build2 (COMPOUND_EXPR, void_type_node,
2927 build2 (COMPOUND_EXPR, void_type_node,
2928 reload_fenv, restore_fnenv), update_call);
2929}
2930
ef01e6bb
DZ
2931/* Resolve overloaded MEMTAG build-in functions. */
2932#define AARCH64_BUILTIN_SUBCODE(F) \
2933 (DECL_MD_FUNCTION_CODE (F) >> AARCH64_BUILTIN_SHIFT)
2934
2935static tree
2936aarch64_resolve_overloaded_memtag (location_t loc,
2937 tree fndecl, void *pass_params)
2938{
2939 vec<tree, va_gc> *params = static_cast<vec<tree, va_gc> *> (pass_params);
2940 unsigned param_num = params ? params->length() : 0;
2941 unsigned int fcode = AARCH64_BUILTIN_SUBCODE (fndecl);
2942 tree inittype = aarch64_memtag_builtin_data[
2943 fcode - AARCH64_MEMTAG_BUILTIN_START - 1].ftype;
2944 unsigned arg_num = list_length (TYPE_ARG_TYPES (inittype)) - 1;
2945
2946 if (param_num != arg_num)
2947 {
2948 TREE_TYPE (fndecl) = inittype;
2949 return NULL_TREE;
2950 }
2951 tree retype = NULL;
2952
2953 if (fcode == AARCH64_MEMTAG_BUILTIN_SUBP)
2954 {
2955 tree t0 = TREE_TYPE ((*params)[0]);
2956 tree t1 = TREE_TYPE ((*params)[1]);
2957
2958 if (t0 == error_mark_node || TREE_CODE (t0) != POINTER_TYPE)
2959 t0 = ptr_type_node;
2960 if (t1 == error_mark_node || TREE_CODE (t1) != POINTER_TYPE)
2961 t1 = ptr_type_node;
2962
2963 if (TYPE_MODE (t0) != DImode)
2964 warning_at (loc, 1, "expected 64-bit address but argument 1 is %d-bit",
2965 (int)tree_to_shwi (DECL_SIZE ((*params)[0])));
2966
2967 if (TYPE_MODE (t1) != DImode)
2968 warning_at (loc, 1, "expected 64-bit address but argument 2 is %d-bit",
2969 (int)tree_to_shwi (DECL_SIZE ((*params)[1])));
2970
2971 retype = build_function_type_list (ptrdiff_type_node, t0, t1, NULL);
2972 }
2973 else
2974 {
2975 tree t0 = TREE_TYPE ((*params)[0]);
2976
2977 if (t0 == error_mark_node || TREE_CODE (t0) != POINTER_TYPE)
2978 {
2979 TREE_TYPE (fndecl) = inittype;
2980 return NULL_TREE;
2981 }
2982
2983 if (TYPE_MODE (t0) != DImode)
2984 warning_at (loc, 1, "expected 64-bit address but argument 1 is %d-bit",
2985 (int)tree_to_shwi (DECL_SIZE ((*params)[0])));
2986
2987 switch (fcode)
2988 {
2989 case AARCH64_MEMTAG_BUILTIN_IRG:
2990 retype = build_function_type_list (t0, t0, uint64_type_node, NULL);
2991 break;
2992 case AARCH64_MEMTAG_BUILTIN_GMI:
2993 retype = build_function_type_list (uint64_type_node, t0,
2994 uint64_type_node, NULL);
2995 break;
2996 case AARCH64_MEMTAG_BUILTIN_INC_TAG:
2997 retype = build_function_type_list (t0, t0, unsigned_type_node, NULL);
2998 break;
2999 case AARCH64_MEMTAG_BUILTIN_SET_TAG:
3000 retype = build_function_type_list (void_type_node, t0, NULL);
3001 break;
3002 case AARCH64_MEMTAG_BUILTIN_GET_TAG:
3003 retype = build_function_type_list (t0, t0, NULL);
3004 break;
3005 default:
3006 return NULL_TREE;
3007 }
3008 }
3009
3010 if (!retype || retype == error_mark_node)
3011 TREE_TYPE (fndecl) = inittype;
3012 else
3013 TREE_TYPE (fndecl) = retype;
3014
3015 return NULL_TREE;
3016}
3017
3018/* Called at aarch64_resolve_overloaded_builtin in aarch64-c.c. */
3019tree
3020aarch64_resolve_overloaded_builtin_general (location_t loc, tree function,
3021 void *pass_params)
3022{
3023 unsigned int fcode = AARCH64_BUILTIN_SUBCODE (function);
3024
3025 if (fcode >= AARCH64_MEMTAG_BUILTIN_START
3026 && fcode <= AARCH64_MEMTAG_BUILTIN_END)
3027 return aarch64_resolve_overloaded_memtag(loc, function, pass_params);
3028
3029 return NULL_TREE;
3030}
aa87aced 3031
42fc9a7f
JG
3032#undef AARCH64_CHECK_BUILTIN_MODE
3033#undef AARCH64_FIND_FRINT_VARIANT
0ddec79f
JG
3034#undef CF0
3035#undef CF1
3036#undef CF2
3037#undef CF3
3038#undef CF4
3039#undef CF10
3040#undef VAR1
3041#undef VAR2
3042#undef VAR3
3043#undef VAR4
3044#undef VAR5
3045#undef VAR6
3046#undef VAR7
3047#undef VAR8
3048#undef VAR9
3049#undef VAR10
3050#undef VAR11
3051
3c03d39d 3052#include "gt-aarch64-builtins.h"