xref: /dflybsd-src/contrib/gcc-4.7/gcc/builtins.c (revision 0a8dc9fc45f4d0b236341a473fac4a486375f60c)
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 = &target;
5292e4b17023SJohn Marino       else
5293e4b17023SJohn Marino 	poval = &target;
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