1 /* Builtins' description for AArch64 SIMD architecture.
2 Copyright (C) 2011-2014 Free Software Foundation, Inc.
3 Contributed by ARM Ltd.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
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"
49
50 enum aarch64_simd_builtin_type_mode
51 {
52 T_V8QI,
53 T_V4HI,
54 T_V2SI,
55 T_V2SF,
56 T_DI,
57 T_DF,
58 T_V16QI,
59 T_V8HI,
60 T_V4SI,
61 T_V4SF,
62 T_V2DI,
63 T_V2DF,
64 T_TI,
65 T_EI,
66 T_OI,
67 T_XI,
68 T_SI,
69 T_SF,
70 T_HI,
71 T_QI,
72 T_MAX
73 };
74
75 #define v8qi_UP T_V8QI
76 #define v4hi_UP T_V4HI
77 #define v2si_UP T_V2SI
78 #define v2sf_UP T_V2SF
79 #define di_UP T_DI
80 #define df_UP T_DF
81 #define v16qi_UP T_V16QI
82 #define v8hi_UP T_V8HI
83 #define v4si_UP T_V4SI
84 #define v4sf_UP T_V4SF
85 #define v2di_UP T_V2DI
86 #define v2df_UP T_V2DF
87 #define ti_UP T_TI
88 #define ei_UP T_EI
89 #define oi_UP T_OI
90 #define xi_UP T_XI
91 #define si_UP T_SI
92 #define sf_UP T_SF
93 #define hi_UP T_HI
94 #define qi_UP T_QI
95
96 #define UP(X) X##_UP
97
98 #define SIMD_MAX_BUILTIN_ARGS 5
99
100 enum aarch64_type_qualifiers
101 {
102 /* T foo. */
103 qualifier_none = 0x0,
104 /* unsigned T foo. */
105 qualifier_unsigned = 0x1, /* 1 << 0 */
106 /* const T foo. */
107 qualifier_const = 0x2, /* 1 << 1 */
108 /* T *foo. */
109 qualifier_pointer = 0x4, /* 1 << 2 */
110 /* const T *foo. */
111 qualifier_const_pointer = 0x6, /* qualifier_const | qualifier_pointer */
112 /* Used when expanding arguments if an operand could
113 be an immediate. */
114 qualifier_immediate = 0x8, /* 1 << 3 */
115 qualifier_maybe_immediate = 0x10, /* 1 << 4 */
116 /* void foo (...). */
117 qualifier_void = 0x20, /* 1 << 5 */
118 /* Some patterns may have internal operands, this qualifier is an
119 instruction to the initialisation code to skip this operand. */
120 qualifier_internal = 0x40, /* 1 << 6 */
121 /* Some builtins should use the T_*mode* encoded in a simd_builtin_datum
122 rather than using the type of the operand. */
123 qualifier_map_mode = 0x80, /* 1 << 7 */
124 /* qualifier_pointer | qualifier_map_mode */
125 qualifier_pointer_map_mode = 0x84,
126 /* qualifier_const_pointer | qualifier_map_mode */
127 qualifier_const_pointer_map_mode = 0x86,
128 /* Polynomial types. */
129 qualifier_poly = 0x100
130 };
131
132 typedef struct
133 {
134 const char *name;
135 enum aarch64_simd_builtin_type_mode mode;
136 const enum insn_code code;
137 unsigned int fcode;
138 enum aarch64_type_qualifiers *qualifiers;
139 } aarch64_simd_builtin_datum;
140
141 static enum aarch64_type_qualifiers
142 aarch64_types_unop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
143 = { qualifier_none, qualifier_none };
144 #define TYPES_UNOP (aarch64_types_unop_qualifiers)
145 static enum aarch64_type_qualifiers
146 aarch64_types_unopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
147 = { qualifier_unsigned, qualifier_unsigned };
148 #define TYPES_UNOPU (aarch64_types_unopu_qualifiers)
149 #define TYPES_CREATE (aarch64_types_unop_qualifiers)
150 #define TYPES_REINTERP (aarch64_types_unop_qualifiers)
151 static enum aarch64_type_qualifiers
152 aarch64_types_binop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
153 = { qualifier_none, qualifier_none, qualifier_maybe_immediate };
154 #define TYPES_BINOP (aarch64_types_binop_qualifiers)
155 static enum aarch64_type_qualifiers
156 aarch64_types_binopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
157 = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned };
158 #define TYPES_BINOPU (aarch64_types_binopu_qualifiers)
159 static enum aarch64_type_qualifiers
160 aarch64_types_binopp_qualifiers[SIMD_MAX_BUILTIN_ARGS]
161 = { qualifier_poly, qualifier_poly, qualifier_poly };
162 #define TYPES_BINOPP (aarch64_types_binopp_qualifiers)
163
164 static enum aarch64_type_qualifiers
165 aarch64_types_ternop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
166 = { qualifier_none, qualifier_none, qualifier_none, qualifier_none };
167 #define TYPES_TERNOP (aarch64_types_ternop_qualifiers)
168 static enum aarch64_type_qualifiers
169 aarch64_types_ternopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
170 = { qualifier_unsigned, qualifier_unsigned,
171 qualifier_unsigned, qualifier_unsigned };
172 #define TYPES_TERNOPU (aarch64_types_ternopu_qualifiers)
173
174 static enum aarch64_type_qualifiers
175 aarch64_types_quadop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
176 = { qualifier_none, qualifier_none, qualifier_none,
177 qualifier_none, qualifier_none };
178 #define TYPES_QUADOP (aarch64_types_quadop_qualifiers)
179
180 static enum aarch64_type_qualifiers
181 aarch64_types_getlane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
182 = { qualifier_none, qualifier_none, qualifier_immediate };
183 #define TYPES_GETLANE (aarch64_types_getlane_qualifiers)
184 #define TYPES_SHIFTIMM (aarch64_types_getlane_qualifiers)
185 static enum aarch64_type_qualifiers
186 aarch64_types_unsigned_shift_qualifiers[SIMD_MAX_BUILTIN_ARGS]
187 = { qualifier_unsigned, qualifier_unsigned, qualifier_immediate };
188 #define TYPES_USHIFTIMM (aarch64_types_unsigned_shift_qualifiers)
189 static enum aarch64_type_qualifiers
190 aarch64_types_setlane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
191 = { qualifier_none, qualifier_none, qualifier_none, qualifier_immediate };
192 #define TYPES_SETLANE (aarch64_types_setlane_qualifiers)
193 #define TYPES_SHIFTINSERT (aarch64_types_setlane_qualifiers)
194 #define TYPES_SHIFTACC (aarch64_types_setlane_qualifiers)
195
196 static enum aarch64_type_qualifiers
197 aarch64_types_combine_qualifiers[SIMD_MAX_BUILTIN_ARGS]
198 = { qualifier_none, qualifier_none, qualifier_none };
199 #define TYPES_COMBINE (aarch64_types_combine_qualifiers)
200
201 static enum aarch64_type_qualifiers
202 aarch64_types_load1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
203 = { qualifier_none, qualifier_const_pointer_map_mode };
204 #define TYPES_LOAD1 (aarch64_types_load1_qualifiers)
205 #define TYPES_LOADSTRUCT (aarch64_types_load1_qualifiers)
206
207 static enum aarch64_type_qualifiers
208 aarch64_types_bsl_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
209 = { qualifier_poly, qualifier_unsigned,
210 qualifier_poly, qualifier_poly };
211 #define TYPES_BSL_P (aarch64_types_bsl_p_qualifiers)
212 static enum aarch64_type_qualifiers
213 aarch64_types_bsl_s_qualifiers[SIMD_MAX_BUILTIN_ARGS]
214 = { qualifier_none, qualifier_unsigned,
215 qualifier_none, qualifier_none };
216 #define TYPES_BSL_S (aarch64_types_bsl_s_qualifiers)
217 static enum aarch64_type_qualifiers
218 aarch64_types_bsl_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
219 = { qualifier_unsigned, qualifier_unsigned,
220 qualifier_unsigned, qualifier_unsigned };
221 #define TYPES_BSL_U (aarch64_types_bsl_u_qualifiers)
222
223 /* The first argument (return type) of a store should be void type,
224 which we represent with qualifier_void. Their first operand will be
225 a DImode pointer to the location to store to, so we must use
226 qualifier_map_mode | qualifier_pointer to build a pointer to the
227 element type of the vector. */
228 static enum aarch64_type_qualifiers
229 aarch64_types_store1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
230 = { qualifier_void, qualifier_pointer_map_mode, qualifier_none };
231 #define TYPES_STORE1 (aarch64_types_store1_qualifiers)
232 #define TYPES_STORESTRUCT (aarch64_types_store1_qualifiers)
233
234 #define CF0(N, X) CODE_FOR_aarch64_##N##X
235 #define CF1(N, X) CODE_FOR_##N##X##1
236 #define CF2(N, X) CODE_FOR_##N##X##2
237 #define CF3(N, X) CODE_FOR_##N##X##3
238 #define CF4(N, X) CODE_FOR_##N##X##4
239 #define CF10(N, X) CODE_FOR_##N##X
240
241 #define VAR1(T, N, MAP, A) \
242 {#N, UP (A), CF##MAP (N, A), 0, TYPES_##T},
243 #define VAR2(T, N, MAP, A, B) \
244 VAR1 (T, N, MAP, A) \
245 VAR1 (T, N, MAP, B)
246 #define VAR3(T, N, MAP, A, B, C) \
247 VAR2 (T, N, MAP, A, B) \
248 VAR1 (T, N, MAP, C)
249 #define VAR4(T, N, MAP, A, B, C, D) \
250 VAR3 (T, N, MAP, A, B, C) \
251 VAR1 (T, N, MAP, D)
252 #define VAR5(T, N, MAP, A, B, C, D, E) \
253 VAR4 (T, N, MAP, A, B, C, D) \
254 VAR1 (T, N, MAP, E)
255 #define VAR6(T, N, MAP, A, B, C, D, E, F) \
256 VAR5 (T, N, MAP, A, B, C, D, E) \
257 VAR1 (T, N, MAP, F)
258 #define VAR7(T, N, MAP, A, B, C, D, E, F, G) \
259 VAR6 (T, N, MAP, A, B, C, D, E, F) \
260 VAR1 (T, N, MAP, G)
261 #define VAR8(T, N, MAP, A, B, C, D, E, F, G, H) \
262 VAR7 (T, N, MAP, A, B, C, D, E, F, G) \
263 VAR1 (T, N, MAP, H)
264 #define VAR9(T, N, MAP, A, B, C, D, E, F, G, H, I) \
265 VAR8 (T, N, MAP, A, B, C, D, E, F, G, H) \
266 VAR1 (T, N, MAP, I)
267 #define VAR10(T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
268 VAR9 (T, N, MAP, A, B, C, D, E, F, G, H, I) \
269 VAR1 (T, N, MAP, J)
270 #define VAR11(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
271 VAR10 (T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
272 VAR1 (T, N, MAP, K)
273 #define VAR12(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K, L) \
274 VAR11 (T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
275 VAR1 (T, N, MAP, L)
276
277 /* BUILTIN_<ITERATOR> macros should expand to cover the same range of
278 modes as is given for each define_mode_iterator in
279 config/aarch64/iterators.md. */
280
281 #define BUILTIN_DX(T, N, MAP) \
282 VAR2 (T, N, MAP, di, df)
283 #define BUILTIN_GPF(T, N, MAP) \
284 VAR2 (T, N, MAP, sf, df)
285 #define BUILTIN_SDQ_I(T, N, MAP) \
286 VAR4 (T, N, MAP, qi, hi, si, di)
287 #define BUILTIN_SD_HSI(T, N, MAP) \
288 VAR2 (T, N, MAP, hi, si)
289 #define BUILTIN_V2F(T, N, MAP) \
290 VAR2 (T, N, MAP, v2sf, v2df)
291 #define BUILTIN_VALL(T, N, MAP) \
292 VAR10 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, \
293 v4si, v2di, v2sf, v4sf, v2df)
294 #define BUILTIN_VALLDI(T, N, MAP) \
295 VAR11 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, \
296 v4si, v2di, v2sf, v4sf, v2df, di)
297 #define BUILTIN_VALLDIF(T, N, MAP) \
298 VAR12 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, \
299 v4si, v2di, v2sf, v4sf, v2df, di, df)
300 #define BUILTIN_VB(T, N, MAP) \
301 VAR2 (T, N, MAP, v8qi, v16qi)
302 #define BUILTIN_VD(T, N, MAP) \
303 VAR4 (T, N, MAP, v8qi, v4hi, v2si, v2sf)
304 #define BUILTIN_VDC(T, N, MAP) \
305 VAR6 (T, N, MAP, v8qi, v4hi, v2si, v2sf, di, df)
306 #define BUILTIN_VDIC(T, N, MAP) \
307 VAR3 (T, N, MAP, v8qi, v4hi, v2si)
308 #define BUILTIN_VDN(T, N, MAP) \
309 VAR3 (T, N, MAP, v4hi, v2si, di)
310 #define BUILTIN_VDQ(T, N, MAP) \
311 VAR7 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di)
312 #define BUILTIN_VDQF(T, N, MAP) \
313 VAR3 (T, N, MAP, v2sf, v4sf, v2df)
314 #define BUILTIN_VDQH(T, N, MAP) \
315 VAR2 (T, N, MAP, v4hi, v8hi)
316 #define BUILTIN_VDQHS(T, N, MAP) \
317 VAR4 (T, N, MAP, v4hi, v8hi, v2si, v4si)
318 #define BUILTIN_VDQIF(T, N, MAP) \
319 VAR9 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2sf, v4sf, v2df)
320 #define BUILTIN_VDQM(T, N, MAP) \
321 VAR6 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si)
322 #define BUILTIN_VDQV(T, N, MAP) \
323 VAR5 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v4si)
324 #define BUILTIN_VDQQH(T, N, MAP) \
325 VAR4 (T, N, MAP, v8qi, v16qi, v4hi, v8hi)
326 #define BUILTIN_VDQ_BHSI(T, N, MAP) \
327 VAR6 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si)
328 #define BUILTIN_VDQ_I(T, N, MAP) \
329 VAR7 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di)
330 #define BUILTIN_VDW(T, N, MAP) \
331 VAR3 (T, N, MAP, v8qi, v4hi, v2si)
332 #define BUILTIN_VD_BHSI(T, N, MAP) \
333 VAR3 (T, N, MAP, v8qi, v4hi, v2si)
334 #define BUILTIN_VD_HSI(T, N, MAP) \
335 VAR2 (T, N, MAP, v4hi, v2si)
336 #define BUILTIN_VD_RE(T, N, MAP) \
337 VAR6 (T, N, MAP, v8qi, v4hi, v2si, v2sf, di, df)
338 #define BUILTIN_VQ(T, N, MAP) \
339 VAR6 (T, N, MAP, v16qi, v8hi, v4si, v2di, v4sf, v2df)
340 #define BUILTIN_VQN(T, N, MAP) \
341 VAR3 (T, N, MAP, v8hi, v4si, v2di)
342 #define BUILTIN_VQW(T, N, MAP) \
343 VAR3 (T, N, MAP, v16qi, v8hi, v4si)
344 #define BUILTIN_VQ_HSI(T, N, MAP) \
345 VAR2 (T, N, MAP, v8hi, v4si)
346 #define BUILTIN_VQ_S(T, N, MAP) \
347 VAR6 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si)
348 #define BUILTIN_VSDQ_HSI(T, N, MAP) \
349 VAR6 (T, N, MAP, v4hi, v8hi, v2si, v4si, hi, si)
350 #define BUILTIN_VSDQ_I(T, N, MAP) \
351 VAR11 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di, qi, hi, si, di)
352 #define BUILTIN_VSDQ_I_BHSI(T, N, MAP) \
353 VAR10 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di, qi, hi, si)
354 #define BUILTIN_VSDQ_I_DI(T, N, MAP) \
355 VAR8 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di, di)
356 #define BUILTIN_VSD_HSI(T, N, MAP) \
357 VAR4 (T, N, MAP, v4hi, v2si, hi, si)
358 #define BUILTIN_VSQN_HSDI(T, N, MAP) \
359 VAR6 (T, N, MAP, v8hi, v4si, v2di, hi, si, di)
360 #define BUILTIN_VSTRUCT(T, N, MAP) \
361 VAR3 (T, N, MAP, oi, ci, xi)
362
363 static aarch64_simd_builtin_datum aarch64_simd_builtin_data[] = {
364 #include "aarch64-simd-builtins.def"
365 };
366
367 #undef VAR1
368 #define VAR1(T, N, MAP, A) \
369 AARCH64_SIMD_BUILTIN_##T##_##N##A,
370
371 enum aarch64_builtins
372 {
373 AARCH64_BUILTIN_MIN,
374 AARCH64_SIMD_BUILTIN_BASE,
375 #include "aarch64-simd-builtins.def"
376 AARCH64_SIMD_BUILTIN_MAX = AARCH64_SIMD_BUILTIN_BASE
377 + ARRAY_SIZE (aarch64_simd_builtin_data),
378 AARCH64_BUILTIN_MAX
379 };
380
381 static GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX];
382
383 #define NUM_DREG_TYPES 6
384 #define NUM_QREG_TYPES 6
385
386 /* Return a tree for a signed or unsigned argument of either
387 the mode specified by MODE, or the inner mode of MODE. */
388 tree
aarch64_build_scalar_type(enum machine_mode mode,bool unsigned_p,bool poly_p)389 aarch64_build_scalar_type (enum machine_mode mode,
390 bool unsigned_p,
391 bool poly_p)
392 {
393 #undef INT_TYPES
394 #define INT_TYPES \
395 AARCH64_TYPE_BUILDER (QI) \
396 AARCH64_TYPE_BUILDER (HI) \
397 AARCH64_TYPE_BUILDER (SI) \
398 AARCH64_TYPE_BUILDER (DI) \
399 AARCH64_TYPE_BUILDER (EI) \
400 AARCH64_TYPE_BUILDER (OI) \
401 AARCH64_TYPE_BUILDER (CI) \
402 AARCH64_TYPE_BUILDER (XI) \
403 AARCH64_TYPE_BUILDER (TI) \
404
405 /* Statically declare all the possible types we might need. */
406 #undef AARCH64_TYPE_BUILDER
407 #define AARCH64_TYPE_BUILDER(X) \
408 static tree X##_aarch64_type_node_p = NULL; \
409 static tree X##_aarch64_type_node_s = NULL; \
410 static tree X##_aarch64_type_node_u = NULL;
411
412 INT_TYPES
413
414 static tree float_aarch64_type_node = NULL;
415 static tree double_aarch64_type_node = NULL;
416
417 gcc_assert (!VECTOR_MODE_P (mode));
418
419 /* If we've already initialised this type, don't initialise it again,
420 otherwise ask for a new type of the correct size. */
421 #undef AARCH64_TYPE_BUILDER
422 #define AARCH64_TYPE_BUILDER(X) \
423 case X##mode: \
424 if (unsigned_p) \
425 return (X##_aarch64_type_node_u \
426 ? X##_aarch64_type_node_u \
427 : X##_aarch64_type_node_u \
428 = make_unsigned_type (GET_MODE_PRECISION (mode))); \
429 else if (poly_p) \
430 return (X##_aarch64_type_node_p \
431 ? X##_aarch64_type_node_p \
432 : X##_aarch64_type_node_p \
433 = make_unsigned_type (GET_MODE_PRECISION (mode))); \
434 else \
435 return (X##_aarch64_type_node_s \
436 ? X##_aarch64_type_node_s \
437 : X##_aarch64_type_node_s \
438 = make_signed_type (GET_MODE_PRECISION (mode))); \
439 break;
440
441 switch (mode)
442 {
443 INT_TYPES
444 case SFmode:
445 if (!float_aarch64_type_node)
446 {
447 float_aarch64_type_node = make_node (REAL_TYPE);
448 TYPE_PRECISION (float_aarch64_type_node) = FLOAT_TYPE_SIZE;
449 layout_type (float_aarch64_type_node);
450 }
451 return float_aarch64_type_node;
452 break;
453 case DFmode:
454 if (!double_aarch64_type_node)
455 {
456 double_aarch64_type_node = make_node (REAL_TYPE);
457 TYPE_PRECISION (double_aarch64_type_node) = DOUBLE_TYPE_SIZE;
458 layout_type (double_aarch64_type_node);
459 }
460 return double_aarch64_type_node;
461 break;
462 default:
463 gcc_unreachable ();
464 }
465 }
466
467 tree
aarch64_build_vector_type(enum machine_mode mode,bool unsigned_p,bool poly_p)468 aarch64_build_vector_type (enum machine_mode mode,
469 bool unsigned_p,
470 bool poly_p)
471 {
472 tree eltype;
473
474 #define VECTOR_TYPES \
475 AARCH64_TYPE_BUILDER (V16QI) \
476 AARCH64_TYPE_BUILDER (V8HI) \
477 AARCH64_TYPE_BUILDER (V4SI) \
478 AARCH64_TYPE_BUILDER (V2DI) \
479 AARCH64_TYPE_BUILDER (V8QI) \
480 AARCH64_TYPE_BUILDER (V4HI) \
481 AARCH64_TYPE_BUILDER (V2SI) \
482 \
483 AARCH64_TYPE_BUILDER (V4SF) \
484 AARCH64_TYPE_BUILDER (V2DF) \
485 AARCH64_TYPE_BUILDER (V2SF) \
486 /* Declare our "cache" of values. */
487 #undef AARCH64_TYPE_BUILDER
488 #define AARCH64_TYPE_BUILDER(X) \
489 static tree X##_aarch64_type_node_s = NULL; \
490 static tree X##_aarch64_type_node_u = NULL; \
491 static tree X##_aarch64_type_node_p = NULL;
492
493 VECTOR_TYPES
494
495 gcc_assert (VECTOR_MODE_P (mode));
496
497 #undef AARCH64_TYPE_BUILDER
498 #define AARCH64_TYPE_BUILDER(X) \
499 case X##mode: \
500 if (unsigned_p) \
501 return X##_aarch64_type_node_u \
502 ? X##_aarch64_type_node_u \
503 : X##_aarch64_type_node_u \
504 = build_vector_type_for_mode (aarch64_build_scalar_type \
505 (GET_MODE_INNER (mode), \
506 unsigned_p, poly_p), mode); \
507 else if (poly_p) \
508 return X##_aarch64_type_node_p \
509 ? X##_aarch64_type_node_p \
510 : X##_aarch64_type_node_p \
511 = build_vector_type_for_mode (aarch64_build_scalar_type \
512 (GET_MODE_INNER (mode), \
513 unsigned_p, poly_p), mode); \
514 else \
515 return X##_aarch64_type_node_s \
516 ? X##_aarch64_type_node_s \
517 : X##_aarch64_type_node_s \
518 = build_vector_type_for_mode (aarch64_build_scalar_type \
519 (GET_MODE_INNER (mode), \
520 unsigned_p, poly_p), mode); \
521 break;
522
523 switch (mode)
524 {
525 default:
526 eltype = aarch64_build_scalar_type (GET_MODE_INNER (mode),
527 unsigned_p, poly_p);
528 return build_vector_type_for_mode (eltype, mode);
529 break;
530 VECTOR_TYPES
531 }
532 }
533
534 tree
aarch64_build_type(enum machine_mode mode,bool unsigned_p,bool poly_p)535 aarch64_build_type (enum machine_mode mode, bool unsigned_p, bool poly_p)
536 {
537 if (VECTOR_MODE_P (mode))
538 return aarch64_build_vector_type (mode, unsigned_p, poly_p);
539 else
540 return aarch64_build_scalar_type (mode, unsigned_p, poly_p);
541 }
542
543 tree
aarch64_build_signed_type(enum machine_mode mode)544 aarch64_build_signed_type (enum machine_mode mode)
545 {
546 return aarch64_build_type (mode, false, false);
547 }
548
549 tree
aarch64_build_unsigned_type(enum machine_mode mode)550 aarch64_build_unsigned_type (enum machine_mode mode)
551 {
552 return aarch64_build_type (mode, true, false);
553 }
554
555 tree
aarch64_build_poly_type(enum machine_mode mode)556 aarch64_build_poly_type (enum machine_mode mode)
557 {
558 return aarch64_build_type (mode, false, true);
559 }
560
561 static void
aarch64_init_simd_builtins(void)562 aarch64_init_simd_builtins (void)
563 {
564 unsigned int i, fcode = AARCH64_SIMD_BUILTIN_BASE + 1;
565
566 /* Signed scalar type nodes. */
567 tree aarch64_simd_intQI_type_node = aarch64_build_signed_type (QImode);
568 tree aarch64_simd_intHI_type_node = aarch64_build_signed_type (HImode);
569 tree aarch64_simd_intSI_type_node = aarch64_build_signed_type (SImode);
570 tree aarch64_simd_intDI_type_node = aarch64_build_signed_type (DImode);
571 tree aarch64_simd_intTI_type_node = aarch64_build_signed_type (TImode);
572 tree aarch64_simd_intEI_type_node = aarch64_build_signed_type (EImode);
573 tree aarch64_simd_intOI_type_node = aarch64_build_signed_type (OImode);
574 tree aarch64_simd_intCI_type_node = aarch64_build_signed_type (CImode);
575 tree aarch64_simd_intXI_type_node = aarch64_build_signed_type (XImode);
576
577 /* Unsigned scalar type nodes. */
578 tree aarch64_simd_intUQI_type_node = aarch64_build_unsigned_type (QImode);
579 tree aarch64_simd_intUHI_type_node = aarch64_build_unsigned_type (HImode);
580 tree aarch64_simd_intUSI_type_node = aarch64_build_unsigned_type (SImode);
581 tree aarch64_simd_intUDI_type_node = aarch64_build_unsigned_type (DImode);
582
583 /* Poly scalar type nodes. */
584 tree aarch64_simd_polyQI_type_node = aarch64_build_poly_type (QImode);
585 tree aarch64_simd_polyHI_type_node = aarch64_build_poly_type (HImode);
586 tree aarch64_simd_polyDI_type_node = aarch64_build_poly_type (DImode);
587 tree aarch64_simd_polyTI_type_node = aarch64_build_poly_type (TImode);
588
589 /* Float type nodes. */
590 tree aarch64_simd_float_type_node = aarch64_build_signed_type (SFmode);
591 tree aarch64_simd_double_type_node = aarch64_build_signed_type (DFmode);
592
593 /* Define typedefs which exactly correspond to the modes we are basing vector
594 types on. If you change these names you'll need to change
595 the table used by aarch64_mangle_type too. */
596 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intQI_type_node,
597 "__builtin_aarch64_simd_qi");
598 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intHI_type_node,
599 "__builtin_aarch64_simd_hi");
600 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intSI_type_node,
601 "__builtin_aarch64_simd_si");
602 (*lang_hooks.types.register_builtin_type) (aarch64_simd_float_type_node,
603 "__builtin_aarch64_simd_sf");
604 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intDI_type_node,
605 "__builtin_aarch64_simd_di");
606 (*lang_hooks.types.register_builtin_type) (aarch64_simd_double_type_node,
607 "__builtin_aarch64_simd_df");
608 (*lang_hooks.types.register_builtin_type) (aarch64_simd_polyQI_type_node,
609 "__builtin_aarch64_simd_poly8");
610 (*lang_hooks.types.register_builtin_type) (aarch64_simd_polyHI_type_node,
611 "__builtin_aarch64_simd_poly16");
612 (*lang_hooks.types.register_builtin_type) (aarch64_simd_polyDI_type_node,
613 "__builtin_aarch64_simd_poly64");
614 (*lang_hooks.types.register_builtin_type) (aarch64_simd_polyTI_type_node,
615 "__builtin_aarch64_simd_poly128");
616 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intTI_type_node,
617 "__builtin_aarch64_simd_ti");
618 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intEI_type_node,
619 "__builtin_aarch64_simd_ei");
620 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intOI_type_node,
621 "__builtin_aarch64_simd_oi");
622 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intCI_type_node,
623 "__builtin_aarch64_simd_ci");
624 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intXI_type_node,
625 "__builtin_aarch64_simd_xi");
626
627 /* Unsigned integer types for various mode sizes. */
628 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUQI_type_node,
629 "__builtin_aarch64_simd_uqi");
630 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUHI_type_node,
631 "__builtin_aarch64_simd_uhi");
632 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUSI_type_node,
633 "__builtin_aarch64_simd_usi");
634 (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUDI_type_node,
635 "__builtin_aarch64_simd_udi");
636
637 for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++)
638 {
639 bool print_type_signature_p = false;
640 char type_signature[SIMD_MAX_BUILTIN_ARGS] = { 0 };
641 aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i];
642 const char *const modenames[] =
643 {
644 "v8qi", "v4hi", "v2si", "v2sf", "di", "df",
645 "v16qi", "v8hi", "v4si", "v4sf", "v2di", "v2df",
646 "ti", "ei", "oi", "xi", "si", "sf", "hi", "qi"
647 };
648 const enum machine_mode modes[] =
649 {
650 V8QImode, V4HImode, V2SImode, V2SFmode, DImode, DFmode,
651 V16QImode, V8HImode, V4SImode, V4SFmode, V2DImode,
652 V2DFmode, TImode, EImode, OImode, XImode, SImode,
653 SFmode, HImode, QImode
654 };
655 char namebuf[60];
656 tree ftype = NULL;
657 tree fndecl = NULL;
658
659 gcc_assert (ARRAY_SIZE (modenames) == T_MAX);
660
661 d->fcode = fcode;
662
663 /* We must track two variables here. op_num is
664 the operand number as in the RTL pattern. This is
665 required to access the mode (e.g. V4SF mode) of the
666 argument, from which the base type can be derived.
667 arg_num is an index in to the qualifiers data, which
668 gives qualifiers to the type (e.g. const unsigned).
669 The reason these two variables may differ by one is the
670 void return type. While all return types take the 0th entry
671 in the qualifiers array, there is no operand for them in the
672 RTL pattern. */
673 int op_num = insn_data[d->code].n_operands - 1;
674 int arg_num = d->qualifiers[0] & qualifier_void
675 ? op_num + 1
676 : op_num;
677 tree return_type = void_type_node, args = void_list_node;
678 tree eltype;
679
680 /* Build a function type directly from the insn_data for this
681 builtin. The build_function_type () function takes care of
682 removing duplicates for us. */
683 for (; op_num >= 0; arg_num--, op_num--)
684 {
685 enum machine_mode op_mode = insn_data[d->code].operand[op_num].mode;
686 enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num];
687
688 if (qualifiers & qualifier_unsigned)
689 {
690 type_signature[arg_num] = 'u';
691 print_type_signature_p = true;
692 }
693 else if (qualifiers & qualifier_poly)
694 {
695 type_signature[arg_num] = 'p';
696 print_type_signature_p = true;
697 }
698 else
699 type_signature[arg_num] = 's';
700
701 /* Skip an internal operand for vget_{low, high}. */
702 if (qualifiers & qualifier_internal)
703 continue;
704
705 /* Some builtins have different user-facing types
706 for certain arguments, encoded in d->mode. */
707 if (qualifiers & qualifier_map_mode)
708 op_mode = modes[d->mode];
709
710 /* For pointers, we want a pointer to the basic type
711 of the vector. */
712 if (qualifiers & qualifier_pointer && VECTOR_MODE_P (op_mode))
713 op_mode = GET_MODE_INNER (op_mode);
714
715 eltype = aarch64_build_type (op_mode,
716 qualifiers & qualifier_unsigned,
717 qualifiers & qualifier_poly);
718
719 /* Add qualifiers. */
720 if (qualifiers & qualifier_const)
721 eltype = build_qualified_type (eltype, TYPE_QUAL_CONST);
722
723 if (qualifiers & qualifier_pointer)
724 eltype = build_pointer_type (eltype);
725
726 /* If we have reached arg_num == 0, we are at a non-void
727 return type. Otherwise, we are still processing
728 arguments. */
729 if (arg_num == 0)
730 return_type = eltype;
731 else
732 args = tree_cons (NULL_TREE, eltype, args);
733 }
734
735 ftype = build_function_type (return_type, args);
736
737 gcc_assert (ftype != NULL);
738
739 if (print_type_signature_p)
740 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s%s_%s",
741 d->name, modenames[d->mode], type_signature);
742 else
743 snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s%s",
744 d->name, modenames[d->mode]);
745
746 fndecl = add_builtin_function (namebuf, ftype, fcode, BUILT_IN_MD,
747 NULL, NULL_TREE);
748 aarch64_builtin_decls[fcode] = fndecl;
749 }
750 }
751
752 void
aarch64_init_builtins(void)753 aarch64_init_builtins (void)
754 {
755 if (TARGET_SIMD)
756 aarch64_init_simd_builtins ();
757 }
758
759 tree
aarch64_builtin_decl(unsigned code,bool initialize_p ATTRIBUTE_UNUSED)760 aarch64_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
761 {
762 if (code >= AARCH64_BUILTIN_MAX)
763 return error_mark_node;
764
765 return aarch64_builtin_decls[code];
766 }
767
768 typedef enum
769 {
770 SIMD_ARG_COPY_TO_REG,
771 SIMD_ARG_CONSTANT,
772 SIMD_ARG_STOP
773 } builtin_simd_arg;
774
775 static rtx
aarch64_simd_expand_args(rtx target,int icode,int have_retval,tree exp,...)776 aarch64_simd_expand_args (rtx target, int icode, int have_retval,
777 tree exp, ...)
778 {
779 va_list ap;
780 rtx pat;
781 tree arg[SIMD_MAX_BUILTIN_ARGS];
782 rtx op[SIMD_MAX_BUILTIN_ARGS];
783 enum machine_mode tmode = insn_data[icode].operand[0].mode;
784 enum machine_mode mode[SIMD_MAX_BUILTIN_ARGS];
785 int argc = 0;
786
787 if (have_retval
788 && (!target
789 || GET_MODE (target) != tmode
790 || !(*insn_data[icode].operand[0].predicate) (target, tmode)))
791 target = gen_reg_rtx (tmode);
792
793 va_start (ap, exp);
794
795 for (;;)
796 {
797 builtin_simd_arg thisarg = (builtin_simd_arg) va_arg (ap, int);
798
799 if (thisarg == SIMD_ARG_STOP)
800 break;
801 else
802 {
803 arg[argc] = CALL_EXPR_ARG (exp, argc);
804 op[argc] = expand_normal (arg[argc]);
805 mode[argc] = insn_data[icode].operand[argc + have_retval].mode;
806
807 switch (thisarg)
808 {
809 case SIMD_ARG_COPY_TO_REG:
810 if (POINTER_TYPE_P (TREE_TYPE (arg[argc])))
811 op[argc] = convert_memory_address (Pmode, op[argc]);
812 /*gcc_assert (GET_MODE (op[argc]) == mode[argc]); */
813 if (!(*insn_data[icode].operand[argc + have_retval].predicate)
814 (op[argc], mode[argc]))
815 op[argc] = copy_to_mode_reg (mode[argc], op[argc]);
816 break;
817
818 case SIMD_ARG_CONSTANT:
819 if (!(*insn_data[icode].operand[argc + have_retval].predicate)
820 (op[argc], mode[argc]))
821 error_at (EXPR_LOCATION (exp), "incompatible type for argument %d, "
822 "expected %<const int%>", argc + 1);
823 break;
824
825 case SIMD_ARG_STOP:
826 gcc_unreachable ();
827 }
828
829 argc++;
830 }
831 }
832
833 va_end (ap);
834
835 if (have_retval)
836 switch (argc)
837 {
838 case 1:
839 pat = GEN_FCN (icode) (target, op[0]);
840 break;
841
842 case 2:
843 pat = GEN_FCN (icode) (target, op[0], op[1]);
844 break;
845
846 case 3:
847 pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
848 break;
849
850 case 4:
851 pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
852 break;
853
854 case 5:
855 pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
856 break;
857
858 default:
859 gcc_unreachable ();
860 }
861 else
862 switch (argc)
863 {
864 case 1:
865 pat = GEN_FCN (icode) (op[0]);
866 break;
867
868 case 2:
869 pat = GEN_FCN (icode) (op[0], op[1]);
870 break;
871
872 case 3:
873 pat = GEN_FCN (icode) (op[0], op[1], op[2]);
874 break;
875
876 case 4:
877 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
878 break;
879
880 case 5:
881 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
882 break;
883
884 default:
885 gcc_unreachable ();
886 }
887
888 if (!pat)
889 return 0;
890
891 emit_insn (pat);
892
893 return target;
894 }
895
896 /* Expand an AArch64 AdvSIMD builtin(intrinsic). */
897 rtx
aarch64_simd_expand_builtin(int fcode,tree exp,rtx target)898 aarch64_simd_expand_builtin (int fcode, tree exp, rtx target)
899 {
900 aarch64_simd_builtin_datum *d =
901 &aarch64_simd_builtin_data[fcode - (AARCH64_SIMD_BUILTIN_BASE + 1)];
902 enum insn_code icode = d->code;
903 builtin_simd_arg args[SIMD_MAX_BUILTIN_ARGS];
904 int num_args = insn_data[d->code].n_operands;
905 int is_void = 0;
906 int k;
907
908 is_void = !!(d->qualifiers[0] & qualifier_void);
909
910 num_args += is_void;
911
912 for (k = 1; k < num_args; k++)
913 {
914 /* We have four arrays of data, each indexed in a different fashion.
915 qualifiers - element 0 always describes the function return type.
916 operands - element 0 is either the operand for return value (if
917 the function has a non-void return type) or the operand for the
918 first argument.
919 expr_args - element 0 always holds the first argument.
920 args - element 0 is always used for the return type. */
921 int qualifiers_k = k;
922 int operands_k = k - is_void;
923 int expr_args_k = k - 1;
924
925 if (d->qualifiers[qualifiers_k] & qualifier_immediate)
926 args[k] = SIMD_ARG_CONSTANT;
927 else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate)
928 {
929 rtx arg
930 = expand_normal (CALL_EXPR_ARG (exp,
931 (expr_args_k)));
932 /* Handle constants only if the predicate allows it. */
933 bool op_const_int_p =
934 (CONST_INT_P (arg)
935 && (*insn_data[icode].operand[operands_k].predicate)
936 (arg, insn_data[icode].operand[operands_k].mode));
937 args[k] = op_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG;
938 }
939 else
940 args[k] = SIMD_ARG_COPY_TO_REG;
941
942 }
943 args[k] = SIMD_ARG_STOP;
944
945 /* The interface to aarch64_simd_expand_args expects a 0 if
946 the function is void, and a 1 if it is not. */
947 return aarch64_simd_expand_args
948 (target, icode, !is_void, exp,
949 args[1],
950 args[2],
951 args[3],
952 args[4],
953 SIMD_ARG_STOP);
954 }
955
956 /* Expand an expression EXP that calls a built-in function,
957 with result going to TARGET if that's convenient. */
958 rtx
aarch64_expand_builtin(tree exp,rtx target,rtx subtarget ATTRIBUTE_UNUSED,enum machine_mode mode ATTRIBUTE_UNUSED,int ignore ATTRIBUTE_UNUSED)959 aarch64_expand_builtin (tree exp,
960 rtx target,
961 rtx subtarget ATTRIBUTE_UNUSED,
962 enum machine_mode mode ATTRIBUTE_UNUSED,
963 int ignore ATTRIBUTE_UNUSED)
964 {
965 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
966 int fcode = DECL_FUNCTION_CODE (fndecl);
967
968 if (fcode >= AARCH64_SIMD_BUILTIN_BASE)
969 return aarch64_simd_expand_builtin (fcode, exp, target);
970
971 return NULL_RTX;
972 }
973
974 tree
aarch64_builtin_vectorized_function(tree fndecl,tree type_out,tree type_in)975 aarch64_builtin_vectorized_function (tree fndecl, tree type_out, tree type_in)
976 {
977 enum machine_mode in_mode, out_mode;
978 int in_n, out_n;
979
980 if (TREE_CODE (type_out) != VECTOR_TYPE
981 || TREE_CODE (type_in) != VECTOR_TYPE)
982 return NULL_TREE;
983
984 out_mode = TYPE_MODE (TREE_TYPE (type_out));
985 out_n = TYPE_VECTOR_SUBPARTS (type_out);
986 in_mode = TYPE_MODE (TREE_TYPE (type_in));
987 in_n = TYPE_VECTOR_SUBPARTS (type_in);
988
989 #undef AARCH64_CHECK_BUILTIN_MODE
990 #define AARCH64_CHECK_BUILTIN_MODE(C, N) 1
991 #define AARCH64_FIND_FRINT_VARIANT(N) \
992 (AARCH64_CHECK_BUILTIN_MODE (2, D) \
993 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2df] \
994 : (AARCH64_CHECK_BUILTIN_MODE (4, S) \
995 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v4sf] \
996 : (AARCH64_CHECK_BUILTIN_MODE (2, S) \
997 ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2sf] \
998 : NULL_TREE)))
999 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
1000 {
1001 enum built_in_function fn = DECL_FUNCTION_CODE (fndecl);
1002 switch (fn)
1003 {
1004 #undef AARCH64_CHECK_BUILTIN_MODE
1005 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1006 (out_mode == N##Fmode && out_n == C \
1007 && in_mode == N##Fmode && in_n == C)
1008 case BUILT_IN_FLOOR:
1009 case BUILT_IN_FLOORF:
1010 return AARCH64_FIND_FRINT_VARIANT (floor);
1011 case BUILT_IN_CEIL:
1012 case BUILT_IN_CEILF:
1013 return AARCH64_FIND_FRINT_VARIANT (ceil);
1014 case BUILT_IN_TRUNC:
1015 case BUILT_IN_TRUNCF:
1016 return AARCH64_FIND_FRINT_VARIANT (btrunc);
1017 case BUILT_IN_ROUND:
1018 case BUILT_IN_ROUNDF:
1019 return AARCH64_FIND_FRINT_VARIANT (round);
1020 case BUILT_IN_NEARBYINT:
1021 case BUILT_IN_NEARBYINTF:
1022 return AARCH64_FIND_FRINT_VARIANT (nearbyint);
1023 case BUILT_IN_SQRT:
1024 case BUILT_IN_SQRTF:
1025 return AARCH64_FIND_FRINT_VARIANT (sqrt);
1026 #undef AARCH64_CHECK_BUILTIN_MODE
1027 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1028 (out_mode == SImode && out_n == C \
1029 && in_mode == N##Imode && in_n == C)
1030 case BUILT_IN_CLZ:
1031 {
1032 if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1033 return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_clzv4si];
1034 return NULL_TREE;
1035 }
1036 #undef AARCH64_CHECK_BUILTIN_MODE
1037 #define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1038 (out_mode == N##Imode && out_n == C \
1039 && in_mode == N##Fmode && in_n == C)
1040 case BUILT_IN_LFLOOR:
1041 case BUILT_IN_LFLOORF:
1042 case BUILT_IN_LLFLOOR:
1043 case BUILT_IN_IFLOORF:
1044 {
1045 enum aarch64_builtins builtin;
1046 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1047 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2dfv2di;
1048 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1049 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv4sfv4si;
1050 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1051 builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2sfv2si;
1052 else
1053 return NULL_TREE;
1054
1055 return aarch64_builtin_decls[builtin];
1056 }
1057 case BUILT_IN_LCEIL:
1058 case BUILT_IN_LCEILF:
1059 case BUILT_IN_LLCEIL:
1060 case BUILT_IN_ICEILF:
1061 {
1062 enum aarch64_builtins builtin;
1063 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1064 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2dfv2di;
1065 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1066 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv4sfv4si;
1067 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1068 builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2sfv2si;
1069 else
1070 return NULL_TREE;
1071
1072 return aarch64_builtin_decls[builtin];
1073 }
1074 case BUILT_IN_LROUND:
1075 case BUILT_IN_IROUNDF:
1076 {
1077 enum aarch64_builtins builtin;
1078 if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1079 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2dfv2di;
1080 else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1081 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv4sfv4si;
1082 else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1083 builtin = AARCH64_SIMD_BUILTIN_UNOP_lroundv2sfv2si;
1084 else
1085 return NULL_TREE;
1086
1087 return aarch64_builtin_decls[builtin];
1088 }
1089
1090 default:
1091 return NULL_TREE;
1092 }
1093 }
1094
1095 return NULL_TREE;
1096 }
1097
1098 #undef VAR1
1099 #define VAR1(T, N, MAP, A) \
1100 case AARCH64_SIMD_BUILTIN_##T##_##N##A:
1101
1102 tree
aarch64_fold_builtin(tree fndecl,int n_args ATTRIBUTE_UNUSED,tree * args,bool ignore ATTRIBUTE_UNUSED)1103 aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args,
1104 bool ignore ATTRIBUTE_UNUSED)
1105 {
1106 int fcode = DECL_FUNCTION_CODE (fndecl);
1107 tree type = TREE_TYPE (TREE_TYPE (fndecl));
1108
1109 switch (fcode)
1110 {
1111 BUILTIN_VALLDI (UNOP, abs, 2)
1112 return fold_build1 (ABS_EXPR, type, args[0]);
1113 break;
1114 BUILTIN_VALLDI (BINOP, cmge, 0)
1115 return fold_build2 (GE_EXPR, type, args[0], args[1]);
1116 break;
1117 BUILTIN_VALLDI (BINOP, cmgt, 0)
1118 return fold_build2 (GT_EXPR, type, args[0], args[1]);
1119 break;
1120 BUILTIN_VALLDI (BINOP, cmeq, 0)
1121 return fold_build2 (EQ_EXPR, type, args[0], args[1]);
1122 break;
1123 BUILTIN_VSDQ_I_DI (BINOP, cmtst, 0)
1124 {
1125 tree and_node = fold_build2 (BIT_AND_EXPR, type, args[0], args[1]);
1126 tree vec_zero_node = build_zero_cst (type);
1127 return fold_build2 (NE_EXPR, type, and_node, vec_zero_node);
1128 break;
1129 }
1130 VAR1 (UNOP, floatv2si, 2, v2sf)
1131 VAR1 (UNOP, floatv4si, 2, v4sf)
1132 VAR1 (UNOP, floatv2di, 2, v2df)
1133 return fold_build1 (FLOAT_EXPR, type, args[0]);
1134 default:
1135 break;
1136 }
1137
1138 return NULL_TREE;
1139 }
1140
1141 bool
aarch64_gimple_fold_builtin(gimple_stmt_iterator * gsi)1142 aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi)
1143 {
1144 bool changed = false;
1145 gimple stmt = gsi_stmt (*gsi);
1146 tree call = gimple_call_fn (stmt);
1147 tree fndecl;
1148 gimple new_stmt = NULL;
1149 if (call)
1150 {
1151 fndecl = gimple_call_fndecl (stmt);
1152 if (fndecl)
1153 {
1154 int fcode = DECL_FUNCTION_CODE (fndecl);
1155 int nargs = gimple_call_num_args (stmt);
1156 tree *args = (nargs > 0
1157 ? gimple_call_arg_ptr (stmt, 0)
1158 : &error_mark_node);
1159
1160 switch (fcode)
1161 {
1162 BUILTIN_VALL (UNOP, reduc_splus_, 10)
1163 new_stmt = gimple_build_assign_with_ops (
1164 REDUC_PLUS_EXPR,
1165 gimple_call_lhs (stmt),
1166 args[0],
1167 NULL_TREE);
1168 break;
1169 BUILTIN_VDQIF (UNOP, reduc_smax_, 10)
1170 new_stmt = gimple_build_assign_with_ops (
1171 REDUC_MAX_EXPR,
1172 gimple_call_lhs (stmt),
1173 args[0],
1174 NULL_TREE);
1175 break;
1176 BUILTIN_VDQIF (UNOP, reduc_smin_, 10)
1177 new_stmt = gimple_build_assign_with_ops (
1178 REDUC_MIN_EXPR,
1179 gimple_call_lhs (stmt),
1180 args[0],
1181 NULL_TREE);
1182 break;
1183
1184 default:
1185 break;
1186 }
1187 }
1188 }
1189
1190 if (new_stmt)
1191 {
1192 gsi_replace (gsi, new_stmt, true);
1193 changed = true;
1194 }
1195
1196 return changed;
1197 }
1198
1199 #undef AARCH64_CHECK_BUILTIN_MODE
1200 #undef AARCH64_FIND_FRINT_VARIANT
1201 #undef BUILTIN_DX
1202 #undef BUILTIN_SDQ_I
1203 #undef BUILTIN_SD_HSI
1204 #undef BUILTIN_V2F
1205 #undef BUILTIN_VALL
1206 #undef BUILTIN_VB
1207 #undef BUILTIN_VD
1208 #undef BUILTIN_VDC
1209 #undef BUILTIN_VDIC
1210 #undef BUILTIN_VDN
1211 #undef BUILTIN_VDQ
1212 #undef BUILTIN_VDQF
1213 #undef BUILTIN_VDQH
1214 #undef BUILTIN_VDQHS
1215 #undef BUILTIN_VDQIF
1216 #undef BUILTIN_VDQM
1217 #undef BUILTIN_VDQV
1218 #undef BUILTIN_VDQ_BHSI
1219 #undef BUILTIN_VDQ_I
1220 #undef BUILTIN_VDW
1221 #undef BUILTIN_VD_BHSI
1222 #undef BUILTIN_VD_HSI
1223 #undef BUILTIN_VD_RE
1224 #undef BUILTIN_VQ
1225 #undef BUILTIN_VQN
1226 #undef BUILTIN_VQW
1227 #undef BUILTIN_VQ_HSI
1228 #undef BUILTIN_VQ_S
1229 #undef BUILTIN_VSDQ_HSI
1230 #undef BUILTIN_VSDQ_I
1231 #undef BUILTIN_VSDQ_I_BHSI
1232 #undef BUILTIN_VSDQ_I_DI
1233 #undef BUILTIN_VSD_HSI
1234 #undef BUILTIN_VSQN_HSDI
1235 #undef BUILTIN_VSTRUCT
1236 #undef CF0
1237 #undef CF1
1238 #undef CF2
1239 #undef CF3
1240 #undef CF4
1241 #undef CF10
1242 #undef VAR1
1243 #undef VAR2
1244 #undef VAR3
1245 #undef VAR4
1246 #undef VAR5
1247 #undef VAR6
1248 #undef VAR7
1249 #undef VAR8
1250 #undef VAR9
1251 #undef VAR10
1252 #undef VAR11
1253
1254