runtime: allow preemption in fast syscall return
[official-gcc.git] / gcc / config / aarch64 / aarch64-builtins.c
blob02c6738d2207d19b63f9bd429942068e92c16292
1 /* Builtins' description for AArch64 SIMD architecture.
2 Copyright (C) 2011-2018 Free Software Foundation, Inc.
3 Contributed by ARM Ltd.
5 This file is part of GCC.
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.
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.
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/>. */
21 #define IN_TARGET_CODE 1
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "function.h"
28 #include "basic-block.h"
29 #include "rtl.h"
30 #include "tree.h"
31 #include "gimple.h"
32 #include "memmodel.h"
33 #include "tm_p.h"
34 #include "expmed.h"
35 #include "optabs.h"
36 #include "recog.h"
37 #include "diagnostic-core.h"
38 #include "fold-const.h"
39 #include "stor-layout.h"
40 #include "explow.h"
41 #include "expr.h"
42 #include "langhooks.h"
43 #include "gimple-iterator.h"
44 #include "case-cfn-macros.h"
46 #define v8qi_UP E_V8QImode
47 #define v4hi_UP E_V4HImode
48 #define v4hf_UP E_V4HFmode
49 #define v2si_UP E_V2SImode
50 #define v2sf_UP E_V2SFmode
51 #define v1df_UP E_V1DFmode
52 #define di_UP E_DImode
53 #define df_UP E_DFmode
54 #define v16qi_UP E_V16QImode
55 #define v8hi_UP E_V8HImode
56 #define v8hf_UP E_V8HFmode
57 #define v4si_UP E_V4SImode
58 #define v4sf_UP E_V4SFmode
59 #define v2di_UP E_V2DImode
60 #define v2df_UP E_V2DFmode
61 #define ti_UP E_TImode
62 #define oi_UP E_OImode
63 #define ci_UP E_CImode
64 #define xi_UP E_XImode
65 #define si_UP E_SImode
66 #define sf_UP E_SFmode
67 #define hi_UP E_HImode
68 #define hf_UP E_HFmode
69 #define qi_UP E_QImode
70 #define UP(X) X##_UP
72 #define SIMD_MAX_BUILTIN_ARGS 5
74 enum aarch64_type_qualifiers
76 /* T foo. */
77 qualifier_none = 0x0,
78 /* unsigned T foo. */
79 qualifier_unsigned = 0x1, /* 1 << 0 */
80 /* const T foo. */
81 qualifier_const = 0x2, /* 1 << 1 */
82 /* T *foo. */
83 qualifier_pointer = 0x4, /* 1 << 2 */
84 /* Used when expanding arguments if an operand could
85 be an immediate. */
86 qualifier_immediate = 0x8, /* 1 << 3 */
87 qualifier_maybe_immediate = 0x10, /* 1 << 4 */
88 /* void foo (...). */
89 qualifier_void = 0x20, /* 1 << 5 */
90 /* Some patterns may have internal operands, this qualifier is an
91 instruction to the initialisation code to skip this operand. */
92 qualifier_internal = 0x40, /* 1 << 6 */
93 /* Some builtins should use the T_*mode* encoded in a simd_builtin_datum
94 rather than using the type of the operand. */
95 qualifier_map_mode = 0x80, /* 1 << 7 */
96 /* qualifier_pointer | qualifier_map_mode */
97 qualifier_pointer_map_mode = 0x84,
98 /* qualifier_const | qualifier_pointer | qualifier_map_mode */
99 qualifier_const_pointer_map_mode = 0x86,
100 /* Polynomial types. */
101 qualifier_poly = 0x100,
102 /* Lane indices - must be in range, and flipped for bigendian. */
103 qualifier_lane_index = 0x200,
104 /* Lane indices for single lane structure loads and stores. */
105 qualifier_struct_load_store_lane_index = 0x400
108 typedef struct
110 const char *name;
111 machine_mode mode;
112 const enum insn_code code;
113 unsigned int fcode;
114 enum aarch64_type_qualifiers *qualifiers;
115 } aarch64_simd_builtin_datum;
117 static enum aarch64_type_qualifiers
118 aarch64_types_unop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
119 = { qualifier_none, qualifier_none };
120 #define TYPES_UNOP (aarch64_types_unop_qualifiers)
121 static enum aarch64_type_qualifiers
122 aarch64_types_unopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
123 = { qualifier_unsigned, qualifier_unsigned };
124 #define TYPES_UNOPU (aarch64_types_unopu_qualifiers)
125 static enum aarch64_type_qualifiers
126 aarch64_types_unopus_qualifiers[SIMD_MAX_BUILTIN_ARGS]
127 = { qualifier_unsigned, qualifier_none };
128 #define TYPES_UNOPUS (aarch64_types_unopus_qualifiers)
129 static enum aarch64_type_qualifiers
130 aarch64_types_binop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
131 = { qualifier_none, qualifier_none, qualifier_maybe_immediate };
132 #define TYPES_BINOP (aarch64_types_binop_qualifiers)
133 static enum aarch64_type_qualifiers
134 aarch64_types_binopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
135 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned };
136 #define TYPES_BINOPU (aarch64_types_binopu_qualifiers)
137 static enum aarch64_type_qualifiers
138 aarch64_types_binop_uus_qualifiers[SIMD_MAX_BUILTIN_ARGS]
139 = { qualifier_unsigned, qualifier_unsigned, qualifier_none };
140 #define TYPES_BINOP_UUS (aarch64_types_binop_uus_qualifiers)
141 static enum aarch64_type_qualifiers
142 aarch64_types_binop_ssu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
143 = { qualifier_none, qualifier_none, qualifier_unsigned };
144 #define TYPES_BINOP_SSU (aarch64_types_binop_ssu_qualifiers)
145 static enum aarch64_type_qualifiers
146 aarch64_types_binop_uss_qualifiers[SIMD_MAX_BUILTIN_ARGS]
147 = { qualifier_unsigned, qualifier_none, qualifier_none };
148 #define TYPES_BINOP_USS (aarch64_types_binop_uss_qualifiers)
149 static enum aarch64_type_qualifiers
150 aarch64_types_binopp_qualifiers[SIMD_MAX_BUILTIN_ARGS]
151 = { qualifier_poly, qualifier_poly, qualifier_poly };
152 #define TYPES_BINOPP (aarch64_types_binopp_qualifiers)
154 static enum aarch64_type_qualifiers
155 aarch64_types_ternop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
156 = { qualifier_none, qualifier_none, qualifier_none, qualifier_none };
157 #define TYPES_TERNOP (aarch64_types_ternop_qualifiers)
158 static enum aarch64_type_qualifiers
159 aarch64_types_ternop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
160 = { qualifier_none, qualifier_none, qualifier_none, qualifier_lane_index };
161 #define TYPES_TERNOP_LANE (aarch64_types_ternop_lane_qualifiers)
162 static enum aarch64_type_qualifiers
163 aarch64_types_ternopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
164 = { qualifier_unsigned, qualifier_unsigned,
165 qualifier_unsigned, qualifier_unsigned };
166 #define TYPES_TERNOPU (aarch64_types_ternopu_qualifiers)
167 static enum aarch64_type_qualifiers
168 aarch64_types_ternopu_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
169 = { qualifier_unsigned, qualifier_unsigned,
170 qualifier_unsigned, qualifier_immediate };
171 #define TYPES_TERNOPUI (aarch64_types_ternopu_imm_qualifiers)
174 static enum aarch64_type_qualifiers
175 aarch64_types_quadop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
176 = { qualifier_none, qualifier_none, qualifier_none,
177 qualifier_none, qualifier_lane_index };
178 #define TYPES_QUADOP_LANE (aarch64_types_quadop_lane_qualifiers)
179 static enum aarch64_type_qualifiers
180 aarch64_types_quadopu_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
181 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
182 qualifier_unsigned, qualifier_lane_index };
183 #define TYPES_QUADOPU_LANE (aarch64_types_quadopu_lane_qualifiers)
185 static enum aarch64_type_qualifiers
186 aarch64_types_quadopu_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
187 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
188 qualifier_unsigned, qualifier_immediate };
189 #define TYPES_QUADOPUI (aarch64_types_quadopu_imm_qualifiers)
191 static enum aarch64_type_qualifiers
192 aarch64_types_binop_imm_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
193 = { qualifier_poly, qualifier_none, qualifier_immediate };
194 #define TYPES_GETREGP (aarch64_types_binop_imm_p_qualifiers)
195 static enum aarch64_type_qualifiers
196 aarch64_types_binop_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
197 = { qualifier_none, qualifier_none, qualifier_immediate };
198 #define TYPES_GETREG (aarch64_types_binop_imm_qualifiers)
199 #define TYPES_SHIFTIMM (aarch64_types_binop_imm_qualifiers)
200 static enum aarch64_type_qualifiers
201 aarch64_types_shift_to_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS]
202 = { qualifier_unsigned, qualifier_none, qualifier_immediate };
203 #define TYPES_SHIFTIMM_USS (aarch64_types_shift_to_unsigned_qualifiers)
204 static enum aarch64_type_qualifiers
205 aarch64_types_fcvt_from_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS]
206 = { qualifier_none, qualifier_unsigned, qualifier_immediate };
207 #define TYPES_FCVTIMM_SUS (aarch64_types_fcvt_from_unsigned_qualifiers)
208 static enum aarch64_type_qualifiers
209 aarch64_types_unsigned_shift_qualifiers[SIMD_MAX_BUILTIN_ARGS]
210 = { qualifier_unsigned, qualifier_unsigned, qualifier_immediate };
211 #define TYPES_USHIFTIMM (aarch64_types_unsigned_shift_qualifiers)
213 static enum aarch64_type_qualifiers
214 aarch64_types_ternop_s_imm_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
215 = { qualifier_none, qualifier_none, qualifier_poly, qualifier_immediate};
216 #define TYPES_SETREGP (aarch64_types_ternop_s_imm_p_qualifiers)
217 static enum aarch64_type_qualifiers
218 aarch64_types_ternop_s_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
219 = { qualifier_none, qualifier_none, qualifier_none, qualifier_immediate};
220 #define TYPES_SETREG (aarch64_types_ternop_s_imm_qualifiers)
221 #define TYPES_SHIFTINSERT (aarch64_types_ternop_s_imm_qualifiers)
222 #define TYPES_SHIFTACC (aarch64_types_ternop_s_imm_qualifiers)
224 static enum aarch64_type_qualifiers
225 aarch64_types_ternop_p_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
226 = { qualifier_poly, qualifier_poly, qualifier_poly, qualifier_immediate};
227 #define TYPES_SHIFTINSERTP (aarch64_types_ternop_p_imm_qualifiers)
229 static enum aarch64_type_qualifiers
230 aarch64_types_unsigned_shiftacc_qualifiers[SIMD_MAX_BUILTIN_ARGS]
231 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
232 qualifier_immediate };
233 #define TYPES_USHIFTACC (aarch64_types_unsigned_shiftacc_qualifiers)
236 static enum aarch64_type_qualifiers
237 aarch64_types_combine_qualifiers[SIMD_MAX_BUILTIN_ARGS]
238 = { qualifier_none, qualifier_none, qualifier_none };
239 #define TYPES_COMBINE (aarch64_types_combine_qualifiers)
241 static enum aarch64_type_qualifiers
242 aarch64_types_combine_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
243 = { qualifier_poly, qualifier_poly, qualifier_poly };
244 #define TYPES_COMBINEP (aarch64_types_combine_p_qualifiers)
246 static enum aarch64_type_qualifiers
247 aarch64_types_load1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
248 = { qualifier_none, qualifier_const_pointer_map_mode };
249 #define TYPES_LOAD1 (aarch64_types_load1_qualifiers)
250 #define TYPES_LOADSTRUCT (aarch64_types_load1_qualifiers)
251 static enum aarch64_type_qualifiers
252 aarch64_types_loadstruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
253 = { qualifier_none, qualifier_const_pointer_map_mode,
254 qualifier_none, qualifier_struct_load_store_lane_index };
255 #define TYPES_LOADSTRUCT_LANE (aarch64_types_loadstruct_lane_qualifiers)
257 static enum aarch64_type_qualifiers
258 aarch64_types_bsl_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
259 = { qualifier_poly, qualifier_unsigned,
260 qualifier_poly, qualifier_poly };
261 #define TYPES_BSL_P (aarch64_types_bsl_p_qualifiers)
262 static enum aarch64_type_qualifiers
263 aarch64_types_bsl_s_qualifiers[SIMD_MAX_BUILTIN_ARGS]
264 = { qualifier_none, qualifier_unsigned,
265 qualifier_none, qualifier_none };
266 #define TYPES_BSL_S (aarch64_types_bsl_s_qualifiers)
267 static enum aarch64_type_qualifiers
268 aarch64_types_bsl_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
269 = { qualifier_unsigned, qualifier_unsigned,
270 qualifier_unsigned, qualifier_unsigned };
271 #define TYPES_BSL_U (aarch64_types_bsl_u_qualifiers)
273 /* The first argument (return type) of a store should be void type,
274 which we represent with qualifier_void. Their first operand will be
275 a DImode pointer to the location to store to, so we must use
276 qualifier_map_mode | qualifier_pointer to build a pointer to the
277 element type of the vector. */
278 static enum aarch64_type_qualifiers
279 aarch64_types_store1_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
280 = { qualifier_void, qualifier_pointer_map_mode, qualifier_poly };
281 #define TYPES_STORE1P (aarch64_types_store1_p_qualifiers)
282 static enum aarch64_type_qualifiers
283 aarch64_types_store1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
284 = { qualifier_void, qualifier_pointer_map_mode, qualifier_none };
285 #define TYPES_STORE1 (aarch64_types_store1_qualifiers)
286 #define TYPES_STORESTRUCT (aarch64_types_store1_qualifiers)
287 static enum aarch64_type_qualifiers
288 aarch64_types_storestruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
289 = { qualifier_void, qualifier_pointer_map_mode,
290 qualifier_none, qualifier_struct_load_store_lane_index };
291 #define TYPES_STORESTRUCT_LANE (aarch64_types_storestruct_lane_qualifiers)
293 #define CF0(N, X) CODE_FOR_aarch64_##N##X
294 #define CF1(N, X) CODE_FOR_##N##X##1
295 #define CF2(N, X) CODE_FOR_##N##X##2
296 #define CF3(N, X) CODE_FOR_##N##X##3
297 #define CF4(N, X) CODE_FOR_##N##X##4
298 #define CF10(N, X) CODE_FOR_##N##X
300 #define VAR1(T, N, MAP, A) \
301 {#N #A, UP (A), CF##MAP (N, A), 0, TYPES_##T},
302 #define VAR2(T, N, MAP, A, B) \
303 VAR1 (T, N, MAP, A) \
304 VAR1 (T, N, MAP, B)
305 #define VAR3(T, N, MAP, A, B, C) \
306 VAR2 (T, N, MAP, A, B) \
307 VAR1 (T, N, MAP, C)
308 #define VAR4(T, N, MAP, A, B, C, D) \
309 VAR3 (T, N, MAP, A, B, C) \
310 VAR1 (T, N, MAP, D)
311 #define VAR5(T, N, MAP, A, B, C, D, E) \
312 VAR4 (T, N, MAP, A, B, C, D) \
313 VAR1 (T, N, MAP, E)
314 #define VAR6(T, N, MAP, A, B, C, D, E, F) \
315 VAR5 (T, N, MAP, A, B, C, D, E) \
316 VAR1 (T, N, MAP, F)
317 #define VAR7(T, N, MAP, A, B, C, D, E, F, G) \
318 VAR6 (T, N, MAP, A, B, C, D, E, F) \
319 VAR1 (T, N, MAP, G)
320 #define VAR8(T, N, MAP, A, B, C, D, E, F, G, H) \
321 VAR7 (T, N, MAP, A, B, C, D, E, F, G) \
322 VAR1 (T, N, MAP, H)
323 #define VAR9(T, N, MAP, A, B, C, D, E, F, G, H, I) \
324 VAR8 (T, N, MAP, A, B, C, D, E, F, G, H) \
325 VAR1 (T, N, MAP, I)
326 #define VAR10(T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
327 VAR9 (T, N, MAP, A, B, C, D, E, F, G, H, I) \
328 VAR1 (T, N, MAP, J)
329 #define VAR11(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
330 VAR10 (T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
331 VAR1 (T, N, MAP, K)
332 #define VAR12(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K, L) \
333 VAR11 (T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
334 VAR1 (T, N, MAP, L)
335 #define VAR13(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K, L, M) \
336 VAR12 (T, N, MAP, A, B, C, D, E, F, G, H, I, J, K, L) \
337 VAR1 (T, N, MAP, M)
338 #define VAR14(T, X, MAP, A, B, C, D, E, F, G, H, I, J, K, L, M, N) \
339 VAR13 (T, X, MAP, A, B, C, D, E, F, G, H, I, J, K, L, M) \
340 VAR1 (T, X, MAP, N)
342 #include "aarch64-builtin-iterators.h"
344 static aarch64_simd_builtin_datum aarch64_simd_builtin_data[] = {
345 #include "aarch64-simd-builtins.def"
348 /* There's only 8 CRC32 builtins. Probably not worth their own .def file. */
349 #define AARCH64_CRC32_BUILTINS \
350 CRC32_BUILTIN (crc32b, QI) \
351 CRC32_BUILTIN (crc32h, HI) \
352 CRC32_BUILTIN (crc32w, SI) \
353 CRC32_BUILTIN (crc32x, DI) \
354 CRC32_BUILTIN (crc32cb, QI) \
355 CRC32_BUILTIN (crc32ch, HI) \
356 CRC32_BUILTIN (crc32cw, SI) \
357 CRC32_BUILTIN (crc32cx, DI)
359 typedef struct
361 const char *name;
362 machine_mode mode;
363 const enum insn_code icode;
364 unsigned int fcode;
365 } aarch64_crc_builtin_datum;
367 #define CRC32_BUILTIN(N, M) \
368 AARCH64_BUILTIN_##N,
370 #undef VAR1
371 #define VAR1(T, N, MAP, A) \
372 AARCH64_SIMD_BUILTIN_##T##_##N##A,
374 enum aarch64_builtins
376 AARCH64_BUILTIN_MIN,
378 AARCH64_BUILTIN_GET_FPCR,
379 AARCH64_BUILTIN_SET_FPCR,
380 AARCH64_BUILTIN_GET_FPSR,
381 AARCH64_BUILTIN_SET_FPSR,
383 AARCH64_BUILTIN_RSQRT_DF,
384 AARCH64_BUILTIN_RSQRT_SF,
385 AARCH64_BUILTIN_RSQRT_V2DF,
386 AARCH64_BUILTIN_RSQRT_V2SF,
387 AARCH64_BUILTIN_RSQRT_V4SF,
388 AARCH64_SIMD_BUILTIN_BASE,
389 AARCH64_SIMD_BUILTIN_LANE_CHECK,
390 #include "aarch64-simd-builtins.def"
391 /* The first enum element which is based on an insn_data pattern. */
392 AARCH64_SIMD_PATTERN_START = AARCH64_SIMD_BUILTIN_LANE_CHECK + 1,
393 AARCH64_SIMD_BUILTIN_MAX = AARCH64_SIMD_PATTERN_START
394 + ARRAY_SIZE (aarch64_simd_builtin_data) - 1,
395 AARCH64_CRC32_BUILTIN_BASE,
396 AARCH64_CRC32_BUILTINS
397 AARCH64_CRC32_BUILTIN_MAX,
398 /* ARMv8.3-A Pointer Authentication Builtins. */
399 AARCH64_PAUTH_BUILTIN_AUTIA1716,
400 AARCH64_PAUTH_BUILTIN_PACIA1716,
401 AARCH64_PAUTH_BUILTIN_XPACLRI,
402 AARCH64_BUILTIN_MAX
405 #undef CRC32_BUILTIN
406 #define CRC32_BUILTIN(N, M) \
407 {"__builtin_aarch64_"#N, E_##M##mode, CODE_FOR_aarch64_##N, AARCH64_BUILTIN_##N},
409 static aarch64_crc_builtin_datum aarch64_crc_builtin_data[] = {
410 AARCH64_CRC32_BUILTINS
413 #undef CRC32_BUILTIN
415 static GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX];
417 #define NUM_DREG_TYPES 6
418 #define NUM_QREG_TYPES 6
420 /* Internal scalar builtin types. These types are used to support
421 neon intrinsic builtins. They are _not_ user-visible types. Therefore
422 the mangling for these types are implementation defined. */
423 const char *aarch64_scalar_builtin_types[] = {
424 "__builtin_aarch64_simd_qi",
425 "__builtin_aarch64_simd_hi",
426 "__builtin_aarch64_simd_si",
427 "__builtin_aarch64_simd_hf",
428 "__builtin_aarch64_simd_sf",
429 "__builtin_aarch64_simd_di",
430 "__builtin_aarch64_simd_df",
431 "__builtin_aarch64_simd_poly8",
432 "__builtin_aarch64_simd_poly16",
433 "__builtin_aarch64_simd_poly64",
434 "__builtin_aarch64_simd_poly128",
435 "__builtin_aarch64_simd_ti",
436 "__builtin_aarch64_simd_uqi",
437 "__builtin_aarch64_simd_uhi",
438 "__builtin_aarch64_simd_usi",
439 "__builtin_aarch64_simd_udi",
440 "__builtin_aarch64_simd_ei",
441 "__builtin_aarch64_simd_oi",
442 "__builtin_aarch64_simd_ci",
443 "__builtin_aarch64_simd_xi",
444 NULL
447 #define ENTRY(E, M, Q, G) E,
448 enum aarch64_simd_type
450 #include "aarch64-simd-builtin-types.def"
451 ARM_NEON_H_TYPES_LAST
453 #undef ENTRY
455 struct aarch64_simd_type_info
457 enum aarch64_simd_type type;
459 /* Internal type name. */
460 const char *name;
462 /* Internal type name(mangled). The mangled names conform to the
463 AAPCS64 (see "Procedure Call Standard for the ARM 64-bit Architecture",
464 Appendix A). To qualify for emission with the mangled names defined in
465 that document, a vector type must not only be of the correct mode but also
466 be of the correct internal AdvSIMD vector type (e.g. __Int8x8_t); these
467 types are registered by aarch64_init_simd_builtin_types (). In other
468 words, vector types defined in other ways e.g. via vector_size attribute
469 will get default mangled names. */
470 const char *mangle;
472 /* Internal type. */
473 tree itype;
475 /* Element type. */
476 tree eltype;
478 /* Machine mode the internal type maps to. */
479 enum machine_mode mode;
481 /* Qualifiers. */
482 enum aarch64_type_qualifiers q;
485 #define ENTRY(E, M, Q, G) \
486 {E, "__" #E, #G "__" #E, NULL_TREE, NULL_TREE, E_##M##mode, qualifier_##Q},
487 static struct aarch64_simd_type_info aarch64_simd_types [] = {
488 #include "aarch64-simd-builtin-types.def"
490 #undef ENTRY
492 static tree aarch64_simd_intOI_type_node = NULL_TREE;
493 static tree aarch64_simd_intCI_type_node = NULL_TREE;
494 static tree aarch64_simd_intXI_type_node = NULL_TREE;
496 /* The user-visible __fp16 type, and a pointer to that type. Used
497 across the back-end. */
498 tree aarch64_fp16_type_node = NULL_TREE;
499 tree aarch64_fp16_ptr_type_node = NULL_TREE;
501 static const char *
502 aarch64_mangle_builtin_scalar_type (const_tree type)
504 int i = 0;
506 while (aarch64_scalar_builtin_types[i] != NULL)
508 const char *name = aarch64_scalar_builtin_types[i];
510 if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
511 && DECL_NAME (TYPE_NAME (type))
512 && !strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), name))
513 return aarch64_scalar_builtin_types[i];
514 i++;
516 return NULL;
519 static const char *
520 aarch64_mangle_builtin_vector_type (const_tree type)
522 int i;
523 int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
525 for (i = 0; i < nelts; i++)
526 if (aarch64_simd_types[i].mode == TYPE_MODE (type)
527 && TYPE_NAME (type)
528 && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
529 && DECL_NAME (TYPE_NAME (type))
530 && !strcmp
531 (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))),
532 aarch64_simd_types[i].name))
533 return aarch64_simd_types[i].mangle;
535 return NULL;
538 const char *
539 aarch64_mangle_builtin_type (const_tree type)
541 const char *mangle;
542 /* Walk through all the AArch64 builtins types tables to filter out the
543 incoming type. */
544 if ((mangle = aarch64_mangle_builtin_vector_type (type))
545 || (mangle = aarch64_mangle_builtin_scalar_type (type)))
546 return mangle;
548 return NULL;
551 static tree
552 aarch64_simd_builtin_std_type (machine_mode mode,
553 enum aarch64_type_qualifiers q)
555 #define QUAL_TYPE(M) \
556 ((q == qualifier_none) ? int##M##_type_node : unsigned_int##M##_type_node);
557 switch (mode)
559 case E_QImode:
560 return QUAL_TYPE (QI);
561 case E_HImode:
562 return QUAL_TYPE (HI);
563 case E_SImode:
564 return QUAL_TYPE (SI);
565 case E_DImode:
566 return QUAL_TYPE (DI);
567 case E_TImode:
568 return QUAL_TYPE (TI);
569 case E_OImode:
570 return aarch64_simd_intOI_type_node;
571 case E_CImode:
572 return aarch64_simd_intCI_type_node;
573 case E_XImode:
574 return aarch64_simd_intXI_type_node;
575 case E_HFmode:
576 return aarch64_fp16_type_node;
577 case E_SFmode:
578 return float_type_node;
579 case E_DFmode:
580 return double_type_node;
581 default:
582 gcc_unreachable ();
584 #undef QUAL_TYPE
587 static tree
588 aarch64_lookup_simd_builtin_type (machine_mode mode,
589 enum aarch64_type_qualifiers q)
591 int i;
592 int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
594 /* Non-poly scalar modes map to standard types not in the table. */
595 if (q != qualifier_poly && !VECTOR_MODE_P (mode))
596 return aarch64_simd_builtin_std_type (mode, q);
598 for (i = 0; i < nelts; i++)
599 if (aarch64_simd_types[i].mode == mode
600 && aarch64_simd_types[i].q == q)
601 return aarch64_simd_types[i].itype;
603 return NULL_TREE;
606 static tree
607 aarch64_simd_builtin_type (machine_mode mode,
608 bool unsigned_p, bool poly_p)
610 if (poly_p)
611 return aarch64_lookup_simd_builtin_type (mode, qualifier_poly);
612 else if (unsigned_p)
613 return aarch64_lookup_simd_builtin_type (mode, qualifier_unsigned);
614 else
615 return aarch64_lookup_simd_builtin_type (mode, qualifier_none);
618 static void
619 aarch64_init_simd_builtin_types (void)
621 int i;
622 int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
623 tree tdecl;
625 /* Init all the element types built by the front-end. */
626 aarch64_simd_types[Int8x8_t].eltype = intQI_type_node;
627 aarch64_simd_types[Int8x16_t].eltype = intQI_type_node;
628 aarch64_simd_types[Int16x4_t].eltype = intHI_type_node;
629 aarch64_simd_types[Int16x8_t].eltype = intHI_type_node;
630 aarch64_simd_types[Int32x2_t].eltype = intSI_type_node;
631 aarch64_simd_types[Int32x4_t].eltype = intSI_type_node;
632 aarch64_simd_types[Int64x1_t].eltype = intDI_type_node;
633 aarch64_simd_types[Int64x2_t].eltype = intDI_type_node;
634 aarch64_simd_types[Uint8x8_t].eltype = unsigned_intQI_type_node;
635 aarch64_simd_types[Uint8x16_t].eltype = unsigned_intQI_type_node;
636 aarch64_simd_types[Uint16x4_t].eltype = unsigned_intHI_type_node;
637 aarch64_simd_types[Uint16x8_t].eltype = unsigned_intHI_type_node;
638 aarch64_simd_types[Uint32x2_t].eltype = unsigned_intSI_type_node;
639 aarch64_simd_types[Uint32x4_t].eltype = unsigned_intSI_type_node;
640 aarch64_simd_types[Uint64x1_t].eltype = unsigned_intDI_type_node;
641 aarch64_simd_types[Uint64x2_t].eltype = unsigned_intDI_type_node;
643 /* Poly types are a world of their own. */
644 aarch64_simd_types[Poly8_t].eltype = aarch64_simd_types[Poly8_t].itype =
645 build_distinct_type_copy (unsigned_intQI_type_node);
646 aarch64_simd_types[Poly16_t].eltype = aarch64_simd_types[Poly16_t].itype =
647 build_distinct_type_copy (unsigned_intHI_type_node);
648 aarch64_simd_types[Poly64_t].eltype = aarch64_simd_types[Poly64_t].itype =
649 build_distinct_type_copy (unsigned_intDI_type_node);
650 aarch64_simd_types[Poly128_t].eltype = aarch64_simd_types[Poly128_t].itype =
651 build_distinct_type_copy (unsigned_intTI_type_node);
652 /* Init poly vector element types with scalar poly types. */
653 aarch64_simd_types[Poly8x8_t].eltype = aarch64_simd_types[Poly8_t].itype;
654 aarch64_simd_types[Poly8x16_t].eltype = aarch64_simd_types[Poly8_t].itype;
655 aarch64_simd_types[Poly16x4_t].eltype = aarch64_simd_types[Poly16_t].itype;
656 aarch64_simd_types[Poly16x8_t].eltype = aarch64_simd_types[Poly16_t].itype;
657 aarch64_simd_types[Poly64x1_t].eltype = aarch64_simd_types[Poly64_t].itype;
658 aarch64_simd_types[Poly64x2_t].eltype = aarch64_simd_types[Poly64_t].itype;
660 /* Continue with standard types. */
661 aarch64_simd_types[Float16x4_t].eltype = aarch64_fp16_type_node;
662 aarch64_simd_types[Float16x8_t].eltype = aarch64_fp16_type_node;
663 aarch64_simd_types[Float32x2_t].eltype = float_type_node;
664 aarch64_simd_types[Float32x4_t].eltype = float_type_node;
665 aarch64_simd_types[Float64x1_t].eltype = double_type_node;
666 aarch64_simd_types[Float64x2_t].eltype = double_type_node;
668 for (i = 0; i < nelts; i++)
670 tree eltype = aarch64_simd_types[i].eltype;
671 machine_mode mode = aarch64_simd_types[i].mode;
673 if (aarch64_simd_types[i].itype == NULL)
675 aarch64_simd_types[i].itype
676 = build_distinct_type_copy
677 (build_vector_type (eltype, GET_MODE_NUNITS (mode)));
678 SET_TYPE_STRUCTURAL_EQUALITY (aarch64_simd_types[i].itype);
681 tdecl = add_builtin_type (aarch64_simd_types[i].name,
682 aarch64_simd_types[i].itype);
683 TYPE_NAME (aarch64_simd_types[i].itype) = tdecl;
686 #define AARCH64_BUILD_SIGNED_TYPE(mode) \
687 make_signed_type (GET_MODE_PRECISION (mode));
688 aarch64_simd_intOI_type_node = AARCH64_BUILD_SIGNED_TYPE (OImode);
689 aarch64_simd_intCI_type_node = AARCH64_BUILD_SIGNED_TYPE (CImode);
690 aarch64_simd_intXI_type_node = AARCH64_BUILD_SIGNED_TYPE (XImode);
691 #undef AARCH64_BUILD_SIGNED_TYPE
693 tdecl = add_builtin_type
694 ("__builtin_aarch64_simd_oi" , aarch64_simd_intOI_type_node);
695 TYPE_NAME (aarch64_simd_intOI_type_node) = tdecl;
696 tdecl = add_builtin_type
697 ("__builtin_aarch64_simd_ci" , aarch64_simd_intCI_type_node);
698 TYPE_NAME (aarch64_simd_intCI_type_node) = tdecl;
699 tdecl = add_builtin_type
700 ("__builtin_aarch64_simd_xi" , aarch64_simd_intXI_type_node);
701 TYPE_NAME (aarch64_simd_intXI_type_node) = tdecl;
704 static void
705 aarch64_init_simd_builtin_scalar_types (void)
707 /* Define typedefs for all the standard scalar types. */
708 (*lang_hooks.types.register_builtin_type) (intQI_type_node,
709 "__builtin_aarch64_simd_qi");
710 (*lang_hooks.types.register_builtin_type) (intHI_type_node,
711 "__builtin_aarch64_simd_hi");
712 (*lang_hooks.types.register_builtin_type) (aarch64_fp16_type_node,
713 "__builtin_aarch64_simd_hf");
714 (*lang_hooks.types.register_builtin_type) (intSI_type_node,
715 "__builtin_aarch64_simd_si");
716 (*lang_hooks.types.register_builtin_type) (float_type_node,
717 "__builtin_aarch64_simd_sf");
718 (*lang_hooks.types.register_builtin_type) (intDI_type_node,
719 "__builtin_aarch64_simd_di");
720 (*lang_hooks.types.register_builtin_type) (double_type_node,
721 "__builtin_aarch64_simd_df");
722 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
723 "__builtin_aarch64_simd_poly8");
724 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
725 "__builtin_aarch64_simd_poly16");
726 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
727 "__builtin_aarch64_simd_poly64");
728 (*lang_hooks.types.register_builtin_type) (unsigned_intTI_type_node,
729 "__builtin_aarch64_simd_poly128");
730 (*lang_hooks.types.register_builtin_type) (intTI_type_node,
731 "__builtin_aarch64_simd_ti");
732 /* Unsigned integer types for various mode sizes. */
733 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
734 "__builtin_aarch64_simd_uqi");
735 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
736 "__builtin_aarch64_simd_uhi");
737 (*lang_hooks.types.register_builtin_type) (unsigned_intSI_type_node,
738 "__builtin_aarch64_simd_usi");
739 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
740 "__builtin_aarch64_simd_udi");
743 static bool aarch64_simd_builtins_initialized_p = false;
745 void
746 aarch64_init_simd_builtins (void)
748 unsigned int i, fcode = AARCH64_SIMD_PATTERN_START;
750 if (aarch64_simd_builtins_initialized_p)
751 return;
753 aarch64_simd_builtins_initialized_p = true;
755 aarch64_init_simd_builtin_types ();
757 /* Strong-typing hasn't been implemented for all AdvSIMD builtin intrinsics.
758 Therefore we need to preserve the old __builtin scalar types. It can be
759 removed once all the intrinsics become strongly typed using the qualifier
760 system. */
761 aarch64_init_simd_builtin_scalar_types ();
763 tree lane_check_fpr = build_function_type_list (void_type_node,
764 size_type_node,
765 size_type_node,
766 intSI_type_node,
767 NULL);
768 aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_LANE_CHECK] =
769 add_builtin_function ("__builtin_aarch64_im_lane_boundsi", lane_check_fpr,
770 AARCH64_SIMD_BUILTIN_LANE_CHECK, BUILT_IN_MD,
771 NULL, NULL_TREE);
773 for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++)
775 bool print_type_signature_p = false;
776 char type_signature[SIMD_MAX_BUILTIN_ARGS + 1] = { 0 };
777 aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i];
778 char namebuf[60];
779 tree ftype = NULL;
780 tree fndecl = NULL;
782 d->fcode = fcode;
784 /* We must track two variables here. op_num is
785 the operand number as in the RTL pattern. This is
786 required to access the mode (e.g. V4SF mode) of the
787 argument, from which the base type can be derived.
788 arg_num is an index in to the qualifiers data, which
789 gives qualifiers to the type (e.g. const unsigned).
790 The reason these two variables may differ by one is the
791 void return type. While all return types take the 0th entry
792 in the qualifiers array, there is no operand for them in the
793 RTL pattern. */
794 int op_num = insn_data[d->code].n_operands - 1;
795 int arg_num = d->qualifiers[0] & qualifier_void
796 ? op_num + 1
797 : op_num;
798 tree return_type = void_type_node, args = void_list_node;
799 tree eltype;
801 /* Build a function type directly from the insn_data for this
802 builtin. The build_function_type () function takes care of
803 removing duplicates for us. */
804 for (; op_num >= 0; arg_num--, op_num--)
806 machine_mode op_mode = insn_data[d->code].operand[op_num].mode;
807 enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num];
809 if (qualifiers & qualifier_unsigned)
811 type_signature[op_num] = 'u';
812 print_type_signature_p = true;
814 else if (qualifiers & qualifier_poly)
816 type_signature[op_num] = 'p';
817 print_type_signature_p = true;
819 else
820 type_signature[op_num] = 's';
822 /* Skip an internal operand for vget_{low, high}. */
823 if (qualifiers & qualifier_internal)
824 continue;
826 /* Some builtins have different user-facing types
827 for certain arguments, encoded in d->mode. */
828 if (qualifiers & qualifier_map_mode)
829 op_mode = d->mode;
831 /* For pointers, we want a pointer to the basic type
832 of the vector. */
833 if (qualifiers & qualifier_pointer && VECTOR_MODE_P (op_mode))
834 op_mode = GET_MODE_INNER (op_mode);
836 eltype = aarch64_simd_builtin_type
837 (op_mode,
838 (qualifiers & qualifier_unsigned) != 0,
839 (qualifiers & qualifier_poly) != 0);
840 gcc_assert (eltype != NULL);
842 /* Add qualifiers. */
843 if (qualifiers & qualifier_const)
844 eltype = build_qualified_type (eltype, TYPE_QUAL_CONST);
846 if (qualifiers & qualifier_pointer)
847 eltype = build_pointer_type (eltype);
849 /* If we have reached arg_num == 0, we are at a non-void
850 return type. Otherwise, we are still processing
851 arguments. */
852 if (arg_num == 0)
853 return_type = eltype;
854 else
855 args = tree_cons (NULL_TREE, eltype, args);
858 ftype = build_function_type (return_type, args);
860 gcc_assert (ftype != NULL);
862 if (print_type_signature_p)
863 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s_%s",
864 d->name, type_signature);
865 else
866 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s",
867 d->name);
869 fndecl = add_builtin_function (namebuf, ftype, fcode, BUILT_IN_MD,
870 NULL, NULL_TREE);
871 aarch64_builtin_decls[fcode] = fndecl;
875 static void
876 aarch64_init_crc32_builtins ()
878 tree usi_type = aarch64_simd_builtin_std_type (SImode, qualifier_unsigned);
879 unsigned int i = 0;
881 for (i = 0; i < ARRAY_SIZE (aarch64_crc_builtin_data); ++i)
883 aarch64_crc_builtin_datum* d = &aarch64_crc_builtin_data[i];
884 tree argtype = aarch64_simd_builtin_std_type (d->mode,
885 qualifier_unsigned);
886 tree ftype = build_function_type_list (usi_type, usi_type, argtype, NULL_TREE);
887 tree fndecl = add_builtin_function (d->name, ftype, d->fcode,
888 BUILT_IN_MD, NULL, NULL_TREE);
890 aarch64_builtin_decls[d->fcode] = fndecl;
894 /* Add builtins for reciprocal square root. */
896 void
897 aarch64_init_builtin_rsqrt (void)
899 tree fndecl = NULL;
900 tree ftype = NULL;
902 tree V2SF_type_node = build_vector_type (float_type_node, 2);
903 tree V2DF_type_node = build_vector_type (double_type_node, 2);
904 tree V4SF_type_node = build_vector_type (float_type_node, 4);
906 struct builtin_decls_data
908 tree type_node;
909 const char *builtin_name;
910 int function_code;
913 builtin_decls_data bdda[] =
915 { double_type_node, "__builtin_aarch64_rsqrt_df", AARCH64_BUILTIN_RSQRT_DF },
916 { float_type_node, "__builtin_aarch64_rsqrt_sf", AARCH64_BUILTIN_RSQRT_SF },
917 { V2DF_type_node, "__builtin_aarch64_rsqrt_v2df", AARCH64_BUILTIN_RSQRT_V2DF },
918 { V2SF_type_node, "__builtin_aarch64_rsqrt_v2sf", AARCH64_BUILTIN_RSQRT_V2SF },
919 { V4SF_type_node, "__builtin_aarch64_rsqrt_v4sf", AARCH64_BUILTIN_RSQRT_V4SF }
922 builtin_decls_data *bdd = bdda;
923 builtin_decls_data *bdd_end = bdd + (sizeof (bdda) / sizeof (builtin_decls_data));
925 for (; bdd < bdd_end; bdd++)
927 ftype = build_function_type_list (bdd->type_node, bdd->type_node, NULL_TREE);
928 fndecl = add_builtin_function (bdd->builtin_name,
929 ftype, bdd->function_code, BUILT_IN_MD, NULL, NULL_TREE);
930 aarch64_builtin_decls[bdd->function_code] = fndecl;
934 /* Initialize the backend types that support the user-visible __fp16
935 type, also initialize a pointer to that type, to be used when
936 forming HFAs. */
938 static void
939 aarch64_init_fp16_types (void)
941 aarch64_fp16_type_node = make_node (REAL_TYPE);
942 TYPE_PRECISION (aarch64_fp16_type_node) = 16;
943 layout_type (aarch64_fp16_type_node);
945 (*lang_hooks.types.register_builtin_type) (aarch64_fp16_type_node, "__fp16");
946 aarch64_fp16_ptr_type_node = build_pointer_type (aarch64_fp16_type_node);
949 /* Pointer authentication builtins that will become NOP on legacy platform.
950 Currently, these builtins are for internal use only (libgcc EH unwinder). */
952 void
953 aarch64_init_pauth_hint_builtins (void)
955 /* Pointer Authentication builtins. */
956 tree ftype_pointer_auth
957 = build_function_type_list (ptr_type_node, ptr_type_node,
958 unsigned_intDI_type_node, NULL_TREE);
959 tree ftype_pointer_strip
960 = build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE);
962 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_AUTIA1716]
963 = add_builtin_function ("__builtin_aarch64_autia1716", ftype_pointer_auth,
964 AARCH64_PAUTH_BUILTIN_AUTIA1716, BUILT_IN_MD, NULL,
965 NULL_TREE);
966 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_PACIA1716]
967 = add_builtin_function ("__builtin_aarch64_pacia1716", ftype_pointer_auth,
968 AARCH64_PAUTH_BUILTIN_PACIA1716, BUILT_IN_MD, NULL,
969 NULL_TREE);
970 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_XPACLRI]
971 = add_builtin_function ("__builtin_aarch64_xpaclri", ftype_pointer_strip,
972 AARCH64_PAUTH_BUILTIN_XPACLRI, BUILT_IN_MD, NULL,
973 NULL_TREE);
976 void
977 aarch64_init_builtins (void)
979 tree ftype_set_fpr
980 = build_function_type_list (void_type_node, unsigned_type_node, NULL);
981 tree ftype_get_fpr
982 = build_function_type_list (unsigned_type_node, NULL);
984 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR]
985 = add_builtin_function ("__builtin_aarch64_get_fpcr", ftype_get_fpr,
986 AARCH64_BUILTIN_GET_FPCR, BUILT_IN_MD, NULL, NULL_TREE);
987 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR]
988 = add_builtin_function ("__builtin_aarch64_set_fpcr", ftype_set_fpr,
989 AARCH64_BUILTIN_SET_FPCR, BUILT_IN_MD, NULL, NULL_TREE);
990 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR]
991 = add_builtin_function ("__builtin_aarch64_get_fpsr", ftype_get_fpr,
992 AARCH64_BUILTIN_GET_FPSR, BUILT_IN_MD, NULL, NULL_TREE);
993 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR]
994 = add_builtin_function ("__builtin_aarch64_set_fpsr", ftype_set_fpr,
995 AARCH64_BUILTIN_SET_FPSR, BUILT_IN_MD, NULL, NULL_TREE);
997 aarch64_init_fp16_types ();
999 if (TARGET_SIMD)
1000 aarch64_init_simd_builtins ();
1002 aarch64_init_crc32_builtins ();
1003 aarch64_init_builtin_rsqrt ();
1005 /* Initialize pointer authentication builtins which are backed by instructions
1006 in NOP encoding space.
1008 NOTE: these builtins are supposed to be used by libgcc unwinder only, as
1009 there is no support on return address signing under ILP32, we don't
1010 register them. */
1011 if (!TARGET_ILP32)
1012 aarch64_init_pauth_hint_builtins ();
1015 tree
1016 aarch64_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
1018 if (code >= AARCH64_BUILTIN_MAX)
1019 return error_mark_node;
1021 return aarch64_builtin_decls[code];
1024 typedef enum
1026 SIMD_ARG_COPY_TO_REG,
1027 SIMD_ARG_CONSTANT,
1028 SIMD_ARG_LANE_INDEX,
1029 SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX,
1030 SIMD_ARG_STOP
1031 } builtin_simd_arg;
1034 static rtx
1035 aarch64_simd_expand_args (rtx target, int icode, int have_retval,
1036 tree exp, builtin_simd_arg *args,
1037 machine_mode builtin_mode)
1039 rtx pat;
1040 rtx op[SIMD_MAX_BUILTIN_ARGS + 1]; /* First element for result operand. */
1041 int opc = 0;
1043 if (have_retval)
1045 machine_mode tmode = insn_data[icode].operand[0].mode;
1046 if (!target
1047 || GET_MODE (target) != tmode
1048 || !(*insn_data[icode].operand[0].predicate) (target, tmode))
1049 target = gen_reg_rtx (tmode);
1050 op[opc++] = target;
1053 for (;;)
1055 builtin_simd_arg thisarg = args[opc - have_retval];
1057 if (thisarg == SIMD_ARG_STOP)
1058 break;
1059 else
1061 tree arg = CALL_EXPR_ARG (exp, opc - have_retval);
1062 machine_mode mode = insn_data[icode].operand[opc].mode;
1063 op[opc] = expand_normal (arg);
1065 switch (thisarg)
1067 case SIMD_ARG_COPY_TO_REG:
1068 if (POINTER_TYPE_P (TREE_TYPE (arg)))
1069 op[opc] = convert_memory_address (Pmode, op[opc]);
1070 /*gcc_assert (GET_MODE (op[opc]) == mode); */
1071 if (!(*insn_data[icode].operand[opc].predicate)
1072 (op[opc], mode))
1073 op[opc] = copy_to_mode_reg (mode, op[opc]);
1074 break;
1076 case SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX:
1077 gcc_assert (opc > 1);
1078 if (CONST_INT_P (op[opc]))
1080 unsigned int nunits
1081 = GET_MODE_NUNITS (builtin_mode).to_constant ();
1082 aarch64_simd_lane_bounds (op[opc], 0, nunits, exp);
1083 /* Keep to GCC-vector-extension lane indices in the RTL. */
1084 op[opc] = aarch64_endian_lane_rtx (builtin_mode,
1085 INTVAL (op[opc]));
1087 goto constant_arg;
1089 case SIMD_ARG_LANE_INDEX:
1090 /* Must be a previous operand into which this is an index. */
1091 gcc_assert (opc > 0);
1092 if (CONST_INT_P (op[opc]))
1094 machine_mode vmode = insn_data[icode].operand[opc - 1].mode;
1095 unsigned int nunits
1096 = GET_MODE_NUNITS (vmode).to_constant ();
1097 aarch64_simd_lane_bounds (op[opc], 0, nunits, exp);
1098 /* Keep to GCC-vector-extension lane indices in the RTL. */
1099 op[opc] = aarch64_endian_lane_rtx (vmode, INTVAL (op[opc]));
1101 /* Fall through - if the lane index isn't a constant then
1102 the next case will error. */
1103 /* FALLTHRU */
1104 case SIMD_ARG_CONSTANT:
1105 constant_arg:
1106 if (!(*insn_data[icode].operand[opc].predicate)
1107 (op[opc], mode))
1109 error ("%Kargument %d must be a constant immediate",
1110 exp, opc + 1 - have_retval);
1111 return const0_rtx;
1113 break;
1115 case SIMD_ARG_STOP:
1116 gcc_unreachable ();
1119 opc++;
1123 switch (opc)
1125 case 1:
1126 pat = GEN_FCN (icode) (op[0]);
1127 break;
1129 case 2:
1130 pat = GEN_FCN (icode) (op[0], op[1]);
1131 break;
1133 case 3:
1134 pat = GEN_FCN (icode) (op[0], op[1], op[2]);
1135 break;
1137 case 4:
1138 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
1139 break;
1141 case 5:
1142 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
1143 break;
1145 case 6:
1146 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]);
1147 break;
1149 default:
1150 gcc_unreachable ();
1153 if (!pat)
1154 return NULL_RTX;
1156 emit_insn (pat);
1158 return target;
1161 /* Expand an AArch64 AdvSIMD builtin(intrinsic). */
1163 aarch64_simd_expand_builtin (int fcode, tree exp, rtx target)
1165 if (fcode == AARCH64_SIMD_BUILTIN_LANE_CHECK)
1167 rtx totalsize = expand_normal (CALL_EXPR_ARG (exp, 0));
1168 rtx elementsize = expand_normal (CALL_EXPR_ARG (exp, 1));
1169 if (CONST_INT_P (totalsize) && CONST_INT_P (elementsize)
1170 && UINTVAL (elementsize) != 0
1171 && UINTVAL (totalsize) != 0)
1173 rtx lane_idx = expand_normal (CALL_EXPR_ARG (exp, 2));
1174 if (CONST_INT_P (lane_idx))
1175 aarch64_simd_lane_bounds (lane_idx, 0,
1176 UINTVAL (totalsize)
1177 / UINTVAL (elementsize),
1178 exp);
1179 else
1180 error ("%Klane index must be a constant immediate", exp);
1182 else
1183 error ("%Ktotal size and element size must be a non-zero constant immediate", exp);
1184 /* Don't generate any RTL. */
1185 return const0_rtx;
1187 aarch64_simd_builtin_datum *d =
1188 &aarch64_simd_builtin_data[fcode - AARCH64_SIMD_PATTERN_START];
1189 enum insn_code icode = d->code;
1190 builtin_simd_arg args[SIMD_MAX_BUILTIN_ARGS + 1];
1191 int num_args = insn_data[d->code].n_operands;
1192 int is_void = 0;
1193 int k;
1195 is_void = !!(d->qualifiers[0] & qualifier_void);
1197 num_args += is_void;
1199 for (k = 1; k < num_args; k++)
1201 /* We have four arrays of data, each indexed in a different fashion.
1202 qualifiers - element 0 always describes the function return type.
1203 operands - element 0 is either the operand for return value (if
1204 the function has a non-void return type) or the operand for the
1205 first argument.
1206 expr_args - element 0 always holds the first argument.
1207 args - element 0 is always used for the return type. */
1208 int qualifiers_k = k;
1209 int operands_k = k - is_void;
1210 int expr_args_k = k - 1;
1212 if (d->qualifiers[qualifiers_k] & qualifier_lane_index)
1213 args[k] = SIMD_ARG_LANE_INDEX;
1214 else if (d->qualifiers[qualifiers_k] & qualifier_struct_load_store_lane_index)
1215 args[k] = SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX;
1216 else if (d->qualifiers[qualifiers_k] & qualifier_immediate)
1217 args[k] = SIMD_ARG_CONSTANT;
1218 else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate)
1220 rtx arg
1221 = expand_normal (CALL_EXPR_ARG (exp,
1222 (expr_args_k)));
1223 /* Handle constants only if the predicate allows it. */
1224 bool op_const_int_p =
1225 (CONST_INT_P (arg)
1226 && (*insn_data[icode].operand[operands_k].predicate)
1227 (arg, insn_data[icode].operand[operands_k].mode));
1228 args[k] = op_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG;
1230 else
1231 args[k] = SIMD_ARG_COPY_TO_REG;
1234 args[k] = SIMD_ARG_STOP;
1236 /* The interface to aarch64_simd_expand_args expects a 0 if
1237 the function is void, and a 1 if it is not. */
1238 return aarch64_simd_expand_args
1239 (target, icode, !is_void, exp, &args[1], d->mode);
1243 aarch64_crc32_expand_builtin (int fcode, tree exp, rtx target)
1245 rtx pat;
1246 aarch64_crc_builtin_datum *d
1247 = &aarch64_crc_builtin_data[fcode - (AARCH64_CRC32_BUILTIN_BASE + 1)];
1248 enum insn_code icode = d->icode;
1249 tree arg0 = CALL_EXPR_ARG (exp, 0);
1250 tree arg1 = CALL_EXPR_ARG (exp, 1);
1251 rtx op0 = expand_normal (arg0);
1252 rtx op1 = expand_normal (arg1);
1253 machine_mode tmode = insn_data[icode].operand[0].mode;
1254 machine_mode mode0 = insn_data[icode].operand[1].mode;
1255 machine_mode mode1 = insn_data[icode].operand[2].mode;
1257 if (! target
1258 || GET_MODE (target) != tmode
1259 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1260 target = gen_reg_rtx (tmode);
1262 gcc_assert ((GET_MODE (op0) == mode0 || GET_MODE (op0) == VOIDmode)
1263 && (GET_MODE (op1) == mode1 || GET_MODE (op1) == VOIDmode));
1265 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1266 op0 = copy_to_mode_reg (mode0, op0);
1267 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
1268 op1 = copy_to_mode_reg (mode1, op1);
1270 pat = GEN_FCN (icode) (target, op0, op1);
1271 if (!pat)
1272 return NULL_RTX;
1274 emit_insn (pat);
1275 return target;
1278 /* Function to expand reciprocal square root builtins. */
1280 static rtx
1281 aarch64_expand_builtin_rsqrt (int fcode, tree exp, rtx target)
1283 tree arg0 = CALL_EXPR_ARG (exp, 0);
1284 rtx op0 = expand_normal (arg0);
1286 rtx (*gen) (rtx, rtx);
1288 switch (fcode)
1290 case AARCH64_BUILTIN_RSQRT_DF:
1291 gen = gen_rsqrtdf2;
1292 break;
1293 case AARCH64_BUILTIN_RSQRT_SF:
1294 gen = gen_rsqrtsf2;
1295 break;
1296 case AARCH64_BUILTIN_RSQRT_V2DF:
1297 gen = gen_rsqrtv2df2;
1298 break;
1299 case AARCH64_BUILTIN_RSQRT_V2SF:
1300 gen = gen_rsqrtv2sf2;
1301 break;
1302 case AARCH64_BUILTIN_RSQRT_V4SF:
1303 gen = gen_rsqrtv4sf2;
1304 break;
1305 default: gcc_unreachable ();
1308 if (!target)
1309 target = gen_reg_rtx (GET_MODE (op0));
1311 emit_insn (gen (target, op0));
1313 return target;
1316 /* Expand an expression EXP that calls a built-in function,
1317 with result going to TARGET if that's convenient. */
1319 aarch64_expand_builtin (tree exp,
1320 rtx target,
1321 rtx subtarget ATTRIBUTE_UNUSED,
1322 machine_mode mode ATTRIBUTE_UNUSED,
1323 int ignore ATTRIBUTE_UNUSED)
1325 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
1326 int fcode = DECL_FUNCTION_CODE (fndecl);
1327 int icode;
1328 rtx pat, op0;
1329 tree arg0;
1331 switch (fcode)
1333 case AARCH64_BUILTIN_GET_FPCR:
1334 case AARCH64_BUILTIN_SET_FPCR:
1335 case AARCH64_BUILTIN_GET_FPSR:
1336 case AARCH64_BUILTIN_SET_FPSR:
1337 if ((fcode == AARCH64_BUILTIN_GET_FPCR)
1338 || (fcode == AARCH64_BUILTIN_GET_FPSR))
1340 icode = (fcode == AARCH64_BUILTIN_GET_FPSR) ?
1341 CODE_FOR_get_fpsr : CODE_FOR_get_fpcr;
1342 target = gen_reg_rtx (SImode);
1343 pat = GEN_FCN (icode) (target);
1345 else
1347 target = NULL_RTX;
1348 icode = (fcode == AARCH64_BUILTIN_SET_FPSR) ?
1349 CODE_FOR_set_fpsr : CODE_FOR_set_fpcr;
1350 arg0 = CALL_EXPR_ARG (exp, 0);
1351 op0 = force_reg (SImode, expand_normal (arg0));
1352 pat = GEN_FCN (icode) (op0);
1354 emit_insn (pat);
1355 return target;
1357 case AARCH64_PAUTH_BUILTIN_AUTIA1716:
1358 case AARCH64_PAUTH_BUILTIN_PACIA1716:
1359 case AARCH64_PAUTH_BUILTIN_XPACLRI:
1360 arg0 = CALL_EXPR_ARG (exp, 0);
1361 op0 = force_reg (Pmode, expand_normal (arg0));
1363 if (!target)
1364 target = gen_reg_rtx (Pmode);
1365 else
1366 target = force_reg (Pmode, target);
1368 emit_move_insn (target, op0);
1370 if (fcode == AARCH64_PAUTH_BUILTIN_XPACLRI)
1372 rtx lr = gen_rtx_REG (Pmode, R30_REGNUM);
1373 icode = CODE_FOR_xpaclri;
1374 emit_move_insn (lr, op0);
1375 emit_insn (GEN_FCN (icode) ());
1376 emit_move_insn (target, lr);
1378 else
1380 tree arg1 = CALL_EXPR_ARG (exp, 1);
1381 rtx op1 = force_reg (Pmode, expand_normal (arg1));
1382 icode = (fcode == AARCH64_PAUTH_BUILTIN_PACIA1716
1383 ? CODE_FOR_paci1716 : CODE_FOR_auti1716);
1385 rtx x16_reg = gen_rtx_REG (Pmode, R16_REGNUM);
1386 rtx x17_reg = gen_rtx_REG (Pmode, R17_REGNUM);
1387 emit_move_insn (x17_reg, op0);
1388 emit_move_insn (x16_reg, op1);
1389 emit_insn (GEN_FCN (icode) ());
1390 emit_move_insn (target, x17_reg);
1393 return target;
1396 if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
1397 return aarch64_simd_expand_builtin (fcode, exp, target);
1398 else if (fcode >= AARCH64_CRC32_BUILTIN_BASE && fcode <= AARCH64_CRC32_BUILTIN_MAX)
1399 return aarch64_crc32_expand_builtin (fcode, exp, target);
1401 if (fcode == AARCH64_BUILTIN_RSQRT_DF
1402 || fcode == AARCH64_BUILTIN_RSQRT_SF
1403 || fcode == AARCH64_BUILTIN_RSQRT_V2DF
1404 || fcode == AARCH64_BUILTIN_RSQRT_V2SF
1405 || fcode == AARCH64_BUILTIN_RSQRT_V4SF)
1406 return aarch64_expand_builtin_rsqrt (fcode, exp, target);
1408 gcc_unreachable ();
1411 tree
1412 aarch64_builtin_vectorized_function (unsigned int fn, tree type_out,
1413 tree type_in)
1415 machine_mode in_mode, out_mode;
1416 unsigned HOST_WIDE_INT in_n, out_n;
1418 if (TREE_CODE (type_out) != VECTOR_TYPE
1419 || TREE_CODE (type_in) != VECTOR_TYPE)
1420 return NULL_TREE;
1422 out_mode = TYPE_MODE (TREE_TYPE (type_out));
1423 in_mode = TYPE_MODE (TREE_TYPE (type_in));
1424 if (!TYPE_VECTOR_SUBPARTS (type_out).is_constant (&out_n)
1425 || !TYPE_VECTOR_SUBPARTS (type_in).is_constant (&in_n))
1426 return NULL_TREE;
1428 #undef AARCH64_CHECK_BUILTIN_MODE
1429 #define AARCH64_CHECK_BUILTIN_MODE(C, N) 1
1430 #define AARCH64_FIND_FRINT_VARIANT(N) \
1431 (AARCH64_CHECK_BUILTIN_MODE (2, D) \
1432 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2df] \
1433 : (AARCH64_CHECK_BUILTIN_MODE (4, S) \
1434 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v4sf] \
1435 : (AARCH64_CHECK_BUILTIN_MODE (2, S) \
1436 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2sf] \
1437 : NULL_TREE)))
1438 switch (fn)
1440 #undef AARCH64_CHECK_BUILTIN_MODE
1441 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1442 (out_mode == N##Fmode && out_n == C \
1443 && in_mode == N##Fmode && in_n == C)
1444 CASE_CFN_FLOOR:
1445 return AARCH64_FIND_FRINT_VARIANT (floor);
1446 CASE_CFN_CEIL:
1447 return AARCH64_FIND_FRINT_VARIANT (ceil);
1448 CASE_CFN_TRUNC:
1449 return AARCH64_FIND_FRINT_VARIANT (btrunc);
1450 CASE_CFN_ROUND:
1451 return AARCH64_FIND_FRINT_VARIANT (round);
1452 CASE_CFN_NEARBYINT:
1453 return AARCH64_FIND_FRINT_VARIANT (nearbyint);
1454 CASE_CFN_SQRT:
1455 return AARCH64_FIND_FRINT_VARIANT (sqrt);
1456 #undef AARCH64_CHECK_BUILTIN_MODE
1457 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1458 (out_mode == SImode && out_n == C \
1459 && in_mode == N##Imode && in_n == C)
1460 CASE_CFN_CLZ:
1462 if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1463 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_clzv4si];
1464 return NULL_TREE;
1466 CASE_CFN_CTZ:
1468 if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1469 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv2si];
1470 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1471 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv4si];
1472 return NULL_TREE;
1474 #undef AARCH64_CHECK_BUILTIN_MODE
1475 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1476 (out_mode == N##Imode && out_n == C \
1477 && in_mode == N##Fmode && in_n == C)
1478 CASE_CFN_IFLOOR:
1479 CASE_CFN_LFLOOR:
1480 CASE_CFN_LLFLOOR:
1482 enum aarch64_builtins builtin;
1483 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1484 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2dfv2di;
1485 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1486 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv4sfv4si;
1487 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1488 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2sfv2si;
1489 else
1490 return NULL_TREE;
1492 return aarch64_builtin_decls[builtin];
1494 CASE_CFN_ICEIL:
1495 CASE_CFN_LCEIL:
1496 CASE_CFN_LLCEIL:
1498 enum aarch64_builtins builtin;
1499 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1500 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2dfv2di;
1501 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1502 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv4sfv4si;
1503 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1504 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2sfv2si;
1505 else
1506 return NULL_TREE;
1508 return aarch64_builtin_decls[builtin];
1510 CASE_CFN_IROUND:
1511 CASE_CFN_LROUND:
1512 CASE_CFN_LLROUND:
1514 enum aarch64_builtins builtin;
1515 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1516 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2dfv2di;
1517 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1518 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv4sfv4si;
1519 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1520 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2sfv2si;
1521 else
1522 return NULL_TREE;
1524 return aarch64_builtin_decls[builtin];
1526 case CFN_BUILT_IN_BSWAP16:
1527 #undef AARCH64_CHECK_BUILTIN_MODE
1528 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1529 (out_mode == N##Imode && out_n == C \
1530 && in_mode == N##Imode && in_n == C)
1531 if (AARCH64_CHECK_BUILTIN_MODE (4, H))
1532 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4hi];
1533 else if (AARCH64_CHECK_BUILTIN_MODE (8, H))
1534 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv8hi];
1535 else
1536 return NULL_TREE;
1537 case CFN_BUILT_IN_BSWAP32:
1538 if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1539 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2si];
1540 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1541 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4si];
1542 else
1543 return NULL_TREE;
1544 case CFN_BUILT_IN_BSWAP64:
1545 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1546 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2di];
1547 else
1548 return NULL_TREE;
1549 default:
1550 return NULL_TREE;
1553 return NULL_TREE;
1556 /* Return builtin for reciprocal square root. */
1558 tree
1559 aarch64_builtin_rsqrt (unsigned int fn)
1561 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv2df)
1562 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V2DF];
1563 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv2sf)
1564 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V2SF];
1565 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv4sf)
1566 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V4SF];
1567 return NULL_TREE;
1570 #undef VAR1
1571 #define VAR1(T, N, MAP, A) \
1572 case AARCH64_SIMD_BUILTIN_##T##_##N##A:
1574 tree
1575 aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args,
1576 bool ignore ATTRIBUTE_UNUSED)
1578 int fcode = DECL_FUNCTION_CODE (fndecl);
1579 tree type = TREE_TYPE (TREE_TYPE (fndecl));
1581 switch (fcode)
1583 BUILTIN_VDQF (UNOP, abs, 2)
1584 return fold_build1 (ABS_EXPR, type, args[0]);
1585 VAR1 (UNOP, floatv2si, 2, v2sf)
1586 VAR1 (UNOP, floatv4si, 2, v4sf)
1587 VAR1 (UNOP, floatv2di, 2, v2df)
1588 return fold_build1 (FLOAT_EXPR, type, args[0]);
1589 default:
1590 break;
1593 return NULL_TREE;
1596 bool
1597 aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi)
1599 bool changed = false;
1600 gimple *stmt = gsi_stmt (*gsi);
1601 tree call = gimple_call_fn (stmt);
1602 tree fndecl;
1603 gimple *new_stmt = NULL;
1605 if (call)
1607 fndecl = gimple_call_fndecl (stmt);
1608 if (fndecl)
1610 int fcode = DECL_FUNCTION_CODE (fndecl);
1611 unsigned nargs = gimple_call_num_args (stmt);
1612 tree *args = (nargs > 0
1613 ? gimple_call_arg_ptr (stmt, 0)
1614 : &error_mark_node);
1616 /* We use gimple's IFN_REDUC_(PLUS|MIN|MAX)s for float, signed int
1617 and unsigned int; it will distinguish according to the types of
1618 the arguments to the __builtin. */
1619 switch (fcode)
1621 BUILTIN_VALL (UNOP, reduc_plus_scal_, 10)
1622 new_stmt = gimple_build_call_internal (IFN_REDUC_PLUS,
1623 1, args[0]);
1624 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
1625 break;
1626 BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10)
1627 BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10)
1628 new_stmt = gimple_build_call_internal (IFN_REDUC_MAX,
1629 1, args[0]);
1630 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
1631 break;
1632 BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10)
1633 BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10)
1634 new_stmt = gimple_build_call_internal (IFN_REDUC_MIN,
1635 1, args[0]);
1636 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
1637 break;
1638 BUILTIN_GPF (BINOP, fmulx, 0)
1640 gcc_assert (nargs == 2);
1641 bool a0_cst_p = TREE_CODE (args[0]) == REAL_CST;
1642 bool a1_cst_p = TREE_CODE (args[1]) == REAL_CST;
1643 if (a0_cst_p || a1_cst_p)
1645 if (a0_cst_p && a1_cst_p)
1647 tree t0 = TREE_TYPE (args[0]);
1648 real_value a0 = (TREE_REAL_CST (args[0]));
1649 real_value a1 = (TREE_REAL_CST (args[1]));
1650 if (real_equal (&a1, &dconst0))
1651 std::swap (a0, a1);
1652 /* According to real_equal (), +0 equals -0. */
1653 if (real_equal (&a0, &dconst0) && real_isinf (&a1))
1655 real_value res = dconst2;
1656 res.sign = a0.sign ^ a1.sign;
1657 new_stmt =
1658 gimple_build_assign (gimple_call_lhs (stmt),
1659 REAL_CST,
1660 build_real (t0, res));
1662 else
1663 new_stmt =
1664 gimple_build_assign (gimple_call_lhs (stmt),
1665 MULT_EXPR,
1666 args[0], args[1]);
1668 else /* a0_cst_p ^ a1_cst_p. */
1670 real_value const_part = a0_cst_p
1671 ? TREE_REAL_CST (args[0]) : TREE_REAL_CST (args[1]);
1672 if (!real_equal (&const_part, &dconst0)
1673 && !real_isinf (&const_part))
1674 new_stmt =
1675 gimple_build_assign (gimple_call_lhs (stmt),
1676 MULT_EXPR, args[0], args[1]);
1679 if (new_stmt)
1681 gimple_set_vuse (new_stmt, gimple_vuse (stmt));
1682 gimple_set_vdef (new_stmt, gimple_vdef (stmt));
1684 break;
1686 default:
1687 break;
1692 if (new_stmt)
1694 gsi_replace (gsi, new_stmt, true);
1695 changed = true;
1698 return changed;
1701 void
1702 aarch64_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
1704 const unsigned AARCH64_FE_INVALID = 1;
1705 const unsigned AARCH64_FE_DIVBYZERO = 2;
1706 const unsigned AARCH64_FE_OVERFLOW = 4;
1707 const unsigned AARCH64_FE_UNDERFLOW = 8;
1708 const unsigned AARCH64_FE_INEXACT = 16;
1709 const unsigned HOST_WIDE_INT AARCH64_FE_ALL_EXCEPT = (AARCH64_FE_INVALID
1710 | AARCH64_FE_DIVBYZERO
1711 | AARCH64_FE_OVERFLOW
1712 | AARCH64_FE_UNDERFLOW
1713 | AARCH64_FE_INEXACT);
1714 const unsigned HOST_WIDE_INT AARCH64_FE_EXCEPT_SHIFT = 8;
1715 tree fenv_cr, fenv_sr, get_fpcr, set_fpcr, mask_cr, mask_sr;
1716 tree ld_fenv_cr, ld_fenv_sr, masked_fenv_cr, masked_fenv_sr, hold_fnclex_cr;
1717 tree hold_fnclex_sr, new_fenv_var, reload_fenv, restore_fnenv, get_fpsr, set_fpsr;
1718 tree update_call, atomic_feraiseexcept, hold_fnclex, masked_fenv, ld_fenv;
1720 /* Generate the equivalence of :
1721 unsigned int fenv_cr;
1722 fenv_cr = __builtin_aarch64_get_fpcr ();
1724 unsigned int fenv_sr;
1725 fenv_sr = __builtin_aarch64_get_fpsr ();
1727 Now set all exceptions to non-stop
1728 unsigned int mask_cr
1729 = ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT);
1730 unsigned int masked_cr;
1731 masked_cr = fenv_cr & mask_cr;
1733 And clear all exception flags
1734 unsigned int maske_sr = ~AARCH64_FE_ALL_EXCEPT;
1735 unsigned int masked_cr;
1736 masked_sr = fenv_sr & mask_sr;
1738 __builtin_aarch64_set_cr (masked_cr);
1739 __builtin_aarch64_set_sr (masked_sr); */
1741 fenv_cr = create_tmp_var_raw (unsigned_type_node);
1742 fenv_sr = create_tmp_var_raw (unsigned_type_node);
1744 get_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR];
1745 set_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR];
1746 get_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR];
1747 set_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR];
1749 mask_cr = build_int_cst (unsigned_type_node,
1750 ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT));
1751 mask_sr = build_int_cst (unsigned_type_node,
1752 ~(AARCH64_FE_ALL_EXCEPT));
1754 ld_fenv_cr = build2 (MODIFY_EXPR, unsigned_type_node,
1755 fenv_cr, build_call_expr (get_fpcr, 0));
1756 ld_fenv_sr = build2 (MODIFY_EXPR, unsigned_type_node,
1757 fenv_sr, build_call_expr (get_fpsr, 0));
1759 masked_fenv_cr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_cr, mask_cr);
1760 masked_fenv_sr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_sr, mask_sr);
1762 hold_fnclex_cr = build_call_expr (set_fpcr, 1, masked_fenv_cr);
1763 hold_fnclex_sr = build_call_expr (set_fpsr, 1, masked_fenv_sr);
1765 hold_fnclex = build2 (COMPOUND_EXPR, void_type_node, hold_fnclex_cr,
1766 hold_fnclex_sr);
1767 masked_fenv = build2 (COMPOUND_EXPR, void_type_node, masked_fenv_cr,
1768 masked_fenv_sr);
1769 ld_fenv = build2 (COMPOUND_EXPR, void_type_node, ld_fenv_cr, ld_fenv_sr);
1771 *hold = build2 (COMPOUND_EXPR, void_type_node,
1772 build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv),
1773 hold_fnclex);
1775 /* Store the value of masked_fenv to clear the exceptions:
1776 __builtin_aarch64_set_fpsr (masked_fenv_sr); */
1778 *clear = build_call_expr (set_fpsr, 1, masked_fenv_sr);
1780 /* Generate the equivalent of :
1781 unsigned int new_fenv_var;
1782 new_fenv_var = __builtin_aarch64_get_fpsr ();
1784 __builtin_aarch64_set_fpsr (fenv_sr);
1786 __atomic_feraiseexcept (new_fenv_var); */
1788 new_fenv_var = create_tmp_var_raw (unsigned_type_node);
1789 reload_fenv = build2 (MODIFY_EXPR, unsigned_type_node,
1790 new_fenv_var, build_call_expr (get_fpsr, 0));
1791 restore_fnenv = build_call_expr (set_fpsr, 1, fenv_sr);
1792 atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT);
1793 update_call = build_call_expr (atomic_feraiseexcept, 1,
1794 fold_convert (integer_type_node, new_fenv_var));
1795 *update = build2 (COMPOUND_EXPR, void_type_node,
1796 build2 (COMPOUND_EXPR, void_type_node,
1797 reload_fenv, restore_fnenv), update_call);
1801 #undef AARCH64_CHECK_BUILTIN_MODE
1802 #undef AARCH64_FIND_FRINT_VARIANT
1803 #undef CF0
1804 #undef CF1
1805 #undef CF2
1806 #undef CF3
1807 #undef CF4
1808 #undef CF10
1809 #undef VAR1
1810 #undef VAR2
1811 #undef VAR3
1812 #undef VAR4
1813 #undef VAR5
1814 #undef VAR6
1815 #undef VAR7
1816 #undef VAR8
1817 #undef VAR9
1818 #undef VAR10
1819 #undef VAR11
1821 #include "gt-aarch64-builtins.h"