PR tree-optimization/71625 - missing strlen optimization on different array
[official-gcc.git] / gcc / config / aarch64 / aarch64-builtins.c
blob8cced94567008e28b1761ec8771589a3925f2904
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 /* Prevent front-ends from transforming Poly8_t arrays into string
647 literals. */
648 TYPE_STRING_FLAG (aarch64_simd_types[Poly8_t].eltype) = false;
650 aarch64_simd_types[Poly16_t].eltype = aarch64_simd_types[Poly16_t].itype =
651 build_distinct_type_copy (unsigned_intHI_type_node);
652 aarch64_simd_types[Poly64_t].eltype = aarch64_simd_types[Poly64_t].itype =
653 build_distinct_type_copy (unsigned_intDI_type_node);
654 aarch64_simd_types[Poly128_t].eltype = aarch64_simd_types[Poly128_t].itype =
655 build_distinct_type_copy (unsigned_intTI_type_node);
656 /* Init poly vector element types with scalar poly types. */
657 aarch64_simd_types[Poly8x8_t].eltype = aarch64_simd_types[Poly8_t].itype;
658 aarch64_simd_types[Poly8x16_t].eltype = aarch64_simd_types[Poly8_t].itype;
659 aarch64_simd_types[Poly16x4_t].eltype = aarch64_simd_types[Poly16_t].itype;
660 aarch64_simd_types[Poly16x8_t].eltype = aarch64_simd_types[Poly16_t].itype;
661 aarch64_simd_types[Poly64x1_t].eltype = aarch64_simd_types[Poly64_t].itype;
662 aarch64_simd_types[Poly64x2_t].eltype = aarch64_simd_types[Poly64_t].itype;
664 /* Continue with standard types. */
665 aarch64_simd_types[Float16x4_t].eltype = aarch64_fp16_type_node;
666 aarch64_simd_types[Float16x8_t].eltype = aarch64_fp16_type_node;
667 aarch64_simd_types[Float32x2_t].eltype = float_type_node;
668 aarch64_simd_types[Float32x4_t].eltype = float_type_node;
669 aarch64_simd_types[Float64x1_t].eltype = double_type_node;
670 aarch64_simd_types[Float64x2_t].eltype = double_type_node;
672 for (i = 0; i < nelts; i++)
674 tree eltype = aarch64_simd_types[i].eltype;
675 machine_mode mode = aarch64_simd_types[i].mode;
677 if (aarch64_simd_types[i].itype == NULL)
679 aarch64_simd_types[i].itype
680 = build_distinct_type_copy
681 (build_vector_type (eltype, GET_MODE_NUNITS (mode)));
682 SET_TYPE_STRUCTURAL_EQUALITY (aarch64_simd_types[i].itype);
685 tdecl = add_builtin_type (aarch64_simd_types[i].name,
686 aarch64_simd_types[i].itype);
687 TYPE_NAME (aarch64_simd_types[i].itype) = tdecl;
690 #define AARCH64_BUILD_SIGNED_TYPE(mode) \
691 make_signed_type (GET_MODE_PRECISION (mode));
692 aarch64_simd_intOI_type_node = AARCH64_BUILD_SIGNED_TYPE (OImode);
693 aarch64_simd_intCI_type_node = AARCH64_BUILD_SIGNED_TYPE (CImode);
694 aarch64_simd_intXI_type_node = AARCH64_BUILD_SIGNED_TYPE (XImode);
695 #undef AARCH64_BUILD_SIGNED_TYPE
697 tdecl = add_builtin_type
698 ("__builtin_aarch64_simd_oi" , aarch64_simd_intOI_type_node);
699 TYPE_NAME (aarch64_simd_intOI_type_node) = tdecl;
700 tdecl = add_builtin_type
701 ("__builtin_aarch64_simd_ci" , aarch64_simd_intCI_type_node);
702 TYPE_NAME (aarch64_simd_intCI_type_node) = tdecl;
703 tdecl = add_builtin_type
704 ("__builtin_aarch64_simd_xi" , aarch64_simd_intXI_type_node);
705 TYPE_NAME (aarch64_simd_intXI_type_node) = tdecl;
708 static void
709 aarch64_init_simd_builtin_scalar_types (void)
711 /* Define typedefs for all the standard scalar types. */
712 (*lang_hooks.types.register_builtin_type) (intQI_type_node,
713 "__builtin_aarch64_simd_qi");
714 (*lang_hooks.types.register_builtin_type) (intHI_type_node,
715 "__builtin_aarch64_simd_hi");
716 (*lang_hooks.types.register_builtin_type) (aarch64_fp16_type_node,
717 "__builtin_aarch64_simd_hf");
718 (*lang_hooks.types.register_builtin_type) (intSI_type_node,
719 "__builtin_aarch64_simd_si");
720 (*lang_hooks.types.register_builtin_type) (float_type_node,
721 "__builtin_aarch64_simd_sf");
722 (*lang_hooks.types.register_builtin_type) (intDI_type_node,
723 "__builtin_aarch64_simd_di");
724 (*lang_hooks.types.register_builtin_type) (double_type_node,
725 "__builtin_aarch64_simd_df");
726 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
727 "__builtin_aarch64_simd_poly8");
728 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
729 "__builtin_aarch64_simd_poly16");
730 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
731 "__builtin_aarch64_simd_poly64");
732 (*lang_hooks.types.register_builtin_type) (unsigned_intTI_type_node,
733 "__builtin_aarch64_simd_poly128");
734 (*lang_hooks.types.register_builtin_type) (intTI_type_node,
735 "__builtin_aarch64_simd_ti");
736 /* Unsigned integer types for various mode sizes. */
737 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
738 "__builtin_aarch64_simd_uqi");
739 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
740 "__builtin_aarch64_simd_uhi");
741 (*lang_hooks.types.register_builtin_type) (unsigned_intSI_type_node,
742 "__builtin_aarch64_simd_usi");
743 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
744 "__builtin_aarch64_simd_udi");
747 static bool aarch64_simd_builtins_initialized_p = false;
749 void
750 aarch64_init_simd_builtins (void)
752 unsigned int i, fcode = AARCH64_SIMD_PATTERN_START;
754 if (aarch64_simd_builtins_initialized_p)
755 return;
757 aarch64_simd_builtins_initialized_p = true;
759 aarch64_init_simd_builtin_types ();
761 /* Strong-typing hasn't been implemented for all AdvSIMD builtin intrinsics.
762 Therefore we need to preserve the old __builtin scalar types. It can be
763 removed once all the intrinsics become strongly typed using the qualifier
764 system. */
765 aarch64_init_simd_builtin_scalar_types ();
767 tree lane_check_fpr = build_function_type_list (void_type_node,
768 size_type_node,
769 size_type_node,
770 intSI_type_node,
771 NULL);
772 aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_LANE_CHECK] =
773 add_builtin_function ("__builtin_aarch64_im_lane_boundsi", lane_check_fpr,
774 AARCH64_SIMD_BUILTIN_LANE_CHECK, BUILT_IN_MD,
775 NULL, NULL_TREE);
777 for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++)
779 bool print_type_signature_p = false;
780 char type_signature[SIMD_MAX_BUILTIN_ARGS + 1] = { 0 };
781 aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i];
782 char namebuf[60];
783 tree ftype = NULL;
784 tree fndecl = NULL;
786 d->fcode = fcode;
788 /* We must track two variables here. op_num is
789 the operand number as in the RTL pattern. This is
790 required to access the mode (e.g. V4SF mode) of the
791 argument, from which the base type can be derived.
792 arg_num is an index in to the qualifiers data, which
793 gives qualifiers to the type (e.g. const unsigned).
794 The reason these two variables may differ by one is the
795 void return type. While all return types take the 0th entry
796 in the qualifiers array, there is no operand for them in the
797 RTL pattern. */
798 int op_num = insn_data[d->code].n_operands - 1;
799 int arg_num = d->qualifiers[0] & qualifier_void
800 ? op_num + 1
801 : op_num;
802 tree return_type = void_type_node, args = void_list_node;
803 tree eltype;
805 /* Build a function type directly from the insn_data for this
806 builtin. The build_function_type () function takes care of
807 removing duplicates for us. */
808 for (; op_num >= 0; arg_num--, op_num--)
810 machine_mode op_mode = insn_data[d->code].operand[op_num].mode;
811 enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num];
813 if (qualifiers & qualifier_unsigned)
815 type_signature[op_num] = 'u';
816 print_type_signature_p = true;
818 else if (qualifiers & qualifier_poly)
820 type_signature[op_num] = 'p';
821 print_type_signature_p = true;
823 else
824 type_signature[op_num] = 's';
826 /* Skip an internal operand for vget_{low, high}. */
827 if (qualifiers & qualifier_internal)
828 continue;
830 /* Some builtins have different user-facing types
831 for certain arguments, encoded in d->mode. */
832 if (qualifiers & qualifier_map_mode)
833 op_mode = d->mode;
835 /* For pointers, we want a pointer to the basic type
836 of the vector. */
837 if (qualifiers & qualifier_pointer && VECTOR_MODE_P (op_mode))
838 op_mode = GET_MODE_INNER (op_mode);
840 eltype = aarch64_simd_builtin_type
841 (op_mode,
842 (qualifiers & qualifier_unsigned) != 0,
843 (qualifiers & qualifier_poly) != 0);
844 gcc_assert (eltype != NULL);
846 /* Add qualifiers. */
847 if (qualifiers & qualifier_const)
848 eltype = build_qualified_type (eltype, TYPE_QUAL_CONST);
850 if (qualifiers & qualifier_pointer)
851 eltype = build_pointer_type (eltype);
853 /* If we have reached arg_num == 0, we are at a non-void
854 return type. Otherwise, we are still processing
855 arguments. */
856 if (arg_num == 0)
857 return_type = eltype;
858 else
859 args = tree_cons (NULL_TREE, eltype, args);
862 ftype = build_function_type (return_type, args);
864 gcc_assert (ftype != NULL);
866 if (print_type_signature_p)
867 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s_%s",
868 d->name, type_signature);
869 else
870 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s",
871 d->name);
873 fndecl = add_builtin_function (namebuf, ftype, fcode, BUILT_IN_MD,
874 NULL, NULL_TREE);
875 aarch64_builtin_decls[fcode] = fndecl;
879 static void
880 aarch64_init_crc32_builtins ()
882 tree usi_type = aarch64_simd_builtin_std_type (SImode, qualifier_unsigned);
883 unsigned int i = 0;
885 for (i = 0; i < ARRAY_SIZE (aarch64_crc_builtin_data); ++i)
887 aarch64_crc_builtin_datum* d = &aarch64_crc_builtin_data[i];
888 tree argtype = aarch64_simd_builtin_std_type (d->mode,
889 qualifier_unsigned);
890 tree ftype = build_function_type_list (usi_type, usi_type, argtype, NULL_TREE);
891 tree fndecl = add_builtin_function (d->name, ftype, d->fcode,
892 BUILT_IN_MD, NULL, NULL_TREE);
894 aarch64_builtin_decls[d->fcode] = fndecl;
898 /* Add builtins for reciprocal square root. */
900 void
901 aarch64_init_builtin_rsqrt (void)
903 tree fndecl = NULL;
904 tree ftype = NULL;
906 tree V2SF_type_node = build_vector_type (float_type_node, 2);
907 tree V2DF_type_node = build_vector_type (double_type_node, 2);
908 tree V4SF_type_node = build_vector_type (float_type_node, 4);
910 struct builtin_decls_data
912 tree type_node;
913 const char *builtin_name;
914 int function_code;
917 builtin_decls_data bdda[] =
919 { double_type_node, "__builtin_aarch64_rsqrt_df", AARCH64_BUILTIN_RSQRT_DF },
920 { float_type_node, "__builtin_aarch64_rsqrt_sf", AARCH64_BUILTIN_RSQRT_SF },
921 { V2DF_type_node, "__builtin_aarch64_rsqrt_v2df", AARCH64_BUILTIN_RSQRT_V2DF },
922 { V2SF_type_node, "__builtin_aarch64_rsqrt_v2sf", AARCH64_BUILTIN_RSQRT_V2SF },
923 { V4SF_type_node, "__builtin_aarch64_rsqrt_v4sf", AARCH64_BUILTIN_RSQRT_V4SF }
926 builtin_decls_data *bdd = bdda;
927 builtin_decls_data *bdd_end = bdd + (sizeof (bdda) / sizeof (builtin_decls_data));
929 for (; bdd < bdd_end; bdd++)
931 ftype = build_function_type_list (bdd->type_node, bdd->type_node, NULL_TREE);
932 fndecl = add_builtin_function (bdd->builtin_name,
933 ftype, bdd->function_code, BUILT_IN_MD, NULL, NULL_TREE);
934 aarch64_builtin_decls[bdd->function_code] = fndecl;
938 /* Initialize the backend types that support the user-visible __fp16
939 type, also initialize a pointer to that type, to be used when
940 forming HFAs. */
942 static void
943 aarch64_init_fp16_types (void)
945 aarch64_fp16_type_node = make_node (REAL_TYPE);
946 TYPE_PRECISION (aarch64_fp16_type_node) = 16;
947 layout_type (aarch64_fp16_type_node);
949 (*lang_hooks.types.register_builtin_type) (aarch64_fp16_type_node, "__fp16");
950 aarch64_fp16_ptr_type_node = build_pointer_type (aarch64_fp16_type_node);
953 /* Pointer authentication builtins that will become NOP on legacy platform.
954 Currently, these builtins are for internal use only (libgcc EH unwinder). */
956 void
957 aarch64_init_pauth_hint_builtins (void)
959 /* Pointer Authentication builtins. */
960 tree ftype_pointer_auth
961 = build_function_type_list (ptr_type_node, ptr_type_node,
962 unsigned_intDI_type_node, NULL_TREE);
963 tree ftype_pointer_strip
964 = build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE);
966 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_AUTIA1716]
967 = add_builtin_function ("__builtin_aarch64_autia1716", ftype_pointer_auth,
968 AARCH64_PAUTH_BUILTIN_AUTIA1716, BUILT_IN_MD, NULL,
969 NULL_TREE);
970 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_PACIA1716]
971 = add_builtin_function ("__builtin_aarch64_pacia1716", ftype_pointer_auth,
972 AARCH64_PAUTH_BUILTIN_PACIA1716, BUILT_IN_MD, NULL,
973 NULL_TREE);
974 aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_XPACLRI]
975 = add_builtin_function ("__builtin_aarch64_xpaclri", ftype_pointer_strip,
976 AARCH64_PAUTH_BUILTIN_XPACLRI, BUILT_IN_MD, NULL,
977 NULL_TREE);
980 void
981 aarch64_init_builtins (void)
983 tree ftype_set_fpr
984 = build_function_type_list (void_type_node, unsigned_type_node, NULL);
985 tree ftype_get_fpr
986 = build_function_type_list (unsigned_type_node, NULL);
988 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR]
989 = add_builtin_function ("__builtin_aarch64_get_fpcr", ftype_get_fpr,
990 AARCH64_BUILTIN_GET_FPCR, BUILT_IN_MD, NULL, NULL_TREE);
991 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR]
992 = add_builtin_function ("__builtin_aarch64_set_fpcr", ftype_set_fpr,
993 AARCH64_BUILTIN_SET_FPCR, BUILT_IN_MD, NULL, NULL_TREE);
994 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR]
995 = add_builtin_function ("__builtin_aarch64_get_fpsr", ftype_get_fpr,
996 AARCH64_BUILTIN_GET_FPSR, BUILT_IN_MD, NULL, NULL_TREE);
997 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR]
998 = add_builtin_function ("__builtin_aarch64_set_fpsr", ftype_set_fpr,
999 AARCH64_BUILTIN_SET_FPSR, BUILT_IN_MD, NULL, NULL_TREE);
1001 aarch64_init_fp16_types ();
1003 if (TARGET_SIMD)
1004 aarch64_init_simd_builtins ();
1006 aarch64_init_crc32_builtins ();
1007 aarch64_init_builtin_rsqrt ();
1009 /* Initialize pointer authentication builtins which are backed by instructions
1010 in NOP encoding space.
1012 NOTE: these builtins are supposed to be used by libgcc unwinder only, as
1013 there is no support on return address signing under ILP32, we don't
1014 register them. */
1015 if (!TARGET_ILP32)
1016 aarch64_init_pauth_hint_builtins ();
1019 tree
1020 aarch64_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
1022 if (code >= AARCH64_BUILTIN_MAX)
1023 return error_mark_node;
1025 return aarch64_builtin_decls[code];
1028 typedef enum
1030 SIMD_ARG_COPY_TO_REG,
1031 SIMD_ARG_CONSTANT,
1032 SIMD_ARG_LANE_INDEX,
1033 SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX,
1034 SIMD_ARG_STOP
1035 } builtin_simd_arg;
1038 static rtx
1039 aarch64_simd_expand_args (rtx target, int icode, int have_retval,
1040 tree exp, builtin_simd_arg *args,
1041 machine_mode builtin_mode)
1043 rtx pat;
1044 rtx op[SIMD_MAX_BUILTIN_ARGS + 1]; /* First element for result operand. */
1045 int opc = 0;
1047 if (have_retval)
1049 machine_mode tmode = insn_data[icode].operand[0].mode;
1050 if (!target
1051 || GET_MODE (target) != tmode
1052 || !(*insn_data[icode].operand[0].predicate) (target, tmode))
1053 target = gen_reg_rtx (tmode);
1054 op[opc++] = target;
1057 for (;;)
1059 builtin_simd_arg thisarg = args[opc - have_retval];
1061 if (thisarg == SIMD_ARG_STOP)
1062 break;
1063 else
1065 tree arg = CALL_EXPR_ARG (exp, opc - have_retval);
1066 machine_mode mode = insn_data[icode].operand[opc].mode;
1067 op[opc] = expand_normal (arg);
1069 switch (thisarg)
1071 case SIMD_ARG_COPY_TO_REG:
1072 if (POINTER_TYPE_P (TREE_TYPE (arg)))
1073 op[opc] = convert_memory_address (Pmode, op[opc]);
1074 /*gcc_assert (GET_MODE (op[opc]) == mode); */
1075 if (!(*insn_data[icode].operand[opc].predicate)
1076 (op[opc], mode))
1077 op[opc] = copy_to_mode_reg (mode, op[opc]);
1078 break;
1080 case SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX:
1081 gcc_assert (opc > 1);
1082 if (CONST_INT_P (op[opc]))
1084 unsigned int nunits
1085 = GET_MODE_NUNITS (builtin_mode).to_constant ();
1086 aarch64_simd_lane_bounds (op[opc], 0, nunits, exp);
1087 /* Keep to GCC-vector-extension lane indices in the RTL. */
1088 op[opc] = aarch64_endian_lane_rtx (builtin_mode,
1089 INTVAL (op[opc]));
1091 goto constant_arg;
1093 case SIMD_ARG_LANE_INDEX:
1094 /* Must be a previous operand into which this is an index. */
1095 gcc_assert (opc > 0);
1096 if (CONST_INT_P (op[opc]))
1098 machine_mode vmode = insn_data[icode].operand[opc - 1].mode;
1099 unsigned int nunits
1100 = GET_MODE_NUNITS (vmode).to_constant ();
1101 aarch64_simd_lane_bounds (op[opc], 0, nunits, exp);
1102 /* Keep to GCC-vector-extension lane indices in the RTL. */
1103 op[opc] = aarch64_endian_lane_rtx (vmode, INTVAL (op[opc]));
1105 /* Fall through - if the lane index isn't a constant then
1106 the next case will error. */
1107 /* FALLTHRU */
1108 case SIMD_ARG_CONSTANT:
1109 constant_arg:
1110 if (!(*insn_data[icode].operand[opc].predicate)
1111 (op[opc], mode))
1113 error ("%Kargument %d must be a constant immediate",
1114 exp, opc + 1 - have_retval);
1115 return const0_rtx;
1117 break;
1119 case SIMD_ARG_STOP:
1120 gcc_unreachable ();
1123 opc++;
1127 switch (opc)
1129 case 1:
1130 pat = GEN_FCN (icode) (op[0]);
1131 break;
1133 case 2:
1134 pat = GEN_FCN (icode) (op[0], op[1]);
1135 break;
1137 case 3:
1138 pat = GEN_FCN (icode) (op[0], op[1], op[2]);
1139 break;
1141 case 4:
1142 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
1143 break;
1145 case 5:
1146 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
1147 break;
1149 case 6:
1150 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]);
1151 break;
1153 default:
1154 gcc_unreachable ();
1157 if (!pat)
1158 return NULL_RTX;
1160 emit_insn (pat);
1162 return target;
1165 /* Expand an AArch64 AdvSIMD builtin(intrinsic). */
1167 aarch64_simd_expand_builtin (int fcode, tree exp, rtx target)
1169 if (fcode == AARCH64_SIMD_BUILTIN_LANE_CHECK)
1171 rtx totalsize = expand_normal (CALL_EXPR_ARG (exp, 0));
1172 rtx elementsize = expand_normal (CALL_EXPR_ARG (exp, 1));
1173 if (CONST_INT_P (totalsize) && CONST_INT_P (elementsize)
1174 && UINTVAL (elementsize) != 0
1175 && UINTVAL (totalsize) != 0)
1177 rtx lane_idx = expand_normal (CALL_EXPR_ARG (exp, 2));
1178 if (CONST_INT_P (lane_idx))
1179 aarch64_simd_lane_bounds (lane_idx, 0,
1180 UINTVAL (totalsize)
1181 / UINTVAL (elementsize),
1182 exp);
1183 else
1184 error ("%Klane index must be a constant immediate", exp);
1186 else
1187 error ("%Ktotal size and element size must be a non-zero constant immediate", exp);
1188 /* Don't generate any RTL. */
1189 return const0_rtx;
1191 aarch64_simd_builtin_datum *d =
1192 &aarch64_simd_builtin_data[fcode - AARCH64_SIMD_PATTERN_START];
1193 enum insn_code icode = d->code;
1194 builtin_simd_arg args[SIMD_MAX_BUILTIN_ARGS + 1];
1195 int num_args = insn_data[d->code].n_operands;
1196 int is_void = 0;
1197 int k;
1199 is_void = !!(d->qualifiers[0] & qualifier_void);
1201 num_args += is_void;
1203 for (k = 1; k < num_args; k++)
1205 /* We have four arrays of data, each indexed in a different fashion.
1206 qualifiers - element 0 always describes the function return type.
1207 operands - element 0 is either the operand for return value (if
1208 the function has a non-void return type) or the operand for the
1209 first argument.
1210 expr_args - element 0 always holds the first argument.
1211 args - element 0 is always used for the return type. */
1212 int qualifiers_k = k;
1213 int operands_k = k - is_void;
1214 int expr_args_k = k - 1;
1216 if (d->qualifiers[qualifiers_k] & qualifier_lane_index)
1217 args[k] = SIMD_ARG_LANE_INDEX;
1218 else if (d->qualifiers[qualifiers_k] & qualifier_struct_load_store_lane_index)
1219 args[k] = SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX;
1220 else if (d->qualifiers[qualifiers_k] & qualifier_immediate)
1221 args[k] = SIMD_ARG_CONSTANT;
1222 else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate)
1224 rtx arg
1225 = expand_normal (CALL_EXPR_ARG (exp,
1226 (expr_args_k)));
1227 /* Handle constants only if the predicate allows it. */
1228 bool op_const_int_p =
1229 (CONST_INT_P (arg)
1230 && (*insn_data[icode].operand[operands_k].predicate)
1231 (arg, insn_data[icode].operand[operands_k].mode));
1232 args[k] = op_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG;
1234 else
1235 args[k] = SIMD_ARG_COPY_TO_REG;
1238 args[k] = SIMD_ARG_STOP;
1240 /* The interface to aarch64_simd_expand_args expects a 0 if
1241 the function is void, and a 1 if it is not. */
1242 return aarch64_simd_expand_args
1243 (target, icode, !is_void, exp, &args[1], d->mode);
1247 aarch64_crc32_expand_builtin (int fcode, tree exp, rtx target)
1249 rtx pat;
1250 aarch64_crc_builtin_datum *d
1251 = &aarch64_crc_builtin_data[fcode - (AARCH64_CRC32_BUILTIN_BASE + 1)];
1252 enum insn_code icode = d->icode;
1253 tree arg0 = CALL_EXPR_ARG (exp, 0);
1254 tree arg1 = CALL_EXPR_ARG (exp, 1);
1255 rtx op0 = expand_normal (arg0);
1256 rtx op1 = expand_normal (arg1);
1257 machine_mode tmode = insn_data[icode].operand[0].mode;
1258 machine_mode mode0 = insn_data[icode].operand[1].mode;
1259 machine_mode mode1 = insn_data[icode].operand[2].mode;
1261 if (! target
1262 || GET_MODE (target) != tmode
1263 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1264 target = gen_reg_rtx (tmode);
1266 gcc_assert ((GET_MODE (op0) == mode0 || GET_MODE (op0) == VOIDmode)
1267 && (GET_MODE (op1) == mode1 || GET_MODE (op1) == VOIDmode));
1269 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1270 op0 = copy_to_mode_reg (mode0, op0);
1271 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
1272 op1 = copy_to_mode_reg (mode1, op1);
1274 pat = GEN_FCN (icode) (target, op0, op1);
1275 if (!pat)
1276 return NULL_RTX;
1278 emit_insn (pat);
1279 return target;
1282 /* Function to expand reciprocal square root builtins. */
1284 static rtx
1285 aarch64_expand_builtin_rsqrt (int fcode, tree exp, rtx target)
1287 tree arg0 = CALL_EXPR_ARG (exp, 0);
1288 rtx op0 = expand_normal (arg0);
1290 rtx (*gen) (rtx, rtx);
1292 switch (fcode)
1294 case AARCH64_BUILTIN_RSQRT_DF:
1295 gen = gen_rsqrtdf2;
1296 break;
1297 case AARCH64_BUILTIN_RSQRT_SF:
1298 gen = gen_rsqrtsf2;
1299 break;
1300 case AARCH64_BUILTIN_RSQRT_V2DF:
1301 gen = gen_rsqrtv2df2;
1302 break;
1303 case AARCH64_BUILTIN_RSQRT_V2SF:
1304 gen = gen_rsqrtv2sf2;
1305 break;
1306 case AARCH64_BUILTIN_RSQRT_V4SF:
1307 gen = gen_rsqrtv4sf2;
1308 break;
1309 default: gcc_unreachable ();
1312 if (!target)
1313 target = gen_reg_rtx (GET_MODE (op0));
1315 emit_insn (gen (target, op0));
1317 return target;
1320 /* Expand an expression EXP that calls a built-in function,
1321 with result going to TARGET if that's convenient. */
1323 aarch64_expand_builtin (tree exp,
1324 rtx target,
1325 rtx subtarget ATTRIBUTE_UNUSED,
1326 machine_mode mode ATTRIBUTE_UNUSED,
1327 int ignore ATTRIBUTE_UNUSED)
1329 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
1330 int fcode = DECL_FUNCTION_CODE (fndecl);
1331 int icode;
1332 rtx pat, op0;
1333 tree arg0;
1335 switch (fcode)
1337 case AARCH64_BUILTIN_GET_FPCR:
1338 case AARCH64_BUILTIN_SET_FPCR:
1339 case AARCH64_BUILTIN_GET_FPSR:
1340 case AARCH64_BUILTIN_SET_FPSR:
1341 if ((fcode == AARCH64_BUILTIN_GET_FPCR)
1342 || (fcode == AARCH64_BUILTIN_GET_FPSR))
1344 icode = (fcode == AARCH64_BUILTIN_GET_FPSR) ?
1345 CODE_FOR_get_fpsr : CODE_FOR_get_fpcr;
1346 target = gen_reg_rtx (SImode);
1347 pat = GEN_FCN (icode) (target);
1349 else
1351 target = NULL_RTX;
1352 icode = (fcode == AARCH64_BUILTIN_SET_FPSR) ?
1353 CODE_FOR_set_fpsr : CODE_FOR_set_fpcr;
1354 arg0 = CALL_EXPR_ARG (exp, 0);
1355 op0 = force_reg (SImode, expand_normal (arg0));
1356 pat = GEN_FCN (icode) (op0);
1358 emit_insn (pat);
1359 return target;
1361 case AARCH64_PAUTH_BUILTIN_AUTIA1716:
1362 case AARCH64_PAUTH_BUILTIN_PACIA1716:
1363 case AARCH64_PAUTH_BUILTIN_XPACLRI:
1364 arg0 = CALL_EXPR_ARG (exp, 0);
1365 op0 = force_reg (Pmode, expand_normal (arg0));
1367 if (!target)
1368 target = gen_reg_rtx (Pmode);
1369 else
1370 target = force_reg (Pmode, target);
1372 emit_move_insn (target, op0);
1374 if (fcode == AARCH64_PAUTH_BUILTIN_XPACLRI)
1376 rtx lr = gen_rtx_REG (Pmode, R30_REGNUM);
1377 icode = CODE_FOR_xpaclri;
1378 emit_move_insn (lr, op0);
1379 emit_insn (GEN_FCN (icode) ());
1380 emit_move_insn (target, lr);
1382 else
1384 tree arg1 = CALL_EXPR_ARG (exp, 1);
1385 rtx op1 = force_reg (Pmode, expand_normal (arg1));
1386 icode = (fcode == AARCH64_PAUTH_BUILTIN_PACIA1716
1387 ? CODE_FOR_paci1716 : CODE_FOR_auti1716);
1389 rtx x16_reg = gen_rtx_REG (Pmode, R16_REGNUM);
1390 rtx x17_reg = gen_rtx_REG (Pmode, R17_REGNUM);
1391 emit_move_insn (x17_reg, op0);
1392 emit_move_insn (x16_reg, op1);
1393 emit_insn (GEN_FCN (icode) ());
1394 emit_move_insn (target, x17_reg);
1397 return target;
1400 if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
1401 return aarch64_simd_expand_builtin (fcode, exp, target);
1402 else if (fcode >= AARCH64_CRC32_BUILTIN_BASE && fcode <= AARCH64_CRC32_BUILTIN_MAX)
1403 return aarch64_crc32_expand_builtin (fcode, exp, target);
1405 if (fcode == AARCH64_BUILTIN_RSQRT_DF
1406 || fcode == AARCH64_BUILTIN_RSQRT_SF
1407 || fcode == AARCH64_BUILTIN_RSQRT_V2DF
1408 || fcode == AARCH64_BUILTIN_RSQRT_V2SF
1409 || fcode == AARCH64_BUILTIN_RSQRT_V4SF)
1410 return aarch64_expand_builtin_rsqrt (fcode, exp, target);
1412 gcc_unreachable ();
1415 tree
1416 aarch64_builtin_vectorized_function (unsigned int fn, tree type_out,
1417 tree type_in)
1419 machine_mode in_mode, out_mode;
1420 unsigned HOST_WIDE_INT in_n, out_n;
1422 if (TREE_CODE (type_out) != VECTOR_TYPE
1423 || TREE_CODE (type_in) != VECTOR_TYPE)
1424 return NULL_TREE;
1426 out_mode = TYPE_MODE (TREE_TYPE (type_out));
1427 in_mode = TYPE_MODE (TREE_TYPE (type_in));
1428 if (!TYPE_VECTOR_SUBPARTS (type_out).is_constant (&out_n)
1429 || !TYPE_VECTOR_SUBPARTS (type_in).is_constant (&in_n))
1430 return NULL_TREE;
1432 #undef AARCH64_CHECK_BUILTIN_MODE
1433 #define AARCH64_CHECK_BUILTIN_MODE(C, N) 1
1434 #define AARCH64_FIND_FRINT_VARIANT(N) \
1435 (AARCH64_CHECK_BUILTIN_MODE (2, D) \
1436 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2df] \
1437 : (AARCH64_CHECK_BUILTIN_MODE (4, S) \
1438 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v4sf] \
1439 : (AARCH64_CHECK_BUILTIN_MODE (2, S) \
1440 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2sf] \
1441 : NULL_TREE)))
1442 switch (fn)
1444 #undef AARCH64_CHECK_BUILTIN_MODE
1445 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1446 (out_mode == N##Fmode && out_n == C \
1447 && in_mode == N##Fmode && in_n == C)
1448 CASE_CFN_FLOOR:
1449 return AARCH64_FIND_FRINT_VARIANT (floor);
1450 CASE_CFN_CEIL:
1451 return AARCH64_FIND_FRINT_VARIANT (ceil);
1452 CASE_CFN_TRUNC:
1453 return AARCH64_FIND_FRINT_VARIANT (btrunc);
1454 CASE_CFN_ROUND:
1455 return AARCH64_FIND_FRINT_VARIANT (round);
1456 CASE_CFN_NEARBYINT:
1457 return AARCH64_FIND_FRINT_VARIANT (nearbyint);
1458 CASE_CFN_SQRT:
1459 return AARCH64_FIND_FRINT_VARIANT (sqrt);
1460 #undef AARCH64_CHECK_BUILTIN_MODE
1461 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1462 (out_mode == SImode && out_n == C \
1463 && in_mode == N##Imode && in_n == C)
1464 CASE_CFN_CLZ:
1466 if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1467 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_clzv4si];
1468 return NULL_TREE;
1470 CASE_CFN_CTZ:
1472 if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1473 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv2si];
1474 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1475 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv4si];
1476 return NULL_TREE;
1478 #undef AARCH64_CHECK_BUILTIN_MODE
1479 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1480 (out_mode == N##Imode && out_n == C \
1481 && in_mode == N##Fmode && in_n == C)
1482 CASE_CFN_IFLOOR:
1483 CASE_CFN_LFLOOR:
1484 CASE_CFN_LLFLOOR:
1486 enum aarch64_builtins builtin;
1487 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1488 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2dfv2di;
1489 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1490 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv4sfv4si;
1491 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1492 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2sfv2si;
1493 else
1494 return NULL_TREE;
1496 return aarch64_builtin_decls[builtin];
1498 CASE_CFN_ICEIL:
1499 CASE_CFN_LCEIL:
1500 CASE_CFN_LLCEIL:
1502 enum aarch64_builtins builtin;
1503 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1504 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2dfv2di;
1505 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1506 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv4sfv4si;
1507 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1508 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2sfv2si;
1509 else
1510 return NULL_TREE;
1512 return aarch64_builtin_decls[builtin];
1514 CASE_CFN_IROUND:
1515 CASE_CFN_LROUND:
1516 CASE_CFN_LLROUND:
1518 enum aarch64_builtins builtin;
1519 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1520 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2dfv2di;
1521 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1522 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv4sfv4si;
1523 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1524 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2sfv2si;
1525 else
1526 return NULL_TREE;
1528 return aarch64_builtin_decls[builtin];
1530 case CFN_BUILT_IN_BSWAP16:
1531 #undef AARCH64_CHECK_BUILTIN_MODE
1532 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1533 (out_mode == N##Imode && out_n == C \
1534 && in_mode == N##Imode && in_n == C)
1535 if (AARCH64_CHECK_BUILTIN_MODE (4, H))
1536 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4hi];
1537 else if (AARCH64_CHECK_BUILTIN_MODE (8, H))
1538 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv8hi];
1539 else
1540 return NULL_TREE;
1541 case CFN_BUILT_IN_BSWAP32:
1542 if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1543 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2si];
1544 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1545 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4si];
1546 else
1547 return NULL_TREE;
1548 case CFN_BUILT_IN_BSWAP64:
1549 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1550 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2di];
1551 else
1552 return NULL_TREE;
1553 default:
1554 return NULL_TREE;
1557 return NULL_TREE;
1560 /* Return builtin for reciprocal square root. */
1562 tree
1563 aarch64_builtin_rsqrt (unsigned int fn)
1565 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv2df)
1566 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V2DF];
1567 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv2sf)
1568 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V2SF];
1569 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv4sf)
1570 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V4SF];
1571 return NULL_TREE;
1574 #undef VAR1
1575 #define VAR1(T, N, MAP, A) \
1576 case AARCH64_SIMD_BUILTIN_##T##_##N##A:
1578 tree
1579 aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args,
1580 bool ignore ATTRIBUTE_UNUSED)
1582 int fcode = DECL_FUNCTION_CODE (fndecl);
1583 tree type = TREE_TYPE (TREE_TYPE (fndecl));
1585 switch (fcode)
1587 BUILTIN_VDQF (UNOP, abs, 2)
1588 return fold_build1 (ABS_EXPR, type, args[0]);
1589 VAR1 (UNOP, floatv2si, 2, v2sf)
1590 VAR1 (UNOP, floatv4si, 2, v4sf)
1591 VAR1 (UNOP, floatv2di, 2, v2df)
1592 return fold_build1 (FLOAT_EXPR, type, args[0]);
1593 default:
1594 break;
1597 return NULL_TREE;
1600 bool
1601 aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi)
1603 bool changed = false;
1604 gimple *stmt = gsi_stmt (*gsi);
1605 tree call = gimple_call_fn (stmt);
1606 tree fndecl;
1607 gimple *new_stmt = NULL;
1609 if (call)
1611 fndecl = gimple_call_fndecl (stmt);
1612 if (fndecl)
1614 int fcode = DECL_FUNCTION_CODE (fndecl);
1615 unsigned nargs = gimple_call_num_args (stmt);
1616 tree *args = (nargs > 0
1617 ? gimple_call_arg_ptr (stmt, 0)
1618 : &error_mark_node);
1620 /* We use gimple's IFN_REDUC_(PLUS|MIN|MAX)s for float, signed int
1621 and unsigned int; it will distinguish according to the types of
1622 the arguments to the __builtin. */
1623 switch (fcode)
1625 BUILTIN_VALL (UNOP, reduc_plus_scal_, 10)
1626 new_stmt = gimple_build_call_internal (IFN_REDUC_PLUS,
1627 1, args[0]);
1628 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
1629 break;
1630 BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10)
1631 BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10)
1632 new_stmt = gimple_build_call_internal (IFN_REDUC_MAX,
1633 1, args[0]);
1634 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
1635 break;
1636 BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10)
1637 BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10)
1638 new_stmt = gimple_build_call_internal (IFN_REDUC_MIN,
1639 1, args[0]);
1640 gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
1641 break;
1642 BUILTIN_GPF (BINOP, fmulx, 0)
1644 gcc_assert (nargs == 2);
1645 bool a0_cst_p = TREE_CODE (args[0]) == REAL_CST;
1646 bool a1_cst_p = TREE_CODE (args[1]) == REAL_CST;
1647 if (a0_cst_p || a1_cst_p)
1649 if (a0_cst_p && a1_cst_p)
1651 tree t0 = TREE_TYPE (args[0]);
1652 real_value a0 = (TREE_REAL_CST (args[0]));
1653 real_value a1 = (TREE_REAL_CST (args[1]));
1654 if (real_equal (&a1, &dconst0))
1655 std::swap (a0, a1);
1656 /* According to real_equal (), +0 equals -0. */
1657 if (real_equal (&a0, &dconst0) && real_isinf (&a1))
1659 real_value res = dconst2;
1660 res.sign = a0.sign ^ a1.sign;
1661 new_stmt =
1662 gimple_build_assign (gimple_call_lhs (stmt),
1663 REAL_CST,
1664 build_real (t0, res));
1666 else
1667 new_stmt =
1668 gimple_build_assign (gimple_call_lhs (stmt),
1669 MULT_EXPR,
1670 args[0], args[1]);
1672 else /* a0_cst_p ^ a1_cst_p. */
1674 real_value const_part = a0_cst_p
1675 ? TREE_REAL_CST (args[0]) : TREE_REAL_CST (args[1]);
1676 if (!real_equal (&const_part, &dconst0)
1677 && !real_isinf (&const_part))
1678 new_stmt =
1679 gimple_build_assign (gimple_call_lhs (stmt),
1680 MULT_EXPR, args[0], args[1]);
1683 if (new_stmt)
1685 gimple_set_vuse (new_stmt, gimple_vuse (stmt));
1686 gimple_set_vdef (new_stmt, gimple_vdef (stmt));
1688 break;
1690 default:
1691 break;
1696 if (new_stmt)
1698 gsi_replace (gsi, new_stmt, true);
1699 changed = true;
1702 return changed;
1705 void
1706 aarch64_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
1708 const unsigned AARCH64_FE_INVALID = 1;
1709 const unsigned AARCH64_FE_DIVBYZERO = 2;
1710 const unsigned AARCH64_FE_OVERFLOW = 4;
1711 const unsigned AARCH64_FE_UNDERFLOW = 8;
1712 const unsigned AARCH64_FE_INEXACT = 16;
1713 const unsigned HOST_WIDE_INT AARCH64_FE_ALL_EXCEPT = (AARCH64_FE_INVALID
1714 | AARCH64_FE_DIVBYZERO
1715 | AARCH64_FE_OVERFLOW
1716 | AARCH64_FE_UNDERFLOW
1717 | AARCH64_FE_INEXACT);
1718 const unsigned HOST_WIDE_INT AARCH64_FE_EXCEPT_SHIFT = 8;
1719 tree fenv_cr, fenv_sr, get_fpcr, set_fpcr, mask_cr, mask_sr;
1720 tree ld_fenv_cr, ld_fenv_sr, masked_fenv_cr, masked_fenv_sr, hold_fnclex_cr;
1721 tree hold_fnclex_sr, new_fenv_var, reload_fenv, restore_fnenv, get_fpsr, set_fpsr;
1722 tree update_call, atomic_feraiseexcept, hold_fnclex, masked_fenv, ld_fenv;
1724 /* Generate the equivalence of :
1725 unsigned int fenv_cr;
1726 fenv_cr = __builtin_aarch64_get_fpcr ();
1728 unsigned int fenv_sr;
1729 fenv_sr = __builtin_aarch64_get_fpsr ();
1731 Now set all exceptions to non-stop
1732 unsigned int mask_cr
1733 = ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT);
1734 unsigned int masked_cr;
1735 masked_cr = fenv_cr & mask_cr;
1737 And clear all exception flags
1738 unsigned int maske_sr = ~AARCH64_FE_ALL_EXCEPT;
1739 unsigned int masked_cr;
1740 masked_sr = fenv_sr & mask_sr;
1742 __builtin_aarch64_set_cr (masked_cr);
1743 __builtin_aarch64_set_sr (masked_sr); */
1745 fenv_cr = create_tmp_var_raw (unsigned_type_node);
1746 fenv_sr = create_tmp_var_raw (unsigned_type_node);
1748 get_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR];
1749 set_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR];
1750 get_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR];
1751 set_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR];
1753 mask_cr = build_int_cst (unsigned_type_node,
1754 ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT));
1755 mask_sr = build_int_cst (unsigned_type_node,
1756 ~(AARCH64_FE_ALL_EXCEPT));
1758 ld_fenv_cr = build2 (MODIFY_EXPR, unsigned_type_node,
1759 fenv_cr, build_call_expr (get_fpcr, 0));
1760 ld_fenv_sr = build2 (MODIFY_EXPR, unsigned_type_node,
1761 fenv_sr, build_call_expr (get_fpsr, 0));
1763 masked_fenv_cr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_cr, mask_cr);
1764 masked_fenv_sr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_sr, mask_sr);
1766 hold_fnclex_cr = build_call_expr (set_fpcr, 1, masked_fenv_cr);
1767 hold_fnclex_sr = build_call_expr (set_fpsr, 1, masked_fenv_sr);
1769 hold_fnclex = build2 (COMPOUND_EXPR, void_type_node, hold_fnclex_cr,
1770 hold_fnclex_sr);
1771 masked_fenv = build2 (COMPOUND_EXPR, void_type_node, masked_fenv_cr,
1772 masked_fenv_sr);
1773 ld_fenv = build2 (COMPOUND_EXPR, void_type_node, ld_fenv_cr, ld_fenv_sr);
1775 *hold = build2 (COMPOUND_EXPR, void_type_node,
1776 build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv),
1777 hold_fnclex);
1779 /* Store the value of masked_fenv to clear the exceptions:
1780 __builtin_aarch64_set_fpsr (masked_fenv_sr); */
1782 *clear = build_call_expr (set_fpsr, 1, masked_fenv_sr);
1784 /* Generate the equivalent of :
1785 unsigned int new_fenv_var;
1786 new_fenv_var = __builtin_aarch64_get_fpsr ();
1788 __builtin_aarch64_set_fpsr (fenv_sr);
1790 __atomic_feraiseexcept (new_fenv_var); */
1792 new_fenv_var = create_tmp_var_raw (unsigned_type_node);
1793 reload_fenv = build2 (MODIFY_EXPR, unsigned_type_node,
1794 new_fenv_var, build_call_expr (get_fpsr, 0));
1795 restore_fnenv = build_call_expr (set_fpsr, 1, fenv_sr);
1796 atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT);
1797 update_call = build_call_expr (atomic_feraiseexcept, 1,
1798 fold_convert (integer_type_node, new_fenv_var));
1799 *update = build2 (COMPOUND_EXPR, void_type_node,
1800 build2 (COMPOUND_EXPR, void_type_node,
1801 reload_fenv, restore_fnenv), update_call);
1805 #undef AARCH64_CHECK_BUILTIN_MODE
1806 #undef AARCH64_FIND_FRINT_VARIANT
1807 #undef CF0
1808 #undef CF1
1809 #undef CF2
1810 #undef CF3
1811 #undef CF4
1812 #undef CF10
1813 #undef VAR1
1814 #undef VAR2
1815 #undef VAR3
1816 #undef VAR4
1817 #undef VAR5
1818 #undef VAR6
1819 #undef VAR7
1820 #undef VAR8
1821 #undef VAR9
1822 #undef VAR10
1823 #undef VAR11
1825 #include "gt-aarch64-builtins.h"