]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/aarch64/aarch64-builtins.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / config / aarch64 / aarch64-builtins.cc
CommitLineData
43e9d192 1/* Builtins' description for AArch64 SIMD architecture.
a945c346 2 Copyright (C) 2011-2024 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"
fc42900d 50#include "builtins.h"
c5353607 51#include "aarch64-builtins.h"
43e9d192 52
0d4a1197 53#define v8qi_UP E_V8QImode
fdcddba8 54#define v8di_UP E_V8DImode
0d4a1197
RS
55#define v4hi_UP E_V4HImode
56#define v4hf_UP E_V4HFmode
57#define v2si_UP E_V2SImode
58#define v2sf_UP E_V2SFmode
59#define v1df_UP E_V1DFmode
5ba864c5 60#define v1di_UP E_V1DImode
0d4a1197
RS
61#define di_UP E_DImode
62#define df_UP E_DFmode
63#define v16qi_UP E_V16QImode
64#define v8hi_UP E_V8HImode
65#define v8hf_UP E_V8HFmode
66#define v4si_UP E_V4SImode
67#define v4sf_UP E_V4SFmode
68#define v2di_UP E_V2DImode
69#define v2df_UP E_V2DFmode
70#define ti_UP E_TImode
71#define oi_UP E_OImode
72#define ci_UP E_CImode
73#define xi_UP E_XImode
74#define si_UP E_SImode
75#define sf_UP E_SFmode
76#define hi_UP E_HImode
77#define hf_UP E_HFmode
78#define qi_UP E_QImode
abbe1ed2
SMW
79#define bf_UP E_BFmode
80#define v4bf_UP E_V4BFmode
81#define v8bf_UP E_V8BFmode
66f206b8
JW
82#define v2x8qi_UP E_V2x8QImode
83#define v2x4hi_UP E_V2x4HImode
84#define v2x4hf_UP E_V2x4HFmode
85#define v2x4bf_UP E_V2x4BFmode
86#define v2x2si_UP E_V2x2SImode
87#define v2x2sf_UP E_V2x2SFmode
88#define v2x1di_UP E_V2x1DImode
89#define v2x1df_UP E_V2x1DFmode
90#define v2x16qi_UP E_V2x16QImode
91#define v2x8hi_UP E_V2x8HImode
92#define v2x8hf_UP E_V2x8HFmode
93#define v2x8bf_UP E_V2x8BFmode
94#define v2x4si_UP E_V2x4SImode
95#define v2x4sf_UP E_V2x4SFmode
96#define v2x2di_UP E_V2x2DImode
97#define v2x2df_UP E_V2x2DFmode
98#define v3x8qi_UP E_V3x8QImode
99#define v3x4hi_UP E_V3x4HImode
100#define v3x4hf_UP E_V3x4HFmode
101#define v3x4bf_UP E_V3x4BFmode
102#define v3x2si_UP E_V3x2SImode
103#define v3x2sf_UP E_V3x2SFmode
104#define v3x1di_UP E_V3x1DImode
105#define v3x1df_UP E_V3x1DFmode
106#define v3x16qi_UP E_V3x16QImode
107#define v3x8hi_UP E_V3x8HImode
108#define v3x8hf_UP E_V3x8HFmode
109#define v3x8bf_UP E_V3x8BFmode
110#define v3x4si_UP E_V3x4SImode
111#define v3x4sf_UP E_V3x4SFmode
112#define v3x2di_UP E_V3x2DImode
113#define v3x2df_UP E_V3x2DFmode
114#define v4x8qi_UP E_V4x8QImode
115#define v4x4hi_UP E_V4x4HImode
116#define v4x4hf_UP E_V4x4HFmode
117#define v4x4bf_UP E_V4x4BFmode
118#define v4x2si_UP E_V4x2SImode
119#define v4x2sf_UP E_V4x2SFmode
120#define v4x1di_UP E_V4x1DImode
121#define v4x1df_UP E_V4x1DFmode
122#define v4x16qi_UP E_V4x16QImode
123#define v4x8hi_UP E_V4x8HImode
124#define v4x8hf_UP E_V4x8HFmode
125#define v4x8bf_UP E_V4x8BFmode
126#define v4x4si_UP E_V4x4SImode
127#define v4x4sf_UP E_V4x4SFmode
128#define v4x2di_UP E_V4x2DImode
129#define v4x2df_UP E_V4x2DFmode
43e9d192
IB
130#define UP(X) X##_UP
131
c906efc7
AC
132#define MODE_d_bf16 E_V4BFmode
133#define MODE_d_f16 E_V4HFmode
134#define MODE_d_f32 E_V2SFmode
135#define MODE_d_f64 E_V1DFmode
136#define MODE_d_s8 E_V8QImode
137#define MODE_d_s16 E_V4HImode
138#define MODE_d_s32 E_V2SImode
139#define MODE_d_s64 E_V1DImode
140#define MODE_d_u8 E_V8QImode
141#define MODE_d_u16 E_V4HImode
142#define MODE_d_u32 E_V2SImode
143#define MODE_d_u64 E_V1DImode
144#define MODE_d_p8 E_V8QImode
145#define MODE_d_p16 E_V4HImode
146#define MODE_d_p64 E_V1DImode
147#define MODE_q_bf16 E_V8BFmode
148#define MODE_q_f16 E_V8HFmode
149#define MODE_q_f32 E_V4SFmode
150#define MODE_q_f64 E_V2DFmode
151#define MODE_q_s8 E_V16QImode
152#define MODE_q_s16 E_V8HImode
153#define MODE_q_s32 E_V4SImode
154#define MODE_q_s64 E_V2DImode
155#define MODE_q_u8 E_V16QImode
156#define MODE_q_u16 E_V8HImode
157#define MODE_q_u32 E_V4SImode
158#define MODE_q_u64 E_V2DImode
159#define MODE_q_p8 E_V16QImode
160#define MODE_q_p16 E_V8HImode
161#define MODE_q_p64 E_V2DImode
162#define MODE_q_p128 E_TImode
163
164#define QUAL_bf16 qualifier_none
165#define QUAL_f16 qualifier_none
166#define QUAL_f32 qualifier_none
167#define QUAL_f64 qualifier_none
168#define QUAL_s8 qualifier_none
169#define QUAL_s16 qualifier_none
170#define QUAL_s32 qualifier_none
171#define QUAL_s64 qualifier_none
172#define QUAL_u8 qualifier_unsigned
173#define QUAL_u16 qualifier_unsigned
174#define QUAL_u32 qualifier_unsigned
175#define QUAL_u64 qualifier_unsigned
176#define QUAL_p8 qualifier_poly
177#define QUAL_p16 qualifier_poly
178#define QUAL_p64 qualifier_poly
179#define QUAL_p128 qualifier_poly
180
181#define LENGTH_d ""
182#define LENGTH_q "q"
183
184#define SIMD_INTR_MODE(suffix, length) MODE_##length##_##suffix
185#define SIMD_INTR_QUAL(suffix) QUAL_##suffix
186#define SIMD_INTR_LENGTH_CHAR(length) LENGTH_##length
187
b5828b4b
JG
188#define SIMD_MAX_BUILTIN_ARGS 5
189
bf592b2f 190/* Flags that describe what a function might do. */
191const unsigned int FLAG_NONE = 0U;
192const unsigned int FLAG_READ_FPCR = 1U << 0;
193const unsigned int FLAG_RAISE_FP_EXCEPTIONS = 1U << 1;
194const unsigned int FLAG_READ_MEMORY = 1U << 2;
195const unsigned int FLAG_PREFETCH_MEMORY = 1U << 3;
196const unsigned int FLAG_WRITE_MEMORY = 1U << 4;
197
35ffd4d1 198/* Not all FP intrinsics raise FP exceptions or read FPCR register,
199 use this flag to suppress it. */
200const unsigned int FLAG_AUTO_FP = 1U << 5;
201
bf592b2f 202const unsigned int FLAG_FP = FLAG_READ_FPCR | FLAG_RAISE_FP_EXCEPTIONS;
203const unsigned int FLAG_ALL = FLAG_READ_FPCR | FLAG_RAISE_FP_EXCEPTIONS
204 | FLAG_READ_MEMORY | FLAG_PREFETCH_MEMORY | FLAG_WRITE_MEMORY;
2d5aad69 205const unsigned int FLAG_STORE = FLAG_WRITE_MEMORY | FLAG_AUTO_FP;
e8062ad4 206const unsigned int FLAG_LOAD = FLAG_READ_MEMORY | FLAG_AUTO_FP;
bf592b2f 207
43e9d192
IB
208typedef struct
209{
210 const char *name;
ef4bddc2 211 machine_mode mode;
342be7f7
JG
212 const enum insn_code code;
213 unsigned int fcode;
b5828b4b 214 enum aarch64_type_qualifiers *qualifiers;
bf592b2f 215 unsigned int flags;
43e9d192
IB
216} aarch64_simd_builtin_datum;
217
b5828b4b
JG
218static enum aarch64_type_qualifiers
219aarch64_types_unop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
8f905d69 220 = { qualifier_none, qualifier_none };
b5828b4b 221#define TYPES_UNOP (aarch64_types_unop_qualifiers)
5a7a4e80
TB
222static enum aarch64_type_qualifiers
223aarch64_types_unopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
224 = { qualifier_unsigned, qualifier_unsigned };
225#define TYPES_UNOPU (aarch64_types_unopu_qualifiers)
b5828b4b 226static enum aarch64_type_qualifiers
a579f4c7
JW
227aarch64_types_unopus_qualifiers[SIMD_MAX_BUILTIN_ARGS]
228 = { qualifier_unsigned, qualifier_none };
229#define TYPES_UNOPUS (aarch64_types_unopus_qualifiers)
230static enum aarch64_type_qualifiers
b5828b4b
JG
231aarch64_types_binop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
232 = { qualifier_none, qualifier_none, qualifier_maybe_immediate };
233#define TYPES_BINOP (aarch64_types_binop_qualifiers)
234static enum aarch64_type_qualifiers
5a7a4e80
TB
235aarch64_types_binopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
236 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned };
237#define TYPES_BINOPU (aarch64_types_binopu_qualifiers)
7baa225d 238static enum aarch64_type_qualifiers
de10bcce
AL
239aarch64_types_binop_uus_qualifiers[SIMD_MAX_BUILTIN_ARGS]
240 = { qualifier_unsigned, qualifier_unsigned, qualifier_none };
241#define TYPES_BINOP_UUS (aarch64_types_binop_uus_qualifiers)
242static enum aarch64_type_qualifiers
918621d3
AL
243aarch64_types_binop_ssu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
244 = { qualifier_none, qualifier_none, qualifier_unsigned };
245#define TYPES_BINOP_SSU (aarch64_types_binop_ssu_qualifiers)
246static enum aarch64_type_qualifiers
daef0a8c
JW
247aarch64_types_binop_uss_qualifiers[SIMD_MAX_BUILTIN_ARGS]
248 = { qualifier_unsigned, qualifier_none, qualifier_none };
249#define TYPES_BINOP_USS (aarch64_types_binop_uss_qualifiers)
250static enum aarch64_type_qualifiers
7baa225d
TB
251aarch64_types_binopp_qualifiers[SIMD_MAX_BUILTIN_ARGS]
252 = { qualifier_poly, qualifier_poly, qualifier_poly };
253#define TYPES_BINOPP (aarch64_types_binopp_qualifiers)
3caf7f87
JW
254static enum aarch64_type_qualifiers
255aarch64_types_binop_ppu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
256 = { qualifier_poly, qualifier_poly, qualifier_unsigned };
257#define TYPES_BINOP_PPU (aarch64_types_binop_ppu_qualifiers)
7baa225d 258
5a7a4e80 259static enum aarch64_type_qualifiers
b5828b4b
JG
260aarch64_types_ternop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
261 = { qualifier_none, qualifier_none, qualifier_none, qualifier_none };
262#define TYPES_TERNOP (aarch64_types_ternop_qualifiers)
30442682 263static enum aarch64_type_qualifiers
2a49c16d
AL
264aarch64_types_ternop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
265 = { qualifier_none, qualifier_none, qualifier_none, qualifier_lane_index };
266#define TYPES_TERNOP_LANE (aarch64_types_ternop_lane_qualifiers)
267static enum aarch64_type_qualifiers
30442682
TB
268aarch64_types_ternopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
269 = { qualifier_unsigned, qualifier_unsigned,
270 qualifier_unsigned, qualifier_unsigned };
271#define TYPES_TERNOPU (aarch64_types_ternopu_qualifiers)
27086ea3 272static enum aarch64_type_qualifiers
0b839322
WD
273aarch64_types_ternopu_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
274 = { qualifier_unsigned, qualifier_unsigned,
275 qualifier_unsigned, qualifier_lane_index };
276#define TYPES_TERNOPU_LANE (aarch64_types_ternopu_lane_qualifiers)
277static enum aarch64_type_qualifiers
27086ea3
MC
278aarch64_types_ternopu_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
279 = { qualifier_unsigned, qualifier_unsigned,
280 qualifier_unsigned, qualifier_immediate };
281#define TYPES_TERNOPUI (aarch64_types_ternopu_imm_qualifiers)
8c197c85 282static enum aarch64_type_qualifiers
3caf7f87
JW
283aarch64_types_ternop_sssu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
284 = { qualifier_none, qualifier_none, qualifier_none, qualifier_unsigned };
285#define TYPES_TERNOP_SSSU (aarch64_types_ternop_sssu_qualifiers)
286static enum aarch64_type_qualifiers
8c197c85
SMW
287aarch64_types_ternop_ssus_qualifiers[SIMD_MAX_BUILTIN_ARGS]
288 = { qualifier_none, qualifier_none, qualifier_unsigned, qualifier_none };
289#define TYPES_TERNOP_SSUS (aarch64_types_ternop_ssus_qualifiers)
2050ac1a
TC
290static enum aarch64_type_qualifiers
291aarch64_types_ternop_suss_qualifiers[SIMD_MAX_BUILTIN_ARGS]
292 = { qualifier_none, qualifier_unsigned, qualifier_none, qualifier_none };
293#define TYPES_TERNOP_SUSS (aarch64_types_ternop_suss_qualifiers)
3caf7f87
JW
294static enum aarch64_type_qualifiers
295aarch64_types_binop_pppu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
296 = { qualifier_poly, qualifier_poly, qualifier_poly, qualifier_unsigned };
297#define TYPES_TERNOP_PPPU (aarch64_types_binop_pppu_qualifiers)
27086ea3 298
9d63f43b
TC
299static enum aarch64_type_qualifiers
300aarch64_types_quadop_lane_pair_qualifiers[SIMD_MAX_BUILTIN_ARGS]
301 = { qualifier_none, qualifier_none, qualifier_none,
302 qualifier_none, qualifier_lane_pair_index };
303#define TYPES_QUADOP_LANE_PAIR (aarch64_types_quadop_lane_pair_qualifiers)
b5828b4b 304static enum aarch64_type_qualifiers
2a49c16d 305aarch64_types_quadop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
b5828b4b 306 = { qualifier_none, qualifier_none, qualifier_none,
2a49c16d
AL
307 qualifier_none, qualifier_lane_index };
308#define TYPES_QUADOP_LANE (aarch64_types_quadop_lane_qualifiers)
7a08d813
TC
309static enum aarch64_type_qualifiers
310aarch64_types_quadopu_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
311 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
312 qualifier_unsigned, qualifier_lane_index };
313#define TYPES_QUADOPU_LANE (aarch64_types_quadopu_lane_qualifiers)
b5828b4b 314
8c197c85
SMW
315static enum aarch64_type_qualifiers
316aarch64_types_quadopssus_lane_quadtup_qualifiers[SIMD_MAX_BUILTIN_ARGS]
317 = { qualifier_none, qualifier_none, qualifier_unsigned,
318 qualifier_none, qualifier_lane_quadtup_index };
319#define TYPES_QUADOPSSUS_LANE_QUADTUP \
320 (aarch64_types_quadopssus_lane_quadtup_qualifiers)
321static enum aarch64_type_qualifiers
322aarch64_types_quadopsssu_lane_quadtup_qualifiers[SIMD_MAX_BUILTIN_ARGS]
323 = { qualifier_none, qualifier_none, qualifier_none,
324 qualifier_unsigned, qualifier_lane_quadtup_index };
325#define TYPES_QUADOPSSSU_LANE_QUADTUP \
326 (aarch64_types_quadopsssu_lane_quadtup_qualifiers)
327
27086ea3
MC
328static enum aarch64_type_qualifiers
329aarch64_types_quadopu_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
330 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
331 qualifier_unsigned, qualifier_immediate };
332#define TYPES_QUADOPUI (aarch64_types_quadopu_imm_qualifiers)
333
b5828b4b 334static enum aarch64_type_qualifiers
2a49c16d 335aarch64_types_binop_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
b5828b4b 336 = { qualifier_none, qualifier_none, qualifier_immediate };
2a49c16d
AL
337#define TYPES_GETREG (aarch64_types_binop_imm_qualifiers)
338#define TYPES_SHIFTIMM (aarch64_types_binop_imm_qualifiers)
b5828b4b 339static enum aarch64_type_qualifiers
de10bcce
AL
340aarch64_types_shift_to_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS]
341 = { qualifier_unsigned, qualifier_none, qualifier_immediate };
342#define TYPES_SHIFTIMM_USS (aarch64_types_shift_to_unsigned_qualifiers)
343static enum aarch64_type_qualifiers
1f0e9e34
JG
344aarch64_types_fcvt_from_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS]
345 = { qualifier_none, qualifier_unsigned, qualifier_immediate };
346#define TYPES_FCVTIMM_SUS (aarch64_types_fcvt_from_unsigned_qualifiers)
347static enum aarch64_type_qualifiers
252c7556
AV
348aarch64_types_unsigned_shift_qualifiers[SIMD_MAX_BUILTIN_ARGS]
349 = { qualifier_unsigned, qualifier_unsigned, qualifier_immediate };
350#define TYPES_USHIFTIMM (aarch64_types_unsigned_shift_qualifiers)
05f1883c
DC
351#define TYPES_USHIFT2IMM (aarch64_types_ternopu_imm_qualifiers)
352static enum aarch64_type_qualifiers
353aarch64_types_shift2_to_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS]
354 = { qualifier_unsigned, qualifier_unsigned, qualifier_none, qualifier_immediate };
355#define TYPES_SHIFT2IMM_UUSS (aarch64_types_shift2_to_unsigned_qualifiers)
de10bcce 356
159b8724
TC
357static enum aarch64_type_qualifiers
358aarch64_types_ternop_s_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
359 = { qualifier_none, qualifier_none, qualifier_none, qualifier_immediate};
360#define TYPES_SETREG (aarch64_types_ternop_s_imm_qualifiers)
361#define TYPES_SHIFTINSERT (aarch64_types_ternop_s_imm_qualifiers)
362#define TYPES_SHIFTACC (aarch64_types_ternop_s_imm_qualifiers)
05f1883c 363#define TYPES_SHIFT2IMM (aarch64_types_ternop_s_imm_qualifiers)
159b8724
TC
364
365static enum aarch64_type_qualifiers
366aarch64_types_ternop_p_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
367 = { qualifier_poly, qualifier_poly, qualifier_poly, qualifier_immediate};
368#define TYPES_SHIFTINSERTP (aarch64_types_ternop_p_imm_qualifiers)
b5828b4b 369
de10bcce
AL
370static enum aarch64_type_qualifiers
371aarch64_types_unsigned_shiftacc_qualifiers[SIMD_MAX_BUILTIN_ARGS]
372 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
373 qualifier_immediate };
374#define TYPES_USHIFTACC (aarch64_types_unsigned_shiftacc_qualifiers)
375
b5828b4b
JG
376static enum aarch64_type_qualifiers
377aarch64_types_load1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
378 = { qualifier_none, qualifier_const_pointer_map_mode };
379#define TYPES_LOAD1 (aarch64_types_load1_qualifiers)
380#define TYPES_LOADSTRUCT (aarch64_types_load1_qualifiers)
66f206b8
JW
381static enum aarch64_type_qualifiers
382aarch64_types_load1_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
383 = { qualifier_unsigned, qualifier_const_pointer_map_mode };
1716ddd1 384#define TYPES_LOAD1_U (aarch64_types_load1_u_qualifiers)
66f206b8
JW
385#define TYPES_LOADSTRUCT_U (aarch64_types_load1_u_qualifiers)
386static enum aarch64_type_qualifiers
387aarch64_types_load1_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
388 = { qualifier_poly, qualifier_const_pointer_map_mode };
1716ddd1 389#define TYPES_LOAD1_P (aarch64_types_load1_p_qualifiers)
66f206b8
JW
390#define TYPES_LOADSTRUCT_P (aarch64_types_load1_p_qualifiers)
391
3ec1be97
CB
392static enum aarch64_type_qualifiers
393aarch64_types_loadstruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
394 = { qualifier_none, qualifier_const_pointer_map_mode,
4d0a0237 395 qualifier_none, qualifier_struct_load_store_lane_index };
3ec1be97 396#define TYPES_LOADSTRUCT_LANE (aarch64_types_loadstruct_lane_qualifiers)
66f206b8
JW
397static enum aarch64_type_qualifiers
398aarch64_types_loadstruct_lane_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
399 = { qualifier_unsigned, qualifier_const_pointer_map_mode,
400 qualifier_unsigned, qualifier_struct_load_store_lane_index };
401#define TYPES_LOADSTRUCT_LANE_U (aarch64_types_loadstruct_lane_u_qualifiers)
402static enum aarch64_type_qualifiers
403aarch64_types_loadstruct_lane_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
404 = { qualifier_poly, qualifier_const_pointer_map_mode,
405 qualifier_poly, qualifier_struct_load_store_lane_index };
406#define TYPES_LOADSTRUCT_LANE_P (aarch64_types_loadstruct_lane_p_qualifiers)
b5828b4b 407
46e778c4
JG
408static enum aarch64_type_qualifiers
409aarch64_types_bsl_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
410 = { qualifier_poly, qualifier_unsigned,
411 qualifier_poly, qualifier_poly };
412#define TYPES_BSL_P (aarch64_types_bsl_p_qualifiers)
413static enum aarch64_type_qualifiers
414aarch64_types_bsl_s_qualifiers[SIMD_MAX_BUILTIN_ARGS]
415 = { qualifier_none, qualifier_unsigned,
416 qualifier_none, qualifier_none };
417#define TYPES_BSL_S (aarch64_types_bsl_s_qualifiers)
418static enum aarch64_type_qualifiers
419aarch64_types_bsl_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
420 = { qualifier_unsigned, qualifier_unsigned,
421 qualifier_unsigned, qualifier_unsigned };
422#define TYPES_BSL_U (aarch64_types_bsl_u_qualifiers)
423
b5828b4b
JG
424/* The first argument (return type) of a store should be void type,
425 which we represent with qualifier_void. Their first operand will be
426 a DImode pointer to the location to store to, so we must use
427 qualifier_map_mode | qualifier_pointer to build a pointer to the
428 element type of the vector. */
429static enum aarch64_type_qualifiers
430aarch64_types_store1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
431 = { qualifier_void, qualifier_pointer_map_mode, qualifier_none };
432#define TYPES_STORE1 (aarch64_types_store1_qualifiers)
433#define TYPES_STORESTRUCT (aarch64_types_store1_qualifiers)
66f206b8
JW
434static enum aarch64_type_qualifiers
435aarch64_types_store1_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
436 = { qualifier_void, qualifier_pointer_map_mode, qualifier_unsigned };
1716ddd1 437#define TYPES_STORE1_U (aarch64_types_store1_u_qualifiers)
66f206b8
JW
438#define TYPES_STORESTRUCT_U (aarch64_types_store1_u_qualifiers)
439static enum aarch64_type_qualifiers
440aarch64_types_store1_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
441 = { qualifier_void, qualifier_pointer_map_mode, qualifier_poly };
1716ddd1 442#define TYPES_STORE1_P (aarch64_types_store1_p_qualifiers)
66f206b8
JW
443#define TYPES_STORESTRUCT_P (aarch64_types_store1_p_qualifiers)
444
ba081b77
JG
445static enum aarch64_type_qualifiers
446aarch64_types_storestruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
447 = { qualifier_void, qualifier_pointer_map_mode,
4d0a0237 448 qualifier_none, qualifier_struct_load_store_lane_index };
ba081b77 449#define TYPES_STORESTRUCT_LANE (aarch64_types_storestruct_lane_qualifiers)
66f206b8
JW
450static enum aarch64_type_qualifiers
451aarch64_types_storestruct_lane_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
452 = { qualifier_void, qualifier_pointer_map_mode,
453 qualifier_unsigned, qualifier_struct_load_store_lane_index };
454#define TYPES_STORESTRUCT_LANE_U (aarch64_types_storestruct_lane_u_qualifiers)
455static enum aarch64_type_qualifiers
456aarch64_types_storestruct_lane_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
457 = { qualifier_void, qualifier_pointer_map_mode,
458 qualifier_poly, qualifier_struct_load_store_lane_index };
459#define TYPES_STORESTRUCT_LANE_P (aarch64_types_storestruct_lane_p_qualifiers)
b5828b4b 460
0ddec79f
JG
461#define CF0(N, X) CODE_FOR_aarch64_##N##X
462#define CF1(N, X) CODE_FOR_##N##X##1
463#define CF2(N, X) CODE_FOR_##N##X##2
464#define CF3(N, X) CODE_FOR_##N##X##3
465#define CF4(N, X) CODE_FOR_##N##X##4
466#define CF10(N, X) CODE_FOR_##N##X
467
a4dae58a
KT
468/* Define cascading VAR<N> macros that are used from
469 aarch64-builtin-iterators.h to iterate over modes. These definitions
470 will end up generating a number of VAR1 expansions and code later on in the
471 file should redefine VAR1 to whatever it needs to process on a per-mode
472 basis. */
bf592b2f 473#define VAR2(T, N, MAP, FLAG, A, B) \
474 VAR1 (T, N, MAP, FLAG, A) \
475 VAR1 (T, N, MAP, FLAG, B)
476#define VAR3(T, N, MAP, FLAG, A, B, C) \
477 VAR2 (T, N, MAP, FLAG, A, B) \
478 VAR1 (T, N, MAP, FLAG, C)
479#define VAR4(T, N, MAP, FLAG, A, B, C, D) \
480 VAR3 (T, N, MAP, FLAG, A, B, C) \
481 VAR1 (T, N, MAP, FLAG, D)
482#define VAR5(T, N, MAP, FLAG, A, B, C, D, E) \
483 VAR4 (T, N, MAP, FLAG, A, B, C, D) \
484 VAR1 (T, N, MAP, FLAG, E)
485#define VAR6(T, N, MAP, FLAG, A, B, C, D, E, F) \
486 VAR5 (T, N, MAP, FLAG, A, B, C, D, E) \
487 VAR1 (T, N, MAP, FLAG, F)
488#define VAR7(T, N, MAP, FLAG, A, B, C, D, E, F, G) \
489 VAR6 (T, N, MAP, FLAG, A, B, C, D, E, F) \
490 VAR1 (T, N, MAP, FLAG, G)
491#define VAR8(T, N, MAP, FLAG, A, B, C, D, E, F, G, H) \
492 VAR7 (T, N, MAP, FLAG, A, B, C, D, E, F, G) \
493 VAR1 (T, N, MAP, FLAG, H)
494#define VAR9(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I) \
495 VAR8 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H) \
496 VAR1 (T, N, MAP, FLAG, I)
497#define VAR10(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J) \
498 VAR9 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I) \
499 VAR1 (T, N, MAP, FLAG, J)
500#define VAR11(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K) \
501 VAR10 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J) \
502 VAR1 (T, N, MAP, FLAG, K)
503#define VAR12(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L) \
504 VAR11 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K) \
505 VAR1 (T, N, MAP, FLAG, L)
506#define VAR13(T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M) \
507 VAR12 (T, N, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L) \
508 VAR1 (T, N, MAP, FLAG, M)
509#define VAR14(T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N) \
510 VAR13 (T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M) \
511 VAR1 (T, X, MAP, FLAG, N)
512#define VAR15(T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) \
513 VAR14 (T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N) \
514 VAR1 (T, X, MAP, FLAG, O)
515#define VAR16(T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) \
516 VAR15 (T, X, MAP, FLAG, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) \
517 VAR1 (T, X, MAP, FLAG, P)
342be7f7 518
f421c516 519#include "aarch64-builtin-iterators.h"
43e9d192 520
a4dae58a
KT
521/* The builtins below should be expanded through the standard optabs
522 CODE_FOR_[u]avg<mode>3_[floor,ceil]. However the mapping scheme in
523 aarch64-simd-builtins.def does not easily allow us to have a pre-mode
524 ("uavg") and post-mode string ("_ceil") in the CODE_FOR_* construction.
525 So the builtins use a name that is natural for AArch64 instructions
526 e.g. "aarch64_srhadd<mode>" and we re-map these to the optab-related
527 CODE_FOR_ here. */
528#undef VAR1
529#define VAR1(F,T1,T2,I,M) \
530constexpr insn_code CODE_FOR_aarch64_##F##M = CODE_FOR_##T1##M##3##T2;
531
532BUILTIN_VDQ_BHSI (srhadd, avg, _ceil, 0)
533BUILTIN_VDQ_BHSI (urhadd, uavg, _ceil, 0)
534BUILTIN_VDQ_BHSI (shadd, avg, _floor, 0)
535BUILTIN_VDQ_BHSI (uhadd, uavg, _floor, 0)
536
537#undef VAR1
538#define VAR1(T, N, MAP, FLAG, A) \
539 {#N #A, UP (A), CF##MAP (N, A), 0, TYPES_##T, FLAG_##FLAG},
540
43e9d192 541static aarch64_simd_builtin_datum aarch64_simd_builtin_data[] = {
342be7f7
JG
542#include "aarch64-simd-builtins.def"
543};
544
5d357f26
KT
545/* There's only 8 CRC32 builtins. Probably not worth their own .def file. */
546#define AARCH64_CRC32_BUILTINS \
547 CRC32_BUILTIN (crc32b, QI) \
548 CRC32_BUILTIN (crc32h, HI) \
549 CRC32_BUILTIN (crc32w, SI) \
550 CRC32_BUILTIN (crc32x, DI) \
551 CRC32_BUILTIN (crc32cb, QI) \
552 CRC32_BUILTIN (crc32ch, HI) \
553 CRC32_BUILTIN (crc32cw, SI) \
554 CRC32_BUILTIN (crc32cx, DI)
555
9d63f43b
TC
556/* The next 8 FCMLA instrinsics require some special handling compared the
557 normal simd intrinsics. */
558#define AARCH64_SIMD_FCMLA_LANEQ_BUILTINS \
559 FCMLA_LANEQ_BUILTIN (0, v2sf, fcmla, V2SF, false) \
560 FCMLA_LANEQ_BUILTIN (90, v2sf, fcmla, V2SF, false) \
561 FCMLA_LANEQ_BUILTIN (180, v2sf, fcmla, V2SF, false) \
562 FCMLA_LANEQ_BUILTIN (270, v2sf, fcmla, V2SF, false) \
563 FCMLA_LANEQ_BUILTIN (0, v4hf, fcmla_laneq, V4HF, true) \
564 FCMLA_LANEQ_BUILTIN (90, v4hf, fcmla_laneq, V4HF, true) \
565 FCMLA_LANEQ_BUILTIN (180, v4hf, fcmla_laneq, V4HF, true) \
566 FCMLA_LANEQ_BUILTIN (270, v4hf, fcmla_laneq, V4HF, true) \
567
c906efc7
AC
568
569/* vreinterpret intrinsics are defined for any pair of element types.
570 { _bf16 } { _bf16 }
571 { _f16 _f32 _f64 } { _f16 _f32 _f64 }
572 { _s8 _s16 _s32 _s64 } x { _s8 _s16 _s32 _s64 }
573 { _u8 _u16 _u32 _u64 } { _u8 _u16 _u32 _u64 }
574 { _p8 _p16 _p64 } { _p8 _p16 _p64 }. */
575#define VREINTERPRET_BUILTIN2(A, B) \
576 VREINTERPRET_BUILTIN (A, B, d)
577
578#define VREINTERPRET_BUILTINS1(A) \
579 VREINTERPRET_BUILTIN2 (A, bf16) \
580 VREINTERPRET_BUILTIN2 (A, f16) \
581 VREINTERPRET_BUILTIN2 (A, f32) \
582 VREINTERPRET_BUILTIN2 (A, f64) \
583 VREINTERPRET_BUILTIN2 (A, s8) \
584 VREINTERPRET_BUILTIN2 (A, s16) \
585 VREINTERPRET_BUILTIN2 (A, s32) \
586 VREINTERPRET_BUILTIN2 (A, s64) \
587 VREINTERPRET_BUILTIN2 (A, u8) \
588 VREINTERPRET_BUILTIN2 (A, u16) \
589 VREINTERPRET_BUILTIN2 (A, u32) \
590 VREINTERPRET_BUILTIN2 (A, u64) \
591 VREINTERPRET_BUILTIN2 (A, p8) \
592 VREINTERPRET_BUILTIN2 (A, p16) \
593 VREINTERPRET_BUILTIN2 (A, p64)
594
595#define VREINTERPRET_BUILTINS \
596 VREINTERPRET_BUILTINS1 (bf16) \
597 VREINTERPRET_BUILTINS1 (f16) \
598 VREINTERPRET_BUILTINS1 (f32) \
599 VREINTERPRET_BUILTINS1 (f64) \
600 VREINTERPRET_BUILTINS1 (s8) \
601 VREINTERPRET_BUILTINS1 (s16) \
602 VREINTERPRET_BUILTINS1 (s32) \
603 VREINTERPRET_BUILTINS1 (s64) \
604 VREINTERPRET_BUILTINS1 (u8) \
605 VREINTERPRET_BUILTINS1 (u16) \
606 VREINTERPRET_BUILTINS1 (u32) \
607 VREINTERPRET_BUILTINS1 (u64) \
608 VREINTERPRET_BUILTINS1 (p8) \
609 VREINTERPRET_BUILTINS1 (p16) \
610 VREINTERPRET_BUILTINS1 (p64)
611
612/* vreinterpretq intrinsics are additionally defined for p128.
613 { _bf16 } { _bf16 }
614 { _f16 _f32 _f64 } { _f16 _f32 _f64 }
615 { _s8 _s16 _s32 _s64 } x { _s8 _s16 _s32 _s64 }
616 { _u8 _u16 _u32 _u64 } { _u8 _u16 _u32 _u64 }
617 { _p8 _p16 _p64 _p128 } { _p8 _p16 _p64 _p128 }. */
618#define VREINTERPRETQ_BUILTIN2(A, B) \
619 VREINTERPRET_BUILTIN (A, B, q)
620
621#define VREINTERPRETQ_BUILTINS1(A) \
622 VREINTERPRETQ_BUILTIN2 (A, bf16) \
623 VREINTERPRETQ_BUILTIN2 (A, f16) \
624 VREINTERPRETQ_BUILTIN2 (A, f32) \
625 VREINTERPRETQ_BUILTIN2 (A, f64) \
626 VREINTERPRETQ_BUILTIN2 (A, s8) \
627 VREINTERPRETQ_BUILTIN2 (A, s16) \
628 VREINTERPRETQ_BUILTIN2 (A, s32) \
629 VREINTERPRETQ_BUILTIN2 (A, s64) \
630 VREINTERPRETQ_BUILTIN2 (A, u8) \
631 VREINTERPRETQ_BUILTIN2 (A, u16) \
632 VREINTERPRETQ_BUILTIN2 (A, u32) \
633 VREINTERPRETQ_BUILTIN2 (A, u64) \
634 VREINTERPRETQ_BUILTIN2 (A, p8) \
635 VREINTERPRETQ_BUILTIN2 (A, p16) \
636 VREINTERPRETQ_BUILTIN2 (A, p64) \
637 VREINTERPRETQ_BUILTIN2 (A, p128)
638
639#define VREINTERPRETQ_BUILTINS \
640 VREINTERPRETQ_BUILTINS1 (bf16) \
641 VREINTERPRETQ_BUILTINS1 (f16) \
642 VREINTERPRETQ_BUILTINS1 (f32) \
643 VREINTERPRETQ_BUILTINS1 (f64) \
644 VREINTERPRETQ_BUILTINS1 (s8) \
645 VREINTERPRETQ_BUILTINS1 (s16) \
646 VREINTERPRETQ_BUILTINS1 (s32) \
647 VREINTERPRETQ_BUILTINS1 (s64) \
648 VREINTERPRETQ_BUILTINS1 (u8) \
649 VREINTERPRETQ_BUILTINS1 (u16) \
650 VREINTERPRETQ_BUILTINS1 (u32) \
651 VREINTERPRETQ_BUILTINS1 (u64) \
652 VREINTERPRETQ_BUILTINS1 (p8) \
653 VREINTERPRETQ_BUILTINS1 (p16) \
654 VREINTERPRETQ_BUILTINS1 (p64) \
655 VREINTERPRETQ_BUILTINS1 (p128)
656
657#define AARCH64_SIMD_VREINTERPRET_BUILTINS \
658 VREINTERPRET_BUILTINS \
659 VREINTERPRETQ_BUILTINS
660
5d357f26
KT
661typedef struct
662{
663 const char *name;
ef4bddc2 664 machine_mode mode;
5d357f26
KT
665 const enum insn_code icode;
666 unsigned int fcode;
667} aarch64_crc_builtin_datum;
668
9d63f43b
TC
669/* Hold information about how to expand the FCMLA_LANEQ builtins. */
670typedef struct
671{
672 const char *name;
673 machine_mode mode;
674 const enum insn_code icode;
675 unsigned int fcode;
676 bool lane;
677} aarch64_fcmla_laneq_builtin_datum;
678
c906efc7
AC
679/* Hold information about how to declare SIMD intrinsics. */
680typedef struct
681{
682 const char *name;
683 unsigned int fcode;
684 unsigned int op_count;
685 machine_mode op_modes[SIMD_MAX_BUILTIN_ARGS];
686 enum aarch64_type_qualifiers qualifiers[SIMD_MAX_BUILTIN_ARGS];
687 unsigned int flags;
688 bool skip;
689} aarch64_simd_intrinsic_datum;
690
5d357f26
KT
691#define CRC32_BUILTIN(N, M) \
692 AARCH64_BUILTIN_##N,
693
9d63f43b
TC
694#define FCMLA_LANEQ_BUILTIN(I, N, X, M, T) \
695 AARCH64_SIMD_BUILTIN_FCMLA_LANEQ##I##_##M,
696
c906efc7
AC
697#define VREINTERPRET_BUILTIN(A, B, L) \
698 AARCH64_SIMD_BUILTIN_VREINTERPRET##L##_##A##_##B,
699
342be7f7 700#undef VAR1
bf592b2f 701#define VAR1(T, N, MAP, FLAG, A) \
e993fea1 702 AARCH64_SIMD_BUILTIN_##T##_##N##A,
342be7f7
JG
703
704enum aarch64_builtins
705{
706 AARCH64_BUILTIN_MIN,
aa87aced
KV
707
708 AARCH64_BUILTIN_GET_FPCR,
709 AARCH64_BUILTIN_SET_FPCR,
710 AARCH64_BUILTIN_GET_FPSR,
711 AARCH64_BUILTIN_SET_FPSR,
712
0d7e5fa6
AC
713 AARCH64_BUILTIN_GET_FPCR64,
714 AARCH64_BUILTIN_SET_FPCR64,
715 AARCH64_BUILTIN_GET_FPSR64,
716 AARCH64_BUILTIN_SET_FPSR64,
717
a6fc00da
BH
718 AARCH64_BUILTIN_RSQRT_DF,
719 AARCH64_BUILTIN_RSQRT_SF,
720 AARCH64_BUILTIN_RSQRT_V2DF,
721 AARCH64_BUILTIN_RSQRT_V2SF,
722 AARCH64_BUILTIN_RSQRT_V4SF,
342be7f7 723 AARCH64_SIMD_BUILTIN_BASE,
661fce82 724 AARCH64_SIMD_BUILTIN_LANE_CHECK,
342be7f7 725#include "aarch64-simd-builtins.def"
661fce82
AL
726 /* The first enum element which is based on an insn_data pattern. */
727 AARCH64_SIMD_PATTERN_START = AARCH64_SIMD_BUILTIN_LANE_CHECK + 1,
728 AARCH64_SIMD_BUILTIN_MAX = AARCH64_SIMD_PATTERN_START
729 + ARRAY_SIZE (aarch64_simd_builtin_data) - 1,
5d357f26
KT
730 AARCH64_CRC32_BUILTIN_BASE,
731 AARCH64_CRC32_BUILTINS
732 AARCH64_CRC32_BUILTIN_MAX,
c906efc7
AC
733 /* SIMD intrinsic builtins. */
734 AARCH64_SIMD_VREINTERPRET_BUILTINS
312492bd
JW
735 /* ARMv8.3-A Pointer Authentication Builtins. */
736 AARCH64_PAUTH_BUILTIN_AUTIA1716,
737 AARCH64_PAUTH_BUILTIN_PACIA1716,
8fc16d72
ST
738 AARCH64_PAUTH_BUILTIN_AUTIB1716,
739 AARCH64_PAUTH_BUILTIN_PACIB1716,
312492bd 740 AARCH64_PAUTH_BUILTIN_XPACLRI,
9d63f43b
TC
741 /* Special cased Armv8.3-A Complex FMA by Lane quad Builtins. */
742 AARCH64_SIMD_FCMLA_LANEQ_BUILTIN_BASE,
743 AARCH64_SIMD_FCMLA_LANEQ_BUILTINS
e1d5d19e
KT
744 /* Builtin for Arm8.3-a Javascript conversion instruction. */
745 AARCH64_JSCVT,
89626179
SD
746 /* TME builtins. */
747 AARCH64_TME_BUILTIN_TSTART,
748 AARCH64_TME_BUILTIN_TCOMMIT,
749 AARCH64_TME_BUILTIN_TTEST,
750 AARCH64_TME_BUILTIN_TCANCEL,
c5dc215d
KT
751 /* Armv8.5-a RNG instruction builtins. */
752 AARCH64_BUILTIN_RNG_RNDR,
753 AARCH64_BUILTIN_RNG_RNDRRS,
ef01e6bb
DZ
754 /* MEMTAG builtins. */
755 AARCH64_MEMTAG_BUILTIN_START,
756 AARCH64_MEMTAG_BUILTIN_IRG,
757 AARCH64_MEMTAG_BUILTIN_GMI,
758 AARCH64_MEMTAG_BUILTIN_SUBP,
759 AARCH64_MEMTAG_BUILTIN_INC_TAG,
760 AARCH64_MEMTAG_BUILTIN_SET_TAG,
761 AARCH64_MEMTAG_BUILTIN_GET_TAG,
762 AARCH64_MEMTAG_BUILTIN_END,
fdcddba8
PW
763 /* LS64 builtins. */
764 AARCH64_LS64_BUILTIN_LD64B,
765 AARCH64_LS64_BUILTIN_ST64B,
766 AARCH64_LS64_BUILTIN_ST64BV,
767 AARCH64_LS64_BUILTIN_ST64BV0,
eb966d39
ASDV
768 AARCH64_REV16,
769 AARCH64_REV16L,
770 AARCH64_REV16LL,
771 AARCH64_RBIT,
772 AARCH64_RBITL,
773 AARCH64_RBITLL,
fc42900d
VDN
774 /* System register builtins. */
775 AARCH64_RSR,
776 AARCH64_RSRP,
777 AARCH64_RSR64,
778 AARCH64_RSRF,
779 AARCH64_RSRF64,
88157c88 780 AARCH64_RSR128,
fc42900d
VDN
781 AARCH64_WSR,
782 AARCH64_WSRP,
783 AARCH64_WSR64,
784 AARCH64_WSRF,
785 AARCH64_WSRF64,
88157c88 786 AARCH64_WSR128,
9fba6637
VDN
787 AARCH64_PLD,
788 AARCH64_PLDX,
789 AARCH64_PLI,
790 AARCH64_PLIX,
342be7f7 791 AARCH64_BUILTIN_MAX
43e9d192
IB
792};
793
5d357f26
KT
794#undef CRC32_BUILTIN
795#define CRC32_BUILTIN(N, M) \
0d4a1197 796 {"__builtin_aarch64_"#N, E_##M##mode, CODE_FOR_aarch64_##N, AARCH64_BUILTIN_##N},
5d357f26
KT
797
798static aarch64_crc_builtin_datum aarch64_crc_builtin_data[] = {
799 AARCH64_CRC32_BUILTINS
800};
801
9d63f43b
TC
802
803#undef FCMLA_LANEQ_BUILTIN
804#define FCMLA_LANEQ_BUILTIN(I, N, X, M, T) \
805 {"__builtin_aarch64_fcmla_laneq"#I#N, E_##M##mode, CODE_FOR_aarch64_##X##I##N, \
806 AARCH64_SIMD_BUILTIN_FCMLA_LANEQ##I##_##M, T},
807
808/* This structure contains how to manage the mapping form the builtin to the
809 instruction to generate in the backend and how to invoke the instruction. */
5eb9ac1e 810static aarch64_fcmla_laneq_builtin_datum aarch64_fcmla_lane_builtin_data[] = {
9d63f43b
TC
811 AARCH64_SIMD_FCMLA_LANEQ_BUILTINS
812};
813
c906efc7
AC
814#undef VREINTERPRET_BUILTIN
815#define VREINTERPRET_BUILTIN(A, B, L) \
816 {"vreinterpret" SIMD_INTR_LENGTH_CHAR(L) "_" #A "_" #B, \
817 AARCH64_SIMD_BUILTIN_VREINTERPRET##L##_##A##_##B, \
818 2, \
819 { SIMD_INTR_MODE(A, L), SIMD_INTR_MODE(B, L) }, \
820 { SIMD_INTR_QUAL(A), SIMD_INTR_QUAL(B) }, \
821 FLAG_AUTO_FP, \
822 SIMD_INTR_MODE(A, L) == SIMD_INTR_MODE(B, L) \
823 && SIMD_INTR_QUAL(A) == SIMD_INTR_QUAL(B) \
824 },
825
826static const aarch64_simd_intrinsic_datum aarch64_simd_intrinsic_data[] = {
827 AARCH64_SIMD_VREINTERPRET_BUILTINS
828};
829
830
5d357f26
KT
831#undef CRC32_BUILTIN
832
119103ca
JG
833static GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX];
834
43e9d192
IB
835#define NUM_DREG_TYPES 6
836#define NUM_QREG_TYPES 6
837
f9d53c27
TB
838/* Internal scalar builtin types. These types are used to support
839 neon intrinsic builtins. They are _not_ user-visible types. Therefore
840 the mangling for these types are implementation defined. */
841const char *aarch64_scalar_builtin_types[] = {
842 "__builtin_aarch64_simd_qi",
843 "__builtin_aarch64_simd_hi",
844 "__builtin_aarch64_simd_si",
7c369485 845 "__builtin_aarch64_simd_hf",
f9d53c27
TB
846 "__builtin_aarch64_simd_sf",
847 "__builtin_aarch64_simd_di",
848 "__builtin_aarch64_simd_df",
849 "__builtin_aarch64_simd_poly8",
850 "__builtin_aarch64_simd_poly16",
851 "__builtin_aarch64_simd_poly64",
852 "__builtin_aarch64_simd_poly128",
853 "__builtin_aarch64_simd_ti",
854 "__builtin_aarch64_simd_uqi",
855 "__builtin_aarch64_simd_uhi",
856 "__builtin_aarch64_simd_usi",
857 "__builtin_aarch64_simd_udi",
858 "__builtin_aarch64_simd_ei",
859 "__builtin_aarch64_simd_oi",
860 "__builtin_aarch64_simd_ci",
861 "__builtin_aarch64_simd_xi",
e603cd43 862 "__builtin_aarch64_simd_bf",
f9d53c27
TB
863 NULL
864};
b5828b4b 865
f9d53c27 866#define ENTRY(E, M, Q, G) \
0d4a1197 867 {E, "__" #E, #G "__" #E, NULL_TREE, NULL_TREE, E_##M##mode, qualifier_##Q},
c5353607 868GTY(()) struct aarch64_simd_type_info aarch64_simd_types [] = {
f9d53c27
TB
869#include "aarch64-simd-builtin-types.def"
870};
871#undef ENTRY
872
14814e20 873static machine_mode aarch64_simd_tuple_modes[ARM_NEON_H_TYPES_LAST][3];
66f206b8
JW
874static GTY(()) tree aarch64_simd_tuple_types[ARM_NEON_H_TYPES_LAST][3];
875
98f1dd02
AP
876static GTY(()) tree aarch64_simd_intOI_type_node = NULL_TREE;
877static GTY(()) tree aarch64_simd_intCI_type_node = NULL_TREE;
878static GTY(()) tree aarch64_simd_intXI_type_node = NULL_TREE;
f9d53c27 879
1b62ed4f
JG
880/* The user-visible __fp16 type, and a pointer to that type. Used
881 across the back-end. */
882tree aarch64_fp16_type_node = NULL_TREE;
883tree aarch64_fp16_ptr_type_node = NULL_TREE;
884
abbe1ed2 885/* Back-end node type for brain float (bfloat) types. */
abbe1ed2
SMW
886tree aarch64_bf16_ptr_type_node = NULL_TREE;
887
6d4d616a 888/* Wrapper around add_builtin_function. NAME is the name of the built-in
072a8b8f 889 function, TYPE is the function type, CODE is the function subcode
890 (relative to AARCH64_BUILTIN_GENERAL), and ATTRS is the function
891 attributes. */
6d4d616a 892static tree
072a8b8f 893aarch64_general_add_builtin (const char *name, tree type, unsigned int code,
894 tree attrs = NULL_TREE)
6d4d616a
RS
895{
896 code = (code << AARCH64_BUILTIN_SHIFT) | AARCH64_BUILTIN_GENERAL;
897 return add_builtin_function (name, type, code, BUILT_IN_MD,
072a8b8f 898 NULL, attrs);
6d4d616a
RS
899}
900
9963029a
AC
901static tree
902aarch64_general_simulate_builtin (const char *name, tree fntype,
903 unsigned int code,
904 tree attrs = NULL_TREE)
905{
906 code = (code << AARCH64_BUILTIN_SHIFT) | AARCH64_BUILTIN_GENERAL;
907 return simulate_builtin_function_decl (input_location, name, fntype,
908 code, NULL, attrs);
909}
910
f9d53c27
TB
911static const char *
912aarch64_mangle_builtin_scalar_type (const_tree type)
913{
914 int i = 0;
915
916 while (aarch64_scalar_builtin_types[i] != NULL)
b5828b4b 917 {
f9d53c27
TB
918 const char *name = aarch64_scalar_builtin_types[i];
919
920 if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
921 && DECL_NAME (TYPE_NAME (type))
922 && !strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), name))
923 return aarch64_scalar_builtin_types[i];
924 i++;
925 }
926 return NULL;
b5828b4b
JG
927}
928
f9d53c27
TB
929static const char *
930aarch64_mangle_builtin_vector_type (const_tree type)
b5828b4b 931{
31427b97
RS
932 tree attrs = TYPE_ATTRIBUTES (type);
933 if (tree attr = lookup_attribute ("Advanced SIMD type", attrs))
934 {
935 tree mangled_name = TREE_VALUE (TREE_VALUE (attr));
936 return IDENTIFIER_POINTER (mangled_name);
937 }
f9d53c27
TB
938
939 return NULL;
6db1ec94
JG
940}
941
f9d53c27 942const char *
6d4d616a 943aarch64_general_mangle_builtin_type (const_tree type)
6db1ec94 944{
f9d53c27
TB
945 const char *mangle;
946 /* Walk through all the AArch64 builtins types tables to filter out the
947 incoming type. */
948 if ((mangle = aarch64_mangle_builtin_vector_type (type))
949 || (mangle = aarch64_mangle_builtin_scalar_type (type)))
950 return mangle;
951
952 return NULL;
6db1ec94
JG
953}
954
f023cc54 955/* Helper function for aarch64_simd_builtin_type. */
f9d53c27 956static tree
f023cc54
AC
957aarch64_int_or_fp_type (machine_mode mode,
958 enum aarch64_type_qualifiers qualifiers)
6db1ec94 959{
f023cc54
AC
960#define QUAL_TYPE(M) ((qualifiers & qualifier_unsigned) \
961 ? unsigned_int##M##_type_node : int##M##_type_node);
f9d53c27
TB
962 switch (mode)
963 {
4e10a5a7 964 case E_QImode:
f9d53c27 965 return QUAL_TYPE (QI);
4e10a5a7 966 case E_HImode:
f9d53c27 967 return QUAL_TYPE (HI);
4e10a5a7 968 case E_SImode:
f9d53c27 969 return QUAL_TYPE (SI);
4e10a5a7 970 case E_DImode:
f9d53c27 971 return QUAL_TYPE (DI);
4e10a5a7 972 case E_TImode:
f9d53c27 973 return QUAL_TYPE (TI);
4e10a5a7 974 case E_OImode:
f9d53c27 975 return aarch64_simd_intOI_type_node;
4e10a5a7 976 case E_CImode:
f9d53c27 977 return aarch64_simd_intCI_type_node;
4e10a5a7 978 case E_XImode:
f9d53c27 979 return aarch64_simd_intXI_type_node;
4e10a5a7 980 case E_HFmode:
71a11456 981 return aarch64_fp16_type_node;
4e10a5a7 982 case E_SFmode:
f9d53c27 983 return float_type_node;
4e10a5a7 984 case E_DFmode:
f9d53c27 985 return double_type_node;
abbe1ed2 986 case E_BFmode:
13071c3c 987 return bfloat16_type_node;
f9d53c27
TB
988 default:
989 gcc_unreachable ();
990 }
991#undef QUAL_TYPE
6db1ec94
JG
992}
993
f023cc54 994/* Helper function for aarch64_simd_builtin_type. */
f9d53c27 995static tree
f023cc54
AC
996aarch64_lookup_simd_type_in_table (machine_mode mode,
997 enum aarch64_type_qualifiers qualifiers)
6db1ec94 998{
f9d53c27 999 int i;
ca32b29e 1000 int nelts = ARRAY_SIZE (aarch64_simd_types);
f023cc54 1001 int q = qualifiers & (qualifier_poly | qualifier_unsigned);
f9d53c27
TB
1002
1003 for (i = 0; i < nelts; i++)
66f206b8
JW
1004 {
1005 if (aarch64_simd_types[i].mode == mode
1006 && aarch64_simd_types[i].q == q)
1007 return aarch64_simd_types[i].itype;
1008 if (aarch64_simd_tuple_types[i][0] != NULL_TREE)
1009 for (int j = 0; j < 3; j++)
14814e20 1010 if (aarch64_simd_tuple_modes[i][j] == mode
66f206b8
JW
1011 && aarch64_simd_types[i].q == q)
1012 return aarch64_simd_tuple_types[i][j];
1013 }
f9d53c27
TB
1014
1015 return NULL_TREE;
b5828b4b
JG
1016}
1017
f023cc54 1018/* Return a type for an operand with specified mode and qualifiers. */
f9d53c27 1019static tree
b8506a8a 1020aarch64_simd_builtin_type (machine_mode mode,
f023cc54 1021 enum aarch64_type_qualifiers qualifiers)
f9d53c27 1022{
f023cc54
AC
1023 tree type = NULL_TREE;
1024
1025 /* For pointers, we want a pointer to the basic type of the vector. */
1026 if ((qualifiers & qualifier_pointer) && VECTOR_MODE_P (mode))
1027 mode = GET_MODE_INNER (mode);
1028
1029 /* Non-poly scalar modes map to standard types not in the table. */
1030 if ((qualifiers & qualifier_poly) || VECTOR_MODE_P (mode))
1031 type = aarch64_lookup_simd_type_in_table (mode, qualifiers);
f9d53c27 1032 else
f023cc54
AC
1033 type = aarch64_int_or_fp_type (mode, qualifiers);
1034
1035 gcc_assert (type != NULL_TREE);
1036
1037 /* Add qualifiers. */
1038 if (qualifiers & qualifier_const)
1039 type = build_qualified_type (type, TYPE_QUAL_CONST);
1040 if (qualifiers & qualifier_pointer)
1041 type = build_pointer_type (type);
1042
1043 return type;
f9d53c27
TB
1044}
1045
af55e82d 1046static void
f9d53c27 1047aarch64_init_simd_builtin_types (void)
43e9d192 1048{
f9d53c27 1049 int i;
ca32b29e 1050 int nelts = ARRAY_SIZE (aarch64_simd_types);
f9d53c27
TB
1051 tree tdecl;
1052
1053 /* Init all the element types built by the front-end. */
1054 aarch64_simd_types[Int8x8_t].eltype = intQI_type_node;
1055 aarch64_simd_types[Int8x16_t].eltype = intQI_type_node;
1056 aarch64_simd_types[Int16x4_t].eltype = intHI_type_node;
1057 aarch64_simd_types[Int16x8_t].eltype = intHI_type_node;
1058 aarch64_simd_types[Int32x2_t].eltype = intSI_type_node;
1059 aarch64_simd_types[Int32x4_t].eltype = intSI_type_node;
1060 aarch64_simd_types[Int64x1_t].eltype = intDI_type_node;
1061 aarch64_simd_types[Int64x2_t].eltype = intDI_type_node;
1062 aarch64_simd_types[Uint8x8_t].eltype = unsigned_intQI_type_node;
1063 aarch64_simd_types[Uint8x16_t].eltype = unsigned_intQI_type_node;
1064 aarch64_simd_types[Uint16x4_t].eltype = unsigned_intHI_type_node;
1065 aarch64_simd_types[Uint16x8_t].eltype = unsigned_intHI_type_node;
1066 aarch64_simd_types[Uint32x2_t].eltype = unsigned_intSI_type_node;
1067 aarch64_simd_types[Uint32x4_t].eltype = unsigned_intSI_type_node;
1068 aarch64_simd_types[Uint64x1_t].eltype = unsigned_intDI_type_node;
1069 aarch64_simd_types[Uint64x2_t].eltype = unsigned_intDI_type_node;
1070
1071 /* Poly types are a world of their own. */
1072 aarch64_simd_types[Poly8_t].eltype = aarch64_simd_types[Poly8_t].itype =
1073 build_distinct_type_copy (unsigned_intQI_type_node);
bcee52c4
MS
1074 /* Prevent front-ends from transforming Poly8_t arrays into string
1075 literals. */
1076 TYPE_STRING_FLAG (aarch64_simd_types[Poly8_t].eltype) = false;
1077
f9d53c27
TB
1078 aarch64_simd_types[Poly16_t].eltype = aarch64_simd_types[Poly16_t].itype =
1079 build_distinct_type_copy (unsigned_intHI_type_node);
1080 aarch64_simd_types[Poly64_t].eltype = aarch64_simd_types[Poly64_t].itype =
1081 build_distinct_type_copy (unsigned_intDI_type_node);
1082 aarch64_simd_types[Poly128_t].eltype = aarch64_simd_types[Poly128_t].itype =
1083 build_distinct_type_copy (unsigned_intTI_type_node);
1084 /* Init poly vector element types with scalar poly types. */
1085 aarch64_simd_types[Poly8x8_t].eltype = aarch64_simd_types[Poly8_t].itype;
1086 aarch64_simd_types[Poly8x16_t].eltype = aarch64_simd_types[Poly8_t].itype;
1087 aarch64_simd_types[Poly16x4_t].eltype = aarch64_simd_types[Poly16_t].itype;
1088 aarch64_simd_types[Poly16x8_t].eltype = aarch64_simd_types[Poly16_t].itype;
1089 aarch64_simd_types[Poly64x1_t].eltype = aarch64_simd_types[Poly64_t].itype;
1090 aarch64_simd_types[Poly64x2_t].eltype = aarch64_simd_types[Poly64_t].itype;
1091
1092 /* Continue with standard types. */
71a11456
AL
1093 aarch64_simd_types[Float16x4_t].eltype = aarch64_fp16_type_node;
1094 aarch64_simd_types[Float16x8_t].eltype = aarch64_fp16_type_node;
f9d53c27
TB
1095 aarch64_simd_types[Float32x2_t].eltype = float_type_node;
1096 aarch64_simd_types[Float32x4_t].eltype = float_type_node;
1097 aarch64_simd_types[Float64x1_t].eltype = double_type_node;
1098 aarch64_simd_types[Float64x2_t].eltype = double_type_node;
1099
abbe1ed2 1100 /* Init Bfloat vector types with underlying __bf16 type. */
13071c3c
JJ
1101 aarch64_simd_types[Bfloat16x4_t].eltype = bfloat16_type_node;
1102 aarch64_simd_types[Bfloat16x8_t].eltype = bfloat16_type_node;
abbe1ed2 1103
f9d53c27
TB
1104 for (i = 0; i < nelts; i++)
1105 {
1106 tree eltype = aarch64_simd_types[i].eltype;
b8506a8a 1107 machine_mode mode = aarch64_simd_types[i].mode;
f9d53c27
TB
1108
1109 if (aarch64_simd_types[i].itype == NULL)
b96824c4 1110 {
31427b97
RS
1111 tree type = build_vector_type (eltype, GET_MODE_NUNITS (mode));
1112 type = build_distinct_type_copy (type);
1113 SET_TYPE_STRUCTURAL_EQUALITY (type);
1114
1115 tree mangled_name = get_identifier (aarch64_simd_types[i].mangle);
1116 tree value = tree_cons (NULL_TREE, mangled_name, NULL_TREE);
1117 TYPE_ATTRIBUTES (type)
1118 = tree_cons (get_identifier ("Advanced SIMD type"), value,
1119 TYPE_ATTRIBUTES (type));
1120 aarch64_simd_types[i].itype = type;
b96824c4 1121 }
f9d53c27
TB
1122
1123 tdecl = add_builtin_type (aarch64_simd_types[i].name,
1124 aarch64_simd_types[i].itype);
1125 TYPE_NAME (aarch64_simd_types[i].itype) = tdecl;
f9d53c27 1126 }
43e9d192 1127
f9d53c27
TB
1128#define AARCH64_BUILD_SIGNED_TYPE(mode) \
1129 make_signed_type (GET_MODE_PRECISION (mode));
1130 aarch64_simd_intOI_type_node = AARCH64_BUILD_SIGNED_TYPE (OImode);
f9d53c27
TB
1131 aarch64_simd_intCI_type_node = AARCH64_BUILD_SIGNED_TYPE (CImode);
1132 aarch64_simd_intXI_type_node = AARCH64_BUILD_SIGNED_TYPE (XImode);
1133#undef AARCH64_BUILD_SIGNED_TYPE
1134
f9d53c27
TB
1135 tdecl = add_builtin_type
1136 ("__builtin_aarch64_simd_oi" , aarch64_simd_intOI_type_node);
1137 TYPE_NAME (aarch64_simd_intOI_type_node) = tdecl;
1138 tdecl = add_builtin_type
1139 ("__builtin_aarch64_simd_ci" , aarch64_simd_intCI_type_node);
1140 TYPE_NAME (aarch64_simd_intCI_type_node) = tdecl;
1141 tdecl = add_builtin_type
1142 ("__builtin_aarch64_simd_xi" , aarch64_simd_intXI_type_node);
1143 TYPE_NAME (aarch64_simd_intXI_type_node) = tdecl;
1144}
1145
1146static void
1147aarch64_init_simd_builtin_scalar_types (void)
1148{
1149 /* Define typedefs for all the standard scalar types. */
1150 (*lang_hooks.types.register_builtin_type) (intQI_type_node,
43e9d192 1151 "__builtin_aarch64_simd_qi");
f9d53c27 1152 (*lang_hooks.types.register_builtin_type) (intHI_type_node,
43e9d192 1153 "__builtin_aarch64_simd_hi");
7c369485
AL
1154 (*lang_hooks.types.register_builtin_type) (aarch64_fp16_type_node,
1155 "__builtin_aarch64_simd_hf");
f9d53c27 1156 (*lang_hooks.types.register_builtin_type) (intSI_type_node,
43e9d192 1157 "__builtin_aarch64_simd_si");
f9d53c27 1158 (*lang_hooks.types.register_builtin_type) (float_type_node,
43e9d192 1159 "__builtin_aarch64_simd_sf");
f9d53c27 1160 (*lang_hooks.types.register_builtin_type) (intDI_type_node,
43e9d192 1161 "__builtin_aarch64_simd_di");
f9d53c27 1162 (*lang_hooks.types.register_builtin_type) (double_type_node,
43e9d192 1163 "__builtin_aarch64_simd_df");
f9d53c27 1164 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
43e9d192 1165 "__builtin_aarch64_simd_poly8");
f9d53c27 1166 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
43e9d192 1167 "__builtin_aarch64_simd_poly16");
f9d53c27 1168 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
7baa225d 1169 "__builtin_aarch64_simd_poly64");
f9d53c27 1170 (*lang_hooks.types.register_builtin_type) (unsigned_intTI_type_node,
7baa225d 1171 "__builtin_aarch64_simd_poly128");
f9d53c27 1172 (*lang_hooks.types.register_builtin_type) (intTI_type_node,
43e9d192 1173 "__builtin_aarch64_simd_ti");
13071c3c 1174 (*lang_hooks.types.register_builtin_type) (bfloat16_type_node,
e603cd43 1175 "__builtin_aarch64_simd_bf");
b5828b4b 1176 /* Unsigned integer types for various mode sizes. */
f9d53c27 1177 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
b5828b4b 1178 "__builtin_aarch64_simd_uqi");
f9d53c27 1179 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
b5828b4b 1180 "__builtin_aarch64_simd_uhi");
f9d53c27 1181 (*lang_hooks.types.register_builtin_type) (unsigned_intSI_type_node,
b5828b4b 1182 "__builtin_aarch64_simd_usi");
f9d53c27 1183 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
b5828b4b 1184 "__builtin_aarch64_simd_udi");
f9d53c27
TB
1185}
1186
079c23cf
KT
1187/* Return a set of FLAG_* flags derived from FLAGS
1188 that describe what a function with result MODE could do,
072a8b8f 1189 taking the command-line flags into account. */
1190static unsigned int
079c23cf 1191aarch64_call_properties (unsigned int flags, machine_mode mode)
072a8b8f 1192{
079c23cf 1193 if (!(flags & FLAG_AUTO_FP) && FLOAT_MODE_P (mode))
35ffd4d1 1194 flags |= FLAG_FP;
072a8b8f 1195
1196 /* -fno-trapping-math means that we can assume any FP exceptions
1197 are not user-visible. */
1198 if (!flag_trapping_math)
1199 flags &= ~FLAG_RAISE_FP_EXCEPTIONS;
1200
1201 return flags;
1202}
1203
079c23cf
KT
1204/* Return true if calls to a function with flags F and mode MODE
1205 could modify some form of global state. */
072a8b8f 1206static bool
079c23cf 1207aarch64_modifies_global_state_p (unsigned int f, machine_mode mode)
072a8b8f 1208{
079c23cf 1209 unsigned int flags = aarch64_call_properties (f, mode);
072a8b8f 1210
1211 if (flags & FLAG_RAISE_FP_EXCEPTIONS)
1212 return true;
1213
1214 if (flags & FLAG_PREFETCH_MEMORY)
1215 return true;
1216
1217 return flags & FLAG_WRITE_MEMORY;
1218}
1219
079c23cf
KT
1220/* Return true if calls to a function with flags F and mode MODE
1221 could read some form of global state. */
072a8b8f 1222static bool
079c23cf 1223aarch64_reads_global_state_p (unsigned int f, machine_mode mode)
072a8b8f 1224{
079c23cf 1225 unsigned int flags = aarch64_call_properties (f, mode);
072a8b8f 1226
1227 if (flags & FLAG_READ_FPCR)
1228 return true;
1229
1230 return flags & FLAG_READ_MEMORY;
1231}
1232
079c23cf
KT
1233/* Return true if calls to a function with flags F and mode MODE
1234 could raise a signal. */
072a8b8f 1235static bool
079c23cf 1236aarch64_could_trap_p (unsigned int f, machine_mode mode)
072a8b8f 1237{
079c23cf 1238 unsigned int flags = aarch64_call_properties (f, mode);
072a8b8f 1239
1240 if (flags & FLAG_RAISE_FP_EXCEPTIONS)
1241 return true;
1242
1243 if (flags & (FLAG_READ_MEMORY | FLAG_WRITE_MEMORY))
1244 return true;
1245
1246 return false;
1247}
1248
1249/* Add attribute NAME to ATTRS. */
1250static tree
1251aarch64_add_attribute (const char *name, tree attrs)
1252{
1253 return tree_cons (get_identifier (name), NULL_TREE, attrs);
1254}
1255
079c23cf
KT
1256/* Return the appropriate attributes for a function that has
1257 flags F and mode MODE. */
072a8b8f 1258static tree
079c23cf 1259aarch64_get_attributes (unsigned int f, machine_mode mode)
072a8b8f 1260{
1261 tree attrs = NULL_TREE;
1262
079c23cf 1263 if (!aarch64_modifies_global_state_p (f, mode))
072a8b8f 1264 {
079c23cf 1265 if (aarch64_reads_global_state_p (f, mode))
072a8b8f 1266 attrs = aarch64_add_attribute ("pure", attrs);
1267 else
1268 attrs = aarch64_add_attribute ("const", attrs);
1269 }
1270
079c23cf 1271 if (!flag_non_call_exceptions || !aarch64_could_trap_p (f, mode))
072a8b8f 1272 attrs = aarch64_add_attribute ("nothrow", attrs);
1273
1274 return aarch64_add_attribute ("leaf", attrs);
1275}
1276
9d63f43b
TC
1277/* Due to the architecture not providing lane variant of the lane instructions
1278 for fcmla we can't use the standard simd builtin expansion code, but we
1279 still want the majority of the validation that would normally be done. */
1280
1281void
1282aarch64_init_fcmla_laneq_builtins (void)
1283{
1284 unsigned int i = 0;
1285
1286 for (i = 0; i < ARRAY_SIZE (aarch64_fcmla_lane_builtin_data); ++i)
1287 {
1288 aarch64_fcmla_laneq_builtin_datum* d
1289 = &aarch64_fcmla_lane_builtin_data[i];
f023cc54 1290 tree argtype = aarch64_simd_builtin_type (d->mode, qualifier_none);
9d63f43b 1291 machine_mode quadmode = GET_MODE_2XWIDER_MODE (d->mode).require ();
f023cc54 1292 tree quadtype = aarch64_simd_builtin_type (quadmode, qualifier_none);
9d63f43b 1293 tree lanetype
f023cc54 1294 = aarch64_simd_builtin_type (SImode, qualifier_lane_pair_index);
9d63f43b
TC
1295 tree ftype = build_function_type_list (argtype, argtype, argtype,
1296 quadtype, lanetype, NULL_TREE);
079c23cf
KT
1297 tree attrs = aarch64_get_attributes (FLAG_FP, d->mode);
1298 tree fndecl
1299 = aarch64_general_add_builtin (d->name, ftype, d->fcode, attrs);
9d63f43b
TC
1300
1301 aarch64_builtin_decls[d->fcode] = fndecl;
1302 }
1303}
1304
c906efc7
AC
1305void
1306aarch64_init_simd_intrinsics (void)
1307{
1308 unsigned int i = 0;
1309
1310 for (i = 0; i < ARRAY_SIZE (aarch64_simd_intrinsic_data); ++i)
1311 {
1312 auto d = &aarch64_simd_intrinsic_data[i];
1313
1314 if (d->skip)
1315 continue;
1316
1317 tree return_type = void_type_node;
1318 tree args = void_list_node;
1319
1320 for (int op_num = d->op_count - 1; op_num >= 0; op_num--)
1321 {
1322 machine_mode op_mode = d->op_modes[op_num];
1323 enum aarch64_type_qualifiers qualifiers = d->qualifiers[op_num];
1324
1325 tree eltype = aarch64_simd_builtin_type (op_mode, qualifiers);
1326
1327 if (op_num == 0)
1328 return_type = eltype;
1329 else
1330 args = tree_cons (NULL_TREE, eltype, args);
1331 }
1332
1333 tree ftype = build_function_type (return_type, args);
8b271f60 1334 tree attrs = aarch64_get_attributes (d->flags, d->op_modes[0]);
c906efc7
AC
1335 unsigned int code
1336 = (d->fcode << AARCH64_BUILTIN_SHIFT | AARCH64_BUILTIN_GENERAL);
1337 tree fndecl = simulate_builtin_function_decl (input_location, d->name,
1338 ftype, code, NULL, attrs);
1339 aarch64_builtin_decls[d->fcode] = fndecl;
1340 }
1341}
1342
e95a988a 1343void
8197ab94 1344aarch64_init_simd_builtin_functions (bool called_from_pragma)
f9d53c27 1345{
661fce82 1346 unsigned int i, fcode = AARCH64_SIMD_PATTERN_START;
f9d53c27 1347
8197ab94
JW
1348 if (!called_from_pragma)
1349 {
1350 tree lane_check_fpr = build_function_type_list (void_type_node,
1351 size_type_node,
1352 size_type_node,
1353 intSI_type_node,
1354 NULL);
1355 aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_LANE_CHECK]
1356 = aarch64_general_add_builtin ("__builtin_aarch64_im_lane_boundsi",
1357 lane_check_fpr,
1358 AARCH64_SIMD_BUILTIN_LANE_CHECK);
1359 }
661fce82 1360
342be7f7 1361 for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++)
43e9d192 1362 {
b5828b4b 1363 bool print_type_signature_p = false;
cae83731 1364 char type_signature[SIMD_MAX_BUILTIN_ARGS + 1] = { 0 };
43e9d192 1365 aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i];
342be7f7
JG
1366 char namebuf[60];
1367 tree ftype = NULL;
119103ca 1368 tree fndecl = NULL;
342be7f7 1369
342be7f7 1370 d->fcode = fcode;
43e9d192 1371
b5828b4b
JG
1372 /* We must track two variables here. op_num is
1373 the operand number as in the RTL pattern. This is
1374 required to access the mode (e.g. V4SF mode) of the
1375 argument, from which the base type can be derived.
1376 arg_num is an index in to the qualifiers data, which
1377 gives qualifiers to the type (e.g. const unsigned).
1378 The reason these two variables may differ by one is the
1379 void return type. While all return types take the 0th entry
1380 in the qualifiers array, there is no operand for them in the
1381 RTL pattern. */
1382 int op_num = insn_data[d->code].n_operands - 1;
1383 int arg_num = d->qualifiers[0] & qualifier_void
1384 ? op_num + 1
1385 : op_num;
1386 tree return_type = void_type_node, args = void_list_node;
1387 tree eltype;
1388
8197ab94
JW
1389 int struct_mode_args = 0;
1390 for (int j = op_num; j >= 0; j--)
1391 {
1392 machine_mode op_mode = insn_data[d->code].operand[j].mode;
1393 if (aarch64_advsimd_struct_mode_p (op_mode))
1394 struct_mode_args++;
1395 }
1396
1397 if ((called_from_pragma && struct_mode_args == 0)
1398 || (!called_from_pragma && struct_mode_args > 0))
1399 continue;
1400
b5828b4b
JG
1401 /* Build a function type directly from the insn_data for this
1402 builtin. The build_function_type () function takes care of
1403 removing duplicates for us. */
1404 for (; op_num >= 0; arg_num--, op_num--)
43e9d192 1405 {
ef4bddc2 1406 machine_mode op_mode = insn_data[d->code].operand[op_num].mode;
b5828b4b 1407 enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num];
43e9d192 1408
b5828b4b
JG
1409 if (qualifiers & qualifier_unsigned)
1410 {
9fd2074d 1411 type_signature[op_num] = 'u';
b5828b4b
JG
1412 print_type_signature_p = true;
1413 }
6db1ec94
JG
1414 else if (qualifiers & qualifier_poly)
1415 {
9fd2074d 1416 type_signature[op_num] = 'p';
6db1ec94
JG
1417 print_type_signature_p = true;
1418 }
b5828b4b 1419 else
9fd2074d 1420 type_signature[op_num] = 's';
b5828b4b 1421
b5828b4b
JG
1422 /* Some builtins have different user-facing types
1423 for certain arguments, encoded in d->mode. */
1424 if (qualifiers & qualifier_map_mode)
bc5e395d 1425 op_mode = d->mode;
b5828b4b 1426
f023cc54 1427 eltype = aarch64_simd_builtin_type (op_mode, qualifiers);
b5828b4b
JG
1428
1429 /* If we have reached arg_num == 0, we are at a non-void
1430 return type. Otherwise, we are still processing
1431 arguments. */
1432 if (arg_num == 0)
1433 return_type = eltype;
1434 else
1435 args = tree_cons (NULL_TREE, eltype, args);
1436 }
342be7f7 1437
b5828b4b 1438 ftype = build_function_type (return_type, args);
43e9d192 1439
342be7f7 1440 gcc_assert (ftype != NULL);
43e9d192 1441
b5828b4b 1442 if (print_type_signature_p)
bc5e395d
JG
1443 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s_%s",
1444 d->name, type_signature);
b5828b4b 1445 else
bc5e395d
JG
1446 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s",
1447 d->name);
43e9d192 1448
079c23cf 1449 tree attrs = aarch64_get_attributes (d->flags, d->mode);
072a8b8f 1450
66f206b8
JW
1451 if (called_from_pragma)
1452 {
1453 unsigned int raw_code
1454 = (fcode << AARCH64_BUILTIN_SHIFT) | AARCH64_BUILTIN_GENERAL;
1455 fndecl = simulate_builtin_function_decl (input_location, namebuf,
1456 ftype, raw_code, NULL,
1457 attrs);
1458 }
1459 else
1460 fndecl = aarch64_general_add_builtin (namebuf, ftype, fcode, attrs);
1461
119103ca 1462 aarch64_builtin_decls[fcode] = fndecl;
43e9d192 1463 }
8197ab94
JW
1464}
1465
1466/* Register the tuple type that contains NUM_VECTORS of the AdvSIMD type
1467 indexed by TYPE_INDEX. */
1468static void
1469register_tuple_type (unsigned int num_vectors, unsigned int type_index)
1470{
1471 aarch64_simd_type_info *type = &aarch64_simd_types[type_index];
1472
1473 /* Synthesize the name of the user-visible vector tuple type. */
1474 const char *vector_type_name = type->name;
1475 char tuple_type_name[sizeof ("bfloat16x4x2_t")];
1476 snprintf (tuple_type_name, sizeof (tuple_type_name), "%.*sx%d_t",
1477 (int) strlen (vector_type_name) - 4, vector_type_name + 2,
1478 num_vectors);
1479 tuple_type_name[0] = TOLOWER (tuple_type_name[0]);
1480
1481 tree vector_type = type->itype;
1482 tree array_type = build_array_type_nelts (vector_type, num_vectors);
66f206b8
JW
1483 if (type->mode == DImode)
1484 {
1485 if (num_vectors == 2)
1486 SET_TYPE_MODE (array_type, V2x1DImode);
1487 else if (num_vectors == 3)
1488 SET_TYPE_MODE (array_type, V3x1DImode);
1489 else if (num_vectors == 4)
1490 SET_TYPE_MODE (array_type, V4x1DImode);
1491 }
1492
8197ab94 1493 unsigned int alignment
14814e20
RS
1494 = known_eq (GET_MODE_SIZE (type->mode), 16) ? 128 : 64;
1495 machine_mode tuple_mode = TYPE_MODE_RAW (array_type);
1496 gcc_assert (VECTOR_MODE_P (tuple_mode)
1497 && TYPE_MODE (array_type) == tuple_mode
8197ab94
JW
1498 && TYPE_ALIGN (array_type) == alignment);
1499
1500 tree field = build_decl (input_location, FIELD_DECL,
1501 get_identifier ("val"), array_type);
1502
1503 tree t = lang_hooks.types.simulate_record_decl (input_location,
1504 tuple_type_name,
1505 make_array_slice (&field,
1506 1));
1507 gcc_assert (TYPE_MODE_RAW (t) == TYPE_MODE (t)
14814e20
RS
1508 && (flag_pack_struct
1509 || maximum_field_alignment
1510 || (TYPE_MODE_RAW (t) == tuple_mode
1511 && TYPE_ALIGN (t) == alignment)));
1512
1513 aarch64_simd_tuple_modes[type_index][num_vectors - 2] = tuple_mode;
1514 aarch64_simd_tuple_types[type_index][num_vectors - 2] = t;
8197ab94
JW
1515}
1516
1517static bool
1518aarch64_scalar_builtin_type_p (aarch64_simd_type t)
1519{
1520 return (t == Poly8_t || t == Poly16_t || t == Poly64_t || t == Poly128_t);
1521}
1522
14814e20
RS
1523/* Enable AARCH64_FL_* flags EXTRA_FLAGS on top of the base Advanced SIMD
1524 set. */
a1a9ce24 1525aarch64_simd_switcher::aarch64_simd_switcher (aarch64_feature_flags extra_flags)
2a269bda 1526 : m_old_asm_isa_flags (aarch64_asm_isa_flags),
14814e20
RS
1527 m_old_general_regs_only (TARGET_GENERAL_REGS_ONLY)
1528{
1529 /* Changing the ISA flags should be enough here. We shouldn't need to
1530 pay the compile-time cost of a full target switch. */
14814e20 1531 global_options.x_target_flags &= ~MASK_GENERAL_REGS_ONLY;
2a269bda 1532 aarch64_set_asm_isa_flags (AARCH64_FL_FP | AARCH64_FL_SIMD | extra_flags);
14814e20
RS
1533}
1534
1535aarch64_simd_switcher::~aarch64_simd_switcher ()
1536{
1537 if (m_old_general_regs_only)
1538 global_options.x_target_flags |= MASK_GENERAL_REGS_ONLY;
2a269bda 1539 aarch64_set_asm_isa_flags (m_old_asm_isa_flags);
14814e20
RS
1540}
1541
c906efc7
AC
1542/* Implement #pragma GCC aarch64 "arm_neon.h".
1543
1544 The types and functions defined here need to be available internally
1545 during LTO as well. */
8197ab94
JW
1546void
1547handle_arm_neon_h (void)
1548{
14814e20
RS
1549 aarch64_simd_switcher simd;
1550
8197ab94
JW
1551 /* Register the AdvSIMD vector tuple types. */
1552 for (unsigned int i = 0; i < ARM_NEON_H_TYPES_LAST; i++)
1553 for (unsigned int count = 2; count <= 4; ++count)
1554 if (!aarch64_scalar_builtin_type_p (aarch64_simd_types[i].type))
1555 register_tuple_type (count, i);
1556
1557 aarch64_init_simd_builtin_functions (true);
c906efc7 1558 aarch64_init_simd_intrinsics ();
8197ab94
JW
1559}
1560
d29ecf23 1561static void
8197ab94
JW
1562aarch64_init_simd_builtins (void)
1563{
8197ab94
JW
1564 aarch64_init_simd_builtin_types ();
1565
1566 /* Strong-typing hasn't been implemented for all AdvSIMD builtin intrinsics.
1567 Therefore we need to preserve the old __builtin scalar types. It can be
1568 removed once all the intrinsics become strongly typed using the qualifier
1569 system. */
1570 aarch64_init_simd_builtin_scalar_types ();
1571
1572 aarch64_init_simd_builtin_functions (false);
1573 if (in_lto_p)
1574 handle_arm_neon_h ();
280d970b 1575
8197ab94
JW
1576 /* Initialize the remaining fcmla_laneq intrinsics. */
1577 aarch64_init_fcmla_laneq_builtins ();
43e9d192
IB
1578}
1579
5d357f26
KT
1580static void
1581aarch64_init_crc32_builtins ()
1582{
f023cc54 1583 tree usi_type = aarch64_simd_builtin_type (SImode, qualifier_unsigned);
5d357f26
KT
1584 unsigned int i = 0;
1585
1586 for (i = 0; i < ARRAY_SIZE (aarch64_crc_builtin_data); ++i)
1587 {
1588 aarch64_crc_builtin_datum* d = &aarch64_crc_builtin_data[i];
f023cc54 1589 tree argtype = aarch64_simd_builtin_type (d->mode, qualifier_unsigned);
5d357f26 1590 tree ftype = build_function_type_list (usi_type, usi_type, argtype, NULL_TREE);
079c23cf
KT
1591 tree attrs = aarch64_get_attributes (FLAG_NONE, d->mode);
1592 tree fndecl
1593 = aarch64_general_add_builtin (d->name, ftype, d->fcode, attrs);
5d357f26
KT
1594
1595 aarch64_builtin_decls[d->fcode] = fndecl;
1596 }
1597}
1598
a6fc00da
BH
1599/* Add builtins for reciprocal square root. */
1600
1601void
1602aarch64_init_builtin_rsqrt (void)
1603{
1604 tree fndecl = NULL;
1605 tree ftype = NULL;
1606
1607 tree V2SF_type_node = build_vector_type (float_type_node, 2);
1608 tree V2DF_type_node = build_vector_type (double_type_node, 2);
1609 tree V4SF_type_node = build_vector_type (float_type_node, 4);
1610
1611 struct builtin_decls_data
1612 {
1613 tree type_node;
1614 const char *builtin_name;
1615 int function_code;
1616 };
1617
1618 builtin_decls_data bdda[] =
1619 {
1620 { double_type_node, "__builtin_aarch64_rsqrt_df", AARCH64_BUILTIN_RSQRT_DF },
1621 { float_type_node, "__builtin_aarch64_rsqrt_sf", AARCH64_BUILTIN_RSQRT_SF },
1622 { V2DF_type_node, "__builtin_aarch64_rsqrt_v2df", AARCH64_BUILTIN_RSQRT_V2DF },
1623 { V2SF_type_node, "__builtin_aarch64_rsqrt_v2sf", AARCH64_BUILTIN_RSQRT_V2SF },
1624 { V4SF_type_node, "__builtin_aarch64_rsqrt_v4sf", AARCH64_BUILTIN_RSQRT_V4SF }
1625 };
1626
1627 builtin_decls_data *bdd = bdda;
ca32b29e 1628 builtin_decls_data *bdd_end = bdd + (ARRAY_SIZE (bdda));
a6fc00da
BH
1629
1630 for (; bdd < bdd_end; bdd++)
1631 {
1632 ftype = build_function_type_list (bdd->type_node, bdd->type_node, NULL_TREE);
079c23cf 1633 tree attrs = aarch64_get_attributes (FLAG_FP, TYPE_MODE (bdd->type_node));
6d4d616a 1634 fndecl = aarch64_general_add_builtin (bdd->builtin_name,
079c23cf 1635 ftype, bdd->function_code, attrs);
a6fc00da
BH
1636 aarch64_builtin_decls[bdd->function_code] = fndecl;
1637 }
1638}
1639
1b62ed4f
JG
1640/* Initialize the backend types that support the user-visible __fp16
1641 type, also initialize a pointer to that type, to be used when
1642 forming HFAs. */
1643
1644static void
1645aarch64_init_fp16_types (void)
1646{
1647 aarch64_fp16_type_node = make_node (REAL_TYPE);
1648 TYPE_PRECISION (aarch64_fp16_type_node) = 16;
1649 layout_type (aarch64_fp16_type_node);
1650
1651 (*lang_hooks.types.register_builtin_type) (aarch64_fp16_type_node, "__fp16");
1652 aarch64_fp16_ptr_type_node = build_pointer_type (aarch64_fp16_type_node);
1653}
1654
abbe1ed2
SMW
1655/* Initialize the backend REAL_TYPE type supporting bfloat types. */
1656static void
1657aarch64_init_bf16_types (void)
1658{
13071c3c
JJ
1659 lang_hooks.types.register_builtin_type (bfloat16_type_node, "__bf16");
1660 aarch64_bf16_ptr_type_node = build_pointer_type (bfloat16_type_node);
abbe1ed2
SMW
1661}
1662
312492bd
JW
1663/* Pointer authentication builtins that will become NOP on legacy platform.
1664 Currently, these builtins are for internal use only (libgcc EH unwinder). */
1665
1666void
1667aarch64_init_pauth_hint_builtins (void)
1668{
1669 /* Pointer Authentication builtins. */
1670 tree ftype_pointer_auth
1671 = build_function_type_list (ptr_type_node, ptr_type_node,
1672 unsigned_intDI_type_node, NULL_TREE);
1673 tree ftype_pointer_strip
1674 = build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE);
1675
1676 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_AUTIA1716]
6d4d616a
RS
1677 = aarch64_general_add_builtin ("__builtin_aarch64_autia1716",
1678 ftype_pointer_auth,
1679 AARCH64_PAUTH_BUILTIN_AUTIA1716);
312492bd 1680 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_PACIA1716]
6d4d616a
RS
1681 = aarch64_general_add_builtin ("__builtin_aarch64_pacia1716",
1682 ftype_pointer_auth,
1683 AARCH64_PAUTH_BUILTIN_PACIA1716);
8fc16d72 1684 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_AUTIB1716]
6d4d616a
RS
1685 = aarch64_general_add_builtin ("__builtin_aarch64_autib1716",
1686 ftype_pointer_auth,
1687 AARCH64_PAUTH_BUILTIN_AUTIB1716);
8fc16d72 1688 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_PACIB1716]
6d4d616a
RS
1689 = aarch64_general_add_builtin ("__builtin_aarch64_pacib1716",
1690 ftype_pointer_auth,
1691 AARCH64_PAUTH_BUILTIN_PACIB1716);
312492bd 1692 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_XPACLRI]
6d4d616a
RS
1693 = aarch64_general_add_builtin ("__builtin_aarch64_xpaclri",
1694 ftype_pointer_strip,
1695 AARCH64_PAUTH_BUILTIN_XPACLRI);
312492bd
JW
1696}
1697
89626179
SD
1698/* Initialize the transactional memory extension (TME) builtins. */
1699static void
1700aarch64_init_tme_builtins (void)
1701{
1702 tree ftype_uint64_void
1703 = build_function_type_list (uint64_type_node, NULL);
1704 tree ftype_void_void
1705 = build_function_type_list (void_type_node, NULL);
1706 tree ftype_void_uint64
1707 = build_function_type_list (void_type_node, uint64_type_node, NULL);
1708
1709 aarch64_builtin_decls[AARCH64_TME_BUILTIN_TSTART]
6d4d616a
RS
1710 = aarch64_general_add_builtin ("__builtin_aarch64_tstart",
1711 ftype_uint64_void,
1712 AARCH64_TME_BUILTIN_TSTART);
89626179 1713 aarch64_builtin_decls[AARCH64_TME_BUILTIN_TTEST]
6d4d616a
RS
1714 = aarch64_general_add_builtin ("__builtin_aarch64_ttest",
1715 ftype_uint64_void,
1716 AARCH64_TME_BUILTIN_TTEST);
89626179 1717 aarch64_builtin_decls[AARCH64_TME_BUILTIN_TCOMMIT]
6d4d616a
RS
1718 = aarch64_general_add_builtin ("__builtin_aarch64_tcommit",
1719 ftype_void_void,
1720 AARCH64_TME_BUILTIN_TCOMMIT);
89626179 1721 aarch64_builtin_decls[AARCH64_TME_BUILTIN_TCANCEL]
6d4d616a
RS
1722 = aarch64_general_add_builtin ("__builtin_aarch64_tcancel",
1723 ftype_void_uint64,
1724 AARCH64_TME_BUILTIN_TCANCEL);
89626179
SD
1725}
1726
c5dc215d
KT
1727/* Add builtins for Random Number instructions. */
1728
1729static void
1730aarch64_init_rng_builtins (void)
1731{
1732 tree unsigned_ptr_type = build_pointer_type (unsigned_intDI_type_node);
1733 tree ftype
1734 = build_function_type_list (integer_type_node, unsigned_ptr_type, NULL);
1735 aarch64_builtin_decls[AARCH64_BUILTIN_RNG_RNDR]
1736 = aarch64_general_add_builtin ("__builtin_aarch64_rndr", ftype,
1737 AARCH64_BUILTIN_RNG_RNDR);
1738 aarch64_builtin_decls[AARCH64_BUILTIN_RNG_RNDRRS]
1739 = aarch64_general_add_builtin ("__builtin_aarch64_rndrrs", ftype,
1740 AARCH64_BUILTIN_RNG_RNDRRS);
1741}
1742
fc42900d
VDN
1743/* Add builtins for reading system register. */
1744static void
1745aarch64_init_rwsr_builtins (void)
1746{
1747 tree fntype = NULL;
1748 tree const_char_ptr_type
1749 = build_pointer_type (build_type_variant (char_type_node, true, false));
1750
1751#define AARCH64_INIT_RWSR_BUILTINS_DECL(F, N, T) \
1752 aarch64_builtin_decls[AARCH64_##F] \
1753 = aarch64_general_add_builtin ("__builtin_aarch64_"#N, T, AARCH64_##F);
1754
1755 fntype
1756 = build_function_type_list (uint32_type_node, const_char_ptr_type, NULL);
1757 AARCH64_INIT_RWSR_BUILTINS_DECL (RSR, rsr, fntype);
1758
1759 fntype
1760 = build_function_type_list (ptr_type_node, const_char_ptr_type, NULL);
1761 AARCH64_INIT_RWSR_BUILTINS_DECL (RSRP, rsrp, fntype);
1762
1763 fntype
1764 = build_function_type_list (uint64_type_node, const_char_ptr_type, NULL);
1765 AARCH64_INIT_RWSR_BUILTINS_DECL (RSR64, rsr64, fntype);
1766
1767 fntype
1768 = build_function_type_list (float_type_node, const_char_ptr_type, NULL);
1769 AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF, rsrf, fntype);
1770
1771 fntype
1772 = build_function_type_list (double_type_node, const_char_ptr_type, NULL);
1773 AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF64, rsrf64, fntype);
1774
88157c88
VDN
1775 fntype
1776 = build_function_type_list (uint128_type_node, const_char_ptr_type, NULL);
1777 AARCH64_INIT_RWSR_BUILTINS_DECL (RSR128, rsr128, fntype);
1778
fc42900d
VDN
1779 fntype
1780 = build_function_type_list (void_type_node, const_char_ptr_type,
1781 uint32_type_node, NULL);
1782
1783 AARCH64_INIT_RWSR_BUILTINS_DECL (WSR, wsr, fntype);
1784
1785 fntype
1786 = build_function_type_list (void_type_node, const_char_ptr_type,
1787 const_ptr_type_node, NULL);
1788 AARCH64_INIT_RWSR_BUILTINS_DECL (WSRP, wsrp, fntype);
1789
1790 fntype
1791 = build_function_type_list (void_type_node, const_char_ptr_type,
1792 uint64_type_node, NULL);
1793 AARCH64_INIT_RWSR_BUILTINS_DECL (WSR64, wsr64, fntype);
1794
1795 fntype
1796 = build_function_type_list (void_type_node, const_char_ptr_type,
1797 float_type_node, NULL);
1798 AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF, wsrf, fntype);
1799
1800 fntype
1801 = build_function_type_list (void_type_node, const_char_ptr_type,
1802 double_type_node, NULL);
1803 AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF64, wsrf64, fntype);
88157c88
VDN
1804
1805 fntype
1806 = build_function_type_list (void_type_node, const_char_ptr_type,
1807 uint128_type_node, NULL);
1808 AARCH64_INIT_RWSR_BUILTINS_DECL (WSR128, wsr128, fntype);
9fba6637
VDN
1809}
1810
1811/* Add builtins for data and instrution prefetch. */
1812static void
1813aarch64_init_prefetch_builtin (void)
1814{
1815#define AARCH64_INIT_PREFETCH_BUILTIN(INDEX, N) \
1816 aarch64_builtin_decls[INDEX] = \
1817 aarch64_general_add_builtin ("__builtin_aarch64_" N, ftype, INDEX)
88157c88 1818
9fba6637
VDN
1819 tree ftype;
1820 tree cv_argtype;
1821 cv_argtype = build_qualified_type (void_type_node, TYPE_QUAL_CONST
1822 | TYPE_QUAL_VOLATILE);
1823 cv_argtype = build_pointer_type (cv_argtype);
1824
1825 ftype = build_function_type_list (void_type_node, cv_argtype, NULL);
1826 AARCH64_INIT_PREFETCH_BUILTIN (AARCH64_PLD, "pld");
1827 AARCH64_INIT_PREFETCH_BUILTIN (AARCH64_PLI, "pli");
1828
1829 ftype = build_function_type_list (void_type_node, unsigned_type_node,
1830 unsigned_type_node, unsigned_type_node,
1831 cv_argtype, NULL);
1832 AARCH64_INIT_PREFETCH_BUILTIN (AARCH64_PLDX, "pldx");
1833
1834 ftype = build_function_type_list (void_type_node, unsigned_type_node,
1835 unsigned_type_node, cv_argtype, NULL);
1836 AARCH64_INIT_PREFETCH_BUILTIN (AARCH64_PLIX, "plix");
fc42900d
VDN
1837}
1838
ef01e6bb
DZ
1839/* Initialize the memory tagging extension (MTE) builtins. */
1840struct
1841{
1842 tree ftype;
1843 enum insn_code icode;
1844} aarch64_memtag_builtin_data[AARCH64_MEMTAG_BUILTIN_END -
1845 AARCH64_MEMTAG_BUILTIN_START - 1];
1846
1847static void
1848aarch64_init_memtag_builtins (void)
1849{
1850 tree fntype = NULL;
1851
1852#define AARCH64_INIT_MEMTAG_BUILTINS_DECL(F, N, I, T) \
1853 aarch64_builtin_decls[AARCH64_MEMTAG_BUILTIN_##F] \
1854 = aarch64_general_add_builtin ("__builtin_aarch64_memtag_"#N, \
1855 T, AARCH64_MEMTAG_BUILTIN_##F); \
1856 aarch64_memtag_builtin_data[AARCH64_MEMTAG_BUILTIN_##F - \
1857 AARCH64_MEMTAG_BUILTIN_START - 1] = \
1858 {T, CODE_FOR_##I};
1859
1860 fntype = build_function_type_list (ptr_type_node, ptr_type_node,
1861 uint64_type_node, NULL);
1862 AARCH64_INIT_MEMTAG_BUILTINS_DECL (IRG, irg, irg, fntype);
1863
1864 fntype = build_function_type_list (uint64_type_node, ptr_type_node,
1865 uint64_type_node, NULL);
1866 AARCH64_INIT_MEMTAG_BUILTINS_DECL (GMI, gmi, gmi, fntype);
1867
1868 fntype = build_function_type_list (ptrdiff_type_node, ptr_type_node,
1869 ptr_type_node, NULL);
1870 AARCH64_INIT_MEMTAG_BUILTINS_DECL (SUBP, subp, subp, fntype);
1871
1872 fntype = build_function_type_list (ptr_type_node, ptr_type_node,
1873 unsigned_type_node, NULL);
1874 AARCH64_INIT_MEMTAG_BUILTINS_DECL (INC_TAG, inc_tag, addg, fntype);
1875
1876 fntype = build_function_type_list (void_type_node, ptr_type_node, NULL);
1877 AARCH64_INIT_MEMTAG_BUILTINS_DECL (SET_TAG, set_tag, stg, fntype);
1878
1879 fntype = build_function_type_list (ptr_type_node, ptr_type_node, NULL);
1880 AARCH64_INIT_MEMTAG_BUILTINS_DECL (GET_TAG, get_tag, ldg, fntype);
1881
1882#undef AARCH64_INIT_MEMTAG_BUILTINS_DECL
1883}
c5dc215d 1884
fdcddba8
PW
1885/* Add builtins for Load/store 64 Byte instructions. */
1886
1887typedef struct
1888{
1889 const char *name;
1890 unsigned int code;
1891 tree type;
1892} ls64_builtins_data;
1893
1894static GTY(()) tree ls64_arm_data_t = NULL_TREE;
1895
1896static void
1897aarch64_init_ls64_builtins_types (void)
1898{
1899 /* Synthesize:
1900
1901 typedef struct {
1902 uint64_t val[8];
1903 } __arm_data512_t; */
1904 const char *tuple_type_name = "__arm_data512_t";
1905 tree node_type = get_typenode_from_name (UINT64_TYPE);
1906 tree array_type = build_array_type_nelts (node_type, 8);
1907 SET_TYPE_MODE (array_type, V8DImode);
1908
1909 gcc_assert (TYPE_MODE_RAW (array_type) == TYPE_MODE (array_type));
1910 gcc_assert (TYPE_ALIGN (array_type) == 64);
1911
1912 tree field = build_decl (input_location, FIELD_DECL,
71361354 1913 get_identifier ("val"), array_type);
fdcddba8
PW
1914
1915 ls64_arm_data_t = lang_hooks.types.simulate_record_decl (input_location,
71361354
AC
1916 tuple_type_name,
1917 make_array_slice (&field, 1));
fdcddba8
PW
1918
1919 gcc_assert (TYPE_MODE (ls64_arm_data_t) == V8DImode);
1920 gcc_assert (TYPE_MODE_RAW (ls64_arm_data_t) == TYPE_MODE (ls64_arm_data_t));
1921 gcc_assert (TYPE_ALIGN (ls64_arm_data_t) == 64);
1922}
1923
1924static void
1925aarch64_init_ls64_builtins (void)
1926{
1927 aarch64_init_ls64_builtins_types ();
1928
1929 ls64_builtins_data data[4] = {
9963029a 1930 {"__arm_ld64b", AARCH64_LS64_BUILTIN_LD64B,
fdcddba8 1931 build_function_type_list (ls64_arm_data_t,
71361354 1932 const_ptr_type_node, NULL_TREE)},
9963029a 1933 {"__arm_st64b", AARCH64_LS64_BUILTIN_ST64B,
fdcddba8 1934 build_function_type_list (void_type_node, ptr_type_node,
71361354 1935 ls64_arm_data_t, NULL_TREE)},
9963029a 1936 {"__arm_st64bv", AARCH64_LS64_BUILTIN_ST64BV,
fdcddba8 1937 build_function_type_list (uint64_type_node, ptr_type_node,
71361354 1938 ls64_arm_data_t, NULL_TREE)},
9963029a 1939 {"__arm_st64bv0", AARCH64_LS64_BUILTIN_ST64BV0,
fdcddba8 1940 build_function_type_list (uint64_type_node, ptr_type_node,
71361354 1941 ls64_arm_data_t, NULL_TREE)},
fdcddba8
PW
1942 };
1943
1944 for (size_t i = 0; i < ARRAY_SIZE (data); ++i)
1945 aarch64_builtin_decls[data[i].code]
9963029a
AC
1946 = aarch64_general_simulate_builtin (data[i].name, data[i].type,
1947 data[i].code);
fdcddba8
PW
1948}
1949
eb966d39
ASDV
1950static void
1951aarch64_init_data_intrinsics (void)
1952{
1953 tree uint32_fntype = build_function_type_list (uint32_type_node,
1954 uint32_type_node, NULL_TREE);
1955 tree ulong_fntype = build_function_type_list (long_unsigned_type_node,
1956 long_unsigned_type_node,
1957 NULL_TREE);
1958 tree uint64_fntype = build_function_type_list (uint64_type_node,
1959 uint64_type_node, NULL_TREE);
1960 aarch64_builtin_decls[AARCH64_REV16]
1961 = aarch64_general_add_builtin ("__builtin_aarch64_rev16", uint32_fntype,
1962 AARCH64_REV16);
1963 aarch64_builtin_decls[AARCH64_REV16L]
1964 = aarch64_general_add_builtin ("__builtin_aarch64_rev16l", ulong_fntype,
1965 AARCH64_REV16L);
1966 aarch64_builtin_decls[AARCH64_REV16LL]
1967 = aarch64_general_add_builtin ("__builtin_aarch64_rev16ll", uint64_fntype,
1968 AARCH64_REV16LL);
1969 aarch64_builtin_decls[AARCH64_RBIT]
1970 = aarch64_general_add_builtin ("__builtin_aarch64_rbit", uint32_fntype,
1971 AARCH64_RBIT);
1972 aarch64_builtin_decls[AARCH64_RBITL]
1973 = aarch64_general_add_builtin ("__builtin_aarch64_rbitl", ulong_fntype,
1974 AARCH64_RBITL);
1975 aarch64_builtin_decls[AARCH64_RBITLL]
1976 = aarch64_general_add_builtin ("__builtin_aarch64_rbitll", uint64_fntype,
1977 AARCH64_RBITLL);
1978}
1979
af3cadb5
TC
1980/* Implement #pragma GCC aarch64 "arm_acle.h". */
1981void
1982handle_arm_acle_h (void)
1983{
1984 if (TARGET_LS64)
1985 aarch64_init_ls64_builtins ();
1986}
1987
0d7e5fa6 1988/* Initialize fpsr fpcr getters and setters. */
c5dc215d 1989
0d7e5fa6
AC
1990static void
1991aarch64_init_fpsr_fpcr_builtins (void)
43e9d192 1992{
0d7e5fa6 1993 tree ftype_set
aa87aced 1994 = build_function_type_list (void_type_node, unsigned_type_node, NULL);
0d7e5fa6 1995 tree ftype_get
aa87aced
KV
1996 = build_function_type_list (unsigned_type_node, NULL);
1997
1998 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR]
6d4d616a 1999 = aarch64_general_add_builtin ("__builtin_aarch64_get_fpcr",
0d7e5fa6 2000 ftype_get,
6d4d616a 2001 AARCH64_BUILTIN_GET_FPCR);
aa87aced 2002 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR]
6d4d616a 2003 = aarch64_general_add_builtin ("__builtin_aarch64_set_fpcr",
0d7e5fa6 2004 ftype_set,
6d4d616a 2005 AARCH64_BUILTIN_SET_FPCR);
aa87aced 2006 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR]
6d4d616a 2007 = aarch64_general_add_builtin ("__builtin_aarch64_get_fpsr",
0d7e5fa6 2008 ftype_get,
6d4d616a 2009 AARCH64_BUILTIN_GET_FPSR);
aa87aced 2010 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR]
6d4d616a 2011 = aarch64_general_add_builtin ("__builtin_aarch64_set_fpsr",
0d7e5fa6 2012 ftype_set,
6d4d616a 2013 AARCH64_BUILTIN_SET_FPSR);
aa87aced 2014
0d7e5fa6
AC
2015 ftype_set
2016 = build_function_type_list (void_type_node, long_long_unsigned_type_node,
2017 NULL);
2018 ftype_get
2019 = build_function_type_list (long_long_unsigned_type_node, NULL);
2020
2021 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR64]
2022 = aarch64_general_add_builtin ("__builtin_aarch64_get_fpcr64",
2023 ftype_get,
2024 AARCH64_BUILTIN_GET_FPCR64);
2025 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR64]
2026 = aarch64_general_add_builtin ("__builtin_aarch64_set_fpcr64",
2027 ftype_set,
2028 AARCH64_BUILTIN_SET_FPCR64);
2029 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR64]
2030 = aarch64_general_add_builtin ("__builtin_aarch64_get_fpsr64",
2031 ftype_get,
2032 AARCH64_BUILTIN_GET_FPSR64);
2033 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR64]
2034 = aarch64_general_add_builtin ("__builtin_aarch64_set_fpsr64",
2035 ftype_set,
2036 AARCH64_BUILTIN_SET_FPSR64);
2037}
2038
2039/* Initialize all builtins in the AARCH64_BUILTIN_GENERAL group. */
2040
2041void
2042aarch64_general_init_builtins (void)
2043{
2044 aarch64_init_fpsr_fpcr_builtins ();
2045
1b62ed4f 2046 aarch64_init_fp16_types ();
c2ec330c 2047
abbe1ed2
SMW
2048 aarch64_init_bf16_types ();
2049
14814e20
RS
2050 {
2051 aarch64_simd_switcher simd;
280d970b 2052 aarch64_init_simd_builtins ();
14814e20 2053 }
e95a988a
KT
2054
2055 aarch64_init_crc32_builtins ();
a6fc00da 2056 aarch64_init_builtin_rsqrt ();
c5dc215d 2057 aarch64_init_rng_builtins ();
eb966d39 2058 aarch64_init_data_intrinsics ();
312492bd 2059
fc42900d 2060 aarch64_init_rwsr_builtins ();
9fba6637 2061 aarch64_init_prefetch_builtin ();
fc42900d 2062
e1d5d19e
KT
2063 tree ftype_jcvt
2064 = build_function_type_list (intSI_type_node, double_type_node, NULL);
2065 aarch64_builtin_decls[AARCH64_JSCVT]
6d4d616a
RS
2066 = aarch64_general_add_builtin ("__builtin_aarch64_jcvtzs", ftype_jcvt,
2067 AARCH64_JSCVT);
e1d5d19e 2068
a876231c
JW
2069 /* Initialize pointer authentication builtins which are backed by instructions
2070 in NOP encoding space.
2071
2072 NOTE: these builtins are supposed to be used by libgcc unwinder only, as
2073 there is no support on return address signing under ILP32, we don't
2074 register them. */
2075 if (!TARGET_ILP32)
2076 aarch64_init_pauth_hint_builtins ();
89626179
SD
2077
2078 if (TARGET_TME)
2079 aarch64_init_tme_builtins ();
ef01e6bb
DZ
2080
2081 if (TARGET_MEMTAG)
2082 aarch64_init_memtag_builtins ();
9963029a
AC
2083
2084 if (in_lto_p)
2085 handle_arm_acle_h ();
43e9d192
IB
2086}
2087
6d4d616a 2088/* Implement TARGET_BUILTIN_DECL for the AARCH64_BUILTIN_GENERAL group. */
119103ca 2089tree
6d4d616a 2090aarch64_general_builtin_decl (unsigned code, bool)
119103ca
JG
2091{
2092 if (code >= AARCH64_BUILTIN_MAX)
2093 return error_mark_node;
2094
2095 return aarch64_builtin_decls[code];
2096}
2097
5af697d7
VDN
2098bool
2099aarch64_general_check_builtin_call (location_t location, vec<location_t>,
2100 unsigned int code, tree fndecl,
2101 unsigned int nargs ATTRIBUTE_UNUSED, tree *args)
2102{
2103 switch (code)
2104 {
2105 case AARCH64_RSR:
2106 case AARCH64_RSRP:
2107 case AARCH64_RSR64:
2108 case AARCH64_RSRF:
2109 case AARCH64_RSRF64:
2110 case AARCH64_WSR:
2111 case AARCH64_WSRP:
2112 case AARCH64_WSR64:
2113 case AARCH64_WSRF:
2114 case AARCH64_WSRF64:
2115 tree addr = STRIP_NOPS (args[0]);
2116 if (TREE_CODE (TREE_TYPE (addr)) != POINTER_TYPE
2117 || TREE_CODE (addr) != ADDR_EXPR
2118 || TREE_CODE (TREE_OPERAND (addr, 0)) != STRING_CST)
2119 {
2120 error_at (location, "first argument to %qD must be a string literal",
2121 fndecl);
2122 return false;
2123 }
2124 }
2125 /* Default behavior. */
2126 return true;
2127}
2128
43e9d192
IB
2129typedef enum
2130{
2131 SIMD_ARG_COPY_TO_REG,
2132 SIMD_ARG_CONSTANT,
2a49c16d 2133 SIMD_ARG_LANE_INDEX,
4d0a0237 2134 SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX,
9d63f43b 2135 SIMD_ARG_LANE_PAIR_INDEX,
8c197c85 2136 SIMD_ARG_LANE_QUADTUP_INDEX,
43e9d192
IB
2137 SIMD_ARG_STOP
2138} builtin_simd_arg;
2139
e95a988a 2140
43e9d192
IB
2141static rtx
2142aarch64_simd_expand_args (rtx target, int icode, int have_retval,
4d0a0237 2143 tree exp, builtin_simd_arg *args,
b8506a8a 2144 machine_mode builtin_mode)
43e9d192 2145{
43e9d192 2146 rtx pat;
d9e80f49
AL
2147 rtx op[SIMD_MAX_BUILTIN_ARGS + 1]; /* First element for result operand. */
2148 int opc = 0;
2149
2150 if (have_retval)
2151 {
2152 machine_mode tmode = insn_data[icode].operand[0].mode;
2153 if (!target
43e9d192 2154 || GET_MODE (target) != tmode
d9e80f49
AL
2155 || !(*insn_data[icode].operand[0].predicate) (target, tmode))
2156 target = gen_reg_rtx (tmode);
2157 op[opc++] = target;
2158 }
43e9d192 2159
43e9d192
IB
2160 for (;;)
2161 {
d9e80f49 2162 builtin_simd_arg thisarg = args[opc - have_retval];
43e9d192
IB
2163
2164 if (thisarg == SIMD_ARG_STOP)
2165 break;
2166 else
2167 {
d9e80f49 2168 tree arg = CALL_EXPR_ARG (exp, opc - have_retval);
b8506a8a 2169 machine_mode mode = insn_data[icode].operand[opc].mode;
d9e80f49 2170 op[opc] = expand_normal (arg);
43e9d192
IB
2171
2172 switch (thisarg)
2173 {
2174 case SIMD_ARG_COPY_TO_REG:
d9e80f49
AL
2175 if (POINTER_TYPE_P (TREE_TYPE (arg)))
2176 op[opc] = convert_memory_address (Pmode, op[opc]);
2177 /*gcc_assert (GET_MODE (op[opc]) == mode); */
2178 if (!(*insn_data[icode].operand[opc].predicate)
2179 (op[opc], mode))
2180 op[opc] = copy_to_mode_reg (mode, op[opc]);
43e9d192
IB
2181 break;
2182
4d0a0237
CB
2183 case SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX:
2184 gcc_assert (opc > 1);
2185 if (CONST_INT_P (op[opc]))
2186 {
6a70badb
RS
2187 unsigned int nunits
2188 = GET_MODE_NUNITS (builtin_mode).to_constant ();
2189 aarch64_simd_lane_bounds (op[opc], 0, nunits, exp);
4d0a0237 2190 /* Keep to GCC-vector-extension lane indices in the RTL. */
7ac29c0f
RS
2191 op[opc] = aarch64_endian_lane_rtx (builtin_mode,
2192 INTVAL (op[opc]));
4d0a0237
CB
2193 }
2194 goto constant_arg;
2195
2a49c16d
AL
2196 case SIMD_ARG_LANE_INDEX:
2197 /* Must be a previous operand into which this is an index. */
d9e80f49
AL
2198 gcc_assert (opc > 0);
2199 if (CONST_INT_P (op[opc]))
2a49c16d 2200 {
d9e80f49 2201 machine_mode vmode = insn_data[icode].operand[opc - 1].mode;
6a70badb
RS
2202 unsigned int nunits
2203 = GET_MODE_NUNITS (vmode).to_constant ();
2204 aarch64_simd_lane_bounds (op[opc], 0, nunits, exp);
2a49c16d 2205 /* Keep to GCC-vector-extension lane indices in the RTL. */
7ac29c0f 2206 op[opc] = aarch64_endian_lane_rtx (vmode, INTVAL (op[opc]));
2a49c16d 2207 }
9d63f43b
TC
2208 /* If the lane index isn't a constant then error out. */
2209 goto constant_arg;
2210
2211 case SIMD_ARG_LANE_PAIR_INDEX:
2212 /* Must be a previous operand into which this is an index and
2213 index is restricted to nunits / 2. */
2214 gcc_assert (opc > 0);
2215 if (CONST_INT_P (op[opc]))
2216 {
2217 machine_mode vmode = insn_data[icode].operand[opc - 1].mode;
2218 unsigned int nunits
2219 = GET_MODE_NUNITS (vmode).to_constant ();
2220 aarch64_simd_lane_bounds (op[opc], 0, nunits / 2, exp);
2221 /* Keep to GCC-vector-extension lane indices in the RTL. */
33b5a38c
TC
2222 int lane = INTVAL (op[opc]);
2223 op[opc] = gen_int_mode (ENDIAN_LANE_N (nunits / 2, lane),
2224 SImode);
9d63f43b 2225 }
8c197c85
SMW
2226 /* If the lane index isn't a constant then error out. */
2227 goto constant_arg;
2228 case SIMD_ARG_LANE_QUADTUP_INDEX:
2229 /* Must be a previous operand into which this is an index and
2230 index is restricted to nunits / 4. */
2231 gcc_assert (opc > 0);
2232 if (CONST_INT_P (op[opc]))
2233 {
2234 machine_mode vmode = insn_data[icode].operand[opc - 1].mode;
2235 unsigned int nunits
2236 = GET_MODE_NUNITS (vmode).to_constant ();
2237 aarch64_simd_lane_bounds (op[opc], 0, nunits / 4, exp);
2238 /* Keep to GCC-vector-extension lane indices in the RTL. */
2239 int lane = INTVAL (op[opc]);
2240 op[opc] = gen_int_mode (ENDIAN_LANE_N (nunits / 4, lane),
2241 SImode);
2242 }
2243 /* If the lane index isn't a constant then error out. */
2244 goto constant_arg;
43e9d192 2245 case SIMD_ARG_CONSTANT:
4d0a0237 2246constant_arg:
d9e80f49
AL
2247 if (!(*insn_data[icode].operand[opc].predicate)
2248 (op[opc], mode))
d5a29419 2249 {
62e43587
MS
2250 error_at (EXPR_LOCATION (exp),
2251 "argument %d must be a constant immediate",
2252 opc + 1 - have_retval);
d5a29419
KT
2253 return const0_rtx;
2254 }
43e9d192
IB
2255 break;
2256
2257 case SIMD_ARG_STOP:
2258 gcc_unreachable ();
2259 }
2260
d9e80f49 2261 opc++;
43e9d192
IB
2262 }
2263 }
2264
d9e80f49
AL
2265 switch (opc)
2266 {
2267 case 1:
2268 pat = GEN_FCN (icode) (op[0]);
2269 break;
43e9d192 2270
d9e80f49
AL
2271 case 2:
2272 pat = GEN_FCN (icode) (op[0], op[1]);
2273 break;
43e9d192 2274
d9e80f49
AL
2275 case 3:
2276 pat = GEN_FCN (icode) (op[0], op[1], op[2]);
2277 break;
43e9d192 2278
d9e80f49
AL
2279 case 4:
2280 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
2281 break;
43e9d192 2282
d9e80f49
AL
2283 case 5:
2284 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
2285 break;
43e9d192 2286
d9e80f49
AL
2287 case 6:
2288 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]);
2289 break;
43e9d192 2290
d9e80f49
AL
2291 default:
2292 gcc_unreachable ();
2293 }
43e9d192
IB
2294
2295 if (!pat)
d5a29419 2296 return NULL_RTX;
43e9d192
IB
2297
2298 emit_insn (pat);
2299
2300 return target;
2301}
2302
2303/* Expand an AArch64 AdvSIMD builtin(intrinsic). */
2304rtx
2305aarch64_simd_expand_builtin (int fcode, tree exp, rtx target)
2306{
661fce82
AL
2307 if (fcode == AARCH64_SIMD_BUILTIN_LANE_CHECK)
2308 {
9c4f25cc
AP
2309 rtx totalsize = expand_normal (CALL_EXPR_ARG (exp, 0));
2310 rtx elementsize = expand_normal (CALL_EXPR_ARG (exp, 1));
2311 if (CONST_INT_P (totalsize) && CONST_INT_P (elementsize)
2312 && UINTVAL (elementsize) != 0
2313 && UINTVAL (totalsize) != 0)
2314 {
2315 rtx lane_idx = expand_normal (CALL_EXPR_ARG (exp, 2));
2316 if (CONST_INT_P (lane_idx))
2317 aarch64_simd_lane_bounds (lane_idx, 0,
2318 UINTVAL (totalsize)
2319 / UINTVAL (elementsize),
2320 exp);
2321 else
62e43587
MS
2322 error_at (EXPR_LOCATION (exp),
2323 "lane index must be a constant immediate");
9c4f25cc 2324 }
661fce82 2325 else
62e43587 2326 error_at (EXPR_LOCATION (exp),
58385f6a 2327 "total size and element size must be a nonzero "
62e43587 2328 "constant immediate");
661fce82
AL
2329 /* Don't generate any RTL. */
2330 return const0_rtx;
2331 }
342be7f7 2332 aarch64_simd_builtin_datum *d =
661fce82 2333 &aarch64_simd_builtin_data[fcode - AARCH64_SIMD_PATTERN_START];
342be7f7 2334 enum insn_code icode = d->code;
0ff2bf46 2335 builtin_simd_arg args[SIMD_MAX_BUILTIN_ARGS + 1];
b5828b4b
JG
2336 int num_args = insn_data[d->code].n_operands;
2337 int is_void = 0;
2338 int k;
43e9d192 2339
b5828b4b 2340 is_void = !!(d->qualifiers[0] & qualifier_void);
43e9d192 2341
b5828b4b
JG
2342 num_args += is_void;
2343
2344 for (k = 1; k < num_args; k++)
2345 {
2346 /* We have four arrays of data, each indexed in a different fashion.
2347 qualifiers - element 0 always describes the function return type.
2348 operands - element 0 is either the operand for return value (if
2349 the function has a non-void return type) or the operand for the
2350 first argument.
2351 expr_args - element 0 always holds the first argument.
2352 args - element 0 is always used for the return type. */
2353 int qualifiers_k = k;
2354 int operands_k = k - is_void;
2355 int expr_args_k = k - 1;
2356
2a49c16d
AL
2357 if (d->qualifiers[qualifiers_k] & qualifier_lane_index)
2358 args[k] = SIMD_ARG_LANE_INDEX;
9d63f43b
TC
2359 else if (d->qualifiers[qualifiers_k] & qualifier_lane_pair_index)
2360 args[k] = SIMD_ARG_LANE_PAIR_INDEX;
8c197c85
SMW
2361 else if (d->qualifiers[qualifiers_k] & qualifier_lane_quadtup_index)
2362 args[k] = SIMD_ARG_LANE_QUADTUP_INDEX;
4d0a0237
CB
2363 else if (d->qualifiers[qualifiers_k] & qualifier_struct_load_store_lane_index)
2364 args[k] = SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX;
2a49c16d 2365 else if (d->qualifiers[qualifiers_k] & qualifier_immediate)
b5828b4b
JG
2366 args[k] = SIMD_ARG_CONSTANT;
2367 else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate)
2368 {
2369 rtx arg
2370 = expand_normal (CALL_EXPR_ARG (exp,
2371 (expr_args_k)));
2372 /* Handle constants only if the predicate allows it. */
2373 bool op_const_int_p =
2374 (CONST_INT_P (arg)
2375 && (*insn_data[icode].operand[operands_k].predicate)
2376 (arg, insn_data[icode].operand[operands_k].mode));
2377 args[k] = op_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG;
2378 }
2379 else
2380 args[k] = SIMD_ARG_COPY_TO_REG;
43e9d192 2381
43e9d192 2382 }
b5828b4b
JG
2383 args[k] = SIMD_ARG_STOP;
2384
2385 /* The interface to aarch64_simd_expand_args expects a 0 if
2386 the function is void, and a 1 if it is not. */
2387 return aarch64_simd_expand_args
4d0a0237 2388 (target, icode, !is_void, exp, &args[1], d->mode);
43e9d192 2389}
342be7f7 2390
5d357f26
KT
2391rtx
2392aarch64_crc32_expand_builtin (int fcode, tree exp, rtx target)
2393{
2394 rtx pat;
2395 aarch64_crc_builtin_datum *d
2396 = &aarch64_crc_builtin_data[fcode - (AARCH64_CRC32_BUILTIN_BASE + 1)];
2397 enum insn_code icode = d->icode;
2398 tree arg0 = CALL_EXPR_ARG (exp, 0);
2399 tree arg1 = CALL_EXPR_ARG (exp, 1);
2400 rtx op0 = expand_normal (arg0);
2401 rtx op1 = expand_normal (arg1);
ef4bddc2
RS
2402 machine_mode tmode = insn_data[icode].operand[0].mode;
2403 machine_mode mode0 = insn_data[icode].operand[1].mode;
2404 machine_mode mode1 = insn_data[icode].operand[2].mode;
5d357f26
KT
2405
2406 if (! target
2407 || GET_MODE (target) != tmode
2408 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
2409 target = gen_reg_rtx (tmode);
2410
2411 gcc_assert ((GET_MODE (op0) == mode0 || GET_MODE (op0) == VOIDmode)
2412 && (GET_MODE (op1) == mode1 || GET_MODE (op1) == VOIDmode));
2413
2414 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
2415 op0 = copy_to_mode_reg (mode0, op0);
2416 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
2417 op1 = copy_to_mode_reg (mode1, op1);
2418
2419 pat = GEN_FCN (icode) (target, op0, op1);
d5a29419
KT
2420 if (!pat)
2421 return NULL_RTX;
2422
5d357f26
KT
2423 emit_insn (pat);
2424 return target;
2425}
2426
a6fc00da
BH
2427/* Function to expand reciprocal square root builtins. */
2428
2429static rtx
2430aarch64_expand_builtin_rsqrt (int fcode, tree exp, rtx target)
2431{
2432 tree arg0 = CALL_EXPR_ARG (exp, 0);
2433 rtx op0 = expand_normal (arg0);
2434
2435 rtx (*gen) (rtx, rtx);
2436
2437 switch (fcode)
2438 {
2439 case AARCH64_BUILTIN_RSQRT_DF:
ee62a5a6 2440 gen = gen_rsqrtdf2;
a6fc00da
BH
2441 break;
2442 case AARCH64_BUILTIN_RSQRT_SF:
ee62a5a6 2443 gen = gen_rsqrtsf2;
a6fc00da
BH
2444 break;
2445 case AARCH64_BUILTIN_RSQRT_V2DF:
ee62a5a6 2446 gen = gen_rsqrtv2df2;
a6fc00da
BH
2447 break;
2448 case AARCH64_BUILTIN_RSQRT_V2SF:
ee62a5a6 2449 gen = gen_rsqrtv2sf2;
a6fc00da
BH
2450 break;
2451 case AARCH64_BUILTIN_RSQRT_V4SF:
ee62a5a6 2452 gen = gen_rsqrtv4sf2;
a6fc00da
BH
2453 break;
2454 default: gcc_unreachable ();
2455 }
2456
2457 if (!target)
2458 target = gen_reg_rtx (GET_MODE (op0));
2459
2460 emit_insn (gen (target, op0));
2461
2462 return target;
2463}
2464
9d63f43b
TC
2465/* Expand a FCMLA lane expression EXP with code FCODE and
2466 result going to TARGET if that is convenient. */
2467
2468rtx
2469aarch64_expand_fcmla_builtin (tree exp, rtx target, int fcode)
2470{
2471 int bcode = fcode - AARCH64_SIMD_FCMLA_LANEQ_BUILTIN_BASE - 1;
2472 aarch64_fcmla_laneq_builtin_datum* d
2473 = &aarch64_fcmla_lane_builtin_data[bcode];
2474 machine_mode quadmode = GET_MODE_2XWIDER_MODE (d->mode).require ();
2475 rtx op0 = force_reg (d->mode, expand_normal (CALL_EXPR_ARG (exp, 0)));
2476 rtx op1 = force_reg (d->mode, expand_normal (CALL_EXPR_ARG (exp, 1)));
2477 rtx op2 = force_reg (quadmode, expand_normal (CALL_EXPR_ARG (exp, 2)));
2478 tree tmp = CALL_EXPR_ARG (exp, 3);
2479 rtx lane_idx = expand_expr (tmp, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
2480
2481 /* Validate that the lane index is a constant. */
2482 if (!CONST_INT_P (lane_idx))
2483 {
62e43587
MS
2484 error_at (EXPR_LOCATION (exp),
2485 "argument %d must be a constant immediate", 4);
9d63f43b
TC
2486 return const0_rtx;
2487 }
2488
2489 /* Validate that the index is within the expected range. */
2490 int nunits = GET_MODE_NUNITS (quadmode).to_constant ();
2491 aarch64_simd_lane_bounds (lane_idx, 0, nunits / 2, exp);
2492
9d63f43b
TC
2493 /* Generate the correct register and mode. */
2494 int lane = INTVAL (lane_idx);
2495
2496 if (lane < nunits / 4)
33b5a38c
TC
2497 op2 = simplify_gen_subreg (d->mode, op2, quadmode,
2498 subreg_lowpart_offset (d->mode, quadmode));
9d63f43b
TC
2499 else
2500 {
2501 /* Select the upper 64 bits, either a V2SF or V4HF, this however
2502 is quite messy, as the operation required even though simple
2503 doesn't have a simple RTL pattern, and seems it's quite hard to
2504 define using a single RTL pattern. The target generic version
2505 gen_highpart_mode generates code that isn't optimal. */
2506 rtx temp1 = gen_reg_rtx (d->mode);
2507 rtx temp2 = gen_reg_rtx (DImode);
33b5a38c
TC
2508 temp1 = simplify_gen_subreg (d->mode, op2, quadmode,
2509 subreg_lowpart_offset (d->mode, quadmode));
9d63f43b 2510 temp1 = simplify_gen_subreg (V2DImode, temp1, d->mode, 0);
33b5a38c
TC
2511 if (BYTES_BIG_ENDIAN)
2512 emit_insn (gen_aarch64_get_lanev2di (temp2, temp1, const0_rtx));
2513 else
2514 emit_insn (gen_aarch64_get_lanev2di (temp2, temp1, const1_rtx));
9d63f43b
TC
2515 op2 = simplify_gen_subreg (d->mode, temp2, GET_MODE (temp2), 0);
2516
2517 /* And recalculate the index. */
2518 lane -= nunits / 4;
2519 }
2520
33b5a38c
TC
2521 /* Keep to GCC-vector-extension lane indices in the RTL, only nunits / 4
2522 (max nunits in range check) are valid. Which means only 0-1, so we
2523 only need to know the order in a V2mode. */
2524 lane_idx = aarch64_endian_lane_rtx (V2DImode, lane);
2525
fa59c8dc
AC
2526 if (!target
2527 || !REG_P (target)
2528 || GET_MODE (target) != d->mode)
9d63f43b 2529 target = gen_reg_rtx (d->mode);
9d63f43b
TC
2530
2531 rtx pat = NULL_RTX;
2532
2533 if (d->lane)
33b5a38c 2534 pat = GEN_FCN (d->icode) (target, op0, op1, op2, lane_idx);
9d63f43b
TC
2535 else
2536 pat = GEN_FCN (d->icode) (target, op0, op1, op2);
2537
2538 if (!pat)
2539 return NULL_RTX;
2540
2541 emit_insn (pat);
2542 return target;
2543}
2544
89626179
SD
2545/* Function to expand an expression EXP which calls one of the Transactional
2546 Memory Extension (TME) builtins FCODE with the result going to TARGET. */
2547static rtx
2548aarch64_expand_builtin_tme (int fcode, tree exp, rtx target)
2549{
2550 switch (fcode)
2551 {
2552 case AARCH64_TME_BUILTIN_TSTART:
2553 target = gen_reg_rtx (DImode);
2554 emit_insn (GEN_FCN (CODE_FOR_tstart) (target));
2555 break;
2556
2557 case AARCH64_TME_BUILTIN_TTEST:
2558 target = gen_reg_rtx (DImode);
2559 emit_insn (GEN_FCN (CODE_FOR_ttest) (target));
2560 break;
2561
2562 case AARCH64_TME_BUILTIN_TCOMMIT:
2563 emit_insn (GEN_FCN (CODE_FOR_tcommit) ());
2564 break;
2565
2566 case AARCH64_TME_BUILTIN_TCANCEL:
2567 {
2568 tree arg0 = CALL_EXPR_ARG (exp, 0);
2569 rtx op0 = expand_normal (arg0);
2570 if (CONST_INT_P (op0) && UINTVAL (op0) <= 65536)
2571 emit_insn (GEN_FCN (CODE_FOR_tcancel) (op0));
2572 else
2573 {
62e43587
MS
2574 error_at (EXPR_LOCATION (exp),
2575 "argument must be a 16-bit constant immediate");
89626179
SD
2576 return const0_rtx;
2577 }
2578 }
2579 break;
2580
2581 default :
2582 gcc_unreachable ();
2583 }
2584 return target;
2585}
2586
fdcddba8
PW
2587/* Function to expand an expression EXP which calls one of the Load/Store
2588 64 Byte extension (LS64) builtins FCODE with the result going to TARGET. */
2589static rtx
2590aarch64_expand_builtin_ls64 (int fcode, tree exp, rtx target)
2591{
2592 expand_operand ops[3];
2593
2594 switch (fcode)
2595 {
2596 case AARCH64_LS64_BUILTIN_LD64B:
2597 {
71361354
AC
2598 rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
2599 create_output_operand (&ops[0], target, V8DImode);
2600 create_input_operand (&ops[1], op0, DImode);
2601 expand_insn (CODE_FOR_ld64b, 2, ops);
2602 return ops[0].value;
fdcddba8
PW
2603 }
2604 case AARCH64_LS64_BUILTIN_ST64B:
2605 {
71361354
AC
2606 rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
2607 rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
737a0b74 2608 create_input_operand (&ops[0], op0, DImode);
71361354
AC
2609 create_input_operand (&ops[1], op1, V8DImode);
2610 expand_insn (CODE_FOR_st64b, 2, ops);
2611 return const0_rtx;
fdcddba8
PW
2612 }
2613 case AARCH64_LS64_BUILTIN_ST64BV:
2614 {
71361354
AC
2615 rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
2616 rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
2617 create_output_operand (&ops[0], target, DImode);
2618 create_input_operand (&ops[1], op0, DImode);
2619 create_input_operand (&ops[2], op1, V8DImode);
2620 expand_insn (CODE_FOR_st64bv, 3, ops);
2621 return ops[0].value;
fdcddba8
PW
2622 }
2623 case AARCH64_LS64_BUILTIN_ST64BV0:
2624 {
71361354
AC
2625 rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
2626 rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
2627 create_output_operand (&ops[0], target, DImode);
2628 create_input_operand (&ops[1], op0, DImode);
2629 create_input_operand (&ops[2], op1, V8DImode);
2630 expand_insn (CODE_FOR_st64bv0, 3, ops);
2631 return ops[0].value;
fdcddba8
PW
2632 }
2633 }
2634
2635 gcc_unreachable ();
2636}
2637
c5dc215d
KT
2638/* Expand a random number builtin EXP with code FCODE, putting the result
2639 int TARGET. If IGNORE is true the return value is ignored. */
2640
2641rtx
2642aarch64_expand_rng_builtin (tree exp, rtx target, int fcode, int ignore)
2643{
2644 rtx pat;
2645 enum insn_code icode;
2646 if (fcode == AARCH64_BUILTIN_RNG_RNDR)
2647 icode = CODE_FOR_aarch64_rndr;
2648 else if (fcode == AARCH64_BUILTIN_RNG_RNDRRS)
2649 icode = CODE_FOR_aarch64_rndrrs;
2650 else
2651 gcc_unreachable ();
2652
2653 rtx rand = gen_reg_rtx (DImode);
2654 pat = GEN_FCN (icode) (rand);
2655 if (!pat)
2656 return NULL_RTX;
2657
2658 tree arg0 = CALL_EXPR_ARG (exp, 0);
2659 rtx res_addr = expand_normal (arg0);
2660 res_addr = convert_memory_address (Pmode, res_addr);
2661 rtx res_mem = gen_rtx_MEM (DImode, res_addr);
2662 emit_insn (pat);
2663 emit_move_insn (res_mem, rand);
2664 /* If the status result is unused don't generate the CSET code. */
2665 if (ignore)
2666 return target;
2667
2668 rtx cc_reg = gen_rtx_REG (CC_Zmode, CC_REGNUM);
f7581eb3 2669 rtx cmp_rtx = gen_rtx_fmt_ee (EQ, SImode, cc_reg, const0_rtx);
c5dc215d
KT
2670 emit_insn (gen_aarch64_cstoresi (target, cmp_rtx, cc_reg));
2671 return target;
2672}
2673
fc42900d
VDN
2674/* Expand the read/write system register builtin EXPs. */
2675rtx
2676aarch64_expand_rwsr_builtin (tree exp, rtx target, int fcode)
2677{
2678 tree arg0, arg1;
2679 rtx const_str, input_val, subreg;
2680 enum machine_mode mode;
88157c88 2681 enum insn_code icode;
fc42900d
VDN
2682 class expand_operand ops[2];
2683
2684 arg0 = CALL_EXPR_ARG (exp, 0);
2685
2686 bool write_op = (fcode == AARCH64_WSR
2687 || fcode == AARCH64_WSRP
2688 || fcode == AARCH64_WSR64
2689 || fcode == AARCH64_WSRF
88157c88
VDN
2690 || fcode == AARCH64_WSRF64
2691 || fcode == AARCH64_WSR128);
2692
2693 bool op128 = (fcode == AARCH64_RSR128 || fcode == AARCH64_WSR128);
2694 enum machine_mode sysreg_mode = op128 ? TImode : DImode;
2695
2696 if (op128 && !TARGET_D128)
2697 {
2698 error_at (EXPR_LOCATION (exp), "128-bit system register support requires"
2699 " the %<d128%> extension");
2700 return const0_rtx;
2701 }
fc42900d
VDN
2702
2703 /* Argument 0 (system register name) must be a string literal. */
2704 gcc_assert (TREE_CODE (arg0) == ADDR_EXPR
2705 && TREE_CODE (TREE_TYPE (arg0)) == POINTER_TYPE
2706 && TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST);
2707
2708 const char *name_input = TREE_STRING_POINTER (TREE_OPERAND (arg0, 0));
2709
2710 tree len_tree = c_strlen (arg0, 1);
2711 if (len_tree == NULL_TREE)
2712 {
2713 error_at (EXPR_LOCATION (exp), "invalid system register name provided");
2714 return const0_rtx;
2715 }
2716
2717 size_t len = TREE_INT_CST_LOW (len_tree);
2718 char *sysreg_name = xstrdup (name_input);
2719
2720 for (unsigned pos = 0; pos <= len; pos++)
2721 sysreg_name[pos] = TOLOWER (sysreg_name[pos]);
2722
88157c88
VDN
2723 const char* name_output = aarch64_retrieve_sysreg ((const char *) sysreg_name,
2724 write_op, op128);
fc42900d
VDN
2725 if (name_output == NULL)
2726 {
2727 error_at (EXPR_LOCATION (exp), "invalid system register name %qs",
2728 sysreg_name);
2729 return const0_rtx;
2730 }
2731
2732 /* Assign the string corresponding to the system register name to an RTX. */
2733 const_str = rtx_alloc (CONST_STRING);
2734 PUT_CODE (const_str, CONST_STRING);
2735 XSTR (const_str, 0) = ggc_strdup (name_output);
2736
2737 /* Set up expander operands and call instruction expansion. */
2738 if (write_op)
2739 {
2740 arg1 = CALL_EXPR_ARG (exp, 1);
2741 mode = TYPE_MODE (TREE_TYPE (arg1));
2742 input_val = copy_to_mode_reg (mode, expand_normal (arg1));
2743
88157c88
VDN
2744 icode = (op128 ? CODE_FOR_aarch64_write_sysregti
2745 : CODE_FOR_aarch64_write_sysregdi);
2746
fc42900d
VDN
2747 switch (fcode)
2748 {
2749 case AARCH64_WSR:
2750 case AARCH64_WSRP:
2751 case AARCH64_WSR64:
2752 case AARCH64_WSRF64:
88157c88
VDN
2753 case AARCH64_WSR128:
2754 subreg = lowpart_subreg (sysreg_mode, input_val, mode);
fc42900d
VDN
2755 break;
2756 case AARCH64_WSRF:
2757 subreg = gen_lowpart_SUBREG (SImode, input_val);
2758 subreg = gen_lowpart_SUBREG (DImode, subreg);
2759 break;
2760 }
2761
2762 create_fixed_operand (&ops[0], const_str);
88157c88
VDN
2763 create_input_operand (&ops[1], subreg, sysreg_mode);
2764 expand_insn (icode, 2, ops);
fc42900d
VDN
2765
2766 return target;
2767 }
2768
2769 /* Read operations are implied by !write_op. */
2770 gcc_assert (call_expr_nargs (exp) == 1);
2771
88157c88
VDN
2772 icode = (op128 ? CODE_FOR_aarch64_read_sysregti
2773 : CODE_FOR_aarch64_read_sysregdi);
2774
fc42900d 2775 /* Emit the initial read_sysregdi rtx. */
88157c88 2776 create_output_operand (&ops[0], target, sysreg_mode);
fc42900d 2777 create_fixed_operand (&ops[1], const_str);
88157c88 2778 expand_insn (icode, 2, ops);
fc42900d
VDN
2779 target = ops[0].value;
2780
2781 /* Do any necessary post-processing on the result. */
2782 switch (fcode)
2783 {
2784 case AARCH64_RSR:
2785 case AARCH64_RSRP:
2786 case AARCH64_RSR64:
2787 case AARCH64_RSRF64:
88157c88
VDN
2788 case AARCH64_RSR128:
2789 return lowpart_subreg (TYPE_MODE (TREE_TYPE (exp)), target, sysreg_mode);
fc42900d
VDN
2790 case AARCH64_RSRF:
2791 subreg = gen_lowpart_SUBREG (SImode, target);
2792 return gen_lowpart_SUBREG (SFmode, subreg);
2793 default:
2794 gcc_unreachable ();
2795 }
2796}
2797
9fba6637
VDN
2798/* Ensure argument ARGNO in EXP represents a const-type argument in the range
2799 [MINVAL, MAXVAL). */
2800static HOST_WIDE_INT
2801require_const_argument (tree exp, unsigned int argno, HOST_WIDE_INT minval,
2802 HOST_WIDE_INT maxval)
2803{
2804 maxval--;
2805 tree arg = CALL_EXPR_ARG (exp, argno);
2806 if (TREE_CODE (arg) != INTEGER_CST)
2807 error_at (EXPR_LOCATION (exp), "Constant-type argument expected");
2808
2809 auto argval = wi::to_widest (arg);
2810
2811 if (argval < minval || argval > maxval)
2812 error_at (EXPR_LOCATION (exp),
2813 "argument %d must be a constant immediate "
2814 "in range [%wd,%wd]", argno + 1, minval, maxval);
2815
2816 HOST_WIDE_INT retval = argval.to_shwi ();
2817 return retval;
2818}
2819
2820
2821/* Expand a prefetch builtin EXP. */
2822void
2823aarch64_expand_prefetch_builtin (tree exp, int fcode)
2824{
2825 int kind_id = -1;
2826 int level_id = -1;
2827 int rettn_id = -1;
2828 char prfop[11];
2829 class expand_operand ops[2];
2830
2831 static const char *kind_s[] = {"PLD", "PST", "PLI"};
2832 static const char *level_s[] = {"L1", "L2", "L3", "SLC"};
2833 static const char *rettn_s[] = {"KEEP", "STRM"};
2834
2835 /* Each of the four prefetch builtins takes a different number of arguments,
2836 but proceeds to call the PRFM insn which requires 4 pieces of information
2837 to be fully defined. Where one of these takes less than 4 arguments, set
2838 sensible defaults. */
2839 switch (fcode)
2840 {
2841 case AARCH64_PLDX:
2842 break;
2843 case AARCH64_PLIX:
2844 kind_id = 2;
2845 break;
2846 case AARCH64_PLI:
2847 case AARCH64_PLD:
2848 kind_id = (fcode == AARCH64_PLD) ? 0 : 2;
2849 level_id = 0;
2850 rettn_id = 0;
2851 break;
2852 default:
2853 gcc_unreachable ();
2854 }
2855
2856 /* Any -1 id variable is to be user-supplied. Here we fill these in and run
2857 bounds checks on them. "PLI" is used only implicitly by AARCH64_PLI &
2858 AARCH64_PLIX, never explicitly. */
2859 int argno = 0;
2860 if (kind_id < 0)
2861 kind_id = require_const_argument (exp, argno++, 0, ARRAY_SIZE (kind_s) - 1);
2862 if (level_id < 0)
2863 level_id = require_const_argument (exp, argno++, 0, ARRAY_SIZE (level_s));
2864 if (rettn_id < 0)
2865 rettn_id = require_const_argument (exp, argno++, 0, ARRAY_SIZE (rettn_s));
2866 rtx address = expand_expr (CALL_EXPR_ARG (exp, argno), NULL_RTX, Pmode,
2867 EXPAND_NORMAL);
2868
2869 if (seen_error ())
2870 return;
2871
2872 sprintf (prfop, "%s%s%s", kind_s[kind_id],
2873 level_s[level_id],
2874 rettn_s[rettn_id]);
2875
2876 rtx const_str = rtx_alloc (CONST_STRING);
2877 PUT_CODE (const_str, CONST_STRING);
2878 XSTR (const_str, 0) = ggc_strdup (prfop);
2879
2880 create_fixed_operand (&ops[0], const_str);
2881 create_address_operand (&ops[1], address);
2882 maybe_expand_insn (CODE_FOR_aarch64_pldx, 2, ops);
2883}
2884
ef01e6bb
DZ
2885/* Expand an expression EXP that calls a MEMTAG built-in FCODE
2886 with result going to TARGET. */
2887static rtx
2888aarch64_expand_builtin_memtag (int fcode, tree exp, rtx target)
2889{
2890 if (TARGET_ILP32)
2891 {
2892 error ("Memory Tagging Extension does not support %<-mabi=ilp32%>");
2893 return const0_rtx;
2894 }
2895
2896 rtx pat = NULL;
2897 enum insn_code icode = aarch64_memtag_builtin_data[fcode -
2898 AARCH64_MEMTAG_BUILTIN_START - 1].icode;
2899
2900 rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
2901 machine_mode mode0 = GET_MODE (op0);
2902 op0 = force_reg (mode0 == VOIDmode ? DImode : mode0, op0);
2903 op0 = convert_to_mode (DImode, op0, true);
2904
2905 switch (fcode)
2906 {
2907 case AARCH64_MEMTAG_BUILTIN_IRG:
2908 case AARCH64_MEMTAG_BUILTIN_GMI:
2909 case AARCH64_MEMTAG_BUILTIN_SUBP:
2910 case AARCH64_MEMTAG_BUILTIN_INC_TAG:
2911 {
2912 if (! target
2913 || GET_MODE (target) != DImode
2914 || ! (*insn_data[icode].operand[0].predicate) (target, DImode))
2915 target = gen_reg_rtx (DImode);
2916
2917 if (fcode == AARCH64_MEMTAG_BUILTIN_INC_TAG)
2918 {
2919 rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
2920
2921 if ((*insn_data[icode].operand[3].predicate) (op1, QImode))
2922 {
2923 pat = GEN_FCN (icode) (target, op0, const0_rtx, op1);
2924 break;
2925 }
62e43587
MS
2926 error_at (EXPR_LOCATION (exp),
2927 "argument %d must be a constant immediate "
2928 "in range [0,15]", 2);
ef01e6bb
DZ
2929 return const0_rtx;
2930 }
2931 else
2932 {
2933 rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
2934 machine_mode mode1 = GET_MODE (op1);
2935 op1 = force_reg (mode1 == VOIDmode ? DImode : mode1, op1);
2936 op1 = convert_to_mode (DImode, op1, true);
2937 pat = GEN_FCN (icode) (target, op0, op1);
2938 }
2939 break;
2940 }
2941 case AARCH64_MEMTAG_BUILTIN_GET_TAG:
2942 target = op0;
2943 pat = GEN_FCN (icode) (target, op0, const0_rtx);
2944 break;
2945 case AARCH64_MEMTAG_BUILTIN_SET_TAG:
2946 pat = GEN_FCN (icode) (op0, op0, const0_rtx);
2947 break;
2948 default:
2949 gcc_unreachable();
2950 }
2951
2952 if (!pat)
2953 return NULL_RTX;
2954
2955 emit_insn (pat);
2956 return target;
2957}
2958
eb966d39
ASDV
2959/* Function to expand an expression EXP which calls one of the ACLE Data
2960 Intrinsic builtins FCODE with the result going to TARGET. */
2961static rtx
2962aarch64_expand_builtin_data_intrinsic (unsigned int fcode, tree exp, rtx target)
2963{
2964 expand_operand ops[2];
98756bcb 2965 machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
eb966d39
ASDV
2966 create_output_operand (&ops[0], target, mode);
2967 create_input_operand (&ops[1], expand_normal (CALL_EXPR_ARG (exp, 0)), mode);
2968 enum insn_code icode;
2969
2970 switch (fcode)
2971 {
2972 case AARCH64_REV16:
2973 case AARCH64_REV16L:
2974 case AARCH64_REV16LL:
2975 icode = code_for_aarch64_rev16 (mode);
2976 break;
2977 case AARCH64_RBIT:
2978 case AARCH64_RBITL:
2979 case AARCH64_RBITLL:
2980 icode = code_for_aarch64_rbit (mode);
2981 break;
2982 default:
2983 gcc_unreachable ();
2984 }
2985
2986 expand_insn (icode, 2, ops);
2987 return ops[0].value;
2988}
2989
f5e73de0 2990/* Expand an expression EXP as fpsr or fpcr setter (depending on
0d7e5fa6
AC
2991 UNSPEC) using MODE. */
2992static void
2993aarch64_expand_fpsr_fpcr_setter (int unspec, machine_mode mode, tree exp)
2994{
2995 tree arg = CALL_EXPR_ARG (exp, 0);
2996 rtx op = force_reg (mode, expand_normal (arg));
2997 emit_insn (gen_aarch64_set (unspec, mode, op));
2998}
2999
f5e73de0
AC
3000/* Expand a fpsr or fpcr getter (depending on UNSPEC) using MODE.
3001 Return the target. */
3002static rtx
3003aarch64_expand_fpsr_fpcr_getter (enum insn_code icode, machine_mode mode,
3004 rtx target)
3005{
3006 expand_operand op;
3007 create_output_operand (&op, target, mode);
3008 expand_insn (icode, 1, &op);
3009 return op.value;
3010}
3011
6d4d616a 3012/* Expand an expression EXP that calls built-in function FCODE,
c5dc215d
KT
3013 with result going to TARGET if that's convenient. IGNORE is true
3014 if the result of the builtin is ignored. */
342be7f7 3015rtx
c5dc215d
KT
3016aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target,
3017 int ignore)
342be7f7 3018{
aa87aced 3019 int icode;
0d7e5fa6 3020 rtx op0;
aa87aced
KV
3021 tree arg0;
3022
3023 switch (fcode)
3024 {
3025 case AARCH64_BUILTIN_GET_FPCR:
f5e73de0
AC
3026 return aarch64_expand_fpsr_fpcr_getter (CODE_FOR_aarch64_get_fpcrsi,
3027 SImode, target);
aa87aced 3028 case AARCH64_BUILTIN_SET_FPCR:
0d7e5fa6
AC
3029 aarch64_expand_fpsr_fpcr_setter (UNSPECV_SET_FPCR, SImode, exp);
3030 return target;
aa87aced 3031 case AARCH64_BUILTIN_GET_FPSR:
f5e73de0
AC
3032 return aarch64_expand_fpsr_fpcr_getter (CODE_FOR_aarch64_get_fpsrsi,
3033 SImode, target);
aa87aced 3034 case AARCH64_BUILTIN_SET_FPSR:
0d7e5fa6
AC
3035 aarch64_expand_fpsr_fpcr_setter (UNSPECV_SET_FPSR, SImode, exp);
3036 return target;
3037 case AARCH64_BUILTIN_GET_FPCR64:
f5e73de0
AC
3038 return aarch64_expand_fpsr_fpcr_getter (CODE_FOR_aarch64_get_fpcrdi,
3039 DImode, target);
0d7e5fa6
AC
3040 case AARCH64_BUILTIN_SET_FPCR64:
3041 aarch64_expand_fpsr_fpcr_setter (UNSPECV_SET_FPCR, DImode, exp);
3042 return target;
3043 case AARCH64_BUILTIN_GET_FPSR64:
f5e73de0
AC
3044 return aarch64_expand_fpsr_fpcr_getter (CODE_FOR_aarch64_get_fpsrdi,
3045 DImode, target);
0d7e5fa6
AC
3046 case AARCH64_BUILTIN_SET_FPSR64:
3047 aarch64_expand_fpsr_fpcr_setter (UNSPECV_SET_FPSR, DImode, exp);
aa87aced 3048 return target;
312492bd
JW
3049 case AARCH64_PAUTH_BUILTIN_AUTIA1716:
3050 case AARCH64_PAUTH_BUILTIN_PACIA1716:
8fc16d72
ST
3051 case AARCH64_PAUTH_BUILTIN_AUTIB1716:
3052 case AARCH64_PAUTH_BUILTIN_PACIB1716:
312492bd
JW
3053 case AARCH64_PAUTH_BUILTIN_XPACLRI:
3054 arg0 = CALL_EXPR_ARG (exp, 0);
3055 op0 = force_reg (Pmode, expand_normal (arg0));
3056
312492bd
JW
3057 if (fcode == AARCH64_PAUTH_BUILTIN_XPACLRI)
3058 {
3059 rtx lr = gen_rtx_REG (Pmode, R30_REGNUM);
3060 icode = CODE_FOR_xpaclri;
3061 emit_move_insn (lr, op0);
3062 emit_insn (GEN_FCN (icode) ());
92f0d3d0 3063 return lr;
312492bd
JW
3064 }
3065 else
3066 {
3067 tree arg1 = CALL_EXPR_ARG (exp, 1);
3068 rtx op1 = force_reg (Pmode, expand_normal (arg1));
8fc16d72
ST
3069 switch (fcode)
3070 {
3071 case AARCH64_PAUTH_BUILTIN_AUTIA1716:
3072 icode = CODE_FOR_autia1716;
3073 break;
3074 case AARCH64_PAUTH_BUILTIN_AUTIB1716:
3075 icode = CODE_FOR_autib1716;
3076 break;
3077 case AARCH64_PAUTH_BUILTIN_PACIA1716:
3078 icode = CODE_FOR_pacia1716;
3079 break;
3080 case AARCH64_PAUTH_BUILTIN_PACIB1716:
3081 icode = CODE_FOR_pacib1716;
3082 break;
3083 default:
3084 icode = 0;
3085 gcc_unreachable ();
3086 }
312492bd
JW
3087
3088 rtx x16_reg = gen_rtx_REG (Pmode, R16_REGNUM);
3089 rtx x17_reg = gen_rtx_REG (Pmode, R17_REGNUM);
3090 emit_move_insn (x17_reg, op0);
3091 emit_move_insn (x16_reg, op1);
3092 emit_insn (GEN_FCN (icode) ());
92f0d3d0 3093 return x17_reg;
312492bd
JW
3094 }
3095
e1d5d19e 3096 case AARCH64_JSCVT:
2c62952f
AC
3097 {
3098 expand_operand ops[2];
3099 create_output_operand (&ops[0], target, SImode);
3100 op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
3101 create_input_operand (&ops[1], op0, DFmode);
3102 expand_insn (CODE_FOR_aarch64_fjcvtzs, 2, ops);
3103 return ops[0].value;
3104 }
e1d5d19e 3105
9d63f43b
TC
3106 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ0_V2SF:
3107 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ90_V2SF:
3108 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ180_V2SF:
3109 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ270_V2SF:
3110 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ0_V4HF:
3111 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ90_V4HF:
3112 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ180_V4HF:
3113 case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ270_V4HF:
3114 return aarch64_expand_fcmla_builtin (exp, target, fcode);
c5dc215d
KT
3115 case AARCH64_BUILTIN_RNG_RNDR:
3116 case AARCH64_BUILTIN_RNG_RNDRRS:
3117 return aarch64_expand_rng_builtin (exp, target, fcode, ignore);
fc42900d
VDN
3118 case AARCH64_RSR:
3119 case AARCH64_RSRP:
3120 case AARCH64_RSR64:
3121 case AARCH64_RSRF:
3122 case AARCH64_RSRF64:
88157c88 3123 case AARCH64_RSR128:
fc42900d
VDN
3124 case AARCH64_WSR:
3125 case AARCH64_WSRP:
3126 case AARCH64_WSR64:
3127 case AARCH64_WSRF:
3128 case AARCH64_WSRF64:
88157c88 3129 case AARCH64_WSR128:
fc42900d 3130 return aarch64_expand_rwsr_builtin (exp, target, fcode);
9fba6637
VDN
3131 case AARCH64_PLD:
3132 case AARCH64_PLDX:
3133 case AARCH64_PLI:
3134 case AARCH64_PLIX:
3135 aarch64_expand_prefetch_builtin (exp, fcode);
3136 return target;
aa87aced 3137 }
342be7f7 3138
5d357f26 3139 if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
342be7f7 3140 return aarch64_simd_expand_builtin (fcode, exp, target);
5d357f26
KT
3141 else if (fcode >= AARCH64_CRC32_BUILTIN_BASE && fcode <= AARCH64_CRC32_BUILTIN_MAX)
3142 return aarch64_crc32_expand_builtin (fcode, exp, target);
342be7f7 3143
a6fc00da
BH
3144 if (fcode == AARCH64_BUILTIN_RSQRT_DF
3145 || fcode == AARCH64_BUILTIN_RSQRT_SF
3146 || fcode == AARCH64_BUILTIN_RSQRT_V2DF
3147 || fcode == AARCH64_BUILTIN_RSQRT_V2SF
3148 || fcode == AARCH64_BUILTIN_RSQRT_V4SF)
3149 return aarch64_expand_builtin_rsqrt (fcode, exp, target);
3150
89626179
SD
3151 if (fcode == AARCH64_TME_BUILTIN_TSTART
3152 || fcode == AARCH64_TME_BUILTIN_TCOMMIT
3153 || fcode == AARCH64_TME_BUILTIN_TTEST
3154 || fcode == AARCH64_TME_BUILTIN_TCANCEL)
3155 return aarch64_expand_builtin_tme (fcode, exp, target);
3156
fdcddba8
PW
3157 if (fcode == AARCH64_LS64_BUILTIN_LD64B
3158 || fcode == AARCH64_LS64_BUILTIN_ST64B
3159 || fcode == AARCH64_LS64_BUILTIN_ST64BV
3160 || fcode == AARCH64_LS64_BUILTIN_ST64BV0)
3161 return aarch64_expand_builtin_ls64 (fcode, exp, target);
3162
ef01e6bb
DZ
3163 if (fcode >= AARCH64_MEMTAG_BUILTIN_START
3164 && fcode <= AARCH64_MEMTAG_BUILTIN_END)
3165 return aarch64_expand_builtin_memtag (fcode, exp, target);
eb966d39
ASDV
3166 if (fcode >= AARCH64_REV16
3167 && fcode <= AARCH64_RBITLL)
3168 return aarch64_expand_builtin_data_intrinsic (fcode, exp, target);
ef01e6bb 3169
d5a29419 3170 gcc_unreachable ();
342be7f7 3171}
42fc9a7f 3172
a6fc00da
BH
3173/* Return builtin for reciprocal square root. */
3174
3175tree
6d4d616a 3176aarch64_general_builtin_rsqrt (unsigned int fn)
a6fc00da 3177{
ee62a5a6
RS
3178 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv2df)
3179 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V2DF];
3180 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv2sf)
3181 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V2SF];
3182 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv4sf)
3183 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V4SF];
a6fc00da
BH
3184 return NULL_TREE;
3185}
3186
03312cbd
AP
3187/* Return true if the lane check can be removed as there is no
3188 error going to be emitted. */
3189static bool
3190aarch64_fold_builtin_lane_check (tree arg0, tree arg1, tree arg2)
3191{
3192 if (TREE_CODE (arg0) != INTEGER_CST)
3193 return false;
3194 if (TREE_CODE (arg1) != INTEGER_CST)
3195 return false;
3196 if (TREE_CODE (arg2) != INTEGER_CST)
3197 return false;
3198
3199 auto totalsize = wi::to_widest (arg0);
3200 auto elementsize = wi::to_widest (arg1);
3201 if (totalsize == 0 || elementsize == 0)
3202 return false;
3203 auto lane = wi::to_widest (arg2);
3204 auto high = wi::udiv_trunc (totalsize, elementsize);
3205 return wi::ltu_p (lane, high);
3206}
3207
0ac198d3 3208#undef VAR1
bf592b2f 3209#define VAR1(T, N, MAP, FLAG, A) \
e993fea1 3210 case AARCH64_SIMD_BUILTIN_##T##_##N##A:
0ac198d3 3211
c906efc7
AC
3212#undef VREINTERPRET_BUILTIN
3213#define VREINTERPRET_BUILTIN(A, B, L) \
3214 case AARCH64_SIMD_BUILTIN_VREINTERPRET##L##_##A##_##B:
3215
3216
6d4d616a
RS
3217/* Try to fold a call to the built-in function with subcode FCODE. The
3218 function is passed the N_ARGS arguments in ARGS and it returns a value
3219 of type TYPE. Return the new expression on success and NULL_TREE on
3220 failure. */
9697e620 3221tree
6d4d616a
RS
3222aarch64_general_fold_builtin (unsigned int fcode, tree type,
3223 unsigned int n_args ATTRIBUTE_UNUSED, tree *args)
9697e620 3224{
9697e620
JG
3225 switch (fcode)
3226 {
bf592b2f 3227 BUILTIN_VDQF (UNOP, abs, 2, ALL)
9697e620 3228 return fold_build1 (ABS_EXPR, type, args[0]);
bf592b2f 3229 VAR1 (UNOP, floatv2si, 2, ALL, v2sf)
3230 VAR1 (UNOP, floatv4si, 2, ALL, v4sf)
3231 VAR1 (UNOP, floatv2di, 2, ALL, v2df)
1709ff9b 3232 return fold_build1 (FLOAT_EXPR, type, args[0]);
c906efc7
AC
3233 AARCH64_SIMD_VREINTERPRET_BUILTINS
3234 return fold_build1 (VIEW_CONVERT_EXPR, type, args[0]);
03312cbd
AP
3235 case AARCH64_SIMD_BUILTIN_LANE_CHECK:
3236 gcc_assert (n_args == 3);
3237 if (aarch64_fold_builtin_lane_check (args[0], args[1], args[2]))
3238 return void_node;
3239 break;
9697e620
JG
3240 default:
3241 break;
3242 }
3243
3244 return NULL_TREE;
3245}
3246
ad44c6a5
ASDV
3247enum aarch64_simd_type
3248get_mem_type_for_load_store (unsigned int fcode)
3249{
3250 switch (fcode)
3251 {
1716ddd1
JW
3252 VAR1 (LOAD1, ld1, 0, LOAD, v8qi)
3253 VAR1 (STORE1, st1, 0, STORE, v8qi)
ad44c6a5 3254 return Int8x8_t;
1716ddd1
JW
3255 VAR1 (LOAD1, ld1, 0, LOAD, v16qi)
3256 VAR1 (STORE1, st1, 0, STORE, v16qi)
ad44c6a5 3257 return Int8x16_t;
1716ddd1
JW
3258 VAR1 (LOAD1, ld1, 0, LOAD, v4hi)
3259 VAR1 (STORE1, st1, 0, STORE, v4hi)
ad44c6a5 3260 return Int16x4_t;
1716ddd1
JW
3261 VAR1 (LOAD1, ld1, 0, LOAD, v8hi)
3262 VAR1 (STORE1, st1, 0, STORE, v8hi)
ad44c6a5 3263 return Int16x8_t;
1716ddd1
JW
3264 VAR1 (LOAD1, ld1, 0, LOAD, v2si)
3265 VAR1 (STORE1, st1, 0, STORE, v2si)
ad44c6a5 3266 return Int32x2_t;
1716ddd1
JW
3267 VAR1 (LOAD1, ld1, 0, LOAD, v4si)
3268 VAR1 (STORE1, st1, 0, STORE, v4si)
ad44c6a5 3269 return Int32x4_t;
1716ddd1
JW
3270 VAR1 (LOAD1, ld1, 0, LOAD, v2di)
3271 VAR1 (STORE1, st1, 0, STORE, v2di)
ad44c6a5 3272 return Int64x2_t;
1716ddd1
JW
3273 VAR1 (LOAD1_U, ld1, 0, LOAD, v8qi)
3274 VAR1 (STORE1_U, st1, 0, STORE, v8qi)
3275 return Uint8x8_t;
3276 VAR1 (LOAD1_U, ld1, 0, LOAD, v16qi)
3277 VAR1 (STORE1_U, st1, 0, STORE, v16qi)
3278 return Uint8x16_t;
3279 VAR1 (LOAD1_U, ld1, 0, LOAD, v4hi)
3280 VAR1 (STORE1_U, st1, 0, STORE, v4hi)
3281 return Uint16x4_t;
3282 VAR1 (LOAD1_U, ld1, 0, LOAD, v8hi)
3283 VAR1 (STORE1_U, st1, 0, STORE, v8hi)
3284 return Uint16x8_t;
3285 VAR1 (LOAD1_U, ld1, 0, LOAD, v2si)
3286 VAR1 (STORE1_U, st1, 0, STORE, v2si)
3287 return Uint32x2_t;
3288 VAR1 (LOAD1_U, ld1, 0, LOAD, v4si)
3289 VAR1 (STORE1_U, st1, 0, STORE, v4si)
3290 return Uint32x4_t;
3291 VAR1 (LOAD1_U, ld1, 0, LOAD, v2di)
3292 VAR1 (STORE1_U, st1, 0, STORE, v2di)
3293 return Uint64x2_t;
3294 VAR1 (LOAD1_P, ld1, 0, LOAD, v8qi)
3295 VAR1 (STORE1_P, st1, 0, STORE, v8qi)
3296 return Poly8x8_t;
3297 VAR1 (LOAD1_P, ld1, 0, LOAD, v16qi)
3298 VAR1 (STORE1_P, st1, 0, STORE, v16qi)
3299 return Poly8x16_t;
3300 VAR1 (LOAD1_P, ld1, 0, LOAD, v4hi)
3301 VAR1 (STORE1_P, st1, 0, STORE, v4hi)
3302 return Poly16x4_t;
3303 VAR1 (LOAD1_P, ld1, 0, LOAD, v8hi)
3304 VAR1 (STORE1_P, st1, 0, STORE, v8hi)
3305 return Poly16x8_t;
3306 VAR1 (LOAD1_P, ld1, 0, LOAD, v2di)
3307 VAR1 (STORE1_P, st1, 0, STORE, v2di)
3308 return Poly64x2_t;
3309 VAR1 (LOAD1, ld1, 0, LOAD, v4hf)
3310 VAR1 (STORE1, st1, 0, STORE, v4hf)
ad44c6a5 3311 return Float16x4_t;
1716ddd1
JW
3312 VAR1 (LOAD1, ld1, 0, LOAD, v8hf)
3313 VAR1 (STORE1, st1, 0, STORE, v8hf)
ad44c6a5 3314 return Float16x8_t;
1716ddd1
JW
3315 VAR1 (LOAD1, ld1, 0, LOAD, v4bf)
3316 VAR1 (STORE1, st1, 0, STORE, v4bf)
ad44c6a5 3317 return Bfloat16x4_t;
1716ddd1
JW
3318 VAR1 (LOAD1, ld1, 0, LOAD, v8bf)
3319 VAR1 (STORE1, st1, 0, STORE, v8bf)
ad44c6a5 3320 return Bfloat16x8_t;
1716ddd1
JW
3321 VAR1 (LOAD1, ld1, 0, LOAD, v2sf)
3322 VAR1 (STORE1, st1, 0, STORE, v2sf)
ad44c6a5 3323 return Float32x2_t;
1716ddd1
JW
3324 VAR1 (LOAD1, ld1, 0, LOAD, v4sf)
3325 VAR1 (STORE1, st1, 0, STORE, v4sf)
ad44c6a5 3326 return Float32x4_t;
1716ddd1
JW
3327 VAR1 (LOAD1, ld1, 0, LOAD, v2df)
3328 VAR1 (STORE1, st1, 0, STORE, v2df)
ad44c6a5
ASDV
3329 return Float64x2_t;
3330 default:
3331 gcc_unreachable ();
3332 break;
3333 }
3334}
3335
fcb41156
RS
3336/* We've seen a vector load from address ADDR. Record it in
3337 vector_load_decls, if appropriate. */
3338static void
3339aarch64_record_vector_load_arg (tree addr)
3340{
3341 tree decl = aarch64_vector_load_decl (addr);
3342 if (!decl)
3343 return;
3344 if (!cfun->machine->vector_load_decls)
3345 cfun->machine->vector_load_decls = hash_set<tree>::create_ggc (31);
3346 cfun->machine->vector_load_decls->add (decl);
3347}
3348
6d4d616a
RS
3349/* Try to fold STMT, given that it's a call to the built-in function with
3350 subcode FCODE. Return the new statement on success and null on
3351 failure. */
3352gimple *
ad44c6a5 3353aarch64_general_gimple_fold_builtin (unsigned int fcode, gcall *stmt,
03f7843c 3354 gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED)
0ac198d3 3355{
355fe088 3356 gimple *new_stmt = NULL;
6d4d616a
RS
3357 unsigned nargs = gimple_call_num_args (stmt);
3358 tree *args = (nargs > 0
3359 ? gimple_call_arg_ptr (stmt, 0)
3360 : &error_mark_node);
3361
3362 /* We use gimple's IFN_REDUC_(PLUS|MIN|MAX)s for float, signed int
3363 and unsigned int; it will distinguish according to the types of
3364 the arguments to the __builtin. */
3365 switch (fcode)
0ac198d3 3366 {
bf592b2f 3367 BUILTIN_VALL (UNOP, reduc_plus_scal_, 10, ALL)
6be5d852 3368 BUILTIN_VDQ_I (UNOPU, reduc_plus_scal_, 10, NONE)
6d4d616a
RS
3369 new_stmt = gimple_build_call_internal (IFN_REDUC_PLUS,
3370 1, args[0]);
3371 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
3372 break;
ad44c6a5 3373
cbcf4a50
AP
3374 /* Lower sqrt builtins to gimple/internal function sqrt. */
3375 BUILTIN_VHSDF_DF (UNOP, sqrt, 2, FP)
3376 new_stmt = gimple_build_call_internal (IFN_SQRT,
3377 1, args[0]);
3378 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
3379 break;
3380
8a1e05b7
AC
3381 BUILTIN_VDC (BINOP, combine, 0, AUTO_FP)
3382 BUILTIN_VD_I (BINOPU, combine, 0, NONE)
3383 BUILTIN_VDC_P (BINOPP, combine, 0, NONE)
3384 {
3385 tree first_part, second_part;
3386 if (BYTES_BIG_ENDIAN)
3387 {
3388 second_part = args[0];
3389 first_part = args[1];
3390 }
3391 else
3392 {
3393 first_part = args[0];
3394 second_part = args[1];
3395 }
3396 tree ret_type = gimple_call_return_type (stmt);
3397 tree ctor = build_constructor_va (ret_type, 2, NULL_TREE, first_part,
3398 NULL_TREE, second_part);
3399 new_stmt = gimple_build_assign (gimple_call_lhs (stmt), ctor);
3400 }
3401 break;
3402
ad44c6a5
ASDV
3403 /*lower store and load neon builtins to gimple. */
3404 BUILTIN_VALL_F16 (LOAD1, ld1, 0, LOAD)
1716ddd1
JW
3405 BUILTIN_VDQ_I (LOAD1_U, ld1, 0, LOAD)
3406 BUILTIN_VALLP_NO_DI (LOAD1_P, ld1, 0, LOAD)
fcb41156
RS
3407 /* Punt until after inlining, so that we stand more chance of
3408 recording something meaningful in vector_load_decls. */
3409 if (!cfun->after_inlining)
3410 break;
3411 aarch64_record_vector_load_arg (args[0]);
ad44c6a5
ASDV
3412 if (!BYTES_BIG_ENDIAN)
3413 {
3414 enum aarch64_simd_type mem_type
3415 = get_mem_type_for_load_store(fcode);
3416 aarch64_simd_type_info simd_type
3417 = aarch64_simd_types[mem_type];
0f685601
AV
3418 tree elt_ptr_type = build_pointer_type_for_mode (simd_type.eltype,
3419 VOIDmode, true);
ad44c6a5 3420 tree zero = build_zero_cst (elt_ptr_type);
0f685601
AV
3421 /* Use element type alignment. */
3422 tree access_type
3423 = build_aligned_type (simd_type.itype,
3424 TYPE_ALIGN (simd_type.eltype));
ad44c6a5
ASDV
3425 new_stmt
3426 = gimple_build_assign (gimple_get_lhs (stmt),
3427 fold_build2 (MEM_REF,
0f685601
AV
3428 access_type,
3429 args[0], zero));
fcb41156
RS
3430 gimple_set_vuse (new_stmt, gimple_vuse (stmt));
3431 gimple_set_vdef (new_stmt, gimple_vdef (stmt));
ad44c6a5
ASDV
3432 }
3433 break;
3434
3435 BUILTIN_VALL_F16 (STORE1, st1, 0, STORE)
1716ddd1
JW
3436 BUILTIN_VDQ_I (STORE1_U, st1, 0, STORE)
3437 BUILTIN_VALLP_NO_DI (STORE1_P, st1, 0, STORE)
ad44c6a5
ASDV
3438 if (!BYTES_BIG_ENDIAN)
3439 {
3440 enum aarch64_simd_type mem_type
3441 = get_mem_type_for_load_store(fcode);
3442 aarch64_simd_type_info simd_type
3443 = aarch64_simd_types[mem_type];
0f685601
AV
3444 tree elt_ptr_type = build_pointer_type_for_mode (simd_type.eltype,
3445 VOIDmode, true);
ad44c6a5 3446 tree zero = build_zero_cst (elt_ptr_type);
0f685601
AV
3447 /* Use element type alignment. */
3448 tree access_type
3449 = build_aligned_type (simd_type.itype,
3450 TYPE_ALIGN (simd_type.eltype));
ad44c6a5 3451 new_stmt
0f685601
AV
3452 = gimple_build_assign (fold_build2 (MEM_REF, access_type,
3453 args[0], zero),
3454 args[1]);
fcb41156
RS
3455 gimple_set_vuse (new_stmt, gimple_vuse (stmt));
3456 gimple_set_vdef (new_stmt, gimple_vdef (stmt));
ad44c6a5
ASDV
3457 }
3458 break;
3459
bf592b2f 3460 BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10, ALL)
3461 BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10, ALL)
6d4d616a
RS
3462 new_stmt = gimple_build_call_internal (IFN_REDUC_MAX,
3463 1, args[0]);
3464 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
3465 break;
bf592b2f 3466 BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10, ALL)
3467 BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10, ALL)
6d4d616a
RS
3468 new_stmt = gimple_build_call_internal (IFN_REDUC_MIN,
3469 1, args[0]);
3470 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
3471 break;
1b4a6359
TC
3472 BUILTIN_VSDQ_I_DI (BINOP, ashl, 3, NONE)
3473 if (TREE_CODE (args[1]) == INTEGER_CST
3474 && wi::ltu_p (wi::to_wide (args[1]), element_precision (args[0])))
3475 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
3476 LSHIFT_EXPR, args[0], args[1]);
3477 break;
3478 BUILTIN_VSDQ_I_DI (BINOP, sshl, 0, NONE)
3479 BUILTIN_VSDQ_I_DI (BINOP_UUS, ushl, 0, NONE)
3480 {
3481 tree cst = args[1];
3482 tree ctype = TREE_TYPE (cst);
3483 /* Left shifts can be both scalar or vector, e.g. uint64x1_t is
3484 treated as a scalar type not a vector one. */
3485 if ((cst = uniform_integer_cst_p (cst)) != NULL_TREE)
3486 {
3487 wide_int wcst = wi::to_wide (cst);
3488 tree unit_ty = TREE_TYPE (cst);
3489
3490 wide_int abs_cst = wi::abs (wcst);
3491 if (wi::geu_p (abs_cst, element_precision (args[0])))
3492 break;
3493
3494 if (wi::neg_p (wcst, TYPE_SIGN (ctype)))
3495 {
3496 tree final_cst;
3497 final_cst = wide_int_to_tree (unit_ty, abs_cst);
3498 if (TREE_CODE (cst) != INTEGER_CST)
3499 final_cst = build_uniform_cst (ctype, final_cst);
3500
3501 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
3502 RSHIFT_EXPR, args[0],
3503 final_cst);
3504 }
3505 else
3506 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
3507 LSHIFT_EXPR, args[0], args[1]);
3508 }
3509 }
3510 break;
3511 BUILTIN_VDQ_I (SHIFTIMM, ashr, 3, NONE)
3512 VAR1 (SHIFTIMM, ashr_simd, 0, NONE, di)
3513 BUILTIN_VDQ_I (USHIFTIMM, lshr, 3, NONE)
3514 VAR1 (USHIFTIMM, lshr_simd, 0, NONE, di)
3515 if (TREE_CODE (args[1]) == INTEGER_CST
3516 && wi::ltu_p (wi::to_wide (args[1]), element_precision (args[0])))
3517 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
3518 RSHIFT_EXPR, args[0], args[1]);
3519 break;
bf592b2f 3520 BUILTIN_GPF (BINOP, fmulx, 0, ALL)
0ac198d3 3521 {
6d4d616a
RS
3522 gcc_assert (nargs == 2);
3523 bool a0_cst_p = TREE_CODE (args[0]) == REAL_CST;
3524 bool a1_cst_p = TREE_CODE (args[1]) == REAL_CST;
3525 if (a0_cst_p || a1_cst_p)
0ac198d3 3526 {
6d4d616a 3527 if (a0_cst_p && a1_cst_p)
546e500c 3528 {
6d4d616a
RS
3529 tree t0 = TREE_TYPE (args[0]);
3530 real_value a0 = (TREE_REAL_CST (args[0]));
3531 real_value a1 = (TREE_REAL_CST (args[1]));
3532 if (real_equal (&a1, &dconst0))
3533 std::swap (a0, a1);
3534 /* According to real_equal (), +0 equals -0. */
3535 if (real_equal (&a0, &dconst0) && real_isinf (&a1))
546e500c 3536 {
6d4d616a
RS
3537 real_value res = dconst2;
3538 res.sign = a0.sign ^ a1.sign;
3539 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
3540 REAL_CST,
3541 build_real (t0, res));
546e500c 3542 }
6d4d616a
RS
3543 else
3544 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
3545 MULT_EXPR,
3546 args[0], args[1]);
546e500c 3547 }
6d4d616a
RS
3548 else /* a0_cst_p ^ a1_cst_p. */
3549 {
3550 real_value const_part = a0_cst_p
3551 ? TREE_REAL_CST (args[0]) : TREE_REAL_CST (args[1]);
3552 if (!real_equal (&const_part, &dconst0)
3553 && !real_isinf (&const_part))
3554 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
3555 MULT_EXPR, args[0],
3556 args[1]);
3557 }
3558 }
3559 if (new_stmt)
3560 {
3561 gimple_set_vuse (new_stmt, gimple_vuse (stmt));
3562 gimple_set_vdef (new_stmt, gimple_vdef (stmt));
0ac198d3 3563 }
6d4d616a 3564 break;
0ac198d3 3565 }
03312cbd
AP
3566 case AARCH64_SIMD_BUILTIN_LANE_CHECK:
3567 if (aarch64_fold_builtin_lane_check (args[0], args[1], args[2]))
3568 {
3569 unlink_stmt_vdef (stmt);
3570 release_defs (stmt);
3571 new_stmt = gimple_build_nop ();
3572 }
3573 break;
6d4d616a
RS
3574 default:
3575 break;
0ac198d3 3576 }
e9cad1e5
AC
3577
3578 /* GIMPLE assign statements (unlike calls) require a non-null lhs. If we
3579 created an assign statement with a null lhs, then fix this by assigning
3580 to a new (and subsequently unused) variable. */
3581 if (new_stmt && is_gimple_assign (new_stmt) && !gimple_assign_lhs (new_stmt))
3582 {
3583 tree new_lhs = make_ssa_name (gimple_call_return_type (stmt));
3584 gimple_assign_set_lhs (new_stmt, new_lhs);
3585 }
3586
6d4d616a 3587 return new_stmt;
0ac198d3
JG
3588}
3589
aa87aced
KV
3590void
3591aarch64_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
3592{
3593 const unsigned AARCH64_FE_INVALID = 1;
3594 const unsigned AARCH64_FE_DIVBYZERO = 2;
3595 const unsigned AARCH64_FE_OVERFLOW = 4;
3596 const unsigned AARCH64_FE_UNDERFLOW = 8;
3597 const unsigned AARCH64_FE_INEXACT = 16;
3598 const unsigned HOST_WIDE_INT AARCH64_FE_ALL_EXCEPT = (AARCH64_FE_INVALID
3599 | AARCH64_FE_DIVBYZERO
3600 | AARCH64_FE_OVERFLOW
3601 | AARCH64_FE_UNDERFLOW
3602 | AARCH64_FE_INEXACT);
3603 const unsigned HOST_WIDE_INT AARCH64_FE_EXCEPT_SHIFT = 8;
3604 tree fenv_cr, fenv_sr, get_fpcr, set_fpcr, mask_cr, mask_sr;
3605 tree ld_fenv_cr, ld_fenv_sr, masked_fenv_cr, masked_fenv_sr, hold_fnclex_cr;
3606 tree hold_fnclex_sr, new_fenv_var, reload_fenv, restore_fnenv, get_fpsr, set_fpsr;
3607 tree update_call, atomic_feraiseexcept, hold_fnclex, masked_fenv, ld_fenv;
3608
3609 /* Generate the equivalence of :
3610 unsigned int fenv_cr;
3611 fenv_cr = __builtin_aarch64_get_fpcr ();
3612
3613 unsigned int fenv_sr;
3614 fenv_sr = __builtin_aarch64_get_fpsr ();
3615
3616 Now set all exceptions to non-stop
3617 unsigned int mask_cr
3618 = ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT);
3619 unsigned int masked_cr;
3620 masked_cr = fenv_cr & mask_cr;
3621
3622 And clear all exception flags
3623 unsigned int maske_sr = ~AARCH64_FE_ALL_EXCEPT;
3624 unsigned int masked_cr;
3625 masked_sr = fenv_sr & mask_sr;
3626
3627 __builtin_aarch64_set_cr (masked_cr);
3628 __builtin_aarch64_set_sr (masked_sr); */
3629
09ba9ef7
RR
3630 fenv_cr = create_tmp_var_raw (unsigned_type_node);
3631 fenv_sr = create_tmp_var_raw (unsigned_type_node);
aa87aced
KV
3632
3633 get_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR];
3634 set_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR];
3635 get_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR];
3636 set_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR];
3637
3638 mask_cr = build_int_cst (unsigned_type_node,
3639 ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT));
3640 mask_sr = build_int_cst (unsigned_type_node,
3641 ~(AARCH64_FE_ALL_EXCEPT));
3642
d81bc2af
HZ
3643 ld_fenv_cr = build4 (TARGET_EXPR, unsigned_type_node,
3644 fenv_cr, build_call_expr (get_fpcr, 0),
3645 NULL_TREE, NULL_TREE);
3646 ld_fenv_sr = build4 (TARGET_EXPR, unsigned_type_node,
3647 fenv_sr, build_call_expr (get_fpsr, 0),
3648 NULL_TREE, NULL_TREE);
aa87aced
KV
3649
3650 masked_fenv_cr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_cr, mask_cr);
3651 masked_fenv_sr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_sr, mask_sr);
3652
3653 hold_fnclex_cr = build_call_expr (set_fpcr, 1, masked_fenv_cr);
3654 hold_fnclex_sr = build_call_expr (set_fpsr, 1, masked_fenv_sr);
3655
3656 hold_fnclex = build2 (COMPOUND_EXPR, void_type_node, hold_fnclex_cr,
3657 hold_fnclex_sr);
3658 masked_fenv = build2 (COMPOUND_EXPR, void_type_node, masked_fenv_cr,
3659 masked_fenv_sr);
3660 ld_fenv = build2 (COMPOUND_EXPR, void_type_node, ld_fenv_cr, ld_fenv_sr);
3661
3662 *hold = build2 (COMPOUND_EXPR, void_type_node,
3663 build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv),
3664 hold_fnclex);
3665
3666 /* Store the value of masked_fenv to clear the exceptions:
3667 __builtin_aarch64_set_fpsr (masked_fenv_sr); */
3668
3669 *clear = build_call_expr (set_fpsr, 1, masked_fenv_sr);
3670
3671 /* Generate the equivalent of :
3672 unsigned int new_fenv_var;
3673 new_fenv_var = __builtin_aarch64_get_fpsr ();
3674
3675 __builtin_aarch64_set_fpsr (fenv_sr);
3676
3677 __atomic_feraiseexcept (new_fenv_var); */
3678
09ba9ef7 3679 new_fenv_var = create_tmp_var_raw (unsigned_type_node);
d81bc2af
HZ
3680 reload_fenv = build4 (TARGET_EXPR, unsigned_type_node,
3681 new_fenv_var, build_call_expr (get_fpsr, 0),
3682 NULL_TREE, NULL_TREE);
aa87aced
KV
3683 restore_fnenv = build_call_expr (set_fpsr, 1, fenv_sr);
3684 atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT);
3685 update_call = build_call_expr (atomic_feraiseexcept, 1,
3686 fold_convert (integer_type_node, new_fenv_var));
3687 *update = build2 (COMPOUND_EXPR, void_type_node,
3688 build2 (COMPOUND_EXPR, void_type_node,
3689 reload_fenv, restore_fnenv), update_call);
3690}
3691
ef01e6bb
DZ
3692/* Resolve overloaded MEMTAG build-in functions. */
3693#define AARCH64_BUILTIN_SUBCODE(F) \
3694 (DECL_MD_FUNCTION_CODE (F) >> AARCH64_BUILTIN_SHIFT)
3695
3696static tree
3697aarch64_resolve_overloaded_memtag (location_t loc,
3698 tree fndecl, void *pass_params)
3699{
3700 vec<tree, va_gc> *params = static_cast<vec<tree, va_gc> *> (pass_params);
3701 unsigned param_num = params ? params->length() : 0;
3702 unsigned int fcode = AARCH64_BUILTIN_SUBCODE (fndecl);
3703 tree inittype = aarch64_memtag_builtin_data[
3704 fcode - AARCH64_MEMTAG_BUILTIN_START - 1].ftype;
3705 unsigned arg_num = list_length (TYPE_ARG_TYPES (inittype)) - 1;
3706
3707 if (param_num != arg_num)
3708 {
3709 TREE_TYPE (fndecl) = inittype;
3710 return NULL_TREE;
3711 }
3712 tree retype = NULL;
3713
3714 if (fcode == AARCH64_MEMTAG_BUILTIN_SUBP)
3715 {
3716 tree t0 = TREE_TYPE ((*params)[0]);
3717 tree t1 = TREE_TYPE ((*params)[1]);
3718
3719 if (t0 == error_mark_node || TREE_CODE (t0) != POINTER_TYPE)
3720 t0 = ptr_type_node;
3721 if (t1 == error_mark_node || TREE_CODE (t1) != POINTER_TYPE)
3722 t1 = ptr_type_node;
3723
3724 if (TYPE_MODE (t0) != DImode)
3725 warning_at (loc, 1, "expected 64-bit address but argument 1 is %d-bit",
3726 (int)tree_to_shwi (DECL_SIZE ((*params)[0])));
3727
3728 if (TYPE_MODE (t1) != DImode)
3729 warning_at (loc, 1, "expected 64-bit address but argument 2 is %d-bit",
3730 (int)tree_to_shwi (DECL_SIZE ((*params)[1])));
3731
3732 retype = build_function_type_list (ptrdiff_type_node, t0, t1, NULL);
3733 }
3734 else
3735 {
3736 tree t0 = TREE_TYPE ((*params)[0]);
3737
3738 if (t0 == error_mark_node || TREE_CODE (t0) != POINTER_TYPE)
3739 {
3740 TREE_TYPE (fndecl) = inittype;
3741 return NULL_TREE;
3742 }
3743
3744 if (TYPE_MODE (t0) != DImode)
3745 warning_at (loc, 1, "expected 64-bit address but argument 1 is %d-bit",
3746 (int)tree_to_shwi (DECL_SIZE ((*params)[0])));
3747
3748 switch (fcode)
3749 {
3750 case AARCH64_MEMTAG_BUILTIN_IRG:
3751 retype = build_function_type_list (t0, t0, uint64_type_node, NULL);
3752 break;
3753 case AARCH64_MEMTAG_BUILTIN_GMI:
3754 retype = build_function_type_list (uint64_type_node, t0,
3755 uint64_type_node, NULL);
3756 break;
3757 case AARCH64_MEMTAG_BUILTIN_INC_TAG:
3758 retype = build_function_type_list (t0, t0, unsigned_type_node, NULL);
3759 break;
3760 case AARCH64_MEMTAG_BUILTIN_SET_TAG:
3761 retype = build_function_type_list (void_type_node, t0, NULL);
3762 break;
3763 case AARCH64_MEMTAG_BUILTIN_GET_TAG:
3764 retype = build_function_type_list (t0, t0, NULL);
3765 break;
3766 default:
3767 return NULL_TREE;
3768 }
3769 }
3770
3771 if (!retype || retype == error_mark_node)
3772 TREE_TYPE (fndecl) = inittype;
3773 else
3774 TREE_TYPE (fndecl) = retype;
3775
3776 return NULL_TREE;
3777}
3778
e53b6e56 3779/* Called at aarch64_resolve_overloaded_builtin in aarch64-c.cc. */
ef01e6bb
DZ
3780tree
3781aarch64_resolve_overloaded_builtin_general (location_t loc, tree function,
3782 void *pass_params)
3783{
3784 unsigned int fcode = AARCH64_BUILTIN_SUBCODE (function);
3785
3786 if (fcode >= AARCH64_MEMTAG_BUILTIN_START
3787 && fcode <= AARCH64_MEMTAG_BUILTIN_END)
3788 return aarch64_resolve_overloaded_memtag(loc, function, pass_params);
3789
3790 return NULL_TREE;
3791}
aa87aced 3792
42fc9a7f
JG
3793#undef AARCH64_CHECK_BUILTIN_MODE
3794#undef AARCH64_FIND_FRINT_VARIANT
0ddec79f
JG
3795#undef CF0
3796#undef CF1
3797#undef CF2
3798#undef CF3
3799#undef CF4
3800#undef CF10
3801#undef VAR1
3802#undef VAR2
3803#undef VAR3
3804#undef VAR4
3805#undef VAR5
3806#undef VAR6
3807#undef VAR7
3808#undef VAR8
3809#undef VAR9
3810#undef VAR10
3811#undef VAR11
3812
3c03d39d 3813#include "gt-aarch64-builtins.h"