1235783Skib/* Builtins' description for AArch64 SIMD architecture.
2235783Skib   Copyright (C) 2011-2015 Free Software Foundation, Inc.
3235783Skib   Contributed by ARM Ltd.
4235783Skib
5235783Skib   This file is part of GCC.
6235783Skib
7235783Skib   GCC is free software; you can redistribute it and/or modify it
8235783Skib   under the terms of the GNU General Public License as published by
9235783Skib   the Free Software Foundation; either version 3, or (at your option)
10235783Skib   any later version.
11235783Skib
12235783Skib   GCC is distributed in the hope that it will be useful, but
13235783Skib   WITHOUT ANY WARRANTY; without even the implied warranty of
14235783Skib   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15235783Skib   General Public License for more details.
16235783Skib
17235783Skib   You should have received a copy of the GNU General Public License
18235783Skib   along with GCC; see the file COPYING3.  If not see
19235783Skib   <http://www.gnu.org/licenses/>.  */
20235783Skib
21235783Skib#include "config.h"
22235783Skib#include "system.h"
23235783Skib#include "coretypes.h"
24235783Skib#include "tm.h"
25235783Skib#include "rtl.h"
26235783Skib#include "hash-set.h"
27235783Skib#include "machmode.h"
28235783Skib#include "vec.h"
29235783Skib#include "double-int.h"
30235783Skib#include "input.h"
31235783Skib#include "alias.h"
32235783Skib#include "symtab.h"
33235783Skib#include "wide-int.h"
34235783Skib#include "inchash.h"
35235783Skib#include "tree.h"
36235783Skib#include "fold-const.h"
37235783Skib#include "stor-layout.h"
38235783Skib#include "stringpool.h"
39235783Skib#include "calls.h"
40235783Skib#include "hashtab.h"
41235783Skib#include "hard-reg-set.h"
42235783Skib#include "function.h"
43235783Skib#include "flags.h"
44235783Skib#include "statistics.h"
45235783Skib#include "real.h"
46235783Skib#include "fixed-value.h"
47235783Skib#include "insn-config.h"
48235783Skib#include "expmed.h"
49235783Skib#include "dojump.h"
50235783Skib#include "explow.h"
51235783Skib#include "emit-rtl.h"
52235783Skib#include "varasm.h"
53235783Skib#include "stmt.h"
54235783Skib#include "expr.h"
55235783Skib#include "tm_p.h"
56235783Skib#include "recog.h"
57235783Skib#include "langhooks.h"
58235783Skib#include "diagnostic-core.h"
59235783Skib#include "insn-codes.h"
60235783Skib#include "optabs.h"
61235783Skib#include "hash-table.h"
62235783Skib#include "ggc.h"
63235783Skib#include "predict.h"
64235783Skib#include "dominance.h"
65235783Skib#include "cfg.h"
66235783Skib#include "cfgrtl.h"
67235783Skib#include "cfganal.h"
68235783Skib#include "lcm.h"
69235783Skib#include "cfgbuild.h"
70235783Skib#include "cfgcleanup.h"
71235783Skib#include "basic-block.h"
72235783Skib#include "tree-ssa-alias.h"
73235783Skib#include "internal-fn.h"
74235783Skib#include "gimple-fold.h"
75235783Skib#include "tree-eh.h"
76235783Skib#include "gimple-expr.h"
77235783Skib#include "is-a.h"
78235783Skib#include "gimple.h"
79235783Skib#include "gimple-iterator.h"
80235783Skib
81235783Skib#define v8qi_UP  V8QImode
82235783Skib#define v4hi_UP  V4HImode
83235783Skib#define v2si_UP  V2SImode
84235783Skib#define v2sf_UP  V2SFmode
85235783Skib#define v1df_UP  V1DFmode
86235783Skib#define di_UP    DImode
87235783Skib#define df_UP    DFmode
88235783Skib#define v16qi_UP V16QImode
89235783Skib#define v8hi_UP  V8HImode
90235783Skib#define v4si_UP  V4SImode
91235783Skib#define v4sf_UP  V4SFmode
92235783Skib#define v2di_UP  V2DImode
93235783Skib#define v2df_UP  V2DFmode
94235783Skib#define ti_UP	 TImode
95235783Skib#define ei_UP	 EImode
96235783Skib#define oi_UP	 OImode
97235783Skib#define ci_UP	 CImode
98235783Skib#define xi_UP	 XImode
99235783Skib#define si_UP    SImode
100235783Skib#define sf_UP    SFmode
101235783Skib#define hi_UP    HImode
102235783Skib#define qi_UP    QImode
103235783Skib#define UP(X) X##_UP
104235783Skib
105235783Skib#define SIMD_MAX_BUILTIN_ARGS 5
106235783Skib
107235783Skibenum aarch64_type_qualifiers
108235783Skib{
109235783Skib  /* T foo.  */
110235783Skib  qualifier_none = 0x0,
111235783Skib  /* unsigned T foo.  */
112235783Skib  qualifier_unsigned = 0x1, /* 1 << 0  */
113235783Skib  /* const T foo.  */
114235783Skib  qualifier_const = 0x2, /* 1 << 1  */
115235783Skib  /* T *foo.  */
116235783Skib  qualifier_pointer = 0x4, /* 1 << 2  */
117235783Skib  /* Used when expanding arguments if an operand could
118235783Skib     be an immediate.  */
119235783Skib  qualifier_immediate = 0x8, /* 1 << 3  */
120235783Skib  qualifier_maybe_immediate = 0x10, /* 1 << 4  */
121235783Skib  /* void foo (...).  */
122235783Skib  qualifier_void = 0x20, /* 1 << 5  */
123235783Skib  /* Some patterns may have internal operands, this qualifier is an
124235783Skib     instruction to the initialisation code to skip this operand.  */
125235783Skib  qualifier_internal = 0x40, /* 1 << 6  */
126235783Skib  /* Some builtins should use the T_*mode* encoded in a simd_builtin_datum
127235783Skib     rather than using the type of the operand.  */
128235783Skib  qualifier_map_mode = 0x80, /* 1 << 7  */
129235783Skib  /* qualifier_pointer | qualifier_map_mode  */
130235783Skib  qualifier_pointer_map_mode = 0x84,
131235783Skib  /* qualifier_const | qualifier_pointer | qualifier_map_mode  */
132235783Skib  qualifier_const_pointer_map_mode = 0x86,
133235783Skib  /* Polynomial types.  */
134235783Skib  qualifier_poly = 0x100,
135235783Skib  /* Lane indices - must be in range, and flipped for bigendian.  */
136235783Skib  qualifier_lane_index = 0x200
137235783Skib};
138235783Skib
139235783Skibtypedef struct
140235783Skib{
141235783Skib  const char *name;
142235783Skib  machine_mode mode;
143235783Skib  const enum insn_code code;
144235783Skib  unsigned int fcode;
145235783Skib  enum aarch64_type_qualifiers *qualifiers;
146235783Skib} aarch64_simd_builtin_datum;
147235783Skib
148235783Skibstatic enum aarch64_type_qualifiers
149235783Skibaarch64_types_unop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
150235783Skib  = { qualifier_none, qualifier_none };
151235783Skib#define TYPES_UNOP (aarch64_types_unop_qualifiers)
152235783Skibstatic enum aarch64_type_qualifiers
153235783Skibaarch64_types_unopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
154235783Skib  = { qualifier_unsigned, qualifier_unsigned };
155235783Skib#define TYPES_UNOPU (aarch64_types_unopu_qualifiers)
156235783Skibstatic enum aarch64_type_qualifiers
157235783Skibaarch64_types_binop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
158235783Skib  = { qualifier_none, qualifier_none, qualifier_maybe_immediate };
159235783Skib#define TYPES_BINOP (aarch64_types_binop_qualifiers)
160235783Skibstatic enum aarch64_type_qualifiers
161235783Skibaarch64_types_binopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
162235783Skib  = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned };
163235783Skib#define TYPES_BINOPU (aarch64_types_binopu_qualifiers)
164235783Skibstatic enum aarch64_type_qualifiers
165235783Skibaarch64_types_binop_uus_qualifiers[SIMD_MAX_BUILTIN_ARGS]
166235783Skib  = { qualifier_unsigned, qualifier_unsigned, qualifier_none };
167235783Skib#define TYPES_BINOP_UUS (aarch64_types_binop_uus_qualifiers)
168235783Skibstatic enum aarch64_type_qualifiers
169235783Skibaarch64_types_binop_ssu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
170235783Skib  = { qualifier_none, qualifier_none, qualifier_unsigned };
171235783Skib#define TYPES_BINOP_SSU (aarch64_types_binop_ssu_qualifiers)
172235783Skibstatic enum aarch64_type_qualifiers
173235783Skibaarch64_types_binopp_qualifiers[SIMD_MAX_BUILTIN_ARGS]
174235783Skib  = { qualifier_poly, qualifier_poly, qualifier_poly };
175235783Skib#define TYPES_BINOPP (aarch64_types_binopp_qualifiers)
176235783Skib
177235783Skibstatic enum aarch64_type_qualifiers
178235783Skibaarch64_types_ternop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
179235783Skib  = { qualifier_none, qualifier_none, qualifier_none, qualifier_none };
180235783Skib#define TYPES_TERNOP (aarch64_types_ternop_qualifiers)
181235783Skibstatic enum aarch64_type_qualifiers
182235783Skibaarch64_types_ternop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
183235783Skib  = { qualifier_none, qualifier_none, qualifier_none, qualifier_lane_index };
184235783Skib#define TYPES_TERNOP_LANE (aarch64_types_ternop_lane_qualifiers)
185235783Skibstatic enum aarch64_type_qualifiers
186235783Skibaarch64_types_ternopu_qualifiers[SIMD_MAX_BUILTIN_ARGS]
187235783Skib  = { qualifier_unsigned, qualifier_unsigned,
188235783Skib      qualifier_unsigned, qualifier_unsigned };
189235783Skib#define TYPES_TERNOPU (aarch64_types_ternopu_qualifiers)
190235783Skib
191235783Skibstatic enum aarch64_type_qualifiers
192235783Skibaarch64_types_quadop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
193235783Skib  = { qualifier_none, qualifier_none, qualifier_none,
194235783Skib      qualifier_none, qualifier_lane_index };
195235783Skib#define TYPES_QUADOP_LANE (aarch64_types_quadop_lane_qualifiers)
196235783Skib
197235783Skibstatic enum aarch64_type_qualifiers
198235783Skibaarch64_types_binop_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
199235783Skib  = { qualifier_none, qualifier_none, qualifier_immediate };
200235783Skib#define TYPES_GETREG (aarch64_types_binop_imm_qualifiers)
201235783Skib#define TYPES_SHIFTIMM (aarch64_types_binop_imm_qualifiers)
202235783Skibstatic enum aarch64_type_qualifiers
203235783Skibaarch64_types_shift_to_unsigned_qualifiers[SIMD_MAX_BUILTIN_ARGS]
204235783Skib  = { qualifier_unsigned, qualifier_none, qualifier_immediate };
205235783Skib#define TYPES_SHIFTIMM_USS (aarch64_types_shift_to_unsigned_qualifiers)
206235783Skibstatic enum aarch64_type_qualifiers
207235783Skibaarch64_types_unsigned_shift_qualifiers[SIMD_MAX_BUILTIN_ARGS]
208235783Skib  = { qualifier_unsigned, qualifier_unsigned, qualifier_immediate };
209235783Skib#define TYPES_USHIFTIMM (aarch64_types_unsigned_shift_qualifiers)
210235783Skib
211235783Skibstatic enum aarch64_type_qualifiers
212235783Skibaarch64_types_ternop_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
213235783Skib  = { qualifier_none, qualifier_none, qualifier_none, qualifier_immediate };
214235783Skib#define TYPES_SETREG (aarch64_types_ternop_imm_qualifiers)
215235783Skib#define TYPES_SHIFTINSERT (aarch64_types_ternop_imm_qualifiers)
216235783Skib#define TYPES_SHIFTACC (aarch64_types_ternop_imm_qualifiers)
217235783Skib
218235783Skibstatic enum aarch64_type_qualifiers
219235783Skibaarch64_types_unsigned_shiftacc_qualifiers[SIMD_MAX_BUILTIN_ARGS]
220235783Skib  = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
221235783Skib      qualifier_immediate };
222235783Skib#define TYPES_USHIFTACC (aarch64_types_unsigned_shiftacc_qualifiers)
223235783Skib
224235783Skib
225235783Skibstatic enum aarch64_type_qualifiers
226235783Skibaarch64_types_combine_qualifiers[SIMD_MAX_BUILTIN_ARGS]
227235783Skib  = { qualifier_none, qualifier_none, qualifier_none };
228235783Skib#define TYPES_COMBINE (aarch64_types_combine_qualifiers)
229235783Skib
230235783Skibstatic enum aarch64_type_qualifiers
231235783Skibaarch64_types_load1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
232235783Skib  = { qualifier_none, qualifier_const_pointer_map_mode };
233235783Skib#define TYPES_LOAD1 (aarch64_types_load1_qualifiers)
234235783Skib#define TYPES_LOADSTRUCT (aarch64_types_load1_qualifiers)
235235783Skibstatic enum aarch64_type_qualifiers
236235783Skibaarch64_types_loadstruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
237235783Skib  = { qualifier_none, qualifier_const_pointer_map_mode,
238235783Skib      qualifier_none, qualifier_none };
239235783Skib#define TYPES_LOADSTRUCT_LANE (aarch64_types_loadstruct_lane_qualifiers)
240235783Skib
241235783Skibstatic enum aarch64_type_qualifiers
242235783Skibaarch64_types_bsl_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
243235783Skib  = { qualifier_poly, qualifier_unsigned,
244235783Skib      qualifier_poly, qualifier_poly };
245235783Skib#define TYPES_BSL_P (aarch64_types_bsl_p_qualifiers)
246235783Skibstatic enum aarch64_type_qualifiers
247235783Skibaarch64_types_bsl_s_qualifiers[SIMD_MAX_BUILTIN_ARGS]
248235783Skib  = { qualifier_none, qualifier_unsigned,
249235783Skib      qualifier_none, qualifier_none };
250235783Skib#define TYPES_BSL_S (aarch64_types_bsl_s_qualifiers)
251235783Skibstatic enum aarch64_type_qualifiers
252235783Skibaarch64_types_bsl_u_qualifiers[SIMD_MAX_BUILTIN_ARGS]
253235783Skib  = { qualifier_unsigned, qualifier_unsigned,
254235783Skib      qualifier_unsigned, qualifier_unsigned };
255235783Skib#define TYPES_BSL_U (aarch64_types_bsl_u_qualifiers)
256235783Skib
257235783Skib/* The first argument (return type) of a store should be void type,
258235783Skib   which we represent with qualifier_void.  Their first operand will be
259235783Skib   a DImode pointer to the location to store to, so we must use
260235783Skib   qualifier_map_mode | qualifier_pointer to build a pointer to the
261235783Skib   element type of the vector.  */
262235783Skibstatic enum aarch64_type_qualifiers
263235783Skibaarch64_types_store1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
264235783Skib  = { qualifier_void, qualifier_pointer_map_mode, qualifier_none };
265235783Skib#define TYPES_STORE1 (aarch64_types_store1_qualifiers)
266235783Skib#define TYPES_STORESTRUCT (aarch64_types_store1_qualifiers)
267235783Skibstatic enum aarch64_type_qualifiers
268235783Skibaarch64_types_storestruct_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
269235783Skib  = { qualifier_void, qualifier_pointer_map_mode,
270235783Skib      qualifier_none, qualifier_none };
271235783Skib#define TYPES_STORESTRUCT_LANE (aarch64_types_storestruct_lane_qualifiers)
272235783Skib
273235783Skib#define CF0(N, X) CODE_FOR_aarch64_##N##X
274235783Skib#define CF1(N, X) CODE_FOR_##N##X##1
275235783Skib#define CF2(N, X) CODE_FOR_##N##X##2
276235783Skib#define CF3(N, X) CODE_FOR_##N##X##3
277235783Skib#define CF4(N, X) CODE_FOR_##N##X##4
278235783Skib#define CF10(N, X) CODE_FOR_##N##X
279235783Skib
280235783Skib#define VAR1(T, N, MAP, A) \
281235783Skib  {#N #A, UP (A), CF##MAP (N, A), 0, TYPES_##T},
282235783Skib#define VAR2(T, N, MAP, A, B) \
283235783Skib  VAR1 (T, N, MAP, A) \
284235783Skib  VAR1 (T, N, MAP, B)
285235783Skib#define VAR3(T, N, MAP, A, B, C) \
286235783Skib  VAR2 (T, N, MAP, A, B) \
287235783Skib  VAR1 (T, N, MAP, C)
288235783Skib#define VAR4(T, N, MAP, A, B, C, D) \
289235783Skib  VAR3 (T, N, MAP, A, B, C) \
290235783Skib  VAR1 (T, N, MAP, D)
291235783Skib#define VAR5(T, N, MAP, A, B, C, D, E) \
292235783Skib  VAR4 (T, N, MAP, A, B, C, D) \
293235783Skib  VAR1 (T, N, MAP, E)
294235783Skib#define VAR6(T, N, MAP, A, B, C, D, E, F) \
295235783Skib  VAR5 (T, N, MAP, A, B, C, D, E) \
296235783Skib  VAR1 (T, N, MAP, F)
297235783Skib#define VAR7(T, N, MAP, A, B, C, D, E, F, G) \
298235783Skib  VAR6 (T, N, MAP, A, B, C, D, E, F) \
299235783Skib  VAR1 (T, N, MAP, G)
300235783Skib#define VAR8(T, N, MAP, A, B, C, D, E, F, G, H) \
301235783Skib  VAR7 (T, N, MAP, A, B, C, D, E, F, G) \
302235783Skib  VAR1 (T, N, MAP, H)
303235783Skib#define VAR9(T, N, MAP, A, B, C, D, E, F, G, H, I) \
304235783Skib  VAR8 (T, N, MAP, A, B, C, D, E, F, G, H) \
305235783Skib  VAR1 (T, N, MAP, I)
306235783Skib#define VAR10(T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
307235783Skib  VAR9 (T, N, MAP, A, B, C, D, E, F, G, H, I) \
308235783Skib  VAR1 (T, N, MAP, J)
309235783Skib#define VAR11(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
310235783Skib  VAR10 (T, N, MAP, A, B, C, D, E, F, G, H, I, J) \
311235783Skib  VAR1 (T, N, MAP, K)
312235783Skib#define VAR12(T, N, MAP, A, B, C, D, E, F, G, H, I, J, K, L) \
313235783Skib  VAR11 (T, N, MAP, A, B, C, D, E, F, G, H, I, J, K) \
314235783Skib  VAR1 (T, N, MAP, L)
315235783Skib
316235783Skib#include "aarch64-builtin-iterators.h"
317235783Skib
318235783Skibstatic aarch64_simd_builtin_datum aarch64_simd_builtin_data[] = {
319235783Skib#include "aarch64-simd-builtins.def"
320235783Skib};
321235783Skib
322235783Skib/* There's only 8 CRC32 builtins.  Probably not worth their own .def file.  */
323235783Skib#define AARCH64_CRC32_BUILTINS \
324235783Skib  CRC32_BUILTIN (crc32b, QI) \
325235783Skib  CRC32_BUILTIN (crc32h, HI) \
326235783Skib  CRC32_BUILTIN (crc32w, SI) \
327235783Skib  CRC32_BUILTIN (crc32x, DI) \
328235783Skib  CRC32_BUILTIN (crc32cb, QI) \
329235783Skib  CRC32_BUILTIN (crc32ch, HI) \
330235783Skib  CRC32_BUILTIN (crc32cw, SI) \
331235783Skib  CRC32_BUILTIN (crc32cx, DI)
332235783Skib
333235783Skibtypedef struct
334235783Skib{
335235783Skib  const char *name;
336235783Skib  machine_mode mode;
337235783Skib  const enum insn_code icode;
338235783Skib  unsigned int fcode;
339235783Skib} aarch64_crc_builtin_datum;
340235783Skib
341235783Skib#define CRC32_BUILTIN(N, M) \
342235783Skib  AARCH64_BUILTIN_##N,
343235783Skib
344235783Skib#undef VAR1
345235783Skib#define VAR1(T, N, MAP, A) \
346235783Skib  AARCH64_SIMD_BUILTIN_##T##_##N##A,
347235783Skib
348235783Skibenum aarch64_builtins
349235783Skib{
350235783Skib  AARCH64_BUILTIN_MIN,
351235783Skib
352235783Skib  AARCH64_BUILTIN_GET_FPCR,
353235783Skib  AARCH64_BUILTIN_SET_FPCR,
354235783Skib  AARCH64_BUILTIN_GET_FPSR,
355235783Skib  AARCH64_BUILTIN_SET_FPSR,
356235783Skib
357235783Skib  AARCH64_SIMD_BUILTIN_BASE,
358235783Skib  AARCH64_SIMD_BUILTIN_LANE_CHECK,
359235783Skib#include "aarch64-simd-builtins.def"
360235783Skib  /* The first enum element which is based on an insn_data pattern.  */
361235783Skib  AARCH64_SIMD_PATTERN_START = AARCH64_SIMD_BUILTIN_LANE_CHECK + 1,
362235783Skib  AARCH64_SIMD_BUILTIN_MAX = AARCH64_SIMD_PATTERN_START
363235783Skib			      + ARRAY_SIZE (aarch64_simd_builtin_data) - 1,
364235783Skib  AARCH64_CRC32_BUILTIN_BASE,
365235783Skib  AARCH64_CRC32_BUILTINS
366235783Skib  AARCH64_CRC32_BUILTIN_MAX,
367235783Skib  AARCH64_BUILTIN_MAX
368235783Skib};
369235783Skib
370235783Skib#undef CRC32_BUILTIN
371235783Skib#define CRC32_BUILTIN(N, M) \
372235783Skib  {"__builtin_aarch64_"#N, M##mode, CODE_FOR_aarch64_##N, AARCH64_BUILTIN_##N},
373235783Skib
374235783Skibstatic aarch64_crc_builtin_datum aarch64_crc_builtin_data[] = {
375235783Skib  AARCH64_CRC32_BUILTINS
376235783Skib};
377235783Skib
378235783Skib#undef CRC32_BUILTIN
379235783Skib
380235783Skibstatic GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX];
381235783Skib
382235783Skib#define NUM_DREG_TYPES 6
383235783Skib#define NUM_QREG_TYPES 6
384235783Skib
385235783Skib/* Internal scalar builtin types.  These types are used to support
386235783Skib   neon intrinsic builtins.  They are _not_ user-visible types.  Therefore
387235783Skib   the mangling for these types are implementation defined.  */
388235783Skibconst char *aarch64_scalar_builtin_types[] = {
389235783Skib  "__builtin_aarch64_simd_qi",
390235783Skib  "__builtin_aarch64_simd_hi",
391235783Skib  "__builtin_aarch64_simd_si",
392235783Skib  "__builtin_aarch64_simd_sf",
393235783Skib  "__builtin_aarch64_simd_di",
394235783Skib  "__builtin_aarch64_simd_df",
395235783Skib  "__builtin_aarch64_simd_poly8",
396235783Skib  "__builtin_aarch64_simd_poly16",
397235783Skib  "__builtin_aarch64_simd_poly64",
398235783Skib  "__builtin_aarch64_simd_poly128",
399235783Skib  "__builtin_aarch64_simd_ti",
400235783Skib  "__builtin_aarch64_simd_uqi",
401235783Skib  "__builtin_aarch64_simd_uhi",
402235783Skib  "__builtin_aarch64_simd_usi",
403235783Skib  "__builtin_aarch64_simd_udi",
404235783Skib  "__builtin_aarch64_simd_ei",
405235783Skib  "__builtin_aarch64_simd_oi",
406235783Skib  "__builtin_aarch64_simd_ci",
407235783Skib  "__builtin_aarch64_simd_xi",
408235783Skib  NULL
409235783Skib};
410235783Skib
411235783Skib#define ENTRY(E, M, Q, G) E,
412235783Skibenum aarch64_simd_type
413235783Skib{
414235783Skib#include "aarch64-simd-builtin-types.def"
415235783Skib  ARM_NEON_H_TYPES_LAST
416235783Skib};
417235783Skib#undef ENTRY
418235783Skib
419235783Skibstruct aarch64_simd_type_info
420235783Skib{
421235783Skib  enum aarch64_simd_type type;
422235783Skib
423235783Skib  /* Internal type name.  */
424235783Skib  const char *name;
425235783Skib
426235783Skib  /* Internal type name(mangled).  The mangled names conform to the
427235783Skib     AAPCS64 (see "Procedure Call Standard for the ARM 64-bit Architecture",
428235783Skib     Appendix A).  To qualify for emission with the mangled names defined in
429235783Skib     that document, a vector type must not only be of the correct mode but also
430235783Skib     be of the correct internal AdvSIMD vector type (e.g. __Int8x8_t); these
431235783Skib     types are registered by aarch64_init_simd_builtin_types ().  In other
432235783Skib     words, vector types defined in other ways e.g. via vector_size attribute
433235783Skib     will get default mangled names.  */
434235783Skib  const char *mangle;
435235783Skib
436235783Skib  /* Internal type.  */
437235783Skib  tree itype;
438235783Skib
439235783Skib  /* Element type.  */
440235783Skib  tree eltype;
441235783Skib
442235783Skib  /* Machine mode the internal type maps to.  */
443235783Skib  enum machine_mode mode;
444235783Skib
445235783Skib  /* Qualifiers.  */
446235783Skib  enum aarch64_type_qualifiers q;
447235783Skib};
448235783Skib
449235783Skib#define ENTRY(E, M, Q, G)  \
450235783Skib  {E, "__" #E, #G "__" #E, NULL_TREE, NULL_TREE, M##mode, qualifier_##Q},
451235783Skibstatic struct aarch64_simd_type_info aarch64_simd_types [] = {
452235783Skib#include "aarch64-simd-builtin-types.def"
453235783Skib};
454235783Skib#undef ENTRY
455235783Skib
456235783Skibstatic tree aarch64_simd_intOI_type_node = NULL_TREE;
457235783Skibstatic tree aarch64_simd_intEI_type_node = NULL_TREE;
458235783Skibstatic tree aarch64_simd_intCI_type_node = NULL_TREE;
459235783Skibstatic tree aarch64_simd_intXI_type_node = NULL_TREE;
460235783Skib
461235783Skibstatic const char *
462235783Skibaarch64_mangle_builtin_scalar_type (const_tree type)
463235783Skib{
464235783Skib  int i = 0;
465235783Skib
466235783Skib  while (aarch64_scalar_builtin_types[i] != NULL)
467235783Skib    {
468235783Skib      const char *name = aarch64_scalar_builtin_types[i];
469235783Skib
470235783Skib      if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
471235783Skib	  && DECL_NAME (TYPE_NAME (type))
472235783Skib	  && !strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), name))
473235783Skib	return aarch64_scalar_builtin_types[i];
474235783Skib      i++;
475235783Skib    }
476235783Skib  return NULL;
477235783Skib}
478235783Skib
479235783Skibstatic const char *
480235783Skibaarch64_mangle_builtin_vector_type (const_tree type)
481235783Skib{
482235783Skib  int i;
483235783Skib  int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
484235783Skib
485235783Skib  for (i = 0; i < nelts; i++)
486235783Skib    if (aarch64_simd_types[i].mode ==  TYPE_MODE (type)
487235783Skib	&& TYPE_NAME (type)
488235783Skib	&& TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
489235783Skib	&& DECL_NAME (TYPE_NAME (type))
490235783Skib	&& !strcmp
491235783Skib	     (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))),
492235783Skib	      aarch64_simd_types[i].name))
493235783Skib      return aarch64_simd_types[i].mangle;
494235783Skib
495235783Skib  return NULL;
496235783Skib}
497235783Skib
498235783Skibconst char *
499235783Skibaarch64_mangle_builtin_type (const_tree type)
500235783Skib{
501235783Skib  const char *mangle;
502235783Skib  /* Walk through all the AArch64 builtins types tables to filter out the
503235783Skib     incoming type.  */
504235783Skib  if ((mangle = aarch64_mangle_builtin_vector_type (type))
505235783Skib      || (mangle = aarch64_mangle_builtin_scalar_type (type)))
506235783Skib    return mangle;
507235783Skib
508235783Skib  return NULL;
509235783Skib}
510235783Skib
511235783Skibstatic tree
512235783Skibaarch64_simd_builtin_std_type (enum machine_mode mode,
513235783Skib			       enum aarch64_type_qualifiers q)
514235783Skib{
515235783Skib#define QUAL_TYPE(M)  \
516235783Skib  ((q == qualifier_none) ? int##M##_type_node : unsigned_int##M##_type_node);
517235783Skib  switch (mode)
518235783Skib    {
519235783Skib    case QImode:
520235783Skib      return QUAL_TYPE (QI);
521235783Skib    case HImode:
522235783Skib      return QUAL_TYPE (HI);
523235783Skib    case SImode:
524235783Skib      return QUAL_TYPE (SI);
525235783Skib    case DImode:
526235783Skib      return QUAL_TYPE (DI);
527235783Skib    case TImode:
528235783Skib      return QUAL_TYPE (TI);
529235783Skib    case OImode:
530235783Skib      return aarch64_simd_intOI_type_node;
531235783Skib    case EImode:
532235783Skib      return aarch64_simd_intEI_type_node;
533235783Skib    case CImode:
534235783Skib      return aarch64_simd_intCI_type_node;
535235783Skib    case XImode:
536235783Skib      return aarch64_simd_intXI_type_node;
537235783Skib    case SFmode:
538235783Skib      return float_type_node;
539235783Skib    case DFmode:
540235783Skib      return double_type_node;
541235783Skib    default:
542235783Skib      gcc_unreachable ();
543235783Skib    }
544235783Skib#undef QUAL_TYPE
545235783Skib}
546235783Skib
547235783Skibstatic tree
548235783Skibaarch64_lookup_simd_builtin_type (enum machine_mode mode,
549235783Skib				  enum aarch64_type_qualifiers q)
550235783Skib{
551235783Skib  int i;
552235783Skib  int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
553235783Skib
554235783Skib  /* Non-poly scalar modes map to standard types not in the table.  */
555235783Skib  if (q != qualifier_poly && !VECTOR_MODE_P (mode))
556235783Skib    return aarch64_simd_builtin_std_type (mode, q);
557235783Skib
558235783Skib  for (i = 0; i < nelts; i++)
559235783Skib    if (aarch64_simd_types[i].mode == mode
560235783Skib	&& aarch64_simd_types[i].q == q)
561235783Skib      return aarch64_simd_types[i].itype;
562235783Skib
563235783Skib  return NULL_TREE;
564235783Skib}
565235783Skib
566235783Skibstatic tree
567235783Skibaarch64_simd_builtin_type (enum machine_mode mode,
568235783Skib			   bool unsigned_p, bool poly_p)
569235783Skib{
570235783Skib  if (poly_p)
571235783Skib    return aarch64_lookup_simd_builtin_type (mode, qualifier_poly);
572235783Skib  else if (unsigned_p)
573235783Skib    return aarch64_lookup_simd_builtin_type (mode, qualifier_unsigned);
574235783Skib  else
575235783Skib    return aarch64_lookup_simd_builtin_type (mode, qualifier_none);
576235783Skib}
577235783Skib
578235783Skibstatic void
579235783Skibaarch64_init_simd_builtin_types (void)
580235783Skib{
581235783Skib  int i;
582235783Skib  int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
583235783Skib  tree tdecl;
584235783Skib
585235783Skib  /* Init all the element types built by the front-end.  */
586235783Skib  aarch64_simd_types[Int8x8_t].eltype = intQI_type_node;
587235783Skib  aarch64_simd_types[Int8x16_t].eltype = intQI_type_node;
588235783Skib  aarch64_simd_types[Int16x4_t].eltype = intHI_type_node;
589235783Skib  aarch64_simd_types[Int16x8_t].eltype = intHI_type_node;
590235783Skib  aarch64_simd_types[Int32x2_t].eltype = intSI_type_node;
591235783Skib  aarch64_simd_types[Int32x4_t].eltype = intSI_type_node;
592235783Skib  aarch64_simd_types[Int64x1_t].eltype = intDI_type_node;
593235783Skib  aarch64_simd_types[Int64x2_t].eltype = intDI_type_node;
594235783Skib  aarch64_simd_types[Uint8x8_t].eltype = unsigned_intQI_type_node;
595235783Skib  aarch64_simd_types[Uint8x16_t].eltype = unsigned_intQI_type_node;
596235783Skib  aarch64_simd_types[Uint16x4_t].eltype = unsigned_intHI_type_node;
597235783Skib  aarch64_simd_types[Uint16x8_t].eltype = unsigned_intHI_type_node;
598235783Skib  aarch64_simd_types[Uint32x2_t].eltype = unsigned_intSI_type_node;
599235783Skib  aarch64_simd_types[Uint32x4_t].eltype = unsigned_intSI_type_node;
600235783Skib  aarch64_simd_types[Uint64x1_t].eltype = unsigned_intDI_type_node;
601235783Skib  aarch64_simd_types[Uint64x2_t].eltype = unsigned_intDI_type_node;
602235783Skib
603235783Skib  /* Poly types are a world of their own.  */
604235783Skib  aarch64_simd_types[Poly8_t].eltype = aarch64_simd_types[Poly8_t].itype =
605235783Skib    build_distinct_type_copy (unsigned_intQI_type_node);
606235783Skib  aarch64_simd_types[Poly16_t].eltype = aarch64_simd_types[Poly16_t].itype =
607235783Skib    build_distinct_type_copy (unsigned_intHI_type_node);
608235783Skib  aarch64_simd_types[Poly64_t].eltype = aarch64_simd_types[Poly64_t].itype =
609235783Skib    build_distinct_type_copy (unsigned_intDI_type_node);
610235783Skib  aarch64_simd_types[Poly128_t].eltype = aarch64_simd_types[Poly128_t].itype =
611235783Skib    build_distinct_type_copy (unsigned_intTI_type_node);
612235783Skib  /* Init poly vector element types with scalar poly types.  */
613235783Skib  aarch64_simd_types[Poly8x8_t].eltype = aarch64_simd_types[Poly8_t].itype;
614235783Skib  aarch64_simd_types[Poly8x16_t].eltype = aarch64_simd_types[Poly8_t].itype;
615235783Skib  aarch64_simd_types[Poly16x4_t].eltype = aarch64_simd_types[Poly16_t].itype;
616235783Skib  aarch64_simd_types[Poly16x8_t].eltype = aarch64_simd_types[Poly16_t].itype;
617235783Skib  aarch64_simd_types[Poly64x1_t].eltype = aarch64_simd_types[Poly64_t].itype;
618235783Skib  aarch64_simd_types[Poly64x2_t].eltype = aarch64_simd_types[Poly64_t].itype;
619235783Skib
620235783Skib  /* Continue with standard types.  */
621235783Skib  aarch64_simd_types[Float32x2_t].eltype = float_type_node;
622235783Skib  aarch64_simd_types[Float32x4_t].eltype = float_type_node;
623235783Skib  aarch64_simd_types[Float64x1_t].eltype = double_type_node;
624235783Skib  aarch64_simd_types[Float64x2_t].eltype = double_type_node;
625235783Skib
626235783Skib  for (i = 0; i < nelts; i++)
627235783Skib    {
628235783Skib      tree eltype = aarch64_simd_types[i].eltype;
629235783Skib      enum machine_mode mode = aarch64_simd_types[i].mode;
630235783Skib
631235783Skib      if (aarch64_simd_types[i].itype == NULL)
632235783Skib	{
633235783Skib	  aarch64_simd_types[i].itype
634235783Skib	    = build_distinct_type_copy
635235783Skib	      (build_vector_type (eltype, GET_MODE_NUNITS (mode)));
636235783Skib	  SET_TYPE_STRUCTURAL_EQUALITY (aarch64_simd_types[i].itype);
637235783Skib	}
638235783Skib
639235783Skib      tdecl = add_builtin_type (aarch64_simd_types[i].name,
640235783Skib				aarch64_simd_types[i].itype);
641235783Skib      TYPE_NAME (aarch64_simd_types[i].itype) = tdecl;
642235783Skib    }
643235783Skib
644235783Skib#define AARCH64_BUILD_SIGNED_TYPE(mode)  \
645235783Skib  make_signed_type (GET_MODE_PRECISION (mode));
646235783Skib  aarch64_simd_intOI_type_node = AARCH64_BUILD_SIGNED_TYPE (OImode);
647235783Skib  aarch64_simd_intEI_type_node = AARCH64_BUILD_SIGNED_TYPE (EImode);
648235783Skib  aarch64_simd_intCI_type_node = AARCH64_BUILD_SIGNED_TYPE (CImode);
649235783Skib  aarch64_simd_intXI_type_node = AARCH64_BUILD_SIGNED_TYPE (XImode);
650235783Skib#undef AARCH64_BUILD_SIGNED_TYPE
651235783Skib
652235783Skib  tdecl = add_builtin_type
653235783Skib	    ("__builtin_aarch64_simd_ei" , aarch64_simd_intEI_type_node);
654235783Skib  TYPE_NAME (aarch64_simd_intEI_type_node) = tdecl;
655235783Skib  tdecl = add_builtin_type
656235783Skib	    ("__builtin_aarch64_simd_oi" , aarch64_simd_intOI_type_node);
657235783Skib  TYPE_NAME (aarch64_simd_intOI_type_node) = tdecl;
658235783Skib  tdecl = add_builtin_type
659235783Skib	    ("__builtin_aarch64_simd_ci" , aarch64_simd_intCI_type_node);
660235783Skib  TYPE_NAME (aarch64_simd_intCI_type_node) = tdecl;
661235783Skib  tdecl = add_builtin_type
662235783Skib	    ("__builtin_aarch64_simd_xi" , aarch64_simd_intXI_type_node);
663235783Skib  TYPE_NAME (aarch64_simd_intXI_type_node) = tdecl;
664235783Skib}
665235783Skib
666235783Skibstatic void
667235783Skibaarch64_init_simd_builtin_scalar_types (void)
668235783Skib{
669235783Skib  /* Define typedefs for all the standard scalar types.  */
670235783Skib  (*lang_hooks.types.register_builtin_type) (intQI_type_node,
671235783Skib					     "__builtin_aarch64_simd_qi");
672235783Skib  (*lang_hooks.types.register_builtin_type) (intHI_type_node,
673235783Skib					     "__builtin_aarch64_simd_hi");
674235783Skib  (*lang_hooks.types.register_builtin_type) (intSI_type_node,
675235783Skib					     "__builtin_aarch64_simd_si");
676235783Skib  (*lang_hooks.types.register_builtin_type) (float_type_node,
677235783Skib					     "__builtin_aarch64_simd_sf");
678235783Skib  (*lang_hooks.types.register_builtin_type) (intDI_type_node,
679235783Skib					     "__builtin_aarch64_simd_di");
680235783Skib  (*lang_hooks.types.register_builtin_type) (double_type_node,
681235783Skib					     "__builtin_aarch64_simd_df");
682235783Skib  (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
683235783Skib					     "__builtin_aarch64_simd_poly8");
684235783Skib  (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
685235783Skib					     "__builtin_aarch64_simd_poly16");
686235783Skib  (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
687235783Skib					     "__builtin_aarch64_simd_poly64");
688235783Skib  (*lang_hooks.types.register_builtin_type) (unsigned_intTI_type_node,
689235783Skib					     "__builtin_aarch64_simd_poly128");
690235783Skib  (*lang_hooks.types.register_builtin_type) (intTI_type_node,
691235783Skib					     "__builtin_aarch64_simd_ti");
692235783Skib  /* Unsigned integer types for various mode sizes.  */
693235783Skib  (*lang_hooks.types.register_builtin_type) (unsigned_intQI_type_node,
694235783Skib					     "__builtin_aarch64_simd_uqi");
695235783Skib  (*lang_hooks.types.register_builtin_type) (unsigned_intHI_type_node,
696235783Skib					     "__builtin_aarch64_simd_uhi");
697235783Skib  (*lang_hooks.types.register_builtin_type) (unsigned_intSI_type_node,
698235783Skib					     "__builtin_aarch64_simd_usi");
699235783Skib  (*lang_hooks.types.register_builtin_type) (unsigned_intDI_type_node,
700235783Skib					     "__builtin_aarch64_simd_udi");
701235783Skib}
702235783Skib
703235783Skibstatic void
704235783Skibaarch64_init_simd_builtins (void)
705235783Skib{
706235783Skib  unsigned int i, fcode = AARCH64_SIMD_PATTERN_START;
707235783Skib
708235783Skib  aarch64_init_simd_builtin_types ();
709235783Skib
710235783Skib  /* Strong-typing hasn't been implemented for all AdvSIMD builtin intrinsics.
711235783Skib     Therefore we need to preserve the old __builtin scalar types.  It can be
712235783Skib     removed once all the intrinsics become strongly typed using the qualifier
713235783Skib     system.  */
714235783Skib  aarch64_init_simd_builtin_scalar_types ();
715235783Skib
716235783Skib  tree lane_check_fpr = build_function_type_list (void_type_node,
717235783Skib						  size_type_node,
718235783Skib						  size_type_node,
719235783Skib						  intSI_type_node,
720235783Skib						  NULL);
721235783Skib  aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_LANE_CHECK] =
722235783Skib      add_builtin_function ("__builtin_aarch64_im_lane_boundsi", lane_check_fpr,
723235783Skib			    AARCH64_SIMD_BUILTIN_LANE_CHECK, BUILT_IN_MD,
724235783Skib			    NULL, NULL_TREE);
725235783Skib
726235783Skib  for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++)
727235783Skib    {
728235783Skib      bool print_type_signature_p = false;
729235783Skib      char type_signature[SIMD_MAX_BUILTIN_ARGS] = { 0 };
730235783Skib      aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i];
731235783Skib      char namebuf[60];
732235783Skib      tree ftype = NULL;
733235783Skib      tree fndecl = NULL;
734235783Skib
735235783Skib      d->fcode = fcode;
736235783Skib
737235783Skib      /* We must track two variables here.  op_num is
738235783Skib	 the operand number as in the RTL pattern.  This is
739235783Skib	 required to access the mode (e.g. V4SF mode) of the
740235783Skib	 argument, from which the base type can be derived.
741235783Skib	 arg_num is an index in to the qualifiers data, which
742235783Skib	 gives qualifiers to the type (e.g. const unsigned).
743235783Skib	 The reason these two variables may differ by one is the
744235783Skib	 void return type.  While all return types take the 0th entry
745235783Skib	 in the qualifiers array, there is no operand for them in the
746235783Skib	 RTL pattern.  */
747235783Skib      int op_num = insn_data[d->code].n_operands - 1;
748235783Skib      int arg_num = d->qualifiers[0] & qualifier_void
749235783Skib		      ? op_num + 1
750235783Skib		      : op_num;
751235783Skib      tree return_type = void_type_node, args = void_list_node;
752235783Skib      tree eltype;
753235783Skib
754235783Skib      /* Build a function type directly from the insn_data for this
755235783Skib	 builtin.  The build_function_type () function takes care of
756235783Skib	 removing duplicates for us.  */
757235783Skib      for (; op_num >= 0; arg_num--, op_num--)
758235783Skib	{
759235783Skib	  machine_mode op_mode = insn_data[d->code].operand[op_num].mode;
760235783Skib	  enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num];
761235783Skib
762235783Skib	  if (qualifiers & qualifier_unsigned)
763235783Skib	    {
764235783Skib	      type_signature[arg_num] = 'u';
765235783Skib	      print_type_signature_p = true;
766235783Skib	    }
767235783Skib	  else if (qualifiers & qualifier_poly)
768235783Skib	    {
769235783Skib	      type_signature[arg_num] = 'p';
770235783Skib	      print_type_signature_p = true;
771235783Skib	    }
772235783Skib	  else
773235783Skib	    type_signature[arg_num] = 's';
774235783Skib
775235783Skib	  /* Skip an internal operand for vget_{low, high}.  */
776235783Skib	  if (qualifiers & qualifier_internal)
777235783Skib	    continue;
778235783Skib
779235783Skib	  /* Some builtins have different user-facing types
780235783Skib	     for certain arguments, encoded in d->mode.  */
781235783Skib	  if (qualifiers & qualifier_map_mode)
782235783Skib	      op_mode = d->mode;
783235783Skib
784235783Skib	  /* For pointers, we want a pointer to the basic type
785235783Skib	     of the vector.  */
786235783Skib	  if (qualifiers & qualifier_pointer && VECTOR_MODE_P (op_mode))
787235783Skib	    op_mode = GET_MODE_INNER (op_mode);
788235783Skib
789235783Skib	  eltype = aarch64_simd_builtin_type
790235783Skib		     (op_mode,
791235783Skib		      (qualifiers & qualifier_unsigned) != 0,
792235783Skib		      (qualifiers & qualifier_poly) != 0);
793235783Skib	  gcc_assert (eltype != NULL);
794235783Skib
795235783Skib	  /* Add qualifiers.  */
796235783Skib	  if (qualifiers & qualifier_const)
797235783Skib	    eltype = build_qualified_type (eltype, TYPE_QUAL_CONST);
798235783Skib
799235783Skib	  if (qualifiers & qualifier_pointer)
800235783Skib	      eltype = build_pointer_type (eltype);
801235783Skib
802235783Skib	  /* If we have reached arg_num == 0, we are at a non-void
803235783Skib	     return type.  Otherwise, we are still processing
804235783Skib	     arguments.  */
805235783Skib	  if (arg_num == 0)
806235783Skib	    return_type = eltype;
807235783Skib	  else
808235783Skib	    args = tree_cons (NULL_TREE, eltype, args);
809235783Skib	}
810235783Skib
811235783Skib      ftype = build_function_type (return_type, args);
812235783Skib
813235783Skib      gcc_assert (ftype != NULL);
814235783Skib
815235783Skib      if (print_type_signature_p)
816235783Skib	snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s_%s",
817235783Skib		  d->name, type_signature);
818235783Skib      else
819235783Skib	snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s",
820235783Skib		  d->name);
821235783Skib
822235783Skib      fndecl = add_builtin_function (namebuf, ftype, fcode, BUILT_IN_MD,
823235783Skib				     NULL, NULL_TREE);
824235783Skib      aarch64_builtin_decls[fcode] = fndecl;
825235783Skib    }
826235783Skib}
827235783Skib
828235783Skibstatic void
829235783Skibaarch64_init_crc32_builtins ()
830235783Skib{
831235783Skib  tree usi_type = aarch64_simd_builtin_std_type (SImode, qualifier_unsigned);
832235783Skib  unsigned int i = 0;
833235783Skib
834235783Skib  for (i = 0; i < ARRAY_SIZE (aarch64_crc_builtin_data); ++i)
835235783Skib    {
836235783Skib      aarch64_crc_builtin_datum* d = &aarch64_crc_builtin_data[i];
837235783Skib      tree argtype = aarch64_simd_builtin_std_type (d->mode,
838235783Skib						    qualifier_unsigned);
839235783Skib      tree ftype = build_function_type_list (usi_type, usi_type, argtype, NULL_TREE);
840235783Skib      tree fndecl = add_builtin_function (d->name, ftype, d->fcode,
841235783Skib                                          BUILT_IN_MD, NULL, NULL_TREE);
842235783Skib
843235783Skib      aarch64_builtin_decls[d->fcode] = fndecl;
844235783Skib    }
845235783Skib}
846235783Skib
847235783Skibvoid
848235783Skibaarch64_init_builtins (void)
849235783Skib{
850235783Skib  tree ftype_set_fpr
851235783Skib    = build_function_type_list (void_type_node, unsigned_type_node, NULL);
852235783Skib  tree ftype_get_fpr
853235783Skib    = build_function_type_list (unsigned_type_node, NULL);
854235783Skib
855235783Skib  aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR]
856235783Skib    = add_builtin_function ("__builtin_aarch64_get_fpcr", ftype_get_fpr,
857235783Skib			    AARCH64_BUILTIN_GET_FPCR, BUILT_IN_MD, NULL, NULL_TREE);
858235783Skib  aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR]
859235783Skib    = add_builtin_function ("__builtin_aarch64_set_fpcr", ftype_set_fpr,
860235783Skib			    AARCH64_BUILTIN_SET_FPCR, BUILT_IN_MD, NULL, NULL_TREE);
861235783Skib  aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR]
862235783Skib    = add_builtin_function ("__builtin_aarch64_get_fpsr", ftype_get_fpr,
863235783Skib			    AARCH64_BUILTIN_GET_FPSR, BUILT_IN_MD, NULL, NULL_TREE);
864235783Skib  aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR]
865235783Skib    = add_builtin_function ("__builtin_aarch64_set_fpsr", ftype_set_fpr,
866235783Skib			    AARCH64_BUILTIN_SET_FPSR, BUILT_IN_MD, NULL, NULL_TREE);
867235783Skib
868235783Skib  if (TARGET_SIMD)
869235783Skib    aarch64_init_simd_builtins ();
870235783Skib  if (TARGET_CRC32)
871235783Skib    aarch64_init_crc32_builtins ();
872235783Skib}
873235783Skib
874235783Skibtree
875235783Skibaarch64_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
876235783Skib{
877235783Skib  if (code >= AARCH64_BUILTIN_MAX)
878235783Skib    return error_mark_node;
879235783Skib
880235783Skib  return aarch64_builtin_decls[code];
881235783Skib}
882235783Skib
883235783Skibtypedef enum
884235783Skib{
885235783Skib  SIMD_ARG_COPY_TO_REG,
886235783Skib  SIMD_ARG_CONSTANT,
887235783Skib  SIMD_ARG_LANE_INDEX,
888235783Skib  SIMD_ARG_STOP
889235783Skib} builtin_simd_arg;
890235783Skib
891235783Skibstatic rtx
892235783Skibaarch64_simd_expand_args (rtx target, int icode, int have_retval,
893235783Skib			  tree exp, builtin_simd_arg *args)
894235783Skib{
895235783Skib  rtx pat;
896235783Skib  rtx op[SIMD_MAX_BUILTIN_ARGS + 1]; /* First element for result operand.  */
897235783Skib  int opc = 0;
898235783Skib
899235783Skib  if (have_retval)
900235783Skib    {
901235783Skib      machine_mode tmode = insn_data[icode].operand[0].mode;
902235783Skib      if (!target
903235783Skib	  || GET_MODE (target) != tmode
904235783Skib	  || !(*insn_data[icode].operand[0].predicate) (target, tmode))
905235783Skib	target = gen_reg_rtx (tmode);
906235783Skib      op[opc++] = target;
907235783Skib    }
908235783Skib
909235783Skib  for (;;)
910235783Skib    {
911235783Skib      builtin_simd_arg thisarg = args[opc - have_retval];
912235783Skib
913235783Skib      if (thisarg == SIMD_ARG_STOP)
914235783Skib	break;
915235783Skib      else
916235783Skib	{
917235783Skib	  tree arg = CALL_EXPR_ARG (exp, opc - have_retval);
918235783Skib	  enum machine_mode mode = insn_data[icode].operand[opc].mode;
919235783Skib	  op[opc] = expand_normal (arg);
920235783Skib
921235783Skib	  switch (thisarg)
922235783Skib	    {
923235783Skib	    case SIMD_ARG_COPY_TO_REG:
924235783Skib	      if (POINTER_TYPE_P (TREE_TYPE (arg)))
925235783Skib		op[opc] = convert_memory_address (Pmode, op[opc]);
926235783Skib	      /*gcc_assert (GET_MODE (op[opc]) == mode); */
927235783Skib	      if (!(*insn_data[icode].operand[opc].predicate)
928235783Skib		  (op[opc], mode))
929235783Skib		op[opc] = copy_to_mode_reg (mode, op[opc]);
930235783Skib	      break;
931235783Skib
932235783Skib	    case SIMD_ARG_LANE_INDEX:
933235783Skib	      /* Must be a previous operand into which this is an index.  */
934235783Skib	      gcc_assert (opc > 0);
935235783Skib	      if (CONST_INT_P (op[opc]))
936235783Skib		{
937235783Skib		  machine_mode vmode = insn_data[icode].operand[opc - 1].mode;
938235783Skib		  aarch64_simd_lane_bounds (op[opc],
939235783Skib					    0, GET_MODE_NUNITS (vmode), exp);
940235783Skib		  /* Keep to GCC-vector-extension lane indices in the RTL.  */
941235783Skib		  op[opc] = GEN_INT (ENDIAN_LANE_N (vmode, INTVAL (op[opc])));
942235783Skib		}
943235783Skib	      /* Fall through - if the lane index isn't a constant then
944235783Skib		 the next case will error.  */
945235783Skib	    case SIMD_ARG_CONSTANT:
946235783Skib	      if (!(*insn_data[icode].operand[opc].predicate)
947235783Skib		  (op[opc], mode))
948235783Skib	      {
949235783Skib		error ("%Kargument %d must be a constant immediate",
950235783Skib		       exp, opc + 1 - have_retval);
951235783Skib		return const0_rtx;
952235783Skib	      }
953235783Skib	      break;
954235783Skib
955235783Skib	    case SIMD_ARG_STOP:
956235783Skib	      gcc_unreachable ();
957235783Skib	    }
958235783Skib
959235783Skib	  opc++;
960235783Skib	}
961235783Skib    }
962235783Skib
963235783Skib  switch (opc)
964235783Skib    {
965235783Skib    case 1:
966235783Skib      pat = GEN_FCN (icode) (op[0]);
967235783Skib      break;
968235783Skib
969235783Skib    case 2:
970235783Skib      pat = GEN_FCN (icode) (op[0], op[1]);
971235783Skib      break;
972
973    case 3:
974      pat = GEN_FCN (icode) (op[0], op[1], op[2]);
975      break;
976
977    case 4:
978      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
979      break;
980
981    case 5:
982      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
983      break;
984
985    case 6:
986      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]);
987      break;
988
989    default:
990      gcc_unreachable ();
991    }
992
993  if (!pat)
994    return NULL_RTX;
995
996  emit_insn (pat);
997
998  return target;
999}
1000
1001/* Expand an AArch64 AdvSIMD builtin(intrinsic).  */
1002rtx
1003aarch64_simd_expand_builtin (int fcode, tree exp, rtx target)
1004{
1005  if (fcode == AARCH64_SIMD_BUILTIN_LANE_CHECK)
1006    {
1007      rtx totalsize = expand_normal (CALL_EXPR_ARG (exp, 0));
1008      rtx elementsize = expand_normal (CALL_EXPR_ARG (exp, 1));
1009      if (CONST_INT_P (totalsize) && CONST_INT_P (elementsize)
1010	  && UINTVAL (elementsize) != 0
1011	  && UINTVAL (totalsize) != 0)
1012	{
1013	  rtx lane_idx = expand_normal (CALL_EXPR_ARG (exp, 2));
1014          if (CONST_INT_P (lane_idx))
1015	    aarch64_simd_lane_bounds (lane_idx, 0,
1016				      UINTVAL (totalsize)
1017				       / UINTVAL (elementsize),
1018				      exp);
1019          else
1020	    error ("%Klane index must be a constant immediate", exp);
1021	}
1022      else
1023	error ("%Ktotal size and element size must be a non-zero constant immediate", exp);
1024      /* Don't generate any RTL.  */
1025      return const0_rtx;
1026    }
1027  aarch64_simd_builtin_datum *d =
1028		&aarch64_simd_builtin_data[fcode - AARCH64_SIMD_PATTERN_START];
1029  enum insn_code icode = d->code;
1030  builtin_simd_arg args[SIMD_MAX_BUILTIN_ARGS + 1];
1031  int num_args = insn_data[d->code].n_operands;
1032  int is_void = 0;
1033  int k;
1034
1035  is_void = !!(d->qualifiers[0] & qualifier_void);
1036
1037  num_args += is_void;
1038
1039  for (k = 1; k < num_args; k++)
1040    {
1041      /* We have four arrays of data, each indexed in a different fashion.
1042	 qualifiers - element 0 always describes the function return type.
1043	 operands - element 0 is either the operand for return value (if
1044	   the function has a non-void return type) or the operand for the
1045	   first argument.
1046	 expr_args - element 0 always holds the first argument.
1047	 args - element 0 is always used for the return type.  */
1048      int qualifiers_k = k;
1049      int operands_k = k - is_void;
1050      int expr_args_k = k - 1;
1051
1052      if (d->qualifiers[qualifiers_k] & qualifier_lane_index)
1053	args[k] = SIMD_ARG_LANE_INDEX;
1054      else if (d->qualifiers[qualifiers_k] & qualifier_immediate)
1055	args[k] = SIMD_ARG_CONSTANT;
1056      else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate)
1057	{
1058	  rtx arg
1059	    = expand_normal (CALL_EXPR_ARG (exp,
1060					    (expr_args_k)));
1061	  /* Handle constants only if the predicate allows it.  */
1062	  bool op_const_int_p =
1063	    (CONST_INT_P (arg)
1064	     && (*insn_data[icode].operand[operands_k].predicate)
1065		(arg, insn_data[icode].operand[operands_k].mode));
1066	  args[k] = op_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG;
1067	}
1068      else
1069	args[k] = SIMD_ARG_COPY_TO_REG;
1070
1071    }
1072  args[k] = SIMD_ARG_STOP;
1073
1074  /* The interface to aarch64_simd_expand_args expects a 0 if
1075     the function is void, and a 1 if it is not.  */
1076  return aarch64_simd_expand_args
1077	  (target, icode, !is_void, exp, &args[1]);
1078}
1079
1080rtx
1081aarch64_crc32_expand_builtin (int fcode, tree exp, rtx target)
1082{
1083  rtx pat;
1084  aarch64_crc_builtin_datum *d
1085    = &aarch64_crc_builtin_data[fcode - (AARCH64_CRC32_BUILTIN_BASE + 1)];
1086  enum insn_code icode = d->icode;
1087  tree arg0 = CALL_EXPR_ARG (exp, 0);
1088  tree arg1 = CALL_EXPR_ARG (exp, 1);
1089  rtx op0 = expand_normal (arg0);
1090  rtx op1 = expand_normal (arg1);
1091  machine_mode tmode = insn_data[icode].operand[0].mode;
1092  machine_mode mode0 = insn_data[icode].operand[1].mode;
1093  machine_mode mode1 = insn_data[icode].operand[2].mode;
1094
1095  if (! target
1096      || GET_MODE (target) != tmode
1097      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1098    target = gen_reg_rtx (tmode);
1099
1100  gcc_assert ((GET_MODE (op0) == mode0 || GET_MODE (op0) == VOIDmode)
1101	      && (GET_MODE (op1) == mode1 || GET_MODE (op1) == VOIDmode));
1102
1103  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1104    op0 = copy_to_mode_reg (mode0, op0);
1105  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
1106    op1 = copy_to_mode_reg (mode1, op1);
1107
1108  pat = GEN_FCN (icode) (target, op0, op1);
1109  if (!pat)
1110    return NULL_RTX;
1111
1112  emit_insn (pat);
1113  return target;
1114}
1115
1116/* Expand an expression EXP that calls a built-in function,
1117   with result going to TARGET if that's convenient.  */
1118rtx
1119aarch64_expand_builtin (tree exp,
1120		     rtx target,
1121		     rtx subtarget ATTRIBUTE_UNUSED,
1122		     machine_mode mode ATTRIBUTE_UNUSED,
1123		     int ignore ATTRIBUTE_UNUSED)
1124{
1125  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
1126  int fcode = DECL_FUNCTION_CODE (fndecl);
1127  int icode;
1128  rtx pat, op0;
1129  tree arg0;
1130
1131  switch (fcode)
1132    {
1133    case AARCH64_BUILTIN_GET_FPCR:
1134    case AARCH64_BUILTIN_SET_FPCR:
1135    case AARCH64_BUILTIN_GET_FPSR:
1136    case AARCH64_BUILTIN_SET_FPSR:
1137      if ((fcode == AARCH64_BUILTIN_GET_FPCR)
1138	  || (fcode == AARCH64_BUILTIN_GET_FPSR))
1139	{
1140	  icode = (fcode == AARCH64_BUILTIN_GET_FPSR) ?
1141	    CODE_FOR_get_fpsr : CODE_FOR_get_fpcr;
1142	  target = gen_reg_rtx (SImode);
1143	  pat = GEN_FCN (icode) (target);
1144	}
1145      else
1146	{
1147	  target = NULL_RTX;
1148	  icode = (fcode == AARCH64_BUILTIN_SET_FPSR) ?
1149	    CODE_FOR_set_fpsr : CODE_FOR_set_fpcr;
1150	  arg0 = CALL_EXPR_ARG (exp, 0);
1151	  op0 = expand_normal (arg0);
1152	  pat = GEN_FCN (icode) (op0);
1153	}
1154      emit_insn (pat);
1155      return target;
1156    }
1157
1158  if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
1159    return aarch64_simd_expand_builtin (fcode, exp, target);
1160  else if (fcode >= AARCH64_CRC32_BUILTIN_BASE && fcode <= AARCH64_CRC32_BUILTIN_MAX)
1161    return aarch64_crc32_expand_builtin (fcode, exp, target);
1162
1163  gcc_unreachable ();
1164}
1165
1166tree
1167aarch64_builtin_vectorized_function (tree fndecl, tree type_out, tree type_in)
1168{
1169  machine_mode in_mode, out_mode;
1170  int in_n, out_n;
1171
1172  if (TREE_CODE (type_out) != VECTOR_TYPE
1173      || TREE_CODE (type_in) != VECTOR_TYPE)
1174    return NULL_TREE;
1175
1176  out_mode = TYPE_MODE (TREE_TYPE (type_out));
1177  out_n = TYPE_VECTOR_SUBPARTS (type_out);
1178  in_mode = TYPE_MODE (TREE_TYPE (type_in));
1179  in_n = TYPE_VECTOR_SUBPARTS (type_in);
1180
1181#undef AARCH64_CHECK_BUILTIN_MODE
1182#define AARCH64_CHECK_BUILTIN_MODE(C, N) 1
1183#define AARCH64_FIND_FRINT_VARIANT(N) \
1184  (AARCH64_CHECK_BUILTIN_MODE (2, D) \
1185    ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2df] \
1186    : (AARCH64_CHECK_BUILTIN_MODE (4, S) \
1187	? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v4sf] \
1188	: (AARCH64_CHECK_BUILTIN_MODE (2, S) \
1189	   ? aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_##N##v2sf] \
1190	   : NULL_TREE)))
1191  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
1192    {
1193      enum built_in_function fn = DECL_FUNCTION_CODE (fndecl);
1194      switch (fn)
1195	{
1196#undef AARCH64_CHECK_BUILTIN_MODE
1197#define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1198  (out_mode == N##Fmode && out_n == C \
1199   && in_mode == N##Fmode && in_n == C)
1200	case BUILT_IN_FLOOR:
1201	case BUILT_IN_FLOORF:
1202	  return AARCH64_FIND_FRINT_VARIANT (floor);
1203	case BUILT_IN_CEIL:
1204	case BUILT_IN_CEILF:
1205	  return AARCH64_FIND_FRINT_VARIANT (ceil);
1206	case BUILT_IN_TRUNC:
1207	case BUILT_IN_TRUNCF:
1208	  return AARCH64_FIND_FRINT_VARIANT (btrunc);
1209	case BUILT_IN_ROUND:
1210	case BUILT_IN_ROUNDF:
1211	  return AARCH64_FIND_FRINT_VARIANT (round);
1212	case BUILT_IN_NEARBYINT:
1213	case BUILT_IN_NEARBYINTF:
1214	  return AARCH64_FIND_FRINT_VARIANT (nearbyint);
1215	case BUILT_IN_SQRT:
1216	case BUILT_IN_SQRTF:
1217	  return AARCH64_FIND_FRINT_VARIANT (sqrt);
1218#undef AARCH64_CHECK_BUILTIN_MODE
1219#define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1220  (out_mode == SImode && out_n == C \
1221   && in_mode == N##Imode && in_n == C)
1222        case BUILT_IN_CLZ:
1223          {
1224            if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1225              return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_clzv4si];
1226            return NULL_TREE;
1227          }
1228	case BUILT_IN_CTZ:
1229          {
1230	    if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1231	      return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv2si];
1232	    else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1233	      return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOP_ctzv4si];
1234	    return NULL_TREE;
1235          }
1236#undef AARCH64_CHECK_BUILTIN_MODE
1237#define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1238  (out_mode == N##Imode && out_n == C \
1239   && in_mode == N##Fmode && in_n == C)
1240	case BUILT_IN_LFLOOR:
1241	case BUILT_IN_LFLOORF:
1242	case BUILT_IN_LLFLOOR:
1243	case BUILT_IN_IFLOORF:
1244	  {
1245	    enum aarch64_builtins builtin;
1246	    if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1247	      builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2dfv2di;
1248	    else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1249	      builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv4sfv4si;
1250	    else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1251	      builtin = AARCH64_SIMD_BUILTIN_UNOP_lfloorv2sfv2si;
1252	    else
1253	      return NULL_TREE;
1254
1255	    return aarch64_builtin_decls[builtin];
1256	  }
1257	case BUILT_IN_LCEIL:
1258	case BUILT_IN_LCEILF:
1259	case BUILT_IN_LLCEIL:
1260	case BUILT_IN_ICEILF:
1261	  {
1262	    enum aarch64_builtins builtin;
1263	    if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1264	      builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2dfv2di;
1265	    else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1266	      builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv4sfv4si;
1267	    else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1268	      builtin = AARCH64_SIMD_BUILTIN_UNOP_lceilv2sfv2si;
1269	    else
1270	      return NULL_TREE;
1271
1272	    return aarch64_builtin_decls[builtin];
1273	  }
1274	case BUILT_IN_LROUND:
1275	case BUILT_IN_IROUNDF:
1276	  {
1277	    enum aarch64_builtins builtin;
1278	    if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1279	      builtin =	AARCH64_SIMD_BUILTIN_UNOP_lroundv2dfv2di;
1280	    else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1281	      builtin =	AARCH64_SIMD_BUILTIN_UNOP_lroundv4sfv4si;
1282	    else if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1283	      builtin =	AARCH64_SIMD_BUILTIN_UNOP_lroundv2sfv2si;
1284	    else
1285	      return NULL_TREE;
1286
1287	    return aarch64_builtin_decls[builtin];
1288	  }
1289	case BUILT_IN_BSWAP16:
1290#undef AARCH64_CHECK_BUILTIN_MODE
1291#define AARCH64_CHECK_BUILTIN_MODE(C, N) \
1292  (out_mode == N##Imode && out_n == C \
1293   && in_mode == N##Imode && in_n == C)
1294	  if (AARCH64_CHECK_BUILTIN_MODE (4, H))
1295	    return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4hi];
1296	  else if (AARCH64_CHECK_BUILTIN_MODE (8, H))
1297	    return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv8hi];
1298	  else
1299	    return NULL_TREE;
1300	case BUILT_IN_BSWAP32:
1301	  if (AARCH64_CHECK_BUILTIN_MODE (2, S))
1302	    return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2si];
1303	  else if (AARCH64_CHECK_BUILTIN_MODE (4, S))
1304	    return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv4si];
1305	  else
1306	    return NULL_TREE;
1307	case BUILT_IN_BSWAP64:
1308	  if (AARCH64_CHECK_BUILTIN_MODE (2, D))
1309	    return aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_UNOPU_bswapv2di];
1310	  else
1311	    return NULL_TREE;
1312	default:
1313	  return NULL_TREE;
1314      }
1315    }
1316
1317  return NULL_TREE;
1318}
1319
1320#undef VAR1
1321#define VAR1(T, N, MAP, A) \
1322  case AARCH64_SIMD_BUILTIN_##T##_##N##A:
1323
1324tree
1325aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args,
1326		      bool ignore ATTRIBUTE_UNUSED)
1327{
1328  int fcode = DECL_FUNCTION_CODE (fndecl);
1329  tree type = TREE_TYPE (TREE_TYPE (fndecl));
1330
1331  switch (fcode)
1332    {
1333      BUILTIN_VDQF (UNOP, abs, 2)
1334	return fold_build1 (ABS_EXPR, type, args[0]);
1335	break;
1336      VAR1 (UNOP, floatv2si, 2, v2sf)
1337      VAR1 (UNOP, floatv4si, 2, v4sf)
1338      VAR1 (UNOP, floatv2di, 2, v2df)
1339	return fold_build1 (FLOAT_EXPR, type, args[0]);
1340      default:
1341	break;
1342    }
1343
1344  return NULL_TREE;
1345}
1346
1347bool
1348aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi)
1349{
1350  bool changed = false;
1351  gimple stmt = gsi_stmt (*gsi);
1352  tree call = gimple_call_fn (stmt);
1353  tree fndecl;
1354  gimple new_stmt = NULL;
1355
1356  if (call)
1357    {
1358      fndecl = gimple_call_fndecl (stmt);
1359      if (fndecl)
1360	{
1361	  int fcode = DECL_FUNCTION_CODE (fndecl);
1362	  int nargs = gimple_call_num_args (stmt);
1363	  tree *args = (nargs > 0
1364			? gimple_call_arg_ptr (stmt, 0)
1365			: &error_mark_node);
1366
1367	  /* We use gimple's REDUC_(PLUS|MIN|MAX)_EXPRs for float, signed int
1368	     and unsigned int; it will distinguish according to the types of
1369	     the arguments to the __builtin.  */
1370	  switch (fcode)
1371	    {
1372	      BUILTIN_VALL (UNOP, reduc_plus_scal_, 10)
1373	        new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
1374						REDUC_PLUS_EXPR, args[0]);
1375		break;
1376	      BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10)
1377	      BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10)
1378		new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
1379						REDUC_MAX_EXPR, args[0]);
1380		break;
1381	      BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10)
1382	      BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10)
1383		new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
1384						REDUC_MIN_EXPR, args[0]);
1385		break;
1386
1387	    default:
1388	      break;
1389	    }
1390	}
1391    }
1392
1393  if (new_stmt)
1394    {
1395      gsi_replace (gsi, new_stmt, true);
1396      changed = true;
1397    }
1398
1399  return changed;
1400}
1401
1402void
1403aarch64_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
1404{
1405  const unsigned AARCH64_FE_INVALID = 1;
1406  const unsigned AARCH64_FE_DIVBYZERO = 2;
1407  const unsigned AARCH64_FE_OVERFLOW = 4;
1408  const unsigned AARCH64_FE_UNDERFLOW = 8;
1409  const unsigned AARCH64_FE_INEXACT = 16;
1410  const unsigned HOST_WIDE_INT AARCH64_FE_ALL_EXCEPT = (AARCH64_FE_INVALID
1411							| AARCH64_FE_DIVBYZERO
1412							| AARCH64_FE_OVERFLOW
1413							| AARCH64_FE_UNDERFLOW
1414							| AARCH64_FE_INEXACT);
1415  const unsigned HOST_WIDE_INT AARCH64_FE_EXCEPT_SHIFT = 8;
1416  tree fenv_cr, fenv_sr, get_fpcr, set_fpcr, mask_cr, mask_sr;
1417  tree ld_fenv_cr, ld_fenv_sr, masked_fenv_cr, masked_fenv_sr, hold_fnclex_cr;
1418  tree hold_fnclex_sr, new_fenv_var, reload_fenv, restore_fnenv, get_fpsr, set_fpsr;
1419  tree update_call, atomic_feraiseexcept, hold_fnclex, masked_fenv, ld_fenv;
1420
1421  /* Generate the equivalence of :
1422       unsigned int fenv_cr;
1423       fenv_cr = __builtin_aarch64_get_fpcr ();
1424
1425       unsigned int fenv_sr;
1426       fenv_sr = __builtin_aarch64_get_fpsr ();
1427
1428       Now set all exceptions to non-stop
1429       unsigned int mask_cr
1430		= ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT);
1431       unsigned int masked_cr;
1432       masked_cr = fenv_cr & mask_cr;
1433
1434       And clear all exception flags
1435       unsigned int maske_sr = ~AARCH64_FE_ALL_EXCEPT;
1436       unsigned int masked_cr;
1437       masked_sr = fenv_sr & mask_sr;
1438
1439       __builtin_aarch64_set_cr (masked_cr);
1440       __builtin_aarch64_set_sr (masked_sr);  */
1441
1442  fenv_cr = create_tmp_var (unsigned_type_node);
1443  fenv_sr = create_tmp_var (unsigned_type_node);
1444
1445  get_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR];
1446  set_fpcr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR];
1447  get_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR];
1448  set_fpsr = aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR];
1449
1450  mask_cr = build_int_cst (unsigned_type_node,
1451			   ~(AARCH64_FE_ALL_EXCEPT << AARCH64_FE_EXCEPT_SHIFT));
1452  mask_sr = build_int_cst (unsigned_type_node,
1453			   ~(AARCH64_FE_ALL_EXCEPT));
1454
1455  ld_fenv_cr = build2 (MODIFY_EXPR, unsigned_type_node,
1456		    fenv_cr, build_call_expr (get_fpcr, 0));
1457  ld_fenv_sr = build2 (MODIFY_EXPR, unsigned_type_node,
1458		    fenv_sr, build_call_expr (get_fpsr, 0));
1459
1460  masked_fenv_cr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_cr, mask_cr);
1461  masked_fenv_sr = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_sr, mask_sr);
1462
1463  hold_fnclex_cr = build_call_expr (set_fpcr, 1, masked_fenv_cr);
1464  hold_fnclex_sr = build_call_expr (set_fpsr, 1, masked_fenv_sr);
1465
1466  hold_fnclex = build2 (COMPOUND_EXPR, void_type_node, hold_fnclex_cr,
1467			hold_fnclex_sr);
1468  masked_fenv = build2 (COMPOUND_EXPR, void_type_node, masked_fenv_cr,
1469			masked_fenv_sr);
1470  ld_fenv = build2 (COMPOUND_EXPR, void_type_node, ld_fenv_cr, ld_fenv_sr);
1471
1472  *hold = build2 (COMPOUND_EXPR, void_type_node,
1473		  build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv),
1474		  hold_fnclex);
1475
1476  /* Store the value of masked_fenv to clear the exceptions:
1477     __builtin_aarch64_set_fpsr (masked_fenv_sr);  */
1478
1479  *clear = build_call_expr (set_fpsr, 1, masked_fenv_sr);
1480
1481  /* Generate the equivalent of :
1482       unsigned int new_fenv_var;
1483       new_fenv_var = __builtin_aarch64_get_fpsr ();
1484
1485       __builtin_aarch64_set_fpsr (fenv_sr);
1486
1487       __atomic_feraiseexcept (new_fenv_var);  */
1488
1489  new_fenv_var = create_tmp_var (unsigned_type_node);
1490  reload_fenv = build2 (MODIFY_EXPR, unsigned_type_node,
1491			new_fenv_var, build_call_expr (get_fpsr, 0));
1492  restore_fnenv = build_call_expr (set_fpsr, 1, fenv_sr);
1493  atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT);
1494  update_call = build_call_expr (atomic_feraiseexcept, 1,
1495				 fold_convert (integer_type_node, new_fenv_var));
1496  *update = build2 (COMPOUND_EXPR, void_type_node,
1497		    build2 (COMPOUND_EXPR, void_type_node,
1498			    reload_fenv, restore_fnenv), update_call);
1499}
1500
1501
1502#undef AARCH64_CHECK_BUILTIN_MODE
1503#undef AARCH64_FIND_FRINT_VARIANT
1504#undef CF0
1505#undef CF1
1506#undef CF2
1507#undef CF3
1508#undef CF4
1509#undef CF10
1510#undef VAR1
1511#undef VAR2
1512#undef VAR3
1513#undef VAR4
1514#undef VAR5
1515#undef VAR6
1516#undef VAR7
1517#undef VAR8
1518#undef VAR9
1519#undef VAR10
1520#undef VAR11
1521
1522#include "gt-aarch64-builtins.h"
1523