2016-11-28 Tamar Christina <tamar.christina@arm.com>
[official-gcc.git] / gcc / config / aarch64 / aarch64-builtins.c
blob05cc52eba33053f60fb3a590f7f88d178f9fd905
1 /* Builtins' description for AArch64 SIMD architecture.
2 Copyright (C) 2011-2016 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 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "function.h"
26 #include "basic-block.h"
27 #include "rtl.h"
28 #include "tree.h"
29 #include "gimple.h"
30 #include "memmodel.h"
31 #include "tm_p.h"
32 #include "expmed.h"
33 #include "optabs.h"
34 #include "recog.h"
35 #include "diagnostic-core.h"
36 #include "fold-const.h"
37 #include "stor-layout.h"
38 #include "explow.h"
39 #include "expr.h"
40 #include "langhooks.h"
41 #include "gimple-iterator.h"
42 #include "case-cfn-macros.h"
44 #define v8qi_UP V8QImode
45 #define v4hi_UP V4HImode
46 #define v4hf_UP V4HFmode
47 #define v2si_UP V2SImode
48 #define v2sf_UP V2SFmode
49 #define v1df_UP V1DFmode
50 #define di_UP DImode
51 #define df_UP DFmode
52 #define v16qi_UP V16QImode
53 #define v8hi_UP V8HImode
54 #define v8hf_UP V8HFmode
55 #define v4si_UP V4SImode
56 #define v4sf_UP V4SFmode
57 #define v2di_UP V2DImode
58 #define v2df_UP V2DFmode
59 #define ti_UP TImode
60 #define oi_UP OImode
61 #define ci_UP CImode
62 #define xi_UP XImode
63 #define si_UP SImode
64 #define sf_UP SFmode
65 #define hi_UP HImode
66 #define hf_UP HFmode
67 #define qi_UP QImode
68 #define UP(X) X##_UP
70 #define SIMD_MAX_BUILTIN_ARGS 5
72 enum aarch64_type_qualifiers
74 /* T foo. */
75 qualifier_none = 0x0,
76 /* unsigned T foo. */
77 qualifier_unsigned = 0x1, /* 1 << 0 */
78 /* const T foo. */
79 qualifier_const = 0x2, /* 1 << 1 */
80 /* T *foo. */
81 qualifier_pointer = 0x4, /* 1 << 2 */
82 /* Used when expanding arguments if an operand could
83 be an immediate. */
84 qualifier_immediate = 0x8, /* 1 << 3 */
85 qualifier_maybe_immediate = 0x10, /* 1 << 4 */
86 /* void foo (...). */
87 qualifier_void = 0x20, /* 1 << 5 */
88 /* Some patterns may have internal operands, this qualifier is an
89 instruction to the initialisation code to skip this operand. */
90 qualifier_internal = 0x40, /* 1 << 6 */
91 /* Some builtins should use the T_*mode* encoded in a simd_builtin_datum
92 rather than using the type of the operand. */
93 qualifier_map_mode = 0x80, /* 1 << 7 */
94 /* qualifier_pointer | qualifier_map_mode */
95 qualifier_pointer_map_mode = 0x84,
96 /* qualifier_const | qualifier_pointer | qualifier_map_mode */
97 qualifier_const_pointer_map_mode = 0x86,
98 /* Polynomial types. */
99 qualifier_poly = 0x100,
100 /* Lane indices - must be in range, and flipped for bigendian. */
101 qualifier_lane_index = 0x200,
102 /* Lane indices for single lane structure loads and stores. */
103 qualifier_struct_load_store_lane_index = 0x400
106 typedef struct
108 const char *name;
109 machine_mode mode;
110 const enum insn_code code;
111 unsigned int fcode;
112 enum aarch64_type_qualifiers *qualifiers;
113 } aarch64_simd_builtin_datum;
115 static enum aarch64_type_qualifiers
116 aarch64_types_unop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
117 = { qualifier_none, qualifier_none };
118 #define TYPES_UNOP (aarch64_types_unop_qualifiers)
119 static enum aarch64_type_qualifiers
120 aarch64_types_unopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
121 = { qualifier_unsigned, qualifier_unsigned };
122 #define TYPES_UNOPU (aarch64_types_unopu_qualifiers)
123 static enum aarch64_type_qualifiers
124 aarch64_types_unopus_qualifiers[SIMD_MAX_BUILTIN_ARGS]
125 = { qualifier_unsigned, qualifier_none };
126 #define TYPES_UNOPUS (aarch64_types_unopus_qualifiers)
127 static enum aarch64_type_qualifiers
128 aarch64_types_binop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
129 = { qualifier_none, qualifier_none, qualifier_maybe_immediate };
130 #define TYPES_BINOP (aarch64_types_binop_qualifiers)
131 static enum aarch64_type_qualifiers
132 aarch64_types_binopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
133 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned };
134 #define TYPES_BINOPU (aarch64_types_binopu_qualifiers)
135 static enum aarch64_type_qualifiers
136 aarch64_types_binop_uus_qualifiers[SIMD_MAX_BUILTIN_ARGS]
137 = { qualifier_unsigned, qualifier_unsigned, qualifier_none };
138 #define TYPES_BINOP_UUS (aarch64_types_binop_uus_qualifiers)
139 static enum aarch64_type_qualifiers
140 aarch64_types_binop_ssu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
141 = { qualifier_none, qualifier_none, qualifier_unsigned };
142 #define TYPES_BINOP_SSU (aarch64_types_binop_ssu_qualifiers)
143 static enum aarch64_type_qualifiers
144 aarch64_types_binop_uss_qualifiers[SIMD_MAX_BUILTIN_ARGS]
145 = { qualifier_unsigned, qualifier_none, qualifier_none };
146 #define TYPES_BINOP_USS (aarch64_types_binop_uss_qualifiers)
147 static enum aarch64_type_qualifiers
148 aarch64_types_binopp_qualifiers[SIMD_MAX_BUILTIN_ARGS]
149 = { qualifier_poly, qualifier_poly, qualifier_poly };
150 #define TYPES_BINOPP (aarch64_types_binopp_qualifiers)
152 static enum aarch64_type_qualifiers
153 aarch64_types_ternop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
154 = { qualifier_none, qualifier_none, qualifier_none, qualifier_none };
155 #define TYPES_TERNOP (aarch64_types_ternop_qualifiers)
156 static enum aarch64_type_qualifiers
157 aarch64_types_ternop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
158 = { qualifier_none, qualifier_none, qualifier_none, qualifier_lane_index };
159 #define TYPES_TERNOP_LANE (aarch64_types_ternop_lane_qualifiers)
160 static enum aarch64_type_qualifiers
161 aarch64_types_ternopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
162 = { qualifier_unsigned, qualifier_unsigned,
163 qualifier_unsigned, qualifier_unsigned };
164 #define TYPES_TERNOPU (aarch64_types_ternopu_qualifiers)
166 static enum aarch64_type_qualifiers
167 aarch64_types_quadop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
168 = { qualifier_none, qualifier_none, qualifier_none,
169 qualifier_none, qualifier_lane_index };
170 #define TYPES_QUADOP_LANE (aarch64_types_quadop_lane_qualifiers)
172 static enum aarch64_type_qualifiers
173 aarch64_types_binop_imm_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
174 = { qualifier_poly, qualifier_none, qualifier_immediate };
175 #define TYPES_GETREGP (aarch64_types_binop_imm_p_qualifiers)
176 static enum aarch64_type_qualifiers
177 aarch64_types_binop_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
178 = { qualifier_none, qualifier_none, qualifier_immediate };
179 #define TYPES_GETREG (aarch64_types_binop_imm_qualifiers)
180 #define TYPES_SHIFTIMM (aarch64_types_binop_imm_qualifiers)
181 static enum aarch64_type_qualifiers
182 aarch64_types_shift_to_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS]
183 = { qualifier_unsigned, qualifier_none, qualifier_immediate };
184 #define TYPES_SHIFTIMM_USS (aarch64_types_shift_to_unsigned_qualifiers)
185 static enum aarch64_type_qualifiers
186 aarch64_types_fcvt_from_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS]
187 = { qualifier_none, qualifier_unsigned, qualifier_immediate };
188 #define TYPES_FCVTIMM_SUS (aarch64_types_fcvt_from_unsigned_qualifiers)
189 static enum aarch64_type_qualifiers
190 aarch64_types_unsigned_shift_qualifiers[SIMD_MAX_BUILTIN_ARGS]
191 = { qualifier_unsigned, qualifier_unsigned, qualifier_immediate };
192 #define TYPES_USHIFTIMM (aarch64_types_unsigned_shift_qualifiers)
194 static enum aarch64_type_qualifiers
195 aarch64_types_ternop_s_imm_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
196 = { qualifier_none, qualifier_none, qualifier_poly, qualifier_immediate};
197 #define TYPES_SETREGP (aarch64_types_ternop_s_imm_p_qualifiers)
198 static enum aarch64_type_qualifiers
199 aarch64_types_ternop_s_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
200 = { qualifier_none, qualifier_none, qualifier_none, qualifier_immediate};
201 #define TYPES_SETREG (aarch64_types_ternop_s_imm_qualifiers)
202 #define TYPES_SHIFTINSERT (aarch64_types_ternop_s_imm_qualifiers)
203 #define TYPES_SHIFTACC (aarch64_types_ternop_s_imm_qualifiers)
205 static enum aarch64_type_qualifiers
206 aarch64_types_ternop_p_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
207 = { qualifier_poly, qualifier_poly, qualifier_poly, qualifier_immediate};
208 #define TYPES_SHIFTINSERTP (aarch64_types_ternop_p_imm_qualifiers)
210 static enum aarch64_type_qualifiers
211 aarch64_types_unsigned_shiftacc_qualifiers[SIMD_MAX_BUILTIN_ARGS]
212 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
213 qualifier_immediate };
214 #define TYPES_USHIFTACC (aarch64_types_unsigned_shiftacc_qualifiers)
217 static enum aarch64_type_qualifiers
218 aarch64_types_combine_qualifiers[SIMD_MAX_BUILTIN_ARGS]
219 = { qualifier_none, qualifier_none, qualifier_none };
220 #define TYPES_COMBINE (aarch64_types_combine_qualifiers)
222 static enum aarch64_type_qualifiers
223 aarch64_types_combine_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
224 = { qualifier_poly, qualifier_poly, qualifier_poly };
225 #define TYPES_COMBINEP (aarch64_types_combine_p_qualifiers)
227 static enum aarch64_type_qualifiers
228 aarch64_types_load1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
229 = { qualifier_none, qualifier_const_pointer_map_mode };
230 #define TYPES_LOAD1 (aarch64_types_load1_qualifiers)
231 #define TYPES_LOADSTRUCT (aarch64_types_load1_qualifiers)
232 static enum aarch64_type_qualifiers
233 aarch64_types_loadstruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
234 = { qualifier_none, qualifier_const_pointer_map_mode,
235 qualifier_none, qualifier_struct_load_store_lane_index };
236 #define TYPES_LOADSTRUCT_LANE (aarch64_types_loadstruct_lane_qualifiers)
238 static enum aarch64_type_qualifiers
239 aarch64_types_bsl_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
240 = { qualifier_poly, qualifier_unsigned,
241 qualifier_poly, qualifier_poly };
242 #define TYPES_BSL_P (aarch64_types_bsl_p_qualifiers)
243 static enum aarch64_type_qualifiers
244 aarch64_types_bsl_s_qualifiers[SIMD_MAX_BUILTIN_ARGS]
245 = { qualifier_none, qualifier_unsigned,
246 qualifier_none, qualifier_none };
247 #define TYPES_BSL_S (aarch64_types_bsl_s_qualifiers)
248 static enum aarch64_type_qualifiers
249 aarch64_types_bsl_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
250 = { qualifier_unsigned, qualifier_unsigned,
251 qualifier_unsigned, qualifier_unsigned };
252 #define TYPES_BSL_U (aarch64_types_bsl_u_qualifiers)
254 /* The first argument (return type) of a store should be void type,
255 which we represent with qualifier_void. Their first operand will be
256 a DImode pointer to the location to store to, so we must use
257 qualifier_map_mode | qualifier_pointer to build a pointer to the
258 element type of the vector. */
259 static enum aarch64_type_qualifiers
260 aarch64_types_store1_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
261 = { qualifier_void, qualifier_pointer_map_mode, qualifier_poly };
262 #define TYPES_STORE1P (aarch64_types_store1_p_qualifiers)
263 static enum aarch64_type_qualifiers
264 aarch64_types_store1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
265 = { qualifier_void, qualifier_pointer_map_mode, qualifier_none };
266 #define TYPES_STORE1 (aarch64_types_store1_qualifiers)
267 #define TYPES_STORESTRUCT (aarch64_types_store1_qualifiers)
268 static enum aarch64_type_qualifiers
269 aarch64_types_storestruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
270 = { qualifier_void, qualifier_pointer_map_mode,
271 qualifier_none, qualifier_struct_load_store_lane_index };
272 #define TYPES_STORESTRUCT_LANE (aarch64_types_storestruct_lane_qualifiers)
274 #define CF0(N, X) CODE_FOR_aarch64_##N##X
275 #define CF1(N, X) CODE_FOR_##N##X##1
276 #define CF2(N, X) CODE_FOR_##N##X##2
277 #define CF3(N, X) CODE_FOR_##N##X##3
278 #define CF4(N, X) CODE_FOR_##N##X##4
279 #define CF10(N, X) CODE_FOR_##N##X
281 #define VAR1(T, N, MAP, A) \
282 {#N #A, UP (A), CF##MAP (N, A), 0, TYPES_##T},
283 #define VAR2(T, N, MAP, A, B) \
284 VAR1 (T, N, MAP, A) \
285 VAR1 (T, N, MAP, B)
286 #define VAR3(T, N, MAP, A, B, C) \
287 VAR2 (T, N, MAP, A, B) \
288 VAR1 (T, N, MAP, C)
289 #define VAR4(T, N, MAP, A, B, C, D) \
290 VAR3 (T, N, MAP, A, B, C) \
291 VAR1 (T, N, MAP, D)
292 #define VAR5(T, N, MAP, A, B, C, D, E) \
293 VAR4 (T, N, MAP, A, B, C, D) \
294 VAR1 (T, N, MAP, E)
295 #define VAR6(T, N, MAP, A, B, C, D, E, F) \
296 VAR5 (T, N, MAP, A, B, C, D, E) \
297 VAR1 (T, N, MAP, F)
298 #define VAR7(T, N, MAP, A, B, C, D, E, F, G) \
299 VAR6 (T, N, MAP, A, B, C, D, E, F) \
300 VAR1 (T, N, MAP, G)
301 #define VAR8(T, N, MAP, A, B, C, D, E, F, G, H) \
302 VAR7 (T, N, MAP, A, B, C, D, E, F, G) \
303 VAR1 (T, N, MAP, H)
304 #define VAR9(T, N, MAP, A, B, C, D, E, F, G, H, I) \
305 VAR8 (T, N, MAP, A, B, C, D, E, F, G, H) \
306 VAR1 (T, N, MAP, I)
307 #define VAR10(T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
308 VAR9 (T, N, MAP, A, B, C, D, E, F, G, H, I) \
309 VAR1 (T, N, MAP, J)
310 #define VAR11(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
311 VAR10 (T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
312 VAR1 (T, N, MAP, K)
313 #define VAR12(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K, L) \
314 VAR11 (T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
315 VAR1 (T, N, MAP, L)
316 #define VAR13(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K, L, M) \
317 VAR12 (T, N, MAP, A, B, C, D, E, F, G, H, I, J, K, L) \
318 VAR1 (T, N, MAP, M)
319 #define VAR14(T, X, MAP, A, B, C, D, E, F, G, H, I, J, K, L, M, N) \
320 VAR13 (T, X, MAP, A, B, C, D, E, F, G, H, I, J, K, L, M) \
321 VAR1 (T, X, MAP, N)
323 #include "aarch64-builtin-iterators.h"
325 static aarch64_simd_builtin_datum aarch64_simd_builtin_data[] = {
326 #include "aarch64-simd-builtins.def"
329 /* There's only 8 CRC32 builtins. Probably not worth their own .def file. */
330 #define AARCH64_CRC32_BUILTINS \
331 CRC32_BUILTIN (crc32b, QI) \
332 CRC32_BUILTIN (crc32h, HI) \
333 CRC32_BUILTIN (crc32w, SI) \
334 CRC32_BUILTIN (crc32x, DI) \
335 CRC32_BUILTIN (crc32cb, QI) \
336 CRC32_BUILTIN (crc32ch, HI) \
337 CRC32_BUILTIN (crc32cw, SI) \
338 CRC32_BUILTIN (crc32cx, DI)
340 typedef struct
342 const char *name;
343 machine_mode mode;
344 const enum insn_code icode;
345 unsigned int fcode;
346 } aarch64_crc_builtin_datum;
348 #define CRC32_BUILTIN(N, M) \
349 AARCH64_BUILTIN_##N,
351 #undef VAR1
352 #define VAR1(T, N, MAP, A) \
353 AARCH64_SIMD_BUILTIN_##T##_##N##A,
355 enum aarch64_builtins
357 AARCH64_BUILTIN_MIN,
359 AARCH64_BUILTIN_GET_FPCR,
360 AARCH64_BUILTIN_SET_FPCR,
361 AARCH64_BUILTIN_GET_FPSR,
362 AARCH64_BUILTIN_SET_FPSR,
364 AARCH64_BUILTIN_RSQRT_DF,
365 AARCH64_BUILTIN_RSQRT_SF,
366 AARCH64_BUILTIN_RSQRT_V2DF,
367 AARCH64_BUILTIN_RSQRT_V2SF,
368 AARCH64_BUILTIN_RSQRT_V4SF,
369 AARCH64_SIMD_BUILTIN_BASE,
370 AARCH64_SIMD_BUILTIN_LANE_CHECK,
371 #include "aarch64-simd-builtins.def"
372 /* The first enum element which is based on an insn_data pattern. */
373 AARCH64_SIMD_PATTERN_START = AARCH64_SIMD_BUILTIN_LANE_CHECK + 1,
374 AARCH64_SIMD_BUILTIN_MAX = AARCH64_SIMD_PATTERN_START
375 + ARRAY_SIZE (aarch64_simd_builtin_data) - 1,
376 AARCH64_CRC32_BUILTIN_BASE,
377 AARCH64_CRC32_BUILTINS
378 AARCH64_CRC32_BUILTIN_MAX,
379 AARCH64_BUILTIN_MAX
382 #undef CRC32_BUILTIN
383 #define CRC32_BUILTIN(N, M) \
384 {"__builtin_aarch64_"#N, M##mode, CODE_FOR_aarch64_##N, AARCH64_BUILTIN_##N},
386 static aarch64_crc_builtin_datum aarch64_crc_builtin_data[] = {
387 AARCH64_CRC32_BUILTINS
390 #undef CRC32_BUILTIN
392 static GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX];
394 #define NUM_DREG_TYPES 6
395 #define NUM_QREG_TYPES 6
397 /* Internal scalar builtin types. These types are used to support
398 neon intrinsic builtins. They are _not_ user-visible types. Therefore
399 the mangling for these types are implementation defined. */
400 const char *aarch64_scalar_builtin_types[] = {
401 "__builtin_aarch64_simd_qi",
402 "__builtin_aarch64_simd_hi",
403 "__builtin_aarch64_simd_si",
404 "__builtin_aarch64_simd_hf",
405 "__builtin_aarch64_simd_sf",
406 "__builtin_aarch64_simd_di",
407 "__builtin_aarch64_simd_df",
408 "__builtin_aarch64_simd_poly8",
409 "__builtin_aarch64_simd_poly16",
410 "__builtin_aarch64_simd_poly64",
411 "__builtin_aarch64_simd_poly128",
412 "__builtin_aarch64_simd_ti",
413 "__builtin_aarch64_simd_uqi",
414 "__builtin_aarch64_simd_uhi",
415 "__builtin_aarch64_simd_usi",
416 "__builtin_aarch64_simd_udi",
417 "__builtin_aarch64_simd_ei",
418 "__builtin_aarch64_simd_oi",
419 "__builtin_aarch64_simd_ci",
420 "__builtin_aarch64_simd_xi",
421 NULL
424 #define ENTRY(E, M, Q, G) E,
425 enum aarch64_simd_type
427 #include "aarch64-simd-builtin-types.def"
428 ARM_NEON_H_TYPES_LAST
430 #undef ENTRY
432 struct aarch64_simd_type_info
434 enum aarch64_simd_type type;
436 /* Internal type name. */
437 const char *name;
439 /* Internal type name(mangled). The mangled names conform to the
440 AAPCS64 (see "Procedure Call Standard for the ARM 64-bit Architecture",
441 Appendix A). To qualify for emission with the mangled names defined in
442 that document, a vector type must not only be of the correct mode but also
443 be of the correct internal AdvSIMD vector type (e.g. __Int8x8_t); these
444 types are registered by aarch64_init_simd_builtin_types (). In other
445 words, vector types defined in other ways e.g. via vector_size attribute
446 will get default mangled names. */
447 const char *mangle;
449 /* Internal type. */
450 tree itype;
452 /* Element type. */
453 tree eltype;
455 /* Machine mode the internal type maps to. */
456 enum machine_mode mode;
458 /* Qualifiers. */
459 enum aarch64_type_qualifiers q;
462 #define ENTRY(E, M, Q, G) \
463 {E, "__" #E, #G "__" #E, NULL_TREE, NULL_TREE, M##mode, qualifier_##Q},
464 static struct aarch64_simd_type_info aarch64_simd_types [] = {
465 #include "aarch64-simd-builtin-types.def"
467 #undef ENTRY
469 static tree aarch64_simd_intOI_type_node = NULL_TREE;
470 static tree aarch64_simd_intCI_type_node = NULL_TREE;
471 static tree aarch64_simd_intXI_type_node = NULL_TREE;
473 /* The user-visible __fp16 type, and a pointer to that type. Used
474 across the back-end. */
475 tree aarch64_fp16_type_node = NULL_TREE;
476 tree aarch64_fp16_ptr_type_node = NULL_TREE;
478 static const char *
479 aarch64_mangle_builtin_scalar_type (const_tree type)
481 int i = 0;
483 while (aarch64_scalar_builtin_types[i] != NULL)
485 const char *name = aarch64_scalar_builtin_types[i];
487 if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
488 && DECL_NAME (TYPE_NAME (type))
489 && !strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), name))
490 return aarch64_scalar_builtin_types[i];
491 i++;
493 return NULL;
496 static const char *
497 aarch64_mangle_builtin_vector_type (const_tree type)
499 int i;
500 int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
502 for (i = 0; i < nelts; i++)
503 if (aarch64_simd_types[i].mode == TYPE_MODE (type)
504 && TYPE_NAME (type)
505 && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
506 && DECL_NAME (TYPE_NAME (type))
507 && !strcmp
508 (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))),
509 aarch64_simd_types[i].name))
510 return aarch64_simd_types[i].mangle;
512 return NULL;
515 const char *
516 aarch64_mangle_builtin_type (const_tree type)
518 const char *mangle;
519 /* Walk through all the AArch64 builtins types tables to filter out the
520 incoming type. */
521 if ((mangle = aarch64_mangle_builtin_vector_type (type))
522 || (mangle = aarch64_mangle_builtin_scalar_type (type)))
523 return mangle;
525 return NULL;
528 static tree
529 aarch64_simd_builtin_std_type (enum machine_mode mode,
530 enum aarch64_type_qualifiers q)
532 #define QUAL_TYPE(M) \
533 ((q == qualifier_none) ? int##M##_type_node : unsigned_int##M##_type_node);
534 switch (mode)
536 case QImode:
537 return QUAL_TYPE (QI);
538 case HImode:
539 return QUAL_TYPE (HI);
540 case SImode:
541 return QUAL_TYPE (SI);
542 case DImode:
543 return QUAL_TYPE (DI);
544 case TImode:
545 return QUAL_TYPE (TI);
546 case OImode:
547 return aarch64_simd_intOI_type_node;
548 case CImode:
549 return aarch64_simd_intCI_type_node;
550 case XImode:
551 return aarch64_simd_intXI_type_node;
552 case HFmode:
553 return aarch64_fp16_type_node;
554 case SFmode:
555 return float_type_node;
556 case DFmode:
557 return double_type_node;
558 default:
559 gcc_unreachable ();
561 #undef QUAL_TYPE
564 static tree
565 aarch64_lookup_simd_builtin_type (enum machine_mode mode,
566 enum aarch64_type_qualifiers q)
568 int i;
569 int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
571 /* Non-poly scalar modes map to standard types not in the table. */
572 if (q != qualifier_poly && !VECTOR_MODE_P (mode))
573 return aarch64_simd_builtin_std_type (mode, q);
575 for (i = 0; i < nelts; i++)
576 if (aarch64_simd_types[i].mode == mode
577 && aarch64_simd_types[i].q == q)
578 return aarch64_simd_types[i].itype;
580 return NULL_TREE;
583 static tree
584 aarch64_simd_builtin_type (enum machine_mode mode,
585 bool unsigned_p, bool poly_p)
587 if (poly_p)
588 return aarch64_lookup_simd_builtin_type (mode, qualifier_poly);
589 else if (unsigned_p)
590 return aarch64_lookup_simd_builtin_type (mode, qualifier_unsigned);
591 else
592 return aarch64_lookup_simd_builtin_type (mode, qualifier_none);
595 static void
596 aarch64_init_simd_builtin_types (void)
598 int i;
599 int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
600 tree tdecl;
602 /* Init all the element types built by the front-end. */
603 aarch64_simd_types[Int8x8_t].eltype = intQI_type_node;
604 aarch64_simd_types[Int8x16_t].eltype = intQI_type_node;
605 aarch64_simd_types[Int16x4_t].eltype = intHI_type_node;
606 aarch64_simd_types[Int16x8_t].eltype = intHI_type_node;
607 aarch64_simd_types[Int32x2_t].eltype = intSI_type_node;
608 aarch64_simd_types[Int32x4_t].eltype = intSI_type_node;
609 aarch64_simd_types[Int64x1_t].eltype = intDI_type_node;
610 aarch64_simd_types[Int64x2_t].eltype = intDI_type_node;
611 aarch64_simd_types[Uint8x8_t].eltype = unsigned_intQI_type_node;
612 aarch64_simd_types[Uint8x16_t].eltype = unsigned_intQI_type_node;
613 aarch64_simd_types[Uint16x4_t].eltype = unsigned_intHI_type_node;
614 aarch64_simd_types[Uint16x8_t].eltype = unsigned_intHI_type_node;
615 aarch64_simd_types[Uint32x2_t].eltype = unsigned_intSI_type_node;
616 aarch64_simd_types[Uint32x4_t].eltype = unsigned_intSI_type_node;
617 aarch64_simd_types[Uint64x1_t].eltype = unsigned_intDI_type_node;
618 aarch64_simd_types[Uint64x2_t].eltype = unsigned_intDI_type_node;
620 /* Poly types are a world of their own. */
621 aarch64_simd_types[Poly8_t].eltype = aarch64_simd_types[Poly8_t].itype =
622 build_distinct_type_copy (unsigned_intQI_type_node);
623 aarch64_simd_types[Poly16_t].eltype = aarch64_simd_types[Poly16_t].itype =
624 build_distinct_type_copy (unsigned_intHI_type_node);
625 aarch64_simd_types[Poly64_t].eltype = aarch64_simd_types[Poly64_t].itype =
626 build_distinct_type_copy (unsigned_intDI_type_node);
627 aarch64_simd_types[Poly128_t].eltype = aarch64_simd_types[Poly128_t].itype =
628 build_distinct_type_copy (unsigned_intTI_type_node);
629 /* Init poly vector element types with scalar poly types. */
630 aarch64_simd_types[Poly8x8_t].eltype = aarch64_simd_types[Poly8_t].itype;
631 aarch64_simd_types[Poly8x16_t].eltype = aarch64_simd_types[Poly8_t].itype;
632 aarch64_simd_types[Poly16x4_t].eltype = aarch64_simd_types[Poly16_t].itype;
633 aarch64_simd_types[Poly16x8_t].eltype = aarch64_simd_types[Poly16_t].itype;
634 aarch64_simd_types[Poly64x1_t].eltype = aarch64_simd_types[Poly64_t].itype;
635 aarch64_simd_types[Poly64x2_t].eltype = aarch64_simd_types[Poly64_t].itype;
637 /* Continue with standard types. */
638 aarch64_simd_types[Float16x4_t].eltype = aarch64_fp16_type_node;
639 aarch64_simd_types[Float16x8_t].eltype = aarch64_fp16_type_node;
640 aarch64_simd_types[Float32x2_t].eltype = float_type_node;
641 aarch64_simd_types[Float32x4_t].eltype = float_type_node;
642 aarch64_simd_types[Float64x1_t].eltype = double_type_node;
643 aarch64_simd_types[Float64x2_t].eltype = double_type_node;
645 for (i = 0; i < nelts; i++)
647 tree eltype = aarch64_simd_types[i].eltype;
648 enum machine_mode mode = aarch64_simd_types[i].mode;
650 if (aarch64_simd_types[i].itype == NULL)
652 aarch64_simd_types[i].itype
653 = build_distinct_type_copy
654 (build_vector_type (eltype, GET_MODE_NUNITS (mode)));
655 SET_TYPE_STRUCTURAL_EQUALITY (aarch64_simd_types[i].itype);
658 tdecl = add_builtin_type (aarch64_simd_types[i].name,
659 aarch64_simd_types[i].itype);
660 TYPE_NAME (aarch64_simd_types[i].itype) = tdecl;
663 #define AARCH64_BUILD_SIGNED_TYPE(mode) \
664 make_signed_type (GET_MODE_PRECISION (mode));
665 aarch64_simd_intOI_type_node = AARCH64_BUILD_SIGNED_TYPE (OImode);
666 aarch64_simd_intCI_type_node = AARCH64_BUILD_SIGNED_TYPE (CImode);
667 aarch64_simd_intXI_type_node = AARCH64_BUILD_SIGNED_TYPE (XImode);
668 #undef AARCH64_BUILD_SIGNED_TYPE
670 tdecl = add_builtin_type
671 ("__builtin_aarch64_simd_oi" , aarch64_simd_intOI_type_node);
672 TYPE_NAME (aarch64_simd_intOI_type_node) = tdecl;
673 tdecl = add_builtin_type
674 ("__builtin_aarch64_simd_ci" , aarch64_simd_intCI_type_node);
675 TYPE_NAME (aarch64_simd_intCI_type_node) = tdecl;
676 tdecl = add_builtin_type
677 ("__builtin_aarch64_simd_xi" , aarch64_simd_intXI_type_node);
678 TYPE_NAME (aarch64_simd_intXI_type_node) = tdecl;
681 static void
682 aarch64_init_simd_builtin_scalar_types (void)
684 /* Define typedefs for all the standard scalar types. */
685 (*lang_hooks.types.register_builtin_type) (intQI_type_node,
686 "__builtin_aarch64_simd_qi");
687 (*lang_hooks.types.register_builtin_type) (intHI_type_node,
688 "__builtin_aarch64_simd_hi");
689 (*lang_hooks.types.register_builtin_type) (aarch64_fp16_type_node,
690 "__builtin_aarch64_simd_hf");
691 (*lang_hooks.types.register_builtin_type) (intSI_type_node,
692 "__builtin_aarch64_simd_si");
693 (*lang_hooks.types.register_builtin_type) (float_type_node,
694 "__builtin_aarch64_simd_sf");
695 (*lang_hooks.types.register_builtin_type) (intDI_type_node,
696 "__builtin_aarch64_simd_di");
697 (*lang_hooks.types.register_builtin_type) (double_type_node,
698 "__builtin_aarch64_simd_df");
699 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
700 "__builtin_aarch64_simd_poly8");
701 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
702 "__builtin_aarch64_simd_poly16");
703 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
704 "__builtin_aarch64_simd_poly64");
705 (*lang_hooks.types.register_builtin_type) (unsigned_intTI_type_node,
706 "__builtin_aarch64_simd_poly128");
707 (*lang_hooks.types.register_builtin_type) (intTI_type_node,
708 "__builtin_aarch64_simd_ti");
709 /* Unsigned integer types for various mode sizes. */
710 (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
711 "__builtin_aarch64_simd_uqi");
712 (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
713 "__builtin_aarch64_simd_uhi");
714 (*lang_hooks.types.register_builtin_type) (unsigned_intSI_type_node,
715 "__builtin_aarch64_simd_usi");
716 (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
717 "__builtin_aarch64_simd_udi");
720 static bool aarch64_simd_builtins_initialized_p = false;
722 void
723 aarch64_init_simd_builtins (void)
725 unsigned int i, fcode = AARCH64_SIMD_PATTERN_START;
727 if (aarch64_simd_builtins_initialized_p)
728 return;
730 aarch64_simd_builtins_initialized_p = true;
732 aarch64_init_simd_builtin_types ();
734 /* Strong-typing hasn't been implemented for all AdvSIMD builtin intrinsics.
735 Therefore we need to preserve the old __builtin scalar types. It can be
736 removed once all the intrinsics become strongly typed using the qualifier
737 system. */
738 aarch64_init_simd_builtin_scalar_types ();
740 tree lane_check_fpr = build_function_type_list (void_type_node,
741 size_type_node,
742 size_type_node,
743 intSI_type_node,
744 NULL);
745 aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_LANE_CHECK] =
746 add_builtin_function ("__builtin_aarch64_im_lane_boundsi", lane_check_fpr,
747 AARCH64_SIMD_BUILTIN_LANE_CHECK, BUILT_IN_MD,
748 NULL, NULL_TREE);
750 for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++)
752 bool print_type_signature_p = false;
753 char type_signature[SIMD_MAX_BUILTIN_ARGS] = { 0 };
754 aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i];
755 char namebuf[60];
756 tree ftype = NULL;
757 tree fndecl = NULL;
759 d->fcode = fcode;
761 /* We must track two variables here. op_num is
762 the operand number as in the RTL pattern. This is
763 required to access the mode (e.g. V4SF mode) of the
764 argument, from which the base type can be derived.
765 arg_num is an index in to the qualifiers data, which
766 gives qualifiers to the type (e.g. const unsigned).
767 The reason these two variables may differ by one is the
768 void return type. While all return types take the 0th entry
769 in the qualifiers array, there is no operand for them in the
770 RTL pattern. */
771 int op_num = insn_data[d->code].n_operands - 1;
772 int arg_num = d->qualifiers[0] & qualifier_void
773 ? op_num + 1
774 : op_num;
775 tree return_type = void_type_node, args = void_list_node;
776 tree eltype;
778 /* Build a function type directly from the insn_data for this
779 builtin. The build_function_type () function takes care of
780 removing duplicates for us. */
781 for (; op_num >= 0; arg_num--, op_num--)
783 machine_mode op_mode = insn_data[d->code].operand[op_num].mode;
784 enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num];
786 if (qualifiers & qualifier_unsigned)
788 type_signature[op_num] = 'u';
789 print_type_signature_p = true;
791 else if (qualifiers & qualifier_poly)
793 type_signature[op_num] = 'p';
794 print_type_signature_p = true;
796 else
797 type_signature[op_num] = 's';
799 /* Skip an internal operand for vget_{low, high}. */
800 if (qualifiers & qualifier_internal)
801 continue;
803 /* Some builtins have different user-facing types
804 for certain arguments, encoded in d->mode. */
805 if (qualifiers & qualifier_map_mode)
806 op_mode = d->mode;
808 /* For pointers, we want a pointer to the basic type
809 of the vector. */
810 if (qualifiers & qualifier_pointer && VECTOR_MODE_P (op_mode))
811 op_mode = GET_MODE_INNER (op_mode);
813 eltype = aarch64_simd_builtin_type
814 (op_mode,
815 (qualifiers & qualifier_unsigned) != 0,
816 (qualifiers & qualifier_poly) != 0);
817 gcc_assert (eltype != NULL);
819 /* Add qualifiers. */
820 if (qualifiers & qualifier_const)
821 eltype = build_qualified_type (eltype, TYPE_QUAL_CONST);
823 if (qualifiers & qualifier_pointer)
824 eltype = build_pointer_type (eltype);
826 /* If we have reached arg_num == 0, we are at a non-void
827 return type. Otherwise, we are still processing
828 arguments. */
829 if (arg_num == 0)
830 return_type = eltype;
831 else
832 args = tree_cons (NULL_TREE, eltype, args);
835 ftype = build_function_type (return_type, args);
837 gcc_assert (ftype != NULL);
839 if (print_type_signature_p)
840 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s_%s",
841 d->name, type_signature);
842 else
843 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s",
844 d->name);
846 fndecl = add_builtin_function (namebuf, ftype, fcode, BUILT_IN_MD,
847 NULL, NULL_TREE);
848 aarch64_builtin_decls[fcode] = fndecl;
852 static void
853 aarch64_init_crc32_builtins ()
855 tree usi_type = aarch64_simd_builtin_std_type (SImode, qualifier_unsigned);
856 unsigned int i = 0;
858 for (i = 0; i < ARRAY_SIZE (aarch64_crc_builtin_data); ++i)
860 aarch64_crc_builtin_datum* d = &aarch64_crc_builtin_data[i];
861 tree argtype = aarch64_simd_builtin_std_type (d->mode,
862 qualifier_unsigned);
863 tree ftype = build_function_type_list (usi_type, usi_type, argtype, NULL_TREE);
864 tree fndecl = add_builtin_function (d->name, ftype, d->fcode,
865 BUILT_IN_MD, NULL, NULL_TREE);
867 aarch64_builtin_decls[d->fcode] = fndecl;
871 /* Add builtins for reciprocal square root. */
873 void
874 aarch64_init_builtin_rsqrt (void)
876 tree fndecl = NULL;
877 tree ftype = NULL;
879 tree V2SF_type_node = build_vector_type (float_type_node, 2);
880 tree V2DF_type_node = build_vector_type (double_type_node, 2);
881 tree V4SF_type_node = build_vector_type (float_type_node, 4);
883 struct builtin_decls_data
885 tree type_node;
886 const char *builtin_name;
887 int function_code;
890 builtin_decls_data bdda[] =
892 { double_type_node, "__builtin_aarch64_rsqrt_df", AARCH64_BUILTIN_RSQRT_DF },
893 { float_type_node, "__builtin_aarch64_rsqrt_sf", AARCH64_BUILTIN_RSQRT_SF },
894 { V2DF_type_node, "__builtin_aarch64_rsqrt_v2df", AARCH64_BUILTIN_RSQRT_V2DF },
895 { V2SF_type_node, "__builtin_aarch64_rsqrt_v2sf", AARCH64_BUILTIN_RSQRT_V2SF },
896 { V4SF_type_node, "__builtin_aarch64_rsqrt_v4sf", AARCH64_BUILTIN_RSQRT_V4SF }
899 builtin_decls_data *bdd = bdda;
900 builtin_decls_data *bdd_end = bdd + (sizeof (bdda) / sizeof (builtin_decls_data));
902 for (; bdd < bdd_end; bdd++)
904 ftype = build_function_type_list (bdd->type_node, bdd->type_node, NULL_TREE);
905 fndecl = add_builtin_function (bdd->builtin_name,
906 ftype, bdd->function_code, BUILT_IN_MD, NULL, NULL_TREE);
907 aarch64_builtin_decls[bdd->function_code] = fndecl;
911 /* Initialize the backend types that support the user-visible __fp16
912 type, also initialize a pointer to that type, to be used when
913 forming HFAs. */
915 static void
916 aarch64_init_fp16_types (void)
918 aarch64_fp16_type_node = make_node (REAL_TYPE);
919 TYPE_PRECISION (aarch64_fp16_type_node) = 16;
920 layout_type (aarch64_fp16_type_node);
922 (*lang_hooks.types.register_builtin_type) (aarch64_fp16_type_node, "__fp16");
923 aarch64_fp16_ptr_type_node = build_pointer_type (aarch64_fp16_type_node);
926 void
927 aarch64_init_builtins (void)
929 tree ftype_set_fpr
930 = build_function_type_list (void_type_node, unsigned_type_node, NULL);
931 tree ftype_get_fpr
932 = build_function_type_list (unsigned_type_node, NULL);
934 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR]
935 = add_builtin_function ("__builtin_aarch64_get_fpcr", ftype_get_fpr,
936 AARCH64_BUILTIN_GET_FPCR, BUILT_IN_MD, NULL, NULL_TREE);
937 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR]
938 = add_builtin_function ("__builtin_aarch64_set_fpcr", ftype_set_fpr,
939 AARCH64_BUILTIN_SET_FPCR, BUILT_IN_MD, NULL, NULL_TREE);
940 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR]
941 = add_builtin_function ("__builtin_aarch64_get_fpsr", ftype_get_fpr,
942 AARCH64_BUILTIN_GET_FPSR, BUILT_IN_MD, NULL, NULL_TREE);
943 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR]
944 = add_builtin_function ("__builtin_aarch64_set_fpsr", ftype_set_fpr,
945 AARCH64_BUILTIN_SET_FPSR, BUILT_IN_MD, NULL, NULL_TREE);
947 aarch64_init_fp16_types ();
949 if (TARGET_SIMD)
950 aarch64_init_simd_builtins ();
952 aarch64_init_crc32_builtins ();
953 aarch64_init_builtin_rsqrt ();
956 tree
957 aarch64_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
959 if (code >= AARCH64_BUILTIN_MAX)
960 return error_mark_node;
962 return aarch64_builtin_decls[code];
965 typedef enum
967 SIMD_ARG_COPY_TO_REG,
968 SIMD_ARG_CONSTANT,
969 SIMD_ARG_LANE_INDEX,
970 SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX,
971 SIMD_ARG_STOP
972 } builtin_simd_arg;
975 static rtx
976 aarch64_simd_expand_args (rtx target, int icode, int have_retval,
977 tree exp, builtin_simd_arg *args,
978 enum machine_mode builtin_mode)
980 rtx pat;
981 rtx op[SIMD_MAX_BUILTIN_ARGS + 1]; /* First element for result operand. */
982 int opc = 0;
984 if (have_retval)
986 machine_mode tmode = insn_data[icode].operand[0].mode;
987 if (!target
988 || GET_MODE (target) != tmode
989 || !(*insn_data[icode].operand[0].predicate) (target, tmode))
990 target = gen_reg_rtx (tmode);
991 op[opc++] = target;
994 for (;;)
996 builtin_simd_arg thisarg = args[opc - have_retval];
998 if (thisarg == SIMD_ARG_STOP)
999 break;
1000 else
1002 tree arg = CALL_EXPR_ARG (exp, opc - have_retval);
1003 enum machine_mode mode = insn_data[icode].operand[opc].mode;
1004 op[opc] = expand_normal (arg);
1006 switch (thisarg)
1008 case SIMD_ARG_COPY_TO_REG:
1009 if (POINTER_TYPE_P (TREE_TYPE (arg)))
1010 op[opc] = convert_memory_address (Pmode, op[opc]);
1011 /*gcc_assert (GET_MODE (op[opc]) == mode); */
1012 if (!(*insn_data[icode].operand[opc].predicate)
1013 (op[opc], mode))
1014 op[opc] = copy_to_mode_reg (mode, op[opc]);
1015 break;
1017 case SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX:
1018 gcc_assert (opc > 1);
1019 if (CONST_INT_P (op[opc]))
1021 aarch64_simd_lane_bounds (op[opc], 0,
1022 GET_MODE_NUNITS (builtin_mode),
1023 exp);
1024 /* Keep to GCC-vector-extension lane indices in the RTL. */
1025 op[opc] =
1026 GEN_INT (ENDIAN_LANE_N (builtin_mode, INTVAL (op[opc])));
1028 goto constant_arg;
1030 case SIMD_ARG_LANE_INDEX:
1031 /* Must be a previous operand into which this is an index. */
1032 gcc_assert (opc > 0);
1033 if (CONST_INT_P (op[opc]))
1035 machine_mode vmode = insn_data[icode].operand[opc - 1].mode;
1036 aarch64_simd_lane_bounds (op[opc],
1037 0, GET_MODE_NUNITS (vmode), exp);
1038 /* Keep to GCC-vector-extension lane indices in the RTL. */
1039 op[opc] = GEN_INT (ENDIAN_LANE_N (vmode, INTVAL (op[opc])));
1041 /* Fall through - if the lane index isn't a constant then
1042 the next case will error. */
1043 /* FALLTHRU */
1044 case SIMD_ARG_CONSTANT:
1045 constant_arg:
1046 if (!(*insn_data[icode].operand[opc].predicate)
1047 (op[opc], mode))
1049 error ("%Kargument %d must be a constant immediate",
1050 exp, opc + 1 - have_retval);
1051 return const0_rtx;
1053 break;
1055 case SIMD_ARG_STOP:
1056 gcc_unreachable ();
1059 opc++;
1063 switch (opc)
1065 case 1:
1066 pat = GEN_FCN (icode) (op[0]);
1067 break;
1069 case 2:
1070 pat = GEN_FCN (icode) (op[0], op[1]);
1071 break;
1073 case 3:
1074 pat = GEN_FCN (icode) (op[0], op[1], op[2]);
1075 break;
1077 case 4:
1078 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
1079 break;
1081 case 5:
1082 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
1083 break;
1085 case 6:
1086 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]);
1087 break;
1089 default:
1090 gcc_unreachable ();
1093 if (!pat)
1094 return NULL_RTX;
1096 emit_insn (pat);
1098 return target;
1101 /* Expand an AArch64 AdvSIMD builtin(intrinsic). */
1103 aarch64_simd_expand_builtin (int fcode, tree exp, rtx target)
1105 if (fcode == AARCH64_SIMD_BUILTIN_LANE_CHECK)
1107 rtx totalsize = expand_normal (CALL_EXPR_ARG (exp, 0));
1108 rtx elementsize = expand_normal (CALL_EXPR_ARG (exp, 1));
1109 if (CONST_INT_P (totalsize) && CONST_INT_P (elementsize)
1110 && UINTVAL (elementsize) != 0
1111 && UINTVAL (totalsize) != 0)
1113 rtx lane_idx = expand_normal (CALL_EXPR_ARG (exp, 2));
1114 if (CONST_INT_P (lane_idx))
1115 aarch64_simd_lane_bounds (lane_idx, 0,
1116 UINTVAL (totalsize)
1117 / UINTVAL (elementsize),
1118 exp);
1119 else
1120 error ("%Klane index must be a constant immediate", exp);
1122 else
1123 error ("%Ktotal size and element size must be a non-zero constant immediate", exp);
1124 /* Don't generate any RTL. */
1125 return const0_rtx;
1127 aarch64_simd_builtin_datum *d =
1128 &aarch64_simd_builtin_data[fcode - AARCH64_SIMD_PATTERN_START];
1129 enum insn_code icode = d->code;
1130 builtin_simd_arg args[SIMD_MAX_BUILTIN_ARGS + 1];
1131 int num_args = insn_data[d->code].n_operands;
1132 int is_void = 0;
1133 int k;
1135 is_void = !!(d->qualifiers[0] & qualifier_void);
1137 num_args += is_void;
1139 for (k = 1; k < num_args; k++)
1141 /* We have four arrays of data, each indexed in a different fashion.
1142 qualifiers - element 0 always describes the function return type.
1143 operands - element 0 is either the operand for return value (if
1144 the function has a non-void return type) or the operand for the
1145 first argument.
1146 expr_args - element 0 always holds the first argument.
1147 args - element 0 is always used for the return type. */
1148 int qualifiers_k = k;
1149 int operands_k = k - is_void;
1150 int expr_args_k = k - 1;
1152 if (d->qualifiers[qualifiers_k] & qualifier_lane_index)
1153 args[k] = SIMD_ARG_LANE_INDEX;
1154 else if (d->qualifiers[qualifiers_k] & qualifier_struct_load_store_lane_index)
1155 args[k] = SIMD_ARG_STRUCT_LOAD_STORE_LANE_INDEX;
1156 else if (d->qualifiers[qualifiers_k] & qualifier_immediate)
1157 args[k] = SIMD_ARG_CONSTANT;
1158 else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate)
1160 rtx arg
1161 = expand_normal (CALL_EXPR_ARG (exp,
1162 (expr_args_k)));
1163 /* Handle constants only if the predicate allows it. */
1164 bool op_const_int_p =
1165 (CONST_INT_P (arg)
1166 && (*insn_data[icode].operand[operands_k].predicate)
1167 (arg, insn_data[icode].operand[operands_k].mode));
1168 args[k] = op_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG;
1170 else
1171 args[k] = SIMD_ARG_COPY_TO_REG;
1174 args[k] = SIMD_ARG_STOP;
1176 /* The interface to aarch64_simd_expand_args expects a 0 if
1177 the function is void, and a 1 if it is not. */
1178 return aarch64_simd_expand_args
1179 (target, icode, !is_void, exp, &args[1], d->mode);
1183 aarch64_crc32_expand_builtin (int fcode, tree exp, rtx target)
1185 rtx pat;
1186 aarch64_crc_builtin_datum *d
1187 = &aarch64_crc_builtin_data[fcode - (AARCH64_CRC32_BUILTIN_BASE + 1)];
1188 enum insn_code icode = d->icode;
1189 tree arg0 = CALL_EXPR_ARG (exp, 0);
1190 tree arg1 = CALL_EXPR_ARG (exp, 1);
1191 rtx op0 = expand_normal (arg0);
1192 rtx op1 = expand_normal (arg1);
1193 machine_mode tmode = insn_data[icode].operand[0].mode;
1194 machine_mode mode0 = insn_data[icode].operand[1].mode;
1195 machine_mode mode1 = insn_data[icode].operand[2].mode;
1197 if (! target
1198 || GET_MODE (target) != tmode
1199 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1200 target = gen_reg_rtx (tmode);
1202 gcc_assert ((GET_MODE (op0) == mode0 || GET_MODE (op0) == VOIDmode)
1203 && (GET_MODE (op1) == mode1 || GET_MODE (op1) == VOIDmode));
1205 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1206 op0 = copy_to_mode_reg (mode0, op0);
1207 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
1208 op1 = copy_to_mode_reg (mode1, op1);
1210 pat = GEN_FCN (icode) (target, op0, op1);
1211 if (!pat)
1212 return NULL_RTX;
1214 emit_insn (pat);
1215 return target;
1218 /* Function to expand reciprocal square root builtins. */
1220 static rtx
1221 aarch64_expand_builtin_rsqrt (int fcode, tree exp, rtx target)
1223 tree arg0 = CALL_EXPR_ARG (exp, 0);
1224 rtx op0 = expand_normal (arg0);
1226 rtx (*gen) (rtx, rtx);
1228 switch (fcode)
1230 case AARCH64_BUILTIN_RSQRT_DF:
1231 gen = gen_rsqrtdf2;
1232 break;
1233 case AARCH64_BUILTIN_RSQRT_SF:
1234 gen = gen_rsqrtsf2;
1235 break;
1236 case AARCH64_BUILTIN_RSQRT_V2DF:
1237 gen = gen_rsqrtv2df2;
1238 break;
1239 case AARCH64_BUILTIN_RSQRT_V2SF:
1240 gen = gen_rsqrtv2sf2;
1241 break;
1242 case AARCH64_BUILTIN_RSQRT_V4SF:
1243 gen = gen_rsqrtv4sf2;
1244 break;
1245 default: gcc_unreachable ();
1248 if (!target)
1249 target = gen_reg_rtx (GET_MODE (op0));
1251 emit_insn (gen (target, op0));
1253 return target;
1256 /* Expand an expression EXP that calls a built-in function,
1257 with result going to TARGET if that's convenient. */
1259 aarch64_expand_builtin (tree exp,
1260 rtx target,
1261 rtx subtarget ATTRIBUTE_UNUSED,
1262 machine_mode mode ATTRIBUTE_UNUSED,
1263 int ignore ATTRIBUTE_UNUSED)
1265 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
1266 int fcode = DECL_FUNCTION_CODE (fndecl);
1267 int icode;
1268 rtx pat, op0;
1269 tree arg0;
1271 switch (fcode)
1273 case AARCH64_BUILTIN_GET_FPCR:
1274 case AARCH64_BUILTIN_SET_FPCR:
1275 case AARCH64_BUILTIN_GET_FPSR:
1276 case AARCH64_BUILTIN_SET_FPSR:
1277 if ((fcode == AARCH64_BUILTIN_GET_FPCR)
1278 || (fcode == AARCH64_BUILTIN_GET_FPSR))
1280 icode = (fcode == AARCH64_BUILTIN_GET_FPSR) ?
1281 CODE_FOR_get_fpsr : CODE_FOR_get_fpcr;
1282 target = gen_reg_rtx (SImode);
1283 pat = GEN_FCN (icode) (target);
1285 else
1287 target = NULL_RTX;
1288 icode = (fcode == AARCH64_BUILTIN_SET_FPSR) ?
1289 CODE_FOR_set_fpsr : CODE_FOR_set_fpcr;
1290 arg0 = CALL_EXPR_ARG (exp, 0);
1291 op0 = force_reg (SImode, expand_normal (arg0));
1292 pat = GEN_FCN (icode) (op0);
1294 emit_insn (pat);
1295 return target;
1298 if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
1299 return aarch64_simd_expand_builtin (fcode, exp, target);
1300 else if (fcode >= AARCH64_CRC32_BUILTIN_BASE && fcode <= AARCH64_CRC32_BUILTIN_MAX)
1301 return aarch64_crc32_expand_builtin (fcode, exp, target);
1303 if (fcode == AARCH64_BUILTIN_RSQRT_DF
1304 || fcode == AARCH64_BUILTIN_RSQRT_SF
1305 || fcode == AARCH64_BUILTIN_RSQRT_V2DF
1306 || fcode == AARCH64_BUILTIN_RSQRT_V2SF
1307 || fcode == AARCH64_BUILTIN_RSQRT_V4SF)
1308 return aarch64_expand_builtin_rsqrt (fcode, exp, target);
1310 gcc_unreachable ();
1313 tree
1314 aarch64_builtin_vectorized_function (unsigned int fn, tree type_out,
1315 tree type_in)
1317 machine_mode in_mode, out_mode;
1318 int in_n, out_n;
1320 if (TREE_CODE (type_out) != VECTOR_TYPE
1321 || TREE_CODE (type_in) != VECTOR_TYPE)
1322 return NULL_TREE;
1324 out_mode = TYPE_MODE (TREE_TYPE (type_out));
1325 out_n = TYPE_VECTOR_SUBPARTS (type_out);
1326 in_mode = TYPE_MODE (TREE_TYPE (type_in));
1327 in_n = TYPE_VECTOR_SUBPARTS (type_in);
1329 #undef AARCH64_CHECK_BUILTIN_MODE
1330 #define AARCH64_CHECK_BUILTIN_MODE(C, N) 1
1331 #define AARCH64_FIND_FRINT_VARIANT(N) \
1332 (AARCH64_CHECK_BUILTIN_MODE (2, D) \
1333 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2df] \
1334 : (AARCH64_CHECK_BUILTIN_MODE (4, S) \
1335 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v4sf] \
1336 : (AARCH64_CHECK_BUILTIN_MODE (2, S) \
1337 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2sf] \
1338 : NULL_TREE)))
1339 switch (fn)
1341 #undef AARCH64_CHECK_BUILTIN_MODE
1342 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1343 (out_mode == N##Fmode && out_n == C \
1344 && in_mode == N##Fmode && in_n == C)
1345 CASE_CFN_FLOOR:
1346 return AARCH64_FIND_FRINT_VARIANT (floor);
1347 CASE_CFN_CEIL:
1348 return AARCH64_FIND_FRINT_VARIANT (ceil);
1349 CASE_CFN_TRUNC:
1350 return AARCH64_FIND_FRINT_VARIANT (btrunc);
1351 CASE_CFN_ROUND:
1352 return AARCH64_FIND_FRINT_VARIANT (round);
1353 CASE_CFN_NEARBYINT:
1354 return AARCH64_FIND_FRINT_VARIANT (nearbyint);
1355 CASE_CFN_SQRT:
1356 return AARCH64_FIND_FRINT_VARIANT (sqrt);
1357 #undef AARCH64_CHECK_BUILTIN_MODE
1358 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1359 (out_mode == SImode && out_n == C \
1360 && in_mode == N##Imode && in_n == C)
1361 CASE_CFN_CLZ:
1363 if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1364 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_clzv4si];
1365 return NULL_TREE;
1367 CASE_CFN_CTZ:
1369 if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1370 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv2si];
1371 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1372 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv4si];
1373 return NULL_TREE;
1375 #undef AARCH64_CHECK_BUILTIN_MODE
1376 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1377 (out_mode == N##Imode && out_n == C \
1378 && in_mode == N##Fmode && in_n == C)
1379 CASE_CFN_IFLOOR:
1380 CASE_CFN_LFLOOR:
1381 CASE_CFN_LLFLOOR:
1383 enum aarch64_builtins builtin;
1384 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1385 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2dfv2di;
1386 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1387 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv4sfv4si;
1388 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1389 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2sfv2si;
1390 else
1391 return NULL_TREE;
1393 return aarch64_builtin_decls[builtin];
1395 CASE_CFN_ICEIL:
1396 CASE_CFN_LCEIL:
1397 CASE_CFN_LLCEIL:
1399 enum aarch64_builtins builtin;
1400 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1401 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2dfv2di;
1402 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1403 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv4sfv4si;
1404 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1405 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2sfv2si;
1406 else
1407 return NULL_TREE;
1409 return aarch64_builtin_decls[builtin];
1411 CASE_CFN_IROUND:
1412 CASE_CFN_LROUND:
1413 CASE_CFN_LLROUND:
1415 enum aarch64_builtins builtin;
1416 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1417 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2dfv2di;
1418 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1419 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv4sfv4si;
1420 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1421 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2sfv2si;
1422 else
1423 return NULL_TREE;
1425 return aarch64_builtin_decls[builtin];
1427 case CFN_BUILT_IN_BSWAP16:
1428 #undef AARCH64_CHECK_BUILTIN_MODE
1429 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1430 (out_mode == N##Imode && out_n == C \
1431 && in_mode == N##Imode && in_n == C)
1432 if (AARCH64_CHECK_BUILTIN_MODE (4, H))
1433 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4hi];
1434 else if (AARCH64_CHECK_BUILTIN_MODE (8, H))
1435 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv8hi];
1436 else
1437 return NULL_TREE;
1438 case CFN_BUILT_IN_BSWAP32:
1439 if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1440 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2si];
1441 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1442 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4si];
1443 else
1444 return NULL_TREE;
1445 case CFN_BUILT_IN_BSWAP64:
1446 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1447 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2di];
1448 else
1449 return NULL_TREE;
1450 default:
1451 return NULL_TREE;
1454 return NULL_TREE;
1457 /* Return builtin for reciprocal square root. */
1459 tree
1460 aarch64_builtin_rsqrt (unsigned int fn)
1462 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv2df)
1463 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V2DF];
1464 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv2sf)
1465 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V2SF];
1466 if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv4sf)
1467 return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V4SF];
1468 return NULL_TREE;
1471 #undef VAR1
1472 #define VAR1(T, N, MAP, A) \
1473 case AARCH64_SIMD_BUILTIN_##T##_##N##A:
1475 tree
1476 aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args,
1477 bool ignore ATTRIBUTE_UNUSED)
1479 int fcode = DECL_FUNCTION_CODE (fndecl);
1480 tree type = TREE_TYPE (TREE_TYPE (fndecl));
1482 switch (fcode)
1484 BUILTIN_VDQF (UNOP, abs, 2)
1485 return fold_build1 (ABS_EXPR, type, args[0]);
1486 VAR1 (UNOP, floatv2si, 2, v2sf)
1487 VAR1 (UNOP, floatv4si, 2, v4sf)
1488 VAR1 (UNOP, floatv2di, 2, v2df)
1489 return fold_build1 (FLOAT_EXPR, type, args[0]);
1490 default:
1491 break;
1494 return NULL_TREE;
1497 bool
1498 aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi)
1500 bool changed = false;
1501 gimple *stmt = gsi_stmt (*gsi);
1502 tree call = gimple_call_fn (stmt);
1503 tree fndecl;
1504 gimple *new_stmt = NULL;
1506 if (call)
1508 fndecl = gimple_call_fndecl (stmt);
1509 if (fndecl)
1511 int fcode = DECL_FUNCTION_CODE (fndecl);
1512 unsigned nargs = gimple_call_num_args (stmt);
1513 tree *args = (nargs > 0
1514 ? gimple_call_arg_ptr (stmt, 0)
1515 : &error_mark_node);
1517 /* We use gimple's REDUC_(PLUS|MIN|MAX)_EXPRs for float, signed int
1518 and unsigned int; it will distinguish according to the types of
1519 the arguments to the __builtin. */
1520 switch (fcode)
1522 BUILTIN_VALL (UNOP, reduc_plus_scal_, 10)
1523 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
1524 REDUC_PLUS_EXPR, args[0]);
1525 break;
1526 BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10)
1527 BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10)
1528 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
1529 REDUC_MAX_EXPR, args[0]);
1530 break;
1531 BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10)
1532 BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10)
1533 new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
1534 REDUC_MIN_EXPR, args[0]);
1535 break;
1536 BUILTIN_GPF (BINOP, fmulx, 0)
1538 gcc_assert (nargs == 2);
1539 bool a0_cst_p = TREE_CODE (args[0]) == REAL_CST;
1540 bool a1_cst_p = TREE_CODE (args[1]) == REAL_CST;
1541 if (a0_cst_p || a1_cst_p)
1543 if (a0_cst_p && a1_cst_p)
1545 tree t0 = TREE_TYPE (args[0]);
1546 real_value a0 = (TREE_REAL_CST (args[0]));
1547 real_value a1 = (TREE_REAL_CST (args[1]));
1548 if (real_equal (&a1, &dconst0))
1549 std::swap (a0, a1);
1550 /* According to real_equal (), +0 equals -0. */
1551 if (real_equal (&a0, &dconst0) && real_isinf (&a1))
1553 real_value res = dconst2;
1554 res.sign = a0.sign ^ a1.sign;
1555 new_stmt =
1556 gimple_build_assign (gimple_call_lhs (stmt),
1557 REAL_CST,
1558 build_real (t0, res));
1560 else
1561 new_stmt =
1562 gimple_build_assign (gimple_call_lhs (stmt),
1563 MULT_EXPR,
1564 args[0], args[1]);
1566 else /* a0_cst_p ^ a1_cst_p. */
1568 real_value const_part = a0_cst_p
1569 ? TREE_REAL_CST (args[0]) : TREE_REAL_CST (args[1]);
1570 if (!real_equal (&const_part, &dconst0)
1571 && !real_isinf (&const_part))
1572 new_stmt =
1573 gimple_build_assign (gimple_call_lhs (stmt),
1574 MULT_EXPR, args[0], args[1]);
1577 if (new_stmt)
1579 gimple_set_vuse (new_stmt, gimple_vuse (stmt));
1580 gimple_set_vdef (new_stmt, gimple_vdef (stmt));
1582 break;
1584 default:
1585 break;
1590 if (new_stmt)
1592 gsi_replace (gsi, new_stmt, true);
1593 changed = true;
1596 return changed;
1599 void
1600 aarch64_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
1602 const unsigned AARCH64_FE_INVALID = 1;
1603 const unsigned AARCH64_FE_DIVBYZERO = 2;
1604 const unsigned AARCH64_FE_OVERFLOW = 4;
1605 const unsigned AARCH64_FE_UNDERFLOW = 8;
1606 const unsigned AARCH64_FE_INEXACT = 16;
1607 const unsigned HOST_WIDE_INT AARCH64_FE_ALL_EXCEPT = (AARCH64_FE_INVALID
1608 | AARCH64_FE_DIVBYZERO
1609 | AARCH64_FE_OVERFLOW
1610 | AARCH64_FE_UNDERFLOW
1611 | AARCH64_FE_INEXACT);
1612 const unsigned HOST_WIDE_INT AARCH64_FE_EXCEPT_SHIFT = 8;
1613 tree fenv_cr, fenv_sr, get_fpcr, set_fpcr, mask_cr, mask_sr;
1614 tree ld_fenv_cr, ld_fenv_sr, masked_fenv_cr, masked_fenv_sr, hold_fnclex_cr;
1615 tree hold_fnclex_sr, new_fenv_var, reload_fenv, restore_fnenv, get_fpsr, set_fpsr;
1616 tree update_call, atomic_feraiseexcept, hold_fnclex, masked_fenv, ld_fenv;
1618 /* Generate the equivalence of :
1619 unsigned int fenv_cr;
1620 fenv_cr = __builtin_aarch64_get_fpcr ();
1622 unsigned int fenv_sr;
1623 fenv_sr = __builtin_aarch64_get_fpsr ();
1625 Now set all exceptions to non-stop
1626 unsigned int mask_cr
1627 = ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT);
1628 unsigned int masked_cr;
1629 masked_cr = fenv_cr & mask_cr;
1631 And clear all exception flags
1632 unsigned int maske_sr = ~AARCH64_FE_ALL_EXCEPT;
1633 unsigned int masked_cr;
1634 masked_sr = fenv_sr & mask_sr;
1636 __builtin_aarch64_set_cr (masked_cr);
1637 __builtin_aarch64_set_sr (masked_sr); */
1639 fenv_cr = create_tmp_var_raw (unsigned_type_node);
1640 fenv_sr = create_tmp_var_raw (unsigned_type_node);
1642 get_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR];
1643 set_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR];
1644 get_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR];
1645 set_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR];
1647 mask_cr = build_int_cst (unsigned_type_node,
1648 ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT));
1649 mask_sr = build_int_cst (unsigned_type_node,
1650 ~(AARCH64_FE_ALL_EXCEPT));
1652 ld_fenv_cr = build2 (MODIFY_EXPR, unsigned_type_node,
1653 fenv_cr, build_call_expr (get_fpcr, 0));
1654 ld_fenv_sr = build2 (MODIFY_EXPR, unsigned_type_node,
1655 fenv_sr, build_call_expr (get_fpsr, 0));
1657 masked_fenv_cr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_cr, mask_cr);
1658 masked_fenv_sr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_sr, mask_sr);
1660 hold_fnclex_cr = build_call_expr (set_fpcr, 1, masked_fenv_cr);
1661 hold_fnclex_sr = build_call_expr (set_fpsr, 1, masked_fenv_sr);
1663 hold_fnclex = build2 (COMPOUND_EXPR, void_type_node, hold_fnclex_cr,
1664 hold_fnclex_sr);
1665 masked_fenv = build2 (COMPOUND_EXPR, void_type_node, masked_fenv_cr,
1666 masked_fenv_sr);
1667 ld_fenv = build2 (COMPOUND_EXPR, void_type_node, ld_fenv_cr, ld_fenv_sr);
1669 *hold = build2 (COMPOUND_EXPR, void_type_node,
1670 build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv),
1671 hold_fnclex);
1673 /* Store the value of masked_fenv to clear the exceptions:
1674 __builtin_aarch64_set_fpsr (masked_fenv_sr); */
1676 *clear = build_call_expr (set_fpsr, 1, masked_fenv_sr);
1678 /* Generate the equivalent of :
1679 unsigned int new_fenv_var;
1680 new_fenv_var = __builtin_aarch64_get_fpsr ();
1682 __builtin_aarch64_set_fpsr (fenv_sr);
1684 __atomic_feraiseexcept (new_fenv_var); */
1686 new_fenv_var = create_tmp_var_raw (unsigned_type_node);
1687 reload_fenv = build2 (MODIFY_EXPR, unsigned_type_node,
1688 new_fenv_var, build_call_expr (get_fpsr, 0));
1689 restore_fnenv = build_call_expr (set_fpsr, 1, fenv_sr);
1690 atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT);
1691 update_call = build_call_expr (atomic_feraiseexcept, 1,
1692 fold_convert (integer_type_node, new_fenv_var));
1693 *update = build2 (COMPOUND_EXPR, void_type_node,
1694 build2 (COMPOUND_EXPR, void_type_node,
1695 reload_fenv, restore_fnenv), update_call);
1699 #undef AARCH64_CHECK_BUILTIN_MODE
1700 #undef AARCH64_FIND_FRINT_VARIANT
1701 #undef CF0
1702 #undef CF1
1703 #undef CF2
1704 #undef CF3
1705 #undef CF4
1706 #undef CF10
1707 #undef VAR1
1708 #undef VAR2
1709 #undef VAR3
1710 #undef VAR4
1711 #undef VAR5
1712 #undef VAR6
1713 #undef VAR7
1714 #undef VAR8
1715 #undef VAR9
1716 #undef VAR10
1717 #undef VAR11
1719 #include "gt-aarch64-builtins.h"