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