Rebase.
[official-gcc.git] / gcc / config / aarch64 / aarch64-builtins.c
blobba58a99174a2d2014b4268c1a3e7b3972c4ba568
1 /* Builtins' description for AArch64 SIMD architecture.
2 Copyright (C) 2011-2014 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 "rtl.h"
26 #include "tree.h"
27 #include "stor-layout.h"
28 #include "stringpool.h"
29 #include "calls.h"
30 #include "expr.h"
31 #include "tm_p.h"
32 #include "recog.h"
33 #include "langhooks.h"
34 #include "diagnostic-core.h"
35 #include "optabs.h"
36 #include "pointer-set.h"
37 #include "hash-table.h"
38 #include "vec.h"
39 #include "ggc.h"
40 #include "basic-block.h"
41 #include "tree-ssa-alias.h"
42 #include "internal-fn.h"
43 #include "gimple-fold.h"
44 #include "tree-eh.h"
45 #include "gimple-expr.h"
46 #include "is-a.h"
47 #include "gimple.h"
48 #include "gimple-iterator.h"
50 #define v8qi_UP V8QImode
51 #define v4hi_UP V4HImode
52 #define v2si_UP V2SImode
53 #define v2sf_UP V2SFmode
54 #define v1df_UP V1DFmode
55 #define di_UP DImode
56 #define df_UP DFmode
57 #define v16qi_UP V16QImode
58 #define v8hi_UP V8HImode
59 #define v4si_UP V4SImode
60 #define v4sf_UP V4SFmode
61 #define v2di_UP V2DImode
62 #define v2df_UP V2DFmode
63 #define ti_UP TImode
64 #define ei_UP EImode
65 #define oi_UP OImode
66 #define ci_UP CImode
67 #define xi_UP XImode
68 #define si_UP SImode
69 #define sf_UP SFmode
70 #define hi_UP HImode
71 #define qi_UP QImode
72 #define UP(X) X##_UP
74 #define SIMD_MAX_BUILTIN_ARGS 5
76 enum aarch64_type_qualifiers
78 /* T foo. */
79 qualifier_none = 0x0,
80 /* unsigned T foo. */
81 qualifier_unsigned = 0x1, /* 1 << 0 */
82 /* const T foo. */
83 qualifier_const = 0x2, /* 1 << 1 */
84 /* T *foo. */
85 qualifier_pointer = 0x4, /* 1 << 2 */
86 /* const T *foo. */
87 qualifier_const_pointer = 0x6, /* qualifier_const | qualifier_pointer */
88 /* Used when expanding arguments if an operand could
89 be an immediate. */
90 qualifier_immediate = 0x8, /* 1 << 3 */
91 qualifier_maybe_immediate = 0x10, /* 1 << 4 */
92 /* void foo (...). */
93 qualifier_void = 0x20, /* 1 << 5 */
94 /* Some patterns may have internal operands, this qualifier is an
95 instruction to the initialisation code to skip this operand. */
96 qualifier_internal = 0x40, /* 1 << 6 */
97 /* Some builtins should use the T_*mode* encoded in a simd_builtin_datum
98 rather than using the type of the operand. */
99 qualifier_map_mode = 0x80, /* 1 << 7 */
100 /* qualifier_pointer | qualifier_map_mode */
101 qualifier_pointer_map_mode = 0x84,
102 /* qualifier_const_pointer | qualifier_map_mode */
103 qualifier_const_pointer_map_mode = 0x86,
104 /* Polynomial types. */
105 qualifier_poly = 0x100
108 typedef struct
110 const char *name;
111 enum 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 /* The qualifier_internal allows generation of a unary builtin from
118 a pattern with a third pseudo-operand such as a match_scratch. */
119 static enum aarch64_type_qualifiers
120 aarch64_types_unop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
121 = { qualifier_none, qualifier_none, qualifier_internal };
122 #define TYPES_UNOP (aarch64_types_unop_qualifiers)
123 static enum aarch64_type_qualifiers
124 aarch64_types_unopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
125 = { qualifier_unsigned, qualifier_unsigned };
126 #define TYPES_UNOPU (aarch64_types_unopu_qualifiers)
127 #define TYPES_CREATE (aarch64_types_unop_qualifiers)
128 #define TYPES_REINTERP_SS (aarch64_types_unop_qualifiers)
129 static enum aarch64_type_qualifiers
130 aarch64_types_unop_su_qualifiers[SIMD_MAX_BUILTIN_ARGS]
131 = { qualifier_none, qualifier_unsigned };
132 #define TYPES_REINTERP_SU (aarch64_types_unop_su_qualifiers)
133 static enum aarch64_type_qualifiers
134 aarch64_types_unop_sp_qualifiers[SIMD_MAX_BUILTIN_ARGS]
135 = { qualifier_none, qualifier_poly };
136 #define TYPES_REINTERP_SP (aarch64_types_unop_sp_qualifiers)
137 static enum aarch64_type_qualifiers
138 aarch64_types_unop_us_qualifiers[SIMD_MAX_BUILTIN_ARGS]
139 = { qualifier_unsigned, qualifier_none };
140 #define TYPES_REINTERP_US (aarch64_types_unop_us_qualifiers)
141 static enum aarch64_type_qualifiers
142 aarch64_types_unop_ps_qualifiers[SIMD_MAX_BUILTIN_ARGS]
143 = { qualifier_poly, qualifier_none };
144 #define TYPES_REINTERP_PS (aarch64_types_unop_ps_qualifiers)
145 static enum aarch64_type_qualifiers
146 aarch64_types_binop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
147 = { qualifier_none, qualifier_none, qualifier_maybe_immediate };
148 #define TYPES_BINOP (aarch64_types_binop_qualifiers)
149 static enum aarch64_type_qualifiers
150 aarch64_types_binopv_qualifiers[SIMD_MAX_BUILTIN_ARGS]
151 = { qualifier_void, qualifier_none, qualifier_none };
152 #define TYPES_BINOPV (aarch64_types_binopv_qualifiers)
153 static enum aarch64_type_qualifiers
154 aarch64_types_binopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
155 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned };
156 #define TYPES_BINOPU (aarch64_types_binopu_qualifiers)
157 static enum aarch64_type_qualifiers
158 aarch64_types_binop_uus_qualifiers[SIMD_MAX_BUILTIN_ARGS]
159 = { qualifier_unsigned, qualifier_unsigned, qualifier_none };
160 #define TYPES_BINOP_UUS (aarch64_types_binop_uus_qualifiers)
161 static enum aarch64_type_qualifiers
162 aarch64_types_binop_ssu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
163 = { qualifier_none, qualifier_none, qualifier_unsigned };
164 #define TYPES_BINOP_SSU (aarch64_types_binop_ssu_qualifiers)
165 static enum aarch64_type_qualifiers
166 aarch64_types_binopp_qualifiers[SIMD_MAX_BUILTIN_ARGS]
167 = { qualifier_poly, qualifier_poly, qualifier_poly };
168 #define TYPES_BINOPP (aarch64_types_binopp_qualifiers)
170 static enum aarch64_type_qualifiers
171 aarch64_types_ternop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
172 = { qualifier_none, qualifier_none, qualifier_none, qualifier_none };
173 #define TYPES_TERNOP (aarch64_types_ternop_qualifiers)
174 static enum aarch64_type_qualifiers
175 aarch64_types_ternopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
176 = { qualifier_unsigned, qualifier_unsigned,
177 qualifier_unsigned, qualifier_unsigned };
178 #define TYPES_TERNOPU (aarch64_types_ternopu_qualifiers)
180 static enum aarch64_type_qualifiers
181 aarch64_types_quadop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
182 = { qualifier_none, qualifier_none, qualifier_none,
183 qualifier_none, qualifier_none };
184 #define TYPES_QUADOP (aarch64_types_quadop_qualifiers)
186 static enum aarch64_type_qualifiers
187 aarch64_types_getlane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
188 = { qualifier_none, qualifier_none, qualifier_immediate };
189 #define TYPES_GETLANE (aarch64_types_getlane_qualifiers)
190 #define TYPES_SHIFTIMM (aarch64_types_getlane_qualifiers)
191 static enum aarch64_type_qualifiers
192 aarch64_types_shift_to_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS]
193 = { qualifier_unsigned, qualifier_none, qualifier_immediate };
194 #define TYPES_SHIFTIMM_USS (aarch64_types_shift_to_unsigned_qualifiers)
195 static enum aarch64_type_qualifiers
196 aarch64_types_unsigned_shift_qualifiers[SIMD_MAX_BUILTIN_ARGS]
197 = { qualifier_unsigned, qualifier_unsigned, qualifier_immediate };
198 #define TYPES_USHIFTIMM (aarch64_types_unsigned_shift_qualifiers)
200 static enum aarch64_type_qualifiers
201 aarch64_types_setlane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
202 = { qualifier_none, qualifier_none, qualifier_none, qualifier_immediate };
203 #define TYPES_SETLANE (aarch64_types_setlane_qualifiers)
204 #define TYPES_SHIFTINSERT (aarch64_types_setlane_qualifiers)
205 #define TYPES_SHIFTACC (aarch64_types_setlane_qualifiers)
207 static enum aarch64_type_qualifiers
208 aarch64_types_unsigned_shiftacc_qualifiers[SIMD_MAX_BUILTIN_ARGS]
209 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
210 qualifier_immediate };
211 #define TYPES_USHIFTACC (aarch64_types_unsigned_shiftacc_qualifiers)
214 static enum aarch64_type_qualifiers
215 aarch64_types_combine_qualifiers[SIMD_MAX_BUILTIN_ARGS]
216 = { qualifier_none, qualifier_none, qualifier_none };
217 #define TYPES_COMBINE (aarch64_types_combine_qualifiers)
219 static enum aarch64_type_qualifiers
220 aarch64_types_load1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
221 = { qualifier_none, qualifier_const_pointer_map_mode };
222 #define TYPES_LOAD1 (aarch64_types_load1_qualifiers)
223 #define TYPES_LOADSTRUCT (aarch64_types_load1_qualifiers)
225 static enum aarch64_type_qualifiers
226 aarch64_types_bsl_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
227 = { qualifier_poly, qualifier_unsigned,
228 qualifier_poly, qualifier_poly };
229 #define TYPES_BSL_P (aarch64_types_bsl_p_qualifiers)
230 static enum aarch64_type_qualifiers
231 aarch64_types_bsl_s_qualifiers[SIMD_MAX_BUILTIN_ARGS]
232 = { qualifier_none, qualifier_unsigned,
233 qualifier_none, qualifier_none };
234 #define TYPES_BSL_S (aarch64_types_bsl_s_qualifiers)
235 static enum aarch64_type_qualifiers
236 aarch64_types_bsl_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
237 = { qualifier_unsigned, qualifier_unsigned,
238 qualifier_unsigned, qualifier_unsigned };
239 #define TYPES_BSL_U (aarch64_types_bsl_u_qualifiers)
241 /* The first argument (return type) of a store should be void type,
242 which we represent with qualifier_void. Their first operand will be
243 a DImode pointer to the location to store to, so we must use
244 qualifier_map_mode | qualifier_pointer to build a pointer to the
245 element type of the vector. */
246 static enum aarch64_type_qualifiers
247 aarch64_types_store1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
248 = { qualifier_void, qualifier_pointer_map_mode, qualifier_none };
249 #define TYPES_STORE1 (aarch64_types_store1_qualifiers)
250 #define TYPES_STORESTRUCT (aarch64_types_store1_qualifiers)
251 static enum aarch64_type_qualifiers
252 aarch64_types_storestruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
253 = { qualifier_void, qualifier_pointer_map_mode,
254 qualifier_none, qualifier_none };
255 #define TYPES_STORESTRUCT_LANE (aarch64_types_storestruct_lane_qualifiers)
257 #define CF0(N, X) CODE_FOR_aarch64_##N##X
258 #define CF1(N, X) CODE_FOR_##N##X##1
259 #define CF2(N, X) CODE_FOR_##N##X##2
260 #define CF3(N, X) CODE_FOR_##N##X##3
261 #define CF4(N, X) CODE_FOR_##N##X##4
262 #define CF10(N, X) CODE_FOR_##N##X
264 #define VAR1(T, N, MAP, A) \
265 {#N #A, UP (A), CF##MAP (N, A), 0, TYPES_##T},
266 #define VAR2(T, N, MAP, A, B) \
267 VAR1 (T, N, MAP, A) \
268 VAR1 (T, N, MAP, B)
269 #define VAR3(T, N, MAP, A, B, C) \
270 VAR2 (T, N, MAP, A, B) \
271 VAR1 (T, N, MAP, C)
272 #define VAR4(T, N, MAP, A, B, C, D) \
273 VAR3 (T, N, MAP, A, B, C) \
274 VAR1 (T, N, MAP, D)
275 #define VAR5(T, N, MAP, A, B, C, D, E) \
276 VAR4 (T, N, MAP, A, B, C, D) \
277 VAR1 (T, N, MAP, E)
278 #define VAR6(T, N, MAP, A, B, C, D, E, F) \
279 VAR5 (T, N, MAP, A, B, C, D, E) \
280 VAR1 (T, N, MAP, F)
281 #define VAR7(T, N, MAP, A, B, C, D, E, F, G) \
282 VAR6 (T, N, MAP, A, B, C, D, E, F) \
283 VAR1 (T, N, MAP, G)
284 #define VAR8(T, N, MAP, A, B, C, D, E, F, G, H) \
285 VAR7 (T, N, MAP, A, B, C, D, E, F, G) \
286 VAR1 (T, N, MAP, H)
287 #define VAR9(T, N, MAP, A, B, C, D, E, F, G, H, I) \
288 VAR8 (T, N, MAP, A, B, C, D, E, F, G, H) \
289 VAR1 (T, N, MAP, I)
290 #define VAR10(T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
291 VAR9 (T, N, MAP, A, B, C, D, E, F, G, H, I) \
292 VAR1 (T, N, MAP, J)
293 #define VAR11(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
294 VAR10 (T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
295 VAR1 (T, N, MAP, K)
296 #define VAR12(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K, L) \
297 VAR11 (T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
298 VAR1 (T, N, MAP, L)
300 /* BUILTIN_<ITERATOR> macros should expand to cover the same range of
301 modes as is given for each define_mode_iterator in
302 config/aarch64/iterators.md. */
304 #define BUILTIN_DX(T, N, MAP) \
305 VAR2 (T, N, MAP, di, df)
306 #define BUILTIN_GPF(T, N, MAP) \
307 VAR2 (T, N, MAP, sf, df)
308 #define BUILTIN_SDQ_I(T, N, MAP) \
309 VAR4 (T, N, MAP, qi, hi, si, di)
310 #define BUILTIN_SD_HSI(T, N, MAP) \
311 VAR2 (T, N, MAP, hi, si)
312 #define BUILTIN_V2F(T, N, MAP) \
313 VAR2 (T, N, MAP, v2sf, v2df)
314 #define BUILTIN_VALL(T, N, MAP) \
315 VAR10 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, \
316 v4si, v2di, v2sf, v4sf, v2df)
317 #define BUILTIN_VALLDI(T, N, MAP) \
318 VAR11 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, \
319 v4si, v2di, v2sf, v4sf, v2df, di)
320 #define BUILTIN_VALLDIF(T, N, MAP) \
321 VAR12 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, \
322 v4si, v2di, v2sf, v4sf, v2df, di, df)
323 #define BUILTIN_VB(T, N, MAP) \
324 VAR2 (T, N, MAP, v8qi, v16qi)
325 #define BUILTIN_VD(T, N, MAP) \
326 VAR4 (T, N, MAP, v8qi, v4hi, v2si, v2sf)
327 #define BUILTIN_VD1(T, N, MAP) \
328 VAR5 (T, N, MAP, v8qi, v4hi, v2si, v2sf, v1df)
329 #define BUILTIN_VDC(T, N, MAP) \
330 VAR6 (T, N, MAP, v8qi, v4hi, v2si, v2sf, di, df)
331 #define BUILTIN_VDIC(T, N, MAP) \
332 VAR3 (T, N, MAP, v8qi, v4hi, v2si)
333 #define BUILTIN_VDN(T, N, MAP) \
334 VAR3 (T, N, MAP, v4hi, v2si, di)
335 #define BUILTIN_VDQ(T, N, MAP) \
336 VAR7 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di)
337 #define BUILTIN_VDQF(T, N, MAP) \
338 VAR3 (T, N, MAP, v2sf, v4sf, v2df)
339 #define BUILTIN_VDQF_DF(T, N, MAP) \
340 VAR4 (T, N, MAP, v2sf, v4sf, v2df, df)
341 #define BUILTIN_VDQH(T, N, MAP) \
342 VAR2 (T, N, MAP, v4hi, v8hi)
343 #define BUILTIN_VDQHS(T, N, MAP) \
344 VAR4 (T, N, MAP, v4hi, v8hi, v2si, v4si)
345 #define BUILTIN_VDQIF(T, N, MAP) \
346 VAR9 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2sf, v4sf, v2df)
347 #define BUILTIN_VDQM(T, N, MAP) \
348 VAR6 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si)
349 #define BUILTIN_VDQV(T, N, MAP) \
350 VAR5 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v4si)
351 #define BUILTIN_VDQQH(T, N, MAP) \
352 VAR4 (T, N, MAP, v8qi, v16qi, v4hi, v8hi)
353 #define BUILTIN_VDQ_BHSI(T, N, MAP) \
354 VAR6 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si)
355 #define BUILTIN_VDQ_I(T, N, MAP) \
356 VAR7 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di)
357 #define BUILTIN_VDW(T, N, MAP) \
358 VAR3 (T, N, MAP, v8qi, v4hi, v2si)
359 #define BUILTIN_VD_BHSI(T, N, MAP) \
360 VAR3 (T, N, MAP, v8qi, v4hi, v2si)
361 #define BUILTIN_VD_HSI(T, N, MAP) \
362 VAR2 (T, N, MAP, v4hi, v2si)
363 #define BUILTIN_VQ(T, N, MAP) \
364 VAR6 (T, N, MAP, v16qi, v8hi, v4si, v2di, v4sf, v2df)
365 #define BUILTIN_VQN(T, N, MAP) \
366 VAR3 (T, N, MAP, v8hi, v4si, v2di)
367 #define BUILTIN_VQW(T, N, MAP) \
368 VAR3 (T, N, MAP, v16qi, v8hi, v4si)
369 #define BUILTIN_VQ_HSI(T, N, MAP) \
370 VAR2 (T, N, MAP, v8hi, v4si)
371 #define BUILTIN_VQ_S(T, N, MAP) \
372 VAR6 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si)
373 #define BUILTIN_VSDQ_HSI(T, N, MAP) \
374 VAR6 (T, N, MAP, v4hi, v8hi, v2si, v4si, hi, si)
375 #define BUILTIN_VSDQ_I(T, N, MAP) \
376 VAR11 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di, qi, hi, si, di)
377 #define BUILTIN_VSDQ_I_BHSI(T, N, MAP) \
378 VAR10 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di, qi, hi, si)
379 #define BUILTIN_VSDQ_I_DI(T, N, MAP) \
380 VAR8 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di, di)
381 #define BUILTIN_VSD_HSI(T, N, MAP) \
382 VAR4 (T, N, MAP, v4hi, v2si, hi, si)
383 #define BUILTIN_VSQN_HSDI(T, N, MAP) \
384 VAR6 (T, N, MAP, v8hi, v4si, v2di, hi, si, di)
385 #define BUILTIN_VSTRUCT(T, N, MAP) \
386 VAR3 (T, N, MAP, oi, ci, xi)
388 static aarch64_simd_builtin_datum aarch64_simd_builtin_data[] = {
389 #include "aarch64-simd-builtins.def"
392 /* There's only 8 CRC32 builtins. Probably not worth their own .def file. */
393 #define AARCH64_CRC32_BUILTINS \
394 CRC32_BUILTIN (crc32b, QI) \
395 CRC32_BUILTIN (crc32h, HI) \
396 CRC32_BUILTIN (crc32w, SI) \
397 CRC32_BUILTIN (crc32x, DI) \
398 CRC32_BUILTIN (crc32cb, QI) \
399 CRC32_BUILTIN (crc32ch, HI) \
400 CRC32_BUILTIN (crc32cw, SI) \
401 CRC32_BUILTIN (crc32cx, DI)
403 typedef struct
405 const char *name;
406 enum machine_mode mode;
407 const enum insn_code icode;
408 unsigned int fcode;
409 } aarch64_crc_builtin_datum;
411 #define CRC32_BUILTIN(N, M) \
412 AARCH64_BUILTIN_##N,
414 #undef VAR1
415 #define VAR1(T, N, MAP, A) \
416 AARCH64_SIMD_BUILTIN_##T##_##N##A,
418 enum aarch64_builtins
420 AARCH64_BUILTIN_MIN,
422 AARCH64_BUILTIN_GET_FPCR,
423 AARCH64_BUILTIN_SET_FPCR,
424 AARCH64_BUILTIN_GET_FPSR,
425 AARCH64_BUILTIN_SET_FPSR,
427 AARCH64_SIMD_BUILTIN_BASE,
428 #include "aarch64-simd-builtins.def"
429 AARCH64_SIMD_BUILTIN_MAX = AARCH64_SIMD_BUILTIN_BASE
430 + ARRAY_SIZE (aarch64_simd_builtin_data),
431 AARCH64_CRC32_BUILTIN_BASE,
432 AARCH64_CRC32_BUILTINS
433 AARCH64_CRC32_BUILTIN_MAX,
434 AARCH64_BUILTIN_MAX
437 #undef CRC32_BUILTIN
438 #define CRC32_BUILTIN(N, M) \
439 {"__builtin_aarch64_"#N, M##mode, CODE_FOR_aarch64_##N, AARCH64_BUILTIN_##N},
441 static aarch64_crc_builtin_datum aarch64_crc_builtin_data[] = {
442 AARCH64_CRC32_BUILTINS
445 #undef CRC32_BUILTIN
447 static GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX];
449 #define NUM_DREG_TYPES 6
450 #define NUM_QREG_TYPES 6
452 /* Return a tree for a signed or unsigned argument of either
453 the mode specified by MODE, or the inner mode of MODE. */
454 tree
455 aarch64_build_scalar_type (enum machine_mode mode,
456 bool unsigned_p,
457 bool poly_p)
459 #undef INT_TYPES
460 #define INT_TYPES \
461 AARCH64_TYPE_BUILDER (QI) \
462 AARCH64_TYPE_BUILDER (HI) \
463 AARCH64_TYPE_BUILDER (SI) \
464 AARCH64_TYPE_BUILDER (DI) \
465 AARCH64_TYPE_BUILDER (EI) \
466 AARCH64_TYPE_BUILDER (OI) \
467 AARCH64_TYPE_BUILDER (CI) \
468 AARCH64_TYPE_BUILDER (XI) \
469 AARCH64_TYPE_BUILDER (TI) \
471 /* Statically declare all the possible types we might need. */
472 #undef AARCH64_TYPE_BUILDER
473 #define AARCH64_TYPE_BUILDER(X) \
474 static tree X##_aarch64_type_node_p = NULL; \
475 static tree X##_aarch64_type_node_s = NULL; \
476 static tree X##_aarch64_type_node_u = NULL;
478 INT_TYPES
480 static tree float_aarch64_type_node = NULL;
481 static tree double_aarch64_type_node = NULL;
483 gcc_assert (!VECTOR_MODE_P (mode));
485 /* If we've already initialised this type, don't initialise it again,
486 otherwise ask for a new type of the correct size. */
487 #undef AARCH64_TYPE_BUILDER
488 #define AARCH64_TYPE_BUILDER(X) \
489 case X##mode: \
490 if (unsigned_p) \
491 return (X##_aarch64_type_node_u \
492 ? X##_aarch64_type_node_u \
493 : X##_aarch64_type_node_u \
494 = make_unsigned_type (GET_MODE_PRECISION (mode))); \
495 else if (poly_p) \
496 return (X##_aarch64_type_node_p \
497 ? X##_aarch64_type_node_p \
498 : X##_aarch64_type_node_p \
499 = make_unsigned_type (GET_MODE_PRECISION (mode))); \
500 else \
501 return (X##_aarch64_type_node_s \
502 ? X##_aarch64_type_node_s \
503 : X##_aarch64_type_node_s \
504 = make_signed_type (GET_MODE_PRECISION (mode))); \
505 break;
507 switch (mode)
509 INT_TYPES
510 case SFmode:
511 if (!float_aarch64_type_node)
513 float_aarch64_type_node = make_node (REAL_TYPE);
514 TYPE_PRECISION (float_aarch64_type_node) = FLOAT_TYPE_SIZE;
515 layout_type (float_aarch64_type_node);
517 return float_aarch64_type_node;
518 break;
519 case DFmode:
520 if (!double_aarch64_type_node)
522 double_aarch64_type_node = make_node (REAL_TYPE);
523 TYPE_PRECISION (double_aarch64_type_node) = DOUBLE_TYPE_SIZE;
524 layout_type (double_aarch64_type_node);
526 return double_aarch64_type_node;
527 break;
528 default:
529 gcc_unreachable ();
533 tree
534 aarch64_build_vector_type (enum machine_mode mode,
535 bool unsigned_p,
536 bool poly_p)
538 tree eltype;
540 #define VECTOR_TYPES \
541 AARCH64_TYPE_BUILDER (V16QI) \
542 AARCH64_TYPE_BUILDER (V8HI) \
543 AARCH64_TYPE_BUILDER (V4SI) \
544 AARCH64_TYPE_BUILDER (V2DI) \
545 AARCH64_TYPE_BUILDER (V8QI) \
546 AARCH64_TYPE_BUILDER (V4HI) \
547 AARCH64_TYPE_BUILDER (V2SI) \
549 AARCH64_TYPE_BUILDER (V4SF) \
550 AARCH64_TYPE_BUILDER (V2DF) \
551 AARCH64_TYPE_BUILDER (V2SF) \
552 /* Declare our "cache" of values. */
553 #undef AARCH64_TYPE_BUILDER
554 #define AARCH64_TYPE_BUILDER(X) \
555 static tree X##_aarch64_type_node_s = NULL; \
556 static tree X##_aarch64_type_node_u = NULL; \
557 static tree X##_aarch64_type_node_p = NULL;
559 VECTOR_TYPES
561 gcc_assert (VECTOR_MODE_P (mode));
563 #undef AARCH64_TYPE_BUILDER
564 #define AARCH64_TYPE_BUILDER(X) \
565 case X##mode: \
566 if (unsigned_p) \
567 return X##_aarch64_type_node_u \
568 ? X##_aarch64_type_node_u \
569 : X##_aarch64_type_node_u \
570 = build_vector_type_for_mode (aarch64_build_scalar_type \
571 (GET_MODE_INNER (mode), \
572 unsigned_p, poly_p), mode); \
573 else if (poly_p) \
574 return X##_aarch64_type_node_p \
575 ? X##_aarch64_type_node_p \
576 : X##_aarch64_type_node_p \
577 = build_vector_type_for_mode (aarch64_build_scalar_type \
578 (GET_MODE_INNER (mode), \
579 unsigned_p, poly_p), mode); \
580 else \
581 return X##_aarch64_type_node_s \
582 ? X##_aarch64_type_node_s \
583 : X##_aarch64_type_node_s \
584 = build_vector_type_for_mode (aarch64_build_scalar_type \
585 (GET_MODE_INNER (mode), \
586 unsigned_p, poly_p), mode); \
587 break;
589 switch (mode)
591 default:
592 eltype = aarch64_build_scalar_type (GET_MODE_INNER (mode),
593 unsigned_p, poly_p);
594 return build_vector_type_for_mode (eltype, mode);
595 break;
596 VECTOR_TYPES
600 tree
601 aarch64_build_type (enum machine_mode mode, bool unsigned_p, bool poly_p)
603 if (VECTOR_MODE_P (mode))
604 return aarch64_build_vector_type (mode, unsigned_p, poly_p);
605 else
606 return aarch64_build_scalar_type (mode, unsigned_p, poly_p);
609 tree
610 aarch64_build_signed_type (enum machine_mode mode)
612 return aarch64_build_type (mode, false, false);
615 tree
616 aarch64_build_unsigned_type (enum machine_mode mode)
618 return aarch64_build_type (mode, true, false);
621 tree
622 aarch64_build_poly_type (enum machine_mode mode)
624 return aarch64_build_type (mode, false, true);
627 static void
628 aarch64_init_simd_builtins (void)
630 unsigned int i, fcode = AARCH64_SIMD_BUILTIN_BASE + 1;
632 /* Signed scalar type nodes. */
633 tree aarch64_simd_intQI_type_node = aarch64_build_signed_type (QImode);
634 tree aarch64_simd_intHI_type_node = aarch64_build_signed_type (HImode);
635 tree aarch64_simd_intSI_type_node = aarch64_build_signed_type (SImode);
636 tree aarch64_simd_intDI_type_node = aarch64_build_signed_type (DImode);
637 tree aarch64_simd_intTI_type_node = aarch64_build_signed_type (TImode);
638 tree aarch64_simd_intEI_type_node = aarch64_build_signed_type (EImode);
639 tree aarch64_simd_intOI_type_node = aarch64_build_signed_type (OImode);
640 tree aarch64_simd_intCI_type_node = aarch64_build_signed_type (CImode);
641 tree aarch64_simd_intXI_type_node = aarch64_build_signed_type (XImode);
643 /* Unsigned scalar type nodes. */
644 tree aarch64_simd_intUQI_type_node = aarch64_build_unsigned_type (QImode);
645 tree aarch64_simd_intUHI_type_node = aarch64_build_unsigned_type (HImode);
646 tree aarch64_simd_intUSI_type_node = aarch64_build_unsigned_type (SImode);
647 tree aarch64_simd_intUDI_type_node = aarch64_build_unsigned_type (DImode);
649 /* Poly scalar type nodes. */
650 tree aarch64_simd_polyQI_type_node = aarch64_build_poly_type (QImode);
651 tree aarch64_simd_polyHI_type_node = aarch64_build_poly_type (HImode);
652 tree aarch64_simd_polyDI_type_node = aarch64_build_poly_type (DImode);
653 tree aarch64_simd_polyTI_type_node = aarch64_build_poly_type (TImode);
655 /* Float type nodes. */
656 tree aarch64_simd_float_type_node = aarch64_build_signed_type (SFmode);
657 tree aarch64_simd_double_type_node = aarch64_build_signed_type (DFmode);
659 /* Define typedefs which exactly correspond to the modes we are basing vector
660 types on. If you change these names you'll need to change
661 the table used by aarch64_mangle_type too. */
662 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intQI_type_node,
663 "__builtin_aarch64_simd_qi");
664 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intHI_type_node,
665 "__builtin_aarch64_simd_hi");
666 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intSI_type_node,
667 "__builtin_aarch64_simd_si");
668 (*lang_hooks.types.register_builtin_type) (aarch64_simd_float_type_node,
669 "__builtin_aarch64_simd_sf");
670 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intDI_type_node,
671 "__builtin_aarch64_simd_di");
672 (*lang_hooks.types.register_builtin_type) (aarch64_simd_double_type_node,
673 "__builtin_aarch64_simd_df");
674 (*lang_hooks.types.register_builtin_type) (aarch64_simd_polyQI_type_node,
675 "__builtin_aarch64_simd_poly8");
676 (*lang_hooks.types.register_builtin_type) (aarch64_simd_polyHI_type_node,
677 "__builtin_aarch64_simd_poly16");
678 (*lang_hooks.types.register_builtin_type) (aarch64_simd_polyDI_type_node,
679 "__builtin_aarch64_simd_poly64");
680 (*lang_hooks.types.register_builtin_type) (aarch64_simd_polyTI_type_node,
681 "__builtin_aarch64_simd_poly128");
682 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intTI_type_node,
683 "__builtin_aarch64_simd_ti");
684 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intEI_type_node,
685 "__builtin_aarch64_simd_ei");
686 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intOI_type_node,
687 "__builtin_aarch64_simd_oi");
688 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intCI_type_node,
689 "__builtin_aarch64_simd_ci");
690 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intXI_type_node,
691 "__builtin_aarch64_simd_xi");
693 /* Unsigned integer types for various mode sizes. */
694 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUQI_type_node,
695 "__builtin_aarch64_simd_uqi");
696 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUHI_type_node,
697 "__builtin_aarch64_simd_uhi");
698 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUSI_type_node,
699 "__builtin_aarch64_simd_usi");
700 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUDI_type_node,
701 "__builtin_aarch64_simd_udi");
703 for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++)
705 bool print_type_signature_p = false;
706 char type_signature[SIMD_MAX_BUILTIN_ARGS] = { 0 };
707 aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i];
708 char namebuf[60];
709 tree ftype = NULL;
710 tree fndecl = NULL;
712 d->fcode = fcode;
714 /* We must track two variables here. op_num is
715 the operand number as in the RTL pattern. This is
716 required to access the mode (e.g. V4SF mode) of the
717 argument, from which the base type can be derived.
718 arg_num is an index in to the qualifiers data, which
719 gives qualifiers to the type (e.g. const unsigned).
720 The reason these two variables may differ by one is the
721 void return type. While all return types take the 0th entry
722 in the qualifiers array, there is no operand for them in the
723 RTL pattern. */
724 int op_num = insn_data[d->code].n_operands - 1;
725 int arg_num = d->qualifiers[0] & qualifier_void
726 ? op_num + 1
727 : op_num;
728 tree return_type = void_type_node, args = void_list_node;
729 tree eltype;
731 /* Build a function type directly from the insn_data for this
732 builtin. The build_function_type () function takes care of
733 removing duplicates for us. */
734 for (; op_num >= 0; arg_num--, op_num--)
736 enum machine_mode op_mode = insn_data[d->code].operand[op_num].mode;
737 enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num];
739 if (qualifiers & qualifier_unsigned)
741 type_signature[arg_num] = 'u';
742 print_type_signature_p = true;
744 else if (qualifiers & qualifier_poly)
746 type_signature[arg_num] = 'p';
747 print_type_signature_p = true;
749 else
750 type_signature[arg_num] = 's';
752 /* Skip an internal operand for vget_{low, high}. */
753 if (qualifiers & qualifier_internal)
754 continue;
756 /* Some builtins have different user-facing types
757 for certain arguments, encoded in d->mode. */
758 if (qualifiers & qualifier_map_mode)
759 op_mode = d->mode;
761 /* For pointers, we want a pointer to the basic type
762 of the vector. */
763 if (qualifiers & qualifier_pointer && VECTOR_MODE_P (op_mode))
764 op_mode = GET_MODE_INNER (op_mode);
766 eltype = aarch64_build_type (op_mode,
767 qualifiers & qualifier_unsigned,
768 qualifiers & qualifier_poly);
770 /* Add qualifiers. */
771 if (qualifiers & qualifier_const)
772 eltype = build_qualified_type (eltype, TYPE_QUAL_CONST);
774 if (qualifiers & qualifier_pointer)
775 eltype = build_pointer_type (eltype);
777 /* If we have reached arg_num == 0, we are at a non-void
778 return type. Otherwise, we are still processing
779 arguments. */
780 if (arg_num == 0)
781 return_type = eltype;
782 else
783 args = tree_cons (NULL_TREE, eltype, args);
786 ftype = build_function_type (return_type, args);
788 gcc_assert (ftype != NULL);
790 if (print_type_signature_p)
791 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s_%s",
792 d->name, type_signature);
793 else
794 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s",
795 d->name);
797 fndecl = add_builtin_function (namebuf, ftype, fcode, BUILT_IN_MD,
798 NULL, NULL_TREE);
799 aarch64_builtin_decls[fcode] = fndecl;
803 static void
804 aarch64_init_crc32_builtins ()
806 tree usi_type = aarch64_build_unsigned_type (SImode);
807 unsigned int i = 0;
809 for (i = 0; i < ARRAY_SIZE (aarch64_crc_builtin_data); ++i)
811 aarch64_crc_builtin_datum* d = &aarch64_crc_builtin_data[i];
812 tree argtype = aarch64_build_unsigned_type (d->mode);
813 tree ftype = build_function_type_list (usi_type, usi_type, argtype, NULL_TREE);
814 tree fndecl = add_builtin_function (d->name, ftype, d->fcode,
815 BUILT_IN_MD, NULL, NULL_TREE);
817 aarch64_builtin_decls[d->fcode] = fndecl;
821 void
822 aarch64_init_builtins (void)
824 tree ftype_set_fpr
825 = build_function_type_list (void_type_node, unsigned_type_node, NULL);
826 tree ftype_get_fpr
827 = build_function_type_list (unsigned_type_node, NULL);
829 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR]
830 = add_builtin_function ("__builtin_aarch64_get_fpcr", ftype_get_fpr,
831 AARCH64_BUILTIN_GET_FPCR, BUILT_IN_MD, NULL, NULL_TREE);
832 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR]
833 = add_builtin_function ("__builtin_aarch64_set_fpcr", ftype_set_fpr,
834 AARCH64_BUILTIN_SET_FPCR, BUILT_IN_MD, NULL, NULL_TREE);
835 aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR]
836 = add_builtin_function ("__builtin_aarch64_get_fpsr", ftype_get_fpr,
837 AARCH64_BUILTIN_GET_FPSR, BUILT_IN_MD, NULL, NULL_TREE);
838 aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR]
839 = add_builtin_function ("__builtin_aarch64_set_fpsr", ftype_set_fpr,
840 AARCH64_BUILTIN_SET_FPSR, BUILT_IN_MD, NULL, NULL_TREE);
842 if (TARGET_SIMD)
843 aarch64_init_simd_builtins ();
844 if (TARGET_CRC32)
845 aarch64_init_crc32_builtins ();
848 tree
849 aarch64_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
851 if (code >= AARCH64_BUILTIN_MAX)
852 return error_mark_node;
854 return aarch64_builtin_decls[code];
857 typedef enum
859 SIMD_ARG_COPY_TO_REG,
860 SIMD_ARG_CONSTANT,
861 SIMD_ARG_STOP
862 } builtin_simd_arg;
864 static rtx
865 aarch64_simd_expand_args (rtx target, int icode, int have_retval,
866 tree exp, ...)
868 va_list ap;
869 rtx pat;
870 tree arg[SIMD_MAX_BUILTIN_ARGS];
871 rtx op[SIMD_MAX_BUILTIN_ARGS];
872 enum machine_mode tmode = insn_data[icode].operand[0].mode;
873 enum machine_mode mode[SIMD_MAX_BUILTIN_ARGS];
874 int argc = 0;
876 if (have_retval
877 && (!target
878 || GET_MODE (target) != tmode
879 || !(*insn_data[icode].operand[0].predicate) (target, tmode)))
880 target = gen_reg_rtx (tmode);
882 va_start (ap, exp);
884 for (;;)
886 builtin_simd_arg thisarg = (builtin_simd_arg) va_arg (ap, int);
888 if (thisarg == SIMD_ARG_STOP)
889 break;
890 else
892 arg[argc] = CALL_EXPR_ARG (exp, argc);
893 op[argc] = expand_normal (arg[argc]);
894 mode[argc] = insn_data[icode].operand[argc + have_retval].mode;
896 switch (thisarg)
898 case SIMD_ARG_COPY_TO_REG:
899 if (POINTER_TYPE_P (TREE_TYPE (arg[argc])))
900 op[argc] = convert_memory_address (Pmode, op[argc]);
901 /*gcc_assert (GET_MODE (op[argc]) == mode[argc]); */
902 if (!(*insn_data[icode].operand[argc + have_retval].predicate)
903 (op[argc], mode[argc]))
904 op[argc] = copy_to_mode_reg (mode[argc], op[argc]);
905 break;
907 case SIMD_ARG_CONSTANT:
908 if (!(*insn_data[icode].operand[argc + have_retval].predicate)
909 (op[argc], mode[argc]))
910 error_at (EXPR_LOCATION (exp), "incompatible type for argument %d, "
911 "expected %<const int%>", argc + 1);
912 break;
914 case SIMD_ARG_STOP:
915 gcc_unreachable ();
918 argc++;
922 va_end (ap);
924 if (have_retval)
925 switch (argc)
927 case 1:
928 pat = GEN_FCN (icode) (target, op[0]);
929 break;
931 case 2:
932 pat = GEN_FCN (icode) (target, op[0], op[1]);
933 break;
935 case 3:
936 pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
937 break;
939 case 4:
940 pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
941 break;
943 case 5:
944 pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
945 break;
947 default:
948 gcc_unreachable ();
950 else
951 switch (argc)
953 case 1:
954 pat = GEN_FCN (icode) (op[0]);
955 break;
957 case 2:
958 pat = GEN_FCN (icode) (op[0], op[1]);
959 break;
961 case 3:
962 pat = GEN_FCN (icode) (op[0], op[1], op[2]);
963 break;
965 case 4:
966 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
967 break;
969 case 5:
970 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
971 break;
973 default:
974 gcc_unreachable ();
977 if (!pat)
978 return 0;
980 emit_insn (pat);
982 return target;
985 /* Expand an AArch64 AdvSIMD builtin(intrinsic). */
987 aarch64_simd_expand_builtin (int fcode, tree exp, rtx target)
989 aarch64_simd_builtin_datum *d =
990 &aarch64_simd_builtin_data[fcode - (AARCH64_SIMD_BUILTIN_BASE + 1)];
991 enum insn_code icode = d->code;
992 builtin_simd_arg args[SIMD_MAX_BUILTIN_ARGS];
993 int num_args = insn_data[d->code].n_operands;
994 int is_void = 0;
995 int k;
997 is_void = !!(d->qualifiers[0] & qualifier_void);
999 num_args += is_void;
1001 for (k = 1; k < num_args; k++)
1003 /* We have four arrays of data, each indexed in a different fashion.
1004 qualifiers - element 0 always describes the function return type.
1005 operands - element 0 is either the operand for return value (if
1006 the function has a non-void return type) or the operand for the
1007 first argument.
1008 expr_args - element 0 always holds the first argument.
1009 args - element 0 is always used for the return type. */
1010 int qualifiers_k = k;
1011 int operands_k = k - is_void;
1012 int expr_args_k = k - 1;
1014 if (d->qualifiers[qualifiers_k] & qualifier_immediate)
1015 args[k] = SIMD_ARG_CONSTANT;
1016 else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate)
1018 rtx arg
1019 = expand_normal (CALL_EXPR_ARG (exp,
1020 (expr_args_k)));
1021 /* Handle constants only if the predicate allows it. */
1022 bool op_const_int_p =
1023 (CONST_INT_P (arg)
1024 && (*insn_data[icode].operand[operands_k].predicate)
1025 (arg, insn_data[icode].operand[operands_k].mode));
1026 args[k] = op_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG;
1028 else
1029 args[k] = SIMD_ARG_COPY_TO_REG;
1032 args[k] = SIMD_ARG_STOP;
1034 /* The interface to aarch64_simd_expand_args expects a 0 if
1035 the function is void, and a 1 if it is not. */
1036 return aarch64_simd_expand_args
1037 (target, icode, !is_void, exp,
1038 args[1],
1039 args[2],
1040 args[3],
1041 args[4],
1042 SIMD_ARG_STOP);
1046 aarch64_crc32_expand_builtin (int fcode, tree exp, rtx target)
1048 rtx pat;
1049 aarch64_crc_builtin_datum *d
1050 = &aarch64_crc_builtin_data[fcode - (AARCH64_CRC32_BUILTIN_BASE + 1)];
1051 enum insn_code icode = d->icode;
1052 tree arg0 = CALL_EXPR_ARG (exp, 0);
1053 tree arg1 = CALL_EXPR_ARG (exp, 1);
1054 rtx op0 = expand_normal (arg0);
1055 rtx op1 = expand_normal (arg1);
1056 enum machine_mode tmode = insn_data[icode].operand[0].mode;
1057 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
1058 enum machine_mode mode1 = insn_data[icode].operand[2].mode;
1060 if (! target
1061 || GET_MODE (target) != tmode
1062 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1063 target = gen_reg_rtx (tmode);
1065 gcc_assert ((GET_MODE (op0) == mode0 || GET_MODE (op0) == VOIDmode)
1066 && (GET_MODE (op1) == mode1 || GET_MODE (op1) == VOIDmode));
1068 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1069 op0 = copy_to_mode_reg (mode0, op0);
1070 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
1071 op1 = copy_to_mode_reg (mode1, op1);
1073 pat = GEN_FCN (icode) (target, op0, op1);
1074 if (! pat)
1075 return 0;
1076 emit_insn (pat);
1077 return target;
1080 /* Expand an expression EXP that calls a built-in function,
1081 with result going to TARGET if that's convenient. */
1083 aarch64_expand_builtin (tree exp,
1084 rtx target,
1085 rtx subtarget ATTRIBUTE_UNUSED,
1086 enum machine_mode mode ATTRIBUTE_UNUSED,
1087 int ignore ATTRIBUTE_UNUSED)
1089 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
1090 int fcode = DECL_FUNCTION_CODE (fndecl);
1091 int icode;
1092 rtx pat, op0;
1093 tree arg0;
1095 switch (fcode)
1097 case AARCH64_BUILTIN_GET_FPCR:
1098 case AARCH64_BUILTIN_SET_FPCR:
1099 case AARCH64_BUILTIN_GET_FPSR:
1100 case AARCH64_BUILTIN_SET_FPSR:
1101 if ((fcode == AARCH64_BUILTIN_GET_FPCR)
1102 || (fcode == AARCH64_BUILTIN_GET_FPSR))
1104 icode = (fcode == AARCH64_BUILTIN_GET_FPSR) ?
1105 CODE_FOR_get_fpsr : CODE_FOR_get_fpcr;
1106 target = gen_reg_rtx (SImode);
1107 pat = GEN_FCN (icode) (target);
1109 else
1111 target = NULL_RTX;
1112 icode = (fcode == AARCH64_BUILTIN_SET_FPSR) ?
1113 CODE_FOR_set_fpsr : CODE_FOR_set_fpcr;
1114 arg0 = CALL_EXPR_ARG (exp, 0);
1115 op0 = expand_normal (arg0);
1116 pat = GEN_FCN (icode) (op0);
1118 emit_insn (pat);
1119 return target;
1122 if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
1123 return aarch64_simd_expand_builtin (fcode, exp, target);
1124 else if (fcode >= AARCH64_CRC32_BUILTIN_BASE && fcode <= AARCH64_CRC32_BUILTIN_MAX)
1125 return aarch64_crc32_expand_builtin (fcode, exp, target);
1127 return NULL_RTX;
1130 tree
1131 aarch64_builtin_vectorized_function (tree fndecl, tree type_out, tree type_in)
1133 enum machine_mode in_mode, out_mode;
1134 int in_n, out_n;
1136 if (TREE_CODE (type_out) != VECTOR_TYPE
1137 || TREE_CODE (type_in) != VECTOR_TYPE)
1138 return NULL_TREE;
1140 out_mode = TYPE_MODE (TREE_TYPE (type_out));
1141 out_n = TYPE_VECTOR_SUBPARTS (type_out);
1142 in_mode = TYPE_MODE (TREE_TYPE (type_in));
1143 in_n = TYPE_VECTOR_SUBPARTS (type_in);
1145 #undef AARCH64_CHECK_BUILTIN_MODE
1146 #define AARCH64_CHECK_BUILTIN_MODE(C, N) 1
1147 #define AARCH64_FIND_FRINT_VARIANT(N) \
1148 (AARCH64_CHECK_BUILTIN_MODE (2, D) \
1149 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2df] \
1150 : (AARCH64_CHECK_BUILTIN_MODE (4, S) \
1151 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v4sf] \
1152 : (AARCH64_CHECK_BUILTIN_MODE (2, S) \
1153 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2sf] \
1154 : NULL_TREE)))
1155 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
1157 enum built_in_function fn = DECL_FUNCTION_CODE (fndecl);
1158 switch (fn)
1160 #undef AARCH64_CHECK_BUILTIN_MODE
1161 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1162 (out_mode == N##Fmode && out_n == C \
1163 && in_mode == N##Fmode && in_n == C)
1164 case BUILT_IN_FLOOR:
1165 case BUILT_IN_FLOORF:
1166 return AARCH64_FIND_FRINT_VARIANT (floor);
1167 case BUILT_IN_CEIL:
1168 case BUILT_IN_CEILF:
1169 return AARCH64_FIND_FRINT_VARIANT (ceil);
1170 case BUILT_IN_TRUNC:
1171 case BUILT_IN_TRUNCF:
1172 return AARCH64_FIND_FRINT_VARIANT (btrunc);
1173 case BUILT_IN_ROUND:
1174 case BUILT_IN_ROUNDF:
1175 return AARCH64_FIND_FRINT_VARIANT (round);
1176 case BUILT_IN_NEARBYINT:
1177 case BUILT_IN_NEARBYINTF:
1178 return AARCH64_FIND_FRINT_VARIANT (nearbyint);
1179 case BUILT_IN_SQRT:
1180 case BUILT_IN_SQRTF:
1181 return AARCH64_FIND_FRINT_VARIANT (sqrt);
1182 #undef AARCH64_CHECK_BUILTIN_MODE
1183 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1184 (out_mode == SImode && out_n == C \
1185 && in_mode == N##Imode && in_n == C)
1186 case BUILT_IN_CLZ:
1188 if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1189 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_clzv4si];
1190 return NULL_TREE;
1192 #undef AARCH64_CHECK_BUILTIN_MODE
1193 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1194 (out_mode == N##Imode && out_n == C \
1195 && in_mode == N##Fmode && in_n == C)
1196 case BUILT_IN_LFLOOR:
1197 case BUILT_IN_LFLOORF:
1198 case BUILT_IN_LLFLOOR:
1199 case BUILT_IN_IFLOORF:
1201 enum aarch64_builtins builtin;
1202 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1203 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2dfv2di;
1204 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1205 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv4sfv4si;
1206 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1207 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2sfv2si;
1208 else
1209 return NULL_TREE;
1211 return aarch64_builtin_decls[builtin];
1213 case BUILT_IN_LCEIL:
1214 case BUILT_IN_LCEILF:
1215 case BUILT_IN_LLCEIL:
1216 case BUILT_IN_ICEILF:
1218 enum aarch64_builtins builtin;
1219 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1220 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2dfv2di;
1221 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1222 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv4sfv4si;
1223 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1224 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2sfv2si;
1225 else
1226 return NULL_TREE;
1228 return aarch64_builtin_decls[builtin];
1230 case BUILT_IN_LROUND:
1231 case BUILT_IN_IROUNDF:
1233 enum aarch64_builtins builtin;
1234 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1235 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2dfv2di;
1236 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1237 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv4sfv4si;
1238 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1239 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2sfv2si;
1240 else
1241 return NULL_TREE;
1243 return aarch64_builtin_decls[builtin];
1245 case BUILT_IN_BSWAP16:
1246 #undef AARCH64_CHECK_BUILTIN_MODE
1247 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1248 (out_mode == N##Imode && out_n == C \
1249 && in_mode == N##Imode && in_n == C)
1250 if (AARCH64_CHECK_BUILTIN_MODE (4, H))
1251 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4hi];
1252 else if (AARCH64_CHECK_BUILTIN_MODE (8, H))
1253 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv8hi];
1254 else
1255 return NULL_TREE;
1256 case BUILT_IN_BSWAP32:
1257 if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1258 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2si];
1259 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1260 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4si];
1261 else
1262 return NULL_TREE;
1263 case BUILT_IN_BSWAP64:
1264 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1265 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2di];
1266 else
1267 return NULL_TREE;
1268 default:
1269 return NULL_TREE;
1273 return NULL_TREE;
1276 #undef VAR1
1277 #define VAR1(T, N, MAP, A) \
1278 case AARCH64_SIMD_BUILTIN_##T##_##N##A:
1280 tree
1281 aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args,
1282 bool ignore ATTRIBUTE_UNUSED)
1284 int fcode = DECL_FUNCTION_CODE (fndecl);
1285 tree type = TREE_TYPE (TREE_TYPE (fndecl));
1287 switch (fcode)
1289 BUILTIN_VALLDI (UNOP, abs, 2)
1290 return fold_build1 (ABS_EXPR, type, args[0]);
1291 break;
1292 BUILTIN_VALLDI (BINOP, cmge, 0)
1293 return fold_build2 (GE_EXPR, type, args[0], args[1]);
1294 break;
1295 BUILTIN_VALLDI (BINOP, cmgt, 0)
1296 return fold_build2 (GT_EXPR, type, args[0], args[1]);
1297 break;
1298 BUILTIN_VALLDI (BINOP, cmeq, 0)
1299 return fold_build2 (EQ_EXPR, type, args[0], args[1]);
1300 break;
1301 BUILTIN_VSDQ_I_DI (BINOP, cmtst, 0)
1303 tree and_node = fold_build2 (BIT_AND_EXPR, type, args[0], args[1]);
1304 tree vec_zero_node = build_zero_cst (type);
1305 return fold_build2 (NE_EXPR, type, and_node, vec_zero_node);
1306 break;
1308 VAR1 (REINTERP_SS, reinterpretdi, 0, v1df)
1309 VAR1 (REINTERP_SS, reinterpretv8qi, 0, v1df)
1310 VAR1 (REINTERP_SS, reinterpretv4hi, 0, v1df)
1311 VAR1 (REINTERP_SS, reinterpretv2si, 0, v1df)
1312 VAR1 (REINTERP_SS, reinterpretv2sf, 0, v1df)
1313 BUILTIN_VD (REINTERP_SS, reinterpretv1df, 0)
1314 BUILTIN_VD (REINTERP_SU, reinterpretv1df, 0)
1315 VAR1 (REINTERP_US, reinterpretdi, 0, v1df)
1316 VAR1 (REINTERP_US, reinterpretv8qi, 0, v1df)
1317 VAR1 (REINTERP_US, reinterpretv4hi, 0, v1df)
1318 VAR1 (REINTERP_US, reinterpretv2si, 0, v1df)
1319 VAR1 (REINTERP_US, reinterpretv2sf, 0, v1df)
1320 BUILTIN_VD (REINTERP_SP, reinterpretv1df, 0)
1321 VAR1 (REINTERP_PS, reinterpretdi, 0, v1df)
1322 VAR1 (REINTERP_PS, reinterpretv8qi, 0, v1df)
1323 VAR1 (REINTERP_PS, reinterpretv4hi, 0, v1df)
1324 VAR1 (REINTERP_PS, reinterpretv2sf, 0, v1df)
1325 return fold_build1 (VIEW_CONVERT_EXPR, type, args[0]);
1326 VAR1 (UNOP, floatv2si, 2, v2sf)
1327 VAR1 (UNOP, floatv4si, 2, v4sf)
1328 VAR1 (UNOP, floatv2di, 2, v2df)
1329 return fold_build1 (FLOAT_EXPR, type, args[0]);
1330 default:
1331 break;
1334 return NULL_TREE;
1337 bool
1338 aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi)
1340 bool changed = false;
1341 gimple stmt = gsi_stmt (*gsi);
1342 tree call = gimple_call_fn (stmt);
1343 tree fndecl;
1344 gimple new_stmt = NULL;
1346 /* The operations folded below are reduction operations. These are
1347 defined to leave their result in the 0'th element (from the perspective
1348 of GCC). The architectural instruction we are folding will leave the
1349 result in the 0'th element (from the perspective of the architecture).
1350 For big-endian systems, these perspectives are not aligned.
1352 It is therefore wrong to perform this fold on big-endian. There
1353 are some tricks we could play with shuffling, but the mid-end is
1354 inconsistent in the way it treats reduction operations, so we will
1355 end up in difficulty. Until we fix the ambiguity - just bail out. */
1356 if (BYTES_BIG_ENDIAN)
1357 return false;
1359 if (call)
1361 fndecl = gimple_call_fndecl (stmt);
1362 if (fndecl)
1364 int fcode = DECL_FUNCTION_CODE (fndecl);
1365 int nargs = gimple_call_num_args (stmt);
1366 tree *args = (nargs > 0
1367 ? gimple_call_arg_ptr (stmt, 0)
1368 : &error_mark_node);
1370 switch (fcode)
1372 BUILTIN_VALL (UNOP, reduc_splus_, 10)
1373 new_stmt = gimple_build_assign_with_ops (
1374 REDUC_PLUS_EXPR,
1375 gimple_call_lhs (stmt),
1376 args[0],
1377 NULL_TREE);
1378 break;
1379 BUILTIN_VDQIF (UNOP, reduc_smax_, 10)
1380 new_stmt = gimple_build_assign_with_ops (
1381 REDUC_MAX_EXPR,
1382 gimple_call_lhs (stmt),
1383 args[0],
1384 NULL_TREE);
1385 break;
1386 BUILTIN_VDQIF (UNOP, reduc_smin_, 10)
1387 new_stmt = gimple_build_assign_with_ops (
1388 REDUC_MIN_EXPR,
1389 gimple_call_lhs (stmt),
1390 args[0],
1391 NULL_TREE);
1392 break;
1394 default:
1395 break;
1400 if (new_stmt)
1402 gsi_replace (gsi, new_stmt, true);
1403 changed = true;
1406 return changed;
1409 void
1410 aarch64_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
1412 const unsigned AARCH64_FE_INVALID = 1;
1413 const unsigned AARCH64_FE_DIVBYZERO = 2;
1414 const unsigned AARCH64_FE_OVERFLOW = 4;
1415 const unsigned AARCH64_FE_UNDERFLOW = 8;
1416 const unsigned AARCH64_FE_INEXACT = 16;
1417 const unsigned HOST_WIDE_INT AARCH64_FE_ALL_EXCEPT = (AARCH64_FE_INVALID
1418 | AARCH64_FE_DIVBYZERO
1419 | AARCH64_FE_OVERFLOW
1420 | AARCH64_FE_UNDERFLOW
1421 | AARCH64_FE_INEXACT);
1422 const unsigned HOST_WIDE_INT AARCH64_FE_EXCEPT_SHIFT = 8;
1423 tree fenv_cr, fenv_sr, get_fpcr, set_fpcr, mask_cr, mask_sr;
1424 tree ld_fenv_cr, ld_fenv_sr, masked_fenv_cr, masked_fenv_sr, hold_fnclex_cr;
1425 tree hold_fnclex_sr, new_fenv_var, reload_fenv, restore_fnenv, get_fpsr, set_fpsr;
1426 tree update_call, atomic_feraiseexcept, hold_fnclex, masked_fenv, ld_fenv;
1428 /* Generate the equivalence of :
1429 unsigned int fenv_cr;
1430 fenv_cr = __builtin_aarch64_get_fpcr ();
1432 unsigned int fenv_sr;
1433 fenv_sr = __builtin_aarch64_get_fpsr ();
1435 Now set all exceptions to non-stop
1436 unsigned int mask_cr
1437 = ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT);
1438 unsigned int masked_cr;
1439 masked_cr = fenv_cr & mask_cr;
1441 And clear all exception flags
1442 unsigned int maske_sr = ~AARCH64_FE_ALL_EXCEPT;
1443 unsigned int masked_cr;
1444 masked_sr = fenv_sr & mask_sr;
1446 __builtin_aarch64_set_cr (masked_cr);
1447 __builtin_aarch64_set_sr (masked_sr); */
1449 fenv_cr = create_tmp_var (unsigned_type_node, NULL);
1450 fenv_sr = create_tmp_var (unsigned_type_node, NULL);
1452 get_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR];
1453 set_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR];
1454 get_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR];
1455 set_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR];
1457 mask_cr = build_int_cst (unsigned_type_node,
1458 ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT));
1459 mask_sr = build_int_cst (unsigned_type_node,
1460 ~(AARCH64_FE_ALL_EXCEPT));
1462 ld_fenv_cr = build2 (MODIFY_EXPR, unsigned_type_node,
1463 fenv_cr, build_call_expr (get_fpcr, 0));
1464 ld_fenv_sr = build2 (MODIFY_EXPR, unsigned_type_node,
1465 fenv_sr, build_call_expr (get_fpsr, 0));
1467 masked_fenv_cr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_cr, mask_cr);
1468 masked_fenv_sr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_sr, mask_sr);
1470 hold_fnclex_cr = build_call_expr (set_fpcr, 1, masked_fenv_cr);
1471 hold_fnclex_sr = build_call_expr (set_fpsr, 1, masked_fenv_sr);
1473 hold_fnclex = build2 (COMPOUND_EXPR, void_type_node, hold_fnclex_cr,
1474 hold_fnclex_sr);
1475 masked_fenv = build2 (COMPOUND_EXPR, void_type_node, masked_fenv_cr,
1476 masked_fenv_sr);
1477 ld_fenv = build2 (COMPOUND_EXPR, void_type_node, ld_fenv_cr, ld_fenv_sr);
1479 *hold = build2 (COMPOUND_EXPR, void_type_node,
1480 build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv),
1481 hold_fnclex);
1483 /* Store the value of masked_fenv to clear the exceptions:
1484 __builtin_aarch64_set_fpsr (masked_fenv_sr); */
1486 *clear = build_call_expr (set_fpsr, 1, masked_fenv_sr);
1488 /* Generate the equivalent of :
1489 unsigned int new_fenv_var;
1490 new_fenv_var = __builtin_aarch64_get_fpsr ();
1492 __builtin_aarch64_set_fpsr (fenv_sr);
1494 __atomic_feraiseexcept (new_fenv_var); */
1496 new_fenv_var = create_tmp_var (unsigned_type_node, NULL);
1497 reload_fenv = build2 (MODIFY_EXPR, unsigned_type_node,
1498 new_fenv_var, build_call_expr (get_fpsr, 0));
1499 restore_fnenv = build_call_expr (set_fpsr, 1, fenv_sr);
1500 atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT);
1501 update_call = build_call_expr (atomic_feraiseexcept, 1,
1502 fold_convert (integer_type_node, new_fenv_var));
1503 *update = build2 (COMPOUND_EXPR, void_type_node,
1504 build2 (COMPOUND_EXPR, void_type_node,
1505 reload_fenv, restore_fnenv), update_call);
1509 #undef AARCH64_CHECK_BUILTIN_MODE
1510 #undef AARCH64_FIND_FRINT_VARIANT
1511 #undef BUILTIN_DX
1512 #undef BUILTIN_SDQ_I
1513 #undef BUILTIN_SD_HSI
1514 #undef BUILTIN_V2F
1515 #undef BUILTIN_VALL
1516 #undef BUILTIN_VB
1517 #undef BUILTIN_VD
1518 #undef BUILTIN_VD1
1519 #undef BUILTIN_VDC
1520 #undef BUILTIN_VDIC
1521 #undef BUILTIN_VDN
1522 #undef BUILTIN_VDQ
1523 #undef BUILTIN_VDQF
1524 #undef BUILTIN_VDQH
1525 #undef BUILTIN_VDQHS
1526 #undef BUILTIN_VDQIF
1527 #undef BUILTIN_VDQM
1528 #undef BUILTIN_VDQV
1529 #undef BUILTIN_VDQ_BHSI
1530 #undef BUILTIN_VDQ_I
1531 #undef BUILTIN_VDW
1532 #undef BUILTIN_VD_BHSI
1533 #undef BUILTIN_VD_HSI
1534 #undef BUILTIN_VQ
1535 #undef BUILTIN_VQN
1536 #undef BUILTIN_VQW
1537 #undef BUILTIN_VQ_HSI
1538 #undef BUILTIN_VQ_S
1539 #undef BUILTIN_VSDQ_HSI
1540 #undef BUILTIN_VSDQ_I
1541 #undef BUILTIN_VSDQ_I_BHSI
1542 #undef BUILTIN_VSDQ_I_DI
1543 #undef BUILTIN_VSD_HSI
1544 #undef BUILTIN_VSQN_HSDI
1545 #undef BUILTIN_VSTRUCT
1546 #undef CF0
1547 #undef CF1
1548 #undef CF2
1549 #undef CF3
1550 #undef CF4
1551 #undef CF10
1552 #undef VAR1
1553 #undef VAR2
1554 #undef VAR3
1555 #undef VAR4
1556 #undef VAR5
1557 #undef VAR6
1558 #undef VAR7
1559 #undef VAR8
1560 #undef VAR9
1561 #undef VAR10
1562 #undef VAR11