1e4b17023SJohn Marino /* Expand builtin functions.
2e4b17023SJohn Marino Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3e4b17023SJohn Marino 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
4e4b17023SJohn Marino 2012 Free Software Foundation, Inc.
5e4b17023SJohn Marino
6e4b17023SJohn Marino This file is part of GCC.
7e4b17023SJohn Marino
8e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under
9e4b17023SJohn Marino the terms of the GNU General Public License as published by the Free
10e4b17023SJohn Marino Software Foundation; either version 3, or (at your option) any later
11e4b17023SJohn Marino version.
12e4b17023SJohn Marino
13e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or
15e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16e4b17023SJohn Marino for more details.
17e4b17023SJohn Marino
18e4b17023SJohn Marino You should have received a copy of the GNU General Public License
19e4b17023SJohn Marino along with GCC; see the file COPYING3. If not see
20e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
21e4b17023SJohn Marino
22e4b17023SJohn Marino #include "config.h"
23e4b17023SJohn Marino #include "system.h"
24e4b17023SJohn Marino #include "coretypes.h"
25e4b17023SJohn Marino #include "tm.h"
26e4b17023SJohn Marino #include "machmode.h"
27e4b17023SJohn Marino #include "rtl.h"
28e4b17023SJohn Marino #include "tree.h"
29e4b17023SJohn Marino #include "realmpfr.h"
30e4b17023SJohn Marino #include "gimple.h"
31e4b17023SJohn Marino #include "flags.h"
32e4b17023SJohn Marino #include "regs.h"
33e4b17023SJohn Marino #include "hard-reg-set.h"
34e4b17023SJohn Marino #include "except.h"
35e4b17023SJohn Marino #include "function.h"
36e4b17023SJohn Marino #include "insn-config.h"
37e4b17023SJohn Marino #include "expr.h"
38e4b17023SJohn Marino #include "optabs.h"
39e4b17023SJohn Marino #include "libfuncs.h"
40e4b17023SJohn Marino #include "recog.h"
41e4b17023SJohn Marino #include "output.h"
42e4b17023SJohn Marino #include "typeclass.h"
43e4b17023SJohn Marino #include "predict.h"
44e4b17023SJohn Marino #include "tm_p.h"
45e4b17023SJohn Marino #include "target.h"
46e4b17023SJohn Marino #include "langhooks.h"
47e4b17023SJohn Marino #include "basic-block.h"
48e4b17023SJohn Marino #include "tree-mudflap.h"
49e4b17023SJohn Marino #include "tree-flow.h"
50e4b17023SJohn Marino #include "value-prof.h"
51e4b17023SJohn Marino #include "diagnostic-core.h"
52e4b17023SJohn Marino #include "builtins.h"
53e4b17023SJohn Marino
54e4b17023SJohn Marino
55e4b17023SJohn Marino #ifndef PAD_VARARGS_DOWN
56e4b17023SJohn Marino #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
57e4b17023SJohn Marino #endif
58e4b17023SJohn Marino static tree do_mpc_arg1 (tree, tree, int (*)(mpc_ptr, mpc_srcptr, mpc_rnd_t));
59e4b17023SJohn Marino
60e4b17023SJohn Marino struct target_builtins default_target_builtins;
61e4b17023SJohn Marino #if SWITCHABLE_TARGET
62e4b17023SJohn Marino struct target_builtins *this_target_builtins = &default_target_builtins;
63e4b17023SJohn Marino #endif
64e4b17023SJohn Marino
65e4b17023SJohn Marino /* Define the names of the builtin function types and codes. */
66e4b17023SJohn Marino const char *const built_in_class_names[4]
67e4b17023SJohn Marino = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
68e4b17023SJohn Marino
69e4b17023SJohn Marino #define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT, IM, COND) #X,
70e4b17023SJohn Marino const char * built_in_names[(int) END_BUILTINS] =
71e4b17023SJohn Marino {
72e4b17023SJohn Marino #include "builtins.def"
73e4b17023SJohn Marino };
74e4b17023SJohn Marino #undef DEF_BUILTIN
75e4b17023SJohn Marino
76e4b17023SJohn Marino /* Setup an array of _DECL trees, make sure each element is
77e4b17023SJohn Marino initialized to NULL_TREE. */
78e4b17023SJohn Marino builtin_info_type builtin_info;
79e4b17023SJohn Marino
80e4b17023SJohn Marino static const char *c_getstr (tree);
81e4b17023SJohn Marino static rtx c_readstr (const char *, enum machine_mode);
82e4b17023SJohn Marino static int target_char_cast (tree, char *);
83e4b17023SJohn Marino static rtx get_memory_rtx (tree, tree);
84e4b17023SJohn Marino static int apply_args_size (void);
85e4b17023SJohn Marino static int apply_result_size (void);
86e4b17023SJohn Marino #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
87e4b17023SJohn Marino static rtx result_vector (int, rtx);
88e4b17023SJohn Marino #endif
89e4b17023SJohn Marino static void expand_builtin_update_setjmp_buf (rtx);
90e4b17023SJohn Marino static void expand_builtin_prefetch (tree);
91e4b17023SJohn Marino static rtx expand_builtin_apply_args (void);
92e4b17023SJohn Marino static rtx expand_builtin_apply_args_1 (void);
93e4b17023SJohn Marino static rtx expand_builtin_apply (rtx, rtx, rtx);
94e4b17023SJohn Marino static void expand_builtin_return (rtx);
95e4b17023SJohn Marino static enum type_class type_to_class (tree);
96e4b17023SJohn Marino static rtx expand_builtin_classify_type (tree);
97e4b17023SJohn Marino static void expand_errno_check (tree, rtx);
98e4b17023SJohn Marino static rtx expand_builtin_mathfn (tree, rtx, rtx);
99e4b17023SJohn Marino static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
100e4b17023SJohn Marino static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
101e4b17023SJohn Marino static rtx expand_builtin_mathfn_ternary (tree, rtx, rtx);
102e4b17023SJohn Marino static rtx expand_builtin_interclass_mathfn (tree, rtx);
103e4b17023SJohn Marino static rtx expand_builtin_sincos (tree);
104e4b17023SJohn Marino static rtx expand_builtin_cexpi (tree, rtx);
105e4b17023SJohn Marino static rtx expand_builtin_int_roundingfn (tree, rtx);
106e4b17023SJohn Marino static rtx expand_builtin_int_roundingfn_2 (tree, rtx);
107e4b17023SJohn Marino static rtx expand_builtin_next_arg (void);
108e4b17023SJohn Marino static rtx expand_builtin_va_start (tree);
109e4b17023SJohn Marino static rtx expand_builtin_va_end (tree);
110e4b17023SJohn Marino static rtx expand_builtin_va_copy (tree);
111e4b17023SJohn Marino static rtx expand_builtin_memcmp (tree, rtx, enum machine_mode);
112e4b17023SJohn Marino static rtx expand_builtin_strcmp (tree, rtx);
113e4b17023SJohn Marino static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
114e4b17023SJohn Marino static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
115e4b17023SJohn Marino static rtx expand_builtin_memcpy (tree, rtx);
116e4b17023SJohn Marino static rtx expand_builtin_mempcpy (tree, rtx, enum machine_mode);
117e4b17023SJohn Marino static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx,
118e4b17023SJohn Marino enum machine_mode, int);
119e4b17023SJohn Marino static rtx expand_builtin_strcpy (tree, rtx);
120e4b17023SJohn Marino static rtx expand_builtin_strcpy_args (tree, tree, rtx);
121e4b17023SJohn Marino static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
122e4b17023SJohn Marino static rtx expand_builtin_strncpy (tree, rtx);
123e4b17023SJohn Marino static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, enum machine_mode);
124e4b17023SJohn Marino static rtx expand_builtin_memset (tree, rtx, enum machine_mode);
125e4b17023SJohn Marino static rtx expand_builtin_memset_args (tree, tree, tree, rtx, enum machine_mode, tree);
126e4b17023SJohn Marino static rtx expand_builtin_bzero (tree);
127e4b17023SJohn Marino static rtx expand_builtin_strlen (tree, rtx, enum machine_mode);
128e4b17023SJohn Marino static rtx expand_builtin_alloca (tree, bool);
129e4b17023SJohn Marino static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
130e4b17023SJohn Marino static rtx expand_builtin_frame_address (tree, tree);
131e4b17023SJohn Marino static tree stabilize_va_list_loc (location_t, tree, int);
132e4b17023SJohn Marino static rtx expand_builtin_expect (tree, rtx);
133e4b17023SJohn Marino static tree fold_builtin_constant_p (tree);
134e4b17023SJohn Marino static tree fold_builtin_expect (location_t, tree, tree);
135e4b17023SJohn Marino static tree fold_builtin_classify_type (tree);
136e4b17023SJohn Marino static tree fold_builtin_strlen (location_t, tree, tree);
137e4b17023SJohn Marino static tree fold_builtin_inf (location_t, tree, int);
138e4b17023SJohn Marino static tree fold_builtin_nan (tree, tree, int);
139e4b17023SJohn Marino static tree rewrite_call_expr (location_t, tree, int, tree, int, ...);
140e4b17023SJohn Marino static bool validate_arg (const_tree, enum tree_code code);
141e4b17023SJohn Marino static bool integer_valued_real_p (tree);
142e4b17023SJohn Marino static tree fold_trunc_transparent_mathfn (location_t, tree, tree);
143e4b17023SJohn Marino static bool readonly_data_expr (tree);
144e4b17023SJohn Marino static rtx expand_builtin_fabs (tree, rtx, rtx);
145e4b17023SJohn Marino static rtx expand_builtin_signbit (tree, rtx);
146e4b17023SJohn Marino static tree fold_builtin_sqrt (location_t, tree, tree);
147e4b17023SJohn Marino static tree fold_builtin_cbrt (location_t, tree, tree);
148e4b17023SJohn Marino static tree fold_builtin_pow (location_t, tree, tree, tree, tree);
149e4b17023SJohn Marino static tree fold_builtin_powi (location_t, tree, tree, tree, tree);
150e4b17023SJohn Marino static tree fold_builtin_cos (location_t, tree, tree, tree);
151e4b17023SJohn Marino static tree fold_builtin_cosh (location_t, tree, tree, tree);
152e4b17023SJohn Marino static tree fold_builtin_tan (tree, tree);
153e4b17023SJohn Marino static tree fold_builtin_trunc (location_t, tree, tree);
154e4b17023SJohn Marino static tree fold_builtin_floor (location_t, tree, tree);
155e4b17023SJohn Marino static tree fold_builtin_ceil (location_t, tree, tree);
156e4b17023SJohn Marino static tree fold_builtin_round (location_t, tree, tree);
157e4b17023SJohn Marino static tree fold_builtin_int_roundingfn (location_t, tree, tree);
158e4b17023SJohn Marino static tree fold_builtin_bitop (tree, tree);
159e4b17023SJohn Marino static tree fold_builtin_memory_op (location_t, tree, tree, tree, tree, bool, int);
160e4b17023SJohn Marino static tree fold_builtin_strchr (location_t, tree, tree, tree);
161e4b17023SJohn Marino static tree fold_builtin_memchr (location_t, tree, tree, tree, tree);
162e4b17023SJohn Marino static tree fold_builtin_memcmp (location_t, tree, tree, tree);
163e4b17023SJohn Marino static tree fold_builtin_strcmp (location_t, tree, tree);
164e4b17023SJohn Marino static tree fold_builtin_strncmp (location_t, tree, tree, tree);
165e4b17023SJohn Marino static tree fold_builtin_signbit (location_t, tree, tree);
166e4b17023SJohn Marino static tree fold_builtin_copysign (location_t, tree, tree, tree, tree);
167e4b17023SJohn Marino static tree fold_builtin_isascii (location_t, tree);
168e4b17023SJohn Marino static tree fold_builtin_toascii (location_t, tree);
169e4b17023SJohn Marino static tree fold_builtin_isdigit (location_t, tree);
170e4b17023SJohn Marino static tree fold_builtin_fabs (location_t, tree, tree);
171e4b17023SJohn Marino static tree fold_builtin_abs (location_t, tree, tree);
172e4b17023SJohn Marino static tree fold_builtin_unordered_cmp (location_t, tree, tree, tree, enum tree_code,
173e4b17023SJohn Marino enum tree_code);
174e4b17023SJohn Marino static tree fold_builtin_n (location_t, tree, tree *, int, bool);
175e4b17023SJohn Marino static tree fold_builtin_0 (location_t, tree, bool);
176e4b17023SJohn Marino static tree fold_builtin_1 (location_t, tree, tree, bool);
177e4b17023SJohn Marino static tree fold_builtin_2 (location_t, tree, tree, tree, bool);
178e4b17023SJohn Marino static tree fold_builtin_3 (location_t, tree, tree, tree, tree, bool);
179e4b17023SJohn Marino static tree fold_builtin_4 (location_t, tree, tree, tree, tree, tree, bool);
180e4b17023SJohn Marino static tree fold_builtin_varargs (location_t, tree, tree, bool);
181e4b17023SJohn Marino
182e4b17023SJohn Marino static tree fold_builtin_strpbrk (location_t, tree, tree, tree);
183e4b17023SJohn Marino static tree fold_builtin_strstr (location_t, tree, tree, tree);
184e4b17023SJohn Marino static tree fold_builtin_strrchr (location_t, tree, tree, tree);
185e4b17023SJohn Marino static tree fold_builtin_strcat (location_t, tree, tree);
186e4b17023SJohn Marino static tree fold_builtin_strncat (location_t, tree, tree, tree);
187e4b17023SJohn Marino static tree fold_builtin_strspn (location_t, tree, tree);
188e4b17023SJohn Marino static tree fold_builtin_strcspn (location_t, tree, tree);
189e4b17023SJohn Marino static tree fold_builtin_sprintf (location_t, tree, tree, tree, int);
190e4b17023SJohn Marino static tree fold_builtin_snprintf (location_t, tree, tree, tree, tree, int);
191e4b17023SJohn Marino
192e4b17023SJohn Marino static rtx expand_builtin_object_size (tree);
193e4b17023SJohn Marino static rtx expand_builtin_memory_chk (tree, rtx, enum machine_mode,
194e4b17023SJohn Marino enum built_in_function);
195e4b17023SJohn Marino static void maybe_emit_chk_warning (tree, enum built_in_function);
196e4b17023SJohn Marino static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function);
197e4b17023SJohn Marino static void maybe_emit_free_warning (tree);
198e4b17023SJohn Marino static tree fold_builtin_object_size (tree, tree);
199e4b17023SJohn Marino static tree fold_builtin_strcat_chk (location_t, tree, tree, tree, tree);
200e4b17023SJohn Marino static tree fold_builtin_strncat_chk (location_t, tree, tree, tree, tree, tree);
201e4b17023SJohn Marino static tree fold_builtin_sprintf_chk (location_t, tree, enum built_in_function);
202e4b17023SJohn Marino static tree fold_builtin_printf (location_t, tree, tree, tree, bool, enum built_in_function);
203e4b17023SJohn Marino static tree fold_builtin_fprintf (location_t, tree, tree, tree, tree, bool,
204e4b17023SJohn Marino enum built_in_function);
205e4b17023SJohn Marino static bool init_target_chars (void);
206e4b17023SJohn Marino
207e4b17023SJohn Marino static unsigned HOST_WIDE_INT target_newline;
208e4b17023SJohn Marino static unsigned HOST_WIDE_INT target_percent;
209e4b17023SJohn Marino static unsigned HOST_WIDE_INT target_c;
210e4b17023SJohn Marino static unsigned HOST_WIDE_INT target_s;
211e4b17023SJohn Marino static char target_percent_c[3];
212e4b17023SJohn Marino static char target_percent_s[3];
213e4b17023SJohn Marino static char target_percent_s_newline[4];
214e4b17023SJohn Marino static tree do_mpfr_arg1 (tree, tree, int (*)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
215e4b17023SJohn Marino const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, bool);
216e4b17023SJohn Marino static tree do_mpfr_arg2 (tree, tree, tree,
217e4b17023SJohn Marino int (*)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t));
218e4b17023SJohn Marino static tree do_mpfr_arg3 (tree, tree, tree, tree,
219e4b17023SJohn Marino int (*)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t));
220e4b17023SJohn Marino static tree do_mpfr_sincos (tree, tree, tree);
221e4b17023SJohn Marino static tree do_mpfr_bessel_n (tree, tree, tree,
222e4b17023SJohn Marino int (*)(mpfr_ptr, long, mpfr_srcptr, mp_rnd_t),
223e4b17023SJohn Marino const REAL_VALUE_TYPE *, bool);
224e4b17023SJohn Marino static tree do_mpfr_remquo (tree, tree, tree);
225e4b17023SJohn Marino static tree do_mpfr_lgamma_r (tree, tree, tree);
226e4b17023SJohn Marino static void expand_builtin_sync_synchronize (void);
227e4b17023SJohn Marino
228e4b17023SJohn Marino /* Return true if NAME starts with __builtin_ or __sync_. */
229e4b17023SJohn Marino
230e4b17023SJohn Marino static bool
is_builtin_name(const char * name)231e4b17023SJohn Marino is_builtin_name (const char *name)
232e4b17023SJohn Marino {
233e4b17023SJohn Marino if (strncmp (name, "__builtin_", 10) == 0)
234e4b17023SJohn Marino return true;
235e4b17023SJohn Marino if (strncmp (name, "__sync_", 7) == 0)
236e4b17023SJohn Marino return true;
237e4b17023SJohn Marino if (strncmp (name, "__atomic_", 9) == 0)
238e4b17023SJohn Marino return true;
239e4b17023SJohn Marino return false;
240e4b17023SJohn Marino }
241e4b17023SJohn Marino
242e4b17023SJohn Marino
243e4b17023SJohn Marino /* Return true if DECL is a function symbol representing a built-in. */
244e4b17023SJohn Marino
245e4b17023SJohn Marino bool
is_builtin_fn(tree decl)246e4b17023SJohn Marino is_builtin_fn (tree decl)
247e4b17023SJohn Marino {
248e4b17023SJohn Marino return TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl);
249e4b17023SJohn Marino }
250e4b17023SJohn Marino
251e4b17023SJohn Marino
252e4b17023SJohn Marino /* Return true if NODE should be considered for inline expansion regardless
253e4b17023SJohn Marino of the optimization level. This means whenever a function is invoked with
254e4b17023SJohn Marino its "internal" name, which normally contains the prefix "__builtin". */
255e4b17023SJohn Marino
256e4b17023SJohn Marino static bool
called_as_built_in(tree node)257e4b17023SJohn Marino called_as_built_in (tree node)
258e4b17023SJohn Marino {
259e4b17023SJohn Marino /* Note that we must use DECL_NAME, not DECL_ASSEMBLER_NAME_SET_P since
260e4b17023SJohn Marino we want the name used to call the function, not the name it
261e4b17023SJohn Marino will have. */
262e4b17023SJohn Marino const char *name = IDENTIFIER_POINTER (DECL_NAME (node));
263e4b17023SJohn Marino return is_builtin_name (name);
264e4b17023SJohn Marino }
265e4b17023SJohn Marino
266e4b17023SJohn Marino /* Compute values M and N such that M divides (address of EXP - N) and
267e4b17023SJohn Marino such that N < M. Store N in *BITPOSP and return M.
268e4b17023SJohn Marino
269e4b17023SJohn Marino Note that the address (and thus the alignment) computed here is based
270e4b17023SJohn Marino on the address to which a symbol resolves, whereas DECL_ALIGN is based
271e4b17023SJohn Marino on the address at which an object is actually located. These two
272e4b17023SJohn Marino addresses are not always the same. For example, on ARM targets,
273e4b17023SJohn Marino the address &foo of a Thumb function foo() has the lowest bit set,
274e4b17023SJohn Marino whereas foo() itself starts on an even address. */
275e4b17023SJohn Marino
276e4b17023SJohn Marino unsigned int
get_object_alignment_1(tree exp,unsigned HOST_WIDE_INT * bitposp)277e4b17023SJohn Marino get_object_alignment_1 (tree exp, unsigned HOST_WIDE_INT *bitposp)
278e4b17023SJohn Marino {
279e4b17023SJohn Marino HOST_WIDE_INT bitsize, bitpos;
280e4b17023SJohn Marino tree offset;
281e4b17023SJohn Marino enum machine_mode mode;
282e4b17023SJohn Marino int unsignedp, volatilep;
283e4b17023SJohn Marino unsigned int align, inner;
284e4b17023SJohn Marino
285e4b17023SJohn Marino /* Get the innermost object and the constant (bitpos) and possibly
286e4b17023SJohn Marino variable (offset) offset of the access. */
287e4b17023SJohn Marino exp = get_inner_reference (exp, &bitsize, &bitpos, &offset,
288e4b17023SJohn Marino &mode, &unsignedp, &volatilep, true);
289e4b17023SJohn Marino
290e4b17023SJohn Marino /* Extract alignment information from the innermost object and
291e4b17023SJohn Marino possibly adjust bitpos and offset. */
292e4b17023SJohn Marino if (TREE_CODE (exp) == CONST_DECL)
293e4b17023SJohn Marino exp = DECL_INITIAL (exp);
294e4b17023SJohn Marino if (DECL_P (exp)
295e4b17023SJohn Marino && TREE_CODE (exp) != LABEL_DECL)
296e4b17023SJohn Marino {
297e4b17023SJohn Marino if (TREE_CODE (exp) == FUNCTION_DECL)
298e4b17023SJohn Marino {
299e4b17023SJohn Marino /* Function addresses can encode extra information besides their
300e4b17023SJohn Marino alignment. However, if TARGET_PTRMEMFUNC_VBIT_LOCATION
301e4b17023SJohn Marino allows the low bit to be used as a virtual bit, we know
302e4b17023SJohn Marino that the address itself must be 2-byte aligned. */
303e4b17023SJohn Marino if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn)
304e4b17023SJohn Marino align = 2 * BITS_PER_UNIT;
305e4b17023SJohn Marino else
306e4b17023SJohn Marino align = BITS_PER_UNIT;
307e4b17023SJohn Marino }
308e4b17023SJohn Marino else
309e4b17023SJohn Marino align = DECL_ALIGN (exp);
310e4b17023SJohn Marino }
311e4b17023SJohn Marino else if (CONSTANT_CLASS_P (exp))
312e4b17023SJohn Marino {
313e4b17023SJohn Marino align = TYPE_ALIGN (TREE_TYPE (exp));
314e4b17023SJohn Marino #ifdef CONSTANT_ALIGNMENT
315e4b17023SJohn Marino align = (unsigned)CONSTANT_ALIGNMENT (exp, align);
316e4b17023SJohn Marino #endif
317e4b17023SJohn Marino }
318e4b17023SJohn Marino else if (TREE_CODE (exp) == VIEW_CONVERT_EXPR)
319e4b17023SJohn Marino align = TYPE_ALIGN (TREE_TYPE (exp));
320e4b17023SJohn Marino else if (TREE_CODE (exp) == INDIRECT_REF)
321e4b17023SJohn Marino align = TYPE_ALIGN (TREE_TYPE (exp));
322e4b17023SJohn Marino else if (TREE_CODE (exp) == MEM_REF)
323e4b17023SJohn Marino {
324e4b17023SJohn Marino tree addr = TREE_OPERAND (exp, 0);
325e4b17023SJohn Marino struct ptr_info_def *pi;
326e4b17023SJohn Marino if (TREE_CODE (addr) == BIT_AND_EXPR
327e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
328e4b17023SJohn Marino {
329e4b17023SJohn Marino align = (TREE_INT_CST_LOW (TREE_OPERAND (addr, 1))
330e4b17023SJohn Marino & -TREE_INT_CST_LOW (TREE_OPERAND (addr, 1)));
331e4b17023SJohn Marino align *= BITS_PER_UNIT;
332e4b17023SJohn Marino addr = TREE_OPERAND (addr, 0);
333e4b17023SJohn Marino }
334e4b17023SJohn Marino else
335e4b17023SJohn Marino align = BITS_PER_UNIT;
336e4b17023SJohn Marino if (TREE_CODE (addr) == SSA_NAME
337e4b17023SJohn Marino && (pi = SSA_NAME_PTR_INFO (addr)))
338e4b17023SJohn Marino {
339e4b17023SJohn Marino bitpos += (pi->misalign * BITS_PER_UNIT) & ~(align - 1);
340e4b17023SJohn Marino align = MAX (pi->align * BITS_PER_UNIT, align);
341e4b17023SJohn Marino }
342e4b17023SJohn Marino else if (TREE_CODE (addr) == ADDR_EXPR)
343e4b17023SJohn Marino align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0)));
344e4b17023SJohn Marino bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT;
345e4b17023SJohn Marino }
346e4b17023SJohn Marino else if (TREE_CODE (exp) == TARGET_MEM_REF)
347e4b17023SJohn Marino {
348e4b17023SJohn Marino struct ptr_info_def *pi;
349e4b17023SJohn Marino tree addr = TMR_BASE (exp);
350e4b17023SJohn Marino if (TREE_CODE (addr) == BIT_AND_EXPR
351e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
352e4b17023SJohn Marino {
353e4b17023SJohn Marino align = (TREE_INT_CST_LOW (TREE_OPERAND (addr, 1))
354e4b17023SJohn Marino & -TREE_INT_CST_LOW (TREE_OPERAND (addr, 1)));
355e4b17023SJohn Marino align *= BITS_PER_UNIT;
356e4b17023SJohn Marino addr = TREE_OPERAND (addr, 0);
357e4b17023SJohn Marino }
358e4b17023SJohn Marino else
359e4b17023SJohn Marino align = BITS_PER_UNIT;
360e4b17023SJohn Marino if (TREE_CODE (addr) == SSA_NAME
361e4b17023SJohn Marino && (pi = SSA_NAME_PTR_INFO (addr)))
362e4b17023SJohn Marino {
363e4b17023SJohn Marino bitpos += (pi->misalign * BITS_PER_UNIT) & ~(align - 1);
364e4b17023SJohn Marino align = MAX (pi->align * BITS_PER_UNIT, align);
365e4b17023SJohn Marino }
366e4b17023SJohn Marino else if (TREE_CODE (addr) == ADDR_EXPR)
367e4b17023SJohn Marino align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0)));
368e4b17023SJohn Marino if (TMR_OFFSET (exp))
369e4b17023SJohn Marino bitpos += TREE_INT_CST_LOW (TMR_OFFSET (exp)) * BITS_PER_UNIT;
370e4b17023SJohn Marino if (TMR_INDEX (exp) && TMR_STEP (exp))
371e4b17023SJohn Marino {
372e4b17023SJohn Marino unsigned HOST_WIDE_INT step = TREE_INT_CST_LOW (TMR_STEP (exp));
373e4b17023SJohn Marino align = MIN (align, (step & -step) * BITS_PER_UNIT);
374e4b17023SJohn Marino }
375e4b17023SJohn Marino else if (TMR_INDEX (exp))
376e4b17023SJohn Marino align = BITS_PER_UNIT;
377e4b17023SJohn Marino if (TMR_INDEX2 (exp))
378e4b17023SJohn Marino align = BITS_PER_UNIT;
379e4b17023SJohn Marino }
380e4b17023SJohn Marino else
381e4b17023SJohn Marino align = BITS_PER_UNIT;
382e4b17023SJohn Marino
383e4b17023SJohn Marino /* If there is a non-constant offset part extract the maximum
384e4b17023SJohn Marino alignment that can prevail. */
385e4b17023SJohn Marino inner = ~0U;
386e4b17023SJohn Marino while (offset)
387e4b17023SJohn Marino {
388e4b17023SJohn Marino tree next_offset;
389e4b17023SJohn Marino
390e4b17023SJohn Marino if (TREE_CODE (offset) == PLUS_EXPR)
391e4b17023SJohn Marino {
392e4b17023SJohn Marino next_offset = TREE_OPERAND (offset, 0);
393e4b17023SJohn Marino offset = TREE_OPERAND (offset, 1);
394e4b17023SJohn Marino }
395e4b17023SJohn Marino else
396e4b17023SJohn Marino next_offset = NULL;
397e4b17023SJohn Marino if (host_integerp (offset, 1))
398e4b17023SJohn Marino {
399e4b17023SJohn Marino /* Any overflow in calculating offset_bits won't change
400e4b17023SJohn Marino the alignment. */
401e4b17023SJohn Marino unsigned offset_bits
402e4b17023SJohn Marino = ((unsigned) tree_low_cst (offset, 1) * BITS_PER_UNIT);
403e4b17023SJohn Marino
404e4b17023SJohn Marino if (offset_bits)
405e4b17023SJohn Marino inner = MIN (inner, (offset_bits & -offset_bits));
406e4b17023SJohn Marino }
407e4b17023SJohn Marino else if (TREE_CODE (offset) == MULT_EXPR
408e4b17023SJohn Marino && host_integerp (TREE_OPERAND (offset, 1), 1))
409e4b17023SJohn Marino {
410e4b17023SJohn Marino /* Any overflow in calculating offset_factor won't change
411e4b17023SJohn Marino the alignment. */
412e4b17023SJohn Marino unsigned offset_factor
413e4b17023SJohn Marino = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
414e4b17023SJohn Marino * BITS_PER_UNIT);
415e4b17023SJohn Marino
416e4b17023SJohn Marino if (offset_factor)
417e4b17023SJohn Marino inner = MIN (inner, (offset_factor & -offset_factor));
418e4b17023SJohn Marino }
419e4b17023SJohn Marino else
420e4b17023SJohn Marino {
421e4b17023SJohn Marino inner = MIN (inner, BITS_PER_UNIT);
422e4b17023SJohn Marino break;
423e4b17023SJohn Marino }
424e4b17023SJohn Marino offset = next_offset;
425e4b17023SJohn Marino }
426e4b17023SJohn Marino
427e4b17023SJohn Marino /* Alignment is innermost object alignment adjusted by the constant
428e4b17023SJohn Marino and non-constant offset parts. */
429e4b17023SJohn Marino align = MIN (align, inner);
430e4b17023SJohn Marino bitpos = bitpos & (align - 1);
431e4b17023SJohn Marino
432e4b17023SJohn Marino *bitposp = bitpos;
433e4b17023SJohn Marino return align;
434e4b17023SJohn Marino }
435e4b17023SJohn Marino
436e4b17023SJohn Marino /* Return the alignment in bits of EXP, an object. */
437e4b17023SJohn Marino
438e4b17023SJohn Marino unsigned int
get_object_alignment(tree exp)439e4b17023SJohn Marino get_object_alignment (tree exp)
440e4b17023SJohn Marino {
441e4b17023SJohn Marino unsigned HOST_WIDE_INT bitpos = 0;
442e4b17023SJohn Marino unsigned int align;
443e4b17023SJohn Marino
444e4b17023SJohn Marino align = get_object_alignment_1 (exp, &bitpos);
445e4b17023SJohn Marino
446e4b17023SJohn Marino /* align and bitpos now specify known low bits of the pointer.
447e4b17023SJohn Marino ptr & (align - 1) == bitpos. */
448e4b17023SJohn Marino
449e4b17023SJohn Marino if (bitpos != 0)
450e4b17023SJohn Marino align = (bitpos & -bitpos);
451e4b17023SJohn Marino
452e4b17023SJohn Marino return align;
453e4b17023SJohn Marino }
454e4b17023SJohn Marino
455e4b17023SJohn Marino /* Return the alignment of object EXP, also considering its type when we do
456e4b17023SJohn Marino not know of explicit misalignment. Only handle MEM_REF and TARGET_MEM_REF.
457e4b17023SJohn Marino
458e4b17023SJohn Marino ??? Note that, in the general case, the type of an expression is not kept
459e4b17023SJohn Marino consistent with misalignment information by the front-end, for example when
460e4b17023SJohn Marino taking the address of a member of a packed structure. However, in most of
461e4b17023SJohn Marino the cases, expressions have the alignment of their type so we optimistically
462e4b17023SJohn Marino fall back to this alignment when we cannot compute a misalignment. */
463e4b17023SJohn Marino
464e4b17023SJohn Marino unsigned int
get_object_or_type_alignment(tree exp)465e4b17023SJohn Marino get_object_or_type_alignment (tree exp)
466e4b17023SJohn Marino {
467e4b17023SJohn Marino unsigned HOST_WIDE_INT misalign;
468e4b17023SJohn Marino unsigned int align = get_object_alignment_1 (exp, &misalign);
469e4b17023SJohn Marino
470e4b17023SJohn Marino gcc_assert (TREE_CODE (exp) == MEM_REF || TREE_CODE (exp) == TARGET_MEM_REF);
471e4b17023SJohn Marino
472e4b17023SJohn Marino if (misalign != 0)
473e4b17023SJohn Marino align = (misalign & -misalign);
474e4b17023SJohn Marino else
475e4b17023SJohn Marino align = MAX (TYPE_ALIGN (TREE_TYPE (exp)), align);
476e4b17023SJohn Marino
477e4b17023SJohn Marino return align;
478e4b17023SJohn Marino }
479e4b17023SJohn Marino
480e4b17023SJohn Marino /* For a pointer valued expression EXP compute values M and N such that
481e4b17023SJohn Marino M divides (EXP - N) and such that N < M. Store N in *BITPOSP and return M.
482e4b17023SJohn Marino
483e4b17023SJohn Marino If EXP is not a pointer, 0 is returned. */
484e4b17023SJohn Marino
485e4b17023SJohn Marino unsigned int
get_pointer_alignment_1(tree exp,unsigned HOST_WIDE_INT * bitposp)486e4b17023SJohn Marino get_pointer_alignment_1 (tree exp, unsigned HOST_WIDE_INT *bitposp)
487e4b17023SJohn Marino {
488e4b17023SJohn Marino STRIP_NOPS (exp);
489e4b17023SJohn Marino
490e4b17023SJohn Marino if (TREE_CODE (exp) == ADDR_EXPR)
491e4b17023SJohn Marino return get_object_alignment_1 (TREE_OPERAND (exp, 0), bitposp);
492e4b17023SJohn Marino else if (TREE_CODE (exp) == SSA_NAME
493e4b17023SJohn Marino && POINTER_TYPE_P (TREE_TYPE (exp)))
494e4b17023SJohn Marino {
495e4b17023SJohn Marino struct ptr_info_def *pi = SSA_NAME_PTR_INFO (exp);
496e4b17023SJohn Marino if (!pi)
497e4b17023SJohn Marino {
498e4b17023SJohn Marino *bitposp = 0;
499e4b17023SJohn Marino return BITS_PER_UNIT;
500e4b17023SJohn Marino }
501e4b17023SJohn Marino *bitposp = pi->misalign * BITS_PER_UNIT;
502e4b17023SJohn Marino return pi->align * BITS_PER_UNIT;
503e4b17023SJohn Marino }
504e4b17023SJohn Marino
505e4b17023SJohn Marino *bitposp = 0;
506e4b17023SJohn Marino return POINTER_TYPE_P (TREE_TYPE (exp)) ? BITS_PER_UNIT : 0;
507e4b17023SJohn Marino }
508e4b17023SJohn Marino
509e4b17023SJohn Marino /* Return the alignment in bits of EXP, a pointer valued expression.
510e4b17023SJohn Marino The alignment returned is, by default, the alignment of the thing that
511e4b17023SJohn Marino EXP points to. If it is not a POINTER_TYPE, 0 is returned.
512e4b17023SJohn Marino
513e4b17023SJohn Marino Otherwise, look at the expression to see if we can do better, i.e., if the
514e4b17023SJohn Marino expression is actually pointing at an object whose alignment is tighter. */
515e4b17023SJohn Marino
516e4b17023SJohn Marino unsigned int
get_pointer_alignment(tree exp)517e4b17023SJohn Marino get_pointer_alignment (tree exp)
518e4b17023SJohn Marino {
519e4b17023SJohn Marino unsigned HOST_WIDE_INT bitpos = 0;
520e4b17023SJohn Marino unsigned int align;
521e4b17023SJohn Marino
522e4b17023SJohn Marino align = get_pointer_alignment_1 (exp, &bitpos);
523e4b17023SJohn Marino
524e4b17023SJohn Marino /* align and bitpos now specify known low bits of the pointer.
525e4b17023SJohn Marino ptr & (align - 1) == bitpos. */
526e4b17023SJohn Marino
527e4b17023SJohn Marino if (bitpos != 0)
528e4b17023SJohn Marino align = (bitpos & -bitpos);
529e4b17023SJohn Marino
530e4b17023SJohn Marino return align;
531e4b17023SJohn Marino }
532e4b17023SJohn Marino
533e4b17023SJohn Marino /* Compute the length of a C string. TREE_STRING_LENGTH is not the right
534e4b17023SJohn Marino way, because it could contain a zero byte in the middle.
535e4b17023SJohn Marino TREE_STRING_LENGTH is the size of the character array, not the string.
536e4b17023SJohn Marino
537e4b17023SJohn Marino ONLY_VALUE should be nonzero if the result is not going to be emitted
538e4b17023SJohn Marino into the instruction stream and zero if it is going to be expanded.
539e4b17023SJohn Marino E.g. with i++ ? "foo" : "bar", if ONLY_VALUE is nonzero, constant 3
540e4b17023SJohn Marino is returned, otherwise NULL, since
541e4b17023SJohn Marino len = c_strlen (src, 1); if (len) expand_expr (len, ...); would not
542e4b17023SJohn Marino evaluate the side-effects.
543e4b17023SJohn Marino
544e4b17023SJohn Marino The value returned is of type `ssizetype'.
545e4b17023SJohn Marino
546e4b17023SJohn Marino Unfortunately, string_constant can't access the values of const char
547e4b17023SJohn Marino arrays with initializers, so neither can we do so here. */
548e4b17023SJohn Marino
549e4b17023SJohn Marino tree
c_strlen(tree src,int only_value)550e4b17023SJohn Marino c_strlen (tree src, int only_value)
551e4b17023SJohn Marino {
552e4b17023SJohn Marino tree offset_node;
553e4b17023SJohn Marino HOST_WIDE_INT offset;
554e4b17023SJohn Marino int max;
555e4b17023SJohn Marino const char *ptr;
556e4b17023SJohn Marino location_t loc;
557e4b17023SJohn Marino
558e4b17023SJohn Marino STRIP_NOPS (src);
559e4b17023SJohn Marino if (TREE_CODE (src) == COND_EXPR
560e4b17023SJohn Marino && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
561e4b17023SJohn Marino {
562e4b17023SJohn Marino tree len1, len2;
563e4b17023SJohn Marino
564e4b17023SJohn Marino len1 = c_strlen (TREE_OPERAND (src, 1), only_value);
565e4b17023SJohn Marino len2 = c_strlen (TREE_OPERAND (src, 2), only_value);
566e4b17023SJohn Marino if (tree_int_cst_equal (len1, len2))
567e4b17023SJohn Marino return len1;
568e4b17023SJohn Marino }
569e4b17023SJohn Marino
570e4b17023SJohn Marino if (TREE_CODE (src) == COMPOUND_EXPR
571e4b17023SJohn Marino && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
572e4b17023SJohn Marino return c_strlen (TREE_OPERAND (src, 1), only_value);
573e4b17023SJohn Marino
574e4b17023SJohn Marino loc = EXPR_LOC_OR_HERE (src);
575e4b17023SJohn Marino
576e4b17023SJohn Marino src = string_constant (src, &offset_node);
577e4b17023SJohn Marino if (src == 0)
578e4b17023SJohn Marino return NULL_TREE;
579e4b17023SJohn Marino
580e4b17023SJohn Marino max = TREE_STRING_LENGTH (src) - 1;
581e4b17023SJohn Marino ptr = TREE_STRING_POINTER (src);
582e4b17023SJohn Marino
583e4b17023SJohn Marino if (offset_node && TREE_CODE (offset_node) != INTEGER_CST)
584e4b17023SJohn Marino {
585e4b17023SJohn Marino /* If the string has an internal zero byte (e.g., "foo\0bar"), we can't
586e4b17023SJohn Marino compute the offset to the following null if we don't know where to
587e4b17023SJohn Marino start searching for it. */
588e4b17023SJohn Marino int i;
589e4b17023SJohn Marino
590e4b17023SJohn Marino for (i = 0; i < max; i++)
591e4b17023SJohn Marino if (ptr[i] == 0)
592e4b17023SJohn Marino return NULL_TREE;
593e4b17023SJohn Marino
594e4b17023SJohn Marino /* We don't know the starting offset, but we do know that the string
595e4b17023SJohn Marino has no internal zero bytes. We can assume that the offset falls
596e4b17023SJohn Marino within the bounds of the string; otherwise, the programmer deserves
597e4b17023SJohn Marino what he gets. Subtract the offset from the length of the string,
598e4b17023SJohn Marino and return that. This would perhaps not be valid if we were dealing
599e4b17023SJohn Marino with named arrays in addition to literal string constants. */
600e4b17023SJohn Marino
601e4b17023SJohn Marino return size_diffop_loc (loc, size_int (max), offset_node);
602e4b17023SJohn Marino }
603e4b17023SJohn Marino
604e4b17023SJohn Marino /* We have a known offset into the string. Start searching there for
605e4b17023SJohn Marino a null character if we can represent it as a single HOST_WIDE_INT. */
606e4b17023SJohn Marino if (offset_node == 0)
607e4b17023SJohn Marino offset = 0;
608e4b17023SJohn Marino else if (! host_integerp (offset_node, 0))
609e4b17023SJohn Marino offset = -1;
610e4b17023SJohn Marino else
611e4b17023SJohn Marino offset = tree_low_cst (offset_node, 0);
612e4b17023SJohn Marino
613e4b17023SJohn Marino /* If the offset is known to be out of bounds, warn, and call strlen at
614e4b17023SJohn Marino runtime. */
615e4b17023SJohn Marino if (offset < 0 || offset > max)
616e4b17023SJohn Marino {
617e4b17023SJohn Marino /* Suppress multiple warnings for propagated constant strings. */
618e4b17023SJohn Marino if (! TREE_NO_WARNING (src))
619e4b17023SJohn Marino {
620e4b17023SJohn Marino warning_at (loc, 0, "offset outside bounds of constant string");
621e4b17023SJohn Marino TREE_NO_WARNING (src) = 1;
622e4b17023SJohn Marino }
623e4b17023SJohn Marino return NULL_TREE;
624e4b17023SJohn Marino }
625e4b17023SJohn Marino
626e4b17023SJohn Marino /* Use strlen to search for the first zero byte. Since any strings
627e4b17023SJohn Marino constructed with build_string will have nulls appended, we win even
628e4b17023SJohn Marino if we get handed something like (char[4])"abcd".
629e4b17023SJohn Marino
630e4b17023SJohn Marino Since OFFSET is our starting index into the string, no further
631e4b17023SJohn Marino calculation is needed. */
632e4b17023SJohn Marino return ssize_int (strlen (ptr + offset));
633e4b17023SJohn Marino }
634e4b17023SJohn Marino
635e4b17023SJohn Marino /* Return a char pointer for a C string if it is a string constant
636e4b17023SJohn Marino or sum of string constant and integer constant. */
637e4b17023SJohn Marino
638e4b17023SJohn Marino static const char *
c_getstr(tree src)639e4b17023SJohn Marino c_getstr (tree src)
640e4b17023SJohn Marino {
641e4b17023SJohn Marino tree offset_node;
642e4b17023SJohn Marino
643e4b17023SJohn Marino src = string_constant (src, &offset_node);
644e4b17023SJohn Marino if (src == 0)
645e4b17023SJohn Marino return 0;
646e4b17023SJohn Marino
647e4b17023SJohn Marino if (offset_node == 0)
648e4b17023SJohn Marino return TREE_STRING_POINTER (src);
649e4b17023SJohn Marino else if (!host_integerp (offset_node, 1)
650e4b17023SJohn Marino || compare_tree_int (offset_node, TREE_STRING_LENGTH (src) - 1) > 0)
651e4b17023SJohn Marino return 0;
652e4b17023SJohn Marino
653e4b17023SJohn Marino return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
654e4b17023SJohn Marino }
655e4b17023SJohn Marino
656e4b17023SJohn Marino /* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
657e4b17023SJohn Marino GET_MODE_BITSIZE (MODE) bits from string constant STR. */
658e4b17023SJohn Marino
659e4b17023SJohn Marino static rtx
c_readstr(const char * str,enum machine_mode mode)660e4b17023SJohn Marino c_readstr (const char *str, enum machine_mode mode)
661e4b17023SJohn Marino {
662e4b17023SJohn Marino HOST_WIDE_INT c[2];
663e4b17023SJohn Marino HOST_WIDE_INT ch;
664e4b17023SJohn Marino unsigned int i, j;
665e4b17023SJohn Marino
666e4b17023SJohn Marino gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
667e4b17023SJohn Marino
668e4b17023SJohn Marino c[0] = 0;
669e4b17023SJohn Marino c[1] = 0;
670e4b17023SJohn Marino ch = 1;
671e4b17023SJohn Marino for (i = 0; i < GET_MODE_SIZE (mode); i++)
672e4b17023SJohn Marino {
673e4b17023SJohn Marino j = i;
674e4b17023SJohn Marino if (WORDS_BIG_ENDIAN)
675e4b17023SJohn Marino j = GET_MODE_SIZE (mode) - i - 1;
676e4b17023SJohn Marino if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
677e4b17023SJohn Marino && GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
678e4b17023SJohn Marino j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
679e4b17023SJohn Marino j *= BITS_PER_UNIT;
680e4b17023SJohn Marino gcc_assert (j < 2 * HOST_BITS_PER_WIDE_INT);
681e4b17023SJohn Marino
682e4b17023SJohn Marino if (ch)
683e4b17023SJohn Marino ch = (unsigned char) str[i];
684e4b17023SJohn Marino c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
685e4b17023SJohn Marino }
686e4b17023SJohn Marino return immed_double_const (c[0], c[1], mode);
687e4b17023SJohn Marino }
688e4b17023SJohn Marino
689e4b17023SJohn Marino /* Cast a target constant CST to target CHAR and if that value fits into
690e4b17023SJohn Marino host char type, return zero and put that value into variable pointed to by
691e4b17023SJohn Marino P. */
692e4b17023SJohn Marino
693e4b17023SJohn Marino static int
target_char_cast(tree cst,char * p)694e4b17023SJohn Marino target_char_cast (tree cst, char *p)
695e4b17023SJohn Marino {
696e4b17023SJohn Marino unsigned HOST_WIDE_INT val, hostval;
697e4b17023SJohn Marino
698e4b17023SJohn Marino if (TREE_CODE (cst) != INTEGER_CST
699e4b17023SJohn Marino || CHAR_TYPE_SIZE > HOST_BITS_PER_WIDE_INT)
700e4b17023SJohn Marino return 1;
701e4b17023SJohn Marino
702e4b17023SJohn Marino val = TREE_INT_CST_LOW (cst);
703e4b17023SJohn Marino if (CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT)
704e4b17023SJohn Marino val &= (((unsigned HOST_WIDE_INT) 1) << CHAR_TYPE_SIZE) - 1;
705e4b17023SJohn Marino
706e4b17023SJohn Marino hostval = val;
707e4b17023SJohn Marino if (HOST_BITS_PER_CHAR < HOST_BITS_PER_WIDE_INT)
708e4b17023SJohn Marino hostval &= (((unsigned HOST_WIDE_INT) 1) << HOST_BITS_PER_CHAR) - 1;
709e4b17023SJohn Marino
710e4b17023SJohn Marino if (val != hostval)
711e4b17023SJohn Marino return 1;
712e4b17023SJohn Marino
713e4b17023SJohn Marino *p = hostval;
714e4b17023SJohn Marino return 0;
715e4b17023SJohn Marino }
716e4b17023SJohn Marino
717e4b17023SJohn Marino /* Similar to save_expr, but assumes that arbitrary code is not executed
718e4b17023SJohn Marino in between the multiple evaluations. In particular, we assume that a
719e4b17023SJohn Marino non-addressable local variable will not be modified. */
720e4b17023SJohn Marino
721e4b17023SJohn Marino static tree
builtin_save_expr(tree exp)722e4b17023SJohn Marino builtin_save_expr (tree exp)
723e4b17023SJohn Marino {
724e4b17023SJohn Marino if (TREE_CODE (exp) == SSA_NAME
725e4b17023SJohn Marino || (TREE_ADDRESSABLE (exp) == 0
726e4b17023SJohn Marino && (TREE_CODE (exp) == PARM_DECL
727e4b17023SJohn Marino || (TREE_CODE (exp) == VAR_DECL && !TREE_STATIC (exp)))))
728e4b17023SJohn Marino return exp;
729e4b17023SJohn Marino
730e4b17023SJohn Marino return save_expr (exp);
731e4b17023SJohn Marino }
732e4b17023SJohn Marino
733e4b17023SJohn Marino /* Given TEM, a pointer to a stack frame, follow the dynamic chain COUNT
734e4b17023SJohn Marino times to get the address of either a higher stack frame, or a return
735e4b17023SJohn Marino address located within it (depending on FNDECL_CODE). */
736e4b17023SJohn Marino
737e4b17023SJohn Marino static rtx
expand_builtin_return_addr(enum built_in_function fndecl_code,int count)738e4b17023SJohn Marino expand_builtin_return_addr (enum built_in_function fndecl_code, int count)
739e4b17023SJohn Marino {
740e4b17023SJohn Marino int i;
741e4b17023SJohn Marino
742e4b17023SJohn Marino #ifdef INITIAL_FRAME_ADDRESS_RTX
743e4b17023SJohn Marino rtx tem = INITIAL_FRAME_ADDRESS_RTX;
744e4b17023SJohn Marino #else
745e4b17023SJohn Marino rtx tem;
746e4b17023SJohn Marino
747e4b17023SJohn Marino /* For a zero count with __builtin_return_address, we don't care what
748e4b17023SJohn Marino frame address we return, because target-specific definitions will
749e4b17023SJohn Marino override us. Therefore frame pointer elimination is OK, and using
750e4b17023SJohn Marino the soft frame pointer is OK.
751e4b17023SJohn Marino
752e4b17023SJohn Marino For a nonzero count, or a zero count with __builtin_frame_address,
753e4b17023SJohn Marino we require a stable offset from the current frame pointer to the
754e4b17023SJohn Marino previous one, so we must use the hard frame pointer, and
755e4b17023SJohn Marino we must disable frame pointer elimination. */
756e4b17023SJohn Marino if (count == 0 && fndecl_code == BUILT_IN_RETURN_ADDRESS)
757e4b17023SJohn Marino tem = frame_pointer_rtx;
758e4b17023SJohn Marino else
759e4b17023SJohn Marino {
760e4b17023SJohn Marino tem = hard_frame_pointer_rtx;
761e4b17023SJohn Marino
762e4b17023SJohn Marino /* Tell reload not to eliminate the frame pointer. */
763e4b17023SJohn Marino crtl->accesses_prior_frames = 1;
764e4b17023SJohn Marino }
765e4b17023SJohn Marino #endif
766e4b17023SJohn Marino
767e4b17023SJohn Marino /* Some machines need special handling before we can access
768e4b17023SJohn Marino arbitrary frames. For example, on the SPARC, we must first flush
769e4b17023SJohn Marino all register windows to the stack. */
770e4b17023SJohn Marino #ifdef SETUP_FRAME_ADDRESSES
771e4b17023SJohn Marino if (count > 0)
772e4b17023SJohn Marino SETUP_FRAME_ADDRESSES ();
773e4b17023SJohn Marino #endif
774e4b17023SJohn Marino
775e4b17023SJohn Marino /* On the SPARC, the return address is not in the frame, it is in a
776e4b17023SJohn Marino register. There is no way to access it off of the current frame
777e4b17023SJohn Marino pointer, but it can be accessed off the previous frame pointer by
778e4b17023SJohn Marino reading the value from the register window save area. */
779e4b17023SJohn Marino #ifdef RETURN_ADDR_IN_PREVIOUS_FRAME
780e4b17023SJohn Marino if (fndecl_code == BUILT_IN_RETURN_ADDRESS)
781e4b17023SJohn Marino count--;
782e4b17023SJohn Marino #endif
783e4b17023SJohn Marino
784e4b17023SJohn Marino /* Scan back COUNT frames to the specified frame. */
785e4b17023SJohn Marino for (i = 0; i < count; i++)
786e4b17023SJohn Marino {
787e4b17023SJohn Marino /* Assume the dynamic chain pointer is in the word that the
788e4b17023SJohn Marino frame address points to, unless otherwise specified. */
789e4b17023SJohn Marino #ifdef DYNAMIC_CHAIN_ADDRESS
790e4b17023SJohn Marino tem = DYNAMIC_CHAIN_ADDRESS (tem);
791e4b17023SJohn Marino #endif
792e4b17023SJohn Marino tem = memory_address (Pmode, tem);
793e4b17023SJohn Marino tem = gen_frame_mem (Pmode, tem);
794e4b17023SJohn Marino tem = copy_to_reg (tem);
795e4b17023SJohn Marino }
796e4b17023SJohn Marino
797e4b17023SJohn Marino /* For __builtin_frame_address, return what we've got. But, on
798e4b17023SJohn Marino the SPARC for example, we may have to add a bias. */
799e4b17023SJohn Marino if (fndecl_code == BUILT_IN_FRAME_ADDRESS)
800e4b17023SJohn Marino #ifdef FRAME_ADDR_RTX
801e4b17023SJohn Marino return FRAME_ADDR_RTX (tem);
802e4b17023SJohn Marino #else
803e4b17023SJohn Marino return tem;
804e4b17023SJohn Marino #endif
805e4b17023SJohn Marino
806e4b17023SJohn Marino /* For __builtin_return_address, get the return address from that frame. */
807e4b17023SJohn Marino #ifdef RETURN_ADDR_RTX
808e4b17023SJohn Marino tem = RETURN_ADDR_RTX (count, tem);
809e4b17023SJohn Marino #else
810e4b17023SJohn Marino tem = memory_address (Pmode,
811e4b17023SJohn Marino plus_constant (tem, GET_MODE_SIZE (Pmode)));
812e4b17023SJohn Marino tem = gen_frame_mem (Pmode, tem);
813e4b17023SJohn Marino #endif
814e4b17023SJohn Marino return tem;
815e4b17023SJohn Marino }
816e4b17023SJohn Marino
817e4b17023SJohn Marino /* Alias set used for setjmp buffer. */
818e4b17023SJohn Marino static alias_set_type setjmp_alias_set = -1;
819e4b17023SJohn Marino
820e4b17023SJohn Marino /* Construct the leading half of a __builtin_setjmp call. Control will
821e4b17023SJohn Marino return to RECEIVER_LABEL. This is also called directly by the SJLJ
822e4b17023SJohn Marino exception handling code. */
823e4b17023SJohn Marino
824e4b17023SJohn Marino void
expand_builtin_setjmp_setup(rtx buf_addr,rtx receiver_label)825e4b17023SJohn Marino expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
826e4b17023SJohn Marino {
827e4b17023SJohn Marino enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
828e4b17023SJohn Marino rtx stack_save;
829e4b17023SJohn Marino rtx mem;
830e4b17023SJohn Marino
831e4b17023SJohn Marino if (setjmp_alias_set == -1)
832e4b17023SJohn Marino setjmp_alias_set = new_alias_set ();
833e4b17023SJohn Marino
834e4b17023SJohn Marino buf_addr = convert_memory_address (Pmode, buf_addr);
835e4b17023SJohn Marino
836e4b17023SJohn Marino buf_addr = force_reg (Pmode, force_operand (buf_addr, NULL_RTX));
837e4b17023SJohn Marino
838e4b17023SJohn Marino /* We store the frame pointer and the address of receiver_label in
839e4b17023SJohn Marino the buffer and use the rest of it for the stack save area, which
840e4b17023SJohn Marino is machine-dependent. */
841e4b17023SJohn Marino
842e4b17023SJohn Marino mem = gen_rtx_MEM (Pmode, buf_addr);
843e4b17023SJohn Marino set_mem_alias_set (mem, setjmp_alias_set);
844e4b17023SJohn Marino emit_move_insn (mem, targetm.builtin_setjmp_frame_value ());
845e4b17023SJohn Marino
846e4b17023SJohn Marino mem = gen_rtx_MEM (Pmode, plus_constant (buf_addr, GET_MODE_SIZE (Pmode))),
847e4b17023SJohn Marino set_mem_alias_set (mem, setjmp_alias_set);
848e4b17023SJohn Marino
849e4b17023SJohn Marino emit_move_insn (validize_mem (mem),
850e4b17023SJohn Marino force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, receiver_label)));
851e4b17023SJohn Marino
852e4b17023SJohn Marino stack_save = gen_rtx_MEM (sa_mode,
853e4b17023SJohn Marino plus_constant (buf_addr,
854e4b17023SJohn Marino 2 * GET_MODE_SIZE (Pmode)));
855e4b17023SJohn Marino set_mem_alias_set (stack_save, setjmp_alias_set);
856e4b17023SJohn Marino emit_stack_save (SAVE_NONLOCAL, &stack_save);
857e4b17023SJohn Marino
858e4b17023SJohn Marino /* If there is further processing to do, do it. */
859e4b17023SJohn Marino #ifdef HAVE_builtin_setjmp_setup
860e4b17023SJohn Marino if (HAVE_builtin_setjmp_setup)
861e4b17023SJohn Marino emit_insn (gen_builtin_setjmp_setup (buf_addr));
862e4b17023SJohn Marino #endif
863e4b17023SJohn Marino
864e4b17023SJohn Marino /* We have a nonlocal label. */
865e4b17023SJohn Marino cfun->has_nonlocal_label = 1;
866e4b17023SJohn Marino }
867e4b17023SJohn Marino
868e4b17023SJohn Marino /* Construct the trailing part of a __builtin_setjmp call. This is
869e4b17023SJohn Marino also called directly by the SJLJ exception handling code. */
870e4b17023SJohn Marino
871e4b17023SJohn Marino void
expand_builtin_setjmp_receiver(rtx receiver_label ATTRIBUTE_UNUSED)872e4b17023SJohn Marino expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
873e4b17023SJohn Marino {
874e4b17023SJohn Marino rtx chain;
875e4b17023SJohn Marino
876e4b17023SJohn Marino /* Clobber the FP when we get here, so we have to make sure it's
877e4b17023SJohn Marino marked as used by this function. */
878e4b17023SJohn Marino emit_use (hard_frame_pointer_rtx);
879e4b17023SJohn Marino
880e4b17023SJohn Marino /* Mark the static chain as clobbered here so life information
881e4b17023SJohn Marino doesn't get messed up for it. */
882e4b17023SJohn Marino chain = targetm.calls.static_chain (current_function_decl, true);
883e4b17023SJohn Marino if (chain && REG_P (chain))
884e4b17023SJohn Marino emit_clobber (chain);
885e4b17023SJohn Marino
886e4b17023SJohn Marino /* Now put in the code to restore the frame pointer, and argument
887e4b17023SJohn Marino pointer, if needed. */
888e4b17023SJohn Marino #ifdef HAVE_nonlocal_goto
889e4b17023SJohn Marino if (! HAVE_nonlocal_goto)
890e4b17023SJohn Marino #endif
891e4b17023SJohn Marino {
892e4b17023SJohn Marino emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
893e4b17023SJohn Marino /* This might change the hard frame pointer in ways that aren't
894e4b17023SJohn Marino apparent to early optimization passes, so force a clobber. */
895e4b17023SJohn Marino emit_clobber (hard_frame_pointer_rtx);
896e4b17023SJohn Marino }
897e4b17023SJohn Marino
898e4b17023SJohn Marino #if !HARD_FRAME_POINTER_IS_ARG_POINTER
899e4b17023SJohn Marino if (fixed_regs[ARG_POINTER_REGNUM])
900e4b17023SJohn Marino {
901e4b17023SJohn Marino #ifdef ELIMINABLE_REGS
902e4b17023SJohn Marino size_t i;
903e4b17023SJohn Marino static const struct elims {const int from, to;} elim_regs[] = ELIMINABLE_REGS;
904e4b17023SJohn Marino
905e4b17023SJohn Marino for (i = 0; i < ARRAY_SIZE (elim_regs); i++)
906e4b17023SJohn Marino if (elim_regs[i].from == ARG_POINTER_REGNUM
907e4b17023SJohn Marino && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
908e4b17023SJohn Marino break;
909e4b17023SJohn Marino
910e4b17023SJohn Marino if (i == ARRAY_SIZE (elim_regs))
911e4b17023SJohn Marino #endif
912e4b17023SJohn Marino {
913e4b17023SJohn Marino /* Now restore our arg pointer from the address at which it
914e4b17023SJohn Marino was saved in our stack frame. */
915e4b17023SJohn Marino emit_move_insn (crtl->args.internal_arg_pointer,
916e4b17023SJohn Marino copy_to_reg (get_arg_pointer_save_area ()));
917e4b17023SJohn Marino }
918e4b17023SJohn Marino }
919e4b17023SJohn Marino #endif
920e4b17023SJohn Marino
921e4b17023SJohn Marino #ifdef HAVE_builtin_setjmp_receiver
922e4b17023SJohn Marino if (HAVE_builtin_setjmp_receiver)
923e4b17023SJohn Marino emit_insn (gen_builtin_setjmp_receiver (receiver_label));
924e4b17023SJohn Marino else
925e4b17023SJohn Marino #endif
926e4b17023SJohn Marino #ifdef HAVE_nonlocal_goto_receiver
927e4b17023SJohn Marino if (HAVE_nonlocal_goto_receiver)
928e4b17023SJohn Marino emit_insn (gen_nonlocal_goto_receiver ());
929e4b17023SJohn Marino else
930e4b17023SJohn Marino #endif
931e4b17023SJohn Marino { /* Nothing */ }
932e4b17023SJohn Marino
933e4b17023SJohn Marino /* We must not allow the code we just generated to be reordered by
934e4b17023SJohn Marino scheduling. Specifically, the update of the frame pointer must
935e4b17023SJohn Marino happen immediately, not later. */
936e4b17023SJohn Marino emit_insn (gen_blockage ());
937e4b17023SJohn Marino }
938e4b17023SJohn Marino
939e4b17023SJohn Marino /* __builtin_longjmp is passed a pointer to an array of five words (not
940e4b17023SJohn Marino all will be used on all machines). It operates similarly to the C
941e4b17023SJohn Marino library function of the same name, but is more efficient. Much of
942e4b17023SJohn Marino the code below is copied from the handling of non-local gotos. */
943e4b17023SJohn Marino
944e4b17023SJohn Marino static void
expand_builtin_longjmp(rtx buf_addr,rtx value)945e4b17023SJohn Marino expand_builtin_longjmp (rtx buf_addr, rtx value)
946e4b17023SJohn Marino {
947e4b17023SJohn Marino rtx fp, lab, stack, insn, last;
948e4b17023SJohn Marino enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
949e4b17023SJohn Marino
950e4b17023SJohn Marino /* DRAP is needed for stack realign if longjmp is expanded to current
951e4b17023SJohn Marino function */
952e4b17023SJohn Marino if (SUPPORTS_STACK_ALIGNMENT)
953e4b17023SJohn Marino crtl->need_drap = true;
954e4b17023SJohn Marino
955e4b17023SJohn Marino if (setjmp_alias_set == -1)
956e4b17023SJohn Marino setjmp_alias_set = new_alias_set ();
957e4b17023SJohn Marino
958e4b17023SJohn Marino buf_addr = convert_memory_address (Pmode, buf_addr);
959e4b17023SJohn Marino
960e4b17023SJohn Marino buf_addr = force_reg (Pmode, buf_addr);
961e4b17023SJohn Marino
962e4b17023SJohn Marino /* We require that the user must pass a second argument of 1, because
963e4b17023SJohn Marino that is what builtin_setjmp will return. */
964e4b17023SJohn Marino gcc_assert (value == const1_rtx);
965e4b17023SJohn Marino
966e4b17023SJohn Marino last = get_last_insn ();
967e4b17023SJohn Marino #ifdef HAVE_builtin_longjmp
968e4b17023SJohn Marino if (HAVE_builtin_longjmp)
969e4b17023SJohn Marino emit_insn (gen_builtin_longjmp (buf_addr));
970e4b17023SJohn Marino else
971e4b17023SJohn Marino #endif
972e4b17023SJohn Marino {
973e4b17023SJohn Marino fp = gen_rtx_MEM (Pmode, buf_addr);
974e4b17023SJohn Marino lab = gen_rtx_MEM (Pmode, plus_constant (buf_addr,
975e4b17023SJohn Marino GET_MODE_SIZE (Pmode)));
976e4b17023SJohn Marino
977e4b17023SJohn Marino stack = gen_rtx_MEM (sa_mode, plus_constant (buf_addr,
978e4b17023SJohn Marino 2 * GET_MODE_SIZE (Pmode)));
979e4b17023SJohn Marino set_mem_alias_set (fp, setjmp_alias_set);
980e4b17023SJohn Marino set_mem_alias_set (lab, setjmp_alias_set);
981e4b17023SJohn Marino set_mem_alias_set (stack, setjmp_alias_set);
982e4b17023SJohn Marino
983e4b17023SJohn Marino /* Pick up FP, label, and SP from the block and jump. This code is
984e4b17023SJohn Marino from expand_goto in stmt.c; see there for detailed comments. */
985e4b17023SJohn Marino #ifdef HAVE_nonlocal_goto
986e4b17023SJohn Marino if (HAVE_nonlocal_goto)
987e4b17023SJohn Marino /* We have to pass a value to the nonlocal_goto pattern that will
988e4b17023SJohn Marino get copied into the static_chain pointer, but it does not matter
989e4b17023SJohn Marino what that value is, because builtin_setjmp does not use it. */
990e4b17023SJohn Marino emit_insn (gen_nonlocal_goto (value, lab, stack, fp));
991e4b17023SJohn Marino else
992e4b17023SJohn Marino #endif
993e4b17023SJohn Marino {
994e4b17023SJohn Marino lab = copy_to_reg (lab);
995e4b17023SJohn Marino
996e4b17023SJohn Marino emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
997e4b17023SJohn Marino emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
998e4b17023SJohn Marino
999e4b17023SJohn Marino emit_move_insn (hard_frame_pointer_rtx, fp);
1000e4b17023SJohn Marino emit_stack_restore (SAVE_NONLOCAL, stack);
1001e4b17023SJohn Marino
1002e4b17023SJohn Marino emit_use (hard_frame_pointer_rtx);
1003e4b17023SJohn Marino emit_use (stack_pointer_rtx);
1004e4b17023SJohn Marino emit_indirect_jump (lab);
1005e4b17023SJohn Marino }
1006e4b17023SJohn Marino }
1007e4b17023SJohn Marino
1008e4b17023SJohn Marino /* Search backwards and mark the jump insn as a non-local goto.
1009e4b17023SJohn Marino Note that this precludes the use of __builtin_longjmp to a
1010e4b17023SJohn Marino __builtin_setjmp target in the same function. However, we've
1011e4b17023SJohn Marino already cautioned the user that these functions are for
1012e4b17023SJohn Marino internal exception handling use only. */
1013e4b17023SJohn Marino for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
1014e4b17023SJohn Marino {
1015e4b17023SJohn Marino gcc_assert (insn != last);
1016e4b17023SJohn Marino
1017e4b17023SJohn Marino if (JUMP_P (insn))
1018e4b17023SJohn Marino {
1019e4b17023SJohn Marino add_reg_note (insn, REG_NON_LOCAL_GOTO, const0_rtx);
1020e4b17023SJohn Marino break;
1021e4b17023SJohn Marino }
1022e4b17023SJohn Marino else if (CALL_P (insn))
1023e4b17023SJohn Marino break;
1024e4b17023SJohn Marino }
1025e4b17023SJohn Marino }
1026e4b17023SJohn Marino
1027e4b17023SJohn Marino /* Expand a call to __builtin_nonlocal_goto. We're passed the target label
1028e4b17023SJohn Marino and the address of the save area. */
1029e4b17023SJohn Marino
1030e4b17023SJohn Marino static rtx
expand_builtin_nonlocal_goto(tree exp)1031e4b17023SJohn Marino expand_builtin_nonlocal_goto (tree exp)
1032e4b17023SJohn Marino {
1033e4b17023SJohn Marino tree t_label, t_save_area;
1034e4b17023SJohn Marino rtx r_label, r_save_area, r_fp, r_sp, insn;
1035e4b17023SJohn Marino
1036e4b17023SJohn Marino if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
1037e4b17023SJohn Marino return NULL_RTX;
1038e4b17023SJohn Marino
1039e4b17023SJohn Marino t_label = CALL_EXPR_ARG (exp, 0);
1040e4b17023SJohn Marino t_save_area = CALL_EXPR_ARG (exp, 1);
1041e4b17023SJohn Marino
1042e4b17023SJohn Marino r_label = expand_normal (t_label);
1043e4b17023SJohn Marino r_label = convert_memory_address (Pmode, r_label);
1044e4b17023SJohn Marino r_save_area = expand_normal (t_save_area);
1045e4b17023SJohn Marino r_save_area = convert_memory_address (Pmode, r_save_area);
1046e4b17023SJohn Marino /* Copy the address of the save location to a register just in case it was
1047e4b17023SJohn Marino based on the frame pointer. */
1048e4b17023SJohn Marino r_save_area = copy_to_reg (r_save_area);
1049e4b17023SJohn Marino r_fp = gen_rtx_MEM (Pmode, r_save_area);
1050e4b17023SJohn Marino r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL),
1051e4b17023SJohn Marino plus_constant (r_save_area, GET_MODE_SIZE (Pmode)));
1052e4b17023SJohn Marino
1053e4b17023SJohn Marino crtl->has_nonlocal_goto = 1;
1054e4b17023SJohn Marino
1055e4b17023SJohn Marino #ifdef HAVE_nonlocal_goto
1056e4b17023SJohn Marino /* ??? We no longer need to pass the static chain value, afaik. */
1057e4b17023SJohn Marino if (HAVE_nonlocal_goto)
1058e4b17023SJohn Marino emit_insn (gen_nonlocal_goto (const0_rtx, r_label, r_sp, r_fp));
1059e4b17023SJohn Marino else
1060e4b17023SJohn Marino #endif
1061e4b17023SJohn Marino {
1062e4b17023SJohn Marino r_label = copy_to_reg (r_label);
1063e4b17023SJohn Marino
1064e4b17023SJohn Marino emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
1065e4b17023SJohn Marino emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
1066e4b17023SJohn Marino
1067e4b17023SJohn Marino /* Restore frame pointer for containing function. */
1068e4b17023SJohn Marino emit_move_insn (hard_frame_pointer_rtx, r_fp);
1069e4b17023SJohn Marino emit_stack_restore (SAVE_NONLOCAL, r_sp);
1070e4b17023SJohn Marino
1071e4b17023SJohn Marino /* USE of hard_frame_pointer_rtx added for consistency;
1072e4b17023SJohn Marino not clear if really needed. */
1073e4b17023SJohn Marino emit_use (hard_frame_pointer_rtx);
1074e4b17023SJohn Marino emit_use (stack_pointer_rtx);
1075e4b17023SJohn Marino
1076e4b17023SJohn Marino /* If the architecture is using a GP register, we must
1077e4b17023SJohn Marino conservatively assume that the target function makes use of it.
1078e4b17023SJohn Marino The prologue of functions with nonlocal gotos must therefore
1079e4b17023SJohn Marino initialize the GP register to the appropriate value, and we
1080e4b17023SJohn Marino must then make sure that this value is live at the point
1081e4b17023SJohn Marino of the jump. (Note that this doesn't necessarily apply
1082e4b17023SJohn Marino to targets with a nonlocal_goto pattern; they are free
1083e4b17023SJohn Marino to implement it in their own way. Note also that this is
1084e4b17023SJohn Marino a no-op if the GP register is a global invariant.) */
1085e4b17023SJohn Marino if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
1086e4b17023SJohn Marino && fixed_regs[PIC_OFFSET_TABLE_REGNUM])
1087e4b17023SJohn Marino emit_use (pic_offset_table_rtx);
1088e4b17023SJohn Marino
1089e4b17023SJohn Marino emit_indirect_jump (r_label);
1090e4b17023SJohn Marino }
1091e4b17023SJohn Marino
1092e4b17023SJohn Marino /* Search backwards to the jump insn and mark it as a
1093e4b17023SJohn Marino non-local goto. */
1094e4b17023SJohn Marino for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
1095e4b17023SJohn Marino {
1096e4b17023SJohn Marino if (JUMP_P (insn))
1097e4b17023SJohn Marino {
1098e4b17023SJohn Marino add_reg_note (insn, REG_NON_LOCAL_GOTO, const0_rtx);
1099e4b17023SJohn Marino break;
1100e4b17023SJohn Marino }
1101e4b17023SJohn Marino else if (CALL_P (insn))
1102e4b17023SJohn Marino break;
1103e4b17023SJohn Marino }
1104e4b17023SJohn Marino
1105e4b17023SJohn Marino return const0_rtx;
1106e4b17023SJohn Marino }
1107e4b17023SJohn Marino
1108e4b17023SJohn Marino /* __builtin_update_setjmp_buf is passed a pointer to an array of five words
1109e4b17023SJohn Marino (not all will be used on all machines) that was passed to __builtin_setjmp.
1110e4b17023SJohn Marino It updates the stack pointer in that block to correspond to the current
1111e4b17023SJohn Marino stack pointer. */
1112e4b17023SJohn Marino
1113e4b17023SJohn Marino static void
expand_builtin_update_setjmp_buf(rtx buf_addr)1114e4b17023SJohn Marino expand_builtin_update_setjmp_buf (rtx buf_addr)
1115e4b17023SJohn Marino {
1116e4b17023SJohn Marino enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
1117e4b17023SJohn Marino rtx stack_save
1118e4b17023SJohn Marino = gen_rtx_MEM (sa_mode,
1119e4b17023SJohn Marino memory_address
1120e4b17023SJohn Marino (sa_mode,
1121e4b17023SJohn Marino plus_constant (buf_addr, 2 * GET_MODE_SIZE (Pmode))));
1122e4b17023SJohn Marino
1123e4b17023SJohn Marino emit_stack_save (SAVE_NONLOCAL, &stack_save);
1124e4b17023SJohn Marino }
1125e4b17023SJohn Marino
1126e4b17023SJohn Marino /* Expand a call to __builtin_prefetch. For a target that does not support
1127e4b17023SJohn Marino data prefetch, evaluate the memory address argument in case it has side
1128e4b17023SJohn Marino effects. */
1129e4b17023SJohn Marino
1130e4b17023SJohn Marino static void
expand_builtin_prefetch(tree exp)1131e4b17023SJohn Marino expand_builtin_prefetch (tree exp)
1132e4b17023SJohn Marino {
1133e4b17023SJohn Marino tree arg0, arg1, arg2;
1134e4b17023SJohn Marino int nargs;
1135e4b17023SJohn Marino rtx op0, op1, op2;
1136e4b17023SJohn Marino
1137e4b17023SJohn Marino if (!validate_arglist (exp, POINTER_TYPE, 0))
1138e4b17023SJohn Marino return;
1139e4b17023SJohn Marino
1140e4b17023SJohn Marino arg0 = CALL_EXPR_ARG (exp, 0);
1141e4b17023SJohn Marino
1142e4b17023SJohn Marino /* Arguments 1 and 2 are optional; argument 1 (read/write) defaults to
1143e4b17023SJohn Marino zero (read) and argument 2 (locality) defaults to 3 (high degree of
1144e4b17023SJohn Marino locality). */
1145e4b17023SJohn Marino nargs = call_expr_nargs (exp);
1146e4b17023SJohn Marino if (nargs > 1)
1147e4b17023SJohn Marino arg1 = CALL_EXPR_ARG (exp, 1);
1148e4b17023SJohn Marino else
1149e4b17023SJohn Marino arg1 = integer_zero_node;
1150e4b17023SJohn Marino if (nargs > 2)
1151e4b17023SJohn Marino arg2 = CALL_EXPR_ARG (exp, 2);
1152e4b17023SJohn Marino else
1153e4b17023SJohn Marino arg2 = integer_three_node;
1154e4b17023SJohn Marino
1155e4b17023SJohn Marino /* Argument 0 is an address. */
1156e4b17023SJohn Marino op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
1157e4b17023SJohn Marino
1158e4b17023SJohn Marino /* Argument 1 (read/write flag) must be a compile-time constant int. */
1159e4b17023SJohn Marino if (TREE_CODE (arg1) != INTEGER_CST)
1160e4b17023SJohn Marino {
1161e4b17023SJohn Marino error ("second argument to %<__builtin_prefetch%> must be a constant");
1162e4b17023SJohn Marino arg1 = integer_zero_node;
1163e4b17023SJohn Marino }
1164e4b17023SJohn Marino op1 = expand_normal (arg1);
1165e4b17023SJohn Marino /* Argument 1 must be either zero or one. */
1166e4b17023SJohn Marino if (INTVAL (op1) != 0 && INTVAL (op1) != 1)
1167e4b17023SJohn Marino {
1168e4b17023SJohn Marino warning (0, "invalid second argument to %<__builtin_prefetch%>;"
1169e4b17023SJohn Marino " using zero");
1170e4b17023SJohn Marino op1 = const0_rtx;
1171e4b17023SJohn Marino }
1172e4b17023SJohn Marino
1173e4b17023SJohn Marino /* Argument 2 (locality) must be a compile-time constant int. */
1174e4b17023SJohn Marino if (TREE_CODE (arg2) != INTEGER_CST)
1175e4b17023SJohn Marino {
1176e4b17023SJohn Marino error ("third argument to %<__builtin_prefetch%> must be a constant");
1177e4b17023SJohn Marino arg2 = integer_zero_node;
1178e4b17023SJohn Marino }
1179e4b17023SJohn Marino op2 = expand_normal (arg2);
1180e4b17023SJohn Marino /* Argument 2 must be 0, 1, 2, or 3. */
1181e4b17023SJohn Marino if (INTVAL (op2) < 0 || INTVAL (op2) > 3)
1182e4b17023SJohn Marino {
1183e4b17023SJohn Marino warning (0, "invalid third argument to %<__builtin_prefetch%>; using zero");
1184e4b17023SJohn Marino op2 = const0_rtx;
1185e4b17023SJohn Marino }
1186e4b17023SJohn Marino
1187e4b17023SJohn Marino #ifdef HAVE_prefetch
1188e4b17023SJohn Marino if (HAVE_prefetch)
1189e4b17023SJohn Marino {
1190e4b17023SJohn Marino struct expand_operand ops[3];
1191e4b17023SJohn Marino
1192e4b17023SJohn Marino create_address_operand (&ops[0], op0);
1193e4b17023SJohn Marino create_integer_operand (&ops[1], INTVAL (op1));
1194e4b17023SJohn Marino create_integer_operand (&ops[2], INTVAL (op2));
1195e4b17023SJohn Marino if (maybe_expand_insn (CODE_FOR_prefetch, 3, ops))
1196e4b17023SJohn Marino return;
1197e4b17023SJohn Marino }
1198e4b17023SJohn Marino #endif
1199e4b17023SJohn Marino
1200e4b17023SJohn Marino /* Don't do anything with direct references to volatile memory, but
1201e4b17023SJohn Marino generate code to handle other side effects. */
1202e4b17023SJohn Marino if (!MEM_P (op0) && side_effects_p (op0))
1203e4b17023SJohn Marino emit_insn (op0);
1204e4b17023SJohn Marino }
1205e4b17023SJohn Marino
1206e4b17023SJohn Marino /* Get a MEM rtx for expression EXP which is the address of an operand
1207e4b17023SJohn Marino to be used in a string instruction (cmpstrsi, movmemsi, ..). LEN is
1208e4b17023SJohn Marino the maximum length of the block of memory that might be accessed or
1209e4b17023SJohn Marino NULL if unknown. */
1210e4b17023SJohn Marino
1211e4b17023SJohn Marino static rtx
get_memory_rtx(tree exp,tree len)1212e4b17023SJohn Marino get_memory_rtx (tree exp, tree len)
1213e4b17023SJohn Marino {
1214e4b17023SJohn Marino tree orig_exp = exp;
1215e4b17023SJohn Marino rtx addr, mem;
1216e4b17023SJohn Marino HOST_WIDE_INT off;
1217e4b17023SJohn Marino
1218e4b17023SJohn Marino /* When EXP is not resolved SAVE_EXPR, MEM_ATTRS can be still derived
1219e4b17023SJohn Marino from its expression, for expr->a.b only <variable>.a.b is recorded. */
1220e4b17023SJohn Marino if (TREE_CODE (exp) == SAVE_EXPR && !SAVE_EXPR_RESOLVED_P (exp))
1221e4b17023SJohn Marino exp = TREE_OPERAND (exp, 0);
1222e4b17023SJohn Marino
1223e4b17023SJohn Marino addr = expand_expr (orig_exp, NULL_RTX, ptr_mode, EXPAND_NORMAL);
1224e4b17023SJohn Marino mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
1225e4b17023SJohn Marino
1226e4b17023SJohn Marino /* Get an expression we can use to find the attributes to assign to MEM.
1227e4b17023SJohn Marino If it is an ADDR_EXPR, use the operand. Otherwise, dereference it if
1228e4b17023SJohn Marino we can. First remove any nops. */
1229e4b17023SJohn Marino while (CONVERT_EXPR_P (exp)
1230e4b17023SJohn Marino && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
1231e4b17023SJohn Marino exp = TREE_OPERAND (exp, 0);
1232e4b17023SJohn Marino
1233e4b17023SJohn Marino off = 0;
1234e4b17023SJohn Marino if (TREE_CODE (exp) == POINTER_PLUS_EXPR
1235e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
1236e4b17023SJohn Marino && host_integerp (TREE_OPERAND (exp, 1), 0)
1237e4b17023SJohn Marino && (off = tree_low_cst (TREE_OPERAND (exp, 1), 0)) > 0)
1238e4b17023SJohn Marino exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
1239e4b17023SJohn Marino else if (TREE_CODE (exp) == ADDR_EXPR)
1240e4b17023SJohn Marino exp = TREE_OPERAND (exp, 0);
1241e4b17023SJohn Marino else if (POINTER_TYPE_P (TREE_TYPE (exp)))
1242e4b17023SJohn Marino exp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (exp)), exp);
1243e4b17023SJohn Marino else
1244e4b17023SJohn Marino exp = NULL;
1245e4b17023SJohn Marino
1246e4b17023SJohn Marino /* Honor attributes derived from exp, except for the alias set
1247e4b17023SJohn Marino (as builtin stringops may alias with anything) and the size
1248e4b17023SJohn Marino (as stringops may access multiple array elements). */
1249e4b17023SJohn Marino if (exp)
1250e4b17023SJohn Marino {
1251e4b17023SJohn Marino set_mem_attributes (mem, exp, 0);
1252e4b17023SJohn Marino
1253e4b17023SJohn Marino if (off)
1254e4b17023SJohn Marino mem = adjust_automodify_address_nv (mem, BLKmode, NULL, off);
1255e4b17023SJohn Marino
1256e4b17023SJohn Marino /* Allow the string and memory builtins to overflow from one
1257e4b17023SJohn Marino field into another, see http://gcc.gnu.org/PR23561.
1258e4b17023SJohn Marino Thus avoid COMPONENT_REFs in MEM_EXPR unless we know the whole
1259e4b17023SJohn Marino memory accessed by the string or memory builtin will fit
1260e4b17023SJohn Marino within the field. */
1261e4b17023SJohn Marino if (MEM_EXPR (mem) && TREE_CODE (MEM_EXPR (mem)) == COMPONENT_REF)
1262e4b17023SJohn Marino {
1263e4b17023SJohn Marino tree mem_expr = MEM_EXPR (mem);
1264e4b17023SJohn Marino HOST_WIDE_INT offset = -1, length = -1;
1265e4b17023SJohn Marino tree inner = exp;
1266e4b17023SJohn Marino
1267e4b17023SJohn Marino while (TREE_CODE (inner) == ARRAY_REF
1268e4b17023SJohn Marino || CONVERT_EXPR_P (inner)
1269e4b17023SJohn Marino || TREE_CODE (inner) == VIEW_CONVERT_EXPR
1270e4b17023SJohn Marino || TREE_CODE (inner) == SAVE_EXPR)
1271e4b17023SJohn Marino inner = TREE_OPERAND (inner, 0);
1272e4b17023SJohn Marino
1273e4b17023SJohn Marino gcc_assert (TREE_CODE (inner) == COMPONENT_REF);
1274e4b17023SJohn Marino
1275e4b17023SJohn Marino if (MEM_OFFSET_KNOWN_P (mem))
1276e4b17023SJohn Marino offset = MEM_OFFSET (mem);
1277e4b17023SJohn Marino
1278e4b17023SJohn Marino if (offset >= 0 && len && host_integerp (len, 0))
1279e4b17023SJohn Marino length = tree_low_cst (len, 0);
1280e4b17023SJohn Marino
1281e4b17023SJohn Marino while (TREE_CODE (inner) == COMPONENT_REF)
1282e4b17023SJohn Marino {
1283e4b17023SJohn Marino tree field = TREE_OPERAND (inner, 1);
1284e4b17023SJohn Marino gcc_assert (TREE_CODE (mem_expr) == COMPONENT_REF);
1285e4b17023SJohn Marino gcc_assert (field == TREE_OPERAND (mem_expr, 1));
1286e4b17023SJohn Marino
1287e4b17023SJohn Marino /* Bitfields are generally not byte-addressable. */
1288e4b17023SJohn Marino gcc_assert (!DECL_BIT_FIELD (field)
1289e4b17023SJohn Marino || ((tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
1290e4b17023SJohn Marino % BITS_PER_UNIT) == 0
1291e4b17023SJohn Marino && host_integerp (DECL_SIZE (field), 0)
1292e4b17023SJohn Marino && (TREE_INT_CST_LOW (DECL_SIZE (field))
1293e4b17023SJohn Marino % BITS_PER_UNIT) == 0));
1294e4b17023SJohn Marino
1295e4b17023SJohn Marino /* If we can prove that the memory starting at XEXP (mem, 0) and
1296e4b17023SJohn Marino ending at XEXP (mem, 0) + LENGTH will fit into this field, we
1297e4b17023SJohn Marino can keep the COMPONENT_REF in MEM_EXPR. But be careful with
1298e4b17023SJohn Marino fields without DECL_SIZE_UNIT like flexible array members. */
1299e4b17023SJohn Marino if (length >= 0
1300e4b17023SJohn Marino && DECL_SIZE_UNIT (field)
1301e4b17023SJohn Marino && host_integerp (DECL_SIZE_UNIT (field), 0))
1302e4b17023SJohn Marino {
1303e4b17023SJohn Marino HOST_WIDE_INT size
1304e4b17023SJohn Marino = TREE_INT_CST_LOW (DECL_SIZE_UNIT (field));
1305e4b17023SJohn Marino if (offset <= size
1306e4b17023SJohn Marino && length <= size
1307e4b17023SJohn Marino && offset + length <= size)
1308e4b17023SJohn Marino break;
1309e4b17023SJohn Marino }
1310e4b17023SJohn Marino
1311e4b17023SJohn Marino if (offset >= 0
1312e4b17023SJohn Marino && host_integerp (DECL_FIELD_OFFSET (field), 0))
1313e4b17023SJohn Marino offset += TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field))
1314e4b17023SJohn Marino + tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
1315e4b17023SJohn Marino / BITS_PER_UNIT;
1316e4b17023SJohn Marino else
1317e4b17023SJohn Marino {
1318e4b17023SJohn Marino offset = -1;
1319e4b17023SJohn Marino length = -1;
1320e4b17023SJohn Marino }
1321e4b17023SJohn Marino
1322e4b17023SJohn Marino mem_expr = TREE_OPERAND (mem_expr, 0);
1323e4b17023SJohn Marino inner = TREE_OPERAND (inner, 0);
1324e4b17023SJohn Marino }
1325e4b17023SJohn Marino
1326e4b17023SJohn Marino if (mem_expr == NULL)
1327e4b17023SJohn Marino offset = -1;
1328e4b17023SJohn Marino if (mem_expr != MEM_EXPR (mem))
1329e4b17023SJohn Marino {
1330e4b17023SJohn Marino set_mem_expr (mem, mem_expr);
1331e4b17023SJohn Marino if (offset >= 0)
1332e4b17023SJohn Marino set_mem_offset (mem, offset);
1333e4b17023SJohn Marino else
1334e4b17023SJohn Marino clear_mem_offset (mem);
1335e4b17023SJohn Marino }
1336e4b17023SJohn Marino }
1337e4b17023SJohn Marino set_mem_alias_set (mem, 0);
1338e4b17023SJohn Marino clear_mem_size (mem);
1339e4b17023SJohn Marino }
1340e4b17023SJohn Marino
1341e4b17023SJohn Marino return mem;
1342e4b17023SJohn Marino }
1343e4b17023SJohn Marino
1344e4b17023SJohn Marino /* Built-in functions to perform an untyped call and return. */
1345e4b17023SJohn Marino
1346e4b17023SJohn Marino #define apply_args_mode \
1347e4b17023SJohn Marino (this_target_builtins->x_apply_args_mode)
1348e4b17023SJohn Marino #define apply_result_mode \
1349e4b17023SJohn Marino (this_target_builtins->x_apply_result_mode)
1350e4b17023SJohn Marino
1351e4b17023SJohn Marino /* Return the size required for the block returned by __builtin_apply_args,
1352e4b17023SJohn Marino and initialize apply_args_mode. */
1353e4b17023SJohn Marino
1354e4b17023SJohn Marino static int
apply_args_size(void)1355e4b17023SJohn Marino apply_args_size (void)
1356e4b17023SJohn Marino {
1357e4b17023SJohn Marino static int size = -1;
1358e4b17023SJohn Marino int align;
1359e4b17023SJohn Marino unsigned int regno;
1360e4b17023SJohn Marino enum machine_mode mode;
1361e4b17023SJohn Marino
1362e4b17023SJohn Marino /* The values computed by this function never change. */
1363e4b17023SJohn Marino if (size < 0)
1364e4b17023SJohn Marino {
1365e4b17023SJohn Marino /* The first value is the incoming arg-pointer. */
1366e4b17023SJohn Marino size = GET_MODE_SIZE (Pmode);
1367e4b17023SJohn Marino
1368e4b17023SJohn Marino /* The second value is the structure value address unless this is
1369e4b17023SJohn Marino passed as an "invisible" first argument. */
1370e4b17023SJohn Marino if (targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 0))
1371e4b17023SJohn Marino size += GET_MODE_SIZE (Pmode);
1372e4b17023SJohn Marino
1373e4b17023SJohn Marino for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1374e4b17023SJohn Marino if (FUNCTION_ARG_REGNO_P (regno))
1375e4b17023SJohn Marino {
1376e4b17023SJohn Marino mode = targetm.calls.get_raw_arg_mode (regno);
1377e4b17023SJohn Marino
1378e4b17023SJohn Marino gcc_assert (mode != VOIDmode);
1379e4b17023SJohn Marino
1380e4b17023SJohn Marino align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1381e4b17023SJohn Marino if (size % align != 0)
1382e4b17023SJohn Marino size = CEIL (size, align) * align;
1383e4b17023SJohn Marino size += GET_MODE_SIZE (mode);
1384e4b17023SJohn Marino apply_args_mode[regno] = mode;
1385e4b17023SJohn Marino }
1386e4b17023SJohn Marino else
1387e4b17023SJohn Marino {
1388e4b17023SJohn Marino apply_args_mode[regno] = VOIDmode;
1389e4b17023SJohn Marino }
1390e4b17023SJohn Marino }
1391e4b17023SJohn Marino return size;
1392e4b17023SJohn Marino }
1393e4b17023SJohn Marino
1394e4b17023SJohn Marino /* Return the size required for the block returned by __builtin_apply,
1395e4b17023SJohn Marino and initialize apply_result_mode. */
1396e4b17023SJohn Marino
1397e4b17023SJohn Marino static int
apply_result_size(void)1398e4b17023SJohn Marino apply_result_size (void)
1399e4b17023SJohn Marino {
1400e4b17023SJohn Marino static int size = -1;
1401e4b17023SJohn Marino int align, regno;
1402e4b17023SJohn Marino enum machine_mode mode;
1403e4b17023SJohn Marino
1404e4b17023SJohn Marino /* The values computed by this function never change. */
1405e4b17023SJohn Marino if (size < 0)
1406e4b17023SJohn Marino {
1407e4b17023SJohn Marino size = 0;
1408e4b17023SJohn Marino
1409e4b17023SJohn Marino for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1410e4b17023SJohn Marino if (targetm.calls.function_value_regno_p (regno))
1411e4b17023SJohn Marino {
1412e4b17023SJohn Marino mode = targetm.calls.get_raw_result_mode (regno);
1413e4b17023SJohn Marino
1414e4b17023SJohn Marino gcc_assert (mode != VOIDmode);
1415e4b17023SJohn Marino
1416e4b17023SJohn Marino align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1417e4b17023SJohn Marino if (size % align != 0)
1418e4b17023SJohn Marino size = CEIL (size, align) * align;
1419e4b17023SJohn Marino size += GET_MODE_SIZE (mode);
1420e4b17023SJohn Marino apply_result_mode[regno] = mode;
1421e4b17023SJohn Marino }
1422e4b17023SJohn Marino else
1423e4b17023SJohn Marino apply_result_mode[regno] = VOIDmode;
1424e4b17023SJohn Marino
1425e4b17023SJohn Marino /* Allow targets that use untyped_call and untyped_return to override
1426e4b17023SJohn Marino the size so that machine-specific information can be stored here. */
1427e4b17023SJohn Marino #ifdef APPLY_RESULT_SIZE
1428e4b17023SJohn Marino size = APPLY_RESULT_SIZE;
1429e4b17023SJohn Marino #endif
1430e4b17023SJohn Marino }
1431e4b17023SJohn Marino return size;
1432e4b17023SJohn Marino }
1433e4b17023SJohn Marino
1434e4b17023SJohn Marino #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
1435e4b17023SJohn Marino /* Create a vector describing the result block RESULT. If SAVEP is true,
1436e4b17023SJohn Marino the result block is used to save the values; otherwise it is used to
1437e4b17023SJohn Marino restore the values. */
1438e4b17023SJohn Marino
1439e4b17023SJohn Marino static rtx
result_vector(int savep,rtx result)1440e4b17023SJohn Marino result_vector (int savep, rtx result)
1441e4b17023SJohn Marino {
1442e4b17023SJohn Marino int regno, size, align, nelts;
1443e4b17023SJohn Marino enum machine_mode mode;
1444e4b17023SJohn Marino rtx reg, mem;
1445e4b17023SJohn Marino rtx *savevec = XALLOCAVEC (rtx, FIRST_PSEUDO_REGISTER);
1446e4b17023SJohn Marino
1447e4b17023SJohn Marino size = nelts = 0;
1448e4b17023SJohn Marino for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1449e4b17023SJohn Marino if ((mode = apply_result_mode[regno]) != VOIDmode)
1450e4b17023SJohn Marino {
1451e4b17023SJohn Marino align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1452e4b17023SJohn Marino if (size % align != 0)
1453e4b17023SJohn Marino size = CEIL (size, align) * align;
1454e4b17023SJohn Marino reg = gen_rtx_REG (mode, savep ? regno : INCOMING_REGNO (regno));
1455e4b17023SJohn Marino mem = adjust_address (result, mode, size);
1456e4b17023SJohn Marino savevec[nelts++] = (savep
1457e4b17023SJohn Marino ? gen_rtx_SET (VOIDmode, mem, reg)
1458e4b17023SJohn Marino : gen_rtx_SET (VOIDmode, reg, mem));
1459e4b17023SJohn Marino size += GET_MODE_SIZE (mode);
1460e4b17023SJohn Marino }
1461e4b17023SJohn Marino return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nelts, savevec));
1462e4b17023SJohn Marino }
1463e4b17023SJohn Marino #endif /* HAVE_untyped_call or HAVE_untyped_return */
1464e4b17023SJohn Marino
1465e4b17023SJohn Marino /* Save the state required to perform an untyped call with the same
1466e4b17023SJohn Marino arguments as were passed to the current function. */
1467e4b17023SJohn Marino
1468e4b17023SJohn Marino static rtx
expand_builtin_apply_args_1(void)1469e4b17023SJohn Marino expand_builtin_apply_args_1 (void)
1470e4b17023SJohn Marino {
1471e4b17023SJohn Marino rtx registers, tem;
1472e4b17023SJohn Marino int size, align, regno;
1473e4b17023SJohn Marino enum machine_mode mode;
1474e4b17023SJohn Marino rtx struct_incoming_value = targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 1);
1475e4b17023SJohn Marino
1476e4b17023SJohn Marino /* Create a block where the arg-pointer, structure value address,
1477e4b17023SJohn Marino and argument registers can be saved. */
1478e4b17023SJohn Marino registers = assign_stack_local (BLKmode, apply_args_size (), -1);
1479e4b17023SJohn Marino
1480e4b17023SJohn Marino /* Walk past the arg-pointer and structure value address. */
1481e4b17023SJohn Marino size = GET_MODE_SIZE (Pmode);
1482e4b17023SJohn Marino if (targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 0))
1483e4b17023SJohn Marino size += GET_MODE_SIZE (Pmode);
1484e4b17023SJohn Marino
1485e4b17023SJohn Marino /* Save each register used in calling a function to the block. */
1486e4b17023SJohn Marino for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1487e4b17023SJohn Marino if ((mode = apply_args_mode[regno]) != VOIDmode)
1488e4b17023SJohn Marino {
1489e4b17023SJohn Marino align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1490e4b17023SJohn Marino if (size % align != 0)
1491e4b17023SJohn Marino size = CEIL (size, align) * align;
1492e4b17023SJohn Marino
1493e4b17023SJohn Marino tem = gen_rtx_REG (mode, INCOMING_REGNO (regno));
1494e4b17023SJohn Marino
1495e4b17023SJohn Marino emit_move_insn (adjust_address (registers, mode, size), tem);
1496e4b17023SJohn Marino size += GET_MODE_SIZE (mode);
1497e4b17023SJohn Marino }
1498e4b17023SJohn Marino
1499e4b17023SJohn Marino /* Save the arg pointer to the block. */
1500e4b17023SJohn Marino tem = copy_to_reg (crtl->args.internal_arg_pointer);
1501e4b17023SJohn Marino #ifdef STACK_GROWS_DOWNWARD
1502e4b17023SJohn Marino /* We need the pointer as the caller actually passed them to us, not
1503e4b17023SJohn Marino as we might have pretended they were passed. Make sure it's a valid
1504e4b17023SJohn Marino operand, as emit_move_insn isn't expected to handle a PLUS. */
1505e4b17023SJohn Marino tem
1506e4b17023SJohn Marino = force_operand (plus_constant (tem, crtl->args.pretend_args_size),
1507e4b17023SJohn Marino NULL_RTX);
1508e4b17023SJohn Marino #endif
1509e4b17023SJohn Marino emit_move_insn (adjust_address (registers, Pmode, 0), tem);
1510e4b17023SJohn Marino
1511e4b17023SJohn Marino size = GET_MODE_SIZE (Pmode);
1512e4b17023SJohn Marino
1513e4b17023SJohn Marino /* Save the structure value address unless this is passed as an
1514e4b17023SJohn Marino "invisible" first argument. */
1515e4b17023SJohn Marino if (struct_incoming_value)
1516e4b17023SJohn Marino {
1517e4b17023SJohn Marino emit_move_insn (adjust_address (registers, Pmode, size),
1518e4b17023SJohn Marino copy_to_reg (struct_incoming_value));
1519e4b17023SJohn Marino size += GET_MODE_SIZE (Pmode);
1520e4b17023SJohn Marino }
1521e4b17023SJohn Marino
1522e4b17023SJohn Marino /* Return the address of the block. */
1523e4b17023SJohn Marino return copy_addr_to_reg (XEXP (registers, 0));
1524e4b17023SJohn Marino }
1525e4b17023SJohn Marino
1526e4b17023SJohn Marino /* __builtin_apply_args returns block of memory allocated on
1527e4b17023SJohn Marino the stack into which is stored the arg pointer, structure
1528e4b17023SJohn Marino value address, static chain, and all the registers that might
1529e4b17023SJohn Marino possibly be used in performing a function call. The code is
1530e4b17023SJohn Marino moved to the start of the function so the incoming values are
1531e4b17023SJohn Marino saved. */
1532e4b17023SJohn Marino
1533e4b17023SJohn Marino static rtx
expand_builtin_apply_args(void)1534e4b17023SJohn Marino expand_builtin_apply_args (void)
1535e4b17023SJohn Marino {
1536e4b17023SJohn Marino /* Don't do __builtin_apply_args more than once in a function.
1537e4b17023SJohn Marino Save the result of the first call and reuse it. */
1538e4b17023SJohn Marino if (apply_args_value != 0)
1539e4b17023SJohn Marino return apply_args_value;
1540e4b17023SJohn Marino {
1541e4b17023SJohn Marino /* When this function is called, it means that registers must be
1542e4b17023SJohn Marino saved on entry to this function. So we migrate the
1543e4b17023SJohn Marino call to the first insn of this function. */
1544e4b17023SJohn Marino rtx temp;
1545e4b17023SJohn Marino rtx seq;
1546e4b17023SJohn Marino
1547e4b17023SJohn Marino start_sequence ();
1548e4b17023SJohn Marino temp = expand_builtin_apply_args_1 ();
1549e4b17023SJohn Marino seq = get_insns ();
1550e4b17023SJohn Marino end_sequence ();
1551e4b17023SJohn Marino
1552e4b17023SJohn Marino apply_args_value = temp;
1553e4b17023SJohn Marino
1554e4b17023SJohn Marino /* Put the insns after the NOTE that starts the function.
1555e4b17023SJohn Marino If this is inside a start_sequence, make the outer-level insn
1556e4b17023SJohn Marino chain current, so the code is placed at the start of the
1557e4b17023SJohn Marino function. If internal_arg_pointer is a non-virtual pseudo,
1558e4b17023SJohn Marino it needs to be placed after the function that initializes
1559e4b17023SJohn Marino that pseudo. */
1560e4b17023SJohn Marino push_topmost_sequence ();
1561e4b17023SJohn Marino if (REG_P (crtl->args.internal_arg_pointer)
1562e4b17023SJohn Marino && REGNO (crtl->args.internal_arg_pointer) > LAST_VIRTUAL_REGISTER)
1563e4b17023SJohn Marino emit_insn_before (seq, parm_birth_insn);
1564e4b17023SJohn Marino else
1565e4b17023SJohn Marino emit_insn_before (seq, NEXT_INSN (entry_of_function ()));
1566e4b17023SJohn Marino pop_topmost_sequence ();
1567e4b17023SJohn Marino return temp;
1568e4b17023SJohn Marino }
1569e4b17023SJohn Marino }
1570e4b17023SJohn Marino
1571e4b17023SJohn Marino /* Perform an untyped call and save the state required to perform an
1572e4b17023SJohn Marino untyped return of whatever value was returned by the given function. */
1573e4b17023SJohn Marino
1574e4b17023SJohn Marino static rtx
expand_builtin_apply(rtx function,rtx arguments,rtx argsize)1575e4b17023SJohn Marino expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
1576e4b17023SJohn Marino {
1577e4b17023SJohn Marino int size, align, regno;
1578e4b17023SJohn Marino enum machine_mode mode;
1579e4b17023SJohn Marino rtx incoming_args, result, reg, dest, src, call_insn;
1580e4b17023SJohn Marino rtx old_stack_level = 0;
1581e4b17023SJohn Marino rtx call_fusage = 0;
1582e4b17023SJohn Marino rtx struct_value = targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 0);
1583e4b17023SJohn Marino
1584e4b17023SJohn Marino arguments = convert_memory_address (Pmode, arguments);
1585e4b17023SJohn Marino
1586e4b17023SJohn Marino /* Create a block where the return registers can be saved. */
1587e4b17023SJohn Marino result = assign_stack_local (BLKmode, apply_result_size (), -1);
1588e4b17023SJohn Marino
1589e4b17023SJohn Marino /* Fetch the arg pointer from the ARGUMENTS block. */
1590e4b17023SJohn Marino incoming_args = gen_reg_rtx (Pmode);
1591e4b17023SJohn Marino emit_move_insn (incoming_args, gen_rtx_MEM (Pmode, arguments));
1592e4b17023SJohn Marino #ifndef STACK_GROWS_DOWNWARD
1593e4b17023SJohn Marino incoming_args = expand_simple_binop (Pmode, MINUS, incoming_args, argsize,
1594e4b17023SJohn Marino incoming_args, 0, OPTAB_LIB_WIDEN);
1595e4b17023SJohn Marino #endif
1596e4b17023SJohn Marino
1597e4b17023SJohn Marino /* Push a new argument block and copy the arguments. Do not allow
1598e4b17023SJohn Marino the (potential) memcpy call below to interfere with our stack
1599e4b17023SJohn Marino manipulations. */
1600e4b17023SJohn Marino do_pending_stack_adjust ();
1601e4b17023SJohn Marino NO_DEFER_POP;
1602e4b17023SJohn Marino
1603e4b17023SJohn Marino /* Save the stack with nonlocal if available. */
1604e4b17023SJohn Marino #ifdef HAVE_save_stack_nonlocal
1605e4b17023SJohn Marino if (HAVE_save_stack_nonlocal)
1606e4b17023SJohn Marino emit_stack_save (SAVE_NONLOCAL, &old_stack_level);
1607e4b17023SJohn Marino else
1608e4b17023SJohn Marino #endif
1609e4b17023SJohn Marino emit_stack_save (SAVE_BLOCK, &old_stack_level);
1610e4b17023SJohn Marino
1611e4b17023SJohn Marino /* Allocate a block of memory onto the stack and copy the memory
1612e4b17023SJohn Marino arguments to the outgoing arguments address. We can pass TRUE
1613e4b17023SJohn Marino as the 4th argument because we just saved the stack pointer
1614e4b17023SJohn Marino and will restore it right after the call. */
1615e4b17023SJohn Marino allocate_dynamic_stack_space (argsize, 0, BIGGEST_ALIGNMENT, true);
1616e4b17023SJohn Marino
1617e4b17023SJohn Marino /* Set DRAP flag to true, even though allocate_dynamic_stack_space
1618e4b17023SJohn Marino may have already set current_function_calls_alloca to true.
1619e4b17023SJohn Marino current_function_calls_alloca won't be set if argsize is zero,
1620e4b17023SJohn Marino so we have to guarantee need_drap is true here. */
1621e4b17023SJohn Marino if (SUPPORTS_STACK_ALIGNMENT)
1622e4b17023SJohn Marino crtl->need_drap = true;
1623e4b17023SJohn Marino
1624e4b17023SJohn Marino dest = virtual_outgoing_args_rtx;
1625e4b17023SJohn Marino #ifndef STACK_GROWS_DOWNWARD
1626e4b17023SJohn Marino if (CONST_INT_P (argsize))
1627e4b17023SJohn Marino dest = plus_constant (dest, -INTVAL (argsize));
1628e4b17023SJohn Marino else
1629e4b17023SJohn Marino dest = gen_rtx_PLUS (Pmode, dest, negate_rtx (Pmode, argsize));
1630e4b17023SJohn Marino #endif
1631e4b17023SJohn Marino dest = gen_rtx_MEM (BLKmode, dest);
1632e4b17023SJohn Marino set_mem_align (dest, PARM_BOUNDARY);
1633e4b17023SJohn Marino src = gen_rtx_MEM (BLKmode, incoming_args);
1634e4b17023SJohn Marino set_mem_align (src, PARM_BOUNDARY);
1635e4b17023SJohn Marino emit_block_move (dest, src, argsize, BLOCK_OP_NORMAL);
1636e4b17023SJohn Marino
1637e4b17023SJohn Marino /* Refer to the argument block. */
1638e4b17023SJohn Marino apply_args_size ();
1639e4b17023SJohn Marino arguments = gen_rtx_MEM (BLKmode, arguments);
1640e4b17023SJohn Marino set_mem_align (arguments, PARM_BOUNDARY);
1641e4b17023SJohn Marino
1642e4b17023SJohn Marino /* Walk past the arg-pointer and structure value address. */
1643e4b17023SJohn Marino size = GET_MODE_SIZE (Pmode);
1644e4b17023SJohn Marino if (struct_value)
1645e4b17023SJohn Marino size += GET_MODE_SIZE (Pmode);
1646e4b17023SJohn Marino
1647e4b17023SJohn Marino /* Restore each of the registers previously saved. Make USE insns
1648e4b17023SJohn Marino for each of these registers for use in making the call. */
1649e4b17023SJohn Marino for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1650e4b17023SJohn Marino if ((mode = apply_args_mode[regno]) != VOIDmode)
1651e4b17023SJohn Marino {
1652e4b17023SJohn Marino align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1653e4b17023SJohn Marino if (size % align != 0)
1654e4b17023SJohn Marino size = CEIL (size, align) * align;
1655e4b17023SJohn Marino reg = gen_rtx_REG (mode, regno);
1656e4b17023SJohn Marino emit_move_insn (reg, adjust_address (arguments, mode, size));
1657e4b17023SJohn Marino use_reg (&call_fusage, reg);
1658e4b17023SJohn Marino size += GET_MODE_SIZE (mode);
1659e4b17023SJohn Marino }
1660e4b17023SJohn Marino
1661e4b17023SJohn Marino /* Restore the structure value address unless this is passed as an
1662e4b17023SJohn Marino "invisible" first argument. */
1663e4b17023SJohn Marino size = GET_MODE_SIZE (Pmode);
1664e4b17023SJohn Marino if (struct_value)
1665e4b17023SJohn Marino {
1666e4b17023SJohn Marino rtx value = gen_reg_rtx (Pmode);
1667e4b17023SJohn Marino emit_move_insn (value, adjust_address (arguments, Pmode, size));
1668e4b17023SJohn Marino emit_move_insn (struct_value, value);
1669e4b17023SJohn Marino if (REG_P (struct_value))
1670e4b17023SJohn Marino use_reg (&call_fusage, struct_value);
1671e4b17023SJohn Marino size += GET_MODE_SIZE (Pmode);
1672e4b17023SJohn Marino }
1673e4b17023SJohn Marino
1674e4b17023SJohn Marino /* All arguments and registers used for the call are set up by now! */
1675e4b17023SJohn Marino function = prepare_call_address (NULL, function, NULL, &call_fusage, 0, 0);
1676e4b17023SJohn Marino
1677e4b17023SJohn Marino /* Ensure address is valid. SYMBOL_REF is already valid, so no need,
1678e4b17023SJohn Marino and we don't want to load it into a register as an optimization,
1679e4b17023SJohn Marino because prepare_call_address already did it if it should be done. */
1680e4b17023SJohn Marino if (GET_CODE (function) != SYMBOL_REF)
1681e4b17023SJohn Marino function = memory_address (FUNCTION_MODE, function);
1682e4b17023SJohn Marino
1683e4b17023SJohn Marino /* Generate the actual call instruction and save the return value. */
1684e4b17023SJohn Marino #ifdef HAVE_untyped_call
1685e4b17023SJohn Marino if (HAVE_untyped_call)
1686e4b17023SJohn Marino emit_call_insn (gen_untyped_call (gen_rtx_MEM (FUNCTION_MODE, function),
1687e4b17023SJohn Marino result, result_vector (1, result)));
1688e4b17023SJohn Marino else
1689e4b17023SJohn Marino #endif
1690e4b17023SJohn Marino #ifdef HAVE_call_value
1691e4b17023SJohn Marino if (HAVE_call_value)
1692e4b17023SJohn Marino {
1693e4b17023SJohn Marino rtx valreg = 0;
1694e4b17023SJohn Marino
1695e4b17023SJohn Marino /* Locate the unique return register. It is not possible to
1696e4b17023SJohn Marino express a call that sets more than one return register using
1697e4b17023SJohn Marino call_value; use untyped_call for that. In fact, untyped_call
1698e4b17023SJohn Marino only needs to save the return registers in the given block. */
1699e4b17023SJohn Marino for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1700e4b17023SJohn Marino if ((mode = apply_result_mode[regno]) != VOIDmode)
1701e4b17023SJohn Marino {
1702e4b17023SJohn Marino gcc_assert (!valreg); /* HAVE_untyped_call required. */
1703e4b17023SJohn Marino
1704e4b17023SJohn Marino valreg = gen_rtx_REG (mode, regno);
1705e4b17023SJohn Marino }
1706e4b17023SJohn Marino
1707e4b17023SJohn Marino emit_call_insn (GEN_CALL_VALUE (valreg,
1708e4b17023SJohn Marino gen_rtx_MEM (FUNCTION_MODE, function),
1709e4b17023SJohn Marino const0_rtx, NULL_RTX, const0_rtx));
1710e4b17023SJohn Marino
1711e4b17023SJohn Marino emit_move_insn (adjust_address (result, GET_MODE (valreg), 0), valreg);
1712e4b17023SJohn Marino }
1713e4b17023SJohn Marino else
1714e4b17023SJohn Marino #endif
1715e4b17023SJohn Marino gcc_unreachable ();
1716e4b17023SJohn Marino
1717e4b17023SJohn Marino /* Find the CALL insn we just emitted, and attach the register usage
1718e4b17023SJohn Marino information. */
1719e4b17023SJohn Marino call_insn = last_call_insn ();
1720e4b17023SJohn Marino add_function_usage_to (call_insn, call_fusage);
1721e4b17023SJohn Marino
1722e4b17023SJohn Marino /* Restore the stack. */
1723e4b17023SJohn Marino #ifdef HAVE_save_stack_nonlocal
1724e4b17023SJohn Marino if (HAVE_save_stack_nonlocal)
1725e4b17023SJohn Marino emit_stack_restore (SAVE_NONLOCAL, old_stack_level);
1726e4b17023SJohn Marino else
1727e4b17023SJohn Marino #endif
1728e4b17023SJohn Marino emit_stack_restore (SAVE_BLOCK, old_stack_level);
1729e4b17023SJohn Marino fixup_args_size_notes (call_insn, get_last_insn(), 0);
1730e4b17023SJohn Marino
1731e4b17023SJohn Marino OK_DEFER_POP;
1732e4b17023SJohn Marino
1733e4b17023SJohn Marino /* Return the address of the result block. */
1734e4b17023SJohn Marino result = copy_addr_to_reg (XEXP (result, 0));
1735e4b17023SJohn Marino return convert_memory_address (ptr_mode, result);
1736e4b17023SJohn Marino }
1737e4b17023SJohn Marino
1738e4b17023SJohn Marino /* Perform an untyped return. */
1739e4b17023SJohn Marino
1740e4b17023SJohn Marino static void
expand_builtin_return(rtx result)1741e4b17023SJohn Marino expand_builtin_return (rtx result)
1742e4b17023SJohn Marino {
1743e4b17023SJohn Marino int size, align, regno;
1744e4b17023SJohn Marino enum machine_mode mode;
1745e4b17023SJohn Marino rtx reg;
1746e4b17023SJohn Marino rtx call_fusage = 0;
1747e4b17023SJohn Marino
1748e4b17023SJohn Marino result = convert_memory_address (Pmode, result);
1749e4b17023SJohn Marino
1750e4b17023SJohn Marino apply_result_size ();
1751e4b17023SJohn Marino result = gen_rtx_MEM (BLKmode, result);
1752e4b17023SJohn Marino
1753e4b17023SJohn Marino #ifdef HAVE_untyped_return
1754e4b17023SJohn Marino if (HAVE_untyped_return)
1755e4b17023SJohn Marino {
1756e4b17023SJohn Marino emit_jump_insn (gen_untyped_return (result, result_vector (0, result)));
1757e4b17023SJohn Marino emit_barrier ();
1758e4b17023SJohn Marino return;
1759e4b17023SJohn Marino }
1760e4b17023SJohn Marino #endif
1761e4b17023SJohn Marino
1762e4b17023SJohn Marino /* Restore the return value and note that each value is used. */
1763e4b17023SJohn Marino size = 0;
1764e4b17023SJohn Marino for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1765e4b17023SJohn Marino if ((mode = apply_result_mode[regno]) != VOIDmode)
1766e4b17023SJohn Marino {
1767e4b17023SJohn Marino align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1768e4b17023SJohn Marino if (size % align != 0)
1769e4b17023SJohn Marino size = CEIL (size, align) * align;
1770e4b17023SJohn Marino reg = gen_rtx_REG (mode, INCOMING_REGNO (regno));
1771e4b17023SJohn Marino emit_move_insn (reg, adjust_address (result, mode, size));
1772e4b17023SJohn Marino
1773e4b17023SJohn Marino push_to_sequence (call_fusage);
1774e4b17023SJohn Marino emit_use (reg);
1775e4b17023SJohn Marino call_fusage = get_insns ();
1776e4b17023SJohn Marino end_sequence ();
1777e4b17023SJohn Marino size += GET_MODE_SIZE (mode);
1778e4b17023SJohn Marino }
1779e4b17023SJohn Marino
1780e4b17023SJohn Marino /* Put the USE insns before the return. */
1781e4b17023SJohn Marino emit_insn (call_fusage);
1782e4b17023SJohn Marino
1783e4b17023SJohn Marino /* Return whatever values was restored by jumping directly to the end
1784e4b17023SJohn Marino of the function. */
1785e4b17023SJohn Marino expand_naked_return ();
1786e4b17023SJohn Marino }
1787e4b17023SJohn Marino
1788e4b17023SJohn Marino /* Used by expand_builtin_classify_type and fold_builtin_classify_type. */
1789e4b17023SJohn Marino
1790e4b17023SJohn Marino static enum type_class
type_to_class(tree type)1791e4b17023SJohn Marino type_to_class (tree type)
1792e4b17023SJohn Marino {
1793e4b17023SJohn Marino switch (TREE_CODE (type))
1794e4b17023SJohn Marino {
1795e4b17023SJohn Marino case VOID_TYPE: return void_type_class;
1796e4b17023SJohn Marino case INTEGER_TYPE: return integer_type_class;
1797e4b17023SJohn Marino case ENUMERAL_TYPE: return enumeral_type_class;
1798e4b17023SJohn Marino case BOOLEAN_TYPE: return boolean_type_class;
1799e4b17023SJohn Marino case POINTER_TYPE: return pointer_type_class;
1800e4b17023SJohn Marino case REFERENCE_TYPE: return reference_type_class;
1801e4b17023SJohn Marino case OFFSET_TYPE: return offset_type_class;
1802e4b17023SJohn Marino case REAL_TYPE: return real_type_class;
1803e4b17023SJohn Marino case COMPLEX_TYPE: return complex_type_class;
1804e4b17023SJohn Marino case FUNCTION_TYPE: return function_type_class;
1805e4b17023SJohn Marino case METHOD_TYPE: return method_type_class;
1806e4b17023SJohn Marino case RECORD_TYPE: return record_type_class;
1807e4b17023SJohn Marino case UNION_TYPE:
1808e4b17023SJohn Marino case QUAL_UNION_TYPE: return union_type_class;
1809e4b17023SJohn Marino case ARRAY_TYPE: return (TYPE_STRING_FLAG (type)
1810e4b17023SJohn Marino ? string_type_class : array_type_class);
1811e4b17023SJohn Marino case LANG_TYPE: return lang_type_class;
1812e4b17023SJohn Marino default: return no_type_class;
1813e4b17023SJohn Marino }
1814e4b17023SJohn Marino }
1815e4b17023SJohn Marino
1816e4b17023SJohn Marino /* Expand a call EXP to __builtin_classify_type. */
1817e4b17023SJohn Marino
1818e4b17023SJohn Marino static rtx
expand_builtin_classify_type(tree exp)1819e4b17023SJohn Marino expand_builtin_classify_type (tree exp)
1820e4b17023SJohn Marino {
1821e4b17023SJohn Marino if (call_expr_nargs (exp))
1822e4b17023SJohn Marino return GEN_INT (type_to_class (TREE_TYPE (CALL_EXPR_ARG (exp, 0))));
1823e4b17023SJohn Marino return GEN_INT (no_type_class);
1824e4b17023SJohn Marino }
1825e4b17023SJohn Marino
1826e4b17023SJohn Marino /* This helper macro, meant to be used in mathfn_built_in below,
1827e4b17023SJohn Marino determines which among a set of three builtin math functions is
1828e4b17023SJohn Marino appropriate for a given type mode. The `F' and `L' cases are
1829e4b17023SJohn Marino automatically generated from the `double' case. */
1830e4b17023SJohn Marino #define CASE_MATHFN(BUILT_IN_MATHFN) \
1831e4b17023SJohn Marino case BUILT_IN_MATHFN: case BUILT_IN_MATHFN##F: case BUILT_IN_MATHFN##L: \
1832e4b17023SJohn Marino fcode = BUILT_IN_MATHFN; fcodef = BUILT_IN_MATHFN##F ; \
1833e4b17023SJohn Marino fcodel = BUILT_IN_MATHFN##L ; break;
1834e4b17023SJohn Marino /* Similar to above, but appends _R after any F/L suffix. */
1835e4b17023SJohn Marino #define CASE_MATHFN_REENT(BUILT_IN_MATHFN) \
1836e4b17023SJohn Marino case BUILT_IN_MATHFN##_R: case BUILT_IN_MATHFN##F_R: case BUILT_IN_MATHFN##L_R: \
1837e4b17023SJohn Marino fcode = BUILT_IN_MATHFN##_R; fcodef = BUILT_IN_MATHFN##F_R ; \
1838e4b17023SJohn Marino fcodel = BUILT_IN_MATHFN##L_R ; break;
1839e4b17023SJohn Marino
1840e4b17023SJohn Marino /* Return mathematic function equivalent to FN but operating directly on TYPE,
1841e4b17023SJohn Marino if available. If IMPLICIT is true use the implicit builtin declaration,
1842e4b17023SJohn Marino otherwise use the explicit declaration. If we can't do the conversion,
1843e4b17023SJohn Marino return zero. */
1844e4b17023SJohn Marino
1845e4b17023SJohn Marino static tree
mathfn_built_in_1(tree type,enum built_in_function fn,bool implicit_p)1846e4b17023SJohn Marino mathfn_built_in_1 (tree type, enum built_in_function fn, bool implicit_p)
1847e4b17023SJohn Marino {
1848e4b17023SJohn Marino enum built_in_function fcode, fcodef, fcodel, fcode2;
1849e4b17023SJohn Marino
1850e4b17023SJohn Marino switch (fn)
1851e4b17023SJohn Marino {
1852e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_ACOS)
1853e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_ACOSH)
1854e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_ASIN)
1855e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_ASINH)
1856e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_ATAN)
1857e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_ATAN2)
1858e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_ATANH)
1859e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_CBRT)
1860e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_CEIL)
1861e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_CEXPI)
1862e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_COPYSIGN)
1863e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_COS)
1864e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_COSH)
1865e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_DREM)
1866e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_ERF)
1867e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_ERFC)
1868e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_EXP)
1869e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_EXP10)
1870e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_EXP2)
1871e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_EXPM1)
1872e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_FABS)
1873e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_FDIM)
1874e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_FLOOR)
1875e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_FMA)
1876e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_FMAX)
1877e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_FMIN)
1878e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_FMOD)
1879e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_FREXP)
1880e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_GAMMA)
1881e4b17023SJohn Marino CASE_MATHFN_REENT (BUILT_IN_GAMMA) /* GAMMA_R */
1882e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_HUGE_VAL)
1883e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_HYPOT)
1884e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_ILOGB)
1885e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_ICEIL)
1886e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_IFLOOR)
1887e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_INF)
1888e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_IRINT)
1889e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_IROUND)
1890e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_ISINF)
1891e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_J0)
1892e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_J1)
1893e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_JN)
1894e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LCEIL)
1895e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LDEXP)
1896e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LFLOOR)
1897e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LGAMMA)
1898e4b17023SJohn Marino CASE_MATHFN_REENT (BUILT_IN_LGAMMA) /* LGAMMA_R */
1899e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LLCEIL)
1900e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LLFLOOR)
1901e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LLRINT)
1902e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LLROUND)
1903e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LOG)
1904e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LOG10)
1905e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LOG1P)
1906e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LOG2)
1907e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LOGB)
1908e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LRINT)
1909e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_LROUND)
1910e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_MODF)
1911e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_NAN)
1912e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_NANS)
1913e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_NEARBYINT)
1914e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_NEXTAFTER)
1915e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_NEXTTOWARD)
1916e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_POW)
1917e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_POWI)
1918e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_POW10)
1919e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_REMAINDER)
1920e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_REMQUO)
1921e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_RINT)
1922e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_ROUND)
1923e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_SCALB)
1924e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_SCALBLN)
1925e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_SCALBN)
1926e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_SIGNBIT)
1927e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_SIGNIFICAND)
1928e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_SIN)
1929e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_SINCOS)
1930e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_SINH)
1931e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_SQRT)
1932e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_TAN)
1933e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_TANH)
1934e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_TGAMMA)
1935e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_TRUNC)
1936e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_Y0)
1937e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_Y1)
1938e4b17023SJohn Marino CASE_MATHFN (BUILT_IN_YN)
1939e4b17023SJohn Marino
1940e4b17023SJohn Marino default:
1941e4b17023SJohn Marino return NULL_TREE;
1942e4b17023SJohn Marino }
1943e4b17023SJohn Marino
1944e4b17023SJohn Marino if (TYPE_MAIN_VARIANT (type) == double_type_node)
1945e4b17023SJohn Marino fcode2 = fcode;
1946e4b17023SJohn Marino else if (TYPE_MAIN_VARIANT (type) == float_type_node)
1947e4b17023SJohn Marino fcode2 = fcodef;
1948e4b17023SJohn Marino else if (TYPE_MAIN_VARIANT (type) == long_double_type_node)
1949e4b17023SJohn Marino fcode2 = fcodel;
1950e4b17023SJohn Marino else
1951e4b17023SJohn Marino return NULL_TREE;
1952e4b17023SJohn Marino
1953e4b17023SJohn Marino if (implicit_p && !builtin_decl_implicit_p (fcode2))
1954e4b17023SJohn Marino return NULL_TREE;
1955e4b17023SJohn Marino
1956e4b17023SJohn Marino return builtin_decl_explicit (fcode2);
1957e4b17023SJohn Marino }
1958e4b17023SJohn Marino
1959e4b17023SJohn Marino /* Like mathfn_built_in_1(), but always use the implicit array. */
1960e4b17023SJohn Marino
1961e4b17023SJohn Marino tree
mathfn_built_in(tree type,enum built_in_function fn)1962e4b17023SJohn Marino mathfn_built_in (tree type, enum built_in_function fn)
1963e4b17023SJohn Marino {
1964e4b17023SJohn Marino return mathfn_built_in_1 (type, fn, /*implicit=*/ 1);
1965e4b17023SJohn Marino }
1966e4b17023SJohn Marino
1967e4b17023SJohn Marino /* If errno must be maintained, expand the RTL to check if the result,
1968e4b17023SJohn Marino TARGET, of a built-in function call, EXP, is NaN, and if so set
1969e4b17023SJohn Marino errno to EDOM. */
1970e4b17023SJohn Marino
1971e4b17023SJohn Marino static void
expand_errno_check(tree exp,rtx target)1972e4b17023SJohn Marino expand_errno_check (tree exp, rtx target)
1973e4b17023SJohn Marino {
1974e4b17023SJohn Marino rtx lab = gen_label_rtx ();
1975e4b17023SJohn Marino
1976e4b17023SJohn Marino /* Test the result; if it is NaN, set errno=EDOM because
1977e4b17023SJohn Marino the argument was not in the domain. */
1978e4b17023SJohn Marino do_compare_rtx_and_jump (target, target, EQ, 0, GET_MODE (target),
1979e4b17023SJohn Marino NULL_RTX, NULL_RTX, lab,
1980e4b17023SJohn Marino /* The jump is very likely. */
1981e4b17023SJohn Marino REG_BR_PROB_BASE - (REG_BR_PROB_BASE / 2000 - 1));
1982e4b17023SJohn Marino
1983e4b17023SJohn Marino #ifdef TARGET_EDOM
1984e4b17023SJohn Marino /* If this built-in doesn't throw an exception, set errno directly. */
1985e4b17023SJohn Marino if (TREE_NOTHROW (TREE_OPERAND (CALL_EXPR_FN (exp), 0)))
1986e4b17023SJohn Marino {
1987e4b17023SJohn Marino #ifdef GEN_ERRNO_RTX
1988e4b17023SJohn Marino rtx errno_rtx = GEN_ERRNO_RTX;
1989e4b17023SJohn Marino #else
1990e4b17023SJohn Marino rtx errno_rtx
1991e4b17023SJohn Marino = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
1992e4b17023SJohn Marino #endif
1993e4b17023SJohn Marino emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
1994e4b17023SJohn Marino emit_label (lab);
1995e4b17023SJohn Marino return;
1996e4b17023SJohn Marino }
1997e4b17023SJohn Marino #endif
1998e4b17023SJohn Marino
1999e4b17023SJohn Marino /* Make sure the library call isn't expanded as a tail call. */
2000e4b17023SJohn Marino CALL_EXPR_TAILCALL (exp) = 0;
2001e4b17023SJohn Marino
2002e4b17023SJohn Marino /* We can't set errno=EDOM directly; let the library call do it.
2003e4b17023SJohn Marino Pop the arguments right away in case the call gets deleted. */
2004e4b17023SJohn Marino NO_DEFER_POP;
2005e4b17023SJohn Marino expand_call (exp, target, 0);
2006e4b17023SJohn Marino OK_DEFER_POP;
2007e4b17023SJohn Marino emit_label (lab);
2008e4b17023SJohn Marino }
2009e4b17023SJohn Marino
2010e4b17023SJohn Marino /* Expand a call to one of the builtin math functions (sqrt, exp, or log).
2011e4b17023SJohn Marino Return NULL_RTX if a normal call should be emitted rather than expanding
2012e4b17023SJohn Marino the function in-line. EXP is the expression that is a call to the builtin
2013e4b17023SJohn Marino function; if convenient, the result should be placed in TARGET.
2014e4b17023SJohn Marino SUBTARGET may be used as the target for computing one of EXP's operands. */
2015e4b17023SJohn Marino
2016e4b17023SJohn Marino static rtx
expand_builtin_mathfn(tree exp,rtx target,rtx subtarget)2017e4b17023SJohn Marino expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
2018e4b17023SJohn Marino {
2019e4b17023SJohn Marino optab builtin_optab;
2020e4b17023SJohn Marino rtx op0, insns;
2021e4b17023SJohn Marino tree fndecl = get_callee_fndecl (exp);
2022e4b17023SJohn Marino enum machine_mode mode;
2023e4b17023SJohn Marino bool errno_set = false;
2024e4b17023SJohn Marino tree arg;
2025e4b17023SJohn Marino
2026e4b17023SJohn Marino if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
2027e4b17023SJohn Marino return NULL_RTX;
2028e4b17023SJohn Marino
2029e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 0);
2030e4b17023SJohn Marino
2031e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
2032e4b17023SJohn Marino {
2033e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SQRT):
2034e4b17023SJohn Marino errno_set = ! tree_expr_nonnegative_p (arg);
2035e4b17023SJohn Marino builtin_optab = sqrt_optab;
2036e4b17023SJohn Marino break;
2037e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXP):
2038e4b17023SJohn Marino errno_set = true; builtin_optab = exp_optab; break;
2039e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXP10):
2040e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_POW10):
2041e4b17023SJohn Marino errno_set = true; builtin_optab = exp10_optab; break;
2042e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXP2):
2043e4b17023SJohn Marino errno_set = true; builtin_optab = exp2_optab; break;
2044e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXPM1):
2045e4b17023SJohn Marino errno_set = true; builtin_optab = expm1_optab; break;
2046e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOGB):
2047e4b17023SJohn Marino errno_set = true; builtin_optab = logb_optab; break;
2048e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOG):
2049e4b17023SJohn Marino errno_set = true; builtin_optab = log_optab; break;
2050e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOG10):
2051e4b17023SJohn Marino errno_set = true; builtin_optab = log10_optab; break;
2052e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOG2):
2053e4b17023SJohn Marino errno_set = true; builtin_optab = log2_optab; break;
2054e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOG1P):
2055e4b17023SJohn Marino errno_set = true; builtin_optab = log1p_optab; break;
2056e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ASIN):
2057e4b17023SJohn Marino builtin_optab = asin_optab; break;
2058e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ACOS):
2059e4b17023SJohn Marino builtin_optab = acos_optab; break;
2060e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_TAN):
2061e4b17023SJohn Marino builtin_optab = tan_optab; break;
2062e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ATAN):
2063e4b17023SJohn Marino builtin_optab = atan_optab; break;
2064e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FLOOR):
2065e4b17023SJohn Marino builtin_optab = floor_optab; break;
2066e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CEIL):
2067e4b17023SJohn Marino builtin_optab = ceil_optab; break;
2068e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_TRUNC):
2069e4b17023SJohn Marino builtin_optab = btrunc_optab; break;
2070e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ROUND):
2071e4b17023SJohn Marino builtin_optab = round_optab; break;
2072e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_NEARBYINT):
2073e4b17023SJohn Marino builtin_optab = nearbyint_optab;
2074e4b17023SJohn Marino if (flag_trapping_math)
2075e4b17023SJohn Marino break;
2076e4b17023SJohn Marino /* Else fallthrough and expand as rint. */
2077e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_RINT):
2078e4b17023SJohn Marino builtin_optab = rint_optab; break;
2079e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SIGNIFICAND):
2080e4b17023SJohn Marino builtin_optab = significand_optab; break;
2081e4b17023SJohn Marino default:
2082e4b17023SJohn Marino gcc_unreachable ();
2083e4b17023SJohn Marino }
2084e4b17023SJohn Marino
2085e4b17023SJohn Marino /* Make a suitable register to place result in. */
2086e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (exp));
2087e4b17023SJohn Marino
2088e4b17023SJohn Marino if (! flag_errno_math || ! HONOR_NANS (mode))
2089e4b17023SJohn Marino errno_set = false;
2090e4b17023SJohn Marino
2091e4b17023SJohn Marino /* Before working hard, check whether the instruction is available. */
2092e4b17023SJohn Marino if (optab_handler (builtin_optab, mode) != CODE_FOR_nothing
2093e4b17023SJohn Marino && (!errno_set || !optimize_insn_for_size_p ()))
2094e4b17023SJohn Marino {
2095e4b17023SJohn Marino target = gen_reg_rtx (mode);
2096e4b17023SJohn Marino
2097e4b17023SJohn Marino /* Wrap the computation of the argument in a SAVE_EXPR, as we may
2098e4b17023SJohn Marino need to expand the argument again. This way, we will not perform
2099e4b17023SJohn Marino side-effects more the once. */
2100e4b17023SJohn Marino CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
2101e4b17023SJohn Marino
2102e4b17023SJohn Marino op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
2103e4b17023SJohn Marino
2104e4b17023SJohn Marino start_sequence ();
2105e4b17023SJohn Marino
2106e4b17023SJohn Marino /* Compute into TARGET.
2107e4b17023SJohn Marino Set TARGET to wherever the result comes back. */
2108e4b17023SJohn Marino target = expand_unop (mode, builtin_optab, op0, target, 0);
2109e4b17023SJohn Marino
2110e4b17023SJohn Marino if (target != 0)
2111e4b17023SJohn Marino {
2112e4b17023SJohn Marino if (errno_set)
2113e4b17023SJohn Marino expand_errno_check (exp, target);
2114e4b17023SJohn Marino
2115e4b17023SJohn Marino /* Output the entire sequence. */
2116e4b17023SJohn Marino insns = get_insns ();
2117e4b17023SJohn Marino end_sequence ();
2118e4b17023SJohn Marino emit_insn (insns);
2119e4b17023SJohn Marino return target;
2120e4b17023SJohn Marino }
2121e4b17023SJohn Marino
2122e4b17023SJohn Marino /* If we were unable to expand via the builtin, stop the sequence
2123e4b17023SJohn Marino (without outputting the insns) and call to the library function
2124e4b17023SJohn Marino with the stabilized argument list. */
2125e4b17023SJohn Marino end_sequence ();
2126e4b17023SJohn Marino }
2127e4b17023SJohn Marino
2128e4b17023SJohn Marino return expand_call (exp, target, target == const0_rtx);
2129e4b17023SJohn Marino }
2130e4b17023SJohn Marino
2131e4b17023SJohn Marino /* Expand a call to the builtin binary math functions (pow and atan2).
2132e4b17023SJohn Marino Return NULL_RTX if a normal call should be emitted rather than expanding the
2133e4b17023SJohn Marino function in-line. EXP is the expression that is a call to the builtin
2134e4b17023SJohn Marino function; if convenient, the result should be placed in TARGET.
2135e4b17023SJohn Marino SUBTARGET may be used as the target for computing one of EXP's
2136e4b17023SJohn Marino operands. */
2137e4b17023SJohn Marino
2138e4b17023SJohn Marino static rtx
expand_builtin_mathfn_2(tree exp,rtx target,rtx subtarget)2139e4b17023SJohn Marino expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
2140e4b17023SJohn Marino {
2141e4b17023SJohn Marino optab builtin_optab;
2142e4b17023SJohn Marino rtx op0, op1, insns;
2143e4b17023SJohn Marino int op1_type = REAL_TYPE;
2144e4b17023SJohn Marino tree fndecl = get_callee_fndecl (exp);
2145e4b17023SJohn Marino tree arg0, arg1;
2146e4b17023SJohn Marino enum machine_mode mode;
2147e4b17023SJohn Marino bool errno_set = true;
2148e4b17023SJohn Marino
2149e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
2150e4b17023SJohn Marino {
2151e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SCALBN):
2152e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SCALBLN):
2153e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LDEXP):
2154e4b17023SJohn Marino op1_type = INTEGER_TYPE;
2155e4b17023SJohn Marino default:
2156e4b17023SJohn Marino break;
2157e4b17023SJohn Marino }
2158e4b17023SJohn Marino
2159e4b17023SJohn Marino if (!validate_arglist (exp, REAL_TYPE, op1_type, VOID_TYPE))
2160e4b17023SJohn Marino return NULL_RTX;
2161e4b17023SJohn Marino
2162e4b17023SJohn Marino arg0 = CALL_EXPR_ARG (exp, 0);
2163e4b17023SJohn Marino arg1 = CALL_EXPR_ARG (exp, 1);
2164e4b17023SJohn Marino
2165e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
2166e4b17023SJohn Marino {
2167e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_POW):
2168e4b17023SJohn Marino builtin_optab = pow_optab; break;
2169e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ATAN2):
2170e4b17023SJohn Marino builtin_optab = atan2_optab; break;
2171e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SCALB):
2172e4b17023SJohn Marino if (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (exp)))->b != 2)
2173e4b17023SJohn Marino return 0;
2174e4b17023SJohn Marino builtin_optab = scalb_optab; break;
2175e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SCALBN):
2176e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SCALBLN):
2177e4b17023SJohn Marino if (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (exp)))->b != 2)
2178e4b17023SJohn Marino return 0;
2179e4b17023SJohn Marino /* Fall through... */
2180e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LDEXP):
2181e4b17023SJohn Marino builtin_optab = ldexp_optab; break;
2182e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FMOD):
2183e4b17023SJohn Marino builtin_optab = fmod_optab; break;
2184e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_REMAINDER):
2185e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_DREM):
2186e4b17023SJohn Marino builtin_optab = remainder_optab; break;
2187e4b17023SJohn Marino default:
2188e4b17023SJohn Marino gcc_unreachable ();
2189e4b17023SJohn Marino }
2190e4b17023SJohn Marino
2191e4b17023SJohn Marino /* Make a suitable register to place result in. */
2192e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (exp));
2193e4b17023SJohn Marino
2194e4b17023SJohn Marino /* Before working hard, check whether the instruction is available. */
2195e4b17023SJohn Marino if (optab_handler (builtin_optab, mode) == CODE_FOR_nothing)
2196e4b17023SJohn Marino return NULL_RTX;
2197e4b17023SJohn Marino
2198e4b17023SJohn Marino target = gen_reg_rtx (mode);
2199e4b17023SJohn Marino
2200e4b17023SJohn Marino if (! flag_errno_math || ! HONOR_NANS (mode))
2201e4b17023SJohn Marino errno_set = false;
2202e4b17023SJohn Marino
2203e4b17023SJohn Marino if (errno_set && optimize_insn_for_size_p ())
2204e4b17023SJohn Marino return 0;
2205e4b17023SJohn Marino
2206e4b17023SJohn Marino /* Always stabilize the argument list. */
2207e4b17023SJohn Marino CALL_EXPR_ARG (exp, 0) = arg0 = builtin_save_expr (arg0);
2208e4b17023SJohn Marino CALL_EXPR_ARG (exp, 1) = arg1 = builtin_save_expr (arg1);
2209e4b17023SJohn Marino
2210e4b17023SJohn Marino op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
2211e4b17023SJohn Marino op1 = expand_normal (arg1);
2212e4b17023SJohn Marino
2213e4b17023SJohn Marino start_sequence ();
2214e4b17023SJohn Marino
2215e4b17023SJohn Marino /* Compute into TARGET.
2216e4b17023SJohn Marino Set TARGET to wherever the result comes back. */
2217e4b17023SJohn Marino target = expand_binop (mode, builtin_optab, op0, op1,
2218e4b17023SJohn Marino target, 0, OPTAB_DIRECT);
2219e4b17023SJohn Marino
2220e4b17023SJohn Marino /* If we were unable to expand via the builtin, stop the sequence
2221e4b17023SJohn Marino (without outputting the insns) and call to the library function
2222e4b17023SJohn Marino with the stabilized argument list. */
2223e4b17023SJohn Marino if (target == 0)
2224e4b17023SJohn Marino {
2225e4b17023SJohn Marino end_sequence ();
2226e4b17023SJohn Marino return expand_call (exp, target, target == const0_rtx);
2227e4b17023SJohn Marino }
2228e4b17023SJohn Marino
2229e4b17023SJohn Marino if (errno_set)
2230e4b17023SJohn Marino expand_errno_check (exp, target);
2231e4b17023SJohn Marino
2232e4b17023SJohn Marino /* Output the entire sequence. */
2233e4b17023SJohn Marino insns = get_insns ();
2234e4b17023SJohn Marino end_sequence ();
2235e4b17023SJohn Marino emit_insn (insns);
2236e4b17023SJohn Marino
2237e4b17023SJohn Marino return target;
2238e4b17023SJohn Marino }
2239e4b17023SJohn Marino
2240e4b17023SJohn Marino /* Expand a call to the builtin trinary math functions (fma).
2241e4b17023SJohn Marino Return NULL_RTX if a normal call should be emitted rather than expanding the
2242e4b17023SJohn Marino function in-line. EXP is the expression that is a call to the builtin
2243e4b17023SJohn Marino function; if convenient, the result should be placed in TARGET.
2244e4b17023SJohn Marino SUBTARGET may be used as the target for computing one of EXP's
2245e4b17023SJohn Marino operands. */
2246e4b17023SJohn Marino
2247e4b17023SJohn Marino static rtx
expand_builtin_mathfn_ternary(tree exp,rtx target,rtx subtarget)2248e4b17023SJohn Marino expand_builtin_mathfn_ternary (tree exp, rtx target, rtx subtarget)
2249e4b17023SJohn Marino {
2250e4b17023SJohn Marino optab builtin_optab;
2251e4b17023SJohn Marino rtx op0, op1, op2, insns;
2252e4b17023SJohn Marino tree fndecl = get_callee_fndecl (exp);
2253e4b17023SJohn Marino tree arg0, arg1, arg2;
2254e4b17023SJohn Marino enum machine_mode mode;
2255e4b17023SJohn Marino
2256e4b17023SJohn Marino if (!validate_arglist (exp, REAL_TYPE, REAL_TYPE, REAL_TYPE, VOID_TYPE))
2257e4b17023SJohn Marino return NULL_RTX;
2258e4b17023SJohn Marino
2259e4b17023SJohn Marino arg0 = CALL_EXPR_ARG (exp, 0);
2260e4b17023SJohn Marino arg1 = CALL_EXPR_ARG (exp, 1);
2261e4b17023SJohn Marino arg2 = CALL_EXPR_ARG (exp, 2);
2262e4b17023SJohn Marino
2263e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
2264e4b17023SJohn Marino {
2265e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FMA):
2266e4b17023SJohn Marino builtin_optab = fma_optab; break;
2267e4b17023SJohn Marino default:
2268e4b17023SJohn Marino gcc_unreachable ();
2269e4b17023SJohn Marino }
2270e4b17023SJohn Marino
2271e4b17023SJohn Marino /* Make a suitable register to place result in. */
2272e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (exp));
2273e4b17023SJohn Marino
2274e4b17023SJohn Marino /* Before working hard, check whether the instruction is available. */
2275e4b17023SJohn Marino if (optab_handler (builtin_optab, mode) == CODE_FOR_nothing)
2276e4b17023SJohn Marino return NULL_RTX;
2277e4b17023SJohn Marino
2278e4b17023SJohn Marino target = gen_reg_rtx (mode);
2279e4b17023SJohn Marino
2280e4b17023SJohn Marino /* Always stabilize the argument list. */
2281e4b17023SJohn Marino CALL_EXPR_ARG (exp, 0) = arg0 = builtin_save_expr (arg0);
2282e4b17023SJohn Marino CALL_EXPR_ARG (exp, 1) = arg1 = builtin_save_expr (arg1);
2283e4b17023SJohn Marino CALL_EXPR_ARG (exp, 2) = arg2 = builtin_save_expr (arg2);
2284e4b17023SJohn Marino
2285e4b17023SJohn Marino op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
2286e4b17023SJohn Marino op1 = expand_normal (arg1);
2287e4b17023SJohn Marino op2 = expand_normal (arg2);
2288e4b17023SJohn Marino
2289e4b17023SJohn Marino start_sequence ();
2290e4b17023SJohn Marino
2291e4b17023SJohn Marino /* Compute into TARGET.
2292e4b17023SJohn Marino Set TARGET to wherever the result comes back. */
2293e4b17023SJohn Marino target = expand_ternary_op (mode, builtin_optab, op0, op1, op2,
2294e4b17023SJohn Marino target, 0);
2295e4b17023SJohn Marino
2296e4b17023SJohn Marino /* If we were unable to expand via the builtin, stop the sequence
2297e4b17023SJohn Marino (without outputting the insns) and call to the library function
2298e4b17023SJohn Marino with the stabilized argument list. */
2299e4b17023SJohn Marino if (target == 0)
2300e4b17023SJohn Marino {
2301e4b17023SJohn Marino end_sequence ();
2302e4b17023SJohn Marino return expand_call (exp, target, target == const0_rtx);
2303e4b17023SJohn Marino }
2304e4b17023SJohn Marino
2305e4b17023SJohn Marino /* Output the entire sequence. */
2306e4b17023SJohn Marino insns = get_insns ();
2307e4b17023SJohn Marino end_sequence ();
2308e4b17023SJohn Marino emit_insn (insns);
2309e4b17023SJohn Marino
2310e4b17023SJohn Marino return target;
2311e4b17023SJohn Marino }
2312e4b17023SJohn Marino
2313e4b17023SJohn Marino /* Expand a call to the builtin sin and cos math functions.
2314e4b17023SJohn Marino Return NULL_RTX if a normal call should be emitted rather than expanding the
2315e4b17023SJohn Marino function in-line. EXP is the expression that is a call to the builtin
2316e4b17023SJohn Marino function; if convenient, the result should be placed in TARGET.
2317e4b17023SJohn Marino SUBTARGET may be used as the target for computing one of EXP's
2318e4b17023SJohn Marino operands. */
2319e4b17023SJohn Marino
2320e4b17023SJohn Marino static rtx
expand_builtin_mathfn_3(tree exp,rtx target,rtx subtarget)2321e4b17023SJohn Marino expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
2322e4b17023SJohn Marino {
2323e4b17023SJohn Marino optab builtin_optab;
2324e4b17023SJohn Marino rtx op0, insns;
2325e4b17023SJohn Marino tree fndecl = get_callee_fndecl (exp);
2326e4b17023SJohn Marino enum machine_mode mode;
2327e4b17023SJohn Marino tree arg;
2328e4b17023SJohn Marino
2329e4b17023SJohn Marino if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
2330e4b17023SJohn Marino return NULL_RTX;
2331e4b17023SJohn Marino
2332e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 0);
2333e4b17023SJohn Marino
2334e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
2335e4b17023SJohn Marino {
2336e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SIN):
2337e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_COS):
2338e4b17023SJohn Marino builtin_optab = sincos_optab; break;
2339e4b17023SJohn Marino default:
2340e4b17023SJohn Marino gcc_unreachable ();
2341e4b17023SJohn Marino }
2342e4b17023SJohn Marino
2343e4b17023SJohn Marino /* Make a suitable register to place result in. */
2344e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (exp));
2345e4b17023SJohn Marino
2346e4b17023SJohn Marino /* Check if sincos insn is available, otherwise fallback
2347e4b17023SJohn Marino to sin or cos insn. */
2348e4b17023SJohn Marino if (optab_handler (builtin_optab, mode) == CODE_FOR_nothing)
2349e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
2350e4b17023SJohn Marino {
2351e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SIN):
2352e4b17023SJohn Marino builtin_optab = sin_optab; break;
2353e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_COS):
2354e4b17023SJohn Marino builtin_optab = cos_optab; break;
2355e4b17023SJohn Marino default:
2356e4b17023SJohn Marino gcc_unreachable ();
2357e4b17023SJohn Marino }
2358e4b17023SJohn Marino
2359e4b17023SJohn Marino /* Before working hard, check whether the instruction is available. */
2360e4b17023SJohn Marino if (optab_handler (builtin_optab, mode) != CODE_FOR_nothing)
2361e4b17023SJohn Marino {
2362e4b17023SJohn Marino target = gen_reg_rtx (mode);
2363e4b17023SJohn Marino
2364e4b17023SJohn Marino /* Wrap the computation of the argument in a SAVE_EXPR, as we may
2365e4b17023SJohn Marino need to expand the argument again. This way, we will not perform
2366e4b17023SJohn Marino side-effects more the once. */
2367e4b17023SJohn Marino CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
2368e4b17023SJohn Marino
2369e4b17023SJohn Marino op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
2370e4b17023SJohn Marino
2371e4b17023SJohn Marino start_sequence ();
2372e4b17023SJohn Marino
2373e4b17023SJohn Marino /* Compute into TARGET.
2374e4b17023SJohn Marino Set TARGET to wherever the result comes back. */
2375e4b17023SJohn Marino if (builtin_optab == sincos_optab)
2376e4b17023SJohn Marino {
2377e4b17023SJohn Marino int result;
2378e4b17023SJohn Marino
2379e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
2380e4b17023SJohn Marino {
2381e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SIN):
2382e4b17023SJohn Marino result = expand_twoval_unop (builtin_optab, op0, 0, target, 0);
2383e4b17023SJohn Marino break;
2384e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_COS):
2385e4b17023SJohn Marino result = expand_twoval_unop (builtin_optab, op0, target, 0, 0);
2386e4b17023SJohn Marino break;
2387e4b17023SJohn Marino default:
2388e4b17023SJohn Marino gcc_unreachable ();
2389e4b17023SJohn Marino }
2390e4b17023SJohn Marino gcc_assert (result);
2391e4b17023SJohn Marino }
2392e4b17023SJohn Marino else
2393e4b17023SJohn Marino {
2394e4b17023SJohn Marino target = expand_unop (mode, builtin_optab, op0, target, 0);
2395e4b17023SJohn Marino }
2396e4b17023SJohn Marino
2397e4b17023SJohn Marino if (target != 0)
2398e4b17023SJohn Marino {
2399e4b17023SJohn Marino /* Output the entire sequence. */
2400e4b17023SJohn Marino insns = get_insns ();
2401e4b17023SJohn Marino end_sequence ();
2402e4b17023SJohn Marino emit_insn (insns);
2403e4b17023SJohn Marino return target;
2404e4b17023SJohn Marino }
2405e4b17023SJohn Marino
2406e4b17023SJohn Marino /* If we were unable to expand via the builtin, stop the sequence
2407e4b17023SJohn Marino (without outputting the insns) and call to the library function
2408e4b17023SJohn Marino with the stabilized argument list. */
2409e4b17023SJohn Marino end_sequence ();
2410e4b17023SJohn Marino }
2411e4b17023SJohn Marino
2412e4b17023SJohn Marino target = expand_call (exp, target, target == const0_rtx);
2413e4b17023SJohn Marino
2414e4b17023SJohn Marino return target;
2415e4b17023SJohn Marino }
2416e4b17023SJohn Marino
2417e4b17023SJohn Marino /* Given an interclass math builtin decl FNDECL and it's argument ARG
2418e4b17023SJohn Marino return an RTL instruction code that implements the functionality.
2419e4b17023SJohn Marino If that isn't possible or available return CODE_FOR_nothing. */
2420e4b17023SJohn Marino
2421e4b17023SJohn Marino static enum insn_code
interclass_mathfn_icode(tree arg,tree fndecl)2422e4b17023SJohn Marino interclass_mathfn_icode (tree arg, tree fndecl)
2423e4b17023SJohn Marino {
2424e4b17023SJohn Marino bool errno_set = false;
2425e4b17023SJohn Marino optab builtin_optab = 0;
2426e4b17023SJohn Marino enum machine_mode mode;
2427e4b17023SJohn Marino
2428e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
2429e4b17023SJohn Marino {
2430e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ILOGB):
2431e4b17023SJohn Marino errno_set = true; builtin_optab = ilogb_optab; break;
2432e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ISINF):
2433e4b17023SJohn Marino builtin_optab = isinf_optab; break;
2434e4b17023SJohn Marino case BUILT_IN_ISNORMAL:
2435e4b17023SJohn Marino case BUILT_IN_ISFINITE:
2436e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FINITE):
2437e4b17023SJohn Marino case BUILT_IN_FINITED32:
2438e4b17023SJohn Marino case BUILT_IN_FINITED64:
2439e4b17023SJohn Marino case BUILT_IN_FINITED128:
2440e4b17023SJohn Marino case BUILT_IN_ISINFD32:
2441e4b17023SJohn Marino case BUILT_IN_ISINFD64:
2442e4b17023SJohn Marino case BUILT_IN_ISINFD128:
2443e4b17023SJohn Marino /* These builtins have no optabs (yet). */
2444e4b17023SJohn Marino break;
2445e4b17023SJohn Marino default:
2446e4b17023SJohn Marino gcc_unreachable ();
2447e4b17023SJohn Marino }
2448e4b17023SJohn Marino
2449e4b17023SJohn Marino /* There's no easy way to detect the case we need to set EDOM. */
2450e4b17023SJohn Marino if (flag_errno_math && errno_set)
2451e4b17023SJohn Marino return CODE_FOR_nothing;
2452e4b17023SJohn Marino
2453e4b17023SJohn Marino /* Optab mode depends on the mode of the input argument. */
2454e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (arg));
2455e4b17023SJohn Marino
2456e4b17023SJohn Marino if (builtin_optab)
2457e4b17023SJohn Marino return optab_handler (builtin_optab, mode);
2458e4b17023SJohn Marino return CODE_FOR_nothing;
2459e4b17023SJohn Marino }
2460e4b17023SJohn Marino
2461e4b17023SJohn Marino /* Expand a call to one of the builtin math functions that operate on
2462e4b17023SJohn Marino floating point argument and output an integer result (ilogb, isinf,
2463e4b17023SJohn Marino isnan, etc).
2464e4b17023SJohn Marino Return 0 if a normal call should be emitted rather than expanding the
2465e4b17023SJohn Marino function in-line. EXP is the expression that is a call to the builtin
2466e4b17023SJohn Marino function; if convenient, the result should be placed in TARGET. */
2467e4b17023SJohn Marino
2468e4b17023SJohn Marino static rtx
expand_builtin_interclass_mathfn(tree exp,rtx target)2469e4b17023SJohn Marino expand_builtin_interclass_mathfn (tree exp, rtx target)
2470e4b17023SJohn Marino {
2471e4b17023SJohn Marino enum insn_code icode = CODE_FOR_nothing;
2472e4b17023SJohn Marino rtx op0;
2473e4b17023SJohn Marino tree fndecl = get_callee_fndecl (exp);
2474e4b17023SJohn Marino enum machine_mode mode;
2475e4b17023SJohn Marino tree arg;
2476e4b17023SJohn Marino
2477e4b17023SJohn Marino if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
2478e4b17023SJohn Marino return NULL_RTX;
2479e4b17023SJohn Marino
2480e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 0);
2481e4b17023SJohn Marino icode = interclass_mathfn_icode (arg, fndecl);
2482e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (arg));
2483e4b17023SJohn Marino
2484e4b17023SJohn Marino if (icode != CODE_FOR_nothing)
2485e4b17023SJohn Marino {
2486e4b17023SJohn Marino struct expand_operand ops[1];
2487e4b17023SJohn Marino rtx last = get_last_insn ();
2488e4b17023SJohn Marino tree orig_arg = arg;
2489e4b17023SJohn Marino
2490e4b17023SJohn Marino /* Wrap the computation of the argument in a SAVE_EXPR, as we may
2491e4b17023SJohn Marino need to expand the argument again. This way, we will not perform
2492e4b17023SJohn Marino side-effects more the once. */
2493e4b17023SJohn Marino CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
2494e4b17023SJohn Marino
2495e4b17023SJohn Marino op0 = expand_expr (arg, NULL_RTX, VOIDmode, EXPAND_NORMAL);
2496e4b17023SJohn Marino
2497e4b17023SJohn Marino if (mode != GET_MODE (op0))
2498e4b17023SJohn Marino op0 = convert_to_mode (mode, op0, 0);
2499e4b17023SJohn Marino
2500e4b17023SJohn Marino create_output_operand (&ops[0], target, TYPE_MODE (TREE_TYPE (exp)));
2501e4b17023SJohn Marino if (maybe_legitimize_operands (icode, 0, 1, ops)
2502e4b17023SJohn Marino && maybe_emit_unop_insn (icode, ops[0].value, op0, UNKNOWN))
2503e4b17023SJohn Marino return ops[0].value;
2504e4b17023SJohn Marino
2505e4b17023SJohn Marino delete_insns_since (last);
2506e4b17023SJohn Marino CALL_EXPR_ARG (exp, 0) = orig_arg;
2507e4b17023SJohn Marino }
2508e4b17023SJohn Marino
2509e4b17023SJohn Marino return NULL_RTX;
2510e4b17023SJohn Marino }
2511e4b17023SJohn Marino
2512e4b17023SJohn Marino /* Expand a call to the builtin sincos math function.
2513e4b17023SJohn Marino Return NULL_RTX if a normal call should be emitted rather than expanding the
2514e4b17023SJohn Marino function in-line. EXP is the expression that is a call to the builtin
2515e4b17023SJohn Marino function. */
2516e4b17023SJohn Marino
2517e4b17023SJohn Marino static rtx
expand_builtin_sincos(tree exp)2518e4b17023SJohn Marino expand_builtin_sincos (tree exp)
2519e4b17023SJohn Marino {
2520e4b17023SJohn Marino rtx op0, op1, op2, target1, target2;
2521e4b17023SJohn Marino enum machine_mode mode;
2522e4b17023SJohn Marino tree arg, sinp, cosp;
2523e4b17023SJohn Marino int result;
2524e4b17023SJohn Marino location_t loc = EXPR_LOCATION (exp);
2525e4b17023SJohn Marino tree alias_type, alias_off;
2526e4b17023SJohn Marino
2527e4b17023SJohn Marino if (!validate_arglist (exp, REAL_TYPE,
2528e4b17023SJohn Marino POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
2529e4b17023SJohn Marino return NULL_RTX;
2530e4b17023SJohn Marino
2531e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 0);
2532e4b17023SJohn Marino sinp = CALL_EXPR_ARG (exp, 1);
2533e4b17023SJohn Marino cosp = CALL_EXPR_ARG (exp, 2);
2534e4b17023SJohn Marino
2535e4b17023SJohn Marino /* Make a suitable register to place result in. */
2536e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (arg));
2537e4b17023SJohn Marino
2538e4b17023SJohn Marino /* Check if sincos insn is available, otherwise emit the call. */
2539e4b17023SJohn Marino if (optab_handler (sincos_optab, mode) == CODE_FOR_nothing)
2540e4b17023SJohn Marino return NULL_RTX;
2541e4b17023SJohn Marino
2542e4b17023SJohn Marino target1 = gen_reg_rtx (mode);
2543e4b17023SJohn Marino target2 = gen_reg_rtx (mode);
2544e4b17023SJohn Marino
2545e4b17023SJohn Marino op0 = expand_normal (arg);
2546e4b17023SJohn Marino alias_type = build_pointer_type_for_mode (TREE_TYPE (arg), ptr_mode, true);
2547e4b17023SJohn Marino alias_off = build_int_cst (alias_type, 0);
2548e4b17023SJohn Marino op1 = expand_normal (fold_build2_loc (loc, MEM_REF, TREE_TYPE (arg),
2549e4b17023SJohn Marino sinp, alias_off));
2550e4b17023SJohn Marino op2 = expand_normal (fold_build2_loc (loc, MEM_REF, TREE_TYPE (arg),
2551e4b17023SJohn Marino cosp, alias_off));
2552e4b17023SJohn Marino
2553e4b17023SJohn Marino /* Compute into target1 and target2.
2554e4b17023SJohn Marino Set TARGET to wherever the result comes back. */
2555e4b17023SJohn Marino result = expand_twoval_unop (sincos_optab, op0, target2, target1, 0);
2556e4b17023SJohn Marino gcc_assert (result);
2557e4b17023SJohn Marino
2558e4b17023SJohn Marino /* Move target1 and target2 to the memory locations indicated
2559e4b17023SJohn Marino by op1 and op2. */
2560e4b17023SJohn Marino emit_move_insn (op1, target1);
2561e4b17023SJohn Marino emit_move_insn (op2, target2);
2562e4b17023SJohn Marino
2563e4b17023SJohn Marino return const0_rtx;
2564e4b17023SJohn Marino }
2565e4b17023SJohn Marino
2566e4b17023SJohn Marino /* Expand a call to the internal cexpi builtin to the sincos math function.
2567e4b17023SJohn Marino EXP is the expression that is a call to the builtin function; if convenient,
2568e4b17023SJohn Marino the result should be placed in TARGET. */
2569e4b17023SJohn Marino
2570e4b17023SJohn Marino static rtx
expand_builtin_cexpi(tree exp,rtx target)2571e4b17023SJohn Marino expand_builtin_cexpi (tree exp, rtx target)
2572e4b17023SJohn Marino {
2573e4b17023SJohn Marino tree fndecl = get_callee_fndecl (exp);
2574e4b17023SJohn Marino tree arg, type;
2575e4b17023SJohn Marino enum machine_mode mode;
2576e4b17023SJohn Marino rtx op0, op1, op2;
2577e4b17023SJohn Marino location_t loc = EXPR_LOCATION (exp);
2578e4b17023SJohn Marino
2579e4b17023SJohn Marino if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
2580e4b17023SJohn Marino return NULL_RTX;
2581e4b17023SJohn Marino
2582e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 0);
2583e4b17023SJohn Marino type = TREE_TYPE (arg);
2584e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (arg));
2585e4b17023SJohn Marino
2586e4b17023SJohn Marino /* Try expanding via a sincos optab, fall back to emitting a libcall
2587e4b17023SJohn Marino to sincos or cexp. We are sure we have sincos or cexp because cexpi
2588e4b17023SJohn Marino is only generated from sincos, cexp or if we have either of them. */
2589e4b17023SJohn Marino if (optab_handler (sincos_optab, mode) != CODE_FOR_nothing)
2590e4b17023SJohn Marino {
2591e4b17023SJohn Marino op1 = gen_reg_rtx (mode);
2592e4b17023SJohn Marino op2 = gen_reg_rtx (mode);
2593e4b17023SJohn Marino
2594e4b17023SJohn Marino op0 = expand_expr (arg, NULL_RTX, VOIDmode, EXPAND_NORMAL);
2595e4b17023SJohn Marino
2596e4b17023SJohn Marino /* Compute into op1 and op2. */
2597e4b17023SJohn Marino expand_twoval_unop (sincos_optab, op0, op2, op1, 0);
2598e4b17023SJohn Marino }
2599e4b17023SJohn Marino else if (TARGET_HAS_SINCOS)
2600e4b17023SJohn Marino {
2601e4b17023SJohn Marino tree call, fn = NULL_TREE;
2602e4b17023SJohn Marino tree top1, top2;
2603e4b17023SJohn Marino rtx op1a, op2a;
2604e4b17023SJohn Marino
2605e4b17023SJohn Marino if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
2606e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_SINCOSF);
2607e4b17023SJohn Marino else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
2608e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_SINCOS);
2609e4b17023SJohn Marino else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIL)
2610e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_SINCOSL);
2611e4b17023SJohn Marino else
2612e4b17023SJohn Marino gcc_unreachable ();
2613e4b17023SJohn Marino
2614e4b17023SJohn Marino op1 = assign_temp (TREE_TYPE (arg), 0, 1, 1);
2615e4b17023SJohn Marino op2 = assign_temp (TREE_TYPE (arg), 0, 1, 1);
2616e4b17023SJohn Marino op1a = copy_to_mode_reg (Pmode, XEXP (op1, 0));
2617e4b17023SJohn Marino op2a = copy_to_mode_reg (Pmode, XEXP (op2, 0));
2618e4b17023SJohn Marino top1 = make_tree (build_pointer_type (TREE_TYPE (arg)), op1a);
2619e4b17023SJohn Marino top2 = make_tree (build_pointer_type (TREE_TYPE (arg)), op2a);
2620e4b17023SJohn Marino
2621e4b17023SJohn Marino /* Make sure not to fold the sincos call again. */
2622e4b17023SJohn Marino call = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
2623e4b17023SJohn Marino expand_normal (build_call_nary (TREE_TYPE (TREE_TYPE (fn)),
2624e4b17023SJohn Marino call, 3, arg, top1, top2));
2625e4b17023SJohn Marino }
2626e4b17023SJohn Marino else
2627e4b17023SJohn Marino {
2628e4b17023SJohn Marino tree call, fn = NULL_TREE, narg;
2629e4b17023SJohn Marino tree ctype = build_complex_type (type);
2630e4b17023SJohn Marino
2631e4b17023SJohn Marino if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
2632e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_CEXPF);
2633e4b17023SJohn Marino else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
2634e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_CEXP);
2635e4b17023SJohn Marino else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIL)
2636e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_CEXPL);
2637e4b17023SJohn Marino else
2638e4b17023SJohn Marino gcc_unreachable ();
2639e4b17023SJohn Marino
2640e4b17023SJohn Marino /* If we don't have a decl for cexp create one. This is the
2641e4b17023SJohn Marino friendliest fallback if the user calls __builtin_cexpi
2642e4b17023SJohn Marino without full target C99 function support. */
2643e4b17023SJohn Marino if (fn == NULL_TREE)
2644e4b17023SJohn Marino {
2645e4b17023SJohn Marino tree fntype;
2646e4b17023SJohn Marino const char *name = NULL;
2647e4b17023SJohn Marino
2648e4b17023SJohn Marino if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
2649e4b17023SJohn Marino name = "cexpf";
2650e4b17023SJohn Marino else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
2651e4b17023SJohn Marino name = "cexp";
2652e4b17023SJohn Marino else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIL)
2653e4b17023SJohn Marino name = "cexpl";
2654e4b17023SJohn Marino
2655e4b17023SJohn Marino fntype = build_function_type_list (ctype, ctype, NULL_TREE);
2656e4b17023SJohn Marino fn = build_fn_decl (name, fntype);
2657e4b17023SJohn Marino }
2658e4b17023SJohn Marino
2659e4b17023SJohn Marino narg = fold_build2_loc (loc, COMPLEX_EXPR, ctype,
2660e4b17023SJohn Marino build_real (type, dconst0), arg);
2661e4b17023SJohn Marino
2662e4b17023SJohn Marino /* Make sure not to fold the cexp call again. */
2663e4b17023SJohn Marino call = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
2664e4b17023SJohn Marino return expand_expr (build_call_nary (ctype, call, 1, narg),
2665e4b17023SJohn Marino target, VOIDmode, EXPAND_NORMAL);
2666e4b17023SJohn Marino }
2667e4b17023SJohn Marino
2668e4b17023SJohn Marino /* Now build the proper return type. */
2669e4b17023SJohn Marino return expand_expr (build2 (COMPLEX_EXPR, build_complex_type (type),
2670e4b17023SJohn Marino make_tree (TREE_TYPE (arg), op2),
2671e4b17023SJohn Marino make_tree (TREE_TYPE (arg), op1)),
2672e4b17023SJohn Marino target, VOIDmode, EXPAND_NORMAL);
2673e4b17023SJohn Marino }
2674e4b17023SJohn Marino
2675e4b17023SJohn Marino /* Conveniently construct a function call expression. FNDECL names the
2676e4b17023SJohn Marino function to be called, N is the number of arguments, and the "..."
2677e4b17023SJohn Marino parameters are the argument expressions. Unlike build_call_exr
2678e4b17023SJohn Marino this doesn't fold the call, hence it will always return a CALL_EXPR. */
2679e4b17023SJohn Marino
2680e4b17023SJohn Marino static tree
build_call_nofold_loc(location_t loc,tree fndecl,int n,...)2681e4b17023SJohn Marino build_call_nofold_loc (location_t loc, tree fndecl, int n, ...)
2682e4b17023SJohn Marino {
2683e4b17023SJohn Marino va_list ap;
2684e4b17023SJohn Marino tree fntype = TREE_TYPE (fndecl);
2685e4b17023SJohn Marino tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
2686e4b17023SJohn Marino
2687e4b17023SJohn Marino va_start (ap, n);
2688e4b17023SJohn Marino fn = build_call_valist (TREE_TYPE (fntype), fn, n, ap);
2689e4b17023SJohn Marino va_end (ap);
2690e4b17023SJohn Marino SET_EXPR_LOCATION (fn, loc);
2691e4b17023SJohn Marino return fn;
2692e4b17023SJohn Marino }
2693e4b17023SJohn Marino
2694e4b17023SJohn Marino /* Expand a call to one of the builtin rounding functions gcc defines
2695e4b17023SJohn Marino as an extension (lfloor and lceil). As these are gcc extensions we
2696e4b17023SJohn Marino do not need to worry about setting errno to EDOM.
2697e4b17023SJohn Marino If expanding via optab fails, lower expression to (int)(floor(x)).
2698e4b17023SJohn Marino EXP is the expression that is a call to the builtin function;
2699e4b17023SJohn Marino if convenient, the result should be placed in TARGET. */
2700e4b17023SJohn Marino
2701e4b17023SJohn Marino static rtx
expand_builtin_int_roundingfn(tree exp,rtx target)2702e4b17023SJohn Marino expand_builtin_int_roundingfn (tree exp, rtx target)
2703e4b17023SJohn Marino {
2704e4b17023SJohn Marino convert_optab builtin_optab;
2705e4b17023SJohn Marino rtx op0, insns, tmp;
2706e4b17023SJohn Marino tree fndecl = get_callee_fndecl (exp);
2707e4b17023SJohn Marino enum built_in_function fallback_fn;
2708e4b17023SJohn Marino tree fallback_fndecl;
2709e4b17023SJohn Marino enum machine_mode mode;
2710e4b17023SJohn Marino tree arg;
2711e4b17023SJohn Marino
2712e4b17023SJohn Marino if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
2713e4b17023SJohn Marino gcc_unreachable ();
2714e4b17023SJohn Marino
2715e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 0);
2716e4b17023SJohn Marino
2717e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
2718e4b17023SJohn Marino {
2719e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ICEIL):
2720e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LCEIL):
2721e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLCEIL):
2722e4b17023SJohn Marino builtin_optab = lceil_optab;
2723e4b17023SJohn Marino fallback_fn = BUILT_IN_CEIL;
2724e4b17023SJohn Marino break;
2725e4b17023SJohn Marino
2726e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IFLOOR):
2727e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LFLOOR):
2728e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLFLOOR):
2729e4b17023SJohn Marino builtin_optab = lfloor_optab;
2730e4b17023SJohn Marino fallback_fn = BUILT_IN_FLOOR;
2731e4b17023SJohn Marino break;
2732e4b17023SJohn Marino
2733e4b17023SJohn Marino default:
2734e4b17023SJohn Marino gcc_unreachable ();
2735e4b17023SJohn Marino }
2736e4b17023SJohn Marino
2737e4b17023SJohn Marino /* Make a suitable register to place result in. */
2738e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (exp));
2739e4b17023SJohn Marino
2740e4b17023SJohn Marino target = gen_reg_rtx (mode);
2741e4b17023SJohn Marino
2742e4b17023SJohn Marino /* Wrap the computation of the argument in a SAVE_EXPR, as we may
2743e4b17023SJohn Marino need to expand the argument again. This way, we will not perform
2744e4b17023SJohn Marino side-effects more the once. */
2745e4b17023SJohn Marino CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
2746e4b17023SJohn Marino
2747e4b17023SJohn Marino op0 = expand_expr (arg, NULL, VOIDmode, EXPAND_NORMAL);
2748e4b17023SJohn Marino
2749e4b17023SJohn Marino start_sequence ();
2750e4b17023SJohn Marino
2751e4b17023SJohn Marino /* Compute into TARGET. */
2752e4b17023SJohn Marino if (expand_sfix_optab (target, op0, builtin_optab))
2753e4b17023SJohn Marino {
2754e4b17023SJohn Marino /* Output the entire sequence. */
2755e4b17023SJohn Marino insns = get_insns ();
2756e4b17023SJohn Marino end_sequence ();
2757e4b17023SJohn Marino emit_insn (insns);
2758e4b17023SJohn Marino return target;
2759e4b17023SJohn Marino }
2760e4b17023SJohn Marino
2761e4b17023SJohn Marino /* If we were unable to expand via the builtin, stop the sequence
2762e4b17023SJohn Marino (without outputting the insns). */
2763e4b17023SJohn Marino end_sequence ();
2764e4b17023SJohn Marino
2765e4b17023SJohn Marino /* Fall back to floating point rounding optab. */
2766e4b17023SJohn Marino fallback_fndecl = mathfn_built_in (TREE_TYPE (arg), fallback_fn);
2767e4b17023SJohn Marino
2768e4b17023SJohn Marino /* For non-C99 targets we may end up without a fallback fndecl here
2769e4b17023SJohn Marino if the user called __builtin_lfloor directly. In this case emit
2770e4b17023SJohn Marino a call to the floor/ceil variants nevertheless. This should result
2771e4b17023SJohn Marino in the best user experience for not full C99 targets. */
2772e4b17023SJohn Marino if (fallback_fndecl == NULL_TREE)
2773e4b17023SJohn Marino {
2774e4b17023SJohn Marino tree fntype;
2775e4b17023SJohn Marino const char *name = NULL;
2776e4b17023SJohn Marino
2777e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
2778e4b17023SJohn Marino {
2779e4b17023SJohn Marino case BUILT_IN_ICEIL:
2780e4b17023SJohn Marino case BUILT_IN_LCEIL:
2781e4b17023SJohn Marino case BUILT_IN_LLCEIL:
2782e4b17023SJohn Marino name = "ceil";
2783e4b17023SJohn Marino break;
2784e4b17023SJohn Marino case BUILT_IN_ICEILF:
2785e4b17023SJohn Marino case BUILT_IN_LCEILF:
2786e4b17023SJohn Marino case BUILT_IN_LLCEILF:
2787e4b17023SJohn Marino name = "ceilf";
2788e4b17023SJohn Marino break;
2789e4b17023SJohn Marino case BUILT_IN_ICEILL:
2790e4b17023SJohn Marino case BUILT_IN_LCEILL:
2791e4b17023SJohn Marino case BUILT_IN_LLCEILL:
2792e4b17023SJohn Marino name = "ceill";
2793e4b17023SJohn Marino break;
2794e4b17023SJohn Marino case BUILT_IN_IFLOOR:
2795e4b17023SJohn Marino case BUILT_IN_LFLOOR:
2796e4b17023SJohn Marino case BUILT_IN_LLFLOOR:
2797e4b17023SJohn Marino name = "floor";
2798e4b17023SJohn Marino break;
2799e4b17023SJohn Marino case BUILT_IN_IFLOORF:
2800e4b17023SJohn Marino case BUILT_IN_LFLOORF:
2801e4b17023SJohn Marino case BUILT_IN_LLFLOORF:
2802e4b17023SJohn Marino name = "floorf";
2803e4b17023SJohn Marino break;
2804e4b17023SJohn Marino case BUILT_IN_IFLOORL:
2805e4b17023SJohn Marino case BUILT_IN_LFLOORL:
2806e4b17023SJohn Marino case BUILT_IN_LLFLOORL:
2807e4b17023SJohn Marino name = "floorl";
2808e4b17023SJohn Marino break;
2809e4b17023SJohn Marino default:
2810e4b17023SJohn Marino gcc_unreachable ();
2811e4b17023SJohn Marino }
2812e4b17023SJohn Marino
2813e4b17023SJohn Marino fntype = build_function_type_list (TREE_TYPE (arg),
2814e4b17023SJohn Marino TREE_TYPE (arg), NULL_TREE);
2815e4b17023SJohn Marino fallback_fndecl = build_fn_decl (name, fntype);
2816e4b17023SJohn Marino }
2817e4b17023SJohn Marino
2818e4b17023SJohn Marino exp = build_call_nofold_loc (EXPR_LOCATION (exp), fallback_fndecl, 1, arg);
2819e4b17023SJohn Marino
2820e4b17023SJohn Marino tmp = expand_normal (exp);
2821e4b17023SJohn Marino
2822e4b17023SJohn Marino /* Truncate the result of floating point optab to integer
2823e4b17023SJohn Marino via expand_fix (). */
2824e4b17023SJohn Marino target = gen_reg_rtx (mode);
2825e4b17023SJohn Marino expand_fix (target, tmp, 0);
2826e4b17023SJohn Marino
2827e4b17023SJohn Marino return target;
2828e4b17023SJohn Marino }
2829e4b17023SJohn Marino
2830e4b17023SJohn Marino /* Expand a call to one of the builtin math functions doing integer
2831e4b17023SJohn Marino conversion (lrint).
2832e4b17023SJohn Marino Return 0 if a normal call should be emitted rather than expanding the
2833e4b17023SJohn Marino function in-line. EXP is the expression that is a call to the builtin
2834e4b17023SJohn Marino function; if convenient, the result should be placed in TARGET. */
2835e4b17023SJohn Marino
2836e4b17023SJohn Marino static rtx
expand_builtin_int_roundingfn_2(tree exp,rtx target)2837e4b17023SJohn Marino expand_builtin_int_roundingfn_2 (tree exp, rtx target)
2838e4b17023SJohn Marino {
2839e4b17023SJohn Marino convert_optab builtin_optab;
2840e4b17023SJohn Marino rtx op0, insns;
2841e4b17023SJohn Marino tree fndecl = get_callee_fndecl (exp);
2842e4b17023SJohn Marino tree arg;
2843e4b17023SJohn Marino enum machine_mode mode;
2844e4b17023SJohn Marino enum built_in_function fallback_fn = BUILT_IN_NONE;
2845e4b17023SJohn Marino
2846e4b17023SJohn Marino if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
2847e4b17023SJohn Marino gcc_unreachable ();
2848e4b17023SJohn Marino
2849e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 0);
2850e4b17023SJohn Marino
2851e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
2852e4b17023SJohn Marino {
2853e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IRINT):
2854e4b17023SJohn Marino fallback_fn = BUILT_IN_LRINT;
2855e4b17023SJohn Marino /* FALLTHRU */
2856e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LRINT):
2857e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLRINT):
2858e4b17023SJohn Marino builtin_optab = lrint_optab;
2859e4b17023SJohn Marino break;
2860e4b17023SJohn Marino
2861e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IROUND):
2862e4b17023SJohn Marino fallback_fn = BUILT_IN_LROUND;
2863e4b17023SJohn Marino /* FALLTHRU */
2864e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LROUND):
2865e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLROUND):
2866e4b17023SJohn Marino builtin_optab = lround_optab;
2867e4b17023SJohn Marino break;
2868e4b17023SJohn Marino
2869e4b17023SJohn Marino default:
2870e4b17023SJohn Marino gcc_unreachable ();
2871e4b17023SJohn Marino }
2872e4b17023SJohn Marino
2873e4b17023SJohn Marino /* There's no easy way to detect the case we need to set EDOM. */
2874e4b17023SJohn Marino if (flag_errno_math && fallback_fn == BUILT_IN_NONE)
2875e4b17023SJohn Marino return NULL_RTX;
2876e4b17023SJohn Marino
2877e4b17023SJohn Marino /* Make a suitable register to place result in. */
2878e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (exp));
2879e4b17023SJohn Marino
2880e4b17023SJohn Marino /* There's no easy way to detect the case we need to set EDOM. */
2881e4b17023SJohn Marino if (!flag_errno_math)
2882e4b17023SJohn Marino {
2883e4b17023SJohn Marino target = gen_reg_rtx (mode);
2884e4b17023SJohn Marino
2885e4b17023SJohn Marino /* Wrap the computation of the argument in a SAVE_EXPR, as we may
2886e4b17023SJohn Marino need to expand the argument again. This way, we will not perform
2887e4b17023SJohn Marino side-effects more the once. */
2888e4b17023SJohn Marino CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
2889e4b17023SJohn Marino
2890e4b17023SJohn Marino op0 = expand_expr (arg, NULL, VOIDmode, EXPAND_NORMAL);
2891e4b17023SJohn Marino
2892e4b17023SJohn Marino start_sequence ();
2893e4b17023SJohn Marino
2894e4b17023SJohn Marino if (expand_sfix_optab (target, op0, builtin_optab))
2895e4b17023SJohn Marino {
2896e4b17023SJohn Marino /* Output the entire sequence. */
2897e4b17023SJohn Marino insns = get_insns ();
2898e4b17023SJohn Marino end_sequence ();
2899e4b17023SJohn Marino emit_insn (insns);
2900e4b17023SJohn Marino return target;
2901e4b17023SJohn Marino }
2902e4b17023SJohn Marino
2903e4b17023SJohn Marino /* If we were unable to expand via the builtin, stop the sequence
2904e4b17023SJohn Marino (without outputting the insns) and call to the library function
2905e4b17023SJohn Marino with the stabilized argument list. */
2906e4b17023SJohn Marino end_sequence ();
2907e4b17023SJohn Marino }
2908e4b17023SJohn Marino
2909e4b17023SJohn Marino if (fallback_fn != BUILT_IN_NONE)
2910e4b17023SJohn Marino {
2911e4b17023SJohn Marino /* Fall back to rounding to long int. Use implicit_p 0 - for non-C99
2912e4b17023SJohn Marino targets, (int) round (x) should never be transformed into
2913e4b17023SJohn Marino BUILT_IN_IROUND and if __builtin_iround is called directly, emit
2914e4b17023SJohn Marino a call to lround in the hope that the target provides at least some
2915e4b17023SJohn Marino C99 functions. This should result in the best user experience for
2916e4b17023SJohn Marino not full C99 targets. */
2917e4b17023SJohn Marino tree fallback_fndecl = mathfn_built_in_1 (TREE_TYPE (arg),
2918e4b17023SJohn Marino fallback_fn, 0);
2919e4b17023SJohn Marino
2920e4b17023SJohn Marino exp = build_call_nofold_loc (EXPR_LOCATION (exp),
2921e4b17023SJohn Marino fallback_fndecl, 1, arg);
2922e4b17023SJohn Marino
2923e4b17023SJohn Marino target = expand_call (exp, NULL_RTX, target == const0_rtx);
2924e4b17023SJohn Marino return convert_to_mode (mode, target, 0);
2925e4b17023SJohn Marino }
2926e4b17023SJohn Marino
2927e4b17023SJohn Marino target = expand_call (exp, target, target == const0_rtx);
2928e4b17023SJohn Marino
2929e4b17023SJohn Marino return target;
2930e4b17023SJohn Marino }
2931e4b17023SJohn Marino
2932e4b17023SJohn Marino /* Expand a call to the powi built-in mathematical function. Return NULL_RTX if
2933e4b17023SJohn Marino a normal call should be emitted rather than expanding the function
2934e4b17023SJohn Marino in-line. EXP is the expression that is a call to the builtin
2935e4b17023SJohn Marino function; if convenient, the result should be placed in TARGET. */
2936e4b17023SJohn Marino
2937e4b17023SJohn Marino static rtx
expand_builtin_powi(tree exp,rtx target)2938e4b17023SJohn Marino expand_builtin_powi (tree exp, rtx target)
2939e4b17023SJohn Marino {
2940e4b17023SJohn Marino tree arg0, arg1;
2941e4b17023SJohn Marino rtx op0, op1;
2942e4b17023SJohn Marino enum machine_mode mode;
2943e4b17023SJohn Marino enum machine_mode mode2;
2944e4b17023SJohn Marino
2945e4b17023SJohn Marino if (! validate_arglist (exp, REAL_TYPE, INTEGER_TYPE, VOID_TYPE))
2946e4b17023SJohn Marino return NULL_RTX;
2947e4b17023SJohn Marino
2948e4b17023SJohn Marino arg0 = CALL_EXPR_ARG (exp, 0);
2949e4b17023SJohn Marino arg1 = CALL_EXPR_ARG (exp, 1);
2950e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (exp));
2951e4b17023SJohn Marino
2952e4b17023SJohn Marino /* Emit a libcall to libgcc. */
2953e4b17023SJohn Marino
2954e4b17023SJohn Marino /* Mode of the 2nd argument must match that of an int. */
2955e4b17023SJohn Marino mode2 = mode_for_size (INT_TYPE_SIZE, MODE_INT, 0);
2956e4b17023SJohn Marino
2957e4b17023SJohn Marino if (target == NULL_RTX)
2958e4b17023SJohn Marino target = gen_reg_rtx (mode);
2959e4b17023SJohn Marino
2960e4b17023SJohn Marino op0 = expand_expr (arg0, NULL_RTX, mode, EXPAND_NORMAL);
2961e4b17023SJohn Marino if (GET_MODE (op0) != mode)
2962e4b17023SJohn Marino op0 = convert_to_mode (mode, op0, 0);
2963e4b17023SJohn Marino op1 = expand_expr (arg1, NULL_RTX, mode2, EXPAND_NORMAL);
2964e4b17023SJohn Marino if (GET_MODE (op1) != mode2)
2965e4b17023SJohn Marino op1 = convert_to_mode (mode2, op1, 0);
2966e4b17023SJohn Marino
2967e4b17023SJohn Marino target = emit_library_call_value (optab_libfunc (powi_optab, mode),
2968e4b17023SJohn Marino target, LCT_CONST, mode, 2,
2969e4b17023SJohn Marino op0, mode, op1, mode2);
2970e4b17023SJohn Marino
2971e4b17023SJohn Marino return target;
2972e4b17023SJohn Marino }
2973e4b17023SJohn Marino
2974e4b17023SJohn Marino /* Expand expression EXP which is a call to the strlen builtin. Return
2975e4b17023SJohn Marino NULL_RTX if we failed the caller should emit a normal call, otherwise
2976e4b17023SJohn Marino try to get the result in TARGET, if convenient. */
2977e4b17023SJohn Marino
2978e4b17023SJohn Marino static rtx
expand_builtin_strlen(tree exp,rtx target,enum machine_mode target_mode)2979e4b17023SJohn Marino expand_builtin_strlen (tree exp, rtx target,
2980e4b17023SJohn Marino enum machine_mode target_mode)
2981e4b17023SJohn Marino {
2982e4b17023SJohn Marino if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
2983e4b17023SJohn Marino return NULL_RTX;
2984e4b17023SJohn Marino else
2985e4b17023SJohn Marino {
2986e4b17023SJohn Marino struct expand_operand ops[4];
2987e4b17023SJohn Marino rtx pat;
2988e4b17023SJohn Marino tree len;
2989e4b17023SJohn Marino tree src = CALL_EXPR_ARG (exp, 0);
2990e4b17023SJohn Marino rtx src_reg, before_strlen;
2991e4b17023SJohn Marino enum machine_mode insn_mode = target_mode;
2992e4b17023SJohn Marino enum insn_code icode = CODE_FOR_nothing;
2993e4b17023SJohn Marino unsigned int align;
2994e4b17023SJohn Marino
2995e4b17023SJohn Marino /* If the length can be computed at compile-time, return it. */
2996e4b17023SJohn Marino len = c_strlen (src, 0);
2997e4b17023SJohn Marino if (len)
2998e4b17023SJohn Marino return expand_expr (len, target, target_mode, EXPAND_NORMAL);
2999e4b17023SJohn Marino
3000e4b17023SJohn Marino /* If the length can be computed at compile-time and is constant
3001e4b17023SJohn Marino integer, but there are side-effects in src, evaluate
3002e4b17023SJohn Marino src for side-effects, then return len.
3003e4b17023SJohn Marino E.g. x = strlen (i++ ? "xfoo" + 1 : "bar");
3004e4b17023SJohn Marino can be optimized into: i++; x = 3; */
3005e4b17023SJohn Marino len = c_strlen (src, 1);
3006e4b17023SJohn Marino if (len && TREE_CODE (len) == INTEGER_CST)
3007e4b17023SJohn Marino {
3008e4b17023SJohn Marino expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
3009e4b17023SJohn Marino return expand_expr (len, target, target_mode, EXPAND_NORMAL);
3010e4b17023SJohn Marino }
3011e4b17023SJohn Marino
3012e4b17023SJohn Marino align = get_pointer_alignment (src) / BITS_PER_UNIT;
3013e4b17023SJohn Marino
3014e4b17023SJohn Marino /* If SRC is not a pointer type, don't do this operation inline. */
3015e4b17023SJohn Marino if (align == 0)
3016e4b17023SJohn Marino return NULL_RTX;
3017e4b17023SJohn Marino
3018e4b17023SJohn Marino /* Bail out if we can't compute strlen in the right mode. */
3019e4b17023SJohn Marino while (insn_mode != VOIDmode)
3020e4b17023SJohn Marino {
3021e4b17023SJohn Marino icode = optab_handler (strlen_optab, insn_mode);
3022e4b17023SJohn Marino if (icode != CODE_FOR_nothing)
3023e4b17023SJohn Marino break;
3024e4b17023SJohn Marino
3025e4b17023SJohn Marino insn_mode = GET_MODE_WIDER_MODE (insn_mode);
3026e4b17023SJohn Marino }
3027e4b17023SJohn Marino if (insn_mode == VOIDmode)
3028e4b17023SJohn Marino return NULL_RTX;
3029e4b17023SJohn Marino
3030e4b17023SJohn Marino /* Make a place to hold the source address. We will not expand
3031e4b17023SJohn Marino the actual source until we are sure that the expansion will
3032e4b17023SJohn Marino not fail -- there are trees that cannot be expanded twice. */
3033e4b17023SJohn Marino src_reg = gen_reg_rtx (Pmode);
3034e4b17023SJohn Marino
3035e4b17023SJohn Marino /* Mark the beginning of the strlen sequence so we can emit the
3036e4b17023SJohn Marino source operand later. */
3037e4b17023SJohn Marino before_strlen = get_last_insn ();
3038e4b17023SJohn Marino
3039e4b17023SJohn Marino create_output_operand (&ops[0], target, insn_mode);
3040e4b17023SJohn Marino create_fixed_operand (&ops[1], gen_rtx_MEM (BLKmode, src_reg));
3041e4b17023SJohn Marino create_integer_operand (&ops[2], 0);
3042e4b17023SJohn Marino create_integer_operand (&ops[3], align);
3043e4b17023SJohn Marino if (!maybe_expand_insn (icode, 4, ops))
3044e4b17023SJohn Marino return NULL_RTX;
3045e4b17023SJohn Marino
3046e4b17023SJohn Marino /* Now that we are assured of success, expand the source. */
3047e4b17023SJohn Marino start_sequence ();
3048e4b17023SJohn Marino pat = expand_expr (src, src_reg, Pmode, EXPAND_NORMAL);
3049e4b17023SJohn Marino if (pat != src_reg)
3050e4b17023SJohn Marino {
3051e4b17023SJohn Marino #ifdef POINTERS_EXTEND_UNSIGNED
3052e4b17023SJohn Marino if (GET_MODE (pat) != Pmode)
3053e4b17023SJohn Marino pat = convert_to_mode (Pmode, pat,
3054e4b17023SJohn Marino POINTERS_EXTEND_UNSIGNED);
3055e4b17023SJohn Marino #endif
3056e4b17023SJohn Marino emit_move_insn (src_reg, pat);
3057e4b17023SJohn Marino }
3058e4b17023SJohn Marino pat = get_insns ();
3059e4b17023SJohn Marino end_sequence ();
3060e4b17023SJohn Marino
3061e4b17023SJohn Marino if (before_strlen)
3062e4b17023SJohn Marino emit_insn_after (pat, before_strlen);
3063e4b17023SJohn Marino else
3064e4b17023SJohn Marino emit_insn_before (pat, get_insns ());
3065e4b17023SJohn Marino
3066e4b17023SJohn Marino /* Return the value in the proper mode for this function. */
3067e4b17023SJohn Marino if (GET_MODE (ops[0].value) == target_mode)
3068e4b17023SJohn Marino target = ops[0].value;
3069e4b17023SJohn Marino else if (target != 0)
3070e4b17023SJohn Marino convert_move (target, ops[0].value, 0);
3071e4b17023SJohn Marino else
3072e4b17023SJohn Marino target = convert_to_mode (target_mode, ops[0].value, 0);
3073e4b17023SJohn Marino
3074e4b17023SJohn Marino return target;
3075e4b17023SJohn Marino }
3076e4b17023SJohn Marino }
3077e4b17023SJohn Marino
3078e4b17023SJohn Marino /* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
3079e4b17023SJohn Marino bytes from constant string DATA + OFFSET and return it as target
3080e4b17023SJohn Marino constant. */
3081e4b17023SJohn Marino
3082e4b17023SJohn Marino static rtx
builtin_memcpy_read_str(void * data,HOST_WIDE_INT offset,enum machine_mode mode)3083e4b17023SJohn Marino builtin_memcpy_read_str (void *data, HOST_WIDE_INT offset,
3084e4b17023SJohn Marino enum machine_mode mode)
3085e4b17023SJohn Marino {
3086e4b17023SJohn Marino const char *str = (const char *) data;
3087e4b17023SJohn Marino
3088e4b17023SJohn Marino gcc_assert (offset >= 0
3089e4b17023SJohn Marino && ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode)
3090e4b17023SJohn Marino <= strlen (str) + 1));
3091e4b17023SJohn Marino
3092e4b17023SJohn Marino return c_readstr (str + offset, mode);
3093e4b17023SJohn Marino }
3094e4b17023SJohn Marino
3095e4b17023SJohn Marino /* Expand a call EXP to the memcpy builtin.
3096e4b17023SJohn Marino Return NULL_RTX if we failed, the caller should emit a normal call,
3097e4b17023SJohn Marino otherwise try to get the result in TARGET, if convenient (and in
3098e4b17023SJohn Marino mode MODE if that's convenient). */
3099e4b17023SJohn Marino
3100e4b17023SJohn Marino static rtx
expand_builtin_memcpy(tree exp,rtx target)3101e4b17023SJohn Marino expand_builtin_memcpy (tree exp, rtx target)
3102e4b17023SJohn Marino {
3103e4b17023SJohn Marino if (!validate_arglist (exp,
3104e4b17023SJohn Marino POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
3105e4b17023SJohn Marino return NULL_RTX;
3106e4b17023SJohn Marino else
3107e4b17023SJohn Marino {
3108e4b17023SJohn Marino tree dest = CALL_EXPR_ARG (exp, 0);
3109e4b17023SJohn Marino tree src = CALL_EXPR_ARG (exp, 1);
3110e4b17023SJohn Marino tree len = CALL_EXPR_ARG (exp, 2);
3111e4b17023SJohn Marino const char *src_str;
3112e4b17023SJohn Marino unsigned int src_align = get_pointer_alignment (src);
3113e4b17023SJohn Marino unsigned int dest_align = get_pointer_alignment (dest);
3114e4b17023SJohn Marino rtx dest_mem, src_mem, dest_addr, len_rtx;
3115e4b17023SJohn Marino HOST_WIDE_INT expected_size = -1;
3116e4b17023SJohn Marino unsigned int expected_align = 0;
3117e4b17023SJohn Marino
3118e4b17023SJohn Marino /* If DEST is not a pointer type, call the normal function. */
3119e4b17023SJohn Marino if (dest_align == 0)
3120e4b17023SJohn Marino return NULL_RTX;
3121e4b17023SJohn Marino
3122e4b17023SJohn Marino /* If either SRC is not a pointer type, don't do this
3123e4b17023SJohn Marino operation in-line. */
3124e4b17023SJohn Marino if (src_align == 0)
3125e4b17023SJohn Marino return NULL_RTX;
3126e4b17023SJohn Marino
3127e4b17023SJohn Marino if (currently_expanding_gimple_stmt)
3128e4b17023SJohn Marino stringop_block_profile (currently_expanding_gimple_stmt,
3129e4b17023SJohn Marino &expected_align, &expected_size);
3130e4b17023SJohn Marino
3131e4b17023SJohn Marino if (expected_align < dest_align)
3132e4b17023SJohn Marino expected_align = dest_align;
3133e4b17023SJohn Marino dest_mem = get_memory_rtx (dest, len);
3134e4b17023SJohn Marino set_mem_align (dest_mem, dest_align);
3135e4b17023SJohn Marino len_rtx = expand_normal (len);
3136e4b17023SJohn Marino src_str = c_getstr (src);
3137e4b17023SJohn Marino
3138e4b17023SJohn Marino /* If SRC is a string constant and block move would be done
3139e4b17023SJohn Marino by pieces, we can avoid loading the string from memory
3140e4b17023SJohn Marino and only stored the computed constants. */
3141e4b17023SJohn Marino if (src_str
3142e4b17023SJohn Marino && CONST_INT_P (len_rtx)
3143e4b17023SJohn Marino && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
3144e4b17023SJohn Marino && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
3145e4b17023SJohn Marino CONST_CAST (char *, src_str),
3146e4b17023SJohn Marino dest_align, false))
3147e4b17023SJohn Marino {
3148e4b17023SJohn Marino dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
3149e4b17023SJohn Marino builtin_memcpy_read_str,
3150e4b17023SJohn Marino CONST_CAST (char *, src_str),
3151e4b17023SJohn Marino dest_align, false, 0);
3152e4b17023SJohn Marino dest_mem = force_operand (XEXP (dest_mem, 0), target);
3153e4b17023SJohn Marino dest_mem = convert_memory_address (ptr_mode, dest_mem);
3154e4b17023SJohn Marino return dest_mem;
3155e4b17023SJohn Marino }
3156e4b17023SJohn Marino
3157e4b17023SJohn Marino src_mem = get_memory_rtx (src, len);
3158e4b17023SJohn Marino set_mem_align (src_mem, src_align);
3159e4b17023SJohn Marino
3160e4b17023SJohn Marino /* Copy word part most expediently. */
3161e4b17023SJohn Marino dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx,
3162e4b17023SJohn Marino CALL_EXPR_TAILCALL (exp)
3163e4b17023SJohn Marino ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL,
3164e4b17023SJohn Marino expected_align, expected_size);
3165e4b17023SJohn Marino
3166e4b17023SJohn Marino if (dest_addr == 0)
3167e4b17023SJohn Marino {
3168e4b17023SJohn Marino dest_addr = force_operand (XEXP (dest_mem, 0), target);
3169e4b17023SJohn Marino dest_addr = convert_memory_address (ptr_mode, dest_addr);
3170e4b17023SJohn Marino }
3171e4b17023SJohn Marino return dest_addr;
3172e4b17023SJohn Marino }
3173e4b17023SJohn Marino }
3174e4b17023SJohn Marino
3175e4b17023SJohn Marino /* Expand a call EXP to the mempcpy builtin.
3176e4b17023SJohn Marino Return NULL_RTX if we failed; the caller should emit a normal call,
3177e4b17023SJohn Marino otherwise try to get the result in TARGET, if convenient (and in
3178e4b17023SJohn Marino mode MODE if that's convenient). If ENDP is 0 return the
3179e4b17023SJohn Marino destination pointer, if ENDP is 1 return the end pointer ala
3180e4b17023SJohn Marino mempcpy, and if ENDP is 2 return the end pointer minus one ala
3181e4b17023SJohn Marino stpcpy. */
3182e4b17023SJohn Marino
3183e4b17023SJohn Marino static rtx
expand_builtin_mempcpy(tree exp,rtx target,enum machine_mode mode)3184e4b17023SJohn Marino expand_builtin_mempcpy (tree exp, rtx target, enum machine_mode mode)
3185e4b17023SJohn Marino {
3186e4b17023SJohn Marino if (!validate_arglist (exp,
3187e4b17023SJohn Marino POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
3188e4b17023SJohn Marino return NULL_RTX;
3189e4b17023SJohn Marino else
3190e4b17023SJohn Marino {
3191e4b17023SJohn Marino tree dest = CALL_EXPR_ARG (exp, 0);
3192e4b17023SJohn Marino tree src = CALL_EXPR_ARG (exp, 1);
3193e4b17023SJohn Marino tree len = CALL_EXPR_ARG (exp, 2);
3194e4b17023SJohn Marino return expand_builtin_mempcpy_args (dest, src, len,
3195e4b17023SJohn Marino target, mode, /*endp=*/ 1);
3196e4b17023SJohn Marino }
3197e4b17023SJohn Marino }
3198e4b17023SJohn Marino
3199e4b17023SJohn Marino /* Helper function to do the actual work for expand_builtin_mempcpy. The
3200e4b17023SJohn Marino arguments to the builtin_mempcpy call DEST, SRC, and LEN are broken out
3201e4b17023SJohn Marino so that this can also be called without constructing an actual CALL_EXPR.
3202e4b17023SJohn Marino The other arguments and return value are the same as for
3203e4b17023SJohn Marino expand_builtin_mempcpy. */
3204e4b17023SJohn Marino
3205e4b17023SJohn Marino static rtx
expand_builtin_mempcpy_args(tree dest,tree src,tree len,rtx target,enum machine_mode mode,int endp)3206e4b17023SJohn Marino expand_builtin_mempcpy_args (tree dest, tree src, tree len,
3207e4b17023SJohn Marino rtx target, enum machine_mode mode, int endp)
3208e4b17023SJohn Marino {
3209e4b17023SJohn Marino /* If return value is ignored, transform mempcpy into memcpy. */
3210e4b17023SJohn Marino if (target == const0_rtx && builtin_decl_implicit_p (BUILT_IN_MEMCPY))
3211e4b17023SJohn Marino {
3212e4b17023SJohn Marino tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
3213e4b17023SJohn Marino tree result = build_call_nofold_loc (UNKNOWN_LOCATION, fn, 3,
3214e4b17023SJohn Marino dest, src, len);
3215e4b17023SJohn Marino return expand_expr (result, target, mode, EXPAND_NORMAL);
3216e4b17023SJohn Marino }
3217e4b17023SJohn Marino else
3218e4b17023SJohn Marino {
3219e4b17023SJohn Marino const char *src_str;
3220e4b17023SJohn Marino unsigned int src_align = get_pointer_alignment (src);
3221e4b17023SJohn Marino unsigned int dest_align = get_pointer_alignment (dest);
3222e4b17023SJohn Marino rtx dest_mem, src_mem, len_rtx;
3223e4b17023SJohn Marino
3224e4b17023SJohn Marino /* If either SRC or DEST is not a pointer type, don't do this
3225e4b17023SJohn Marino operation in-line. */
3226e4b17023SJohn Marino if (dest_align == 0 || src_align == 0)
3227e4b17023SJohn Marino return NULL_RTX;
3228e4b17023SJohn Marino
3229e4b17023SJohn Marino /* If LEN is not constant, call the normal function. */
3230e4b17023SJohn Marino if (! host_integerp (len, 1))
3231e4b17023SJohn Marino return NULL_RTX;
3232e4b17023SJohn Marino
3233e4b17023SJohn Marino len_rtx = expand_normal (len);
3234e4b17023SJohn Marino src_str = c_getstr (src);
3235e4b17023SJohn Marino
3236e4b17023SJohn Marino /* If SRC is a string constant and block move would be done
3237e4b17023SJohn Marino by pieces, we can avoid loading the string from memory
3238e4b17023SJohn Marino and only stored the computed constants. */
3239e4b17023SJohn Marino if (src_str
3240e4b17023SJohn Marino && CONST_INT_P (len_rtx)
3241e4b17023SJohn Marino && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
3242e4b17023SJohn Marino && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
3243e4b17023SJohn Marino CONST_CAST (char *, src_str),
3244e4b17023SJohn Marino dest_align, false))
3245e4b17023SJohn Marino {
3246e4b17023SJohn Marino dest_mem = get_memory_rtx (dest, len);
3247e4b17023SJohn Marino set_mem_align (dest_mem, dest_align);
3248e4b17023SJohn Marino dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
3249e4b17023SJohn Marino builtin_memcpy_read_str,
3250e4b17023SJohn Marino CONST_CAST (char *, src_str),
3251e4b17023SJohn Marino dest_align, false, endp);
3252e4b17023SJohn Marino dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
3253e4b17023SJohn Marino dest_mem = convert_memory_address (ptr_mode, dest_mem);
3254e4b17023SJohn Marino return dest_mem;
3255e4b17023SJohn Marino }
3256e4b17023SJohn Marino
3257e4b17023SJohn Marino if (CONST_INT_P (len_rtx)
3258e4b17023SJohn Marino && can_move_by_pieces (INTVAL (len_rtx),
3259e4b17023SJohn Marino MIN (dest_align, src_align)))
3260e4b17023SJohn Marino {
3261e4b17023SJohn Marino dest_mem = get_memory_rtx (dest, len);
3262e4b17023SJohn Marino set_mem_align (dest_mem, dest_align);
3263e4b17023SJohn Marino src_mem = get_memory_rtx (src, len);
3264e4b17023SJohn Marino set_mem_align (src_mem, src_align);
3265e4b17023SJohn Marino dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx),
3266e4b17023SJohn Marino MIN (dest_align, src_align), endp);
3267e4b17023SJohn Marino dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
3268e4b17023SJohn Marino dest_mem = convert_memory_address (ptr_mode, dest_mem);
3269e4b17023SJohn Marino return dest_mem;
3270e4b17023SJohn Marino }
3271e4b17023SJohn Marino
3272e4b17023SJohn Marino return NULL_RTX;
3273e4b17023SJohn Marino }
3274e4b17023SJohn Marino }
3275e4b17023SJohn Marino
3276e4b17023SJohn Marino #ifndef HAVE_movstr
3277e4b17023SJohn Marino # define HAVE_movstr 0
3278e4b17023SJohn Marino # define CODE_FOR_movstr CODE_FOR_nothing
3279e4b17023SJohn Marino #endif
3280e4b17023SJohn Marino
3281e4b17023SJohn Marino /* Expand into a movstr instruction, if one is available. Return NULL_RTX if
3282e4b17023SJohn Marino we failed, the caller should emit a normal call, otherwise try to
3283e4b17023SJohn Marino get the result in TARGET, if convenient. If ENDP is 0 return the
3284e4b17023SJohn Marino destination pointer, if ENDP is 1 return the end pointer ala
3285e4b17023SJohn Marino mempcpy, and if ENDP is 2 return the end pointer minus one ala
3286e4b17023SJohn Marino stpcpy. */
3287e4b17023SJohn Marino
3288e4b17023SJohn Marino static rtx
expand_movstr(tree dest,tree src,rtx target,int endp)3289e4b17023SJohn Marino expand_movstr (tree dest, tree src, rtx target, int endp)
3290e4b17023SJohn Marino {
3291e4b17023SJohn Marino struct expand_operand ops[3];
3292e4b17023SJohn Marino rtx dest_mem;
3293e4b17023SJohn Marino rtx src_mem;
3294e4b17023SJohn Marino
3295e4b17023SJohn Marino if (!HAVE_movstr)
3296e4b17023SJohn Marino return NULL_RTX;
3297e4b17023SJohn Marino
3298e4b17023SJohn Marino dest_mem = get_memory_rtx (dest, NULL);
3299e4b17023SJohn Marino src_mem = get_memory_rtx (src, NULL);
3300e4b17023SJohn Marino if (!endp)
3301e4b17023SJohn Marino {
3302e4b17023SJohn Marino target = force_reg (Pmode, XEXP (dest_mem, 0));
3303e4b17023SJohn Marino dest_mem = replace_equiv_address (dest_mem, target);
3304e4b17023SJohn Marino }
3305e4b17023SJohn Marino
3306e4b17023SJohn Marino create_output_operand (&ops[0], endp ? target : NULL_RTX, Pmode);
3307e4b17023SJohn Marino create_fixed_operand (&ops[1], dest_mem);
3308e4b17023SJohn Marino create_fixed_operand (&ops[2], src_mem);
3309e4b17023SJohn Marino expand_insn (CODE_FOR_movstr, 3, ops);
3310e4b17023SJohn Marino
3311e4b17023SJohn Marino if (endp && target != const0_rtx)
3312e4b17023SJohn Marino {
3313e4b17023SJohn Marino target = ops[0].value;
3314e4b17023SJohn Marino /* movstr is supposed to set end to the address of the NUL
3315e4b17023SJohn Marino terminator. If the caller requested a mempcpy-like return value,
3316e4b17023SJohn Marino adjust it. */
3317e4b17023SJohn Marino if (endp == 1)
3318e4b17023SJohn Marino {
3319e4b17023SJohn Marino rtx tem = plus_constant (gen_lowpart (GET_MODE (target), target), 1);
3320e4b17023SJohn Marino emit_move_insn (target, force_operand (tem, NULL_RTX));
3321e4b17023SJohn Marino }
3322e4b17023SJohn Marino }
3323e4b17023SJohn Marino return target;
3324e4b17023SJohn Marino }
3325e4b17023SJohn Marino
3326e4b17023SJohn Marino /* Expand expression EXP, which is a call to the strcpy builtin. Return
3327e4b17023SJohn Marino NULL_RTX if we failed the caller should emit a normal call, otherwise
3328e4b17023SJohn Marino try to get the result in TARGET, if convenient (and in mode MODE if that's
3329e4b17023SJohn Marino convenient). */
3330e4b17023SJohn Marino
3331e4b17023SJohn Marino static rtx
expand_builtin_strcpy(tree exp,rtx target)3332e4b17023SJohn Marino expand_builtin_strcpy (tree exp, rtx target)
3333e4b17023SJohn Marino {
3334e4b17023SJohn Marino if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
3335e4b17023SJohn Marino {
3336e4b17023SJohn Marino tree dest = CALL_EXPR_ARG (exp, 0);
3337e4b17023SJohn Marino tree src = CALL_EXPR_ARG (exp, 1);
3338e4b17023SJohn Marino return expand_builtin_strcpy_args (dest, src, target);
3339e4b17023SJohn Marino }
3340e4b17023SJohn Marino return NULL_RTX;
3341e4b17023SJohn Marino }
3342e4b17023SJohn Marino
3343e4b17023SJohn Marino /* Helper function to do the actual work for expand_builtin_strcpy. The
3344e4b17023SJohn Marino arguments to the builtin_strcpy call DEST and SRC are broken out
3345e4b17023SJohn Marino so that this can also be called without constructing an actual CALL_EXPR.
3346e4b17023SJohn Marino The other arguments and return value are the same as for
3347e4b17023SJohn Marino expand_builtin_strcpy. */
3348e4b17023SJohn Marino
3349e4b17023SJohn Marino static rtx
expand_builtin_strcpy_args(tree dest,tree src,rtx target)3350e4b17023SJohn Marino expand_builtin_strcpy_args (tree dest, tree src, rtx target)
3351e4b17023SJohn Marino {
3352e4b17023SJohn Marino return expand_movstr (dest, src, target, /*endp=*/0);
3353e4b17023SJohn Marino }
3354e4b17023SJohn Marino
3355e4b17023SJohn Marino /* Expand a call EXP to the stpcpy builtin.
3356e4b17023SJohn Marino Return NULL_RTX if we failed the caller should emit a normal call,
3357e4b17023SJohn Marino otherwise try to get the result in TARGET, if convenient (and in
3358e4b17023SJohn Marino mode MODE if that's convenient). */
3359e4b17023SJohn Marino
3360e4b17023SJohn Marino static rtx
expand_builtin_stpcpy(tree exp,rtx target,enum machine_mode mode)3361e4b17023SJohn Marino expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode)
3362e4b17023SJohn Marino {
3363e4b17023SJohn Marino tree dst, src;
3364e4b17023SJohn Marino location_t loc = EXPR_LOCATION (exp);
3365e4b17023SJohn Marino
3366e4b17023SJohn Marino if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
3367e4b17023SJohn Marino return NULL_RTX;
3368e4b17023SJohn Marino
3369e4b17023SJohn Marino dst = CALL_EXPR_ARG (exp, 0);
3370e4b17023SJohn Marino src = CALL_EXPR_ARG (exp, 1);
3371e4b17023SJohn Marino
3372e4b17023SJohn Marino /* If return value is ignored, transform stpcpy into strcpy. */
3373e4b17023SJohn Marino if (target == const0_rtx && builtin_decl_implicit (BUILT_IN_STRCPY))
3374e4b17023SJohn Marino {
3375e4b17023SJohn Marino tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
3376e4b17023SJohn Marino tree result = build_call_nofold_loc (loc, fn, 2, dst, src);
3377e4b17023SJohn Marino return expand_expr (result, target, mode, EXPAND_NORMAL);
3378e4b17023SJohn Marino }
3379e4b17023SJohn Marino else
3380e4b17023SJohn Marino {
3381e4b17023SJohn Marino tree len, lenp1;
3382e4b17023SJohn Marino rtx ret;
3383e4b17023SJohn Marino
3384e4b17023SJohn Marino /* Ensure we get an actual string whose length can be evaluated at
3385e4b17023SJohn Marino compile-time, not an expression containing a string. This is
3386e4b17023SJohn Marino because the latter will potentially produce pessimized code
3387e4b17023SJohn Marino when used to produce the return value. */
3388e4b17023SJohn Marino if (! c_getstr (src) || ! (len = c_strlen (src, 0)))
3389e4b17023SJohn Marino return expand_movstr (dst, src, target, /*endp=*/2);
3390e4b17023SJohn Marino
3391e4b17023SJohn Marino lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
3392e4b17023SJohn Marino ret = expand_builtin_mempcpy_args (dst, src, lenp1,
3393e4b17023SJohn Marino target, mode, /*endp=*/2);
3394e4b17023SJohn Marino
3395e4b17023SJohn Marino if (ret)
3396e4b17023SJohn Marino return ret;
3397e4b17023SJohn Marino
3398e4b17023SJohn Marino if (TREE_CODE (len) == INTEGER_CST)
3399e4b17023SJohn Marino {
3400e4b17023SJohn Marino rtx len_rtx = expand_normal (len);
3401e4b17023SJohn Marino
3402e4b17023SJohn Marino if (CONST_INT_P (len_rtx))
3403e4b17023SJohn Marino {
3404e4b17023SJohn Marino ret = expand_builtin_strcpy_args (dst, src, target);
3405e4b17023SJohn Marino
3406e4b17023SJohn Marino if (ret)
3407e4b17023SJohn Marino {
3408e4b17023SJohn Marino if (! target)
3409e4b17023SJohn Marino {
3410e4b17023SJohn Marino if (mode != VOIDmode)
3411e4b17023SJohn Marino target = gen_reg_rtx (mode);
3412e4b17023SJohn Marino else
3413e4b17023SJohn Marino target = gen_reg_rtx (GET_MODE (ret));
3414e4b17023SJohn Marino }
3415e4b17023SJohn Marino if (GET_MODE (target) != GET_MODE (ret))
3416e4b17023SJohn Marino ret = gen_lowpart (GET_MODE (target), ret);
3417e4b17023SJohn Marino
3418e4b17023SJohn Marino ret = plus_constant (ret, INTVAL (len_rtx));
3419e4b17023SJohn Marino ret = emit_move_insn (target, force_operand (ret, NULL_RTX));
3420e4b17023SJohn Marino gcc_assert (ret);
3421e4b17023SJohn Marino
3422e4b17023SJohn Marino return target;
3423e4b17023SJohn Marino }
3424e4b17023SJohn Marino }
3425e4b17023SJohn Marino }
3426e4b17023SJohn Marino
3427e4b17023SJohn Marino return expand_movstr (dst, src, target, /*endp=*/2);
3428e4b17023SJohn Marino }
3429e4b17023SJohn Marino }
3430e4b17023SJohn Marino
3431e4b17023SJohn Marino /* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
3432e4b17023SJohn Marino bytes from constant string DATA + OFFSET and return it as target
3433e4b17023SJohn Marino constant. */
3434e4b17023SJohn Marino
3435e4b17023SJohn Marino rtx
builtin_strncpy_read_str(void * data,HOST_WIDE_INT offset,enum machine_mode mode)3436e4b17023SJohn Marino builtin_strncpy_read_str (void *data, HOST_WIDE_INT offset,
3437e4b17023SJohn Marino enum machine_mode mode)
3438e4b17023SJohn Marino {
3439e4b17023SJohn Marino const char *str = (const char *) data;
3440e4b17023SJohn Marino
3441e4b17023SJohn Marino if ((unsigned HOST_WIDE_INT) offset > strlen (str))
3442e4b17023SJohn Marino return const0_rtx;
3443e4b17023SJohn Marino
3444e4b17023SJohn Marino return c_readstr (str + offset, mode);
3445e4b17023SJohn Marino }
3446e4b17023SJohn Marino
3447e4b17023SJohn Marino /* Expand expression EXP, which is a call to the strncpy builtin. Return
3448e4b17023SJohn Marino NULL_RTX if we failed the caller should emit a normal call. */
3449e4b17023SJohn Marino
3450e4b17023SJohn Marino static rtx
expand_builtin_strncpy(tree exp,rtx target)3451e4b17023SJohn Marino expand_builtin_strncpy (tree exp, rtx target)
3452e4b17023SJohn Marino {
3453e4b17023SJohn Marino location_t loc = EXPR_LOCATION (exp);
3454e4b17023SJohn Marino
3455e4b17023SJohn Marino if (validate_arglist (exp,
3456e4b17023SJohn Marino POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
3457e4b17023SJohn Marino {
3458e4b17023SJohn Marino tree dest = CALL_EXPR_ARG (exp, 0);
3459e4b17023SJohn Marino tree src = CALL_EXPR_ARG (exp, 1);
3460e4b17023SJohn Marino tree len = CALL_EXPR_ARG (exp, 2);
3461e4b17023SJohn Marino tree slen = c_strlen (src, 1);
3462e4b17023SJohn Marino
3463e4b17023SJohn Marino /* We must be passed a constant len and src parameter. */
3464e4b17023SJohn Marino if (!host_integerp (len, 1) || !slen || !host_integerp (slen, 1))
3465e4b17023SJohn Marino return NULL_RTX;
3466e4b17023SJohn Marino
3467e4b17023SJohn Marino slen = size_binop_loc (loc, PLUS_EXPR, slen, ssize_int (1));
3468e4b17023SJohn Marino
3469e4b17023SJohn Marino /* We're required to pad with trailing zeros if the requested
3470e4b17023SJohn Marino len is greater than strlen(s2)+1. In that case try to
3471e4b17023SJohn Marino use store_by_pieces, if it fails, punt. */
3472e4b17023SJohn Marino if (tree_int_cst_lt (slen, len))
3473e4b17023SJohn Marino {
3474e4b17023SJohn Marino unsigned int dest_align = get_pointer_alignment (dest);
3475e4b17023SJohn Marino const char *p = c_getstr (src);
3476e4b17023SJohn Marino rtx dest_mem;
3477e4b17023SJohn Marino
3478e4b17023SJohn Marino if (!p || dest_align == 0 || !host_integerp (len, 1)
3479e4b17023SJohn Marino || !can_store_by_pieces (tree_low_cst (len, 1),
3480e4b17023SJohn Marino builtin_strncpy_read_str,
3481e4b17023SJohn Marino CONST_CAST (char *, p),
3482e4b17023SJohn Marino dest_align, false))
3483e4b17023SJohn Marino return NULL_RTX;
3484e4b17023SJohn Marino
3485e4b17023SJohn Marino dest_mem = get_memory_rtx (dest, len);
3486e4b17023SJohn Marino store_by_pieces (dest_mem, tree_low_cst (len, 1),
3487e4b17023SJohn Marino builtin_strncpy_read_str,
3488e4b17023SJohn Marino CONST_CAST (char *, p), dest_align, false, 0);
3489e4b17023SJohn Marino dest_mem = force_operand (XEXP (dest_mem, 0), target);
3490e4b17023SJohn Marino dest_mem = convert_memory_address (ptr_mode, dest_mem);
3491e4b17023SJohn Marino return dest_mem;
3492e4b17023SJohn Marino }
3493e4b17023SJohn Marino }
3494e4b17023SJohn Marino return NULL_RTX;
3495e4b17023SJohn Marino }
3496e4b17023SJohn Marino
3497e4b17023SJohn Marino /* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
3498e4b17023SJohn Marino bytes from constant string DATA + OFFSET and return it as target
3499e4b17023SJohn Marino constant. */
3500e4b17023SJohn Marino
3501e4b17023SJohn Marino rtx
builtin_memset_read_str(void * data,HOST_WIDE_INT offset ATTRIBUTE_UNUSED,enum machine_mode mode)3502e4b17023SJohn Marino builtin_memset_read_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
3503e4b17023SJohn Marino enum machine_mode mode)
3504e4b17023SJohn Marino {
3505e4b17023SJohn Marino const char *c = (const char *) data;
3506e4b17023SJohn Marino char *p = XALLOCAVEC (char, GET_MODE_SIZE (mode));
3507e4b17023SJohn Marino
3508e4b17023SJohn Marino memset (p, *c, GET_MODE_SIZE (mode));
3509e4b17023SJohn Marino
3510e4b17023SJohn Marino return c_readstr (p, mode);
3511e4b17023SJohn Marino }
3512e4b17023SJohn Marino
3513e4b17023SJohn Marino /* Callback routine for store_by_pieces. Return the RTL of a register
3514e4b17023SJohn Marino containing GET_MODE_SIZE (MODE) consecutive copies of the unsigned
3515e4b17023SJohn Marino char value given in the RTL register data. For example, if mode is
3516e4b17023SJohn Marino 4 bytes wide, return the RTL for 0x01010101*data. */
3517e4b17023SJohn Marino
3518e4b17023SJohn Marino static rtx
builtin_memset_gen_str(void * data,HOST_WIDE_INT offset ATTRIBUTE_UNUSED,enum machine_mode mode)3519e4b17023SJohn Marino builtin_memset_gen_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
3520e4b17023SJohn Marino enum machine_mode mode)
3521e4b17023SJohn Marino {
3522e4b17023SJohn Marino rtx target, coeff;
3523e4b17023SJohn Marino size_t size;
3524e4b17023SJohn Marino char *p;
3525e4b17023SJohn Marino
3526e4b17023SJohn Marino size = GET_MODE_SIZE (mode);
3527e4b17023SJohn Marino if (size == 1)
3528e4b17023SJohn Marino return (rtx) data;
3529e4b17023SJohn Marino
3530e4b17023SJohn Marino p = XALLOCAVEC (char, size);
3531e4b17023SJohn Marino memset (p, 1, size);
3532e4b17023SJohn Marino coeff = c_readstr (p, mode);
3533e4b17023SJohn Marino
3534e4b17023SJohn Marino target = convert_to_mode (mode, (rtx) data, 1);
3535e4b17023SJohn Marino target = expand_mult (mode, target, coeff, NULL_RTX, 1);
3536e4b17023SJohn Marino return force_reg (mode, target);
3537e4b17023SJohn Marino }
3538e4b17023SJohn Marino
3539e4b17023SJohn Marino /* Expand expression EXP, which is a call to the memset builtin. Return
3540e4b17023SJohn Marino NULL_RTX if we failed the caller should emit a normal call, otherwise
3541e4b17023SJohn Marino try to get the result in TARGET, if convenient (and in mode MODE if that's
3542e4b17023SJohn Marino convenient). */
3543e4b17023SJohn Marino
3544e4b17023SJohn Marino static rtx
expand_builtin_memset(tree exp,rtx target,enum machine_mode mode)3545e4b17023SJohn Marino expand_builtin_memset (tree exp, rtx target, enum machine_mode mode)
3546e4b17023SJohn Marino {
3547e4b17023SJohn Marino if (!validate_arglist (exp,
3548e4b17023SJohn Marino POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
3549e4b17023SJohn Marino return NULL_RTX;
3550e4b17023SJohn Marino else
3551e4b17023SJohn Marino {
3552e4b17023SJohn Marino tree dest = CALL_EXPR_ARG (exp, 0);
3553e4b17023SJohn Marino tree val = CALL_EXPR_ARG (exp, 1);
3554e4b17023SJohn Marino tree len = CALL_EXPR_ARG (exp, 2);
3555e4b17023SJohn Marino return expand_builtin_memset_args (dest, val, len, target, mode, exp);
3556e4b17023SJohn Marino }
3557e4b17023SJohn Marino }
3558e4b17023SJohn Marino
3559e4b17023SJohn Marino /* Helper function to do the actual work for expand_builtin_memset. The
3560e4b17023SJohn Marino arguments to the builtin_memset call DEST, VAL, and LEN are broken out
3561e4b17023SJohn Marino so that this can also be called without constructing an actual CALL_EXPR.
3562e4b17023SJohn Marino The other arguments and return value are the same as for
3563e4b17023SJohn Marino expand_builtin_memset. */
3564e4b17023SJohn Marino
3565e4b17023SJohn Marino static rtx
expand_builtin_memset_args(tree dest,tree val,tree len,rtx target,enum machine_mode mode,tree orig_exp)3566e4b17023SJohn Marino expand_builtin_memset_args (tree dest, tree val, tree len,
3567e4b17023SJohn Marino rtx target, enum machine_mode mode, tree orig_exp)
3568e4b17023SJohn Marino {
3569e4b17023SJohn Marino tree fndecl, fn;
3570e4b17023SJohn Marino enum built_in_function fcode;
3571e4b17023SJohn Marino enum machine_mode val_mode;
3572e4b17023SJohn Marino char c;
3573e4b17023SJohn Marino unsigned int dest_align;
3574e4b17023SJohn Marino rtx dest_mem, dest_addr, len_rtx;
3575e4b17023SJohn Marino HOST_WIDE_INT expected_size = -1;
3576e4b17023SJohn Marino unsigned int expected_align = 0;
3577e4b17023SJohn Marino
3578e4b17023SJohn Marino dest_align = get_pointer_alignment (dest);
3579e4b17023SJohn Marino
3580e4b17023SJohn Marino /* If DEST is not a pointer type, don't do this operation in-line. */
3581e4b17023SJohn Marino if (dest_align == 0)
3582e4b17023SJohn Marino return NULL_RTX;
3583e4b17023SJohn Marino
3584e4b17023SJohn Marino if (currently_expanding_gimple_stmt)
3585e4b17023SJohn Marino stringop_block_profile (currently_expanding_gimple_stmt,
3586e4b17023SJohn Marino &expected_align, &expected_size);
3587e4b17023SJohn Marino
3588e4b17023SJohn Marino if (expected_align < dest_align)
3589e4b17023SJohn Marino expected_align = dest_align;
3590e4b17023SJohn Marino
3591e4b17023SJohn Marino /* If the LEN parameter is zero, return DEST. */
3592e4b17023SJohn Marino if (integer_zerop (len))
3593e4b17023SJohn Marino {
3594e4b17023SJohn Marino /* Evaluate and ignore VAL in case it has side-effects. */
3595e4b17023SJohn Marino expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL);
3596e4b17023SJohn Marino return expand_expr (dest, target, mode, EXPAND_NORMAL);
3597e4b17023SJohn Marino }
3598e4b17023SJohn Marino
3599e4b17023SJohn Marino /* Stabilize the arguments in case we fail. */
3600e4b17023SJohn Marino dest = builtin_save_expr (dest);
3601e4b17023SJohn Marino val = builtin_save_expr (val);
3602e4b17023SJohn Marino len = builtin_save_expr (len);
3603e4b17023SJohn Marino
3604e4b17023SJohn Marino len_rtx = expand_normal (len);
3605e4b17023SJohn Marino dest_mem = get_memory_rtx (dest, len);
3606e4b17023SJohn Marino val_mode = TYPE_MODE (unsigned_char_type_node);
3607e4b17023SJohn Marino
3608e4b17023SJohn Marino if (TREE_CODE (val) != INTEGER_CST)
3609e4b17023SJohn Marino {
3610e4b17023SJohn Marino rtx val_rtx;
3611e4b17023SJohn Marino
3612e4b17023SJohn Marino val_rtx = expand_normal (val);
3613e4b17023SJohn Marino val_rtx = convert_to_mode (val_mode, val_rtx, 0);
3614e4b17023SJohn Marino
3615e4b17023SJohn Marino /* Assume that we can memset by pieces if we can store
3616e4b17023SJohn Marino * the coefficients by pieces (in the required modes).
3617e4b17023SJohn Marino * We can't pass builtin_memset_gen_str as that emits RTL. */
3618e4b17023SJohn Marino c = 1;
3619e4b17023SJohn Marino if (host_integerp (len, 1)
3620e4b17023SJohn Marino && can_store_by_pieces (tree_low_cst (len, 1),
3621e4b17023SJohn Marino builtin_memset_read_str, &c, dest_align,
3622e4b17023SJohn Marino true))
3623e4b17023SJohn Marino {
3624e4b17023SJohn Marino val_rtx = force_reg (val_mode, val_rtx);
3625e4b17023SJohn Marino store_by_pieces (dest_mem, tree_low_cst (len, 1),
3626e4b17023SJohn Marino builtin_memset_gen_str, val_rtx, dest_align,
3627e4b17023SJohn Marino true, 0);
3628e4b17023SJohn Marino }
3629e4b17023SJohn Marino else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx,
3630e4b17023SJohn Marino dest_align, expected_align,
3631e4b17023SJohn Marino expected_size))
3632e4b17023SJohn Marino goto do_libcall;
3633e4b17023SJohn Marino
3634e4b17023SJohn Marino dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
3635e4b17023SJohn Marino dest_mem = convert_memory_address (ptr_mode, dest_mem);
3636e4b17023SJohn Marino return dest_mem;
3637e4b17023SJohn Marino }
3638e4b17023SJohn Marino
3639e4b17023SJohn Marino if (target_char_cast (val, &c))
3640e4b17023SJohn Marino goto do_libcall;
3641e4b17023SJohn Marino
3642e4b17023SJohn Marino if (c)
3643e4b17023SJohn Marino {
3644e4b17023SJohn Marino if (host_integerp (len, 1)
3645e4b17023SJohn Marino && can_store_by_pieces (tree_low_cst (len, 1),
3646e4b17023SJohn Marino builtin_memset_read_str, &c, dest_align,
3647e4b17023SJohn Marino true))
3648e4b17023SJohn Marino store_by_pieces (dest_mem, tree_low_cst (len, 1),
3649e4b17023SJohn Marino builtin_memset_read_str, &c, dest_align, true, 0);
3650e4b17023SJohn Marino else if (!set_storage_via_setmem (dest_mem, len_rtx,
3651e4b17023SJohn Marino gen_int_mode (c, val_mode),
3652e4b17023SJohn Marino dest_align, expected_align,
3653e4b17023SJohn Marino expected_size))
3654e4b17023SJohn Marino goto do_libcall;
3655e4b17023SJohn Marino
3656e4b17023SJohn Marino dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
3657e4b17023SJohn Marino dest_mem = convert_memory_address (ptr_mode, dest_mem);
3658e4b17023SJohn Marino return dest_mem;
3659e4b17023SJohn Marino }
3660e4b17023SJohn Marino
3661e4b17023SJohn Marino set_mem_align (dest_mem, dest_align);
3662e4b17023SJohn Marino dest_addr = clear_storage_hints (dest_mem, len_rtx,
3663e4b17023SJohn Marino CALL_EXPR_TAILCALL (orig_exp)
3664e4b17023SJohn Marino ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL,
3665e4b17023SJohn Marino expected_align, expected_size);
3666e4b17023SJohn Marino
3667e4b17023SJohn Marino if (dest_addr == 0)
3668e4b17023SJohn Marino {
3669e4b17023SJohn Marino dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
3670e4b17023SJohn Marino dest_addr = convert_memory_address (ptr_mode, dest_addr);
3671e4b17023SJohn Marino }
3672e4b17023SJohn Marino
3673e4b17023SJohn Marino return dest_addr;
3674e4b17023SJohn Marino
3675e4b17023SJohn Marino do_libcall:
3676e4b17023SJohn Marino fndecl = get_callee_fndecl (orig_exp);
3677e4b17023SJohn Marino fcode = DECL_FUNCTION_CODE (fndecl);
3678e4b17023SJohn Marino if (fcode == BUILT_IN_MEMSET)
3679e4b17023SJohn Marino fn = build_call_nofold_loc (EXPR_LOCATION (orig_exp), fndecl, 3,
3680e4b17023SJohn Marino dest, val, len);
3681e4b17023SJohn Marino else if (fcode == BUILT_IN_BZERO)
3682e4b17023SJohn Marino fn = build_call_nofold_loc (EXPR_LOCATION (orig_exp), fndecl, 2,
3683e4b17023SJohn Marino dest, len);
3684e4b17023SJohn Marino else
3685e4b17023SJohn Marino gcc_unreachable ();
3686e4b17023SJohn Marino gcc_assert (TREE_CODE (fn) == CALL_EXPR);
3687e4b17023SJohn Marino CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp);
3688e4b17023SJohn Marino return expand_call (fn, target, target == const0_rtx);
3689e4b17023SJohn Marino }
3690e4b17023SJohn Marino
3691e4b17023SJohn Marino /* Expand expression EXP, which is a call to the bzero builtin. Return
3692e4b17023SJohn Marino NULL_RTX if we failed the caller should emit a normal call. */
3693e4b17023SJohn Marino
3694e4b17023SJohn Marino static rtx
expand_builtin_bzero(tree exp)3695e4b17023SJohn Marino expand_builtin_bzero (tree exp)
3696e4b17023SJohn Marino {
3697e4b17023SJohn Marino tree dest, size;
3698e4b17023SJohn Marino location_t loc = EXPR_LOCATION (exp);
3699e4b17023SJohn Marino
3700e4b17023SJohn Marino if (!validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
3701e4b17023SJohn Marino return NULL_RTX;
3702e4b17023SJohn Marino
3703e4b17023SJohn Marino dest = CALL_EXPR_ARG (exp, 0);
3704e4b17023SJohn Marino size = CALL_EXPR_ARG (exp, 1);
3705e4b17023SJohn Marino
3706e4b17023SJohn Marino /* New argument list transforming bzero(ptr x, int y) to
3707e4b17023SJohn Marino memset(ptr x, int 0, size_t y). This is done this way
3708e4b17023SJohn Marino so that if it isn't expanded inline, we fallback to
3709e4b17023SJohn Marino calling bzero instead of memset. */
3710e4b17023SJohn Marino
3711e4b17023SJohn Marino return expand_builtin_memset_args (dest, integer_zero_node,
3712e4b17023SJohn Marino fold_convert_loc (loc,
3713e4b17023SJohn Marino size_type_node, size),
3714e4b17023SJohn Marino const0_rtx, VOIDmode, exp);
3715e4b17023SJohn Marino }
3716e4b17023SJohn Marino
3717e4b17023SJohn Marino /* Expand expression EXP, which is a call to the memcmp built-in function.
3718e4b17023SJohn Marino Return NULL_RTX if we failed and the caller should emit a normal call,
3719e4b17023SJohn Marino otherwise try to get the result in TARGET, if convenient (and in mode
3720e4b17023SJohn Marino MODE, if that's convenient). */
3721e4b17023SJohn Marino
3722e4b17023SJohn Marino static rtx
expand_builtin_memcmp(tree exp,ATTRIBUTE_UNUSED rtx target,ATTRIBUTE_UNUSED enum machine_mode mode)3723e4b17023SJohn Marino expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target,
3724e4b17023SJohn Marino ATTRIBUTE_UNUSED enum machine_mode mode)
3725e4b17023SJohn Marino {
3726e4b17023SJohn Marino location_t loc ATTRIBUTE_UNUSED = EXPR_LOCATION (exp);
3727e4b17023SJohn Marino
3728e4b17023SJohn Marino if (!validate_arglist (exp,
3729e4b17023SJohn Marino POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
3730e4b17023SJohn Marino return NULL_RTX;
3731e4b17023SJohn Marino
3732e4b17023SJohn Marino /* Note: The cmpstrnsi pattern, if it exists, is not suitable for
3733e4b17023SJohn Marino implementing memcmp because it will stop if it encounters two
3734e4b17023SJohn Marino zero bytes. */
3735e4b17023SJohn Marino #if defined HAVE_cmpmemsi
3736e4b17023SJohn Marino {
3737e4b17023SJohn Marino rtx arg1_rtx, arg2_rtx, arg3_rtx;
3738e4b17023SJohn Marino rtx result;
3739e4b17023SJohn Marino rtx insn;
3740e4b17023SJohn Marino tree arg1 = CALL_EXPR_ARG (exp, 0);
3741e4b17023SJohn Marino tree arg2 = CALL_EXPR_ARG (exp, 1);
3742e4b17023SJohn Marino tree len = CALL_EXPR_ARG (exp, 2);
3743e4b17023SJohn Marino
3744e4b17023SJohn Marino unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
3745e4b17023SJohn Marino unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
3746e4b17023SJohn Marino enum machine_mode insn_mode;
3747e4b17023SJohn Marino
3748e4b17023SJohn Marino if (HAVE_cmpmemsi)
3749e4b17023SJohn Marino insn_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode;
3750e4b17023SJohn Marino else
3751e4b17023SJohn Marino return NULL_RTX;
3752e4b17023SJohn Marino
3753e4b17023SJohn Marino /* If we don't have POINTER_TYPE, call the function. */
3754e4b17023SJohn Marino if (arg1_align == 0 || arg2_align == 0)
3755e4b17023SJohn Marino return NULL_RTX;
3756e4b17023SJohn Marino
3757e4b17023SJohn Marino /* Make a place to write the result of the instruction. */
3758e4b17023SJohn Marino result = target;
3759e4b17023SJohn Marino if (! (result != 0
3760e4b17023SJohn Marino && REG_P (result) && GET_MODE (result) == insn_mode
3761e4b17023SJohn Marino && REGNO (result) >= FIRST_PSEUDO_REGISTER))
3762e4b17023SJohn Marino result = gen_reg_rtx (insn_mode);
3763e4b17023SJohn Marino
3764e4b17023SJohn Marino arg1_rtx = get_memory_rtx (arg1, len);
3765e4b17023SJohn Marino arg2_rtx = get_memory_rtx (arg2, len);
3766e4b17023SJohn Marino arg3_rtx = expand_normal (fold_convert_loc (loc, sizetype, len));
3767e4b17023SJohn Marino
3768e4b17023SJohn Marino /* Set MEM_SIZE as appropriate. */
3769e4b17023SJohn Marino if (CONST_INT_P (arg3_rtx))
3770e4b17023SJohn Marino {
3771e4b17023SJohn Marino set_mem_size (arg1_rtx, INTVAL (arg3_rtx));
3772e4b17023SJohn Marino set_mem_size (arg2_rtx, INTVAL (arg3_rtx));
3773e4b17023SJohn Marino }
3774e4b17023SJohn Marino
3775e4b17023SJohn Marino if (HAVE_cmpmemsi)
3776e4b17023SJohn Marino insn = gen_cmpmemsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
3777e4b17023SJohn Marino GEN_INT (MIN (arg1_align, arg2_align)));
3778e4b17023SJohn Marino else
3779e4b17023SJohn Marino gcc_unreachable ();
3780e4b17023SJohn Marino
3781e4b17023SJohn Marino if (insn)
3782e4b17023SJohn Marino emit_insn (insn);
3783e4b17023SJohn Marino else
3784e4b17023SJohn Marino emit_library_call_value (memcmp_libfunc, result, LCT_PURE,
3785e4b17023SJohn Marino TYPE_MODE (integer_type_node), 3,
3786e4b17023SJohn Marino XEXP (arg1_rtx, 0), Pmode,
3787e4b17023SJohn Marino XEXP (arg2_rtx, 0), Pmode,
3788e4b17023SJohn Marino convert_to_mode (TYPE_MODE (sizetype), arg3_rtx,
3789e4b17023SJohn Marino TYPE_UNSIGNED (sizetype)),
3790e4b17023SJohn Marino TYPE_MODE (sizetype));
3791e4b17023SJohn Marino
3792e4b17023SJohn Marino /* Return the value in the proper mode for this function. */
3793e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (exp));
3794e4b17023SJohn Marino if (GET_MODE (result) == mode)
3795e4b17023SJohn Marino return result;
3796e4b17023SJohn Marino else if (target != 0)
3797e4b17023SJohn Marino {
3798e4b17023SJohn Marino convert_move (target, result, 0);
3799e4b17023SJohn Marino return target;
3800e4b17023SJohn Marino }
3801e4b17023SJohn Marino else
3802e4b17023SJohn Marino return convert_to_mode (mode, result, 0);
3803e4b17023SJohn Marino }
3804e4b17023SJohn Marino #endif /* HAVE_cmpmemsi. */
3805e4b17023SJohn Marino
3806e4b17023SJohn Marino return NULL_RTX;
3807e4b17023SJohn Marino }
3808e4b17023SJohn Marino
3809e4b17023SJohn Marino /* Expand expression EXP, which is a call to the strcmp builtin. Return NULL_RTX
3810e4b17023SJohn Marino if we failed the caller should emit a normal call, otherwise try to get
3811e4b17023SJohn Marino the result in TARGET, if convenient. */
3812e4b17023SJohn Marino
3813e4b17023SJohn Marino static rtx
expand_builtin_strcmp(tree exp,ATTRIBUTE_UNUSED rtx target)3814e4b17023SJohn Marino expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
3815e4b17023SJohn Marino {
3816e4b17023SJohn Marino if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
3817e4b17023SJohn Marino return NULL_RTX;
3818e4b17023SJohn Marino
3819e4b17023SJohn Marino #if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi
3820e4b17023SJohn Marino if (direct_optab_handler (cmpstr_optab, SImode) != CODE_FOR_nothing
3821e4b17023SJohn Marino || direct_optab_handler (cmpstrn_optab, SImode) != CODE_FOR_nothing)
3822e4b17023SJohn Marino {
3823e4b17023SJohn Marino rtx arg1_rtx, arg2_rtx;
3824e4b17023SJohn Marino rtx result, insn = NULL_RTX;
3825e4b17023SJohn Marino tree fndecl, fn;
3826e4b17023SJohn Marino tree arg1 = CALL_EXPR_ARG (exp, 0);
3827e4b17023SJohn Marino tree arg2 = CALL_EXPR_ARG (exp, 1);
3828e4b17023SJohn Marino
3829e4b17023SJohn Marino unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
3830e4b17023SJohn Marino unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
3831e4b17023SJohn Marino
3832e4b17023SJohn Marino /* If we don't have POINTER_TYPE, call the function. */
3833e4b17023SJohn Marino if (arg1_align == 0 || arg2_align == 0)
3834e4b17023SJohn Marino return NULL_RTX;
3835e4b17023SJohn Marino
3836e4b17023SJohn Marino /* Stabilize the arguments in case gen_cmpstr(n)si fail. */
3837e4b17023SJohn Marino arg1 = builtin_save_expr (arg1);
3838e4b17023SJohn Marino arg2 = builtin_save_expr (arg2);
3839e4b17023SJohn Marino
3840e4b17023SJohn Marino arg1_rtx = get_memory_rtx (arg1, NULL);
3841e4b17023SJohn Marino arg2_rtx = get_memory_rtx (arg2, NULL);
3842e4b17023SJohn Marino
3843e4b17023SJohn Marino #ifdef HAVE_cmpstrsi
3844e4b17023SJohn Marino /* Try to call cmpstrsi. */
3845e4b17023SJohn Marino if (HAVE_cmpstrsi)
3846e4b17023SJohn Marino {
3847e4b17023SJohn Marino enum machine_mode insn_mode
3848e4b17023SJohn Marino = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
3849e4b17023SJohn Marino
3850e4b17023SJohn Marino /* Make a place to write the result of the instruction. */
3851e4b17023SJohn Marino result = target;
3852e4b17023SJohn Marino if (! (result != 0
3853e4b17023SJohn Marino && REG_P (result) && GET_MODE (result) == insn_mode
3854e4b17023SJohn Marino && REGNO (result) >= FIRST_PSEUDO_REGISTER))
3855e4b17023SJohn Marino result = gen_reg_rtx (insn_mode);
3856e4b17023SJohn Marino
3857e4b17023SJohn Marino insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx,
3858e4b17023SJohn Marino GEN_INT (MIN (arg1_align, arg2_align)));
3859e4b17023SJohn Marino }
3860e4b17023SJohn Marino #endif
3861e4b17023SJohn Marino #ifdef HAVE_cmpstrnsi
3862e4b17023SJohn Marino /* Try to determine at least one length and call cmpstrnsi. */
3863e4b17023SJohn Marino if (!insn && HAVE_cmpstrnsi)
3864e4b17023SJohn Marino {
3865e4b17023SJohn Marino tree len;
3866e4b17023SJohn Marino rtx arg3_rtx;
3867e4b17023SJohn Marino
3868e4b17023SJohn Marino enum machine_mode insn_mode
3869e4b17023SJohn Marino = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
3870e4b17023SJohn Marino tree len1 = c_strlen (arg1, 1);
3871e4b17023SJohn Marino tree len2 = c_strlen (arg2, 1);
3872e4b17023SJohn Marino
3873e4b17023SJohn Marino if (len1)
3874e4b17023SJohn Marino len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
3875e4b17023SJohn Marino if (len2)
3876e4b17023SJohn Marino len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
3877e4b17023SJohn Marino
3878e4b17023SJohn Marino /* If we don't have a constant length for the first, use the length
3879e4b17023SJohn Marino of the second, if we know it. We don't require a constant for
3880e4b17023SJohn Marino this case; some cost analysis could be done if both are available
3881e4b17023SJohn Marino but neither is constant. For now, assume they're equally cheap,
3882e4b17023SJohn Marino unless one has side effects. If both strings have constant lengths,
3883e4b17023SJohn Marino use the smaller. */
3884e4b17023SJohn Marino
3885e4b17023SJohn Marino if (!len1)
3886e4b17023SJohn Marino len = len2;
3887e4b17023SJohn Marino else if (!len2)
3888e4b17023SJohn Marino len = len1;
3889e4b17023SJohn Marino else if (TREE_SIDE_EFFECTS (len1))
3890e4b17023SJohn Marino len = len2;
3891e4b17023SJohn Marino else if (TREE_SIDE_EFFECTS (len2))
3892e4b17023SJohn Marino len = len1;
3893e4b17023SJohn Marino else if (TREE_CODE (len1) != INTEGER_CST)
3894e4b17023SJohn Marino len = len2;
3895e4b17023SJohn Marino else if (TREE_CODE (len2) != INTEGER_CST)
3896e4b17023SJohn Marino len = len1;
3897e4b17023SJohn Marino else if (tree_int_cst_lt (len1, len2))
3898e4b17023SJohn Marino len = len1;
3899e4b17023SJohn Marino else
3900e4b17023SJohn Marino len = len2;
3901e4b17023SJohn Marino
3902e4b17023SJohn Marino /* If both arguments have side effects, we cannot optimize. */
3903e4b17023SJohn Marino if (!len || TREE_SIDE_EFFECTS (len))
3904e4b17023SJohn Marino goto do_libcall;
3905e4b17023SJohn Marino
3906e4b17023SJohn Marino arg3_rtx = expand_normal (len);
3907e4b17023SJohn Marino
3908e4b17023SJohn Marino /* Make a place to write the result of the instruction. */
3909e4b17023SJohn Marino result = target;
3910e4b17023SJohn Marino if (! (result != 0
3911e4b17023SJohn Marino && REG_P (result) && GET_MODE (result) == insn_mode
3912e4b17023SJohn Marino && REGNO (result) >= FIRST_PSEUDO_REGISTER))
3913e4b17023SJohn Marino result = gen_reg_rtx (insn_mode);
3914e4b17023SJohn Marino
3915e4b17023SJohn Marino insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
3916e4b17023SJohn Marino GEN_INT (MIN (arg1_align, arg2_align)));
3917e4b17023SJohn Marino }
3918e4b17023SJohn Marino #endif
3919e4b17023SJohn Marino
3920e4b17023SJohn Marino if (insn)
3921e4b17023SJohn Marino {
3922e4b17023SJohn Marino enum machine_mode mode;
3923e4b17023SJohn Marino emit_insn (insn);
3924e4b17023SJohn Marino
3925e4b17023SJohn Marino /* Return the value in the proper mode for this function. */
3926e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (exp));
3927e4b17023SJohn Marino if (GET_MODE (result) == mode)
3928e4b17023SJohn Marino return result;
3929e4b17023SJohn Marino if (target == 0)
3930e4b17023SJohn Marino return convert_to_mode (mode, result, 0);
3931e4b17023SJohn Marino convert_move (target, result, 0);
3932e4b17023SJohn Marino return target;
3933e4b17023SJohn Marino }
3934e4b17023SJohn Marino
3935e4b17023SJohn Marino /* Expand the library call ourselves using a stabilized argument
3936e4b17023SJohn Marino list to avoid re-evaluating the function's arguments twice. */
3937e4b17023SJohn Marino #ifdef HAVE_cmpstrnsi
3938e4b17023SJohn Marino do_libcall:
3939e4b17023SJohn Marino #endif
3940e4b17023SJohn Marino fndecl = get_callee_fndecl (exp);
3941e4b17023SJohn Marino fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2);
3942e4b17023SJohn Marino gcc_assert (TREE_CODE (fn) == CALL_EXPR);
3943e4b17023SJohn Marino CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
3944e4b17023SJohn Marino return expand_call (fn, target, target == const0_rtx);
3945e4b17023SJohn Marino }
3946e4b17023SJohn Marino #endif
3947e4b17023SJohn Marino return NULL_RTX;
3948e4b17023SJohn Marino }
3949e4b17023SJohn Marino
3950e4b17023SJohn Marino /* Expand expression EXP, which is a call to the strncmp builtin. Return
3951e4b17023SJohn Marino NULL_RTX if we failed the caller should emit a normal call, otherwise try to get
3952e4b17023SJohn Marino the result in TARGET, if convenient. */
3953e4b17023SJohn Marino
3954e4b17023SJohn Marino static rtx
expand_builtin_strncmp(tree exp,ATTRIBUTE_UNUSED rtx target,ATTRIBUTE_UNUSED enum machine_mode mode)3955e4b17023SJohn Marino expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
3956e4b17023SJohn Marino ATTRIBUTE_UNUSED enum machine_mode mode)
3957e4b17023SJohn Marino {
3958e4b17023SJohn Marino location_t loc ATTRIBUTE_UNUSED = EXPR_LOCATION (exp);
3959e4b17023SJohn Marino
3960e4b17023SJohn Marino if (!validate_arglist (exp,
3961e4b17023SJohn Marino POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
3962e4b17023SJohn Marino return NULL_RTX;
3963e4b17023SJohn Marino
3964e4b17023SJohn Marino /* If c_strlen can determine an expression for one of the string
3965e4b17023SJohn Marino lengths, and it doesn't have side effects, then emit cmpstrnsi
3966e4b17023SJohn Marino using length MIN(strlen(string)+1, arg3). */
3967e4b17023SJohn Marino #ifdef HAVE_cmpstrnsi
3968e4b17023SJohn Marino if (HAVE_cmpstrnsi)
3969e4b17023SJohn Marino {
3970e4b17023SJohn Marino tree len, len1, len2;
3971e4b17023SJohn Marino rtx arg1_rtx, arg2_rtx, arg3_rtx;
3972e4b17023SJohn Marino rtx result, insn;
3973e4b17023SJohn Marino tree fndecl, fn;
3974e4b17023SJohn Marino tree arg1 = CALL_EXPR_ARG (exp, 0);
3975e4b17023SJohn Marino tree arg2 = CALL_EXPR_ARG (exp, 1);
3976e4b17023SJohn Marino tree arg3 = CALL_EXPR_ARG (exp, 2);
3977e4b17023SJohn Marino
3978e4b17023SJohn Marino unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
3979e4b17023SJohn Marino unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
3980e4b17023SJohn Marino enum machine_mode insn_mode
3981e4b17023SJohn Marino = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
3982e4b17023SJohn Marino
3983e4b17023SJohn Marino len1 = c_strlen (arg1, 1);
3984e4b17023SJohn Marino len2 = c_strlen (arg2, 1);
3985e4b17023SJohn Marino
3986e4b17023SJohn Marino if (len1)
3987e4b17023SJohn Marino len1 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len1);
3988e4b17023SJohn Marino if (len2)
3989e4b17023SJohn Marino len2 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len2);
3990e4b17023SJohn Marino
3991e4b17023SJohn Marino /* If we don't have a constant length for the first, use the length
3992e4b17023SJohn Marino of the second, if we know it. We don't require a constant for
3993e4b17023SJohn Marino this case; some cost analysis could be done if both are available
3994e4b17023SJohn Marino but neither is constant. For now, assume they're equally cheap,
3995e4b17023SJohn Marino unless one has side effects. If both strings have constant lengths,
3996e4b17023SJohn Marino use the smaller. */
3997e4b17023SJohn Marino
3998e4b17023SJohn Marino if (!len1)
3999e4b17023SJohn Marino len = len2;
4000e4b17023SJohn Marino else if (!len2)
4001e4b17023SJohn Marino len = len1;
4002e4b17023SJohn Marino else if (TREE_SIDE_EFFECTS (len1))
4003e4b17023SJohn Marino len = len2;
4004e4b17023SJohn Marino else if (TREE_SIDE_EFFECTS (len2))
4005e4b17023SJohn Marino len = len1;
4006e4b17023SJohn Marino else if (TREE_CODE (len1) != INTEGER_CST)
4007e4b17023SJohn Marino len = len2;
4008e4b17023SJohn Marino else if (TREE_CODE (len2) != INTEGER_CST)
4009e4b17023SJohn Marino len = len1;
4010e4b17023SJohn Marino else if (tree_int_cst_lt (len1, len2))
4011e4b17023SJohn Marino len = len1;
4012e4b17023SJohn Marino else
4013e4b17023SJohn Marino len = len2;
4014e4b17023SJohn Marino
4015e4b17023SJohn Marino /* If both arguments have side effects, we cannot optimize. */
4016e4b17023SJohn Marino if (!len || TREE_SIDE_EFFECTS (len))
4017e4b17023SJohn Marino return NULL_RTX;
4018e4b17023SJohn Marino
4019e4b17023SJohn Marino /* The actual new length parameter is MIN(len,arg3). */
4020e4b17023SJohn Marino len = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (len), len,
4021e4b17023SJohn Marino fold_convert_loc (loc, TREE_TYPE (len), arg3));
4022e4b17023SJohn Marino
4023e4b17023SJohn Marino /* If we don't have POINTER_TYPE, call the function. */
4024e4b17023SJohn Marino if (arg1_align == 0 || arg2_align == 0)
4025e4b17023SJohn Marino return NULL_RTX;
4026e4b17023SJohn Marino
4027e4b17023SJohn Marino /* Make a place to write the result of the instruction. */
4028e4b17023SJohn Marino result = target;
4029e4b17023SJohn Marino if (! (result != 0
4030e4b17023SJohn Marino && REG_P (result) && GET_MODE (result) == insn_mode
4031e4b17023SJohn Marino && REGNO (result) >= FIRST_PSEUDO_REGISTER))
4032e4b17023SJohn Marino result = gen_reg_rtx (insn_mode);
4033e4b17023SJohn Marino
4034e4b17023SJohn Marino /* Stabilize the arguments in case gen_cmpstrnsi fails. */
4035e4b17023SJohn Marino arg1 = builtin_save_expr (arg1);
4036e4b17023SJohn Marino arg2 = builtin_save_expr (arg2);
4037e4b17023SJohn Marino len = builtin_save_expr (len);
4038e4b17023SJohn Marino
4039e4b17023SJohn Marino arg1_rtx = get_memory_rtx (arg1, len);
4040e4b17023SJohn Marino arg2_rtx = get_memory_rtx (arg2, len);
4041e4b17023SJohn Marino arg3_rtx = expand_normal (len);
4042e4b17023SJohn Marino insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
4043e4b17023SJohn Marino GEN_INT (MIN (arg1_align, arg2_align)));
4044e4b17023SJohn Marino if (insn)
4045e4b17023SJohn Marino {
4046e4b17023SJohn Marino emit_insn (insn);
4047e4b17023SJohn Marino
4048e4b17023SJohn Marino /* Return the value in the proper mode for this function. */
4049e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (exp));
4050e4b17023SJohn Marino if (GET_MODE (result) == mode)
4051e4b17023SJohn Marino return result;
4052e4b17023SJohn Marino if (target == 0)
4053e4b17023SJohn Marino return convert_to_mode (mode, result, 0);
4054e4b17023SJohn Marino convert_move (target, result, 0);
4055e4b17023SJohn Marino return target;
4056e4b17023SJohn Marino }
4057e4b17023SJohn Marino
4058e4b17023SJohn Marino /* Expand the library call ourselves using a stabilized argument
4059e4b17023SJohn Marino list to avoid re-evaluating the function's arguments twice. */
4060e4b17023SJohn Marino fndecl = get_callee_fndecl (exp);
4061e4b17023SJohn Marino fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 3,
4062e4b17023SJohn Marino arg1, arg2, len);
4063e4b17023SJohn Marino gcc_assert (TREE_CODE (fn) == CALL_EXPR);
4064e4b17023SJohn Marino CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
4065e4b17023SJohn Marino return expand_call (fn, target, target == const0_rtx);
4066e4b17023SJohn Marino }
4067e4b17023SJohn Marino #endif
4068e4b17023SJohn Marino return NULL_RTX;
4069e4b17023SJohn Marino }
4070e4b17023SJohn Marino
4071e4b17023SJohn Marino /* Expand a call to __builtin_saveregs, generating the result in TARGET,
4072e4b17023SJohn Marino if that's convenient. */
4073e4b17023SJohn Marino
4074e4b17023SJohn Marino rtx
expand_builtin_saveregs(void)4075e4b17023SJohn Marino expand_builtin_saveregs (void)
4076e4b17023SJohn Marino {
4077e4b17023SJohn Marino rtx val, seq;
4078e4b17023SJohn Marino
4079e4b17023SJohn Marino /* Don't do __builtin_saveregs more than once in a function.
4080e4b17023SJohn Marino Save the result of the first call and reuse it. */
4081e4b17023SJohn Marino if (saveregs_value != 0)
4082e4b17023SJohn Marino return saveregs_value;
4083e4b17023SJohn Marino
4084e4b17023SJohn Marino /* When this function is called, it means that registers must be
4085e4b17023SJohn Marino saved on entry to this function. So we migrate the call to the
4086e4b17023SJohn Marino first insn of this function. */
4087e4b17023SJohn Marino
4088e4b17023SJohn Marino start_sequence ();
4089e4b17023SJohn Marino
4090e4b17023SJohn Marino /* Do whatever the machine needs done in this case. */
4091e4b17023SJohn Marino val = targetm.calls.expand_builtin_saveregs ();
4092e4b17023SJohn Marino
4093e4b17023SJohn Marino seq = get_insns ();
4094e4b17023SJohn Marino end_sequence ();
4095e4b17023SJohn Marino
4096e4b17023SJohn Marino saveregs_value = val;
4097e4b17023SJohn Marino
4098e4b17023SJohn Marino /* Put the insns after the NOTE that starts the function. If this
4099e4b17023SJohn Marino is inside a start_sequence, make the outer-level insn chain current, so
4100e4b17023SJohn Marino the code is placed at the start of the function. */
4101e4b17023SJohn Marino push_topmost_sequence ();
4102e4b17023SJohn Marino emit_insn_after (seq, entry_of_function ());
4103e4b17023SJohn Marino pop_topmost_sequence ();
4104e4b17023SJohn Marino
4105e4b17023SJohn Marino return val;
4106e4b17023SJohn Marino }
4107e4b17023SJohn Marino
4108e4b17023SJohn Marino /* Expand a call to __builtin_next_arg. */
4109e4b17023SJohn Marino
4110e4b17023SJohn Marino static rtx
expand_builtin_next_arg(void)4111e4b17023SJohn Marino expand_builtin_next_arg (void)
4112e4b17023SJohn Marino {
4113e4b17023SJohn Marino /* Checking arguments is already done in fold_builtin_next_arg
4114e4b17023SJohn Marino that must be called before this function. */
4115e4b17023SJohn Marino return expand_binop (ptr_mode, add_optab,
4116e4b17023SJohn Marino crtl->args.internal_arg_pointer,
4117e4b17023SJohn Marino crtl->args.arg_offset_rtx,
4118e4b17023SJohn Marino NULL_RTX, 0, OPTAB_LIB_WIDEN);
4119e4b17023SJohn Marino }
4120e4b17023SJohn Marino
4121e4b17023SJohn Marino /* Make it easier for the backends by protecting the valist argument
4122e4b17023SJohn Marino from multiple evaluations. */
4123e4b17023SJohn Marino
4124e4b17023SJohn Marino static tree
stabilize_va_list_loc(location_t loc,tree valist,int needs_lvalue)4125e4b17023SJohn Marino stabilize_va_list_loc (location_t loc, tree valist, int needs_lvalue)
4126e4b17023SJohn Marino {
4127e4b17023SJohn Marino tree vatype = targetm.canonical_va_list_type (TREE_TYPE (valist));
4128e4b17023SJohn Marino
4129e4b17023SJohn Marino /* The current way of determining the type of valist is completely
4130e4b17023SJohn Marino bogus. We should have the information on the va builtin instead. */
4131e4b17023SJohn Marino if (!vatype)
4132e4b17023SJohn Marino vatype = targetm.fn_abi_va_list (cfun->decl);
4133e4b17023SJohn Marino
4134e4b17023SJohn Marino if (TREE_CODE (vatype) == ARRAY_TYPE)
4135e4b17023SJohn Marino {
4136e4b17023SJohn Marino if (TREE_SIDE_EFFECTS (valist))
4137e4b17023SJohn Marino valist = save_expr (valist);
4138e4b17023SJohn Marino
4139e4b17023SJohn Marino /* For this case, the backends will be expecting a pointer to
4140e4b17023SJohn Marino vatype, but it's possible we've actually been given an array
4141e4b17023SJohn Marino (an actual TARGET_CANONICAL_VA_LIST_TYPE (valist)).
4142e4b17023SJohn Marino So fix it. */
4143e4b17023SJohn Marino if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
4144e4b17023SJohn Marino {
4145e4b17023SJohn Marino tree p1 = build_pointer_type (TREE_TYPE (vatype));
4146e4b17023SJohn Marino valist = build_fold_addr_expr_with_type_loc (loc, valist, p1);
4147e4b17023SJohn Marino }
4148e4b17023SJohn Marino }
4149e4b17023SJohn Marino else
4150e4b17023SJohn Marino {
4151e4b17023SJohn Marino tree pt = build_pointer_type (vatype);
4152e4b17023SJohn Marino
4153e4b17023SJohn Marino if (! needs_lvalue)
4154e4b17023SJohn Marino {
4155e4b17023SJohn Marino if (! TREE_SIDE_EFFECTS (valist))
4156e4b17023SJohn Marino return valist;
4157e4b17023SJohn Marino
4158e4b17023SJohn Marino valist = fold_build1_loc (loc, ADDR_EXPR, pt, valist);
4159e4b17023SJohn Marino TREE_SIDE_EFFECTS (valist) = 1;
4160e4b17023SJohn Marino }
4161e4b17023SJohn Marino
4162e4b17023SJohn Marino if (TREE_SIDE_EFFECTS (valist))
4163e4b17023SJohn Marino valist = save_expr (valist);
4164e4b17023SJohn Marino valist = fold_build2_loc (loc, MEM_REF,
4165e4b17023SJohn Marino vatype, valist, build_int_cst (pt, 0));
4166e4b17023SJohn Marino }
4167e4b17023SJohn Marino
4168e4b17023SJohn Marino return valist;
4169e4b17023SJohn Marino }
4170e4b17023SJohn Marino
4171e4b17023SJohn Marino /* The "standard" definition of va_list is void*. */
4172e4b17023SJohn Marino
4173e4b17023SJohn Marino tree
std_build_builtin_va_list(void)4174e4b17023SJohn Marino std_build_builtin_va_list (void)
4175e4b17023SJohn Marino {
4176e4b17023SJohn Marino return ptr_type_node;
4177e4b17023SJohn Marino }
4178e4b17023SJohn Marino
4179e4b17023SJohn Marino /* The "standard" abi va_list is va_list_type_node. */
4180e4b17023SJohn Marino
4181e4b17023SJohn Marino tree
std_fn_abi_va_list(tree fndecl ATTRIBUTE_UNUSED)4182e4b17023SJohn Marino std_fn_abi_va_list (tree fndecl ATTRIBUTE_UNUSED)
4183e4b17023SJohn Marino {
4184e4b17023SJohn Marino return va_list_type_node;
4185e4b17023SJohn Marino }
4186e4b17023SJohn Marino
4187e4b17023SJohn Marino /* The "standard" type of va_list is va_list_type_node. */
4188e4b17023SJohn Marino
4189e4b17023SJohn Marino tree
std_canonical_va_list_type(tree type)4190e4b17023SJohn Marino std_canonical_va_list_type (tree type)
4191e4b17023SJohn Marino {
4192e4b17023SJohn Marino tree wtype, htype;
4193e4b17023SJohn Marino
4194e4b17023SJohn Marino if (INDIRECT_REF_P (type))
4195e4b17023SJohn Marino type = TREE_TYPE (type);
4196e4b17023SJohn Marino else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE(type)))
4197e4b17023SJohn Marino type = TREE_TYPE (type);
4198e4b17023SJohn Marino wtype = va_list_type_node;
4199e4b17023SJohn Marino htype = type;
4200e4b17023SJohn Marino /* Treat structure va_list types. */
4201e4b17023SJohn Marino if (TREE_CODE (wtype) == RECORD_TYPE && POINTER_TYPE_P (htype))
4202e4b17023SJohn Marino htype = TREE_TYPE (htype);
4203e4b17023SJohn Marino else if (TREE_CODE (wtype) == ARRAY_TYPE)
4204e4b17023SJohn Marino {
4205e4b17023SJohn Marino /* If va_list is an array type, the argument may have decayed
4206e4b17023SJohn Marino to a pointer type, e.g. by being passed to another function.
4207e4b17023SJohn Marino In that case, unwrap both types so that we can compare the
4208e4b17023SJohn Marino underlying records. */
4209e4b17023SJohn Marino if (TREE_CODE (htype) == ARRAY_TYPE
4210e4b17023SJohn Marino || POINTER_TYPE_P (htype))
4211e4b17023SJohn Marino {
4212e4b17023SJohn Marino wtype = TREE_TYPE (wtype);
4213e4b17023SJohn Marino htype = TREE_TYPE (htype);
4214e4b17023SJohn Marino }
4215e4b17023SJohn Marino }
4216e4b17023SJohn Marino if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype))
4217e4b17023SJohn Marino return va_list_type_node;
4218e4b17023SJohn Marino
4219e4b17023SJohn Marino return NULL_TREE;
4220e4b17023SJohn Marino }
4221e4b17023SJohn Marino
4222e4b17023SJohn Marino /* The "standard" implementation of va_start: just assign `nextarg' to
4223e4b17023SJohn Marino the variable. */
4224e4b17023SJohn Marino
4225e4b17023SJohn Marino void
std_expand_builtin_va_start(tree valist,rtx nextarg)4226e4b17023SJohn Marino std_expand_builtin_va_start (tree valist, rtx nextarg)
4227e4b17023SJohn Marino {
4228e4b17023SJohn Marino rtx va_r = expand_expr (valist, NULL_RTX, VOIDmode, EXPAND_WRITE);
4229e4b17023SJohn Marino convert_move (va_r, nextarg, 0);
4230e4b17023SJohn Marino }
4231e4b17023SJohn Marino
4232e4b17023SJohn Marino /* Expand EXP, a call to __builtin_va_start. */
4233e4b17023SJohn Marino
4234e4b17023SJohn Marino static rtx
expand_builtin_va_start(tree exp)4235e4b17023SJohn Marino expand_builtin_va_start (tree exp)
4236e4b17023SJohn Marino {
4237e4b17023SJohn Marino rtx nextarg;
4238e4b17023SJohn Marino tree valist;
4239e4b17023SJohn Marino location_t loc = EXPR_LOCATION (exp);
4240e4b17023SJohn Marino
4241e4b17023SJohn Marino if (call_expr_nargs (exp) < 2)
4242e4b17023SJohn Marino {
4243e4b17023SJohn Marino error_at (loc, "too few arguments to function %<va_start%>");
4244e4b17023SJohn Marino return const0_rtx;
4245e4b17023SJohn Marino }
4246e4b17023SJohn Marino
4247e4b17023SJohn Marino if (fold_builtin_next_arg (exp, true))
4248e4b17023SJohn Marino return const0_rtx;
4249e4b17023SJohn Marino
4250e4b17023SJohn Marino nextarg = expand_builtin_next_arg ();
4251e4b17023SJohn Marino valist = stabilize_va_list_loc (loc, CALL_EXPR_ARG (exp, 0), 1);
4252e4b17023SJohn Marino
4253e4b17023SJohn Marino if (targetm.expand_builtin_va_start)
4254e4b17023SJohn Marino targetm.expand_builtin_va_start (valist, nextarg);
4255e4b17023SJohn Marino else
4256e4b17023SJohn Marino std_expand_builtin_va_start (valist, nextarg);
4257e4b17023SJohn Marino
4258e4b17023SJohn Marino return const0_rtx;
4259e4b17023SJohn Marino }
4260e4b17023SJohn Marino
4261e4b17023SJohn Marino /* The "standard" implementation of va_arg: read the value from the
4262e4b17023SJohn Marino current (padded) address and increment by the (padded) size. */
4263e4b17023SJohn Marino
4264e4b17023SJohn Marino tree
std_gimplify_va_arg_expr(tree valist,tree type,gimple_seq * pre_p,gimple_seq * post_p)4265e4b17023SJohn Marino std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
4266e4b17023SJohn Marino gimple_seq *post_p)
4267e4b17023SJohn Marino {
4268e4b17023SJohn Marino tree addr, t, type_size, rounded_size, valist_tmp;
4269e4b17023SJohn Marino unsigned HOST_WIDE_INT align, boundary;
4270e4b17023SJohn Marino bool indirect;
4271e4b17023SJohn Marino
4272e4b17023SJohn Marino #ifdef ARGS_GROW_DOWNWARD
4273e4b17023SJohn Marino /* All of the alignment and movement below is for args-grow-up machines.
4274e4b17023SJohn Marino As of 2004, there are only 3 ARGS_GROW_DOWNWARD targets, and they all
4275e4b17023SJohn Marino implement their own specialized gimplify_va_arg_expr routines. */
4276e4b17023SJohn Marino gcc_unreachable ();
4277e4b17023SJohn Marino #endif
4278e4b17023SJohn Marino
4279e4b17023SJohn Marino indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);
4280e4b17023SJohn Marino if (indirect)
4281e4b17023SJohn Marino type = build_pointer_type (type);
4282e4b17023SJohn Marino
4283e4b17023SJohn Marino align = PARM_BOUNDARY / BITS_PER_UNIT;
4284e4b17023SJohn Marino boundary = targetm.calls.function_arg_boundary (TYPE_MODE (type), type);
4285e4b17023SJohn Marino
4286e4b17023SJohn Marino /* When we align parameter on stack for caller, if the parameter
4287e4b17023SJohn Marino alignment is beyond MAX_SUPPORTED_STACK_ALIGNMENT, it will be
4288e4b17023SJohn Marino aligned at MAX_SUPPORTED_STACK_ALIGNMENT. We will match callee
4289e4b17023SJohn Marino here with caller. */
4290e4b17023SJohn Marino if (boundary > MAX_SUPPORTED_STACK_ALIGNMENT)
4291e4b17023SJohn Marino boundary = MAX_SUPPORTED_STACK_ALIGNMENT;
4292e4b17023SJohn Marino
4293e4b17023SJohn Marino boundary /= BITS_PER_UNIT;
4294e4b17023SJohn Marino
4295e4b17023SJohn Marino /* Hoist the valist value into a temporary for the moment. */
4296e4b17023SJohn Marino valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
4297e4b17023SJohn Marino
4298e4b17023SJohn Marino /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
4299e4b17023SJohn Marino requires greater alignment, we must perform dynamic alignment. */
4300e4b17023SJohn Marino if (boundary > align
4301e4b17023SJohn Marino && !integer_zerop (TYPE_SIZE (type)))
4302e4b17023SJohn Marino {
4303e4b17023SJohn Marino t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
4304e4b17023SJohn Marino fold_build_pointer_plus_hwi (valist_tmp, boundary - 1));
4305e4b17023SJohn Marino gimplify_and_add (t, pre_p);
4306e4b17023SJohn Marino
4307e4b17023SJohn Marino t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
4308e4b17023SJohn Marino fold_build2 (BIT_AND_EXPR, TREE_TYPE (valist),
4309e4b17023SJohn Marino valist_tmp,
4310e4b17023SJohn Marino build_int_cst (TREE_TYPE (valist), -boundary)));
4311e4b17023SJohn Marino gimplify_and_add (t, pre_p);
4312e4b17023SJohn Marino }
4313e4b17023SJohn Marino else
4314e4b17023SJohn Marino boundary = align;
4315e4b17023SJohn Marino
4316e4b17023SJohn Marino /* If the actual alignment is less than the alignment of the type,
4317e4b17023SJohn Marino adjust the type accordingly so that we don't assume strict alignment
4318e4b17023SJohn Marino when dereferencing the pointer. */
4319e4b17023SJohn Marino boundary *= BITS_PER_UNIT;
4320e4b17023SJohn Marino if (boundary < TYPE_ALIGN (type))
4321e4b17023SJohn Marino {
4322e4b17023SJohn Marino type = build_variant_type_copy (type);
4323e4b17023SJohn Marino TYPE_ALIGN (type) = boundary;
4324e4b17023SJohn Marino }
4325e4b17023SJohn Marino
4326e4b17023SJohn Marino /* Compute the rounded size of the type. */
4327e4b17023SJohn Marino type_size = size_in_bytes (type);
4328e4b17023SJohn Marino rounded_size = round_up (type_size, align);
4329e4b17023SJohn Marino
4330e4b17023SJohn Marino /* Reduce rounded_size so it's sharable with the postqueue. */
4331e4b17023SJohn Marino gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
4332e4b17023SJohn Marino
4333e4b17023SJohn Marino /* Get AP. */
4334e4b17023SJohn Marino addr = valist_tmp;
4335e4b17023SJohn Marino if (PAD_VARARGS_DOWN && !integer_zerop (rounded_size))
4336e4b17023SJohn Marino {
4337e4b17023SJohn Marino /* Small args are padded downward. */
4338e4b17023SJohn Marino t = fold_build2_loc (input_location, GT_EXPR, sizetype,
4339e4b17023SJohn Marino rounded_size, size_int (align));
4340e4b17023SJohn Marino t = fold_build3 (COND_EXPR, sizetype, t, size_zero_node,
4341e4b17023SJohn Marino size_binop (MINUS_EXPR, rounded_size, type_size));
4342e4b17023SJohn Marino addr = fold_build_pointer_plus (addr, t);
4343e4b17023SJohn Marino }
4344e4b17023SJohn Marino
4345e4b17023SJohn Marino /* Compute new value for AP. */
4346e4b17023SJohn Marino t = fold_build_pointer_plus (valist_tmp, rounded_size);
4347e4b17023SJohn Marino t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
4348e4b17023SJohn Marino gimplify_and_add (t, pre_p);
4349e4b17023SJohn Marino
4350e4b17023SJohn Marino addr = fold_convert (build_pointer_type (type), addr);
4351e4b17023SJohn Marino
4352e4b17023SJohn Marino if (indirect)
4353e4b17023SJohn Marino addr = build_va_arg_indirect_ref (addr);
4354e4b17023SJohn Marino
4355e4b17023SJohn Marino return build_va_arg_indirect_ref (addr);
4356e4b17023SJohn Marino }
4357e4b17023SJohn Marino
4358e4b17023SJohn Marino /* Build an indirect-ref expression over the given TREE, which represents a
4359e4b17023SJohn Marino piece of a va_arg() expansion. */
4360e4b17023SJohn Marino tree
build_va_arg_indirect_ref(tree addr)4361e4b17023SJohn Marino build_va_arg_indirect_ref (tree addr)
4362e4b17023SJohn Marino {
4363e4b17023SJohn Marino addr = build_simple_mem_ref_loc (EXPR_LOCATION (addr), addr);
4364e4b17023SJohn Marino
4365e4b17023SJohn Marino if (flag_mudflap) /* Don't instrument va_arg INDIRECT_REF. */
4366e4b17023SJohn Marino mf_mark (addr);
4367e4b17023SJohn Marino
4368e4b17023SJohn Marino return addr;
4369e4b17023SJohn Marino }
4370e4b17023SJohn Marino
4371e4b17023SJohn Marino /* Return a dummy expression of type TYPE in order to keep going after an
4372e4b17023SJohn Marino error. */
4373e4b17023SJohn Marino
4374e4b17023SJohn Marino static tree
dummy_object(tree type)4375e4b17023SJohn Marino dummy_object (tree type)
4376e4b17023SJohn Marino {
4377e4b17023SJohn Marino tree t = build_int_cst (build_pointer_type (type), 0);
4378e4b17023SJohn Marino return build2 (MEM_REF, type, t, t);
4379e4b17023SJohn Marino }
4380e4b17023SJohn Marino
4381e4b17023SJohn Marino /* Gimplify __builtin_va_arg, aka VA_ARG_EXPR, which is not really a
4382e4b17023SJohn Marino builtin function, but a very special sort of operator. */
4383e4b17023SJohn Marino
4384e4b17023SJohn Marino enum gimplify_status
gimplify_va_arg_expr(tree * expr_p,gimple_seq * pre_p,gimple_seq * post_p)4385e4b17023SJohn Marino gimplify_va_arg_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
4386e4b17023SJohn Marino {
4387e4b17023SJohn Marino tree promoted_type, have_va_type;
4388e4b17023SJohn Marino tree valist = TREE_OPERAND (*expr_p, 0);
4389e4b17023SJohn Marino tree type = TREE_TYPE (*expr_p);
4390e4b17023SJohn Marino tree t;
4391e4b17023SJohn Marino location_t loc = EXPR_LOCATION (*expr_p);
4392e4b17023SJohn Marino
4393e4b17023SJohn Marino /* Verify that valist is of the proper type. */
4394e4b17023SJohn Marino have_va_type = TREE_TYPE (valist);
4395e4b17023SJohn Marino if (have_va_type == error_mark_node)
4396e4b17023SJohn Marino return GS_ERROR;
4397e4b17023SJohn Marino have_va_type = targetm.canonical_va_list_type (have_va_type);
4398e4b17023SJohn Marino
4399e4b17023SJohn Marino if (have_va_type == NULL_TREE)
4400e4b17023SJohn Marino {
4401e4b17023SJohn Marino error_at (loc, "first argument to %<va_arg%> not of type %<va_list%>");
4402e4b17023SJohn Marino return GS_ERROR;
4403e4b17023SJohn Marino }
4404e4b17023SJohn Marino
4405e4b17023SJohn Marino /* Generate a diagnostic for requesting data of a type that cannot
4406e4b17023SJohn Marino be passed through `...' due to type promotion at the call site. */
4407e4b17023SJohn Marino if ((promoted_type = lang_hooks.types.type_promotes_to (type))
4408e4b17023SJohn Marino != type)
4409e4b17023SJohn Marino {
4410e4b17023SJohn Marino static bool gave_help;
4411e4b17023SJohn Marino bool warned;
4412e4b17023SJohn Marino
4413e4b17023SJohn Marino /* Unfortunately, this is merely undefined, rather than a constraint
4414e4b17023SJohn Marino violation, so we cannot make this an error. If this call is never
4415e4b17023SJohn Marino executed, the program is still strictly conforming. */
4416e4b17023SJohn Marino warned = warning_at (loc, 0,
4417e4b17023SJohn Marino "%qT is promoted to %qT when passed through %<...%>",
4418e4b17023SJohn Marino type, promoted_type);
4419e4b17023SJohn Marino if (!gave_help && warned)
4420e4b17023SJohn Marino {
4421e4b17023SJohn Marino gave_help = true;
4422e4b17023SJohn Marino inform (loc, "(so you should pass %qT not %qT to %<va_arg%>)",
4423e4b17023SJohn Marino promoted_type, type);
4424e4b17023SJohn Marino }
4425e4b17023SJohn Marino
4426e4b17023SJohn Marino /* We can, however, treat "undefined" any way we please.
4427e4b17023SJohn Marino Call abort to encourage the user to fix the program. */
4428e4b17023SJohn Marino if (warned)
4429e4b17023SJohn Marino inform (loc, "if this code is reached, the program will abort");
4430e4b17023SJohn Marino /* Before the abort, allow the evaluation of the va_list
4431e4b17023SJohn Marino expression to exit or longjmp. */
4432e4b17023SJohn Marino gimplify_and_add (valist, pre_p);
4433e4b17023SJohn Marino t = build_call_expr_loc (loc,
4434e4b17023SJohn Marino builtin_decl_implicit (BUILT_IN_TRAP), 0);
4435e4b17023SJohn Marino gimplify_and_add (t, pre_p);
4436e4b17023SJohn Marino
4437e4b17023SJohn Marino /* This is dead code, but go ahead and finish so that the
4438e4b17023SJohn Marino mode of the result comes out right. */
4439e4b17023SJohn Marino *expr_p = dummy_object (type);
4440e4b17023SJohn Marino return GS_ALL_DONE;
4441e4b17023SJohn Marino }
4442e4b17023SJohn Marino else
4443e4b17023SJohn Marino {
4444e4b17023SJohn Marino /* Make it easier for the backends by protecting the valist argument
4445e4b17023SJohn Marino from multiple evaluations. */
4446e4b17023SJohn Marino if (TREE_CODE (have_va_type) == ARRAY_TYPE)
4447e4b17023SJohn Marino {
4448e4b17023SJohn Marino /* For this case, the backends will be expecting a pointer to
4449e4b17023SJohn Marino TREE_TYPE (abi), but it's possible we've
4450e4b17023SJohn Marino actually been given an array (an actual TARGET_FN_ABI_VA_LIST).
4451e4b17023SJohn Marino So fix it. */
4452e4b17023SJohn Marino if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
4453e4b17023SJohn Marino {
4454e4b17023SJohn Marino tree p1 = build_pointer_type (TREE_TYPE (have_va_type));
4455e4b17023SJohn Marino valist = fold_convert_loc (loc, p1,
4456e4b17023SJohn Marino build_fold_addr_expr_loc (loc, valist));
4457e4b17023SJohn Marino }
4458e4b17023SJohn Marino
4459e4b17023SJohn Marino gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
4460e4b17023SJohn Marino }
4461e4b17023SJohn Marino else
4462e4b17023SJohn Marino gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
4463e4b17023SJohn Marino
4464e4b17023SJohn Marino if (!targetm.gimplify_va_arg_expr)
4465e4b17023SJohn Marino /* FIXME: Once most targets are converted we should merely
4466e4b17023SJohn Marino assert this is non-null. */
4467e4b17023SJohn Marino return GS_ALL_DONE;
4468e4b17023SJohn Marino
4469e4b17023SJohn Marino *expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p);
4470e4b17023SJohn Marino return GS_OK;
4471e4b17023SJohn Marino }
4472e4b17023SJohn Marino }
4473e4b17023SJohn Marino
4474e4b17023SJohn Marino /* Expand EXP, a call to __builtin_va_end. */
4475e4b17023SJohn Marino
4476e4b17023SJohn Marino static rtx
expand_builtin_va_end(tree exp)4477e4b17023SJohn Marino expand_builtin_va_end (tree exp)
4478e4b17023SJohn Marino {
4479e4b17023SJohn Marino tree valist = CALL_EXPR_ARG (exp, 0);
4480e4b17023SJohn Marino
4481e4b17023SJohn Marino /* Evaluate for side effects, if needed. I hate macros that don't
4482e4b17023SJohn Marino do that. */
4483e4b17023SJohn Marino if (TREE_SIDE_EFFECTS (valist))
4484e4b17023SJohn Marino expand_expr (valist, const0_rtx, VOIDmode, EXPAND_NORMAL);
4485e4b17023SJohn Marino
4486e4b17023SJohn Marino return const0_rtx;
4487e4b17023SJohn Marino }
4488e4b17023SJohn Marino
4489e4b17023SJohn Marino /* Expand EXP, a call to __builtin_va_copy. We do this as a
4490e4b17023SJohn Marino builtin rather than just as an assignment in stdarg.h because of the
4491e4b17023SJohn Marino nastiness of array-type va_list types. */
4492e4b17023SJohn Marino
4493e4b17023SJohn Marino static rtx
expand_builtin_va_copy(tree exp)4494e4b17023SJohn Marino expand_builtin_va_copy (tree exp)
4495e4b17023SJohn Marino {
4496e4b17023SJohn Marino tree dst, src, t;
4497e4b17023SJohn Marino location_t loc = EXPR_LOCATION (exp);
4498e4b17023SJohn Marino
4499e4b17023SJohn Marino dst = CALL_EXPR_ARG (exp, 0);
4500e4b17023SJohn Marino src = CALL_EXPR_ARG (exp, 1);
4501e4b17023SJohn Marino
4502e4b17023SJohn Marino dst = stabilize_va_list_loc (loc, dst, 1);
4503e4b17023SJohn Marino src = stabilize_va_list_loc (loc, src, 0);
4504e4b17023SJohn Marino
4505e4b17023SJohn Marino gcc_assert (cfun != NULL && cfun->decl != NULL_TREE);
4506e4b17023SJohn Marino
4507e4b17023SJohn Marino if (TREE_CODE (targetm.fn_abi_va_list (cfun->decl)) != ARRAY_TYPE)
4508e4b17023SJohn Marino {
4509e4b17023SJohn Marino t = build2 (MODIFY_EXPR, targetm.fn_abi_va_list (cfun->decl), dst, src);
4510e4b17023SJohn Marino TREE_SIDE_EFFECTS (t) = 1;
4511e4b17023SJohn Marino expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
4512e4b17023SJohn Marino }
4513e4b17023SJohn Marino else
4514e4b17023SJohn Marino {
4515e4b17023SJohn Marino rtx dstb, srcb, size;
4516e4b17023SJohn Marino
4517e4b17023SJohn Marino /* Evaluate to pointers. */
4518e4b17023SJohn Marino dstb = expand_expr (dst, NULL_RTX, Pmode, EXPAND_NORMAL);
4519e4b17023SJohn Marino srcb = expand_expr (src, NULL_RTX, Pmode, EXPAND_NORMAL);
4520e4b17023SJohn Marino size = expand_expr (TYPE_SIZE_UNIT (targetm.fn_abi_va_list (cfun->decl)),
4521e4b17023SJohn Marino NULL_RTX, VOIDmode, EXPAND_NORMAL);
4522e4b17023SJohn Marino
4523e4b17023SJohn Marino dstb = convert_memory_address (Pmode, dstb);
4524e4b17023SJohn Marino srcb = convert_memory_address (Pmode, srcb);
4525e4b17023SJohn Marino
4526e4b17023SJohn Marino /* "Dereference" to BLKmode memories. */
4527e4b17023SJohn Marino dstb = gen_rtx_MEM (BLKmode, dstb);
4528e4b17023SJohn Marino set_mem_alias_set (dstb, get_alias_set (TREE_TYPE (TREE_TYPE (dst))));
4529e4b17023SJohn Marino set_mem_align (dstb, TYPE_ALIGN (targetm.fn_abi_va_list (cfun->decl)));
4530e4b17023SJohn Marino srcb = gen_rtx_MEM (BLKmode, srcb);
4531e4b17023SJohn Marino set_mem_alias_set (srcb, get_alias_set (TREE_TYPE (TREE_TYPE (src))));
4532e4b17023SJohn Marino set_mem_align (srcb, TYPE_ALIGN (targetm.fn_abi_va_list (cfun->decl)));
4533e4b17023SJohn Marino
4534e4b17023SJohn Marino /* Copy. */
4535e4b17023SJohn Marino emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL);
4536e4b17023SJohn Marino }
4537e4b17023SJohn Marino
4538e4b17023SJohn Marino return const0_rtx;
4539e4b17023SJohn Marino }
4540e4b17023SJohn Marino
4541e4b17023SJohn Marino /* Expand a call to one of the builtin functions __builtin_frame_address or
4542e4b17023SJohn Marino __builtin_return_address. */
4543e4b17023SJohn Marino
4544e4b17023SJohn Marino static rtx
expand_builtin_frame_address(tree fndecl,tree exp)4545e4b17023SJohn Marino expand_builtin_frame_address (tree fndecl, tree exp)
4546e4b17023SJohn Marino {
4547e4b17023SJohn Marino /* The argument must be a nonnegative integer constant.
4548e4b17023SJohn Marino It counts the number of frames to scan up the stack.
4549e4b17023SJohn Marino The value is the return address saved in that frame. */
4550e4b17023SJohn Marino if (call_expr_nargs (exp) == 0)
4551e4b17023SJohn Marino /* Warning about missing arg was already issued. */
4552e4b17023SJohn Marino return const0_rtx;
4553e4b17023SJohn Marino else if (! host_integerp (CALL_EXPR_ARG (exp, 0), 1))
4554e4b17023SJohn Marino {
4555e4b17023SJohn Marino if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
4556e4b17023SJohn Marino error ("invalid argument to %<__builtin_frame_address%>");
4557e4b17023SJohn Marino else
4558e4b17023SJohn Marino error ("invalid argument to %<__builtin_return_address%>");
4559e4b17023SJohn Marino return const0_rtx;
4560e4b17023SJohn Marino }
4561e4b17023SJohn Marino else
4562e4b17023SJohn Marino {
4563e4b17023SJohn Marino rtx tem
4564e4b17023SJohn Marino = expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl),
4565e4b17023SJohn Marino tree_low_cst (CALL_EXPR_ARG (exp, 0), 1));
4566e4b17023SJohn Marino
4567e4b17023SJohn Marino /* Some ports cannot access arbitrary stack frames. */
4568e4b17023SJohn Marino if (tem == NULL)
4569e4b17023SJohn Marino {
4570e4b17023SJohn Marino if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
4571e4b17023SJohn Marino warning (0, "unsupported argument to %<__builtin_frame_address%>");
4572e4b17023SJohn Marino else
4573e4b17023SJohn Marino warning (0, "unsupported argument to %<__builtin_return_address%>");
4574e4b17023SJohn Marino return const0_rtx;
4575e4b17023SJohn Marino }
4576e4b17023SJohn Marino
4577e4b17023SJohn Marino /* For __builtin_frame_address, return what we've got. */
4578e4b17023SJohn Marino if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
4579e4b17023SJohn Marino return tem;
4580e4b17023SJohn Marino
4581e4b17023SJohn Marino if (!REG_P (tem)
4582e4b17023SJohn Marino && ! CONSTANT_P (tem))
4583e4b17023SJohn Marino tem = copy_to_mode_reg (Pmode, tem);
4584e4b17023SJohn Marino return tem;
4585e4b17023SJohn Marino }
4586e4b17023SJohn Marino }
4587e4b17023SJohn Marino
4588e4b17023SJohn Marino /* Expand EXP, a call to the alloca builtin. Return NULL_RTX if we
4589e4b17023SJohn Marino failed and the caller should emit a normal call. CANNOT_ACCUMULATE
4590e4b17023SJohn Marino is the same as for allocate_dynamic_stack_space. */
4591e4b17023SJohn Marino
4592e4b17023SJohn Marino static rtx
expand_builtin_alloca(tree exp,bool cannot_accumulate)4593e4b17023SJohn Marino expand_builtin_alloca (tree exp, bool cannot_accumulate)
4594e4b17023SJohn Marino {
4595e4b17023SJohn Marino rtx op0;
4596e4b17023SJohn Marino rtx result;
4597e4b17023SJohn Marino bool valid_arglist;
4598e4b17023SJohn Marino unsigned int align;
4599e4b17023SJohn Marino bool alloca_with_align = (DECL_FUNCTION_CODE (get_callee_fndecl (exp))
4600e4b17023SJohn Marino == BUILT_IN_ALLOCA_WITH_ALIGN);
4601e4b17023SJohn Marino
4602e4b17023SJohn Marino /* Emit normal call if we use mudflap. */
4603e4b17023SJohn Marino if (flag_mudflap)
4604e4b17023SJohn Marino return NULL_RTX;
4605e4b17023SJohn Marino
4606e4b17023SJohn Marino valid_arglist
4607e4b17023SJohn Marino = (alloca_with_align
4608e4b17023SJohn Marino ? validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)
4609e4b17023SJohn Marino : validate_arglist (exp, INTEGER_TYPE, VOID_TYPE));
4610e4b17023SJohn Marino
4611e4b17023SJohn Marino if (!valid_arglist)
4612e4b17023SJohn Marino return NULL_RTX;
4613e4b17023SJohn Marino
4614e4b17023SJohn Marino /* Compute the argument. */
4615e4b17023SJohn Marino op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
4616e4b17023SJohn Marino
4617e4b17023SJohn Marino /* Compute the alignment. */
4618e4b17023SJohn Marino align = (alloca_with_align
4619e4b17023SJohn Marino ? TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 1))
4620e4b17023SJohn Marino : BIGGEST_ALIGNMENT);
4621e4b17023SJohn Marino
4622e4b17023SJohn Marino /* Allocate the desired space. */
4623e4b17023SJohn Marino result = allocate_dynamic_stack_space (op0, 0, align, cannot_accumulate);
4624e4b17023SJohn Marino result = convert_memory_address (ptr_mode, result);
4625e4b17023SJohn Marino
4626e4b17023SJohn Marino return result;
4627e4b17023SJohn Marino }
4628e4b17023SJohn Marino
4629e4b17023SJohn Marino /* Expand a call to a bswap builtin with argument ARG0. MODE
4630e4b17023SJohn Marino is the mode to expand with. */
4631e4b17023SJohn Marino
4632e4b17023SJohn Marino static rtx
expand_builtin_bswap(tree exp,rtx target,rtx subtarget)4633e4b17023SJohn Marino expand_builtin_bswap (tree exp, rtx target, rtx subtarget)
4634e4b17023SJohn Marino {
4635e4b17023SJohn Marino enum machine_mode mode;
4636e4b17023SJohn Marino tree arg;
4637e4b17023SJohn Marino rtx op0;
4638e4b17023SJohn Marino
4639e4b17023SJohn Marino if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE))
4640e4b17023SJohn Marino return NULL_RTX;
4641e4b17023SJohn Marino
4642e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 0);
4643e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (arg));
4644e4b17023SJohn Marino op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
4645e4b17023SJohn Marino
4646e4b17023SJohn Marino target = expand_unop (mode, bswap_optab, op0, target, 1);
4647e4b17023SJohn Marino
4648e4b17023SJohn Marino gcc_assert (target);
4649e4b17023SJohn Marino
4650e4b17023SJohn Marino return convert_to_mode (mode, target, 0);
4651e4b17023SJohn Marino }
4652e4b17023SJohn Marino
4653e4b17023SJohn Marino /* Expand a call to a unary builtin in EXP.
4654e4b17023SJohn Marino Return NULL_RTX if a normal call should be emitted rather than expanding the
4655e4b17023SJohn Marino function in-line. If convenient, the result should be placed in TARGET.
4656e4b17023SJohn Marino SUBTARGET may be used as the target for computing one of EXP's operands. */
4657e4b17023SJohn Marino
4658e4b17023SJohn Marino static rtx
expand_builtin_unop(enum machine_mode target_mode,tree exp,rtx target,rtx subtarget,optab op_optab)4659e4b17023SJohn Marino expand_builtin_unop (enum machine_mode target_mode, tree exp, rtx target,
4660e4b17023SJohn Marino rtx subtarget, optab op_optab)
4661e4b17023SJohn Marino {
4662e4b17023SJohn Marino rtx op0;
4663e4b17023SJohn Marino
4664e4b17023SJohn Marino if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE))
4665e4b17023SJohn Marino return NULL_RTX;
4666e4b17023SJohn Marino
4667e4b17023SJohn Marino /* Compute the argument. */
4668e4b17023SJohn Marino op0 = expand_expr (CALL_EXPR_ARG (exp, 0),
4669e4b17023SJohn Marino (subtarget
4670e4b17023SJohn Marino && (TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 0)))
4671e4b17023SJohn Marino == GET_MODE (subtarget))) ? subtarget : NULL_RTX,
4672e4b17023SJohn Marino VOIDmode, EXPAND_NORMAL);
4673e4b17023SJohn Marino /* Compute op, into TARGET if possible.
4674e4b17023SJohn Marino Set TARGET to wherever the result comes back. */
4675e4b17023SJohn Marino target = expand_unop (TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 0))),
4676e4b17023SJohn Marino op_optab, op0, target, op_optab != clrsb_optab);
4677e4b17023SJohn Marino gcc_assert (target);
4678e4b17023SJohn Marino
4679e4b17023SJohn Marino return convert_to_mode (target_mode, target, 0);
4680e4b17023SJohn Marino }
4681e4b17023SJohn Marino
4682e4b17023SJohn Marino /* Expand a call to __builtin_expect. We just return our argument
4683e4b17023SJohn Marino as the builtin_expect semantic should've been already executed by
4684e4b17023SJohn Marino tree branch prediction pass. */
4685e4b17023SJohn Marino
4686e4b17023SJohn Marino static rtx
expand_builtin_expect(tree exp,rtx target)4687e4b17023SJohn Marino expand_builtin_expect (tree exp, rtx target)
4688e4b17023SJohn Marino {
4689e4b17023SJohn Marino tree arg;
4690e4b17023SJohn Marino
4691e4b17023SJohn Marino if (call_expr_nargs (exp) < 2)
4692e4b17023SJohn Marino return const0_rtx;
4693e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 0);
4694e4b17023SJohn Marino
4695e4b17023SJohn Marino target = expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
4696e4b17023SJohn Marino /* When guessing was done, the hints should be already stripped away. */
4697e4b17023SJohn Marino gcc_assert (!flag_guess_branch_prob
4698e4b17023SJohn Marino || optimize == 0 || seen_error ());
4699e4b17023SJohn Marino return target;
4700e4b17023SJohn Marino }
4701e4b17023SJohn Marino
4702e4b17023SJohn Marino /* Expand a call to __builtin_assume_aligned. We just return our first
4703e4b17023SJohn Marino argument as the builtin_assume_aligned semantic should've been already
4704e4b17023SJohn Marino executed by CCP. */
4705e4b17023SJohn Marino
4706e4b17023SJohn Marino static rtx
expand_builtin_assume_aligned(tree exp,rtx target)4707e4b17023SJohn Marino expand_builtin_assume_aligned (tree exp, rtx target)
4708e4b17023SJohn Marino {
4709e4b17023SJohn Marino if (call_expr_nargs (exp) < 2)
4710e4b17023SJohn Marino return const0_rtx;
4711e4b17023SJohn Marino target = expand_expr (CALL_EXPR_ARG (exp, 0), target, VOIDmode,
4712e4b17023SJohn Marino EXPAND_NORMAL);
4713e4b17023SJohn Marino gcc_assert (!TREE_SIDE_EFFECTS (CALL_EXPR_ARG (exp, 1))
4714e4b17023SJohn Marino && (call_expr_nargs (exp) < 3
4715e4b17023SJohn Marino || !TREE_SIDE_EFFECTS (CALL_EXPR_ARG (exp, 2))));
4716e4b17023SJohn Marino return target;
4717e4b17023SJohn Marino }
4718e4b17023SJohn Marino
4719e4b17023SJohn Marino void
expand_builtin_trap(void)4720e4b17023SJohn Marino expand_builtin_trap (void)
4721e4b17023SJohn Marino {
4722e4b17023SJohn Marino #ifdef HAVE_trap
4723e4b17023SJohn Marino if (HAVE_trap)
47245ce9237cSJohn Marino {
47255ce9237cSJohn Marino rtx insn = emit_insn (gen_trap ());
47265ce9237cSJohn Marino /* For trap insns when not accumulating outgoing args force
47275ce9237cSJohn Marino REG_ARGS_SIZE note to prevent crossjumping of calls with
47285ce9237cSJohn Marino different args sizes. */
47295ce9237cSJohn Marino if (!ACCUMULATE_OUTGOING_ARGS)
47305ce9237cSJohn Marino add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
47315ce9237cSJohn Marino }
4732e4b17023SJohn Marino else
4733e4b17023SJohn Marino #endif
4734e4b17023SJohn Marino emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
4735e4b17023SJohn Marino emit_barrier ();
4736e4b17023SJohn Marino }
4737e4b17023SJohn Marino
4738e4b17023SJohn Marino /* Expand a call to __builtin_unreachable. We do nothing except emit
4739e4b17023SJohn Marino a barrier saying that control flow will not pass here.
4740e4b17023SJohn Marino
4741e4b17023SJohn Marino It is the responsibility of the program being compiled to ensure
4742e4b17023SJohn Marino that control flow does never reach __builtin_unreachable. */
4743e4b17023SJohn Marino static void
expand_builtin_unreachable(void)4744e4b17023SJohn Marino expand_builtin_unreachable (void)
4745e4b17023SJohn Marino {
4746e4b17023SJohn Marino emit_barrier ();
4747e4b17023SJohn Marino }
4748e4b17023SJohn Marino
4749e4b17023SJohn Marino /* Expand EXP, a call to fabs, fabsf or fabsl.
4750e4b17023SJohn Marino Return NULL_RTX if a normal call should be emitted rather than expanding
4751e4b17023SJohn Marino the function inline. If convenient, the result should be placed
4752e4b17023SJohn Marino in TARGET. SUBTARGET may be used as the target for computing
4753e4b17023SJohn Marino the operand. */
4754e4b17023SJohn Marino
4755e4b17023SJohn Marino static rtx
expand_builtin_fabs(tree exp,rtx target,rtx subtarget)4756e4b17023SJohn Marino expand_builtin_fabs (tree exp, rtx target, rtx subtarget)
4757e4b17023SJohn Marino {
4758e4b17023SJohn Marino enum machine_mode mode;
4759e4b17023SJohn Marino tree arg;
4760e4b17023SJohn Marino rtx op0;
4761e4b17023SJohn Marino
4762e4b17023SJohn Marino if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
4763e4b17023SJohn Marino return NULL_RTX;
4764e4b17023SJohn Marino
4765e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 0);
4766e4b17023SJohn Marino CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
4767e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (arg));
4768e4b17023SJohn Marino op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
4769e4b17023SJohn Marino return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
4770e4b17023SJohn Marino }
4771e4b17023SJohn Marino
4772e4b17023SJohn Marino /* Expand EXP, a call to copysign, copysignf, or copysignl.
4773e4b17023SJohn Marino Return NULL is a normal call should be emitted rather than expanding the
4774e4b17023SJohn Marino function inline. If convenient, the result should be placed in TARGET.
4775e4b17023SJohn Marino SUBTARGET may be used as the target for computing the operand. */
4776e4b17023SJohn Marino
4777e4b17023SJohn Marino static rtx
expand_builtin_copysign(tree exp,rtx target,rtx subtarget)4778e4b17023SJohn Marino expand_builtin_copysign (tree exp, rtx target, rtx subtarget)
4779e4b17023SJohn Marino {
4780e4b17023SJohn Marino rtx op0, op1;
4781e4b17023SJohn Marino tree arg;
4782e4b17023SJohn Marino
4783e4b17023SJohn Marino if (!validate_arglist (exp, REAL_TYPE, REAL_TYPE, VOID_TYPE))
4784e4b17023SJohn Marino return NULL_RTX;
4785e4b17023SJohn Marino
4786e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 0);
4787e4b17023SJohn Marino op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
4788e4b17023SJohn Marino
4789e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 1);
4790e4b17023SJohn Marino op1 = expand_normal (arg);
4791e4b17023SJohn Marino
4792e4b17023SJohn Marino return expand_copysign (op0, op1, target);
4793e4b17023SJohn Marino }
4794e4b17023SJohn Marino
4795e4b17023SJohn Marino /* Create a new constant string literal and return a char* pointer to it.
4796e4b17023SJohn Marino The STRING_CST value is the LEN characters at STR. */
4797e4b17023SJohn Marino tree
build_string_literal(int len,const char * str)4798e4b17023SJohn Marino build_string_literal (int len, const char *str)
4799e4b17023SJohn Marino {
4800e4b17023SJohn Marino tree t, elem, index, type;
4801e4b17023SJohn Marino
4802e4b17023SJohn Marino t = build_string (len, str);
4803e4b17023SJohn Marino elem = build_type_variant (char_type_node, 1, 0);
4804e4b17023SJohn Marino index = build_index_type (size_int (len - 1));
4805e4b17023SJohn Marino type = build_array_type (elem, index);
4806e4b17023SJohn Marino TREE_TYPE (t) = type;
4807e4b17023SJohn Marino TREE_CONSTANT (t) = 1;
4808e4b17023SJohn Marino TREE_READONLY (t) = 1;
4809e4b17023SJohn Marino TREE_STATIC (t) = 1;
4810e4b17023SJohn Marino
4811e4b17023SJohn Marino type = build_pointer_type (elem);
4812e4b17023SJohn Marino t = build1 (ADDR_EXPR, type,
4813e4b17023SJohn Marino build4 (ARRAY_REF, elem,
4814e4b17023SJohn Marino t, integer_zero_node, NULL_TREE, NULL_TREE));
4815e4b17023SJohn Marino return t;
4816e4b17023SJohn Marino }
4817e4b17023SJohn Marino
4818e4b17023SJohn Marino /* Expand a call to __builtin___clear_cache. */
4819e4b17023SJohn Marino
4820e4b17023SJohn Marino static rtx
expand_builtin___clear_cache(tree exp ATTRIBUTE_UNUSED)4821e4b17023SJohn Marino expand_builtin___clear_cache (tree exp ATTRIBUTE_UNUSED)
4822e4b17023SJohn Marino {
4823e4b17023SJohn Marino #ifndef HAVE_clear_cache
4824e4b17023SJohn Marino #ifdef CLEAR_INSN_CACHE
4825e4b17023SJohn Marino /* There is no "clear_cache" insn, and __clear_cache() in libgcc
4826e4b17023SJohn Marino does something. Just do the default expansion to a call to
4827e4b17023SJohn Marino __clear_cache(). */
4828e4b17023SJohn Marino return NULL_RTX;
4829e4b17023SJohn Marino #else
4830e4b17023SJohn Marino /* There is no "clear_cache" insn, and __clear_cache() in libgcc
4831e4b17023SJohn Marino does nothing. There is no need to call it. Do nothing. */
4832e4b17023SJohn Marino return const0_rtx;
4833e4b17023SJohn Marino #endif /* CLEAR_INSN_CACHE */
4834e4b17023SJohn Marino #else
4835e4b17023SJohn Marino /* We have a "clear_cache" insn, and it will handle everything. */
4836e4b17023SJohn Marino tree begin, end;
4837e4b17023SJohn Marino rtx begin_rtx, end_rtx;
4838e4b17023SJohn Marino
4839e4b17023SJohn Marino /* We must not expand to a library call. If we did, any
4840e4b17023SJohn Marino fallback library function in libgcc that might contain a call to
4841e4b17023SJohn Marino __builtin___clear_cache() would recurse infinitely. */
4842e4b17023SJohn Marino if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
4843e4b17023SJohn Marino {
4844e4b17023SJohn Marino error ("both arguments to %<__builtin___clear_cache%> must be pointers");
4845e4b17023SJohn Marino return const0_rtx;
4846e4b17023SJohn Marino }
4847e4b17023SJohn Marino
4848e4b17023SJohn Marino if (HAVE_clear_cache)
4849e4b17023SJohn Marino {
4850e4b17023SJohn Marino struct expand_operand ops[2];
4851e4b17023SJohn Marino
4852e4b17023SJohn Marino begin = CALL_EXPR_ARG (exp, 0);
4853e4b17023SJohn Marino begin_rtx = expand_expr (begin, NULL_RTX, Pmode, EXPAND_NORMAL);
4854e4b17023SJohn Marino
4855e4b17023SJohn Marino end = CALL_EXPR_ARG (exp, 1);
4856e4b17023SJohn Marino end_rtx = expand_expr (end, NULL_RTX, Pmode, EXPAND_NORMAL);
4857e4b17023SJohn Marino
4858e4b17023SJohn Marino create_address_operand (&ops[0], begin_rtx);
4859e4b17023SJohn Marino create_address_operand (&ops[1], end_rtx);
4860e4b17023SJohn Marino if (maybe_expand_insn (CODE_FOR_clear_cache, 2, ops))
4861e4b17023SJohn Marino return const0_rtx;
4862e4b17023SJohn Marino }
4863e4b17023SJohn Marino return const0_rtx;
4864e4b17023SJohn Marino #endif /* HAVE_clear_cache */
4865e4b17023SJohn Marino }
4866e4b17023SJohn Marino
4867e4b17023SJohn Marino /* Given a trampoline address, make sure it satisfies TRAMPOLINE_ALIGNMENT. */
4868e4b17023SJohn Marino
4869e4b17023SJohn Marino static rtx
round_trampoline_addr(rtx tramp)4870e4b17023SJohn Marino round_trampoline_addr (rtx tramp)
4871e4b17023SJohn Marino {
4872e4b17023SJohn Marino rtx temp, addend, mask;
4873e4b17023SJohn Marino
4874e4b17023SJohn Marino /* If we don't need too much alignment, we'll have been guaranteed
4875e4b17023SJohn Marino proper alignment by get_trampoline_type. */
4876e4b17023SJohn Marino if (TRAMPOLINE_ALIGNMENT <= STACK_BOUNDARY)
4877e4b17023SJohn Marino return tramp;
4878e4b17023SJohn Marino
4879e4b17023SJohn Marino /* Round address up to desired boundary. */
4880e4b17023SJohn Marino temp = gen_reg_rtx (Pmode);
4881e4b17023SJohn Marino addend = GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1);
4882e4b17023SJohn Marino mask = GEN_INT (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
4883e4b17023SJohn Marino
4884e4b17023SJohn Marino temp = expand_simple_binop (Pmode, PLUS, tramp, addend,
4885e4b17023SJohn Marino temp, 0, OPTAB_LIB_WIDEN);
4886e4b17023SJohn Marino tramp = expand_simple_binop (Pmode, AND, temp, mask,
4887e4b17023SJohn Marino temp, 0, OPTAB_LIB_WIDEN);
4888e4b17023SJohn Marino
4889e4b17023SJohn Marino return tramp;
4890e4b17023SJohn Marino }
4891e4b17023SJohn Marino
4892e4b17023SJohn Marino static rtx
expand_builtin_init_trampoline(tree exp,bool onstack)4893e4b17023SJohn Marino expand_builtin_init_trampoline (tree exp, bool onstack)
4894e4b17023SJohn Marino {
4895e4b17023SJohn Marino tree t_tramp, t_func, t_chain;
4896e4b17023SJohn Marino rtx m_tramp, r_tramp, r_chain, tmp;
4897e4b17023SJohn Marino
4898e4b17023SJohn Marino if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE,
4899e4b17023SJohn Marino POINTER_TYPE, VOID_TYPE))
4900e4b17023SJohn Marino return NULL_RTX;
4901e4b17023SJohn Marino
4902e4b17023SJohn Marino t_tramp = CALL_EXPR_ARG (exp, 0);
4903e4b17023SJohn Marino t_func = CALL_EXPR_ARG (exp, 1);
4904e4b17023SJohn Marino t_chain = CALL_EXPR_ARG (exp, 2);
4905e4b17023SJohn Marino
4906e4b17023SJohn Marino r_tramp = expand_normal (t_tramp);
4907e4b17023SJohn Marino m_tramp = gen_rtx_MEM (BLKmode, r_tramp);
4908e4b17023SJohn Marino MEM_NOTRAP_P (m_tramp) = 1;
4909e4b17023SJohn Marino
4910e4b17023SJohn Marino /* If ONSTACK, the TRAMP argument should be the address of a field
4911e4b17023SJohn Marino within the local function's FRAME decl. Either way, let's see if
4912e4b17023SJohn Marino we can fill in the MEM_ATTRs for this memory. */
4913e4b17023SJohn Marino if (TREE_CODE (t_tramp) == ADDR_EXPR)
4914e4b17023SJohn Marino set_mem_attributes_minus_bitpos (m_tramp, TREE_OPERAND (t_tramp, 0),
4915e4b17023SJohn Marino true, 0);
4916e4b17023SJohn Marino
4917e4b17023SJohn Marino /* Creator of a heap trampoline is responsible for making sure the
4918e4b17023SJohn Marino address is aligned to at least STACK_BOUNDARY. Normally malloc
4919e4b17023SJohn Marino will ensure this anyhow. */
4920e4b17023SJohn Marino tmp = round_trampoline_addr (r_tramp);
4921e4b17023SJohn Marino if (tmp != r_tramp)
4922e4b17023SJohn Marino {
4923e4b17023SJohn Marino m_tramp = change_address (m_tramp, BLKmode, tmp);
4924e4b17023SJohn Marino set_mem_align (m_tramp, TRAMPOLINE_ALIGNMENT);
4925e4b17023SJohn Marino set_mem_size (m_tramp, TRAMPOLINE_SIZE);
4926e4b17023SJohn Marino }
4927e4b17023SJohn Marino
4928e4b17023SJohn Marino /* The FUNC argument should be the address of the nested function.
4929e4b17023SJohn Marino Extract the actual function decl to pass to the hook. */
4930e4b17023SJohn Marino gcc_assert (TREE_CODE (t_func) == ADDR_EXPR);
4931e4b17023SJohn Marino t_func = TREE_OPERAND (t_func, 0);
4932e4b17023SJohn Marino gcc_assert (TREE_CODE (t_func) == FUNCTION_DECL);
4933e4b17023SJohn Marino
4934e4b17023SJohn Marino r_chain = expand_normal (t_chain);
4935e4b17023SJohn Marino
4936e4b17023SJohn Marino /* Generate insns to initialize the trampoline. */
4937e4b17023SJohn Marino targetm.calls.trampoline_init (m_tramp, t_func, r_chain);
4938e4b17023SJohn Marino
4939e4b17023SJohn Marino if (onstack)
4940e4b17023SJohn Marino {
4941e4b17023SJohn Marino trampolines_created = 1;
4942e4b17023SJohn Marino
4943e4b17023SJohn Marino warning_at (DECL_SOURCE_LOCATION (t_func), OPT_Wtrampolines,
4944e4b17023SJohn Marino "trampoline generated for nested function %qD", t_func);
4945e4b17023SJohn Marino }
4946e4b17023SJohn Marino
4947e4b17023SJohn Marino return const0_rtx;
4948e4b17023SJohn Marino }
4949e4b17023SJohn Marino
4950e4b17023SJohn Marino static rtx
expand_builtin_adjust_trampoline(tree exp)4951e4b17023SJohn Marino expand_builtin_adjust_trampoline (tree exp)
4952e4b17023SJohn Marino {
4953e4b17023SJohn Marino rtx tramp;
4954e4b17023SJohn Marino
4955e4b17023SJohn Marino if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
4956e4b17023SJohn Marino return NULL_RTX;
4957e4b17023SJohn Marino
4958e4b17023SJohn Marino tramp = expand_normal (CALL_EXPR_ARG (exp, 0));
4959e4b17023SJohn Marino tramp = round_trampoline_addr (tramp);
4960e4b17023SJohn Marino if (targetm.calls.trampoline_adjust_address)
4961e4b17023SJohn Marino tramp = targetm.calls.trampoline_adjust_address (tramp);
4962e4b17023SJohn Marino
4963e4b17023SJohn Marino return tramp;
4964e4b17023SJohn Marino }
4965e4b17023SJohn Marino
4966e4b17023SJohn Marino /* Expand the call EXP to the built-in signbit, signbitf or signbitl
4967e4b17023SJohn Marino function. The function first checks whether the back end provides
4968e4b17023SJohn Marino an insn to implement signbit for the respective mode. If not, it
4969e4b17023SJohn Marino checks whether the floating point format of the value is such that
4970e4b17023SJohn Marino the sign bit can be extracted. If that is not the case, the
4971e4b17023SJohn Marino function returns NULL_RTX to indicate that a normal call should be
4972e4b17023SJohn Marino emitted rather than expanding the function in-line. EXP is the
4973e4b17023SJohn Marino expression that is a call to the builtin function; if convenient,
4974e4b17023SJohn Marino the result should be placed in TARGET. */
4975e4b17023SJohn Marino static rtx
expand_builtin_signbit(tree exp,rtx target)4976e4b17023SJohn Marino expand_builtin_signbit (tree exp, rtx target)
4977e4b17023SJohn Marino {
4978e4b17023SJohn Marino const struct real_format *fmt;
4979e4b17023SJohn Marino enum machine_mode fmode, imode, rmode;
4980e4b17023SJohn Marino tree arg;
4981e4b17023SJohn Marino int word, bitpos;
4982e4b17023SJohn Marino enum insn_code icode;
4983e4b17023SJohn Marino rtx temp;
4984e4b17023SJohn Marino location_t loc = EXPR_LOCATION (exp);
4985e4b17023SJohn Marino
4986e4b17023SJohn Marino if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
4987e4b17023SJohn Marino return NULL_RTX;
4988e4b17023SJohn Marino
4989e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 0);
4990e4b17023SJohn Marino fmode = TYPE_MODE (TREE_TYPE (arg));
4991e4b17023SJohn Marino rmode = TYPE_MODE (TREE_TYPE (exp));
4992e4b17023SJohn Marino fmt = REAL_MODE_FORMAT (fmode);
4993e4b17023SJohn Marino
4994e4b17023SJohn Marino arg = builtin_save_expr (arg);
4995e4b17023SJohn Marino
4996e4b17023SJohn Marino /* Expand the argument yielding a RTX expression. */
4997e4b17023SJohn Marino temp = expand_normal (arg);
4998e4b17023SJohn Marino
4999e4b17023SJohn Marino /* Check if the back end provides an insn that handles signbit for the
5000e4b17023SJohn Marino argument's mode. */
5001e4b17023SJohn Marino icode = optab_handler (signbit_optab, fmode);
5002e4b17023SJohn Marino if (icode != CODE_FOR_nothing)
5003e4b17023SJohn Marino {
5004e4b17023SJohn Marino rtx last = get_last_insn ();
5005e4b17023SJohn Marino target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
5006e4b17023SJohn Marino if (maybe_emit_unop_insn (icode, target, temp, UNKNOWN))
5007e4b17023SJohn Marino return target;
5008e4b17023SJohn Marino delete_insns_since (last);
5009e4b17023SJohn Marino }
5010e4b17023SJohn Marino
5011e4b17023SJohn Marino /* For floating point formats without a sign bit, implement signbit
5012e4b17023SJohn Marino as "ARG < 0.0". */
5013e4b17023SJohn Marino bitpos = fmt->signbit_ro;
5014e4b17023SJohn Marino if (bitpos < 0)
5015e4b17023SJohn Marino {
5016e4b17023SJohn Marino /* But we can't do this if the format supports signed zero. */
5017e4b17023SJohn Marino if (fmt->has_signed_zero && HONOR_SIGNED_ZEROS (fmode))
5018e4b17023SJohn Marino return NULL_RTX;
5019e4b17023SJohn Marino
5020e4b17023SJohn Marino arg = fold_build2_loc (loc, LT_EXPR, TREE_TYPE (exp), arg,
5021e4b17023SJohn Marino build_real (TREE_TYPE (arg), dconst0));
5022e4b17023SJohn Marino return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
5023e4b17023SJohn Marino }
5024e4b17023SJohn Marino
5025e4b17023SJohn Marino if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
5026e4b17023SJohn Marino {
5027e4b17023SJohn Marino imode = int_mode_for_mode (fmode);
5028e4b17023SJohn Marino if (imode == BLKmode)
5029e4b17023SJohn Marino return NULL_RTX;
5030e4b17023SJohn Marino temp = gen_lowpart (imode, temp);
5031e4b17023SJohn Marino }
5032e4b17023SJohn Marino else
5033e4b17023SJohn Marino {
5034e4b17023SJohn Marino imode = word_mode;
5035e4b17023SJohn Marino /* Handle targets with different FP word orders. */
5036e4b17023SJohn Marino if (FLOAT_WORDS_BIG_ENDIAN)
5037e4b17023SJohn Marino word = (GET_MODE_BITSIZE (fmode) - bitpos) / BITS_PER_WORD;
5038e4b17023SJohn Marino else
5039e4b17023SJohn Marino word = bitpos / BITS_PER_WORD;
5040e4b17023SJohn Marino temp = operand_subword_force (temp, word, fmode);
5041e4b17023SJohn Marino bitpos = bitpos % BITS_PER_WORD;
5042e4b17023SJohn Marino }
5043e4b17023SJohn Marino
5044e4b17023SJohn Marino /* Force the intermediate word_mode (or narrower) result into a
5045e4b17023SJohn Marino register. This avoids attempting to create paradoxical SUBREGs
5046e4b17023SJohn Marino of floating point modes below. */
5047e4b17023SJohn Marino temp = force_reg (imode, temp);
5048e4b17023SJohn Marino
5049e4b17023SJohn Marino /* If the bitpos is within the "result mode" lowpart, the operation
5050e4b17023SJohn Marino can be implement with a single bitwise AND. Otherwise, we need
5051e4b17023SJohn Marino a right shift and an AND. */
5052e4b17023SJohn Marino
5053e4b17023SJohn Marino if (bitpos < GET_MODE_BITSIZE (rmode))
5054e4b17023SJohn Marino {
5055e4b17023SJohn Marino double_int mask = double_int_setbit (double_int_zero, bitpos);
5056e4b17023SJohn Marino
5057e4b17023SJohn Marino if (GET_MODE_SIZE (imode) > GET_MODE_SIZE (rmode))
5058e4b17023SJohn Marino temp = gen_lowpart (rmode, temp);
5059e4b17023SJohn Marino temp = expand_binop (rmode, and_optab, temp,
5060e4b17023SJohn Marino immed_double_int_const (mask, rmode),
5061e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
5062e4b17023SJohn Marino }
5063e4b17023SJohn Marino else
5064e4b17023SJohn Marino {
5065e4b17023SJohn Marino /* Perform a logical right shift to place the signbit in the least
5066e4b17023SJohn Marino significant bit, then truncate the result to the desired mode
5067e4b17023SJohn Marino and mask just this bit. */
5068e4b17023SJohn Marino temp = expand_shift (RSHIFT_EXPR, imode, temp, bitpos, NULL_RTX, 1);
5069e4b17023SJohn Marino temp = gen_lowpart (rmode, temp);
5070e4b17023SJohn Marino temp = expand_binop (rmode, and_optab, temp, const1_rtx,
5071e4b17023SJohn Marino NULL_RTX, 1, OPTAB_LIB_WIDEN);
5072e4b17023SJohn Marino }
5073e4b17023SJohn Marino
5074e4b17023SJohn Marino return temp;
5075e4b17023SJohn Marino }
5076e4b17023SJohn Marino
5077e4b17023SJohn Marino /* Expand fork or exec calls. TARGET is the desired target of the
5078e4b17023SJohn Marino call. EXP is the call. FN is the
5079e4b17023SJohn Marino identificator of the actual function. IGNORE is nonzero if the
5080e4b17023SJohn Marino value is to be ignored. */
5081e4b17023SJohn Marino
5082e4b17023SJohn Marino static rtx
expand_builtin_fork_or_exec(tree fn,tree exp,rtx target,int ignore)5083e4b17023SJohn Marino expand_builtin_fork_or_exec (tree fn, tree exp, rtx target, int ignore)
5084e4b17023SJohn Marino {
5085e4b17023SJohn Marino tree id, decl;
5086e4b17023SJohn Marino tree call;
5087e4b17023SJohn Marino
5088e4b17023SJohn Marino /* If we are not profiling, just call the function. */
5089e4b17023SJohn Marino if (!profile_arc_flag)
5090e4b17023SJohn Marino return NULL_RTX;
5091e4b17023SJohn Marino
5092e4b17023SJohn Marino /* Otherwise call the wrapper. This should be equivalent for the rest of
5093e4b17023SJohn Marino compiler, so the code does not diverge, and the wrapper may run the
5094e4b17023SJohn Marino code necessary for keeping the profiling sane. */
5095e4b17023SJohn Marino
5096e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fn))
5097e4b17023SJohn Marino {
5098e4b17023SJohn Marino case BUILT_IN_FORK:
5099e4b17023SJohn Marino id = get_identifier ("__gcov_fork");
5100e4b17023SJohn Marino break;
5101e4b17023SJohn Marino
5102e4b17023SJohn Marino case BUILT_IN_EXECL:
5103e4b17023SJohn Marino id = get_identifier ("__gcov_execl");
5104e4b17023SJohn Marino break;
5105e4b17023SJohn Marino
5106e4b17023SJohn Marino case BUILT_IN_EXECV:
5107e4b17023SJohn Marino id = get_identifier ("__gcov_execv");
5108e4b17023SJohn Marino break;
5109e4b17023SJohn Marino
5110e4b17023SJohn Marino case BUILT_IN_EXECLP:
5111e4b17023SJohn Marino id = get_identifier ("__gcov_execlp");
5112e4b17023SJohn Marino break;
5113e4b17023SJohn Marino
5114e4b17023SJohn Marino case BUILT_IN_EXECLE:
5115e4b17023SJohn Marino id = get_identifier ("__gcov_execle");
5116e4b17023SJohn Marino break;
5117e4b17023SJohn Marino
5118e4b17023SJohn Marino case BUILT_IN_EXECVP:
5119e4b17023SJohn Marino id = get_identifier ("__gcov_execvp");
5120e4b17023SJohn Marino break;
5121e4b17023SJohn Marino
5122e4b17023SJohn Marino case BUILT_IN_EXECVE:
5123e4b17023SJohn Marino id = get_identifier ("__gcov_execve");
5124e4b17023SJohn Marino break;
5125e4b17023SJohn Marino
5126e4b17023SJohn Marino default:
5127e4b17023SJohn Marino gcc_unreachable ();
5128e4b17023SJohn Marino }
5129e4b17023SJohn Marino
5130e4b17023SJohn Marino decl = build_decl (DECL_SOURCE_LOCATION (fn),
5131e4b17023SJohn Marino FUNCTION_DECL, id, TREE_TYPE (fn));
5132e4b17023SJohn Marino DECL_EXTERNAL (decl) = 1;
5133e4b17023SJohn Marino TREE_PUBLIC (decl) = 1;
5134e4b17023SJohn Marino DECL_ARTIFICIAL (decl) = 1;
5135e4b17023SJohn Marino TREE_NOTHROW (decl) = 1;
5136e4b17023SJohn Marino DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
5137e4b17023SJohn Marino DECL_VISIBILITY_SPECIFIED (decl) = 1;
5138e4b17023SJohn Marino call = rewrite_call_expr (EXPR_LOCATION (exp), exp, 0, decl, 0);
5139e4b17023SJohn Marino return expand_call (call, target, ignore);
5140e4b17023SJohn Marino }
5141e4b17023SJohn Marino
5142e4b17023SJohn Marino
5143e4b17023SJohn Marino
5144e4b17023SJohn Marino /* Reconstitute a mode for a __sync intrinsic operation. Since the type of
5145e4b17023SJohn Marino the pointer in these functions is void*, the tree optimizers may remove
5146e4b17023SJohn Marino casts. The mode computed in expand_builtin isn't reliable either, due
5147e4b17023SJohn Marino to __sync_bool_compare_and_swap.
5148e4b17023SJohn Marino
5149e4b17023SJohn Marino FCODE_DIFF should be fcode - base, where base is the FOO_1 code for the
5150e4b17023SJohn Marino group of builtins. This gives us log2 of the mode size. */
5151e4b17023SJohn Marino
5152e4b17023SJohn Marino static inline enum machine_mode
get_builtin_sync_mode(int fcode_diff)5153e4b17023SJohn Marino get_builtin_sync_mode (int fcode_diff)
5154e4b17023SJohn Marino {
5155e4b17023SJohn Marino /* The size is not negotiable, so ask not to get BLKmode in return
5156e4b17023SJohn Marino if the target indicates that a smaller size would be better. */
5157e4b17023SJohn Marino return mode_for_size (BITS_PER_UNIT << fcode_diff, MODE_INT, 0);
5158e4b17023SJohn Marino }
5159e4b17023SJohn Marino
5160e4b17023SJohn Marino /* Expand the memory expression LOC and return the appropriate memory operand
5161e4b17023SJohn Marino for the builtin_sync operations. */
5162e4b17023SJohn Marino
5163e4b17023SJohn Marino static rtx
get_builtin_sync_mem(tree loc,enum machine_mode mode)5164e4b17023SJohn Marino get_builtin_sync_mem (tree loc, enum machine_mode mode)
5165e4b17023SJohn Marino {
5166e4b17023SJohn Marino rtx addr, mem;
5167e4b17023SJohn Marino
5168e4b17023SJohn Marino addr = expand_expr (loc, NULL_RTX, ptr_mode, EXPAND_SUM);
5169e4b17023SJohn Marino addr = convert_memory_address (Pmode, addr);
5170e4b17023SJohn Marino
5171e4b17023SJohn Marino /* Note that we explicitly do not want any alias information for this
5172e4b17023SJohn Marino memory, so that we kill all other live memories. Otherwise we don't
5173e4b17023SJohn Marino satisfy the full barrier semantics of the intrinsic. */
5174e4b17023SJohn Marino mem = validize_mem (gen_rtx_MEM (mode, addr));
5175e4b17023SJohn Marino
5176e4b17023SJohn Marino /* The alignment needs to be at least according to that of the mode. */
5177e4b17023SJohn Marino set_mem_align (mem, MAX (GET_MODE_ALIGNMENT (mode),
5178e4b17023SJohn Marino get_pointer_alignment (loc)));
5179e4b17023SJohn Marino set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER);
5180e4b17023SJohn Marino MEM_VOLATILE_P (mem) = 1;
5181e4b17023SJohn Marino
5182e4b17023SJohn Marino return mem;
5183e4b17023SJohn Marino }
5184e4b17023SJohn Marino
5185e4b17023SJohn Marino /* Make sure an argument is in the right mode.
5186e4b17023SJohn Marino EXP is the tree argument.
5187e4b17023SJohn Marino MODE is the mode it should be in. */
5188e4b17023SJohn Marino
5189e4b17023SJohn Marino static rtx
expand_expr_force_mode(tree exp,enum machine_mode mode)5190e4b17023SJohn Marino expand_expr_force_mode (tree exp, enum machine_mode mode)
5191e4b17023SJohn Marino {
5192e4b17023SJohn Marino rtx val;
5193e4b17023SJohn Marino enum machine_mode old_mode;
5194e4b17023SJohn Marino
5195e4b17023SJohn Marino val = expand_expr (exp, NULL_RTX, mode, EXPAND_NORMAL);
5196e4b17023SJohn Marino /* If VAL is promoted to a wider mode, convert it back to MODE. Take care
5197e4b17023SJohn Marino of CONST_INTs, where we know the old_mode only from the call argument. */
5198e4b17023SJohn Marino
5199e4b17023SJohn Marino old_mode = GET_MODE (val);
5200e4b17023SJohn Marino if (old_mode == VOIDmode)
5201e4b17023SJohn Marino old_mode = TYPE_MODE (TREE_TYPE (exp));
5202e4b17023SJohn Marino val = convert_modes (mode, old_mode, val, 1);
5203e4b17023SJohn Marino return val;
5204e4b17023SJohn Marino }
5205e4b17023SJohn Marino
5206e4b17023SJohn Marino
5207e4b17023SJohn Marino /* Expand the __sync_xxx_and_fetch and __sync_fetch_and_xxx intrinsics.
5208e4b17023SJohn Marino EXP is the CALL_EXPR. CODE is the rtx code
5209e4b17023SJohn Marino that corresponds to the arithmetic or logical operation from the name;
5210e4b17023SJohn Marino an exception here is that NOT actually means NAND. TARGET is an optional
5211e4b17023SJohn Marino place for us to store the results; AFTER is true if this is the
5212e4b17023SJohn Marino fetch_and_xxx form. */
5213e4b17023SJohn Marino
5214e4b17023SJohn Marino static rtx
expand_builtin_sync_operation(enum machine_mode mode,tree exp,enum rtx_code code,bool after,rtx target)5215e4b17023SJohn Marino expand_builtin_sync_operation (enum machine_mode mode, tree exp,
5216e4b17023SJohn Marino enum rtx_code code, bool after,
5217e4b17023SJohn Marino rtx target)
5218e4b17023SJohn Marino {
5219e4b17023SJohn Marino rtx val, mem;
5220e4b17023SJohn Marino location_t loc = EXPR_LOCATION (exp);
5221e4b17023SJohn Marino
5222e4b17023SJohn Marino if (code == NOT && warn_sync_nand)
5223e4b17023SJohn Marino {
5224e4b17023SJohn Marino tree fndecl = get_callee_fndecl (exp);
5225e4b17023SJohn Marino enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
5226e4b17023SJohn Marino
5227e4b17023SJohn Marino static bool warned_f_a_n, warned_n_a_f;
5228e4b17023SJohn Marino
5229e4b17023SJohn Marino switch (fcode)
5230e4b17023SJohn Marino {
5231e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_NAND_1:
5232e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_NAND_2:
5233e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_NAND_4:
5234e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_NAND_8:
5235e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_NAND_16:
5236e4b17023SJohn Marino if (warned_f_a_n)
5237e4b17023SJohn Marino break;
5238e4b17023SJohn Marino
5239e4b17023SJohn Marino fndecl = builtin_decl_implicit (BUILT_IN_SYNC_FETCH_AND_NAND_N);
5240e4b17023SJohn Marino inform (loc, "%qD changed semantics in GCC 4.4", fndecl);
5241e4b17023SJohn Marino warned_f_a_n = true;
5242e4b17023SJohn Marino break;
5243e4b17023SJohn Marino
5244e4b17023SJohn Marino case BUILT_IN_SYNC_NAND_AND_FETCH_1:
5245e4b17023SJohn Marino case BUILT_IN_SYNC_NAND_AND_FETCH_2:
5246e4b17023SJohn Marino case BUILT_IN_SYNC_NAND_AND_FETCH_4:
5247e4b17023SJohn Marino case BUILT_IN_SYNC_NAND_AND_FETCH_8:
5248e4b17023SJohn Marino case BUILT_IN_SYNC_NAND_AND_FETCH_16:
5249e4b17023SJohn Marino if (warned_n_a_f)
5250e4b17023SJohn Marino break;
5251e4b17023SJohn Marino
5252e4b17023SJohn Marino fndecl = builtin_decl_implicit (BUILT_IN_SYNC_NAND_AND_FETCH_N);
5253e4b17023SJohn Marino inform (loc, "%qD changed semantics in GCC 4.4", fndecl);
5254e4b17023SJohn Marino warned_n_a_f = true;
5255e4b17023SJohn Marino break;
5256e4b17023SJohn Marino
5257e4b17023SJohn Marino default:
5258e4b17023SJohn Marino gcc_unreachable ();
5259e4b17023SJohn Marino }
5260e4b17023SJohn Marino }
5261e4b17023SJohn Marino
5262e4b17023SJohn Marino /* Expand the operands. */
5263e4b17023SJohn Marino mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5264e4b17023SJohn Marino val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
5265e4b17023SJohn Marino
5266e4b17023SJohn Marino return expand_atomic_fetch_op (target, mem, val, code, MEMMODEL_SEQ_CST,
5267e4b17023SJohn Marino after);
5268e4b17023SJohn Marino }
5269e4b17023SJohn Marino
5270e4b17023SJohn Marino /* Expand the __sync_val_compare_and_swap and __sync_bool_compare_and_swap
5271e4b17023SJohn Marino intrinsics. EXP is the CALL_EXPR. IS_BOOL is
5272e4b17023SJohn Marino true if this is the boolean form. TARGET is a place for us to store the
5273e4b17023SJohn Marino results; this is NOT optional if IS_BOOL is true. */
5274e4b17023SJohn Marino
5275e4b17023SJohn Marino static rtx
expand_builtin_compare_and_swap(enum machine_mode mode,tree exp,bool is_bool,rtx target)5276e4b17023SJohn Marino expand_builtin_compare_and_swap (enum machine_mode mode, tree exp,
5277e4b17023SJohn Marino bool is_bool, rtx target)
5278e4b17023SJohn Marino {
5279e4b17023SJohn Marino rtx old_val, new_val, mem;
5280e4b17023SJohn Marino rtx *pbool, *poval;
5281e4b17023SJohn Marino
5282e4b17023SJohn Marino /* Expand the operands. */
5283e4b17023SJohn Marino mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5284e4b17023SJohn Marino old_val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
5285e4b17023SJohn Marino new_val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 2), mode);
5286e4b17023SJohn Marino
5287e4b17023SJohn Marino pbool = poval = NULL;
5288e4b17023SJohn Marino if (target != const0_rtx)
5289e4b17023SJohn Marino {
5290e4b17023SJohn Marino if (is_bool)
5291e4b17023SJohn Marino pbool = ⌖
5292e4b17023SJohn Marino else
5293e4b17023SJohn Marino poval = ⌖
5294e4b17023SJohn Marino }
5295e4b17023SJohn Marino if (!expand_atomic_compare_and_swap (pbool, poval, mem, old_val, new_val,
5296e4b17023SJohn Marino false, MEMMODEL_SEQ_CST,
5297e4b17023SJohn Marino MEMMODEL_SEQ_CST))
5298e4b17023SJohn Marino return NULL_RTX;
5299e4b17023SJohn Marino
5300e4b17023SJohn Marino return target;
5301e4b17023SJohn Marino }
5302e4b17023SJohn Marino
5303e4b17023SJohn Marino /* Expand the __sync_lock_test_and_set intrinsic. Note that the most
5304e4b17023SJohn Marino general form is actually an atomic exchange, and some targets only
5305e4b17023SJohn Marino support a reduced form with the second argument being a constant 1.
5306e4b17023SJohn Marino EXP is the CALL_EXPR; TARGET is an optional place for us to store
5307e4b17023SJohn Marino the results. */
5308e4b17023SJohn Marino
5309e4b17023SJohn Marino static rtx
expand_builtin_sync_lock_test_and_set(enum machine_mode mode,tree exp,rtx target)5310e4b17023SJohn Marino expand_builtin_sync_lock_test_and_set (enum machine_mode mode, tree exp,
5311e4b17023SJohn Marino rtx target)
5312e4b17023SJohn Marino {
5313e4b17023SJohn Marino rtx val, mem;
5314e4b17023SJohn Marino
5315e4b17023SJohn Marino /* Expand the operands. */
5316e4b17023SJohn Marino mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5317e4b17023SJohn Marino val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
5318e4b17023SJohn Marino
5319e4b17023SJohn Marino return expand_sync_lock_test_and_set (target, mem, val);
5320e4b17023SJohn Marino }
5321e4b17023SJohn Marino
5322e4b17023SJohn Marino /* Expand the __sync_lock_release intrinsic. EXP is the CALL_EXPR. */
5323e4b17023SJohn Marino
5324e4b17023SJohn Marino static void
expand_builtin_sync_lock_release(enum machine_mode mode,tree exp)5325e4b17023SJohn Marino expand_builtin_sync_lock_release (enum machine_mode mode, tree exp)
5326e4b17023SJohn Marino {
5327e4b17023SJohn Marino rtx mem;
5328e4b17023SJohn Marino
5329e4b17023SJohn Marino /* Expand the operands. */
5330e4b17023SJohn Marino mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5331e4b17023SJohn Marino
5332e4b17023SJohn Marino expand_atomic_store (mem, const0_rtx, MEMMODEL_RELEASE, true);
5333e4b17023SJohn Marino }
5334e4b17023SJohn Marino
5335e4b17023SJohn Marino /* Given an integer representing an ``enum memmodel'', verify its
5336e4b17023SJohn Marino correctness and return the memory model enum. */
5337e4b17023SJohn Marino
5338e4b17023SJohn Marino static enum memmodel
get_memmodel(tree exp)5339e4b17023SJohn Marino get_memmodel (tree exp)
5340e4b17023SJohn Marino {
5341e4b17023SJohn Marino rtx op;
5342e4b17023SJohn Marino
5343e4b17023SJohn Marino /* If the parameter is not a constant, it's a run time value so we'll just
5344e4b17023SJohn Marino convert it to MEMMODEL_SEQ_CST to avoid annoying runtime checking. */
5345e4b17023SJohn Marino if (TREE_CODE (exp) != INTEGER_CST)
5346e4b17023SJohn Marino return MEMMODEL_SEQ_CST;
5347e4b17023SJohn Marino
5348e4b17023SJohn Marino op = expand_normal (exp);
5349e4b17023SJohn Marino if (INTVAL (op) < 0 || INTVAL (op) >= MEMMODEL_LAST)
5350e4b17023SJohn Marino {
5351e4b17023SJohn Marino warning (OPT_Winvalid_memory_model,
5352e4b17023SJohn Marino "invalid memory model argument to builtin");
5353e4b17023SJohn Marino return MEMMODEL_SEQ_CST;
5354e4b17023SJohn Marino }
5355e4b17023SJohn Marino return (enum memmodel) INTVAL (op);
5356e4b17023SJohn Marino }
5357e4b17023SJohn Marino
5358e4b17023SJohn Marino /* Expand the __atomic_exchange intrinsic:
5359e4b17023SJohn Marino TYPE __atomic_exchange (TYPE *object, TYPE desired, enum memmodel)
5360e4b17023SJohn Marino EXP is the CALL_EXPR.
5361e4b17023SJohn Marino TARGET is an optional place for us to store the results. */
5362e4b17023SJohn Marino
5363e4b17023SJohn Marino static rtx
expand_builtin_atomic_exchange(enum machine_mode mode,tree exp,rtx target)5364e4b17023SJohn Marino expand_builtin_atomic_exchange (enum machine_mode mode, tree exp, rtx target)
5365e4b17023SJohn Marino {
5366e4b17023SJohn Marino rtx val, mem;
5367e4b17023SJohn Marino enum memmodel model;
5368e4b17023SJohn Marino
5369e4b17023SJohn Marino model = get_memmodel (CALL_EXPR_ARG (exp, 2));
5370e4b17023SJohn Marino if (model == MEMMODEL_CONSUME)
5371e4b17023SJohn Marino {
5372e4b17023SJohn Marino error ("invalid memory model for %<__atomic_exchange%>");
5373e4b17023SJohn Marino return NULL_RTX;
5374e4b17023SJohn Marino }
5375e4b17023SJohn Marino
5376e4b17023SJohn Marino if (!flag_inline_atomics)
5377e4b17023SJohn Marino return NULL_RTX;
5378e4b17023SJohn Marino
5379e4b17023SJohn Marino /* Expand the operands. */
5380e4b17023SJohn Marino mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5381e4b17023SJohn Marino val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
5382e4b17023SJohn Marino
5383e4b17023SJohn Marino return expand_atomic_exchange (target, mem, val, model);
5384e4b17023SJohn Marino }
5385e4b17023SJohn Marino
5386e4b17023SJohn Marino /* Expand the __atomic_compare_exchange intrinsic:
5387e4b17023SJohn Marino bool __atomic_compare_exchange (TYPE *object, TYPE *expect,
5388e4b17023SJohn Marino TYPE desired, BOOL weak,
5389e4b17023SJohn Marino enum memmodel success,
5390e4b17023SJohn Marino enum memmodel failure)
5391e4b17023SJohn Marino EXP is the CALL_EXPR.
5392e4b17023SJohn Marino TARGET is an optional place for us to store the results. */
5393e4b17023SJohn Marino
5394e4b17023SJohn Marino static rtx
expand_builtin_atomic_compare_exchange(enum machine_mode mode,tree exp,rtx target)5395e4b17023SJohn Marino expand_builtin_atomic_compare_exchange (enum machine_mode mode, tree exp,
5396e4b17023SJohn Marino rtx target)
5397e4b17023SJohn Marino {
5398e4b17023SJohn Marino rtx expect, desired, mem, oldval;
5399e4b17023SJohn Marino enum memmodel success, failure;
5400e4b17023SJohn Marino tree weak;
5401e4b17023SJohn Marino bool is_weak;
5402e4b17023SJohn Marino
5403e4b17023SJohn Marino success = get_memmodel (CALL_EXPR_ARG (exp, 4));
5404e4b17023SJohn Marino failure = get_memmodel (CALL_EXPR_ARG (exp, 5));
5405e4b17023SJohn Marino
5406e4b17023SJohn Marino if (failure == MEMMODEL_RELEASE || failure == MEMMODEL_ACQ_REL)
5407e4b17023SJohn Marino {
5408e4b17023SJohn Marino error ("invalid failure memory model for %<__atomic_compare_exchange%>");
5409e4b17023SJohn Marino return NULL_RTX;
5410e4b17023SJohn Marino }
5411e4b17023SJohn Marino
5412e4b17023SJohn Marino if (failure > success)
5413e4b17023SJohn Marino {
5414e4b17023SJohn Marino error ("failure memory model cannot be stronger than success "
5415e4b17023SJohn Marino "memory model for %<__atomic_compare_exchange%>");
5416e4b17023SJohn Marino return NULL_RTX;
5417e4b17023SJohn Marino }
5418e4b17023SJohn Marino
5419e4b17023SJohn Marino if (!flag_inline_atomics)
5420e4b17023SJohn Marino return NULL_RTX;
5421e4b17023SJohn Marino
5422e4b17023SJohn Marino /* Expand the operands. */
5423e4b17023SJohn Marino mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5424e4b17023SJohn Marino
5425e4b17023SJohn Marino expect = expand_normal (CALL_EXPR_ARG (exp, 1));
5426e4b17023SJohn Marino expect = convert_memory_address (Pmode, expect);
5427e4b17023SJohn Marino desired = expand_expr_force_mode (CALL_EXPR_ARG (exp, 2), mode);
5428e4b17023SJohn Marino
5429e4b17023SJohn Marino weak = CALL_EXPR_ARG (exp, 3);
5430e4b17023SJohn Marino is_weak = false;
5431e4b17023SJohn Marino if (host_integerp (weak, 0) && tree_low_cst (weak, 0) != 0)
5432e4b17023SJohn Marino is_weak = true;
5433e4b17023SJohn Marino
5434e4b17023SJohn Marino oldval = copy_to_reg (gen_rtx_MEM (mode, expect));
5435e4b17023SJohn Marino
5436e4b17023SJohn Marino if (!expand_atomic_compare_and_swap ((target == const0_rtx ? NULL : &target),
5437e4b17023SJohn Marino &oldval, mem, oldval, desired,
5438e4b17023SJohn Marino is_weak, success, failure))
5439e4b17023SJohn Marino return NULL_RTX;
5440e4b17023SJohn Marino
5441e4b17023SJohn Marino emit_move_insn (gen_rtx_MEM (mode, expect), oldval);
5442e4b17023SJohn Marino return target;
5443e4b17023SJohn Marino }
5444e4b17023SJohn Marino
5445e4b17023SJohn Marino /* Expand the __atomic_load intrinsic:
5446e4b17023SJohn Marino TYPE __atomic_load (TYPE *object, enum memmodel)
5447e4b17023SJohn Marino EXP is the CALL_EXPR.
5448e4b17023SJohn Marino TARGET is an optional place for us to store the results. */
5449e4b17023SJohn Marino
5450e4b17023SJohn Marino static rtx
expand_builtin_atomic_load(enum machine_mode mode,tree exp,rtx target)5451e4b17023SJohn Marino expand_builtin_atomic_load (enum machine_mode mode, tree exp, rtx target)
5452e4b17023SJohn Marino {
5453e4b17023SJohn Marino rtx mem;
5454e4b17023SJohn Marino enum memmodel model;
5455e4b17023SJohn Marino
5456e4b17023SJohn Marino model = get_memmodel (CALL_EXPR_ARG (exp, 1));
5457e4b17023SJohn Marino if (model == MEMMODEL_RELEASE
5458e4b17023SJohn Marino || model == MEMMODEL_ACQ_REL)
5459e4b17023SJohn Marino {
5460e4b17023SJohn Marino error ("invalid memory model for %<__atomic_load%>");
5461e4b17023SJohn Marino return NULL_RTX;
5462e4b17023SJohn Marino }
5463e4b17023SJohn Marino
5464e4b17023SJohn Marino if (!flag_inline_atomics)
5465e4b17023SJohn Marino return NULL_RTX;
5466e4b17023SJohn Marino
5467e4b17023SJohn Marino /* Expand the operand. */
5468e4b17023SJohn Marino mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5469e4b17023SJohn Marino
5470e4b17023SJohn Marino return expand_atomic_load (target, mem, model);
5471e4b17023SJohn Marino }
5472e4b17023SJohn Marino
5473e4b17023SJohn Marino
5474e4b17023SJohn Marino /* Expand the __atomic_store intrinsic:
5475e4b17023SJohn Marino void __atomic_store (TYPE *object, TYPE desired, enum memmodel)
5476e4b17023SJohn Marino EXP is the CALL_EXPR.
5477e4b17023SJohn Marino TARGET is an optional place for us to store the results. */
5478e4b17023SJohn Marino
5479e4b17023SJohn Marino static rtx
expand_builtin_atomic_store(enum machine_mode mode,tree exp)5480e4b17023SJohn Marino expand_builtin_atomic_store (enum machine_mode mode, tree exp)
5481e4b17023SJohn Marino {
5482e4b17023SJohn Marino rtx mem, val;
5483e4b17023SJohn Marino enum memmodel model;
5484e4b17023SJohn Marino
5485e4b17023SJohn Marino model = get_memmodel (CALL_EXPR_ARG (exp, 2));
5486e4b17023SJohn Marino if (model != MEMMODEL_RELAXED
5487e4b17023SJohn Marino && model != MEMMODEL_SEQ_CST
5488e4b17023SJohn Marino && model != MEMMODEL_RELEASE)
5489e4b17023SJohn Marino {
5490e4b17023SJohn Marino error ("invalid memory model for %<__atomic_store%>");
5491e4b17023SJohn Marino return NULL_RTX;
5492e4b17023SJohn Marino }
5493e4b17023SJohn Marino
5494e4b17023SJohn Marino if (!flag_inline_atomics)
5495e4b17023SJohn Marino return NULL_RTX;
5496e4b17023SJohn Marino
5497e4b17023SJohn Marino /* Expand the operands. */
5498e4b17023SJohn Marino mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5499e4b17023SJohn Marino val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
5500e4b17023SJohn Marino
5501e4b17023SJohn Marino return expand_atomic_store (mem, val, model, false);
5502e4b17023SJohn Marino }
5503e4b17023SJohn Marino
5504e4b17023SJohn Marino /* Expand the __atomic_fetch_XXX intrinsic:
5505e4b17023SJohn Marino TYPE __atomic_fetch_XXX (TYPE *object, TYPE val, enum memmodel)
5506e4b17023SJohn Marino EXP is the CALL_EXPR.
5507e4b17023SJohn Marino TARGET is an optional place for us to store the results.
5508e4b17023SJohn Marino CODE is the operation, PLUS, MINUS, ADD, XOR, or IOR.
5509e4b17023SJohn Marino FETCH_AFTER is true if returning the result of the operation.
5510e4b17023SJohn Marino FETCH_AFTER is false if returning the value before the operation.
5511e4b17023SJohn Marino IGNORE is true if the result is not used.
5512e4b17023SJohn Marino EXT_CALL is the correct builtin for an external call if this cannot be
5513e4b17023SJohn Marino resolved to an instruction sequence. */
5514e4b17023SJohn Marino
5515e4b17023SJohn Marino static rtx
expand_builtin_atomic_fetch_op(enum machine_mode mode,tree exp,rtx target,enum rtx_code code,bool fetch_after,bool ignore,enum built_in_function ext_call)5516e4b17023SJohn Marino expand_builtin_atomic_fetch_op (enum machine_mode mode, tree exp, rtx target,
5517e4b17023SJohn Marino enum rtx_code code, bool fetch_after,
5518e4b17023SJohn Marino bool ignore, enum built_in_function ext_call)
5519e4b17023SJohn Marino {
5520e4b17023SJohn Marino rtx val, mem, ret;
5521e4b17023SJohn Marino enum memmodel model;
5522e4b17023SJohn Marino tree fndecl;
5523e4b17023SJohn Marino tree addr;
5524e4b17023SJohn Marino
5525e4b17023SJohn Marino model = get_memmodel (CALL_EXPR_ARG (exp, 2));
5526e4b17023SJohn Marino
5527e4b17023SJohn Marino /* Expand the operands. */
5528e4b17023SJohn Marino mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5529e4b17023SJohn Marino val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
5530e4b17023SJohn Marino
5531e4b17023SJohn Marino /* Only try generating instructions if inlining is turned on. */
5532e4b17023SJohn Marino if (flag_inline_atomics)
5533e4b17023SJohn Marino {
5534e4b17023SJohn Marino ret = expand_atomic_fetch_op (target, mem, val, code, model, fetch_after);
5535e4b17023SJohn Marino if (ret)
5536e4b17023SJohn Marino return ret;
5537e4b17023SJohn Marino }
5538e4b17023SJohn Marino
5539e4b17023SJohn Marino /* Return if a different routine isn't needed for the library call. */
5540e4b17023SJohn Marino if (ext_call == BUILT_IN_NONE)
5541e4b17023SJohn Marino return NULL_RTX;
5542e4b17023SJohn Marino
5543e4b17023SJohn Marino /* Change the call to the specified function. */
5544e4b17023SJohn Marino fndecl = get_callee_fndecl (exp);
5545e4b17023SJohn Marino addr = CALL_EXPR_FN (exp);
5546e4b17023SJohn Marino STRIP_NOPS (addr);
5547e4b17023SJohn Marino
5548e4b17023SJohn Marino gcc_assert (TREE_OPERAND (addr, 0) == fndecl);
5549e4b17023SJohn Marino TREE_OPERAND (addr, 0) = builtin_decl_explicit(ext_call);
5550e4b17023SJohn Marino
5551e4b17023SJohn Marino /* Expand the call here so we can emit trailing code. */
5552e4b17023SJohn Marino ret = expand_call (exp, target, ignore);
5553e4b17023SJohn Marino
5554e4b17023SJohn Marino /* Replace the original function just in case it matters. */
5555e4b17023SJohn Marino TREE_OPERAND (addr, 0) = fndecl;
5556e4b17023SJohn Marino
5557e4b17023SJohn Marino /* Then issue the arithmetic correction to return the right result. */
5558e4b17023SJohn Marino if (!ignore)
5559e4b17023SJohn Marino {
5560e4b17023SJohn Marino if (code == NOT)
5561e4b17023SJohn Marino {
5562e4b17023SJohn Marino ret = expand_simple_binop (mode, AND, ret, val, NULL_RTX, true,
5563e4b17023SJohn Marino OPTAB_LIB_WIDEN);
5564e4b17023SJohn Marino ret = expand_simple_unop (mode, NOT, ret, target, true);
5565e4b17023SJohn Marino }
5566e4b17023SJohn Marino else
5567e4b17023SJohn Marino ret = expand_simple_binop (mode, code, ret, val, target, true,
5568e4b17023SJohn Marino OPTAB_LIB_WIDEN);
5569e4b17023SJohn Marino }
5570e4b17023SJohn Marino return ret;
5571e4b17023SJohn Marino }
5572e4b17023SJohn Marino
5573e4b17023SJohn Marino
5574e4b17023SJohn Marino #ifndef HAVE_atomic_clear
5575e4b17023SJohn Marino # define HAVE_atomic_clear 0
5576e4b17023SJohn Marino # define gen_atomic_clear(x,y) (gcc_unreachable (), NULL_RTX)
5577e4b17023SJohn Marino #endif
5578e4b17023SJohn Marino
5579e4b17023SJohn Marino /* Expand an atomic clear operation.
5580e4b17023SJohn Marino void _atomic_clear (BOOL *obj, enum memmodel)
5581e4b17023SJohn Marino EXP is the call expression. */
5582e4b17023SJohn Marino
5583e4b17023SJohn Marino static rtx
expand_builtin_atomic_clear(tree exp)5584e4b17023SJohn Marino expand_builtin_atomic_clear (tree exp)
5585e4b17023SJohn Marino {
5586e4b17023SJohn Marino enum machine_mode mode;
5587e4b17023SJohn Marino rtx mem, ret;
5588e4b17023SJohn Marino enum memmodel model;
5589e4b17023SJohn Marino
5590e4b17023SJohn Marino mode = mode_for_size (BOOL_TYPE_SIZE, MODE_INT, 0);
5591e4b17023SJohn Marino mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5592e4b17023SJohn Marino model = get_memmodel (CALL_EXPR_ARG (exp, 1));
5593e4b17023SJohn Marino
5594e4b17023SJohn Marino if (model == MEMMODEL_ACQUIRE || model == MEMMODEL_ACQ_REL)
5595e4b17023SJohn Marino {
5596e4b17023SJohn Marino error ("invalid memory model for %<__atomic_store%>");
5597e4b17023SJohn Marino return const0_rtx;
5598e4b17023SJohn Marino }
5599e4b17023SJohn Marino
5600e4b17023SJohn Marino if (HAVE_atomic_clear)
5601e4b17023SJohn Marino {
5602e4b17023SJohn Marino emit_insn (gen_atomic_clear (mem, model));
5603e4b17023SJohn Marino return const0_rtx;
5604e4b17023SJohn Marino }
5605e4b17023SJohn Marino
5606e4b17023SJohn Marino /* Try issuing an __atomic_store, and allow fallback to __sync_lock_release.
5607e4b17023SJohn Marino Failing that, a store is issued by __atomic_store. The only way this can
5608e4b17023SJohn Marino fail is if the bool type is larger than a word size. Unlikely, but
5609e4b17023SJohn Marino handle it anyway for completeness. Assume a single threaded model since
5610e4b17023SJohn Marino there is no atomic support in this case, and no barriers are required. */
5611e4b17023SJohn Marino ret = expand_atomic_store (mem, const0_rtx, model, true);
5612e4b17023SJohn Marino if (!ret)
5613e4b17023SJohn Marino emit_move_insn (mem, const0_rtx);
5614e4b17023SJohn Marino return const0_rtx;
5615e4b17023SJohn Marino }
5616e4b17023SJohn Marino
5617e4b17023SJohn Marino /* Expand an atomic test_and_set operation.
5618e4b17023SJohn Marino bool _atomic_test_and_set (BOOL *obj, enum memmodel)
5619e4b17023SJohn Marino EXP is the call expression. */
5620e4b17023SJohn Marino
5621e4b17023SJohn Marino static rtx
expand_builtin_atomic_test_and_set(tree exp,rtx target)5622e4b17023SJohn Marino expand_builtin_atomic_test_and_set (tree exp, rtx target)
5623e4b17023SJohn Marino {
5624e4b17023SJohn Marino rtx mem;
5625e4b17023SJohn Marino enum memmodel model;
5626e4b17023SJohn Marino enum machine_mode mode;
5627e4b17023SJohn Marino
5628e4b17023SJohn Marino mode = mode_for_size (BOOL_TYPE_SIZE, MODE_INT, 0);
5629e4b17023SJohn Marino mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5630e4b17023SJohn Marino model = get_memmodel (CALL_EXPR_ARG (exp, 1));
5631e4b17023SJohn Marino
5632e4b17023SJohn Marino return expand_atomic_test_and_set (target, mem, model);
5633e4b17023SJohn Marino }
5634e4b17023SJohn Marino
5635e4b17023SJohn Marino
5636e4b17023SJohn Marino /* Return true if (optional) argument ARG1 of size ARG0 is always lock free on
5637e4b17023SJohn Marino this architecture. If ARG1 is NULL, use typical alignment for size ARG0. */
5638e4b17023SJohn Marino
5639e4b17023SJohn Marino static tree
fold_builtin_atomic_always_lock_free(tree arg0,tree arg1)5640e4b17023SJohn Marino fold_builtin_atomic_always_lock_free (tree arg0, tree arg1)
5641e4b17023SJohn Marino {
5642e4b17023SJohn Marino int size;
5643e4b17023SJohn Marino enum machine_mode mode;
5644e4b17023SJohn Marino unsigned int mode_align, type_align;
5645e4b17023SJohn Marino
5646e4b17023SJohn Marino if (TREE_CODE (arg0) != INTEGER_CST)
5647e4b17023SJohn Marino return NULL_TREE;
5648e4b17023SJohn Marino
5649e4b17023SJohn Marino size = INTVAL (expand_normal (arg0)) * BITS_PER_UNIT;
5650e4b17023SJohn Marino mode = mode_for_size (size, MODE_INT, 0);
5651e4b17023SJohn Marino mode_align = GET_MODE_ALIGNMENT (mode);
5652e4b17023SJohn Marino
5653e4b17023SJohn Marino if (TREE_CODE (arg1) == INTEGER_CST && INTVAL (expand_normal (arg1)) == 0)
5654e4b17023SJohn Marino type_align = mode_align;
5655e4b17023SJohn Marino else
5656e4b17023SJohn Marino {
5657e4b17023SJohn Marino tree ttype = TREE_TYPE (arg1);
5658e4b17023SJohn Marino
5659e4b17023SJohn Marino /* This function is usually invoked and folded immediately by the front
5660e4b17023SJohn Marino end before anything else has a chance to look at it. The pointer
5661e4b17023SJohn Marino parameter at this point is usually cast to a void *, so check for that
5662e4b17023SJohn Marino and look past the cast. */
5663e4b17023SJohn Marino if (TREE_CODE (arg1) == NOP_EXPR && POINTER_TYPE_P (ttype)
5664e4b17023SJohn Marino && VOID_TYPE_P (TREE_TYPE (ttype)))
5665e4b17023SJohn Marino arg1 = TREE_OPERAND (arg1, 0);
5666e4b17023SJohn Marino
5667e4b17023SJohn Marino ttype = TREE_TYPE (arg1);
5668e4b17023SJohn Marino gcc_assert (POINTER_TYPE_P (ttype));
5669e4b17023SJohn Marino
5670e4b17023SJohn Marino /* Get the underlying type of the object. */
5671e4b17023SJohn Marino ttype = TREE_TYPE (ttype);
5672e4b17023SJohn Marino type_align = TYPE_ALIGN (ttype);
5673e4b17023SJohn Marino }
5674e4b17023SJohn Marino
5675e4b17023SJohn Marino /* If the object has smaller alignment, the the lock free routines cannot
5676e4b17023SJohn Marino be used. */
5677e4b17023SJohn Marino if (type_align < mode_align)
5678e4b17023SJohn Marino return boolean_false_node;
5679e4b17023SJohn Marino
5680e4b17023SJohn Marino /* Check if a compare_and_swap pattern exists for the mode which represents
5681e4b17023SJohn Marino the required size. The pattern is not allowed to fail, so the existence
5682e4b17023SJohn Marino of the pattern indicates support is present. */
5683e4b17023SJohn Marino if (can_compare_and_swap_p (mode, true))
5684e4b17023SJohn Marino return boolean_true_node;
5685e4b17023SJohn Marino else
5686e4b17023SJohn Marino return boolean_false_node;
5687e4b17023SJohn Marino }
5688e4b17023SJohn Marino
5689e4b17023SJohn Marino /* Return true if the parameters to call EXP represent an object which will
5690e4b17023SJohn Marino always generate lock free instructions. The first argument represents the
5691e4b17023SJohn Marino size of the object, and the second parameter is a pointer to the object
5692e4b17023SJohn Marino itself. If NULL is passed for the object, then the result is based on
5693e4b17023SJohn Marino typical alignment for an object of the specified size. Otherwise return
5694e4b17023SJohn Marino false. */
5695e4b17023SJohn Marino
5696e4b17023SJohn Marino static rtx
expand_builtin_atomic_always_lock_free(tree exp)5697e4b17023SJohn Marino expand_builtin_atomic_always_lock_free (tree exp)
5698e4b17023SJohn Marino {
5699e4b17023SJohn Marino tree size;
5700e4b17023SJohn Marino tree arg0 = CALL_EXPR_ARG (exp, 0);
5701e4b17023SJohn Marino tree arg1 = CALL_EXPR_ARG (exp, 1);
5702e4b17023SJohn Marino
5703e4b17023SJohn Marino if (TREE_CODE (arg0) != INTEGER_CST)
5704e4b17023SJohn Marino {
5705e4b17023SJohn Marino error ("non-constant argument 1 to __atomic_always_lock_free");
5706e4b17023SJohn Marino return const0_rtx;
5707e4b17023SJohn Marino }
5708e4b17023SJohn Marino
5709e4b17023SJohn Marino size = fold_builtin_atomic_always_lock_free (arg0, arg1);
5710e4b17023SJohn Marino if (size == boolean_true_node)
5711e4b17023SJohn Marino return const1_rtx;
5712e4b17023SJohn Marino return const0_rtx;
5713e4b17023SJohn Marino }
5714e4b17023SJohn Marino
5715e4b17023SJohn Marino /* Return a one or zero if it can be determined that object ARG1 of size ARG
5716e4b17023SJohn Marino is lock free on this architecture. */
5717e4b17023SJohn Marino
5718e4b17023SJohn Marino static tree
fold_builtin_atomic_is_lock_free(tree arg0,tree arg1)5719e4b17023SJohn Marino fold_builtin_atomic_is_lock_free (tree arg0, tree arg1)
5720e4b17023SJohn Marino {
5721e4b17023SJohn Marino if (!flag_inline_atomics)
5722e4b17023SJohn Marino return NULL_TREE;
5723e4b17023SJohn Marino
5724e4b17023SJohn Marino /* If it isn't always lock free, don't generate a result. */
5725e4b17023SJohn Marino if (fold_builtin_atomic_always_lock_free (arg0, arg1) == boolean_true_node)
5726e4b17023SJohn Marino return boolean_true_node;
5727e4b17023SJohn Marino
5728e4b17023SJohn Marino return NULL_TREE;
5729e4b17023SJohn Marino }
5730e4b17023SJohn Marino
5731e4b17023SJohn Marino /* Return true if the parameters to call EXP represent an object which will
5732e4b17023SJohn Marino always generate lock free instructions. The first argument represents the
5733e4b17023SJohn Marino size of the object, and the second parameter is a pointer to the object
5734e4b17023SJohn Marino itself. If NULL is passed for the object, then the result is based on
5735e4b17023SJohn Marino typical alignment for an object of the specified size. Otherwise return
5736e4b17023SJohn Marino NULL*/
5737e4b17023SJohn Marino
5738e4b17023SJohn Marino static rtx
expand_builtin_atomic_is_lock_free(tree exp)5739e4b17023SJohn Marino expand_builtin_atomic_is_lock_free (tree exp)
5740e4b17023SJohn Marino {
5741e4b17023SJohn Marino tree size;
5742e4b17023SJohn Marino tree arg0 = CALL_EXPR_ARG (exp, 0);
5743e4b17023SJohn Marino tree arg1 = CALL_EXPR_ARG (exp, 1);
5744e4b17023SJohn Marino
5745e4b17023SJohn Marino if (!INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
5746e4b17023SJohn Marino {
5747e4b17023SJohn Marino error ("non-integer argument 1 to __atomic_is_lock_free");
5748e4b17023SJohn Marino return NULL_RTX;
5749e4b17023SJohn Marino }
5750e4b17023SJohn Marino
5751e4b17023SJohn Marino if (!flag_inline_atomics)
5752e4b17023SJohn Marino return NULL_RTX;
5753e4b17023SJohn Marino
5754e4b17023SJohn Marino /* If the value is known at compile time, return the RTX for it. */
5755e4b17023SJohn Marino size = fold_builtin_atomic_is_lock_free (arg0, arg1);
5756e4b17023SJohn Marino if (size == boolean_true_node)
5757e4b17023SJohn Marino return const1_rtx;
5758e4b17023SJohn Marino
5759e4b17023SJohn Marino return NULL_RTX;
5760e4b17023SJohn Marino }
5761e4b17023SJohn Marino
5762e4b17023SJohn Marino /* Expand the __atomic_thread_fence intrinsic:
5763e4b17023SJohn Marino void __atomic_thread_fence (enum memmodel)
5764e4b17023SJohn Marino EXP is the CALL_EXPR. */
5765e4b17023SJohn Marino
5766e4b17023SJohn Marino static void
expand_builtin_atomic_thread_fence(tree exp)5767e4b17023SJohn Marino expand_builtin_atomic_thread_fence (tree exp)
5768e4b17023SJohn Marino {
5769e4b17023SJohn Marino enum memmodel model = get_memmodel (CALL_EXPR_ARG (exp, 0));
5770e4b17023SJohn Marino expand_mem_thread_fence (model);
5771e4b17023SJohn Marino }
5772e4b17023SJohn Marino
5773e4b17023SJohn Marino /* Expand the __atomic_signal_fence intrinsic:
5774e4b17023SJohn Marino void __atomic_signal_fence (enum memmodel)
5775e4b17023SJohn Marino EXP is the CALL_EXPR. */
5776e4b17023SJohn Marino
5777e4b17023SJohn Marino static void
expand_builtin_atomic_signal_fence(tree exp)5778e4b17023SJohn Marino expand_builtin_atomic_signal_fence (tree exp)
5779e4b17023SJohn Marino {
5780e4b17023SJohn Marino enum memmodel model = get_memmodel (CALL_EXPR_ARG (exp, 0));
5781e4b17023SJohn Marino expand_mem_signal_fence (model);
5782e4b17023SJohn Marino }
5783e4b17023SJohn Marino
5784e4b17023SJohn Marino /* Expand the __sync_synchronize intrinsic. */
5785e4b17023SJohn Marino
5786e4b17023SJohn Marino static void
expand_builtin_sync_synchronize(void)5787e4b17023SJohn Marino expand_builtin_sync_synchronize (void)
5788e4b17023SJohn Marino {
5789e4b17023SJohn Marino expand_mem_thread_fence (MEMMODEL_SEQ_CST);
5790e4b17023SJohn Marino }
5791e4b17023SJohn Marino
5792e4b17023SJohn Marino
5793e4b17023SJohn Marino /* Expand an expression EXP that calls a built-in function,
5794e4b17023SJohn Marino with result going to TARGET if that's convenient
5795e4b17023SJohn Marino (and in mode MODE if that's convenient).
5796e4b17023SJohn Marino SUBTARGET may be used as the target for computing one of EXP's operands.
5797e4b17023SJohn Marino IGNORE is nonzero if the value is to be ignored. */
5798e4b17023SJohn Marino
5799e4b17023SJohn Marino rtx
expand_builtin(tree exp,rtx target,rtx subtarget,enum machine_mode mode,int ignore)5800e4b17023SJohn Marino expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
5801e4b17023SJohn Marino int ignore)
5802e4b17023SJohn Marino {
5803e4b17023SJohn Marino tree fndecl = get_callee_fndecl (exp);
5804e4b17023SJohn Marino enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
5805e4b17023SJohn Marino enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
5806e4b17023SJohn Marino int flags;
5807e4b17023SJohn Marino
5808e4b17023SJohn Marino if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
5809e4b17023SJohn Marino return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
5810e4b17023SJohn Marino
5811e4b17023SJohn Marino /* When not optimizing, generate calls to library functions for a certain
5812e4b17023SJohn Marino set of builtins. */
5813e4b17023SJohn Marino if (!optimize
5814e4b17023SJohn Marino && !called_as_built_in (fndecl)
5815e4b17023SJohn Marino && fcode != BUILT_IN_ALLOCA
5816e4b17023SJohn Marino && fcode != BUILT_IN_ALLOCA_WITH_ALIGN
5817e4b17023SJohn Marino && fcode != BUILT_IN_FREE)
5818e4b17023SJohn Marino return expand_call (exp, target, ignore);
5819e4b17023SJohn Marino
5820e4b17023SJohn Marino /* The built-in function expanders test for target == const0_rtx
5821e4b17023SJohn Marino to determine whether the function's result will be ignored. */
5822e4b17023SJohn Marino if (ignore)
5823e4b17023SJohn Marino target = const0_rtx;
5824e4b17023SJohn Marino
5825e4b17023SJohn Marino /* If the result of a pure or const built-in function is ignored, and
5826e4b17023SJohn Marino none of its arguments are volatile, we can avoid expanding the
5827e4b17023SJohn Marino built-in call and just evaluate the arguments for side-effects. */
5828e4b17023SJohn Marino if (target == const0_rtx
5829e4b17023SJohn Marino && ((flags = flags_from_decl_or_type (fndecl)) & (ECF_CONST | ECF_PURE))
5830e4b17023SJohn Marino && !(flags & ECF_LOOPING_CONST_OR_PURE))
5831e4b17023SJohn Marino {
5832e4b17023SJohn Marino bool volatilep = false;
5833e4b17023SJohn Marino tree arg;
5834e4b17023SJohn Marino call_expr_arg_iterator iter;
5835e4b17023SJohn Marino
5836e4b17023SJohn Marino FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
5837e4b17023SJohn Marino if (TREE_THIS_VOLATILE (arg))
5838e4b17023SJohn Marino {
5839e4b17023SJohn Marino volatilep = true;
5840e4b17023SJohn Marino break;
5841e4b17023SJohn Marino }
5842e4b17023SJohn Marino
5843e4b17023SJohn Marino if (! volatilep)
5844e4b17023SJohn Marino {
5845e4b17023SJohn Marino FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
5846e4b17023SJohn Marino expand_expr (arg, const0_rtx, VOIDmode, EXPAND_NORMAL);
5847e4b17023SJohn Marino return const0_rtx;
5848e4b17023SJohn Marino }
5849e4b17023SJohn Marino }
5850e4b17023SJohn Marino
5851e4b17023SJohn Marino switch (fcode)
5852e4b17023SJohn Marino {
5853e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FABS):
5854e4b17023SJohn Marino target = expand_builtin_fabs (exp, target, subtarget);
5855e4b17023SJohn Marino if (target)
5856e4b17023SJohn Marino return target;
5857e4b17023SJohn Marino break;
5858e4b17023SJohn Marino
5859e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_COPYSIGN):
5860e4b17023SJohn Marino target = expand_builtin_copysign (exp, target, subtarget);
5861e4b17023SJohn Marino if (target)
5862e4b17023SJohn Marino return target;
5863e4b17023SJohn Marino break;
5864e4b17023SJohn Marino
5865e4b17023SJohn Marino /* Just do a normal library call if we were unable to fold
5866e4b17023SJohn Marino the values. */
5867e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CABS):
5868e4b17023SJohn Marino break;
5869e4b17023SJohn Marino
5870e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXP):
5871e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXP10):
5872e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_POW10):
5873e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXP2):
5874e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXPM1):
5875e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOGB):
5876e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOG):
5877e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOG10):
5878e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOG2):
5879e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOG1P):
5880e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_TAN):
5881e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ASIN):
5882e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ACOS):
5883e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ATAN):
5884e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SIGNIFICAND):
5885e4b17023SJohn Marino /* Treat these like sqrt only if unsafe math optimizations are allowed,
5886e4b17023SJohn Marino because of possible accuracy problems. */
5887e4b17023SJohn Marino if (! flag_unsafe_math_optimizations)
5888e4b17023SJohn Marino break;
5889e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SQRT):
5890e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FLOOR):
5891e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CEIL):
5892e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_TRUNC):
5893e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ROUND):
5894e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_NEARBYINT):
5895e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_RINT):
5896e4b17023SJohn Marino target = expand_builtin_mathfn (exp, target, subtarget);
5897e4b17023SJohn Marino if (target)
5898e4b17023SJohn Marino return target;
5899e4b17023SJohn Marino break;
5900e4b17023SJohn Marino
5901e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FMA):
5902e4b17023SJohn Marino target = expand_builtin_mathfn_ternary (exp, target, subtarget);
5903e4b17023SJohn Marino if (target)
5904e4b17023SJohn Marino return target;
5905e4b17023SJohn Marino break;
5906e4b17023SJohn Marino
5907e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ILOGB):
5908e4b17023SJohn Marino if (! flag_unsafe_math_optimizations)
5909e4b17023SJohn Marino break;
5910e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ISINF):
5911e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FINITE):
5912e4b17023SJohn Marino case BUILT_IN_ISFINITE:
5913e4b17023SJohn Marino case BUILT_IN_ISNORMAL:
5914e4b17023SJohn Marino target = expand_builtin_interclass_mathfn (exp, target);
5915e4b17023SJohn Marino if (target)
5916e4b17023SJohn Marino return target;
5917e4b17023SJohn Marino break;
5918e4b17023SJohn Marino
5919e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ICEIL):
5920e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LCEIL):
5921e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLCEIL):
5922e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LFLOOR):
5923e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IFLOOR):
5924e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLFLOOR):
5925e4b17023SJohn Marino target = expand_builtin_int_roundingfn (exp, target);
5926e4b17023SJohn Marino if (target)
5927e4b17023SJohn Marino return target;
5928e4b17023SJohn Marino break;
5929e4b17023SJohn Marino
5930e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IRINT):
5931e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LRINT):
5932e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLRINT):
5933e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IROUND):
5934e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LROUND):
5935e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLROUND):
5936e4b17023SJohn Marino target = expand_builtin_int_roundingfn_2 (exp, target);
5937e4b17023SJohn Marino if (target)
5938e4b17023SJohn Marino return target;
5939e4b17023SJohn Marino break;
5940e4b17023SJohn Marino
5941e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_POWI):
5942e4b17023SJohn Marino target = expand_builtin_powi (exp, target);
5943e4b17023SJohn Marino if (target)
5944e4b17023SJohn Marino return target;
5945e4b17023SJohn Marino break;
5946e4b17023SJohn Marino
5947e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ATAN2):
5948e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LDEXP):
5949e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SCALB):
5950e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SCALBN):
5951e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SCALBLN):
5952e4b17023SJohn Marino if (! flag_unsafe_math_optimizations)
5953e4b17023SJohn Marino break;
5954e4b17023SJohn Marino
5955e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FMOD):
5956e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_REMAINDER):
5957e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_DREM):
5958e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_POW):
5959e4b17023SJohn Marino target = expand_builtin_mathfn_2 (exp, target, subtarget);
5960e4b17023SJohn Marino if (target)
5961e4b17023SJohn Marino return target;
5962e4b17023SJohn Marino break;
5963e4b17023SJohn Marino
5964e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CEXPI):
5965e4b17023SJohn Marino target = expand_builtin_cexpi (exp, target);
5966e4b17023SJohn Marino gcc_assert (target);
5967e4b17023SJohn Marino return target;
5968e4b17023SJohn Marino
5969e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SIN):
5970e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_COS):
5971e4b17023SJohn Marino if (! flag_unsafe_math_optimizations)
5972e4b17023SJohn Marino break;
5973e4b17023SJohn Marino target = expand_builtin_mathfn_3 (exp, target, subtarget);
5974e4b17023SJohn Marino if (target)
5975e4b17023SJohn Marino return target;
5976e4b17023SJohn Marino break;
5977e4b17023SJohn Marino
5978e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SINCOS):
5979e4b17023SJohn Marino if (! flag_unsafe_math_optimizations)
5980e4b17023SJohn Marino break;
5981e4b17023SJohn Marino target = expand_builtin_sincos (exp);
5982e4b17023SJohn Marino if (target)
5983e4b17023SJohn Marino return target;
5984e4b17023SJohn Marino break;
5985e4b17023SJohn Marino
5986e4b17023SJohn Marino case BUILT_IN_APPLY_ARGS:
5987e4b17023SJohn Marino return expand_builtin_apply_args ();
5988e4b17023SJohn Marino
5989e4b17023SJohn Marino /* __builtin_apply (FUNCTION, ARGUMENTS, ARGSIZE) invokes
5990e4b17023SJohn Marino FUNCTION with a copy of the parameters described by
5991e4b17023SJohn Marino ARGUMENTS, and ARGSIZE. It returns a block of memory
5992e4b17023SJohn Marino allocated on the stack into which is stored all the registers
5993e4b17023SJohn Marino that might possibly be used for returning the result of a
5994e4b17023SJohn Marino function. ARGUMENTS is the value returned by
5995e4b17023SJohn Marino __builtin_apply_args. ARGSIZE is the number of bytes of
5996e4b17023SJohn Marino arguments that must be copied. ??? How should this value be
5997e4b17023SJohn Marino computed? We'll also need a safe worst case value for varargs
5998e4b17023SJohn Marino functions. */
5999e4b17023SJohn Marino case BUILT_IN_APPLY:
6000e4b17023SJohn Marino if (!validate_arglist (exp, POINTER_TYPE,
6001e4b17023SJohn Marino POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
6002e4b17023SJohn Marino && !validate_arglist (exp, REFERENCE_TYPE,
6003e4b17023SJohn Marino POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
6004e4b17023SJohn Marino return const0_rtx;
6005e4b17023SJohn Marino else
6006e4b17023SJohn Marino {
6007e4b17023SJohn Marino rtx ops[3];
6008e4b17023SJohn Marino
6009e4b17023SJohn Marino ops[0] = expand_normal (CALL_EXPR_ARG (exp, 0));
6010e4b17023SJohn Marino ops[1] = expand_normal (CALL_EXPR_ARG (exp, 1));
6011e4b17023SJohn Marino ops[2] = expand_normal (CALL_EXPR_ARG (exp, 2));
6012e4b17023SJohn Marino
6013e4b17023SJohn Marino return expand_builtin_apply (ops[0], ops[1], ops[2]);
6014e4b17023SJohn Marino }
6015e4b17023SJohn Marino
6016e4b17023SJohn Marino /* __builtin_return (RESULT) causes the function to return the
6017e4b17023SJohn Marino value described by RESULT. RESULT is address of the block of
6018e4b17023SJohn Marino memory returned by __builtin_apply. */
6019e4b17023SJohn Marino case BUILT_IN_RETURN:
6020e4b17023SJohn Marino if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
6021e4b17023SJohn Marino expand_builtin_return (expand_normal (CALL_EXPR_ARG (exp, 0)));
6022e4b17023SJohn Marino return const0_rtx;
6023e4b17023SJohn Marino
6024e4b17023SJohn Marino case BUILT_IN_SAVEREGS:
6025e4b17023SJohn Marino return expand_builtin_saveregs ();
6026e4b17023SJohn Marino
6027e4b17023SJohn Marino case BUILT_IN_VA_ARG_PACK:
6028e4b17023SJohn Marino /* All valid uses of __builtin_va_arg_pack () are removed during
6029e4b17023SJohn Marino inlining. */
6030e4b17023SJohn Marino error ("%Kinvalid use of %<__builtin_va_arg_pack ()%>", exp);
6031e4b17023SJohn Marino return const0_rtx;
6032e4b17023SJohn Marino
6033e4b17023SJohn Marino case BUILT_IN_VA_ARG_PACK_LEN:
6034e4b17023SJohn Marino /* All valid uses of __builtin_va_arg_pack_len () are removed during
6035e4b17023SJohn Marino inlining. */
6036e4b17023SJohn Marino error ("%Kinvalid use of %<__builtin_va_arg_pack_len ()%>", exp);
6037e4b17023SJohn Marino return const0_rtx;
6038e4b17023SJohn Marino
6039e4b17023SJohn Marino /* Return the address of the first anonymous stack arg. */
6040e4b17023SJohn Marino case BUILT_IN_NEXT_ARG:
6041e4b17023SJohn Marino if (fold_builtin_next_arg (exp, false))
6042e4b17023SJohn Marino return const0_rtx;
6043e4b17023SJohn Marino return expand_builtin_next_arg ();
6044e4b17023SJohn Marino
6045e4b17023SJohn Marino case BUILT_IN_CLEAR_CACHE:
6046e4b17023SJohn Marino target = expand_builtin___clear_cache (exp);
6047e4b17023SJohn Marino if (target)
6048e4b17023SJohn Marino return target;
6049e4b17023SJohn Marino break;
6050e4b17023SJohn Marino
6051e4b17023SJohn Marino case BUILT_IN_CLASSIFY_TYPE:
6052e4b17023SJohn Marino return expand_builtin_classify_type (exp);
6053e4b17023SJohn Marino
6054e4b17023SJohn Marino case BUILT_IN_CONSTANT_P:
6055e4b17023SJohn Marino return const0_rtx;
6056e4b17023SJohn Marino
6057e4b17023SJohn Marino case BUILT_IN_FRAME_ADDRESS:
6058e4b17023SJohn Marino case BUILT_IN_RETURN_ADDRESS:
6059e4b17023SJohn Marino return expand_builtin_frame_address (fndecl, exp);
6060e4b17023SJohn Marino
6061e4b17023SJohn Marino /* Returns the address of the area where the structure is returned.
6062e4b17023SJohn Marino 0 otherwise. */
6063e4b17023SJohn Marino case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
6064e4b17023SJohn Marino if (call_expr_nargs (exp) != 0
6065e4b17023SJohn Marino || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
6066e4b17023SJohn Marino || !MEM_P (DECL_RTL (DECL_RESULT (current_function_decl))))
6067e4b17023SJohn Marino return const0_rtx;
6068e4b17023SJohn Marino else
6069e4b17023SJohn Marino return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
6070e4b17023SJohn Marino
6071e4b17023SJohn Marino case BUILT_IN_ALLOCA:
6072e4b17023SJohn Marino case BUILT_IN_ALLOCA_WITH_ALIGN:
6073e4b17023SJohn Marino /* If the allocation stems from the declaration of a variable-sized
6074e4b17023SJohn Marino object, it cannot accumulate. */
6075e4b17023SJohn Marino target = expand_builtin_alloca (exp, CALL_ALLOCA_FOR_VAR_P (exp));
6076e4b17023SJohn Marino if (target)
6077e4b17023SJohn Marino return target;
6078e4b17023SJohn Marino break;
6079e4b17023SJohn Marino
6080e4b17023SJohn Marino case BUILT_IN_STACK_SAVE:
6081e4b17023SJohn Marino return expand_stack_save ();
6082e4b17023SJohn Marino
6083e4b17023SJohn Marino case BUILT_IN_STACK_RESTORE:
6084e4b17023SJohn Marino expand_stack_restore (CALL_EXPR_ARG (exp, 0));
6085e4b17023SJohn Marino return const0_rtx;
6086e4b17023SJohn Marino
6087e4b17023SJohn Marino case BUILT_IN_BSWAP32:
6088e4b17023SJohn Marino case BUILT_IN_BSWAP64:
6089e4b17023SJohn Marino target = expand_builtin_bswap (exp, target, subtarget);
6090e4b17023SJohn Marino
6091e4b17023SJohn Marino if (target)
6092e4b17023SJohn Marino return target;
6093e4b17023SJohn Marino break;
6094e4b17023SJohn Marino
6095e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_FFS):
6096e4b17023SJohn Marino case BUILT_IN_FFSIMAX:
6097e4b17023SJohn Marino target = expand_builtin_unop (target_mode, exp, target,
6098e4b17023SJohn Marino subtarget, ffs_optab);
6099e4b17023SJohn Marino if (target)
6100e4b17023SJohn Marino return target;
6101e4b17023SJohn Marino break;
6102e4b17023SJohn Marino
6103e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_CLZ):
6104e4b17023SJohn Marino case BUILT_IN_CLZIMAX:
6105e4b17023SJohn Marino target = expand_builtin_unop (target_mode, exp, target,
6106e4b17023SJohn Marino subtarget, clz_optab);
6107e4b17023SJohn Marino if (target)
6108e4b17023SJohn Marino return target;
6109e4b17023SJohn Marino break;
6110e4b17023SJohn Marino
6111e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_CTZ):
6112e4b17023SJohn Marino case BUILT_IN_CTZIMAX:
6113e4b17023SJohn Marino target = expand_builtin_unop (target_mode, exp, target,
6114e4b17023SJohn Marino subtarget, ctz_optab);
6115e4b17023SJohn Marino if (target)
6116e4b17023SJohn Marino return target;
6117e4b17023SJohn Marino break;
6118e4b17023SJohn Marino
6119e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_CLRSB):
6120e4b17023SJohn Marino case BUILT_IN_CLRSBIMAX:
6121e4b17023SJohn Marino target = expand_builtin_unop (target_mode, exp, target,
6122e4b17023SJohn Marino subtarget, clrsb_optab);
6123e4b17023SJohn Marino if (target)
6124e4b17023SJohn Marino return target;
6125e4b17023SJohn Marino break;
6126e4b17023SJohn Marino
6127e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_POPCOUNT):
6128e4b17023SJohn Marino case BUILT_IN_POPCOUNTIMAX:
6129e4b17023SJohn Marino target = expand_builtin_unop (target_mode, exp, target,
6130e4b17023SJohn Marino subtarget, popcount_optab);
6131e4b17023SJohn Marino if (target)
6132e4b17023SJohn Marino return target;
6133e4b17023SJohn Marino break;
6134e4b17023SJohn Marino
6135e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_PARITY):
6136e4b17023SJohn Marino case BUILT_IN_PARITYIMAX:
6137e4b17023SJohn Marino target = expand_builtin_unop (target_mode, exp, target,
6138e4b17023SJohn Marino subtarget, parity_optab);
6139e4b17023SJohn Marino if (target)
6140e4b17023SJohn Marino return target;
6141e4b17023SJohn Marino break;
6142e4b17023SJohn Marino
6143e4b17023SJohn Marino case BUILT_IN_STRLEN:
6144e4b17023SJohn Marino target = expand_builtin_strlen (exp, target, target_mode);
6145e4b17023SJohn Marino if (target)
6146e4b17023SJohn Marino return target;
6147e4b17023SJohn Marino break;
6148e4b17023SJohn Marino
6149e4b17023SJohn Marino case BUILT_IN_STRCPY:
6150e4b17023SJohn Marino target = expand_builtin_strcpy (exp, target);
6151e4b17023SJohn Marino if (target)
6152e4b17023SJohn Marino return target;
6153e4b17023SJohn Marino break;
6154e4b17023SJohn Marino
6155e4b17023SJohn Marino case BUILT_IN_STRNCPY:
6156e4b17023SJohn Marino target = expand_builtin_strncpy (exp, target);
6157e4b17023SJohn Marino if (target)
6158e4b17023SJohn Marino return target;
6159e4b17023SJohn Marino break;
6160e4b17023SJohn Marino
6161e4b17023SJohn Marino case BUILT_IN_STPCPY:
6162e4b17023SJohn Marino target = expand_builtin_stpcpy (exp, target, mode);
6163e4b17023SJohn Marino if (target)
6164e4b17023SJohn Marino return target;
6165e4b17023SJohn Marino break;
6166e4b17023SJohn Marino
6167e4b17023SJohn Marino case BUILT_IN_MEMCPY:
6168e4b17023SJohn Marino target = expand_builtin_memcpy (exp, target);
6169e4b17023SJohn Marino if (target)
6170e4b17023SJohn Marino return target;
6171e4b17023SJohn Marino break;
6172e4b17023SJohn Marino
6173e4b17023SJohn Marino case BUILT_IN_MEMPCPY:
6174e4b17023SJohn Marino target = expand_builtin_mempcpy (exp, target, mode);
6175e4b17023SJohn Marino if (target)
6176e4b17023SJohn Marino return target;
6177e4b17023SJohn Marino break;
6178e4b17023SJohn Marino
6179e4b17023SJohn Marino case BUILT_IN_MEMSET:
6180e4b17023SJohn Marino target = expand_builtin_memset (exp, target, mode);
6181e4b17023SJohn Marino if (target)
6182e4b17023SJohn Marino return target;
6183e4b17023SJohn Marino break;
6184e4b17023SJohn Marino
6185e4b17023SJohn Marino case BUILT_IN_BZERO:
6186e4b17023SJohn Marino target = expand_builtin_bzero (exp);
6187e4b17023SJohn Marino if (target)
6188e4b17023SJohn Marino return target;
6189e4b17023SJohn Marino break;
6190e4b17023SJohn Marino
6191e4b17023SJohn Marino case BUILT_IN_STRCMP:
6192e4b17023SJohn Marino target = expand_builtin_strcmp (exp, target);
6193e4b17023SJohn Marino if (target)
6194e4b17023SJohn Marino return target;
6195e4b17023SJohn Marino break;
6196e4b17023SJohn Marino
6197e4b17023SJohn Marino case BUILT_IN_STRNCMP:
6198e4b17023SJohn Marino target = expand_builtin_strncmp (exp, target, mode);
6199e4b17023SJohn Marino if (target)
6200e4b17023SJohn Marino return target;
6201e4b17023SJohn Marino break;
6202e4b17023SJohn Marino
6203e4b17023SJohn Marino case BUILT_IN_BCMP:
6204e4b17023SJohn Marino case BUILT_IN_MEMCMP:
6205e4b17023SJohn Marino target = expand_builtin_memcmp (exp, target, mode);
6206e4b17023SJohn Marino if (target)
6207e4b17023SJohn Marino return target;
6208e4b17023SJohn Marino break;
6209e4b17023SJohn Marino
6210e4b17023SJohn Marino case BUILT_IN_SETJMP:
6211e4b17023SJohn Marino /* This should have been lowered to the builtins below. */
6212e4b17023SJohn Marino gcc_unreachable ();
6213e4b17023SJohn Marino
6214e4b17023SJohn Marino case BUILT_IN_SETJMP_SETUP:
6215e4b17023SJohn Marino /* __builtin_setjmp_setup is passed a pointer to an array of five words
6216e4b17023SJohn Marino and the receiver label. */
6217e4b17023SJohn Marino if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
6218e4b17023SJohn Marino {
6219e4b17023SJohn Marino rtx buf_addr = expand_expr (CALL_EXPR_ARG (exp, 0), subtarget,
6220e4b17023SJohn Marino VOIDmode, EXPAND_NORMAL);
6221e4b17023SJohn Marino tree label = TREE_OPERAND (CALL_EXPR_ARG (exp, 1), 0);
6222e4b17023SJohn Marino rtx label_r = label_rtx (label);
6223e4b17023SJohn Marino
6224e4b17023SJohn Marino /* This is copied from the handling of non-local gotos. */
6225e4b17023SJohn Marino expand_builtin_setjmp_setup (buf_addr, label_r);
6226e4b17023SJohn Marino nonlocal_goto_handler_labels
6227e4b17023SJohn Marino = gen_rtx_EXPR_LIST (VOIDmode, label_r,
6228e4b17023SJohn Marino nonlocal_goto_handler_labels);
6229e4b17023SJohn Marino /* ??? Do not let expand_label treat us as such since we would
6230e4b17023SJohn Marino not want to be both on the list of non-local labels and on
6231e4b17023SJohn Marino the list of forced labels. */
6232e4b17023SJohn Marino FORCED_LABEL (label) = 0;
6233e4b17023SJohn Marino return const0_rtx;
6234e4b17023SJohn Marino }
6235e4b17023SJohn Marino break;
6236e4b17023SJohn Marino
6237e4b17023SJohn Marino case BUILT_IN_SETJMP_DISPATCHER:
6238e4b17023SJohn Marino /* __builtin_setjmp_dispatcher is passed the dispatcher label. */
6239e4b17023SJohn Marino if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
6240e4b17023SJohn Marino {
6241e4b17023SJohn Marino tree label = TREE_OPERAND (CALL_EXPR_ARG (exp, 0), 0);
6242e4b17023SJohn Marino rtx label_r = label_rtx (label);
6243e4b17023SJohn Marino
6244e4b17023SJohn Marino /* Remove the dispatcher label from the list of non-local labels
6245e4b17023SJohn Marino since the receiver labels have been added to it above. */
6246e4b17023SJohn Marino remove_node_from_expr_list (label_r, &nonlocal_goto_handler_labels);
6247e4b17023SJohn Marino return const0_rtx;
6248e4b17023SJohn Marino }
6249e4b17023SJohn Marino break;
6250e4b17023SJohn Marino
6251e4b17023SJohn Marino case BUILT_IN_SETJMP_RECEIVER:
6252e4b17023SJohn Marino /* __builtin_setjmp_receiver is passed the receiver label. */
6253e4b17023SJohn Marino if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
6254e4b17023SJohn Marino {
6255e4b17023SJohn Marino tree label = TREE_OPERAND (CALL_EXPR_ARG (exp, 0), 0);
6256e4b17023SJohn Marino rtx label_r = label_rtx (label);
6257e4b17023SJohn Marino
6258e4b17023SJohn Marino expand_builtin_setjmp_receiver (label_r);
6259e4b17023SJohn Marino return const0_rtx;
6260e4b17023SJohn Marino }
6261e4b17023SJohn Marino break;
6262e4b17023SJohn Marino
6263e4b17023SJohn Marino /* __builtin_longjmp is passed a pointer to an array of five words.
6264e4b17023SJohn Marino It's similar to the C library longjmp function but works with
6265e4b17023SJohn Marino __builtin_setjmp above. */
6266e4b17023SJohn Marino case BUILT_IN_LONGJMP:
6267e4b17023SJohn Marino if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
6268e4b17023SJohn Marino {
6269e4b17023SJohn Marino rtx buf_addr = expand_expr (CALL_EXPR_ARG (exp, 0), subtarget,
6270e4b17023SJohn Marino VOIDmode, EXPAND_NORMAL);
6271e4b17023SJohn Marino rtx value = expand_normal (CALL_EXPR_ARG (exp, 1));
6272e4b17023SJohn Marino
6273e4b17023SJohn Marino if (value != const1_rtx)
6274e4b17023SJohn Marino {
6275e4b17023SJohn Marino error ("%<__builtin_longjmp%> second argument must be 1");
6276e4b17023SJohn Marino return const0_rtx;
6277e4b17023SJohn Marino }
6278e4b17023SJohn Marino
6279e4b17023SJohn Marino expand_builtin_longjmp (buf_addr, value);
6280e4b17023SJohn Marino return const0_rtx;
6281e4b17023SJohn Marino }
6282e4b17023SJohn Marino break;
6283e4b17023SJohn Marino
6284e4b17023SJohn Marino case BUILT_IN_NONLOCAL_GOTO:
6285e4b17023SJohn Marino target = expand_builtin_nonlocal_goto (exp);
6286e4b17023SJohn Marino if (target)
6287e4b17023SJohn Marino return target;
6288e4b17023SJohn Marino break;
6289e4b17023SJohn Marino
6290e4b17023SJohn Marino /* This updates the setjmp buffer that is its argument with the value
6291e4b17023SJohn Marino of the current stack pointer. */
6292e4b17023SJohn Marino case BUILT_IN_UPDATE_SETJMP_BUF:
6293e4b17023SJohn Marino if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
6294e4b17023SJohn Marino {
6295e4b17023SJohn Marino rtx buf_addr
6296e4b17023SJohn Marino = expand_normal (CALL_EXPR_ARG (exp, 0));
6297e4b17023SJohn Marino
6298e4b17023SJohn Marino expand_builtin_update_setjmp_buf (buf_addr);
6299e4b17023SJohn Marino return const0_rtx;
6300e4b17023SJohn Marino }
6301e4b17023SJohn Marino break;
6302e4b17023SJohn Marino
6303e4b17023SJohn Marino case BUILT_IN_TRAP:
6304e4b17023SJohn Marino expand_builtin_trap ();
6305e4b17023SJohn Marino return const0_rtx;
6306e4b17023SJohn Marino
6307e4b17023SJohn Marino case BUILT_IN_UNREACHABLE:
6308e4b17023SJohn Marino expand_builtin_unreachable ();
6309e4b17023SJohn Marino return const0_rtx;
6310e4b17023SJohn Marino
6311e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SIGNBIT):
6312e4b17023SJohn Marino case BUILT_IN_SIGNBITD32:
6313e4b17023SJohn Marino case BUILT_IN_SIGNBITD64:
6314e4b17023SJohn Marino case BUILT_IN_SIGNBITD128:
6315e4b17023SJohn Marino target = expand_builtin_signbit (exp, target);
6316e4b17023SJohn Marino if (target)
6317e4b17023SJohn Marino return target;
6318e4b17023SJohn Marino break;
6319e4b17023SJohn Marino
6320e4b17023SJohn Marino /* Various hooks for the DWARF 2 __throw routine. */
6321e4b17023SJohn Marino case BUILT_IN_UNWIND_INIT:
6322e4b17023SJohn Marino expand_builtin_unwind_init ();
6323e4b17023SJohn Marino return const0_rtx;
6324e4b17023SJohn Marino case BUILT_IN_DWARF_CFA:
6325e4b17023SJohn Marino return virtual_cfa_rtx;
6326e4b17023SJohn Marino #ifdef DWARF2_UNWIND_INFO
6327e4b17023SJohn Marino case BUILT_IN_DWARF_SP_COLUMN:
6328e4b17023SJohn Marino return expand_builtin_dwarf_sp_column ();
6329e4b17023SJohn Marino case BUILT_IN_INIT_DWARF_REG_SIZES:
6330e4b17023SJohn Marino expand_builtin_init_dwarf_reg_sizes (CALL_EXPR_ARG (exp, 0));
6331e4b17023SJohn Marino return const0_rtx;
6332e4b17023SJohn Marino #endif
6333e4b17023SJohn Marino case BUILT_IN_FROB_RETURN_ADDR:
6334e4b17023SJohn Marino return expand_builtin_frob_return_addr (CALL_EXPR_ARG (exp, 0));
6335e4b17023SJohn Marino case BUILT_IN_EXTRACT_RETURN_ADDR:
6336e4b17023SJohn Marino return expand_builtin_extract_return_addr (CALL_EXPR_ARG (exp, 0));
6337e4b17023SJohn Marino case BUILT_IN_EH_RETURN:
6338e4b17023SJohn Marino expand_builtin_eh_return (CALL_EXPR_ARG (exp, 0),
6339e4b17023SJohn Marino CALL_EXPR_ARG (exp, 1));
6340e4b17023SJohn Marino return const0_rtx;
6341e4b17023SJohn Marino #ifdef EH_RETURN_DATA_REGNO
6342e4b17023SJohn Marino case BUILT_IN_EH_RETURN_DATA_REGNO:
6343e4b17023SJohn Marino return expand_builtin_eh_return_data_regno (exp);
6344e4b17023SJohn Marino #endif
6345e4b17023SJohn Marino case BUILT_IN_EXTEND_POINTER:
6346e4b17023SJohn Marino return expand_builtin_extend_pointer (CALL_EXPR_ARG (exp, 0));
6347e4b17023SJohn Marino case BUILT_IN_EH_POINTER:
6348e4b17023SJohn Marino return expand_builtin_eh_pointer (exp);
6349e4b17023SJohn Marino case BUILT_IN_EH_FILTER:
6350e4b17023SJohn Marino return expand_builtin_eh_filter (exp);
6351e4b17023SJohn Marino case BUILT_IN_EH_COPY_VALUES:
6352e4b17023SJohn Marino return expand_builtin_eh_copy_values (exp);
6353e4b17023SJohn Marino
6354e4b17023SJohn Marino case BUILT_IN_VA_START:
6355e4b17023SJohn Marino return expand_builtin_va_start (exp);
6356e4b17023SJohn Marino case BUILT_IN_VA_END:
6357e4b17023SJohn Marino return expand_builtin_va_end (exp);
6358e4b17023SJohn Marino case BUILT_IN_VA_COPY:
6359e4b17023SJohn Marino return expand_builtin_va_copy (exp);
6360e4b17023SJohn Marino case BUILT_IN_EXPECT:
6361e4b17023SJohn Marino return expand_builtin_expect (exp, target);
6362e4b17023SJohn Marino case BUILT_IN_ASSUME_ALIGNED:
6363e4b17023SJohn Marino return expand_builtin_assume_aligned (exp, target);
6364e4b17023SJohn Marino case BUILT_IN_PREFETCH:
6365e4b17023SJohn Marino expand_builtin_prefetch (exp);
6366e4b17023SJohn Marino return const0_rtx;
6367e4b17023SJohn Marino
6368e4b17023SJohn Marino case BUILT_IN_INIT_TRAMPOLINE:
6369e4b17023SJohn Marino return expand_builtin_init_trampoline (exp, true);
6370e4b17023SJohn Marino case BUILT_IN_INIT_HEAP_TRAMPOLINE:
6371e4b17023SJohn Marino return expand_builtin_init_trampoline (exp, false);
6372e4b17023SJohn Marino case BUILT_IN_ADJUST_TRAMPOLINE:
6373e4b17023SJohn Marino return expand_builtin_adjust_trampoline (exp);
6374e4b17023SJohn Marino
6375e4b17023SJohn Marino case BUILT_IN_FORK:
6376e4b17023SJohn Marino case BUILT_IN_EXECL:
6377e4b17023SJohn Marino case BUILT_IN_EXECV:
6378e4b17023SJohn Marino case BUILT_IN_EXECLP:
6379e4b17023SJohn Marino case BUILT_IN_EXECLE:
6380e4b17023SJohn Marino case BUILT_IN_EXECVP:
6381e4b17023SJohn Marino case BUILT_IN_EXECVE:
6382e4b17023SJohn Marino target = expand_builtin_fork_or_exec (fndecl, exp, target, ignore);
6383e4b17023SJohn Marino if (target)
6384e4b17023SJohn Marino return target;
6385e4b17023SJohn Marino break;
6386e4b17023SJohn Marino
6387e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_ADD_1:
6388e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_ADD_2:
6389e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_ADD_4:
6390e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_ADD_8:
6391e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_ADD_16:
6392e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_ADD_1);
6393e4b17023SJohn Marino target = expand_builtin_sync_operation (mode, exp, PLUS, false, target);
6394e4b17023SJohn Marino if (target)
6395e4b17023SJohn Marino return target;
6396e4b17023SJohn Marino break;
6397e4b17023SJohn Marino
6398e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_SUB_1:
6399e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_SUB_2:
6400e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_SUB_4:
6401e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_SUB_8:
6402e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_SUB_16:
6403e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_SUB_1);
6404e4b17023SJohn Marino target = expand_builtin_sync_operation (mode, exp, MINUS, false, target);
6405e4b17023SJohn Marino if (target)
6406e4b17023SJohn Marino return target;
6407e4b17023SJohn Marino break;
6408e4b17023SJohn Marino
6409e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_OR_1:
6410e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_OR_2:
6411e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_OR_4:
6412e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_OR_8:
6413e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_OR_16:
6414e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_OR_1);
6415e4b17023SJohn Marino target = expand_builtin_sync_operation (mode, exp, IOR, false, target);
6416e4b17023SJohn Marino if (target)
6417e4b17023SJohn Marino return target;
6418e4b17023SJohn Marino break;
6419e4b17023SJohn Marino
6420e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_AND_1:
6421e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_AND_2:
6422e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_AND_4:
6423e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_AND_8:
6424e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_AND_16:
6425e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_AND_1);
6426e4b17023SJohn Marino target = expand_builtin_sync_operation (mode, exp, AND, false, target);
6427e4b17023SJohn Marino if (target)
6428e4b17023SJohn Marino return target;
6429e4b17023SJohn Marino break;
6430e4b17023SJohn Marino
6431e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_XOR_1:
6432e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_XOR_2:
6433e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_XOR_4:
6434e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_XOR_8:
6435e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_XOR_16:
6436e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_XOR_1);
6437e4b17023SJohn Marino target = expand_builtin_sync_operation (mode, exp, XOR, false, target);
6438e4b17023SJohn Marino if (target)
6439e4b17023SJohn Marino return target;
6440e4b17023SJohn Marino break;
6441e4b17023SJohn Marino
6442e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_NAND_1:
6443e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_NAND_2:
6444e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_NAND_4:
6445e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_NAND_8:
6446e4b17023SJohn Marino case BUILT_IN_SYNC_FETCH_AND_NAND_16:
6447e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_NAND_1);
6448e4b17023SJohn Marino target = expand_builtin_sync_operation (mode, exp, NOT, false, target);
6449e4b17023SJohn Marino if (target)
6450e4b17023SJohn Marino return target;
6451e4b17023SJohn Marino break;
6452e4b17023SJohn Marino
6453e4b17023SJohn Marino case BUILT_IN_SYNC_ADD_AND_FETCH_1:
6454e4b17023SJohn Marino case BUILT_IN_SYNC_ADD_AND_FETCH_2:
6455e4b17023SJohn Marino case BUILT_IN_SYNC_ADD_AND_FETCH_4:
6456e4b17023SJohn Marino case BUILT_IN_SYNC_ADD_AND_FETCH_8:
6457e4b17023SJohn Marino case BUILT_IN_SYNC_ADD_AND_FETCH_16:
6458e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_ADD_AND_FETCH_1);
6459e4b17023SJohn Marino target = expand_builtin_sync_operation (mode, exp, PLUS, true, target);
6460e4b17023SJohn Marino if (target)
6461e4b17023SJohn Marino return target;
6462e4b17023SJohn Marino break;
6463e4b17023SJohn Marino
6464e4b17023SJohn Marino case BUILT_IN_SYNC_SUB_AND_FETCH_1:
6465e4b17023SJohn Marino case BUILT_IN_SYNC_SUB_AND_FETCH_2:
6466e4b17023SJohn Marino case BUILT_IN_SYNC_SUB_AND_FETCH_4:
6467e4b17023SJohn Marino case BUILT_IN_SYNC_SUB_AND_FETCH_8:
6468e4b17023SJohn Marino case BUILT_IN_SYNC_SUB_AND_FETCH_16:
6469e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_SUB_AND_FETCH_1);
6470e4b17023SJohn Marino target = expand_builtin_sync_operation (mode, exp, MINUS, true, target);
6471e4b17023SJohn Marino if (target)
6472e4b17023SJohn Marino return target;
6473e4b17023SJohn Marino break;
6474e4b17023SJohn Marino
6475e4b17023SJohn Marino case BUILT_IN_SYNC_OR_AND_FETCH_1:
6476e4b17023SJohn Marino case BUILT_IN_SYNC_OR_AND_FETCH_2:
6477e4b17023SJohn Marino case BUILT_IN_SYNC_OR_AND_FETCH_4:
6478e4b17023SJohn Marino case BUILT_IN_SYNC_OR_AND_FETCH_8:
6479e4b17023SJohn Marino case BUILT_IN_SYNC_OR_AND_FETCH_16:
6480e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_OR_AND_FETCH_1);
6481e4b17023SJohn Marino target = expand_builtin_sync_operation (mode, exp, IOR, true, target);
6482e4b17023SJohn Marino if (target)
6483e4b17023SJohn Marino return target;
6484e4b17023SJohn Marino break;
6485e4b17023SJohn Marino
6486e4b17023SJohn Marino case BUILT_IN_SYNC_AND_AND_FETCH_1:
6487e4b17023SJohn Marino case BUILT_IN_SYNC_AND_AND_FETCH_2:
6488e4b17023SJohn Marino case BUILT_IN_SYNC_AND_AND_FETCH_4:
6489e4b17023SJohn Marino case BUILT_IN_SYNC_AND_AND_FETCH_8:
6490e4b17023SJohn Marino case BUILT_IN_SYNC_AND_AND_FETCH_16:
6491e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_AND_AND_FETCH_1);
6492e4b17023SJohn Marino target = expand_builtin_sync_operation (mode, exp, AND, true, target);
6493e4b17023SJohn Marino if (target)
6494e4b17023SJohn Marino return target;
6495e4b17023SJohn Marino break;
6496e4b17023SJohn Marino
6497e4b17023SJohn Marino case BUILT_IN_SYNC_XOR_AND_FETCH_1:
6498e4b17023SJohn Marino case BUILT_IN_SYNC_XOR_AND_FETCH_2:
6499e4b17023SJohn Marino case BUILT_IN_SYNC_XOR_AND_FETCH_4:
6500e4b17023SJohn Marino case BUILT_IN_SYNC_XOR_AND_FETCH_8:
6501e4b17023SJohn Marino case BUILT_IN_SYNC_XOR_AND_FETCH_16:
6502e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_XOR_AND_FETCH_1);
6503e4b17023SJohn Marino target = expand_builtin_sync_operation (mode, exp, XOR, true, target);
6504e4b17023SJohn Marino if (target)
6505e4b17023SJohn Marino return target;
6506e4b17023SJohn Marino break;
6507e4b17023SJohn Marino
6508e4b17023SJohn Marino case BUILT_IN_SYNC_NAND_AND_FETCH_1:
6509e4b17023SJohn Marino case BUILT_IN_SYNC_NAND_AND_FETCH_2:
6510e4b17023SJohn Marino case BUILT_IN_SYNC_NAND_AND_FETCH_4:
6511e4b17023SJohn Marino case BUILT_IN_SYNC_NAND_AND_FETCH_8:
6512e4b17023SJohn Marino case BUILT_IN_SYNC_NAND_AND_FETCH_16:
6513e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_NAND_AND_FETCH_1);
6514e4b17023SJohn Marino target = expand_builtin_sync_operation (mode, exp, NOT, true, target);
6515e4b17023SJohn Marino if (target)
6516e4b17023SJohn Marino return target;
6517e4b17023SJohn Marino break;
6518e4b17023SJohn Marino
6519e4b17023SJohn Marino case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1:
6520e4b17023SJohn Marino case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_2:
6521e4b17023SJohn Marino case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4:
6522e4b17023SJohn Marino case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8:
6523e4b17023SJohn Marino case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_16:
6524e4b17023SJohn Marino if (mode == VOIDmode)
6525e4b17023SJohn Marino mode = TYPE_MODE (boolean_type_node);
6526e4b17023SJohn Marino if (!target || !register_operand (target, mode))
6527e4b17023SJohn Marino target = gen_reg_rtx (mode);
6528e4b17023SJohn Marino
6529e4b17023SJohn Marino mode = get_builtin_sync_mode
6530e4b17023SJohn Marino (fcode - BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1);
6531e4b17023SJohn Marino target = expand_builtin_compare_and_swap (mode, exp, true, target);
6532e4b17023SJohn Marino if (target)
6533e4b17023SJohn Marino return target;
6534e4b17023SJohn Marino break;
6535e4b17023SJohn Marino
6536e4b17023SJohn Marino case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_1:
6537e4b17023SJohn Marino case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_2:
6538e4b17023SJohn Marino case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_4:
6539e4b17023SJohn Marino case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_8:
6540e4b17023SJohn Marino case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_16:
6541e4b17023SJohn Marino mode = get_builtin_sync_mode
6542e4b17023SJohn Marino (fcode - BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_1);
6543e4b17023SJohn Marino target = expand_builtin_compare_and_swap (mode, exp, false, target);
6544e4b17023SJohn Marino if (target)
6545e4b17023SJohn Marino return target;
6546e4b17023SJohn Marino break;
6547e4b17023SJohn Marino
6548e4b17023SJohn Marino case BUILT_IN_SYNC_LOCK_TEST_AND_SET_1:
6549e4b17023SJohn Marino case BUILT_IN_SYNC_LOCK_TEST_AND_SET_2:
6550e4b17023SJohn Marino case BUILT_IN_SYNC_LOCK_TEST_AND_SET_4:
6551e4b17023SJohn Marino case BUILT_IN_SYNC_LOCK_TEST_AND_SET_8:
6552e4b17023SJohn Marino case BUILT_IN_SYNC_LOCK_TEST_AND_SET_16:
6553e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_LOCK_TEST_AND_SET_1);
6554e4b17023SJohn Marino target = expand_builtin_sync_lock_test_and_set (mode, exp, target);
6555e4b17023SJohn Marino if (target)
6556e4b17023SJohn Marino return target;
6557e4b17023SJohn Marino break;
6558e4b17023SJohn Marino
6559e4b17023SJohn Marino case BUILT_IN_SYNC_LOCK_RELEASE_1:
6560e4b17023SJohn Marino case BUILT_IN_SYNC_LOCK_RELEASE_2:
6561e4b17023SJohn Marino case BUILT_IN_SYNC_LOCK_RELEASE_4:
6562e4b17023SJohn Marino case BUILT_IN_SYNC_LOCK_RELEASE_8:
6563e4b17023SJohn Marino case BUILT_IN_SYNC_LOCK_RELEASE_16:
6564e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_LOCK_RELEASE_1);
6565e4b17023SJohn Marino expand_builtin_sync_lock_release (mode, exp);
6566e4b17023SJohn Marino return const0_rtx;
6567e4b17023SJohn Marino
6568e4b17023SJohn Marino case BUILT_IN_SYNC_SYNCHRONIZE:
6569e4b17023SJohn Marino expand_builtin_sync_synchronize ();
6570e4b17023SJohn Marino return const0_rtx;
6571e4b17023SJohn Marino
6572e4b17023SJohn Marino case BUILT_IN_ATOMIC_EXCHANGE_1:
6573e4b17023SJohn Marino case BUILT_IN_ATOMIC_EXCHANGE_2:
6574e4b17023SJohn Marino case BUILT_IN_ATOMIC_EXCHANGE_4:
6575e4b17023SJohn Marino case BUILT_IN_ATOMIC_EXCHANGE_8:
6576e4b17023SJohn Marino case BUILT_IN_ATOMIC_EXCHANGE_16:
6577e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_EXCHANGE_1);
6578e4b17023SJohn Marino target = expand_builtin_atomic_exchange (mode, exp, target);
6579e4b17023SJohn Marino if (target)
6580e4b17023SJohn Marino return target;
6581e4b17023SJohn Marino break;
6582e4b17023SJohn Marino
6583e4b17023SJohn Marino case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1:
6584e4b17023SJohn Marino case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_2:
6585e4b17023SJohn Marino case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4:
6586e4b17023SJohn Marino case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8:
6587e4b17023SJohn Marino case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16:
6588e4b17023SJohn Marino {
6589e4b17023SJohn Marino unsigned int nargs, z;
6590e4b17023SJohn Marino VEC(tree,gc) *vec;
6591e4b17023SJohn Marino
6592e4b17023SJohn Marino mode =
6593e4b17023SJohn Marino get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1);
6594e4b17023SJohn Marino target = expand_builtin_atomic_compare_exchange (mode, exp, target);
6595e4b17023SJohn Marino if (target)
6596e4b17023SJohn Marino return target;
6597e4b17023SJohn Marino
6598e4b17023SJohn Marino /* If this is turned into an external library call, the weak parameter
6599e4b17023SJohn Marino must be dropped to match the expected parameter list. */
6600e4b17023SJohn Marino nargs = call_expr_nargs (exp);
6601e4b17023SJohn Marino vec = VEC_alloc (tree, gc, nargs - 1);
6602e4b17023SJohn Marino for (z = 0; z < 3; z++)
6603e4b17023SJohn Marino VEC_quick_push (tree, vec, CALL_EXPR_ARG (exp, z));
6604e4b17023SJohn Marino /* Skip the boolean weak parameter. */
6605e4b17023SJohn Marino for (z = 4; z < 6; z++)
6606e4b17023SJohn Marino VEC_quick_push (tree, vec, CALL_EXPR_ARG (exp, z));
6607e4b17023SJohn Marino exp = build_call_vec (TREE_TYPE (exp), CALL_EXPR_FN (exp), vec);
6608e4b17023SJohn Marino break;
6609e4b17023SJohn Marino }
6610e4b17023SJohn Marino
6611e4b17023SJohn Marino case BUILT_IN_ATOMIC_LOAD_1:
6612e4b17023SJohn Marino case BUILT_IN_ATOMIC_LOAD_2:
6613e4b17023SJohn Marino case BUILT_IN_ATOMIC_LOAD_4:
6614e4b17023SJohn Marino case BUILT_IN_ATOMIC_LOAD_8:
6615e4b17023SJohn Marino case BUILT_IN_ATOMIC_LOAD_16:
6616e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_LOAD_1);
6617e4b17023SJohn Marino target = expand_builtin_atomic_load (mode, exp, target);
6618e4b17023SJohn Marino if (target)
6619e4b17023SJohn Marino return target;
6620e4b17023SJohn Marino break;
6621e4b17023SJohn Marino
6622e4b17023SJohn Marino case BUILT_IN_ATOMIC_STORE_1:
6623e4b17023SJohn Marino case BUILT_IN_ATOMIC_STORE_2:
6624e4b17023SJohn Marino case BUILT_IN_ATOMIC_STORE_4:
6625e4b17023SJohn Marino case BUILT_IN_ATOMIC_STORE_8:
6626e4b17023SJohn Marino case BUILT_IN_ATOMIC_STORE_16:
6627e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_STORE_1);
6628e4b17023SJohn Marino target = expand_builtin_atomic_store (mode, exp);
6629e4b17023SJohn Marino if (target)
6630e4b17023SJohn Marino return const0_rtx;
6631e4b17023SJohn Marino break;
6632e4b17023SJohn Marino
6633e4b17023SJohn Marino case BUILT_IN_ATOMIC_ADD_FETCH_1:
6634e4b17023SJohn Marino case BUILT_IN_ATOMIC_ADD_FETCH_2:
6635e4b17023SJohn Marino case BUILT_IN_ATOMIC_ADD_FETCH_4:
6636e4b17023SJohn Marino case BUILT_IN_ATOMIC_ADD_FETCH_8:
6637e4b17023SJohn Marino case BUILT_IN_ATOMIC_ADD_FETCH_16:
6638e4b17023SJohn Marino {
6639e4b17023SJohn Marino enum built_in_function lib;
6640e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_ADD_FETCH_1);
6641e4b17023SJohn Marino lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_ADD_1 +
6642e4b17023SJohn Marino (fcode - BUILT_IN_ATOMIC_ADD_FETCH_1));
6643e4b17023SJohn Marino target = expand_builtin_atomic_fetch_op (mode, exp, target, PLUS, true,
6644e4b17023SJohn Marino ignore, lib);
6645e4b17023SJohn Marino if (target)
6646e4b17023SJohn Marino return target;
6647e4b17023SJohn Marino break;
6648e4b17023SJohn Marino }
6649e4b17023SJohn Marino case BUILT_IN_ATOMIC_SUB_FETCH_1:
6650e4b17023SJohn Marino case BUILT_IN_ATOMIC_SUB_FETCH_2:
6651e4b17023SJohn Marino case BUILT_IN_ATOMIC_SUB_FETCH_4:
6652e4b17023SJohn Marino case BUILT_IN_ATOMIC_SUB_FETCH_8:
6653e4b17023SJohn Marino case BUILT_IN_ATOMIC_SUB_FETCH_16:
6654e4b17023SJohn Marino {
6655e4b17023SJohn Marino enum built_in_function lib;
6656e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_SUB_FETCH_1);
6657e4b17023SJohn Marino lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_SUB_1 +
6658e4b17023SJohn Marino (fcode - BUILT_IN_ATOMIC_SUB_FETCH_1));
6659e4b17023SJohn Marino target = expand_builtin_atomic_fetch_op (mode, exp, target, MINUS, true,
6660e4b17023SJohn Marino ignore, lib);
6661e4b17023SJohn Marino if (target)
6662e4b17023SJohn Marino return target;
6663e4b17023SJohn Marino break;
6664e4b17023SJohn Marino }
6665e4b17023SJohn Marino case BUILT_IN_ATOMIC_AND_FETCH_1:
6666e4b17023SJohn Marino case BUILT_IN_ATOMIC_AND_FETCH_2:
6667e4b17023SJohn Marino case BUILT_IN_ATOMIC_AND_FETCH_4:
6668e4b17023SJohn Marino case BUILT_IN_ATOMIC_AND_FETCH_8:
6669e4b17023SJohn Marino case BUILT_IN_ATOMIC_AND_FETCH_16:
6670e4b17023SJohn Marino {
6671e4b17023SJohn Marino enum built_in_function lib;
6672e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_AND_FETCH_1);
6673e4b17023SJohn Marino lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_AND_1 +
6674e4b17023SJohn Marino (fcode - BUILT_IN_ATOMIC_AND_FETCH_1));
6675e4b17023SJohn Marino target = expand_builtin_atomic_fetch_op (mode, exp, target, AND, true,
6676e4b17023SJohn Marino ignore, lib);
6677e4b17023SJohn Marino if (target)
6678e4b17023SJohn Marino return target;
6679e4b17023SJohn Marino break;
6680e4b17023SJohn Marino }
6681e4b17023SJohn Marino case BUILT_IN_ATOMIC_NAND_FETCH_1:
6682e4b17023SJohn Marino case BUILT_IN_ATOMIC_NAND_FETCH_2:
6683e4b17023SJohn Marino case BUILT_IN_ATOMIC_NAND_FETCH_4:
6684e4b17023SJohn Marino case BUILT_IN_ATOMIC_NAND_FETCH_8:
6685e4b17023SJohn Marino case BUILT_IN_ATOMIC_NAND_FETCH_16:
6686e4b17023SJohn Marino {
6687e4b17023SJohn Marino enum built_in_function lib;
6688e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_NAND_FETCH_1);
6689e4b17023SJohn Marino lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_NAND_1 +
6690e4b17023SJohn Marino (fcode - BUILT_IN_ATOMIC_NAND_FETCH_1));
6691e4b17023SJohn Marino target = expand_builtin_atomic_fetch_op (mode, exp, target, NOT, true,
6692e4b17023SJohn Marino ignore, lib);
6693e4b17023SJohn Marino if (target)
6694e4b17023SJohn Marino return target;
6695e4b17023SJohn Marino break;
6696e4b17023SJohn Marino }
6697e4b17023SJohn Marino case BUILT_IN_ATOMIC_XOR_FETCH_1:
6698e4b17023SJohn Marino case BUILT_IN_ATOMIC_XOR_FETCH_2:
6699e4b17023SJohn Marino case BUILT_IN_ATOMIC_XOR_FETCH_4:
6700e4b17023SJohn Marino case BUILT_IN_ATOMIC_XOR_FETCH_8:
6701e4b17023SJohn Marino case BUILT_IN_ATOMIC_XOR_FETCH_16:
6702e4b17023SJohn Marino {
6703e4b17023SJohn Marino enum built_in_function lib;
6704e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_XOR_FETCH_1);
6705e4b17023SJohn Marino lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_XOR_1 +
6706e4b17023SJohn Marino (fcode - BUILT_IN_ATOMIC_XOR_FETCH_1));
6707e4b17023SJohn Marino target = expand_builtin_atomic_fetch_op (mode, exp, target, XOR, true,
6708e4b17023SJohn Marino ignore, lib);
6709e4b17023SJohn Marino if (target)
6710e4b17023SJohn Marino return target;
6711e4b17023SJohn Marino break;
6712e4b17023SJohn Marino }
6713e4b17023SJohn Marino case BUILT_IN_ATOMIC_OR_FETCH_1:
6714e4b17023SJohn Marino case BUILT_IN_ATOMIC_OR_FETCH_2:
6715e4b17023SJohn Marino case BUILT_IN_ATOMIC_OR_FETCH_4:
6716e4b17023SJohn Marino case BUILT_IN_ATOMIC_OR_FETCH_8:
6717e4b17023SJohn Marino case BUILT_IN_ATOMIC_OR_FETCH_16:
6718e4b17023SJohn Marino {
6719e4b17023SJohn Marino enum built_in_function lib;
6720e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_OR_FETCH_1);
6721e4b17023SJohn Marino lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_OR_1 +
6722e4b17023SJohn Marino (fcode - BUILT_IN_ATOMIC_OR_FETCH_1));
6723e4b17023SJohn Marino target = expand_builtin_atomic_fetch_op (mode, exp, target, IOR, true,
6724e4b17023SJohn Marino ignore, lib);
6725e4b17023SJohn Marino if (target)
6726e4b17023SJohn Marino return target;
6727e4b17023SJohn Marino break;
6728e4b17023SJohn Marino }
6729e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_ADD_1:
6730e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_ADD_2:
6731e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_ADD_4:
6732e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_ADD_8:
6733e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_ADD_16:
6734e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_ADD_1);
6735e4b17023SJohn Marino target = expand_builtin_atomic_fetch_op (mode, exp, target, PLUS, false,
6736e4b17023SJohn Marino ignore, BUILT_IN_NONE);
6737e4b17023SJohn Marino if (target)
6738e4b17023SJohn Marino return target;
6739e4b17023SJohn Marino break;
6740e4b17023SJohn Marino
6741e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_SUB_1:
6742e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_SUB_2:
6743e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_SUB_4:
6744e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_SUB_8:
6745e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_SUB_16:
6746e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_SUB_1);
6747e4b17023SJohn Marino target = expand_builtin_atomic_fetch_op (mode, exp, target, MINUS, false,
6748e4b17023SJohn Marino ignore, BUILT_IN_NONE);
6749e4b17023SJohn Marino if (target)
6750e4b17023SJohn Marino return target;
6751e4b17023SJohn Marino break;
6752e4b17023SJohn Marino
6753e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_AND_1:
6754e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_AND_2:
6755e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_AND_4:
6756e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_AND_8:
6757e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_AND_16:
6758e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_AND_1);
6759e4b17023SJohn Marino target = expand_builtin_atomic_fetch_op (mode, exp, target, AND, false,
6760e4b17023SJohn Marino ignore, BUILT_IN_NONE);
6761e4b17023SJohn Marino if (target)
6762e4b17023SJohn Marino return target;
6763e4b17023SJohn Marino break;
6764e4b17023SJohn Marino
6765e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_NAND_1:
6766e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_NAND_2:
6767e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_NAND_4:
6768e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_NAND_8:
6769e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_NAND_16:
6770e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_NAND_1);
6771e4b17023SJohn Marino target = expand_builtin_atomic_fetch_op (mode, exp, target, NOT, false,
6772e4b17023SJohn Marino ignore, BUILT_IN_NONE);
6773e4b17023SJohn Marino if (target)
6774e4b17023SJohn Marino return target;
6775e4b17023SJohn Marino break;
6776e4b17023SJohn Marino
6777e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_XOR_1:
6778e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_XOR_2:
6779e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_XOR_4:
6780e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_XOR_8:
6781e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_XOR_16:
6782e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_XOR_1);
6783e4b17023SJohn Marino target = expand_builtin_atomic_fetch_op (mode, exp, target, XOR, false,
6784e4b17023SJohn Marino ignore, BUILT_IN_NONE);
6785e4b17023SJohn Marino if (target)
6786e4b17023SJohn Marino return target;
6787e4b17023SJohn Marino break;
6788e4b17023SJohn Marino
6789e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_OR_1:
6790e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_OR_2:
6791e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_OR_4:
6792e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_OR_8:
6793e4b17023SJohn Marino case BUILT_IN_ATOMIC_FETCH_OR_16:
6794e4b17023SJohn Marino mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_OR_1);
6795e4b17023SJohn Marino target = expand_builtin_atomic_fetch_op (mode, exp, target, IOR, false,
6796e4b17023SJohn Marino ignore, BUILT_IN_NONE);
6797e4b17023SJohn Marino if (target)
6798e4b17023SJohn Marino return target;
6799e4b17023SJohn Marino break;
6800e4b17023SJohn Marino
6801e4b17023SJohn Marino case BUILT_IN_ATOMIC_TEST_AND_SET:
6802e4b17023SJohn Marino return expand_builtin_atomic_test_and_set (exp, target);
6803e4b17023SJohn Marino
6804e4b17023SJohn Marino case BUILT_IN_ATOMIC_CLEAR:
6805e4b17023SJohn Marino return expand_builtin_atomic_clear (exp);
6806e4b17023SJohn Marino
6807e4b17023SJohn Marino case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
6808e4b17023SJohn Marino return expand_builtin_atomic_always_lock_free (exp);
6809e4b17023SJohn Marino
6810e4b17023SJohn Marino case BUILT_IN_ATOMIC_IS_LOCK_FREE:
6811e4b17023SJohn Marino target = expand_builtin_atomic_is_lock_free (exp);
6812e4b17023SJohn Marino if (target)
6813e4b17023SJohn Marino return target;
6814e4b17023SJohn Marino break;
6815e4b17023SJohn Marino
6816e4b17023SJohn Marino case BUILT_IN_ATOMIC_THREAD_FENCE:
6817e4b17023SJohn Marino expand_builtin_atomic_thread_fence (exp);
6818e4b17023SJohn Marino return const0_rtx;
6819e4b17023SJohn Marino
6820e4b17023SJohn Marino case BUILT_IN_ATOMIC_SIGNAL_FENCE:
6821e4b17023SJohn Marino expand_builtin_atomic_signal_fence (exp);
6822e4b17023SJohn Marino return const0_rtx;
6823e4b17023SJohn Marino
6824e4b17023SJohn Marino case BUILT_IN_OBJECT_SIZE:
6825e4b17023SJohn Marino return expand_builtin_object_size (exp);
6826e4b17023SJohn Marino
6827e4b17023SJohn Marino case BUILT_IN_MEMCPY_CHK:
6828e4b17023SJohn Marino case BUILT_IN_MEMPCPY_CHK:
6829e4b17023SJohn Marino case BUILT_IN_MEMMOVE_CHK:
6830e4b17023SJohn Marino case BUILT_IN_MEMSET_CHK:
6831e4b17023SJohn Marino target = expand_builtin_memory_chk (exp, target, mode, fcode);
6832e4b17023SJohn Marino if (target)
6833e4b17023SJohn Marino return target;
6834e4b17023SJohn Marino break;
6835e4b17023SJohn Marino
6836e4b17023SJohn Marino case BUILT_IN_STRCPY_CHK:
6837e4b17023SJohn Marino case BUILT_IN_STPCPY_CHK:
6838e4b17023SJohn Marino case BUILT_IN_STRNCPY_CHK:
6839e4b17023SJohn Marino case BUILT_IN_STPNCPY_CHK:
6840e4b17023SJohn Marino case BUILT_IN_STRCAT_CHK:
6841e4b17023SJohn Marino case BUILT_IN_STRNCAT_CHK:
6842e4b17023SJohn Marino case BUILT_IN_SNPRINTF_CHK:
6843e4b17023SJohn Marino case BUILT_IN_VSNPRINTF_CHK:
6844e4b17023SJohn Marino maybe_emit_chk_warning (exp, fcode);
6845e4b17023SJohn Marino break;
6846e4b17023SJohn Marino
6847e4b17023SJohn Marino case BUILT_IN_SPRINTF_CHK:
6848e4b17023SJohn Marino case BUILT_IN_VSPRINTF_CHK:
6849e4b17023SJohn Marino maybe_emit_sprintf_chk_warning (exp, fcode);
6850e4b17023SJohn Marino break;
6851e4b17023SJohn Marino
6852e4b17023SJohn Marino case BUILT_IN_FREE:
6853e4b17023SJohn Marino if (warn_free_nonheap_object)
6854e4b17023SJohn Marino maybe_emit_free_warning (exp);
6855e4b17023SJohn Marino break;
6856e4b17023SJohn Marino
6857e4b17023SJohn Marino default: /* just do library call, if unknown builtin */
6858e4b17023SJohn Marino break;
6859e4b17023SJohn Marino }
6860e4b17023SJohn Marino
6861e4b17023SJohn Marino /* The switch statement above can drop through to cause the function
6862e4b17023SJohn Marino to be called normally. */
6863e4b17023SJohn Marino return expand_call (exp, target, ignore);
6864e4b17023SJohn Marino }
6865e4b17023SJohn Marino
6866e4b17023SJohn Marino /* Determine whether a tree node represents a call to a built-in
6867e4b17023SJohn Marino function. If the tree T is a call to a built-in function with
6868e4b17023SJohn Marino the right number of arguments of the appropriate types, return
6869e4b17023SJohn Marino the DECL_FUNCTION_CODE of the call, e.g. BUILT_IN_SQRT.
6870e4b17023SJohn Marino Otherwise the return value is END_BUILTINS. */
6871e4b17023SJohn Marino
6872e4b17023SJohn Marino enum built_in_function
builtin_mathfn_code(const_tree t)6873e4b17023SJohn Marino builtin_mathfn_code (const_tree t)
6874e4b17023SJohn Marino {
6875e4b17023SJohn Marino const_tree fndecl, arg, parmlist;
6876e4b17023SJohn Marino const_tree argtype, parmtype;
6877e4b17023SJohn Marino const_call_expr_arg_iterator iter;
6878e4b17023SJohn Marino
6879e4b17023SJohn Marino if (TREE_CODE (t) != CALL_EXPR
6880e4b17023SJohn Marino || TREE_CODE (CALL_EXPR_FN (t)) != ADDR_EXPR)
6881e4b17023SJohn Marino return END_BUILTINS;
6882e4b17023SJohn Marino
6883e4b17023SJohn Marino fndecl = get_callee_fndecl (t);
6884e4b17023SJohn Marino if (fndecl == NULL_TREE
6885e4b17023SJohn Marino || TREE_CODE (fndecl) != FUNCTION_DECL
6886e4b17023SJohn Marino || ! DECL_BUILT_IN (fndecl)
6887e4b17023SJohn Marino || DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
6888e4b17023SJohn Marino return END_BUILTINS;
6889e4b17023SJohn Marino
6890e4b17023SJohn Marino parmlist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
6891e4b17023SJohn Marino init_const_call_expr_arg_iterator (t, &iter);
6892e4b17023SJohn Marino for (; parmlist; parmlist = TREE_CHAIN (parmlist))
6893e4b17023SJohn Marino {
6894e4b17023SJohn Marino /* If a function doesn't take a variable number of arguments,
6895e4b17023SJohn Marino the last element in the list will have type `void'. */
6896e4b17023SJohn Marino parmtype = TREE_VALUE (parmlist);
6897e4b17023SJohn Marino if (VOID_TYPE_P (parmtype))
6898e4b17023SJohn Marino {
6899e4b17023SJohn Marino if (more_const_call_expr_args_p (&iter))
6900e4b17023SJohn Marino return END_BUILTINS;
6901e4b17023SJohn Marino return DECL_FUNCTION_CODE (fndecl);
6902e4b17023SJohn Marino }
6903e4b17023SJohn Marino
6904e4b17023SJohn Marino if (! more_const_call_expr_args_p (&iter))
6905e4b17023SJohn Marino return END_BUILTINS;
6906e4b17023SJohn Marino
6907e4b17023SJohn Marino arg = next_const_call_expr_arg (&iter);
6908e4b17023SJohn Marino argtype = TREE_TYPE (arg);
6909e4b17023SJohn Marino
6910e4b17023SJohn Marino if (SCALAR_FLOAT_TYPE_P (parmtype))
6911e4b17023SJohn Marino {
6912e4b17023SJohn Marino if (! SCALAR_FLOAT_TYPE_P (argtype))
6913e4b17023SJohn Marino return END_BUILTINS;
6914e4b17023SJohn Marino }
6915e4b17023SJohn Marino else if (COMPLEX_FLOAT_TYPE_P (parmtype))
6916e4b17023SJohn Marino {
6917e4b17023SJohn Marino if (! COMPLEX_FLOAT_TYPE_P (argtype))
6918e4b17023SJohn Marino return END_BUILTINS;
6919e4b17023SJohn Marino }
6920e4b17023SJohn Marino else if (POINTER_TYPE_P (parmtype))
6921e4b17023SJohn Marino {
6922e4b17023SJohn Marino if (! POINTER_TYPE_P (argtype))
6923e4b17023SJohn Marino return END_BUILTINS;
6924e4b17023SJohn Marino }
6925e4b17023SJohn Marino else if (INTEGRAL_TYPE_P (parmtype))
6926e4b17023SJohn Marino {
6927e4b17023SJohn Marino if (! INTEGRAL_TYPE_P (argtype))
6928e4b17023SJohn Marino return END_BUILTINS;
6929e4b17023SJohn Marino }
6930e4b17023SJohn Marino else
6931e4b17023SJohn Marino return END_BUILTINS;
6932e4b17023SJohn Marino }
6933e4b17023SJohn Marino
6934e4b17023SJohn Marino /* Variable-length argument list. */
6935e4b17023SJohn Marino return DECL_FUNCTION_CODE (fndecl);
6936e4b17023SJohn Marino }
6937e4b17023SJohn Marino
6938e4b17023SJohn Marino /* Fold a call to __builtin_constant_p, if we know its argument ARG will
6939e4b17023SJohn Marino evaluate to a constant. */
6940e4b17023SJohn Marino
6941e4b17023SJohn Marino static tree
fold_builtin_constant_p(tree arg)6942e4b17023SJohn Marino fold_builtin_constant_p (tree arg)
6943e4b17023SJohn Marino {
6944e4b17023SJohn Marino /* We return 1 for a numeric type that's known to be a constant
6945e4b17023SJohn Marino value at compile-time or for an aggregate type that's a
6946e4b17023SJohn Marino literal constant. */
6947e4b17023SJohn Marino STRIP_NOPS (arg);
6948e4b17023SJohn Marino
6949e4b17023SJohn Marino /* If we know this is a constant, emit the constant of one. */
6950e4b17023SJohn Marino if (CONSTANT_CLASS_P (arg)
6951e4b17023SJohn Marino || (TREE_CODE (arg) == CONSTRUCTOR
6952e4b17023SJohn Marino && TREE_CONSTANT (arg)))
6953e4b17023SJohn Marino return integer_one_node;
6954e4b17023SJohn Marino if (TREE_CODE (arg) == ADDR_EXPR)
6955e4b17023SJohn Marino {
6956e4b17023SJohn Marino tree op = TREE_OPERAND (arg, 0);
6957e4b17023SJohn Marino if (TREE_CODE (op) == STRING_CST
6958e4b17023SJohn Marino || (TREE_CODE (op) == ARRAY_REF
6959e4b17023SJohn Marino && integer_zerop (TREE_OPERAND (op, 1))
6960e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (op, 0)) == STRING_CST))
6961e4b17023SJohn Marino return integer_one_node;
6962e4b17023SJohn Marino }
6963e4b17023SJohn Marino
6964e4b17023SJohn Marino /* If this expression has side effects, show we don't know it to be a
6965e4b17023SJohn Marino constant. Likewise if it's a pointer or aggregate type since in
6966e4b17023SJohn Marino those case we only want literals, since those are only optimized
6967e4b17023SJohn Marino when generating RTL, not later.
6968e4b17023SJohn Marino And finally, if we are compiling an initializer, not code, we
6969e4b17023SJohn Marino need to return a definite result now; there's not going to be any
6970e4b17023SJohn Marino more optimization done. */
6971e4b17023SJohn Marino if (TREE_SIDE_EFFECTS (arg)
6972e4b17023SJohn Marino || AGGREGATE_TYPE_P (TREE_TYPE (arg))
6973e4b17023SJohn Marino || POINTER_TYPE_P (TREE_TYPE (arg))
6974e4b17023SJohn Marino || cfun == 0
6975e4b17023SJohn Marino || folding_initializer)
6976e4b17023SJohn Marino return integer_zero_node;
6977e4b17023SJohn Marino
6978e4b17023SJohn Marino return NULL_TREE;
6979e4b17023SJohn Marino }
6980e4b17023SJohn Marino
6981e4b17023SJohn Marino /* Create builtin_expect with PRED and EXPECTED as its arguments and
6982e4b17023SJohn Marino return it as a truthvalue. */
6983e4b17023SJohn Marino
6984e4b17023SJohn Marino static tree
build_builtin_expect_predicate(location_t loc,tree pred,tree expected)6985e4b17023SJohn Marino build_builtin_expect_predicate (location_t loc, tree pred, tree expected)
6986e4b17023SJohn Marino {
6987e4b17023SJohn Marino tree fn, arg_types, pred_type, expected_type, call_expr, ret_type;
6988e4b17023SJohn Marino
6989e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_EXPECT);
6990e4b17023SJohn Marino arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
6991e4b17023SJohn Marino ret_type = TREE_TYPE (TREE_TYPE (fn));
6992e4b17023SJohn Marino pred_type = TREE_VALUE (arg_types);
6993e4b17023SJohn Marino expected_type = TREE_VALUE (TREE_CHAIN (arg_types));
6994e4b17023SJohn Marino
6995e4b17023SJohn Marino pred = fold_convert_loc (loc, pred_type, pred);
6996e4b17023SJohn Marino expected = fold_convert_loc (loc, expected_type, expected);
6997e4b17023SJohn Marino call_expr = build_call_expr_loc (loc, fn, 2, pred, expected);
6998e4b17023SJohn Marino
6999e4b17023SJohn Marino return build2 (NE_EXPR, TREE_TYPE (pred), call_expr,
7000e4b17023SJohn Marino build_int_cst (ret_type, 0));
7001e4b17023SJohn Marino }
7002e4b17023SJohn Marino
7003e4b17023SJohn Marino /* Fold a call to builtin_expect with arguments ARG0 and ARG1. Return
7004e4b17023SJohn Marino NULL_TREE if no simplification is possible. */
7005e4b17023SJohn Marino
7006e4b17023SJohn Marino static tree
fold_builtin_expect(location_t loc,tree arg0,tree arg1)7007e4b17023SJohn Marino fold_builtin_expect (location_t loc, tree arg0, tree arg1)
7008e4b17023SJohn Marino {
7009e4b17023SJohn Marino tree inner, fndecl, inner_arg0;
7010e4b17023SJohn Marino enum tree_code code;
7011e4b17023SJohn Marino
7012e4b17023SJohn Marino /* Distribute the expected value over short-circuiting operators.
7013e4b17023SJohn Marino See through the cast from truthvalue_type_node to long. */
7014e4b17023SJohn Marino inner_arg0 = arg0;
7015e4b17023SJohn Marino while (TREE_CODE (inner_arg0) == NOP_EXPR
7016e4b17023SJohn Marino && INTEGRAL_TYPE_P (TREE_TYPE (inner_arg0))
7017e4b17023SJohn Marino && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (inner_arg0, 0))))
7018e4b17023SJohn Marino inner_arg0 = TREE_OPERAND (inner_arg0, 0);
7019e4b17023SJohn Marino
7020e4b17023SJohn Marino /* If this is a builtin_expect within a builtin_expect keep the
7021e4b17023SJohn Marino inner one. See through a comparison against a constant. It
7022e4b17023SJohn Marino might have been added to create a thruthvalue. */
7023e4b17023SJohn Marino inner = inner_arg0;
7024e4b17023SJohn Marino
7025e4b17023SJohn Marino if (COMPARISON_CLASS_P (inner)
7026e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST)
7027e4b17023SJohn Marino inner = TREE_OPERAND (inner, 0);
7028e4b17023SJohn Marino
7029e4b17023SJohn Marino if (TREE_CODE (inner) == CALL_EXPR
7030e4b17023SJohn Marino && (fndecl = get_callee_fndecl (inner))
7031e4b17023SJohn Marino && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
7032e4b17023SJohn Marino && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT)
7033e4b17023SJohn Marino return arg0;
7034e4b17023SJohn Marino
7035e4b17023SJohn Marino inner = inner_arg0;
7036e4b17023SJohn Marino code = TREE_CODE (inner);
7037e4b17023SJohn Marino if (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
7038e4b17023SJohn Marino {
7039e4b17023SJohn Marino tree op0 = TREE_OPERAND (inner, 0);
7040e4b17023SJohn Marino tree op1 = TREE_OPERAND (inner, 1);
7041e4b17023SJohn Marino
7042e4b17023SJohn Marino op0 = build_builtin_expect_predicate (loc, op0, arg1);
7043e4b17023SJohn Marino op1 = build_builtin_expect_predicate (loc, op1, arg1);
7044e4b17023SJohn Marino inner = build2 (code, TREE_TYPE (inner), op0, op1);
7045e4b17023SJohn Marino
7046e4b17023SJohn Marino return fold_convert_loc (loc, TREE_TYPE (arg0), inner);
7047e4b17023SJohn Marino }
7048e4b17023SJohn Marino
7049e4b17023SJohn Marino /* If the argument isn't invariant then there's nothing else we can do. */
7050e4b17023SJohn Marino if (!TREE_CONSTANT (inner_arg0))
7051e4b17023SJohn Marino return NULL_TREE;
7052e4b17023SJohn Marino
7053e4b17023SJohn Marino /* If we expect that a comparison against the argument will fold to
7054e4b17023SJohn Marino a constant return the constant. In practice, this means a true
7055e4b17023SJohn Marino constant or the address of a non-weak symbol. */
7056e4b17023SJohn Marino inner = inner_arg0;
7057e4b17023SJohn Marino STRIP_NOPS (inner);
7058e4b17023SJohn Marino if (TREE_CODE (inner) == ADDR_EXPR)
7059e4b17023SJohn Marino {
7060e4b17023SJohn Marino do
7061e4b17023SJohn Marino {
7062e4b17023SJohn Marino inner = TREE_OPERAND (inner, 0);
7063e4b17023SJohn Marino }
7064e4b17023SJohn Marino while (TREE_CODE (inner) == COMPONENT_REF
7065e4b17023SJohn Marino || TREE_CODE (inner) == ARRAY_REF);
7066e4b17023SJohn Marino if ((TREE_CODE (inner) == VAR_DECL
7067e4b17023SJohn Marino || TREE_CODE (inner) == FUNCTION_DECL)
7068e4b17023SJohn Marino && DECL_WEAK (inner))
7069e4b17023SJohn Marino return NULL_TREE;
7070e4b17023SJohn Marino }
7071e4b17023SJohn Marino
7072e4b17023SJohn Marino /* Otherwise, ARG0 already has the proper type for the return value. */
7073e4b17023SJohn Marino return arg0;
7074e4b17023SJohn Marino }
7075e4b17023SJohn Marino
7076e4b17023SJohn Marino /* Fold a call to __builtin_classify_type with argument ARG. */
7077e4b17023SJohn Marino
7078e4b17023SJohn Marino static tree
fold_builtin_classify_type(tree arg)7079e4b17023SJohn Marino fold_builtin_classify_type (tree arg)
7080e4b17023SJohn Marino {
7081e4b17023SJohn Marino if (arg == 0)
7082e4b17023SJohn Marino return build_int_cst (integer_type_node, no_type_class);
7083e4b17023SJohn Marino
7084e4b17023SJohn Marino return build_int_cst (integer_type_node, type_to_class (TREE_TYPE (arg)));
7085e4b17023SJohn Marino }
7086e4b17023SJohn Marino
7087e4b17023SJohn Marino /* Fold a call to __builtin_strlen with argument ARG. */
7088e4b17023SJohn Marino
7089e4b17023SJohn Marino static tree
fold_builtin_strlen(location_t loc,tree type,tree arg)7090e4b17023SJohn Marino fold_builtin_strlen (location_t loc, tree type, tree arg)
7091e4b17023SJohn Marino {
7092e4b17023SJohn Marino if (!validate_arg (arg, POINTER_TYPE))
7093e4b17023SJohn Marino return NULL_TREE;
7094e4b17023SJohn Marino else
7095e4b17023SJohn Marino {
7096e4b17023SJohn Marino tree len = c_strlen (arg, 0);
7097e4b17023SJohn Marino
7098e4b17023SJohn Marino if (len)
7099e4b17023SJohn Marino return fold_convert_loc (loc, type, len);
7100e4b17023SJohn Marino
7101e4b17023SJohn Marino return NULL_TREE;
7102e4b17023SJohn Marino }
7103e4b17023SJohn Marino }
7104e4b17023SJohn Marino
7105e4b17023SJohn Marino /* Fold a call to __builtin_inf or __builtin_huge_val. */
7106e4b17023SJohn Marino
7107e4b17023SJohn Marino static tree
fold_builtin_inf(location_t loc,tree type,int warn)7108e4b17023SJohn Marino fold_builtin_inf (location_t loc, tree type, int warn)
7109e4b17023SJohn Marino {
7110e4b17023SJohn Marino REAL_VALUE_TYPE real;
7111e4b17023SJohn Marino
7112e4b17023SJohn Marino /* __builtin_inff is intended to be usable to define INFINITY on all
7113e4b17023SJohn Marino targets. If an infinity is not available, INFINITY expands "to a
7114e4b17023SJohn Marino positive constant of type float that overflows at translation
7115e4b17023SJohn Marino time", footnote "In this case, using INFINITY will violate the
7116e4b17023SJohn Marino constraint in 6.4.4 and thus require a diagnostic." (C99 7.12#4).
7117e4b17023SJohn Marino Thus we pedwarn to ensure this constraint violation is
7118e4b17023SJohn Marino diagnosed. */
7119e4b17023SJohn Marino if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) && warn)
7120e4b17023SJohn Marino pedwarn (loc, 0, "target format does not support infinity");
7121e4b17023SJohn Marino
7122e4b17023SJohn Marino real_inf (&real);
7123e4b17023SJohn Marino return build_real (type, real);
7124e4b17023SJohn Marino }
7125e4b17023SJohn Marino
7126e4b17023SJohn Marino /* Fold a call to __builtin_nan or __builtin_nans with argument ARG. */
7127e4b17023SJohn Marino
7128e4b17023SJohn Marino static tree
fold_builtin_nan(tree arg,tree type,int quiet)7129e4b17023SJohn Marino fold_builtin_nan (tree arg, tree type, int quiet)
7130e4b17023SJohn Marino {
7131e4b17023SJohn Marino REAL_VALUE_TYPE real;
7132e4b17023SJohn Marino const char *str;
7133e4b17023SJohn Marino
7134e4b17023SJohn Marino if (!validate_arg (arg, POINTER_TYPE))
7135e4b17023SJohn Marino return NULL_TREE;
7136e4b17023SJohn Marino str = c_getstr (arg);
7137e4b17023SJohn Marino if (!str)
7138e4b17023SJohn Marino return NULL_TREE;
7139e4b17023SJohn Marino
7140e4b17023SJohn Marino if (!real_nan (&real, str, quiet, TYPE_MODE (type)))
7141e4b17023SJohn Marino return NULL_TREE;
7142e4b17023SJohn Marino
7143e4b17023SJohn Marino return build_real (type, real);
7144e4b17023SJohn Marino }
7145e4b17023SJohn Marino
7146e4b17023SJohn Marino /* Return true if the floating point expression T has an integer value.
7147e4b17023SJohn Marino We also allow +Inf, -Inf and NaN to be considered integer values. */
7148e4b17023SJohn Marino
7149e4b17023SJohn Marino static bool
integer_valued_real_p(tree t)7150e4b17023SJohn Marino integer_valued_real_p (tree t)
7151e4b17023SJohn Marino {
7152e4b17023SJohn Marino switch (TREE_CODE (t))
7153e4b17023SJohn Marino {
7154e4b17023SJohn Marino case FLOAT_EXPR:
7155e4b17023SJohn Marino return true;
7156e4b17023SJohn Marino
7157e4b17023SJohn Marino case ABS_EXPR:
7158e4b17023SJohn Marino case SAVE_EXPR:
7159e4b17023SJohn Marino return integer_valued_real_p (TREE_OPERAND (t, 0));
7160e4b17023SJohn Marino
7161e4b17023SJohn Marino case COMPOUND_EXPR:
7162e4b17023SJohn Marino case MODIFY_EXPR:
7163e4b17023SJohn Marino case BIND_EXPR:
7164e4b17023SJohn Marino return integer_valued_real_p (TREE_OPERAND (t, 1));
7165e4b17023SJohn Marino
7166e4b17023SJohn Marino case PLUS_EXPR:
7167e4b17023SJohn Marino case MINUS_EXPR:
7168e4b17023SJohn Marino case MULT_EXPR:
7169e4b17023SJohn Marino case MIN_EXPR:
7170e4b17023SJohn Marino case MAX_EXPR:
7171e4b17023SJohn Marino return integer_valued_real_p (TREE_OPERAND (t, 0))
7172e4b17023SJohn Marino && integer_valued_real_p (TREE_OPERAND (t, 1));
7173e4b17023SJohn Marino
7174e4b17023SJohn Marino case COND_EXPR:
7175e4b17023SJohn Marino return integer_valued_real_p (TREE_OPERAND (t, 1))
7176e4b17023SJohn Marino && integer_valued_real_p (TREE_OPERAND (t, 2));
7177e4b17023SJohn Marino
7178e4b17023SJohn Marino case REAL_CST:
7179e4b17023SJohn Marino return real_isinteger (TREE_REAL_CST_PTR (t), TYPE_MODE (TREE_TYPE (t)));
7180e4b17023SJohn Marino
7181e4b17023SJohn Marino case NOP_EXPR:
7182e4b17023SJohn Marino {
7183e4b17023SJohn Marino tree type = TREE_TYPE (TREE_OPERAND (t, 0));
7184e4b17023SJohn Marino if (TREE_CODE (type) == INTEGER_TYPE)
7185e4b17023SJohn Marino return true;
7186e4b17023SJohn Marino if (TREE_CODE (type) == REAL_TYPE)
7187e4b17023SJohn Marino return integer_valued_real_p (TREE_OPERAND (t, 0));
7188e4b17023SJohn Marino break;
7189e4b17023SJohn Marino }
7190e4b17023SJohn Marino
7191e4b17023SJohn Marino case CALL_EXPR:
7192e4b17023SJohn Marino switch (builtin_mathfn_code (t))
7193e4b17023SJohn Marino {
7194e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CEIL):
7195e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FLOOR):
7196e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_NEARBYINT):
7197e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_RINT):
7198e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ROUND):
7199e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_TRUNC):
7200e4b17023SJohn Marino return true;
7201e4b17023SJohn Marino
7202e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FMIN):
7203e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FMAX):
7204e4b17023SJohn Marino return integer_valued_real_p (CALL_EXPR_ARG (t, 0))
7205e4b17023SJohn Marino && integer_valued_real_p (CALL_EXPR_ARG (t, 1));
7206e4b17023SJohn Marino
7207e4b17023SJohn Marino default:
7208e4b17023SJohn Marino break;
7209e4b17023SJohn Marino }
7210e4b17023SJohn Marino break;
7211e4b17023SJohn Marino
7212e4b17023SJohn Marino default:
7213e4b17023SJohn Marino break;
7214e4b17023SJohn Marino }
7215e4b17023SJohn Marino return false;
7216e4b17023SJohn Marino }
7217e4b17023SJohn Marino
7218e4b17023SJohn Marino /* FNDECL is assumed to be a builtin where truncation can be propagated
7219e4b17023SJohn Marino across (for instance floor((double)f) == (double)floorf (f).
7220e4b17023SJohn Marino Do the transformation for a call with argument ARG. */
7221e4b17023SJohn Marino
7222e4b17023SJohn Marino static tree
fold_trunc_transparent_mathfn(location_t loc,tree fndecl,tree arg)7223e4b17023SJohn Marino fold_trunc_transparent_mathfn (location_t loc, tree fndecl, tree arg)
7224e4b17023SJohn Marino {
7225e4b17023SJohn Marino enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
7226e4b17023SJohn Marino
7227e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
7228e4b17023SJohn Marino return NULL_TREE;
7229e4b17023SJohn Marino
7230e4b17023SJohn Marino /* Integer rounding functions are idempotent. */
7231e4b17023SJohn Marino if (fcode == builtin_mathfn_code (arg))
7232e4b17023SJohn Marino return arg;
7233e4b17023SJohn Marino
7234e4b17023SJohn Marino /* If argument is already integer valued, and we don't need to worry
7235e4b17023SJohn Marino about setting errno, there's no need to perform rounding. */
7236e4b17023SJohn Marino if (! flag_errno_math && integer_valued_real_p (arg))
7237e4b17023SJohn Marino return arg;
7238e4b17023SJohn Marino
7239e4b17023SJohn Marino if (optimize)
7240e4b17023SJohn Marino {
7241e4b17023SJohn Marino tree arg0 = strip_float_extensions (arg);
7242e4b17023SJohn Marino tree ftype = TREE_TYPE (TREE_TYPE (fndecl));
7243e4b17023SJohn Marino tree newtype = TREE_TYPE (arg0);
7244e4b17023SJohn Marino tree decl;
7245e4b17023SJohn Marino
7246e4b17023SJohn Marino if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype)
7247e4b17023SJohn Marino && (decl = mathfn_built_in (newtype, fcode)))
7248e4b17023SJohn Marino return fold_convert_loc (loc, ftype,
7249e4b17023SJohn Marino build_call_expr_loc (loc, decl, 1,
7250e4b17023SJohn Marino fold_convert_loc (loc,
7251e4b17023SJohn Marino newtype,
7252e4b17023SJohn Marino arg0)));
7253e4b17023SJohn Marino }
7254e4b17023SJohn Marino return NULL_TREE;
7255e4b17023SJohn Marino }
7256e4b17023SJohn Marino
7257e4b17023SJohn Marino /* FNDECL is assumed to be builtin which can narrow the FP type of
7258e4b17023SJohn Marino the argument, for instance lround((double)f) -> lroundf (f).
7259e4b17023SJohn Marino Do the transformation for a call with argument ARG. */
7260e4b17023SJohn Marino
7261e4b17023SJohn Marino static tree
fold_fixed_mathfn(location_t loc,tree fndecl,tree arg)7262e4b17023SJohn Marino fold_fixed_mathfn (location_t loc, tree fndecl, tree arg)
7263e4b17023SJohn Marino {
7264e4b17023SJohn Marino enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
7265e4b17023SJohn Marino
7266e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
7267e4b17023SJohn Marino return NULL_TREE;
7268e4b17023SJohn Marino
7269e4b17023SJohn Marino /* If argument is already integer valued, and we don't need to worry
7270e4b17023SJohn Marino about setting errno, there's no need to perform rounding. */
7271e4b17023SJohn Marino if (! flag_errno_math && integer_valued_real_p (arg))
7272e4b17023SJohn Marino return fold_build1_loc (loc, FIX_TRUNC_EXPR,
7273e4b17023SJohn Marino TREE_TYPE (TREE_TYPE (fndecl)), arg);
7274e4b17023SJohn Marino
7275e4b17023SJohn Marino if (optimize)
7276e4b17023SJohn Marino {
7277e4b17023SJohn Marino tree ftype = TREE_TYPE (arg);
7278e4b17023SJohn Marino tree arg0 = strip_float_extensions (arg);
7279e4b17023SJohn Marino tree newtype = TREE_TYPE (arg0);
7280e4b17023SJohn Marino tree decl;
7281e4b17023SJohn Marino
7282e4b17023SJohn Marino if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype)
7283e4b17023SJohn Marino && (decl = mathfn_built_in (newtype, fcode)))
7284e4b17023SJohn Marino return build_call_expr_loc (loc, decl, 1,
7285e4b17023SJohn Marino fold_convert_loc (loc, newtype, arg0));
7286e4b17023SJohn Marino }
7287e4b17023SJohn Marino
7288e4b17023SJohn Marino /* Canonicalize iround (x) to lround (x) on ILP32 targets where
7289e4b17023SJohn Marino sizeof (int) == sizeof (long). */
7290e4b17023SJohn Marino if (TYPE_PRECISION (integer_type_node)
7291e4b17023SJohn Marino == TYPE_PRECISION (long_integer_type_node))
7292e4b17023SJohn Marino {
7293e4b17023SJohn Marino tree newfn = NULL_TREE;
7294e4b17023SJohn Marino switch (fcode)
7295e4b17023SJohn Marino {
7296e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ICEIL):
7297e4b17023SJohn Marino newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LCEIL);
7298e4b17023SJohn Marino break;
7299e4b17023SJohn Marino
7300e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IFLOOR):
7301e4b17023SJohn Marino newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LFLOOR);
7302e4b17023SJohn Marino break;
7303e4b17023SJohn Marino
7304e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IROUND):
7305e4b17023SJohn Marino newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LROUND);
7306e4b17023SJohn Marino break;
7307e4b17023SJohn Marino
7308e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IRINT):
7309e4b17023SJohn Marino newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LRINT);
7310e4b17023SJohn Marino break;
7311e4b17023SJohn Marino
7312e4b17023SJohn Marino default:
7313e4b17023SJohn Marino break;
7314e4b17023SJohn Marino }
7315e4b17023SJohn Marino
7316e4b17023SJohn Marino if (newfn)
7317e4b17023SJohn Marino {
7318e4b17023SJohn Marino tree newcall = build_call_expr_loc (loc, newfn, 1, arg);
7319e4b17023SJohn Marino return fold_convert_loc (loc,
7320e4b17023SJohn Marino TREE_TYPE (TREE_TYPE (fndecl)), newcall);
7321e4b17023SJohn Marino }
7322e4b17023SJohn Marino }
7323e4b17023SJohn Marino
7324e4b17023SJohn Marino /* Canonicalize llround (x) to lround (x) on LP64 targets where
7325e4b17023SJohn Marino sizeof (long long) == sizeof (long). */
7326e4b17023SJohn Marino if (TYPE_PRECISION (long_long_integer_type_node)
7327e4b17023SJohn Marino == TYPE_PRECISION (long_integer_type_node))
7328e4b17023SJohn Marino {
7329e4b17023SJohn Marino tree newfn = NULL_TREE;
7330e4b17023SJohn Marino switch (fcode)
7331e4b17023SJohn Marino {
7332e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLCEIL):
7333e4b17023SJohn Marino newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LCEIL);
7334e4b17023SJohn Marino break;
7335e4b17023SJohn Marino
7336e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLFLOOR):
7337e4b17023SJohn Marino newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LFLOOR);
7338e4b17023SJohn Marino break;
7339e4b17023SJohn Marino
7340e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLROUND):
7341e4b17023SJohn Marino newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LROUND);
7342e4b17023SJohn Marino break;
7343e4b17023SJohn Marino
7344e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLRINT):
7345e4b17023SJohn Marino newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LRINT);
7346e4b17023SJohn Marino break;
7347e4b17023SJohn Marino
7348e4b17023SJohn Marino default:
7349e4b17023SJohn Marino break;
7350e4b17023SJohn Marino }
7351e4b17023SJohn Marino
7352e4b17023SJohn Marino if (newfn)
7353e4b17023SJohn Marino {
7354e4b17023SJohn Marino tree newcall = build_call_expr_loc (loc, newfn, 1, arg);
7355e4b17023SJohn Marino return fold_convert_loc (loc,
7356e4b17023SJohn Marino TREE_TYPE (TREE_TYPE (fndecl)), newcall);
7357e4b17023SJohn Marino }
7358e4b17023SJohn Marino }
7359e4b17023SJohn Marino
7360e4b17023SJohn Marino return NULL_TREE;
7361e4b17023SJohn Marino }
7362e4b17023SJohn Marino
7363e4b17023SJohn Marino /* Fold call to builtin cabs, cabsf or cabsl with argument ARG. TYPE is the
7364e4b17023SJohn Marino return type. Return NULL_TREE if no simplification can be made. */
7365e4b17023SJohn Marino
7366e4b17023SJohn Marino static tree
fold_builtin_cabs(location_t loc,tree arg,tree type,tree fndecl)7367e4b17023SJohn Marino fold_builtin_cabs (location_t loc, tree arg, tree type, tree fndecl)
7368e4b17023SJohn Marino {
7369e4b17023SJohn Marino tree res;
7370e4b17023SJohn Marino
7371e4b17023SJohn Marino if (!validate_arg (arg, COMPLEX_TYPE)
7372e4b17023SJohn Marino || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
7373e4b17023SJohn Marino return NULL_TREE;
7374e4b17023SJohn Marino
7375e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
7376e4b17023SJohn Marino if (TREE_CODE (arg) == COMPLEX_CST
7377e4b17023SJohn Marino && (res = do_mpfr_arg2 (TREE_REALPART (arg), TREE_IMAGPART (arg),
7378e4b17023SJohn Marino type, mpfr_hypot)))
7379e4b17023SJohn Marino return res;
7380e4b17023SJohn Marino
7381e4b17023SJohn Marino if (TREE_CODE (arg) == COMPLEX_EXPR)
7382e4b17023SJohn Marino {
7383e4b17023SJohn Marino tree real = TREE_OPERAND (arg, 0);
7384e4b17023SJohn Marino tree imag = TREE_OPERAND (arg, 1);
7385e4b17023SJohn Marino
7386e4b17023SJohn Marino /* If either part is zero, cabs is fabs of the other. */
7387e4b17023SJohn Marino if (real_zerop (real))
7388e4b17023SJohn Marino return fold_build1_loc (loc, ABS_EXPR, type, imag);
7389e4b17023SJohn Marino if (real_zerop (imag))
7390e4b17023SJohn Marino return fold_build1_loc (loc, ABS_EXPR, type, real);
7391e4b17023SJohn Marino
7392e4b17023SJohn Marino /* cabs(x+xi) -> fabs(x)*sqrt(2). */
7393e4b17023SJohn Marino if (flag_unsafe_math_optimizations
7394e4b17023SJohn Marino && operand_equal_p (real, imag, OEP_PURE_SAME))
7395e4b17023SJohn Marino {
7396e4b17023SJohn Marino const REAL_VALUE_TYPE sqrt2_trunc
7397e4b17023SJohn Marino = real_value_truncate (TYPE_MODE (type), dconst_sqrt2 ());
7398e4b17023SJohn Marino STRIP_NOPS (real);
7399e4b17023SJohn Marino return fold_build2_loc (loc, MULT_EXPR, type,
7400e4b17023SJohn Marino fold_build1_loc (loc, ABS_EXPR, type, real),
7401e4b17023SJohn Marino build_real (type, sqrt2_trunc));
7402e4b17023SJohn Marino }
7403e4b17023SJohn Marino }
7404e4b17023SJohn Marino
7405e4b17023SJohn Marino /* Optimize cabs(-z) and cabs(conj(z)) as cabs(z). */
7406e4b17023SJohn Marino if (TREE_CODE (arg) == NEGATE_EXPR
7407e4b17023SJohn Marino || TREE_CODE (arg) == CONJ_EXPR)
7408e4b17023SJohn Marino return build_call_expr_loc (loc, fndecl, 1, TREE_OPERAND (arg, 0));
7409e4b17023SJohn Marino
7410e4b17023SJohn Marino /* Don't do this when optimizing for size. */
7411e4b17023SJohn Marino if (flag_unsafe_math_optimizations
7412e4b17023SJohn Marino && optimize && optimize_function_for_speed_p (cfun))
7413e4b17023SJohn Marino {
7414e4b17023SJohn Marino tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
7415e4b17023SJohn Marino
7416e4b17023SJohn Marino if (sqrtfn != NULL_TREE)
7417e4b17023SJohn Marino {
7418e4b17023SJohn Marino tree rpart, ipart, result;
7419e4b17023SJohn Marino
7420e4b17023SJohn Marino arg = builtin_save_expr (arg);
7421e4b17023SJohn Marino
7422e4b17023SJohn Marino rpart = fold_build1_loc (loc, REALPART_EXPR, type, arg);
7423e4b17023SJohn Marino ipart = fold_build1_loc (loc, IMAGPART_EXPR, type, arg);
7424e4b17023SJohn Marino
7425e4b17023SJohn Marino rpart = builtin_save_expr (rpart);
7426e4b17023SJohn Marino ipart = builtin_save_expr (ipart);
7427e4b17023SJohn Marino
7428e4b17023SJohn Marino result = fold_build2_loc (loc, PLUS_EXPR, type,
7429e4b17023SJohn Marino fold_build2_loc (loc, MULT_EXPR, type,
7430e4b17023SJohn Marino rpart, rpart),
7431e4b17023SJohn Marino fold_build2_loc (loc, MULT_EXPR, type,
7432e4b17023SJohn Marino ipart, ipart));
7433e4b17023SJohn Marino
7434e4b17023SJohn Marino return build_call_expr_loc (loc, sqrtfn, 1, result);
7435e4b17023SJohn Marino }
7436e4b17023SJohn Marino }
7437e4b17023SJohn Marino
7438e4b17023SJohn Marino return NULL_TREE;
7439e4b17023SJohn Marino }
7440e4b17023SJohn Marino
7441e4b17023SJohn Marino /* Build a complex (inf +- 0i) for the result of cproj. TYPE is the
7442e4b17023SJohn Marino complex tree type of the result. If NEG is true, the imaginary
7443e4b17023SJohn Marino zero is negative. */
7444e4b17023SJohn Marino
7445e4b17023SJohn Marino static tree
build_complex_cproj(tree type,bool neg)7446e4b17023SJohn Marino build_complex_cproj (tree type, bool neg)
7447e4b17023SJohn Marino {
7448e4b17023SJohn Marino REAL_VALUE_TYPE rinf, rzero = dconst0;
7449e4b17023SJohn Marino
7450e4b17023SJohn Marino real_inf (&rinf);
7451e4b17023SJohn Marino rzero.sign = neg;
7452e4b17023SJohn Marino return build_complex (type, build_real (TREE_TYPE (type), rinf),
7453e4b17023SJohn Marino build_real (TREE_TYPE (type), rzero));
7454e4b17023SJohn Marino }
7455e4b17023SJohn Marino
7456e4b17023SJohn Marino /* Fold call to builtin cproj, cprojf or cprojl with argument ARG. TYPE is the
7457e4b17023SJohn Marino return type. Return NULL_TREE if no simplification can be made. */
7458e4b17023SJohn Marino
7459e4b17023SJohn Marino static tree
fold_builtin_cproj(location_t loc,tree arg,tree type)7460e4b17023SJohn Marino fold_builtin_cproj (location_t loc, tree arg, tree type)
7461e4b17023SJohn Marino {
7462e4b17023SJohn Marino if (!validate_arg (arg, COMPLEX_TYPE)
7463e4b17023SJohn Marino || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
7464e4b17023SJohn Marino return NULL_TREE;
7465e4b17023SJohn Marino
7466e4b17023SJohn Marino /* If there are no infinities, return arg. */
7467e4b17023SJohn Marino if (! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (type))))
7468e4b17023SJohn Marino return non_lvalue_loc (loc, arg);
7469e4b17023SJohn Marino
7470e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
7471e4b17023SJohn Marino if (TREE_CODE (arg) == COMPLEX_CST)
7472e4b17023SJohn Marino {
7473e4b17023SJohn Marino const REAL_VALUE_TYPE *real = TREE_REAL_CST_PTR (TREE_REALPART (arg));
7474e4b17023SJohn Marino const REAL_VALUE_TYPE *imag = TREE_REAL_CST_PTR (TREE_IMAGPART (arg));
7475e4b17023SJohn Marino
7476e4b17023SJohn Marino if (real_isinf (real) || real_isinf (imag))
7477e4b17023SJohn Marino return build_complex_cproj (type, imag->sign);
7478e4b17023SJohn Marino else
7479e4b17023SJohn Marino return arg;
7480e4b17023SJohn Marino }
7481e4b17023SJohn Marino else if (TREE_CODE (arg) == COMPLEX_EXPR)
7482e4b17023SJohn Marino {
7483e4b17023SJohn Marino tree real = TREE_OPERAND (arg, 0);
7484e4b17023SJohn Marino tree imag = TREE_OPERAND (arg, 1);
7485e4b17023SJohn Marino
7486e4b17023SJohn Marino STRIP_NOPS (real);
7487e4b17023SJohn Marino STRIP_NOPS (imag);
7488e4b17023SJohn Marino
7489e4b17023SJohn Marino /* If the real part is inf and the imag part is known to be
7490e4b17023SJohn Marino nonnegative, return (inf + 0i). Remember side-effects are
7491e4b17023SJohn Marino possible in the imag part. */
7492e4b17023SJohn Marino if (TREE_CODE (real) == REAL_CST
7493e4b17023SJohn Marino && real_isinf (TREE_REAL_CST_PTR (real))
7494e4b17023SJohn Marino && tree_expr_nonnegative_p (imag))
7495e4b17023SJohn Marino return omit_one_operand_loc (loc, type,
7496e4b17023SJohn Marino build_complex_cproj (type, false),
7497e4b17023SJohn Marino arg);
7498e4b17023SJohn Marino
7499e4b17023SJohn Marino /* If the imag part is inf, return (inf+I*copysign(0,imag)).
7500e4b17023SJohn Marino Remember side-effects are possible in the real part. */
7501e4b17023SJohn Marino if (TREE_CODE (imag) == REAL_CST
7502e4b17023SJohn Marino && real_isinf (TREE_REAL_CST_PTR (imag)))
7503e4b17023SJohn Marino return
7504e4b17023SJohn Marino omit_one_operand_loc (loc, type,
7505e4b17023SJohn Marino build_complex_cproj (type, TREE_REAL_CST_PTR
7506e4b17023SJohn Marino (imag)->sign), arg);
7507e4b17023SJohn Marino }
7508e4b17023SJohn Marino
7509e4b17023SJohn Marino return NULL_TREE;
7510e4b17023SJohn Marino }
7511e4b17023SJohn Marino
7512e4b17023SJohn Marino /* Fold a builtin function call to sqrt, sqrtf, or sqrtl with argument ARG.
7513e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
7514e4b17023SJohn Marino
7515e4b17023SJohn Marino static tree
fold_builtin_sqrt(location_t loc,tree arg,tree type)7516e4b17023SJohn Marino fold_builtin_sqrt (location_t loc, tree arg, tree type)
7517e4b17023SJohn Marino {
7518e4b17023SJohn Marino
7519e4b17023SJohn Marino enum built_in_function fcode;
7520e4b17023SJohn Marino tree res;
7521e4b17023SJohn Marino
7522e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
7523e4b17023SJohn Marino return NULL_TREE;
7524e4b17023SJohn Marino
7525e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
7526e4b17023SJohn Marino if ((res = do_mpfr_arg1 (arg, type, mpfr_sqrt, &dconst0, NULL, true)))
7527e4b17023SJohn Marino return res;
7528e4b17023SJohn Marino
7529e4b17023SJohn Marino /* Optimize sqrt(expN(x)) = expN(x*0.5). */
7530e4b17023SJohn Marino fcode = builtin_mathfn_code (arg);
7531e4b17023SJohn Marino if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
7532e4b17023SJohn Marino {
7533e4b17023SJohn Marino tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0);
7534e4b17023SJohn Marino arg = fold_build2_loc (loc, MULT_EXPR, type,
7535e4b17023SJohn Marino CALL_EXPR_ARG (arg, 0),
7536e4b17023SJohn Marino build_real (type, dconsthalf));
7537e4b17023SJohn Marino return build_call_expr_loc (loc, expfn, 1, arg);
7538e4b17023SJohn Marino }
7539e4b17023SJohn Marino
7540e4b17023SJohn Marino /* Optimize sqrt(Nroot(x)) -> pow(x,1/(2*N)). */
7541e4b17023SJohn Marino if (flag_unsafe_math_optimizations && BUILTIN_ROOT_P (fcode))
7542e4b17023SJohn Marino {
7543e4b17023SJohn Marino tree powfn = mathfn_built_in (type, BUILT_IN_POW);
7544e4b17023SJohn Marino
7545e4b17023SJohn Marino if (powfn)
7546e4b17023SJohn Marino {
7547e4b17023SJohn Marino tree arg0 = CALL_EXPR_ARG (arg, 0);
7548e4b17023SJohn Marino tree tree_root;
7549e4b17023SJohn Marino /* The inner root was either sqrt or cbrt. */
7550e4b17023SJohn Marino /* This was a conditional expression but it triggered a bug
7551e4b17023SJohn Marino in Sun C 5.5. */
7552e4b17023SJohn Marino REAL_VALUE_TYPE dconstroot;
7553e4b17023SJohn Marino if (BUILTIN_SQRT_P (fcode))
7554e4b17023SJohn Marino dconstroot = dconsthalf;
7555e4b17023SJohn Marino else
7556e4b17023SJohn Marino dconstroot = dconst_third ();
7557e4b17023SJohn Marino
7558e4b17023SJohn Marino /* Adjust for the outer root. */
7559e4b17023SJohn Marino SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
7560e4b17023SJohn Marino dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
7561e4b17023SJohn Marino tree_root = build_real (type, dconstroot);
7562e4b17023SJohn Marino return build_call_expr_loc (loc, powfn, 2, arg0, tree_root);
7563e4b17023SJohn Marino }
7564e4b17023SJohn Marino }
7565e4b17023SJohn Marino
7566e4b17023SJohn Marino /* Optimize sqrt(pow(x,y)) = pow(|x|,y*0.5). */
7567e4b17023SJohn Marino if (flag_unsafe_math_optimizations
7568e4b17023SJohn Marino && (fcode == BUILT_IN_POW
7569e4b17023SJohn Marino || fcode == BUILT_IN_POWF
7570e4b17023SJohn Marino || fcode == BUILT_IN_POWL))
7571e4b17023SJohn Marino {
7572e4b17023SJohn Marino tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0);
7573e4b17023SJohn Marino tree arg0 = CALL_EXPR_ARG (arg, 0);
7574e4b17023SJohn Marino tree arg1 = CALL_EXPR_ARG (arg, 1);
7575e4b17023SJohn Marino tree narg1;
7576e4b17023SJohn Marino if (!tree_expr_nonnegative_p (arg0))
7577e4b17023SJohn Marino arg0 = build1 (ABS_EXPR, type, arg0);
7578e4b17023SJohn Marino narg1 = fold_build2_loc (loc, MULT_EXPR, type, arg1,
7579e4b17023SJohn Marino build_real (type, dconsthalf));
7580e4b17023SJohn Marino return build_call_expr_loc (loc, powfn, 2, arg0, narg1);
7581e4b17023SJohn Marino }
7582e4b17023SJohn Marino
7583e4b17023SJohn Marino return NULL_TREE;
7584e4b17023SJohn Marino }
7585e4b17023SJohn Marino
7586e4b17023SJohn Marino /* Fold a builtin function call to cbrt, cbrtf, or cbrtl with argument ARG.
7587e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
7588e4b17023SJohn Marino
7589e4b17023SJohn Marino static tree
fold_builtin_cbrt(location_t loc,tree arg,tree type)7590e4b17023SJohn Marino fold_builtin_cbrt (location_t loc, tree arg, tree type)
7591e4b17023SJohn Marino {
7592e4b17023SJohn Marino const enum built_in_function fcode = builtin_mathfn_code (arg);
7593e4b17023SJohn Marino tree res;
7594e4b17023SJohn Marino
7595e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
7596e4b17023SJohn Marino return NULL_TREE;
7597e4b17023SJohn Marino
7598e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
7599e4b17023SJohn Marino if ((res = do_mpfr_arg1 (arg, type, mpfr_cbrt, NULL, NULL, 0)))
7600e4b17023SJohn Marino return res;
7601e4b17023SJohn Marino
7602e4b17023SJohn Marino if (flag_unsafe_math_optimizations)
7603e4b17023SJohn Marino {
7604e4b17023SJohn Marino /* Optimize cbrt(expN(x)) -> expN(x/3). */
7605e4b17023SJohn Marino if (BUILTIN_EXPONENT_P (fcode))
7606e4b17023SJohn Marino {
7607e4b17023SJohn Marino tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0);
7608e4b17023SJohn Marino const REAL_VALUE_TYPE third_trunc =
7609e4b17023SJohn Marino real_value_truncate (TYPE_MODE (type), dconst_third ());
7610e4b17023SJohn Marino arg = fold_build2_loc (loc, MULT_EXPR, type,
7611e4b17023SJohn Marino CALL_EXPR_ARG (arg, 0),
7612e4b17023SJohn Marino build_real (type, third_trunc));
7613e4b17023SJohn Marino return build_call_expr_loc (loc, expfn, 1, arg);
7614e4b17023SJohn Marino }
7615e4b17023SJohn Marino
7616e4b17023SJohn Marino /* Optimize cbrt(sqrt(x)) -> pow(x,1/6). */
7617e4b17023SJohn Marino if (BUILTIN_SQRT_P (fcode))
7618e4b17023SJohn Marino {
7619e4b17023SJohn Marino tree powfn = mathfn_built_in (type, BUILT_IN_POW);
7620e4b17023SJohn Marino
7621e4b17023SJohn Marino if (powfn)
7622e4b17023SJohn Marino {
7623e4b17023SJohn Marino tree arg0 = CALL_EXPR_ARG (arg, 0);
7624e4b17023SJohn Marino tree tree_root;
7625e4b17023SJohn Marino REAL_VALUE_TYPE dconstroot = dconst_third ();
7626e4b17023SJohn Marino
7627e4b17023SJohn Marino SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
7628e4b17023SJohn Marino dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
7629e4b17023SJohn Marino tree_root = build_real (type, dconstroot);
7630e4b17023SJohn Marino return build_call_expr_loc (loc, powfn, 2, arg0, tree_root);
7631e4b17023SJohn Marino }
7632e4b17023SJohn Marino }
7633e4b17023SJohn Marino
7634e4b17023SJohn Marino /* Optimize cbrt(cbrt(x)) -> pow(x,1/9) iff x is nonnegative. */
7635e4b17023SJohn Marino if (BUILTIN_CBRT_P (fcode))
7636e4b17023SJohn Marino {
7637e4b17023SJohn Marino tree arg0 = CALL_EXPR_ARG (arg, 0);
7638e4b17023SJohn Marino if (tree_expr_nonnegative_p (arg0))
7639e4b17023SJohn Marino {
7640e4b17023SJohn Marino tree powfn = mathfn_built_in (type, BUILT_IN_POW);
7641e4b17023SJohn Marino
7642e4b17023SJohn Marino if (powfn)
7643e4b17023SJohn Marino {
7644e4b17023SJohn Marino tree tree_root;
7645e4b17023SJohn Marino REAL_VALUE_TYPE dconstroot;
7646e4b17023SJohn Marino
7647e4b17023SJohn Marino real_arithmetic (&dconstroot, MULT_EXPR,
7648e4b17023SJohn Marino dconst_third_ptr (), dconst_third_ptr ());
7649e4b17023SJohn Marino dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
7650e4b17023SJohn Marino tree_root = build_real (type, dconstroot);
7651e4b17023SJohn Marino return build_call_expr_loc (loc, powfn, 2, arg0, tree_root);
7652e4b17023SJohn Marino }
7653e4b17023SJohn Marino }
7654e4b17023SJohn Marino }
7655e4b17023SJohn Marino
7656e4b17023SJohn Marino /* Optimize cbrt(pow(x,y)) -> pow(x,y/3) iff x is nonnegative. */
7657e4b17023SJohn Marino if (fcode == BUILT_IN_POW
7658e4b17023SJohn Marino || fcode == BUILT_IN_POWF
7659e4b17023SJohn Marino || fcode == BUILT_IN_POWL)
7660e4b17023SJohn Marino {
7661e4b17023SJohn Marino tree arg00 = CALL_EXPR_ARG (arg, 0);
7662e4b17023SJohn Marino tree arg01 = CALL_EXPR_ARG (arg, 1);
7663e4b17023SJohn Marino if (tree_expr_nonnegative_p (arg00))
7664e4b17023SJohn Marino {
7665e4b17023SJohn Marino tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0);
7666e4b17023SJohn Marino const REAL_VALUE_TYPE dconstroot
7667e4b17023SJohn Marino = real_value_truncate (TYPE_MODE (type), dconst_third ());
7668e4b17023SJohn Marino tree narg01 = fold_build2_loc (loc, MULT_EXPR, type, arg01,
7669e4b17023SJohn Marino build_real (type, dconstroot));
7670e4b17023SJohn Marino return build_call_expr_loc (loc, powfn, 2, arg00, narg01);
7671e4b17023SJohn Marino }
7672e4b17023SJohn Marino }
7673e4b17023SJohn Marino }
7674e4b17023SJohn Marino return NULL_TREE;
7675e4b17023SJohn Marino }
7676e4b17023SJohn Marino
7677e4b17023SJohn Marino /* Fold function call to builtin cos, cosf, or cosl with argument ARG.
7678e4b17023SJohn Marino TYPE is the type of the return value. Return NULL_TREE if no
7679e4b17023SJohn Marino simplification can be made. */
7680e4b17023SJohn Marino
7681e4b17023SJohn Marino static tree
fold_builtin_cos(location_t loc,tree arg,tree type,tree fndecl)7682e4b17023SJohn Marino fold_builtin_cos (location_t loc,
7683e4b17023SJohn Marino tree arg, tree type, tree fndecl)
7684e4b17023SJohn Marino {
7685e4b17023SJohn Marino tree res, narg;
7686e4b17023SJohn Marino
7687e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
7688e4b17023SJohn Marino return NULL_TREE;
7689e4b17023SJohn Marino
7690e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
7691e4b17023SJohn Marino if ((res = do_mpfr_arg1 (arg, type, mpfr_cos, NULL, NULL, 0)))
7692e4b17023SJohn Marino return res;
7693e4b17023SJohn Marino
7694e4b17023SJohn Marino /* Optimize cos(-x) into cos (x). */
7695e4b17023SJohn Marino if ((narg = fold_strip_sign_ops (arg)))
7696e4b17023SJohn Marino return build_call_expr_loc (loc, fndecl, 1, narg);
7697e4b17023SJohn Marino
7698e4b17023SJohn Marino return NULL_TREE;
7699e4b17023SJohn Marino }
7700e4b17023SJohn Marino
7701e4b17023SJohn Marino /* Fold function call to builtin cosh, coshf, or coshl with argument ARG.
7702e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
7703e4b17023SJohn Marino
7704e4b17023SJohn Marino static tree
fold_builtin_cosh(location_t loc,tree arg,tree type,tree fndecl)7705e4b17023SJohn Marino fold_builtin_cosh (location_t loc, tree arg, tree type, tree fndecl)
7706e4b17023SJohn Marino {
7707e4b17023SJohn Marino if (validate_arg (arg, REAL_TYPE))
7708e4b17023SJohn Marino {
7709e4b17023SJohn Marino tree res, narg;
7710e4b17023SJohn Marino
7711e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
7712e4b17023SJohn Marino if ((res = do_mpfr_arg1 (arg, type, mpfr_cosh, NULL, NULL, 0)))
7713e4b17023SJohn Marino return res;
7714e4b17023SJohn Marino
7715e4b17023SJohn Marino /* Optimize cosh(-x) into cosh (x). */
7716e4b17023SJohn Marino if ((narg = fold_strip_sign_ops (arg)))
7717e4b17023SJohn Marino return build_call_expr_loc (loc, fndecl, 1, narg);
7718e4b17023SJohn Marino }
7719e4b17023SJohn Marino
7720e4b17023SJohn Marino return NULL_TREE;
7721e4b17023SJohn Marino }
7722e4b17023SJohn Marino
7723e4b17023SJohn Marino /* Fold function call to builtin ccos (or ccosh if HYPER is TRUE) with
7724e4b17023SJohn Marino argument ARG. TYPE is the type of the return value. Return
7725e4b17023SJohn Marino NULL_TREE if no simplification can be made. */
7726e4b17023SJohn Marino
7727e4b17023SJohn Marino static tree
fold_builtin_ccos(location_t loc,tree arg,tree type,tree fndecl,bool hyper)7728e4b17023SJohn Marino fold_builtin_ccos (location_t loc, tree arg, tree type, tree fndecl,
7729e4b17023SJohn Marino bool hyper)
7730e4b17023SJohn Marino {
7731e4b17023SJohn Marino if (validate_arg (arg, COMPLEX_TYPE)
7732e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE)
7733e4b17023SJohn Marino {
7734e4b17023SJohn Marino tree tmp;
7735e4b17023SJohn Marino
7736e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
7737e4b17023SJohn Marino if ((tmp = do_mpc_arg1 (arg, type, (hyper ? mpc_cosh : mpc_cos))))
7738e4b17023SJohn Marino return tmp;
7739e4b17023SJohn Marino
7740e4b17023SJohn Marino /* Optimize fn(-x) into fn(x). */
7741e4b17023SJohn Marino if ((tmp = fold_strip_sign_ops (arg)))
7742e4b17023SJohn Marino return build_call_expr_loc (loc, fndecl, 1, tmp);
7743e4b17023SJohn Marino }
7744e4b17023SJohn Marino
7745e4b17023SJohn Marino return NULL_TREE;
7746e4b17023SJohn Marino }
7747e4b17023SJohn Marino
7748e4b17023SJohn Marino /* Fold function call to builtin tan, tanf, or tanl with argument ARG.
7749e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
7750e4b17023SJohn Marino
7751e4b17023SJohn Marino static tree
fold_builtin_tan(tree arg,tree type)7752e4b17023SJohn Marino fold_builtin_tan (tree arg, tree type)
7753e4b17023SJohn Marino {
7754e4b17023SJohn Marino enum built_in_function fcode;
7755e4b17023SJohn Marino tree res;
7756e4b17023SJohn Marino
7757e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
7758e4b17023SJohn Marino return NULL_TREE;
7759e4b17023SJohn Marino
7760e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
7761e4b17023SJohn Marino if ((res = do_mpfr_arg1 (arg, type, mpfr_tan, NULL, NULL, 0)))
7762e4b17023SJohn Marino return res;
7763e4b17023SJohn Marino
7764e4b17023SJohn Marino /* Optimize tan(atan(x)) = x. */
7765e4b17023SJohn Marino fcode = builtin_mathfn_code (arg);
7766e4b17023SJohn Marino if (flag_unsafe_math_optimizations
7767e4b17023SJohn Marino && (fcode == BUILT_IN_ATAN
7768e4b17023SJohn Marino || fcode == BUILT_IN_ATANF
7769e4b17023SJohn Marino || fcode == BUILT_IN_ATANL))
7770e4b17023SJohn Marino return CALL_EXPR_ARG (arg, 0);
7771e4b17023SJohn Marino
7772e4b17023SJohn Marino return NULL_TREE;
7773e4b17023SJohn Marino }
7774e4b17023SJohn Marino
7775e4b17023SJohn Marino /* Fold function call to builtin sincos, sincosf, or sincosl. Return
7776e4b17023SJohn Marino NULL_TREE if no simplification can be made. */
7777e4b17023SJohn Marino
7778e4b17023SJohn Marino static tree
fold_builtin_sincos(location_t loc,tree arg0,tree arg1,tree arg2)7779e4b17023SJohn Marino fold_builtin_sincos (location_t loc,
7780e4b17023SJohn Marino tree arg0, tree arg1, tree arg2)
7781e4b17023SJohn Marino {
7782e4b17023SJohn Marino tree type;
7783e4b17023SJohn Marino tree res, fn, call;
7784e4b17023SJohn Marino
7785e4b17023SJohn Marino if (!validate_arg (arg0, REAL_TYPE)
7786e4b17023SJohn Marino || !validate_arg (arg1, POINTER_TYPE)
7787e4b17023SJohn Marino || !validate_arg (arg2, POINTER_TYPE))
7788e4b17023SJohn Marino return NULL_TREE;
7789e4b17023SJohn Marino
7790e4b17023SJohn Marino type = TREE_TYPE (arg0);
7791e4b17023SJohn Marino
7792e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
7793e4b17023SJohn Marino if ((res = do_mpfr_sincos (arg0, arg1, arg2)))
7794e4b17023SJohn Marino return res;
7795e4b17023SJohn Marino
7796e4b17023SJohn Marino /* Canonicalize sincos to cexpi. */
7797e4b17023SJohn Marino if (!TARGET_C99_FUNCTIONS)
7798e4b17023SJohn Marino return NULL_TREE;
7799e4b17023SJohn Marino fn = mathfn_built_in (type, BUILT_IN_CEXPI);
7800e4b17023SJohn Marino if (!fn)
7801e4b17023SJohn Marino return NULL_TREE;
7802e4b17023SJohn Marino
7803e4b17023SJohn Marino call = build_call_expr_loc (loc, fn, 1, arg0);
7804e4b17023SJohn Marino call = builtin_save_expr (call);
7805e4b17023SJohn Marino
7806e4b17023SJohn Marino return build2 (COMPOUND_EXPR, void_type_node,
7807e4b17023SJohn Marino build2 (MODIFY_EXPR, void_type_node,
7808e4b17023SJohn Marino build_fold_indirect_ref_loc (loc, arg1),
7809e4b17023SJohn Marino build1 (IMAGPART_EXPR, type, call)),
7810e4b17023SJohn Marino build2 (MODIFY_EXPR, void_type_node,
7811e4b17023SJohn Marino build_fold_indirect_ref_loc (loc, arg2),
7812e4b17023SJohn Marino build1 (REALPART_EXPR, type, call)));
7813e4b17023SJohn Marino }
7814e4b17023SJohn Marino
7815e4b17023SJohn Marino /* Fold function call to builtin cexp, cexpf, or cexpl. Return
7816e4b17023SJohn Marino NULL_TREE if no simplification can be made. */
7817e4b17023SJohn Marino
7818e4b17023SJohn Marino static tree
fold_builtin_cexp(location_t loc,tree arg0,tree type)7819e4b17023SJohn Marino fold_builtin_cexp (location_t loc, tree arg0, tree type)
7820e4b17023SJohn Marino {
7821e4b17023SJohn Marino tree rtype;
7822e4b17023SJohn Marino tree realp, imagp, ifn;
7823e4b17023SJohn Marino tree res;
7824e4b17023SJohn Marino
7825e4b17023SJohn Marino if (!validate_arg (arg0, COMPLEX_TYPE)
7826e4b17023SJohn Marino || TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) != REAL_TYPE)
7827e4b17023SJohn Marino return NULL_TREE;
7828e4b17023SJohn Marino
7829e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
7830e4b17023SJohn Marino if ((res = do_mpc_arg1 (arg0, type, mpc_exp)))
7831e4b17023SJohn Marino return res;
7832e4b17023SJohn Marino
7833e4b17023SJohn Marino rtype = TREE_TYPE (TREE_TYPE (arg0));
7834e4b17023SJohn Marino
7835e4b17023SJohn Marino /* In case we can figure out the real part of arg0 and it is constant zero
7836e4b17023SJohn Marino fold to cexpi. */
7837e4b17023SJohn Marino if (!TARGET_C99_FUNCTIONS)
7838e4b17023SJohn Marino return NULL_TREE;
7839e4b17023SJohn Marino ifn = mathfn_built_in (rtype, BUILT_IN_CEXPI);
7840e4b17023SJohn Marino if (!ifn)
7841e4b17023SJohn Marino return NULL_TREE;
7842e4b17023SJohn Marino
7843e4b17023SJohn Marino if ((realp = fold_unary_loc (loc, REALPART_EXPR, rtype, arg0))
7844e4b17023SJohn Marino && real_zerop (realp))
7845e4b17023SJohn Marino {
7846e4b17023SJohn Marino tree narg = fold_build1_loc (loc, IMAGPART_EXPR, rtype, arg0);
7847e4b17023SJohn Marino return build_call_expr_loc (loc, ifn, 1, narg);
7848e4b17023SJohn Marino }
7849e4b17023SJohn Marino
7850e4b17023SJohn Marino /* In case we can easily decompose real and imaginary parts split cexp
7851e4b17023SJohn Marino to exp (r) * cexpi (i). */
7852e4b17023SJohn Marino if (flag_unsafe_math_optimizations
7853e4b17023SJohn Marino && realp)
7854e4b17023SJohn Marino {
7855e4b17023SJohn Marino tree rfn, rcall, icall;
7856e4b17023SJohn Marino
7857e4b17023SJohn Marino rfn = mathfn_built_in (rtype, BUILT_IN_EXP);
7858e4b17023SJohn Marino if (!rfn)
7859e4b17023SJohn Marino return NULL_TREE;
7860e4b17023SJohn Marino
7861e4b17023SJohn Marino imagp = fold_unary_loc (loc, IMAGPART_EXPR, rtype, arg0);
7862e4b17023SJohn Marino if (!imagp)
7863e4b17023SJohn Marino return NULL_TREE;
7864e4b17023SJohn Marino
7865e4b17023SJohn Marino icall = build_call_expr_loc (loc, ifn, 1, imagp);
7866e4b17023SJohn Marino icall = builtin_save_expr (icall);
7867e4b17023SJohn Marino rcall = build_call_expr_loc (loc, rfn, 1, realp);
7868e4b17023SJohn Marino rcall = builtin_save_expr (rcall);
7869e4b17023SJohn Marino return fold_build2_loc (loc, COMPLEX_EXPR, type,
7870e4b17023SJohn Marino fold_build2_loc (loc, MULT_EXPR, rtype,
7871e4b17023SJohn Marino rcall,
7872e4b17023SJohn Marino fold_build1_loc (loc, REALPART_EXPR,
7873e4b17023SJohn Marino rtype, icall)),
7874e4b17023SJohn Marino fold_build2_loc (loc, MULT_EXPR, rtype,
7875e4b17023SJohn Marino rcall,
7876e4b17023SJohn Marino fold_build1_loc (loc, IMAGPART_EXPR,
7877e4b17023SJohn Marino rtype, icall)));
7878e4b17023SJohn Marino }
7879e4b17023SJohn Marino
7880e4b17023SJohn Marino return NULL_TREE;
7881e4b17023SJohn Marino }
7882e4b17023SJohn Marino
7883e4b17023SJohn Marino /* Fold function call to builtin trunc, truncf or truncl with argument ARG.
7884e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
7885e4b17023SJohn Marino
7886e4b17023SJohn Marino static tree
fold_builtin_trunc(location_t loc,tree fndecl,tree arg)7887e4b17023SJohn Marino fold_builtin_trunc (location_t loc, tree fndecl, tree arg)
7888e4b17023SJohn Marino {
7889e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
7890e4b17023SJohn Marino return NULL_TREE;
7891e4b17023SJohn Marino
7892e4b17023SJohn Marino /* Optimize trunc of constant value. */
7893e4b17023SJohn Marino if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg))
7894e4b17023SJohn Marino {
7895e4b17023SJohn Marino REAL_VALUE_TYPE r, x;
7896e4b17023SJohn Marino tree type = TREE_TYPE (TREE_TYPE (fndecl));
7897e4b17023SJohn Marino
7898e4b17023SJohn Marino x = TREE_REAL_CST (arg);
7899e4b17023SJohn Marino real_trunc (&r, TYPE_MODE (type), &x);
7900e4b17023SJohn Marino return build_real (type, r);
7901e4b17023SJohn Marino }
7902e4b17023SJohn Marino
7903e4b17023SJohn Marino return fold_trunc_transparent_mathfn (loc, fndecl, arg);
7904e4b17023SJohn Marino }
7905e4b17023SJohn Marino
7906e4b17023SJohn Marino /* Fold function call to builtin floor, floorf or floorl with argument ARG.
7907e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
7908e4b17023SJohn Marino
7909e4b17023SJohn Marino static tree
fold_builtin_floor(location_t loc,tree fndecl,tree arg)7910e4b17023SJohn Marino fold_builtin_floor (location_t loc, tree fndecl, tree arg)
7911e4b17023SJohn Marino {
7912e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
7913e4b17023SJohn Marino return NULL_TREE;
7914e4b17023SJohn Marino
7915e4b17023SJohn Marino /* Optimize floor of constant value. */
7916e4b17023SJohn Marino if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg))
7917e4b17023SJohn Marino {
7918e4b17023SJohn Marino REAL_VALUE_TYPE x;
7919e4b17023SJohn Marino
7920e4b17023SJohn Marino x = TREE_REAL_CST (arg);
7921e4b17023SJohn Marino if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
7922e4b17023SJohn Marino {
7923e4b17023SJohn Marino tree type = TREE_TYPE (TREE_TYPE (fndecl));
7924e4b17023SJohn Marino REAL_VALUE_TYPE r;
7925e4b17023SJohn Marino
7926e4b17023SJohn Marino real_floor (&r, TYPE_MODE (type), &x);
7927e4b17023SJohn Marino return build_real (type, r);
7928e4b17023SJohn Marino }
7929e4b17023SJohn Marino }
7930e4b17023SJohn Marino
7931e4b17023SJohn Marino /* Fold floor (x) where x is nonnegative to trunc (x). */
7932e4b17023SJohn Marino if (tree_expr_nonnegative_p (arg))
7933e4b17023SJohn Marino {
7934e4b17023SJohn Marino tree truncfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_TRUNC);
7935e4b17023SJohn Marino if (truncfn)
7936e4b17023SJohn Marino return build_call_expr_loc (loc, truncfn, 1, arg);
7937e4b17023SJohn Marino }
7938e4b17023SJohn Marino
7939e4b17023SJohn Marino return fold_trunc_transparent_mathfn (loc, fndecl, arg);
7940e4b17023SJohn Marino }
7941e4b17023SJohn Marino
7942e4b17023SJohn Marino /* Fold function call to builtin ceil, ceilf or ceill with argument ARG.
7943e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
7944e4b17023SJohn Marino
7945e4b17023SJohn Marino static tree
fold_builtin_ceil(location_t loc,tree fndecl,tree arg)7946e4b17023SJohn Marino fold_builtin_ceil (location_t loc, tree fndecl, tree arg)
7947e4b17023SJohn Marino {
7948e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
7949e4b17023SJohn Marino return NULL_TREE;
7950e4b17023SJohn Marino
7951e4b17023SJohn Marino /* Optimize ceil of constant value. */
7952e4b17023SJohn Marino if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg))
7953e4b17023SJohn Marino {
7954e4b17023SJohn Marino REAL_VALUE_TYPE x;
7955e4b17023SJohn Marino
7956e4b17023SJohn Marino x = TREE_REAL_CST (arg);
7957e4b17023SJohn Marino if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
7958e4b17023SJohn Marino {
7959e4b17023SJohn Marino tree type = TREE_TYPE (TREE_TYPE (fndecl));
7960e4b17023SJohn Marino REAL_VALUE_TYPE r;
7961e4b17023SJohn Marino
7962e4b17023SJohn Marino real_ceil (&r, TYPE_MODE (type), &x);
7963e4b17023SJohn Marino return build_real (type, r);
7964e4b17023SJohn Marino }
7965e4b17023SJohn Marino }
7966e4b17023SJohn Marino
7967e4b17023SJohn Marino return fold_trunc_transparent_mathfn (loc, fndecl, arg);
7968e4b17023SJohn Marino }
7969e4b17023SJohn Marino
7970e4b17023SJohn Marino /* Fold function call to builtin round, roundf or roundl with argument ARG.
7971e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
7972e4b17023SJohn Marino
7973e4b17023SJohn Marino static tree
fold_builtin_round(location_t loc,tree fndecl,tree arg)7974e4b17023SJohn Marino fold_builtin_round (location_t loc, tree fndecl, tree arg)
7975e4b17023SJohn Marino {
7976e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
7977e4b17023SJohn Marino return NULL_TREE;
7978e4b17023SJohn Marino
7979e4b17023SJohn Marino /* Optimize round of constant value. */
7980e4b17023SJohn Marino if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg))
7981e4b17023SJohn Marino {
7982e4b17023SJohn Marino REAL_VALUE_TYPE x;
7983e4b17023SJohn Marino
7984e4b17023SJohn Marino x = TREE_REAL_CST (arg);
7985e4b17023SJohn Marino if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
7986e4b17023SJohn Marino {
7987e4b17023SJohn Marino tree type = TREE_TYPE (TREE_TYPE (fndecl));
7988e4b17023SJohn Marino REAL_VALUE_TYPE r;
7989e4b17023SJohn Marino
7990e4b17023SJohn Marino real_round (&r, TYPE_MODE (type), &x);
7991e4b17023SJohn Marino return build_real (type, r);
7992e4b17023SJohn Marino }
7993e4b17023SJohn Marino }
7994e4b17023SJohn Marino
7995e4b17023SJohn Marino return fold_trunc_transparent_mathfn (loc, fndecl, arg);
7996e4b17023SJohn Marino }
7997e4b17023SJohn Marino
7998e4b17023SJohn Marino /* Fold function call to builtin lround, lroundf or lroundl (or the
7999e4b17023SJohn Marino corresponding long long versions) and other rounding functions. ARG
8000e4b17023SJohn Marino is the argument to the call. Return NULL_TREE if no simplification
8001e4b17023SJohn Marino can be made. */
8002e4b17023SJohn Marino
8003e4b17023SJohn Marino static tree
fold_builtin_int_roundingfn(location_t loc,tree fndecl,tree arg)8004e4b17023SJohn Marino fold_builtin_int_roundingfn (location_t loc, tree fndecl, tree arg)
8005e4b17023SJohn Marino {
8006e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
8007e4b17023SJohn Marino return NULL_TREE;
8008e4b17023SJohn Marino
8009e4b17023SJohn Marino /* Optimize lround of constant value. */
8010e4b17023SJohn Marino if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg))
8011e4b17023SJohn Marino {
8012e4b17023SJohn Marino const REAL_VALUE_TYPE x = TREE_REAL_CST (arg);
8013e4b17023SJohn Marino
8014e4b17023SJohn Marino if (real_isfinite (&x))
8015e4b17023SJohn Marino {
8016e4b17023SJohn Marino tree itype = TREE_TYPE (TREE_TYPE (fndecl));
8017e4b17023SJohn Marino tree ftype = TREE_TYPE (arg);
8018e4b17023SJohn Marino double_int val;
8019e4b17023SJohn Marino REAL_VALUE_TYPE r;
8020e4b17023SJohn Marino
8021e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
8022e4b17023SJohn Marino {
8023e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IFLOOR):
8024e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LFLOOR):
8025e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLFLOOR):
8026e4b17023SJohn Marino real_floor (&r, TYPE_MODE (ftype), &x);
8027e4b17023SJohn Marino break;
8028e4b17023SJohn Marino
8029e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ICEIL):
8030e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LCEIL):
8031e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLCEIL):
8032e4b17023SJohn Marino real_ceil (&r, TYPE_MODE (ftype), &x);
8033e4b17023SJohn Marino break;
8034e4b17023SJohn Marino
8035e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IROUND):
8036e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LROUND):
8037e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLROUND):
8038e4b17023SJohn Marino real_round (&r, TYPE_MODE (ftype), &x);
8039e4b17023SJohn Marino break;
8040e4b17023SJohn Marino
8041e4b17023SJohn Marino default:
8042e4b17023SJohn Marino gcc_unreachable ();
8043e4b17023SJohn Marino }
8044e4b17023SJohn Marino
8045e4b17023SJohn Marino real_to_integer2 ((HOST_WIDE_INT *)&val.low, &val.high, &r);
8046e4b17023SJohn Marino if (double_int_fits_to_tree_p (itype, val))
8047e4b17023SJohn Marino return double_int_to_tree (itype, val);
8048e4b17023SJohn Marino }
8049e4b17023SJohn Marino }
8050e4b17023SJohn Marino
8051e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
8052e4b17023SJohn Marino {
8053e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LFLOOR):
8054e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLFLOOR):
8055e4b17023SJohn Marino /* Fold lfloor (x) where x is nonnegative to FIX_TRUNC (x). */
8056e4b17023SJohn Marino if (tree_expr_nonnegative_p (arg))
8057e4b17023SJohn Marino return fold_build1_loc (loc, FIX_TRUNC_EXPR,
8058e4b17023SJohn Marino TREE_TYPE (TREE_TYPE (fndecl)), arg);
8059e4b17023SJohn Marino break;
8060e4b17023SJohn Marino default:;
8061e4b17023SJohn Marino }
8062e4b17023SJohn Marino
8063e4b17023SJohn Marino return fold_fixed_mathfn (loc, fndecl, arg);
8064e4b17023SJohn Marino }
8065e4b17023SJohn Marino
8066e4b17023SJohn Marino /* Fold function call to builtin ffs, clz, ctz, popcount and parity
8067e4b17023SJohn Marino and their long and long long variants (i.e. ffsl and ffsll). ARG is
8068e4b17023SJohn Marino the argument to the call. Return NULL_TREE if no simplification can
8069e4b17023SJohn Marino be made. */
8070e4b17023SJohn Marino
8071e4b17023SJohn Marino static tree
fold_builtin_bitop(tree fndecl,tree arg)8072e4b17023SJohn Marino fold_builtin_bitop (tree fndecl, tree arg)
8073e4b17023SJohn Marino {
8074e4b17023SJohn Marino if (!validate_arg (arg, INTEGER_TYPE))
8075e4b17023SJohn Marino return NULL_TREE;
8076e4b17023SJohn Marino
8077e4b17023SJohn Marino /* Optimize for constant argument. */
8078e4b17023SJohn Marino if (TREE_CODE (arg) == INTEGER_CST && !TREE_OVERFLOW (arg))
8079e4b17023SJohn Marino {
8080e4b17023SJohn Marino HOST_WIDE_INT hi, width, result;
8081e4b17023SJohn Marino unsigned HOST_WIDE_INT lo;
8082e4b17023SJohn Marino tree type;
8083e4b17023SJohn Marino
8084e4b17023SJohn Marino type = TREE_TYPE (arg);
8085e4b17023SJohn Marino width = TYPE_PRECISION (type);
8086e4b17023SJohn Marino lo = TREE_INT_CST_LOW (arg);
8087e4b17023SJohn Marino
8088e4b17023SJohn Marino /* Clear all the bits that are beyond the type's precision. */
8089e4b17023SJohn Marino if (width > HOST_BITS_PER_WIDE_INT)
8090e4b17023SJohn Marino {
8091e4b17023SJohn Marino hi = TREE_INT_CST_HIGH (arg);
8092e4b17023SJohn Marino if (width < 2 * HOST_BITS_PER_WIDE_INT)
8093e4b17023SJohn Marino hi &= ~((unsigned HOST_WIDE_INT) (-1)
8094e4b17023SJohn Marino << (width - HOST_BITS_PER_WIDE_INT));
8095e4b17023SJohn Marino }
8096e4b17023SJohn Marino else
8097e4b17023SJohn Marino {
8098e4b17023SJohn Marino hi = 0;
8099e4b17023SJohn Marino if (width < HOST_BITS_PER_WIDE_INT)
8100e4b17023SJohn Marino lo &= ~((unsigned HOST_WIDE_INT) (-1) << width);
8101e4b17023SJohn Marino }
8102e4b17023SJohn Marino
8103e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
8104e4b17023SJohn Marino {
8105e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_FFS):
8106e4b17023SJohn Marino if (lo != 0)
8107e4b17023SJohn Marino result = ffs_hwi (lo);
8108e4b17023SJohn Marino else if (hi != 0)
8109e4b17023SJohn Marino result = HOST_BITS_PER_WIDE_INT + ffs_hwi (hi);
8110e4b17023SJohn Marino else
8111e4b17023SJohn Marino result = 0;
8112e4b17023SJohn Marino break;
8113e4b17023SJohn Marino
8114e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_CLZ):
8115e4b17023SJohn Marino if (hi != 0)
8116e4b17023SJohn Marino result = width - floor_log2 (hi) - 1 - HOST_BITS_PER_WIDE_INT;
8117e4b17023SJohn Marino else if (lo != 0)
8118e4b17023SJohn Marino result = width - floor_log2 (lo) - 1;
8119e4b17023SJohn Marino else if (! CLZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (type), result))
8120e4b17023SJohn Marino result = width;
8121e4b17023SJohn Marino break;
8122e4b17023SJohn Marino
8123e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_CTZ):
8124e4b17023SJohn Marino if (lo != 0)
8125e4b17023SJohn Marino result = ctz_hwi (lo);
8126e4b17023SJohn Marino else if (hi != 0)
8127e4b17023SJohn Marino result = HOST_BITS_PER_WIDE_INT + ctz_hwi (hi);
8128e4b17023SJohn Marino else if (! CTZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (type), result))
8129e4b17023SJohn Marino result = width;
8130e4b17023SJohn Marino break;
8131e4b17023SJohn Marino
8132e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_CLRSB):
8133e4b17023SJohn Marino if (width > HOST_BITS_PER_WIDE_INT
8134e4b17023SJohn Marino && (hi & ((unsigned HOST_WIDE_INT) 1
8135e4b17023SJohn Marino << (width - HOST_BITS_PER_WIDE_INT - 1))) != 0)
8136e4b17023SJohn Marino {
8137e4b17023SJohn Marino hi = ~hi & ~((unsigned HOST_WIDE_INT) (-1)
8138e4b17023SJohn Marino << (width - HOST_BITS_PER_WIDE_INT - 1));
8139e4b17023SJohn Marino lo = ~lo;
8140e4b17023SJohn Marino }
8141e4b17023SJohn Marino else if (width <= HOST_BITS_PER_WIDE_INT
8142e4b17023SJohn Marino && (lo & ((unsigned HOST_WIDE_INT) 1 << (width - 1))) != 0)
8143e4b17023SJohn Marino lo = ~lo & ~((unsigned HOST_WIDE_INT) (-1) << (width - 1));
8144e4b17023SJohn Marino if (hi != 0)
8145e4b17023SJohn Marino result = width - floor_log2 (hi) - 2 - HOST_BITS_PER_WIDE_INT;
8146e4b17023SJohn Marino else if (lo != 0)
8147e4b17023SJohn Marino result = width - floor_log2 (lo) - 2;
8148e4b17023SJohn Marino else
8149e4b17023SJohn Marino result = width - 1;
8150e4b17023SJohn Marino break;
8151e4b17023SJohn Marino
8152e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_POPCOUNT):
8153e4b17023SJohn Marino result = 0;
8154e4b17023SJohn Marino while (lo)
8155e4b17023SJohn Marino result++, lo &= lo - 1;
8156e4b17023SJohn Marino while (hi)
8157e4b17023SJohn Marino result++, hi &= (unsigned HOST_WIDE_INT) hi - 1;
8158e4b17023SJohn Marino break;
8159e4b17023SJohn Marino
8160e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_PARITY):
8161e4b17023SJohn Marino result = 0;
8162e4b17023SJohn Marino while (lo)
8163e4b17023SJohn Marino result++, lo &= lo - 1;
8164e4b17023SJohn Marino while (hi)
8165e4b17023SJohn Marino result++, hi &= (unsigned HOST_WIDE_INT) hi - 1;
8166e4b17023SJohn Marino result &= 1;
8167e4b17023SJohn Marino break;
8168e4b17023SJohn Marino
8169e4b17023SJohn Marino default:
8170e4b17023SJohn Marino gcc_unreachable ();
8171e4b17023SJohn Marino }
8172e4b17023SJohn Marino
8173e4b17023SJohn Marino return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), result);
8174e4b17023SJohn Marino }
8175e4b17023SJohn Marino
8176e4b17023SJohn Marino return NULL_TREE;
8177e4b17023SJohn Marino }
8178e4b17023SJohn Marino
8179e4b17023SJohn Marino /* Fold function call to builtin_bswap and the long and long long
8180e4b17023SJohn Marino variants. Return NULL_TREE if no simplification can be made. */
8181e4b17023SJohn Marino static tree
fold_builtin_bswap(tree fndecl,tree arg)8182e4b17023SJohn Marino fold_builtin_bswap (tree fndecl, tree arg)
8183e4b17023SJohn Marino {
8184e4b17023SJohn Marino if (! validate_arg (arg, INTEGER_TYPE))
8185e4b17023SJohn Marino return NULL_TREE;
8186e4b17023SJohn Marino
8187e4b17023SJohn Marino /* Optimize constant value. */
8188e4b17023SJohn Marino if (TREE_CODE (arg) == INTEGER_CST && !TREE_OVERFLOW (arg))
8189e4b17023SJohn Marino {
8190e4b17023SJohn Marino HOST_WIDE_INT hi, width, r_hi = 0;
8191e4b17023SJohn Marino unsigned HOST_WIDE_INT lo, r_lo = 0;
8192e4b17023SJohn Marino tree type;
8193e4b17023SJohn Marino
8194e4b17023SJohn Marino type = TREE_TYPE (arg);
8195e4b17023SJohn Marino width = TYPE_PRECISION (type);
8196e4b17023SJohn Marino lo = TREE_INT_CST_LOW (arg);
8197e4b17023SJohn Marino hi = TREE_INT_CST_HIGH (arg);
8198e4b17023SJohn Marino
8199e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
8200e4b17023SJohn Marino {
8201e4b17023SJohn Marino case BUILT_IN_BSWAP32:
8202e4b17023SJohn Marino case BUILT_IN_BSWAP64:
8203e4b17023SJohn Marino {
8204e4b17023SJohn Marino int s;
8205e4b17023SJohn Marino
8206e4b17023SJohn Marino for (s = 0; s < width; s += 8)
8207e4b17023SJohn Marino {
8208e4b17023SJohn Marino int d = width - s - 8;
8209e4b17023SJohn Marino unsigned HOST_WIDE_INT byte;
8210e4b17023SJohn Marino
8211e4b17023SJohn Marino if (s < HOST_BITS_PER_WIDE_INT)
8212e4b17023SJohn Marino byte = (lo >> s) & 0xff;
8213e4b17023SJohn Marino else
8214e4b17023SJohn Marino byte = (hi >> (s - HOST_BITS_PER_WIDE_INT)) & 0xff;
8215e4b17023SJohn Marino
8216e4b17023SJohn Marino if (d < HOST_BITS_PER_WIDE_INT)
8217e4b17023SJohn Marino r_lo |= byte << d;
8218e4b17023SJohn Marino else
8219e4b17023SJohn Marino r_hi |= byte << (d - HOST_BITS_PER_WIDE_INT);
8220e4b17023SJohn Marino }
8221e4b17023SJohn Marino }
8222e4b17023SJohn Marino
8223e4b17023SJohn Marino break;
8224e4b17023SJohn Marino
8225e4b17023SJohn Marino default:
8226e4b17023SJohn Marino gcc_unreachable ();
8227e4b17023SJohn Marino }
8228e4b17023SJohn Marino
8229e4b17023SJohn Marino if (width < HOST_BITS_PER_WIDE_INT)
8230e4b17023SJohn Marino return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), r_lo);
8231e4b17023SJohn Marino else
8232e4b17023SJohn Marino return build_int_cst_wide (TREE_TYPE (TREE_TYPE (fndecl)), r_lo, r_hi);
8233e4b17023SJohn Marino }
8234e4b17023SJohn Marino
8235e4b17023SJohn Marino return NULL_TREE;
8236e4b17023SJohn Marino }
8237e4b17023SJohn Marino
8238e4b17023SJohn Marino /* A subroutine of fold_builtin to fold the various logarithmic
8239e4b17023SJohn Marino functions. Return NULL_TREE if no simplification can me made.
8240e4b17023SJohn Marino FUNC is the corresponding MPFR logarithm function. */
8241e4b17023SJohn Marino
8242e4b17023SJohn Marino static tree
fold_builtin_logarithm(location_t loc,tree fndecl,tree arg,int (* func)(mpfr_ptr,mpfr_srcptr,mp_rnd_t))8243e4b17023SJohn Marino fold_builtin_logarithm (location_t loc, tree fndecl, tree arg,
8244e4b17023SJohn Marino int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t))
8245e4b17023SJohn Marino {
8246e4b17023SJohn Marino if (validate_arg (arg, REAL_TYPE))
8247e4b17023SJohn Marino {
8248e4b17023SJohn Marino tree type = TREE_TYPE (TREE_TYPE (fndecl));
8249e4b17023SJohn Marino tree res;
8250e4b17023SJohn Marino const enum built_in_function fcode = builtin_mathfn_code (arg);
8251e4b17023SJohn Marino
8252e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
8253e4b17023SJohn Marino if ((res = do_mpfr_arg1 (arg, type, func, &dconst0, NULL, false)))
8254e4b17023SJohn Marino return res;
8255e4b17023SJohn Marino
8256e4b17023SJohn Marino /* Special case, optimize logN(expN(x)) = x. */
8257e4b17023SJohn Marino if (flag_unsafe_math_optimizations
8258e4b17023SJohn Marino && ((func == mpfr_log
8259e4b17023SJohn Marino && (fcode == BUILT_IN_EXP
8260e4b17023SJohn Marino || fcode == BUILT_IN_EXPF
8261e4b17023SJohn Marino || fcode == BUILT_IN_EXPL))
8262e4b17023SJohn Marino || (func == mpfr_log2
8263e4b17023SJohn Marino && (fcode == BUILT_IN_EXP2
8264e4b17023SJohn Marino || fcode == BUILT_IN_EXP2F
8265e4b17023SJohn Marino || fcode == BUILT_IN_EXP2L))
8266e4b17023SJohn Marino || (func == mpfr_log10 && (BUILTIN_EXP10_P (fcode)))))
8267e4b17023SJohn Marino return fold_convert_loc (loc, type, CALL_EXPR_ARG (arg, 0));
8268e4b17023SJohn Marino
8269e4b17023SJohn Marino /* Optimize logN(func()) for various exponential functions. We
8270e4b17023SJohn Marino want to determine the value "x" and the power "exponent" in
8271e4b17023SJohn Marino order to transform logN(x**exponent) into exponent*logN(x). */
8272e4b17023SJohn Marino if (flag_unsafe_math_optimizations)
8273e4b17023SJohn Marino {
8274e4b17023SJohn Marino tree exponent = 0, x = 0;
8275e4b17023SJohn Marino
8276e4b17023SJohn Marino switch (fcode)
8277e4b17023SJohn Marino {
8278e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXP):
8279e4b17023SJohn Marino /* Prepare to do logN(exp(exponent) -> exponent*logN(e). */
8280e4b17023SJohn Marino x = build_real (type, real_value_truncate (TYPE_MODE (type),
8281e4b17023SJohn Marino dconst_e ()));
8282e4b17023SJohn Marino exponent = CALL_EXPR_ARG (arg, 0);
8283e4b17023SJohn Marino break;
8284e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXP2):
8285e4b17023SJohn Marino /* Prepare to do logN(exp2(exponent) -> exponent*logN(2). */
8286e4b17023SJohn Marino x = build_real (type, dconst2);
8287e4b17023SJohn Marino exponent = CALL_EXPR_ARG (arg, 0);
8288e4b17023SJohn Marino break;
8289e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXP10):
8290e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_POW10):
8291e4b17023SJohn Marino /* Prepare to do logN(exp10(exponent) -> exponent*logN(10). */
8292e4b17023SJohn Marino {
8293e4b17023SJohn Marino REAL_VALUE_TYPE dconst10;
8294e4b17023SJohn Marino real_from_integer (&dconst10, VOIDmode, 10, 0, 0);
8295e4b17023SJohn Marino x = build_real (type, dconst10);
8296e4b17023SJohn Marino }
8297e4b17023SJohn Marino exponent = CALL_EXPR_ARG (arg, 0);
8298e4b17023SJohn Marino break;
8299e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SQRT):
8300e4b17023SJohn Marino /* Prepare to do logN(sqrt(x) -> 0.5*logN(x). */
8301e4b17023SJohn Marino x = CALL_EXPR_ARG (arg, 0);
8302e4b17023SJohn Marino exponent = build_real (type, dconsthalf);
8303e4b17023SJohn Marino break;
8304e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CBRT):
8305e4b17023SJohn Marino /* Prepare to do logN(cbrt(x) -> (1/3)*logN(x). */
8306e4b17023SJohn Marino x = CALL_EXPR_ARG (arg, 0);
8307e4b17023SJohn Marino exponent = build_real (type, real_value_truncate (TYPE_MODE (type),
8308e4b17023SJohn Marino dconst_third ()));
8309e4b17023SJohn Marino break;
8310e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_POW):
8311e4b17023SJohn Marino /* Prepare to do logN(pow(x,exponent) -> exponent*logN(x). */
8312e4b17023SJohn Marino x = CALL_EXPR_ARG (arg, 0);
8313e4b17023SJohn Marino exponent = CALL_EXPR_ARG (arg, 1);
8314e4b17023SJohn Marino break;
8315e4b17023SJohn Marino default:
8316e4b17023SJohn Marino break;
8317e4b17023SJohn Marino }
8318e4b17023SJohn Marino
8319e4b17023SJohn Marino /* Now perform the optimization. */
8320e4b17023SJohn Marino if (x && exponent)
8321e4b17023SJohn Marino {
8322e4b17023SJohn Marino tree logfn = build_call_expr_loc (loc, fndecl, 1, x);
8323e4b17023SJohn Marino return fold_build2_loc (loc, MULT_EXPR, type, exponent, logfn);
8324e4b17023SJohn Marino }
8325e4b17023SJohn Marino }
8326e4b17023SJohn Marino }
8327e4b17023SJohn Marino
8328e4b17023SJohn Marino return NULL_TREE;
8329e4b17023SJohn Marino }
8330e4b17023SJohn Marino
8331e4b17023SJohn Marino /* Fold a builtin function call to hypot, hypotf, or hypotl. Return
8332e4b17023SJohn Marino NULL_TREE if no simplification can be made. */
8333e4b17023SJohn Marino
8334e4b17023SJohn Marino static tree
fold_builtin_hypot(location_t loc,tree fndecl,tree arg0,tree arg1,tree type)8335e4b17023SJohn Marino fold_builtin_hypot (location_t loc, tree fndecl,
8336e4b17023SJohn Marino tree arg0, tree arg1, tree type)
8337e4b17023SJohn Marino {
8338e4b17023SJohn Marino tree res, narg0, narg1;
8339e4b17023SJohn Marino
8340e4b17023SJohn Marino if (!validate_arg (arg0, REAL_TYPE)
8341e4b17023SJohn Marino || !validate_arg (arg1, REAL_TYPE))
8342e4b17023SJohn Marino return NULL_TREE;
8343e4b17023SJohn Marino
8344e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
8345e4b17023SJohn Marino if ((res = do_mpfr_arg2 (arg0, arg1, type, mpfr_hypot)))
8346e4b17023SJohn Marino return res;
8347e4b17023SJohn Marino
8348e4b17023SJohn Marino /* If either argument to hypot has a negate or abs, strip that off.
8349e4b17023SJohn Marino E.g. hypot(-x,fabs(y)) -> hypot(x,y). */
8350e4b17023SJohn Marino narg0 = fold_strip_sign_ops (arg0);
8351e4b17023SJohn Marino narg1 = fold_strip_sign_ops (arg1);
8352e4b17023SJohn Marino if (narg0 || narg1)
8353e4b17023SJohn Marino {
8354e4b17023SJohn Marino return build_call_expr_loc (loc, fndecl, 2, narg0 ? narg0 : arg0,
8355e4b17023SJohn Marino narg1 ? narg1 : arg1);
8356e4b17023SJohn Marino }
8357e4b17023SJohn Marino
8358e4b17023SJohn Marino /* If either argument is zero, hypot is fabs of the other. */
8359e4b17023SJohn Marino if (real_zerop (arg0))
8360e4b17023SJohn Marino return fold_build1_loc (loc, ABS_EXPR, type, arg1);
8361e4b17023SJohn Marino else if (real_zerop (arg1))
8362e4b17023SJohn Marino return fold_build1_loc (loc, ABS_EXPR, type, arg0);
8363e4b17023SJohn Marino
8364e4b17023SJohn Marino /* hypot(x,x) -> fabs(x)*sqrt(2). */
8365e4b17023SJohn Marino if (flag_unsafe_math_optimizations
8366e4b17023SJohn Marino && operand_equal_p (arg0, arg1, OEP_PURE_SAME))
8367e4b17023SJohn Marino {
8368e4b17023SJohn Marino const REAL_VALUE_TYPE sqrt2_trunc
8369e4b17023SJohn Marino = real_value_truncate (TYPE_MODE (type), dconst_sqrt2 ());
8370e4b17023SJohn Marino return fold_build2_loc (loc, MULT_EXPR, type,
8371e4b17023SJohn Marino fold_build1_loc (loc, ABS_EXPR, type, arg0),
8372e4b17023SJohn Marino build_real (type, sqrt2_trunc));
8373e4b17023SJohn Marino }
8374e4b17023SJohn Marino
8375e4b17023SJohn Marino return NULL_TREE;
8376e4b17023SJohn Marino }
8377e4b17023SJohn Marino
8378e4b17023SJohn Marino
8379e4b17023SJohn Marino /* Fold a builtin function call to pow, powf, or powl. Return
8380e4b17023SJohn Marino NULL_TREE if no simplification can be made. */
8381e4b17023SJohn Marino static tree
fold_builtin_pow(location_t loc,tree fndecl,tree arg0,tree arg1,tree type)8382e4b17023SJohn Marino fold_builtin_pow (location_t loc, tree fndecl, tree arg0, tree arg1, tree type)
8383e4b17023SJohn Marino {
8384e4b17023SJohn Marino tree res;
8385e4b17023SJohn Marino
8386e4b17023SJohn Marino if (!validate_arg (arg0, REAL_TYPE)
8387e4b17023SJohn Marino || !validate_arg (arg1, REAL_TYPE))
8388e4b17023SJohn Marino return NULL_TREE;
8389e4b17023SJohn Marino
8390e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
8391e4b17023SJohn Marino if ((res = do_mpfr_arg2 (arg0, arg1, type, mpfr_pow)))
8392e4b17023SJohn Marino return res;
8393e4b17023SJohn Marino
8394e4b17023SJohn Marino /* Optimize pow(1.0,y) = 1.0. */
8395e4b17023SJohn Marino if (real_onep (arg0))
8396e4b17023SJohn Marino return omit_one_operand_loc (loc, type, build_real (type, dconst1), arg1);
8397e4b17023SJohn Marino
8398e4b17023SJohn Marino if (TREE_CODE (arg1) == REAL_CST
8399e4b17023SJohn Marino && !TREE_OVERFLOW (arg1))
8400e4b17023SJohn Marino {
8401e4b17023SJohn Marino REAL_VALUE_TYPE cint;
8402e4b17023SJohn Marino REAL_VALUE_TYPE c;
8403e4b17023SJohn Marino HOST_WIDE_INT n;
8404e4b17023SJohn Marino
8405e4b17023SJohn Marino c = TREE_REAL_CST (arg1);
8406e4b17023SJohn Marino
8407e4b17023SJohn Marino /* Optimize pow(x,0.0) = 1.0. */
8408e4b17023SJohn Marino if (REAL_VALUES_EQUAL (c, dconst0))
8409e4b17023SJohn Marino return omit_one_operand_loc (loc, type, build_real (type, dconst1),
8410e4b17023SJohn Marino arg0);
8411e4b17023SJohn Marino
8412e4b17023SJohn Marino /* Optimize pow(x,1.0) = x. */
8413e4b17023SJohn Marino if (REAL_VALUES_EQUAL (c, dconst1))
8414e4b17023SJohn Marino return arg0;
8415e4b17023SJohn Marino
8416e4b17023SJohn Marino /* Optimize pow(x,-1.0) = 1.0/x. */
8417e4b17023SJohn Marino if (REAL_VALUES_EQUAL (c, dconstm1))
8418e4b17023SJohn Marino return fold_build2_loc (loc, RDIV_EXPR, type,
8419e4b17023SJohn Marino build_real (type, dconst1), arg0);
8420e4b17023SJohn Marino
8421e4b17023SJohn Marino /* Optimize pow(x,0.5) = sqrt(x). */
8422e4b17023SJohn Marino if (flag_unsafe_math_optimizations
8423e4b17023SJohn Marino && REAL_VALUES_EQUAL (c, dconsthalf))
8424e4b17023SJohn Marino {
8425e4b17023SJohn Marino tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
8426e4b17023SJohn Marino
8427e4b17023SJohn Marino if (sqrtfn != NULL_TREE)
8428e4b17023SJohn Marino return build_call_expr_loc (loc, sqrtfn, 1, arg0);
8429e4b17023SJohn Marino }
8430e4b17023SJohn Marino
8431e4b17023SJohn Marino /* Optimize pow(x,1.0/3.0) = cbrt(x). */
8432e4b17023SJohn Marino if (flag_unsafe_math_optimizations)
8433e4b17023SJohn Marino {
8434e4b17023SJohn Marino const REAL_VALUE_TYPE dconstroot
8435e4b17023SJohn Marino = real_value_truncate (TYPE_MODE (type), dconst_third ());
8436e4b17023SJohn Marino
8437e4b17023SJohn Marino if (REAL_VALUES_EQUAL (c, dconstroot))
8438e4b17023SJohn Marino {
8439e4b17023SJohn Marino tree cbrtfn = mathfn_built_in (type, BUILT_IN_CBRT);
8440e4b17023SJohn Marino if (cbrtfn != NULL_TREE)
8441e4b17023SJohn Marino return build_call_expr_loc (loc, cbrtfn, 1, arg0);
8442e4b17023SJohn Marino }
8443e4b17023SJohn Marino }
8444e4b17023SJohn Marino
8445e4b17023SJohn Marino /* Check for an integer exponent. */
8446e4b17023SJohn Marino n = real_to_integer (&c);
8447e4b17023SJohn Marino real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
8448e4b17023SJohn Marino if (real_identical (&c, &cint))
8449e4b17023SJohn Marino {
8450e4b17023SJohn Marino /* Attempt to evaluate pow at compile-time, unless this should
8451e4b17023SJohn Marino raise an exception. */
8452e4b17023SJohn Marino if (TREE_CODE (arg0) == REAL_CST
8453e4b17023SJohn Marino && !TREE_OVERFLOW (arg0)
8454e4b17023SJohn Marino && (n > 0
8455e4b17023SJohn Marino || (!flag_trapping_math && !flag_errno_math)
8456e4b17023SJohn Marino || !REAL_VALUES_EQUAL (TREE_REAL_CST (arg0), dconst0)))
8457e4b17023SJohn Marino {
8458e4b17023SJohn Marino REAL_VALUE_TYPE x;
8459e4b17023SJohn Marino bool inexact;
8460e4b17023SJohn Marino
8461e4b17023SJohn Marino x = TREE_REAL_CST (arg0);
8462e4b17023SJohn Marino inexact = real_powi (&x, TYPE_MODE (type), &x, n);
8463e4b17023SJohn Marino if (flag_unsafe_math_optimizations || !inexact)
8464e4b17023SJohn Marino return build_real (type, x);
8465e4b17023SJohn Marino }
8466e4b17023SJohn Marino
8467e4b17023SJohn Marino /* Strip sign ops from even integer powers. */
8468e4b17023SJohn Marino if ((n & 1) == 0 && flag_unsafe_math_optimizations)
8469e4b17023SJohn Marino {
8470e4b17023SJohn Marino tree narg0 = fold_strip_sign_ops (arg0);
8471e4b17023SJohn Marino if (narg0)
8472e4b17023SJohn Marino return build_call_expr_loc (loc, fndecl, 2, narg0, arg1);
8473e4b17023SJohn Marino }
8474e4b17023SJohn Marino }
8475e4b17023SJohn Marino }
8476e4b17023SJohn Marino
8477e4b17023SJohn Marino if (flag_unsafe_math_optimizations)
8478e4b17023SJohn Marino {
8479e4b17023SJohn Marino const enum built_in_function fcode = builtin_mathfn_code (arg0);
8480e4b17023SJohn Marino
8481e4b17023SJohn Marino /* Optimize pow(expN(x),y) = expN(x*y). */
8482e4b17023SJohn Marino if (BUILTIN_EXPONENT_P (fcode))
8483e4b17023SJohn Marino {
8484e4b17023SJohn Marino tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
8485e4b17023SJohn Marino tree arg = CALL_EXPR_ARG (arg0, 0);
8486e4b17023SJohn Marino arg = fold_build2_loc (loc, MULT_EXPR, type, arg, arg1);
8487e4b17023SJohn Marino return build_call_expr_loc (loc, expfn, 1, arg);
8488e4b17023SJohn Marino }
8489e4b17023SJohn Marino
8490e4b17023SJohn Marino /* Optimize pow(sqrt(x),y) = pow(x,y*0.5). */
8491e4b17023SJohn Marino if (BUILTIN_SQRT_P (fcode))
8492e4b17023SJohn Marino {
8493e4b17023SJohn Marino tree narg0 = CALL_EXPR_ARG (arg0, 0);
8494e4b17023SJohn Marino tree narg1 = fold_build2_loc (loc, MULT_EXPR, type, arg1,
8495e4b17023SJohn Marino build_real (type, dconsthalf));
8496e4b17023SJohn Marino return build_call_expr_loc (loc, fndecl, 2, narg0, narg1);
8497e4b17023SJohn Marino }
8498e4b17023SJohn Marino
8499e4b17023SJohn Marino /* Optimize pow(cbrt(x),y) = pow(x,y/3) iff x is nonnegative. */
8500e4b17023SJohn Marino if (BUILTIN_CBRT_P (fcode))
8501e4b17023SJohn Marino {
8502e4b17023SJohn Marino tree arg = CALL_EXPR_ARG (arg0, 0);
8503e4b17023SJohn Marino if (tree_expr_nonnegative_p (arg))
8504e4b17023SJohn Marino {
8505e4b17023SJohn Marino const REAL_VALUE_TYPE dconstroot
8506e4b17023SJohn Marino = real_value_truncate (TYPE_MODE (type), dconst_third ());
8507e4b17023SJohn Marino tree narg1 = fold_build2_loc (loc, MULT_EXPR, type, arg1,
8508e4b17023SJohn Marino build_real (type, dconstroot));
8509e4b17023SJohn Marino return build_call_expr_loc (loc, fndecl, 2, arg, narg1);
8510e4b17023SJohn Marino }
8511e4b17023SJohn Marino }
8512e4b17023SJohn Marino
8513e4b17023SJohn Marino /* Optimize pow(pow(x,y),z) = pow(x,y*z) iff x is nonnegative. */
8514e4b17023SJohn Marino if (fcode == BUILT_IN_POW
8515e4b17023SJohn Marino || fcode == BUILT_IN_POWF
8516e4b17023SJohn Marino || fcode == BUILT_IN_POWL)
8517e4b17023SJohn Marino {
8518e4b17023SJohn Marino tree arg00 = CALL_EXPR_ARG (arg0, 0);
8519e4b17023SJohn Marino if (tree_expr_nonnegative_p (arg00))
8520e4b17023SJohn Marino {
8521e4b17023SJohn Marino tree arg01 = CALL_EXPR_ARG (arg0, 1);
8522e4b17023SJohn Marino tree narg1 = fold_build2_loc (loc, MULT_EXPR, type, arg01, arg1);
8523e4b17023SJohn Marino return build_call_expr_loc (loc, fndecl, 2, arg00, narg1);
8524e4b17023SJohn Marino }
8525e4b17023SJohn Marino }
8526e4b17023SJohn Marino }
8527e4b17023SJohn Marino
8528e4b17023SJohn Marino return NULL_TREE;
8529e4b17023SJohn Marino }
8530e4b17023SJohn Marino
8531e4b17023SJohn Marino /* Fold a builtin function call to powi, powif, or powil with argument ARG.
8532e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
8533e4b17023SJohn Marino static tree
fold_builtin_powi(location_t loc,tree fndecl ATTRIBUTE_UNUSED,tree arg0,tree arg1,tree type)8534e4b17023SJohn Marino fold_builtin_powi (location_t loc, tree fndecl ATTRIBUTE_UNUSED,
8535e4b17023SJohn Marino tree arg0, tree arg1, tree type)
8536e4b17023SJohn Marino {
8537e4b17023SJohn Marino if (!validate_arg (arg0, REAL_TYPE)
8538e4b17023SJohn Marino || !validate_arg (arg1, INTEGER_TYPE))
8539e4b17023SJohn Marino return NULL_TREE;
8540e4b17023SJohn Marino
8541e4b17023SJohn Marino /* Optimize pow(1.0,y) = 1.0. */
8542e4b17023SJohn Marino if (real_onep (arg0))
8543e4b17023SJohn Marino return omit_one_operand_loc (loc, type, build_real (type, dconst1), arg1);
8544e4b17023SJohn Marino
8545e4b17023SJohn Marino if (host_integerp (arg1, 0))
8546e4b17023SJohn Marino {
8547e4b17023SJohn Marino HOST_WIDE_INT c = TREE_INT_CST_LOW (arg1);
8548e4b17023SJohn Marino
8549e4b17023SJohn Marino /* Evaluate powi at compile-time. */
8550e4b17023SJohn Marino if (TREE_CODE (arg0) == REAL_CST
8551e4b17023SJohn Marino && !TREE_OVERFLOW (arg0))
8552e4b17023SJohn Marino {
8553e4b17023SJohn Marino REAL_VALUE_TYPE x;
8554e4b17023SJohn Marino x = TREE_REAL_CST (arg0);
8555e4b17023SJohn Marino real_powi (&x, TYPE_MODE (type), &x, c);
8556e4b17023SJohn Marino return build_real (type, x);
8557e4b17023SJohn Marino }
8558e4b17023SJohn Marino
8559e4b17023SJohn Marino /* Optimize pow(x,0) = 1.0. */
8560e4b17023SJohn Marino if (c == 0)
8561e4b17023SJohn Marino return omit_one_operand_loc (loc, type, build_real (type, dconst1),
8562e4b17023SJohn Marino arg0);
8563e4b17023SJohn Marino
8564e4b17023SJohn Marino /* Optimize pow(x,1) = x. */
8565e4b17023SJohn Marino if (c == 1)
8566e4b17023SJohn Marino return arg0;
8567e4b17023SJohn Marino
8568e4b17023SJohn Marino /* Optimize pow(x,-1) = 1.0/x. */
8569e4b17023SJohn Marino if (c == -1)
8570e4b17023SJohn Marino return fold_build2_loc (loc, RDIV_EXPR, type,
8571e4b17023SJohn Marino build_real (type, dconst1), arg0);
8572e4b17023SJohn Marino }
8573e4b17023SJohn Marino
8574e4b17023SJohn Marino return NULL_TREE;
8575e4b17023SJohn Marino }
8576e4b17023SJohn Marino
8577e4b17023SJohn Marino /* A subroutine of fold_builtin to fold the various exponent
8578e4b17023SJohn Marino functions. Return NULL_TREE if no simplification can be made.
8579e4b17023SJohn Marino FUNC is the corresponding MPFR exponent function. */
8580e4b17023SJohn Marino
8581e4b17023SJohn Marino static tree
fold_builtin_exponent(location_t loc,tree fndecl,tree arg,int (* func)(mpfr_ptr,mpfr_srcptr,mp_rnd_t))8582e4b17023SJohn Marino fold_builtin_exponent (location_t loc, tree fndecl, tree arg,
8583e4b17023SJohn Marino int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t))
8584e4b17023SJohn Marino {
8585e4b17023SJohn Marino if (validate_arg (arg, REAL_TYPE))
8586e4b17023SJohn Marino {
8587e4b17023SJohn Marino tree type = TREE_TYPE (TREE_TYPE (fndecl));
8588e4b17023SJohn Marino tree res;
8589e4b17023SJohn Marino
8590e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
8591e4b17023SJohn Marino if ((res = do_mpfr_arg1 (arg, type, func, NULL, NULL, 0)))
8592e4b17023SJohn Marino return res;
8593e4b17023SJohn Marino
8594e4b17023SJohn Marino /* Optimize expN(logN(x)) = x. */
8595e4b17023SJohn Marino if (flag_unsafe_math_optimizations)
8596e4b17023SJohn Marino {
8597e4b17023SJohn Marino const enum built_in_function fcode = builtin_mathfn_code (arg);
8598e4b17023SJohn Marino
8599e4b17023SJohn Marino if ((func == mpfr_exp
8600e4b17023SJohn Marino && (fcode == BUILT_IN_LOG
8601e4b17023SJohn Marino || fcode == BUILT_IN_LOGF
8602e4b17023SJohn Marino || fcode == BUILT_IN_LOGL))
8603e4b17023SJohn Marino || (func == mpfr_exp2
8604e4b17023SJohn Marino && (fcode == BUILT_IN_LOG2
8605e4b17023SJohn Marino || fcode == BUILT_IN_LOG2F
8606e4b17023SJohn Marino || fcode == BUILT_IN_LOG2L))
8607e4b17023SJohn Marino || (func == mpfr_exp10
8608e4b17023SJohn Marino && (fcode == BUILT_IN_LOG10
8609e4b17023SJohn Marino || fcode == BUILT_IN_LOG10F
8610e4b17023SJohn Marino || fcode == BUILT_IN_LOG10L)))
8611e4b17023SJohn Marino return fold_convert_loc (loc, type, CALL_EXPR_ARG (arg, 0));
8612e4b17023SJohn Marino }
8613e4b17023SJohn Marino }
8614e4b17023SJohn Marino
8615e4b17023SJohn Marino return NULL_TREE;
8616e4b17023SJohn Marino }
8617e4b17023SJohn Marino
8618e4b17023SJohn Marino /* Return true if VAR is a VAR_DECL or a component thereof. */
8619e4b17023SJohn Marino
8620e4b17023SJohn Marino static bool
var_decl_component_p(tree var)8621e4b17023SJohn Marino var_decl_component_p (tree var)
8622e4b17023SJohn Marino {
8623e4b17023SJohn Marino tree inner = var;
8624e4b17023SJohn Marino while (handled_component_p (inner))
8625e4b17023SJohn Marino inner = TREE_OPERAND (inner, 0);
8626e4b17023SJohn Marino return SSA_VAR_P (inner);
8627e4b17023SJohn Marino }
8628e4b17023SJohn Marino
8629e4b17023SJohn Marino /* Fold function call to builtin memset. Return
8630e4b17023SJohn Marino NULL_TREE if no simplification can be made. */
8631e4b17023SJohn Marino
8632e4b17023SJohn Marino static tree
fold_builtin_memset(location_t loc,tree dest,tree c,tree len,tree type,bool ignore)8633e4b17023SJohn Marino fold_builtin_memset (location_t loc, tree dest, tree c, tree len,
8634e4b17023SJohn Marino tree type, bool ignore)
8635e4b17023SJohn Marino {
8636e4b17023SJohn Marino tree var, ret, etype;
8637e4b17023SJohn Marino unsigned HOST_WIDE_INT length, cval;
8638e4b17023SJohn Marino
8639e4b17023SJohn Marino if (! validate_arg (dest, POINTER_TYPE)
8640e4b17023SJohn Marino || ! validate_arg (c, INTEGER_TYPE)
8641e4b17023SJohn Marino || ! validate_arg (len, INTEGER_TYPE))
8642e4b17023SJohn Marino return NULL_TREE;
8643e4b17023SJohn Marino
8644e4b17023SJohn Marino if (! host_integerp (len, 1))
8645e4b17023SJohn Marino return NULL_TREE;
8646e4b17023SJohn Marino
8647e4b17023SJohn Marino /* If the LEN parameter is zero, return DEST. */
8648e4b17023SJohn Marino if (integer_zerop (len))
8649e4b17023SJohn Marino return omit_one_operand_loc (loc, type, dest, c);
8650e4b17023SJohn Marino
8651e4b17023SJohn Marino if (TREE_CODE (c) != INTEGER_CST || TREE_SIDE_EFFECTS (dest))
8652e4b17023SJohn Marino return NULL_TREE;
8653e4b17023SJohn Marino
8654e4b17023SJohn Marino var = dest;
8655e4b17023SJohn Marino STRIP_NOPS (var);
8656e4b17023SJohn Marino if (TREE_CODE (var) != ADDR_EXPR)
8657e4b17023SJohn Marino return NULL_TREE;
8658e4b17023SJohn Marino
8659e4b17023SJohn Marino var = TREE_OPERAND (var, 0);
8660e4b17023SJohn Marino if (TREE_THIS_VOLATILE (var))
8661e4b17023SJohn Marino return NULL_TREE;
8662e4b17023SJohn Marino
8663e4b17023SJohn Marino etype = TREE_TYPE (var);
8664e4b17023SJohn Marino if (TREE_CODE (etype) == ARRAY_TYPE)
8665e4b17023SJohn Marino etype = TREE_TYPE (etype);
8666e4b17023SJohn Marino
8667e4b17023SJohn Marino if (!INTEGRAL_TYPE_P (etype)
8668e4b17023SJohn Marino && !POINTER_TYPE_P (etype))
8669e4b17023SJohn Marino return NULL_TREE;
8670e4b17023SJohn Marino
8671e4b17023SJohn Marino if (! var_decl_component_p (var))
8672e4b17023SJohn Marino return NULL_TREE;
8673e4b17023SJohn Marino
8674e4b17023SJohn Marino length = tree_low_cst (len, 1);
8675e4b17023SJohn Marino if (GET_MODE_SIZE (TYPE_MODE (etype)) != length
8676e4b17023SJohn Marino || get_pointer_alignment (dest) / BITS_PER_UNIT < length)
8677e4b17023SJohn Marino return NULL_TREE;
8678e4b17023SJohn Marino
8679e4b17023SJohn Marino if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT)
8680e4b17023SJohn Marino return NULL_TREE;
8681e4b17023SJohn Marino
8682e4b17023SJohn Marino if (integer_zerop (c))
8683e4b17023SJohn Marino cval = 0;
8684e4b17023SJohn Marino else
8685e4b17023SJohn Marino {
8686e4b17023SJohn Marino if (CHAR_BIT != 8 || BITS_PER_UNIT != 8 || HOST_BITS_PER_WIDE_INT > 64)
8687e4b17023SJohn Marino return NULL_TREE;
8688e4b17023SJohn Marino
8689e4b17023SJohn Marino cval = TREE_INT_CST_LOW (c);
8690e4b17023SJohn Marino cval &= 0xff;
8691e4b17023SJohn Marino cval |= cval << 8;
8692e4b17023SJohn Marino cval |= cval << 16;
8693e4b17023SJohn Marino cval |= (cval << 31) << 1;
8694e4b17023SJohn Marino }
8695e4b17023SJohn Marino
8696e4b17023SJohn Marino ret = build_int_cst_type (etype, cval);
8697e4b17023SJohn Marino var = build_fold_indirect_ref_loc (loc,
8698e4b17023SJohn Marino fold_convert_loc (loc,
8699e4b17023SJohn Marino build_pointer_type (etype),
8700e4b17023SJohn Marino dest));
8701e4b17023SJohn Marino ret = build2 (MODIFY_EXPR, etype, var, ret);
8702e4b17023SJohn Marino if (ignore)
8703e4b17023SJohn Marino return ret;
8704e4b17023SJohn Marino
8705e4b17023SJohn Marino return omit_one_operand_loc (loc, type, dest, ret);
8706e4b17023SJohn Marino }
8707e4b17023SJohn Marino
8708e4b17023SJohn Marino /* Fold function call to builtin memset. Return
8709e4b17023SJohn Marino NULL_TREE if no simplification can be made. */
8710e4b17023SJohn Marino
8711e4b17023SJohn Marino static tree
fold_builtin_bzero(location_t loc,tree dest,tree size,bool ignore)8712e4b17023SJohn Marino fold_builtin_bzero (location_t loc, tree dest, tree size, bool ignore)
8713e4b17023SJohn Marino {
8714e4b17023SJohn Marino if (! validate_arg (dest, POINTER_TYPE)
8715e4b17023SJohn Marino || ! validate_arg (size, INTEGER_TYPE))
8716e4b17023SJohn Marino return NULL_TREE;
8717e4b17023SJohn Marino
8718e4b17023SJohn Marino if (!ignore)
8719e4b17023SJohn Marino return NULL_TREE;
8720e4b17023SJohn Marino
8721e4b17023SJohn Marino /* New argument list transforming bzero(ptr x, int y) to
8722e4b17023SJohn Marino memset(ptr x, int 0, size_t y). This is done this way
8723e4b17023SJohn Marino so that if it isn't expanded inline, we fallback to
8724e4b17023SJohn Marino calling bzero instead of memset. */
8725e4b17023SJohn Marino
8726e4b17023SJohn Marino return fold_builtin_memset (loc, dest, integer_zero_node,
8727e4b17023SJohn Marino fold_convert_loc (loc, size_type_node, size),
8728e4b17023SJohn Marino void_type_node, ignore);
8729e4b17023SJohn Marino }
8730e4b17023SJohn Marino
8731e4b17023SJohn Marino /* Fold function call to builtin mem{{,p}cpy,move}. Return
8732e4b17023SJohn Marino NULL_TREE if no simplification can be made.
8733e4b17023SJohn Marino If ENDP is 0, return DEST (like memcpy).
8734e4b17023SJohn Marino If ENDP is 1, return DEST+LEN (like mempcpy).
8735e4b17023SJohn Marino If ENDP is 2, return DEST+LEN-1 (like stpcpy).
8736e4b17023SJohn Marino If ENDP is 3, return DEST, additionally *SRC and *DEST may overlap
8737e4b17023SJohn Marino (memmove). */
8738e4b17023SJohn Marino
8739e4b17023SJohn Marino static tree
fold_builtin_memory_op(location_t loc,tree dest,tree src,tree len,tree type,bool ignore,int endp)8740e4b17023SJohn Marino fold_builtin_memory_op (location_t loc, tree dest, tree src,
8741e4b17023SJohn Marino tree len, tree type, bool ignore, int endp)
8742e4b17023SJohn Marino {
8743e4b17023SJohn Marino tree destvar, srcvar, expr;
8744e4b17023SJohn Marino
8745e4b17023SJohn Marino if (! validate_arg (dest, POINTER_TYPE)
8746e4b17023SJohn Marino || ! validate_arg (src, POINTER_TYPE)
8747e4b17023SJohn Marino || ! validate_arg (len, INTEGER_TYPE))
8748e4b17023SJohn Marino return NULL_TREE;
8749e4b17023SJohn Marino
8750e4b17023SJohn Marino /* If the LEN parameter is zero, return DEST. */
8751e4b17023SJohn Marino if (integer_zerop (len))
8752e4b17023SJohn Marino return omit_one_operand_loc (loc, type, dest, src);
8753e4b17023SJohn Marino
8754e4b17023SJohn Marino /* If SRC and DEST are the same (and not volatile), return
8755e4b17023SJohn Marino DEST{,+LEN,+LEN-1}. */
8756e4b17023SJohn Marino if (operand_equal_p (src, dest, 0))
8757e4b17023SJohn Marino expr = len;
8758e4b17023SJohn Marino else
8759e4b17023SJohn Marino {
8760e4b17023SJohn Marino tree srctype, desttype;
8761e4b17023SJohn Marino unsigned int src_align, dest_align;
8762e4b17023SJohn Marino tree off0;
8763e4b17023SJohn Marino
8764e4b17023SJohn Marino if (endp == 3)
8765e4b17023SJohn Marino {
8766e4b17023SJohn Marino src_align = get_pointer_alignment (src);
8767e4b17023SJohn Marino dest_align = get_pointer_alignment (dest);
8768e4b17023SJohn Marino
8769e4b17023SJohn Marino /* Both DEST and SRC must be pointer types.
8770e4b17023SJohn Marino ??? This is what old code did. Is the testing for pointer types
8771e4b17023SJohn Marino really mandatory?
8772e4b17023SJohn Marino
8773e4b17023SJohn Marino If either SRC is readonly or length is 1, we can use memcpy. */
8774e4b17023SJohn Marino if (!dest_align || !src_align)
8775e4b17023SJohn Marino return NULL_TREE;
8776e4b17023SJohn Marino if (readonly_data_expr (src)
8777e4b17023SJohn Marino || (host_integerp (len, 1)
8778e4b17023SJohn Marino && (MIN (src_align, dest_align) / BITS_PER_UNIT
8779e4b17023SJohn Marino >= (unsigned HOST_WIDE_INT) tree_low_cst (len, 1))))
8780e4b17023SJohn Marino {
8781e4b17023SJohn Marino tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
8782e4b17023SJohn Marino if (!fn)
8783e4b17023SJohn Marino return NULL_TREE;
8784e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 3, dest, src, len);
8785e4b17023SJohn Marino }
8786e4b17023SJohn Marino
8787e4b17023SJohn Marino /* If *src and *dest can't overlap, optimize into memcpy as well. */
8788e4b17023SJohn Marino if (TREE_CODE (src) == ADDR_EXPR
8789e4b17023SJohn Marino && TREE_CODE (dest) == ADDR_EXPR)
8790e4b17023SJohn Marino {
8791e4b17023SJohn Marino tree src_base, dest_base, fn;
8792e4b17023SJohn Marino HOST_WIDE_INT src_offset = 0, dest_offset = 0;
8793e4b17023SJohn Marino HOST_WIDE_INT size = -1;
8794e4b17023SJohn Marino HOST_WIDE_INT maxsize = -1;
8795e4b17023SJohn Marino
8796e4b17023SJohn Marino srcvar = TREE_OPERAND (src, 0);
8797e4b17023SJohn Marino src_base = get_ref_base_and_extent (srcvar, &src_offset,
8798e4b17023SJohn Marino &size, &maxsize);
8799e4b17023SJohn Marino destvar = TREE_OPERAND (dest, 0);
8800e4b17023SJohn Marino dest_base = get_ref_base_and_extent (destvar, &dest_offset,
8801e4b17023SJohn Marino &size, &maxsize);
8802e4b17023SJohn Marino if (host_integerp (len, 1))
8803e4b17023SJohn Marino maxsize = tree_low_cst (len, 1);
8804e4b17023SJohn Marino else
8805e4b17023SJohn Marino maxsize = -1;
8806e4b17023SJohn Marino src_offset /= BITS_PER_UNIT;
8807e4b17023SJohn Marino dest_offset /= BITS_PER_UNIT;
8808e4b17023SJohn Marino if (SSA_VAR_P (src_base)
8809e4b17023SJohn Marino && SSA_VAR_P (dest_base))
8810e4b17023SJohn Marino {
8811e4b17023SJohn Marino if (operand_equal_p (src_base, dest_base, 0)
8812e4b17023SJohn Marino && ranges_overlap_p (src_offset, maxsize,
8813e4b17023SJohn Marino dest_offset, maxsize))
8814e4b17023SJohn Marino return NULL_TREE;
8815e4b17023SJohn Marino }
8816e4b17023SJohn Marino else if (TREE_CODE (src_base) == MEM_REF
8817e4b17023SJohn Marino && TREE_CODE (dest_base) == MEM_REF)
8818e4b17023SJohn Marino {
8819e4b17023SJohn Marino double_int off;
8820e4b17023SJohn Marino if (! operand_equal_p (TREE_OPERAND (src_base, 0),
8821e4b17023SJohn Marino TREE_OPERAND (dest_base, 0), 0))
8822e4b17023SJohn Marino return NULL_TREE;
8823e4b17023SJohn Marino off = double_int_add (mem_ref_offset (src_base),
8824e4b17023SJohn Marino shwi_to_double_int (src_offset));
8825e4b17023SJohn Marino if (!double_int_fits_in_shwi_p (off))
8826e4b17023SJohn Marino return NULL_TREE;
8827e4b17023SJohn Marino src_offset = off.low;
8828e4b17023SJohn Marino off = double_int_add (mem_ref_offset (dest_base),
8829e4b17023SJohn Marino shwi_to_double_int (dest_offset));
8830e4b17023SJohn Marino if (!double_int_fits_in_shwi_p (off))
8831e4b17023SJohn Marino return NULL_TREE;
8832e4b17023SJohn Marino dest_offset = off.low;
8833e4b17023SJohn Marino if (ranges_overlap_p (src_offset, maxsize,
8834e4b17023SJohn Marino dest_offset, maxsize))
8835e4b17023SJohn Marino return NULL_TREE;
8836e4b17023SJohn Marino }
8837e4b17023SJohn Marino else
8838e4b17023SJohn Marino return NULL_TREE;
8839e4b17023SJohn Marino
8840e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
8841e4b17023SJohn Marino if (!fn)
8842e4b17023SJohn Marino return NULL_TREE;
8843e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 3, dest, src, len);
8844e4b17023SJohn Marino }
8845e4b17023SJohn Marino
8846e4b17023SJohn Marino /* If the destination and source do not alias optimize into
8847e4b17023SJohn Marino memcpy as well. */
8848e4b17023SJohn Marino if ((is_gimple_min_invariant (dest)
8849e4b17023SJohn Marino || TREE_CODE (dest) == SSA_NAME)
8850e4b17023SJohn Marino && (is_gimple_min_invariant (src)
8851e4b17023SJohn Marino || TREE_CODE (src) == SSA_NAME))
8852e4b17023SJohn Marino {
8853e4b17023SJohn Marino ao_ref destr, srcr;
8854e4b17023SJohn Marino ao_ref_init_from_ptr_and_size (&destr, dest, len);
8855e4b17023SJohn Marino ao_ref_init_from_ptr_and_size (&srcr, src, len);
8856e4b17023SJohn Marino if (!refs_may_alias_p_1 (&destr, &srcr, false))
8857e4b17023SJohn Marino {
8858e4b17023SJohn Marino tree fn;
8859e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
8860e4b17023SJohn Marino if (!fn)
8861e4b17023SJohn Marino return NULL_TREE;
8862e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 3, dest, src, len);
8863e4b17023SJohn Marino }
8864e4b17023SJohn Marino }
8865e4b17023SJohn Marino
8866e4b17023SJohn Marino return NULL_TREE;
8867e4b17023SJohn Marino }
8868e4b17023SJohn Marino
8869e4b17023SJohn Marino if (!host_integerp (len, 0))
8870e4b17023SJohn Marino return NULL_TREE;
8871e4b17023SJohn Marino /* FIXME:
8872e4b17023SJohn Marino This logic lose for arguments like (type *)malloc (sizeof (type)),
8873e4b17023SJohn Marino since we strip the casts of up to VOID return value from malloc.
8874e4b17023SJohn Marino Perhaps we ought to inherit type from non-VOID argument here? */
8875e4b17023SJohn Marino STRIP_NOPS (src);
8876e4b17023SJohn Marino STRIP_NOPS (dest);
8877e4b17023SJohn Marino if (!POINTER_TYPE_P (TREE_TYPE (src))
8878e4b17023SJohn Marino || !POINTER_TYPE_P (TREE_TYPE (dest)))
8879e4b17023SJohn Marino return NULL_TREE;
8880e4b17023SJohn Marino /* As we fold (void *)(p + CST) to (void *)p + CST undo this here. */
8881e4b17023SJohn Marino if (TREE_CODE (src) == POINTER_PLUS_EXPR)
8882e4b17023SJohn Marino {
8883e4b17023SJohn Marino tree tem = TREE_OPERAND (src, 0);
8884e4b17023SJohn Marino STRIP_NOPS (tem);
8885e4b17023SJohn Marino if (tem != TREE_OPERAND (src, 0))
8886e4b17023SJohn Marino src = build1 (NOP_EXPR, TREE_TYPE (tem), src);
8887e4b17023SJohn Marino }
8888e4b17023SJohn Marino if (TREE_CODE (dest) == POINTER_PLUS_EXPR)
8889e4b17023SJohn Marino {
8890e4b17023SJohn Marino tree tem = TREE_OPERAND (dest, 0);
8891e4b17023SJohn Marino STRIP_NOPS (tem);
8892e4b17023SJohn Marino if (tem != TREE_OPERAND (dest, 0))
8893e4b17023SJohn Marino dest = build1 (NOP_EXPR, TREE_TYPE (tem), dest);
8894e4b17023SJohn Marino }
8895e4b17023SJohn Marino srctype = TREE_TYPE (TREE_TYPE (src));
8896e4b17023SJohn Marino if (TREE_CODE (srctype) == ARRAY_TYPE
8897e4b17023SJohn Marino && !tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
8898e4b17023SJohn Marino {
8899e4b17023SJohn Marino srctype = TREE_TYPE (srctype);
8900e4b17023SJohn Marino STRIP_NOPS (src);
8901e4b17023SJohn Marino src = build1 (NOP_EXPR, build_pointer_type (srctype), src);
8902e4b17023SJohn Marino }
8903e4b17023SJohn Marino desttype = TREE_TYPE (TREE_TYPE (dest));
8904e4b17023SJohn Marino if (TREE_CODE (desttype) == ARRAY_TYPE
8905e4b17023SJohn Marino && !tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len))
8906e4b17023SJohn Marino {
8907e4b17023SJohn Marino desttype = TREE_TYPE (desttype);
8908e4b17023SJohn Marino STRIP_NOPS (dest);
8909e4b17023SJohn Marino dest = build1 (NOP_EXPR, build_pointer_type (desttype), dest);
8910e4b17023SJohn Marino }
8911e4b17023SJohn Marino if (TREE_ADDRESSABLE (srctype)
8912e4b17023SJohn Marino || TREE_ADDRESSABLE (desttype))
8913e4b17023SJohn Marino return NULL_TREE;
8914e4b17023SJohn Marino
8915e4b17023SJohn Marino src_align = get_pointer_alignment (src);
8916e4b17023SJohn Marino dest_align = get_pointer_alignment (dest);
8917e4b17023SJohn Marino if (dest_align < TYPE_ALIGN (desttype)
8918e4b17023SJohn Marino || src_align < TYPE_ALIGN (srctype))
8919e4b17023SJohn Marino return NULL_TREE;
8920e4b17023SJohn Marino
8921e4b17023SJohn Marino if (!ignore)
8922e4b17023SJohn Marino dest = builtin_save_expr (dest);
8923e4b17023SJohn Marino
8924e4b17023SJohn Marino /* Build accesses at offset zero with a ref-all character type. */
8925e4b17023SJohn Marino off0 = build_int_cst (build_pointer_type_for_mode (char_type_node,
8926e4b17023SJohn Marino ptr_mode, true), 0);
8927e4b17023SJohn Marino
8928e4b17023SJohn Marino destvar = dest;
8929e4b17023SJohn Marino STRIP_NOPS (destvar);
8930e4b17023SJohn Marino if (TREE_CODE (destvar) == ADDR_EXPR
8931e4b17023SJohn Marino && var_decl_component_p (TREE_OPERAND (destvar, 0))
8932e4b17023SJohn Marino && tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len))
8933e4b17023SJohn Marino destvar = fold_build2 (MEM_REF, desttype, destvar, off0);
8934e4b17023SJohn Marino else
8935e4b17023SJohn Marino destvar = NULL_TREE;
8936e4b17023SJohn Marino
8937e4b17023SJohn Marino srcvar = src;
8938e4b17023SJohn Marino STRIP_NOPS (srcvar);
8939e4b17023SJohn Marino if (TREE_CODE (srcvar) == ADDR_EXPR
8940e4b17023SJohn Marino && var_decl_component_p (TREE_OPERAND (srcvar, 0))
8941e4b17023SJohn Marino && tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
8942e4b17023SJohn Marino {
8943e4b17023SJohn Marino if (!destvar
8944e4b17023SJohn Marino || src_align >= TYPE_ALIGN (desttype))
8945e4b17023SJohn Marino srcvar = fold_build2 (MEM_REF, destvar ? desttype : srctype,
8946e4b17023SJohn Marino srcvar, off0);
8947e4b17023SJohn Marino else if (!STRICT_ALIGNMENT)
8948e4b17023SJohn Marino {
8949e4b17023SJohn Marino srctype = build_aligned_type (TYPE_MAIN_VARIANT (desttype),
8950e4b17023SJohn Marino src_align);
8951e4b17023SJohn Marino srcvar = fold_build2 (MEM_REF, srctype, srcvar, off0);
8952e4b17023SJohn Marino }
8953e4b17023SJohn Marino else
8954e4b17023SJohn Marino srcvar = NULL_TREE;
8955e4b17023SJohn Marino }
8956e4b17023SJohn Marino else
8957e4b17023SJohn Marino srcvar = NULL_TREE;
8958e4b17023SJohn Marino
8959e4b17023SJohn Marino if (srcvar == NULL_TREE && destvar == NULL_TREE)
8960e4b17023SJohn Marino return NULL_TREE;
8961e4b17023SJohn Marino
8962e4b17023SJohn Marino if (srcvar == NULL_TREE)
8963e4b17023SJohn Marino {
8964e4b17023SJohn Marino STRIP_NOPS (src);
8965e4b17023SJohn Marino if (src_align >= TYPE_ALIGN (desttype))
8966e4b17023SJohn Marino srcvar = fold_build2 (MEM_REF, desttype, src, off0);
8967e4b17023SJohn Marino else
8968e4b17023SJohn Marino {
8969e4b17023SJohn Marino if (STRICT_ALIGNMENT)
8970e4b17023SJohn Marino return NULL_TREE;
8971e4b17023SJohn Marino srctype = build_aligned_type (TYPE_MAIN_VARIANT (desttype),
8972e4b17023SJohn Marino src_align);
8973e4b17023SJohn Marino srcvar = fold_build2 (MEM_REF, srctype, src, off0);
8974e4b17023SJohn Marino }
8975e4b17023SJohn Marino }
8976e4b17023SJohn Marino else if (destvar == NULL_TREE)
8977e4b17023SJohn Marino {
8978e4b17023SJohn Marino STRIP_NOPS (dest);
8979e4b17023SJohn Marino if (dest_align >= TYPE_ALIGN (srctype))
8980e4b17023SJohn Marino destvar = fold_build2 (MEM_REF, srctype, dest, off0);
8981e4b17023SJohn Marino else
8982e4b17023SJohn Marino {
8983e4b17023SJohn Marino if (STRICT_ALIGNMENT)
8984e4b17023SJohn Marino return NULL_TREE;
8985e4b17023SJohn Marino desttype = build_aligned_type (TYPE_MAIN_VARIANT (srctype),
8986e4b17023SJohn Marino dest_align);
8987e4b17023SJohn Marino destvar = fold_build2 (MEM_REF, desttype, dest, off0);
8988e4b17023SJohn Marino }
8989e4b17023SJohn Marino }
8990e4b17023SJohn Marino
8991e4b17023SJohn Marino expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, srcvar);
8992e4b17023SJohn Marino }
8993e4b17023SJohn Marino
8994e4b17023SJohn Marino if (ignore)
8995e4b17023SJohn Marino return expr;
8996e4b17023SJohn Marino
8997e4b17023SJohn Marino if (endp == 0 || endp == 3)
8998e4b17023SJohn Marino return omit_one_operand_loc (loc, type, dest, expr);
8999e4b17023SJohn Marino
9000e4b17023SJohn Marino if (expr == len)
9001e4b17023SJohn Marino expr = NULL_TREE;
9002e4b17023SJohn Marino
9003e4b17023SJohn Marino if (endp == 2)
9004e4b17023SJohn Marino len = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (len), len,
9005e4b17023SJohn Marino ssize_int (1));
9006e4b17023SJohn Marino
9007e4b17023SJohn Marino dest = fold_build_pointer_plus_loc (loc, dest, len);
9008e4b17023SJohn Marino dest = fold_convert_loc (loc, type, dest);
9009e4b17023SJohn Marino if (expr)
9010e4b17023SJohn Marino dest = omit_one_operand_loc (loc, type, dest, expr);
9011e4b17023SJohn Marino return dest;
9012e4b17023SJohn Marino }
9013e4b17023SJohn Marino
9014e4b17023SJohn Marino /* Fold function call to builtin strcpy with arguments DEST and SRC.
9015e4b17023SJohn Marino If LEN is not NULL, it represents the length of the string to be
9016e4b17023SJohn Marino copied. Return NULL_TREE if no simplification can be made. */
9017e4b17023SJohn Marino
9018e4b17023SJohn Marino tree
fold_builtin_strcpy(location_t loc,tree fndecl,tree dest,tree src,tree len)9019e4b17023SJohn Marino fold_builtin_strcpy (location_t loc, tree fndecl, tree dest, tree src, tree len)
9020e4b17023SJohn Marino {
9021e4b17023SJohn Marino tree fn;
9022e4b17023SJohn Marino
9023e4b17023SJohn Marino if (!validate_arg (dest, POINTER_TYPE)
9024e4b17023SJohn Marino || !validate_arg (src, POINTER_TYPE))
9025e4b17023SJohn Marino return NULL_TREE;
9026e4b17023SJohn Marino
9027e4b17023SJohn Marino /* If SRC and DEST are the same (and not volatile), return DEST. */
9028e4b17023SJohn Marino if (operand_equal_p (src, dest, 0))
9029e4b17023SJohn Marino return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), dest);
9030e4b17023SJohn Marino
9031e4b17023SJohn Marino if (optimize_function_for_size_p (cfun))
9032e4b17023SJohn Marino return NULL_TREE;
9033e4b17023SJohn Marino
9034e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
9035e4b17023SJohn Marino if (!fn)
9036e4b17023SJohn Marino return NULL_TREE;
9037e4b17023SJohn Marino
9038e4b17023SJohn Marino if (!len)
9039e4b17023SJohn Marino {
9040e4b17023SJohn Marino len = c_strlen (src, 1);
9041e4b17023SJohn Marino if (! len || TREE_SIDE_EFFECTS (len))
9042e4b17023SJohn Marino return NULL_TREE;
9043e4b17023SJohn Marino }
9044e4b17023SJohn Marino
9045e4b17023SJohn Marino len = fold_convert_loc (loc, size_type_node, len);
9046e4b17023SJohn Marino len = size_binop_loc (loc, PLUS_EXPR, len, build_int_cst (size_type_node, 1));
9047e4b17023SJohn Marino return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)),
9048e4b17023SJohn Marino build_call_expr_loc (loc, fn, 3, dest, src, len));
9049e4b17023SJohn Marino }
9050e4b17023SJohn Marino
9051e4b17023SJohn Marino /* Fold function call to builtin stpcpy with arguments DEST and SRC.
9052e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
9053e4b17023SJohn Marino
9054e4b17023SJohn Marino static tree
fold_builtin_stpcpy(location_t loc,tree fndecl,tree dest,tree src)9055e4b17023SJohn Marino fold_builtin_stpcpy (location_t loc, tree fndecl, tree dest, tree src)
9056e4b17023SJohn Marino {
9057e4b17023SJohn Marino tree fn, len, lenp1, call, type;
9058e4b17023SJohn Marino
9059e4b17023SJohn Marino if (!validate_arg (dest, POINTER_TYPE)
9060e4b17023SJohn Marino || !validate_arg (src, POINTER_TYPE))
9061e4b17023SJohn Marino return NULL_TREE;
9062e4b17023SJohn Marino
9063e4b17023SJohn Marino len = c_strlen (src, 1);
9064e4b17023SJohn Marino if (!len
9065e4b17023SJohn Marino || TREE_CODE (len) != INTEGER_CST)
9066e4b17023SJohn Marino return NULL_TREE;
9067e4b17023SJohn Marino
9068e4b17023SJohn Marino if (optimize_function_for_size_p (cfun)
9069e4b17023SJohn Marino /* If length is zero it's small enough. */
9070e4b17023SJohn Marino && !integer_zerop (len))
9071e4b17023SJohn Marino return NULL_TREE;
9072e4b17023SJohn Marino
9073e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
9074e4b17023SJohn Marino if (!fn)
9075e4b17023SJohn Marino return NULL_TREE;
9076e4b17023SJohn Marino
9077e4b17023SJohn Marino lenp1 = size_binop_loc (loc, PLUS_EXPR,
9078e4b17023SJohn Marino fold_convert_loc (loc, size_type_node, len),
9079e4b17023SJohn Marino build_int_cst (size_type_node, 1));
9080e4b17023SJohn Marino /* We use dest twice in building our expression. Save it from
9081e4b17023SJohn Marino multiple expansions. */
9082e4b17023SJohn Marino dest = builtin_save_expr (dest);
9083e4b17023SJohn Marino call = build_call_expr_loc (loc, fn, 3, dest, src, lenp1);
9084e4b17023SJohn Marino
9085e4b17023SJohn Marino type = TREE_TYPE (TREE_TYPE (fndecl));
9086e4b17023SJohn Marino dest = fold_build_pointer_plus_loc (loc, dest, len);
9087e4b17023SJohn Marino dest = fold_convert_loc (loc, type, dest);
9088e4b17023SJohn Marino dest = omit_one_operand_loc (loc, type, dest, call);
9089e4b17023SJohn Marino return dest;
9090e4b17023SJohn Marino }
9091e4b17023SJohn Marino
9092e4b17023SJohn Marino /* Fold function call to builtin strncpy with arguments DEST, SRC, and LEN.
9093e4b17023SJohn Marino If SLEN is not NULL, it represents the length of the source string.
9094e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
9095e4b17023SJohn Marino
9096e4b17023SJohn Marino tree
fold_builtin_strncpy(location_t loc,tree fndecl,tree dest,tree src,tree len,tree slen)9097e4b17023SJohn Marino fold_builtin_strncpy (location_t loc, tree fndecl, tree dest,
9098e4b17023SJohn Marino tree src, tree len, tree slen)
9099e4b17023SJohn Marino {
9100e4b17023SJohn Marino tree fn;
9101e4b17023SJohn Marino
9102e4b17023SJohn Marino if (!validate_arg (dest, POINTER_TYPE)
9103e4b17023SJohn Marino || !validate_arg (src, POINTER_TYPE)
9104e4b17023SJohn Marino || !validate_arg (len, INTEGER_TYPE))
9105e4b17023SJohn Marino return NULL_TREE;
9106e4b17023SJohn Marino
9107e4b17023SJohn Marino /* If the LEN parameter is zero, return DEST. */
9108e4b17023SJohn Marino if (integer_zerop (len))
9109e4b17023SJohn Marino return omit_one_operand_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
9110e4b17023SJohn Marino
9111e4b17023SJohn Marino /* We can't compare slen with len as constants below if len is not a
9112e4b17023SJohn Marino constant. */
9113e4b17023SJohn Marino if (len == 0 || TREE_CODE (len) != INTEGER_CST)
9114e4b17023SJohn Marino return NULL_TREE;
9115e4b17023SJohn Marino
9116e4b17023SJohn Marino if (!slen)
9117e4b17023SJohn Marino slen = c_strlen (src, 1);
9118e4b17023SJohn Marino
9119e4b17023SJohn Marino /* Now, we must be passed a constant src ptr parameter. */
9120e4b17023SJohn Marino if (slen == 0 || TREE_CODE (slen) != INTEGER_CST)
9121e4b17023SJohn Marino return NULL_TREE;
9122e4b17023SJohn Marino
9123e4b17023SJohn Marino slen = size_binop_loc (loc, PLUS_EXPR, slen, ssize_int (1));
9124e4b17023SJohn Marino
9125e4b17023SJohn Marino /* We do not support simplification of this case, though we do
9126e4b17023SJohn Marino support it when expanding trees into RTL. */
9127e4b17023SJohn Marino /* FIXME: generate a call to __builtin_memset. */
9128e4b17023SJohn Marino if (tree_int_cst_lt (slen, len))
9129e4b17023SJohn Marino return NULL_TREE;
9130e4b17023SJohn Marino
9131e4b17023SJohn Marino /* OK transform into builtin memcpy. */
9132e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
9133e4b17023SJohn Marino if (!fn)
9134e4b17023SJohn Marino return NULL_TREE;
9135e4b17023SJohn Marino
9136e4b17023SJohn Marino len = fold_convert_loc (loc, size_type_node, len);
9137e4b17023SJohn Marino return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)),
9138e4b17023SJohn Marino build_call_expr_loc (loc, fn, 3, dest, src, len));
9139e4b17023SJohn Marino }
9140e4b17023SJohn Marino
9141e4b17023SJohn Marino /* Fold function call to builtin memchr. ARG1, ARG2 and LEN are the
9142e4b17023SJohn Marino arguments to the call, and TYPE is its return type.
9143e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
9144e4b17023SJohn Marino
9145e4b17023SJohn Marino static tree
fold_builtin_memchr(location_t loc,tree arg1,tree arg2,tree len,tree type)9146e4b17023SJohn Marino fold_builtin_memchr (location_t loc, tree arg1, tree arg2, tree len, tree type)
9147e4b17023SJohn Marino {
9148e4b17023SJohn Marino if (!validate_arg (arg1, POINTER_TYPE)
9149e4b17023SJohn Marino || !validate_arg (arg2, INTEGER_TYPE)
9150e4b17023SJohn Marino || !validate_arg (len, INTEGER_TYPE))
9151e4b17023SJohn Marino return NULL_TREE;
9152e4b17023SJohn Marino else
9153e4b17023SJohn Marino {
9154e4b17023SJohn Marino const char *p1;
9155e4b17023SJohn Marino
9156e4b17023SJohn Marino if (TREE_CODE (arg2) != INTEGER_CST
9157e4b17023SJohn Marino || !host_integerp (len, 1))
9158e4b17023SJohn Marino return NULL_TREE;
9159e4b17023SJohn Marino
9160e4b17023SJohn Marino p1 = c_getstr (arg1);
9161e4b17023SJohn Marino if (p1 && compare_tree_int (len, strlen (p1) + 1) <= 0)
9162e4b17023SJohn Marino {
9163e4b17023SJohn Marino char c;
9164e4b17023SJohn Marino const char *r;
9165e4b17023SJohn Marino tree tem;
9166e4b17023SJohn Marino
9167e4b17023SJohn Marino if (target_char_cast (arg2, &c))
9168e4b17023SJohn Marino return NULL_TREE;
9169e4b17023SJohn Marino
9170e4b17023SJohn Marino r = (const char *) memchr (p1, c, tree_low_cst (len, 1));
9171e4b17023SJohn Marino
9172e4b17023SJohn Marino if (r == NULL)
9173e4b17023SJohn Marino return build_int_cst (TREE_TYPE (arg1), 0);
9174e4b17023SJohn Marino
9175e4b17023SJohn Marino tem = fold_build_pointer_plus_hwi_loc (loc, arg1, r - p1);
9176e4b17023SJohn Marino return fold_convert_loc (loc, type, tem);
9177e4b17023SJohn Marino }
9178e4b17023SJohn Marino return NULL_TREE;
9179e4b17023SJohn Marino }
9180e4b17023SJohn Marino }
9181e4b17023SJohn Marino
9182e4b17023SJohn Marino /* Fold function call to builtin memcmp with arguments ARG1 and ARG2.
9183e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
9184e4b17023SJohn Marino
9185e4b17023SJohn Marino static tree
fold_builtin_memcmp(location_t loc,tree arg1,tree arg2,tree len)9186e4b17023SJohn Marino fold_builtin_memcmp (location_t loc, tree arg1, tree arg2, tree len)
9187e4b17023SJohn Marino {
9188e4b17023SJohn Marino const char *p1, *p2;
9189e4b17023SJohn Marino
9190e4b17023SJohn Marino if (!validate_arg (arg1, POINTER_TYPE)
9191e4b17023SJohn Marino || !validate_arg (arg2, POINTER_TYPE)
9192e4b17023SJohn Marino || !validate_arg (len, INTEGER_TYPE))
9193e4b17023SJohn Marino return NULL_TREE;
9194e4b17023SJohn Marino
9195e4b17023SJohn Marino /* If the LEN parameter is zero, return zero. */
9196e4b17023SJohn Marino if (integer_zerop (len))
9197e4b17023SJohn Marino return omit_two_operands_loc (loc, integer_type_node, integer_zero_node,
9198e4b17023SJohn Marino arg1, arg2);
9199e4b17023SJohn Marino
9200e4b17023SJohn Marino /* If ARG1 and ARG2 are the same (and not volatile), return zero. */
9201e4b17023SJohn Marino if (operand_equal_p (arg1, arg2, 0))
9202e4b17023SJohn Marino return omit_one_operand_loc (loc, integer_type_node, integer_zero_node, len);
9203e4b17023SJohn Marino
9204e4b17023SJohn Marino p1 = c_getstr (arg1);
9205e4b17023SJohn Marino p2 = c_getstr (arg2);
9206e4b17023SJohn Marino
9207e4b17023SJohn Marino /* If all arguments are constant, and the value of len is not greater
9208e4b17023SJohn Marino than the lengths of arg1 and arg2, evaluate at compile-time. */
9209e4b17023SJohn Marino if (host_integerp (len, 1) && p1 && p2
9210e4b17023SJohn Marino && compare_tree_int (len, strlen (p1) + 1) <= 0
9211e4b17023SJohn Marino && compare_tree_int (len, strlen (p2) + 1) <= 0)
9212e4b17023SJohn Marino {
9213e4b17023SJohn Marino const int r = memcmp (p1, p2, tree_low_cst (len, 1));
9214e4b17023SJohn Marino
9215e4b17023SJohn Marino if (r > 0)
9216e4b17023SJohn Marino return integer_one_node;
9217e4b17023SJohn Marino else if (r < 0)
9218e4b17023SJohn Marino return integer_minus_one_node;
9219e4b17023SJohn Marino else
9220e4b17023SJohn Marino return integer_zero_node;
9221e4b17023SJohn Marino }
9222e4b17023SJohn Marino
9223e4b17023SJohn Marino /* If len parameter is one, return an expression corresponding to
9224e4b17023SJohn Marino (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */
9225e4b17023SJohn Marino if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
9226e4b17023SJohn Marino {
9227e4b17023SJohn Marino tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
9228e4b17023SJohn Marino tree cst_uchar_ptr_node
9229e4b17023SJohn Marino = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
9230e4b17023SJohn Marino
9231e4b17023SJohn Marino tree ind1
9232e4b17023SJohn Marino = fold_convert_loc (loc, integer_type_node,
9233e4b17023SJohn Marino build1 (INDIRECT_REF, cst_uchar_node,
9234e4b17023SJohn Marino fold_convert_loc (loc,
9235e4b17023SJohn Marino cst_uchar_ptr_node,
9236e4b17023SJohn Marino arg1)));
9237e4b17023SJohn Marino tree ind2
9238e4b17023SJohn Marino = fold_convert_loc (loc, integer_type_node,
9239e4b17023SJohn Marino build1 (INDIRECT_REF, cst_uchar_node,
9240e4b17023SJohn Marino fold_convert_loc (loc,
9241e4b17023SJohn Marino cst_uchar_ptr_node,
9242e4b17023SJohn Marino arg2)));
9243e4b17023SJohn Marino return fold_build2_loc (loc, MINUS_EXPR, integer_type_node, ind1, ind2);
9244e4b17023SJohn Marino }
9245e4b17023SJohn Marino
9246e4b17023SJohn Marino return NULL_TREE;
9247e4b17023SJohn Marino }
9248e4b17023SJohn Marino
9249e4b17023SJohn Marino /* Fold function call to builtin strcmp with arguments ARG1 and ARG2.
9250e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
9251e4b17023SJohn Marino
9252e4b17023SJohn Marino static tree
fold_builtin_strcmp(location_t loc,tree arg1,tree arg2)9253e4b17023SJohn Marino fold_builtin_strcmp (location_t loc, tree arg1, tree arg2)
9254e4b17023SJohn Marino {
9255e4b17023SJohn Marino const char *p1, *p2;
9256e4b17023SJohn Marino
9257e4b17023SJohn Marino if (!validate_arg (arg1, POINTER_TYPE)
9258e4b17023SJohn Marino || !validate_arg (arg2, POINTER_TYPE))
9259e4b17023SJohn Marino return NULL_TREE;
9260e4b17023SJohn Marino
9261e4b17023SJohn Marino /* If ARG1 and ARG2 are the same (and not volatile), return zero. */
9262e4b17023SJohn Marino if (operand_equal_p (arg1, arg2, 0))
9263e4b17023SJohn Marino return integer_zero_node;
9264e4b17023SJohn Marino
9265e4b17023SJohn Marino p1 = c_getstr (arg1);
9266e4b17023SJohn Marino p2 = c_getstr (arg2);
9267e4b17023SJohn Marino
9268e4b17023SJohn Marino if (p1 && p2)
9269e4b17023SJohn Marino {
9270e4b17023SJohn Marino const int i = strcmp (p1, p2);
9271e4b17023SJohn Marino if (i < 0)
9272e4b17023SJohn Marino return integer_minus_one_node;
9273e4b17023SJohn Marino else if (i > 0)
9274e4b17023SJohn Marino return integer_one_node;
9275e4b17023SJohn Marino else
9276e4b17023SJohn Marino return integer_zero_node;
9277e4b17023SJohn Marino }
9278e4b17023SJohn Marino
9279e4b17023SJohn Marino /* If the second arg is "", return *(const unsigned char*)arg1. */
9280e4b17023SJohn Marino if (p2 && *p2 == '\0')
9281e4b17023SJohn Marino {
9282e4b17023SJohn Marino tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
9283e4b17023SJohn Marino tree cst_uchar_ptr_node
9284e4b17023SJohn Marino = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
9285e4b17023SJohn Marino
9286e4b17023SJohn Marino return fold_convert_loc (loc, integer_type_node,
9287e4b17023SJohn Marino build1 (INDIRECT_REF, cst_uchar_node,
9288e4b17023SJohn Marino fold_convert_loc (loc,
9289e4b17023SJohn Marino cst_uchar_ptr_node,
9290e4b17023SJohn Marino arg1)));
9291e4b17023SJohn Marino }
9292e4b17023SJohn Marino
9293e4b17023SJohn Marino /* If the first arg is "", return -*(const unsigned char*)arg2. */
9294e4b17023SJohn Marino if (p1 && *p1 == '\0')
9295e4b17023SJohn Marino {
9296e4b17023SJohn Marino tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
9297e4b17023SJohn Marino tree cst_uchar_ptr_node
9298e4b17023SJohn Marino = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
9299e4b17023SJohn Marino
9300e4b17023SJohn Marino tree temp
9301e4b17023SJohn Marino = fold_convert_loc (loc, integer_type_node,
9302e4b17023SJohn Marino build1 (INDIRECT_REF, cst_uchar_node,
9303e4b17023SJohn Marino fold_convert_loc (loc,
9304e4b17023SJohn Marino cst_uchar_ptr_node,
9305e4b17023SJohn Marino arg2)));
9306e4b17023SJohn Marino return fold_build1_loc (loc, NEGATE_EXPR, integer_type_node, temp);
9307e4b17023SJohn Marino }
9308e4b17023SJohn Marino
9309e4b17023SJohn Marino return NULL_TREE;
9310e4b17023SJohn Marino }
9311e4b17023SJohn Marino
9312e4b17023SJohn Marino /* Fold function call to builtin strncmp with arguments ARG1, ARG2, and LEN.
9313e4b17023SJohn Marino Return NULL_TREE if no simplification can be made. */
9314e4b17023SJohn Marino
9315e4b17023SJohn Marino static tree
fold_builtin_strncmp(location_t loc,tree arg1,tree arg2,tree len)9316e4b17023SJohn Marino fold_builtin_strncmp (location_t loc, tree arg1, tree arg2, tree len)
9317e4b17023SJohn Marino {
9318e4b17023SJohn Marino const char *p1, *p2;
9319e4b17023SJohn Marino
9320e4b17023SJohn Marino if (!validate_arg (arg1, POINTER_TYPE)
9321e4b17023SJohn Marino || !validate_arg (arg2, POINTER_TYPE)
9322e4b17023SJohn Marino || !validate_arg (len, INTEGER_TYPE))
9323e4b17023SJohn Marino return NULL_TREE;
9324e4b17023SJohn Marino
9325e4b17023SJohn Marino /* If the LEN parameter is zero, return zero. */
9326e4b17023SJohn Marino if (integer_zerop (len))
9327e4b17023SJohn Marino return omit_two_operands_loc (loc, integer_type_node, integer_zero_node,
9328e4b17023SJohn Marino arg1, arg2);
9329e4b17023SJohn Marino
9330e4b17023SJohn Marino /* If ARG1 and ARG2 are the same (and not volatile), return zero. */
9331e4b17023SJohn Marino if (operand_equal_p (arg1, arg2, 0))
9332e4b17023SJohn Marino return omit_one_operand_loc (loc, integer_type_node, integer_zero_node, len);
9333e4b17023SJohn Marino
9334e4b17023SJohn Marino p1 = c_getstr (arg1);
9335e4b17023SJohn Marino p2 = c_getstr (arg2);
9336e4b17023SJohn Marino
9337e4b17023SJohn Marino if (host_integerp (len, 1) && p1 && p2)
9338e4b17023SJohn Marino {
9339e4b17023SJohn Marino const int i = strncmp (p1, p2, tree_low_cst (len, 1));
9340e4b17023SJohn Marino if (i > 0)
9341e4b17023SJohn Marino return integer_one_node;
9342e4b17023SJohn Marino else if (i < 0)
9343e4b17023SJohn Marino return integer_minus_one_node;
9344e4b17023SJohn Marino else
9345e4b17023SJohn Marino return integer_zero_node;
9346e4b17023SJohn Marino }
9347e4b17023SJohn Marino
9348e4b17023SJohn Marino /* If the second arg is "", and the length is greater than zero,
9349e4b17023SJohn Marino return *(const unsigned char*)arg1. */
9350e4b17023SJohn Marino if (p2 && *p2 == '\0'
9351e4b17023SJohn Marino && TREE_CODE (len) == INTEGER_CST
9352e4b17023SJohn Marino && tree_int_cst_sgn (len) == 1)
9353e4b17023SJohn Marino {
9354e4b17023SJohn Marino tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
9355e4b17023SJohn Marino tree cst_uchar_ptr_node
9356e4b17023SJohn Marino = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
9357e4b17023SJohn Marino
9358e4b17023SJohn Marino return fold_convert_loc (loc, integer_type_node,
9359e4b17023SJohn Marino build1 (INDIRECT_REF, cst_uchar_node,
9360e4b17023SJohn Marino fold_convert_loc (loc,
9361e4b17023SJohn Marino cst_uchar_ptr_node,
9362e4b17023SJohn Marino arg1)));
9363e4b17023SJohn Marino }
9364e4b17023SJohn Marino
9365e4b17023SJohn Marino /* If the first arg is "", and the length is greater than zero,
9366e4b17023SJohn Marino return -*(const unsigned char*)arg2. */
9367e4b17023SJohn Marino if (p1 && *p1 == '\0'
9368e4b17023SJohn Marino && TREE_CODE (len) == INTEGER_CST
9369e4b17023SJohn Marino && tree_int_cst_sgn (len) == 1)
9370e4b17023SJohn Marino {
9371e4b17023SJohn Marino tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
9372e4b17023SJohn Marino tree cst_uchar_ptr_node
9373e4b17023SJohn Marino = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
9374e4b17023SJohn Marino
9375e4b17023SJohn Marino tree temp = fold_convert_loc (loc, integer_type_node,
9376e4b17023SJohn Marino build1 (INDIRECT_REF, cst_uchar_node,
9377e4b17023SJohn Marino fold_convert_loc (loc,
9378e4b17023SJohn Marino cst_uchar_ptr_node,
9379e4b17023SJohn Marino arg2)));
9380e4b17023SJohn Marino return fold_build1_loc (loc, NEGATE_EXPR, integer_type_node, temp);
9381e4b17023SJohn Marino }
9382e4b17023SJohn Marino
9383e4b17023SJohn Marino /* If len parameter is one, return an expression corresponding to
9384e4b17023SJohn Marino (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */
9385e4b17023SJohn Marino if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
9386e4b17023SJohn Marino {
9387e4b17023SJohn Marino tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
9388e4b17023SJohn Marino tree cst_uchar_ptr_node
9389e4b17023SJohn Marino = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
9390e4b17023SJohn Marino
9391e4b17023SJohn Marino tree ind1 = fold_convert_loc (loc, integer_type_node,
9392e4b17023SJohn Marino build1 (INDIRECT_REF, cst_uchar_node,
9393e4b17023SJohn Marino fold_convert_loc (loc,
9394e4b17023SJohn Marino cst_uchar_ptr_node,
9395e4b17023SJohn Marino arg1)));
9396e4b17023SJohn Marino tree ind2 = fold_convert_loc (loc, integer_type_node,
9397e4b17023SJohn Marino build1 (INDIRECT_REF, cst_uchar_node,
9398e4b17023SJohn Marino fold_convert_loc (loc,
9399e4b17023SJohn Marino cst_uchar_ptr_node,
9400e4b17023SJohn Marino arg2)));
9401e4b17023SJohn Marino return fold_build2_loc (loc, MINUS_EXPR, integer_type_node, ind1, ind2);
9402e4b17023SJohn Marino }
9403e4b17023SJohn Marino
9404e4b17023SJohn Marino return NULL_TREE;
9405e4b17023SJohn Marino }
9406e4b17023SJohn Marino
9407e4b17023SJohn Marino /* Fold function call to builtin signbit, signbitf or signbitl with argument
9408e4b17023SJohn Marino ARG. Return NULL_TREE if no simplification can be made. */
9409e4b17023SJohn Marino
9410e4b17023SJohn Marino static tree
fold_builtin_signbit(location_t loc,tree arg,tree type)9411e4b17023SJohn Marino fold_builtin_signbit (location_t loc, tree arg, tree type)
9412e4b17023SJohn Marino {
9413e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
9414e4b17023SJohn Marino return NULL_TREE;
9415e4b17023SJohn Marino
9416e4b17023SJohn Marino /* If ARG is a compile-time constant, determine the result. */
9417e4b17023SJohn Marino if (TREE_CODE (arg) == REAL_CST
9418e4b17023SJohn Marino && !TREE_OVERFLOW (arg))
9419e4b17023SJohn Marino {
9420e4b17023SJohn Marino REAL_VALUE_TYPE c;
9421e4b17023SJohn Marino
9422e4b17023SJohn Marino c = TREE_REAL_CST (arg);
9423e4b17023SJohn Marino return (REAL_VALUE_NEGATIVE (c)
9424e4b17023SJohn Marino ? build_one_cst (type)
9425e4b17023SJohn Marino : build_zero_cst (type));
9426e4b17023SJohn Marino }
9427e4b17023SJohn Marino
9428e4b17023SJohn Marino /* If ARG is non-negative, the result is always zero. */
9429e4b17023SJohn Marino if (tree_expr_nonnegative_p (arg))
9430e4b17023SJohn Marino return omit_one_operand_loc (loc, type, integer_zero_node, arg);
9431e4b17023SJohn Marino
9432e4b17023SJohn Marino /* If ARG's format doesn't have signed zeros, return "arg < 0.0". */
9433e4b17023SJohn Marino if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg))))
9434e4b17023SJohn Marino return fold_convert (type,
9435e4b17023SJohn Marino fold_build2_loc (loc, LT_EXPR, boolean_type_node, arg,
9436e4b17023SJohn Marino build_real (TREE_TYPE (arg), dconst0)));
9437e4b17023SJohn Marino
9438e4b17023SJohn Marino return NULL_TREE;
9439e4b17023SJohn Marino }
9440e4b17023SJohn Marino
9441e4b17023SJohn Marino /* Fold function call to builtin copysign, copysignf or copysignl with
9442e4b17023SJohn Marino arguments ARG1 and ARG2. Return NULL_TREE if no simplification can
9443e4b17023SJohn Marino be made. */
9444e4b17023SJohn Marino
9445e4b17023SJohn Marino static tree
fold_builtin_copysign(location_t loc,tree fndecl,tree arg1,tree arg2,tree type)9446e4b17023SJohn Marino fold_builtin_copysign (location_t loc, tree fndecl,
9447e4b17023SJohn Marino tree arg1, tree arg2, tree type)
9448e4b17023SJohn Marino {
9449e4b17023SJohn Marino tree tem;
9450e4b17023SJohn Marino
9451e4b17023SJohn Marino if (!validate_arg (arg1, REAL_TYPE)
9452e4b17023SJohn Marino || !validate_arg (arg2, REAL_TYPE))
9453e4b17023SJohn Marino return NULL_TREE;
9454e4b17023SJohn Marino
9455e4b17023SJohn Marino /* copysign(X,X) is X. */
9456e4b17023SJohn Marino if (operand_equal_p (arg1, arg2, 0))
9457e4b17023SJohn Marino return fold_convert_loc (loc, type, arg1);
9458e4b17023SJohn Marino
9459e4b17023SJohn Marino /* If ARG1 and ARG2 are compile-time constants, determine the result. */
9460e4b17023SJohn Marino if (TREE_CODE (arg1) == REAL_CST
9461e4b17023SJohn Marino && TREE_CODE (arg2) == REAL_CST
9462e4b17023SJohn Marino && !TREE_OVERFLOW (arg1)
9463e4b17023SJohn Marino && !TREE_OVERFLOW (arg2))
9464e4b17023SJohn Marino {
9465e4b17023SJohn Marino REAL_VALUE_TYPE c1, c2;
9466e4b17023SJohn Marino
9467e4b17023SJohn Marino c1 = TREE_REAL_CST (arg1);
9468e4b17023SJohn Marino c2 = TREE_REAL_CST (arg2);
9469e4b17023SJohn Marino /* c1.sign := c2.sign. */
9470e4b17023SJohn Marino real_copysign (&c1, &c2);
9471e4b17023SJohn Marino return build_real (type, c1);
9472e4b17023SJohn Marino }
9473e4b17023SJohn Marino
9474e4b17023SJohn Marino /* copysign(X, Y) is fabs(X) when Y is always non-negative.
9475e4b17023SJohn Marino Remember to evaluate Y for side-effects. */
9476e4b17023SJohn Marino if (tree_expr_nonnegative_p (arg2))
9477e4b17023SJohn Marino return omit_one_operand_loc (loc, type,
9478e4b17023SJohn Marino fold_build1_loc (loc, ABS_EXPR, type, arg1),
9479e4b17023SJohn Marino arg2);
9480e4b17023SJohn Marino
9481e4b17023SJohn Marino /* Strip sign changing operations for the first argument. */
9482e4b17023SJohn Marino tem = fold_strip_sign_ops (arg1);
9483e4b17023SJohn Marino if (tem)
9484e4b17023SJohn Marino return build_call_expr_loc (loc, fndecl, 2, tem, arg2);
9485e4b17023SJohn Marino
9486e4b17023SJohn Marino return NULL_TREE;
9487e4b17023SJohn Marino }
9488e4b17023SJohn Marino
9489e4b17023SJohn Marino /* Fold a call to builtin isascii with argument ARG. */
9490e4b17023SJohn Marino
9491e4b17023SJohn Marino static tree
fold_builtin_isascii(location_t loc,tree arg)9492e4b17023SJohn Marino fold_builtin_isascii (location_t loc, tree arg)
9493e4b17023SJohn Marino {
9494e4b17023SJohn Marino if (!validate_arg (arg, INTEGER_TYPE))
9495e4b17023SJohn Marino return NULL_TREE;
9496e4b17023SJohn Marino else
9497e4b17023SJohn Marino {
9498e4b17023SJohn Marino /* Transform isascii(c) -> ((c & ~0x7f) == 0). */
9499e4b17023SJohn Marino arg = fold_build2 (BIT_AND_EXPR, integer_type_node, arg,
9500e4b17023SJohn Marino build_int_cst (integer_type_node,
9501e4b17023SJohn Marino ~ (unsigned HOST_WIDE_INT) 0x7f));
9502e4b17023SJohn Marino return fold_build2_loc (loc, EQ_EXPR, integer_type_node,
9503e4b17023SJohn Marino arg, integer_zero_node);
9504e4b17023SJohn Marino }
9505e4b17023SJohn Marino }
9506e4b17023SJohn Marino
9507e4b17023SJohn Marino /* Fold a call to builtin toascii with argument ARG. */
9508e4b17023SJohn Marino
9509e4b17023SJohn Marino static tree
fold_builtin_toascii(location_t loc,tree arg)9510e4b17023SJohn Marino fold_builtin_toascii (location_t loc, tree arg)
9511e4b17023SJohn Marino {
9512e4b17023SJohn Marino if (!validate_arg (arg, INTEGER_TYPE))
9513e4b17023SJohn Marino return NULL_TREE;
9514e4b17023SJohn Marino
9515e4b17023SJohn Marino /* Transform toascii(c) -> (c & 0x7f). */
9516e4b17023SJohn Marino return fold_build2_loc (loc, BIT_AND_EXPR, integer_type_node, arg,
9517e4b17023SJohn Marino build_int_cst (integer_type_node, 0x7f));
9518e4b17023SJohn Marino }
9519e4b17023SJohn Marino
9520e4b17023SJohn Marino /* Fold a call to builtin isdigit with argument ARG. */
9521e4b17023SJohn Marino
9522e4b17023SJohn Marino static tree
fold_builtin_isdigit(location_t loc,tree arg)9523e4b17023SJohn Marino fold_builtin_isdigit (location_t loc, tree arg)
9524e4b17023SJohn Marino {
9525e4b17023SJohn Marino if (!validate_arg (arg, INTEGER_TYPE))
9526e4b17023SJohn Marino return NULL_TREE;
9527e4b17023SJohn Marino else
9528e4b17023SJohn Marino {
9529e4b17023SJohn Marino /* Transform isdigit(c) -> (unsigned)(c) - '0' <= 9. */
9530e4b17023SJohn Marino /* According to the C standard, isdigit is unaffected by locale.
9531e4b17023SJohn Marino However, it definitely is affected by the target character set. */
9532e4b17023SJohn Marino unsigned HOST_WIDE_INT target_digit0
9533e4b17023SJohn Marino = lang_hooks.to_target_charset ('0');
9534e4b17023SJohn Marino
9535e4b17023SJohn Marino if (target_digit0 == 0)
9536e4b17023SJohn Marino return NULL_TREE;
9537e4b17023SJohn Marino
9538e4b17023SJohn Marino arg = fold_convert_loc (loc, unsigned_type_node, arg);
9539e4b17023SJohn Marino arg = fold_build2 (MINUS_EXPR, unsigned_type_node, arg,
9540e4b17023SJohn Marino build_int_cst (unsigned_type_node, target_digit0));
9541e4b17023SJohn Marino return fold_build2_loc (loc, LE_EXPR, integer_type_node, arg,
9542e4b17023SJohn Marino build_int_cst (unsigned_type_node, 9));
9543e4b17023SJohn Marino }
9544e4b17023SJohn Marino }
9545e4b17023SJohn Marino
9546e4b17023SJohn Marino /* Fold a call to fabs, fabsf or fabsl with argument ARG. */
9547e4b17023SJohn Marino
9548e4b17023SJohn Marino static tree
fold_builtin_fabs(location_t loc,tree arg,tree type)9549e4b17023SJohn Marino fold_builtin_fabs (location_t loc, tree arg, tree type)
9550e4b17023SJohn Marino {
9551e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
9552e4b17023SJohn Marino return NULL_TREE;
9553e4b17023SJohn Marino
9554e4b17023SJohn Marino arg = fold_convert_loc (loc, type, arg);
9555e4b17023SJohn Marino if (TREE_CODE (arg) == REAL_CST)
9556e4b17023SJohn Marino return fold_abs_const (arg, type);
9557e4b17023SJohn Marino return fold_build1_loc (loc, ABS_EXPR, type, arg);
9558e4b17023SJohn Marino }
9559e4b17023SJohn Marino
9560e4b17023SJohn Marino /* Fold a call to abs, labs, llabs or imaxabs with argument ARG. */
9561e4b17023SJohn Marino
9562e4b17023SJohn Marino static tree
fold_builtin_abs(location_t loc,tree arg,tree type)9563e4b17023SJohn Marino fold_builtin_abs (location_t loc, tree arg, tree type)
9564e4b17023SJohn Marino {
9565e4b17023SJohn Marino if (!validate_arg (arg, INTEGER_TYPE))
9566e4b17023SJohn Marino return NULL_TREE;
9567e4b17023SJohn Marino
9568e4b17023SJohn Marino arg = fold_convert_loc (loc, type, arg);
9569e4b17023SJohn Marino if (TREE_CODE (arg) == INTEGER_CST)
9570e4b17023SJohn Marino return fold_abs_const (arg, type);
9571e4b17023SJohn Marino return fold_build1_loc (loc, ABS_EXPR, type, arg);
9572e4b17023SJohn Marino }
9573e4b17023SJohn Marino
9574e4b17023SJohn Marino /* Fold a fma operation with arguments ARG[012]. */
9575e4b17023SJohn Marino
9576e4b17023SJohn Marino tree
fold_fma(location_t loc ATTRIBUTE_UNUSED,tree type,tree arg0,tree arg1,tree arg2)9577e4b17023SJohn Marino fold_fma (location_t loc ATTRIBUTE_UNUSED,
9578e4b17023SJohn Marino tree type, tree arg0, tree arg1, tree arg2)
9579e4b17023SJohn Marino {
9580e4b17023SJohn Marino if (TREE_CODE (arg0) == REAL_CST
9581e4b17023SJohn Marino && TREE_CODE (arg1) == REAL_CST
9582e4b17023SJohn Marino && TREE_CODE (arg2) == REAL_CST)
9583e4b17023SJohn Marino return do_mpfr_arg3 (arg0, arg1, arg2, type, mpfr_fma);
9584e4b17023SJohn Marino
9585e4b17023SJohn Marino return NULL_TREE;
9586e4b17023SJohn Marino }
9587e4b17023SJohn Marino
9588e4b17023SJohn Marino /* Fold a call to fma, fmaf, or fmal with arguments ARG[012]. */
9589e4b17023SJohn Marino
9590e4b17023SJohn Marino static tree
fold_builtin_fma(location_t loc,tree arg0,tree arg1,tree arg2,tree type)9591e4b17023SJohn Marino fold_builtin_fma (location_t loc, tree arg0, tree arg1, tree arg2, tree type)
9592e4b17023SJohn Marino {
9593e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE)
9594e4b17023SJohn Marino && validate_arg(arg1, REAL_TYPE)
9595e4b17023SJohn Marino && validate_arg(arg2, REAL_TYPE))
9596e4b17023SJohn Marino {
9597e4b17023SJohn Marino tree tem = fold_fma (loc, type, arg0, arg1, arg2);
9598e4b17023SJohn Marino if (tem)
9599e4b17023SJohn Marino return tem;
9600e4b17023SJohn Marino
9601e4b17023SJohn Marino /* ??? Only expand to FMA_EXPR if it's directly supported. */
9602e4b17023SJohn Marino if (optab_handler (fma_optab, TYPE_MODE (type)) != CODE_FOR_nothing)
9603e4b17023SJohn Marino return fold_build3_loc (loc, FMA_EXPR, type, arg0, arg1, arg2);
9604e4b17023SJohn Marino }
9605e4b17023SJohn Marino return NULL_TREE;
9606e4b17023SJohn Marino }
9607e4b17023SJohn Marino
9608e4b17023SJohn Marino /* Fold a call to builtin fmin or fmax. */
9609e4b17023SJohn Marino
9610e4b17023SJohn Marino static tree
fold_builtin_fmin_fmax(location_t loc,tree arg0,tree arg1,tree type,bool max)9611e4b17023SJohn Marino fold_builtin_fmin_fmax (location_t loc, tree arg0, tree arg1,
9612e4b17023SJohn Marino tree type, bool max)
9613e4b17023SJohn Marino {
9614e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE) && validate_arg (arg1, REAL_TYPE))
9615e4b17023SJohn Marino {
9616e4b17023SJohn Marino /* Calculate the result when the argument is a constant. */
9617e4b17023SJohn Marino tree res = do_mpfr_arg2 (arg0, arg1, type, (max ? mpfr_max : mpfr_min));
9618e4b17023SJohn Marino
9619e4b17023SJohn Marino if (res)
9620e4b17023SJohn Marino return res;
9621e4b17023SJohn Marino
9622e4b17023SJohn Marino /* If either argument is NaN, return the other one. Avoid the
9623e4b17023SJohn Marino transformation if we get (and honor) a signalling NaN. Using
9624e4b17023SJohn Marino omit_one_operand() ensures we create a non-lvalue. */
9625e4b17023SJohn Marino if (TREE_CODE (arg0) == REAL_CST
9626e4b17023SJohn Marino && real_isnan (&TREE_REAL_CST (arg0))
9627e4b17023SJohn Marino && (! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
9628e4b17023SJohn Marino || ! TREE_REAL_CST (arg0).signalling))
9629e4b17023SJohn Marino return omit_one_operand_loc (loc, type, arg1, arg0);
9630e4b17023SJohn Marino if (TREE_CODE (arg1) == REAL_CST
9631e4b17023SJohn Marino && real_isnan (&TREE_REAL_CST (arg1))
9632e4b17023SJohn Marino && (! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1)))
9633e4b17023SJohn Marino || ! TREE_REAL_CST (arg1).signalling))
9634e4b17023SJohn Marino return omit_one_operand_loc (loc, type, arg0, arg1);
9635e4b17023SJohn Marino
9636e4b17023SJohn Marino /* Transform fmin/fmax(x,x) -> x. */
9637e4b17023SJohn Marino if (operand_equal_p (arg0, arg1, OEP_PURE_SAME))
9638e4b17023SJohn Marino return omit_one_operand_loc (loc, type, arg0, arg1);
9639e4b17023SJohn Marino
9640e4b17023SJohn Marino /* Convert fmin/fmax to MIN_EXPR/MAX_EXPR. C99 requires these
9641e4b17023SJohn Marino functions to return the numeric arg if the other one is NaN.
9642e4b17023SJohn Marino These tree codes don't honor that, so only transform if
9643e4b17023SJohn Marino -ffinite-math-only is set. C99 doesn't require -0.0 to be
9644e4b17023SJohn Marino handled, so we don't have to worry about it either. */
9645e4b17023SJohn Marino if (flag_finite_math_only)
9646e4b17023SJohn Marino return fold_build2_loc (loc, (max ? MAX_EXPR : MIN_EXPR), type,
9647e4b17023SJohn Marino fold_convert_loc (loc, type, arg0),
9648e4b17023SJohn Marino fold_convert_loc (loc, type, arg1));
9649e4b17023SJohn Marino }
9650e4b17023SJohn Marino return NULL_TREE;
9651e4b17023SJohn Marino }
9652e4b17023SJohn Marino
9653e4b17023SJohn Marino /* Fold a call to builtin carg(a+bi) -> atan2(b,a). */
9654e4b17023SJohn Marino
9655e4b17023SJohn Marino static tree
fold_builtin_carg(location_t loc,tree arg,tree type)9656e4b17023SJohn Marino fold_builtin_carg (location_t loc, tree arg, tree type)
9657e4b17023SJohn Marino {
9658e4b17023SJohn Marino if (validate_arg (arg, COMPLEX_TYPE)
9659e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE)
9660e4b17023SJohn Marino {
9661e4b17023SJohn Marino tree atan2_fn = mathfn_built_in (type, BUILT_IN_ATAN2);
9662e4b17023SJohn Marino
9663e4b17023SJohn Marino if (atan2_fn)
9664e4b17023SJohn Marino {
9665e4b17023SJohn Marino tree new_arg = builtin_save_expr (arg);
9666e4b17023SJohn Marino tree r_arg = fold_build1_loc (loc, REALPART_EXPR, type, new_arg);
9667e4b17023SJohn Marino tree i_arg = fold_build1_loc (loc, IMAGPART_EXPR, type, new_arg);
9668e4b17023SJohn Marino return build_call_expr_loc (loc, atan2_fn, 2, i_arg, r_arg);
9669e4b17023SJohn Marino }
9670e4b17023SJohn Marino }
9671e4b17023SJohn Marino
9672e4b17023SJohn Marino return NULL_TREE;
9673e4b17023SJohn Marino }
9674e4b17023SJohn Marino
9675e4b17023SJohn Marino /* Fold a call to builtin logb/ilogb. */
9676e4b17023SJohn Marino
9677e4b17023SJohn Marino static tree
fold_builtin_logb(location_t loc,tree arg,tree rettype)9678e4b17023SJohn Marino fold_builtin_logb (location_t loc, tree arg, tree rettype)
9679e4b17023SJohn Marino {
9680e4b17023SJohn Marino if (! validate_arg (arg, REAL_TYPE))
9681e4b17023SJohn Marino return NULL_TREE;
9682e4b17023SJohn Marino
9683e4b17023SJohn Marino STRIP_NOPS (arg);
9684e4b17023SJohn Marino
9685e4b17023SJohn Marino if (TREE_CODE (arg) == REAL_CST && ! TREE_OVERFLOW (arg))
9686e4b17023SJohn Marino {
9687e4b17023SJohn Marino const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg);
9688e4b17023SJohn Marino
9689e4b17023SJohn Marino switch (value->cl)
9690e4b17023SJohn Marino {
9691e4b17023SJohn Marino case rvc_nan:
9692e4b17023SJohn Marino case rvc_inf:
9693e4b17023SJohn Marino /* If arg is Inf or NaN and we're logb, return it. */
9694e4b17023SJohn Marino if (TREE_CODE (rettype) == REAL_TYPE)
9695*95d28233SJohn Marino {
9696*95d28233SJohn Marino /* For logb(-Inf) we have to return +Inf. */
9697*95d28233SJohn Marino if (real_isinf (value) && real_isneg (value))
9698*95d28233SJohn Marino {
9699*95d28233SJohn Marino REAL_VALUE_TYPE tem;
9700*95d28233SJohn Marino real_inf (&tem);
9701*95d28233SJohn Marino return build_real (rettype, tem);
9702*95d28233SJohn Marino }
9703e4b17023SJohn Marino return fold_convert_loc (loc, rettype, arg);
9704*95d28233SJohn Marino }
9705e4b17023SJohn Marino /* Fall through... */
9706e4b17023SJohn Marino case rvc_zero:
9707e4b17023SJohn Marino /* Zero may set errno and/or raise an exception for logb, also
9708e4b17023SJohn Marino for ilogb we don't know FP_ILOGB0. */
9709e4b17023SJohn Marino return NULL_TREE;
9710e4b17023SJohn Marino case rvc_normal:
9711e4b17023SJohn Marino /* For normal numbers, proceed iff radix == 2. In GCC,
9712e4b17023SJohn Marino normalized significands are in the range [0.5, 1.0). We
9713e4b17023SJohn Marino want the exponent as if they were [1.0, 2.0) so get the
9714e4b17023SJohn Marino exponent and subtract 1. */
9715e4b17023SJohn Marino if (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (arg)))->b == 2)
9716e4b17023SJohn Marino return fold_convert_loc (loc, rettype,
9717e4b17023SJohn Marino build_int_cst (integer_type_node,
9718e4b17023SJohn Marino REAL_EXP (value)-1));
9719e4b17023SJohn Marino break;
9720e4b17023SJohn Marino }
9721e4b17023SJohn Marino }
9722e4b17023SJohn Marino
9723e4b17023SJohn Marino return NULL_TREE;
9724e4b17023SJohn Marino }
9725e4b17023SJohn Marino
9726e4b17023SJohn Marino /* Fold a call to builtin significand, if radix == 2. */
9727e4b17023SJohn Marino
9728e4b17023SJohn Marino static tree
fold_builtin_significand(location_t loc,tree arg,tree rettype)9729e4b17023SJohn Marino fold_builtin_significand (location_t loc, tree arg, tree rettype)
9730e4b17023SJohn Marino {
9731e4b17023SJohn Marino if (! validate_arg (arg, REAL_TYPE))
9732e4b17023SJohn Marino return NULL_TREE;
9733e4b17023SJohn Marino
9734e4b17023SJohn Marino STRIP_NOPS (arg);
9735e4b17023SJohn Marino
9736e4b17023SJohn Marino if (TREE_CODE (arg) == REAL_CST && ! TREE_OVERFLOW (arg))
9737e4b17023SJohn Marino {
9738e4b17023SJohn Marino const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg);
9739e4b17023SJohn Marino
9740e4b17023SJohn Marino switch (value->cl)
9741e4b17023SJohn Marino {
9742e4b17023SJohn Marino case rvc_zero:
9743e4b17023SJohn Marino case rvc_nan:
9744e4b17023SJohn Marino case rvc_inf:
9745e4b17023SJohn Marino /* If arg is +-0, +-Inf or +-NaN, then return it. */
9746e4b17023SJohn Marino return fold_convert_loc (loc, rettype, arg);
9747e4b17023SJohn Marino case rvc_normal:
9748e4b17023SJohn Marino /* For normal numbers, proceed iff radix == 2. */
9749e4b17023SJohn Marino if (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (arg)))->b == 2)
9750e4b17023SJohn Marino {
9751e4b17023SJohn Marino REAL_VALUE_TYPE result = *value;
9752e4b17023SJohn Marino /* In GCC, normalized significands are in the range [0.5,
9753e4b17023SJohn Marino 1.0). We want them to be [1.0, 2.0) so set the
9754e4b17023SJohn Marino exponent to 1. */
9755e4b17023SJohn Marino SET_REAL_EXP (&result, 1);
9756e4b17023SJohn Marino return build_real (rettype, result);
9757e4b17023SJohn Marino }
9758e4b17023SJohn Marino break;
9759e4b17023SJohn Marino }
9760e4b17023SJohn Marino }
9761e4b17023SJohn Marino
9762e4b17023SJohn Marino return NULL_TREE;
9763e4b17023SJohn Marino }
9764e4b17023SJohn Marino
9765e4b17023SJohn Marino /* Fold a call to builtin frexp, we can assume the base is 2. */
9766e4b17023SJohn Marino
9767e4b17023SJohn Marino static tree
fold_builtin_frexp(location_t loc,tree arg0,tree arg1,tree rettype)9768e4b17023SJohn Marino fold_builtin_frexp (location_t loc, tree arg0, tree arg1, tree rettype)
9769e4b17023SJohn Marino {
9770e4b17023SJohn Marino if (! validate_arg (arg0, REAL_TYPE) || ! validate_arg (arg1, POINTER_TYPE))
9771e4b17023SJohn Marino return NULL_TREE;
9772e4b17023SJohn Marino
9773e4b17023SJohn Marino STRIP_NOPS (arg0);
9774e4b17023SJohn Marino
9775e4b17023SJohn Marino if (!(TREE_CODE (arg0) == REAL_CST && ! TREE_OVERFLOW (arg0)))
9776e4b17023SJohn Marino return NULL_TREE;
9777e4b17023SJohn Marino
9778e4b17023SJohn Marino arg1 = build_fold_indirect_ref_loc (loc, arg1);
9779e4b17023SJohn Marino
9780e4b17023SJohn Marino /* Proceed if a valid pointer type was passed in. */
9781e4b17023SJohn Marino if (TYPE_MAIN_VARIANT (TREE_TYPE (arg1)) == integer_type_node)
9782e4b17023SJohn Marino {
9783e4b17023SJohn Marino const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg0);
9784e4b17023SJohn Marino tree frac, exp;
9785e4b17023SJohn Marino
9786e4b17023SJohn Marino switch (value->cl)
9787e4b17023SJohn Marino {
9788e4b17023SJohn Marino case rvc_zero:
9789e4b17023SJohn Marino /* For +-0, return (*exp = 0, +-0). */
9790e4b17023SJohn Marino exp = integer_zero_node;
9791e4b17023SJohn Marino frac = arg0;
9792e4b17023SJohn Marino break;
9793e4b17023SJohn Marino case rvc_nan:
9794e4b17023SJohn Marino case rvc_inf:
9795e4b17023SJohn Marino /* For +-NaN or +-Inf, *exp is unspecified, return arg0. */
9796e4b17023SJohn Marino return omit_one_operand_loc (loc, rettype, arg0, arg1);
9797e4b17023SJohn Marino case rvc_normal:
9798e4b17023SJohn Marino {
9799e4b17023SJohn Marino /* Since the frexp function always expects base 2, and in
9800e4b17023SJohn Marino GCC normalized significands are already in the range
9801e4b17023SJohn Marino [0.5, 1.0), we have exactly what frexp wants. */
9802e4b17023SJohn Marino REAL_VALUE_TYPE frac_rvt = *value;
9803e4b17023SJohn Marino SET_REAL_EXP (&frac_rvt, 0);
9804e4b17023SJohn Marino frac = build_real (rettype, frac_rvt);
9805e4b17023SJohn Marino exp = build_int_cst (integer_type_node, REAL_EXP (value));
9806e4b17023SJohn Marino }
9807e4b17023SJohn Marino break;
9808e4b17023SJohn Marino default:
9809e4b17023SJohn Marino gcc_unreachable ();
9810e4b17023SJohn Marino }
9811e4b17023SJohn Marino
9812e4b17023SJohn Marino /* Create the COMPOUND_EXPR (*arg1 = trunc, frac). */
9813e4b17023SJohn Marino arg1 = fold_build2_loc (loc, MODIFY_EXPR, rettype, arg1, exp);
9814e4b17023SJohn Marino TREE_SIDE_EFFECTS (arg1) = 1;
9815e4b17023SJohn Marino return fold_build2_loc (loc, COMPOUND_EXPR, rettype, arg1, frac);
9816e4b17023SJohn Marino }
9817e4b17023SJohn Marino
9818e4b17023SJohn Marino return NULL_TREE;
9819e4b17023SJohn Marino }
9820e4b17023SJohn Marino
9821e4b17023SJohn Marino /* Fold a call to builtin ldexp or scalbn/scalbln. If LDEXP is true
9822e4b17023SJohn Marino then we can assume the base is two. If it's false, then we have to
9823e4b17023SJohn Marino check the mode of the TYPE parameter in certain cases. */
9824e4b17023SJohn Marino
9825e4b17023SJohn Marino static tree
fold_builtin_load_exponent(location_t loc,tree arg0,tree arg1,tree type,bool ldexp)9826e4b17023SJohn Marino fold_builtin_load_exponent (location_t loc, tree arg0, tree arg1,
9827e4b17023SJohn Marino tree type, bool ldexp)
9828e4b17023SJohn Marino {
9829e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE) && validate_arg (arg1, INTEGER_TYPE))
9830e4b17023SJohn Marino {
9831e4b17023SJohn Marino STRIP_NOPS (arg0);
9832e4b17023SJohn Marino STRIP_NOPS (arg1);
9833e4b17023SJohn Marino
9834e4b17023SJohn Marino /* If arg0 is 0, Inf or NaN, or if arg1 is 0, then return arg0. */
9835e4b17023SJohn Marino if (real_zerop (arg0) || integer_zerop (arg1)
9836e4b17023SJohn Marino || (TREE_CODE (arg0) == REAL_CST
9837e4b17023SJohn Marino && !real_isfinite (&TREE_REAL_CST (arg0))))
9838e4b17023SJohn Marino return omit_one_operand_loc (loc, type, arg0, arg1);
9839e4b17023SJohn Marino
9840e4b17023SJohn Marino /* If both arguments are constant, then try to evaluate it. */
9841e4b17023SJohn Marino if ((ldexp || REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2)
9842e4b17023SJohn Marino && TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0)
9843e4b17023SJohn Marino && host_integerp (arg1, 0))
9844e4b17023SJohn Marino {
9845e4b17023SJohn Marino /* Bound the maximum adjustment to twice the range of the
9846e4b17023SJohn Marino mode's valid exponents. Use abs to ensure the range is
9847e4b17023SJohn Marino positive as a sanity check. */
9848e4b17023SJohn Marino const long max_exp_adj = 2 *
9849e4b17023SJohn Marino labs (REAL_MODE_FORMAT (TYPE_MODE (type))->emax
9850e4b17023SJohn Marino - REAL_MODE_FORMAT (TYPE_MODE (type))->emin);
9851e4b17023SJohn Marino
9852e4b17023SJohn Marino /* Get the user-requested adjustment. */
9853e4b17023SJohn Marino const HOST_WIDE_INT req_exp_adj = tree_low_cst (arg1, 0);
9854e4b17023SJohn Marino
9855e4b17023SJohn Marino /* The requested adjustment must be inside this range. This
9856e4b17023SJohn Marino is a preliminary cap to avoid things like overflow, we
9857e4b17023SJohn Marino may still fail to compute the result for other reasons. */
9858e4b17023SJohn Marino if (-max_exp_adj < req_exp_adj && req_exp_adj < max_exp_adj)
9859e4b17023SJohn Marino {
9860e4b17023SJohn Marino REAL_VALUE_TYPE initial_result;
9861e4b17023SJohn Marino
9862e4b17023SJohn Marino real_ldexp (&initial_result, &TREE_REAL_CST (arg0), req_exp_adj);
9863e4b17023SJohn Marino
9864e4b17023SJohn Marino /* Ensure we didn't overflow. */
9865e4b17023SJohn Marino if (! real_isinf (&initial_result))
9866e4b17023SJohn Marino {
9867e4b17023SJohn Marino const REAL_VALUE_TYPE trunc_result
9868e4b17023SJohn Marino = real_value_truncate (TYPE_MODE (type), initial_result);
9869e4b17023SJohn Marino
9870e4b17023SJohn Marino /* Only proceed if the target mode can hold the
9871e4b17023SJohn Marino resulting value. */
9872e4b17023SJohn Marino if (REAL_VALUES_EQUAL (initial_result, trunc_result))
9873e4b17023SJohn Marino return build_real (type, trunc_result);
9874e4b17023SJohn Marino }
9875e4b17023SJohn Marino }
9876e4b17023SJohn Marino }
9877e4b17023SJohn Marino }
9878e4b17023SJohn Marino
9879e4b17023SJohn Marino return NULL_TREE;
9880e4b17023SJohn Marino }
9881e4b17023SJohn Marino
9882e4b17023SJohn Marino /* Fold a call to builtin modf. */
9883e4b17023SJohn Marino
9884e4b17023SJohn Marino static tree
fold_builtin_modf(location_t loc,tree arg0,tree arg1,tree rettype)9885e4b17023SJohn Marino fold_builtin_modf (location_t loc, tree arg0, tree arg1, tree rettype)
9886e4b17023SJohn Marino {
9887e4b17023SJohn Marino if (! validate_arg (arg0, REAL_TYPE) || ! validate_arg (arg1, POINTER_TYPE))
9888e4b17023SJohn Marino return NULL_TREE;
9889e4b17023SJohn Marino
9890e4b17023SJohn Marino STRIP_NOPS (arg0);
9891e4b17023SJohn Marino
9892e4b17023SJohn Marino if (!(TREE_CODE (arg0) == REAL_CST && ! TREE_OVERFLOW (arg0)))
9893e4b17023SJohn Marino return NULL_TREE;
9894e4b17023SJohn Marino
9895e4b17023SJohn Marino arg1 = build_fold_indirect_ref_loc (loc, arg1);
9896e4b17023SJohn Marino
9897e4b17023SJohn Marino /* Proceed if a valid pointer type was passed in. */
9898e4b17023SJohn Marino if (TYPE_MAIN_VARIANT (TREE_TYPE (arg1)) == TYPE_MAIN_VARIANT (rettype))
9899e4b17023SJohn Marino {
9900e4b17023SJohn Marino const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg0);
9901e4b17023SJohn Marino REAL_VALUE_TYPE trunc, frac;
9902e4b17023SJohn Marino
9903e4b17023SJohn Marino switch (value->cl)
9904e4b17023SJohn Marino {
9905e4b17023SJohn Marino case rvc_nan:
9906e4b17023SJohn Marino case rvc_zero:
9907e4b17023SJohn Marino /* For +-NaN or +-0, return (*arg1 = arg0, arg0). */
9908e4b17023SJohn Marino trunc = frac = *value;
9909e4b17023SJohn Marino break;
9910e4b17023SJohn Marino case rvc_inf:
9911e4b17023SJohn Marino /* For +-Inf, return (*arg1 = arg0, +-0). */
9912e4b17023SJohn Marino frac = dconst0;
9913e4b17023SJohn Marino frac.sign = value->sign;
9914e4b17023SJohn Marino trunc = *value;
9915e4b17023SJohn Marino break;
9916e4b17023SJohn Marino case rvc_normal:
9917e4b17023SJohn Marino /* Return (*arg1 = trunc(arg0), arg0-trunc(arg0)). */
9918e4b17023SJohn Marino real_trunc (&trunc, VOIDmode, value);
9919e4b17023SJohn Marino real_arithmetic (&frac, MINUS_EXPR, value, &trunc);
9920e4b17023SJohn Marino /* If the original number was negative and already
9921e4b17023SJohn Marino integral, then the fractional part is -0.0. */
9922e4b17023SJohn Marino if (value->sign && frac.cl == rvc_zero)
9923e4b17023SJohn Marino frac.sign = value->sign;
9924e4b17023SJohn Marino break;
9925e4b17023SJohn Marino }
9926e4b17023SJohn Marino
9927e4b17023SJohn Marino /* Create the COMPOUND_EXPR (*arg1 = trunc, frac). */
9928e4b17023SJohn Marino arg1 = fold_build2_loc (loc, MODIFY_EXPR, rettype, arg1,
9929e4b17023SJohn Marino build_real (rettype, trunc));
9930e4b17023SJohn Marino TREE_SIDE_EFFECTS (arg1) = 1;
9931e4b17023SJohn Marino return fold_build2_loc (loc, COMPOUND_EXPR, rettype, arg1,
9932e4b17023SJohn Marino build_real (rettype, frac));
9933e4b17023SJohn Marino }
9934e4b17023SJohn Marino
9935e4b17023SJohn Marino return NULL_TREE;
9936e4b17023SJohn Marino }
9937e4b17023SJohn Marino
9938e4b17023SJohn Marino /* Given a location LOC, an interclass builtin function decl FNDECL
9939e4b17023SJohn Marino and its single argument ARG, return an folded expression computing
9940e4b17023SJohn Marino the same, or NULL_TREE if we either couldn't or didn't want to fold
9941e4b17023SJohn Marino (the latter happen if there's an RTL instruction available). */
9942e4b17023SJohn Marino
9943e4b17023SJohn Marino static tree
fold_builtin_interclass_mathfn(location_t loc,tree fndecl,tree arg)9944e4b17023SJohn Marino fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg)
9945e4b17023SJohn Marino {
9946e4b17023SJohn Marino enum machine_mode mode;
9947e4b17023SJohn Marino
9948e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
9949e4b17023SJohn Marino return NULL_TREE;
9950e4b17023SJohn Marino
9951e4b17023SJohn Marino if (interclass_mathfn_icode (arg, fndecl) != CODE_FOR_nothing)
9952e4b17023SJohn Marino return NULL_TREE;
9953e4b17023SJohn Marino
9954e4b17023SJohn Marino mode = TYPE_MODE (TREE_TYPE (arg));
9955e4b17023SJohn Marino
9956e4b17023SJohn Marino /* If there is no optab, try generic code. */
9957e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (fndecl))
9958e4b17023SJohn Marino {
9959e4b17023SJohn Marino tree result;
9960e4b17023SJohn Marino
9961e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ISINF):
9962e4b17023SJohn Marino {
9963e4b17023SJohn Marino /* isinf(x) -> isgreater(fabs(x),DBL_MAX). */
9964e4b17023SJohn Marino tree const isgr_fn = builtin_decl_explicit (BUILT_IN_ISGREATER);
9965e4b17023SJohn Marino tree const type = TREE_TYPE (arg);
9966e4b17023SJohn Marino REAL_VALUE_TYPE r;
9967e4b17023SJohn Marino char buf[128];
9968e4b17023SJohn Marino
9969e4b17023SJohn Marino get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
9970e4b17023SJohn Marino real_from_string (&r, buf);
9971e4b17023SJohn Marino result = build_call_expr (isgr_fn, 2,
9972e4b17023SJohn Marino fold_build1_loc (loc, ABS_EXPR, type, arg),
9973e4b17023SJohn Marino build_real (type, r));
9974e4b17023SJohn Marino return result;
9975e4b17023SJohn Marino }
9976e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FINITE):
9977e4b17023SJohn Marino case BUILT_IN_ISFINITE:
9978e4b17023SJohn Marino {
9979e4b17023SJohn Marino /* isfinite(x) -> islessequal(fabs(x),DBL_MAX). */
9980e4b17023SJohn Marino tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL);
9981e4b17023SJohn Marino tree const type = TREE_TYPE (arg);
9982e4b17023SJohn Marino REAL_VALUE_TYPE r;
9983e4b17023SJohn Marino char buf[128];
9984e4b17023SJohn Marino
9985e4b17023SJohn Marino get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
9986e4b17023SJohn Marino real_from_string (&r, buf);
9987e4b17023SJohn Marino result = build_call_expr (isle_fn, 2,
9988e4b17023SJohn Marino fold_build1_loc (loc, ABS_EXPR, type, arg),
9989e4b17023SJohn Marino build_real (type, r));
9990e4b17023SJohn Marino /*result = fold_build2_loc (loc, UNGT_EXPR,
9991e4b17023SJohn Marino TREE_TYPE (TREE_TYPE (fndecl)),
9992e4b17023SJohn Marino fold_build1_loc (loc, ABS_EXPR, type, arg),
9993e4b17023SJohn Marino build_real (type, r));
9994e4b17023SJohn Marino result = fold_build1_loc (loc, TRUTH_NOT_EXPR,
9995e4b17023SJohn Marino TREE_TYPE (TREE_TYPE (fndecl)),
9996e4b17023SJohn Marino result);*/
9997e4b17023SJohn Marino return result;
9998e4b17023SJohn Marino }
9999e4b17023SJohn Marino case BUILT_IN_ISNORMAL:
10000e4b17023SJohn Marino {
10001e4b17023SJohn Marino /* isnormal(x) -> isgreaterequal(fabs(x),DBL_MIN) &
10002e4b17023SJohn Marino islessequal(fabs(x),DBL_MAX). */
10003e4b17023SJohn Marino tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL);
10004e4b17023SJohn Marino tree const isge_fn = builtin_decl_explicit (BUILT_IN_ISGREATEREQUAL);
10005e4b17023SJohn Marino tree const type = TREE_TYPE (arg);
10006e4b17023SJohn Marino REAL_VALUE_TYPE rmax, rmin;
10007e4b17023SJohn Marino char buf[128];
10008e4b17023SJohn Marino
10009e4b17023SJohn Marino get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
10010e4b17023SJohn Marino real_from_string (&rmax, buf);
10011e4b17023SJohn Marino sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1);
10012e4b17023SJohn Marino real_from_string (&rmin, buf);
10013e4b17023SJohn Marino arg = builtin_save_expr (fold_build1_loc (loc, ABS_EXPR, type, arg));
10014e4b17023SJohn Marino result = build_call_expr (isle_fn, 2, arg,
10015e4b17023SJohn Marino build_real (type, rmax));
10016e4b17023SJohn Marino result = fold_build2 (BIT_AND_EXPR, integer_type_node, result,
10017e4b17023SJohn Marino build_call_expr (isge_fn, 2, arg,
10018e4b17023SJohn Marino build_real (type, rmin)));
10019e4b17023SJohn Marino return result;
10020e4b17023SJohn Marino }
10021e4b17023SJohn Marino default:
10022e4b17023SJohn Marino break;
10023e4b17023SJohn Marino }
10024e4b17023SJohn Marino
10025e4b17023SJohn Marino return NULL_TREE;
10026e4b17023SJohn Marino }
10027e4b17023SJohn Marino
10028e4b17023SJohn Marino /* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite.
10029e4b17023SJohn Marino ARG is the argument for the call. */
10030e4b17023SJohn Marino
10031e4b17023SJohn Marino static tree
fold_builtin_classify(location_t loc,tree fndecl,tree arg,int builtin_index)10032e4b17023SJohn Marino fold_builtin_classify (location_t loc, tree fndecl, tree arg, int builtin_index)
10033e4b17023SJohn Marino {
10034e4b17023SJohn Marino tree type = TREE_TYPE (TREE_TYPE (fndecl));
10035e4b17023SJohn Marino REAL_VALUE_TYPE r;
10036e4b17023SJohn Marino
10037e4b17023SJohn Marino if (!validate_arg (arg, REAL_TYPE))
10038e4b17023SJohn Marino return NULL_TREE;
10039e4b17023SJohn Marino
10040e4b17023SJohn Marino switch (builtin_index)
10041e4b17023SJohn Marino {
10042e4b17023SJohn Marino case BUILT_IN_ISINF:
10043e4b17023SJohn Marino if (!HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg))))
10044e4b17023SJohn Marino return omit_one_operand_loc (loc, type, integer_zero_node, arg);
10045e4b17023SJohn Marino
10046e4b17023SJohn Marino if (TREE_CODE (arg) == REAL_CST)
10047e4b17023SJohn Marino {
10048e4b17023SJohn Marino r = TREE_REAL_CST (arg);
10049e4b17023SJohn Marino if (real_isinf (&r))
10050e4b17023SJohn Marino return real_compare (GT_EXPR, &r, &dconst0)
10051e4b17023SJohn Marino ? integer_one_node : integer_minus_one_node;
10052e4b17023SJohn Marino else
10053e4b17023SJohn Marino return integer_zero_node;
10054e4b17023SJohn Marino }
10055e4b17023SJohn Marino
10056e4b17023SJohn Marino return NULL_TREE;
10057e4b17023SJohn Marino
10058e4b17023SJohn Marino case BUILT_IN_ISINF_SIGN:
10059e4b17023SJohn Marino {
10060e4b17023SJohn Marino /* isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0 */
10061e4b17023SJohn Marino /* In a boolean context, GCC will fold the inner COND_EXPR to
10062e4b17023SJohn Marino 1. So e.g. "if (isinf_sign(x))" would be folded to just
10063e4b17023SJohn Marino "if (isinf(x) ? 1 : 0)" which becomes "if (isinf(x))". */
10064e4b17023SJohn Marino tree signbit_fn = mathfn_built_in_1 (TREE_TYPE (arg), BUILT_IN_SIGNBIT, 0);
10065e4b17023SJohn Marino tree isinf_fn = builtin_decl_explicit (BUILT_IN_ISINF);
10066e4b17023SJohn Marino tree tmp = NULL_TREE;
10067e4b17023SJohn Marino
10068e4b17023SJohn Marino arg = builtin_save_expr (arg);
10069e4b17023SJohn Marino
10070e4b17023SJohn Marino if (signbit_fn && isinf_fn)
10071e4b17023SJohn Marino {
10072e4b17023SJohn Marino tree signbit_call = build_call_expr_loc (loc, signbit_fn, 1, arg);
10073e4b17023SJohn Marino tree isinf_call = build_call_expr_loc (loc, isinf_fn, 1, arg);
10074e4b17023SJohn Marino
10075e4b17023SJohn Marino signbit_call = fold_build2_loc (loc, NE_EXPR, integer_type_node,
10076e4b17023SJohn Marino signbit_call, integer_zero_node);
10077e4b17023SJohn Marino isinf_call = fold_build2_loc (loc, NE_EXPR, integer_type_node,
10078e4b17023SJohn Marino isinf_call, integer_zero_node);
10079e4b17023SJohn Marino
10080e4b17023SJohn Marino tmp = fold_build3_loc (loc, COND_EXPR, integer_type_node, signbit_call,
10081e4b17023SJohn Marino integer_minus_one_node, integer_one_node);
10082e4b17023SJohn Marino tmp = fold_build3_loc (loc, COND_EXPR, integer_type_node,
10083e4b17023SJohn Marino isinf_call, tmp,
10084e4b17023SJohn Marino integer_zero_node);
10085e4b17023SJohn Marino }
10086e4b17023SJohn Marino
10087e4b17023SJohn Marino return tmp;
10088e4b17023SJohn Marino }
10089e4b17023SJohn Marino
10090e4b17023SJohn Marino case BUILT_IN_ISFINITE:
10091e4b17023SJohn Marino if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg)))
10092e4b17023SJohn Marino && !HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg))))
10093e4b17023SJohn Marino return omit_one_operand_loc (loc, type, integer_one_node, arg);
10094e4b17023SJohn Marino
10095e4b17023SJohn Marino if (TREE_CODE (arg) == REAL_CST)
10096e4b17023SJohn Marino {
10097e4b17023SJohn Marino r = TREE_REAL_CST (arg);
10098e4b17023SJohn Marino return real_isfinite (&r) ? integer_one_node : integer_zero_node;
10099e4b17023SJohn Marino }
10100e4b17023SJohn Marino
10101e4b17023SJohn Marino return NULL_TREE;
10102e4b17023SJohn Marino
10103e4b17023SJohn Marino case BUILT_IN_ISNAN:
10104e4b17023SJohn Marino if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg))))
10105e4b17023SJohn Marino return omit_one_operand_loc (loc, type, integer_zero_node, arg);
10106e4b17023SJohn Marino
10107e4b17023SJohn Marino if (TREE_CODE (arg) == REAL_CST)
10108e4b17023SJohn Marino {
10109e4b17023SJohn Marino r = TREE_REAL_CST (arg);
10110e4b17023SJohn Marino return real_isnan (&r) ? integer_one_node : integer_zero_node;
10111e4b17023SJohn Marino }
10112e4b17023SJohn Marino
10113e4b17023SJohn Marino arg = builtin_save_expr (arg);
10114e4b17023SJohn Marino return fold_build2_loc (loc, UNORDERED_EXPR, type, arg, arg);
10115e4b17023SJohn Marino
10116e4b17023SJohn Marino default:
10117e4b17023SJohn Marino gcc_unreachable ();
10118e4b17023SJohn Marino }
10119e4b17023SJohn Marino }
10120e4b17023SJohn Marino
10121e4b17023SJohn Marino /* Fold a call to __builtin_fpclassify(int, int, int, int, int, ...).
10122e4b17023SJohn Marino This builtin will generate code to return the appropriate floating
10123e4b17023SJohn Marino point classification depending on the value of the floating point
10124e4b17023SJohn Marino number passed in. The possible return values must be supplied as
10125e4b17023SJohn Marino int arguments to the call in the following order: FP_NAN, FP_INFINITE,
10126e4b17023SJohn Marino FP_NORMAL, FP_SUBNORMAL and FP_ZERO. The ellipses is for exactly
10127e4b17023SJohn Marino one floating point argument which is "type generic". */
10128e4b17023SJohn Marino
10129e4b17023SJohn Marino static tree
fold_builtin_fpclassify(location_t loc,tree exp)10130e4b17023SJohn Marino fold_builtin_fpclassify (location_t loc, tree exp)
10131e4b17023SJohn Marino {
10132e4b17023SJohn Marino tree fp_nan, fp_infinite, fp_normal, fp_subnormal, fp_zero,
10133e4b17023SJohn Marino arg, type, res, tmp;
10134e4b17023SJohn Marino enum machine_mode mode;
10135e4b17023SJohn Marino REAL_VALUE_TYPE r;
10136e4b17023SJohn Marino char buf[128];
10137e4b17023SJohn Marino
10138e4b17023SJohn Marino /* Verify the required arguments in the original call. */
10139e4b17023SJohn Marino if (!validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE,
10140e4b17023SJohn Marino INTEGER_TYPE, INTEGER_TYPE,
10141e4b17023SJohn Marino INTEGER_TYPE, REAL_TYPE, VOID_TYPE))
10142e4b17023SJohn Marino return NULL_TREE;
10143e4b17023SJohn Marino
10144e4b17023SJohn Marino fp_nan = CALL_EXPR_ARG (exp, 0);
10145e4b17023SJohn Marino fp_infinite = CALL_EXPR_ARG (exp, 1);
10146e4b17023SJohn Marino fp_normal = CALL_EXPR_ARG (exp, 2);
10147e4b17023SJohn Marino fp_subnormal = CALL_EXPR_ARG (exp, 3);
10148e4b17023SJohn Marino fp_zero = CALL_EXPR_ARG (exp, 4);
10149e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 5);
10150e4b17023SJohn Marino type = TREE_TYPE (arg);
10151e4b17023SJohn Marino mode = TYPE_MODE (type);
10152e4b17023SJohn Marino arg = builtin_save_expr (fold_build1_loc (loc, ABS_EXPR, type, arg));
10153e4b17023SJohn Marino
10154e4b17023SJohn Marino /* fpclassify(x) ->
10155e4b17023SJohn Marino isnan(x) ? FP_NAN :
10156e4b17023SJohn Marino (fabs(x) == Inf ? FP_INFINITE :
10157e4b17023SJohn Marino (fabs(x) >= DBL_MIN ? FP_NORMAL :
10158e4b17023SJohn Marino (x == 0 ? FP_ZERO : FP_SUBNORMAL))). */
10159e4b17023SJohn Marino
10160e4b17023SJohn Marino tmp = fold_build2_loc (loc, EQ_EXPR, integer_type_node, arg,
10161e4b17023SJohn Marino build_real (type, dconst0));
10162e4b17023SJohn Marino res = fold_build3_loc (loc, COND_EXPR, integer_type_node,
10163e4b17023SJohn Marino tmp, fp_zero, fp_subnormal);
10164e4b17023SJohn Marino
10165e4b17023SJohn Marino sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1);
10166e4b17023SJohn Marino real_from_string (&r, buf);
10167e4b17023SJohn Marino tmp = fold_build2_loc (loc, GE_EXPR, integer_type_node,
10168e4b17023SJohn Marino arg, build_real (type, r));
10169e4b17023SJohn Marino res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp, fp_normal, res);
10170e4b17023SJohn Marino
10171e4b17023SJohn Marino if (HONOR_INFINITIES (mode))
10172e4b17023SJohn Marino {
10173e4b17023SJohn Marino real_inf (&r);
10174e4b17023SJohn Marino tmp = fold_build2_loc (loc, EQ_EXPR, integer_type_node, arg,
10175e4b17023SJohn Marino build_real (type, r));
10176e4b17023SJohn Marino res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp,
10177e4b17023SJohn Marino fp_infinite, res);
10178e4b17023SJohn Marino }
10179e4b17023SJohn Marino
10180e4b17023SJohn Marino if (HONOR_NANS (mode))
10181e4b17023SJohn Marino {
10182e4b17023SJohn Marino tmp = fold_build2_loc (loc, ORDERED_EXPR, integer_type_node, arg, arg);
10183e4b17023SJohn Marino res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp, res, fp_nan);
10184e4b17023SJohn Marino }
10185e4b17023SJohn Marino
10186e4b17023SJohn Marino return res;
10187e4b17023SJohn Marino }
10188e4b17023SJohn Marino
10189e4b17023SJohn Marino /* Fold a call to an unordered comparison function such as
10190e4b17023SJohn Marino __builtin_isgreater(). FNDECL is the FUNCTION_DECL for the function
10191e4b17023SJohn Marino being called and ARG0 and ARG1 are the arguments for the call.
10192e4b17023SJohn Marino UNORDERED_CODE and ORDERED_CODE are comparison codes that give
10193e4b17023SJohn Marino the opposite of the desired result. UNORDERED_CODE is used
10194e4b17023SJohn Marino for modes that can hold NaNs and ORDERED_CODE is used for
10195e4b17023SJohn Marino the rest. */
10196e4b17023SJohn Marino
10197e4b17023SJohn Marino static tree
fold_builtin_unordered_cmp(location_t loc,tree fndecl,tree arg0,tree arg1,enum tree_code unordered_code,enum tree_code ordered_code)10198e4b17023SJohn Marino fold_builtin_unordered_cmp (location_t loc, tree fndecl, tree arg0, tree arg1,
10199e4b17023SJohn Marino enum tree_code unordered_code,
10200e4b17023SJohn Marino enum tree_code ordered_code)
10201e4b17023SJohn Marino {
10202e4b17023SJohn Marino tree type = TREE_TYPE (TREE_TYPE (fndecl));
10203e4b17023SJohn Marino enum tree_code code;
10204e4b17023SJohn Marino tree type0, type1;
10205e4b17023SJohn Marino enum tree_code code0, code1;
10206e4b17023SJohn Marino tree cmp_type = NULL_TREE;
10207e4b17023SJohn Marino
10208e4b17023SJohn Marino type0 = TREE_TYPE (arg0);
10209e4b17023SJohn Marino type1 = TREE_TYPE (arg1);
10210e4b17023SJohn Marino
10211e4b17023SJohn Marino code0 = TREE_CODE (type0);
10212e4b17023SJohn Marino code1 = TREE_CODE (type1);
10213e4b17023SJohn Marino
10214e4b17023SJohn Marino if (code0 == REAL_TYPE && code1 == REAL_TYPE)
10215e4b17023SJohn Marino /* Choose the wider of two real types. */
10216e4b17023SJohn Marino cmp_type = TYPE_PRECISION (type0) >= TYPE_PRECISION (type1)
10217e4b17023SJohn Marino ? type0 : type1;
10218e4b17023SJohn Marino else if (code0 == REAL_TYPE && code1 == INTEGER_TYPE)
10219e4b17023SJohn Marino cmp_type = type0;
10220e4b17023SJohn Marino else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE)
10221e4b17023SJohn Marino cmp_type = type1;
10222e4b17023SJohn Marino
10223e4b17023SJohn Marino arg0 = fold_convert_loc (loc, cmp_type, arg0);
10224e4b17023SJohn Marino arg1 = fold_convert_loc (loc, cmp_type, arg1);
10225e4b17023SJohn Marino
10226e4b17023SJohn Marino if (unordered_code == UNORDERED_EXPR)
10227e4b17023SJohn Marino {
10228e4b17023SJohn Marino if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
10229e4b17023SJohn Marino return omit_two_operands_loc (loc, type, integer_zero_node, arg0, arg1);
10230e4b17023SJohn Marino return fold_build2_loc (loc, UNORDERED_EXPR, type, arg0, arg1);
10231e4b17023SJohn Marino }
10232e4b17023SJohn Marino
10233e4b17023SJohn Marino code = HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))) ? unordered_code
10234e4b17023SJohn Marino : ordered_code;
10235e4b17023SJohn Marino return fold_build1_loc (loc, TRUTH_NOT_EXPR, type,
10236e4b17023SJohn Marino fold_build2_loc (loc, code, type, arg0, arg1));
10237e4b17023SJohn Marino }
10238e4b17023SJohn Marino
10239e4b17023SJohn Marino /* Fold a call to built-in function FNDECL with 0 arguments.
10240e4b17023SJohn Marino IGNORE is true if the result of the function call is ignored. This
10241e4b17023SJohn Marino function returns NULL_TREE if no simplification was possible. */
10242e4b17023SJohn Marino
10243e4b17023SJohn Marino static tree
fold_builtin_0(location_t loc,tree fndecl,bool ignore ATTRIBUTE_UNUSED)10244e4b17023SJohn Marino fold_builtin_0 (location_t loc, tree fndecl, bool ignore ATTRIBUTE_UNUSED)
10245e4b17023SJohn Marino {
10246e4b17023SJohn Marino tree type = TREE_TYPE (TREE_TYPE (fndecl));
10247e4b17023SJohn Marino enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
10248e4b17023SJohn Marino switch (fcode)
10249e4b17023SJohn Marino {
10250e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_INF):
10251e4b17023SJohn Marino case BUILT_IN_INFD32:
10252e4b17023SJohn Marino case BUILT_IN_INFD64:
10253e4b17023SJohn Marino case BUILT_IN_INFD128:
10254e4b17023SJohn Marino return fold_builtin_inf (loc, type, true);
10255e4b17023SJohn Marino
10256e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_HUGE_VAL):
10257e4b17023SJohn Marino return fold_builtin_inf (loc, type, false);
10258e4b17023SJohn Marino
10259e4b17023SJohn Marino case BUILT_IN_CLASSIFY_TYPE:
10260e4b17023SJohn Marino return fold_builtin_classify_type (NULL_TREE);
10261e4b17023SJohn Marino
10262e4b17023SJohn Marino default:
10263e4b17023SJohn Marino break;
10264e4b17023SJohn Marino }
10265e4b17023SJohn Marino return NULL_TREE;
10266e4b17023SJohn Marino }
10267e4b17023SJohn Marino
10268e4b17023SJohn Marino /* Fold a call to built-in function FNDECL with 1 argument, ARG0.
10269e4b17023SJohn Marino IGNORE is true if the result of the function call is ignored. This
10270e4b17023SJohn Marino function returns NULL_TREE if no simplification was possible. */
10271e4b17023SJohn Marino
10272e4b17023SJohn Marino static tree
fold_builtin_1(location_t loc,tree fndecl,tree arg0,bool ignore)10273e4b17023SJohn Marino fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
10274e4b17023SJohn Marino {
10275e4b17023SJohn Marino tree type = TREE_TYPE (TREE_TYPE (fndecl));
10276e4b17023SJohn Marino enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
10277e4b17023SJohn Marino switch (fcode)
10278e4b17023SJohn Marino {
10279e4b17023SJohn Marino case BUILT_IN_CONSTANT_P:
10280e4b17023SJohn Marino {
10281e4b17023SJohn Marino tree val = fold_builtin_constant_p (arg0);
10282e4b17023SJohn Marino
10283e4b17023SJohn Marino /* Gimplification will pull the CALL_EXPR for the builtin out of
10284e4b17023SJohn Marino an if condition. When not optimizing, we'll not CSE it back.
10285e4b17023SJohn Marino To avoid link error types of regressions, return false now. */
10286e4b17023SJohn Marino if (!val && !optimize)
10287e4b17023SJohn Marino val = integer_zero_node;
10288e4b17023SJohn Marino
10289e4b17023SJohn Marino return val;
10290e4b17023SJohn Marino }
10291e4b17023SJohn Marino
10292e4b17023SJohn Marino case BUILT_IN_CLASSIFY_TYPE:
10293e4b17023SJohn Marino return fold_builtin_classify_type (arg0);
10294e4b17023SJohn Marino
10295e4b17023SJohn Marino case BUILT_IN_STRLEN:
10296e4b17023SJohn Marino return fold_builtin_strlen (loc, type, arg0);
10297e4b17023SJohn Marino
10298e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FABS):
10299e4b17023SJohn Marino return fold_builtin_fabs (loc, arg0, type);
10300e4b17023SJohn Marino
10301e4b17023SJohn Marino case BUILT_IN_ABS:
10302e4b17023SJohn Marino case BUILT_IN_LABS:
10303e4b17023SJohn Marino case BUILT_IN_LLABS:
10304e4b17023SJohn Marino case BUILT_IN_IMAXABS:
10305e4b17023SJohn Marino return fold_builtin_abs (loc, arg0, type);
10306e4b17023SJohn Marino
10307e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CONJ):
10308e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10309e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10310e4b17023SJohn Marino return fold_build1_loc (loc, CONJ_EXPR, type, arg0);
10311e4b17023SJohn Marino break;
10312e4b17023SJohn Marino
10313e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CREAL):
10314e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10315e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10316e4b17023SJohn Marino return non_lvalue_loc (loc, fold_build1_loc (loc, REALPART_EXPR, type, arg0));;
10317e4b17023SJohn Marino break;
10318e4b17023SJohn Marino
10319e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CIMAG):
10320e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10321e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10322e4b17023SJohn Marino return non_lvalue_loc (loc, fold_build1_loc (loc, IMAGPART_EXPR, type, arg0));
10323e4b17023SJohn Marino break;
10324e4b17023SJohn Marino
10325e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CCOS):
10326e4b17023SJohn Marino return fold_builtin_ccos(loc, arg0, type, fndecl, /*hyper=*/ false);
10327e4b17023SJohn Marino
10328e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CCOSH):
10329e4b17023SJohn Marino return fold_builtin_ccos(loc, arg0, type, fndecl, /*hyper=*/ true);
10330e4b17023SJohn Marino
10331e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CPROJ):
10332e4b17023SJohn Marino return fold_builtin_cproj(loc, arg0, type);
10333e4b17023SJohn Marino
10334e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CSIN):
10335e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10336e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10337e4b17023SJohn Marino return do_mpc_arg1 (arg0, type, mpc_sin);
10338e4b17023SJohn Marino break;
10339e4b17023SJohn Marino
10340e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CSINH):
10341e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10342e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10343e4b17023SJohn Marino return do_mpc_arg1 (arg0, type, mpc_sinh);
10344e4b17023SJohn Marino break;
10345e4b17023SJohn Marino
10346e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CTAN):
10347e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10348e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10349e4b17023SJohn Marino return do_mpc_arg1 (arg0, type, mpc_tan);
10350e4b17023SJohn Marino break;
10351e4b17023SJohn Marino
10352e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CTANH):
10353e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10354e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10355e4b17023SJohn Marino return do_mpc_arg1 (arg0, type, mpc_tanh);
10356e4b17023SJohn Marino break;
10357e4b17023SJohn Marino
10358e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CLOG):
10359e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10360e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10361e4b17023SJohn Marino return do_mpc_arg1 (arg0, type, mpc_log);
10362e4b17023SJohn Marino break;
10363e4b17023SJohn Marino
10364e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CSQRT):
10365e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10366e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10367e4b17023SJohn Marino return do_mpc_arg1 (arg0, type, mpc_sqrt);
10368e4b17023SJohn Marino break;
10369e4b17023SJohn Marino
10370e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CASIN):
10371e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10372e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10373e4b17023SJohn Marino return do_mpc_arg1 (arg0, type, mpc_asin);
10374e4b17023SJohn Marino break;
10375e4b17023SJohn Marino
10376e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CACOS):
10377e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10378e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10379e4b17023SJohn Marino return do_mpc_arg1 (arg0, type, mpc_acos);
10380e4b17023SJohn Marino break;
10381e4b17023SJohn Marino
10382e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CATAN):
10383e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10384e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10385e4b17023SJohn Marino return do_mpc_arg1 (arg0, type, mpc_atan);
10386e4b17023SJohn Marino break;
10387e4b17023SJohn Marino
10388e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CASINH):
10389e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10390e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10391e4b17023SJohn Marino return do_mpc_arg1 (arg0, type, mpc_asinh);
10392e4b17023SJohn Marino break;
10393e4b17023SJohn Marino
10394e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CACOSH):
10395e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10396e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10397e4b17023SJohn Marino return do_mpc_arg1 (arg0, type, mpc_acosh);
10398e4b17023SJohn Marino break;
10399e4b17023SJohn Marino
10400e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CATANH):
10401e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10402e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
10403e4b17023SJohn Marino return do_mpc_arg1 (arg0, type, mpc_atanh);
10404e4b17023SJohn Marino break;
10405e4b17023SJohn Marino
10406e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CABS):
10407e4b17023SJohn Marino return fold_builtin_cabs (loc, arg0, type, fndecl);
10408e4b17023SJohn Marino
10409e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CARG):
10410e4b17023SJohn Marino return fold_builtin_carg (loc, arg0, type);
10411e4b17023SJohn Marino
10412e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SQRT):
10413e4b17023SJohn Marino return fold_builtin_sqrt (loc, arg0, type);
10414e4b17023SJohn Marino
10415e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CBRT):
10416e4b17023SJohn Marino return fold_builtin_cbrt (loc, arg0, type);
10417e4b17023SJohn Marino
10418e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ASIN):
10419e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10420e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_asin,
10421e4b17023SJohn Marino &dconstm1, &dconst1, true);
10422e4b17023SJohn Marino break;
10423e4b17023SJohn Marino
10424e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ACOS):
10425e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10426e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_acos,
10427e4b17023SJohn Marino &dconstm1, &dconst1, true);
10428e4b17023SJohn Marino break;
10429e4b17023SJohn Marino
10430e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ATAN):
10431e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10432e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_atan, NULL, NULL, 0);
10433e4b17023SJohn Marino break;
10434e4b17023SJohn Marino
10435e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ASINH):
10436e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10437e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_asinh, NULL, NULL, 0);
10438e4b17023SJohn Marino break;
10439e4b17023SJohn Marino
10440e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ACOSH):
10441e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10442e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_acosh,
10443e4b17023SJohn Marino &dconst1, NULL, true);
10444e4b17023SJohn Marino break;
10445e4b17023SJohn Marino
10446e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ATANH):
10447e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10448e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_atanh,
10449e4b17023SJohn Marino &dconstm1, &dconst1, false);
10450e4b17023SJohn Marino break;
10451e4b17023SJohn Marino
10452e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SIN):
10453e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10454e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_sin, NULL, NULL, 0);
10455e4b17023SJohn Marino break;
10456e4b17023SJohn Marino
10457e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_COS):
10458e4b17023SJohn Marino return fold_builtin_cos (loc, arg0, type, fndecl);
10459e4b17023SJohn Marino
10460e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_TAN):
10461e4b17023SJohn Marino return fold_builtin_tan (arg0, type);
10462e4b17023SJohn Marino
10463e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CEXP):
10464e4b17023SJohn Marino return fold_builtin_cexp (loc, arg0, type);
10465e4b17023SJohn Marino
10466e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CEXPI):
10467e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10468e4b17023SJohn Marino return do_mpfr_sincos (arg0, NULL_TREE, NULL_TREE);
10469e4b17023SJohn Marino break;
10470e4b17023SJohn Marino
10471e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SINH):
10472e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10473e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_sinh, NULL, NULL, 0);
10474e4b17023SJohn Marino break;
10475e4b17023SJohn Marino
10476e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_COSH):
10477e4b17023SJohn Marino return fold_builtin_cosh (loc, arg0, type, fndecl);
10478e4b17023SJohn Marino
10479e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_TANH):
10480e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10481e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_tanh, NULL, NULL, 0);
10482e4b17023SJohn Marino break;
10483e4b17023SJohn Marino
10484e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ERF):
10485e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10486e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_erf, NULL, NULL, 0);
10487e4b17023SJohn Marino break;
10488e4b17023SJohn Marino
10489e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ERFC):
10490e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10491e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_erfc, NULL, NULL, 0);
10492e4b17023SJohn Marino break;
10493e4b17023SJohn Marino
10494e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_TGAMMA):
10495e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10496e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_gamma, NULL, NULL, 0);
10497e4b17023SJohn Marino break;
10498e4b17023SJohn Marino
10499e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXP):
10500e4b17023SJohn Marino return fold_builtin_exponent (loc, fndecl, arg0, mpfr_exp);
10501e4b17023SJohn Marino
10502e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXP2):
10503e4b17023SJohn Marino return fold_builtin_exponent (loc, fndecl, arg0, mpfr_exp2);
10504e4b17023SJohn Marino
10505e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXP10):
10506e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_POW10):
10507e4b17023SJohn Marino return fold_builtin_exponent (loc, fndecl, arg0, mpfr_exp10);
10508e4b17023SJohn Marino
10509e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_EXPM1):
10510e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10511e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_expm1, NULL, NULL, 0);
10512e4b17023SJohn Marino break;
10513e4b17023SJohn Marino
10514e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOG):
10515e4b17023SJohn Marino return fold_builtin_logarithm (loc, fndecl, arg0, mpfr_log);
10516e4b17023SJohn Marino
10517e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOG2):
10518e4b17023SJohn Marino return fold_builtin_logarithm (loc, fndecl, arg0, mpfr_log2);
10519e4b17023SJohn Marino
10520e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOG10):
10521e4b17023SJohn Marino return fold_builtin_logarithm (loc, fndecl, arg0, mpfr_log10);
10522e4b17023SJohn Marino
10523e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOG1P):
10524e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10525e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_log1p,
10526e4b17023SJohn Marino &dconstm1, NULL, false);
10527e4b17023SJohn Marino break;
10528e4b17023SJohn Marino
10529e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_J0):
10530e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10531e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_j0,
10532e4b17023SJohn Marino NULL, NULL, 0);
10533e4b17023SJohn Marino break;
10534e4b17023SJohn Marino
10535e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_J1):
10536e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10537e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_j1,
10538e4b17023SJohn Marino NULL, NULL, 0);
10539e4b17023SJohn Marino break;
10540e4b17023SJohn Marino
10541e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_Y0):
10542e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10543e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_y0,
10544e4b17023SJohn Marino &dconst0, NULL, false);
10545e4b17023SJohn Marino break;
10546e4b17023SJohn Marino
10547e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_Y1):
10548e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE))
10549e4b17023SJohn Marino return do_mpfr_arg1 (arg0, type, mpfr_y1,
10550e4b17023SJohn Marino &dconst0, NULL, false);
10551e4b17023SJohn Marino break;
10552e4b17023SJohn Marino
10553e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_NAN):
10554e4b17023SJohn Marino case BUILT_IN_NAND32:
10555e4b17023SJohn Marino case BUILT_IN_NAND64:
10556e4b17023SJohn Marino case BUILT_IN_NAND128:
10557e4b17023SJohn Marino return fold_builtin_nan (arg0, type, true);
10558e4b17023SJohn Marino
10559e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_NANS):
10560e4b17023SJohn Marino return fold_builtin_nan (arg0, type, false);
10561e4b17023SJohn Marino
10562e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FLOOR):
10563e4b17023SJohn Marino return fold_builtin_floor (loc, fndecl, arg0);
10564e4b17023SJohn Marino
10565e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CEIL):
10566e4b17023SJohn Marino return fold_builtin_ceil (loc, fndecl, arg0);
10567e4b17023SJohn Marino
10568e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_TRUNC):
10569e4b17023SJohn Marino return fold_builtin_trunc (loc, fndecl, arg0);
10570e4b17023SJohn Marino
10571e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ROUND):
10572e4b17023SJohn Marino return fold_builtin_round (loc, fndecl, arg0);
10573e4b17023SJohn Marino
10574e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_NEARBYINT):
10575e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_RINT):
10576e4b17023SJohn Marino return fold_trunc_transparent_mathfn (loc, fndecl, arg0);
10577e4b17023SJohn Marino
10578e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ICEIL):
10579e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LCEIL):
10580e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLCEIL):
10581e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LFLOOR):
10582e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IFLOOR):
10583e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLFLOOR):
10584e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IROUND):
10585e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LROUND):
10586e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLROUND):
10587e4b17023SJohn Marino return fold_builtin_int_roundingfn (loc, fndecl, arg0);
10588e4b17023SJohn Marino
10589e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_IRINT):
10590e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LRINT):
10591e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LLRINT):
10592e4b17023SJohn Marino return fold_fixed_mathfn (loc, fndecl, arg0);
10593e4b17023SJohn Marino
10594e4b17023SJohn Marino case BUILT_IN_BSWAP32:
10595e4b17023SJohn Marino case BUILT_IN_BSWAP64:
10596e4b17023SJohn Marino return fold_builtin_bswap (fndecl, arg0);
10597e4b17023SJohn Marino
10598e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_FFS):
10599e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_CLZ):
10600e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_CTZ):
10601e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_CLRSB):
10602e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_POPCOUNT):
10603e4b17023SJohn Marino CASE_INT_FN (BUILT_IN_PARITY):
10604e4b17023SJohn Marino return fold_builtin_bitop (fndecl, arg0);
10605e4b17023SJohn Marino
10606e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SIGNBIT):
10607e4b17023SJohn Marino return fold_builtin_signbit (loc, arg0, type);
10608e4b17023SJohn Marino
10609e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SIGNIFICAND):
10610e4b17023SJohn Marino return fold_builtin_significand (loc, arg0, type);
10611e4b17023SJohn Marino
10612e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ILOGB):
10613e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LOGB):
10614e4b17023SJohn Marino return fold_builtin_logb (loc, arg0, type);
10615e4b17023SJohn Marino
10616e4b17023SJohn Marino case BUILT_IN_ISASCII:
10617e4b17023SJohn Marino return fold_builtin_isascii (loc, arg0);
10618e4b17023SJohn Marino
10619e4b17023SJohn Marino case BUILT_IN_TOASCII:
10620e4b17023SJohn Marino return fold_builtin_toascii (loc, arg0);
10621e4b17023SJohn Marino
10622e4b17023SJohn Marino case BUILT_IN_ISDIGIT:
10623e4b17023SJohn Marino return fold_builtin_isdigit (loc, arg0);
10624e4b17023SJohn Marino
10625e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FINITE):
10626e4b17023SJohn Marino case BUILT_IN_FINITED32:
10627e4b17023SJohn Marino case BUILT_IN_FINITED64:
10628e4b17023SJohn Marino case BUILT_IN_FINITED128:
10629e4b17023SJohn Marino case BUILT_IN_ISFINITE:
10630e4b17023SJohn Marino {
10631e4b17023SJohn Marino tree ret = fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISFINITE);
10632e4b17023SJohn Marino if (ret)
10633e4b17023SJohn Marino return ret;
10634e4b17023SJohn Marino return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
10635e4b17023SJohn Marino }
10636e4b17023SJohn Marino
10637e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ISINF):
10638e4b17023SJohn Marino case BUILT_IN_ISINFD32:
10639e4b17023SJohn Marino case BUILT_IN_ISINFD64:
10640e4b17023SJohn Marino case BUILT_IN_ISINFD128:
10641e4b17023SJohn Marino {
10642e4b17023SJohn Marino tree ret = fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF);
10643e4b17023SJohn Marino if (ret)
10644e4b17023SJohn Marino return ret;
10645e4b17023SJohn Marino return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
10646e4b17023SJohn Marino }
10647e4b17023SJohn Marino
10648e4b17023SJohn Marino case BUILT_IN_ISNORMAL:
10649e4b17023SJohn Marino return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
10650e4b17023SJohn Marino
10651e4b17023SJohn Marino case BUILT_IN_ISINF_SIGN:
10652e4b17023SJohn Marino return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF_SIGN);
10653e4b17023SJohn Marino
10654e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ISNAN):
10655e4b17023SJohn Marino case BUILT_IN_ISNAND32:
10656e4b17023SJohn Marino case BUILT_IN_ISNAND64:
10657e4b17023SJohn Marino case BUILT_IN_ISNAND128:
10658e4b17023SJohn Marino return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISNAN);
10659e4b17023SJohn Marino
10660e4b17023SJohn Marino case BUILT_IN_PRINTF:
10661e4b17023SJohn Marino case BUILT_IN_PRINTF_UNLOCKED:
10662e4b17023SJohn Marino case BUILT_IN_VPRINTF:
10663e4b17023SJohn Marino return fold_builtin_printf (loc, fndecl, arg0, NULL_TREE, ignore, fcode);
10664e4b17023SJohn Marino
10665e4b17023SJohn Marino case BUILT_IN_FREE:
10666e4b17023SJohn Marino if (integer_zerop (arg0))
10667e4b17023SJohn Marino return build_empty_stmt (loc);
10668e4b17023SJohn Marino break;
10669e4b17023SJohn Marino
10670e4b17023SJohn Marino default:
10671e4b17023SJohn Marino break;
10672e4b17023SJohn Marino }
10673e4b17023SJohn Marino
10674e4b17023SJohn Marino return NULL_TREE;
10675e4b17023SJohn Marino
10676e4b17023SJohn Marino }
10677e4b17023SJohn Marino
10678e4b17023SJohn Marino /* Fold a call to built-in function FNDECL with 2 arguments, ARG0 and ARG1.
10679e4b17023SJohn Marino IGNORE is true if the result of the function call is ignored. This
10680e4b17023SJohn Marino function returns NULL_TREE if no simplification was possible. */
10681e4b17023SJohn Marino
10682e4b17023SJohn Marino static tree
fold_builtin_2(location_t loc,tree fndecl,tree arg0,tree arg1,bool ignore)10683e4b17023SJohn Marino fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1, bool ignore)
10684e4b17023SJohn Marino {
10685e4b17023SJohn Marino tree type = TREE_TYPE (TREE_TYPE (fndecl));
10686e4b17023SJohn Marino enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
10687e4b17023SJohn Marino
10688e4b17023SJohn Marino switch (fcode)
10689e4b17023SJohn Marino {
10690e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_JN):
10691e4b17023SJohn Marino if (validate_arg (arg0, INTEGER_TYPE)
10692e4b17023SJohn Marino && validate_arg (arg1, REAL_TYPE))
10693e4b17023SJohn Marino return do_mpfr_bessel_n (arg0, arg1, type, mpfr_jn, NULL, 0);
10694e4b17023SJohn Marino break;
10695e4b17023SJohn Marino
10696e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_YN):
10697e4b17023SJohn Marino if (validate_arg (arg0, INTEGER_TYPE)
10698e4b17023SJohn Marino && validate_arg (arg1, REAL_TYPE))
10699e4b17023SJohn Marino return do_mpfr_bessel_n (arg0, arg1, type, mpfr_yn,
10700e4b17023SJohn Marino &dconst0, false);
10701e4b17023SJohn Marino break;
10702e4b17023SJohn Marino
10703e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_DREM):
10704e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_REMAINDER):
10705e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE)
10706e4b17023SJohn Marino && validate_arg(arg1, REAL_TYPE))
10707e4b17023SJohn Marino return do_mpfr_arg2 (arg0, arg1, type, mpfr_remainder);
10708e4b17023SJohn Marino break;
10709e4b17023SJohn Marino
10710e4b17023SJohn Marino CASE_FLT_FN_REENT (BUILT_IN_GAMMA): /* GAMMA_R */
10711e4b17023SJohn Marino CASE_FLT_FN_REENT (BUILT_IN_LGAMMA): /* LGAMMA_R */
10712e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE)
10713e4b17023SJohn Marino && validate_arg(arg1, POINTER_TYPE))
10714e4b17023SJohn Marino return do_mpfr_lgamma_r (arg0, arg1, type);
10715e4b17023SJohn Marino break;
10716e4b17023SJohn Marino
10717e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_ATAN2):
10718e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE)
10719e4b17023SJohn Marino && validate_arg(arg1, REAL_TYPE))
10720e4b17023SJohn Marino return do_mpfr_arg2 (arg0, arg1, type, mpfr_atan2);
10721e4b17023SJohn Marino break;
10722e4b17023SJohn Marino
10723e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FDIM):
10724e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE)
10725e4b17023SJohn Marino && validate_arg(arg1, REAL_TYPE))
10726e4b17023SJohn Marino return do_mpfr_arg2 (arg0, arg1, type, mpfr_dim);
10727e4b17023SJohn Marino break;
10728e4b17023SJohn Marino
10729e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_HYPOT):
10730e4b17023SJohn Marino return fold_builtin_hypot (loc, fndecl, arg0, arg1, type);
10731e4b17023SJohn Marino
10732e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_CPOW):
10733e4b17023SJohn Marino if (validate_arg (arg0, COMPLEX_TYPE)
10734e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE
10735e4b17023SJohn Marino && validate_arg (arg1, COMPLEX_TYPE)
10736e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg1))) == REAL_TYPE)
10737e4b17023SJohn Marino return do_mpc_arg2 (arg0, arg1, type, /*do_nonfinite=*/ 0, mpc_pow);
10738e4b17023SJohn Marino break;
10739e4b17023SJohn Marino
10740e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_LDEXP):
10741e4b17023SJohn Marino return fold_builtin_load_exponent (loc, arg0, arg1, type, /*ldexp=*/true);
10742e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SCALBN):
10743e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SCALBLN):
10744e4b17023SJohn Marino return fold_builtin_load_exponent (loc, arg0, arg1,
10745e4b17023SJohn Marino type, /*ldexp=*/false);
10746e4b17023SJohn Marino
10747e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FREXP):
10748e4b17023SJohn Marino return fold_builtin_frexp (loc, arg0, arg1, type);
10749e4b17023SJohn Marino
10750e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_MODF):
10751e4b17023SJohn Marino return fold_builtin_modf (loc, arg0, arg1, type);
10752e4b17023SJohn Marino
10753e4b17023SJohn Marino case BUILT_IN_BZERO:
10754e4b17023SJohn Marino return fold_builtin_bzero (loc, arg0, arg1, ignore);
10755e4b17023SJohn Marino
10756e4b17023SJohn Marino case BUILT_IN_FPUTS:
10757e4b17023SJohn Marino return fold_builtin_fputs (loc, arg0, arg1, ignore, false, NULL_TREE);
10758e4b17023SJohn Marino
10759e4b17023SJohn Marino case BUILT_IN_FPUTS_UNLOCKED:
10760e4b17023SJohn Marino return fold_builtin_fputs (loc, arg0, arg1, ignore, true, NULL_TREE);
10761e4b17023SJohn Marino
10762e4b17023SJohn Marino case BUILT_IN_STRSTR:
10763e4b17023SJohn Marino return fold_builtin_strstr (loc, arg0, arg1, type);
10764e4b17023SJohn Marino
10765e4b17023SJohn Marino case BUILT_IN_STRCAT:
10766e4b17023SJohn Marino return fold_builtin_strcat (loc, arg0, arg1);
10767e4b17023SJohn Marino
10768e4b17023SJohn Marino case BUILT_IN_STRSPN:
10769e4b17023SJohn Marino return fold_builtin_strspn (loc, arg0, arg1);
10770e4b17023SJohn Marino
10771e4b17023SJohn Marino case BUILT_IN_STRCSPN:
10772e4b17023SJohn Marino return fold_builtin_strcspn (loc, arg0, arg1);
10773e4b17023SJohn Marino
10774e4b17023SJohn Marino case BUILT_IN_STRCHR:
10775e4b17023SJohn Marino case BUILT_IN_INDEX:
10776e4b17023SJohn Marino return fold_builtin_strchr (loc, arg0, arg1, type);
10777e4b17023SJohn Marino
10778e4b17023SJohn Marino case BUILT_IN_STRRCHR:
10779e4b17023SJohn Marino case BUILT_IN_RINDEX:
10780e4b17023SJohn Marino return fold_builtin_strrchr (loc, arg0, arg1, type);
10781e4b17023SJohn Marino
10782e4b17023SJohn Marino case BUILT_IN_STRCPY:
10783e4b17023SJohn Marino return fold_builtin_strcpy (loc, fndecl, arg0, arg1, NULL_TREE);
10784e4b17023SJohn Marino
10785e4b17023SJohn Marino case BUILT_IN_STPCPY:
10786e4b17023SJohn Marino if (ignore)
10787e4b17023SJohn Marino {
10788e4b17023SJohn Marino tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
10789e4b17023SJohn Marino if (!fn)
10790e4b17023SJohn Marino break;
10791e4b17023SJohn Marino
10792e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 2, arg0, arg1);
10793e4b17023SJohn Marino }
10794e4b17023SJohn Marino else
10795e4b17023SJohn Marino return fold_builtin_stpcpy (loc, fndecl, arg0, arg1);
10796e4b17023SJohn Marino break;
10797e4b17023SJohn Marino
10798e4b17023SJohn Marino case BUILT_IN_STRCMP:
10799e4b17023SJohn Marino return fold_builtin_strcmp (loc, arg0, arg1);
10800e4b17023SJohn Marino
10801e4b17023SJohn Marino case BUILT_IN_STRPBRK:
10802e4b17023SJohn Marino return fold_builtin_strpbrk (loc, arg0, arg1, type);
10803e4b17023SJohn Marino
10804e4b17023SJohn Marino case BUILT_IN_EXPECT:
10805e4b17023SJohn Marino return fold_builtin_expect (loc, arg0, arg1);
10806e4b17023SJohn Marino
10807e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_POW):
10808e4b17023SJohn Marino return fold_builtin_pow (loc, fndecl, arg0, arg1, type);
10809e4b17023SJohn Marino
10810e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_POWI):
10811e4b17023SJohn Marino return fold_builtin_powi (loc, fndecl, arg0, arg1, type);
10812e4b17023SJohn Marino
10813e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_COPYSIGN):
10814e4b17023SJohn Marino return fold_builtin_copysign (loc, fndecl, arg0, arg1, type);
10815e4b17023SJohn Marino
10816e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FMIN):
10817e4b17023SJohn Marino return fold_builtin_fmin_fmax (loc, arg0, arg1, type, /*max=*/false);
10818e4b17023SJohn Marino
10819e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FMAX):
10820e4b17023SJohn Marino return fold_builtin_fmin_fmax (loc, arg0, arg1, type, /*max=*/true);
10821e4b17023SJohn Marino
10822e4b17023SJohn Marino case BUILT_IN_ISGREATER:
10823e4b17023SJohn Marino return fold_builtin_unordered_cmp (loc, fndecl,
10824e4b17023SJohn Marino arg0, arg1, UNLE_EXPR, LE_EXPR);
10825e4b17023SJohn Marino case BUILT_IN_ISGREATEREQUAL:
10826e4b17023SJohn Marino return fold_builtin_unordered_cmp (loc, fndecl,
10827e4b17023SJohn Marino arg0, arg1, UNLT_EXPR, LT_EXPR);
10828e4b17023SJohn Marino case BUILT_IN_ISLESS:
10829e4b17023SJohn Marino return fold_builtin_unordered_cmp (loc, fndecl,
10830e4b17023SJohn Marino arg0, arg1, UNGE_EXPR, GE_EXPR);
10831e4b17023SJohn Marino case BUILT_IN_ISLESSEQUAL:
10832e4b17023SJohn Marino return fold_builtin_unordered_cmp (loc, fndecl,
10833e4b17023SJohn Marino arg0, arg1, UNGT_EXPR, GT_EXPR);
10834e4b17023SJohn Marino case BUILT_IN_ISLESSGREATER:
10835e4b17023SJohn Marino return fold_builtin_unordered_cmp (loc, fndecl,
10836e4b17023SJohn Marino arg0, arg1, UNEQ_EXPR, EQ_EXPR);
10837e4b17023SJohn Marino case BUILT_IN_ISUNORDERED:
10838e4b17023SJohn Marino return fold_builtin_unordered_cmp (loc, fndecl,
10839e4b17023SJohn Marino arg0, arg1, UNORDERED_EXPR,
10840e4b17023SJohn Marino NOP_EXPR);
10841e4b17023SJohn Marino
10842e4b17023SJohn Marino /* We do the folding for va_start in the expander. */
10843e4b17023SJohn Marino case BUILT_IN_VA_START:
10844e4b17023SJohn Marino break;
10845e4b17023SJohn Marino
10846e4b17023SJohn Marino case BUILT_IN_SPRINTF:
10847e4b17023SJohn Marino return fold_builtin_sprintf (loc, arg0, arg1, NULL_TREE, ignore);
10848e4b17023SJohn Marino
10849e4b17023SJohn Marino case BUILT_IN_OBJECT_SIZE:
10850e4b17023SJohn Marino return fold_builtin_object_size (arg0, arg1);
10851e4b17023SJohn Marino
10852e4b17023SJohn Marino case BUILT_IN_PRINTF:
10853e4b17023SJohn Marino case BUILT_IN_PRINTF_UNLOCKED:
10854e4b17023SJohn Marino case BUILT_IN_VPRINTF:
10855e4b17023SJohn Marino return fold_builtin_printf (loc, fndecl, arg0, arg1, ignore, fcode);
10856e4b17023SJohn Marino
10857e4b17023SJohn Marino case BUILT_IN_PRINTF_CHK:
10858e4b17023SJohn Marino case BUILT_IN_VPRINTF_CHK:
10859e4b17023SJohn Marino if (!validate_arg (arg0, INTEGER_TYPE)
10860e4b17023SJohn Marino || TREE_SIDE_EFFECTS (arg0))
10861e4b17023SJohn Marino return NULL_TREE;
10862e4b17023SJohn Marino else
10863e4b17023SJohn Marino return fold_builtin_printf (loc, fndecl,
10864e4b17023SJohn Marino arg1, NULL_TREE, ignore, fcode);
10865e4b17023SJohn Marino break;
10866e4b17023SJohn Marino
10867e4b17023SJohn Marino case BUILT_IN_FPRINTF:
10868e4b17023SJohn Marino case BUILT_IN_FPRINTF_UNLOCKED:
10869e4b17023SJohn Marino case BUILT_IN_VFPRINTF:
10870e4b17023SJohn Marino return fold_builtin_fprintf (loc, fndecl, arg0, arg1, NULL_TREE,
10871e4b17023SJohn Marino ignore, fcode);
10872e4b17023SJohn Marino
10873e4b17023SJohn Marino case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
10874e4b17023SJohn Marino return fold_builtin_atomic_always_lock_free (arg0, arg1);
10875e4b17023SJohn Marino
10876e4b17023SJohn Marino case BUILT_IN_ATOMIC_IS_LOCK_FREE:
10877e4b17023SJohn Marino return fold_builtin_atomic_is_lock_free (arg0, arg1);
10878e4b17023SJohn Marino
10879e4b17023SJohn Marino default:
10880e4b17023SJohn Marino break;
10881e4b17023SJohn Marino }
10882e4b17023SJohn Marino return NULL_TREE;
10883e4b17023SJohn Marino }
10884e4b17023SJohn Marino
10885e4b17023SJohn Marino /* Fold a call to built-in function FNDECL with 3 arguments, ARG0, ARG1,
10886e4b17023SJohn Marino and ARG2. IGNORE is true if the result of the function call is ignored.
10887e4b17023SJohn Marino This function returns NULL_TREE if no simplification was possible. */
10888e4b17023SJohn Marino
10889e4b17023SJohn Marino static tree
fold_builtin_3(location_t loc,tree fndecl,tree arg0,tree arg1,tree arg2,bool ignore)10890e4b17023SJohn Marino fold_builtin_3 (location_t loc, tree fndecl,
10891e4b17023SJohn Marino tree arg0, tree arg1, tree arg2, bool ignore)
10892e4b17023SJohn Marino {
10893e4b17023SJohn Marino tree type = TREE_TYPE (TREE_TYPE (fndecl));
10894e4b17023SJohn Marino enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
10895e4b17023SJohn Marino switch (fcode)
10896e4b17023SJohn Marino {
10897e4b17023SJohn Marino
10898e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_SINCOS):
10899e4b17023SJohn Marino return fold_builtin_sincos (loc, arg0, arg1, arg2);
10900e4b17023SJohn Marino
10901e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_FMA):
10902e4b17023SJohn Marino return fold_builtin_fma (loc, arg0, arg1, arg2, type);
10903e4b17023SJohn Marino break;
10904e4b17023SJohn Marino
10905e4b17023SJohn Marino CASE_FLT_FN (BUILT_IN_REMQUO):
10906e4b17023SJohn Marino if (validate_arg (arg0, REAL_TYPE)
10907e4b17023SJohn Marino && validate_arg(arg1, REAL_TYPE)
10908e4b17023SJohn Marino && validate_arg(arg2, POINTER_TYPE))
10909e4b17023SJohn Marino return do_mpfr_remquo (arg0, arg1, arg2);
10910e4b17023SJohn Marino break;
10911e4b17023SJohn Marino
10912e4b17023SJohn Marino case BUILT_IN_MEMSET:
10913e4b17023SJohn Marino return fold_builtin_memset (loc, arg0, arg1, arg2, type, ignore);
10914e4b17023SJohn Marino
10915e4b17023SJohn Marino case BUILT_IN_BCOPY:
10916e4b17023SJohn Marino return fold_builtin_memory_op (loc, arg1, arg0, arg2,
10917e4b17023SJohn Marino void_type_node, true, /*endp=*/3);
10918e4b17023SJohn Marino
10919e4b17023SJohn Marino case BUILT_IN_MEMCPY:
10920e4b17023SJohn Marino return fold_builtin_memory_op (loc, arg0, arg1, arg2,
10921e4b17023SJohn Marino type, ignore, /*endp=*/0);
10922e4b17023SJohn Marino
10923e4b17023SJohn Marino case BUILT_IN_MEMPCPY:
10924e4b17023SJohn Marino return fold_builtin_memory_op (loc, arg0, arg1, arg2,
10925e4b17023SJohn Marino type, ignore, /*endp=*/1);
10926e4b17023SJohn Marino
10927e4b17023SJohn Marino case BUILT_IN_MEMMOVE:
10928e4b17023SJohn Marino return fold_builtin_memory_op (loc, arg0, arg1, arg2,
10929e4b17023SJohn Marino type, ignore, /*endp=*/3);
10930e4b17023SJohn Marino
10931e4b17023SJohn Marino case BUILT_IN_STRNCAT:
10932e4b17023SJohn Marino return fold_builtin_strncat (loc, arg0, arg1, arg2);
10933e4b17023SJohn Marino
10934e4b17023SJohn Marino case BUILT_IN_STRNCPY:
10935e4b17023SJohn Marino return fold_builtin_strncpy (loc, fndecl, arg0, arg1, arg2, NULL_TREE);
10936e4b17023SJohn Marino
10937e4b17023SJohn Marino case BUILT_IN_STRNCMP:
10938e4b17023SJohn Marino return fold_builtin_strncmp (loc, arg0, arg1, arg2);
10939e4b17023SJohn Marino
10940e4b17023SJohn Marino case BUILT_IN_MEMCHR:
10941e4b17023SJohn Marino return fold_builtin_memchr (loc, arg0, arg1, arg2, type);
10942e4b17023SJohn Marino
10943e4b17023SJohn Marino case BUILT_IN_BCMP:
10944e4b17023SJohn Marino case BUILT_IN_MEMCMP:
10945e4b17023SJohn Marino return fold_builtin_memcmp (loc, arg0, arg1, arg2);;
10946e4b17023SJohn Marino
10947e4b17023SJohn Marino case BUILT_IN_SPRINTF:
10948e4b17023SJohn Marino return fold_builtin_sprintf (loc, arg0, arg1, arg2, ignore);
10949e4b17023SJohn Marino
10950e4b17023SJohn Marino case BUILT_IN_SNPRINTF:
10951e4b17023SJohn Marino return fold_builtin_snprintf (loc, arg0, arg1, arg2, NULL_TREE, ignore);
10952e4b17023SJohn Marino
10953e4b17023SJohn Marino case BUILT_IN_STRCPY_CHK:
10954e4b17023SJohn Marino case BUILT_IN_STPCPY_CHK:
10955e4b17023SJohn Marino return fold_builtin_stxcpy_chk (loc, fndecl, arg0, arg1, arg2, NULL_TREE,
10956e4b17023SJohn Marino ignore, fcode);
10957e4b17023SJohn Marino
10958e4b17023SJohn Marino case BUILT_IN_STRCAT_CHK:
10959e4b17023SJohn Marino return fold_builtin_strcat_chk (loc, fndecl, arg0, arg1, arg2);
10960e4b17023SJohn Marino
10961e4b17023SJohn Marino case BUILT_IN_PRINTF_CHK:
10962e4b17023SJohn Marino case BUILT_IN_VPRINTF_CHK:
10963e4b17023SJohn Marino if (!validate_arg (arg0, INTEGER_TYPE)
10964e4b17023SJohn Marino || TREE_SIDE_EFFECTS (arg0))
10965e4b17023SJohn Marino return NULL_TREE;
10966e4b17023SJohn Marino else
10967e4b17023SJohn Marino return fold_builtin_printf (loc, fndecl, arg1, arg2, ignore, fcode);
10968e4b17023SJohn Marino break;
10969e4b17023SJohn Marino
10970e4b17023SJohn Marino case BUILT_IN_FPRINTF:
10971e4b17023SJohn Marino case BUILT_IN_FPRINTF_UNLOCKED:
10972e4b17023SJohn Marino case BUILT_IN_VFPRINTF:
10973e4b17023SJohn Marino return fold_builtin_fprintf (loc, fndecl, arg0, arg1, arg2,
10974e4b17023SJohn Marino ignore, fcode);
10975e4b17023SJohn Marino
10976e4b17023SJohn Marino case BUILT_IN_FPRINTF_CHK:
10977e4b17023SJohn Marino case BUILT_IN_VFPRINTF_CHK:
10978e4b17023SJohn Marino if (!validate_arg (arg1, INTEGER_TYPE)
10979e4b17023SJohn Marino || TREE_SIDE_EFFECTS (arg1))
10980e4b17023SJohn Marino return NULL_TREE;
10981e4b17023SJohn Marino else
10982e4b17023SJohn Marino return fold_builtin_fprintf (loc, fndecl, arg0, arg2, NULL_TREE,
10983e4b17023SJohn Marino ignore, fcode);
10984e4b17023SJohn Marino
10985e4b17023SJohn Marino default:
10986e4b17023SJohn Marino break;
10987e4b17023SJohn Marino }
10988e4b17023SJohn Marino return NULL_TREE;
10989e4b17023SJohn Marino }
10990e4b17023SJohn Marino
10991e4b17023SJohn Marino /* Fold a call to built-in function FNDECL with 4 arguments, ARG0, ARG1,
10992e4b17023SJohn Marino ARG2, and ARG3. IGNORE is true if the result of the function call is
10993e4b17023SJohn Marino ignored. This function returns NULL_TREE if no simplification was
10994e4b17023SJohn Marino possible. */
10995e4b17023SJohn Marino
10996e4b17023SJohn Marino static tree
fold_builtin_4(location_t loc,tree fndecl,tree arg0,tree arg1,tree arg2,tree arg3,bool ignore)10997e4b17023SJohn Marino fold_builtin_4 (location_t loc, tree fndecl,
10998e4b17023SJohn Marino tree arg0, tree arg1, tree arg2, tree arg3, bool ignore)
10999e4b17023SJohn Marino {
11000e4b17023SJohn Marino enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
11001e4b17023SJohn Marino
11002e4b17023SJohn Marino switch (fcode)
11003e4b17023SJohn Marino {
11004e4b17023SJohn Marino case BUILT_IN_MEMCPY_CHK:
11005e4b17023SJohn Marino case BUILT_IN_MEMPCPY_CHK:
11006e4b17023SJohn Marino case BUILT_IN_MEMMOVE_CHK:
11007e4b17023SJohn Marino case BUILT_IN_MEMSET_CHK:
11008e4b17023SJohn Marino return fold_builtin_memory_chk (loc, fndecl, arg0, arg1, arg2, arg3,
11009e4b17023SJohn Marino NULL_TREE, ignore,
11010e4b17023SJohn Marino DECL_FUNCTION_CODE (fndecl));
11011e4b17023SJohn Marino
11012e4b17023SJohn Marino case BUILT_IN_STRNCPY_CHK:
11013e4b17023SJohn Marino case BUILT_IN_STPNCPY_CHK:
11014e4b17023SJohn Marino return fold_builtin_stxncpy_chk (loc, arg0, arg1, arg2, arg3, NULL_TREE,
11015e4b17023SJohn Marino ignore, fcode);
11016e4b17023SJohn Marino
11017e4b17023SJohn Marino case BUILT_IN_STRNCAT_CHK:
11018e4b17023SJohn Marino return fold_builtin_strncat_chk (loc, fndecl, arg0, arg1, arg2, arg3);
11019e4b17023SJohn Marino
11020e4b17023SJohn Marino case BUILT_IN_SNPRINTF:
11021e4b17023SJohn Marino return fold_builtin_snprintf (loc, arg0, arg1, arg2, arg3, ignore);
11022e4b17023SJohn Marino
11023e4b17023SJohn Marino case BUILT_IN_FPRINTF_CHK:
11024e4b17023SJohn Marino case BUILT_IN_VFPRINTF_CHK:
11025e4b17023SJohn Marino if (!validate_arg (arg1, INTEGER_TYPE)
11026e4b17023SJohn Marino || TREE_SIDE_EFFECTS (arg1))
11027e4b17023SJohn Marino return NULL_TREE;
11028e4b17023SJohn Marino else
11029e4b17023SJohn Marino return fold_builtin_fprintf (loc, fndecl, arg0, arg2, arg3,
11030e4b17023SJohn Marino ignore, fcode);
11031e4b17023SJohn Marino break;
11032e4b17023SJohn Marino
11033e4b17023SJohn Marino default:
11034e4b17023SJohn Marino break;
11035e4b17023SJohn Marino }
11036e4b17023SJohn Marino return NULL_TREE;
11037e4b17023SJohn Marino }
11038e4b17023SJohn Marino
11039e4b17023SJohn Marino /* Fold a call to built-in function FNDECL. ARGS is an array of NARGS
11040e4b17023SJohn Marino arguments, where NARGS <= 4. IGNORE is true if the result of the
11041e4b17023SJohn Marino function call is ignored. This function returns NULL_TREE if no
11042e4b17023SJohn Marino simplification was possible. Note that this only folds builtins with
11043e4b17023SJohn Marino fixed argument patterns. Foldings that do varargs-to-varargs
11044e4b17023SJohn Marino transformations, or that match calls with more than 4 arguments,
11045e4b17023SJohn Marino need to be handled with fold_builtin_varargs instead. */
11046e4b17023SJohn Marino
11047e4b17023SJohn Marino #define MAX_ARGS_TO_FOLD_BUILTIN 4
11048e4b17023SJohn Marino
11049e4b17023SJohn Marino static tree
fold_builtin_n(location_t loc,tree fndecl,tree * args,int nargs,bool ignore)11050e4b17023SJohn Marino fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool ignore)
11051e4b17023SJohn Marino {
11052e4b17023SJohn Marino tree ret = NULL_TREE;
11053e4b17023SJohn Marino
11054e4b17023SJohn Marino switch (nargs)
11055e4b17023SJohn Marino {
11056e4b17023SJohn Marino case 0:
11057e4b17023SJohn Marino ret = fold_builtin_0 (loc, fndecl, ignore);
11058e4b17023SJohn Marino break;
11059e4b17023SJohn Marino case 1:
11060e4b17023SJohn Marino ret = fold_builtin_1 (loc, fndecl, args[0], ignore);
11061e4b17023SJohn Marino break;
11062e4b17023SJohn Marino case 2:
11063e4b17023SJohn Marino ret = fold_builtin_2 (loc, fndecl, args[0], args[1], ignore);
11064e4b17023SJohn Marino break;
11065e4b17023SJohn Marino case 3:
11066e4b17023SJohn Marino ret = fold_builtin_3 (loc, fndecl, args[0], args[1], args[2], ignore);
11067e4b17023SJohn Marino break;
11068e4b17023SJohn Marino case 4:
11069e4b17023SJohn Marino ret = fold_builtin_4 (loc, fndecl, args[0], args[1], args[2], args[3],
11070e4b17023SJohn Marino ignore);
11071e4b17023SJohn Marino break;
11072e4b17023SJohn Marino default:
11073e4b17023SJohn Marino break;
11074e4b17023SJohn Marino }
11075e4b17023SJohn Marino if (ret)
11076e4b17023SJohn Marino {
11077e4b17023SJohn Marino ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
11078e4b17023SJohn Marino SET_EXPR_LOCATION (ret, loc);
11079e4b17023SJohn Marino TREE_NO_WARNING (ret) = 1;
11080e4b17023SJohn Marino return ret;
11081e4b17023SJohn Marino }
11082e4b17023SJohn Marino return NULL_TREE;
11083e4b17023SJohn Marino }
11084e4b17023SJohn Marino
11085e4b17023SJohn Marino /* Builtins with folding operations that operate on "..." arguments
11086e4b17023SJohn Marino need special handling; we need to store the arguments in a convenient
11087e4b17023SJohn Marino data structure before attempting any folding. Fortunately there are
11088e4b17023SJohn Marino only a few builtins that fall into this category. FNDECL is the
11089e4b17023SJohn Marino function, EXP is the CALL_EXPR for the call, and IGNORE is true if the
11090e4b17023SJohn Marino result of the function call is ignored. */
11091e4b17023SJohn Marino
11092e4b17023SJohn Marino static tree
fold_builtin_varargs(location_t loc,tree fndecl,tree exp,bool ignore ATTRIBUTE_UNUSED)11093e4b17023SJohn Marino fold_builtin_varargs (location_t loc, tree fndecl, tree exp,
11094e4b17023SJohn Marino bool ignore ATTRIBUTE_UNUSED)
11095e4b17023SJohn Marino {
11096e4b17023SJohn Marino enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
11097e4b17023SJohn Marino tree ret = NULL_TREE;
11098e4b17023SJohn Marino
11099e4b17023SJohn Marino switch (fcode)
11100e4b17023SJohn Marino {
11101e4b17023SJohn Marino case BUILT_IN_SPRINTF_CHK:
11102e4b17023SJohn Marino case BUILT_IN_VSPRINTF_CHK:
11103e4b17023SJohn Marino ret = fold_builtin_sprintf_chk (loc, exp, fcode);
11104e4b17023SJohn Marino break;
11105e4b17023SJohn Marino
11106e4b17023SJohn Marino case BUILT_IN_SNPRINTF_CHK:
11107e4b17023SJohn Marino case BUILT_IN_VSNPRINTF_CHK:
11108e4b17023SJohn Marino ret = fold_builtin_snprintf_chk (loc, exp, NULL_TREE, fcode);
11109e4b17023SJohn Marino break;
11110e4b17023SJohn Marino
11111e4b17023SJohn Marino case BUILT_IN_FPCLASSIFY:
11112e4b17023SJohn Marino ret = fold_builtin_fpclassify (loc, exp);
11113e4b17023SJohn Marino break;
11114e4b17023SJohn Marino
11115e4b17023SJohn Marino default:
11116e4b17023SJohn Marino break;
11117e4b17023SJohn Marino }
11118e4b17023SJohn Marino if (ret)
11119e4b17023SJohn Marino {
11120e4b17023SJohn Marino ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
11121e4b17023SJohn Marino SET_EXPR_LOCATION (ret, loc);
11122e4b17023SJohn Marino TREE_NO_WARNING (ret) = 1;
11123e4b17023SJohn Marino return ret;
11124e4b17023SJohn Marino }
11125e4b17023SJohn Marino return NULL_TREE;
11126e4b17023SJohn Marino }
11127e4b17023SJohn Marino
11128e4b17023SJohn Marino /* Return true if FNDECL shouldn't be folded right now.
11129e4b17023SJohn Marino If a built-in function has an inline attribute always_inline
11130e4b17023SJohn Marino wrapper, defer folding it after always_inline functions have
11131e4b17023SJohn Marino been inlined, otherwise e.g. -D_FORTIFY_SOURCE checking
11132e4b17023SJohn Marino might not be performed. */
11133e4b17023SJohn Marino
11134e4b17023SJohn Marino bool
avoid_folding_inline_builtin(tree fndecl)11135e4b17023SJohn Marino avoid_folding_inline_builtin (tree fndecl)
11136e4b17023SJohn Marino {
11137e4b17023SJohn Marino return (DECL_DECLARED_INLINE_P (fndecl)
11138e4b17023SJohn Marino && DECL_DISREGARD_INLINE_LIMITS (fndecl)
11139e4b17023SJohn Marino && cfun
11140e4b17023SJohn Marino && !cfun->always_inline_functions_inlined
11141e4b17023SJohn Marino && lookup_attribute ("always_inline", DECL_ATTRIBUTES (fndecl)));
11142e4b17023SJohn Marino }
11143e4b17023SJohn Marino
11144e4b17023SJohn Marino /* A wrapper function for builtin folding that prevents warnings for
11145e4b17023SJohn Marino "statement without effect" and the like, caused by removing the
11146e4b17023SJohn Marino call node earlier than the warning is generated. */
11147e4b17023SJohn Marino
11148e4b17023SJohn Marino tree
fold_call_expr(location_t loc,tree exp,bool ignore)11149e4b17023SJohn Marino fold_call_expr (location_t loc, tree exp, bool ignore)
11150e4b17023SJohn Marino {
11151e4b17023SJohn Marino tree ret = NULL_TREE;
11152e4b17023SJohn Marino tree fndecl = get_callee_fndecl (exp);
11153e4b17023SJohn Marino if (fndecl
11154e4b17023SJohn Marino && TREE_CODE (fndecl) == FUNCTION_DECL
11155e4b17023SJohn Marino && DECL_BUILT_IN (fndecl)
11156e4b17023SJohn Marino /* If CALL_EXPR_VA_ARG_PACK is set, the arguments aren't finalized
11157e4b17023SJohn Marino yet. Defer folding until we see all the arguments
11158e4b17023SJohn Marino (after inlining). */
11159e4b17023SJohn Marino && !CALL_EXPR_VA_ARG_PACK (exp))
11160e4b17023SJohn Marino {
11161e4b17023SJohn Marino int nargs = call_expr_nargs (exp);
11162e4b17023SJohn Marino
11163e4b17023SJohn Marino /* Before gimplification CALL_EXPR_VA_ARG_PACK is not set, but
11164e4b17023SJohn Marino instead last argument is __builtin_va_arg_pack (). Defer folding
11165e4b17023SJohn Marino even in that case, until arguments are finalized. */
11166e4b17023SJohn Marino if (nargs && TREE_CODE (CALL_EXPR_ARG (exp, nargs - 1)) == CALL_EXPR)
11167e4b17023SJohn Marino {
11168e4b17023SJohn Marino tree fndecl2 = get_callee_fndecl (CALL_EXPR_ARG (exp, nargs - 1));
11169e4b17023SJohn Marino if (fndecl2
11170e4b17023SJohn Marino && TREE_CODE (fndecl2) == FUNCTION_DECL
11171e4b17023SJohn Marino && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL
11172e4b17023SJohn Marino && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
11173e4b17023SJohn Marino return NULL_TREE;
11174e4b17023SJohn Marino }
11175e4b17023SJohn Marino
11176e4b17023SJohn Marino if (avoid_folding_inline_builtin (fndecl))
11177e4b17023SJohn Marino return NULL_TREE;
11178e4b17023SJohn Marino
11179e4b17023SJohn Marino if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
11180e4b17023SJohn Marino return targetm.fold_builtin (fndecl, call_expr_nargs (exp),
11181e4b17023SJohn Marino CALL_EXPR_ARGP (exp), ignore);
11182e4b17023SJohn Marino else
11183e4b17023SJohn Marino {
11184e4b17023SJohn Marino if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
11185e4b17023SJohn Marino {
11186e4b17023SJohn Marino tree *args = CALL_EXPR_ARGP (exp);
11187e4b17023SJohn Marino ret = fold_builtin_n (loc, fndecl, args, nargs, ignore);
11188e4b17023SJohn Marino }
11189e4b17023SJohn Marino if (!ret)
11190e4b17023SJohn Marino ret = fold_builtin_varargs (loc, fndecl, exp, ignore);
11191e4b17023SJohn Marino if (ret)
11192e4b17023SJohn Marino return ret;
11193e4b17023SJohn Marino }
11194e4b17023SJohn Marino }
11195e4b17023SJohn Marino return NULL_TREE;
11196e4b17023SJohn Marino }
11197e4b17023SJohn Marino
11198e4b17023SJohn Marino /* Conveniently construct a function call expression. FNDECL names the
11199e4b17023SJohn Marino function to be called and N arguments are passed in the array
11200e4b17023SJohn Marino ARGARRAY. */
11201e4b17023SJohn Marino
11202e4b17023SJohn Marino tree
build_call_expr_loc_array(location_t loc,tree fndecl,int n,tree * argarray)11203e4b17023SJohn Marino build_call_expr_loc_array (location_t loc, tree fndecl, int n, tree *argarray)
11204e4b17023SJohn Marino {
11205e4b17023SJohn Marino tree fntype = TREE_TYPE (fndecl);
11206e4b17023SJohn Marino tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
11207e4b17023SJohn Marino
11208e4b17023SJohn Marino return fold_builtin_call_array (loc, TREE_TYPE (fntype), fn, n, argarray);
11209e4b17023SJohn Marino }
11210e4b17023SJohn Marino
11211e4b17023SJohn Marino /* Conveniently construct a function call expression. FNDECL names the
11212e4b17023SJohn Marino function to be called and the arguments are passed in the vector
11213e4b17023SJohn Marino VEC. */
11214e4b17023SJohn Marino
11215e4b17023SJohn Marino tree
build_call_expr_loc_vec(location_t loc,tree fndecl,VEC (tree,gc)* vec)11216e4b17023SJohn Marino build_call_expr_loc_vec (location_t loc, tree fndecl, VEC(tree,gc) *vec)
11217e4b17023SJohn Marino {
11218e4b17023SJohn Marino return build_call_expr_loc_array (loc, fndecl, VEC_length (tree, vec),
11219e4b17023SJohn Marino VEC_address (tree, vec));
11220e4b17023SJohn Marino }
11221e4b17023SJohn Marino
11222e4b17023SJohn Marino
11223e4b17023SJohn Marino /* Conveniently construct a function call expression. FNDECL names the
11224e4b17023SJohn Marino function to be called, N is the number of arguments, and the "..."
11225e4b17023SJohn Marino parameters are the argument expressions. */
11226e4b17023SJohn Marino
11227e4b17023SJohn Marino tree
build_call_expr_loc(location_t loc,tree fndecl,int n,...)11228e4b17023SJohn Marino build_call_expr_loc (location_t loc, tree fndecl, int n, ...)
11229e4b17023SJohn Marino {
11230e4b17023SJohn Marino va_list ap;
11231e4b17023SJohn Marino tree *argarray = XALLOCAVEC (tree, n);
11232e4b17023SJohn Marino int i;
11233e4b17023SJohn Marino
11234e4b17023SJohn Marino va_start (ap, n);
11235e4b17023SJohn Marino for (i = 0; i < n; i++)
11236e4b17023SJohn Marino argarray[i] = va_arg (ap, tree);
11237e4b17023SJohn Marino va_end (ap);
11238e4b17023SJohn Marino return build_call_expr_loc_array (loc, fndecl, n, argarray);
11239e4b17023SJohn Marino }
11240e4b17023SJohn Marino
11241e4b17023SJohn Marino /* Like build_call_expr_loc (UNKNOWN_LOCATION, ...). Duplicated because
11242e4b17023SJohn Marino varargs macros aren't supported by all bootstrap compilers. */
11243e4b17023SJohn Marino
11244e4b17023SJohn Marino tree
build_call_expr(tree fndecl,int n,...)11245e4b17023SJohn Marino build_call_expr (tree fndecl, int n, ...)
11246e4b17023SJohn Marino {
11247e4b17023SJohn Marino va_list ap;
11248e4b17023SJohn Marino tree *argarray = XALLOCAVEC (tree, n);
11249e4b17023SJohn Marino int i;
11250e4b17023SJohn Marino
11251e4b17023SJohn Marino va_start (ap, n);
11252e4b17023SJohn Marino for (i = 0; i < n; i++)
11253e4b17023SJohn Marino argarray[i] = va_arg (ap, tree);
11254e4b17023SJohn Marino va_end (ap);
11255e4b17023SJohn Marino return build_call_expr_loc_array (UNKNOWN_LOCATION, fndecl, n, argarray);
11256e4b17023SJohn Marino }
11257e4b17023SJohn Marino
11258e4b17023SJohn Marino /* Construct a CALL_EXPR with type TYPE with FN as the function expression.
11259e4b17023SJohn Marino N arguments are passed in the array ARGARRAY. */
11260e4b17023SJohn Marino
11261e4b17023SJohn Marino tree
fold_builtin_call_array(location_t loc,tree type,tree fn,int n,tree * argarray)11262e4b17023SJohn Marino fold_builtin_call_array (location_t loc, tree type,
11263e4b17023SJohn Marino tree fn,
11264e4b17023SJohn Marino int n,
11265e4b17023SJohn Marino tree *argarray)
11266e4b17023SJohn Marino {
11267e4b17023SJohn Marino tree ret = NULL_TREE;
11268e4b17023SJohn Marino tree exp;
11269e4b17023SJohn Marino
11270e4b17023SJohn Marino if (TREE_CODE (fn) == ADDR_EXPR)
11271e4b17023SJohn Marino {
11272e4b17023SJohn Marino tree fndecl = TREE_OPERAND (fn, 0);
11273e4b17023SJohn Marino if (TREE_CODE (fndecl) == FUNCTION_DECL
11274e4b17023SJohn Marino && DECL_BUILT_IN (fndecl))
11275e4b17023SJohn Marino {
11276e4b17023SJohn Marino /* If last argument is __builtin_va_arg_pack (), arguments to this
11277e4b17023SJohn Marino function are not finalized yet. Defer folding until they are. */
11278e4b17023SJohn Marino if (n && TREE_CODE (argarray[n - 1]) == CALL_EXPR)
11279e4b17023SJohn Marino {
11280e4b17023SJohn Marino tree fndecl2 = get_callee_fndecl (argarray[n - 1]);
11281e4b17023SJohn Marino if (fndecl2
11282e4b17023SJohn Marino && TREE_CODE (fndecl2) == FUNCTION_DECL
11283e4b17023SJohn Marino && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL
11284e4b17023SJohn Marino && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
11285e4b17023SJohn Marino return build_call_array_loc (loc, type, fn, n, argarray);
11286e4b17023SJohn Marino }
11287e4b17023SJohn Marino if (avoid_folding_inline_builtin (fndecl))
11288e4b17023SJohn Marino return build_call_array_loc (loc, type, fn, n, argarray);
11289e4b17023SJohn Marino if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
11290e4b17023SJohn Marino {
11291e4b17023SJohn Marino ret = targetm.fold_builtin (fndecl, n, argarray, false);
11292e4b17023SJohn Marino if (ret)
11293e4b17023SJohn Marino return ret;
11294e4b17023SJohn Marino
11295e4b17023SJohn Marino return build_call_array_loc (loc, type, fn, n, argarray);
11296e4b17023SJohn Marino }
11297e4b17023SJohn Marino else if (n <= MAX_ARGS_TO_FOLD_BUILTIN)
11298e4b17023SJohn Marino {
11299e4b17023SJohn Marino /* First try the transformations that don't require consing up
11300e4b17023SJohn Marino an exp. */
11301e4b17023SJohn Marino ret = fold_builtin_n (loc, fndecl, argarray, n, false);
11302e4b17023SJohn Marino if (ret)
11303e4b17023SJohn Marino return ret;
11304e4b17023SJohn Marino }
11305e4b17023SJohn Marino
11306e4b17023SJohn Marino /* If we got this far, we need to build an exp. */
11307e4b17023SJohn Marino exp = build_call_array_loc (loc, type, fn, n, argarray);
11308e4b17023SJohn Marino ret = fold_builtin_varargs (loc, fndecl, exp, false);
11309e4b17023SJohn Marino return ret ? ret : exp;
11310e4b17023SJohn Marino }
11311e4b17023SJohn Marino }
11312e4b17023SJohn Marino
11313e4b17023SJohn Marino return build_call_array_loc (loc, type, fn, n, argarray);
11314e4b17023SJohn Marino }
11315e4b17023SJohn Marino
11316e4b17023SJohn Marino /* Construct a new CALL_EXPR to FNDECL using the tail of the argument
11317e4b17023SJohn Marino list ARGS along with N new arguments in NEWARGS. SKIP is the number
11318e4b17023SJohn Marino of arguments in ARGS to be omitted. OLDNARGS is the number of
11319e4b17023SJohn Marino elements in ARGS. */
11320e4b17023SJohn Marino
11321e4b17023SJohn Marino static tree
rewrite_call_expr_valist(location_t loc,int oldnargs,tree * args,int skip,tree fndecl,int n,va_list newargs)11322e4b17023SJohn Marino rewrite_call_expr_valist (location_t loc, int oldnargs, tree *args,
11323e4b17023SJohn Marino int skip, tree fndecl, int n, va_list newargs)
11324e4b17023SJohn Marino {
11325e4b17023SJohn Marino int nargs = oldnargs - skip + n;
11326e4b17023SJohn Marino tree *buffer;
11327e4b17023SJohn Marino
11328e4b17023SJohn Marino if (n > 0)
11329e4b17023SJohn Marino {
11330e4b17023SJohn Marino int i, j;
11331e4b17023SJohn Marino
11332e4b17023SJohn Marino buffer = XALLOCAVEC (tree, nargs);
11333e4b17023SJohn Marino for (i = 0; i < n; i++)
11334e4b17023SJohn Marino buffer[i] = va_arg (newargs, tree);
11335e4b17023SJohn Marino for (j = skip; j < oldnargs; j++, i++)
11336e4b17023SJohn Marino buffer[i] = args[j];
11337e4b17023SJohn Marino }
11338e4b17023SJohn Marino else
11339e4b17023SJohn Marino buffer = args + skip;
11340e4b17023SJohn Marino
11341e4b17023SJohn Marino return build_call_expr_loc_array (loc, fndecl, nargs, buffer);
11342e4b17023SJohn Marino }
11343e4b17023SJohn Marino
11344e4b17023SJohn Marino /* Construct a new CALL_EXPR to FNDECL using the tail of the argument
11345e4b17023SJohn Marino list ARGS along with N new arguments specified as the "..."
11346e4b17023SJohn Marino parameters. SKIP is the number of arguments in ARGS to be omitted.
11347e4b17023SJohn Marino OLDNARGS is the number of elements in ARGS. */
11348e4b17023SJohn Marino
11349e4b17023SJohn Marino static tree
rewrite_call_expr_array(location_t loc,int oldnargs,tree * args,int skip,tree fndecl,int n,...)11350e4b17023SJohn Marino rewrite_call_expr_array (location_t loc, int oldnargs, tree *args,
11351e4b17023SJohn Marino int skip, tree fndecl, int n, ...)
11352e4b17023SJohn Marino {
11353e4b17023SJohn Marino va_list ap;
11354e4b17023SJohn Marino tree t;
11355e4b17023SJohn Marino
11356e4b17023SJohn Marino va_start (ap, n);
11357e4b17023SJohn Marino t = rewrite_call_expr_valist (loc, oldnargs, args, skip, fndecl, n, ap);
11358e4b17023SJohn Marino va_end (ap);
11359e4b17023SJohn Marino
11360e4b17023SJohn Marino return t;
11361e4b17023SJohn Marino }
11362e4b17023SJohn Marino
11363e4b17023SJohn Marino /* Construct a new CALL_EXPR using the tail of the argument list of EXP
11364e4b17023SJohn Marino along with N new arguments specified as the "..." parameters. SKIP
11365e4b17023SJohn Marino is the number of arguments in EXP to be omitted. This function is used
11366e4b17023SJohn Marino to do varargs-to-varargs transformations. */
11367e4b17023SJohn Marino
11368e4b17023SJohn Marino static tree
rewrite_call_expr(location_t loc,tree exp,int skip,tree fndecl,int n,...)11369e4b17023SJohn Marino rewrite_call_expr (location_t loc, tree exp, int skip, tree fndecl, int n, ...)
11370e4b17023SJohn Marino {
11371e4b17023SJohn Marino va_list ap;
11372e4b17023SJohn Marino tree t;
11373e4b17023SJohn Marino
11374e4b17023SJohn Marino va_start (ap, n);
11375e4b17023SJohn Marino t = rewrite_call_expr_valist (loc, call_expr_nargs (exp),
11376e4b17023SJohn Marino CALL_EXPR_ARGP (exp), skip, fndecl, n, ap);
11377e4b17023SJohn Marino va_end (ap);
11378e4b17023SJohn Marino
11379e4b17023SJohn Marino return t;
11380e4b17023SJohn Marino }
11381e4b17023SJohn Marino
11382e4b17023SJohn Marino /* Validate a single argument ARG against a tree code CODE representing
11383e4b17023SJohn Marino a type. */
11384e4b17023SJohn Marino
11385e4b17023SJohn Marino static bool
validate_arg(const_tree arg,enum tree_code code)11386e4b17023SJohn Marino validate_arg (const_tree arg, enum tree_code code)
11387e4b17023SJohn Marino {
11388e4b17023SJohn Marino if (!arg)
11389e4b17023SJohn Marino return false;
11390e4b17023SJohn Marino else if (code == POINTER_TYPE)
11391e4b17023SJohn Marino return POINTER_TYPE_P (TREE_TYPE (arg));
11392e4b17023SJohn Marino else if (code == INTEGER_TYPE)
11393e4b17023SJohn Marino return INTEGRAL_TYPE_P (TREE_TYPE (arg));
11394e4b17023SJohn Marino return code == TREE_CODE (TREE_TYPE (arg));
11395e4b17023SJohn Marino }
11396e4b17023SJohn Marino
11397e4b17023SJohn Marino /* This function validates the types of a function call argument list
11398e4b17023SJohn Marino against a specified list of tree_codes. If the last specifier is a 0,
11399e4b17023SJohn Marino that represents an ellipses, otherwise the last specifier must be a
11400e4b17023SJohn Marino VOID_TYPE.
11401e4b17023SJohn Marino
11402e4b17023SJohn Marino This is the GIMPLE version of validate_arglist. Eventually we want to
11403e4b17023SJohn Marino completely convert builtins.c to work from GIMPLEs and the tree based
11404e4b17023SJohn Marino validate_arglist will then be removed. */
11405e4b17023SJohn Marino
11406e4b17023SJohn Marino bool
validate_gimple_arglist(const_gimple call,...)11407e4b17023SJohn Marino validate_gimple_arglist (const_gimple call, ...)
11408e4b17023SJohn Marino {
11409e4b17023SJohn Marino enum tree_code code;
11410e4b17023SJohn Marino bool res = 0;
11411e4b17023SJohn Marino va_list ap;
11412e4b17023SJohn Marino const_tree arg;
11413e4b17023SJohn Marino size_t i;
11414e4b17023SJohn Marino
11415e4b17023SJohn Marino va_start (ap, call);
11416e4b17023SJohn Marino i = 0;
11417e4b17023SJohn Marino
11418e4b17023SJohn Marino do
11419e4b17023SJohn Marino {
11420e4b17023SJohn Marino code = (enum tree_code) va_arg (ap, int);
11421e4b17023SJohn Marino switch (code)
11422e4b17023SJohn Marino {
11423e4b17023SJohn Marino case 0:
11424e4b17023SJohn Marino /* This signifies an ellipses, any further arguments are all ok. */
11425e4b17023SJohn Marino res = true;
11426e4b17023SJohn Marino goto end;
11427e4b17023SJohn Marino case VOID_TYPE:
11428e4b17023SJohn Marino /* This signifies an endlink, if no arguments remain, return
11429e4b17023SJohn Marino true, otherwise return false. */
11430e4b17023SJohn Marino res = (i == gimple_call_num_args (call));
11431e4b17023SJohn Marino goto end;
11432e4b17023SJohn Marino default:
11433e4b17023SJohn Marino /* If no parameters remain or the parameter's code does not
11434e4b17023SJohn Marino match the specified code, return false. Otherwise continue
11435e4b17023SJohn Marino checking any remaining arguments. */
11436e4b17023SJohn Marino arg = gimple_call_arg (call, i++);
11437e4b17023SJohn Marino if (!validate_arg (arg, code))
11438e4b17023SJohn Marino goto end;
11439e4b17023SJohn Marino break;
11440e4b17023SJohn Marino }
11441e4b17023SJohn Marino }
11442e4b17023SJohn Marino while (1);
11443e4b17023SJohn Marino
11444e4b17023SJohn Marino /* We need gotos here since we can only have one VA_CLOSE in a
11445e4b17023SJohn Marino function. */
11446e4b17023SJohn Marino end: ;
11447e4b17023SJohn Marino va_end (ap);
11448e4b17023SJohn Marino
11449e4b17023SJohn Marino return res;
11450e4b17023SJohn Marino }
11451e4b17023SJohn Marino
11452e4b17023SJohn Marino /* This function validates the types of a function call argument list
11453e4b17023SJohn Marino against a specified list of tree_codes. If the last specifier is a 0,
11454e4b17023SJohn Marino that represents an ellipses, otherwise the last specifier must be a
11455e4b17023SJohn Marino VOID_TYPE. */
11456e4b17023SJohn Marino
11457e4b17023SJohn Marino bool
validate_arglist(const_tree callexpr,...)11458e4b17023SJohn Marino validate_arglist (const_tree callexpr, ...)
11459e4b17023SJohn Marino {
11460e4b17023SJohn Marino enum tree_code code;
11461e4b17023SJohn Marino bool res = 0;
11462e4b17023SJohn Marino va_list ap;
11463e4b17023SJohn Marino const_call_expr_arg_iterator iter;
11464e4b17023SJohn Marino const_tree arg;
11465e4b17023SJohn Marino
11466e4b17023SJohn Marino va_start (ap, callexpr);
11467e4b17023SJohn Marino init_const_call_expr_arg_iterator (callexpr, &iter);
11468e4b17023SJohn Marino
11469e4b17023SJohn Marino do
11470e4b17023SJohn Marino {
11471e4b17023SJohn Marino code = (enum tree_code) va_arg (ap, int);
11472e4b17023SJohn Marino switch (code)
11473e4b17023SJohn Marino {
11474e4b17023SJohn Marino case 0:
11475e4b17023SJohn Marino /* This signifies an ellipses, any further arguments are all ok. */
11476e4b17023SJohn Marino res = true;
11477e4b17023SJohn Marino goto end;
11478e4b17023SJohn Marino case VOID_TYPE:
11479e4b17023SJohn Marino /* This signifies an endlink, if no arguments remain, return
11480e4b17023SJohn Marino true, otherwise return false. */
11481e4b17023SJohn Marino res = !more_const_call_expr_args_p (&iter);
11482e4b17023SJohn Marino goto end;
11483e4b17023SJohn Marino default:
11484e4b17023SJohn Marino /* If no parameters remain or the parameter's code does not
11485e4b17023SJohn Marino match the specified code, return false. Otherwise continue
11486e4b17023SJohn Marino checking any remaining arguments. */
11487e4b17023SJohn Marino arg = next_const_call_expr_arg (&iter);
11488e4b17023SJohn Marino if (!validate_arg (arg, code))
11489e4b17023SJohn Marino goto end;
11490e4b17023SJohn Marino break;
11491e4b17023SJohn Marino }
11492e4b17023SJohn Marino }
11493e4b17023SJohn Marino while (1);
11494e4b17023SJohn Marino
11495e4b17023SJohn Marino /* We need gotos here since we can only have one VA_CLOSE in a
11496e4b17023SJohn Marino function. */
11497e4b17023SJohn Marino end: ;
11498e4b17023SJohn Marino va_end (ap);
11499e4b17023SJohn Marino
11500e4b17023SJohn Marino return res;
11501e4b17023SJohn Marino }
11502e4b17023SJohn Marino
11503e4b17023SJohn Marino /* Default target-specific builtin expander that does nothing. */
11504e4b17023SJohn Marino
11505e4b17023SJohn Marino rtx
default_expand_builtin(tree exp ATTRIBUTE_UNUSED,rtx target ATTRIBUTE_UNUSED,rtx subtarget ATTRIBUTE_UNUSED,enum machine_mode mode ATTRIBUTE_UNUSED,int ignore ATTRIBUTE_UNUSED)11506e4b17023SJohn Marino default_expand_builtin (tree exp ATTRIBUTE_UNUSED,
11507e4b17023SJohn Marino rtx target ATTRIBUTE_UNUSED,
11508e4b17023SJohn Marino rtx subtarget ATTRIBUTE_UNUSED,
11509e4b17023SJohn Marino enum machine_mode mode ATTRIBUTE_UNUSED,
11510e4b17023SJohn Marino int ignore ATTRIBUTE_UNUSED)
11511e4b17023SJohn Marino {
11512e4b17023SJohn Marino return NULL_RTX;
11513e4b17023SJohn Marino }
11514e4b17023SJohn Marino
11515e4b17023SJohn Marino /* Returns true is EXP represents data that would potentially reside
11516e4b17023SJohn Marino in a readonly section. */
11517e4b17023SJohn Marino
11518e4b17023SJohn Marino static bool
readonly_data_expr(tree exp)11519e4b17023SJohn Marino readonly_data_expr (tree exp)
11520e4b17023SJohn Marino {
11521e4b17023SJohn Marino STRIP_NOPS (exp);
11522e4b17023SJohn Marino
11523e4b17023SJohn Marino if (TREE_CODE (exp) != ADDR_EXPR)
11524e4b17023SJohn Marino return false;
11525e4b17023SJohn Marino
11526e4b17023SJohn Marino exp = get_base_address (TREE_OPERAND (exp, 0));
11527e4b17023SJohn Marino if (!exp)
11528e4b17023SJohn Marino return false;
11529e4b17023SJohn Marino
11530e4b17023SJohn Marino /* Make sure we call decl_readonly_section only for trees it
11531e4b17023SJohn Marino can handle (since it returns true for everything it doesn't
11532e4b17023SJohn Marino understand). */
11533e4b17023SJohn Marino if (TREE_CODE (exp) == STRING_CST
11534e4b17023SJohn Marino || TREE_CODE (exp) == CONSTRUCTOR
11535e4b17023SJohn Marino || (TREE_CODE (exp) == VAR_DECL && TREE_STATIC (exp)))
11536e4b17023SJohn Marino return decl_readonly_section (exp, 0);
11537e4b17023SJohn Marino else
11538e4b17023SJohn Marino return false;
11539e4b17023SJohn Marino }
11540e4b17023SJohn Marino
11541e4b17023SJohn Marino /* Simplify a call to the strstr builtin. S1 and S2 are the arguments
11542e4b17023SJohn Marino to the call, and TYPE is its return type.
11543e4b17023SJohn Marino
11544e4b17023SJohn Marino Return NULL_TREE if no simplification was possible, otherwise return the
11545e4b17023SJohn Marino simplified form of the call as a tree.
11546e4b17023SJohn Marino
11547e4b17023SJohn Marino The simplified form may be a constant or other expression which
11548e4b17023SJohn Marino computes the same value, but in a more efficient manner (including
11549e4b17023SJohn Marino calls to other builtin functions).
11550e4b17023SJohn Marino
11551e4b17023SJohn Marino The call may contain arguments which need to be evaluated, but
11552e4b17023SJohn Marino which are not useful to determine the result of the call. In
11553e4b17023SJohn Marino this case we return a chain of COMPOUND_EXPRs. The LHS of each
11554e4b17023SJohn Marino COMPOUND_EXPR will be an argument which must be evaluated.
11555e4b17023SJohn Marino COMPOUND_EXPRs are chained through their RHS. The RHS of the last
11556e4b17023SJohn Marino COMPOUND_EXPR in the chain will contain the tree for the simplified
11557e4b17023SJohn Marino form of the builtin function call. */
11558e4b17023SJohn Marino
11559e4b17023SJohn Marino static tree
fold_builtin_strstr(location_t loc,tree s1,tree s2,tree type)11560e4b17023SJohn Marino fold_builtin_strstr (location_t loc, tree s1, tree s2, tree type)
11561e4b17023SJohn Marino {
11562e4b17023SJohn Marino if (!validate_arg (s1, POINTER_TYPE)
11563e4b17023SJohn Marino || !validate_arg (s2, POINTER_TYPE))
11564e4b17023SJohn Marino return NULL_TREE;
11565e4b17023SJohn Marino else
11566e4b17023SJohn Marino {
11567e4b17023SJohn Marino tree fn;
11568e4b17023SJohn Marino const char *p1, *p2;
11569e4b17023SJohn Marino
11570e4b17023SJohn Marino p2 = c_getstr (s2);
11571e4b17023SJohn Marino if (p2 == NULL)
11572e4b17023SJohn Marino return NULL_TREE;
11573e4b17023SJohn Marino
11574e4b17023SJohn Marino p1 = c_getstr (s1);
11575e4b17023SJohn Marino if (p1 != NULL)
11576e4b17023SJohn Marino {
11577e4b17023SJohn Marino const char *r = strstr (p1, p2);
11578e4b17023SJohn Marino tree tem;
11579e4b17023SJohn Marino
11580e4b17023SJohn Marino if (r == NULL)
11581e4b17023SJohn Marino return build_int_cst (TREE_TYPE (s1), 0);
11582e4b17023SJohn Marino
11583e4b17023SJohn Marino /* Return an offset into the constant string argument. */
11584e4b17023SJohn Marino tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
11585e4b17023SJohn Marino return fold_convert_loc (loc, type, tem);
11586e4b17023SJohn Marino }
11587e4b17023SJohn Marino
11588e4b17023SJohn Marino /* The argument is const char *, and the result is char *, so we need
11589e4b17023SJohn Marino a type conversion here to avoid a warning. */
11590e4b17023SJohn Marino if (p2[0] == '\0')
11591e4b17023SJohn Marino return fold_convert_loc (loc, type, s1);
11592e4b17023SJohn Marino
11593e4b17023SJohn Marino if (p2[1] != '\0')
11594e4b17023SJohn Marino return NULL_TREE;
11595e4b17023SJohn Marino
11596e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_STRCHR);
11597e4b17023SJohn Marino if (!fn)
11598e4b17023SJohn Marino return NULL_TREE;
11599e4b17023SJohn Marino
11600e4b17023SJohn Marino /* New argument list transforming strstr(s1, s2) to
11601e4b17023SJohn Marino strchr(s1, s2[0]). */
11602e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 2, s1,
11603e4b17023SJohn Marino build_int_cst (integer_type_node, p2[0]));
11604e4b17023SJohn Marino }
11605e4b17023SJohn Marino }
11606e4b17023SJohn Marino
11607e4b17023SJohn Marino /* Simplify a call to the strchr builtin. S1 and S2 are the arguments to
11608e4b17023SJohn Marino the call, and TYPE is its return type.
11609e4b17023SJohn Marino
11610e4b17023SJohn Marino Return NULL_TREE if no simplification was possible, otherwise return the
11611e4b17023SJohn Marino simplified form of the call as a tree.
11612e4b17023SJohn Marino
11613e4b17023SJohn Marino The simplified form may be a constant or other expression which
11614e4b17023SJohn Marino computes the same value, but in a more efficient manner (including
11615e4b17023SJohn Marino calls to other builtin functions).
11616e4b17023SJohn Marino
11617e4b17023SJohn Marino The call may contain arguments which need to be evaluated, but
11618e4b17023SJohn Marino which are not useful to determine the result of the call. In
11619e4b17023SJohn Marino this case we return a chain of COMPOUND_EXPRs. The LHS of each
11620e4b17023SJohn Marino COMPOUND_EXPR will be an argument which must be evaluated.
11621e4b17023SJohn Marino COMPOUND_EXPRs are chained through their RHS. The RHS of the last
11622e4b17023SJohn Marino COMPOUND_EXPR in the chain will contain the tree for the simplified
11623e4b17023SJohn Marino form of the builtin function call. */
11624e4b17023SJohn Marino
11625e4b17023SJohn Marino static tree
fold_builtin_strchr(location_t loc,tree s1,tree s2,tree type)11626e4b17023SJohn Marino fold_builtin_strchr (location_t loc, tree s1, tree s2, tree type)
11627e4b17023SJohn Marino {
11628e4b17023SJohn Marino if (!validate_arg (s1, POINTER_TYPE)
11629e4b17023SJohn Marino || !validate_arg (s2, INTEGER_TYPE))
11630e4b17023SJohn Marino return NULL_TREE;
11631e4b17023SJohn Marino else
11632e4b17023SJohn Marino {
11633e4b17023SJohn Marino const char *p1;
11634e4b17023SJohn Marino
11635e4b17023SJohn Marino if (TREE_CODE (s2) != INTEGER_CST)
11636e4b17023SJohn Marino return NULL_TREE;
11637e4b17023SJohn Marino
11638e4b17023SJohn Marino p1 = c_getstr (s1);
11639e4b17023SJohn Marino if (p1 != NULL)
11640e4b17023SJohn Marino {
11641e4b17023SJohn Marino char c;
11642e4b17023SJohn Marino const char *r;
11643e4b17023SJohn Marino tree tem;
11644e4b17023SJohn Marino
11645e4b17023SJohn Marino if (target_char_cast (s2, &c))
11646e4b17023SJohn Marino return NULL_TREE;
11647e4b17023SJohn Marino
11648e4b17023SJohn Marino r = strchr (p1, c);
11649e4b17023SJohn Marino
11650e4b17023SJohn Marino if (r == NULL)
11651e4b17023SJohn Marino return build_int_cst (TREE_TYPE (s1), 0);
11652e4b17023SJohn Marino
11653e4b17023SJohn Marino /* Return an offset into the constant string argument. */
11654e4b17023SJohn Marino tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
11655e4b17023SJohn Marino return fold_convert_loc (loc, type, tem);
11656e4b17023SJohn Marino }
11657e4b17023SJohn Marino return NULL_TREE;
11658e4b17023SJohn Marino }
11659e4b17023SJohn Marino }
11660e4b17023SJohn Marino
11661e4b17023SJohn Marino /* Simplify a call to the strrchr builtin. S1 and S2 are the arguments to
11662e4b17023SJohn Marino the call, and TYPE is its return type.
11663e4b17023SJohn Marino
11664e4b17023SJohn Marino Return NULL_TREE if no simplification was possible, otherwise return the
11665e4b17023SJohn Marino simplified form of the call as a tree.
11666e4b17023SJohn Marino
11667e4b17023SJohn Marino The simplified form may be a constant or other expression which
11668e4b17023SJohn Marino computes the same value, but in a more efficient manner (including
11669e4b17023SJohn Marino calls to other builtin functions).
11670e4b17023SJohn Marino
11671e4b17023SJohn Marino The call may contain arguments which need to be evaluated, but
11672e4b17023SJohn Marino which are not useful to determine the result of the call. In
11673e4b17023SJohn Marino this case we return a chain of COMPOUND_EXPRs. The LHS of each
11674e4b17023SJohn Marino COMPOUND_EXPR will be an argument which must be evaluated.
11675e4b17023SJohn Marino COMPOUND_EXPRs are chained through their RHS. The RHS of the last
11676e4b17023SJohn Marino COMPOUND_EXPR in the chain will contain the tree for the simplified
11677e4b17023SJohn Marino form of the builtin function call. */
11678e4b17023SJohn Marino
11679e4b17023SJohn Marino static tree
fold_builtin_strrchr(location_t loc,tree s1,tree s2,tree type)11680e4b17023SJohn Marino fold_builtin_strrchr (location_t loc, tree s1, tree s2, tree type)
11681e4b17023SJohn Marino {
11682e4b17023SJohn Marino if (!validate_arg (s1, POINTER_TYPE)
11683e4b17023SJohn Marino || !validate_arg (s2, INTEGER_TYPE))
11684e4b17023SJohn Marino return NULL_TREE;
11685e4b17023SJohn Marino else
11686e4b17023SJohn Marino {
11687e4b17023SJohn Marino tree fn;
11688e4b17023SJohn Marino const char *p1;
11689e4b17023SJohn Marino
11690e4b17023SJohn Marino if (TREE_CODE (s2) != INTEGER_CST)
11691e4b17023SJohn Marino return NULL_TREE;
11692e4b17023SJohn Marino
11693e4b17023SJohn Marino p1 = c_getstr (s1);
11694e4b17023SJohn Marino if (p1 != NULL)
11695e4b17023SJohn Marino {
11696e4b17023SJohn Marino char c;
11697e4b17023SJohn Marino const char *r;
11698e4b17023SJohn Marino tree tem;
11699e4b17023SJohn Marino
11700e4b17023SJohn Marino if (target_char_cast (s2, &c))
11701e4b17023SJohn Marino return NULL_TREE;
11702e4b17023SJohn Marino
11703e4b17023SJohn Marino r = strrchr (p1, c);
11704e4b17023SJohn Marino
11705e4b17023SJohn Marino if (r == NULL)
11706e4b17023SJohn Marino return build_int_cst (TREE_TYPE (s1), 0);
11707e4b17023SJohn Marino
11708e4b17023SJohn Marino /* Return an offset into the constant string argument. */
11709e4b17023SJohn Marino tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
11710e4b17023SJohn Marino return fold_convert_loc (loc, type, tem);
11711e4b17023SJohn Marino }
11712e4b17023SJohn Marino
11713e4b17023SJohn Marino if (! integer_zerop (s2))
11714e4b17023SJohn Marino return NULL_TREE;
11715e4b17023SJohn Marino
11716e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_STRCHR);
11717e4b17023SJohn Marino if (!fn)
11718e4b17023SJohn Marino return NULL_TREE;
11719e4b17023SJohn Marino
11720e4b17023SJohn Marino /* Transform strrchr(s1, '\0') to strchr(s1, '\0'). */
11721e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 2, s1, s2);
11722e4b17023SJohn Marino }
11723e4b17023SJohn Marino }
11724e4b17023SJohn Marino
11725e4b17023SJohn Marino /* Simplify a call to the strpbrk builtin. S1 and S2 are the arguments
11726e4b17023SJohn Marino to the call, and TYPE is its return type.
11727e4b17023SJohn Marino
11728e4b17023SJohn Marino Return NULL_TREE if no simplification was possible, otherwise return the
11729e4b17023SJohn Marino simplified form of the call as a tree.
11730e4b17023SJohn Marino
11731e4b17023SJohn Marino The simplified form may be a constant or other expression which
11732e4b17023SJohn Marino computes the same value, but in a more efficient manner (including
11733e4b17023SJohn Marino calls to other builtin functions).
11734e4b17023SJohn Marino
11735e4b17023SJohn Marino The call may contain arguments which need to be evaluated, but
11736e4b17023SJohn Marino which are not useful to determine the result of the call. In
11737e4b17023SJohn Marino this case we return a chain of COMPOUND_EXPRs. The LHS of each
11738e4b17023SJohn Marino COMPOUND_EXPR will be an argument which must be evaluated.
11739e4b17023SJohn Marino COMPOUND_EXPRs are chained through their RHS. The RHS of the last
11740e4b17023SJohn Marino COMPOUND_EXPR in the chain will contain the tree for the simplified
11741e4b17023SJohn Marino form of the builtin function call. */
11742e4b17023SJohn Marino
11743e4b17023SJohn Marino static tree
fold_builtin_strpbrk(location_t loc,tree s1,tree s2,tree type)11744e4b17023SJohn Marino fold_builtin_strpbrk (location_t loc, tree s1, tree s2, tree type)
11745e4b17023SJohn Marino {
11746e4b17023SJohn Marino if (!validate_arg (s1, POINTER_TYPE)
11747e4b17023SJohn Marino || !validate_arg (s2, POINTER_TYPE))
11748e4b17023SJohn Marino return NULL_TREE;
11749e4b17023SJohn Marino else
11750e4b17023SJohn Marino {
11751e4b17023SJohn Marino tree fn;
11752e4b17023SJohn Marino const char *p1, *p2;
11753e4b17023SJohn Marino
11754e4b17023SJohn Marino p2 = c_getstr (s2);
11755e4b17023SJohn Marino if (p2 == NULL)
11756e4b17023SJohn Marino return NULL_TREE;
11757e4b17023SJohn Marino
11758e4b17023SJohn Marino p1 = c_getstr (s1);
11759e4b17023SJohn Marino if (p1 != NULL)
11760e4b17023SJohn Marino {
11761e4b17023SJohn Marino const char *r = strpbrk (p1, p2);
11762e4b17023SJohn Marino tree tem;
11763e4b17023SJohn Marino
11764e4b17023SJohn Marino if (r == NULL)
11765e4b17023SJohn Marino return build_int_cst (TREE_TYPE (s1), 0);
11766e4b17023SJohn Marino
11767e4b17023SJohn Marino /* Return an offset into the constant string argument. */
11768e4b17023SJohn Marino tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
11769e4b17023SJohn Marino return fold_convert_loc (loc, type, tem);
11770e4b17023SJohn Marino }
11771e4b17023SJohn Marino
11772e4b17023SJohn Marino if (p2[0] == '\0')
11773e4b17023SJohn Marino /* strpbrk(x, "") == NULL.
11774e4b17023SJohn Marino Evaluate and ignore s1 in case it had side-effects. */
11775e4b17023SJohn Marino return omit_one_operand_loc (loc, TREE_TYPE (s1), integer_zero_node, s1);
11776e4b17023SJohn Marino
11777e4b17023SJohn Marino if (p2[1] != '\0')
11778e4b17023SJohn Marino return NULL_TREE; /* Really call strpbrk. */
11779e4b17023SJohn Marino
11780e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_STRCHR);
11781e4b17023SJohn Marino if (!fn)
11782e4b17023SJohn Marino return NULL_TREE;
11783e4b17023SJohn Marino
11784e4b17023SJohn Marino /* New argument list transforming strpbrk(s1, s2) to
11785e4b17023SJohn Marino strchr(s1, s2[0]). */
11786e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 2, s1,
11787e4b17023SJohn Marino build_int_cst (integer_type_node, p2[0]));
11788e4b17023SJohn Marino }
11789e4b17023SJohn Marino }
11790e4b17023SJohn Marino
11791e4b17023SJohn Marino /* Simplify a call to the strcat builtin. DST and SRC are the arguments
11792e4b17023SJohn Marino to the call.
11793e4b17023SJohn Marino
11794e4b17023SJohn Marino Return NULL_TREE if no simplification was possible, otherwise return the
11795e4b17023SJohn Marino simplified form of the call as a tree.
11796e4b17023SJohn Marino
11797e4b17023SJohn Marino The simplified form may be a constant or other expression which
11798e4b17023SJohn Marino computes the same value, but in a more efficient manner (including
11799e4b17023SJohn Marino calls to other builtin functions).
11800e4b17023SJohn Marino
11801e4b17023SJohn Marino The call may contain arguments which need to be evaluated, but
11802e4b17023SJohn Marino which are not useful to determine the result of the call. In
11803e4b17023SJohn Marino this case we return a chain of COMPOUND_EXPRs. The LHS of each
11804e4b17023SJohn Marino COMPOUND_EXPR will be an argument which must be evaluated.
11805e4b17023SJohn Marino COMPOUND_EXPRs are chained through their RHS. The RHS of the last
11806e4b17023SJohn Marino COMPOUND_EXPR in the chain will contain the tree for the simplified
11807e4b17023SJohn Marino form of the builtin function call. */
11808e4b17023SJohn Marino
11809e4b17023SJohn Marino static tree
fold_builtin_strcat(location_t loc ATTRIBUTE_UNUSED,tree dst,tree src)11810e4b17023SJohn Marino fold_builtin_strcat (location_t loc ATTRIBUTE_UNUSED, tree dst, tree src)
11811e4b17023SJohn Marino {
11812e4b17023SJohn Marino if (!validate_arg (dst, POINTER_TYPE)
11813e4b17023SJohn Marino || !validate_arg (src, POINTER_TYPE))
11814e4b17023SJohn Marino return NULL_TREE;
11815e4b17023SJohn Marino else
11816e4b17023SJohn Marino {
11817e4b17023SJohn Marino const char *p = c_getstr (src);
11818e4b17023SJohn Marino
11819e4b17023SJohn Marino /* If the string length is zero, return the dst parameter. */
11820e4b17023SJohn Marino if (p && *p == '\0')
11821e4b17023SJohn Marino return dst;
11822e4b17023SJohn Marino
11823e4b17023SJohn Marino if (optimize_insn_for_speed_p ())
11824e4b17023SJohn Marino {
11825e4b17023SJohn Marino /* See if we can store by pieces into (dst + strlen(dst)). */
11826e4b17023SJohn Marino tree newdst, call;
11827e4b17023SJohn Marino tree strlen_fn = builtin_decl_implicit (BUILT_IN_STRLEN);
11828e4b17023SJohn Marino tree strcpy_fn = builtin_decl_implicit (BUILT_IN_STRCPY);
11829e4b17023SJohn Marino
11830e4b17023SJohn Marino if (!strlen_fn || !strcpy_fn)
11831e4b17023SJohn Marino return NULL_TREE;
11832e4b17023SJohn Marino
11833e4b17023SJohn Marino /* If we don't have a movstr we don't want to emit an strcpy
11834e4b17023SJohn Marino call. We have to do that if the length of the source string
11835e4b17023SJohn Marino isn't computable (in that case we can use memcpy probably
11836e4b17023SJohn Marino later expanding to a sequence of mov instructions). If we
11837e4b17023SJohn Marino have movstr instructions we can emit strcpy calls. */
11838e4b17023SJohn Marino if (!HAVE_movstr)
11839e4b17023SJohn Marino {
11840e4b17023SJohn Marino tree len = c_strlen (src, 1);
11841e4b17023SJohn Marino if (! len || TREE_SIDE_EFFECTS (len))
11842e4b17023SJohn Marino return NULL_TREE;
11843e4b17023SJohn Marino }
11844e4b17023SJohn Marino
11845e4b17023SJohn Marino /* Stabilize the argument list. */
11846e4b17023SJohn Marino dst = builtin_save_expr (dst);
11847e4b17023SJohn Marino
11848e4b17023SJohn Marino /* Create strlen (dst). */
11849e4b17023SJohn Marino newdst = build_call_expr_loc (loc, strlen_fn, 1, dst);
11850e4b17023SJohn Marino /* Create (dst p+ strlen (dst)). */
11851e4b17023SJohn Marino
11852e4b17023SJohn Marino newdst = fold_build_pointer_plus_loc (loc, dst, newdst);
11853e4b17023SJohn Marino newdst = builtin_save_expr (newdst);
11854e4b17023SJohn Marino
11855e4b17023SJohn Marino call = build_call_expr_loc (loc, strcpy_fn, 2, newdst, src);
11856e4b17023SJohn Marino return build2 (COMPOUND_EXPR, TREE_TYPE (dst), call, dst);
11857e4b17023SJohn Marino }
11858e4b17023SJohn Marino return NULL_TREE;
11859e4b17023SJohn Marino }
11860e4b17023SJohn Marino }
11861e4b17023SJohn Marino
11862e4b17023SJohn Marino /* Simplify a call to the strncat builtin. DST, SRC, and LEN are the
11863e4b17023SJohn Marino arguments to the call.
11864e4b17023SJohn Marino
11865e4b17023SJohn Marino Return NULL_TREE if no simplification was possible, otherwise return the
11866e4b17023SJohn Marino simplified form of the call as a tree.
11867e4b17023SJohn Marino
11868e4b17023SJohn Marino The simplified form may be a constant or other expression which
11869e4b17023SJohn Marino computes the same value, but in a more efficient manner (including
11870e4b17023SJohn Marino calls to other builtin functions).
11871e4b17023SJohn Marino
11872e4b17023SJohn Marino The call may contain arguments which need to be evaluated, but
11873e4b17023SJohn Marino which are not useful to determine the result of the call. In
11874e4b17023SJohn Marino this case we return a chain of COMPOUND_EXPRs. The LHS of each
11875e4b17023SJohn Marino COMPOUND_EXPR will be an argument which must be evaluated.
11876e4b17023SJohn Marino COMPOUND_EXPRs are chained through their RHS. The RHS of the last
11877e4b17023SJohn Marino COMPOUND_EXPR in the chain will contain the tree for the simplified
11878e4b17023SJohn Marino form of the builtin function call. */
11879e4b17023SJohn Marino
11880e4b17023SJohn Marino static tree
fold_builtin_strncat(location_t loc,tree dst,tree src,tree len)11881e4b17023SJohn Marino fold_builtin_strncat (location_t loc, tree dst, tree src, tree len)
11882e4b17023SJohn Marino {
11883e4b17023SJohn Marino if (!validate_arg (dst, POINTER_TYPE)
11884e4b17023SJohn Marino || !validate_arg (src, POINTER_TYPE)
11885e4b17023SJohn Marino || !validate_arg (len, INTEGER_TYPE))
11886e4b17023SJohn Marino return NULL_TREE;
11887e4b17023SJohn Marino else
11888e4b17023SJohn Marino {
11889e4b17023SJohn Marino const char *p = c_getstr (src);
11890e4b17023SJohn Marino
11891e4b17023SJohn Marino /* If the requested length is zero, or the src parameter string
11892e4b17023SJohn Marino length is zero, return the dst parameter. */
11893e4b17023SJohn Marino if (integer_zerop (len) || (p && *p == '\0'))
11894e4b17023SJohn Marino return omit_two_operands_loc (loc, TREE_TYPE (dst), dst, src, len);
11895e4b17023SJohn Marino
11896e4b17023SJohn Marino /* If the requested len is greater than or equal to the string
11897e4b17023SJohn Marino length, call strcat. */
11898e4b17023SJohn Marino if (TREE_CODE (len) == INTEGER_CST && p
11899e4b17023SJohn Marino && compare_tree_int (len, strlen (p)) >= 0)
11900e4b17023SJohn Marino {
11901e4b17023SJohn Marino tree fn = builtin_decl_implicit (BUILT_IN_STRCAT);
11902e4b17023SJohn Marino
11903e4b17023SJohn Marino /* If the replacement _DECL isn't initialized, don't do the
11904e4b17023SJohn Marino transformation. */
11905e4b17023SJohn Marino if (!fn)
11906e4b17023SJohn Marino return NULL_TREE;
11907e4b17023SJohn Marino
11908e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 2, dst, src);
11909e4b17023SJohn Marino }
11910e4b17023SJohn Marino return NULL_TREE;
11911e4b17023SJohn Marino }
11912e4b17023SJohn Marino }
11913e4b17023SJohn Marino
11914e4b17023SJohn Marino /* Simplify a call to the strspn builtin. S1 and S2 are the arguments
11915e4b17023SJohn Marino to the call.
11916e4b17023SJohn Marino
11917e4b17023SJohn Marino Return NULL_TREE if no simplification was possible, otherwise return the
11918e4b17023SJohn Marino simplified form of the call as a tree.
11919e4b17023SJohn Marino
11920e4b17023SJohn Marino The simplified form may be a constant or other expression which
11921e4b17023SJohn Marino computes the same value, but in a more efficient manner (including
11922e4b17023SJohn Marino calls to other builtin functions).
11923e4b17023SJohn Marino
11924e4b17023SJohn Marino The call may contain arguments which need to be evaluated, but
11925e4b17023SJohn Marino which are not useful to determine the result of the call. In
11926e4b17023SJohn Marino this case we return a chain of COMPOUND_EXPRs. The LHS of each
11927e4b17023SJohn Marino COMPOUND_EXPR will be an argument which must be evaluated.
11928e4b17023SJohn Marino COMPOUND_EXPRs are chained through their RHS. The RHS of the last
11929e4b17023SJohn Marino COMPOUND_EXPR in the chain will contain the tree for the simplified
11930e4b17023SJohn Marino form of the builtin function call. */
11931e4b17023SJohn Marino
11932e4b17023SJohn Marino static tree
fold_builtin_strspn(location_t loc,tree s1,tree s2)11933e4b17023SJohn Marino fold_builtin_strspn (location_t loc, tree s1, tree s2)
11934e4b17023SJohn Marino {
11935e4b17023SJohn Marino if (!validate_arg (s1, POINTER_TYPE)
11936e4b17023SJohn Marino || !validate_arg (s2, POINTER_TYPE))
11937e4b17023SJohn Marino return NULL_TREE;
11938e4b17023SJohn Marino else
11939e4b17023SJohn Marino {
11940e4b17023SJohn Marino const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
11941e4b17023SJohn Marino
11942e4b17023SJohn Marino /* If both arguments are constants, evaluate at compile-time. */
11943e4b17023SJohn Marino if (p1 && p2)
11944e4b17023SJohn Marino {
11945e4b17023SJohn Marino const size_t r = strspn (p1, p2);
11946e4b17023SJohn Marino return build_int_cst (size_type_node, r);
11947e4b17023SJohn Marino }
11948e4b17023SJohn Marino
11949e4b17023SJohn Marino /* If either argument is "", return NULL_TREE. */
11950e4b17023SJohn Marino if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
11951e4b17023SJohn Marino /* Evaluate and ignore both arguments in case either one has
11952e4b17023SJohn Marino side-effects. */
11953e4b17023SJohn Marino return omit_two_operands_loc (loc, size_type_node, size_zero_node,
11954e4b17023SJohn Marino s1, s2);
11955e4b17023SJohn Marino return NULL_TREE;
11956e4b17023SJohn Marino }
11957e4b17023SJohn Marino }
11958e4b17023SJohn Marino
11959e4b17023SJohn Marino /* Simplify a call to the strcspn builtin. S1 and S2 are the arguments
11960e4b17023SJohn Marino to the call.
11961e4b17023SJohn Marino
11962e4b17023SJohn Marino Return NULL_TREE if no simplification was possible, otherwise return the
11963e4b17023SJohn Marino simplified form of the call as a tree.
11964e4b17023SJohn Marino
11965e4b17023SJohn Marino The simplified form may be a constant or other expression which
11966e4b17023SJohn Marino computes the same value, but in a more efficient manner (including
11967e4b17023SJohn Marino calls to other builtin functions).
11968e4b17023SJohn Marino
11969e4b17023SJohn Marino The call may contain arguments which need to be evaluated, but
11970e4b17023SJohn Marino which are not useful to determine the result of the call. In
11971e4b17023SJohn Marino this case we return a chain of COMPOUND_EXPRs. The LHS of each
11972e4b17023SJohn Marino COMPOUND_EXPR will be an argument which must be evaluated.
11973e4b17023SJohn Marino COMPOUND_EXPRs are chained through their RHS. The RHS of the last
11974e4b17023SJohn Marino COMPOUND_EXPR in the chain will contain the tree for the simplified
11975e4b17023SJohn Marino form of the builtin function call. */
11976e4b17023SJohn Marino
11977e4b17023SJohn Marino static tree
fold_builtin_strcspn(location_t loc,tree s1,tree s2)11978e4b17023SJohn Marino fold_builtin_strcspn (location_t loc, tree s1, tree s2)
11979e4b17023SJohn Marino {
11980e4b17023SJohn Marino if (!validate_arg (s1, POINTER_TYPE)
11981e4b17023SJohn Marino || !validate_arg (s2, POINTER_TYPE))
11982e4b17023SJohn Marino return NULL_TREE;
11983e4b17023SJohn Marino else
11984e4b17023SJohn Marino {
11985e4b17023SJohn Marino const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
11986e4b17023SJohn Marino
11987e4b17023SJohn Marino /* If both arguments are constants, evaluate at compile-time. */
11988e4b17023SJohn Marino if (p1 && p2)
11989e4b17023SJohn Marino {
11990e4b17023SJohn Marino const size_t r = strcspn (p1, p2);
11991e4b17023SJohn Marino return build_int_cst (size_type_node, r);
11992e4b17023SJohn Marino }
11993e4b17023SJohn Marino
11994e4b17023SJohn Marino /* If the first argument is "", return NULL_TREE. */
11995e4b17023SJohn Marino if (p1 && *p1 == '\0')
11996e4b17023SJohn Marino {
11997e4b17023SJohn Marino /* Evaluate and ignore argument s2 in case it has
11998e4b17023SJohn Marino side-effects. */
11999e4b17023SJohn Marino return omit_one_operand_loc (loc, size_type_node,
12000e4b17023SJohn Marino size_zero_node, s2);
12001e4b17023SJohn Marino }
12002e4b17023SJohn Marino
12003e4b17023SJohn Marino /* If the second argument is "", return __builtin_strlen(s1). */
12004e4b17023SJohn Marino if (p2 && *p2 == '\0')
12005e4b17023SJohn Marino {
12006e4b17023SJohn Marino tree fn = builtin_decl_implicit (BUILT_IN_STRLEN);
12007e4b17023SJohn Marino
12008e4b17023SJohn Marino /* If the replacement _DECL isn't initialized, don't do the
12009e4b17023SJohn Marino transformation. */
12010e4b17023SJohn Marino if (!fn)
12011e4b17023SJohn Marino return NULL_TREE;
12012e4b17023SJohn Marino
12013e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 1, s1);
12014e4b17023SJohn Marino }
12015e4b17023SJohn Marino return NULL_TREE;
12016e4b17023SJohn Marino }
12017e4b17023SJohn Marino }
12018e4b17023SJohn Marino
12019e4b17023SJohn Marino /* Fold a call to the fputs builtin. ARG0 and ARG1 are the arguments
12020e4b17023SJohn Marino to the call. IGNORE is true if the value returned
12021e4b17023SJohn Marino by the builtin will be ignored. UNLOCKED is true is true if this
12022e4b17023SJohn Marino actually a call to fputs_unlocked. If LEN in non-NULL, it represents
12023e4b17023SJohn Marino the known length of the string. Return NULL_TREE if no simplification
12024e4b17023SJohn Marino was possible. */
12025e4b17023SJohn Marino
12026e4b17023SJohn Marino tree
fold_builtin_fputs(location_t loc,tree arg0,tree arg1,bool ignore,bool unlocked,tree len)12027e4b17023SJohn Marino fold_builtin_fputs (location_t loc, tree arg0, tree arg1,
12028e4b17023SJohn Marino bool ignore, bool unlocked, tree len)
12029e4b17023SJohn Marino {
12030e4b17023SJohn Marino /* If we're using an unlocked function, assume the other unlocked
12031e4b17023SJohn Marino functions exist explicitly. */
12032e4b17023SJohn Marino tree const fn_fputc = (unlocked
12033e4b17023SJohn Marino ? builtin_decl_explicit (BUILT_IN_FPUTC_UNLOCKED)
12034e4b17023SJohn Marino : builtin_decl_implicit (BUILT_IN_FPUTC));
12035e4b17023SJohn Marino tree const fn_fwrite = (unlocked
12036e4b17023SJohn Marino ? builtin_decl_explicit (BUILT_IN_FWRITE_UNLOCKED)
12037e4b17023SJohn Marino : builtin_decl_implicit (BUILT_IN_FWRITE));
12038e4b17023SJohn Marino
12039e4b17023SJohn Marino /* If the return value is used, don't do the transformation. */
12040e4b17023SJohn Marino if (!ignore)
12041e4b17023SJohn Marino return NULL_TREE;
12042e4b17023SJohn Marino
12043e4b17023SJohn Marino /* Verify the arguments in the original call. */
12044e4b17023SJohn Marino if (!validate_arg (arg0, POINTER_TYPE)
12045e4b17023SJohn Marino || !validate_arg (arg1, POINTER_TYPE))
12046e4b17023SJohn Marino return NULL_TREE;
12047e4b17023SJohn Marino
12048e4b17023SJohn Marino if (! len)
12049e4b17023SJohn Marino len = c_strlen (arg0, 0);
12050e4b17023SJohn Marino
12051e4b17023SJohn Marino /* Get the length of the string passed to fputs. If the length
12052e4b17023SJohn Marino can't be determined, punt. */
12053e4b17023SJohn Marino if (!len
12054e4b17023SJohn Marino || TREE_CODE (len) != INTEGER_CST)
12055e4b17023SJohn Marino return NULL_TREE;
12056e4b17023SJohn Marino
12057e4b17023SJohn Marino switch (compare_tree_int (len, 1))
12058e4b17023SJohn Marino {
12059e4b17023SJohn Marino case -1: /* length is 0, delete the call entirely . */
12060e4b17023SJohn Marino return omit_one_operand_loc (loc, integer_type_node,
12061e4b17023SJohn Marino integer_zero_node, arg1);;
12062e4b17023SJohn Marino
12063e4b17023SJohn Marino case 0: /* length is 1, call fputc. */
12064e4b17023SJohn Marino {
12065e4b17023SJohn Marino const char *p = c_getstr (arg0);
12066e4b17023SJohn Marino
12067e4b17023SJohn Marino if (p != NULL)
12068e4b17023SJohn Marino {
12069e4b17023SJohn Marino if (fn_fputc)
12070e4b17023SJohn Marino return build_call_expr_loc (loc, fn_fputc, 2,
12071e4b17023SJohn Marino build_int_cst
12072e4b17023SJohn Marino (integer_type_node, p[0]), arg1);
12073e4b17023SJohn Marino else
12074e4b17023SJohn Marino return NULL_TREE;
12075e4b17023SJohn Marino }
12076e4b17023SJohn Marino }
12077e4b17023SJohn Marino /* FALLTHROUGH */
12078e4b17023SJohn Marino case 1: /* length is greater than 1, call fwrite. */
12079e4b17023SJohn Marino {
12080e4b17023SJohn Marino /* If optimizing for size keep fputs. */
12081e4b17023SJohn Marino if (optimize_function_for_size_p (cfun))
12082e4b17023SJohn Marino return NULL_TREE;
12083e4b17023SJohn Marino /* New argument list transforming fputs(string, stream) to
12084e4b17023SJohn Marino fwrite(string, 1, len, stream). */
12085e4b17023SJohn Marino if (fn_fwrite)
12086e4b17023SJohn Marino return build_call_expr_loc (loc, fn_fwrite, 4, arg0,
12087e4b17023SJohn Marino size_one_node, len, arg1);
12088e4b17023SJohn Marino else
12089e4b17023SJohn Marino return NULL_TREE;
12090e4b17023SJohn Marino }
12091e4b17023SJohn Marino default:
12092e4b17023SJohn Marino gcc_unreachable ();
12093e4b17023SJohn Marino }
12094e4b17023SJohn Marino return NULL_TREE;
12095e4b17023SJohn Marino }
12096e4b17023SJohn Marino
12097e4b17023SJohn Marino /* Fold the next_arg or va_start call EXP. Returns true if there was an error
12098e4b17023SJohn Marino produced. False otherwise. This is done so that we don't output the error
12099e4b17023SJohn Marino or warning twice or three times. */
12100e4b17023SJohn Marino
12101e4b17023SJohn Marino bool
fold_builtin_next_arg(tree exp,bool va_start_p)12102e4b17023SJohn Marino fold_builtin_next_arg (tree exp, bool va_start_p)
12103e4b17023SJohn Marino {
12104e4b17023SJohn Marino tree fntype = TREE_TYPE (current_function_decl);
12105e4b17023SJohn Marino int nargs = call_expr_nargs (exp);
12106e4b17023SJohn Marino tree arg;
12107e4b17023SJohn Marino
12108e4b17023SJohn Marino if (!stdarg_p (fntype))
12109e4b17023SJohn Marino {
12110e4b17023SJohn Marino error ("%<va_start%> used in function with fixed args");
12111e4b17023SJohn Marino return true;
12112e4b17023SJohn Marino }
12113e4b17023SJohn Marino
12114e4b17023SJohn Marino if (va_start_p)
12115e4b17023SJohn Marino {
12116e4b17023SJohn Marino if (va_start_p && (nargs != 2))
12117e4b17023SJohn Marino {
12118e4b17023SJohn Marino error ("wrong number of arguments to function %<va_start%>");
12119e4b17023SJohn Marino return true;
12120e4b17023SJohn Marino }
12121e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 1);
12122e4b17023SJohn Marino }
12123e4b17023SJohn Marino /* We use __builtin_va_start (ap, 0, 0) or __builtin_next_arg (0, 0)
12124e4b17023SJohn Marino when we checked the arguments and if needed issued a warning. */
12125e4b17023SJohn Marino else
12126e4b17023SJohn Marino {
12127e4b17023SJohn Marino if (nargs == 0)
12128e4b17023SJohn Marino {
12129e4b17023SJohn Marino /* Evidently an out of date version of <stdarg.h>; can't validate
12130e4b17023SJohn Marino va_start's second argument, but can still work as intended. */
12131e4b17023SJohn Marino warning (0, "%<__builtin_next_arg%> called without an argument");
12132e4b17023SJohn Marino return true;
12133e4b17023SJohn Marino }
12134e4b17023SJohn Marino else if (nargs > 1)
12135e4b17023SJohn Marino {
12136e4b17023SJohn Marino error ("wrong number of arguments to function %<__builtin_next_arg%>");
12137e4b17023SJohn Marino return true;
12138e4b17023SJohn Marino }
12139e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 0);
12140e4b17023SJohn Marino }
12141e4b17023SJohn Marino
12142e4b17023SJohn Marino if (TREE_CODE (arg) == SSA_NAME)
12143e4b17023SJohn Marino arg = SSA_NAME_VAR (arg);
12144e4b17023SJohn Marino
12145e4b17023SJohn Marino /* We destructively modify the call to be __builtin_va_start (ap, 0)
12146e4b17023SJohn Marino or __builtin_next_arg (0) the first time we see it, after checking
12147e4b17023SJohn Marino the arguments and if needed issuing a warning. */
12148e4b17023SJohn Marino if (!integer_zerop (arg))
12149e4b17023SJohn Marino {
12150e4b17023SJohn Marino tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
12151e4b17023SJohn Marino
12152e4b17023SJohn Marino /* Strip off all nops for the sake of the comparison. This
12153e4b17023SJohn Marino is not quite the same as STRIP_NOPS. It does more.
12154e4b17023SJohn Marino We must also strip off INDIRECT_EXPR for C++ reference
12155e4b17023SJohn Marino parameters. */
12156e4b17023SJohn Marino while (CONVERT_EXPR_P (arg)
12157e4b17023SJohn Marino || TREE_CODE (arg) == INDIRECT_REF)
12158e4b17023SJohn Marino arg = TREE_OPERAND (arg, 0);
12159e4b17023SJohn Marino if (arg != last_parm)
12160e4b17023SJohn Marino {
12161e4b17023SJohn Marino /* FIXME: Sometimes with the tree optimizers we can get the
12162e4b17023SJohn Marino not the last argument even though the user used the last
12163e4b17023SJohn Marino argument. We just warn and set the arg to be the last
12164e4b17023SJohn Marino argument so that we will get wrong-code because of
12165e4b17023SJohn Marino it. */
12166e4b17023SJohn Marino warning (0, "second parameter of %<va_start%> not last named argument");
12167e4b17023SJohn Marino }
12168e4b17023SJohn Marino
12169e4b17023SJohn Marino /* Undefined by C99 7.15.1.4p4 (va_start):
12170e4b17023SJohn Marino "If the parameter parmN is declared with the register storage
12171e4b17023SJohn Marino class, with a function or array type, or with a type that is
12172e4b17023SJohn Marino not compatible with the type that results after application of
12173e4b17023SJohn Marino the default argument promotions, the behavior is undefined."
12174e4b17023SJohn Marino */
12175e4b17023SJohn Marino else if (DECL_REGISTER (arg))
12176e4b17023SJohn Marino warning (0, "undefined behaviour when second parameter of "
12177e4b17023SJohn Marino "%<va_start%> is declared with %<register%> storage");
12178e4b17023SJohn Marino
12179e4b17023SJohn Marino /* We want to verify the second parameter just once before the tree
12180e4b17023SJohn Marino optimizers are run and then avoid keeping it in the tree,
12181e4b17023SJohn Marino as otherwise we could warn even for correct code like:
12182e4b17023SJohn Marino void foo (int i, ...)
12183e4b17023SJohn Marino { va_list ap; i++; va_start (ap, i); va_end (ap); } */
12184e4b17023SJohn Marino if (va_start_p)
12185e4b17023SJohn Marino CALL_EXPR_ARG (exp, 1) = integer_zero_node;
12186e4b17023SJohn Marino else
12187e4b17023SJohn Marino CALL_EXPR_ARG (exp, 0) = integer_zero_node;
12188e4b17023SJohn Marino }
12189e4b17023SJohn Marino return false;
12190e4b17023SJohn Marino }
12191e4b17023SJohn Marino
12192e4b17023SJohn Marino
12193e4b17023SJohn Marino /* Simplify a call to the sprintf builtin with arguments DEST, FMT, and ORIG.
12194e4b17023SJohn Marino ORIG may be null if this is a 2-argument call. We don't attempt to
12195e4b17023SJohn Marino simplify calls with more than 3 arguments.
12196e4b17023SJohn Marino
12197e4b17023SJohn Marino Return NULL_TREE if no simplification was possible, otherwise return the
12198e4b17023SJohn Marino simplified form of the call as a tree. If IGNORED is true, it means that
12199e4b17023SJohn Marino the caller does not use the returned value of the function. */
12200e4b17023SJohn Marino
12201e4b17023SJohn Marino static tree
fold_builtin_sprintf(location_t loc,tree dest,tree fmt,tree orig,int ignored)12202e4b17023SJohn Marino fold_builtin_sprintf (location_t loc, tree dest, tree fmt,
12203e4b17023SJohn Marino tree orig, int ignored)
12204e4b17023SJohn Marino {
12205e4b17023SJohn Marino tree call, retval;
12206e4b17023SJohn Marino const char *fmt_str = NULL;
12207e4b17023SJohn Marino
12208e4b17023SJohn Marino /* Verify the required arguments in the original call. We deal with two
12209e4b17023SJohn Marino types of sprintf() calls: 'sprintf (str, fmt)' and
12210e4b17023SJohn Marino 'sprintf (dest, "%s", orig)'. */
12211e4b17023SJohn Marino if (!validate_arg (dest, POINTER_TYPE)
12212e4b17023SJohn Marino || !validate_arg (fmt, POINTER_TYPE))
12213e4b17023SJohn Marino return NULL_TREE;
12214e4b17023SJohn Marino if (orig && !validate_arg (orig, POINTER_TYPE))
12215e4b17023SJohn Marino return NULL_TREE;
12216e4b17023SJohn Marino
12217e4b17023SJohn Marino /* Check whether the format is a literal string constant. */
12218e4b17023SJohn Marino fmt_str = c_getstr (fmt);
12219e4b17023SJohn Marino if (fmt_str == NULL)
12220e4b17023SJohn Marino return NULL_TREE;
12221e4b17023SJohn Marino
12222e4b17023SJohn Marino call = NULL_TREE;
12223e4b17023SJohn Marino retval = NULL_TREE;
12224e4b17023SJohn Marino
12225e4b17023SJohn Marino if (!init_target_chars ())
12226e4b17023SJohn Marino return NULL_TREE;
12227e4b17023SJohn Marino
12228e4b17023SJohn Marino /* If the format doesn't contain % args or %%, use strcpy. */
12229e4b17023SJohn Marino if (strchr (fmt_str, target_percent) == NULL)
12230e4b17023SJohn Marino {
12231e4b17023SJohn Marino tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
12232e4b17023SJohn Marino
12233e4b17023SJohn Marino if (!fn)
12234e4b17023SJohn Marino return NULL_TREE;
12235e4b17023SJohn Marino
12236e4b17023SJohn Marino /* Don't optimize sprintf (buf, "abc", ptr++). */
12237e4b17023SJohn Marino if (orig)
12238e4b17023SJohn Marino return NULL_TREE;
12239e4b17023SJohn Marino
12240e4b17023SJohn Marino /* Convert sprintf (str, fmt) into strcpy (str, fmt) when
12241e4b17023SJohn Marino 'format' is known to contain no % formats. */
12242e4b17023SJohn Marino call = build_call_expr_loc (loc, fn, 2, dest, fmt);
12243e4b17023SJohn Marino if (!ignored)
12244e4b17023SJohn Marino retval = build_int_cst (integer_type_node, strlen (fmt_str));
12245e4b17023SJohn Marino }
12246e4b17023SJohn Marino
12247e4b17023SJohn Marino /* If the format is "%s", use strcpy if the result isn't used. */
12248e4b17023SJohn Marino else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
12249e4b17023SJohn Marino {
12250e4b17023SJohn Marino tree fn;
12251e4b17023SJohn Marino fn = builtin_decl_implicit (BUILT_IN_STRCPY);
12252e4b17023SJohn Marino
12253e4b17023SJohn Marino if (!fn)
12254e4b17023SJohn Marino return NULL_TREE;
12255e4b17023SJohn Marino
12256e4b17023SJohn Marino /* Don't crash on sprintf (str1, "%s"). */
12257e4b17023SJohn Marino if (!orig)
12258e4b17023SJohn Marino return NULL_TREE;
12259e4b17023SJohn Marino
12260e4b17023SJohn Marino /* Convert sprintf (str1, "%s", str2) into strcpy (str1, str2). */
12261e4b17023SJohn Marino if (!ignored)
12262e4b17023SJohn Marino {
12263e4b17023SJohn Marino retval = c_strlen (orig, 1);
12264e4b17023SJohn Marino if (!retval || TREE_CODE (retval) != INTEGER_CST)
12265e4b17023SJohn Marino return NULL_TREE;
12266e4b17023SJohn Marino }
12267e4b17023SJohn Marino call = build_call_expr_loc (loc, fn, 2, dest, orig);
12268e4b17023SJohn Marino }
12269e4b17023SJohn Marino
12270e4b17023SJohn Marino if (call && retval)
12271e4b17023SJohn Marino {
12272e4b17023SJohn Marino retval = fold_convert_loc
12273e4b17023SJohn Marino (loc, TREE_TYPE (TREE_TYPE (builtin_decl_implicit (BUILT_IN_SPRINTF))),
12274e4b17023SJohn Marino retval);
12275e4b17023SJohn Marino return build2 (COMPOUND_EXPR, TREE_TYPE (retval), call, retval);
12276e4b17023SJohn Marino }
12277e4b17023SJohn Marino else
12278e4b17023SJohn Marino return call;
12279e4b17023SJohn Marino }
12280e4b17023SJohn Marino
12281e4b17023SJohn Marino /* Simplify a call to the snprintf builtin with arguments DEST, DESTSIZE,
12282e4b17023SJohn Marino FMT, and ORIG. ORIG may be null if this is a 3-argument call. We don't
12283e4b17023SJohn Marino attempt to simplify calls with more than 4 arguments.
12284e4b17023SJohn Marino
12285e4b17023SJohn Marino Return NULL_TREE if no simplification was possible, otherwise return the
12286e4b17023SJohn Marino simplified form of the call as a tree. If IGNORED is true, it means that
12287e4b17023SJohn Marino the caller does not use the returned value of the function. */
12288e4b17023SJohn Marino
12289e4b17023SJohn Marino static tree
fold_builtin_snprintf(location_t loc,tree dest,tree destsize,tree fmt,tree orig,int ignored)12290e4b17023SJohn Marino fold_builtin_snprintf (location_t loc, tree dest, tree destsize, tree fmt,
12291e4b17023SJohn Marino tree orig, int ignored)
12292e4b17023SJohn Marino {
12293e4b17023SJohn Marino tree call, retval;
12294e4b17023SJohn Marino const char *fmt_str = NULL;
12295e4b17023SJohn Marino unsigned HOST_WIDE_INT destlen;
12296e4b17023SJohn Marino
12297e4b17023SJohn Marino /* Verify the required arguments in the original call. We deal with two
12298e4b17023SJohn Marino types of snprintf() calls: 'snprintf (str, cst, fmt)' and
12299e4b17023SJohn Marino 'snprintf (dest, cst, "%s", orig)'. */
12300e4b17023SJohn Marino if (!validate_arg (dest, POINTER_TYPE)
12301e4b17023SJohn Marino || !validate_arg (destsize, INTEGER_TYPE)
12302e4b17023SJohn Marino || !validate_arg (fmt, POINTER_TYPE))
12303e4b17023SJohn Marino return NULL_TREE;
12304e4b17023SJohn Marino if (orig && !validate_arg (orig, POINTER_TYPE))
12305e4b17023SJohn Marino return NULL_TREE;
12306e4b17023SJohn Marino
12307e4b17023SJohn Marino if (!host_integerp (destsize, 1))
12308e4b17023SJohn Marino return NULL_TREE;
12309e4b17023SJohn Marino
12310e4b17023SJohn Marino /* Check whether the format is a literal string constant. */
12311e4b17023SJohn Marino fmt_str = c_getstr (fmt);
12312e4b17023SJohn Marino if (fmt_str == NULL)
12313e4b17023SJohn Marino return NULL_TREE;
12314e4b17023SJohn Marino
12315e4b17023SJohn Marino call = NULL_TREE;
12316e4b17023SJohn Marino retval = NULL_TREE;
12317e4b17023SJohn Marino
12318e4b17023SJohn Marino if (!init_target_chars ())
12319e4b17023SJohn Marino return NULL_TREE;
12320e4b17023SJohn Marino
12321e4b17023SJohn Marino destlen = tree_low_cst (destsize, 1);
12322e4b17023SJohn Marino
12323e4b17023SJohn Marino /* If the format doesn't contain % args or %%, use strcpy. */
12324e4b17023SJohn Marino if (strchr (fmt_str, target_percent) == NULL)
12325e4b17023SJohn Marino {
12326e4b17023SJohn Marino tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
12327e4b17023SJohn Marino size_t len = strlen (fmt_str);
12328e4b17023SJohn Marino
12329e4b17023SJohn Marino /* Don't optimize snprintf (buf, 4, "abc", ptr++). */
12330e4b17023SJohn Marino if (orig)
12331e4b17023SJohn Marino return NULL_TREE;
12332e4b17023SJohn Marino
12333e4b17023SJohn Marino /* We could expand this as
12334e4b17023SJohn Marino memcpy (str, fmt, cst - 1); str[cst - 1] = '\0';
12335e4b17023SJohn Marino or to
12336e4b17023SJohn Marino memcpy (str, fmt_with_nul_at_cstm1, cst);
12337e4b17023SJohn Marino but in the former case that might increase code size
12338e4b17023SJohn Marino and in the latter case grow .rodata section too much.
12339e4b17023SJohn Marino So punt for now. */
12340e4b17023SJohn Marino if (len >= destlen)
12341e4b17023SJohn Marino return NULL_TREE;
12342e4b17023SJohn Marino
12343e4b17023SJohn Marino if (!fn)
12344e4b17023SJohn Marino return NULL_TREE;
12345e4b17023SJohn Marino
12346e4b17023SJohn Marino /* Convert snprintf (str, cst, fmt) into strcpy (str, fmt) when
12347e4b17023SJohn Marino 'format' is known to contain no % formats and
12348e4b17023SJohn Marino strlen (fmt) < cst. */
12349e4b17023SJohn Marino call = build_call_expr_loc (loc, fn, 2, dest, fmt);
12350e4b17023SJohn Marino
12351e4b17023SJohn Marino if (!ignored)
12352e4b17023SJohn Marino retval = build_int_cst (integer_type_node, strlen (fmt_str));
12353e4b17023SJohn Marino }
12354e4b17023SJohn Marino
12355e4b17023SJohn Marino /* If the format is "%s", use strcpy if the result isn't used. */
12356e4b17023SJohn Marino else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
12357e4b17023SJohn Marino {
12358e4b17023SJohn Marino tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
12359e4b17023SJohn Marino unsigned HOST_WIDE_INT origlen;
12360e4b17023SJohn Marino
12361e4b17023SJohn Marino /* Don't crash on snprintf (str1, cst, "%s"). */
12362e4b17023SJohn Marino if (!orig)
12363e4b17023SJohn Marino return NULL_TREE;
12364e4b17023SJohn Marino
12365e4b17023SJohn Marino retval = c_strlen (orig, 1);
12366e4b17023SJohn Marino if (!retval || !host_integerp (retval, 1))
12367e4b17023SJohn Marino return NULL_TREE;
12368e4b17023SJohn Marino
12369e4b17023SJohn Marino origlen = tree_low_cst (retval, 1);
12370e4b17023SJohn Marino /* We could expand this as
12371e4b17023SJohn Marino memcpy (str1, str2, cst - 1); str1[cst - 1] = '\0';
12372e4b17023SJohn Marino or to
12373e4b17023SJohn Marino memcpy (str1, str2_with_nul_at_cstm1, cst);
12374e4b17023SJohn Marino but in the former case that might increase code size
12375e4b17023SJohn Marino and in the latter case grow .rodata section too much.
12376e4b17023SJohn Marino So punt for now. */
12377e4b17023SJohn Marino if (origlen >= destlen)
12378e4b17023SJohn Marino return NULL_TREE;
12379e4b17023SJohn Marino
12380e4b17023SJohn Marino /* Convert snprintf (str1, cst, "%s", str2) into
12381e4b17023SJohn Marino strcpy (str1, str2) if strlen (str2) < cst. */
12382e4b17023SJohn Marino if (!fn)
12383e4b17023SJohn Marino return NULL_TREE;
12384e4b17023SJohn Marino
12385e4b17023SJohn Marino call = build_call_expr_loc (loc, fn, 2, dest, orig);
12386e4b17023SJohn Marino
12387e4b17023SJohn Marino if (ignored)
12388e4b17023SJohn Marino retval = NULL_TREE;
12389e4b17023SJohn Marino }
12390e4b17023SJohn Marino
12391e4b17023SJohn Marino if (call && retval)
12392e4b17023SJohn Marino {
12393e4b17023SJohn Marino tree fn = builtin_decl_explicit (BUILT_IN_SNPRINTF);
12394e4b17023SJohn Marino retval = fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fn)), retval);
12395e4b17023SJohn Marino return build2 (COMPOUND_EXPR, TREE_TYPE (retval), call, retval);
12396e4b17023SJohn Marino }
12397e4b17023SJohn Marino else
12398e4b17023SJohn Marino return call;
12399e4b17023SJohn Marino }
12400e4b17023SJohn Marino
12401e4b17023SJohn Marino /* Expand a call EXP to __builtin_object_size. */
12402e4b17023SJohn Marino
12403e4b17023SJohn Marino rtx
expand_builtin_object_size(tree exp)12404e4b17023SJohn Marino expand_builtin_object_size (tree exp)
12405e4b17023SJohn Marino {
12406e4b17023SJohn Marino tree ost;
12407e4b17023SJohn Marino int object_size_type;
12408e4b17023SJohn Marino tree fndecl = get_callee_fndecl (exp);
12409e4b17023SJohn Marino
12410e4b17023SJohn Marino if (!validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
12411e4b17023SJohn Marino {
12412e4b17023SJohn Marino error ("%Kfirst argument of %D must be a pointer, second integer constant",
12413e4b17023SJohn Marino exp, fndecl);
12414e4b17023SJohn Marino expand_builtin_trap ();
12415e4b17023SJohn Marino return const0_rtx;
12416e4b17023SJohn Marino }
12417e4b17023SJohn Marino
12418e4b17023SJohn Marino ost = CALL_EXPR_ARG (exp, 1);
12419e4b17023SJohn Marino STRIP_NOPS (ost);
12420e4b17023SJohn Marino
12421e4b17023SJohn Marino if (TREE_CODE (ost) != INTEGER_CST
12422e4b17023SJohn Marino || tree_int_cst_sgn (ost) < 0
12423e4b17023SJohn Marino || compare_tree_int (ost, 3) > 0)
12424e4b17023SJohn Marino {
12425e4b17023SJohn Marino error ("%Klast argument of %D is not integer constant between 0 and 3",
12426e4b17023SJohn Marino exp, fndecl);
12427e4b17023SJohn Marino expand_builtin_trap ();
12428e4b17023SJohn Marino return const0_rtx;
12429e4b17023SJohn Marino }
12430e4b17023SJohn Marino
12431e4b17023SJohn Marino object_size_type = tree_low_cst (ost, 0);
12432e4b17023SJohn Marino
12433e4b17023SJohn Marino return object_size_type < 2 ? constm1_rtx : const0_rtx;
12434e4b17023SJohn Marino }
12435e4b17023SJohn Marino
12436e4b17023SJohn Marino /* Expand EXP, a call to the __mem{cpy,pcpy,move,set}_chk builtin.
12437e4b17023SJohn Marino FCODE is the BUILT_IN_* to use.
12438e4b17023SJohn Marino Return NULL_RTX if we failed; the caller should emit a normal call,
12439e4b17023SJohn Marino otherwise try to get the result in TARGET, if convenient (and in
12440e4b17023SJohn Marino mode MODE if that's convenient). */
12441e4b17023SJohn Marino
12442e4b17023SJohn Marino static rtx
expand_builtin_memory_chk(tree exp,rtx target,enum machine_mode mode,enum built_in_function fcode)12443e4b17023SJohn Marino expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
12444e4b17023SJohn Marino enum built_in_function fcode)
12445e4b17023SJohn Marino {
12446e4b17023SJohn Marino tree dest, src, len, size;
12447e4b17023SJohn Marino
12448e4b17023SJohn Marino if (!validate_arglist (exp,
12449e4b17023SJohn Marino POINTER_TYPE,
12450e4b17023SJohn Marino fcode == BUILT_IN_MEMSET_CHK
12451e4b17023SJohn Marino ? INTEGER_TYPE : POINTER_TYPE,
12452e4b17023SJohn Marino INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
12453e4b17023SJohn Marino return NULL_RTX;
12454e4b17023SJohn Marino
12455e4b17023SJohn Marino dest = CALL_EXPR_ARG (exp, 0);
12456e4b17023SJohn Marino src = CALL_EXPR_ARG (exp, 1);
12457e4b17023SJohn Marino len = CALL_EXPR_ARG (exp, 2);
12458e4b17023SJohn Marino size = CALL_EXPR_ARG (exp, 3);
12459e4b17023SJohn Marino
12460e4b17023SJohn Marino if (! host_integerp (size, 1))
12461e4b17023SJohn Marino return NULL_RTX;
12462e4b17023SJohn Marino
12463e4b17023SJohn Marino if (host_integerp (len, 1) || integer_all_onesp (size))
12464e4b17023SJohn Marino {
12465e4b17023SJohn Marino tree fn;
12466e4b17023SJohn Marino
12467e4b17023SJohn Marino if (! integer_all_onesp (size) && tree_int_cst_lt (size, len))
12468e4b17023SJohn Marino {
12469e4b17023SJohn Marino warning_at (tree_nonartificial_location (exp),
12470e4b17023SJohn Marino 0, "%Kcall to %D will always overflow destination buffer",
12471e4b17023SJohn Marino exp, get_callee_fndecl (exp));
12472e4b17023SJohn Marino return NULL_RTX;
12473e4b17023SJohn Marino }
12474e4b17023SJohn Marino
12475e4b17023SJohn Marino fn = NULL_TREE;
12476e4b17023SJohn Marino /* If __builtin_mem{cpy,pcpy,move,set}_chk is used, assume
12477e4b17023SJohn Marino mem{cpy,pcpy,move,set} is available. */
12478e4b17023SJohn Marino switch (fcode)
12479e4b17023SJohn Marino {
12480e4b17023SJohn Marino case BUILT_IN_MEMCPY_CHK:
12481e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMCPY);
12482e4b17023SJohn Marino break;
12483e4b17023SJohn Marino case BUILT_IN_MEMPCPY_CHK:
12484e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMPCPY);
12485e4b17023SJohn Marino break;
12486e4b17023SJohn Marino case BUILT_IN_MEMMOVE_CHK:
12487e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMMOVE);
12488e4b17023SJohn Marino break;
12489e4b17023SJohn Marino case BUILT_IN_MEMSET_CHK:
12490e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMSET);
12491e4b17023SJohn Marino break;
12492e4b17023SJohn Marino default:
12493e4b17023SJohn Marino break;
12494e4b17023SJohn Marino }
12495e4b17023SJohn Marino
12496e4b17023SJohn Marino if (! fn)
12497e4b17023SJohn Marino return NULL_RTX;
12498e4b17023SJohn Marino
12499e4b17023SJohn Marino fn = build_call_nofold_loc (EXPR_LOCATION (exp), fn, 3, dest, src, len);
12500e4b17023SJohn Marino gcc_assert (TREE_CODE (fn) == CALL_EXPR);
12501e4b17023SJohn Marino CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
12502e4b17023SJohn Marino return expand_expr (fn, target, mode, EXPAND_NORMAL);
12503e4b17023SJohn Marino }
12504e4b17023SJohn Marino else if (fcode == BUILT_IN_MEMSET_CHK)
12505e4b17023SJohn Marino return NULL_RTX;
12506e4b17023SJohn Marino else
12507e4b17023SJohn Marino {
12508e4b17023SJohn Marino unsigned int dest_align = get_pointer_alignment (dest);
12509e4b17023SJohn Marino
12510e4b17023SJohn Marino /* If DEST is not a pointer type, call the normal function. */
12511e4b17023SJohn Marino if (dest_align == 0)
12512e4b17023SJohn Marino return NULL_RTX;
12513e4b17023SJohn Marino
12514e4b17023SJohn Marino /* If SRC and DEST are the same (and not volatile), do nothing. */
12515e4b17023SJohn Marino if (operand_equal_p (src, dest, 0))
12516e4b17023SJohn Marino {
12517e4b17023SJohn Marino tree expr;
12518e4b17023SJohn Marino
12519e4b17023SJohn Marino if (fcode != BUILT_IN_MEMPCPY_CHK)
12520e4b17023SJohn Marino {
12521e4b17023SJohn Marino /* Evaluate and ignore LEN in case it has side-effects. */
12522e4b17023SJohn Marino expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL);
12523e4b17023SJohn Marino return expand_expr (dest, target, mode, EXPAND_NORMAL);
12524e4b17023SJohn Marino }
12525e4b17023SJohn Marino
12526e4b17023SJohn Marino expr = fold_build_pointer_plus (dest, len);
12527e4b17023SJohn Marino return expand_expr (expr, target, mode, EXPAND_NORMAL);
12528e4b17023SJohn Marino }
12529e4b17023SJohn Marino
12530e4b17023SJohn Marino /* __memmove_chk special case. */
12531e4b17023SJohn Marino if (fcode == BUILT_IN_MEMMOVE_CHK)
12532e4b17023SJohn Marino {
12533e4b17023SJohn Marino unsigned int src_align = get_pointer_alignment (src);
12534e4b17023SJohn Marino
12535e4b17023SJohn Marino if (src_align == 0)
12536e4b17023SJohn Marino return NULL_RTX;
12537e4b17023SJohn Marino
12538e4b17023SJohn Marino /* If src is categorized for a readonly section we can use
12539e4b17023SJohn Marino normal __memcpy_chk. */
12540e4b17023SJohn Marino if (readonly_data_expr (src))
12541e4b17023SJohn Marino {
12542e4b17023SJohn Marino tree fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
12543e4b17023SJohn Marino if (!fn)
12544e4b17023SJohn Marino return NULL_RTX;
12545e4b17023SJohn Marino fn = build_call_nofold_loc (EXPR_LOCATION (exp), fn, 4,
12546e4b17023SJohn Marino dest, src, len, size);
12547e4b17023SJohn Marino gcc_assert (TREE_CODE (fn) == CALL_EXPR);
12548e4b17023SJohn Marino CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
12549e4b17023SJohn Marino return expand_expr (fn, target, mode, EXPAND_NORMAL);
12550e4b17023SJohn Marino }
12551e4b17023SJohn Marino }
12552e4b17023SJohn Marino return NULL_RTX;
12553e4b17023SJohn Marino }
12554e4b17023SJohn Marino }
12555e4b17023SJohn Marino
12556e4b17023SJohn Marino /* Emit warning if a buffer overflow is detected at compile time. */
12557e4b17023SJohn Marino
12558e4b17023SJohn Marino static void
maybe_emit_chk_warning(tree exp,enum built_in_function fcode)12559e4b17023SJohn Marino maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
12560e4b17023SJohn Marino {
12561e4b17023SJohn Marino int is_strlen = 0;
12562e4b17023SJohn Marino tree len, size;
12563e4b17023SJohn Marino location_t loc = tree_nonartificial_location (exp);
12564e4b17023SJohn Marino
12565e4b17023SJohn Marino switch (fcode)
12566e4b17023SJohn Marino {
12567e4b17023SJohn Marino case BUILT_IN_STRCPY_CHK:
12568e4b17023SJohn Marino case BUILT_IN_STPCPY_CHK:
12569e4b17023SJohn Marino /* For __strcat_chk the warning will be emitted only if overflowing
12570e4b17023SJohn Marino by at least strlen (dest) + 1 bytes. */
12571e4b17023SJohn Marino case BUILT_IN_STRCAT_CHK:
12572e4b17023SJohn Marino len = CALL_EXPR_ARG (exp, 1);
12573e4b17023SJohn Marino size = CALL_EXPR_ARG (exp, 2);
12574e4b17023SJohn Marino is_strlen = 1;
12575e4b17023SJohn Marino break;
12576e4b17023SJohn Marino case BUILT_IN_STRNCAT_CHK:
12577e4b17023SJohn Marino case BUILT_IN_STRNCPY_CHK:
12578e4b17023SJohn Marino case BUILT_IN_STPNCPY_CHK:
12579e4b17023SJohn Marino len = CALL_EXPR_ARG (exp, 2);
12580e4b17023SJohn Marino size = CALL_EXPR_ARG (exp, 3);
12581e4b17023SJohn Marino break;
12582e4b17023SJohn Marino case BUILT_IN_SNPRINTF_CHK:
12583e4b17023SJohn Marino case BUILT_IN_VSNPRINTF_CHK:
12584e4b17023SJohn Marino len = CALL_EXPR_ARG (exp, 1);
12585e4b17023SJohn Marino size = CALL_EXPR_ARG (exp, 3);
12586e4b17023SJohn Marino break;
12587e4b17023SJohn Marino default:
12588e4b17023SJohn Marino gcc_unreachable ();
12589e4b17023SJohn Marino }
12590e4b17023SJohn Marino
12591e4b17023SJohn Marino if (!len || !size)
12592e4b17023SJohn Marino return;
12593e4b17023SJohn Marino
12594e4b17023SJohn Marino if (! host_integerp (size, 1) || integer_all_onesp (size))
12595e4b17023SJohn Marino return;
12596e4b17023SJohn Marino
12597e4b17023SJohn Marino if (is_strlen)
12598e4b17023SJohn Marino {
12599e4b17023SJohn Marino len = c_strlen (len, 1);
12600e4b17023SJohn Marino if (! len || ! host_integerp (len, 1) || tree_int_cst_lt (len, size))
12601e4b17023SJohn Marino return;
12602e4b17023SJohn Marino }
12603e4b17023SJohn Marino else if (fcode == BUILT_IN_STRNCAT_CHK)
12604e4b17023SJohn Marino {
12605e4b17023SJohn Marino tree src = CALL_EXPR_ARG (exp, 1);
12606e4b17023SJohn Marino if (! src || ! host_integerp (len, 1) || tree_int_cst_lt (len, size))
12607e4b17023SJohn Marino return;
12608e4b17023SJohn Marino src = c_strlen (src, 1);
12609e4b17023SJohn Marino if (! src || ! host_integerp (src, 1))
12610e4b17023SJohn Marino {
12611e4b17023SJohn Marino warning_at (loc, 0, "%Kcall to %D might overflow destination buffer",
12612e4b17023SJohn Marino exp, get_callee_fndecl (exp));
12613e4b17023SJohn Marino return;
12614e4b17023SJohn Marino }
12615e4b17023SJohn Marino else if (tree_int_cst_lt (src, size))
12616e4b17023SJohn Marino return;
12617e4b17023SJohn Marino }
12618e4b17023SJohn Marino else if (! host_integerp (len, 1) || ! tree_int_cst_lt (size, len))
12619e4b17023SJohn Marino return;
12620e4b17023SJohn Marino
12621e4b17023SJohn Marino warning_at (loc, 0, "%Kcall to %D will always overflow destination buffer",
12622e4b17023SJohn Marino exp, get_callee_fndecl (exp));
12623e4b17023SJohn Marino }
12624e4b17023SJohn Marino
12625e4b17023SJohn Marino /* Emit warning if a buffer overflow is detected at compile time
12626e4b17023SJohn Marino in __sprintf_chk/__vsprintf_chk calls. */
12627e4b17023SJohn Marino
12628e4b17023SJohn Marino static void
maybe_emit_sprintf_chk_warning(tree exp,enum built_in_function fcode)12629e4b17023SJohn Marino maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
12630e4b17023SJohn Marino {
12631e4b17023SJohn Marino tree size, len, fmt;
12632e4b17023SJohn Marino const char *fmt_str;
12633e4b17023SJohn Marino int nargs = call_expr_nargs (exp);
12634e4b17023SJohn Marino
12635e4b17023SJohn Marino /* Verify the required arguments in the original call. */
12636e4b17023SJohn Marino
12637e4b17023SJohn Marino if (nargs < 4)
12638e4b17023SJohn Marino return;
12639e4b17023SJohn Marino size = CALL_EXPR_ARG (exp, 2);
12640e4b17023SJohn Marino fmt = CALL_EXPR_ARG (exp, 3);
12641e4b17023SJohn Marino
12642e4b17023SJohn Marino if (! host_integerp (size, 1) || integer_all_onesp (size))
12643e4b17023SJohn Marino return;
12644e4b17023SJohn Marino
12645e4b17023SJohn Marino /* Check whether the format is a literal string constant. */
12646e4b17023SJohn Marino fmt_str = c_getstr (fmt);
12647e4b17023SJohn Marino if (fmt_str == NULL)
12648e4b17023SJohn Marino return;
12649e4b17023SJohn Marino
12650e4b17023SJohn Marino if (!init_target_chars ())
12651e4b17023SJohn Marino return;
12652e4b17023SJohn Marino
12653e4b17023SJohn Marino /* If the format doesn't contain % args or %%, we know its size. */
12654e4b17023SJohn Marino if (strchr (fmt_str, target_percent) == 0)
12655e4b17023SJohn Marino len = build_int_cstu (size_type_node, strlen (fmt_str));
12656e4b17023SJohn Marino /* If the format is "%s" and first ... argument is a string literal,
12657e4b17023SJohn Marino we know it too. */
12658e4b17023SJohn Marino else if (fcode == BUILT_IN_SPRINTF_CHK
12659e4b17023SJohn Marino && strcmp (fmt_str, target_percent_s) == 0)
12660e4b17023SJohn Marino {
12661e4b17023SJohn Marino tree arg;
12662e4b17023SJohn Marino
12663e4b17023SJohn Marino if (nargs < 5)
12664e4b17023SJohn Marino return;
12665e4b17023SJohn Marino arg = CALL_EXPR_ARG (exp, 4);
12666e4b17023SJohn Marino if (! POINTER_TYPE_P (TREE_TYPE (arg)))
12667e4b17023SJohn Marino return;
12668e4b17023SJohn Marino
12669e4b17023SJohn Marino len = c_strlen (arg, 1);
12670e4b17023SJohn Marino if (!len || ! host_integerp (len, 1))
12671e4b17023SJohn Marino return;
12672e4b17023SJohn Marino }
12673e4b17023SJohn Marino else
12674e4b17023SJohn Marino return;
12675e4b17023SJohn Marino
12676e4b17023SJohn Marino if (! tree_int_cst_lt (len, size))
12677e4b17023SJohn Marino warning_at (tree_nonartificial_location (exp),
12678e4b17023SJohn Marino 0, "%Kcall to %D will always overflow destination buffer",
12679e4b17023SJohn Marino exp, get_callee_fndecl (exp));
12680e4b17023SJohn Marino }
12681e4b17023SJohn Marino
12682e4b17023SJohn Marino /* Emit warning if a free is called with address of a variable. */
12683e4b17023SJohn Marino
12684e4b17023SJohn Marino static void
maybe_emit_free_warning(tree exp)12685e4b17023SJohn Marino maybe_emit_free_warning (tree exp)
12686e4b17023SJohn Marino {
12687e4b17023SJohn Marino tree arg = CALL_EXPR_ARG (exp, 0);
12688e4b17023SJohn Marino
12689e4b17023SJohn Marino STRIP_NOPS (arg);
12690e4b17023SJohn Marino if (TREE_CODE (arg) != ADDR_EXPR)
12691e4b17023SJohn Marino return;
12692e4b17023SJohn Marino
12693e4b17023SJohn Marino arg = get_base_address (TREE_OPERAND (arg, 0));
12694e4b17023SJohn Marino if (arg == NULL || INDIRECT_REF_P (arg) || TREE_CODE (arg) == MEM_REF)
12695e4b17023SJohn Marino return;
12696e4b17023SJohn Marino
12697e4b17023SJohn Marino if (SSA_VAR_P (arg))
12698e4b17023SJohn Marino warning_at (tree_nonartificial_location (exp), OPT_Wfree_nonheap_object,
12699e4b17023SJohn Marino "%Kattempt to free a non-heap object %qD", exp, arg);
12700e4b17023SJohn Marino else
12701e4b17023SJohn Marino warning_at (tree_nonartificial_location (exp), OPT_Wfree_nonheap_object,
12702e4b17023SJohn Marino "%Kattempt to free a non-heap object", exp);
12703e4b17023SJohn Marino }
12704e4b17023SJohn Marino
12705e4b17023SJohn Marino /* Fold a call to __builtin_object_size with arguments PTR and OST,
12706e4b17023SJohn Marino if possible. */
12707e4b17023SJohn Marino
12708e4b17023SJohn Marino tree
fold_builtin_object_size(tree ptr,tree ost)12709e4b17023SJohn Marino fold_builtin_object_size (tree ptr, tree ost)
12710e4b17023SJohn Marino {
12711e4b17023SJohn Marino unsigned HOST_WIDE_INT bytes;
12712e4b17023SJohn Marino int object_size_type;
12713e4b17023SJohn Marino
12714e4b17023SJohn Marino if (!validate_arg (ptr, POINTER_TYPE)
12715e4b17023SJohn Marino || !validate_arg (ost, INTEGER_TYPE))
12716e4b17023SJohn Marino return NULL_TREE;
12717e4b17023SJohn Marino
12718e4b17023SJohn Marino STRIP_NOPS (ost);
12719e4b17023SJohn Marino
12720e4b17023SJohn Marino if (TREE_CODE (ost) != INTEGER_CST
12721e4b17023SJohn Marino || tree_int_cst_sgn (ost) < 0
12722e4b17023SJohn Marino || compare_tree_int (ost, 3) > 0)
12723e4b17023SJohn Marino return NULL_TREE;
12724e4b17023SJohn Marino
12725e4b17023SJohn Marino object_size_type = tree_low_cst (ost, 0);
12726e4b17023SJohn Marino
12727e4b17023SJohn Marino /* __builtin_object_size doesn't evaluate side-effects in its arguments;
12728e4b17023SJohn Marino if there are any side-effects, it returns (size_t) -1 for types 0 and 1
12729e4b17023SJohn Marino and (size_t) 0 for types 2 and 3. */
12730e4b17023SJohn Marino if (TREE_SIDE_EFFECTS (ptr))
12731e4b17023SJohn Marino return build_int_cst_type (size_type_node, object_size_type < 2 ? -1 : 0);
12732e4b17023SJohn Marino
12733e4b17023SJohn Marino if (TREE_CODE (ptr) == ADDR_EXPR)
12734e4b17023SJohn Marino {
12735e4b17023SJohn Marino bytes = compute_builtin_object_size (ptr, object_size_type);
12736e4b17023SJohn Marino if (double_int_fits_to_tree_p (size_type_node,
12737e4b17023SJohn Marino uhwi_to_double_int (bytes)))
12738e4b17023SJohn Marino return build_int_cstu (size_type_node, bytes);
12739e4b17023SJohn Marino }
12740e4b17023SJohn Marino else if (TREE_CODE (ptr) == SSA_NAME)
12741e4b17023SJohn Marino {
12742e4b17023SJohn Marino /* If object size is not known yet, delay folding until
12743e4b17023SJohn Marino later. Maybe subsequent passes will help determining
12744e4b17023SJohn Marino it. */
12745e4b17023SJohn Marino bytes = compute_builtin_object_size (ptr, object_size_type);
12746e4b17023SJohn Marino if (bytes != (unsigned HOST_WIDE_INT) (object_size_type < 2 ? -1 : 0)
12747e4b17023SJohn Marino && double_int_fits_to_tree_p (size_type_node,
12748e4b17023SJohn Marino uhwi_to_double_int (bytes)))
12749e4b17023SJohn Marino return build_int_cstu (size_type_node, bytes);
12750e4b17023SJohn Marino }
12751e4b17023SJohn Marino
12752e4b17023SJohn Marino return NULL_TREE;
12753e4b17023SJohn Marino }
12754e4b17023SJohn Marino
12755e4b17023SJohn Marino /* Fold a call to the __mem{cpy,pcpy,move,set}_chk builtin.
12756e4b17023SJohn Marino DEST, SRC, LEN, and SIZE are the arguments to the call.
12757e4b17023SJohn Marino IGNORE is true, if return value can be ignored. FCODE is the BUILT_IN_*
12758e4b17023SJohn Marino code of the builtin. If MAXLEN is not NULL, it is maximum length
12759e4b17023SJohn Marino passed as third argument. */
12760e4b17023SJohn Marino
12761e4b17023SJohn Marino tree
fold_builtin_memory_chk(location_t loc,tree fndecl,tree dest,tree src,tree len,tree size,tree maxlen,bool ignore,enum built_in_function fcode)12762e4b17023SJohn Marino fold_builtin_memory_chk (location_t loc, tree fndecl,
12763e4b17023SJohn Marino tree dest, tree src, tree len, tree size,
12764e4b17023SJohn Marino tree maxlen, bool ignore,
12765e4b17023SJohn Marino enum built_in_function fcode)
12766e4b17023SJohn Marino {
12767e4b17023SJohn Marino tree fn;
12768e4b17023SJohn Marino
12769e4b17023SJohn Marino if (!validate_arg (dest, POINTER_TYPE)
12770e4b17023SJohn Marino || !validate_arg (src,
12771e4b17023SJohn Marino (fcode == BUILT_IN_MEMSET_CHK
12772e4b17023SJohn Marino ? INTEGER_TYPE : POINTER_TYPE))
12773e4b17023SJohn Marino || !validate_arg (len, INTEGER_TYPE)
12774e4b17023SJohn Marino || !validate_arg (size, INTEGER_TYPE))
12775e4b17023SJohn Marino return NULL_TREE;
12776e4b17023SJohn Marino
12777e4b17023SJohn Marino /* If SRC and DEST are the same (and not volatile), return DEST
12778e4b17023SJohn Marino (resp. DEST+LEN for __mempcpy_chk). */
12779e4b17023SJohn Marino if (fcode != BUILT_IN_MEMSET_CHK && operand_equal_p (src, dest, 0))
12780e4b17023SJohn Marino {
12781e4b17023SJohn Marino if (fcode != BUILT_IN_MEMPCPY_CHK)
12782e4b17023SJohn Marino return omit_one_operand_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)),
12783e4b17023SJohn Marino dest, len);
12784e4b17023SJohn Marino else
12785e4b17023SJohn Marino {
12786e4b17023SJohn Marino tree temp = fold_build_pointer_plus_loc (loc, dest, len);
12787e4b17023SJohn Marino return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), temp);
12788e4b17023SJohn Marino }
12789e4b17023SJohn Marino }
12790e4b17023SJohn Marino
12791e4b17023SJohn Marino if (! host_integerp (size, 1))
12792e4b17023SJohn Marino return NULL_TREE;
12793e4b17023SJohn Marino
12794e4b17023SJohn Marino if (! integer_all_onesp (size))
12795e4b17023SJohn Marino {
12796e4b17023SJohn Marino if (! host_integerp (len, 1))
12797e4b17023SJohn Marino {
12798e4b17023SJohn Marino /* If LEN is not constant, try MAXLEN too.
12799e4b17023SJohn Marino For MAXLEN only allow optimizing into non-_ocs function
12800e4b17023SJohn Marino if SIZE is >= MAXLEN, never convert to __ocs_fail (). */
12801e4b17023SJohn Marino if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
12802e4b17023SJohn Marino {
12803e4b17023SJohn Marino if (fcode == BUILT_IN_MEMPCPY_CHK && ignore)
12804e4b17023SJohn Marino {
12805e4b17023SJohn Marino /* (void) __mempcpy_chk () can be optimized into
12806e4b17023SJohn Marino (void) __memcpy_chk (). */
12807e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
12808e4b17023SJohn Marino if (!fn)
12809e4b17023SJohn Marino return NULL_TREE;
12810e4b17023SJohn Marino
12811e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 4, dest, src, len, size);
12812e4b17023SJohn Marino }
12813e4b17023SJohn Marino return NULL_TREE;
12814e4b17023SJohn Marino }
12815e4b17023SJohn Marino }
12816e4b17023SJohn Marino else
12817e4b17023SJohn Marino maxlen = len;
12818e4b17023SJohn Marino
12819e4b17023SJohn Marino if (tree_int_cst_lt (size, maxlen))
12820e4b17023SJohn Marino return NULL_TREE;
12821e4b17023SJohn Marino }
12822e4b17023SJohn Marino
12823e4b17023SJohn Marino fn = NULL_TREE;
12824e4b17023SJohn Marino /* If __builtin_mem{cpy,pcpy,move,set}_chk is used, assume
12825e4b17023SJohn Marino mem{cpy,pcpy,move,set} is available. */
12826e4b17023SJohn Marino switch (fcode)
12827e4b17023SJohn Marino {
12828e4b17023SJohn Marino case BUILT_IN_MEMCPY_CHK:
12829e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMCPY);
12830e4b17023SJohn Marino break;
12831e4b17023SJohn Marino case BUILT_IN_MEMPCPY_CHK:
12832e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMPCPY);
12833e4b17023SJohn Marino break;
12834e4b17023SJohn Marino case BUILT_IN_MEMMOVE_CHK:
12835e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMMOVE);
12836e4b17023SJohn Marino break;
12837e4b17023SJohn Marino case BUILT_IN_MEMSET_CHK:
12838e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMSET);
12839e4b17023SJohn Marino break;
12840e4b17023SJohn Marino default:
12841e4b17023SJohn Marino break;
12842e4b17023SJohn Marino }
12843e4b17023SJohn Marino
12844e4b17023SJohn Marino if (!fn)
12845e4b17023SJohn Marino return NULL_TREE;
12846e4b17023SJohn Marino
12847e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 3, dest, src, len);
12848e4b17023SJohn Marino }
12849e4b17023SJohn Marino
12850e4b17023SJohn Marino /* Fold a call to the __st[rp]cpy_chk builtin.
12851e4b17023SJohn Marino DEST, SRC, and SIZE are the arguments to the call.
12852e4b17023SJohn Marino IGNORE is true if return value can be ignored. FCODE is the BUILT_IN_*
12853e4b17023SJohn Marino code of the builtin. If MAXLEN is not NULL, it is maximum length of
12854e4b17023SJohn Marino strings passed as second argument. */
12855e4b17023SJohn Marino
12856e4b17023SJohn Marino tree
fold_builtin_stxcpy_chk(location_t loc,tree fndecl,tree dest,tree src,tree size,tree maxlen,bool ignore,enum built_in_function fcode)12857e4b17023SJohn Marino fold_builtin_stxcpy_chk (location_t loc, tree fndecl, tree dest,
12858e4b17023SJohn Marino tree src, tree size,
12859e4b17023SJohn Marino tree maxlen, bool ignore,
12860e4b17023SJohn Marino enum built_in_function fcode)
12861e4b17023SJohn Marino {
12862e4b17023SJohn Marino tree len, fn;
12863e4b17023SJohn Marino
12864e4b17023SJohn Marino if (!validate_arg (dest, POINTER_TYPE)
12865e4b17023SJohn Marino || !validate_arg (src, POINTER_TYPE)
12866e4b17023SJohn Marino || !validate_arg (size, INTEGER_TYPE))
12867e4b17023SJohn Marino return NULL_TREE;
12868e4b17023SJohn Marino
12869e4b17023SJohn Marino /* If SRC and DEST are the same (and not volatile), return DEST. */
12870e4b17023SJohn Marino if (fcode == BUILT_IN_STRCPY_CHK && operand_equal_p (src, dest, 0))
12871e4b17023SJohn Marino return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), dest);
12872e4b17023SJohn Marino
12873e4b17023SJohn Marino if (! host_integerp (size, 1))
12874e4b17023SJohn Marino return NULL_TREE;
12875e4b17023SJohn Marino
12876e4b17023SJohn Marino if (! integer_all_onesp (size))
12877e4b17023SJohn Marino {
12878e4b17023SJohn Marino len = c_strlen (src, 1);
12879e4b17023SJohn Marino if (! len || ! host_integerp (len, 1))
12880e4b17023SJohn Marino {
12881e4b17023SJohn Marino /* If LEN is not constant, try MAXLEN too.
12882e4b17023SJohn Marino For MAXLEN only allow optimizing into non-_ocs function
12883e4b17023SJohn Marino if SIZE is >= MAXLEN, never convert to __ocs_fail (). */
12884e4b17023SJohn Marino if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
12885e4b17023SJohn Marino {
12886e4b17023SJohn Marino if (fcode == BUILT_IN_STPCPY_CHK)
12887e4b17023SJohn Marino {
12888e4b17023SJohn Marino if (! ignore)
12889e4b17023SJohn Marino return NULL_TREE;
12890e4b17023SJohn Marino
12891e4b17023SJohn Marino /* If return value of __stpcpy_chk is ignored,
12892e4b17023SJohn Marino optimize into __strcpy_chk. */
12893e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
12894e4b17023SJohn Marino if (!fn)
12895e4b17023SJohn Marino return NULL_TREE;
12896e4b17023SJohn Marino
12897e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 3, dest, src, size);
12898e4b17023SJohn Marino }
12899e4b17023SJohn Marino
12900e4b17023SJohn Marino if (! len || TREE_SIDE_EFFECTS (len))
12901e4b17023SJohn Marino return NULL_TREE;
12902e4b17023SJohn Marino
12903e4b17023SJohn Marino /* If c_strlen returned something, but not a constant,
12904e4b17023SJohn Marino transform __strcpy_chk into __memcpy_chk. */
12905e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
12906e4b17023SJohn Marino if (!fn)
12907e4b17023SJohn Marino return NULL_TREE;
12908e4b17023SJohn Marino
12909e4b17023SJohn Marino len = fold_convert_loc (loc, size_type_node, len);
12910e4b17023SJohn Marino len = size_binop_loc (loc, PLUS_EXPR, len,
12911e4b17023SJohn Marino build_int_cst (size_type_node, 1));
12912e4b17023SJohn Marino return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)),
12913e4b17023SJohn Marino build_call_expr_loc (loc, fn, 4,
12914e4b17023SJohn Marino dest, src, len, size));
12915e4b17023SJohn Marino }
12916e4b17023SJohn Marino }
12917e4b17023SJohn Marino else
12918e4b17023SJohn Marino maxlen = len;
12919e4b17023SJohn Marino
12920e4b17023SJohn Marino if (! tree_int_cst_lt (maxlen, size))
12921e4b17023SJohn Marino return NULL_TREE;
12922e4b17023SJohn Marino }
12923e4b17023SJohn Marino
12924e4b17023SJohn Marino /* If __builtin_st{r,p}cpy_chk is used, assume st{r,p}cpy is available. */
12925e4b17023SJohn Marino fn = builtin_decl_explicit (fcode == BUILT_IN_STPCPY_CHK
12926e4b17023SJohn Marino ? BUILT_IN_STPCPY : BUILT_IN_STRCPY);
12927e4b17023SJohn Marino if (!fn)
12928e4b17023SJohn Marino return NULL_TREE;
12929e4b17023SJohn Marino
12930e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 2, dest, src);
12931e4b17023SJohn Marino }
12932e4b17023SJohn Marino
12933e4b17023SJohn Marino /* Fold a call to the __st{r,p}ncpy_chk builtin. DEST, SRC, LEN, and SIZE
12934e4b17023SJohn Marino are the arguments to the call. If MAXLEN is not NULL, it is maximum
12935e4b17023SJohn Marino length passed as third argument. IGNORE is true if return value can be
12936e4b17023SJohn Marino ignored. FCODE is the BUILT_IN_* code of the builtin. */
12937e4b17023SJohn Marino
12938e4b17023SJohn Marino tree
fold_builtin_stxncpy_chk(location_t loc,tree dest,tree src,tree len,tree size,tree maxlen,bool ignore,enum built_in_function fcode)12939e4b17023SJohn Marino fold_builtin_stxncpy_chk (location_t loc, tree dest, tree src,
12940e4b17023SJohn Marino tree len, tree size, tree maxlen, bool ignore,
12941e4b17023SJohn Marino enum built_in_function fcode)
12942e4b17023SJohn Marino {
12943e4b17023SJohn Marino tree fn;
12944e4b17023SJohn Marino
12945e4b17023SJohn Marino if (!validate_arg (dest, POINTER_TYPE)
12946e4b17023SJohn Marino || !validate_arg (src, POINTER_TYPE)
12947e4b17023SJohn Marino || !validate_arg (len, INTEGER_TYPE)
12948e4b17023SJohn Marino || !validate_arg (size, INTEGER_TYPE))
12949e4b17023SJohn Marino return NULL_TREE;
12950e4b17023SJohn Marino
12951e4b17023SJohn Marino if (fcode == BUILT_IN_STPNCPY_CHK && ignore)
12952e4b17023SJohn Marino {
12953e4b17023SJohn Marino /* If return value of __stpncpy_chk is ignored,
12954e4b17023SJohn Marino optimize into __strncpy_chk. */
12955e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_STRNCPY_CHK);
12956e4b17023SJohn Marino if (fn)
12957e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 4, dest, src, len, size);
12958e4b17023SJohn Marino }
12959e4b17023SJohn Marino
12960e4b17023SJohn Marino if (! host_integerp (size, 1))
12961e4b17023SJohn Marino return NULL_TREE;
12962e4b17023SJohn Marino
12963e4b17023SJohn Marino if (! integer_all_onesp (size))
12964e4b17023SJohn Marino {
12965e4b17023SJohn Marino if (! host_integerp (len, 1))
12966e4b17023SJohn Marino {
12967e4b17023SJohn Marino /* If LEN is not constant, try MAXLEN too.
12968e4b17023SJohn Marino For MAXLEN only allow optimizing into non-_ocs function
12969e4b17023SJohn Marino if SIZE is >= MAXLEN, never convert to __ocs_fail (). */
12970e4b17023SJohn Marino if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
12971e4b17023SJohn Marino return NULL_TREE;
12972e4b17023SJohn Marino }
12973e4b17023SJohn Marino else
12974e4b17023SJohn Marino maxlen = len;
12975e4b17023SJohn Marino
12976e4b17023SJohn Marino if (tree_int_cst_lt (size, maxlen))
12977e4b17023SJohn Marino return NULL_TREE;
12978e4b17023SJohn Marino }
12979e4b17023SJohn Marino
12980e4b17023SJohn Marino /* If __builtin_st{r,p}ncpy_chk is used, assume st{r,p}ncpy is available. */
12981e4b17023SJohn Marino fn = builtin_decl_explicit (fcode == BUILT_IN_STPNCPY_CHK
12982e4b17023SJohn Marino ? BUILT_IN_STPNCPY : BUILT_IN_STRNCPY);
12983e4b17023SJohn Marino if (!fn)
12984e4b17023SJohn Marino return NULL_TREE;
12985e4b17023SJohn Marino
12986e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 3, dest, src, len);
12987e4b17023SJohn Marino }
12988e4b17023SJohn Marino
12989e4b17023SJohn Marino /* Fold a call to the __strcat_chk builtin FNDECL. DEST, SRC, and SIZE
12990e4b17023SJohn Marino are the arguments to the call. */
12991e4b17023SJohn Marino
12992e4b17023SJohn Marino static tree
fold_builtin_strcat_chk(location_t loc,tree fndecl,tree dest,tree src,tree size)12993e4b17023SJohn Marino fold_builtin_strcat_chk (location_t loc, tree fndecl, tree dest,
12994e4b17023SJohn Marino tree src, tree size)
12995e4b17023SJohn Marino {
12996e4b17023SJohn Marino tree fn;
12997e4b17023SJohn Marino const char *p;
12998e4b17023SJohn Marino
12999e4b17023SJohn Marino if (!validate_arg (dest, POINTER_TYPE)
13000e4b17023SJohn Marino || !validate_arg (src, POINTER_TYPE)
13001e4b17023SJohn Marino || !validate_arg (size, INTEGER_TYPE))
13002e4b17023SJohn Marino return NULL_TREE;
13003e4b17023SJohn Marino
13004e4b17023SJohn Marino p = c_getstr (src);
13005e4b17023SJohn Marino /* If the SRC parameter is "", return DEST. */
13006e4b17023SJohn Marino if (p && *p == '\0')
13007e4b17023SJohn Marino return omit_one_operand_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
13008e4b17023SJohn Marino
13009e4b17023SJohn Marino if (! host_integerp (size, 1) || ! integer_all_onesp (size))
13010e4b17023SJohn Marino return NULL_TREE;
13011e4b17023SJohn Marino
13012e4b17023SJohn Marino /* If __builtin_strcat_chk is used, assume strcat is available. */
13013e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_STRCAT);
13014e4b17023SJohn Marino if (!fn)
13015e4b17023SJohn Marino return NULL_TREE;
13016e4b17023SJohn Marino
13017e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 2, dest, src);
13018e4b17023SJohn Marino }
13019e4b17023SJohn Marino
13020e4b17023SJohn Marino /* Fold a call to the __strncat_chk builtin with arguments DEST, SRC,
13021e4b17023SJohn Marino LEN, and SIZE. */
13022e4b17023SJohn Marino
13023e4b17023SJohn Marino static tree
fold_builtin_strncat_chk(location_t loc,tree fndecl,tree dest,tree src,tree len,tree size)13024e4b17023SJohn Marino fold_builtin_strncat_chk (location_t loc, tree fndecl,
13025e4b17023SJohn Marino tree dest, tree src, tree len, tree size)
13026e4b17023SJohn Marino {
13027e4b17023SJohn Marino tree fn;
13028e4b17023SJohn Marino const char *p;
13029e4b17023SJohn Marino
13030e4b17023SJohn Marino if (!validate_arg (dest, POINTER_TYPE)
13031e4b17023SJohn Marino || !validate_arg (src, POINTER_TYPE)
13032e4b17023SJohn Marino || !validate_arg (size, INTEGER_TYPE)
13033e4b17023SJohn Marino || !validate_arg (size, INTEGER_TYPE))
13034e4b17023SJohn Marino return NULL_TREE;
13035e4b17023SJohn Marino
13036e4b17023SJohn Marino p = c_getstr (src);
13037e4b17023SJohn Marino /* If the SRC parameter is "" or if LEN is 0, return DEST. */
13038e4b17023SJohn Marino if (p && *p == '\0')
13039e4b17023SJohn Marino return omit_one_operand_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), dest, len);
13040e4b17023SJohn Marino else if (integer_zerop (len))
13041e4b17023SJohn Marino return omit_one_operand_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
13042e4b17023SJohn Marino
13043e4b17023SJohn Marino if (! host_integerp (size, 1))
13044e4b17023SJohn Marino return NULL_TREE;
13045e4b17023SJohn Marino
13046e4b17023SJohn Marino if (! integer_all_onesp (size))
13047e4b17023SJohn Marino {
13048e4b17023SJohn Marino tree src_len = c_strlen (src, 1);
13049e4b17023SJohn Marino if (src_len
13050e4b17023SJohn Marino && host_integerp (src_len, 1)
13051e4b17023SJohn Marino && host_integerp (len, 1)
13052e4b17023SJohn Marino && ! tree_int_cst_lt (len, src_len))
13053e4b17023SJohn Marino {
13054e4b17023SJohn Marino /* If LEN >= strlen (SRC), optimize into __strcat_chk. */
13055e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_STRCAT_CHK);
13056e4b17023SJohn Marino if (!fn)
13057e4b17023SJohn Marino return NULL_TREE;
13058e4b17023SJohn Marino
13059e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 3, dest, src, size);
13060e4b17023SJohn Marino }
13061e4b17023SJohn Marino return NULL_TREE;
13062e4b17023SJohn Marino }
13063e4b17023SJohn Marino
13064e4b17023SJohn Marino /* If __builtin_strncat_chk is used, assume strncat is available. */
13065e4b17023SJohn Marino fn = builtin_decl_explicit (BUILT_IN_STRNCAT);
13066e4b17023SJohn Marino if (!fn)
13067e4b17023SJohn Marino return NULL_TREE;
13068e4b17023SJohn Marino
13069e4b17023SJohn Marino return build_call_expr_loc (loc, fn, 3, dest, src, len);
13070e4b17023SJohn Marino }
13071e4b17023SJohn Marino
13072e4b17023SJohn Marino /* Fold a call EXP to __{,v}sprintf_chk having NARGS passed as ARGS.
13073e4b17023SJohn Marino Return NULL_TREE if a normal call should be emitted rather than
13074e4b17023SJohn Marino expanding the function inline. FCODE is either BUILT_IN_SPRINTF_CHK
13075e4b17023SJohn Marino or BUILT_IN_VSPRINTF_CHK. */
13076e4b17023SJohn Marino
13077e4b17023SJohn Marino static tree
fold_builtin_sprintf_chk_1(location_t loc,int nargs,tree * args,enum built_in_function fcode)13078e4b17023SJohn Marino fold_builtin_sprintf_chk_1 (location_t loc, int nargs, tree *args,
13079e4b17023SJohn Marino enum built_in_function fcode)
13080e4b17023SJohn Marino {
13081e4b17023SJohn Marino tree dest, size, len, fn, fmt, flag;
13082e4b17023SJohn Marino const char *fmt_str;
13083e4b17023SJohn Marino
13084e4b17023SJohn Marino /* Verify the required arguments in the original call. */
13085e4b17023SJohn Marino if (nargs < 4)
13086e4b17023SJohn Marino return NULL_TREE;
13087e4b17023SJohn Marino dest = args[0];
13088e4b17023SJohn Marino if (!validate_arg (dest, POINTER_TYPE))
13089e4b17023SJohn Marino return NULL_TREE;
13090e4b17023SJohn Marino flag = args[1];
13091e4b17023SJohn Marino if (!validate_arg (flag, INTEGER_TYPE))
13092e4b17023SJohn Marino return NULL_TREE;
13093e4b17023SJohn Marino size = args[2];
13094e4b17023SJohn Marino if (!validate_arg (size, INTEGER_TYPE))
13095e4b17023SJohn Marino return NULL_TREE;
13096e4b17023SJohn Marino fmt = args[3];
13097e4b17023SJohn Marino if (!validate_arg (fmt, POINTER_TYPE))
13098e4b17023SJohn Marino return NULL_TREE;
13099e4b17023SJohn Marino
13100e4b17023SJohn Marino if (! host_integerp (size, 1))
13101e4b17023SJohn Marino return NULL_TREE;
13102e4b17023SJohn Marino
13103e4b17023SJohn Marino len = NULL_TREE;
13104e4b17023SJohn Marino
13105e4b17023SJohn Marino if (!init_target_chars ())
13106e4b17023SJohn Marino return NULL_TREE;
13107e4b17023SJohn Marino
13108e4b17023SJohn Marino /* Check whether the format is a literal string constant. */
13109e4b17023SJohn Marino fmt_str = c_getstr (fmt);
13110e4b17023SJohn Marino if (fmt_str != NULL)
13111e4b17023SJohn Marino {
13112e4b17023SJohn Marino /* If the format doesn't contain % args or %%, we know the size. */
13113e4b17023SJohn Marino if (strchr (fmt_str, target_percent) == 0)
13114e4b17023SJohn Marino {
13115e4b17023SJohn Marino if (fcode != BUILT_IN_SPRINTF_CHK || nargs == 4)
13116e4b17023SJohn Marino len = build_int_cstu (size_type_node, strlen (fmt_str));
13117e4b17023SJohn Marino }
13118e4b17023SJohn Marino /* If the format is "%s" and first ... argument is a string literal,
13119e4b17023SJohn Marino we know the size too. */
13120e4b17023SJohn Marino else if (fcode == BUILT_IN_SPRINTF_CHK
13121e4b17023SJohn Marino && strcmp (fmt_str, target_percent_s) == 0)
13122e4b17023SJohn Marino {
13123e4b17023SJohn Marino tree arg;
13124e4b17023SJohn Marino
13125e4b17023SJohn Marino if (nargs == 5)
13126e4b17023SJohn Marino {
13127e4b17023SJohn Marino arg = args[4];
13128e4b17023SJohn Marino if (validate_arg (arg, POINTER_TYPE))
13129e4b17023SJohn Marino {
13130e4b17023SJohn Marino len = c_strlen (arg, 1);
13131e4b17023SJohn Marino if (! len || ! host_integerp (len, 1))
13132e4b17023SJohn Marino len = NULL_TREE;
13133e4b17023SJohn Marino }
13134e4b17023SJohn Marino }
13135e4b17023SJohn Marino }
13136e4b17023SJohn Marino }
13137e4b17023SJohn Marino
13138e4b17023SJohn Marino if (! integer_all_onesp (size))
13139e4b17023SJohn Marino {
13140e4b17023SJohn Marino if (! len || ! tree_int_cst_lt (len, size))
13141e4b17023SJohn Marino return NULL_TREE;
13142e4b17023SJohn Marino }
13143e4b17023SJohn Marino
13144e4b17023SJohn Marino /* Only convert __{,v}sprintf_chk to {,v}sprintf if flag is 0
13145e4b17023SJohn Marino or if format doesn't contain % chars or is "%s". */
13146e4b17023SJohn Marino if (! integer_zerop (flag))
13147e4b17023SJohn Marino {
13148e4b17023SJohn Marino if (fmt_str == NULL)
13149e4b17023SJohn Marino return NULL_TREE;
13150e4b17023SJohn Marino if (strchr (fmt_str, target_percent) != NULL
13151e4b17023SJohn Marino && strcmp (fmt_str, target_percent_s))
13152e4b17023SJohn Marino return NULL_TREE;
13153e4b17023SJohn Marino }
13154e4b17023SJohn Marino
13155e4b17023SJohn Marino /* If __builtin_{,v}sprintf_chk is used, assume {,v}sprintf is available. */
13156e4b17023SJohn Marino fn = builtin_decl_explicit (fcode == BUILT_IN_VSPRINTF_CHK
13157e4b17023SJohn Marino ? BUILT_IN_VSPRINTF : BUILT_IN_SPRINTF);
13158e4b17023SJohn Marino if (!fn)
13159e4b17023SJohn Marino return NULL_TREE;
13160e4b17023SJohn Marino
13161e4b17023SJohn Marino return rewrite_call_expr_array (loc, nargs, args, 4, fn, 2, dest, fmt);
13162e4b17023SJohn Marino }
13163e4b17023SJohn Marino
13164e4b17023SJohn Marino /* Fold a call EXP to __{,v}sprintf_chk. Return NULL_TREE if
13165e4b17023SJohn Marino a normal call should be emitted rather than expanding the function
13166e4b17023SJohn Marino inline. FCODE is either BUILT_IN_SPRINTF_CHK or BUILT_IN_VSPRINTF_CHK. */
13167e4b17023SJohn Marino
13168e4b17023SJohn Marino static tree
fold_builtin_sprintf_chk(location_t loc,tree exp,enum built_in_function fcode)13169e4b17023SJohn Marino fold_builtin_sprintf_chk (location_t loc, tree exp,
13170e4b17023SJohn Marino enum built_in_function fcode)
13171e4b17023SJohn Marino {
13172e4b17023SJohn Marino return fold_builtin_sprintf_chk_1 (loc, call_expr_nargs (exp),
13173e4b17023SJohn Marino CALL_EXPR_ARGP (exp), fcode);
13174e4b17023SJohn Marino }
13175e4b17023SJohn Marino
13176e4b17023SJohn Marino /* Fold a call EXP to {,v}snprintf having NARGS passed as ARGS. Return
13177e4b17023SJohn Marino NULL_TREE if a normal call should be emitted rather than expanding
13178e4b17023SJohn Marino the function inline. FCODE is either BUILT_IN_SNPRINTF_CHK or
13179e4b17023SJohn Marino BUILT_IN_VSNPRINTF_CHK. If MAXLEN is not NULL, it is maximum length
13180e4b17023SJohn Marino passed as second argument. */
13181e4b17023SJohn Marino
13182e4b17023SJohn Marino static tree
fold_builtin_snprintf_chk_1(location_t loc,int nargs,tree * args,tree maxlen,enum built_in_function fcode)13183e4b17023SJohn Marino fold_builtin_snprintf_chk_1 (location_t loc, int nargs, tree *args,
13184e4b17023SJohn Marino tree maxlen, enum built_in_function fcode)
13185e4b17023SJohn Marino {
13186e4b17023SJohn Marino tree dest, size, len, fn, fmt, flag;
13187e4b17023SJohn Marino const char *fmt_str;
13188e4b17023SJohn Marino
13189e4b17023SJohn Marino /* Verify the required arguments in the original call. */
13190e4b17023SJohn Marino if (nargs < 5)
13191e4b17023SJohn Marino return NULL_TREE;
13192e4b17023SJohn Marino dest = args[0];
13193e4b17023SJohn Marino if (!validate_arg (dest, POINTER_TYPE))
13194e4b17023SJohn Marino return NULL_TREE;
13195e4b17023SJohn Marino len = args[1];
13196e4b17023SJohn Marino if (!validate_arg (len, INTEGER_TYPE))
13197e4b17023SJohn Marino return NULL_TREE;
13198e4b17023SJohn Marino flag = args[2];
13199e4b17023SJohn Marino if (!validate_arg (flag, INTEGER_TYPE))
13200e4b17023SJohn Marino return NULL_TREE;
13201e4b17023SJohn Marino size = args[3];
13202e4b17023SJohn Marino if (!validate_arg (size, INTEGER_TYPE))
13203e4b17023SJohn Marino return NULL_TREE;
13204e4b17023SJohn Marino fmt = args[4];
13205e4b17023SJohn Marino if (!validate_arg (fmt, POINTER_TYPE))
13206e4b17023SJohn Marino return NULL_TREE;
13207e4b17023SJohn Marino
13208e4b17023SJohn Marino if (! host_integerp (size, 1))
13209e4b17023SJohn Marino return NULL_TREE;
13210e4b17023SJohn Marino
13211e4b17023SJohn Marino if (! integer_all_onesp (size))
13212e4b17023SJohn Marino {
13213e4b17023SJohn Marino if (! host_integerp (len, 1))
13214e4b17023SJohn Marino {
13215e4b17023SJohn Marino /* If LEN is not constant, try MAXLEN too.
13216e4b17023SJohn Marino For MAXLEN only allow optimizing into non-_ocs function
13217e4b17023SJohn Marino if SIZE is >= MAXLEN, never convert to __ocs_fail (). */
13218e4b17023SJohn Marino if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
13219e4b17023SJohn Marino return NULL_TREE;
13220e4b17023SJohn Marino }
13221e4b17023SJohn Marino else
13222e4b17023SJohn Marino maxlen = len;
13223e4b17023SJohn Marino
13224e4b17023SJohn Marino if (tree_int_cst_lt (size, maxlen))
13225e4b17023SJohn Marino return NULL_TREE;
13226e4b17023SJohn Marino }
13227e4b17023SJohn Marino
13228e4b17023SJohn Marino if (!init_target_chars ())
13229e4b17023SJohn Marino return NULL_TREE;
13230e4b17023SJohn Marino
13231e4b17023SJohn Marino /* Only convert __{,v}snprintf_chk to {,v}snprintf if flag is 0
13232e4b17023SJohn Marino or if format doesn't contain % chars or is "%s". */
13233e4b17023SJohn Marino if (! integer_zerop (flag))
13234e4b17023SJohn Marino {
13235e4b17023SJohn Marino fmt_str = c_getstr (fmt);
13236e4b17023SJohn Marino if (fmt_str == NULL)
13237e4b17023SJohn Marino return NULL_TREE;
13238e4b17023SJohn Marino if (strchr (fmt_str, target_percent) != NULL
13239e4b17023SJohn Marino && strcmp (fmt_str, target_percent_s))
13240e4b17023SJohn Marino return NULL_TREE;
13241e4b17023SJohn Marino }
13242e4b17023SJohn Marino
13243e4b17023SJohn Marino /* If __builtin_{,v}snprintf_chk is used, assume {,v}snprintf is
13244e4b17023SJohn Marino available. */
13245e4b17023SJohn Marino fn = builtin_decl_explicit (fcode == BUILT_IN_VSNPRINTF_CHK
13246e4b17023SJohn Marino ? BUILT_IN_VSNPRINTF : BUILT_IN_SNPRINTF);
13247e4b17023SJohn Marino if (!fn)
13248e4b17023SJohn Marino return NULL_TREE;
13249e4b17023SJohn Marino
13250e4b17023SJohn Marino return rewrite_call_expr_array (loc, nargs, args, 5, fn, 3, dest, len, fmt);
13251e4b17023SJohn Marino }
13252e4b17023SJohn Marino
13253e4b17023SJohn Marino /* Fold a call EXP to {,v}snprintf. Return NULL_TREE if
13254e4b17023SJohn Marino a normal call should be emitted rather than expanding the function
13255e4b17023SJohn Marino inline. FCODE is either BUILT_IN_SNPRINTF_CHK or
13256e4b17023SJohn Marino BUILT_IN_VSNPRINTF_CHK. If MAXLEN is not NULL, it is maximum length
13257e4b17023SJohn Marino passed as second argument. */
13258e4b17023SJohn Marino
13259e4b17023SJohn Marino tree
fold_builtin_snprintf_chk(location_t loc,tree exp,tree maxlen,enum built_in_function fcode)13260e4b17023SJohn Marino fold_builtin_snprintf_chk (location_t loc, tree exp, tree maxlen,
13261e4b17023SJohn Marino enum built_in_function fcode)
13262e4b17023SJohn Marino {
13263e4b17023SJohn Marino return fold_builtin_snprintf_chk_1 (loc, call_expr_nargs (exp),
13264e4b17023SJohn Marino CALL_EXPR_ARGP (exp), maxlen, fcode);
13265e4b17023SJohn Marino }
13266e4b17023SJohn Marino
13267e4b17023SJohn Marino /* Fold a call to the {,v}printf{,_unlocked} and __{,v}printf_chk builtins.
13268e4b17023SJohn Marino FMT and ARG are the arguments to the call; we don't fold cases with
13269e4b17023SJohn Marino more than 2 arguments, and ARG may be null if this is a 1-argument case.
13270e4b17023SJohn Marino
13271e4b17023SJohn Marino Return NULL_TREE if no simplification was possible, otherwise return the
13272e4b17023SJohn Marino simplified form of the call as a tree. FCODE is the BUILT_IN_*
13273e4b17023SJohn Marino code of the function to be simplified. */
13274e4b17023SJohn Marino
13275e4b17023SJohn Marino static tree
fold_builtin_printf(location_t loc,tree fndecl,tree fmt,tree arg,bool ignore,enum built_in_function fcode)13276e4b17023SJohn Marino fold_builtin_printf (location_t loc, tree fndecl, tree fmt,
13277e4b17023SJohn Marino tree arg, bool ignore,
13278e4b17023SJohn Marino enum built_in_function fcode)
13279e4b17023SJohn Marino {
13280e4b17023SJohn Marino tree fn_putchar, fn_puts, newarg, call = NULL_TREE;
13281e4b17023SJohn Marino const char *fmt_str = NULL;
13282e4b17023SJohn Marino
13283e4b17023SJohn Marino /* If the return value is used, don't do the transformation. */
13284e4b17023SJohn Marino if (! ignore)
13285e4b17023SJohn Marino return NULL_TREE;
13286e4b17023SJohn Marino
13287e4b17023SJohn Marino /* Verify the required arguments in the original call. */
13288e4b17023SJohn Marino if (!validate_arg (fmt, POINTER_TYPE))
13289e4b17023SJohn Marino return NULL_TREE;
13290e4b17023SJohn Marino
13291e4b17023SJohn Marino /* Check whether the format is a literal string constant. */
13292e4b17023SJohn Marino fmt_str = c_getstr (fmt);
13293e4b17023SJohn Marino if (fmt_str == NULL)
13294e4b17023SJohn Marino return NULL_TREE;
13295e4b17023SJohn Marino
13296e4b17023SJohn Marino if (fcode == BUILT_IN_PRINTF_UNLOCKED)
13297e4b17023SJohn Marino {
13298e4b17023SJohn Marino /* If we're using an unlocked function, assume the other
13299e4b17023SJohn Marino unlocked functions exist explicitly. */
13300e4b17023SJohn Marino fn_putchar = builtin_decl_explicit (BUILT_IN_PUTCHAR_UNLOCKED);
13301e4b17023SJohn Marino fn_puts = builtin_decl_explicit (BUILT_IN_PUTS_UNLOCKED);
13302e4b17023SJohn Marino }
13303e4b17023SJohn Marino else
13304e4b17023SJohn Marino {
13305e4b17023SJohn Marino fn_putchar = builtin_decl_implicit (BUILT_IN_PUTCHAR);
13306e4b17023SJohn Marino fn_puts = builtin_decl_implicit (BUILT_IN_PUTS);
13307e4b17023SJohn Marino }
13308e4b17023SJohn Marino
13309e4b17023SJohn Marino if (!init_target_chars ())
13310e4b17023SJohn Marino return NULL_TREE;
13311e4b17023SJohn Marino
13312e4b17023SJohn Marino if (strcmp (fmt_str, target_percent_s) == 0
13313e4b17023SJohn Marino || strchr (fmt_str, target_percent) == NULL)
13314e4b17023SJohn Marino {
13315e4b17023SJohn Marino const char *str;
13316e4b17023SJohn Marino
13317e4b17023SJohn Marino if (strcmp (fmt_str, target_percent_s) == 0)
13318e4b17023SJohn Marino {
13319e4b17023SJohn Marino if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK)
13320e4b17023SJohn Marino return NULL_TREE;
13321e4b17023SJohn Marino
13322e4b17023SJohn Marino if (!arg || !validate_arg (arg, POINTER_TYPE))
13323e4b17023SJohn Marino return NULL_TREE;
13324e4b17023SJohn Marino
13325e4b17023SJohn Marino str = c_getstr (arg);
13326e4b17023SJohn Marino if (str == NULL)
13327e4b17023SJohn Marino return NULL_TREE;
13328e4b17023SJohn Marino }
13329e4b17023SJohn Marino else
13330e4b17023SJohn Marino {
13331e4b17023SJohn Marino /* The format specifier doesn't contain any '%' characters. */
13332e4b17023SJohn Marino if (fcode != BUILT_IN_VPRINTF && fcode != BUILT_IN_VPRINTF_CHK
13333e4b17023SJohn Marino && arg)
13334e4b17023SJohn Marino return NULL_TREE;
13335e4b17023SJohn Marino str = fmt_str;
13336e4b17023SJohn Marino }
13337e4b17023SJohn Marino
13338e4b17023SJohn Marino /* If the string was "", printf does nothing. */
13339e4b17023SJohn Marino if (str[0] == '\0')
13340e4b17023SJohn Marino return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), 0);
13341e4b17023SJohn Marino
13342e4b17023SJohn Marino /* If the string has length of 1, call putchar. */
13343e4b17023SJohn Marino if (str[1] == '\0')
13344e4b17023SJohn Marino {
13345e4b17023SJohn Marino /* Given printf("c"), (where c is any one character,)
13346e4b17023SJohn Marino convert "c"[0] to an int and pass that to the replacement
13347e4b17023SJohn Marino function. */
13348e4b17023SJohn Marino newarg = build_int_cst (integer_type_node, str[0]);
13349e4b17023SJohn Marino if (fn_putchar)
13350e4b17023SJohn Marino call = build_call_expr_loc (loc, fn_putchar, 1, newarg);
13351e4b17023SJohn Marino }
13352e4b17023SJohn Marino else
13353e4b17023SJohn Marino {
13354e4b17023SJohn Marino /* If the string was "string\n", call puts("string"). */
13355e4b17023SJohn Marino size_t len = strlen (str);
13356e4b17023SJohn Marino if ((unsigned char)str[len - 1] == target_newline
13357e4b17023SJohn Marino && (size_t) (int) len == len
13358e4b17023SJohn Marino && (int) len > 0)
13359e4b17023SJohn Marino {
13360e4b17023SJohn Marino char *newstr;
13361e4b17023SJohn Marino tree offset_node, string_cst;
13362e4b17023SJohn Marino
13363e4b17023SJohn Marino /* Create a NUL-terminated string that's one char shorter
13364e4b17023SJohn Marino than the original, stripping off the trailing '\n'. */
13365e4b17023SJohn Marino newarg = build_string_literal (len, str);
13366e4b17023SJohn Marino string_cst = string_constant (newarg, &offset_node);
13367e4b17023SJohn Marino gcc_checking_assert (string_cst
13368e4b17023SJohn Marino && (TREE_STRING_LENGTH (string_cst)
13369e4b17023SJohn Marino == (int) len)
13370e4b17023SJohn Marino && integer_zerop (offset_node)
13371e4b17023SJohn Marino && (unsigned char)
13372e4b17023SJohn Marino TREE_STRING_POINTER (string_cst)[len - 1]
13373e4b17023SJohn Marino == target_newline);
13374e4b17023SJohn Marino /* build_string_literal creates a new STRING_CST,
13375e4b17023SJohn Marino modify it in place to avoid double copying. */
13376e4b17023SJohn Marino newstr = CONST_CAST (char *, TREE_STRING_POINTER (string_cst));
13377e4b17023SJohn Marino newstr[len - 1] = '\0';
13378e4b17023SJohn Marino if (fn_puts)
13379e4b17023SJohn Marino call = build_call_expr_loc (loc, fn_puts, 1, newarg);
13380e4b17023SJohn Marino }
13381e4b17023SJohn Marino else
13382e4b17023SJohn Marino /* We'd like to arrange to call fputs(string,stdout) here,
13383e4b17023SJohn Marino but we need stdout and don't have a way to get it yet. */
13384e4b17023SJohn Marino return NULL_TREE;
13385e4b17023SJohn Marino }
13386e4b17023SJohn Marino }
13387e4b17023SJohn Marino
13388e4b17023SJohn Marino /* The other optimizations can be done only on the non-va_list variants. */
13389e4b17023SJohn Marino else if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK)
13390e4b17023SJohn Marino return NULL_TREE;
13391e4b17023SJohn Marino
13392e4b17023SJohn Marino /* If the format specifier was "%s\n", call __builtin_puts(arg). */
13393e4b17023SJohn Marino else if (strcmp (fmt_str, target_percent_s_newline) == 0)
13394e4b17023SJohn Marino {
13395e4b17023SJohn Marino if (!arg || !validate_arg (arg, POINTER_TYPE))
13396e4b17023SJohn Marino return NULL_TREE;
13397e4b17023SJohn Marino if (fn_puts)
13398e4b17023SJohn Marino call = build_call_expr_loc (loc, fn_puts, 1, arg);
13399e4b17023SJohn Marino }
13400e4b17023SJohn Marino
13401e4b17023SJohn Marino /* If the format specifier was "%c", call __builtin_putchar(arg). */
13402e4b17023SJohn Marino else if (strcmp (fmt_str, target_percent_c) == 0)
13403e4b17023SJohn Marino {
13404e4b17023SJohn Marino if (!arg || !validate_arg (arg, INTEGER_TYPE))
13405e4b17023SJohn Marino return NULL_TREE;
13406e4b17023SJohn Marino if (fn_putchar)
13407e4b17023SJohn Marino call = build_call_expr_loc (loc, fn_putchar, 1, arg);
13408e4b17023SJohn Marino }
13409e4b17023SJohn Marino
13410e4b17023SJohn Marino if (!call)
13411e4b17023SJohn Marino return NULL_TREE;
13412e4b17023SJohn Marino
13413e4b17023SJohn Marino return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), call);
13414e4b17023SJohn Marino }
13415e4b17023SJohn Marino
13416e4b17023SJohn Marino /* Fold a call to the {,v}fprintf{,_unlocked} and __{,v}printf_chk builtins.
13417e4b17023SJohn Marino FP, FMT, and ARG are the arguments to the call. We don't fold calls with
13418e4b17023SJohn Marino more than 3 arguments, and ARG may be null in the 2-argument case.
13419e4b17023SJohn Marino
13420e4b17023SJohn Marino Return NULL_TREE if no simplification was possible, otherwise return the
13421e4b17023SJohn Marino simplified form of the call as a tree. FCODE is the BUILT_IN_*
13422e4b17023SJohn Marino code of the function to be simplified. */
13423e4b17023SJohn Marino
13424e4b17023SJohn Marino static tree
fold_builtin_fprintf(location_t loc,tree fndecl,tree fp,tree fmt,tree arg,bool ignore,enum built_in_function fcode)13425e4b17023SJohn Marino fold_builtin_fprintf (location_t loc, tree fndecl, tree fp,
13426e4b17023SJohn Marino tree fmt, tree arg, bool ignore,
13427e4b17023SJohn Marino enum built_in_function fcode)
13428e4b17023SJohn Marino {
13429e4b17023SJohn Marino tree fn_fputc, fn_fputs, call = NULL_TREE;
13430e4b17023SJohn Marino const char *fmt_str = NULL;
13431e4b17023SJohn Marino
13432e4b17023SJohn Marino /* If the return value is used, don't do the transformation. */
13433e4b17023SJohn Marino if (! ignore)
13434e4b17023SJohn Marino return NULL_TREE;
13435e4b17023SJohn Marino
13436e4b17023SJohn Marino /* Verify the required arguments in the original call. */
13437e4b17023SJohn Marino if (!validate_arg (fp, POINTER_TYPE))
13438e4b17023SJohn Marino return NULL_TREE;
13439e4b17023SJohn Marino if (!validate_arg (fmt, POINTER_TYPE))
13440e4b17023SJohn Marino return NULL_TREE;
13441e4b17023SJohn Marino
13442e4b17023SJohn Marino /* Check whether the format is a literal string constant. */
13443e4b17023SJohn Marino fmt_str = c_getstr (fmt);
13444e4b17023SJohn Marino if (fmt_str == NULL)
13445e4b17023SJohn Marino return NULL_TREE;
13446e4b17023SJohn Marino
13447e4b17023SJohn Marino if (fcode == BUILT_IN_FPRINTF_UNLOCKED)
13448e4b17023SJohn Marino {
13449e4b17023SJohn Marino /* If we're using an unlocked function, assume the other
13450e4b17023SJohn Marino unlocked functions exist explicitly. */
13451e4b17023SJohn Marino fn_fputc = builtin_decl_explicit (BUILT_IN_FPUTC_UNLOCKED);
13452e4b17023SJohn Marino fn_fputs = builtin_decl_explicit (BUILT_IN_FPUTS_UNLOCKED);
13453e4b17023SJohn Marino }
13454e4b17023SJohn Marino else
13455e4b17023SJohn Marino {
13456e4b17023SJohn Marino fn_fputc = builtin_decl_implicit (BUILT_IN_FPUTC);
13457e4b17023SJohn Marino fn_fputs = builtin_decl_implicit (BUILT_IN_FPUTS);
13458e4b17023SJohn Marino }
13459e4b17023SJohn Marino
13460e4b17023SJohn Marino if (!init_target_chars ())
13461e4b17023SJohn Marino return NULL_TREE;
13462e4b17023SJohn Marino
13463e4b17023SJohn Marino /* If the format doesn't contain % args or %%, use strcpy. */
13464e4b17023SJohn Marino if (strchr (fmt_str, target_percent) == NULL)
13465e4b17023SJohn Marino {
13466e4b17023SJohn Marino if (fcode != BUILT_IN_VFPRINTF && fcode != BUILT_IN_VFPRINTF_CHK
13467e4b17023SJohn Marino && arg)
13468e4b17023SJohn Marino return NULL_TREE;
13469e4b17023SJohn Marino
13470e4b17023SJohn Marino /* If the format specifier was "", fprintf does nothing. */
13471e4b17023SJohn Marino if (fmt_str[0] == '\0')
13472e4b17023SJohn Marino {
13473e4b17023SJohn Marino /* If FP has side-effects, just wait until gimplification is
13474e4b17023SJohn Marino done. */
13475e4b17023SJohn Marino if (TREE_SIDE_EFFECTS (fp))
13476e4b17023SJohn Marino return NULL_TREE;
13477e4b17023SJohn Marino
13478e4b17023SJohn Marino return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), 0);
13479e4b17023SJohn Marino }
13480e4b17023SJohn Marino
13481e4b17023SJohn Marino /* When "string" doesn't contain %, replace all cases of
13482e4b17023SJohn Marino fprintf (fp, string) with fputs (string, fp). The fputs
13483e4b17023SJohn Marino builtin will take care of special cases like length == 1. */
13484e4b17023SJohn Marino if (fn_fputs)
13485e4b17023SJohn Marino call = build_call_expr_loc (loc, fn_fputs, 2, fmt, fp);
13486e4b17023SJohn Marino }
13487e4b17023SJohn Marino
13488e4b17023SJohn Marino /* The other optimizations can be done only on the non-va_list variants. */
13489e4b17023SJohn Marino else if (fcode == BUILT_IN_VFPRINTF || fcode == BUILT_IN_VFPRINTF_CHK)
13490e4b17023SJohn Marino return NULL_TREE;
13491e4b17023SJohn Marino
13492e4b17023SJohn Marino /* If the format specifier was "%s", call __builtin_fputs (arg, fp). */
13493e4b17023SJohn Marino else if (strcmp (fmt_str, target_percent_s) == 0)
13494e4b17023SJohn Marino {
13495e4b17023SJohn Marino if (!arg || !validate_arg (arg, POINTER_TYPE))
13496e4b17023SJohn Marino return NULL_TREE;
13497e4b17023SJohn Marino if (fn_fputs)
13498e4b17023SJohn Marino call = build_call_expr_loc (loc, fn_fputs, 2, arg, fp);
13499e4b17023SJohn Marino }
13500e4b17023SJohn Marino
13501e4b17023SJohn Marino /* If the format specifier was "%c", call __builtin_fputc (arg, fp). */
13502e4b17023SJohn Marino else if (strcmp (fmt_str, target_percent_c) == 0)
13503e4b17023SJohn Marino {
13504e4b17023SJohn Marino if (!arg || !validate_arg (arg, INTEGER_TYPE))
13505e4b17023SJohn Marino return NULL_TREE;
13506e4b17023SJohn Marino if (fn_fputc)
13507e4b17023SJohn Marino call = build_call_expr_loc (loc, fn_fputc, 2, arg, fp);
13508e4b17023SJohn Marino }
13509e4b17023SJohn Marino
13510e4b17023SJohn Marino if (!call)
13511e4b17023SJohn Marino return NULL_TREE;
13512e4b17023SJohn Marino return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), call);
13513e4b17023SJohn Marino }
13514e4b17023SJohn Marino
13515e4b17023SJohn Marino /* Initialize format string characters in the target charset. */
13516e4b17023SJohn Marino
13517e4b17023SJohn Marino static bool
init_target_chars(void)13518e4b17023SJohn Marino init_target_chars (void)
13519e4b17023SJohn Marino {
13520e4b17023SJohn Marino static bool init;
13521e4b17023SJohn Marino if (!init)
13522e4b17023SJohn Marino {
13523e4b17023SJohn Marino target_newline = lang_hooks.to_target_charset ('\n');
13524e4b17023SJohn Marino target_percent = lang_hooks.to_target_charset ('%');
13525e4b17023SJohn Marino target_c = lang_hooks.to_target_charset ('c');
13526e4b17023SJohn Marino target_s = lang_hooks.to_target_charset ('s');
13527e4b17023SJohn Marino if (target_newline == 0 || target_percent == 0 || target_c == 0
13528e4b17023SJohn Marino || target_s == 0)
13529e4b17023SJohn Marino return false;
13530e4b17023SJohn Marino
13531e4b17023SJohn Marino target_percent_c[0] = target_percent;
13532e4b17023SJohn Marino target_percent_c[1] = target_c;
13533e4b17023SJohn Marino target_percent_c[2] = '\0';
13534e4b17023SJohn Marino
13535e4b17023SJohn Marino target_percent_s[0] = target_percent;
13536e4b17023SJohn Marino target_percent_s[1] = target_s;
13537e4b17023SJohn Marino target_percent_s[2] = '\0';
13538e4b17023SJohn Marino
13539e4b17023SJohn Marino target_percent_s_newline[0] = target_percent;
13540e4b17023SJohn Marino target_percent_s_newline[1] = target_s;
13541e4b17023SJohn Marino target_percent_s_newline[2] = target_newline;
13542e4b17023SJohn Marino target_percent_s_newline[3] = '\0';
13543e4b17023SJohn Marino
13544e4b17023SJohn Marino init = true;
13545e4b17023SJohn Marino }
13546e4b17023SJohn Marino return true;
13547e4b17023SJohn Marino }
13548e4b17023SJohn Marino
13549e4b17023SJohn Marino /* Helper function for do_mpfr_arg*(). Ensure M is a normal number
13550e4b17023SJohn Marino and no overflow/underflow occurred. INEXACT is true if M was not
13551e4b17023SJohn Marino exactly calculated. TYPE is the tree type for the result. This
13552e4b17023SJohn Marino function assumes that you cleared the MPFR flags and then
13553e4b17023SJohn Marino calculated M to see if anything subsequently set a flag prior to
13554e4b17023SJohn Marino entering this function. Return NULL_TREE if any checks fail. */
13555e4b17023SJohn Marino
13556e4b17023SJohn Marino static tree
do_mpfr_ckconv(mpfr_srcptr m,tree type,int inexact)13557e4b17023SJohn Marino do_mpfr_ckconv (mpfr_srcptr m, tree type, int inexact)
13558e4b17023SJohn Marino {
13559e4b17023SJohn Marino /* Proceed iff we get a normal number, i.e. not NaN or Inf and no
13560e4b17023SJohn Marino overflow/underflow occurred. If -frounding-math, proceed iff the
13561e4b17023SJohn Marino result of calling FUNC was exact. */
13562e4b17023SJohn Marino if (mpfr_number_p (m) && !mpfr_overflow_p () && !mpfr_underflow_p ()
13563e4b17023SJohn Marino && (!flag_rounding_math || !inexact))
13564e4b17023SJohn Marino {
13565e4b17023SJohn Marino REAL_VALUE_TYPE rr;
13566e4b17023SJohn Marino
13567e4b17023SJohn Marino real_from_mpfr (&rr, m, type, GMP_RNDN);
13568e4b17023SJohn Marino /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR value,
13569e4b17023SJohn Marino check for overflow/underflow. If the REAL_VALUE_TYPE is zero
13570e4b17023SJohn Marino but the mpft_t is not, then we underflowed in the
13571e4b17023SJohn Marino conversion. */
13572e4b17023SJohn Marino if (real_isfinite (&rr)
13573e4b17023SJohn Marino && (rr.cl == rvc_zero) == (mpfr_zero_p (m) != 0))
13574e4b17023SJohn Marino {
13575e4b17023SJohn Marino REAL_VALUE_TYPE rmode;
13576e4b17023SJohn Marino
13577e4b17023SJohn Marino real_convert (&rmode, TYPE_MODE (type), &rr);
13578e4b17023SJohn Marino /* Proceed iff the specified mode can hold the value. */
13579e4b17023SJohn Marino if (real_identical (&rmode, &rr))
13580e4b17023SJohn Marino return build_real (type, rmode);
13581e4b17023SJohn Marino }
13582e4b17023SJohn Marino }
13583e4b17023SJohn Marino return NULL_TREE;
13584e4b17023SJohn Marino }
13585e4b17023SJohn Marino
13586e4b17023SJohn Marino /* Helper function for do_mpc_arg*(). Ensure M is a normal complex
13587e4b17023SJohn Marino number and no overflow/underflow occurred. INEXACT is true if M
13588e4b17023SJohn Marino was not exactly calculated. TYPE is the tree type for the result.
13589e4b17023SJohn Marino This function assumes that you cleared the MPFR flags and then
13590e4b17023SJohn Marino calculated M to see if anything subsequently set a flag prior to
13591e4b17023SJohn Marino entering this function. Return NULL_TREE if any checks fail, if
13592e4b17023SJohn Marino FORCE_CONVERT is true, then bypass the checks. */
13593e4b17023SJohn Marino
13594e4b17023SJohn Marino static tree
do_mpc_ckconv(mpc_srcptr m,tree type,int inexact,int force_convert)13595e4b17023SJohn Marino do_mpc_ckconv (mpc_srcptr m, tree type, int inexact, int force_convert)
13596e4b17023SJohn Marino {
13597e4b17023SJohn Marino /* Proceed iff we get a normal number, i.e. not NaN or Inf and no
13598e4b17023SJohn Marino overflow/underflow occurred. If -frounding-math, proceed iff the
13599e4b17023SJohn Marino result of calling FUNC was exact. */
13600e4b17023SJohn Marino if (force_convert
13601e4b17023SJohn Marino || (mpfr_number_p (mpc_realref (m)) && mpfr_number_p (mpc_imagref (m))
13602e4b17023SJohn Marino && !mpfr_overflow_p () && !mpfr_underflow_p ()
13603e4b17023SJohn Marino && (!flag_rounding_math || !inexact)))
13604e4b17023SJohn Marino {
13605e4b17023SJohn Marino REAL_VALUE_TYPE re, im;
13606e4b17023SJohn Marino
13607e4b17023SJohn Marino real_from_mpfr (&re, mpc_realref (m), TREE_TYPE (type), GMP_RNDN);
13608e4b17023SJohn Marino real_from_mpfr (&im, mpc_imagref (m), TREE_TYPE (type), GMP_RNDN);
13609e4b17023SJohn Marino /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR values,
13610e4b17023SJohn Marino check for overflow/underflow. If the REAL_VALUE_TYPE is zero
13611e4b17023SJohn Marino but the mpft_t is not, then we underflowed in the
13612e4b17023SJohn Marino conversion. */
13613e4b17023SJohn Marino if (force_convert
13614e4b17023SJohn Marino || (real_isfinite (&re) && real_isfinite (&im)
13615e4b17023SJohn Marino && (re.cl == rvc_zero) == (mpfr_zero_p (mpc_realref (m)) != 0)
13616e4b17023SJohn Marino && (im.cl == rvc_zero) == (mpfr_zero_p (mpc_imagref (m)) != 0)))
13617e4b17023SJohn Marino {
13618e4b17023SJohn Marino REAL_VALUE_TYPE re_mode, im_mode;
13619e4b17023SJohn Marino
13620e4b17023SJohn Marino real_convert (&re_mode, TYPE_MODE (TREE_TYPE (type)), &re);
13621e4b17023SJohn Marino real_convert (&im_mode, TYPE_MODE (TREE_TYPE (type)), &im);
13622e4b17023SJohn Marino /* Proceed iff the specified mode can hold the value. */
13623e4b17023SJohn Marino if (force_convert
13624e4b17023SJohn Marino || (real_identical (&re_mode, &re)
13625e4b17023SJohn Marino && real_identical (&im_mode, &im)))
13626e4b17023SJohn Marino return build_complex (type, build_real (TREE_TYPE (type), re_mode),
13627e4b17023SJohn Marino build_real (TREE_TYPE (type), im_mode));
13628e4b17023SJohn Marino }
13629e4b17023SJohn Marino }
13630e4b17023SJohn Marino return NULL_TREE;
13631e4b17023SJohn Marino }
13632e4b17023SJohn Marino
13633e4b17023SJohn Marino /* If argument ARG is a REAL_CST, call the one-argument mpfr function
13634e4b17023SJohn Marino FUNC on it and return the resulting value as a tree with type TYPE.
13635e4b17023SJohn Marino If MIN and/or MAX are not NULL, then the supplied ARG must be
13636e4b17023SJohn Marino within those bounds. If INCLUSIVE is true, then MIN/MAX are
13637e4b17023SJohn Marino acceptable values, otherwise they are not. The mpfr precision is
13638e4b17023SJohn Marino set to the precision of TYPE. We assume that function FUNC returns
13639e4b17023SJohn Marino zero if the result could be calculated exactly within the requested
13640e4b17023SJohn Marino precision. */
13641e4b17023SJohn Marino
13642e4b17023SJohn Marino static tree
do_mpfr_arg1(tree arg,tree type,int (* func)(mpfr_ptr,mpfr_srcptr,mp_rnd_t),const REAL_VALUE_TYPE * min,const REAL_VALUE_TYPE * max,bool inclusive)13643e4b17023SJohn Marino do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
13644e4b17023SJohn Marino const REAL_VALUE_TYPE *min, const REAL_VALUE_TYPE *max,
13645e4b17023SJohn Marino bool inclusive)
13646e4b17023SJohn Marino {
13647e4b17023SJohn Marino tree result = NULL_TREE;
13648e4b17023SJohn Marino
13649e4b17023SJohn Marino STRIP_NOPS (arg);
13650e4b17023SJohn Marino
13651e4b17023SJohn Marino /* To proceed, MPFR must exactly represent the target floating point
13652e4b17023SJohn Marino format, which only happens when the target base equals two. */
13653e4b17023SJohn Marino if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
13654e4b17023SJohn Marino && TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg))
13655e4b17023SJohn Marino {
13656e4b17023SJohn Marino const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg);
13657e4b17023SJohn Marino
13658e4b17023SJohn Marino if (real_isfinite (ra)
13659e4b17023SJohn Marino && (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , ra, min))
13660e4b17023SJohn Marino && (!max || real_compare (inclusive ? LE_EXPR: LT_EXPR , ra, max)))
13661e4b17023SJohn Marino {
13662e4b17023SJohn Marino const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
13663e4b17023SJohn Marino const int prec = fmt->p;
13664e4b17023SJohn Marino const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
13665e4b17023SJohn Marino int inexact;
13666e4b17023SJohn Marino mpfr_t m;
13667e4b17023SJohn Marino
13668e4b17023SJohn Marino mpfr_init2 (m, prec);
13669e4b17023SJohn Marino mpfr_from_real (m, ra, GMP_RNDN);
13670e4b17023SJohn Marino mpfr_clear_flags ();
13671e4b17023SJohn Marino inexact = func (m, m, rnd);
13672e4b17023SJohn Marino result = do_mpfr_ckconv (m, type, inexact);
13673e4b17023SJohn Marino mpfr_clear (m);
13674e4b17023SJohn Marino }
13675e4b17023SJohn Marino }
13676e4b17023SJohn Marino
13677e4b17023SJohn Marino return result;
13678e4b17023SJohn Marino }
13679e4b17023SJohn Marino
13680e4b17023SJohn Marino /* If argument ARG is a REAL_CST, call the two-argument mpfr function
13681e4b17023SJohn Marino FUNC on it and return the resulting value as a tree with type TYPE.
13682e4b17023SJohn Marino The mpfr precision is set to the precision of TYPE. We assume that
13683e4b17023SJohn Marino function FUNC returns zero if the result could be calculated
13684e4b17023SJohn Marino exactly within the requested precision. */
13685e4b17023SJohn Marino
13686e4b17023SJohn Marino static tree
do_mpfr_arg2(tree arg1,tree arg2,tree type,int (* func)(mpfr_ptr,mpfr_srcptr,mpfr_srcptr,mp_rnd_t))13687e4b17023SJohn Marino do_mpfr_arg2 (tree arg1, tree arg2, tree type,
13688e4b17023SJohn Marino int (*func)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t))
13689e4b17023SJohn Marino {
13690e4b17023SJohn Marino tree result = NULL_TREE;
13691e4b17023SJohn Marino
13692e4b17023SJohn Marino STRIP_NOPS (arg1);
13693e4b17023SJohn Marino STRIP_NOPS (arg2);
13694e4b17023SJohn Marino
13695e4b17023SJohn Marino /* To proceed, MPFR must exactly represent the target floating point
13696e4b17023SJohn Marino format, which only happens when the target base equals two. */
13697e4b17023SJohn Marino if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
13698e4b17023SJohn Marino && TREE_CODE (arg1) == REAL_CST && !TREE_OVERFLOW (arg1)
13699e4b17023SJohn Marino && TREE_CODE (arg2) == REAL_CST && !TREE_OVERFLOW (arg2))
13700e4b17023SJohn Marino {
13701e4b17023SJohn Marino const REAL_VALUE_TYPE *const ra1 = &TREE_REAL_CST (arg1);
13702e4b17023SJohn Marino const REAL_VALUE_TYPE *const ra2 = &TREE_REAL_CST (arg2);
13703e4b17023SJohn Marino
13704e4b17023SJohn Marino if (real_isfinite (ra1) && real_isfinite (ra2))
13705e4b17023SJohn Marino {
13706e4b17023SJohn Marino const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
13707e4b17023SJohn Marino const int prec = fmt->p;
13708e4b17023SJohn Marino const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
13709e4b17023SJohn Marino int inexact;
13710e4b17023SJohn Marino mpfr_t m1, m2;
13711e4b17023SJohn Marino
13712e4b17023SJohn Marino mpfr_inits2 (prec, m1, m2, NULL);
13713e4b17023SJohn Marino mpfr_from_real (m1, ra1, GMP_RNDN);
13714e4b17023SJohn Marino mpfr_from_real (m2, ra2, GMP_RNDN);
13715e4b17023SJohn Marino mpfr_clear_flags ();
13716e4b17023SJohn Marino inexact = func (m1, m1, m2, rnd);
13717e4b17023SJohn Marino result = do_mpfr_ckconv (m1, type, inexact);
13718e4b17023SJohn Marino mpfr_clears (m1, m2, NULL);
13719e4b17023SJohn Marino }
13720e4b17023SJohn Marino }
13721e4b17023SJohn Marino
13722e4b17023SJohn Marino return result;
13723e4b17023SJohn Marino }
13724e4b17023SJohn Marino
13725e4b17023SJohn Marino /* If argument ARG is a REAL_CST, call the three-argument mpfr function
13726e4b17023SJohn Marino FUNC on it and return the resulting value as a tree with type TYPE.
13727e4b17023SJohn Marino The mpfr precision is set to the precision of TYPE. We assume that
13728e4b17023SJohn Marino function FUNC returns zero if the result could be calculated
13729e4b17023SJohn Marino exactly within the requested precision. */
13730e4b17023SJohn Marino
13731e4b17023SJohn Marino static tree
do_mpfr_arg3(tree arg1,tree arg2,tree arg3,tree type,int (* func)(mpfr_ptr,mpfr_srcptr,mpfr_srcptr,mpfr_srcptr,mp_rnd_t))13732e4b17023SJohn Marino do_mpfr_arg3 (tree arg1, tree arg2, tree arg3, tree type,
13733e4b17023SJohn Marino int (*func)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t))
13734e4b17023SJohn Marino {
13735e4b17023SJohn Marino tree result = NULL_TREE;
13736e4b17023SJohn Marino
13737e4b17023SJohn Marino STRIP_NOPS (arg1);
13738e4b17023SJohn Marino STRIP_NOPS (arg2);
13739e4b17023SJohn Marino STRIP_NOPS (arg3);
13740e4b17023SJohn Marino
13741e4b17023SJohn Marino /* To proceed, MPFR must exactly represent the target floating point
13742e4b17023SJohn Marino format, which only happens when the target base equals two. */
13743e4b17023SJohn Marino if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
13744e4b17023SJohn Marino && TREE_CODE (arg1) == REAL_CST && !TREE_OVERFLOW (arg1)
13745e4b17023SJohn Marino && TREE_CODE (arg2) == REAL_CST && !TREE_OVERFLOW (arg2)
13746e4b17023SJohn Marino && TREE_CODE (arg3) == REAL_CST && !TREE_OVERFLOW (arg3))
13747e4b17023SJohn Marino {
13748e4b17023SJohn Marino const REAL_VALUE_TYPE *const ra1 = &TREE_REAL_CST (arg1);
13749e4b17023SJohn Marino const REAL_VALUE_TYPE *const ra2 = &TREE_REAL_CST (arg2);
13750e4b17023SJohn Marino const REAL_VALUE_TYPE *const ra3 = &TREE_REAL_CST (arg3);
13751e4b17023SJohn Marino
13752e4b17023SJohn Marino if (real_isfinite (ra1) && real_isfinite (ra2) && real_isfinite (ra3))
13753e4b17023SJohn Marino {
13754e4b17023SJohn Marino const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
13755e4b17023SJohn Marino const int prec = fmt->p;
13756e4b17023SJohn Marino const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
13757e4b17023SJohn Marino int inexact;
13758e4b17023SJohn Marino mpfr_t m1, m2, m3;
13759e4b17023SJohn Marino
13760e4b17023SJohn Marino mpfr_inits2 (prec, m1, m2, m3, NULL);
13761e4b17023SJohn Marino mpfr_from_real (m1, ra1, GMP_RNDN);
13762e4b17023SJohn Marino mpfr_from_real (m2, ra2, GMP_RNDN);
13763e4b17023SJohn Marino mpfr_from_real (m3, ra3, GMP_RNDN);
13764e4b17023SJohn Marino mpfr_clear_flags ();
13765e4b17023SJohn Marino inexact = func (m1, m1, m2, m3, rnd);
13766e4b17023SJohn Marino result = do_mpfr_ckconv (m1, type, inexact);
13767e4b17023SJohn Marino mpfr_clears (m1, m2, m3, NULL);
13768e4b17023SJohn Marino }
13769e4b17023SJohn Marino }
13770e4b17023SJohn Marino
13771e4b17023SJohn Marino return result;
13772e4b17023SJohn Marino }
13773e4b17023SJohn Marino
13774e4b17023SJohn Marino /* If argument ARG is a REAL_CST, call mpfr_sin_cos() on it and set
13775e4b17023SJohn Marino the pointers *(ARG_SINP) and *(ARG_COSP) to the resulting values.
13776e4b17023SJohn Marino If ARG_SINP and ARG_COSP are NULL then the result is returned
13777e4b17023SJohn Marino as a complex value.
13778e4b17023SJohn Marino The type is taken from the type of ARG and is used for setting the
13779e4b17023SJohn Marino precision of the calculation and results. */
13780e4b17023SJohn Marino
13781e4b17023SJohn Marino static tree
do_mpfr_sincos(tree arg,tree arg_sinp,tree arg_cosp)13782e4b17023SJohn Marino do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_cosp)
13783e4b17023SJohn Marino {
13784e4b17023SJohn Marino tree const type = TREE_TYPE (arg);
13785e4b17023SJohn Marino tree result = NULL_TREE;
13786e4b17023SJohn Marino
13787e4b17023SJohn Marino STRIP_NOPS (arg);
13788e4b17023SJohn Marino
13789e4b17023SJohn Marino /* To proceed, MPFR must exactly represent the target floating point
13790e4b17023SJohn Marino format, which only happens when the target base equals two. */
13791e4b17023SJohn Marino if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
13792e4b17023SJohn Marino && TREE_CODE (arg) == REAL_CST
13793e4b17023SJohn Marino && !TREE_OVERFLOW (arg))
13794e4b17023SJohn Marino {
13795e4b17023SJohn Marino const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg);
13796e4b17023SJohn Marino
13797e4b17023SJohn Marino if (real_isfinite (ra))
13798e4b17023SJohn Marino {
13799e4b17023SJohn Marino const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
13800e4b17023SJohn Marino const int prec = fmt->p;
13801e4b17023SJohn Marino const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
13802e4b17023SJohn Marino tree result_s, result_c;
13803e4b17023SJohn Marino int inexact;
13804e4b17023SJohn Marino mpfr_t m, ms, mc;
13805e4b17023SJohn Marino
13806e4b17023SJohn Marino mpfr_inits2 (prec, m, ms, mc, NULL);
13807e4b17023SJohn Marino mpfr_from_real (m, ra, GMP_RNDN);
13808e4b17023SJohn Marino mpfr_clear_flags ();
13809e4b17023SJohn Marino inexact = mpfr_sin_cos (ms, mc, m, rnd);
13810e4b17023SJohn Marino result_s = do_mpfr_ckconv (ms, type, inexact);
13811e4b17023SJohn Marino result_c = do_mpfr_ckconv (mc, type, inexact);
13812e4b17023SJohn Marino mpfr_clears (m, ms, mc, NULL);
13813e4b17023SJohn Marino if (result_s && result_c)
13814e4b17023SJohn Marino {
13815e4b17023SJohn Marino /* If we are to return in a complex value do so. */
13816e4b17023SJohn Marino if (!arg_sinp && !arg_cosp)
13817e4b17023SJohn Marino return build_complex (build_complex_type (type),
13818e4b17023SJohn Marino result_c, result_s);
13819e4b17023SJohn Marino
13820e4b17023SJohn Marino /* Dereference the sin/cos pointer arguments. */
13821e4b17023SJohn Marino arg_sinp = build_fold_indirect_ref (arg_sinp);
13822e4b17023SJohn Marino arg_cosp = build_fold_indirect_ref (arg_cosp);
13823e4b17023SJohn Marino /* Proceed if valid pointer type were passed in. */
13824e4b17023SJohn Marino if (TYPE_MAIN_VARIANT (TREE_TYPE (arg_sinp)) == TYPE_MAIN_VARIANT (type)
13825e4b17023SJohn Marino && TYPE_MAIN_VARIANT (TREE_TYPE (arg_cosp)) == TYPE_MAIN_VARIANT (type))
13826e4b17023SJohn Marino {
13827e4b17023SJohn Marino /* Set the values. */
13828e4b17023SJohn Marino result_s = fold_build2 (MODIFY_EXPR, type, arg_sinp,
13829e4b17023SJohn Marino result_s);
13830e4b17023SJohn Marino TREE_SIDE_EFFECTS (result_s) = 1;
13831e4b17023SJohn Marino result_c = fold_build2 (MODIFY_EXPR, type, arg_cosp,
13832e4b17023SJohn Marino result_c);
13833e4b17023SJohn Marino TREE_SIDE_EFFECTS (result_c) = 1;
13834e4b17023SJohn Marino /* Combine the assignments into a compound expr. */
13835e4b17023SJohn Marino result = non_lvalue (fold_build2 (COMPOUND_EXPR, type,
13836e4b17023SJohn Marino result_s, result_c));
13837e4b17023SJohn Marino }
13838e4b17023SJohn Marino }
13839e4b17023SJohn Marino }
13840e4b17023SJohn Marino }
13841e4b17023SJohn Marino return result;
13842e4b17023SJohn Marino }
13843e4b17023SJohn Marino
13844e4b17023SJohn Marino /* If argument ARG1 is an INTEGER_CST and ARG2 is a REAL_CST, call the
13845e4b17023SJohn Marino two-argument mpfr order N Bessel function FUNC on them and return
13846e4b17023SJohn Marino the resulting value as a tree with type TYPE. The mpfr precision
13847e4b17023SJohn Marino is set to the precision of TYPE. We assume that function FUNC
13848e4b17023SJohn Marino returns zero if the result could be calculated exactly within the
13849e4b17023SJohn Marino requested precision. */
13850e4b17023SJohn Marino static tree
do_mpfr_bessel_n(tree arg1,tree arg2,tree type,int (* func)(mpfr_ptr,long,mpfr_srcptr,mp_rnd_t),const REAL_VALUE_TYPE * min,bool inclusive)13851e4b17023SJohn Marino do_mpfr_bessel_n (tree arg1, tree arg2, tree type,
13852e4b17023SJohn Marino int (*func)(mpfr_ptr, long, mpfr_srcptr, mp_rnd_t),
13853e4b17023SJohn Marino const REAL_VALUE_TYPE *min, bool inclusive)
13854e4b17023SJohn Marino {
13855e4b17023SJohn Marino tree result = NULL_TREE;
13856e4b17023SJohn Marino
13857e4b17023SJohn Marino STRIP_NOPS (arg1);
13858e4b17023SJohn Marino STRIP_NOPS (arg2);
13859e4b17023SJohn Marino
13860e4b17023SJohn Marino /* To proceed, MPFR must exactly represent the target floating point
13861e4b17023SJohn Marino format, which only happens when the target base equals two. */
13862e4b17023SJohn Marino if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
13863e4b17023SJohn Marino && host_integerp (arg1, 0)
13864e4b17023SJohn Marino && TREE_CODE (arg2) == REAL_CST && !TREE_OVERFLOW (arg2))
13865e4b17023SJohn Marino {
13866e4b17023SJohn Marino const HOST_WIDE_INT n = tree_low_cst(arg1, 0);
13867e4b17023SJohn Marino const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg2);
13868e4b17023SJohn Marino
13869e4b17023SJohn Marino if (n == (long)n
13870e4b17023SJohn Marino && real_isfinite (ra)
13871e4b17023SJohn Marino && (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , ra, min)))
13872e4b17023SJohn Marino {
13873e4b17023SJohn Marino const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
13874e4b17023SJohn Marino const int prec = fmt->p;
13875e4b17023SJohn Marino const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
13876e4b17023SJohn Marino int inexact;
13877e4b17023SJohn Marino mpfr_t m;
13878e4b17023SJohn Marino
13879e4b17023SJohn Marino mpfr_init2 (m, prec);
13880e4b17023SJohn Marino mpfr_from_real (m, ra, GMP_RNDN);
13881e4b17023SJohn Marino mpfr_clear_flags ();
13882e4b17023SJohn Marino inexact = func (m, n, m, rnd);
13883e4b17023SJohn Marino result = do_mpfr_ckconv (m, type, inexact);
13884e4b17023SJohn Marino mpfr_clear (m);
13885e4b17023SJohn Marino }
13886e4b17023SJohn Marino }
13887e4b17023SJohn Marino
13888e4b17023SJohn Marino return result;
13889e4b17023SJohn Marino }
13890e4b17023SJohn Marino
13891e4b17023SJohn Marino /* If arguments ARG0 and ARG1 are REAL_CSTs, call mpfr_remquo() to set
13892e4b17023SJohn Marino the pointer *(ARG_QUO) and return the result. The type is taken
13893e4b17023SJohn Marino from the type of ARG0 and is used for setting the precision of the
13894e4b17023SJohn Marino calculation and results. */
13895e4b17023SJohn Marino
13896e4b17023SJohn Marino static tree
do_mpfr_remquo(tree arg0,tree arg1,tree arg_quo)13897e4b17023SJohn Marino do_mpfr_remquo (tree arg0, tree arg1, tree arg_quo)
13898e4b17023SJohn Marino {
13899e4b17023SJohn Marino tree const type = TREE_TYPE (arg0);
13900e4b17023SJohn Marino tree result = NULL_TREE;
13901e4b17023SJohn Marino
13902e4b17023SJohn Marino STRIP_NOPS (arg0);
13903e4b17023SJohn Marino STRIP_NOPS (arg1);
13904e4b17023SJohn Marino
13905e4b17023SJohn Marino /* To proceed, MPFR must exactly represent the target floating point
13906e4b17023SJohn Marino format, which only happens when the target base equals two. */
13907e4b17023SJohn Marino if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
13908e4b17023SJohn Marino && TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0)
13909e4b17023SJohn Marino && TREE_CODE (arg1) == REAL_CST && !TREE_OVERFLOW (arg1))
13910e4b17023SJohn Marino {
13911e4b17023SJohn Marino const REAL_VALUE_TYPE *const ra0 = TREE_REAL_CST_PTR (arg0);
13912e4b17023SJohn Marino const REAL_VALUE_TYPE *const ra1 = TREE_REAL_CST_PTR (arg1);
13913e4b17023SJohn Marino
13914e4b17023SJohn Marino if (real_isfinite (ra0) && real_isfinite (ra1))
13915e4b17023SJohn Marino {
13916e4b17023SJohn Marino const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
13917e4b17023SJohn Marino const int prec = fmt->p;
13918e4b17023SJohn Marino const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
13919e4b17023SJohn Marino tree result_rem;
13920e4b17023SJohn Marino long integer_quo;
13921e4b17023SJohn Marino mpfr_t m0, m1;
13922e4b17023SJohn Marino
13923e4b17023SJohn Marino mpfr_inits2 (prec, m0, m1, NULL);
13924e4b17023SJohn Marino mpfr_from_real (m0, ra0, GMP_RNDN);
13925e4b17023SJohn Marino mpfr_from_real (m1, ra1, GMP_RNDN);
13926e4b17023SJohn Marino mpfr_clear_flags ();
13927e4b17023SJohn Marino mpfr_remquo (m0, &integer_quo, m0, m1, rnd);
13928e4b17023SJohn Marino /* Remquo is independent of the rounding mode, so pass
13929e4b17023SJohn Marino inexact=0 to do_mpfr_ckconv(). */
13930e4b17023SJohn Marino result_rem = do_mpfr_ckconv (m0, type, /*inexact=*/ 0);
13931e4b17023SJohn Marino mpfr_clears (m0, m1, NULL);
13932e4b17023SJohn Marino if (result_rem)
13933e4b17023SJohn Marino {
13934e4b17023SJohn Marino /* MPFR calculates quo in the host's long so it may
13935e4b17023SJohn Marino return more bits in quo than the target int can hold
13936e4b17023SJohn Marino if sizeof(host long) > sizeof(target int). This can
13937e4b17023SJohn Marino happen even for native compilers in LP64 mode. In
13938e4b17023SJohn Marino these cases, modulo the quo value with the largest
13939e4b17023SJohn Marino number that the target int can hold while leaving one
13940e4b17023SJohn Marino bit for the sign. */
13941e4b17023SJohn Marino if (sizeof (integer_quo) * CHAR_BIT > INT_TYPE_SIZE)
13942e4b17023SJohn Marino integer_quo %= (long)(1UL << (INT_TYPE_SIZE - 1));
13943e4b17023SJohn Marino
13944e4b17023SJohn Marino /* Dereference the quo pointer argument. */
13945e4b17023SJohn Marino arg_quo = build_fold_indirect_ref (arg_quo);
13946e4b17023SJohn Marino /* Proceed iff a valid pointer type was passed in. */
13947e4b17023SJohn Marino if (TYPE_MAIN_VARIANT (TREE_TYPE (arg_quo)) == integer_type_node)
13948e4b17023SJohn Marino {
13949e4b17023SJohn Marino /* Set the value. */
13950e4b17023SJohn Marino tree result_quo
13951e4b17023SJohn Marino = fold_build2 (MODIFY_EXPR, TREE_TYPE (arg_quo), arg_quo,
13952e4b17023SJohn Marino build_int_cst (TREE_TYPE (arg_quo),
13953e4b17023SJohn Marino integer_quo));
13954e4b17023SJohn Marino TREE_SIDE_EFFECTS (result_quo) = 1;
13955e4b17023SJohn Marino /* Combine the quo assignment with the rem. */
13956e4b17023SJohn Marino result = non_lvalue (fold_build2 (COMPOUND_EXPR, type,
13957e4b17023SJohn Marino result_quo, result_rem));
13958e4b17023SJohn Marino }
13959e4b17023SJohn Marino }
13960e4b17023SJohn Marino }
13961e4b17023SJohn Marino }
13962e4b17023SJohn Marino return result;
13963e4b17023SJohn Marino }
13964e4b17023SJohn Marino
13965e4b17023SJohn Marino /* If ARG is a REAL_CST, call mpfr_lgamma() on it and return the
13966e4b17023SJohn Marino resulting value as a tree with type TYPE. The mpfr precision is
13967e4b17023SJohn Marino set to the precision of TYPE. We assume that this mpfr function
13968e4b17023SJohn Marino returns zero if the result could be calculated exactly within the
13969e4b17023SJohn Marino requested precision. In addition, the integer pointer represented
13970e4b17023SJohn Marino by ARG_SG will be dereferenced and set to the appropriate signgam
13971e4b17023SJohn Marino (-1,1) value. */
13972e4b17023SJohn Marino
13973e4b17023SJohn Marino static tree
do_mpfr_lgamma_r(tree arg,tree arg_sg,tree type)13974e4b17023SJohn Marino do_mpfr_lgamma_r (tree arg, tree arg_sg, tree type)
13975e4b17023SJohn Marino {
13976e4b17023SJohn Marino tree result = NULL_TREE;
13977e4b17023SJohn Marino
13978e4b17023SJohn Marino STRIP_NOPS (arg);
13979e4b17023SJohn Marino
13980e4b17023SJohn Marino /* To proceed, MPFR must exactly represent the target floating point
13981e4b17023SJohn Marino format, which only happens when the target base equals two. Also
13982e4b17023SJohn Marino verify ARG is a constant and that ARG_SG is an int pointer. */
13983e4b17023SJohn Marino if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
13984e4b17023SJohn Marino && TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg)
13985e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (arg_sg)) == POINTER_TYPE
13986e4b17023SJohn Marino && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (arg_sg))) == integer_type_node)
13987e4b17023SJohn Marino {
13988e4b17023SJohn Marino const REAL_VALUE_TYPE *const ra = TREE_REAL_CST_PTR (arg);
13989e4b17023SJohn Marino
13990e4b17023SJohn Marino /* In addition to NaN and Inf, the argument cannot be zero or a
13991e4b17023SJohn Marino negative integer. */
13992e4b17023SJohn Marino if (real_isfinite (ra)
13993e4b17023SJohn Marino && ra->cl != rvc_zero
13994e4b17023SJohn Marino && !(real_isneg(ra) && real_isinteger(ra, TYPE_MODE (type))))
13995e4b17023SJohn Marino {
13996e4b17023SJohn Marino const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
13997e4b17023SJohn Marino const int prec = fmt->p;
13998e4b17023SJohn Marino const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
13999e4b17023SJohn Marino int inexact, sg;
14000e4b17023SJohn Marino mpfr_t m;
14001e4b17023SJohn Marino tree result_lg;
14002e4b17023SJohn Marino
14003e4b17023SJohn Marino mpfr_init2 (m, prec);
14004e4b17023SJohn Marino mpfr_from_real (m, ra, GMP_RNDN);
14005e4b17023SJohn Marino mpfr_clear_flags ();
14006e4b17023SJohn Marino inexact = mpfr_lgamma (m, &sg, m, rnd);
14007e4b17023SJohn Marino result_lg = do_mpfr_ckconv (m, type, inexact);
14008e4b17023SJohn Marino mpfr_clear (m);
14009e4b17023SJohn Marino if (result_lg)
14010e4b17023SJohn Marino {
14011e4b17023SJohn Marino tree result_sg;
14012e4b17023SJohn Marino
14013e4b17023SJohn Marino /* Dereference the arg_sg pointer argument. */
14014e4b17023SJohn Marino arg_sg = build_fold_indirect_ref (arg_sg);
14015e4b17023SJohn Marino /* Assign the signgam value into *arg_sg. */
14016e4b17023SJohn Marino result_sg = fold_build2 (MODIFY_EXPR,
14017e4b17023SJohn Marino TREE_TYPE (arg_sg), arg_sg,
14018e4b17023SJohn Marino build_int_cst (TREE_TYPE (arg_sg), sg));
14019e4b17023SJohn Marino TREE_SIDE_EFFECTS (result_sg) = 1;
14020e4b17023SJohn Marino /* Combine the signgam assignment with the lgamma result. */
14021e4b17023SJohn Marino result = non_lvalue (fold_build2 (COMPOUND_EXPR, type,
14022e4b17023SJohn Marino result_sg, result_lg));
14023e4b17023SJohn Marino }
14024e4b17023SJohn Marino }
14025e4b17023SJohn Marino }
14026e4b17023SJohn Marino
14027e4b17023SJohn Marino return result;
14028e4b17023SJohn Marino }
14029e4b17023SJohn Marino
14030e4b17023SJohn Marino /* If argument ARG is a COMPLEX_CST, call the one-argument mpc
14031e4b17023SJohn Marino function FUNC on it and return the resulting value as a tree with
14032e4b17023SJohn Marino type TYPE. The mpfr precision is set to the precision of TYPE. We
14033e4b17023SJohn Marino assume that function FUNC returns zero if the result could be
14034e4b17023SJohn Marino calculated exactly within the requested precision. */
14035e4b17023SJohn Marino
14036e4b17023SJohn Marino static tree
do_mpc_arg1(tree arg,tree type,int (* func)(mpc_ptr,mpc_srcptr,mpc_rnd_t))14037e4b17023SJohn Marino do_mpc_arg1 (tree arg, tree type, int (*func)(mpc_ptr, mpc_srcptr, mpc_rnd_t))
14038e4b17023SJohn Marino {
14039e4b17023SJohn Marino tree result = NULL_TREE;
14040e4b17023SJohn Marino
14041e4b17023SJohn Marino STRIP_NOPS (arg);
14042e4b17023SJohn Marino
14043e4b17023SJohn Marino /* To proceed, MPFR must exactly represent the target floating point
14044e4b17023SJohn Marino format, which only happens when the target base equals two. */
14045e4b17023SJohn Marino if (TREE_CODE (arg) == COMPLEX_CST && !TREE_OVERFLOW (arg)
14046e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE
14047e4b17023SJohn Marino && REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (TREE_TYPE (arg))))->b == 2)
14048e4b17023SJohn Marino {
14049e4b17023SJohn Marino const REAL_VALUE_TYPE *const re = TREE_REAL_CST_PTR (TREE_REALPART (arg));
14050e4b17023SJohn Marino const REAL_VALUE_TYPE *const im = TREE_REAL_CST_PTR (TREE_IMAGPART (arg));
14051e4b17023SJohn Marino
14052e4b17023SJohn Marino if (real_isfinite (re) && real_isfinite (im))
14053e4b17023SJohn Marino {
14054e4b17023SJohn Marino const struct real_format *const fmt =
14055e4b17023SJohn Marino REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (type)));
14056e4b17023SJohn Marino const int prec = fmt->p;
14057e4b17023SJohn Marino const mp_rnd_t rnd = fmt->round_towards_zero ? GMP_RNDZ : GMP_RNDN;
14058e4b17023SJohn Marino const mpc_rnd_t crnd = fmt->round_towards_zero ? MPC_RNDZZ : MPC_RNDNN;
14059e4b17023SJohn Marino int inexact;
14060e4b17023SJohn Marino mpc_t m;
14061e4b17023SJohn Marino
14062e4b17023SJohn Marino mpc_init2 (m, prec);
14063e4b17023SJohn Marino mpfr_from_real (mpc_realref(m), re, rnd);
14064e4b17023SJohn Marino mpfr_from_real (mpc_imagref(m), im, rnd);
14065e4b17023SJohn Marino mpfr_clear_flags ();
14066e4b17023SJohn Marino inexact = func (m, m, crnd);
14067e4b17023SJohn Marino result = do_mpc_ckconv (m, type, inexact, /*force_convert=*/ 0);
14068e4b17023SJohn Marino mpc_clear (m);
14069e4b17023SJohn Marino }
14070e4b17023SJohn Marino }
14071e4b17023SJohn Marino
14072e4b17023SJohn Marino return result;
14073e4b17023SJohn Marino }
14074e4b17023SJohn Marino
14075e4b17023SJohn Marino /* If arguments ARG0 and ARG1 are a COMPLEX_CST, call the two-argument
14076e4b17023SJohn Marino mpc function FUNC on it and return the resulting value as a tree
14077e4b17023SJohn Marino with type TYPE. The mpfr precision is set to the precision of
14078e4b17023SJohn Marino TYPE. We assume that function FUNC returns zero if the result
14079e4b17023SJohn Marino could be calculated exactly within the requested precision. If
14080e4b17023SJohn Marino DO_NONFINITE is true, then fold expressions containing Inf or NaN
14081e4b17023SJohn Marino in the arguments and/or results. */
14082e4b17023SJohn Marino
14083e4b17023SJohn Marino tree
do_mpc_arg2(tree arg0,tree arg1,tree type,int do_nonfinite,int (* func)(mpc_ptr,mpc_srcptr,mpc_srcptr,mpc_rnd_t))14084e4b17023SJohn Marino do_mpc_arg2 (tree arg0, tree arg1, tree type, int do_nonfinite,
14085e4b17023SJohn Marino int (*func)(mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t))
14086e4b17023SJohn Marino {
14087e4b17023SJohn Marino tree result = NULL_TREE;
14088e4b17023SJohn Marino
14089e4b17023SJohn Marino STRIP_NOPS (arg0);
14090e4b17023SJohn Marino STRIP_NOPS (arg1);
14091e4b17023SJohn Marino
14092e4b17023SJohn Marino /* To proceed, MPFR must exactly represent the target floating point
14093e4b17023SJohn Marino format, which only happens when the target base equals two. */
14094e4b17023SJohn Marino if (TREE_CODE (arg0) == COMPLEX_CST && !TREE_OVERFLOW (arg0)
14095e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE
14096e4b17023SJohn Marino && TREE_CODE (arg1) == COMPLEX_CST && !TREE_OVERFLOW (arg1)
14097e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (TREE_TYPE (arg1))) == REAL_TYPE
14098e4b17023SJohn Marino && REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0))))->b == 2)
14099e4b17023SJohn Marino {
14100e4b17023SJohn Marino const REAL_VALUE_TYPE *const re0 = TREE_REAL_CST_PTR (TREE_REALPART (arg0));
14101e4b17023SJohn Marino const REAL_VALUE_TYPE *const im0 = TREE_REAL_CST_PTR (TREE_IMAGPART (arg0));
14102e4b17023SJohn Marino const REAL_VALUE_TYPE *const re1 = TREE_REAL_CST_PTR (TREE_REALPART (arg1));
14103e4b17023SJohn Marino const REAL_VALUE_TYPE *const im1 = TREE_REAL_CST_PTR (TREE_IMAGPART (arg1));
14104e4b17023SJohn Marino
14105e4b17023SJohn Marino if (do_nonfinite
14106e4b17023SJohn Marino || (real_isfinite (re0) && real_isfinite (im0)
14107e4b17023SJohn Marino && real_isfinite (re1) && real_isfinite (im1)))
14108e4b17023SJohn Marino {
14109e4b17023SJohn Marino const struct real_format *const fmt =
14110e4b17023SJohn Marino REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (type)));
14111e4b17023SJohn Marino const int prec = fmt->p;
14112e4b17023SJohn Marino const mp_rnd_t rnd = fmt->round_towards_zero ? GMP_RNDZ : GMP_RNDN;
14113e4b17023SJohn Marino const mpc_rnd_t crnd = fmt->round_towards_zero ? MPC_RNDZZ : MPC_RNDNN;
14114e4b17023SJohn Marino int inexact;
14115e4b17023SJohn Marino mpc_t m0, m1;
14116e4b17023SJohn Marino
14117e4b17023SJohn Marino mpc_init2 (m0, prec);
14118e4b17023SJohn Marino mpc_init2 (m1, prec);
14119e4b17023SJohn Marino mpfr_from_real (mpc_realref(m0), re0, rnd);
14120e4b17023SJohn Marino mpfr_from_real (mpc_imagref(m0), im0, rnd);
14121e4b17023SJohn Marino mpfr_from_real (mpc_realref(m1), re1, rnd);
14122e4b17023SJohn Marino mpfr_from_real (mpc_imagref(m1), im1, rnd);
14123e4b17023SJohn Marino mpfr_clear_flags ();
14124e4b17023SJohn Marino inexact = func (m0, m0, m1, crnd);
14125e4b17023SJohn Marino result = do_mpc_ckconv (m0, type, inexact, do_nonfinite);
14126e4b17023SJohn Marino mpc_clear (m0);
14127e4b17023SJohn Marino mpc_clear (m1);
14128e4b17023SJohn Marino }
14129e4b17023SJohn Marino }
14130e4b17023SJohn Marino
14131e4b17023SJohn Marino return result;
14132e4b17023SJohn Marino }
14133e4b17023SJohn Marino
14134e4b17023SJohn Marino /* Fold a call STMT to __{,v}sprintf_chk. Return NULL_TREE if
14135e4b17023SJohn Marino a normal call should be emitted rather than expanding the function
14136e4b17023SJohn Marino inline. FCODE is either BUILT_IN_SPRINTF_CHK or BUILT_IN_VSPRINTF_CHK. */
14137e4b17023SJohn Marino
14138e4b17023SJohn Marino static tree
gimple_fold_builtin_sprintf_chk(gimple stmt,enum built_in_function fcode)14139e4b17023SJohn Marino gimple_fold_builtin_sprintf_chk (gimple stmt, enum built_in_function fcode)
14140e4b17023SJohn Marino {
14141e4b17023SJohn Marino int nargs = gimple_call_num_args (stmt);
14142e4b17023SJohn Marino
14143e4b17023SJohn Marino return fold_builtin_sprintf_chk_1 (gimple_location (stmt), nargs,
14144e4b17023SJohn Marino (nargs > 0
14145e4b17023SJohn Marino ? gimple_call_arg_ptr (stmt, 0)
14146e4b17023SJohn Marino : &error_mark_node), fcode);
14147e4b17023SJohn Marino }
14148e4b17023SJohn Marino
14149e4b17023SJohn Marino /* Fold a call STMT to {,v}snprintf. Return NULL_TREE if
14150e4b17023SJohn Marino a normal call should be emitted rather than expanding the function
14151e4b17023SJohn Marino inline. FCODE is either BUILT_IN_SNPRINTF_CHK or
14152e4b17023SJohn Marino BUILT_IN_VSNPRINTF_CHK. If MAXLEN is not NULL, it is maximum length
14153e4b17023SJohn Marino passed as second argument. */
14154e4b17023SJohn Marino
14155e4b17023SJohn Marino tree
gimple_fold_builtin_snprintf_chk(gimple stmt,tree maxlen,enum built_in_function fcode)14156e4b17023SJohn Marino gimple_fold_builtin_snprintf_chk (gimple stmt, tree maxlen,
14157e4b17023SJohn Marino enum built_in_function fcode)
14158e4b17023SJohn Marino {
14159e4b17023SJohn Marino int nargs = gimple_call_num_args (stmt);
14160e4b17023SJohn Marino
14161e4b17023SJohn Marino return fold_builtin_snprintf_chk_1 (gimple_location (stmt), nargs,
14162e4b17023SJohn Marino (nargs > 0
14163e4b17023SJohn Marino ? gimple_call_arg_ptr (stmt, 0)
14164e4b17023SJohn Marino : &error_mark_node), maxlen, fcode);
14165e4b17023SJohn Marino }
14166e4b17023SJohn Marino
14167e4b17023SJohn Marino /* Builtins with folding operations that operate on "..." arguments
14168e4b17023SJohn Marino need special handling; we need to store the arguments in a convenient
14169e4b17023SJohn Marino data structure before attempting any folding. Fortunately there are
14170e4b17023SJohn Marino only a few builtins that fall into this category. FNDECL is the
14171e4b17023SJohn Marino function, EXP is the CALL_EXPR for the call, and IGNORE is true if the
14172e4b17023SJohn Marino result of the function call is ignored. */
14173e4b17023SJohn Marino
14174e4b17023SJohn Marino static tree
gimple_fold_builtin_varargs(tree fndecl,gimple stmt,bool ignore ATTRIBUTE_UNUSED)14175e4b17023SJohn Marino gimple_fold_builtin_varargs (tree fndecl, gimple stmt,
14176e4b17023SJohn Marino bool ignore ATTRIBUTE_UNUSED)
14177e4b17023SJohn Marino {
14178e4b17023SJohn Marino enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
14179e4b17023SJohn Marino tree ret = NULL_TREE;
14180e4b17023SJohn Marino
14181e4b17023SJohn Marino switch (fcode)
14182e4b17023SJohn Marino {
14183e4b17023SJohn Marino case BUILT_IN_SPRINTF_CHK:
14184e4b17023SJohn Marino case BUILT_IN_VSPRINTF_CHK:
14185e4b17023SJohn Marino ret = gimple_fold_builtin_sprintf_chk (stmt, fcode);
14186e4b17023SJohn Marino break;
14187e4b17023SJohn Marino
14188e4b17023SJohn Marino case BUILT_IN_SNPRINTF_CHK:
14189e4b17023SJohn Marino case BUILT_IN_VSNPRINTF_CHK:
14190e4b17023SJohn Marino ret = gimple_fold_builtin_snprintf_chk (stmt, NULL_TREE, fcode);
14191e4b17023SJohn Marino
14192e4b17023SJohn Marino default:
14193e4b17023SJohn Marino break;
14194e4b17023SJohn Marino }
14195e4b17023SJohn Marino if (ret)
14196e4b17023SJohn Marino {
14197e4b17023SJohn Marino ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
14198e4b17023SJohn Marino TREE_NO_WARNING (ret) = 1;
14199e4b17023SJohn Marino return ret;
14200e4b17023SJohn Marino }
14201e4b17023SJohn Marino return NULL_TREE;
14202e4b17023SJohn Marino }
14203e4b17023SJohn Marino
14204e4b17023SJohn Marino /* A wrapper function for builtin folding that prevents warnings for
14205e4b17023SJohn Marino "statement without effect" and the like, caused by removing the
14206e4b17023SJohn Marino call node earlier than the warning is generated. */
14207e4b17023SJohn Marino
14208e4b17023SJohn Marino tree
fold_call_stmt(gimple stmt,bool ignore)14209e4b17023SJohn Marino fold_call_stmt (gimple stmt, bool ignore)
14210e4b17023SJohn Marino {
14211e4b17023SJohn Marino tree ret = NULL_TREE;
14212e4b17023SJohn Marino tree fndecl = gimple_call_fndecl (stmt);
14213e4b17023SJohn Marino location_t loc = gimple_location (stmt);
14214e4b17023SJohn Marino if (fndecl
14215e4b17023SJohn Marino && TREE_CODE (fndecl) == FUNCTION_DECL
14216e4b17023SJohn Marino && DECL_BUILT_IN (fndecl)
14217e4b17023SJohn Marino && !gimple_call_va_arg_pack_p (stmt))
14218e4b17023SJohn Marino {
14219e4b17023SJohn Marino int nargs = gimple_call_num_args (stmt);
14220e4b17023SJohn Marino tree *args = (nargs > 0
14221e4b17023SJohn Marino ? gimple_call_arg_ptr (stmt, 0)
14222e4b17023SJohn Marino : &error_mark_node);
14223e4b17023SJohn Marino
14224e4b17023SJohn Marino if (avoid_folding_inline_builtin (fndecl))
14225e4b17023SJohn Marino return NULL_TREE;
14226e4b17023SJohn Marino if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
14227e4b17023SJohn Marino {
14228e4b17023SJohn Marino return targetm.fold_builtin (fndecl, nargs, args, ignore);
14229e4b17023SJohn Marino }
14230e4b17023SJohn Marino else
14231e4b17023SJohn Marino {
14232e4b17023SJohn Marino if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
14233e4b17023SJohn Marino ret = fold_builtin_n (loc, fndecl, args, nargs, ignore);
14234e4b17023SJohn Marino if (!ret)
14235e4b17023SJohn Marino ret = gimple_fold_builtin_varargs (fndecl, stmt, ignore);
14236e4b17023SJohn Marino if (ret)
14237e4b17023SJohn Marino {
14238e4b17023SJohn Marino /* Propagate location information from original call to
14239e4b17023SJohn Marino expansion of builtin. Otherwise things like
14240e4b17023SJohn Marino maybe_emit_chk_warning, that operate on the expansion
14241e4b17023SJohn Marino of a builtin, will use the wrong location information. */
14242e4b17023SJohn Marino if (gimple_has_location (stmt))
14243e4b17023SJohn Marino {
14244e4b17023SJohn Marino tree realret = ret;
14245e4b17023SJohn Marino if (TREE_CODE (ret) == NOP_EXPR)
14246e4b17023SJohn Marino realret = TREE_OPERAND (ret, 0);
14247e4b17023SJohn Marino if (CAN_HAVE_LOCATION_P (realret)
14248e4b17023SJohn Marino && !EXPR_HAS_LOCATION (realret))
14249e4b17023SJohn Marino SET_EXPR_LOCATION (realret, loc);
14250e4b17023SJohn Marino return realret;
14251e4b17023SJohn Marino }
14252e4b17023SJohn Marino return ret;
14253e4b17023SJohn Marino }
14254e4b17023SJohn Marino }
14255e4b17023SJohn Marino }
14256e4b17023SJohn Marino return NULL_TREE;
14257e4b17023SJohn Marino }
14258e4b17023SJohn Marino
14259e4b17023SJohn Marino /* Look up the function in builtin_decl that corresponds to DECL
14260e4b17023SJohn Marino and set ASMSPEC as its user assembler name. DECL must be a
14261e4b17023SJohn Marino function decl that declares a builtin. */
14262e4b17023SJohn Marino
14263e4b17023SJohn Marino void
set_builtin_user_assembler_name(tree decl,const char * asmspec)14264e4b17023SJohn Marino set_builtin_user_assembler_name (tree decl, const char *asmspec)
14265e4b17023SJohn Marino {
14266e4b17023SJohn Marino tree builtin;
14267e4b17023SJohn Marino gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
14268e4b17023SJohn Marino && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
14269e4b17023SJohn Marino && asmspec != 0);
14270e4b17023SJohn Marino
14271e4b17023SJohn Marino builtin = builtin_decl_explicit (DECL_FUNCTION_CODE (decl));
14272e4b17023SJohn Marino set_user_assembler_name (builtin, asmspec);
14273e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (decl))
14274e4b17023SJohn Marino {
14275e4b17023SJohn Marino case BUILT_IN_MEMCPY:
14276e4b17023SJohn Marino init_block_move_fn (asmspec);
14277e4b17023SJohn Marino memcpy_libfunc = set_user_assembler_libfunc ("memcpy", asmspec);
14278e4b17023SJohn Marino break;
14279e4b17023SJohn Marino case BUILT_IN_MEMSET:
14280e4b17023SJohn Marino init_block_clear_fn (asmspec);
14281e4b17023SJohn Marino memset_libfunc = set_user_assembler_libfunc ("memset", asmspec);
14282e4b17023SJohn Marino break;
14283e4b17023SJohn Marino case BUILT_IN_MEMMOVE:
14284e4b17023SJohn Marino memmove_libfunc = set_user_assembler_libfunc ("memmove", asmspec);
14285e4b17023SJohn Marino break;
14286e4b17023SJohn Marino case BUILT_IN_MEMCMP:
14287e4b17023SJohn Marino memcmp_libfunc = set_user_assembler_libfunc ("memcmp", asmspec);
14288e4b17023SJohn Marino break;
14289e4b17023SJohn Marino case BUILT_IN_ABORT:
14290e4b17023SJohn Marino abort_libfunc = set_user_assembler_libfunc ("abort", asmspec);
14291e4b17023SJohn Marino break;
14292e4b17023SJohn Marino case BUILT_IN_FFS:
14293e4b17023SJohn Marino if (INT_TYPE_SIZE < BITS_PER_WORD)
14294e4b17023SJohn Marino {
14295e4b17023SJohn Marino set_user_assembler_libfunc ("ffs", asmspec);
14296e4b17023SJohn Marino set_optab_libfunc (ffs_optab, mode_for_size (INT_TYPE_SIZE,
14297e4b17023SJohn Marino MODE_INT, 0), "ffs");
14298e4b17023SJohn Marino }
14299e4b17023SJohn Marino break;
14300e4b17023SJohn Marino default:
14301e4b17023SJohn Marino break;
14302e4b17023SJohn Marino }
14303e4b17023SJohn Marino }
14304e4b17023SJohn Marino
14305e4b17023SJohn Marino /* Return true if DECL is a builtin that expands to a constant or similarly
14306e4b17023SJohn Marino simple code. */
14307e4b17023SJohn Marino bool
is_simple_builtin(tree decl)14308e4b17023SJohn Marino is_simple_builtin (tree decl)
14309e4b17023SJohn Marino {
14310e4b17023SJohn Marino if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
14311e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (decl))
14312e4b17023SJohn Marino {
14313e4b17023SJohn Marino /* Builtins that expand to constants. */
14314e4b17023SJohn Marino case BUILT_IN_CONSTANT_P:
14315e4b17023SJohn Marino case BUILT_IN_EXPECT:
14316e4b17023SJohn Marino case BUILT_IN_OBJECT_SIZE:
14317e4b17023SJohn Marino case BUILT_IN_UNREACHABLE:
14318e4b17023SJohn Marino /* Simple register moves or loads from stack. */
14319e4b17023SJohn Marino case BUILT_IN_ASSUME_ALIGNED:
14320e4b17023SJohn Marino case BUILT_IN_RETURN_ADDRESS:
14321e4b17023SJohn Marino case BUILT_IN_EXTRACT_RETURN_ADDR:
14322e4b17023SJohn Marino case BUILT_IN_FROB_RETURN_ADDR:
14323e4b17023SJohn Marino case BUILT_IN_RETURN:
14324e4b17023SJohn Marino case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
14325e4b17023SJohn Marino case BUILT_IN_FRAME_ADDRESS:
14326e4b17023SJohn Marino case BUILT_IN_VA_END:
14327e4b17023SJohn Marino case BUILT_IN_STACK_SAVE:
14328e4b17023SJohn Marino case BUILT_IN_STACK_RESTORE:
14329e4b17023SJohn Marino /* Exception state returns or moves registers around. */
14330e4b17023SJohn Marino case BUILT_IN_EH_FILTER:
14331e4b17023SJohn Marino case BUILT_IN_EH_POINTER:
14332e4b17023SJohn Marino case BUILT_IN_EH_COPY_VALUES:
14333e4b17023SJohn Marino return true;
14334e4b17023SJohn Marino
14335e4b17023SJohn Marino default:
14336e4b17023SJohn Marino return false;
14337e4b17023SJohn Marino }
14338e4b17023SJohn Marino
14339e4b17023SJohn Marino return false;
14340e4b17023SJohn Marino }
14341e4b17023SJohn Marino
14342e4b17023SJohn Marino /* Return true if DECL is a builtin that is not expensive, i.e., they are
14343e4b17023SJohn Marino most probably expanded inline into reasonably simple code. This is a
14344e4b17023SJohn Marino superset of is_simple_builtin. */
14345e4b17023SJohn Marino bool
is_inexpensive_builtin(tree decl)14346e4b17023SJohn Marino is_inexpensive_builtin (tree decl)
14347e4b17023SJohn Marino {
14348e4b17023SJohn Marino if (!decl)
14349e4b17023SJohn Marino return false;
14350e4b17023SJohn Marino else if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_MD)
14351e4b17023SJohn Marino return true;
14352e4b17023SJohn Marino else if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
14353e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (decl))
14354e4b17023SJohn Marino {
14355e4b17023SJohn Marino case BUILT_IN_ABS:
14356e4b17023SJohn Marino case BUILT_IN_ALLOCA:
14357e4b17023SJohn Marino case BUILT_IN_ALLOCA_WITH_ALIGN:
14358e4b17023SJohn Marino case BUILT_IN_BSWAP32:
14359e4b17023SJohn Marino case BUILT_IN_BSWAP64:
14360e4b17023SJohn Marino case BUILT_IN_CLZ:
14361e4b17023SJohn Marino case BUILT_IN_CLZIMAX:
14362e4b17023SJohn Marino case BUILT_IN_CLZL:
14363e4b17023SJohn Marino case BUILT_IN_CLZLL:
14364e4b17023SJohn Marino case BUILT_IN_CTZ:
14365e4b17023SJohn Marino case BUILT_IN_CTZIMAX:
14366e4b17023SJohn Marino case BUILT_IN_CTZL:
14367e4b17023SJohn Marino case BUILT_IN_CTZLL:
14368e4b17023SJohn Marino case BUILT_IN_FFS:
14369e4b17023SJohn Marino case BUILT_IN_FFSIMAX:
14370e4b17023SJohn Marino case BUILT_IN_FFSL:
14371e4b17023SJohn Marino case BUILT_IN_FFSLL:
14372e4b17023SJohn Marino case BUILT_IN_IMAXABS:
14373e4b17023SJohn Marino case BUILT_IN_FINITE:
14374e4b17023SJohn Marino case BUILT_IN_FINITEF:
14375e4b17023SJohn Marino case BUILT_IN_FINITEL:
14376e4b17023SJohn Marino case BUILT_IN_FINITED32:
14377e4b17023SJohn Marino case BUILT_IN_FINITED64:
14378e4b17023SJohn Marino case BUILT_IN_FINITED128:
14379e4b17023SJohn Marino case BUILT_IN_FPCLASSIFY:
14380e4b17023SJohn Marino case BUILT_IN_ISFINITE:
14381e4b17023SJohn Marino case BUILT_IN_ISINF_SIGN:
14382e4b17023SJohn Marino case BUILT_IN_ISINF:
14383e4b17023SJohn Marino case BUILT_IN_ISINFF:
14384e4b17023SJohn Marino case BUILT_IN_ISINFL:
14385e4b17023SJohn Marino case BUILT_IN_ISINFD32:
14386e4b17023SJohn Marino case BUILT_IN_ISINFD64:
14387e4b17023SJohn Marino case BUILT_IN_ISINFD128:
14388e4b17023SJohn Marino case BUILT_IN_ISNAN:
14389e4b17023SJohn Marino case BUILT_IN_ISNANF:
14390e4b17023SJohn Marino case BUILT_IN_ISNANL:
14391e4b17023SJohn Marino case BUILT_IN_ISNAND32:
14392e4b17023SJohn Marino case BUILT_IN_ISNAND64:
14393e4b17023SJohn Marino case BUILT_IN_ISNAND128:
14394e4b17023SJohn Marino case BUILT_IN_ISNORMAL:
14395e4b17023SJohn Marino case BUILT_IN_ISGREATER:
14396e4b17023SJohn Marino case BUILT_IN_ISGREATEREQUAL:
14397e4b17023SJohn Marino case BUILT_IN_ISLESS:
14398e4b17023SJohn Marino case BUILT_IN_ISLESSEQUAL:
14399e4b17023SJohn Marino case BUILT_IN_ISLESSGREATER:
14400e4b17023SJohn Marino case BUILT_IN_ISUNORDERED:
14401e4b17023SJohn Marino case BUILT_IN_VA_ARG_PACK:
14402e4b17023SJohn Marino case BUILT_IN_VA_ARG_PACK_LEN:
14403e4b17023SJohn Marino case BUILT_IN_VA_COPY:
14404e4b17023SJohn Marino case BUILT_IN_TRAP:
14405e4b17023SJohn Marino case BUILT_IN_SAVEREGS:
14406e4b17023SJohn Marino case BUILT_IN_POPCOUNTL:
14407e4b17023SJohn Marino case BUILT_IN_POPCOUNTLL:
14408e4b17023SJohn Marino case BUILT_IN_POPCOUNTIMAX:
14409e4b17023SJohn Marino case BUILT_IN_POPCOUNT:
14410e4b17023SJohn Marino case BUILT_IN_PARITYL:
14411e4b17023SJohn Marino case BUILT_IN_PARITYLL:
14412e4b17023SJohn Marino case BUILT_IN_PARITYIMAX:
14413e4b17023SJohn Marino case BUILT_IN_PARITY:
14414e4b17023SJohn Marino case BUILT_IN_LABS:
14415e4b17023SJohn Marino case BUILT_IN_LLABS:
14416e4b17023SJohn Marino case BUILT_IN_PREFETCH:
14417e4b17023SJohn Marino return true;
14418e4b17023SJohn Marino
14419e4b17023SJohn Marino default:
14420e4b17023SJohn Marino return is_simple_builtin (decl);
14421e4b17023SJohn Marino }
14422e4b17023SJohn Marino
14423e4b17023SJohn Marino return false;
14424e4b17023SJohn Marino }
14425