xref: /dflybsd-src/contrib/gcc-8.0/gcc/builtins.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
1*38fd1498Szrj /* Expand builtin functions.
2*38fd1498Szrj    Copyright (C) 1988-2018 Free Software Foundation, Inc.
3*38fd1498Szrj 
4*38fd1498Szrj This file is part of GCC.
5*38fd1498Szrj 
6*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
7*38fd1498Szrj the terms of the GNU General Public License as published by the Free
8*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
9*38fd1498Szrj version.
10*38fd1498Szrj 
11*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14*38fd1498Szrj for more details.
15*38fd1498Szrj 
16*38fd1498Szrj You should have received a copy of the GNU General Public License
17*38fd1498Szrj along with GCC; see the file COPYING3.  If not see
18*38fd1498Szrj <http://www.gnu.org/licenses/>.  */
19*38fd1498Szrj 
20*38fd1498Szrj /* Legacy warning!  Please add no further builtin simplifications here
21*38fd1498Szrj    (apart from pure constant folding) - builtin simplifications should go
22*38fd1498Szrj    to match.pd or gimple-fold.c instead.  */
23*38fd1498Szrj 
24*38fd1498Szrj #include "config.h"
25*38fd1498Szrj #include "system.h"
26*38fd1498Szrj #include "coretypes.h"
27*38fd1498Szrj #include "backend.h"
28*38fd1498Szrj #include "target.h"
29*38fd1498Szrj #include "rtl.h"
30*38fd1498Szrj #include "tree.h"
31*38fd1498Szrj #include "memmodel.h"
32*38fd1498Szrj #include "gimple.h"
33*38fd1498Szrj #include "predict.h"
34*38fd1498Szrj #include "tm_p.h"
35*38fd1498Szrj #include "stringpool.h"
36*38fd1498Szrj #include "tree-vrp.h"
37*38fd1498Szrj #include "tree-ssanames.h"
38*38fd1498Szrj #include "expmed.h"
39*38fd1498Szrj #include "optabs.h"
40*38fd1498Szrj #include "emit-rtl.h"
41*38fd1498Szrj #include "recog.h"
42*38fd1498Szrj #include "diagnostic-core.h"
43*38fd1498Szrj #include "alias.h"
44*38fd1498Szrj #include "fold-const.h"
45*38fd1498Szrj #include "fold-const-call.h"
46*38fd1498Szrj #include "gimple-ssa-warn-restrict.h"
47*38fd1498Szrj #include "stor-layout.h"
48*38fd1498Szrj #include "calls.h"
49*38fd1498Szrj #include "varasm.h"
50*38fd1498Szrj #include "tree-object-size.h"
51*38fd1498Szrj #include "realmpfr.h"
52*38fd1498Szrj #include "cfgrtl.h"
53*38fd1498Szrj #include "except.h"
54*38fd1498Szrj #include "dojump.h"
55*38fd1498Szrj #include "explow.h"
56*38fd1498Szrj #include "stmt.h"
57*38fd1498Szrj #include "expr.h"
58*38fd1498Szrj #include "libfuncs.h"
59*38fd1498Szrj #include "output.h"
60*38fd1498Szrj #include "typeclass.h"
61*38fd1498Szrj #include "langhooks.h"
62*38fd1498Szrj #include "value-prof.h"
63*38fd1498Szrj #include "builtins.h"
64*38fd1498Szrj #include "stringpool.h"
65*38fd1498Szrj #include "attribs.h"
66*38fd1498Szrj #include "asan.h"
67*38fd1498Szrj #include "tree-chkp.h"
68*38fd1498Szrj #include "rtl-chkp.h"
69*38fd1498Szrj #include "internal-fn.h"
70*38fd1498Szrj #include "case-cfn-macros.h"
71*38fd1498Szrj #include "gimple-fold.h"
72*38fd1498Szrj #include "intl.h"
73*38fd1498Szrj #include "file-prefix-map.h" /* remap_macro_filename()  */
74*38fd1498Szrj 
75*38fd1498Szrj struct target_builtins default_target_builtins;
76*38fd1498Szrj #if SWITCHABLE_TARGET
77*38fd1498Szrj struct target_builtins *this_target_builtins = &default_target_builtins;
78*38fd1498Szrj #endif
79*38fd1498Szrj 
80*38fd1498Szrj /* Define the names of the builtin function types and codes.  */
81*38fd1498Szrj const char *const built_in_class_names[BUILT_IN_LAST]
82*38fd1498Szrj   = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
83*38fd1498Szrj 
84*38fd1498Szrj #define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT, IM, COND) #X,
85*38fd1498Szrj const char * built_in_names[(int) END_BUILTINS] =
86*38fd1498Szrj {
87*38fd1498Szrj #include "builtins.def"
88*38fd1498Szrj };
89*38fd1498Szrj 
90*38fd1498Szrj /* Setup an array of builtin_info_type, make sure each element decl is
91*38fd1498Szrj    initialized to NULL_TREE.  */
92*38fd1498Szrj builtin_info_type builtin_info[(int)END_BUILTINS];
93*38fd1498Szrj 
94*38fd1498Szrj /* Non-zero if __builtin_constant_p should be folded right away.  */
95*38fd1498Szrj bool force_folding_builtin_constant_p;
96*38fd1498Szrj 
97*38fd1498Szrj static rtx c_readstr (const char *, scalar_int_mode);
98*38fd1498Szrj static int target_char_cast (tree, char *);
99*38fd1498Szrj static rtx get_memory_rtx (tree, tree);
100*38fd1498Szrj static int apply_args_size (void);
101*38fd1498Szrj static int apply_result_size (void);
102*38fd1498Szrj static rtx result_vector (int, rtx);
103*38fd1498Szrj static void expand_builtin_prefetch (tree);
104*38fd1498Szrj static rtx expand_builtin_apply_args (void);
105*38fd1498Szrj static rtx expand_builtin_apply_args_1 (void);
106*38fd1498Szrj static rtx expand_builtin_apply (rtx, rtx, rtx);
107*38fd1498Szrj static void expand_builtin_return (rtx);
108*38fd1498Szrj static enum type_class type_to_class (tree);
109*38fd1498Szrj static rtx expand_builtin_classify_type (tree);
110*38fd1498Szrj static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
111*38fd1498Szrj static rtx expand_builtin_mathfn_ternary (tree, rtx, rtx);
112*38fd1498Szrj static rtx expand_builtin_interclass_mathfn (tree, rtx);
113*38fd1498Szrj static rtx expand_builtin_sincos (tree);
114*38fd1498Szrj static rtx expand_builtin_cexpi (tree, rtx);
115*38fd1498Szrj static rtx expand_builtin_int_roundingfn (tree, rtx);
116*38fd1498Szrj static rtx expand_builtin_int_roundingfn_2 (tree, rtx);
117*38fd1498Szrj static rtx expand_builtin_next_arg (void);
118*38fd1498Szrj static rtx expand_builtin_va_start (tree);
119*38fd1498Szrj static rtx expand_builtin_va_end (tree);
120*38fd1498Szrj static rtx expand_builtin_va_copy (tree);
121*38fd1498Szrj static rtx expand_builtin_strcmp (tree, rtx);
122*38fd1498Szrj static rtx expand_builtin_strncmp (tree, rtx, machine_mode);
123*38fd1498Szrj static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, scalar_int_mode);
124*38fd1498Szrj static rtx expand_builtin_memchr (tree, rtx);
125*38fd1498Szrj static rtx expand_builtin_memcpy (tree, rtx);
126*38fd1498Szrj static rtx expand_builtin_memcpy_with_bounds (tree, rtx);
127*38fd1498Szrj static rtx expand_builtin_memory_copy_args (tree dest, tree src, tree len,
128*38fd1498Szrj 					    rtx target, tree exp, int endp);
129*38fd1498Szrj static rtx expand_builtin_memmove (tree, rtx);
130*38fd1498Szrj static rtx expand_builtin_mempcpy (tree, rtx);
131*38fd1498Szrj static rtx expand_builtin_mempcpy_with_bounds (tree, rtx);
132*38fd1498Szrj static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx, tree, int);
133*38fd1498Szrj static rtx expand_builtin_strcat (tree, rtx);
134*38fd1498Szrj static rtx expand_builtin_strcpy (tree, rtx);
135*38fd1498Szrj static rtx expand_builtin_strcpy_args (tree, tree, rtx);
136*38fd1498Szrj static rtx expand_builtin_stpcpy (tree, rtx, machine_mode);
137*38fd1498Szrj static rtx expand_builtin_stpncpy (tree, rtx);
138*38fd1498Szrj static rtx expand_builtin_strncat (tree, rtx);
139*38fd1498Szrj static rtx expand_builtin_strncpy (tree, rtx);
140*38fd1498Szrj static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, scalar_int_mode);
141*38fd1498Szrj static rtx expand_builtin_memset (tree, rtx, machine_mode);
142*38fd1498Szrj static rtx expand_builtin_memset_with_bounds (tree, rtx, machine_mode);
143*38fd1498Szrj static rtx expand_builtin_memset_args (tree, tree, tree, rtx, machine_mode, tree);
144*38fd1498Szrj static rtx expand_builtin_bzero (tree);
145*38fd1498Szrj static rtx expand_builtin_strlen (tree, rtx, machine_mode);
146*38fd1498Szrj static rtx expand_builtin_alloca (tree);
147*38fd1498Szrj static rtx expand_builtin_unop (machine_mode, tree, rtx, rtx, optab);
148*38fd1498Szrj static rtx expand_builtin_frame_address (tree, tree);
149*38fd1498Szrj static tree stabilize_va_list_loc (location_t, tree, int);
150*38fd1498Szrj static rtx expand_builtin_expect (tree, rtx);
151*38fd1498Szrj static tree fold_builtin_constant_p (tree);
152*38fd1498Szrj static tree fold_builtin_classify_type (tree);
153*38fd1498Szrj static tree fold_builtin_strlen (location_t, tree, tree);
154*38fd1498Szrj static tree fold_builtin_inf (location_t, tree, int);
155*38fd1498Szrj static tree rewrite_call_expr (location_t, tree, int, tree, int, ...);
156*38fd1498Szrj static bool validate_arg (const_tree, enum tree_code code);
157*38fd1498Szrj static rtx expand_builtin_fabs (tree, rtx, rtx);
158*38fd1498Szrj static rtx expand_builtin_signbit (tree, rtx);
159*38fd1498Szrj static tree fold_builtin_memcmp (location_t, tree, tree, tree);
160*38fd1498Szrj static tree fold_builtin_isascii (location_t, tree);
161*38fd1498Szrj static tree fold_builtin_toascii (location_t, tree);
162*38fd1498Szrj static tree fold_builtin_isdigit (location_t, tree);
163*38fd1498Szrj static tree fold_builtin_fabs (location_t, tree, tree);
164*38fd1498Szrj static tree fold_builtin_abs (location_t, tree, tree);
165*38fd1498Szrj static tree fold_builtin_unordered_cmp (location_t, tree, tree, tree, enum tree_code,
166*38fd1498Szrj 					enum tree_code);
167*38fd1498Szrj static tree fold_builtin_0 (location_t, tree);
168*38fd1498Szrj static tree fold_builtin_1 (location_t, tree, tree);
169*38fd1498Szrj static tree fold_builtin_2 (location_t, tree, tree, tree);
170*38fd1498Szrj static tree fold_builtin_3 (location_t, tree, tree, tree, tree);
171*38fd1498Szrj static tree fold_builtin_varargs (location_t, tree, tree*, int);
172*38fd1498Szrj 
173*38fd1498Szrj static tree fold_builtin_strpbrk (location_t, tree, tree, tree);
174*38fd1498Szrj static tree fold_builtin_strspn (location_t, tree, tree);
175*38fd1498Szrj static tree fold_builtin_strcspn (location_t, tree, tree);
176*38fd1498Szrj 
177*38fd1498Szrj static rtx expand_builtin_object_size (tree);
178*38fd1498Szrj static rtx expand_builtin_memory_chk (tree, rtx, machine_mode,
179*38fd1498Szrj 				      enum built_in_function);
180*38fd1498Szrj static void maybe_emit_chk_warning (tree, enum built_in_function);
181*38fd1498Szrj static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function);
182*38fd1498Szrj static void maybe_emit_free_warning (tree);
183*38fd1498Szrj static tree fold_builtin_object_size (tree, tree);
184*38fd1498Szrj 
185*38fd1498Szrj unsigned HOST_WIDE_INT target_newline;
186*38fd1498Szrj unsigned HOST_WIDE_INT target_percent;
187*38fd1498Szrj static unsigned HOST_WIDE_INT target_c;
188*38fd1498Szrj static unsigned HOST_WIDE_INT target_s;
189*38fd1498Szrj char target_percent_c[3];
190*38fd1498Szrj char target_percent_s[3];
191*38fd1498Szrj char target_percent_s_newline[4];
192*38fd1498Szrj static tree do_mpfr_remquo (tree, tree, tree);
193*38fd1498Szrj static tree do_mpfr_lgamma_r (tree, tree, tree);
194*38fd1498Szrj static void expand_builtin_sync_synchronize (void);
195*38fd1498Szrj 
196*38fd1498Szrj /* Return true if NAME starts with __builtin_ or __sync_.  */
197*38fd1498Szrj 
198*38fd1498Szrj static bool
is_builtin_name(const char * name)199*38fd1498Szrj is_builtin_name (const char *name)
200*38fd1498Szrj {
201*38fd1498Szrj   if (strncmp (name, "__builtin_", 10) == 0)
202*38fd1498Szrj     return true;
203*38fd1498Szrj   if (strncmp (name, "__sync_", 7) == 0)
204*38fd1498Szrj     return true;
205*38fd1498Szrj   if (strncmp (name, "__atomic_", 9) == 0)
206*38fd1498Szrj     return true;
207*38fd1498Szrj   return false;
208*38fd1498Szrj }
209*38fd1498Szrj 
210*38fd1498Szrj 
211*38fd1498Szrj /* Return true if DECL is a function symbol representing a built-in.  */
212*38fd1498Szrj 
213*38fd1498Szrj bool
is_builtin_fn(tree decl)214*38fd1498Szrj is_builtin_fn (tree decl)
215*38fd1498Szrj {
216*38fd1498Szrj   return TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl);
217*38fd1498Szrj }
218*38fd1498Szrj 
219*38fd1498Szrj /* Return true if NODE should be considered for inline expansion regardless
220*38fd1498Szrj    of the optimization level.  This means whenever a function is invoked with
221*38fd1498Szrj    its "internal" name, which normally contains the prefix "__builtin".  */
222*38fd1498Szrj 
223*38fd1498Szrj bool
called_as_built_in(tree node)224*38fd1498Szrj called_as_built_in (tree node)
225*38fd1498Szrj {
226*38fd1498Szrj   /* Note that we must use DECL_NAME, not DECL_ASSEMBLER_NAME_SET_P since
227*38fd1498Szrj      we want the name used to call the function, not the name it
228*38fd1498Szrj      will have. */
229*38fd1498Szrj   const char *name = IDENTIFIER_POINTER (DECL_NAME (node));
230*38fd1498Szrj   return is_builtin_name (name);
231*38fd1498Szrj }
232*38fd1498Szrj 
233*38fd1498Szrj /* Compute values M and N such that M divides (address of EXP - N) and such
234*38fd1498Szrj    that N < M.  If these numbers can be determined, store M in alignp and N in
235*38fd1498Szrj    *BITPOSP and return true.  Otherwise return false and store BITS_PER_UNIT to
236*38fd1498Szrj    *alignp and any bit-offset to *bitposp.
237*38fd1498Szrj 
238*38fd1498Szrj    Note that the address (and thus the alignment) computed here is based
239*38fd1498Szrj    on the address to which a symbol resolves, whereas DECL_ALIGN is based
240*38fd1498Szrj    on the address at which an object is actually located.  These two
241*38fd1498Szrj    addresses are not always the same.  For example, on ARM targets,
242*38fd1498Szrj    the address &foo of a Thumb function foo() has the lowest bit set,
243*38fd1498Szrj    whereas foo() itself starts on an even address.
244*38fd1498Szrj 
245*38fd1498Szrj    If ADDR_P is true we are taking the address of the memory reference EXP
246*38fd1498Szrj    and thus cannot rely on the access taking place.  */
247*38fd1498Szrj 
248*38fd1498Szrj static bool
get_object_alignment_2(tree exp,unsigned int * alignp,unsigned HOST_WIDE_INT * bitposp,bool addr_p)249*38fd1498Szrj get_object_alignment_2 (tree exp, unsigned int *alignp,
250*38fd1498Szrj 			unsigned HOST_WIDE_INT *bitposp, bool addr_p)
251*38fd1498Szrj {
252*38fd1498Szrj   poly_int64 bitsize, bitpos;
253*38fd1498Szrj   tree offset;
254*38fd1498Szrj   machine_mode mode;
255*38fd1498Szrj   int unsignedp, reversep, volatilep;
256*38fd1498Szrj   unsigned int align = BITS_PER_UNIT;
257*38fd1498Szrj   bool known_alignment = false;
258*38fd1498Szrj 
259*38fd1498Szrj   /* Get the innermost object and the constant (bitpos) and possibly
260*38fd1498Szrj      variable (offset) offset of the access.  */
261*38fd1498Szrj   exp = get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode,
262*38fd1498Szrj 			     &unsignedp, &reversep, &volatilep);
263*38fd1498Szrj 
264*38fd1498Szrj   /* Extract alignment information from the innermost object and
265*38fd1498Szrj      possibly adjust bitpos and offset.  */
266*38fd1498Szrj   if (TREE_CODE (exp) == FUNCTION_DECL)
267*38fd1498Szrj     {
268*38fd1498Szrj       /* Function addresses can encode extra information besides their
269*38fd1498Szrj 	 alignment.  However, if TARGET_PTRMEMFUNC_VBIT_LOCATION
270*38fd1498Szrj 	 allows the low bit to be used as a virtual bit, we know
271*38fd1498Szrj 	 that the address itself must be at least 2-byte aligned.  */
272*38fd1498Szrj       if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn)
273*38fd1498Szrj 	align = 2 * BITS_PER_UNIT;
274*38fd1498Szrj     }
275*38fd1498Szrj   else if (TREE_CODE (exp) == LABEL_DECL)
276*38fd1498Szrj     ;
277*38fd1498Szrj   else if (TREE_CODE (exp) == CONST_DECL)
278*38fd1498Szrj     {
279*38fd1498Szrj       /* The alignment of a CONST_DECL is determined by its initializer.  */
280*38fd1498Szrj       exp = DECL_INITIAL (exp);
281*38fd1498Szrj       align = TYPE_ALIGN (TREE_TYPE (exp));
282*38fd1498Szrj       if (CONSTANT_CLASS_P (exp))
283*38fd1498Szrj 	align = targetm.constant_alignment (exp, align);
284*38fd1498Szrj 
285*38fd1498Szrj       known_alignment = true;
286*38fd1498Szrj     }
287*38fd1498Szrj   else if (DECL_P (exp))
288*38fd1498Szrj     {
289*38fd1498Szrj       align = DECL_ALIGN (exp);
290*38fd1498Szrj       known_alignment = true;
291*38fd1498Szrj     }
292*38fd1498Szrj   else if (TREE_CODE (exp) == INDIRECT_REF
293*38fd1498Szrj 	   || TREE_CODE (exp) == MEM_REF
294*38fd1498Szrj 	   || TREE_CODE (exp) == TARGET_MEM_REF)
295*38fd1498Szrj     {
296*38fd1498Szrj       tree addr = TREE_OPERAND (exp, 0);
297*38fd1498Szrj       unsigned ptr_align;
298*38fd1498Szrj       unsigned HOST_WIDE_INT ptr_bitpos;
299*38fd1498Szrj       unsigned HOST_WIDE_INT ptr_bitmask = ~0;
300*38fd1498Szrj 
301*38fd1498Szrj       /* If the address is explicitely aligned, handle that.  */
302*38fd1498Szrj       if (TREE_CODE (addr) == BIT_AND_EXPR
303*38fd1498Szrj 	  && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
304*38fd1498Szrj 	{
305*38fd1498Szrj 	  ptr_bitmask = TREE_INT_CST_LOW (TREE_OPERAND (addr, 1));
306*38fd1498Szrj 	  ptr_bitmask *= BITS_PER_UNIT;
307*38fd1498Szrj 	  align = least_bit_hwi (ptr_bitmask);
308*38fd1498Szrj 	  addr = TREE_OPERAND (addr, 0);
309*38fd1498Szrj 	}
310*38fd1498Szrj 
311*38fd1498Szrj       known_alignment
312*38fd1498Szrj 	= get_pointer_alignment_1 (addr, &ptr_align, &ptr_bitpos);
313*38fd1498Szrj       align = MAX (ptr_align, align);
314*38fd1498Szrj 
315*38fd1498Szrj       /* Re-apply explicit alignment to the bitpos.  */
316*38fd1498Szrj       ptr_bitpos &= ptr_bitmask;
317*38fd1498Szrj 
318*38fd1498Szrj       /* The alignment of the pointer operand in a TARGET_MEM_REF
319*38fd1498Szrj 	 has to take the variable offset parts into account.  */
320*38fd1498Szrj       if (TREE_CODE (exp) == TARGET_MEM_REF)
321*38fd1498Szrj 	{
322*38fd1498Szrj 	  if (TMR_INDEX (exp))
323*38fd1498Szrj 	    {
324*38fd1498Szrj 	      unsigned HOST_WIDE_INT step = 1;
325*38fd1498Szrj 	      if (TMR_STEP (exp))
326*38fd1498Szrj 		step = TREE_INT_CST_LOW (TMR_STEP (exp));
327*38fd1498Szrj 	      align = MIN (align, least_bit_hwi (step) * BITS_PER_UNIT);
328*38fd1498Szrj 	    }
329*38fd1498Szrj 	  if (TMR_INDEX2 (exp))
330*38fd1498Szrj 	    align = BITS_PER_UNIT;
331*38fd1498Szrj 	  known_alignment = false;
332*38fd1498Szrj 	}
333*38fd1498Szrj 
334*38fd1498Szrj       /* When EXP is an actual memory reference then we can use
335*38fd1498Szrj 	 TYPE_ALIGN of a pointer indirection to derive alignment.
336*38fd1498Szrj 	 Do so only if get_pointer_alignment_1 did not reveal absolute
337*38fd1498Szrj 	 alignment knowledge and if using that alignment would
338*38fd1498Szrj 	 improve the situation.  */
339*38fd1498Szrj       unsigned int talign;
340*38fd1498Szrj       if (!addr_p && !known_alignment
341*38fd1498Szrj 	  && (talign = min_align_of_type (TREE_TYPE (exp)) * BITS_PER_UNIT)
342*38fd1498Szrj 	  && talign > align)
343*38fd1498Szrj 	align = talign;
344*38fd1498Szrj       else
345*38fd1498Szrj 	{
346*38fd1498Szrj 	  /* Else adjust bitpos accordingly.  */
347*38fd1498Szrj 	  bitpos += ptr_bitpos;
348*38fd1498Szrj 	  if (TREE_CODE (exp) == MEM_REF
349*38fd1498Szrj 	      || TREE_CODE (exp) == TARGET_MEM_REF)
350*38fd1498Szrj 	    bitpos += mem_ref_offset (exp).force_shwi () * BITS_PER_UNIT;
351*38fd1498Szrj 	}
352*38fd1498Szrj     }
353*38fd1498Szrj   else if (TREE_CODE (exp) == STRING_CST)
354*38fd1498Szrj     {
355*38fd1498Szrj       /* STRING_CST are the only constant objects we allow to be not
356*38fd1498Szrj          wrapped inside a CONST_DECL.  */
357*38fd1498Szrj       align = TYPE_ALIGN (TREE_TYPE (exp));
358*38fd1498Szrj       if (CONSTANT_CLASS_P (exp))
359*38fd1498Szrj 	align = targetm.constant_alignment (exp, align);
360*38fd1498Szrj 
361*38fd1498Szrj       known_alignment = true;
362*38fd1498Szrj     }
363*38fd1498Szrj 
364*38fd1498Szrj   /* If there is a non-constant offset part extract the maximum
365*38fd1498Szrj      alignment that can prevail.  */
366*38fd1498Szrj   if (offset)
367*38fd1498Szrj     {
368*38fd1498Szrj       unsigned int trailing_zeros = tree_ctz (offset);
369*38fd1498Szrj       if (trailing_zeros < HOST_BITS_PER_INT)
370*38fd1498Szrj 	{
371*38fd1498Szrj 	  unsigned int inner = (1U << trailing_zeros) * BITS_PER_UNIT;
372*38fd1498Szrj 	  if (inner)
373*38fd1498Szrj 	    align = MIN (align, inner);
374*38fd1498Szrj 	}
375*38fd1498Szrj     }
376*38fd1498Szrj 
377*38fd1498Szrj   /* Account for the alignment of runtime coefficients, so that the constant
378*38fd1498Szrj      bitpos is guaranteed to be accurate.  */
379*38fd1498Szrj   unsigned int alt_align = ::known_alignment (bitpos - bitpos.coeffs[0]);
380*38fd1498Szrj   if (alt_align != 0 && alt_align < align)
381*38fd1498Szrj     {
382*38fd1498Szrj       align = alt_align;
383*38fd1498Szrj       known_alignment = false;
384*38fd1498Szrj     }
385*38fd1498Szrj 
386*38fd1498Szrj   *alignp = align;
387*38fd1498Szrj   *bitposp = bitpos.coeffs[0] & (align - 1);
388*38fd1498Szrj   return known_alignment;
389*38fd1498Szrj }
390*38fd1498Szrj 
391*38fd1498Szrj /* For a memory reference expression EXP compute values M and N such that M
392*38fd1498Szrj    divides (&EXP - N) and such that N < M.  If these numbers can be determined,
393*38fd1498Szrj    store M in alignp and N in *BITPOSP and return true.  Otherwise return false
394*38fd1498Szrj    and store BITS_PER_UNIT to *alignp and any bit-offset to *bitposp.  */
395*38fd1498Szrj 
396*38fd1498Szrj bool
get_object_alignment_1(tree exp,unsigned int * alignp,unsigned HOST_WIDE_INT * bitposp)397*38fd1498Szrj get_object_alignment_1 (tree exp, unsigned int *alignp,
398*38fd1498Szrj 			unsigned HOST_WIDE_INT *bitposp)
399*38fd1498Szrj {
400*38fd1498Szrj   return get_object_alignment_2 (exp, alignp, bitposp, false);
401*38fd1498Szrj }
402*38fd1498Szrj 
403*38fd1498Szrj /* Return the alignment in bits of EXP, an object.  */
404*38fd1498Szrj 
405*38fd1498Szrj unsigned int
get_object_alignment(tree exp)406*38fd1498Szrj get_object_alignment (tree exp)
407*38fd1498Szrj {
408*38fd1498Szrj   unsigned HOST_WIDE_INT bitpos = 0;
409*38fd1498Szrj   unsigned int align;
410*38fd1498Szrj 
411*38fd1498Szrj   get_object_alignment_1 (exp, &align, &bitpos);
412*38fd1498Szrj 
413*38fd1498Szrj   /* align and bitpos now specify known low bits of the pointer.
414*38fd1498Szrj      ptr & (align - 1) == bitpos.  */
415*38fd1498Szrj 
416*38fd1498Szrj   if (bitpos != 0)
417*38fd1498Szrj     align = least_bit_hwi (bitpos);
418*38fd1498Szrj   return align;
419*38fd1498Szrj }
420*38fd1498Szrj 
421*38fd1498Szrj /* For a pointer valued expression EXP compute values M and N such that M
422*38fd1498Szrj    divides (EXP - N) and such that N < M.  If these numbers can be determined,
423*38fd1498Szrj    store M in alignp and N in *BITPOSP and return true.  Return false if
424*38fd1498Szrj    the results are just a conservative approximation.
425*38fd1498Szrj 
426*38fd1498Szrj    If EXP is not a pointer, false is returned too.  */
427*38fd1498Szrj 
428*38fd1498Szrj bool
get_pointer_alignment_1(tree exp,unsigned int * alignp,unsigned HOST_WIDE_INT * bitposp)429*38fd1498Szrj get_pointer_alignment_1 (tree exp, unsigned int *alignp,
430*38fd1498Szrj 			 unsigned HOST_WIDE_INT *bitposp)
431*38fd1498Szrj {
432*38fd1498Szrj   STRIP_NOPS (exp);
433*38fd1498Szrj 
434*38fd1498Szrj   if (TREE_CODE (exp) == ADDR_EXPR)
435*38fd1498Szrj     return get_object_alignment_2 (TREE_OPERAND (exp, 0),
436*38fd1498Szrj 				   alignp, bitposp, true);
437*38fd1498Szrj   else if (TREE_CODE (exp) == POINTER_PLUS_EXPR)
438*38fd1498Szrj     {
439*38fd1498Szrj       unsigned int align;
440*38fd1498Szrj       unsigned HOST_WIDE_INT bitpos;
441*38fd1498Szrj       bool res = get_pointer_alignment_1 (TREE_OPERAND (exp, 0),
442*38fd1498Szrj 					  &align, &bitpos);
443*38fd1498Szrj       if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
444*38fd1498Szrj 	bitpos += TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)) * BITS_PER_UNIT;
445*38fd1498Szrj       else
446*38fd1498Szrj 	{
447*38fd1498Szrj 	  unsigned int trailing_zeros = tree_ctz (TREE_OPERAND (exp, 1));
448*38fd1498Szrj 	  if (trailing_zeros < HOST_BITS_PER_INT)
449*38fd1498Szrj 	    {
450*38fd1498Szrj 	      unsigned int inner = (1U << trailing_zeros) * BITS_PER_UNIT;
451*38fd1498Szrj 	      if (inner)
452*38fd1498Szrj 		align = MIN (align, inner);
453*38fd1498Szrj 	    }
454*38fd1498Szrj 	}
455*38fd1498Szrj       *alignp = align;
456*38fd1498Szrj       *bitposp = bitpos & (align - 1);
457*38fd1498Szrj       return res;
458*38fd1498Szrj     }
459*38fd1498Szrj   else if (TREE_CODE (exp) == SSA_NAME
460*38fd1498Szrj 	   && POINTER_TYPE_P (TREE_TYPE (exp)))
461*38fd1498Szrj     {
462*38fd1498Szrj       unsigned int ptr_align, ptr_misalign;
463*38fd1498Szrj       struct ptr_info_def *pi = SSA_NAME_PTR_INFO (exp);
464*38fd1498Szrj 
465*38fd1498Szrj       if (pi && get_ptr_info_alignment (pi, &ptr_align, &ptr_misalign))
466*38fd1498Szrj 	{
467*38fd1498Szrj 	  *bitposp = ptr_misalign * BITS_PER_UNIT;
468*38fd1498Szrj 	  *alignp = ptr_align * BITS_PER_UNIT;
469*38fd1498Szrj 	  /* Make sure to return a sensible alignment when the multiplication
470*38fd1498Szrj 	     by BITS_PER_UNIT overflowed.  */
471*38fd1498Szrj 	  if (*alignp == 0)
472*38fd1498Szrj 	    *alignp = 1u << (HOST_BITS_PER_INT - 1);
473*38fd1498Szrj 	  /* We cannot really tell whether this result is an approximation.  */
474*38fd1498Szrj 	  return false;
475*38fd1498Szrj 	}
476*38fd1498Szrj       else
477*38fd1498Szrj 	{
478*38fd1498Szrj 	  *bitposp = 0;
479*38fd1498Szrj 	  *alignp = BITS_PER_UNIT;
480*38fd1498Szrj 	  return false;
481*38fd1498Szrj 	}
482*38fd1498Szrj     }
483*38fd1498Szrj   else if (TREE_CODE (exp) == INTEGER_CST)
484*38fd1498Szrj     {
485*38fd1498Szrj       *alignp = BIGGEST_ALIGNMENT;
486*38fd1498Szrj       *bitposp = ((TREE_INT_CST_LOW (exp) * BITS_PER_UNIT)
487*38fd1498Szrj 		  & (BIGGEST_ALIGNMENT - 1));
488*38fd1498Szrj       return true;
489*38fd1498Szrj     }
490*38fd1498Szrj 
491*38fd1498Szrj   *bitposp = 0;
492*38fd1498Szrj   *alignp = BITS_PER_UNIT;
493*38fd1498Szrj   return false;
494*38fd1498Szrj }
495*38fd1498Szrj 
496*38fd1498Szrj /* Return the alignment in bits of EXP, a pointer valued expression.
497*38fd1498Szrj    The alignment returned is, by default, the alignment of the thing that
498*38fd1498Szrj    EXP points to.  If it is not a POINTER_TYPE, 0 is returned.
499*38fd1498Szrj 
500*38fd1498Szrj    Otherwise, look at the expression to see if we can do better, i.e., if the
501*38fd1498Szrj    expression is actually pointing at an object whose alignment is tighter.  */
502*38fd1498Szrj 
503*38fd1498Szrj unsigned int
get_pointer_alignment(tree exp)504*38fd1498Szrj get_pointer_alignment (tree exp)
505*38fd1498Szrj {
506*38fd1498Szrj   unsigned HOST_WIDE_INT bitpos = 0;
507*38fd1498Szrj   unsigned int align;
508*38fd1498Szrj 
509*38fd1498Szrj   get_pointer_alignment_1 (exp, &align, &bitpos);
510*38fd1498Szrj 
511*38fd1498Szrj   /* align and bitpos now specify known low bits of the pointer.
512*38fd1498Szrj      ptr & (align - 1) == bitpos.  */
513*38fd1498Szrj 
514*38fd1498Szrj   if (bitpos != 0)
515*38fd1498Szrj     align = least_bit_hwi (bitpos);
516*38fd1498Szrj 
517*38fd1498Szrj   return align;
518*38fd1498Szrj }
519*38fd1498Szrj 
520*38fd1498Szrj /* Return the number of non-zero elements in the sequence
521*38fd1498Szrj    [ PTR, PTR + MAXELTS ) where each element's size is ELTSIZE bytes.
522*38fd1498Szrj    ELTSIZE must be a power of 2 less than 8.  Used by c_strlen.  */
523*38fd1498Szrj 
524*38fd1498Szrj static unsigned
string_length(const void * ptr,unsigned eltsize,unsigned maxelts)525*38fd1498Szrj string_length (const void *ptr, unsigned eltsize, unsigned maxelts)
526*38fd1498Szrj {
527*38fd1498Szrj   gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4);
528*38fd1498Szrj 
529*38fd1498Szrj   unsigned n;
530*38fd1498Szrj 
531*38fd1498Szrj   if (eltsize == 1)
532*38fd1498Szrj     {
533*38fd1498Szrj       /* Optimize the common case of plain char.  */
534*38fd1498Szrj       for (n = 0; n < maxelts; n++)
535*38fd1498Szrj 	{
536*38fd1498Szrj 	  const char *elt = (const char*) ptr + n;
537*38fd1498Szrj 	  if (!*elt)
538*38fd1498Szrj 	    break;
539*38fd1498Szrj 	}
540*38fd1498Szrj     }
541*38fd1498Szrj   else
542*38fd1498Szrj     {
543*38fd1498Szrj       for (n = 0; n < maxelts; n++)
544*38fd1498Szrj 	{
545*38fd1498Szrj 	  const char *elt = (const char*) ptr + n * eltsize;
546*38fd1498Szrj 	  if (!memcmp (elt, "\0\0\0\0", eltsize))
547*38fd1498Szrj 	    break;
548*38fd1498Szrj 	}
549*38fd1498Szrj     }
550*38fd1498Szrj   return n;
551*38fd1498Szrj }
552*38fd1498Szrj 
553*38fd1498Szrj /* Compute the length of a null-terminated character string or wide
554*38fd1498Szrj    character string handling character sizes of 1, 2, and 4 bytes.
555*38fd1498Szrj    TREE_STRING_LENGTH is not the right way because it evaluates to
556*38fd1498Szrj    the size of the character array in bytes (as opposed to characters)
557*38fd1498Szrj    and because it can contain a zero byte in the middle.
558*38fd1498Szrj 
559*38fd1498Szrj    ONLY_VALUE should be nonzero if the result is not going to be emitted
560*38fd1498Szrj    into the instruction stream and zero if it is going to be expanded.
561*38fd1498Szrj    E.g. with i++ ? "foo" : "bar", if ONLY_VALUE is nonzero, constant 3
562*38fd1498Szrj    is returned, otherwise NULL, since
563*38fd1498Szrj    len = c_strlen (src, 1); if (len) expand_expr (len, ...); would not
564*38fd1498Szrj    evaluate the side-effects.
565*38fd1498Szrj 
566*38fd1498Szrj    If ONLY_VALUE is two then we do not emit warnings about out-of-bound
567*38fd1498Szrj    accesses.  Note that this implies the result is not going to be emitted
568*38fd1498Szrj    into the instruction stream.
569*38fd1498Szrj 
570*38fd1498Szrj    The value returned is of type `ssizetype'.
571*38fd1498Szrj 
572*38fd1498Szrj    Unfortunately, string_constant can't access the values of const char
573*38fd1498Szrj    arrays with initializers, so neither can we do so here.  */
574*38fd1498Szrj 
575*38fd1498Szrj tree
c_strlen(tree src,int only_value)576*38fd1498Szrj c_strlen (tree src, int only_value)
577*38fd1498Szrj {
578*38fd1498Szrj   STRIP_NOPS (src);
579*38fd1498Szrj   if (TREE_CODE (src) == COND_EXPR
580*38fd1498Szrj       && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
581*38fd1498Szrj     {
582*38fd1498Szrj       tree len1, len2;
583*38fd1498Szrj 
584*38fd1498Szrj       len1 = c_strlen (TREE_OPERAND (src, 1), only_value);
585*38fd1498Szrj       len2 = c_strlen (TREE_OPERAND (src, 2), only_value);
586*38fd1498Szrj       if (tree_int_cst_equal (len1, len2))
587*38fd1498Szrj 	return len1;
588*38fd1498Szrj     }
589*38fd1498Szrj 
590*38fd1498Szrj   if (TREE_CODE (src) == COMPOUND_EXPR
591*38fd1498Szrj       && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
592*38fd1498Szrj     return c_strlen (TREE_OPERAND (src, 1), only_value);
593*38fd1498Szrj 
594*38fd1498Szrj   location_t loc = EXPR_LOC_OR_LOC (src, input_location);
595*38fd1498Szrj 
596*38fd1498Szrj   /* Offset from the beginning of the string in bytes.  */
597*38fd1498Szrj   tree byteoff;
598*38fd1498Szrj   src = string_constant (src, &byteoff);
599*38fd1498Szrj   if (src == 0)
600*38fd1498Szrj     return NULL_TREE;
601*38fd1498Szrj 
602*38fd1498Szrj   /* Determine the size of the string element.  */
603*38fd1498Szrj   unsigned eltsize
604*38fd1498Szrj     = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (src))));
605*38fd1498Szrj 
606*38fd1498Szrj   /* Set MAXELTS to sizeof (SRC) / sizeof (*SRC) - 1, the maximum possible
607*38fd1498Szrj      length of SRC.  */
608*38fd1498Szrj   unsigned maxelts = TREE_STRING_LENGTH (src) / eltsize - 1;
609*38fd1498Szrj 
610*38fd1498Szrj   /* PTR can point to the byte representation of any string type, including
611*38fd1498Szrj      char* and wchar_t*.  */
612*38fd1498Szrj   const char *ptr = TREE_STRING_POINTER (src);
613*38fd1498Szrj 
614*38fd1498Szrj   if (byteoff && TREE_CODE (byteoff) != INTEGER_CST)
615*38fd1498Szrj     {
616*38fd1498Szrj       /* If the string has an internal zero byte (e.g., "foo\0bar"), we can't
617*38fd1498Szrj 	 compute the offset to the following null if we don't know where to
618*38fd1498Szrj 	 start searching for it.  */
619*38fd1498Szrj       if (string_length (ptr, eltsize, maxelts) < maxelts)
620*38fd1498Szrj 	{
621*38fd1498Szrj 	  /* Return when an embedded null character is found.  */
622*38fd1498Szrj 	  return NULL_TREE;
623*38fd1498Szrj 	}
624*38fd1498Szrj 
625*38fd1498Szrj       if (!maxelts)
626*38fd1498Szrj 	return ssize_int (0);
627*38fd1498Szrj 
628*38fd1498Szrj       /* We don't know the starting offset, but we do know that the string
629*38fd1498Szrj 	 has no internal zero bytes.  We can assume that the offset falls
630*38fd1498Szrj 	 within the bounds of the string; otherwise, the programmer deserves
631*38fd1498Szrj 	 what he gets.  Subtract the offset from the length of the string,
632*38fd1498Szrj 	 and return that.  This would perhaps not be valid if we were dealing
633*38fd1498Szrj 	 with named arrays in addition to literal string constants.  */
634*38fd1498Szrj 
635*38fd1498Szrj       return size_diffop_loc (loc, size_int (maxelts * eltsize), byteoff);
636*38fd1498Szrj     }
637*38fd1498Szrj 
638*38fd1498Szrj   /* Offset from the beginning of the string in elements.  */
639*38fd1498Szrj   HOST_WIDE_INT eltoff;
640*38fd1498Szrj 
641*38fd1498Szrj   /* We have a known offset into the string.  Start searching there for
642*38fd1498Szrj      a null character if we can represent it as a single HOST_WIDE_INT.  */
643*38fd1498Szrj   if (byteoff == 0)
644*38fd1498Szrj     eltoff = 0;
645*38fd1498Szrj   else if (! tree_fits_shwi_p (byteoff))
646*38fd1498Szrj     eltoff = -1;
647*38fd1498Szrj   else
648*38fd1498Szrj     eltoff = tree_to_shwi (byteoff) / eltsize;
649*38fd1498Szrj 
650*38fd1498Szrj   /* If the offset is known to be out of bounds, warn, and call strlen at
651*38fd1498Szrj      runtime.  */
652*38fd1498Szrj   if (eltoff < 0 || eltoff > maxelts)
653*38fd1498Szrj     {
654*38fd1498Szrj      /* Suppress multiple warnings for propagated constant strings.  */
655*38fd1498Szrj       if (only_value != 2
656*38fd1498Szrj 	  && !TREE_NO_WARNING (src))
657*38fd1498Szrj         {
658*38fd1498Szrj 	  warning_at (loc, OPT_Warray_bounds,
659*38fd1498Szrj 		      "offset %qwi outside bounds of constant string",
660*38fd1498Szrj 		      eltoff);
661*38fd1498Szrj           TREE_NO_WARNING (src) = 1;
662*38fd1498Szrj         }
663*38fd1498Szrj       return NULL_TREE;
664*38fd1498Szrj     }
665*38fd1498Szrj 
666*38fd1498Szrj   /* Use strlen to search for the first zero byte.  Since any strings
667*38fd1498Szrj      constructed with build_string will have nulls appended, we win even
668*38fd1498Szrj      if we get handed something like (char[4])"abcd".
669*38fd1498Szrj 
670*38fd1498Szrj      Since ELTOFF is our starting index into the string, no further
671*38fd1498Szrj      calculation is needed.  */
672*38fd1498Szrj   unsigned len = string_length (ptr + eltoff * eltsize, eltsize,
673*38fd1498Szrj 				maxelts - eltoff);
674*38fd1498Szrj 
675*38fd1498Szrj   return ssize_int (len);
676*38fd1498Szrj }
677*38fd1498Szrj 
678*38fd1498Szrj /* Return a constant integer corresponding to target reading
679*38fd1498Szrj    GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
680*38fd1498Szrj 
681*38fd1498Szrj static rtx
c_readstr(const char * str,scalar_int_mode mode)682*38fd1498Szrj c_readstr (const char *str, scalar_int_mode mode)
683*38fd1498Szrj {
684*38fd1498Szrj   HOST_WIDE_INT ch;
685*38fd1498Szrj   unsigned int i, j;
686*38fd1498Szrj   HOST_WIDE_INT tmp[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
687*38fd1498Szrj 
688*38fd1498Szrj   gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
689*38fd1498Szrj   unsigned int len = (GET_MODE_PRECISION (mode) + HOST_BITS_PER_WIDE_INT - 1)
690*38fd1498Szrj     / HOST_BITS_PER_WIDE_INT;
691*38fd1498Szrj 
692*38fd1498Szrj   gcc_assert (len <= MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT);
693*38fd1498Szrj   for (i = 0; i < len; i++)
694*38fd1498Szrj     tmp[i] = 0;
695*38fd1498Szrj 
696*38fd1498Szrj   ch = 1;
697*38fd1498Szrj   for (i = 0; i < GET_MODE_SIZE (mode); i++)
698*38fd1498Szrj     {
699*38fd1498Szrj       j = i;
700*38fd1498Szrj       if (WORDS_BIG_ENDIAN)
701*38fd1498Szrj 	j = GET_MODE_SIZE (mode) - i - 1;
702*38fd1498Szrj       if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
703*38fd1498Szrj 	  && GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
704*38fd1498Szrj 	j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
705*38fd1498Szrj       j *= BITS_PER_UNIT;
706*38fd1498Szrj 
707*38fd1498Szrj       if (ch)
708*38fd1498Szrj 	ch = (unsigned char) str[i];
709*38fd1498Szrj       tmp[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
710*38fd1498Szrj     }
711*38fd1498Szrj 
712*38fd1498Szrj   wide_int c = wide_int::from_array (tmp, len, GET_MODE_PRECISION (mode));
713*38fd1498Szrj   return immed_wide_int_const (c, mode);
714*38fd1498Szrj }
715*38fd1498Szrj 
716*38fd1498Szrj /* Cast a target constant CST to target CHAR and if that value fits into
717*38fd1498Szrj    host char type, return zero and put that value into variable pointed to by
718*38fd1498Szrj    P.  */
719*38fd1498Szrj 
720*38fd1498Szrj static int
target_char_cast(tree cst,char * p)721*38fd1498Szrj target_char_cast (tree cst, char *p)
722*38fd1498Szrj {
723*38fd1498Szrj   unsigned HOST_WIDE_INT val, hostval;
724*38fd1498Szrj 
725*38fd1498Szrj   if (TREE_CODE (cst) != INTEGER_CST
726*38fd1498Szrj       || CHAR_TYPE_SIZE > HOST_BITS_PER_WIDE_INT)
727*38fd1498Szrj     return 1;
728*38fd1498Szrj 
729*38fd1498Szrj   /* Do not care if it fits or not right here.  */
730*38fd1498Szrj   val = TREE_INT_CST_LOW (cst);
731*38fd1498Szrj 
732*38fd1498Szrj   if (CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT)
733*38fd1498Szrj     val &= (HOST_WIDE_INT_1U << CHAR_TYPE_SIZE) - 1;
734*38fd1498Szrj 
735*38fd1498Szrj   hostval = val;
736*38fd1498Szrj   if (HOST_BITS_PER_CHAR < HOST_BITS_PER_WIDE_INT)
737*38fd1498Szrj     hostval &= (HOST_WIDE_INT_1U << HOST_BITS_PER_CHAR) - 1;
738*38fd1498Szrj 
739*38fd1498Szrj   if (val != hostval)
740*38fd1498Szrj     return 1;
741*38fd1498Szrj 
742*38fd1498Szrj   *p = hostval;
743*38fd1498Szrj   return 0;
744*38fd1498Szrj }
745*38fd1498Szrj 
746*38fd1498Szrj /* Similar to save_expr, but assumes that arbitrary code is not executed
747*38fd1498Szrj    in between the multiple evaluations.  In particular, we assume that a
748*38fd1498Szrj    non-addressable local variable will not be modified.  */
749*38fd1498Szrj 
750*38fd1498Szrj static tree
builtin_save_expr(tree exp)751*38fd1498Szrj builtin_save_expr (tree exp)
752*38fd1498Szrj {
753*38fd1498Szrj   if (TREE_CODE (exp) == SSA_NAME
754*38fd1498Szrj       || (TREE_ADDRESSABLE (exp) == 0
755*38fd1498Szrj 	  && (TREE_CODE (exp) == PARM_DECL
756*38fd1498Szrj 	      || (VAR_P (exp) && !TREE_STATIC (exp)))))
757*38fd1498Szrj     return exp;
758*38fd1498Szrj 
759*38fd1498Szrj   return save_expr (exp);
760*38fd1498Szrj }
761*38fd1498Szrj 
762*38fd1498Szrj /* Given TEM, a pointer to a stack frame, follow the dynamic chain COUNT
763*38fd1498Szrj    times to get the address of either a higher stack frame, or a return
764*38fd1498Szrj    address located within it (depending on FNDECL_CODE).  */
765*38fd1498Szrj 
766*38fd1498Szrj static rtx
expand_builtin_return_addr(enum built_in_function fndecl_code,int count)767*38fd1498Szrj expand_builtin_return_addr (enum built_in_function fndecl_code, int count)
768*38fd1498Szrj {
769*38fd1498Szrj   int i;
770*38fd1498Szrj   rtx tem = INITIAL_FRAME_ADDRESS_RTX;
771*38fd1498Szrj   if (tem == NULL_RTX)
772*38fd1498Szrj     {
773*38fd1498Szrj       /* For a zero count with __builtin_return_address, we don't care what
774*38fd1498Szrj 	 frame address we return, because target-specific definitions will
775*38fd1498Szrj 	 override us.  Therefore frame pointer elimination is OK, and using
776*38fd1498Szrj 	 the soft frame pointer is OK.
777*38fd1498Szrj 
778*38fd1498Szrj 	 For a nonzero count, or a zero count with __builtin_frame_address,
779*38fd1498Szrj 	 we require a stable offset from the current frame pointer to the
780*38fd1498Szrj 	 previous one, so we must use the hard frame pointer, and
781*38fd1498Szrj 	 we must disable frame pointer elimination.  */
782*38fd1498Szrj       if (count == 0 && fndecl_code == BUILT_IN_RETURN_ADDRESS)
783*38fd1498Szrj 	tem = frame_pointer_rtx;
784*38fd1498Szrj       else
785*38fd1498Szrj 	{
786*38fd1498Szrj 	  tem = hard_frame_pointer_rtx;
787*38fd1498Szrj 
788*38fd1498Szrj 	  /* Tell reload not to eliminate the frame pointer.  */
789*38fd1498Szrj 	  crtl->accesses_prior_frames = 1;
790*38fd1498Szrj 	}
791*38fd1498Szrj     }
792*38fd1498Szrj 
793*38fd1498Szrj   if (count > 0)
794*38fd1498Szrj     SETUP_FRAME_ADDRESSES ();
795*38fd1498Szrj 
796*38fd1498Szrj   /* On the SPARC, the return address is not in the frame, it is in a
797*38fd1498Szrj      register.  There is no way to access it off of the current frame
798*38fd1498Szrj      pointer, but it can be accessed off the previous frame pointer by
799*38fd1498Szrj      reading the value from the register window save area.  */
800*38fd1498Szrj   if (RETURN_ADDR_IN_PREVIOUS_FRAME && fndecl_code == BUILT_IN_RETURN_ADDRESS)
801*38fd1498Szrj     count--;
802*38fd1498Szrj 
803*38fd1498Szrj   /* Scan back COUNT frames to the specified frame.  */
804*38fd1498Szrj   for (i = 0; i < count; i++)
805*38fd1498Szrj     {
806*38fd1498Szrj       /* Assume the dynamic chain pointer is in the word that the
807*38fd1498Szrj 	 frame address points to, unless otherwise specified.  */
808*38fd1498Szrj       tem = DYNAMIC_CHAIN_ADDRESS (tem);
809*38fd1498Szrj       tem = memory_address (Pmode, tem);
810*38fd1498Szrj       tem = gen_frame_mem (Pmode, tem);
811*38fd1498Szrj       tem = copy_to_reg (tem);
812*38fd1498Szrj     }
813*38fd1498Szrj 
814*38fd1498Szrj   /* For __builtin_frame_address, return what we've got.  But, on
815*38fd1498Szrj      the SPARC for example, we may have to add a bias.  */
816*38fd1498Szrj   if (fndecl_code == BUILT_IN_FRAME_ADDRESS)
817*38fd1498Szrj     return FRAME_ADDR_RTX (tem);
818*38fd1498Szrj 
819*38fd1498Szrj   /* For __builtin_return_address, get the return address from that frame.  */
820*38fd1498Szrj #ifdef RETURN_ADDR_RTX
821*38fd1498Szrj   tem = RETURN_ADDR_RTX (count, tem);
822*38fd1498Szrj #else
823*38fd1498Szrj   tem = memory_address (Pmode,
824*38fd1498Szrj 			plus_constant (Pmode, tem, GET_MODE_SIZE (Pmode)));
825*38fd1498Szrj   tem = gen_frame_mem (Pmode, tem);
826*38fd1498Szrj #endif
827*38fd1498Szrj   return tem;
828*38fd1498Szrj }
829*38fd1498Szrj 
830*38fd1498Szrj /* Alias set used for setjmp buffer.  */
831*38fd1498Szrj static alias_set_type setjmp_alias_set = -1;
832*38fd1498Szrj 
833*38fd1498Szrj /* Construct the leading half of a __builtin_setjmp call.  Control will
834*38fd1498Szrj    return to RECEIVER_LABEL.  This is also called directly by the SJLJ
835*38fd1498Szrj    exception handling code.  */
836*38fd1498Szrj 
837*38fd1498Szrj void
expand_builtin_setjmp_setup(rtx buf_addr,rtx receiver_label)838*38fd1498Szrj expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
839*38fd1498Szrj {
840*38fd1498Szrj   machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
841*38fd1498Szrj   rtx stack_save;
842*38fd1498Szrj   rtx mem;
843*38fd1498Szrj 
844*38fd1498Szrj   if (setjmp_alias_set == -1)
845*38fd1498Szrj     setjmp_alias_set = new_alias_set ();
846*38fd1498Szrj 
847*38fd1498Szrj   buf_addr = convert_memory_address (Pmode, buf_addr);
848*38fd1498Szrj 
849*38fd1498Szrj   buf_addr = force_reg (Pmode, force_operand (buf_addr, NULL_RTX));
850*38fd1498Szrj 
851*38fd1498Szrj   /* We store the frame pointer and the address of receiver_label in
852*38fd1498Szrj      the buffer and use the rest of it for the stack save area, which
853*38fd1498Szrj      is machine-dependent.  */
854*38fd1498Szrj 
855*38fd1498Szrj   mem = gen_rtx_MEM (Pmode, buf_addr);
856*38fd1498Szrj   set_mem_alias_set (mem, setjmp_alias_set);
857*38fd1498Szrj   emit_move_insn (mem, targetm.builtin_setjmp_frame_value ());
858*38fd1498Szrj 
859*38fd1498Szrj   mem = gen_rtx_MEM (Pmode, plus_constant (Pmode, buf_addr,
860*38fd1498Szrj 					   GET_MODE_SIZE (Pmode))),
861*38fd1498Szrj   set_mem_alias_set (mem, setjmp_alias_set);
862*38fd1498Szrj 
863*38fd1498Szrj   emit_move_insn (validize_mem (mem),
864*38fd1498Szrj 		  force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, receiver_label)));
865*38fd1498Szrj 
866*38fd1498Szrj   stack_save = gen_rtx_MEM (sa_mode,
867*38fd1498Szrj 			    plus_constant (Pmode, buf_addr,
868*38fd1498Szrj 					   2 * GET_MODE_SIZE (Pmode)));
869*38fd1498Szrj   set_mem_alias_set (stack_save, setjmp_alias_set);
870*38fd1498Szrj   emit_stack_save (SAVE_NONLOCAL, &stack_save);
871*38fd1498Szrj 
872*38fd1498Szrj   /* If there is further processing to do, do it.  */
873*38fd1498Szrj   if (targetm.have_builtin_setjmp_setup ())
874*38fd1498Szrj     emit_insn (targetm.gen_builtin_setjmp_setup (buf_addr));
875*38fd1498Szrj 
876*38fd1498Szrj   /* We have a nonlocal label.   */
877*38fd1498Szrj   cfun->has_nonlocal_label = 1;
878*38fd1498Szrj }
879*38fd1498Szrj 
880*38fd1498Szrj /* Construct the trailing part of a __builtin_setjmp call.  This is
881*38fd1498Szrj    also called directly by the SJLJ exception handling code.
882*38fd1498Szrj    If RECEIVER_LABEL is NULL, instead contruct a nonlocal goto handler.  */
883*38fd1498Szrj 
884*38fd1498Szrj void
expand_builtin_setjmp_receiver(rtx receiver_label)885*38fd1498Szrj expand_builtin_setjmp_receiver (rtx receiver_label)
886*38fd1498Szrj {
887*38fd1498Szrj   rtx chain;
888*38fd1498Szrj 
889*38fd1498Szrj   /* Mark the FP as used when we get here, so we have to make sure it's
890*38fd1498Szrj      marked as used by this function.  */
891*38fd1498Szrj   emit_use (hard_frame_pointer_rtx);
892*38fd1498Szrj 
893*38fd1498Szrj   /* Mark the static chain as clobbered here so life information
894*38fd1498Szrj      doesn't get messed up for it.  */
895*38fd1498Szrj   chain = rtx_for_static_chain (current_function_decl, true);
896*38fd1498Szrj   if (chain && REG_P (chain))
897*38fd1498Szrj     emit_clobber (chain);
898*38fd1498Szrj 
899*38fd1498Szrj   /* Now put in the code to restore the frame pointer, and argument
900*38fd1498Szrj      pointer, if needed.  */
901*38fd1498Szrj   if (! targetm.have_nonlocal_goto ())
902*38fd1498Szrj     {
903*38fd1498Szrj       /* First adjust our frame pointer to its actual value.  It was
904*38fd1498Szrj 	 previously set to the start of the virtual area corresponding to
905*38fd1498Szrj 	 the stacked variables when we branched here and now needs to be
906*38fd1498Szrj 	 adjusted to the actual hardware fp value.
907*38fd1498Szrj 
908*38fd1498Szrj 	 Assignments to virtual registers are converted by
909*38fd1498Szrj 	 instantiate_virtual_regs into the corresponding assignment
910*38fd1498Szrj 	 to the underlying register (fp in this case) that makes
911*38fd1498Szrj 	 the original assignment true.
912*38fd1498Szrj 	 So the following insn will actually be decrementing fp by
913*38fd1498Szrj 	 TARGET_STARTING_FRAME_OFFSET.  */
914*38fd1498Szrj       emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
915*38fd1498Szrj 
916*38fd1498Szrj       /* Restoring the frame pointer also modifies the hard frame pointer.
917*38fd1498Szrj 	 Mark it used (so that the previous assignment remains live once
918*38fd1498Szrj 	 the frame pointer is eliminated) and clobbered (to represent the
919*38fd1498Szrj 	 implicit update from the assignment).  */
920*38fd1498Szrj       emit_use (hard_frame_pointer_rtx);
921*38fd1498Szrj       emit_clobber (hard_frame_pointer_rtx);
922*38fd1498Szrj     }
923*38fd1498Szrj 
924*38fd1498Szrj   if (!HARD_FRAME_POINTER_IS_ARG_POINTER && fixed_regs[ARG_POINTER_REGNUM])
925*38fd1498Szrj     {
926*38fd1498Szrj       /* If the argument pointer can be eliminated in favor of the
927*38fd1498Szrj 	 frame pointer, we don't need to restore it.  We assume here
928*38fd1498Szrj 	 that if such an elimination is present, it can always be used.
929*38fd1498Szrj 	 This is the case on all known machines; if we don't make this
930*38fd1498Szrj 	 assumption, we do unnecessary saving on many machines.  */
931*38fd1498Szrj       size_t i;
932*38fd1498Szrj       static const struct elims {const int from, to;} elim_regs[] = ELIMINABLE_REGS;
933*38fd1498Szrj 
934*38fd1498Szrj       for (i = 0; i < ARRAY_SIZE (elim_regs); i++)
935*38fd1498Szrj 	if (elim_regs[i].from == ARG_POINTER_REGNUM
936*38fd1498Szrj 	    && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
937*38fd1498Szrj 	  break;
938*38fd1498Szrj 
939*38fd1498Szrj       if (i == ARRAY_SIZE (elim_regs))
940*38fd1498Szrj 	{
941*38fd1498Szrj 	  /* Now restore our arg pointer from the address at which it
942*38fd1498Szrj 	     was saved in our stack frame.  */
943*38fd1498Szrj 	  emit_move_insn (crtl->args.internal_arg_pointer,
944*38fd1498Szrj 			  copy_to_reg (get_arg_pointer_save_area ()));
945*38fd1498Szrj 	}
946*38fd1498Szrj     }
947*38fd1498Szrj 
948*38fd1498Szrj   if (receiver_label != NULL && targetm.have_builtin_setjmp_receiver ())
949*38fd1498Szrj     emit_insn (targetm.gen_builtin_setjmp_receiver (receiver_label));
950*38fd1498Szrj   else if (targetm.have_nonlocal_goto_receiver ())
951*38fd1498Szrj     emit_insn (targetm.gen_nonlocal_goto_receiver ());
952*38fd1498Szrj   else
953*38fd1498Szrj     { /* Nothing */ }
954*38fd1498Szrj 
955*38fd1498Szrj   /* We must not allow the code we just generated to be reordered by
956*38fd1498Szrj      scheduling.  Specifically, the update of the frame pointer must
957*38fd1498Szrj      happen immediately, not later.  */
958*38fd1498Szrj   emit_insn (gen_blockage ());
959*38fd1498Szrj }
960*38fd1498Szrj 
961*38fd1498Szrj /* __builtin_longjmp is passed a pointer to an array of five words (not
962*38fd1498Szrj    all will be used on all machines).  It operates similarly to the C
963*38fd1498Szrj    library function of the same name, but is more efficient.  Much of
964*38fd1498Szrj    the code below is copied from the handling of non-local gotos.  */
965*38fd1498Szrj 
966*38fd1498Szrj static void
expand_builtin_longjmp(rtx buf_addr,rtx value)967*38fd1498Szrj expand_builtin_longjmp (rtx buf_addr, rtx value)
968*38fd1498Szrj {
969*38fd1498Szrj   rtx fp, lab, stack;
970*38fd1498Szrj   rtx_insn *insn, *last;
971*38fd1498Szrj   machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
972*38fd1498Szrj 
973*38fd1498Szrj   /* DRAP is needed for stack realign if longjmp is expanded to current
974*38fd1498Szrj      function  */
975*38fd1498Szrj   if (SUPPORTS_STACK_ALIGNMENT)
976*38fd1498Szrj     crtl->need_drap = true;
977*38fd1498Szrj 
978*38fd1498Szrj   if (setjmp_alias_set == -1)
979*38fd1498Szrj     setjmp_alias_set = new_alias_set ();
980*38fd1498Szrj 
981*38fd1498Szrj   buf_addr = convert_memory_address (Pmode, buf_addr);
982*38fd1498Szrj 
983*38fd1498Szrj   buf_addr = force_reg (Pmode, buf_addr);
984*38fd1498Szrj 
985*38fd1498Szrj   /* We require that the user must pass a second argument of 1, because
986*38fd1498Szrj      that is what builtin_setjmp will return.  */
987*38fd1498Szrj   gcc_assert (value == const1_rtx);
988*38fd1498Szrj 
989*38fd1498Szrj   last = get_last_insn ();
990*38fd1498Szrj   if (targetm.have_builtin_longjmp ())
991*38fd1498Szrj     emit_insn (targetm.gen_builtin_longjmp (buf_addr));
992*38fd1498Szrj   else
993*38fd1498Szrj     {
994*38fd1498Szrj       fp = gen_rtx_MEM (Pmode, buf_addr);
995*38fd1498Szrj       lab = gen_rtx_MEM (Pmode, plus_constant (Pmode, buf_addr,
996*38fd1498Szrj 					       GET_MODE_SIZE (Pmode)));
997*38fd1498Szrj 
998*38fd1498Szrj       stack = gen_rtx_MEM (sa_mode, plus_constant (Pmode, buf_addr,
999*38fd1498Szrj 						   2 * GET_MODE_SIZE (Pmode)));
1000*38fd1498Szrj       set_mem_alias_set (fp, setjmp_alias_set);
1001*38fd1498Szrj       set_mem_alias_set (lab, setjmp_alias_set);
1002*38fd1498Szrj       set_mem_alias_set (stack, setjmp_alias_set);
1003*38fd1498Szrj 
1004*38fd1498Szrj       /* Pick up FP, label, and SP from the block and jump.  This code is
1005*38fd1498Szrj 	 from expand_goto in stmt.c; see there for detailed comments.  */
1006*38fd1498Szrj       if (targetm.have_nonlocal_goto ())
1007*38fd1498Szrj 	/* We have to pass a value to the nonlocal_goto pattern that will
1008*38fd1498Szrj 	   get copied into the static_chain pointer, but it does not matter
1009*38fd1498Szrj 	   what that value is, because builtin_setjmp does not use it.  */
1010*38fd1498Szrj 	emit_insn (targetm.gen_nonlocal_goto (value, lab, stack, fp));
1011*38fd1498Szrj       else
1012*38fd1498Szrj 	{
1013*38fd1498Szrj 	  lab = copy_to_reg (lab);
1014*38fd1498Szrj 
1015*38fd1498Szrj 	  emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
1016*38fd1498Szrj 	  emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
1017*38fd1498Szrj 
1018*38fd1498Szrj 	  emit_move_insn (hard_frame_pointer_rtx, fp);
1019*38fd1498Szrj 	  emit_stack_restore (SAVE_NONLOCAL, stack);
1020*38fd1498Szrj 
1021*38fd1498Szrj 	  emit_use (hard_frame_pointer_rtx);
1022*38fd1498Szrj 	  emit_use (stack_pointer_rtx);
1023*38fd1498Szrj 	  emit_indirect_jump (lab);
1024*38fd1498Szrj 	}
1025*38fd1498Szrj     }
1026*38fd1498Szrj 
1027*38fd1498Szrj   /* Search backwards and mark the jump insn as a non-local goto.
1028*38fd1498Szrj      Note that this precludes the use of __builtin_longjmp to a
1029*38fd1498Szrj      __builtin_setjmp target in the same function.  However, we've
1030*38fd1498Szrj      already cautioned the user that these functions are for
1031*38fd1498Szrj      internal exception handling use only.  */
1032*38fd1498Szrj   for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
1033*38fd1498Szrj     {
1034*38fd1498Szrj       gcc_assert (insn != last);
1035*38fd1498Szrj 
1036*38fd1498Szrj       if (JUMP_P (insn))
1037*38fd1498Szrj 	{
1038*38fd1498Szrj 	  add_reg_note (insn, REG_NON_LOCAL_GOTO, const0_rtx);
1039*38fd1498Szrj 	  break;
1040*38fd1498Szrj 	}
1041*38fd1498Szrj       else if (CALL_P (insn))
1042*38fd1498Szrj 	break;
1043*38fd1498Szrj     }
1044*38fd1498Szrj }
1045*38fd1498Szrj 
1046*38fd1498Szrj static inline bool
more_const_call_expr_args_p(const const_call_expr_arg_iterator * iter)1047*38fd1498Szrj more_const_call_expr_args_p (const const_call_expr_arg_iterator *iter)
1048*38fd1498Szrj {
1049*38fd1498Szrj   return (iter->i < iter->n);
1050*38fd1498Szrj }
1051*38fd1498Szrj 
1052*38fd1498Szrj /* This function validates the types of a function call argument list
1053*38fd1498Szrj    against a specified list of tree_codes.  If the last specifier is a 0,
1054*38fd1498Szrj    that represents an ellipsis, otherwise the last specifier must be a
1055*38fd1498Szrj    VOID_TYPE.  */
1056*38fd1498Szrj 
1057*38fd1498Szrj static bool
validate_arglist(const_tree callexpr,...)1058*38fd1498Szrj validate_arglist (const_tree callexpr, ...)
1059*38fd1498Szrj {
1060*38fd1498Szrj   enum tree_code code;
1061*38fd1498Szrj   bool res = 0;
1062*38fd1498Szrj   va_list ap;
1063*38fd1498Szrj   const_call_expr_arg_iterator iter;
1064*38fd1498Szrj   const_tree arg;
1065*38fd1498Szrj 
1066*38fd1498Szrj   va_start (ap, callexpr);
1067*38fd1498Szrj   init_const_call_expr_arg_iterator (callexpr, &iter);
1068*38fd1498Szrj 
1069*38fd1498Szrj   /* Get a bitmap of pointer argument numbers declared attribute nonnull.  */
1070*38fd1498Szrj   tree fn = CALL_EXPR_FN (callexpr);
1071*38fd1498Szrj   bitmap argmap = get_nonnull_args (TREE_TYPE (TREE_TYPE (fn)));
1072*38fd1498Szrj 
1073*38fd1498Szrj   for (unsigned argno = 1; ; ++argno)
1074*38fd1498Szrj     {
1075*38fd1498Szrj       code = (enum tree_code) va_arg (ap, int);
1076*38fd1498Szrj 
1077*38fd1498Szrj       switch (code)
1078*38fd1498Szrj 	{
1079*38fd1498Szrj 	case 0:
1080*38fd1498Szrj 	  /* This signifies an ellipses, any further arguments are all ok.  */
1081*38fd1498Szrj 	  res = true;
1082*38fd1498Szrj 	  goto end;
1083*38fd1498Szrj 	case VOID_TYPE:
1084*38fd1498Szrj 	  /* This signifies an endlink, if no arguments remain, return
1085*38fd1498Szrj 	     true, otherwise return false.  */
1086*38fd1498Szrj 	  res = !more_const_call_expr_args_p (&iter);
1087*38fd1498Szrj 	  goto end;
1088*38fd1498Szrj 	case POINTER_TYPE:
1089*38fd1498Szrj 	  /* The actual argument must be nonnull when either the whole
1090*38fd1498Szrj 	     called function has been declared nonnull, or when the formal
1091*38fd1498Szrj 	     argument corresponding to the actual argument has been.  */
1092*38fd1498Szrj 	  if (argmap
1093*38fd1498Szrj 	      && (bitmap_empty_p (argmap) || bitmap_bit_p (argmap, argno)))
1094*38fd1498Szrj 	    {
1095*38fd1498Szrj 	      arg = next_const_call_expr_arg (&iter);
1096*38fd1498Szrj 	      if (!validate_arg (arg, code) || integer_zerop (arg))
1097*38fd1498Szrj 		goto end;
1098*38fd1498Szrj 	      break;
1099*38fd1498Szrj 	    }
1100*38fd1498Szrj 	  /* FALLTHRU */
1101*38fd1498Szrj 	default:
1102*38fd1498Szrj 	  /* If no parameters remain or the parameter's code does not
1103*38fd1498Szrj 	     match the specified code, return false.  Otherwise continue
1104*38fd1498Szrj 	     checking any remaining arguments.  */
1105*38fd1498Szrj 	  arg = next_const_call_expr_arg (&iter);
1106*38fd1498Szrj 	  if (!validate_arg (arg, code))
1107*38fd1498Szrj 	    goto end;
1108*38fd1498Szrj 	  break;
1109*38fd1498Szrj 	}
1110*38fd1498Szrj     }
1111*38fd1498Szrj 
1112*38fd1498Szrj   /* We need gotos here since we can only have one VA_CLOSE in a
1113*38fd1498Szrj      function.  */
1114*38fd1498Szrj  end: ;
1115*38fd1498Szrj   va_end (ap);
1116*38fd1498Szrj 
1117*38fd1498Szrj   BITMAP_FREE (argmap);
1118*38fd1498Szrj 
1119*38fd1498Szrj   return res;
1120*38fd1498Szrj }
1121*38fd1498Szrj 
1122*38fd1498Szrj /* Expand a call to __builtin_nonlocal_goto.  We're passed the target label
1123*38fd1498Szrj    and the address of the save area.  */
1124*38fd1498Szrj 
1125*38fd1498Szrj static rtx
expand_builtin_nonlocal_goto(tree exp)1126*38fd1498Szrj expand_builtin_nonlocal_goto (tree exp)
1127*38fd1498Szrj {
1128*38fd1498Szrj   tree t_label, t_save_area;
1129*38fd1498Szrj   rtx r_label, r_save_area, r_fp, r_sp;
1130*38fd1498Szrj   rtx_insn *insn;
1131*38fd1498Szrj 
1132*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
1133*38fd1498Szrj     return NULL_RTX;
1134*38fd1498Szrj 
1135*38fd1498Szrj   t_label = CALL_EXPR_ARG (exp, 0);
1136*38fd1498Szrj   t_save_area = CALL_EXPR_ARG (exp, 1);
1137*38fd1498Szrj 
1138*38fd1498Szrj   r_label = expand_normal (t_label);
1139*38fd1498Szrj   r_label = convert_memory_address (Pmode, r_label);
1140*38fd1498Szrj   r_save_area = expand_normal (t_save_area);
1141*38fd1498Szrj   r_save_area = convert_memory_address (Pmode, r_save_area);
1142*38fd1498Szrj   /* Copy the address of the save location to a register just in case it was
1143*38fd1498Szrj      based on the frame pointer.   */
1144*38fd1498Szrj   r_save_area = copy_to_reg (r_save_area);
1145*38fd1498Szrj   r_fp = gen_rtx_MEM (Pmode, r_save_area);
1146*38fd1498Szrj   r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL),
1147*38fd1498Szrj 		      plus_constant (Pmode, r_save_area,
1148*38fd1498Szrj 				     GET_MODE_SIZE (Pmode)));
1149*38fd1498Szrj 
1150*38fd1498Szrj   crtl->has_nonlocal_goto = 1;
1151*38fd1498Szrj 
1152*38fd1498Szrj   /* ??? We no longer need to pass the static chain value, afaik.  */
1153*38fd1498Szrj   if (targetm.have_nonlocal_goto ())
1154*38fd1498Szrj     emit_insn (targetm.gen_nonlocal_goto (const0_rtx, r_label, r_sp, r_fp));
1155*38fd1498Szrj   else
1156*38fd1498Szrj     {
1157*38fd1498Szrj       r_label = copy_to_reg (r_label);
1158*38fd1498Szrj 
1159*38fd1498Szrj       emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
1160*38fd1498Szrj       emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
1161*38fd1498Szrj 
1162*38fd1498Szrj       /* Restore frame pointer for containing function.  */
1163*38fd1498Szrj       emit_move_insn (hard_frame_pointer_rtx, r_fp);
1164*38fd1498Szrj       emit_stack_restore (SAVE_NONLOCAL, r_sp);
1165*38fd1498Szrj 
1166*38fd1498Szrj       /* USE of hard_frame_pointer_rtx added for consistency;
1167*38fd1498Szrj 	 not clear if really needed.  */
1168*38fd1498Szrj       emit_use (hard_frame_pointer_rtx);
1169*38fd1498Szrj       emit_use (stack_pointer_rtx);
1170*38fd1498Szrj 
1171*38fd1498Szrj       /* If the architecture is using a GP register, we must
1172*38fd1498Szrj 	 conservatively assume that the target function makes use of it.
1173*38fd1498Szrj 	 The prologue of functions with nonlocal gotos must therefore
1174*38fd1498Szrj 	 initialize the GP register to the appropriate value, and we
1175*38fd1498Szrj 	 must then make sure that this value is live at the point
1176*38fd1498Szrj 	 of the jump.  (Note that this doesn't necessarily apply
1177*38fd1498Szrj 	 to targets with a nonlocal_goto pattern; they are free
1178*38fd1498Szrj 	 to implement it in their own way.  Note also that this is
1179*38fd1498Szrj 	 a no-op if the GP register is a global invariant.)  */
1180*38fd1498Szrj       unsigned regnum = PIC_OFFSET_TABLE_REGNUM;
1181*38fd1498Szrj       if (regnum != INVALID_REGNUM && fixed_regs[regnum])
1182*38fd1498Szrj 	emit_use (pic_offset_table_rtx);
1183*38fd1498Szrj 
1184*38fd1498Szrj       emit_indirect_jump (r_label);
1185*38fd1498Szrj     }
1186*38fd1498Szrj 
1187*38fd1498Szrj   /* Search backwards to the jump insn and mark it as a
1188*38fd1498Szrj      non-local goto.  */
1189*38fd1498Szrj   for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
1190*38fd1498Szrj     {
1191*38fd1498Szrj       if (JUMP_P (insn))
1192*38fd1498Szrj 	{
1193*38fd1498Szrj 	  add_reg_note (insn, REG_NON_LOCAL_GOTO, const0_rtx);
1194*38fd1498Szrj 	  break;
1195*38fd1498Szrj 	}
1196*38fd1498Szrj       else if (CALL_P (insn))
1197*38fd1498Szrj 	break;
1198*38fd1498Szrj     }
1199*38fd1498Szrj 
1200*38fd1498Szrj   return const0_rtx;
1201*38fd1498Szrj }
1202*38fd1498Szrj 
1203*38fd1498Szrj /* __builtin_update_setjmp_buf is passed a pointer to an array of five words
1204*38fd1498Szrj    (not all will be used on all machines) that was passed to __builtin_setjmp.
1205*38fd1498Szrj    It updates the stack pointer in that block to the current value.  This is
1206*38fd1498Szrj    also called directly by the SJLJ exception handling code.  */
1207*38fd1498Szrj 
1208*38fd1498Szrj void
expand_builtin_update_setjmp_buf(rtx buf_addr)1209*38fd1498Szrj expand_builtin_update_setjmp_buf (rtx buf_addr)
1210*38fd1498Szrj {
1211*38fd1498Szrj   machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
1212*38fd1498Szrj   buf_addr = convert_memory_address (Pmode, buf_addr);
1213*38fd1498Szrj   rtx stack_save
1214*38fd1498Szrj     = gen_rtx_MEM (sa_mode,
1215*38fd1498Szrj 		   memory_address
1216*38fd1498Szrj 		   (sa_mode,
1217*38fd1498Szrj 		    plus_constant (Pmode, buf_addr,
1218*38fd1498Szrj 				   2 * GET_MODE_SIZE (Pmode))));
1219*38fd1498Szrj 
1220*38fd1498Szrj   emit_stack_save (SAVE_NONLOCAL, &stack_save);
1221*38fd1498Szrj }
1222*38fd1498Szrj 
1223*38fd1498Szrj /* Expand a call to __builtin_prefetch.  For a target that does not support
1224*38fd1498Szrj    data prefetch, evaluate the memory address argument in case it has side
1225*38fd1498Szrj    effects.  */
1226*38fd1498Szrj 
1227*38fd1498Szrj static void
expand_builtin_prefetch(tree exp)1228*38fd1498Szrj expand_builtin_prefetch (tree exp)
1229*38fd1498Szrj {
1230*38fd1498Szrj   tree arg0, arg1, arg2;
1231*38fd1498Szrj   int nargs;
1232*38fd1498Szrj   rtx op0, op1, op2;
1233*38fd1498Szrj 
1234*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, 0))
1235*38fd1498Szrj     return;
1236*38fd1498Szrj 
1237*38fd1498Szrj   arg0 = CALL_EXPR_ARG (exp, 0);
1238*38fd1498Szrj 
1239*38fd1498Szrj   /* Arguments 1 and 2 are optional; argument 1 (read/write) defaults to
1240*38fd1498Szrj      zero (read) and argument 2 (locality) defaults to 3 (high degree of
1241*38fd1498Szrj      locality).  */
1242*38fd1498Szrj   nargs = call_expr_nargs (exp);
1243*38fd1498Szrj   if (nargs > 1)
1244*38fd1498Szrj     arg1 = CALL_EXPR_ARG (exp, 1);
1245*38fd1498Szrj   else
1246*38fd1498Szrj     arg1 = integer_zero_node;
1247*38fd1498Szrj   if (nargs > 2)
1248*38fd1498Szrj     arg2 = CALL_EXPR_ARG (exp, 2);
1249*38fd1498Szrj   else
1250*38fd1498Szrj     arg2 = integer_three_node;
1251*38fd1498Szrj 
1252*38fd1498Szrj   /* Argument 0 is an address.  */
1253*38fd1498Szrj   op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
1254*38fd1498Szrj 
1255*38fd1498Szrj   /* Argument 1 (read/write flag) must be a compile-time constant int.  */
1256*38fd1498Szrj   if (TREE_CODE (arg1) != INTEGER_CST)
1257*38fd1498Szrj     {
1258*38fd1498Szrj       error ("second argument to %<__builtin_prefetch%> must be a constant");
1259*38fd1498Szrj       arg1 = integer_zero_node;
1260*38fd1498Szrj     }
1261*38fd1498Szrj   op1 = expand_normal (arg1);
1262*38fd1498Szrj   /* Argument 1 must be either zero or one.  */
1263*38fd1498Szrj   if (INTVAL (op1) != 0 && INTVAL (op1) != 1)
1264*38fd1498Szrj     {
1265*38fd1498Szrj       warning (0, "invalid second argument to %<__builtin_prefetch%>;"
1266*38fd1498Szrj 	       " using zero");
1267*38fd1498Szrj       op1 = const0_rtx;
1268*38fd1498Szrj     }
1269*38fd1498Szrj 
1270*38fd1498Szrj   /* Argument 2 (locality) must be a compile-time constant int.  */
1271*38fd1498Szrj   if (TREE_CODE (arg2) != INTEGER_CST)
1272*38fd1498Szrj     {
1273*38fd1498Szrj       error ("third argument to %<__builtin_prefetch%> must be a constant");
1274*38fd1498Szrj       arg2 = integer_zero_node;
1275*38fd1498Szrj     }
1276*38fd1498Szrj   op2 = expand_normal (arg2);
1277*38fd1498Szrj   /* Argument 2 must be 0, 1, 2, or 3.  */
1278*38fd1498Szrj   if (INTVAL (op2) < 0 || INTVAL (op2) > 3)
1279*38fd1498Szrj     {
1280*38fd1498Szrj       warning (0, "invalid third argument to %<__builtin_prefetch%>; using zero");
1281*38fd1498Szrj       op2 = const0_rtx;
1282*38fd1498Szrj     }
1283*38fd1498Szrj 
1284*38fd1498Szrj   if (targetm.have_prefetch ())
1285*38fd1498Szrj     {
1286*38fd1498Szrj       struct expand_operand ops[3];
1287*38fd1498Szrj 
1288*38fd1498Szrj       create_address_operand (&ops[0], op0);
1289*38fd1498Szrj       create_integer_operand (&ops[1], INTVAL (op1));
1290*38fd1498Szrj       create_integer_operand (&ops[2], INTVAL (op2));
1291*38fd1498Szrj       if (maybe_expand_insn (targetm.code_for_prefetch, 3, ops))
1292*38fd1498Szrj 	return;
1293*38fd1498Szrj     }
1294*38fd1498Szrj 
1295*38fd1498Szrj   /* Don't do anything with direct references to volatile memory, but
1296*38fd1498Szrj      generate code to handle other side effects.  */
1297*38fd1498Szrj   if (!MEM_P (op0) && side_effects_p (op0))
1298*38fd1498Szrj     emit_insn (op0);
1299*38fd1498Szrj }
1300*38fd1498Szrj 
1301*38fd1498Szrj /* Get a MEM rtx for expression EXP which is the address of an operand
1302*38fd1498Szrj    to be used in a string instruction (cmpstrsi, movmemsi, ..).  LEN is
1303*38fd1498Szrj    the maximum length of the block of memory that might be accessed or
1304*38fd1498Szrj    NULL if unknown.  */
1305*38fd1498Szrj 
1306*38fd1498Szrj static rtx
get_memory_rtx(tree exp,tree len)1307*38fd1498Szrj get_memory_rtx (tree exp, tree len)
1308*38fd1498Szrj {
1309*38fd1498Szrj   tree orig_exp = exp;
1310*38fd1498Szrj   rtx addr, mem;
1311*38fd1498Szrj 
1312*38fd1498Szrj   /* When EXP is not resolved SAVE_EXPR, MEM_ATTRS can be still derived
1313*38fd1498Szrj      from its expression, for expr->a.b only <variable>.a.b is recorded.  */
1314*38fd1498Szrj   if (TREE_CODE (exp) == SAVE_EXPR && !SAVE_EXPR_RESOLVED_P (exp))
1315*38fd1498Szrj     exp = TREE_OPERAND (exp, 0);
1316*38fd1498Szrj 
1317*38fd1498Szrj   addr = expand_expr (orig_exp, NULL_RTX, ptr_mode, EXPAND_NORMAL);
1318*38fd1498Szrj   mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
1319*38fd1498Szrj 
1320*38fd1498Szrj   /* Get an expression we can use to find the attributes to assign to MEM.
1321*38fd1498Szrj      First remove any nops.  */
1322*38fd1498Szrj   while (CONVERT_EXPR_P (exp)
1323*38fd1498Szrj 	 && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
1324*38fd1498Szrj     exp = TREE_OPERAND (exp, 0);
1325*38fd1498Szrj 
1326*38fd1498Szrj   /* Build a MEM_REF representing the whole accessed area as a byte blob,
1327*38fd1498Szrj      (as builtin stringops may alias with anything).  */
1328*38fd1498Szrj   exp = fold_build2 (MEM_REF,
1329*38fd1498Szrj 		     build_array_type (char_type_node,
1330*38fd1498Szrj 				       build_range_type (sizetype,
1331*38fd1498Szrj 							 size_one_node, len)),
1332*38fd1498Szrj 		     exp, build_int_cst (ptr_type_node, 0));
1333*38fd1498Szrj 
1334*38fd1498Szrj   /* If the MEM_REF has no acceptable address, try to get the base object
1335*38fd1498Szrj      from the original address we got, and build an all-aliasing
1336*38fd1498Szrj      unknown-sized access to that one.  */
1337*38fd1498Szrj   if (is_gimple_mem_ref_addr (TREE_OPERAND (exp, 0)))
1338*38fd1498Szrj     set_mem_attributes (mem, exp, 0);
1339*38fd1498Szrj   else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
1340*38fd1498Szrj 	   && (exp = get_base_address (TREE_OPERAND (TREE_OPERAND (exp, 0),
1341*38fd1498Szrj 						     0))))
1342*38fd1498Szrj     {
1343*38fd1498Szrj       exp = build_fold_addr_expr (exp);
1344*38fd1498Szrj       exp = fold_build2 (MEM_REF,
1345*38fd1498Szrj 			 build_array_type (char_type_node,
1346*38fd1498Szrj 					   build_range_type (sizetype,
1347*38fd1498Szrj 							     size_zero_node,
1348*38fd1498Szrj 							     NULL)),
1349*38fd1498Szrj 			 exp, build_int_cst (ptr_type_node, 0));
1350*38fd1498Szrj       set_mem_attributes (mem, exp, 0);
1351*38fd1498Szrj     }
1352*38fd1498Szrj   set_mem_alias_set (mem, 0);
1353*38fd1498Szrj   return mem;
1354*38fd1498Szrj }
1355*38fd1498Szrj 
1356*38fd1498Szrj /* Built-in functions to perform an untyped call and return.  */
1357*38fd1498Szrj 
1358*38fd1498Szrj #define apply_args_mode \
1359*38fd1498Szrj   (this_target_builtins->x_apply_args_mode)
1360*38fd1498Szrj #define apply_result_mode \
1361*38fd1498Szrj   (this_target_builtins->x_apply_result_mode)
1362*38fd1498Szrj 
1363*38fd1498Szrj /* Return the size required for the block returned by __builtin_apply_args,
1364*38fd1498Szrj    and initialize apply_args_mode.  */
1365*38fd1498Szrj 
1366*38fd1498Szrj static int
apply_args_size(void)1367*38fd1498Szrj apply_args_size (void)
1368*38fd1498Szrj {
1369*38fd1498Szrj   static int size = -1;
1370*38fd1498Szrj   int align;
1371*38fd1498Szrj   unsigned int regno;
1372*38fd1498Szrj 
1373*38fd1498Szrj   /* The values computed by this function never change.  */
1374*38fd1498Szrj   if (size < 0)
1375*38fd1498Szrj     {
1376*38fd1498Szrj       /* The first value is the incoming arg-pointer.  */
1377*38fd1498Szrj       size = GET_MODE_SIZE (Pmode);
1378*38fd1498Szrj 
1379*38fd1498Szrj       /* The second value is the structure value address unless this is
1380*38fd1498Szrj 	 passed as an "invisible" first argument.  */
1381*38fd1498Szrj       if (targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 0))
1382*38fd1498Szrj 	size += GET_MODE_SIZE (Pmode);
1383*38fd1498Szrj 
1384*38fd1498Szrj       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1385*38fd1498Szrj 	if (FUNCTION_ARG_REGNO_P (regno))
1386*38fd1498Szrj 	  {
1387*38fd1498Szrj 	    fixed_size_mode mode = targetm.calls.get_raw_arg_mode (regno);
1388*38fd1498Szrj 
1389*38fd1498Szrj 	    gcc_assert (mode != VOIDmode);
1390*38fd1498Szrj 
1391*38fd1498Szrj 	    align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1392*38fd1498Szrj 	    if (size % align != 0)
1393*38fd1498Szrj 	      size = CEIL (size, align) * align;
1394*38fd1498Szrj 	    size += GET_MODE_SIZE (mode);
1395*38fd1498Szrj 	    apply_args_mode[regno] = mode;
1396*38fd1498Szrj 	  }
1397*38fd1498Szrj 	else
1398*38fd1498Szrj 	  {
1399*38fd1498Szrj 	    apply_args_mode[regno] = as_a <fixed_size_mode> (VOIDmode);
1400*38fd1498Szrj 	  }
1401*38fd1498Szrj     }
1402*38fd1498Szrj   return size;
1403*38fd1498Szrj }
1404*38fd1498Szrj 
1405*38fd1498Szrj /* Return the size required for the block returned by __builtin_apply,
1406*38fd1498Szrj    and initialize apply_result_mode.  */
1407*38fd1498Szrj 
1408*38fd1498Szrj static int
apply_result_size(void)1409*38fd1498Szrj apply_result_size (void)
1410*38fd1498Szrj {
1411*38fd1498Szrj   static int size = -1;
1412*38fd1498Szrj   int align, regno;
1413*38fd1498Szrj 
1414*38fd1498Szrj   /* The values computed by this function never change.  */
1415*38fd1498Szrj   if (size < 0)
1416*38fd1498Szrj     {
1417*38fd1498Szrj       size = 0;
1418*38fd1498Szrj 
1419*38fd1498Szrj       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1420*38fd1498Szrj 	if (targetm.calls.function_value_regno_p (regno))
1421*38fd1498Szrj 	  {
1422*38fd1498Szrj 	    fixed_size_mode mode = targetm.calls.get_raw_result_mode (regno);
1423*38fd1498Szrj 
1424*38fd1498Szrj 	    gcc_assert (mode != VOIDmode);
1425*38fd1498Szrj 
1426*38fd1498Szrj 	    align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1427*38fd1498Szrj 	    if (size % align != 0)
1428*38fd1498Szrj 	      size = CEIL (size, align) * align;
1429*38fd1498Szrj 	    size += GET_MODE_SIZE (mode);
1430*38fd1498Szrj 	    apply_result_mode[regno] = mode;
1431*38fd1498Szrj 	  }
1432*38fd1498Szrj 	else
1433*38fd1498Szrj 	  apply_result_mode[regno] = as_a <fixed_size_mode> (VOIDmode);
1434*38fd1498Szrj 
1435*38fd1498Szrj       /* Allow targets that use untyped_call and untyped_return to override
1436*38fd1498Szrj 	 the size so that machine-specific information can be stored here.  */
1437*38fd1498Szrj #ifdef APPLY_RESULT_SIZE
1438*38fd1498Szrj       size = APPLY_RESULT_SIZE;
1439*38fd1498Szrj #endif
1440*38fd1498Szrj     }
1441*38fd1498Szrj   return size;
1442*38fd1498Szrj }
1443*38fd1498Szrj 
1444*38fd1498Szrj /* Create a vector describing the result block RESULT.  If SAVEP is true,
1445*38fd1498Szrj    the result block is used to save the values; otherwise it is used to
1446*38fd1498Szrj    restore the values.  */
1447*38fd1498Szrj 
1448*38fd1498Szrj static rtx
result_vector(int savep,rtx result)1449*38fd1498Szrj result_vector (int savep, rtx result)
1450*38fd1498Szrj {
1451*38fd1498Szrj   int regno, size, align, nelts;
1452*38fd1498Szrj   fixed_size_mode mode;
1453*38fd1498Szrj   rtx reg, mem;
1454*38fd1498Szrj   rtx *savevec = XALLOCAVEC (rtx, FIRST_PSEUDO_REGISTER);
1455*38fd1498Szrj 
1456*38fd1498Szrj   size = nelts = 0;
1457*38fd1498Szrj   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1458*38fd1498Szrj     if ((mode = apply_result_mode[regno]) != VOIDmode)
1459*38fd1498Szrj       {
1460*38fd1498Szrj 	align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1461*38fd1498Szrj 	if (size % align != 0)
1462*38fd1498Szrj 	  size = CEIL (size, align) * align;
1463*38fd1498Szrj 	reg = gen_rtx_REG (mode, savep ? regno : INCOMING_REGNO (regno));
1464*38fd1498Szrj 	mem = adjust_address (result, mode, size);
1465*38fd1498Szrj 	savevec[nelts++] = (savep
1466*38fd1498Szrj 			    ? gen_rtx_SET (mem, reg)
1467*38fd1498Szrj 			    : gen_rtx_SET (reg, mem));
1468*38fd1498Szrj 	size += GET_MODE_SIZE (mode);
1469*38fd1498Szrj       }
1470*38fd1498Szrj   return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nelts, savevec));
1471*38fd1498Szrj }
1472*38fd1498Szrj 
1473*38fd1498Szrj /* Save the state required to perform an untyped call with the same
1474*38fd1498Szrj    arguments as were passed to the current function.  */
1475*38fd1498Szrj 
1476*38fd1498Szrj static rtx
expand_builtin_apply_args_1(void)1477*38fd1498Szrj expand_builtin_apply_args_1 (void)
1478*38fd1498Szrj {
1479*38fd1498Szrj   rtx registers, tem;
1480*38fd1498Szrj   int size, align, regno;
1481*38fd1498Szrj   fixed_size_mode mode;
1482*38fd1498Szrj   rtx struct_incoming_value = targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 1);
1483*38fd1498Szrj 
1484*38fd1498Szrj   /* Create a block where the arg-pointer, structure value address,
1485*38fd1498Szrj      and argument registers can be saved.  */
1486*38fd1498Szrj   registers = assign_stack_local (BLKmode, apply_args_size (), -1);
1487*38fd1498Szrj 
1488*38fd1498Szrj   /* Walk past the arg-pointer and structure value address.  */
1489*38fd1498Szrj   size = GET_MODE_SIZE (Pmode);
1490*38fd1498Szrj   if (targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 0))
1491*38fd1498Szrj     size += GET_MODE_SIZE (Pmode);
1492*38fd1498Szrj 
1493*38fd1498Szrj   /* Save each register used in calling a function to the block.  */
1494*38fd1498Szrj   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1495*38fd1498Szrj     if ((mode = apply_args_mode[regno]) != VOIDmode)
1496*38fd1498Szrj       {
1497*38fd1498Szrj 	align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1498*38fd1498Szrj 	if (size % align != 0)
1499*38fd1498Szrj 	  size = CEIL (size, align) * align;
1500*38fd1498Szrj 
1501*38fd1498Szrj 	tem = gen_rtx_REG (mode, INCOMING_REGNO (regno));
1502*38fd1498Szrj 
1503*38fd1498Szrj 	emit_move_insn (adjust_address (registers, mode, size), tem);
1504*38fd1498Szrj 	size += GET_MODE_SIZE (mode);
1505*38fd1498Szrj       }
1506*38fd1498Szrj 
1507*38fd1498Szrj   /* Save the arg pointer to the block.  */
1508*38fd1498Szrj   tem = copy_to_reg (crtl->args.internal_arg_pointer);
1509*38fd1498Szrj   /* We need the pointer as the caller actually passed them to us, not
1510*38fd1498Szrj      as we might have pretended they were passed.  Make sure it's a valid
1511*38fd1498Szrj      operand, as emit_move_insn isn't expected to handle a PLUS.  */
1512*38fd1498Szrj   if (STACK_GROWS_DOWNWARD)
1513*38fd1498Szrj     tem
1514*38fd1498Szrj       = force_operand (plus_constant (Pmode, tem,
1515*38fd1498Szrj 				      crtl->args.pretend_args_size),
1516*38fd1498Szrj 		       NULL_RTX);
1517*38fd1498Szrj   emit_move_insn (adjust_address (registers, Pmode, 0), tem);
1518*38fd1498Szrj 
1519*38fd1498Szrj   size = GET_MODE_SIZE (Pmode);
1520*38fd1498Szrj 
1521*38fd1498Szrj   /* Save the structure value address unless this is passed as an
1522*38fd1498Szrj      "invisible" first argument.  */
1523*38fd1498Szrj   if (struct_incoming_value)
1524*38fd1498Szrj     {
1525*38fd1498Szrj       emit_move_insn (adjust_address (registers, Pmode, size),
1526*38fd1498Szrj 		      copy_to_reg (struct_incoming_value));
1527*38fd1498Szrj       size += GET_MODE_SIZE (Pmode);
1528*38fd1498Szrj     }
1529*38fd1498Szrj 
1530*38fd1498Szrj   /* Return the address of the block.  */
1531*38fd1498Szrj   return copy_addr_to_reg (XEXP (registers, 0));
1532*38fd1498Szrj }
1533*38fd1498Szrj 
1534*38fd1498Szrj /* __builtin_apply_args returns block of memory allocated on
1535*38fd1498Szrj    the stack into which is stored the arg pointer, structure
1536*38fd1498Szrj    value address, static chain, and all the registers that might
1537*38fd1498Szrj    possibly be used in performing a function call.  The code is
1538*38fd1498Szrj    moved to the start of the function so the incoming values are
1539*38fd1498Szrj    saved.  */
1540*38fd1498Szrj 
1541*38fd1498Szrj static rtx
expand_builtin_apply_args(void)1542*38fd1498Szrj expand_builtin_apply_args (void)
1543*38fd1498Szrj {
1544*38fd1498Szrj   /* Don't do __builtin_apply_args more than once in a function.
1545*38fd1498Szrj      Save the result of the first call and reuse it.  */
1546*38fd1498Szrj   if (apply_args_value != 0)
1547*38fd1498Szrj     return apply_args_value;
1548*38fd1498Szrj   {
1549*38fd1498Szrj     /* When this function is called, it means that registers must be
1550*38fd1498Szrj        saved on entry to this function.  So we migrate the
1551*38fd1498Szrj        call to the first insn of this function.  */
1552*38fd1498Szrj     rtx temp;
1553*38fd1498Szrj 
1554*38fd1498Szrj     start_sequence ();
1555*38fd1498Szrj     temp = expand_builtin_apply_args_1 ();
1556*38fd1498Szrj     rtx_insn *seq = get_insns ();
1557*38fd1498Szrj     end_sequence ();
1558*38fd1498Szrj 
1559*38fd1498Szrj     apply_args_value = temp;
1560*38fd1498Szrj 
1561*38fd1498Szrj     /* Put the insns after the NOTE that starts the function.
1562*38fd1498Szrj        If this is inside a start_sequence, make the outer-level insn
1563*38fd1498Szrj        chain current, so the code is placed at the start of the
1564*38fd1498Szrj        function.  If internal_arg_pointer is a non-virtual pseudo,
1565*38fd1498Szrj        it needs to be placed after the function that initializes
1566*38fd1498Szrj        that pseudo.  */
1567*38fd1498Szrj     push_topmost_sequence ();
1568*38fd1498Szrj     if (REG_P (crtl->args.internal_arg_pointer)
1569*38fd1498Szrj 	&& REGNO (crtl->args.internal_arg_pointer) > LAST_VIRTUAL_REGISTER)
1570*38fd1498Szrj       emit_insn_before (seq, parm_birth_insn);
1571*38fd1498Szrj     else
1572*38fd1498Szrj       emit_insn_before (seq, NEXT_INSN (entry_of_function ()));
1573*38fd1498Szrj     pop_topmost_sequence ();
1574*38fd1498Szrj     return temp;
1575*38fd1498Szrj   }
1576*38fd1498Szrj }
1577*38fd1498Szrj 
1578*38fd1498Szrj /* Perform an untyped call and save the state required to perform an
1579*38fd1498Szrj    untyped return of whatever value was returned by the given function.  */
1580*38fd1498Szrj 
1581*38fd1498Szrj static rtx
expand_builtin_apply(rtx function,rtx arguments,rtx argsize)1582*38fd1498Szrj expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
1583*38fd1498Szrj {
1584*38fd1498Szrj   int size, align, regno;
1585*38fd1498Szrj   fixed_size_mode mode;
1586*38fd1498Szrj   rtx incoming_args, result, reg, dest, src;
1587*38fd1498Szrj   rtx_call_insn *call_insn;
1588*38fd1498Szrj   rtx old_stack_level = 0;
1589*38fd1498Szrj   rtx call_fusage = 0;
1590*38fd1498Szrj   rtx struct_value = targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 0);
1591*38fd1498Szrj 
1592*38fd1498Szrj   arguments = convert_memory_address (Pmode, arguments);
1593*38fd1498Szrj 
1594*38fd1498Szrj   /* Create a block where the return registers can be saved.  */
1595*38fd1498Szrj   result = assign_stack_local (BLKmode, apply_result_size (), -1);
1596*38fd1498Szrj 
1597*38fd1498Szrj   /* Fetch the arg pointer from the ARGUMENTS block.  */
1598*38fd1498Szrj   incoming_args = gen_reg_rtx (Pmode);
1599*38fd1498Szrj   emit_move_insn (incoming_args, gen_rtx_MEM (Pmode, arguments));
1600*38fd1498Szrj   if (!STACK_GROWS_DOWNWARD)
1601*38fd1498Szrj     incoming_args = expand_simple_binop (Pmode, MINUS, incoming_args, argsize,
1602*38fd1498Szrj 					 incoming_args, 0, OPTAB_LIB_WIDEN);
1603*38fd1498Szrj 
1604*38fd1498Szrj   /* Push a new argument block and copy the arguments.  Do not allow
1605*38fd1498Szrj      the (potential) memcpy call below to interfere with our stack
1606*38fd1498Szrj      manipulations.  */
1607*38fd1498Szrj   do_pending_stack_adjust ();
1608*38fd1498Szrj   NO_DEFER_POP;
1609*38fd1498Szrj 
1610*38fd1498Szrj   /* Save the stack with nonlocal if available.  */
1611*38fd1498Szrj   if (targetm.have_save_stack_nonlocal ())
1612*38fd1498Szrj     emit_stack_save (SAVE_NONLOCAL, &old_stack_level);
1613*38fd1498Szrj   else
1614*38fd1498Szrj     emit_stack_save (SAVE_BLOCK, &old_stack_level);
1615*38fd1498Szrj 
1616*38fd1498Szrj   /* Allocate a block of memory onto the stack and copy the memory
1617*38fd1498Szrj      arguments to the outgoing arguments address.  We can pass TRUE
1618*38fd1498Szrj      as the 4th argument because we just saved the stack pointer
1619*38fd1498Szrj      and will restore it right after the call.  */
1620*38fd1498Szrj   allocate_dynamic_stack_space (argsize, 0, BIGGEST_ALIGNMENT, -1, true);
1621*38fd1498Szrj 
1622*38fd1498Szrj   /* Set DRAP flag to true, even though allocate_dynamic_stack_space
1623*38fd1498Szrj      may have already set current_function_calls_alloca to true.
1624*38fd1498Szrj      current_function_calls_alloca won't be set if argsize is zero,
1625*38fd1498Szrj      so we have to guarantee need_drap is true here.  */
1626*38fd1498Szrj   if (SUPPORTS_STACK_ALIGNMENT)
1627*38fd1498Szrj     crtl->need_drap = true;
1628*38fd1498Szrj 
1629*38fd1498Szrj   dest = virtual_outgoing_args_rtx;
1630*38fd1498Szrj   if (!STACK_GROWS_DOWNWARD)
1631*38fd1498Szrj     {
1632*38fd1498Szrj       if (CONST_INT_P (argsize))
1633*38fd1498Szrj 	dest = plus_constant (Pmode, dest, -INTVAL (argsize));
1634*38fd1498Szrj       else
1635*38fd1498Szrj 	dest = gen_rtx_PLUS (Pmode, dest, negate_rtx (Pmode, argsize));
1636*38fd1498Szrj     }
1637*38fd1498Szrj   dest = gen_rtx_MEM (BLKmode, dest);
1638*38fd1498Szrj   set_mem_align (dest, PARM_BOUNDARY);
1639*38fd1498Szrj   src = gen_rtx_MEM (BLKmode, incoming_args);
1640*38fd1498Szrj   set_mem_align (src, PARM_BOUNDARY);
1641*38fd1498Szrj   emit_block_move (dest, src, argsize, BLOCK_OP_NORMAL);
1642*38fd1498Szrj 
1643*38fd1498Szrj   /* Refer to the argument block.  */
1644*38fd1498Szrj   apply_args_size ();
1645*38fd1498Szrj   arguments = gen_rtx_MEM (BLKmode, arguments);
1646*38fd1498Szrj   set_mem_align (arguments, PARM_BOUNDARY);
1647*38fd1498Szrj 
1648*38fd1498Szrj   /* Walk past the arg-pointer and structure value address.  */
1649*38fd1498Szrj   size = GET_MODE_SIZE (Pmode);
1650*38fd1498Szrj   if (struct_value)
1651*38fd1498Szrj     size += GET_MODE_SIZE (Pmode);
1652*38fd1498Szrj 
1653*38fd1498Szrj   /* Restore each of the registers previously saved.  Make USE insns
1654*38fd1498Szrj      for each of these registers for use in making the call.  */
1655*38fd1498Szrj   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1656*38fd1498Szrj     if ((mode = apply_args_mode[regno]) != VOIDmode)
1657*38fd1498Szrj       {
1658*38fd1498Szrj 	align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1659*38fd1498Szrj 	if (size % align != 0)
1660*38fd1498Szrj 	  size = CEIL (size, align) * align;
1661*38fd1498Szrj 	reg = gen_rtx_REG (mode, regno);
1662*38fd1498Szrj 	emit_move_insn (reg, adjust_address (arguments, mode, size));
1663*38fd1498Szrj 	use_reg (&call_fusage, reg);
1664*38fd1498Szrj 	size += GET_MODE_SIZE (mode);
1665*38fd1498Szrj       }
1666*38fd1498Szrj 
1667*38fd1498Szrj   /* Restore the structure value address unless this is passed as an
1668*38fd1498Szrj      "invisible" first argument.  */
1669*38fd1498Szrj   size = GET_MODE_SIZE (Pmode);
1670*38fd1498Szrj   if (struct_value)
1671*38fd1498Szrj     {
1672*38fd1498Szrj       rtx value = gen_reg_rtx (Pmode);
1673*38fd1498Szrj       emit_move_insn (value, adjust_address (arguments, Pmode, size));
1674*38fd1498Szrj       emit_move_insn (struct_value, value);
1675*38fd1498Szrj       if (REG_P (struct_value))
1676*38fd1498Szrj 	use_reg (&call_fusage, struct_value);
1677*38fd1498Szrj       size += GET_MODE_SIZE (Pmode);
1678*38fd1498Szrj     }
1679*38fd1498Szrj 
1680*38fd1498Szrj   /* All arguments and registers used for the call are set up by now!  */
1681*38fd1498Szrj   function = prepare_call_address (NULL, function, NULL, &call_fusage, 0, 0);
1682*38fd1498Szrj 
1683*38fd1498Szrj   /* Ensure address is valid.  SYMBOL_REF is already valid, so no need,
1684*38fd1498Szrj      and we don't want to load it into a register as an optimization,
1685*38fd1498Szrj      because prepare_call_address already did it if it should be done.  */
1686*38fd1498Szrj   if (GET_CODE (function) != SYMBOL_REF)
1687*38fd1498Szrj     function = memory_address (FUNCTION_MODE, function);
1688*38fd1498Szrj 
1689*38fd1498Szrj   /* Generate the actual call instruction and save the return value.  */
1690*38fd1498Szrj   if (targetm.have_untyped_call ())
1691*38fd1498Szrj     {
1692*38fd1498Szrj       rtx mem = gen_rtx_MEM (FUNCTION_MODE, function);
1693*38fd1498Szrj       emit_call_insn (targetm.gen_untyped_call (mem, result,
1694*38fd1498Szrj 						result_vector (1, result)));
1695*38fd1498Szrj     }
1696*38fd1498Szrj   else if (targetm.have_call_value ())
1697*38fd1498Szrj     {
1698*38fd1498Szrj       rtx valreg = 0;
1699*38fd1498Szrj 
1700*38fd1498Szrj       /* Locate the unique return register.  It is not possible to
1701*38fd1498Szrj 	 express a call that sets more than one return register using
1702*38fd1498Szrj 	 call_value; use untyped_call for that.  In fact, untyped_call
1703*38fd1498Szrj 	 only needs to save the return registers in the given block.  */
1704*38fd1498Szrj       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1705*38fd1498Szrj 	if ((mode = apply_result_mode[regno]) != VOIDmode)
1706*38fd1498Szrj 	  {
1707*38fd1498Szrj 	    gcc_assert (!valreg); /* have_untyped_call required.  */
1708*38fd1498Szrj 
1709*38fd1498Szrj 	    valreg = gen_rtx_REG (mode, regno);
1710*38fd1498Szrj 	  }
1711*38fd1498Szrj 
1712*38fd1498Szrj       emit_insn (targetm.gen_call_value (valreg,
1713*38fd1498Szrj 					 gen_rtx_MEM (FUNCTION_MODE, function),
1714*38fd1498Szrj 					 const0_rtx, NULL_RTX, const0_rtx));
1715*38fd1498Szrj 
1716*38fd1498Szrj       emit_move_insn (adjust_address (result, GET_MODE (valreg), 0), valreg);
1717*38fd1498Szrj     }
1718*38fd1498Szrj   else
1719*38fd1498Szrj     gcc_unreachable ();
1720*38fd1498Szrj 
1721*38fd1498Szrj   /* Find the CALL insn we just emitted, and attach the register usage
1722*38fd1498Szrj      information.  */
1723*38fd1498Szrj   call_insn = last_call_insn ();
1724*38fd1498Szrj   add_function_usage_to (call_insn, call_fusage);
1725*38fd1498Szrj 
1726*38fd1498Szrj   /* Restore the stack.  */
1727*38fd1498Szrj   if (targetm.have_save_stack_nonlocal ())
1728*38fd1498Szrj     emit_stack_restore (SAVE_NONLOCAL, old_stack_level);
1729*38fd1498Szrj   else
1730*38fd1498Szrj     emit_stack_restore (SAVE_BLOCK, old_stack_level);
1731*38fd1498Szrj   fixup_args_size_notes (call_insn, get_last_insn (), 0);
1732*38fd1498Szrj 
1733*38fd1498Szrj   OK_DEFER_POP;
1734*38fd1498Szrj 
1735*38fd1498Szrj   /* Return the address of the result block.  */
1736*38fd1498Szrj   result = copy_addr_to_reg (XEXP (result, 0));
1737*38fd1498Szrj   return convert_memory_address (ptr_mode, result);
1738*38fd1498Szrj }
1739*38fd1498Szrj 
1740*38fd1498Szrj /* Perform an untyped return.  */
1741*38fd1498Szrj 
1742*38fd1498Szrj static void
expand_builtin_return(rtx result)1743*38fd1498Szrj expand_builtin_return (rtx result)
1744*38fd1498Szrj {
1745*38fd1498Szrj   int size, align, regno;
1746*38fd1498Szrj   fixed_size_mode mode;
1747*38fd1498Szrj   rtx reg;
1748*38fd1498Szrj   rtx_insn *call_fusage = 0;
1749*38fd1498Szrj 
1750*38fd1498Szrj   result = convert_memory_address (Pmode, result);
1751*38fd1498Szrj 
1752*38fd1498Szrj   apply_result_size ();
1753*38fd1498Szrj   result = gen_rtx_MEM (BLKmode, result);
1754*38fd1498Szrj 
1755*38fd1498Szrj   if (targetm.have_untyped_return ())
1756*38fd1498Szrj     {
1757*38fd1498Szrj       rtx vector = result_vector (0, result);
1758*38fd1498Szrj       emit_jump_insn (targetm.gen_untyped_return (result, vector));
1759*38fd1498Szrj       emit_barrier ();
1760*38fd1498Szrj       return;
1761*38fd1498Szrj     }
1762*38fd1498Szrj 
1763*38fd1498Szrj   /* Restore the return value and note that each value is used.  */
1764*38fd1498Szrj   size = 0;
1765*38fd1498Szrj   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1766*38fd1498Szrj     if ((mode = apply_result_mode[regno]) != VOIDmode)
1767*38fd1498Szrj       {
1768*38fd1498Szrj 	align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1769*38fd1498Szrj 	if (size % align != 0)
1770*38fd1498Szrj 	  size = CEIL (size, align) * align;
1771*38fd1498Szrj 	reg = gen_rtx_REG (mode, INCOMING_REGNO (regno));
1772*38fd1498Szrj 	emit_move_insn (reg, adjust_address (result, mode, size));
1773*38fd1498Szrj 
1774*38fd1498Szrj 	push_to_sequence (call_fusage);
1775*38fd1498Szrj 	emit_use (reg);
1776*38fd1498Szrj 	call_fusage = get_insns ();
1777*38fd1498Szrj 	end_sequence ();
1778*38fd1498Szrj 	size += GET_MODE_SIZE (mode);
1779*38fd1498Szrj       }
1780*38fd1498Szrj 
1781*38fd1498Szrj   /* Put the USE insns before the return.  */
1782*38fd1498Szrj   emit_insn (call_fusage);
1783*38fd1498Szrj 
1784*38fd1498Szrj   /* Return whatever values was restored by jumping directly to the end
1785*38fd1498Szrj      of the function.  */
1786*38fd1498Szrj   expand_naked_return ();
1787*38fd1498Szrj }
1788*38fd1498Szrj 
1789*38fd1498Szrj /* Used by expand_builtin_classify_type and fold_builtin_classify_type.  */
1790*38fd1498Szrj 
1791*38fd1498Szrj static enum type_class
type_to_class(tree type)1792*38fd1498Szrj type_to_class (tree type)
1793*38fd1498Szrj {
1794*38fd1498Szrj   switch (TREE_CODE (type))
1795*38fd1498Szrj     {
1796*38fd1498Szrj     case VOID_TYPE:	   return void_type_class;
1797*38fd1498Szrj     case INTEGER_TYPE:	   return integer_type_class;
1798*38fd1498Szrj     case ENUMERAL_TYPE:	   return enumeral_type_class;
1799*38fd1498Szrj     case BOOLEAN_TYPE:	   return boolean_type_class;
1800*38fd1498Szrj     case POINTER_TYPE:	   return pointer_type_class;
1801*38fd1498Szrj     case REFERENCE_TYPE:   return reference_type_class;
1802*38fd1498Szrj     case OFFSET_TYPE:	   return offset_type_class;
1803*38fd1498Szrj     case REAL_TYPE:	   return real_type_class;
1804*38fd1498Szrj     case COMPLEX_TYPE:	   return complex_type_class;
1805*38fd1498Szrj     case FUNCTION_TYPE:	   return function_type_class;
1806*38fd1498Szrj     case METHOD_TYPE:	   return method_type_class;
1807*38fd1498Szrj     case RECORD_TYPE:	   return record_type_class;
1808*38fd1498Szrj     case UNION_TYPE:
1809*38fd1498Szrj     case QUAL_UNION_TYPE:  return union_type_class;
1810*38fd1498Szrj     case ARRAY_TYPE:	   return (TYPE_STRING_FLAG (type)
1811*38fd1498Szrj 				   ? string_type_class : array_type_class);
1812*38fd1498Szrj     case LANG_TYPE:	   return lang_type_class;
1813*38fd1498Szrj     default:		   return no_type_class;
1814*38fd1498Szrj     }
1815*38fd1498Szrj }
1816*38fd1498Szrj 
1817*38fd1498Szrj /* Expand a call EXP to __builtin_classify_type.  */
1818*38fd1498Szrj 
1819*38fd1498Szrj static rtx
expand_builtin_classify_type(tree exp)1820*38fd1498Szrj expand_builtin_classify_type (tree exp)
1821*38fd1498Szrj {
1822*38fd1498Szrj   if (call_expr_nargs (exp))
1823*38fd1498Szrj     return GEN_INT (type_to_class (TREE_TYPE (CALL_EXPR_ARG (exp, 0))));
1824*38fd1498Szrj   return GEN_INT (no_type_class);
1825*38fd1498Szrj }
1826*38fd1498Szrj 
1827*38fd1498Szrj /* This helper macro, meant to be used in mathfn_built_in below, determines
1828*38fd1498Szrj    which among a set of builtin math functions is appropriate for a given type
1829*38fd1498Szrj    mode.  The `F' (float) and `L' (long double) are automatically generated
1830*38fd1498Szrj    from the 'double' case.  If a function supports the _Float<N> and _Float<N>X
1831*38fd1498Szrj    types, there are additional types that are considered with 'F32', 'F64',
1832*38fd1498Szrj    'F128', etc. suffixes.  */
1833*38fd1498Szrj #define CASE_MATHFN(MATHFN) \
1834*38fd1498Szrj   CASE_CFN_##MATHFN: \
1835*38fd1498Szrj   fcode = BUILT_IN_##MATHFN; fcodef = BUILT_IN_##MATHFN##F ; \
1836*38fd1498Szrj   fcodel = BUILT_IN_##MATHFN##L ; break;
1837*38fd1498Szrj /* Similar to the above, but also add support for the _Float<N> and _Float<N>X
1838*38fd1498Szrj    types.  */
1839*38fd1498Szrj #define CASE_MATHFN_FLOATN(MATHFN) \
1840*38fd1498Szrj   CASE_CFN_##MATHFN: \
1841*38fd1498Szrj   fcode = BUILT_IN_##MATHFN; fcodef = BUILT_IN_##MATHFN##F ; \
1842*38fd1498Szrj   fcodel = BUILT_IN_##MATHFN##L ; fcodef16 = BUILT_IN_##MATHFN##F16 ; \
1843*38fd1498Szrj   fcodef32 = BUILT_IN_##MATHFN##F32; fcodef64 = BUILT_IN_##MATHFN##F64 ; \
1844*38fd1498Szrj   fcodef128 = BUILT_IN_##MATHFN##F128 ; fcodef32x = BUILT_IN_##MATHFN##F32X ; \
1845*38fd1498Szrj   fcodef64x = BUILT_IN_##MATHFN##F64X ; fcodef128x = BUILT_IN_##MATHFN##F128X ;\
1846*38fd1498Szrj   break;
1847*38fd1498Szrj /* Similar to above, but appends _R after any F/L suffix.  */
1848*38fd1498Szrj #define CASE_MATHFN_REENT(MATHFN) \
1849*38fd1498Szrj   case CFN_BUILT_IN_##MATHFN##_R: \
1850*38fd1498Szrj   case CFN_BUILT_IN_##MATHFN##F_R: \
1851*38fd1498Szrj   case CFN_BUILT_IN_##MATHFN##L_R: \
1852*38fd1498Szrj   fcode = BUILT_IN_##MATHFN##_R; fcodef = BUILT_IN_##MATHFN##F_R ; \
1853*38fd1498Szrj   fcodel = BUILT_IN_##MATHFN##L_R ; break;
1854*38fd1498Szrj 
1855*38fd1498Szrj /* Return a function equivalent to FN but operating on floating-point
1856*38fd1498Szrj    values of type TYPE, or END_BUILTINS if no such function exists.
1857*38fd1498Szrj    This is purely an operation on function codes; it does not guarantee
1858*38fd1498Szrj    that the target actually has an implementation of the function.  */
1859*38fd1498Szrj 
1860*38fd1498Szrj static built_in_function
mathfn_built_in_2(tree type,combined_fn fn)1861*38fd1498Szrj mathfn_built_in_2 (tree type, combined_fn fn)
1862*38fd1498Szrj {
1863*38fd1498Szrj   tree mtype;
1864*38fd1498Szrj   built_in_function fcode, fcodef, fcodel;
1865*38fd1498Szrj   built_in_function fcodef16 = END_BUILTINS;
1866*38fd1498Szrj   built_in_function fcodef32 = END_BUILTINS;
1867*38fd1498Szrj   built_in_function fcodef64 = END_BUILTINS;
1868*38fd1498Szrj   built_in_function fcodef128 = END_BUILTINS;
1869*38fd1498Szrj   built_in_function fcodef32x = END_BUILTINS;
1870*38fd1498Szrj   built_in_function fcodef64x = END_BUILTINS;
1871*38fd1498Szrj   built_in_function fcodef128x = END_BUILTINS;
1872*38fd1498Szrj 
1873*38fd1498Szrj   switch (fn)
1874*38fd1498Szrj     {
1875*38fd1498Szrj     CASE_MATHFN (ACOS)
1876*38fd1498Szrj     CASE_MATHFN (ACOSH)
1877*38fd1498Szrj     CASE_MATHFN (ASIN)
1878*38fd1498Szrj     CASE_MATHFN (ASINH)
1879*38fd1498Szrj     CASE_MATHFN (ATAN)
1880*38fd1498Szrj     CASE_MATHFN (ATAN2)
1881*38fd1498Szrj     CASE_MATHFN (ATANH)
1882*38fd1498Szrj     CASE_MATHFN (CBRT)
1883*38fd1498Szrj     CASE_MATHFN_FLOATN (CEIL)
1884*38fd1498Szrj     CASE_MATHFN (CEXPI)
1885*38fd1498Szrj     CASE_MATHFN_FLOATN (COPYSIGN)
1886*38fd1498Szrj     CASE_MATHFN (COS)
1887*38fd1498Szrj     CASE_MATHFN (COSH)
1888*38fd1498Szrj     CASE_MATHFN (DREM)
1889*38fd1498Szrj     CASE_MATHFN (ERF)
1890*38fd1498Szrj     CASE_MATHFN (ERFC)
1891*38fd1498Szrj     CASE_MATHFN (EXP)
1892*38fd1498Szrj     CASE_MATHFN (EXP10)
1893*38fd1498Szrj     CASE_MATHFN (EXP2)
1894*38fd1498Szrj     CASE_MATHFN (EXPM1)
1895*38fd1498Szrj     CASE_MATHFN (FABS)
1896*38fd1498Szrj     CASE_MATHFN (FDIM)
1897*38fd1498Szrj     CASE_MATHFN_FLOATN (FLOOR)
1898*38fd1498Szrj     CASE_MATHFN_FLOATN (FMA)
1899*38fd1498Szrj     CASE_MATHFN_FLOATN (FMAX)
1900*38fd1498Szrj     CASE_MATHFN_FLOATN (FMIN)
1901*38fd1498Szrj     CASE_MATHFN (FMOD)
1902*38fd1498Szrj     CASE_MATHFN (FREXP)
1903*38fd1498Szrj     CASE_MATHFN (GAMMA)
1904*38fd1498Szrj     CASE_MATHFN_REENT (GAMMA) /* GAMMA_R */
1905*38fd1498Szrj     CASE_MATHFN (HUGE_VAL)
1906*38fd1498Szrj     CASE_MATHFN (HYPOT)
1907*38fd1498Szrj     CASE_MATHFN (ILOGB)
1908*38fd1498Szrj     CASE_MATHFN (ICEIL)
1909*38fd1498Szrj     CASE_MATHFN (IFLOOR)
1910*38fd1498Szrj     CASE_MATHFN (INF)
1911*38fd1498Szrj     CASE_MATHFN (IRINT)
1912*38fd1498Szrj     CASE_MATHFN (IROUND)
1913*38fd1498Szrj     CASE_MATHFN (ISINF)
1914*38fd1498Szrj     CASE_MATHFN (J0)
1915*38fd1498Szrj     CASE_MATHFN (J1)
1916*38fd1498Szrj     CASE_MATHFN (JN)
1917*38fd1498Szrj     CASE_MATHFN (LCEIL)
1918*38fd1498Szrj     CASE_MATHFN (LDEXP)
1919*38fd1498Szrj     CASE_MATHFN (LFLOOR)
1920*38fd1498Szrj     CASE_MATHFN (LGAMMA)
1921*38fd1498Szrj     CASE_MATHFN_REENT (LGAMMA) /* LGAMMA_R */
1922*38fd1498Szrj     CASE_MATHFN (LLCEIL)
1923*38fd1498Szrj     CASE_MATHFN (LLFLOOR)
1924*38fd1498Szrj     CASE_MATHFN (LLRINT)
1925*38fd1498Szrj     CASE_MATHFN (LLROUND)
1926*38fd1498Szrj     CASE_MATHFN (LOG)
1927*38fd1498Szrj     CASE_MATHFN (LOG10)
1928*38fd1498Szrj     CASE_MATHFN (LOG1P)
1929*38fd1498Szrj     CASE_MATHFN (LOG2)
1930*38fd1498Szrj     CASE_MATHFN (LOGB)
1931*38fd1498Szrj     CASE_MATHFN (LRINT)
1932*38fd1498Szrj     CASE_MATHFN (LROUND)
1933*38fd1498Szrj     CASE_MATHFN (MODF)
1934*38fd1498Szrj     CASE_MATHFN (NAN)
1935*38fd1498Szrj     CASE_MATHFN (NANS)
1936*38fd1498Szrj     CASE_MATHFN_FLOATN (NEARBYINT)
1937*38fd1498Szrj     CASE_MATHFN (NEXTAFTER)
1938*38fd1498Szrj     CASE_MATHFN (NEXTTOWARD)
1939*38fd1498Szrj     CASE_MATHFN (POW)
1940*38fd1498Szrj     CASE_MATHFN (POWI)
1941*38fd1498Szrj     CASE_MATHFN (POW10)
1942*38fd1498Szrj     CASE_MATHFN (REMAINDER)
1943*38fd1498Szrj     CASE_MATHFN (REMQUO)
1944*38fd1498Szrj     CASE_MATHFN_FLOATN (RINT)
1945*38fd1498Szrj     CASE_MATHFN_FLOATN (ROUND)
1946*38fd1498Szrj     CASE_MATHFN (SCALB)
1947*38fd1498Szrj     CASE_MATHFN (SCALBLN)
1948*38fd1498Szrj     CASE_MATHFN (SCALBN)
1949*38fd1498Szrj     CASE_MATHFN (SIGNBIT)
1950*38fd1498Szrj     CASE_MATHFN (SIGNIFICAND)
1951*38fd1498Szrj     CASE_MATHFN (SIN)
1952*38fd1498Szrj     CASE_MATHFN (SINCOS)
1953*38fd1498Szrj     CASE_MATHFN (SINH)
1954*38fd1498Szrj     CASE_MATHFN_FLOATN (SQRT)
1955*38fd1498Szrj     CASE_MATHFN (TAN)
1956*38fd1498Szrj     CASE_MATHFN (TANH)
1957*38fd1498Szrj     CASE_MATHFN (TGAMMA)
1958*38fd1498Szrj     CASE_MATHFN_FLOATN (TRUNC)
1959*38fd1498Szrj     CASE_MATHFN (Y0)
1960*38fd1498Szrj     CASE_MATHFN (Y1)
1961*38fd1498Szrj     CASE_MATHFN (YN)
1962*38fd1498Szrj 
1963*38fd1498Szrj     default:
1964*38fd1498Szrj       return END_BUILTINS;
1965*38fd1498Szrj     }
1966*38fd1498Szrj 
1967*38fd1498Szrj   mtype = TYPE_MAIN_VARIANT (type);
1968*38fd1498Szrj   if (mtype == double_type_node)
1969*38fd1498Szrj     return fcode;
1970*38fd1498Szrj   else if (mtype == float_type_node)
1971*38fd1498Szrj     return fcodef;
1972*38fd1498Szrj   else if (mtype == long_double_type_node)
1973*38fd1498Szrj     return fcodel;
1974*38fd1498Szrj   else if (mtype == float16_type_node)
1975*38fd1498Szrj     return fcodef16;
1976*38fd1498Szrj   else if (mtype == float32_type_node)
1977*38fd1498Szrj     return fcodef32;
1978*38fd1498Szrj   else if (mtype == float64_type_node)
1979*38fd1498Szrj     return fcodef64;
1980*38fd1498Szrj   else if (mtype == float128_type_node)
1981*38fd1498Szrj     return fcodef128;
1982*38fd1498Szrj   else if (mtype == float32x_type_node)
1983*38fd1498Szrj     return fcodef32x;
1984*38fd1498Szrj   else if (mtype == float64x_type_node)
1985*38fd1498Szrj     return fcodef64x;
1986*38fd1498Szrj   else if (mtype == float128x_type_node)
1987*38fd1498Szrj     return fcodef128x;
1988*38fd1498Szrj   else
1989*38fd1498Szrj     return END_BUILTINS;
1990*38fd1498Szrj }
1991*38fd1498Szrj 
1992*38fd1498Szrj /* Return mathematic function equivalent to FN but operating directly on TYPE,
1993*38fd1498Szrj    if available.  If IMPLICIT_P is true use the implicit builtin declaration,
1994*38fd1498Szrj    otherwise use the explicit declaration.  If we can't do the conversion,
1995*38fd1498Szrj    return null.  */
1996*38fd1498Szrj 
1997*38fd1498Szrj static tree
mathfn_built_in_1(tree type,combined_fn fn,bool implicit_p)1998*38fd1498Szrj mathfn_built_in_1 (tree type, combined_fn fn, bool implicit_p)
1999*38fd1498Szrj {
2000*38fd1498Szrj   built_in_function fcode2 = mathfn_built_in_2 (type, fn);
2001*38fd1498Szrj   if (fcode2 == END_BUILTINS)
2002*38fd1498Szrj     return NULL_TREE;
2003*38fd1498Szrj 
2004*38fd1498Szrj   if (implicit_p && !builtin_decl_implicit_p (fcode2))
2005*38fd1498Szrj     return NULL_TREE;
2006*38fd1498Szrj 
2007*38fd1498Szrj   return builtin_decl_explicit (fcode2);
2008*38fd1498Szrj }
2009*38fd1498Szrj 
2010*38fd1498Szrj /* Like mathfn_built_in_1, but always use the implicit array.  */
2011*38fd1498Szrj 
2012*38fd1498Szrj tree
mathfn_built_in(tree type,combined_fn fn)2013*38fd1498Szrj mathfn_built_in (tree type, combined_fn fn)
2014*38fd1498Szrj {
2015*38fd1498Szrj   return mathfn_built_in_1 (type, fn, /*implicit=*/ 1);
2016*38fd1498Szrj }
2017*38fd1498Szrj 
2018*38fd1498Szrj /* Like mathfn_built_in_1, but take a built_in_function and
2019*38fd1498Szrj    always use the implicit array.  */
2020*38fd1498Szrj 
2021*38fd1498Szrj tree
mathfn_built_in(tree type,enum built_in_function fn)2022*38fd1498Szrj mathfn_built_in (tree type, enum built_in_function fn)
2023*38fd1498Szrj {
2024*38fd1498Szrj   return mathfn_built_in_1 (type, as_combined_fn (fn), /*implicit=*/ 1);
2025*38fd1498Szrj }
2026*38fd1498Szrj 
2027*38fd1498Szrj /* If BUILT_IN_NORMAL function FNDECL has an associated internal function,
2028*38fd1498Szrj    return its code, otherwise return IFN_LAST.  Note that this function
2029*38fd1498Szrj    only tests whether the function is defined in internals.def, not whether
2030*38fd1498Szrj    it is actually available on the target.  */
2031*38fd1498Szrj 
2032*38fd1498Szrj internal_fn
associated_internal_fn(tree fndecl)2033*38fd1498Szrj associated_internal_fn (tree fndecl)
2034*38fd1498Szrj {
2035*38fd1498Szrj   gcc_checking_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL);
2036*38fd1498Szrj   tree return_type = TREE_TYPE (TREE_TYPE (fndecl));
2037*38fd1498Szrj   switch (DECL_FUNCTION_CODE (fndecl))
2038*38fd1498Szrj     {
2039*38fd1498Szrj #define DEF_INTERNAL_FLT_FN(NAME, FLAGS, OPTAB, TYPE) \
2040*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_##NAME): return IFN_##NAME;
2041*38fd1498Szrj #define DEF_INTERNAL_FLT_FLOATN_FN(NAME, FLAGS, OPTAB, TYPE) \
2042*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_##NAME): return IFN_##NAME; \
2043*38fd1498Szrj     CASE_FLT_FN_FLOATN_NX (BUILT_IN_##NAME): return IFN_##NAME;
2044*38fd1498Szrj #define DEF_INTERNAL_INT_FN(NAME, FLAGS, OPTAB, TYPE) \
2045*38fd1498Szrj     CASE_INT_FN (BUILT_IN_##NAME): return IFN_##NAME;
2046*38fd1498Szrj #include "internal-fn.def"
2047*38fd1498Szrj 
2048*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_POW10):
2049*38fd1498Szrj       return IFN_EXP10;
2050*38fd1498Szrj 
2051*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_DREM):
2052*38fd1498Szrj       return IFN_REMAINDER;
2053*38fd1498Szrj 
2054*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_SCALBN):
2055*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_SCALBLN):
2056*38fd1498Szrj       if (REAL_MODE_FORMAT (TYPE_MODE (return_type))->b == 2)
2057*38fd1498Szrj 	return IFN_LDEXP;
2058*38fd1498Szrj       return IFN_LAST;
2059*38fd1498Szrj 
2060*38fd1498Szrj     default:
2061*38fd1498Szrj       return IFN_LAST;
2062*38fd1498Szrj     }
2063*38fd1498Szrj }
2064*38fd1498Szrj 
2065*38fd1498Szrj /* If CALL is a call to a BUILT_IN_NORMAL function that could be replaced
2066*38fd1498Szrj    on the current target by a call to an internal function, return the
2067*38fd1498Szrj    code of that internal function, otherwise return IFN_LAST.  The caller
2068*38fd1498Szrj    is responsible for ensuring that any side-effects of the built-in
2069*38fd1498Szrj    call are dealt with correctly.  E.g. if CALL sets errno, the caller
2070*38fd1498Szrj    must decide that the errno result isn't needed or make it available
2071*38fd1498Szrj    in some other way.  */
2072*38fd1498Szrj 
2073*38fd1498Szrj internal_fn
replacement_internal_fn(gcall * call)2074*38fd1498Szrj replacement_internal_fn (gcall *call)
2075*38fd1498Szrj {
2076*38fd1498Szrj   if (gimple_call_builtin_p (call, BUILT_IN_NORMAL))
2077*38fd1498Szrj     {
2078*38fd1498Szrj       internal_fn ifn = associated_internal_fn (gimple_call_fndecl (call));
2079*38fd1498Szrj       if (ifn != IFN_LAST)
2080*38fd1498Szrj 	{
2081*38fd1498Szrj 	  tree_pair types = direct_internal_fn_types (ifn, call);
2082*38fd1498Szrj 	  optimization_type opt_type = bb_optimization_type (gimple_bb (call));
2083*38fd1498Szrj 	  if (direct_internal_fn_supported_p (ifn, types, opt_type))
2084*38fd1498Szrj 	    return ifn;
2085*38fd1498Szrj 	}
2086*38fd1498Szrj     }
2087*38fd1498Szrj   return IFN_LAST;
2088*38fd1498Szrj }
2089*38fd1498Szrj 
2090*38fd1498Szrj /* Expand a call to the builtin trinary math functions (fma).
2091*38fd1498Szrj    Return NULL_RTX if a normal call should be emitted rather than expanding the
2092*38fd1498Szrj    function in-line.  EXP is the expression that is a call to the builtin
2093*38fd1498Szrj    function; if convenient, the result should be placed in TARGET.
2094*38fd1498Szrj    SUBTARGET may be used as the target for computing one of EXP's
2095*38fd1498Szrj    operands.  */
2096*38fd1498Szrj 
2097*38fd1498Szrj static rtx
expand_builtin_mathfn_ternary(tree exp,rtx target,rtx subtarget)2098*38fd1498Szrj expand_builtin_mathfn_ternary (tree exp, rtx target, rtx subtarget)
2099*38fd1498Szrj {
2100*38fd1498Szrj   optab builtin_optab;
2101*38fd1498Szrj   rtx op0, op1, op2, result;
2102*38fd1498Szrj   rtx_insn *insns;
2103*38fd1498Szrj   tree fndecl = get_callee_fndecl (exp);
2104*38fd1498Szrj   tree arg0, arg1, arg2;
2105*38fd1498Szrj   machine_mode mode;
2106*38fd1498Szrj 
2107*38fd1498Szrj   if (!validate_arglist (exp, REAL_TYPE, REAL_TYPE, REAL_TYPE, VOID_TYPE))
2108*38fd1498Szrj     return NULL_RTX;
2109*38fd1498Szrj 
2110*38fd1498Szrj   arg0 = CALL_EXPR_ARG (exp, 0);
2111*38fd1498Szrj   arg1 = CALL_EXPR_ARG (exp, 1);
2112*38fd1498Szrj   arg2 = CALL_EXPR_ARG (exp, 2);
2113*38fd1498Szrj 
2114*38fd1498Szrj   switch (DECL_FUNCTION_CODE (fndecl))
2115*38fd1498Szrj     {
2116*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_FMA):
2117*38fd1498Szrj     CASE_FLT_FN_FLOATN_NX (BUILT_IN_FMA):
2118*38fd1498Szrj       builtin_optab = fma_optab; break;
2119*38fd1498Szrj     default:
2120*38fd1498Szrj       gcc_unreachable ();
2121*38fd1498Szrj     }
2122*38fd1498Szrj 
2123*38fd1498Szrj   /* Make a suitable register to place result in.  */
2124*38fd1498Szrj   mode = TYPE_MODE (TREE_TYPE (exp));
2125*38fd1498Szrj 
2126*38fd1498Szrj   /* Before working hard, check whether the instruction is available.  */
2127*38fd1498Szrj   if (optab_handler (builtin_optab, mode) == CODE_FOR_nothing)
2128*38fd1498Szrj     return NULL_RTX;
2129*38fd1498Szrj 
2130*38fd1498Szrj   result = gen_reg_rtx (mode);
2131*38fd1498Szrj 
2132*38fd1498Szrj   /* Always stabilize the argument list.  */
2133*38fd1498Szrj   CALL_EXPR_ARG (exp, 0) = arg0 = builtin_save_expr (arg0);
2134*38fd1498Szrj   CALL_EXPR_ARG (exp, 1) = arg1 = builtin_save_expr (arg1);
2135*38fd1498Szrj   CALL_EXPR_ARG (exp, 2) = arg2 = builtin_save_expr (arg2);
2136*38fd1498Szrj 
2137*38fd1498Szrj   op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
2138*38fd1498Szrj   op1 = expand_normal (arg1);
2139*38fd1498Szrj   op2 = expand_normal (arg2);
2140*38fd1498Szrj 
2141*38fd1498Szrj   start_sequence ();
2142*38fd1498Szrj 
2143*38fd1498Szrj   /* Compute into RESULT.
2144*38fd1498Szrj      Set RESULT to wherever the result comes back.  */
2145*38fd1498Szrj   result = expand_ternary_op (mode, builtin_optab, op0, op1, op2,
2146*38fd1498Szrj 			      result, 0);
2147*38fd1498Szrj 
2148*38fd1498Szrj   /* If we were unable to expand via the builtin, stop the sequence
2149*38fd1498Szrj      (without outputting the insns) and call to the library function
2150*38fd1498Szrj      with the stabilized argument list.  */
2151*38fd1498Szrj   if (result == 0)
2152*38fd1498Szrj     {
2153*38fd1498Szrj       end_sequence ();
2154*38fd1498Szrj       return expand_call (exp, target, target == const0_rtx);
2155*38fd1498Szrj     }
2156*38fd1498Szrj 
2157*38fd1498Szrj   /* Output the entire sequence.  */
2158*38fd1498Szrj   insns = get_insns ();
2159*38fd1498Szrj   end_sequence ();
2160*38fd1498Szrj   emit_insn (insns);
2161*38fd1498Szrj 
2162*38fd1498Szrj   return result;
2163*38fd1498Szrj }
2164*38fd1498Szrj 
2165*38fd1498Szrj /* Expand a call to the builtin sin and cos math functions.
2166*38fd1498Szrj    Return NULL_RTX if a normal call should be emitted rather than expanding the
2167*38fd1498Szrj    function in-line.  EXP is the expression that is a call to the builtin
2168*38fd1498Szrj    function; if convenient, the result should be placed in TARGET.
2169*38fd1498Szrj    SUBTARGET may be used as the target for computing one of EXP's
2170*38fd1498Szrj    operands.  */
2171*38fd1498Szrj 
2172*38fd1498Szrj static rtx
expand_builtin_mathfn_3(tree exp,rtx target,rtx subtarget)2173*38fd1498Szrj expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
2174*38fd1498Szrj {
2175*38fd1498Szrj   optab builtin_optab;
2176*38fd1498Szrj   rtx op0;
2177*38fd1498Szrj   rtx_insn *insns;
2178*38fd1498Szrj   tree fndecl = get_callee_fndecl (exp);
2179*38fd1498Szrj   machine_mode mode;
2180*38fd1498Szrj   tree arg;
2181*38fd1498Szrj 
2182*38fd1498Szrj   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
2183*38fd1498Szrj     return NULL_RTX;
2184*38fd1498Szrj 
2185*38fd1498Szrj   arg = CALL_EXPR_ARG (exp, 0);
2186*38fd1498Szrj 
2187*38fd1498Szrj   switch (DECL_FUNCTION_CODE (fndecl))
2188*38fd1498Szrj     {
2189*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_SIN):
2190*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_COS):
2191*38fd1498Szrj       builtin_optab = sincos_optab; break;
2192*38fd1498Szrj     default:
2193*38fd1498Szrj       gcc_unreachable ();
2194*38fd1498Szrj     }
2195*38fd1498Szrj 
2196*38fd1498Szrj   /* Make a suitable register to place result in.  */
2197*38fd1498Szrj   mode = TYPE_MODE (TREE_TYPE (exp));
2198*38fd1498Szrj 
2199*38fd1498Szrj   /* Check if sincos insn is available, otherwise fallback
2200*38fd1498Szrj      to sin or cos insn.  */
2201*38fd1498Szrj   if (optab_handler (builtin_optab, mode) == CODE_FOR_nothing)
2202*38fd1498Szrj     switch (DECL_FUNCTION_CODE (fndecl))
2203*38fd1498Szrj       {
2204*38fd1498Szrj       CASE_FLT_FN (BUILT_IN_SIN):
2205*38fd1498Szrj 	builtin_optab = sin_optab; break;
2206*38fd1498Szrj       CASE_FLT_FN (BUILT_IN_COS):
2207*38fd1498Szrj 	builtin_optab = cos_optab; break;
2208*38fd1498Szrj       default:
2209*38fd1498Szrj 	gcc_unreachable ();
2210*38fd1498Szrj       }
2211*38fd1498Szrj 
2212*38fd1498Szrj   /* Before working hard, check whether the instruction is available.  */
2213*38fd1498Szrj   if (optab_handler (builtin_optab, mode) != CODE_FOR_nothing)
2214*38fd1498Szrj     {
2215*38fd1498Szrj       rtx result = gen_reg_rtx (mode);
2216*38fd1498Szrj 
2217*38fd1498Szrj       /* Wrap the computation of the argument in a SAVE_EXPR, as we may
2218*38fd1498Szrj 	 need to expand the argument again.  This way, we will not perform
2219*38fd1498Szrj 	 side-effects more the once.  */
2220*38fd1498Szrj       CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
2221*38fd1498Szrj 
2222*38fd1498Szrj       op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
2223*38fd1498Szrj 
2224*38fd1498Szrj       start_sequence ();
2225*38fd1498Szrj 
2226*38fd1498Szrj       /* Compute into RESULT.
2227*38fd1498Szrj 	 Set RESULT to wherever the result comes back.  */
2228*38fd1498Szrj       if (builtin_optab == sincos_optab)
2229*38fd1498Szrj 	{
2230*38fd1498Szrj 	  int ok;
2231*38fd1498Szrj 
2232*38fd1498Szrj 	  switch (DECL_FUNCTION_CODE (fndecl))
2233*38fd1498Szrj 	    {
2234*38fd1498Szrj 	    CASE_FLT_FN (BUILT_IN_SIN):
2235*38fd1498Szrj 	      ok = expand_twoval_unop (builtin_optab, op0, 0, result, 0);
2236*38fd1498Szrj 	      break;
2237*38fd1498Szrj 	    CASE_FLT_FN (BUILT_IN_COS):
2238*38fd1498Szrj 	      ok = expand_twoval_unop (builtin_optab, op0, result, 0, 0);
2239*38fd1498Szrj 	      break;
2240*38fd1498Szrj 	    default:
2241*38fd1498Szrj 	      gcc_unreachable ();
2242*38fd1498Szrj 	    }
2243*38fd1498Szrj 	  gcc_assert (ok);
2244*38fd1498Szrj 	}
2245*38fd1498Szrj       else
2246*38fd1498Szrj 	result = expand_unop (mode, builtin_optab, op0, result, 0);
2247*38fd1498Szrj 
2248*38fd1498Szrj       if (result != 0)
2249*38fd1498Szrj 	{
2250*38fd1498Szrj 	  /* Output the entire sequence.  */
2251*38fd1498Szrj 	  insns = get_insns ();
2252*38fd1498Szrj 	  end_sequence ();
2253*38fd1498Szrj 	  emit_insn (insns);
2254*38fd1498Szrj 	  return result;
2255*38fd1498Szrj 	}
2256*38fd1498Szrj 
2257*38fd1498Szrj       /* If we were unable to expand via the builtin, stop the sequence
2258*38fd1498Szrj 	 (without outputting the insns) and call to the library function
2259*38fd1498Szrj 	 with the stabilized argument list.  */
2260*38fd1498Szrj       end_sequence ();
2261*38fd1498Szrj     }
2262*38fd1498Szrj 
2263*38fd1498Szrj   return expand_call (exp, target, target == const0_rtx);
2264*38fd1498Szrj }
2265*38fd1498Szrj 
2266*38fd1498Szrj /* Given an interclass math builtin decl FNDECL and it's argument ARG
2267*38fd1498Szrj    return an RTL instruction code that implements the functionality.
2268*38fd1498Szrj    If that isn't possible or available return CODE_FOR_nothing.  */
2269*38fd1498Szrj 
2270*38fd1498Szrj static enum insn_code
interclass_mathfn_icode(tree arg,tree fndecl)2271*38fd1498Szrj interclass_mathfn_icode (tree arg, tree fndecl)
2272*38fd1498Szrj {
2273*38fd1498Szrj   bool errno_set = false;
2274*38fd1498Szrj   optab builtin_optab = unknown_optab;
2275*38fd1498Szrj   machine_mode mode;
2276*38fd1498Szrj 
2277*38fd1498Szrj   switch (DECL_FUNCTION_CODE (fndecl))
2278*38fd1498Szrj     {
2279*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_ILOGB):
2280*38fd1498Szrj       errno_set = true; builtin_optab = ilogb_optab; break;
2281*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_ISINF):
2282*38fd1498Szrj       builtin_optab = isinf_optab; break;
2283*38fd1498Szrj     case BUILT_IN_ISNORMAL:
2284*38fd1498Szrj     case BUILT_IN_ISFINITE:
2285*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_FINITE):
2286*38fd1498Szrj     case BUILT_IN_FINITED32:
2287*38fd1498Szrj     case BUILT_IN_FINITED64:
2288*38fd1498Szrj     case BUILT_IN_FINITED128:
2289*38fd1498Szrj     case BUILT_IN_ISINFD32:
2290*38fd1498Szrj     case BUILT_IN_ISINFD64:
2291*38fd1498Szrj     case BUILT_IN_ISINFD128:
2292*38fd1498Szrj       /* These builtins have no optabs (yet).  */
2293*38fd1498Szrj       break;
2294*38fd1498Szrj     default:
2295*38fd1498Szrj       gcc_unreachable ();
2296*38fd1498Szrj     }
2297*38fd1498Szrj 
2298*38fd1498Szrj   /* There's no easy way to detect the case we need to set EDOM.  */
2299*38fd1498Szrj   if (flag_errno_math && errno_set)
2300*38fd1498Szrj     return CODE_FOR_nothing;
2301*38fd1498Szrj 
2302*38fd1498Szrj   /* Optab mode depends on the mode of the input argument.  */
2303*38fd1498Szrj   mode = TYPE_MODE (TREE_TYPE (arg));
2304*38fd1498Szrj 
2305*38fd1498Szrj   if (builtin_optab)
2306*38fd1498Szrj     return optab_handler (builtin_optab, mode);
2307*38fd1498Szrj   return CODE_FOR_nothing;
2308*38fd1498Szrj }
2309*38fd1498Szrj 
2310*38fd1498Szrj /* Expand a call to one of the builtin math functions that operate on
2311*38fd1498Szrj    floating point argument and output an integer result (ilogb, isinf,
2312*38fd1498Szrj    isnan, etc).
2313*38fd1498Szrj    Return 0 if a normal call should be emitted rather than expanding the
2314*38fd1498Szrj    function in-line.  EXP is the expression that is a call to the builtin
2315*38fd1498Szrj    function; if convenient, the result should be placed in TARGET.  */
2316*38fd1498Szrj 
2317*38fd1498Szrj static rtx
expand_builtin_interclass_mathfn(tree exp,rtx target)2318*38fd1498Szrj expand_builtin_interclass_mathfn (tree exp, rtx target)
2319*38fd1498Szrj {
2320*38fd1498Szrj   enum insn_code icode = CODE_FOR_nothing;
2321*38fd1498Szrj   rtx op0;
2322*38fd1498Szrj   tree fndecl = get_callee_fndecl (exp);
2323*38fd1498Szrj   machine_mode mode;
2324*38fd1498Szrj   tree arg;
2325*38fd1498Szrj 
2326*38fd1498Szrj   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
2327*38fd1498Szrj     return NULL_RTX;
2328*38fd1498Szrj 
2329*38fd1498Szrj   arg = CALL_EXPR_ARG (exp, 0);
2330*38fd1498Szrj   icode = interclass_mathfn_icode (arg, fndecl);
2331*38fd1498Szrj   mode = TYPE_MODE (TREE_TYPE (arg));
2332*38fd1498Szrj 
2333*38fd1498Szrj   if (icode != CODE_FOR_nothing)
2334*38fd1498Szrj     {
2335*38fd1498Szrj       struct expand_operand ops[1];
2336*38fd1498Szrj       rtx_insn *last = get_last_insn ();
2337*38fd1498Szrj       tree orig_arg = arg;
2338*38fd1498Szrj 
2339*38fd1498Szrj       /* Wrap the computation of the argument in a SAVE_EXPR, as we may
2340*38fd1498Szrj 	 need to expand the argument again.  This way, we will not perform
2341*38fd1498Szrj 	 side-effects more the once.  */
2342*38fd1498Szrj       CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
2343*38fd1498Szrj 
2344*38fd1498Szrj       op0 = expand_expr (arg, NULL_RTX, VOIDmode, EXPAND_NORMAL);
2345*38fd1498Szrj 
2346*38fd1498Szrj       if (mode != GET_MODE (op0))
2347*38fd1498Szrj 	op0 = convert_to_mode (mode, op0, 0);
2348*38fd1498Szrj 
2349*38fd1498Szrj       create_output_operand (&ops[0], target, TYPE_MODE (TREE_TYPE (exp)));
2350*38fd1498Szrj       if (maybe_legitimize_operands (icode, 0, 1, ops)
2351*38fd1498Szrj 	  && maybe_emit_unop_insn (icode, ops[0].value, op0, UNKNOWN))
2352*38fd1498Szrj 	return ops[0].value;
2353*38fd1498Szrj 
2354*38fd1498Szrj       delete_insns_since (last);
2355*38fd1498Szrj       CALL_EXPR_ARG (exp, 0) = orig_arg;
2356*38fd1498Szrj     }
2357*38fd1498Szrj 
2358*38fd1498Szrj   return NULL_RTX;
2359*38fd1498Szrj }
2360*38fd1498Szrj 
2361*38fd1498Szrj /* Expand a call to the builtin sincos math function.
2362*38fd1498Szrj    Return NULL_RTX if a normal call should be emitted rather than expanding the
2363*38fd1498Szrj    function in-line.  EXP is the expression that is a call to the builtin
2364*38fd1498Szrj    function.  */
2365*38fd1498Szrj 
2366*38fd1498Szrj static rtx
expand_builtin_sincos(tree exp)2367*38fd1498Szrj expand_builtin_sincos (tree exp)
2368*38fd1498Szrj {
2369*38fd1498Szrj   rtx op0, op1, op2, target1, target2;
2370*38fd1498Szrj   machine_mode mode;
2371*38fd1498Szrj   tree arg, sinp, cosp;
2372*38fd1498Szrj   int result;
2373*38fd1498Szrj   location_t loc = EXPR_LOCATION (exp);
2374*38fd1498Szrj   tree alias_type, alias_off;
2375*38fd1498Szrj 
2376*38fd1498Szrj   if (!validate_arglist (exp, REAL_TYPE,
2377*38fd1498Szrj  			 POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
2378*38fd1498Szrj     return NULL_RTX;
2379*38fd1498Szrj 
2380*38fd1498Szrj   arg = CALL_EXPR_ARG (exp, 0);
2381*38fd1498Szrj   sinp = CALL_EXPR_ARG (exp, 1);
2382*38fd1498Szrj   cosp = CALL_EXPR_ARG (exp, 2);
2383*38fd1498Szrj 
2384*38fd1498Szrj   /* Make a suitable register to place result in.  */
2385*38fd1498Szrj   mode = TYPE_MODE (TREE_TYPE (arg));
2386*38fd1498Szrj 
2387*38fd1498Szrj   /* Check if sincos insn is available, otherwise emit the call.  */
2388*38fd1498Szrj   if (optab_handler (sincos_optab, mode) == CODE_FOR_nothing)
2389*38fd1498Szrj     return NULL_RTX;
2390*38fd1498Szrj 
2391*38fd1498Szrj   target1 = gen_reg_rtx (mode);
2392*38fd1498Szrj   target2 = gen_reg_rtx (mode);
2393*38fd1498Szrj 
2394*38fd1498Szrj   op0 = expand_normal (arg);
2395*38fd1498Szrj   alias_type = build_pointer_type_for_mode (TREE_TYPE (arg), ptr_mode, true);
2396*38fd1498Szrj   alias_off = build_int_cst (alias_type, 0);
2397*38fd1498Szrj   op1 = expand_normal (fold_build2_loc (loc, MEM_REF, TREE_TYPE (arg),
2398*38fd1498Szrj 					sinp, alias_off));
2399*38fd1498Szrj   op2 = expand_normal (fold_build2_loc (loc, MEM_REF, TREE_TYPE (arg),
2400*38fd1498Szrj 					cosp, alias_off));
2401*38fd1498Szrj 
2402*38fd1498Szrj   /* Compute into target1 and target2.
2403*38fd1498Szrj      Set TARGET to wherever the result comes back.  */
2404*38fd1498Szrj   result = expand_twoval_unop (sincos_optab, op0, target2, target1, 0);
2405*38fd1498Szrj   gcc_assert (result);
2406*38fd1498Szrj 
2407*38fd1498Szrj   /* Move target1 and target2 to the memory locations indicated
2408*38fd1498Szrj      by op1 and op2.  */
2409*38fd1498Szrj   emit_move_insn (op1, target1);
2410*38fd1498Szrj   emit_move_insn (op2, target2);
2411*38fd1498Szrj 
2412*38fd1498Szrj   return const0_rtx;
2413*38fd1498Szrj }
2414*38fd1498Szrj 
2415*38fd1498Szrj /* Expand a call to the internal cexpi builtin to the sincos math function.
2416*38fd1498Szrj    EXP is the expression that is a call to the builtin function; if convenient,
2417*38fd1498Szrj    the result should be placed in TARGET.  */
2418*38fd1498Szrj 
2419*38fd1498Szrj static rtx
expand_builtin_cexpi(tree exp,rtx target)2420*38fd1498Szrj expand_builtin_cexpi (tree exp, rtx target)
2421*38fd1498Szrj {
2422*38fd1498Szrj   tree fndecl = get_callee_fndecl (exp);
2423*38fd1498Szrj   tree arg, type;
2424*38fd1498Szrj   machine_mode mode;
2425*38fd1498Szrj   rtx op0, op1, op2;
2426*38fd1498Szrj   location_t loc = EXPR_LOCATION (exp);
2427*38fd1498Szrj 
2428*38fd1498Szrj   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
2429*38fd1498Szrj     return NULL_RTX;
2430*38fd1498Szrj 
2431*38fd1498Szrj   arg = CALL_EXPR_ARG (exp, 0);
2432*38fd1498Szrj   type = TREE_TYPE (arg);
2433*38fd1498Szrj   mode = TYPE_MODE (TREE_TYPE (arg));
2434*38fd1498Szrj 
2435*38fd1498Szrj   /* Try expanding via a sincos optab, fall back to emitting a libcall
2436*38fd1498Szrj      to sincos or cexp.  We are sure we have sincos or cexp because cexpi
2437*38fd1498Szrj      is only generated from sincos, cexp or if we have either of them.  */
2438*38fd1498Szrj   if (optab_handler (sincos_optab, mode) != CODE_FOR_nothing)
2439*38fd1498Szrj     {
2440*38fd1498Szrj       op1 = gen_reg_rtx (mode);
2441*38fd1498Szrj       op2 = gen_reg_rtx (mode);
2442*38fd1498Szrj 
2443*38fd1498Szrj       op0 = expand_expr (arg, NULL_RTX, VOIDmode, EXPAND_NORMAL);
2444*38fd1498Szrj 
2445*38fd1498Szrj       /* Compute into op1 and op2.  */
2446*38fd1498Szrj       expand_twoval_unop (sincos_optab, op0, op2, op1, 0);
2447*38fd1498Szrj     }
2448*38fd1498Szrj   else if (targetm.libc_has_function (function_sincos))
2449*38fd1498Szrj     {
2450*38fd1498Szrj       tree call, fn = NULL_TREE;
2451*38fd1498Szrj       tree top1, top2;
2452*38fd1498Szrj       rtx op1a, op2a;
2453*38fd1498Szrj 
2454*38fd1498Szrj       if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
2455*38fd1498Szrj 	fn = builtin_decl_explicit (BUILT_IN_SINCOSF);
2456*38fd1498Szrj       else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
2457*38fd1498Szrj 	fn = builtin_decl_explicit (BUILT_IN_SINCOS);
2458*38fd1498Szrj       else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIL)
2459*38fd1498Szrj 	fn = builtin_decl_explicit (BUILT_IN_SINCOSL);
2460*38fd1498Szrj       else
2461*38fd1498Szrj 	gcc_unreachable ();
2462*38fd1498Szrj 
2463*38fd1498Szrj       op1 = assign_temp (TREE_TYPE (arg), 1, 1);
2464*38fd1498Szrj       op2 = assign_temp (TREE_TYPE (arg), 1, 1);
2465*38fd1498Szrj       op1a = copy_addr_to_reg (XEXP (op1, 0));
2466*38fd1498Szrj       op2a = copy_addr_to_reg (XEXP (op2, 0));
2467*38fd1498Szrj       top1 = make_tree (build_pointer_type (TREE_TYPE (arg)), op1a);
2468*38fd1498Szrj       top2 = make_tree (build_pointer_type (TREE_TYPE (arg)), op2a);
2469*38fd1498Szrj 
2470*38fd1498Szrj       /* Make sure not to fold the sincos call again.  */
2471*38fd1498Szrj       call = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
2472*38fd1498Szrj       expand_normal (build_call_nary (TREE_TYPE (TREE_TYPE (fn)),
2473*38fd1498Szrj 				      call, 3, arg, top1, top2));
2474*38fd1498Szrj     }
2475*38fd1498Szrj   else
2476*38fd1498Szrj     {
2477*38fd1498Szrj       tree call, fn = NULL_TREE, narg;
2478*38fd1498Szrj       tree ctype = build_complex_type (type);
2479*38fd1498Szrj 
2480*38fd1498Szrj       if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
2481*38fd1498Szrj 	fn = builtin_decl_explicit (BUILT_IN_CEXPF);
2482*38fd1498Szrj       else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
2483*38fd1498Szrj 	fn = builtin_decl_explicit (BUILT_IN_CEXP);
2484*38fd1498Szrj       else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIL)
2485*38fd1498Szrj 	fn = builtin_decl_explicit (BUILT_IN_CEXPL);
2486*38fd1498Szrj       else
2487*38fd1498Szrj 	gcc_unreachable ();
2488*38fd1498Szrj 
2489*38fd1498Szrj       /* If we don't have a decl for cexp create one.  This is the
2490*38fd1498Szrj 	 friendliest fallback if the user calls __builtin_cexpi
2491*38fd1498Szrj 	 without full target C99 function support.  */
2492*38fd1498Szrj       if (fn == NULL_TREE)
2493*38fd1498Szrj 	{
2494*38fd1498Szrj 	  tree fntype;
2495*38fd1498Szrj 	  const char *name = NULL;
2496*38fd1498Szrj 
2497*38fd1498Szrj 	  if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
2498*38fd1498Szrj 	    name = "cexpf";
2499*38fd1498Szrj 	  else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
2500*38fd1498Szrj 	    name = "cexp";
2501*38fd1498Szrj 	  else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIL)
2502*38fd1498Szrj 	    name = "cexpl";
2503*38fd1498Szrj 
2504*38fd1498Szrj 	  fntype = build_function_type_list (ctype, ctype, NULL_TREE);
2505*38fd1498Szrj 	  fn = build_fn_decl (name, fntype);
2506*38fd1498Szrj 	}
2507*38fd1498Szrj 
2508*38fd1498Szrj       narg = fold_build2_loc (loc, COMPLEX_EXPR, ctype,
2509*38fd1498Szrj 			  build_real (type, dconst0), arg);
2510*38fd1498Szrj 
2511*38fd1498Szrj       /* Make sure not to fold the cexp call again.  */
2512*38fd1498Szrj       call = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
2513*38fd1498Szrj       return expand_expr (build_call_nary (ctype, call, 1, narg),
2514*38fd1498Szrj 			  target, VOIDmode, EXPAND_NORMAL);
2515*38fd1498Szrj     }
2516*38fd1498Szrj 
2517*38fd1498Szrj   /* Now build the proper return type.  */
2518*38fd1498Szrj   return expand_expr (build2 (COMPLEX_EXPR, build_complex_type (type),
2519*38fd1498Szrj 			      make_tree (TREE_TYPE (arg), op2),
2520*38fd1498Szrj 			      make_tree (TREE_TYPE (arg), op1)),
2521*38fd1498Szrj 		      target, VOIDmode, EXPAND_NORMAL);
2522*38fd1498Szrj }
2523*38fd1498Szrj 
2524*38fd1498Szrj /* Conveniently construct a function call expression.  FNDECL names the
2525*38fd1498Szrj    function to be called, N is the number of arguments, and the "..."
2526*38fd1498Szrj    parameters are the argument expressions.  Unlike build_call_exr
2527*38fd1498Szrj    this doesn't fold the call, hence it will always return a CALL_EXPR.  */
2528*38fd1498Szrj 
2529*38fd1498Szrj static tree
build_call_nofold_loc(location_t loc,tree fndecl,int n,...)2530*38fd1498Szrj build_call_nofold_loc (location_t loc, tree fndecl, int n, ...)
2531*38fd1498Szrj {
2532*38fd1498Szrj   va_list ap;
2533*38fd1498Szrj   tree fntype = TREE_TYPE (fndecl);
2534*38fd1498Szrj   tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
2535*38fd1498Szrj 
2536*38fd1498Szrj   va_start (ap, n);
2537*38fd1498Szrj   fn = build_call_valist (TREE_TYPE (fntype), fn, n, ap);
2538*38fd1498Szrj   va_end (ap);
2539*38fd1498Szrj   SET_EXPR_LOCATION (fn, loc);
2540*38fd1498Szrj   return fn;
2541*38fd1498Szrj }
2542*38fd1498Szrj 
2543*38fd1498Szrj /* Expand a call to one of the builtin rounding functions gcc defines
2544*38fd1498Szrj    as an extension (lfloor and lceil).  As these are gcc extensions we
2545*38fd1498Szrj    do not need to worry about setting errno to EDOM.
2546*38fd1498Szrj    If expanding via optab fails, lower expression to (int)(floor(x)).
2547*38fd1498Szrj    EXP is the expression that is a call to the builtin function;
2548*38fd1498Szrj    if convenient, the result should be placed in TARGET.  */
2549*38fd1498Szrj 
2550*38fd1498Szrj static rtx
expand_builtin_int_roundingfn(tree exp,rtx target)2551*38fd1498Szrj expand_builtin_int_roundingfn (tree exp, rtx target)
2552*38fd1498Szrj {
2553*38fd1498Szrj   convert_optab builtin_optab;
2554*38fd1498Szrj   rtx op0, tmp;
2555*38fd1498Szrj   rtx_insn *insns;
2556*38fd1498Szrj   tree fndecl = get_callee_fndecl (exp);
2557*38fd1498Szrj   enum built_in_function fallback_fn;
2558*38fd1498Szrj   tree fallback_fndecl;
2559*38fd1498Szrj   machine_mode mode;
2560*38fd1498Szrj   tree arg;
2561*38fd1498Szrj 
2562*38fd1498Szrj   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
2563*38fd1498Szrj     gcc_unreachable ();
2564*38fd1498Szrj 
2565*38fd1498Szrj   arg = CALL_EXPR_ARG (exp, 0);
2566*38fd1498Szrj 
2567*38fd1498Szrj   switch (DECL_FUNCTION_CODE (fndecl))
2568*38fd1498Szrj     {
2569*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_ICEIL):
2570*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LCEIL):
2571*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LLCEIL):
2572*38fd1498Szrj       builtin_optab = lceil_optab;
2573*38fd1498Szrj       fallback_fn = BUILT_IN_CEIL;
2574*38fd1498Szrj       break;
2575*38fd1498Szrj 
2576*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_IFLOOR):
2577*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LFLOOR):
2578*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LLFLOOR):
2579*38fd1498Szrj       builtin_optab = lfloor_optab;
2580*38fd1498Szrj       fallback_fn = BUILT_IN_FLOOR;
2581*38fd1498Szrj       break;
2582*38fd1498Szrj 
2583*38fd1498Szrj     default:
2584*38fd1498Szrj       gcc_unreachable ();
2585*38fd1498Szrj     }
2586*38fd1498Szrj 
2587*38fd1498Szrj   /* Make a suitable register to place result in.  */
2588*38fd1498Szrj   mode = TYPE_MODE (TREE_TYPE (exp));
2589*38fd1498Szrj 
2590*38fd1498Szrj   target = gen_reg_rtx (mode);
2591*38fd1498Szrj 
2592*38fd1498Szrj   /* Wrap the computation of the argument in a SAVE_EXPR, as we may
2593*38fd1498Szrj      need to expand the argument again.  This way, we will not perform
2594*38fd1498Szrj      side-effects more the once.  */
2595*38fd1498Szrj   CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
2596*38fd1498Szrj 
2597*38fd1498Szrj   op0 = expand_expr (arg, NULL, VOIDmode, EXPAND_NORMAL);
2598*38fd1498Szrj 
2599*38fd1498Szrj   start_sequence ();
2600*38fd1498Szrj 
2601*38fd1498Szrj   /* Compute into TARGET.  */
2602*38fd1498Szrj   if (expand_sfix_optab (target, op0, builtin_optab))
2603*38fd1498Szrj     {
2604*38fd1498Szrj       /* Output the entire sequence.  */
2605*38fd1498Szrj       insns = get_insns ();
2606*38fd1498Szrj       end_sequence ();
2607*38fd1498Szrj       emit_insn (insns);
2608*38fd1498Szrj       return target;
2609*38fd1498Szrj     }
2610*38fd1498Szrj 
2611*38fd1498Szrj   /* If we were unable to expand via the builtin, stop the sequence
2612*38fd1498Szrj      (without outputting the insns).  */
2613*38fd1498Szrj   end_sequence ();
2614*38fd1498Szrj 
2615*38fd1498Szrj   /* Fall back to floating point rounding optab.  */
2616*38fd1498Szrj   fallback_fndecl = mathfn_built_in (TREE_TYPE (arg), fallback_fn);
2617*38fd1498Szrj 
2618*38fd1498Szrj   /* For non-C99 targets we may end up without a fallback fndecl here
2619*38fd1498Szrj      if the user called __builtin_lfloor directly.  In this case emit
2620*38fd1498Szrj      a call to the floor/ceil variants nevertheless.  This should result
2621*38fd1498Szrj      in the best user experience for not full C99 targets.  */
2622*38fd1498Szrj   if (fallback_fndecl == NULL_TREE)
2623*38fd1498Szrj     {
2624*38fd1498Szrj       tree fntype;
2625*38fd1498Szrj       const char *name = NULL;
2626*38fd1498Szrj 
2627*38fd1498Szrj       switch (DECL_FUNCTION_CODE (fndecl))
2628*38fd1498Szrj 	{
2629*38fd1498Szrj 	case BUILT_IN_ICEIL:
2630*38fd1498Szrj 	case BUILT_IN_LCEIL:
2631*38fd1498Szrj 	case BUILT_IN_LLCEIL:
2632*38fd1498Szrj 	  name = "ceil";
2633*38fd1498Szrj 	  break;
2634*38fd1498Szrj 	case BUILT_IN_ICEILF:
2635*38fd1498Szrj 	case BUILT_IN_LCEILF:
2636*38fd1498Szrj 	case BUILT_IN_LLCEILF:
2637*38fd1498Szrj 	  name = "ceilf";
2638*38fd1498Szrj 	  break;
2639*38fd1498Szrj 	case BUILT_IN_ICEILL:
2640*38fd1498Szrj 	case BUILT_IN_LCEILL:
2641*38fd1498Szrj 	case BUILT_IN_LLCEILL:
2642*38fd1498Szrj 	  name = "ceill";
2643*38fd1498Szrj 	  break;
2644*38fd1498Szrj 	case BUILT_IN_IFLOOR:
2645*38fd1498Szrj 	case BUILT_IN_LFLOOR:
2646*38fd1498Szrj 	case BUILT_IN_LLFLOOR:
2647*38fd1498Szrj 	  name = "floor";
2648*38fd1498Szrj 	  break;
2649*38fd1498Szrj 	case BUILT_IN_IFLOORF:
2650*38fd1498Szrj 	case BUILT_IN_LFLOORF:
2651*38fd1498Szrj 	case BUILT_IN_LLFLOORF:
2652*38fd1498Szrj 	  name = "floorf";
2653*38fd1498Szrj 	  break;
2654*38fd1498Szrj 	case BUILT_IN_IFLOORL:
2655*38fd1498Szrj 	case BUILT_IN_LFLOORL:
2656*38fd1498Szrj 	case BUILT_IN_LLFLOORL:
2657*38fd1498Szrj 	  name = "floorl";
2658*38fd1498Szrj 	  break;
2659*38fd1498Szrj 	default:
2660*38fd1498Szrj 	  gcc_unreachable ();
2661*38fd1498Szrj 	}
2662*38fd1498Szrj 
2663*38fd1498Szrj       fntype = build_function_type_list (TREE_TYPE (arg),
2664*38fd1498Szrj 					 TREE_TYPE (arg), NULL_TREE);
2665*38fd1498Szrj       fallback_fndecl = build_fn_decl (name, fntype);
2666*38fd1498Szrj     }
2667*38fd1498Szrj 
2668*38fd1498Szrj   exp = build_call_nofold_loc (EXPR_LOCATION (exp), fallback_fndecl, 1, arg);
2669*38fd1498Szrj 
2670*38fd1498Szrj   tmp = expand_normal (exp);
2671*38fd1498Szrj   tmp = maybe_emit_group_store (tmp, TREE_TYPE (exp));
2672*38fd1498Szrj 
2673*38fd1498Szrj   /* Truncate the result of floating point optab to integer
2674*38fd1498Szrj      via expand_fix ().  */
2675*38fd1498Szrj   target = gen_reg_rtx (mode);
2676*38fd1498Szrj   expand_fix (target, tmp, 0);
2677*38fd1498Szrj 
2678*38fd1498Szrj   return target;
2679*38fd1498Szrj }
2680*38fd1498Szrj 
2681*38fd1498Szrj /* Expand a call to one of the builtin math functions doing integer
2682*38fd1498Szrj    conversion (lrint).
2683*38fd1498Szrj    Return 0 if a normal call should be emitted rather than expanding the
2684*38fd1498Szrj    function in-line.  EXP is the expression that is a call to the builtin
2685*38fd1498Szrj    function; if convenient, the result should be placed in TARGET.  */
2686*38fd1498Szrj 
2687*38fd1498Szrj static rtx
expand_builtin_int_roundingfn_2(tree exp,rtx target)2688*38fd1498Szrj expand_builtin_int_roundingfn_2 (tree exp, rtx target)
2689*38fd1498Szrj {
2690*38fd1498Szrj   convert_optab builtin_optab;
2691*38fd1498Szrj   rtx op0;
2692*38fd1498Szrj   rtx_insn *insns;
2693*38fd1498Szrj   tree fndecl = get_callee_fndecl (exp);
2694*38fd1498Szrj   tree arg;
2695*38fd1498Szrj   machine_mode mode;
2696*38fd1498Szrj   enum built_in_function fallback_fn = BUILT_IN_NONE;
2697*38fd1498Szrj 
2698*38fd1498Szrj   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
2699*38fd1498Szrj      gcc_unreachable ();
2700*38fd1498Szrj 
2701*38fd1498Szrj   arg = CALL_EXPR_ARG (exp, 0);
2702*38fd1498Szrj 
2703*38fd1498Szrj   switch (DECL_FUNCTION_CODE (fndecl))
2704*38fd1498Szrj     {
2705*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_IRINT):
2706*38fd1498Szrj       fallback_fn = BUILT_IN_LRINT;
2707*38fd1498Szrj       gcc_fallthrough ();
2708*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LRINT):
2709*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LLRINT):
2710*38fd1498Szrj       builtin_optab = lrint_optab;
2711*38fd1498Szrj       break;
2712*38fd1498Szrj 
2713*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_IROUND):
2714*38fd1498Szrj       fallback_fn = BUILT_IN_LROUND;
2715*38fd1498Szrj       gcc_fallthrough ();
2716*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LROUND):
2717*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LLROUND):
2718*38fd1498Szrj       builtin_optab = lround_optab;
2719*38fd1498Szrj       break;
2720*38fd1498Szrj 
2721*38fd1498Szrj     default:
2722*38fd1498Szrj       gcc_unreachable ();
2723*38fd1498Szrj     }
2724*38fd1498Szrj 
2725*38fd1498Szrj   /* There's no easy way to detect the case we need to set EDOM.  */
2726*38fd1498Szrj   if (flag_errno_math && fallback_fn == BUILT_IN_NONE)
2727*38fd1498Szrj     return NULL_RTX;
2728*38fd1498Szrj 
2729*38fd1498Szrj   /* Make a suitable register to place result in.  */
2730*38fd1498Szrj   mode = TYPE_MODE (TREE_TYPE (exp));
2731*38fd1498Szrj 
2732*38fd1498Szrj   /* There's no easy way to detect the case we need to set EDOM.  */
2733*38fd1498Szrj   if (!flag_errno_math)
2734*38fd1498Szrj     {
2735*38fd1498Szrj       rtx result = gen_reg_rtx (mode);
2736*38fd1498Szrj 
2737*38fd1498Szrj       /* Wrap the computation of the argument in a SAVE_EXPR, as we may
2738*38fd1498Szrj 	 need to expand the argument again.  This way, we will not perform
2739*38fd1498Szrj 	 side-effects more the once.  */
2740*38fd1498Szrj       CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
2741*38fd1498Szrj 
2742*38fd1498Szrj       op0 = expand_expr (arg, NULL, VOIDmode, EXPAND_NORMAL);
2743*38fd1498Szrj 
2744*38fd1498Szrj       start_sequence ();
2745*38fd1498Szrj 
2746*38fd1498Szrj       if (expand_sfix_optab (result, op0, builtin_optab))
2747*38fd1498Szrj 	{
2748*38fd1498Szrj 	  /* Output the entire sequence.  */
2749*38fd1498Szrj 	  insns = get_insns ();
2750*38fd1498Szrj 	  end_sequence ();
2751*38fd1498Szrj 	  emit_insn (insns);
2752*38fd1498Szrj 	  return result;
2753*38fd1498Szrj 	}
2754*38fd1498Szrj 
2755*38fd1498Szrj       /* If we were unable to expand via the builtin, stop the sequence
2756*38fd1498Szrj 	 (without outputting the insns) and call to the library function
2757*38fd1498Szrj 	 with the stabilized argument list.  */
2758*38fd1498Szrj       end_sequence ();
2759*38fd1498Szrj     }
2760*38fd1498Szrj 
2761*38fd1498Szrj   if (fallback_fn != BUILT_IN_NONE)
2762*38fd1498Szrj     {
2763*38fd1498Szrj       /* Fall back to rounding to long int.  Use implicit_p 0 - for non-C99
2764*38fd1498Szrj 	 targets, (int) round (x) should never be transformed into
2765*38fd1498Szrj 	 BUILT_IN_IROUND and if __builtin_iround is called directly, emit
2766*38fd1498Szrj 	 a call to lround in the hope that the target provides at least some
2767*38fd1498Szrj 	 C99 functions.  This should result in the best user experience for
2768*38fd1498Szrj 	 not full C99 targets.  */
2769*38fd1498Szrj       tree fallback_fndecl = mathfn_built_in_1
2770*38fd1498Szrj 	(TREE_TYPE (arg), as_combined_fn (fallback_fn), 0);
2771*38fd1498Szrj 
2772*38fd1498Szrj       exp = build_call_nofold_loc (EXPR_LOCATION (exp),
2773*38fd1498Szrj 				   fallback_fndecl, 1, arg);
2774*38fd1498Szrj 
2775*38fd1498Szrj       target = expand_call (exp, NULL_RTX, target == const0_rtx);
2776*38fd1498Szrj       target = maybe_emit_group_store (target, TREE_TYPE (exp));
2777*38fd1498Szrj       return convert_to_mode (mode, target, 0);
2778*38fd1498Szrj     }
2779*38fd1498Szrj 
2780*38fd1498Szrj   return expand_call (exp, target, target == const0_rtx);
2781*38fd1498Szrj }
2782*38fd1498Szrj 
2783*38fd1498Szrj /* Expand a call to the powi built-in mathematical function.  Return NULL_RTX if
2784*38fd1498Szrj    a normal call should be emitted rather than expanding the function
2785*38fd1498Szrj    in-line.  EXP is the expression that is a call to the builtin
2786*38fd1498Szrj    function; if convenient, the result should be placed in TARGET.  */
2787*38fd1498Szrj 
2788*38fd1498Szrj static rtx
expand_builtin_powi(tree exp,rtx target)2789*38fd1498Szrj expand_builtin_powi (tree exp, rtx target)
2790*38fd1498Szrj {
2791*38fd1498Szrj   tree arg0, arg1;
2792*38fd1498Szrj   rtx op0, op1;
2793*38fd1498Szrj   machine_mode mode;
2794*38fd1498Szrj   machine_mode mode2;
2795*38fd1498Szrj 
2796*38fd1498Szrj   if (! validate_arglist (exp, REAL_TYPE, INTEGER_TYPE, VOID_TYPE))
2797*38fd1498Szrj     return NULL_RTX;
2798*38fd1498Szrj 
2799*38fd1498Szrj   arg0 = CALL_EXPR_ARG (exp, 0);
2800*38fd1498Szrj   arg1 = CALL_EXPR_ARG (exp, 1);
2801*38fd1498Szrj   mode = TYPE_MODE (TREE_TYPE (exp));
2802*38fd1498Szrj 
2803*38fd1498Szrj   /* Emit a libcall to libgcc.  */
2804*38fd1498Szrj 
2805*38fd1498Szrj   /* Mode of the 2nd argument must match that of an int.  */
2806*38fd1498Szrj   mode2 = int_mode_for_size (INT_TYPE_SIZE, 0).require ();
2807*38fd1498Szrj 
2808*38fd1498Szrj   if (target == NULL_RTX)
2809*38fd1498Szrj     target = gen_reg_rtx (mode);
2810*38fd1498Szrj 
2811*38fd1498Szrj   op0 = expand_expr (arg0, NULL_RTX, mode, EXPAND_NORMAL);
2812*38fd1498Szrj   if (GET_MODE (op0) != mode)
2813*38fd1498Szrj     op0 = convert_to_mode (mode, op0, 0);
2814*38fd1498Szrj   op1 = expand_expr (arg1, NULL_RTX, mode2, EXPAND_NORMAL);
2815*38fd1498Szrj   if (GET_MODE (op1) != mode2)
2816*38fd1498Szrj     op1 = convert_to_mode (mode2, op1, 0);
2817*38fd1498Szrj 
2818*38fd1498Szrj   target = emit_library_call_value (optab_libfunc (powi_optab, mode),
2819*38fd1498Szrj 				    target, LCT_CONST, mode,
2820*38fd1498Szrj 				    op0, mode, op1, mode2);
2821*38fd1498Szrj 
2822*38fd1498Szrj   return target;
2823*38fd1498Szrj }
2824*38fd1498Szrj 
2825*38fd1498Szrj /* Expand expression EXP which is a call to the strlen builtin.  Return
2826*38fd1498Szrj    NULL_RTX if we failed the caller should emit a normal call, otherwise
2827*38fd1498Szrj    try to get the result in TARGET, if convenient.  */
2828*38fd1498Szrj 
2829*38fd1498Szrj static rtx
expand_builtin_strlen(tree exp,rtx target,machine_mode target_mode)2830*38fd1498Szrj expand_builtin_strlen (tree exp, rtx target,
2831*38fd1498Szrj 		       machine_mode target_mode)
2832*38fd1498Szrj {
2833*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
2834*38fd1498Szrj     return NULL_RTX;
2835*38fd1498Szrj 
2836*38fd1498Szrj   struct expand_operand ops[4];
2837*38fd1498Szrj   rtx pat;
2838*38fd1498Szrj   tree len;
2839*38fd1498Szrj   tree src = CALL_EXPR_ARG (exp, 0);
2840*38fd1498Szrj   rtx src_reg;
2841*38fd1498Szrj   rtx_insn *before_strlen;
2842*38fd1498Szrj   machine_mode insn_mode;
2843*38fd1498Szrj   enum insn_code icode = CODE_FOR_nothing;
2844*38fd1498Szrj   unsigned int align;
2845*38fd1498Szrj 
2846*38fd1498Szrj   /* If the length can be computed at compile-time, return it.  */
2847*38fd1498Szrj   len = c_strlen (src, 0);
2848*38fd1498Szrj   if (len)
2849*38fd1498Szrj     return expand_expr (len, target, target_mode, EXPAND_NORMAL);
2850*38fd1498Szrj 
2851*38fd1498Szrj   /* If the length can be computed at compile-time and is constant
2852*38fd1498Szrj      integer, but there are side-effects in src, evaluate
2853*38fd1498Szrj      src for side-effects, then return len.
2854*38fd1498Szrj      E.g. x = strlen (i++ ? "xfoo" + 1 : "bar");
2855*38fd1498Szrj      can be optimized into: i++; x = 3;  */
2856*38fd1498Szrj   len = c_strlen (src, 1);
2857*38fd1498Szrj   if (len && TREE_CODE (len) == INTEGER_CST)
2858*38fd1498Szrj     {
2859*38fd1498Szrj       expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
2860*38fd1498Szrj       return expand_expr (len, target, target_mode, EXPAND_NORMAL);
2861*38fd1498Szrj     }
2862*38fd1498Szrj 
2863*38fd1498Szrj   align = get_pointer_alignment (src) / BITS_PER_UNIT;
2864*38fd1498Szrj 
2865*38fd1498Szrj   /* If SRC is not a pointer type, don't do this operation inline.  */
2866*38fd1498Szrj   if (align == 0)
2867*38fd1498Szrj     return NULL_RTX;
2868*38fd1498Szrj 
2869*38fd1498Szrj   /* Bail out if we can't compute strlen in the right mode.  */
2870*38fd1498Szrj   FOR_EACH_MODE_FROM (insn_mode, target_mode)
2871*38fd1498Szrj     {
2872*38fd1498Szrj       icode = optab_handler (strlen_optab, insn_mode);
2873*38fd1498Szrj       if (icode != CODE_FOR_nothing)
2874*38fd1498Szrj 	break;
2875*38fd1498Szrj     }
2876*38fd1498Szrj   if (insn_mode == VOIDmode)
2877*38fd1498Szrj     return NULL_RTX;
2878*38fd1498Szrj 
2879*38fd1498Szrj   /* Make a place to hold the source address.  We will not expand
2880*38fd1498Szrj      the actual source until we are sure that the expansion will
2881*38fd1498Szrj      not fail -- there are trees that cannot be expanded twice.  */
2882*38fd1498Szrj   src_reg = gen_reg_rtx (Pmode);
2883*38fd1498Szrj 
2884*38fd1498Szrj   /* Mark the beginning of the strlen sequence so we can emit the
2885*38fd1498Szrj      source operand later.  */
2886*38fd1498Szrj   before_strlen = get_last_insn ();
2887*38fd1498Szrj 
2888*38fd1498Szrj   create_output_operand (&ops[0], target, insn_mode);
2889*38fd1498Szrj   create_fixed_operand (&ops[1], gen_rtx_MEM (BLKmode, src_reg));
2890*38fd1498Szrj   create_integer_operand (&ops[2], 0);
2891*38fd1498Szrj   create_integer_operand (&ops[3], align);
2892*38fd1498Szrj   if (!maybe_expand_insn (icode, 4, ops))
2893*38fd1498Szrj     return NULL_RTX;
2894*38fd1498Szrj 
2895*38fd1498Szrj   /* Check to see if the argument was declared attribute nonstring
2896*38fd1498Szrj      and if so, issue a warning since at this point it's not known
2897*38fd1498Szrj      to be nul-terminated.  */
2898*38fd1498Szrj   maybe_warn_nonstring_arg (get_callee_fndecl (exp), exp);
2899*38fd1498Szrj 
2900*38fd1498Szrj   /* Now that we are assured of success, expand the source.  */
2901*38fd1498Szrj   start_sequence ();
2902*38fd1498Szrj   pat = expand_expr (src, src_reg, Pmode, EXPAND_NORMAL);
2903*38fd1498Szrj   if (pat != src_reg)
2904*38fd1498Szrj     {
2905*38fd1498Szrj #ifdef POINTERS_EXTEND_UNSIGNED
2906*38fd1498Szrj       if (GET_MODE (pat) != Pmode)
2907*38fd1498Szrj 	pat = convert_to_mode (Pmode, pat,
2908*38fd1498Szrj 			       POINTERS_EXTEND_UNSIGNED);
2909*38fd1498Szrj #endif
2910*38fd1498Szrj       emit_move_insn (src_reg, pat);
2911*38fd1498Szrj     }
2912*38fd1498Szrj   pat = get_insns ();
2913*38fd1498Szrj   end_sequence ();
2914*38fd1498Szrj 
2915*38fd1498Szrj   if (before_strlen)
2916*38fd1498Szrj     emit_insn_after (pat, before_strlen);
2917*38fd1498Szrj   else
2918*38fd1498Szrj     emit_insn_before (pat, get_insns ());
2919*38fd1498Szrj 
2920*38fd1498Szrj   /* Return the value in the proper mode for this function.  */
2921*38fd1498Szrj   if (GET_MODE (ops[0].value) == target_mode)
2922*38fd1498Szrj     target = ops[0].value;
2923*38fd1498Szrj   else if (target != 0)
2924*38fd1498Szrj     convert_move (target, ops[0].value, 0);
2925*38fd1498Szrj   else
2926*38fd1498Szrj     target = convert_to_mode (target_mode, ops[0].value, 0);
2927*38fd1498Szrj 
2928*38fd1498Szrj   return target;
2929*38fd1498Szrj }
2930*38fd1498Szrj 
2931*38fd1498Szrj /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
2932*38fd1498Szrj    bytes from constant string DATA + OFFSET and return it as target
2933*38fd1498Szrj    constant.  */
2934*38fd1498Szrj 
2935*38fd1498Szrj static rtx
builtin_memcpy_read_str(void * data,HOST_WIDE_INT offset,scalar_int_mode mode)2936*38fd1498Szrj builtin_memcpy_read_str (void *data, HOST_WIDE_INT offset,
2937*38fd1498Szrj 			 scalar_int_mode mode)
2938*38fd1498Szrj {
2939*38fd1498Szrj   const char *str = (const char *) data;
2940*38fd1498Szrj 
2941*38fd1498Szrj   gcc_assert (offset >= 0
2942*38fd1498Szrj 	      && ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode)
2943*38fd1498Szrj 		  <= strlen (str) + 1));
2944*38fd1498Szrj 
2945*38fd1498Szrj   return c_readstr (str + offset, mode);
2946*38fd1498Szrj }
2947*38fd1498Szrj 
2948*38fd1498Szrj /* LEN specify length of the block of memcpy/memset operation.
2949*38fd1498Szrj    Figure out its range and put it into MIN_SIZE/MAX_SIZE.
2950*38fd1498Szrj    In some cases we can make very likely guess on max size, then we
2951*38fd1498Szrj    set it into PROBABLE_MAX_SIZE.  */
2952*38fd1498Szrj 
2953*38fd1498Szrj static void
determine_block_size(tree len,rtx len_rtx,unsigned HOST_WIDE_INT * min_size,unsigned HOST_WIDE_INT * max_size,unsigned HOST_WIDE_INT * probable_max_size)2954*38fd1498Szrj determine_block_size (tree len, rtx len_rtx,
2955*38fd1498Szrj 		      unsigned HOST_WIDE_INT *min_size,
2956*38fd1498Szrj 		      unsigned HOST_WIDE_INT *max_size,
2957*38fd1498Szrj 		      unsigned HOST_WIDE_INT *probable_max_size)
2958*38fd1498Szrj {
2959*38fd1498Szrj   if (CONST_INT_P (len_rtx))
2960*38fd1498Szrj     {
2961*38fd1498Szrj       *min_size = *max_size = *probable_max_size = UINTVAL (len_rtx);
2962*38fd1498Szrj       return;
2963*38fd1498Szrj     }
2964*38fd1498Szrj   else
2965*38fd1498Szrj     {
2966*38fd1498Szrj       wide_int min, max;
2967*38fd1498Szrj       enum value_range_type range_type = VR_UNDEFINED;
2968*38fd1498Szrj 
2969*38fd1498Szrj       /* Determine bounds from the type.  */
2970*38fd1498Szrj       if (tree_fits_uhwi_p (TYPE_MIN_VALUE (TREE_TYPE (len))))
2971*38fd1498Szrj 	*min_size = tree_to_uhwi (TYPE_MIN_VALUE (TREE_TYPE (len)));
2972*38fd1498Szrj       else
2973*38fd1498Szrj 	*min_size = 0;
2974*38fd1498Szrj       if (tree_fits_uhwi_p (TYPE_MAX_VALUE (TREE_TYPE (len))))
2975*38fd1498Szrj 	*probable_max_size = *max_size
2976*38fd1498Szrj 	  = tree_to_uhwi (TYPE_MAX_VALUE (TREE_TYPE (len)));
2977*38fd1498Szrj       else
2978*38fd1498Szrj 	*probable_max_size = *max_size = GET_MODE_MASK (GET_MODE (len_rtx));
2979*38fd1498Szrj 
2980*38fd1498Szrj       if (TREE_CODE (len) == SSA_NAME)
2981*38fd1498Szrj 	range_type = get_range_info (len, &min, &max);
2982*38fd1498Szrj       if (range_type == VR_RANGE)
2983*38fd1498Szrj 	{
2984*38fd1498Szrj 	  if (wi::fits_uhwi_p (min) && *min_size < min.to_uhwi ())
2985*38fd1498Szrj 	    *min_size = min.to_uhwi ();
2986*38fd1498Szrj 	  if (wi::fits_uhwi_p (max) && *max_size > max.to_uhwi ())
2987*38fd1498Szrj 	    *probable_max_size = *max_size = max.to_uhwi ();
2988*38fd1498Szrj 	}
2989*38fd1498Szrj       else if (range_type == VR_ANTI_RANGE)
2990*38fd1498Szrj 	{
2991*38fd1498Szrj 	  /* Anti range 0...N lets us to determine minimal size to N+1.  */
2992*38fd1498Szrj 	  if (min == 0)
2993*38fd1498Szrj 	    {
2994*38fd1498Szrj 	      if (wi::fits_uhwi_p (max) && max.to_uhwi () + 1 != 0)
2995*38fd1498Szrj 		*min_size = max.to_uhwi () + 1;
2996*38fd1498Szrj 	    }
2997*38fd1498Szrj 	  /* Code like
2998*38fd1498Szrj 
2999*38fd1498Szrj 	     int n;
3000*38fd1498Szrj 	     if (n < 100)
3001*38fd1498Szrj 	       memcpy (a, b, n)
3002*38fd1498Szrj 
3003*38fd1498Szrj 	     Produce anti range allowing negative values of N.  We still
3004*38fd1498Szrj 	     can use the information and make a guess that N is not negative.
3005*38fd1498Szrj 	     */
3006*38fd1498Szrj 	  else if (!wi::leu_p (max, 1 << 30) && wi::fits_uhwi_p (min))
3007*38fd1498Szrj 	    *probable_max_size = min.to_uhwi () - 1;
3008*38fd1498Szrj 	}
3009*38fd1498Szrj     }
3010*38fd1498Szrj   gcc_checking_assert (*max_size <=
3011*38fd1498Szrj 		       (unsigned HOST_WIDE_INT)
3012*38fd1498Szrj 			  GET_MODE_MASK (GET_MODE (len_rtx)));
3013*38fd1498Szrj }
3014*38fd1498Szrj 
3015*38fd1498Szrj /* Try to verify that the sizes and lengths of the arguments to a string
3016*38fd1498Szrj    manipulation function given by EXP are within valid bounds and that
3017*38fd1498Szrj    the operation does not lead to buffer overflow or read past the end.
3018*38fd1498Szrj    Arguments other than EXP may be null.  When non-null, the arguments
3019*38fd1498Szrj    have the following meaning:
3020*38fd1498Szrj    DST is the destination of a copy call or NULL otherwise.
3021*38fd1498Szrj    SRC is the source of a copy call or NULL otherwise.
3022*38fd1498Szrj    DSTWRITE is the number of bytes written into the destination obtained
3023*38fd1498Szrj    from the user-supplied size argument to the function (such as in
3024*38fd1498Szrj    memcpy(DST, SRCs, DSTWRITE) or strncpy(DST, DRC, DSTWRITE).
3025*38fd1498Szrj    MAXREAD is the user-supplied bound on the length of the source sequence
3026*38fd1498Szrj    (such as in strncat(d, s, N).  It specifies the upper limit on the number
3027*38fd1498Szrj    of bytes to write.  If NULL, it's taken to be the same as DSTWRITE.
3028*38fd1498Szrj    SRCSTR is the source string (such as in strcpy(DST, SRC)) when the
3029*38fd1498Szrj    expression EXP is a string function call (as opposed to a memory call
3030*38fd1498Szrj    like memcpy).  As an exception, SRCSTR can also be an integer denoting
3031*38fd1498Szrj    the precomputed size of the source string or object (for functions like
3032*38fd1498Szrj    memcpy).
3033*38fd1498Szrj    DSTSIZE is the size of the destination object specified by the last
3034*38fd1498Szrj    argument to the _chk builtins, typically resulting from the expansion
3035*38fd1498Szrj    of __builtin_object_size (such as in __builtin___strcpy_chk(DST, SRC,
3036*38fd1498Szrj    DSTSIZE).
3037*38fd1498Szrj 
3038*38fd1498Szrj    When DSTWRITE is null LEN is checked to verify that it doesn't exceed
3039*38fd1498Szrj    SIZE_MAX.
3040*38fd1498Szrj 
3041*38fd1498Szrj    If the call is successfully verified as safe return true, otherwise
3042*38fd1498Szrj    return false.  */
3043*38fd1498Szrj 
3044*38fd1498Szrj static bool
check_access(tree exp,tree,tree,tree dstwrite,tree maxread,tree srcstr,tree dstsize)3045*38fd1498Szrj check_access (tree exp, tree, tree, tree dstwrite,
3046*38fd1498Szrj 	      tree maxread, tree srcstr, tree dstsize)
3047*38fd1498Szrj {
3048*38fd1498Szrj   int opt = OPT_Wstringop_overflow_;
3049*38fd1498Szrj 
3050*38fd1498Szrj   /* The size of the largest object is half the address space, or
3051*38fd1498Szrj      PTRDIFF_MAX.  (This is way too permissive.)  */
3052*38fd1498Szrj   tree maxobjsize = max_object_size ();
3053*38fd1498Szrj 
3054*38fd1498Szrj   /* Either the length of the source string for string functions or
3055*38fd1498Szrj      the size of the source object for raw memory functions.  */
3056*38fd1498Szrj   tree slen = NULL_TREE;
3057*38fd1498Szrj 
3058*38fd1498Szrj   tree range[2] = { NULL_TREE, NULL_TREE };
3059*38fd1498Szrj 
3060*38fd1498Szrj   /* Set to true when the exact number of bytes written by a string
3061*38fd1498Szrj      function like strcpy is not known and the only thing that is
3062*38fd1498Szrj      known is that it must be at least one (for the terminating nul).  */
3063*38fd1498Szrj   bool at_least_one = false;
3064*38fd1498Szrj   if (srcstr)
3065*38fd1498Szrj     {
3066*38fd1498Szrj       /* SRCSTR is normally a pointer to string but as a special case
3067*38fd1498Szrj 	 it can be an integer denoting the length of a string.  */
3068*38fd1498Szrj       if (POINTER_TYPE_P (TREE_TYPE (srcstr)))
3069*38fd1498Szrj 	{
3070*38fd1498Szrj 	  /* Try to determine the range of lengths the source string
3071*38fd1498Szrj 	     refers to.  If it can be determined and is less than
3072*38fd1498Szrj 	     the upper bound given by MAXREAD add one to it for
3073*38fd1498Szrj 	     the terminating nul.  Otherwise, set it to one for
3074*38fd1498Szrj 	     the same reason, or to MAXREAD as appropriate.  */
3075*38fd1498Szrj 	  get_range_strlen (srcstr, range);
3076*38fd1498Szrj 	  if (range[0] && (!maxread || TREE_CODE (maxread) == INTEGER_CST))
3077*38fd1498Szrj 	    {
3078*38fd1498Szrj 	      if (maxread && tree_int_cst_le (maxread, range[0]))
3079*38fd1498Szrj 		range[0] = range[1] = maxread;
3080*38fd1498Szrj 	      else
3081*38fd1498Szrj 		range[0] = fold_build2 (PLUS_EXPR, size_type_node,
3082*38fd1498Szrj 					range[0], size_one_node);
3083*38fd1498Szrj 
3084*38fd1498Szrj 	      if (maxread && tree_int_cst_le (maxread, range[1]))
3085*38fd1498Szrj 		range[1] = maxread;
3086*38fd1498Szrj 	      else if (!integer_all_onesp (range[1]))
3087*38fd1498Szrj 		range[1] = fold_build2 (PLUS_EXPR, size_type_node,
3088*38fd1498Szrj 					range[1], size_one_node);
3089*38fd1498Szrj 
3090*38fd1498Szrj 	      slen = range[0];
3091*38fd1498Szrj 	    }
3092*38fd1498Szrj 	  else
3093*38fd1498Szrj 	    {
3094*38fd1498Szrj 	      at_least_one = true;
3095*38fd1498Szrj 	      slen = size_one_node;
3096*38fd1498Szrj 	    }
3097*38fd1498Szrj 	}
3098*38fd1498Szrj       else
3099*38fd1498Szrj 	slen = srcstr;
3100*38fd1498Szrj     }
3101*38fd1498Szrj 
3102*38fd1498Szrj   if (!dstwrite && !maxread)
3103*38fd1498Szrj     {
3104*38fd1498Szrj       /* When the only available piece of data is the object size
3105*38fd1498Szrj 	 there is nothing to do.  */
3106*38fd1498Szrj       if (!slen)
3107*38fd1498Szrj 	return true;
3108*38fd1498Szrj 
3109*38fd1498Szrj       /* Otherwise, when the length of the source sequence is known
3110*38fd1498Szrj 	 (as with strlen), set DSTWRITE to it.  */
3111*38fd1498Szrj       if (!range[0])
3112*38fd1498Szrj 	dstwrite = slen;
3113*38fd1498Szrj     }
3114*38fd1498Szrj 
3115*38fd1498Szrj   if (!dstsize)
3116*38fd1498Szrj     dstsize = maxobjsize;
3117*38fd1498Szrj 
3118*38fd1498Szrj   if (dstwrite)
3119*38fd1498Szrj     get_size_range (dstwrite, range);
3120*38fd1498Szrj 
3121*38fd1498Szrj   tree func = get_callee_fndecl (exp);
3122*38fd1498Szrj 
3123*38fd1498Szrj   /* First check the number of bytes to be written against the maximum
3124*38fd1498Szrj      object size.  */
3125*38fd1498Szrj   if (range[0] && tree_int_cst_lt (maxobjsize, range[0]))
3126*38fd1498Szrj     {
3127*38fd1498Szrj       location_t loc = tree_nonartificial_location (exp);
3128*38fd1498Szrj       loc = expansion_point_location_if_in_system_header (loc);
3129*38fd1498Szrj 
3130*38fd1498Szrj       if (range[0] == range[1])
3131*38fd1498Szrj 	warning_at (loc, opt,
3132*38fd1498Szrj 		    "%K%qD specified size %E "
3133*38fd1498Szrj 		    "exceeds maximum object size %E",
3134*38fd1498Szrj 		    exp, func, range[0], maxobjsize);
3135*38fd1498Szrj 	  else
3136*38fd1498Szrj 	    warning_at (loc, opt,
3137*38fd1498Szrj 			"%K%qD specified size between %E and %E "
3138*38fd1498Szrj 			"exceeds maximum object size %E",
3139*38fd1498Szrj 			exp, func,
3140*38fd1498Szrj 			range[0], range[1], maxobjsize);
3141*38fd1498Szrj       return false;
3142*38fd1498Szrj     }
3143*38fd1498Szrj 
3144*38fd1498Szrj   /* The number of bytes to write is "exact" if DSTWRITE is non-null,
3145*38fd1498Szrj      constant, and in range of unsigned HOST_WIDE_INT.  */
3146*38fd1498Szrj   bool exactwrite = dstwrite && tree_fits_uhwi_p (dstwrite);
3147*38fd1498Szrj 
3148*38fd1498Szrj   /* Next check the number of bytes to be written against the destination
3149*38fd1498Szrj      object size.  */
3150*38fd1498Szrj   if (range[0] || !exactwrite || integer_all_onesp (dstwrite))
3151*38fd1498Szrj     {
3152*38fd1498Szrj       if (range[0]
3153*38fd1498Szrj 	  && ((tree_fits_uhwi_p (dstsize)
3154*38fd1498Szrj 	       && tree_int_cst_lt (dstsize, range[0]))
3155*38fd1498Szrj 	      || (tree_fits_uhwi_p (dstwrite)
3156*38fd1498Szrj 		  && tree_int_cst_lt (dstwrite, range[0]))))
3157*38fd1498Szrj 	{
3158*38fd1498Szrj 	  if (TREE_NO_WARNING (exp))
3159*38fd1498Szrj 	    return false;
3160*38fd1498Szrj 
3161*38fd1498Szrj 	  location_t loc = tree_nonartificial_location (exp);
3162*38fd1498Szrj 	  loc = expansion_point_location_if_in_system_header (loc);
3163*38fd1498Szrj 
3164*38fd1498Szrj 	  if (dstwrite == slen && at_least_one)
3165*38fd1498Szrj 	    {
3166*38fd1498Szrj 	      /* This is a call to strcpy with a destination of 0 size
3167*38fd1498Szrj 		 and a source of unknown length.  The call will write
3168*38fd1498Szrj 		 at least one byte past the end of the destination.  */
3169*38fd1498Szrj 	      warning_at (loc, opt,
3170*38fd1498Szrj 			  "%K%qD writing %E or more bytes into a region "
3171*38fd1498Szrj 			  "of size %E overflows the destination",
3172*38fd1498Szrj 			  exp, func, range[0], dstsize);
3173*38fd1498Szrj 	    }
3174*38fd1498Szrj 	  else if (tree_int_cst_equal (range[0], range[1]))
3175*38fd1498Szrj 	    warning_n (loc, opt, tree_to_uhwi (range[0]),
3176*38fd1498Szrj 		       "%K%qD writing %E byte into a region "
3177*38fd1498Szrj 		       "of size %E overflows the destination",
3178*38fd1498Szrj 		       "%K%qD writing %E bytes into a region "
3179*38fd1498Szrj 		       "of size %E overflows the destination",
3180*38fd1498Szrj 		       exp, func, range[0], dstsize);
3181*38fd1498Szrj 	  else if (tree_int_cst_sign_bit (range[1]))
3182*38fd1498Szrj 	    {
3183*38fd1498Szrj 	      /* Avoid printing the upper bound if it's invalid.  */
3184*38fd1498Szrj 	      warning_at (loc, opt,
3185*38fd1498Szrj 			  "%K%qD writing %E or more bytes into a region "
3186*38fd1498Szrj 			  "of size %E overflows the destination",
3187*38fd1498Szrj 			  exp, func, range[0], dstsize);
3188*38fd1498Szrj 	    }
3189*38fd1498Szrj 	  else
3190*38fd1498Szrj 	    warning_at (loc, opt,
3191*38fd1498Szrj 			"%K%qD writing between %E and %E bytes into "
3192*38fd1498Szrj 			"a region of size %E overflows the destination",
3193*38fd1498Szrj 			exp, func, range[0], range[1],
3194*38fd1498Szrj 			dstsize);
3195*38fd1498Szrj 
3196*38fd1498Szrj 	  /* Return error when an overflow has been detected.  */
3197*38fd1498Szrj 	  return false;
3198*38fd1498Szrj 	}
3199*38fd1498Szrj     }
3200*38fd1498Szrj 
3201*38fd1498Szrj   /* Check the maximum length of the source sequence against the size
3202*38fd1498Szrj      of the destination object if known, or against the maximum size
3203*38fd1498Szrj      of an object.  */
3204*38fd1498Szrj   if (maxread)
3205*38fd1498Szrj     {
3206*38fd1498Szrj       get_size_range (maxread, range);
3207*38fd1498Szrj 
3208*38fd1498Szrj       /* Use the lower end for MAXREAD from now on.  */
3209*38fd1498Szrj       if (range[0])
3210*38fd1498Szrj 	maxread = range[0];
3211*38fd1498Szrj 
3212*38fd1498Szrj       if (range[0] && dstsize && tree_fits_uhwi_p (dstsize))
3213*38fd1498Szrj 	{
3214*38fd1498Szrj 	  location_t loc = tree_nonartificial_location (exp);
3215*38fd1498Szrj 	  loc = expansion_point_location_if_in_system_header (loc);
3216*38fd1498Szrj 
3217*38fd1498Szrj 	  if (tree_int_cst_lt (maxobjsize, range[0]))
3218*38fd1498Szrj 	    {
3219*38fd1498Szrj 	      if (TREE_NO_WARNING (exp))
3220*38fd1498Szrj 		return false;
3221*38fd1498Szrj 
3222*38fd1498Szrj 	      /* Warn about crazy big sizes first since that's more
3223*38fd1498Szrj 		 likely to be meaningful than saying that the bound
3224*38fd1498Szrj 		 is greater than the object size if both are big.  */
3225*38fd1498Szrj 	      if (range[0] == range[1])
3226*38fd1498Szrj 		warning_at (loc, opt,
3227*38fd1498Szrj 			    "%K%qD specified bound %E "
3228*38fd1498Szrj 			    "exceeds maximum object size %E",
3229*38fd1498Szrj 			    exp, func,
3230*38fd1498Szrj 			    range[0], maxobjsize);
3231*38fd1498Szrj 	      else
3232*38fd1498Szrj 		warning_at (loc, opt,
3233*38fd1498Szrj 			    "%K%qD specified bound between %E and %E "
3234*38fd1498Szrj 			    "exceeds maximum object size %E",
3235*38fd1498Szrj 			    exp, func,
3236*38fd1498Szrj 			    range[0], range[1], maxobjsize);
3237*38fd1498Szrj 
3238*38fd1498Szrj 	      return false;
3239*38fd1498Szrj 	    }
3240*38fd1498Szrj 
3241*38fd1498Szrj 	  if (dstsize != maxobjsize && tree_int_cst_lt (dstsize, range[0]))
3242*38fd1498Szrj 	    {
3243*38fd1498Szrj 	      if (TREE_NO_WARNING (exp))
3244*38fd1498Szrj 		return false;
3245*38fd1498Szrj 
3246*38fd1498Szrj 	      if (tree_int_cst_equal (range[0], range[1]))
3247*38fd1498Szrj 		warning_at (loc, opt,
3248*38fd1498Szrj 			    "%K%qD specified bound %E "
3249*38fd1498Szrj 			    "exceeds destination size %E",
3250*38fd1498Szrj 			    exp, func,
3251*38fd1498Szrj 			    range[0], dstsize);
3252*38fd1498Szrj 	      else
3253*38fd1498Szrj 		warning_at (loc, opt,
3254*38fd1498Szrj 			    "%K%qD specified bound between %E and %E "
3255*38fd1498Szrj 			    "exceeds destination size %E",
3256*38fd1498Szrj 			    exp, func,
3257*38fd1498Szrj 			    range[0], range[1], dstsize);
3258*38fd1498Szrj 	      return false;
3259*38fd1498Szrj 	    }
3260*38fd1498Szrj 	}
3261*38fd1498Szrj     }
3262*38fd1498Szrj 
3263*38fd1498Szrj   /* Check for reading past the end of SRC.  */
3264*38fd1498Szrj   if (slen
3265*38fd1498Szrj       && slen == srcstr
3266*38fd1498Szrj       && dstwrite && range[0]
3267*38fd1498Szrj       && tree_int_cst_lt (slen, range[0]))
3268*38fd1498Szrj     {
3269*38fd1498Szrj       if (TREE_NO_WARNING (exp))
3270*38fd1498Szrj 	return false;
3271*38fd1498Szrj 
3272*38fd1498Szrj       location_t loc = tree_nonartificial_location (exp);
3273*38fd1498Szrj 
3274*38fd1498Szrj       if (tree_int_cst_equal (range[0], range[1]))
3275*38fd1498Szrj 	warning_n (loc, opt, tree_to_uhwi (range[0]),
3276*38fd1498Szrj 		   "%K%qD reading %E byte from a region of size %E",
3277*38fd1498Szrj 		   "%K%qD reading %E bytes from a region of size %E",
3278*38fd1498Szrj 		    exp, func, range[0], slen);
3279*38fd1498Szrj       else if (tree_int_cst_sign_bit (range[1]))
3280*38fd1498Szrj 	{
3281*38fd1498Szrj 	  /* Avoid printing the upper bound if it's invalid.  */
3282*38fd1498Szrj 	  warning_at (loc, opt,
3283*38fd1498Szrj 		      "%K%qD reading %E or more bytes from a region "
3284*38fd1498Szrj 		      "of size %E",
3285*38fd1498Szrj 		      exp, func, range[0], slen);
3286*38fd1498Szrj 	}
3287*38fd1498Szrj       else
3288*38fd1498Szrj 	warning_at (loc, opt,
3289*38fd1498Szrj 		    "%K%qD reading between %E and %E bytes from a region "
3290*38fd1498Szrj 		    "of size %E",
3291*38fd1498Szrj 		    exp, func, range[0], range[1], slen);
3292*38fd1498Szrj       return false;
3293*38fd1498Szrj     }
3294*38fd1498Szrj 
3295*38fd1498Szrj   return true;
3296*38fd1498Szrj }
3297*38fd1498Szrj 
3298*38fd1498Szrj /* Helper to compute the size of the object referenced by the DEST
3299*38fd1498Szrj    expression which must have pointer type, using Object Size type
3300*38fd1498Szrj    OSTYPE (only the least significant 2 bits are used).  Return
3301*38fd1498Szrj    an estimate of the size of the object if successful or NULL when
3302*38fd1498Szrj    the size cannot be determined.  When the referenced object involves
3303*38fd1498Szrj    a non-constant offset in some range the returned value represents
3304*38fd1498Szrj    the largest size given the smallest non-negative offset in the
3305*38fd1498Szrj    range.  The function is intended for diagnostics and should not
3306*38fd1498Szrj    be used to influence code generation or optimization.  */
3307*38fd1498Szrj 
3308*38fd1498Szrj tree
compute_objsize(tree dest,int ostype)3309*38fd1498Szrj compute_objsize (tree dest, int ostype)
3310*38fd1498Szrj {
3311*38fd1498Szrj   unsigned HOST_WIDE_INT size;
3312*38fd1498Szrj 
3313*38fd1498Szrj   /* Only the two least significant bits are meaningful.  */
3314*38fd1498Szrj   ostype &= 3;
3315*38fd1498Szrj 
3316*38fd1498Szrj   if (compute_builtin_object_size (dest, ostype, &size))
3317*38fd1498Szrj     return build_int_cst (sizetype, size);
3318*38fd1498Szrj 
3319*38fd1498Szrj   if (TREE_CODE (dest) == SSA_NAME)
3320*38fd1498Szrj     {
3321*38fd1498Szrj       gimple *stmt = SSA_NAME_DEF_STMT (dest);
3322*38fd1498Szrj       if (!is_gimple_assign (stmt))
3323*38fd1498Szrj 	return NULL_TREE;
3324*38fd1498Szrj 
3325*38fd1498Szrj       dest = gimple_assign_rhs1 (stmt);
3326*38fd1498Szrj 
3327*38fd1498Szrj       tree_code code = gimple_assign_rhs_code (stmt);
3328*38fd1498Szrj       if (code == POINTER_PLUS_EXPR)
3329*38fd1498Szrj 	{
3330*38fd1498Szrj 	  /* compute_builtin_object_size fails for addresses with
3331*38fd1498Szrj 	     non-constant offsets.  Try to determine the range of
3332*38fd1498Szrj 	     such an offset here and use it to adjus the constant
3333*38fd1498Szrj 	     size.  */
3334*38fd1498Szrj 	  tree off = gimple_assign_rhs2 (stmt);
3335*38fd1498Szrj 	  if (TREE_CODE (off) == SSA_NAME
3336*38fd1498Szrj 	      && INTEGRAL_TYPE_P (TREE_TYPE (off)))
3337*38fd1498Szrj 	    {
3338*38fd1498Szrj 	      wide_int min, max;
3339*38fd1498Szrj 	      enum value_range_type rng = get_range_info (off, &min, &max);
3340*38fd1498Szrj 
3341*38fd1498Szrj 	      if (rng == VR_RANGE)
3342*38fd1498Szrj 		{
3343*38fd1498Szrj 		  if (tree size = compute_objsize (dest, ostype))
3344*38fd1498Szrj 		    {
3345*38fd1498Szrj 		      wide_int wisiz = wi::to_wide (size);
3346*38fd1498Szrj 
3347*38fd1498Szrj 		      /* Ignore negative offsets for now.  For others,
3348*38fd1498Szrj 			 use the lower bound as the most optimistic
3349*38fd1498Szrj 			 estimate of the (remaining)size.  */
3350*38fd1498Szrj 		      if (wi::sign_mask (min))
3351*38fd1498Szrj 			;
3352*38fd1498Szrj 		      else if (wi::ltu_p (min, wisiz))
3353*38fd1498Szrj 			return wide_int_to_tree (TREE_TYPE (size),
3354*38fd1498Szrj 						 wi::sub (wisiz, min));
3355*38fd1498Szrj 		      else
3356*38fd1498Szrj 			return size_zero_node;
3357*38fd1498Szrj 		    }
3358*38fd1498Szrj 		}
3359*38fd1498Szrj 	    }
3360*38fd1498Szrj 	}
3361*38fd1498Szrj       else if (code != ADDR_EXPR)
3362*38fd1498Szrj 	return NULL_TREE;
3363*38fd1498Szrj     }
3364*38fd1498Szrj 
3365*38fd1498Szrj   /* Unless computing the largest size (for memcpy and other raw memory
3366*38fd1498Szrj      functions), try to determine the size of the object from its type.  */
3367*38fd1498Szrj   if (!ostype)
3368*38fd1498Szrj     return NULL_TREE;
3369*38fd1498Szrj 
3370*38fd1498Szrj   if (TREE_CODE (dest) != ADDR_EXPR)
3371*38fd1498Szrj     return NULL_TREE;
3372*38fd1498Szrj 
3373*38fd1498Szrj   tree type = TREE_TYPE (dest);
3374*38fd1498Szrj   if (TREE_CODE (type) == POINTER_TYPE)
3375*38fd1498Szrj     type = TREE_TYPE (type);
3376*38fd1498Szrj 
3377*38fd1498Szrj   type = TYPE_MAIN_VARIANT (type);
3378*38fd1498Szrj 
3379*38fd1498Szrj   if (TREE_CODE (type) == ARRAY_TYPE
3380*38fd1498Szrj       && !array_at_struct_end_p (TREE_OPERAND (dest, 0)))
3381*38fd1498Szrj     {
3382*38fd1498Szrj       /* Return the constant size unless it's zero (that's a zero-length
3383*38fd1498Szrj 	 array likely at the end of a struct).  */
3384*38fd1498Szrj       tree size = TYPE_SIZE_UNIT (type);
3385*38fd1498Szrj       if (size && TREE_CODE (size) == INTEGER_CST
3386*38fd1498Szrj 	  && !integer_zerop (size))
3387*38fd1498Szrj 	return size;
3388*38fd1498Szrj     }
3389*38fd1498Szrj 
3390*38fd1498Szrj   return NULL_TREE;
3391*38fd1498Szrj }
3392*38fd1498Szrj 
3393*38fd1498Szrj /* Helper to determine and check the sizes of the source and the destination
3394*38fd1498Szrj    of calls to __builtin_{bzero,memcpy,mempcpy,memset} calls.  EXP is the
3395*38fd1498Szrj    call expression, DEST is the destination argument, SRC is the source
3396*38fd1498Szrj    argument or null, and LEN is the number of bytes.  Use Object Size type-0
3397*38fd1498Szrj    regardless of the OPT_Wstringop_overflow_ setting.  Return true on success
3398*38fd1498Szrj    (no overflow or invalid sizes), false otherwise.  */
3399*38fd1498Szrj 
3400*38fd1498Szrj static bool
check_memop_access(tree exp,tree dest,tree src,tree size)3401*38fd1498Szrj check_memop_access (tree exp, tree dest, tree src, tree size)
3402*38fd1498Szrj {
3403*38fd1498Szrj   /* For functions like memset and memcpy that operate on raw memory
3404*38fd1498Szrj      try to determine the size of the largest source and destination
3405*38fd1498Szrj      object using type-0 Object Size regardless of the object size
3406*38fd1498Szrj      type specified by the option.  */
3407*38fd1498Szrj   tree srcsize = src ? compute_objsize (src, 0) : NULL_TREE;
3408*38fd1498Szrj   tree dstsize = compute_objsize (dest, 0);
3409*38fd1498Szrj 
3410*38fd1498Szrj   return check_access (exp, dest, src, size, /*maxread=*/NULL_TREE,
3411*38fd1498Szrj 		       srcsize, dstsize);
3412*38fd1498Szrj }
3413*38fd1498Szrj 
3414*38fd1498Szrj /* Validate memchr arguments without performing any expansion.
3415*38fd1498Szrj    Return NULL_RTX.  */
3416*38fd1498Szrj 
3417*38fd1498Szrj static rtx
expand_builtin_memchr(tree exp,rtx)3418*38fd1498Szrj expand_builtin_memchr (tree exp, rtx)
3419*38fd1498Szrj {
3420*38fd1498Szrj   if (!validate_arglist (exp,
3421*38fd1498Szrj  			 POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
3422*38fd1498Szrj     return NULL_RTX;
3423*38fd1498Szrj 
3424*38fd1498Szrj   tree arg1 = CALL_EXPR_ARG (exp, 0);
3425*38fd1498Szrj   tree len = CALL_EXPR_ARG (exp, 2);
3426*38fd1498Szrj 
3427*38fd1498Szrj   /* Diagnose calls where the specified length exceeds the size
3428*38fd1498Szrj      of the object.  */
3429*38fd1498Szrj   if (warn_stringop_overflow)
3430*38fd1498Szrj     {
3431*38fd1498Szrj       tree size = compute_objsize (arg1, 0);
3432*38fd1498Szrj       check_access (exp, /*dst=*/NULL_TREE, /*src=*/NULL_TREE, len,
3433*38fd1498Szrj 		    /*maxread=*/NULL_TREE, size, /*objsize=*/NULL_TREE);
3434*38fd1498Szrj     }
3435*38fd1498Szrj 
3436*38fd1498Szrj   return NULL_RTX;
3437*38fd1498Szrj }
3438*38fd1498Szrj 
3439*38fd1498Szrj /* Expand a call EXP to the memcpy builtin.
3440*38fd1498Szrj    Return NULL_RTX if we failed, the caller should emit a normal call,
3441*38fd1498Szrj    otherwise try to get the result in TARGET, if convenient (and in
3442*38fd1498Szrj    mode MODE if that's convenient).  */
3443*38fd1498Szrj 
3444*38fd1498Szrj static rtx
expand_builtin_memcpy(tree exp,rtx target)3445*38fd1498Szrj expand_builtin_memcpy (tree exp, rtx target)
3446*38fd1498Szrj {
3447*38fd1498Szrj   if (!validate_arglist (exp,
3448*38fd1498Szrj  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
3449*38fd1498Szrj     return NULL_RTX;
3450*38fd1498Szrj 
3451*38fd1498Szrj   tree dest = CALL_EXPR_ARG (exp, 0);
3452*38fd1498Szrj   tree src = CALL_EXPR_ARG (exp, 1);
3453*38fd1498Szrj   tree len = CALL_EXPR_ARG (exp, 2);
3454*38fd1498Szrj 
3455*38fd1498Szrj   check_memop_access (exp, dest, src, len);
3456*38fd1498Szrj 
3457*38fd1498Szrj   return expand_builtin_memory_copy_args (dest, src, len, target, exp,
3458*38fd1498Szrj 					  /*endp=*/ 0);
3459*38fd1498Szrj }
3460*38fd1498Szrj 
3461*38fd1498Szrj /* Check a call EXP to the memmove built-in for validity.
3462*38fd1498Szrj    Return NULL_RTX on both success and failure.  */
3463*38fd1498Szrj 
3464*38fd1498Szrj static rtx
expand_builtin_memmove(tree exp,rtx)3465*38fd1498Szrj expand_builtin_memmove (tree exp, rtx)
3466*38fd1498Szrj {
3467*38fd1498Szrj   if (!validate_arglist (exp,
3468*38fd1498Szrj  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
3469*38fd1498Szrj     return NULL_RTX;
3470*38fd1498Szrj 
3471*38fd1498Szrj   tree dest = CALL_EXPR_ARG (exp, 0);
3472*38fd1498Szrj   tree src = CALL_EXPR_ARG (exp, 1);
3473*38fd1498Szrj   tree len = CALL_EXPR_ARG (exp, 2);
3474*38fd1498Szrj 
3475*38fd1498Szrj   check_memop_access (exp, dest, src, len);
3476*38fd1498Szrj 
3477*38fd1498Szrj   return NULL_RTX;
3478*38fd1498Szrj }
3479*38fd1498Szrj 
3480*38fd1498Szrj /* Expand an instrumented call EXP to the memcpy builtin.
3481*38fd1498Szrj    Return NULL_RTX if we failed, the caller should emit a normal call,
3482*38fd1498Szrj    otherwise try to get the result in TARGET, if convenient (and in
3483*38fd1498Szrj    mode MODE if that's convenient).  */
3484*38fd1498Szrj 
3485*38fd1498Szrj static rtx
expand_builtin_memcpy_with_bounds(tree exp,rtx target)3486*38fd1498Szrj expand_builtin_memcpy_with_bounds (tree exp, rtx target)
3487*38fd1498Szrj {
3488*38fd1498Szrj   if (!validate_arglist (exp,
3489*38fd1498Szrj 			 POINTER_TYPE, POINTER_BOUNDS_TYPE,
3490*38fd1498Szrj 			 POINTER_TYPE, POINTER_BOUNDS_TYPE,
3491*38fd1498Szrj 			 INTEGER_TYPE, VOID_TYPE))
3492*38fd1498Szrj     return NULL_RTX;
3493*38fd1498Szrj   else
3494*38fd1498Szrj     {
3495*38fd1498Szrj       tree dest = CALL_EXPR_ARG (exp, 0);
3496*38fd1498Szrj       tree src = CALL_EXPR_ARG (exp, 2);
3497*38fd1498Szrj       tree len = CALL_EXPR_ARG (exp, 4);
3498*38fd1498Szrj       rtx res = expand_builtin_memory_copy_args (dest, src, len, target, exp,
3499*38fd1498Szrj 						 /*end_p=*/ 0);
3500*38fd1498Szrj 
3501*38fd1498Szrj       /* Return src bounds with the result.  */
3502*38fd1498Szrj       if (res)
3503*38fd1498Szrj 	{
3504*38fd1498Szrj 	  rtx bnd = force_reg (targetm.chkp_bound_mode (),
3505*38fd1498Szrj 			       expand_normal (CALL_EXPR_ARG (exp, 1)));
3506*38fd1498Szrj 	  res = chkp_join_splitted_slot (res, bnd);
3507*38fd1498Szrj 	}
3508*38fd1498Szrj       return res;
3509*38fd1498Szrj     }
3510*38fd1498Szrj }
3511*38fd1498Szrj 
3512*38fd1498Szrj /* Expand a call EXP to the mempcpy builtin.
3513*38fd1498Szrj    Return NULL_RTX if we failed; the caller should emit a normal call,
3514*38fd1498Szrj    otherwise try to get the result in TARGET, if convenient (and in
3515*38fd1498Szrj    mode MODE if that's convenient).  If ENDP is 0 return the
3516*38fd1498Szrj    destination pointer, if ENDP is 1 return the end pointer ala
3517*38fd1498Szrj    mempcpy, and if ENDP is 2 return the end pointer minus one ala
3518*38fd1498Szrj    stpcpy.  */
3519*38fd1498Szrj 
3520*38fd1498Szrj static rtx
expand_builtin_mempcpy(tree exp,rtx target)3521*38fd1498Szrj expand_builtin_mempcpy (tree exp, rtx target)
3522*38fd1498Szrj {
3523*38fd1498Szrj   if (!validate_arglist (exp,
3524*38fd1498Szrj  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
3525*38fd1498Szrj     return NULL_RTX;
3526*38fd1498Szrj 
3527*38fd1498Szrj   tree dest = CALL_EXPR_ARG (exp, 0);
3528*38fd1498Szrj   tree src = CALL_EXPR_ARG (exp, 1);
3529*38fd1498Szrj   tree len = CALL_EXPR_ARG (exp, 2);
3530*38fd1498Szrj 
3531*38fd1498Szrj   /* Policy does not generally allow using compute_objsize (which
3532*38fd1498Szrj      is used internally by check_memop_size) to change code generation
3533*38fd1498Szrj      or drive optimization decisions.
3534*38fd1498Szrj 
3535*38fd1498Szrj      In this instance it is safe because the code we generate has
3536*38fd1498Szrj      the same semantics regardless of the return value of
3537*38fd1498Szrj      check_memop_sizes.   Exactly the same amount of data is copied
3538*38fd1498Szrj      and the return value is exactly the same in both cases.
3539*38fd1498Szrj 
3540*38fd1498Szrj      Furthermore, check_memop_size always uses mode 0 for the call to
3541*38fd1498Szrj      compute_objsize, so the imprecise nature of compute_objsize is
3542*38fd1498Szrj      avoided.  */
3543*38fd1498Szrj 
3544*38fd1498Szrj   /* Avoid expanding mempcpy into memcpy when the call is determined
3545*38fd1498Szrj      to overflow the buffer.  This also prevents the same overflow
3546*38fd1498Szrj      from being diagnosed again when expanding memcpy.  */
3547*38fd1498Szrj   if (!check_memop_access (exp, dest, src, len))
3548*38fd1498Szrj     return NULL_RTX;
3549*38fd1498Szrj 
3550*38fd1498Szrj   return expand_builtin_mempcpy_args (dest, src, len,
3551*38fd1498Szrj 				      target, exp, /*endp=*/ 1);
3552*38fd1498Szrj }
3553*38fd1498Szrj 
3554*38fd1498Szrj /* Expand an instrumented call EXP to the mempcpy builtin.
3555*38fd1498Szrj    Return NULL_RTX if we failed, the caller should emit a normal call,
3556*38fd1498Szrj    otherwise try to get the result in TARGET, if convenient (and in
3557*38fd1498Szrj    mode MODE if that's convenient).  */
3558*38fd1498Szrj 
3559*38fd1498Szrj static rtx
expand_builtin_mempcpy_with_bounds(tree exp,rtx target)3560*38fd1498Szrj expand_builtin_mempcpy_with_bounds (tree exp, rtx target)
3561*38fd1498Szrj {
3562*38fd1498Szrj   if (!validate_arglist (exp,
3563*38fd1498Szrj 			 POINTER_TYPE, POINTER_BOUNDS_TYPE,
3564*38fd1498Szrj 			 POINTER_TYPE, POINTER_BOUNDS_TYPE,
3565*38fd1498Szrj 			 INTEGER_TYPE, VOID_TYPE))
3566*38fd1498Szrj     return NULL_RTX;
3567*38fd1498Szrj   else
3568*38fd1498Szrj     {
3569*38fd1498Szrj       tree dest = CALL_EXPR_ARG (exp, 0);
3570*38fd1498Szrj       tree src = CALL_EXPR_ARG (exp, 2);
3571*38fd1498Szrj       tree len = CALL_EXPR_ARG (exp, 4);
3572*38fd1498Szrj       rtx res = expand_builtin_mempcpy_args (dest, src, len, target,
3573*38fd1498Szrj 					     exp, 1);
3574*38fd1498Szrj 
3575*38fd1498Szrj       /* Return src bounds with the result.  */
3576*38fd1498Szrj       if (res)
3577*38fd1498Szrj 	{
3578*38fd1498Szrj 	  rtx bnd = force_reg (targetm.chkp_bound_mode (),
3579*38fd1498Szrj 			       expand_normal (CALL_EXPR_ARG (exp, 1)));
3580*38fd1498Szrj 	  res = chkp_join_splitted_slot (res, bnd);
3581*38fd1498Szrj 	}
3582*38fd1498Szrj       return res;
3583*38fd1498Szrj     }
3584*38fd1498Szrj }
3585*38fd1498Szrj 
3586*38fd1498Szrj /* Helper function to do the actual work for expand of memory copy family
3587*38fd1498Szrj    functions (memcpy, mempcpy, stpcpy).  Expansing should assign LEN bytes
3588*38fd1498Szrj    of memory from SRC to DEST and assign to TARGET if convenient.
3589*38fd1498Szrj    If ENDP is 0 return the
3590*38fd1498Szrj    destination pointer, if ENDP is 1 return the end pointer ala
3591*38fd1498Szrj    mempcpy, and if ENDP is 2 return the end pointer minus one ala
3592*38fd1498Szrj    stpcpy.  */
3593*38fd1498Szrj 
3594*38fd1498Szrj static rtx
expand_builtin_memory_copy_args(tree dest,tree src,tree len,rtx target,tree exp,int endp)3595*38fd1498Szrj expand_builtin_memory_copy_args (tree dest, tree src, tree len,
3596*38fd1498Szrj 				 rtx target, tree exp, int endp)
3597*38fd1498Szrj {
3598*38fd1498Szrj   const char *src_str;
3599*38fd1498Szrj   unsigned int src_align = get_pointer_alignment (src);
3600*38fd1498Szrj   unsigned int dest_align = get_pointer_alignment (dest);
3601*38fd1498Szrj   rtx dest_mem, src_mem, dest_addr, len_rtx;
3602*38fd1498Szrj   HOST_WIDE_INT expected_size = -1;
3603*38fd1498Szrj   unsigned int expected_align = 0;
3604*38fd1498Szrj   unsigned HOST_WIDE_INT min_size;
3605*38fd1498Szrj   unsigned HOST_WIDE_INT max_size;
3606*38fd1498Szrj   unsigned HOST_WIDE_INT probable_max_size;
3607*38fd1498Szrj 
3608*38fd1498Szrj   /* If DEST is not a pointer type, call the normal function.  */
3609*38fd1498Szrj   if (dest_align == 0)
3610*38fd1498Szrj     return NULL_RTX;
3611*38fd1498Szrj 
3612*38fd1498Szrj   /* If either SRC is not a pointer type, don't do this
3613*38fd1498Szrj      operation in-line.  */
3614*38fd1498Szrj   if (src_align == 0)
3615*38fd1498Szrj     return NULL_RTX;
3616*38fd1498Szrj 
3617*38fd1498Szrj   if (currently_expanding_gimple_stmt)
3618*38fd1498Szrj     stringop_block_profile (currently_expanding_gimple_stmt,
3619*38fd1498Szrj 			    &expected_align, &expected_size);
3620*38fd1498Szrj 
3621*38fd1498Szrj   if (expected_align < dest_align)
3622*38fd1498Szrj     expected_align = dest_align;
3623*38fd1498Szrj   dest_mem = get_memory_rtx (dest, len);
3624*38fd1498Szrj   set_mem_align (dest_mem, dest_align);
3625*38fd1498Szrj   len_rtx = expand_normal (len);
3626*38fd1498Szrj   determine_block_size (len, len_rtx, &min_size, &max_size,
3627*38fd1498Szrj 			&probable_max_size);
3628*38fd1498Szrj   src_str = c_getstr (src);
3629*38fd1498Szrj 
3630*38fd1498Szrj   /* If SRC is a string constant and block move would be done
3631*38fd1498Szrj      by pieces, we can avoid loading the string from memory
3632*38fd1498Szrj      and only stored the computed constants.  */
3633*38fd1498Szrj   if (src_str
3634*38fd1498Szrj       && CONST_INT_P (len_rtx)
3635*38fd1498Szrj       && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
3636*38fd1498Szrj       && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
3637*38fd1498Szrj 			      CONST_CAST (char *, src_str),
3638*38fd1498Szrj 			      dest_align, false))
3639*38fd1498Szrj     {
3640*38fd1498Szrj       dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
3641*38fd1498Szrj 				  builtin_memcpy_read_str,
3642*38fd1498Szrj 				  CONST_CAST (char *, src_str),
3643*38fd1498Szrj 				  dest_align, false, endp);
3644*38fd1498Szrj       dest_mem = force_operand (XEXP (dest_mem, 0), target);
3645*38fd1498Szrj       dest_mem = convert_memory_address (ptr_mode, dest_mem);
3646*38fd1498Szrj       return dest_mem;
3647*38fd1498Szrj     }
3648*38fd1498Szrj 
3649*38fd1498Szrj   src_mem = get_memory_rtx (src, len);
3650*38fd1498Szrj   set_mem_align (src_mem, src_align);
3651*38fd1498Szrj 
3652*38fd1498Szrj   /* Copy word part most expediently.  */
3653*38fd1498Szrj   enum block_op_methods method = BLOCK_OP_NORMAL;
3654*38fd1498Szrj   if (CALL_EXPR_TAILCALL (exp) && (endp == 0 || target == const0_rtx))
3655*38fd1498Szrj     method = BLOCK_OP_TAILCALL;
3656*38fd1498Szrj   if (endp == 1 && target != const0_rtx)
3657*38fd1498Szrj     method = BLOCK_OP_NO_LIBCALL_RET;
3658*38fd1498Szrj   dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx, method,
3659*38fd1498Szrj 				     expected_align, expected_size,
3660*38fd1498Szrj 				     min_size, max_size, probable_max_size);
3661*38fd1498Szrj   if (dest_addr == pc_rtx)
3662*38fd1498Szrj     return NULL_RTX;
3663*38fd1498Szrj 
3664*38fd1498Szrj   if (dest_addr == 0)
3665*38fd1498Szrj     {
3666*38fd1498Szrj       dest_addr = force_operand (XEXP (dest_mem, 0), target);
3667*38fd1498Szrj       dest_addr = convert_memory_address (ptr_mode, dest_addr);
3668*38fd1498Szrj     }
3669*38fd1498Szrj 
3670*38fd1498Szrj   if (endp && target != const0_rtx)
3671*38fd1498Szrj     {
3672*38fd1498Szrj       dest_addr = gen_rtx_PLUS (ptr_mode, dest_addr, len_rtx);
3673*38fd1498Szrj       /* stpcpy pointer to last byte.  */
3674*38fd1498Szrj       if (endp == 2)
3675*38fd1498Szrj 	dest_addr = gen_rtx_MINUS (ptr_mode, dest_addr, const1_rtx);
3676*38fd1498Szrj     }
3677*38fd1498Szrj 
3678*38fd1498Szrj   return dest_addr;
3679*38fd1498Szrj }
3680*38fd1498Szrj 
3681*38fd1498Szrj static rtx
expand_builtin_mempcpy_args(tree dest,tree src,tree len,rtx target,tree orig_exp,int endp)3682*38fd1498Szrj expand_builtin_mempcpy_args (tree dest, tree src, tree len,
3683*38fd1498Szrj 			     rtx target, tree orig_exp, int endp)
3684*38fd1498Szrj {
3685*38fd1498Szrj   return expand_builtin_memory_copy_args (dest, src, len, target, orig_exp,
3686*38fd1498Szrj 					  endp);
3687*38fd1498Szrj }
3688*38fd1498Szrj 
3689*38fd1498Szrj /* Expand into a movstr instruction, if one is available.  Return NULL_RTX if
3690*38fd1498Szrj    we failed, the caller should emit a normal call, otherwise try to
3691*38fd1498Szrj    get the result in TARGET, if convenient.  If ENDP is 0 return the
3692*38fd1498Szrj    destination pointer, if ENDP is 1 return the end pointer ala
3693*38fd1498Szrj    mempcpy, and if ENDP is 2 return the end pointer minus one ala
3694*38fd1498Szrj    stpcpy.  */
3695*38fd1498Szrj 
3696*38fd1498Szrj static rtx
expand_movstr(tree dest,tree src,rtx target,int endp)3697*38fd1498Szrj expand_movstr (tree dest, tree src, rtx target, int endp)
3698*38fd1498Szrj {
3699*38fd1498Szrj   struct expand_operand ops[3];
3700*38fd1498Szrj   rtx dest_mem;
3701*38fd1498Szrj   rtx src_mem;
3702*38fd1498Szrj 
3703*38fd1498Szrj   if (!targetm.have_movstr ())
3704*38fd1498Szrj     return NULL_RTX;
3705*38fd1498Szrj 
3706*38fd1498Szrj   dest_mem = get_memory_rtx (dest, NULL);
3707*38fd1498Szrj   src_mem = get_memory_rtx (src, NULL);
3708*38fd1498Szrj   if (!endp)
3709*38fd1498Szrj     {
3710*38fd1498Szrj       target = force_reg (Pmode, XEXP (dest_mem, 0));
3711*38fd1498Szrj       dest_mem = replace_equiv_address (dest_mem, target);
3712*38fd1498Szrj     }
3713*38fd1498Szrj 
3714*38fd1498Szrj   create_output_operand (&ops[0], endp ? target : NULL_RTX, Pmode);
3715*38fd1498Szrj   create_fixed_operand (&ops[1], dest_mem);
3716*38fd1498Szrj   create_fixed_operand (&ops[2], src_mem);
3717*38fd1498Szrj   if (!maybe_expand_insn (targetm.code_for_movstr, 3, ops))
3718*38fd1498Szrj     return NULL_RTX;
3719*38fd1498Szrj 
3720*38fd1498Szrj   if (endp && target != const0_rtx)
3721*38fd1498Szrj     {
3722*38fd1498Szrj       target = ops[0].value;
3723*38fd1498Szrj       /* movstr is supposed to set end to the address of the NUL
3724*38fd1498Szrj 	 terminator.  If the caller requested a mempcpy-like return value,
3725*38fd1498Szrj 	 adjust it.  */
3726*38fd1498Szrj       if (endp == 1)
3727*38fd1498Szrj 	{
3728*38fd1498Szrj 	  rtx tem = plus_constant (GET_MODE (target),
3729*38fd1498Szrj 				   gen_lowpart (GET_MODE (target), target), 1);
3730*38fd1498Szrj 	  emit_move_insn (target, force_operand (tem, NULL_RTX));
3731*38fd1498Szrj 	}
3732*38fd1498Szrj     }
3733*38fd1498Szrj   return target;
3734*38fd1498Szrj }
3735*38fd1498Szrj 
3736*38fd1498Szrj /* Do some very basic size validation of a call to the strcpy builtin
3737*38fd1498Szrj    given by EXP.  Return NULL_RTX to have the built-in expand to a call
3738*38fd1498Szrj    to the library function.  */
3739*38fd1498Szrj 
3740*38fd1498Szrj static rtx
expand_builtin_strcat(tree exp,rtx)3741*38fd1498Szrj expand_builtin_strcat (tree exp, rtx)
3742*38fd1498Szrj {
3743*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)
3744*38fd1498Szrj       || !warn_stringop_overflow)
3745*38fd1498Szrj     return NULL_RTX;
3746*38fd1498Szrj 
3747*38fd1498Szrj   tree dest = CALL_EXPR_ARG (exp, 0);
3748*38fd1498Szrj   tree src = CALL_EXPR_ARG (exp, 1);
3749*38fd1498Szrj 
3750*38fd1498Szrj   /* There is no way here to determine the length of the string in
3751*38fd1498Szrj      the destination to which the SRC string is being appended so
3752*38fd1498Szrj      just diagnose cases when the souce string is longer than
3753*38fd1498Szrj      the destination object.  */
3754*38fd1498Szrj 
3755*38fd1498Szrj   tree destsize = compute_objsize (dest, warn_stringop_overflow - 1);
3756*38fd1498Szrj 
3757*38fd1498Szrj   check_access (exp, dest, src, /*size=*/NULL_TREE, /*maxread=*/NULL_TREE, src,
3758*38fd1498Szrj 		destsize);
3759*38fd1498Szrj 
3760*38fd1498Szrj   return NULL_RTX;
3761*38fd1498Szrj }
3762*38fd1498Szrj 
3763*38fd1498Szrj /* Expand expression EXP, which is a call to the strcpy builtin.  Return
3764*38fd1498Szrj    NULL_RTX if we failed the caller should emit a normal call, otherwise
3765*38fd1498Szrj    try to get the result in TARGET, if convenient (and in mode MODE if that's
3766*38fd1498Szrj    convenient).  */
3767*38fd1498Szrj 
3768*38fd1498Szrj static rtx
expand_builtin_strcpy(tree exp,rtx target)3769*38fd1498Szrj expand_builtin_strcpy (tree exp, rtx target)
3770*38fd1498Szrj {
3771*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
3772*38fd1498Szrj     return NULL_RTX;
3773*38fd1498Szrj 
3774*38fd1498Szrj   tree dest = CALL_EXPR_ARG (exp, 0);
3775*38fd1498Szrj   tree src = CALL_EXPR_ARG (exp, 1);
3776*38fd1498Szrj 
3777*38fd1498Szrj   if (warn_stringop_overflow)
3778*38fd1498Szrj     {
3779*38fd1498Szrj       tree destsize = compute_objsize (dest, warn_stringop_overflow - 1);
3780*38fd1498Szrj       check_access (exp, dest, src, /*size=*/NULL_TREE, /*maxread=*/NULL_TREE,
3781*38fd1498Szrj 		    src, destsize);
3782*38fd1498Szrj     }
3783*38fd1498Szrj 
3784*38fd1498Szrj   return expand_builtin_strcpy_args (dest, src, target);
3785*38fd1498Szrj }
3786*38fd1498Szrj 
3787*38fd1498Szrj /* Helper function to do the actual work for expand_builtin_strcpy.  The
3788*38fd1498Szrj    arguments to the builtin_strcpy call DEST and SRC are broken out
3789*38fd1498Szrj    so that this can also be called without constructing an actual CALL_EXPR.
3790*38fd1498Szrj    The other arguments and return value are the same as for
3791*38fd1498Szrj    expand_builtin_strcpy.  */
3792*38fd1498Szrj 
3793*38fd1498Szrj static rtx
expand_builtin_strcpy_args(tree dest,tree src,rtx target)3794*38fd1498Szrj expand_builtin_strcpy_args (tree dest, tree src, rtx target)
3795*38fd1498Szrj {
3796*38fd1498Szrj   return expand_movstr (dest, src, target, /*endp=*/0);
3797*38fd1498Szrj }
3798*38fd1498Szrj 
3799*38fd1498Szrj /* Expand a call EXP to the stpcpy builtin.
3800*38fd1498Szrj    Return NULL_RTX if we failed the caller should emit a normal call,
3801*38fd1498Szrj    otherwise try to get the result in TARGET, if convenient (and in
3802*38fd1498Szrj    mode MODE if that's convenient).  */
3803*38fd1498Szrj 
3804*38fd1498Szrj static rtx
expand_builtin_stpcpy(tree exp,rtx target,machine_mode mode)3805*38fd1498Szrj expand_builtin_stpcpy (tree exp, rtx target, machine_mode mode)
3806*38fd1498Szrj {
3807*38fd1498Szrj   tree dst, src;
3808*38fd1498Szrj   location_t loc = EXPR_LOCATION (exp);
3809*38fd1498Szrj 
3810*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
3811*38fd1498Szrj     return NULL_RTX;
3812*38fd1498Szrj 
3813*38fd1498Szrj   dst = CALL_EXPR_ARG (exp, 0);
3814*38fd1498Szrj   src = CALL_EXPR_ARG (exp, 1);
3815*38fd1498Szrj 
3816*38fd1498Szrj   if (warn_stringop_overflow)
3817*38fd1498Szrj     {
3818*38fd1498Szrj       tree destsize = compute_objsize (dst, warn_stringop_overflow - 1);
3819*38fd1498Szrj       check_access (exp, dst, src, /*size=*/NULL_TREE, /*maxread=*/NULL_TREE,
3820*38fd1498Szrj 		    src, destsize);
3821*38fd1498Szrj     }
3822*38fd1498Szrj 
3823*38fd1498Szrj   /* If return value is ignored, transform stpcpy into strcpy.  */
3824*38fd1498Szrj   if (target == const0_rtx && builtin_decl_implicit (BUILT_IN_STRCPY))
3825*38fd1498Szrj     {
3826*38fd1498Szrj       tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
3827*38fd1498Szrj       tree result = build_call_nofold_loc (loc, fn, 2, dst, src);
3828*38fd1498Szrj       return expand_expr (result, target, mode, EXPAND_NORMAL);
3829*38fd1498Szrj     }
3830*38fd1498Szrj   else
3831*38fd1498Szrj     {
3832*38fd1498Szrj       tree len, lenp1;
3833*38fd1498Szrj       rtx ret;
3834*38fd1498Szrj 
3835*38fd1498Szrj       /* Ensure we get an actual string whose length can be evaluated at
3836*38fd1498Szrj 	 compile-time, not an expression containing a string.  This is
3837*38fd1498Szrj 	 because the latter will potentially produce pessimized code
3838*38fd1498Szrj 	 when used to produce the return value.  */
3839*38fd1498Szrj       if (! c_getstr (src) || ! (len = c_strlen (src, 0)))
3840*38fd1498Szrj 	return expand_movstr (dst, src, target, /*endp=*/2);
3841*38fd1498Szrj 
3842*38fd1498Szrj       lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
3843*38fd1498Szrj       ret = expand_builtin_mempcpy_args (dst, src, lenp1,
3844*38fd1498Szrj 					 target, exp, /*endp=*/2);
3845*38fd1498Szrj 
3846*38fd1498Szrj       if (ret)
3847*38fd1498Szrj 	return ret;
3848*38fd1498Szrj 
3849*38fd1498Szrj       if (TREE_CODE (len) == INTEGER_CST)
3850*38fd1498Szrj 	{
3851*38fd1498Szrj 	  rtx len_rtx = expand_normal (len);
3852*38fd1498Szrj 
3853*38fd1498Szrj 	  if (CONST_INT_P (len_rtx))
3854*38fd1498Szrj 	    {
3855*38fd1498Szrj 	      ret = expand_builtin_strcpy_args (dst, src, target);
3856*38fd1498Szrj 
3857*38fd1498Szrj 	      if (ret)
3858*38fd1498Szrj 		{
3859*38fd1498Szrj 		  if (! target)
3860*38fd1498Szrj 		    {
3861*38fd1498Szrj 		      if (mode != VOIDmode)
3862*38fd1498Szrj 			target = gen_reg_rtx (mode);
3863*38fd1498Szrj 		      else
3864*38fd1498Szrj 			target = gen_reg_rtx (GET_MODE (ret));
3865*38fd1498Szrj 		    }
3866*38fd1498Szrj 		  if (GET_MODE (target) != GET_MODE (ret))
3867*38fd1498Szrj 		    ret = gen_lowpart (GET_MODE (target), ret);
3868*38fd1498Szrj 
3869*38fd1498Szrj 		  ret = plus_constant (GET_MODE (ret), ret, INTVAL (len_rtx));
3870*38fd1498Szrj 		  ret = emit_move_insn (target, force_operand (ret, NULL_RTX));
3871*38fd1498Szrj 		  gcc_assert (ret);
3872*38fd1498Szrj 
3873*38fd1498Szrj 		  return target;
3874*38fd1498Szrj 		}
3875*38fd1498Szrj 	    }
3876*38fd1498Szrj 	}
3877*38fd1498Szrj 
3878*38fd1498Szrj       return expand_movstr (dst, src, target, /*endp=*/2);
3879*38fd1498Szrj     }
3880*38fd1498Szrj }
3881*38fd1498Szrj 
3882*38fd1498Szrj /* Check a call EXP to the stpncpy built-in for validity.
3883*38fd1498Szrj    Return NULL_RTX on both success and failure.  */
3884*38fd1498Szrj 
3885*38fd1498Szrj static rtx
expand_builtin_stpncpy(tree exp,rtx)3886*38fd1498Szrj expand_builtin_stpncpy (tree exp, rtx)
3887*38fd1498Szrj {
3888*38fd1498Szrj   if (!validate_arglist (exp,
3889*38fd1498Szrj 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
3890*38fd1498Szrj       || !warn_stringop_overflow)
3891*38fd1498Szrj     return NULL_RTX;
3892*38fd1498Szrj 
3893*38fd1498Szrj   /* The source and destination of the call.  */
3894*38fd1498Szrj   tree dest = CALL_EXPR_ARG (exp, 0);
3895*38fd1498Szrj   tree src = CALL_EXPR_ARG (exp, 1);
3896*38fd1498Szrj 
3897*38fd1498Szrj   /* The exact number of bytes to write (not the maximum).  */
3898*38fd1498Szrj   tree len = CALL_EXPR_ARG (exp, 2);
3899*38fd1498Szrj 
3900*38fd1498Szrj   /* The size of the destination object.  */
3901*38fd1498Szrj   tree destsize = compute_objsize (dest, warn_stringop_overflow - 1);
3902*38fd1498Szrj 
3903*38fd1498Szrj   check_access (exp, dest, src, len, /*maxread=*/NULL_TREE, src, destsize);
3904*38fd1498Szrj 
3905*38fd1498Szrj   return NULL_RTX;
3906*38fd1498Szrj }
3907*38fd1498Szrj 
3908*38fd1498Szrj /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
3909*38fd1498Szrj    bytes from constant string DATA + OFFSET and return it as target
3910*38fd1498Szrj    constant.  */
3911*38fd1498Szrj 
3912*38fd1498Szrj rtx
builtin_strncpy_read_str(void * data,HOST_WIDE_INT offset,scalar_int_mode mode)3913*38fd1498Szrj builtin_strncpy_read_str (void *data, HOST_WIDE_INT offset,
3914*38fd1498Szrj 			  scalar_int_mode mode)
3915*38fd1498Szrj {
3916*38fd1498Szrj   const char *str = (const char *) data;
3917*38fd1498Szrj 
3918*38fd1498Szrj   if ((unsigned HOST_WIDE_INT) offset > strlen (str))
3919*38fd1498Szrj     return const0_rtx;
3920*38fd1498Szrj 
3921*38fd1498Szrj   return c_readstr (str + offset, mode);
3922*38fd1498Szrj }
3923*38fd1498Szrj 
3924*38fd1498Szrj /* Helper to check the sizes of sequences and the destination of calls
3925*38fd1498Szrj    to __builtin_strncat and __builtin___strncat_chk.  Returns true on
3926*38fd1498Szrj    success (no overflow or invalid sizes), false otherwise.  */
3927*38fd1498Szrj 
3928*38fd1498Szrj static bool
check_strncat_sizes(tree exp,tree objsize)3929*38fd1498Szrj check_strncat_sizes (tree exp, tree objsize)
3930*38fd1498Szrj {
3931*38fd1498Szrj   tree dest = CALL_EXPR_ARG (exp, 0);
3932*38fd1498Szrj   tree src = CALL_EXPR_ARG (exp, 1);
3933*38fd1498Szrj   tree maxread = CALL_EXPR_ARG (exp, 2);
3934*38fd1498Szrj 
3935*38fd1498Szrj   /* Try to determine the range of lengths that the source expression
3936*38fd1498Szrj      refers to.  */
3937*38fd1498Szrj   tree lenrange[2];
3938*38fd1498Szrj   get_range_strlen (src, lenrange);
3939*38fd1498Szrj 
3940*38fd1498Szrj   /* Try to verify that the destination is big enough for the shortest
3941*38fd1498Szrj      string.  */
3942*38fd1498Szrj 
3943*38fd1498Szrj   if (!objsize && warn_stringop_overflow)
3944*38fd1498Szrj     {
3945*38fd1498Szrj       /* If it hasn't been provided by __strncat_chk, try to determine
3946*38fd1498Szrj 	 the size of the destination object into which the source is
3947*38fd1498Szrj 	 being copied.  */
3948*38fd1498Szrj       objsize = compute_objsize (dest, warn_stringop_overflow - 1);
3949*38fd1498Szrj     }
3950*38fd1498Szrj 
3951*38fd1498Szrj   /* Add one for the terminating nul.  */
3952*38fd1498Szrj   tree srclen = (lenrange[0]
3953*38fd1498Szrj 		 ? fold_build2 (PLUS_EXPR, size_type_node, lenrange[0],
3954*38fd1498Szrj 				size_one_node)
3955*38fd1498Szrj 		 : NULL_TREE);
3956*38fd1498Szrj 
3957*38fd1498Szrj   /* The strncat function copies at most MAXREAD bytes and always appends
3958*38fd1498Szrj      the terminating nul so the specified upper bound should never be equal
3959*38fd1498Szrj      to (or greater than) the size of the destination.  */
3960*38fd1498Szrj   if (tree_fits_uhwi_p (maxread) && tree_fits_uhwi_p (objsize)
3961*38fd1498Szrj       && tree_int_cst_equal (objsize, maxread))
3962*38fd1498Szrj     {
3963*38fd1498Szrj       location_t loc = tree_nonartificial_location (exp);
3964*38fd1498Szrj       loc = expansion_point_location_if_in_system_header (loc);
3965*38fd1498Szrj 
3966*38fd1498Szrj       warning_at (loc, OPT_Wstringop_overflow_,
3967*38fd1498Szrj 		  "%K%qD specified bound %E equals destination size",
3968*38fd1498Szrj 		  exp, get_callee_fndecl (exp), maxread);
3969*38fd1498Szrj 
3970*38fd1498Szrj       return false;
3971*38fd1498Szrj     }
3972*38fd1498Szrj 
3973*38fd1498Szrj   if (!srclen
3974*38fd1498Szrj       || (maxread && tree_fits_uhwi_p (maxread)
3975*38fd1498Szrj 	  && tree_fits_uhwi_p (srclen)
3976*38fd1498Szrj 	  && tree_int_cst_lt (maxread, srclen)))
3977*38fd1498Szrj     srclen = maxread;
3978*38fd1498Szrj 
3979*38fd1498Szrj   /* The number of bytes to write is LEN but check_access will also
3980*38fd1498Szrj      check SRCLEN if LEN's value isn't known.  */
3981*38fd1498Szrj   return check_access (exp, dest, src, /*size=*/NULL_TREE, maxread, srclen,
3982*38fd1498Szrj 		       objsize);
3983*38fd1498Szrj }
3984*38fd1498Szrj 
3985*38fd1498Szrj /* Similar to expand_builtin_strcat, do some very basic size validation
3986*38fd1498Szrj    of a call to the strcpy builtin given by EXP.  Return NULL_RTX to have
3987*38fd1498Szrj    the built-in expand to a call to the library function.  */
3988*38fd1498Szrj 
3989*38fd1498Szrj static rtx
expand_builtin_strncat(tree exp,rtx)3990*38fd1498Szrj expand_builtin_strncat (tree exp, rtx)
3991*38fd1498Szrj {
3992*38fd1498Szrj   if (!validate_arglist (exp,
3993*38fd1498Szrj 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
3994*38fd1498Szrj       || !warn_stringop_overflow)
3995*38fd1498Szrj     return NULL_RTX;
3996*38fd1498Szrj 
3997*38fd1498Szrj   tree dest = CALL_EXPR_ARG (exp, 0);
3998*38fd1498Szrj   tree src = CALL_EXPR_ARG (exp, 1);
3999*38fd1498Szrj   /* The upper bound on the number of bytes to write.  */
4000*38fd1498Szrj   tree maxread = CALL_EXPR_ARG (exp, 2);
4001*38fd1498Szrj   /* The length of the source sequence.  */
4002*38fd1498Szrj   tree slen = c_strlen (src, 1);
4003*38fd1498Szrj 
4004*38fd1498Szrj   /* Try to determine the range of lengths that the source expression
4005*38fd1498Szrj      refers to.  */
4006*38fd1498Szrj   tree lenrange[2];
4007*38fd1498Szrj   if (slen)
4008*38fd1498Szrj     lenrange[0] = lenrange[1] = slen;
4009*38fd1498Szrj   else
4010*38fd1498Szrj     get_range_strlen (src, lenrange);
4011*38fd1498Szrj 
4012*38fd1498Szrj   /* Try to verify that the destination is big enough for the shortest
4013*38fd1498Szrj      string.  First try to determine the size of the destination object
4014*38fd1498Szrj      into which the source is being copied.  */
4015*38fd1498Szrj   tree destsize = compute_objsize (dest, warn_stringop_overflow - 1);
4016*38fd1498Szrj 
4017*38fd1498Szrj   /* Add one for the terminating nul.  */
4018*38fd1498Szrj   tree srclen = (lenrange[0]
4019*38fd1498Szrj 		 ? fold_build2 (PLUS_EXPR, size_type_node, lenrange[0],
4020*38fd1498Szrj 				size_one_node)
4021*38fd1498Szrj 		 : NULL_TREE);
4022*38fd1498Szrj 
4023*38fd1498Szrj   /* The strncat function copies at most MAXREAD bytes and always appends
4024*38fd1498Szrj      the terminating nul so the specified upper bound should never be equal
4025*38fd1498Szrj      to (or greater than) the size of the destination.  */
4026*38fd1498Szrj   if (tree_fits_uhwi_p (maxread) && tree_fits_uhwi_p (destsize)
4027*38fd1498Szrj       && tree_int_cst_equal (destsize, maxread))
4028*38fd1498Szrj     {
4029*38fd1498Szrj       location_t loc = tree_nonartificial_location (exp);
4030*38fd1498Szrj       loc = expansion_point_location_if_in_system_header (loc);
4031*38fd1498Szrj 
4032*38fd1498Szrj       warning_at (loc, OPT_Wstringop_overflow_,
4033*38fd1498Szrj 		  "%K%qD specified bound %E equals destination size",
4034*38fd1498Szrj 		  exp, get_callee_fndecl (exp), maxread);
4035*38fd1498Szrj 
4036*38fd1498Szrj       return NULL_RTX;
4037*38fd1498Szrj     }
4038*38fd1498Szrj 
4039*38fd1498Szrj   if (!srclen
4040*38fd1498Szrj       || (maxread && tree_fits_uhwi_p (maxread)
4041*38fd1498Szrj 	  && tree_fits_uhwi_p (srclen)
4042*38fd1498Szrj 	  && tree_int_cst_lt (maxread, srclen)))
4043*38fd1498Szrj     srclen = maxread;
4044*38fd1498Szrj 
4045*38fd1498Szrj   /* The number of bytes to write is SRCLEN.  */
4046*38fd1498Szrj   check_access (exp, dest, src, NULL_TREE, maxread, srclen, destsize);
4047*38fd1498Szrj 
4048*38fd1498Szrj   return NULL_RTX;
4049*38fd1498Szrj }
4050*38fd1498Szrj 
4051*38fd1498Szrj /* Expand expression EXP, which is a call to the strncpy builtin.  Return
4052*38fd1498Szrj    NULL_RTX if we failed the caller should emit a normal call.  */
4053*38fd1498Szrj 
4054*38fd1498Szrj static rtx
expand_builtin_strncpy(tree exp,rtx target)4055*38fd1498Szrj expand_builtin_strncpy (tree exp, rtx target)
4056*38fd1498Szrj {
4057*38fd1498Szrj   location_t loc = EXPR_LOCATION (exp);
4058*38fd1498Szrj 
4059*38fd1498Szrj   if (validate_arglist (exp,
4060*38fd1498Szrj  			POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
4061*38fd1498Szrj     {
4062*38fd1498Szrj       tree dest = CALL_EXPR_ARG (exp, 0);
4063*38fd1498Szrj       tree src = CALL_EXPR_ARG (exp, 1);
4064*38fd1498Szrj       /* The number of bytes to write (not the maximum).  */
4065*38fd1498Szrj       tree len = CALL_EXPR_ARG (exp, 2);
4066*38fd1498Szrj       /* The length of the source sequence.  */
4067*38fd1498Szrj       tree slen = c_strlen (src, 1);
4068*38fd1498Szrj 
4069*38fd1498Szrj       if (warn_stringop_overflow)
4070*38fd1498Szrj 	{
4071*38fd1498Szrj 	  tree destsize = compute_objsize (dest,
4072*38fd1498Szrj 					   warn_stringop_overflow - 1);
4073*38fd1498Szrj 
4074*38fd1498Szrj 	  /* The number of bytes to write is LEN but check_access will also
4075*38fd1498Szrj 	     check SLEN if LEN's value isn't known.  */
4076*38fd1498Szrj 	  check_access (exp, dest, src, len, /*maxread=*/NULL_TREE, src,
4077*38fd1498Szrj 			destsize);
4078*38fd1498Szrj 	}
4079*38fd1498Szrj 
4080*38fd1498Szrj       /* We must be passed a constant len and src parameter.  */
4081*38fd1498Szrj       if (!tree_fits_uhwi_p (len) || !slen || !tree_fits_uhwi_p (slen))
4082*38fd1498Szrj 	return NULL_RTX;
4083*38fd1498Szrj 
4084*38fd1498Szrj       slen = size_binop_loc (loc, PLUS_EXPR, slen, ssize_int (1));
4085*38fd1498Szrj 
4086*38fd1498Szrj       /* We're required to pad with trailing zeros if the requested
4087*38fd1498Szrj 	 len is greater than strlen(s2)+1.  In that case try to
4088*38fd1498Szrj 	 use store_by_pieces, if it fails, punt.  */
4089*38fd1498Szrj       if (tree_int_cst_lt (slen, len))
4090*38fd1498Szrj 	{
4091*38fd1498Szrj 	  unsigned int dest_align = get_pointer_alignment (dest);
4092*38fd1498Szrj 	  const char *p = c_getstr (src);
4093*38fd1498Szrj 	  rtx dest_mem;
4094*38fd1498Szrj 
4095*38fd1498Szrj 	  if (!p || dest_align == 0 || !tree_fits_uhwi_p (len)
4096*38fd1498Szrj 	      || !can_store_by_pieces (tree_to_uhwi (len),
4097*38fd1498Szrj 				       builtin_strncpy_read_str,
4098*38fd1498Szrj 				       CONST_CAST (char *, p),
4099*38fd1498Szrj 				       dest_align, false))
4100*38fd1498Szrj 	    return NULL_RTX;
4101*38fd1498Szrj 
4102*38fd1498Szrj 	  dest_mem = get_memory_rtx (dest, len);
4103*38fd1498Szrj 	  store_by_pieces (dest_mem, tree_to_uhwi (len),
4104*38fd1498Szrj 			   builtin_strncpy_read_str,
4105*38fd1498Szrj 			   CONST_CAST (char *, p), dest_align, false, 0);
4106*38fd1498Szrj 	  dest_mem = force_operand (XEXP (dest_mem, 0), target);
4107*38fd1498Szrj 	  dest_mem = convert_memory_address (ptr_mode, dest_mem);
4108*38fd1498Szrj 	  return dest_mem;
4109*38fd1498Szrj 	}
4110*38fd1498Szrj     }
4111*38fd1498Szrj   return NULL_RTX;
4112*38fd1498Szrj }
4113*38fd1498Szrj 
4114*38fd1498Szrj /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
4115*38fd1498Szrj    bytes from constant string DATA + OFFSET and return it as target
4116*38fd1498Szrj    constant.  */
4117*38fd1498Szrj 
4118*38fd1498Szrj rtx
builtin_memset_read_str(void * data,HOST_WIDE_INT offset ATTRIBUTE_UNUSED,scalar_int_mode mode)4119*38fd1498Szrj builtin_memset_read_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
4120*38fd1498Szrj 			 scalar_int_mode mode)
4121*38fd1498Szrj {
4122*38fd1498Szrj   const char *c = (const char *) data;
4123*38fd1498Szrj   char *p = XALLOCAVEC (char, GET_MODE_SIZE (mode));
4124*38fd1498Szrj 
4125*38fd1498Szrj   memset (p, *c, GET_MODE_SIZE (mode));
4126*38fd1498Szrj 
4127*38fd1498Szrj   return c_readstr (p, mode);
4128*38fd1498Szrj }
4129*38fd1498Szrj 
4130*38fd1498Szrj /* Callback routine for store_by_pieces.  Return the RTL of a register
4131*38fd1498Szrj    containing GET_MODE_SIZE (MODE) consecutive copies of the unsigned
4132*38fd1498Szrj    char value given in the RTL register data.  For example, if mode is
4133*38fd1498Szrj    4 bytes wide, return the RTL for 0x01010101*data.  */
4134*38fd1498Szrj 
4135*38fd1498Szrj static rtx
builtin_memset_gen_str(void * data,HOST_WIDE_INT offset ATTRIBUTE_UNUSED,scalar_int_mode mode)4136*38fd1498Szrj builtin_memset_gen_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
4137*38fd1498Szrj 			scalar_int_mode mode)
4138*38fd1498Szrj {
4139*38fd1498Szrj   rtx target, coeff;
4140*38fd1498Szrj   size_t size;
4141*38fd1498Szrj   char *p;
4142*38fd1498Szrj 
4143*38fd1498Szrj   size = GET_MODE_SIZE (mode);
4144*38fd1498Szrj   if (size == 1)
4145*38fd1498Szrj     return (rtx) data;
4146*38fd1498Szrj 
4147*38fd1498Szrj   p = XALLOCAVEC (char, size);
4148*38fd1498Szrj   memset (p, 1, size);
4149*38fd1498Szrj   coeff = c_readstr (p, mode);
4150*38fd1498Szrj 
4151*38fd1498Szrj   target = convert_to_mode (mode, (rtx) data, 1);
4152*38fd1498Szrj   target = expand_mult (mode, target, coeff, NULL_RTX, 1);
4153*38fd1498Szrj   return force_reg (mode, target);
4154*38fd1498Szrj }
4155*38fd1498Szrj 
4156*38fd1498Szrj /* Expand expression EXP, which is a call to the memset builtin.  Return
4157*38fd1498Szrj    NULL_RTX if we failed the caller should emit a normal call, otherwise
4158*38fd1498Szrj    try to get the result in TARGET, if convenient (and in mode MODE if that's
4159*38fd1498Szrj    convenient).  */
4160*38fd1498Szrj 
4161*38fd1498Szrj static rtx
expand_builtin_memset(tree exp,rtx target,machine_mode mode)4162*38fd1498Szrj expand_builtin_memset (tree exp, rtx target, machine_mode mode)
4163*38fd1498Szrj {
4164*38fd1498Szrj   if (!validate_arglist (exp,
4165*38fd1498Szrj  			 POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
4166*38fd1498Szrj     return NULL_RTX;
4167*38fd1498Szrj 
4168*38fd1498Szrj   tree dest = CALL_EXPR_ARG (exp, 0);
4169*38fd1498Szrj   tree val = CALL_EXPR_ARG (exp, 1);
4170*38fd1498Szrj   tree len = CALL_EXPR_ARG (exp, 2);
4171*38fd1498Szrj 
4172*38fd1498Szrj   check_memop_access (exp, dest, NULL_TREE, len);
4173*38fd1498Szrj 
4174*38fd1498Szrj   return expand_builtin_memset_args (dest, val, len, target, mode, exp);
4175*38fd1498Szrj }
4176*38fd1498Szrj 
4177*38fd1498Szrj /* Expand expression EXP, which is an instrumented call to the memset builtin.
4178*38fd1498Szrj    Return NULL_RTX if we failed the caller should emit a normal call, otherwise
4179*38fd1498Szrj    try to get the result in TARGET, if convenient (and in mode MODE if that's
4180*38fd1498Szrj    convenient).  */
4181*38fd1498Szrj 
4182*38fd1498Szrj static rtx
expand_builtin_memset_with_bounds(tree exp,rtx target,machine_mode mode)4183*38fd1498Szrj expand_builtin_memset_with_bounds (tree exp, rtx target, machine_mode mode)
4184*38fd1498Szrj {
4185*38fd1498Szrj   if (!validate_arglist (exp,
4186*38fd1498Szrj 			 POINTER_TYPE, POINTER_BOUNDS_TYPE,
4187*38fd1498Szrj 			 INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
4188*38fd1498Szrj     return NULL_RTX;
4189*38fd1498Szrj   else
4190*38fd1498Szrj     {
4191*38fd1498Szrj       tree dest = CALL_EXPR_ARG (exp, 0);
4192*38fd1498Szrj       tree val = CALL_EXPR_ARG (exp, 2);
4193*38fd1498Szrj       tree len = CALL_EXPR_ARG (exp, 3);
4194*38fd1498Szrj       rtx res = expand_builtin_memset_args (dest, val, len, target, mode, exp);
4195*38fd1498Szrj 
4196*38fd1498Szrj       /* Return src bounds with the result.  */
4197*38fd1498Szrj       if (res)
4198*38fd1498Szrj 	{
4199*38fd1498Szrj 	  rtx bnd = force_reg (targetm.chkp_bound_mode (),
4200*38fd1498Szrj 			       expand_normal (CALL_EXPR_ARG (exp, 1)));
4201*38fd1498Szrj 	  res = chkp_join_splitted_slot (res, bnd);
4202*38fd1498Szrj 	}
4203*38fd1498Szrj       return res;
4204*38fd1498Szrj     }
4205*38fd1498Szrj }
4206*38fd1498Szrj 
4207*38fd1498Szrj /* Helper function to do the actual work for expand_builtin_memset.  The
4208*38fd1498Szrj    arguments to the builtin_memset call DEST, VAL, and LEN are broken out
4209*38fd1498Szrj    so that this can also be called without constructing an actual CALL_EXPR.
4210*38fd1498Szrj    The other arguments and return value are the same as for
4211*38fd1498Szrj    expand_builtin_memset.  */
4212*38fd1498Szrj 
4213*38fd1498Szrj static rtx
expand_builtin_memset_args(tree dest,tree val,tree len,rtx target,machine_mode mode,tree orig_exp)4214*38fd1498Szrj expand_builtin_memset_args (tree dest, tree val, tree len,
4215*38fd1498Szrj 			    rtx target, machine_mode mode, tree orig_exp)
4216*38fd1498Szrj {
4217*38fd1498Szrj   tree fndecl, fn;
4218*38fd1498Szrj   enum built_in_function fcode;
4219*38fd1498Szrj   machine_mode val_mode;
4220*38fd1498Szrj   char c;
4221*38fd1498Szrj   unsigned int dest_align;
4222*38fd1498Szrj   rtx dest_mem, dest_addr, len_rtx;
4223*38fd1498Szrj   HOST_WIDE_INT expected_size = -1;
4224*38fd1498Szrj   unsigned int expected_align = 0;
4225*38fd1498Szrj   unsigned HOST_WIDE_INT min_size;
4226*38fd1498Szrj   unsigned HOST_WIDE_INT max_size;
4227*38fd1498Szrj   unsigned HOST_WIDE_INT probable_max_size;
4228*38fd1498Szrj 
4229*38fd1498Szrj   dest_align = get_pointer_alignment (dest);
4230*38fd1498Szrj 
4231*38fd1498Szrj   /* If DEST is not a pointer type, don't do this operation in-line.  */
4232*38fd1498Szrj   if (dest_align == 0)
4233*38fd1498Szrj     return NULL_RTX;
4234*38fd1498Szrj 
4235*38fd1498Szrj   if (currently_expanding_gimple_stmt)
4236*38fd1498Szrj     stringop_block_profile (currently_expanding_gimple_stmt,
4237*38fd1498Szrj 			    &expected_align, &expected_size);
4238*38fd1498Szrj 
4239*38fd1498Szrj   if (expected_align < dest_align)
4240*38fd1498Szrj     expected_align = dest_align;
4241*38fd1498Szrj 
4242*38fd1498Szrj   /* If the LEN parameter is zero, return DEST.  */
4243*38fd1498Szrj   if (integer_zerop (len))
4244*38fd1498Szrj     {
4245*38fd1498Szrj       /* Evaluate and ignore VAL in case it has side-effects.  */
4246*38fd1498Szrj       expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL);
4247*38fd1498Szrj       return expand_expr (dest, target, mode, EXPAND_NORMAL);
4248*38fd1498Szrj     }
4249*38fd1498Szrj 
4250*38fd1498Szrj   /* Stabilize the arguments in case we fail.  */
4251*38fd1498Szrj   dest = builtin_save_expr (dest);
4252*38fd1498Szrj   val = builtin_save_expr (val);
4253*38fd1498Szrj   len = builtin_save_expr (len);
4254*38fd1498Szrj 
4255*38fd1498Szrj   len_rtx = expand_normal (len);
4256*38fd1498Szrj   determine_block_size (len, len_rtx, &min_size, &max_size,
4257*38fd1498Szrj 			&probable_max_size);
4258*38fd1498Szrj   dest_mem = get_memory_rtx (dest, len);
4259*38fd1498Szrj   val_mode = TYPE_MODE (unsigned_char_type_node);
4260*38fd1498Szrj 
4261*38fd1498Szrj   if (TREE_CODE (val) != INTEGER_CST)
4262*38fd1498Szrj     {
4263*38fd1498Szrj       rtx val_rtx;
4264*38fd1498Szrj 
4265*38fd1498Szrj       val_rtx = expand_normal (val);
4266*38fd1498Szrj       val_rtx = convert_to_mode (val_mode, val_rtx, 0);
4267*38fd1498Szrj 
4268*38fd1498Szrj       /* Assume that we can memset by pieces if we can store
4269*38fd1498Szrj        * the coefficients by pieces (in the required modes).
4270*38fd1498Szrj        * We can't pass builtin_memset_gen_str as that emits RTL.  */
4271*38fd1498Szrj       c = 1;
4272*38fd1498Szrj       if (tree_fits_uhwi_p (len)
4273*38fd1498Szrj 	  && can_store_by_pieces (tree_to_uhwi (len),
4274*38fd1498Szrj 				  builtin_memset_read_str, &c, dest_align,
4275*38fd1498Szrj 				  true))
4276*38fd1498Szrj 	{
4277*38fd1498Szrj 	  val_rtx = force_reg (val_mode, val_rtx);
4278*38fd1498Szrj 	  store_by_pieces (dest_mem, tree_to_uhwi (len),
4279*38fd1498Szrj 			   builtin_memset_gen_str, val_rtx, dest_align,
4280*38fd1498Szrj 			   true, 0);
4281*38fd1498Szrj 	}
4282*38fd1498Szrj       else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx,
4283*38fd1498Szrj 					dest_align, expected_align,
4284*38fd1498Szrj 					expected_size, min_size, max_size,
4285*38fd1498Szrj 					probable_max_size))
4286*38fd1498Szrj 	goto do_libcall;
4287*38fd1498Szrj 
4288*38fd1498Szrj       dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
4289*38fd1498Szrj       dest_mem = convert_memory_address (ptr_mode, dest_mem);
4290*38fd1498Szrj       return dest_mem;
4291*38fd1498Szrj     }
4292*38fd1498Szrj 
4293*38fd1498Szrj   if (target_char_cast (val, &c))
4294*38fd1498Szrj     goto do_libcall;
4295*38fd1498Szrj 
4296*38fd1498Szrj   if (c)
4297*38fd1498Szrj     {
4298*38fd1498Szrj       if (tree_fits_uhwi_p (len)
4299*38fd1498Szrj 	  && can_store_by_pieces (tree_to_uhwi (len),
4300*38fd1498Szrj 				  builtin_memset_read_str, &c, dest_align,
4301*38fd1498Szrj 				  true))
4302*38fd1498Szrj 	store_by_pieces (dest_mem, tree_to_uhwi (len),
4303*38fd1498Szrj 			 builtin_memset_read_str, &c, dest_align, true, 0);
4304*38fd1498Szrj       else if (!set_storage_via_setmem (dest_mem, len_rtx,
4305*38fd1498Szrj 					gen_int_mode (c, val_mode),
4306*38fd1498Szrj 					dest_align, expected_align,
4307*38fd1498Szrj 					expected_size, min_size, max_size,
4308*38fd1498Szrj 					probable_max_size))
4309*38fd1498Szrj 	goto do_libcall;
4310*38fd1498Szrj 
4311*38fd1498Szrj       dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
4312*38fd1498Szrj       dest_mem = convert_memory_address (ptr_mode, dest_mem);
4313*38fd1498Szrj       return dest_mem;
4314*38fd1498Szrj     }
4315*38fd1498Szrj 
4316*38fd1498Szrj   set_mem_align (dest_mem, dest_align);
4317*38fd1498Szrj   dest_addr = clear_storage_hints (dest_mem, len_rtx,
4318*38fd1498Szrj 				   CALL_EXPR_TAILCALL (orig_exp)
4319*38fd1498Szrj 				   ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL,
4320*38fd1498Szrj 				   expected_align, expected_size,
4321*38fd1498Szrj 				   min_size, max_size,
4322*38fd1498Szrj 				   probable_max_size);
4323*38fd1498Szrj 
4324*38fd1498Szrj   if (dest_addr == 0)
4325*38fd1498Szrj     {
4326*38fd1498Szrj       dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
4327*38fd1498Szrj       dest_addr = convert_memory_address (ptr_mode, dest_addr);
4328*38fd1498Szrj     }
4329*38fd1498Szrj 
4330*38fd1498Szrj   return dest_addr;
4331*38fd1498Szrj 
4332*38fd1498Szrj  do_libcall:
4333*38fd1498Szrj   fndecl = get_callee_fndecl (orig_exp);
4334*38fd1498Szrj   fcode = DECL_FUNCTION_CODE (fndecl);
4335*38fd1498Szrj   if (fcode == BUILT_IN_MEMSET
4336*38fd1498Szrj       || fcode == BUILT_IN_CHKP_MEMSET_NOBND_NOCHK_CHKP)
4337*38fd1498Szrj     fn = build_call_nofold_loc (EXPR_LOCATION (orig_exp), fndecl, 3,
4338*38fd1498Szrj 				dest, val, len);
4339*38fd1498Szrj   else if (fcode == BUILT_IN_BZERO)
4340*38fd1498Szrj     fn = build_call_nofold_loc (EXPR_LOCATION (orig_exp), fndecl, 2,
4341*38fd1498Szrj 				dest, len);
4342*38fd1498Szrj   else
4343*38fd1498Szrj     gcc_unreachable ();
4344*38fd1498Szrj   gcc_assert (TREE_CODE (fn) == CALL_EXPR);
4345*38fd1498Szrj   CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp);
4346*38fd1498Szrj   return expand_call (fn, target, target == const0_rtx);
4347*38fd1498Szrj }
4348*38fd1498Szrj 
4349*38fd1498Szrj /* Expand expression EXP, which is a call to the bzero builtin.  Return
4350*38fd1498Szrj    NULL_RTX if we failed the caller should emit a normal call.  */
4351*38fd1498Szrj 
4352*38fd1498Szrj static rtx
expand_builtin_bzero(tree exp)4353*38fd1498Szrj expand_builtin_bzero (tree exp)
4354*38fd1498Szrj {
4355*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
4356*38fd1498Szrj     return NULL_RTX;
4357*38fd1498Szrj 
4358*38fd1498Szrj   tree dest = CALL_EXPR_ARG (exp, 0);
4359*38fd1498Szrj   tree size = CALL_EXPR_ARG (exp, 1);
4360*38fd1498Szrj 
4361*38fd1498Szrj   check_memop_access (exp, dest, NULL_TREE, size);
4362*38fd1498Szrj 
4363*38fd1498Szrj   /* New argument list transforming bzero(ptr x, int y) to
4364*38fd1498Szrj      memset(ptr x, int 0, size_t y).   This is done this way
4365*38fd1498Szrj      so that if it isn't expanded inline, we fallback to
4366*38fd1498Szrj      calling bzero instead of memset.  */
4367*38fd1498Szrj 
4368*38fd1498Szrj   location_t loc = EXPR_LOCATION (exp);
4369*38fd1498Szrj 
4370*38fd1498Szrj   return expand_builtin_memset_args (dest, integer_zero_node,
4371*38fd1498Szrj 				     fold_convert_loc (loc,
4372*38fd1498Szrj 						       size_type_node, size),
4373*38fd1498Szrj 				     const0_rtx, VOIDmode, exp);
4374*38fd1498Szrj }
4375*38fd1498Szrj 
4376*38fd1498Szrj /* Try to expand cmpstr operation ICODE with the given operands.
4377*38fd1498Szrj    Return the result rtx on success, otherwise return null.  */
4378*38fd1498Szrj 
4379*38fd1498Szrj static rtx
expand_cmpstr(insn_code icode,rtx target,rtx arg1_rtx,rtx arg2_rtx,HOST_WIDE_INT align)4380*38fd1498Szrj expand_cmpstr (insn_code icode, rtx target, rtx arg1_rtx, rtx arg2_rtx,
4381*38fd1498Szrj 	       HOST_WIDE_INT align)
4382*38fd1498Szrj {
4383*38fd1498Szrj   machine_mode insn_mode = insn_data[icode].operand[0].mode;
4384*38fd1498Szrj 
4385*38fd1498Szrj   if (target && (!REG_P (target) || HARD_REGISTER_P (target)))
4386*38fd1498Szrj     target = NULL_RTX;
4387*38fd1498Szrj 
4388*38fd1498Szrj   struct expand_operand ops[4];
4389*38fd1498Szrj   create_output_operand (&ops[0], target, insn_mode);
4390*38fd1498Szrj   create_fixed_operand (&ops[1], arg1_rtx);
4391*38fd1498Szrj   create_fixed_operand (&ops[2], arg2_rtx);
4392*38fd1498Szrj   create_integer_operand (&ops[3], align);
4393*38fd1498Szrj   if (maybe_expand_insn (icode, 4, ops))
4394*38fd1498Szrj     return ops[0].value;
4395*38fd1498Szrj   return NULL_RTX;
4396*38fd1498Szrj }
4397*38fd1498Szrj 
4398*38fd1498Szrj /* Expand expression EXP, which is a call to the memcmp built-in function.
4399*38fd1498Szrj    Return NULL_RTX if we failed and the caller should emit a normal call,
4400*38fd1498Szrj    otherwise try to get the result in TARGET, if convenient.
4401*38fd1498Szrj    RESULT_EQ is true if we can relax the returned value to be either zero
4402*38fd1498Szrj    or nonzero, without caring about the sign.  */
4403*38fd1498Szrj 
4404*38fd1498Szrj static rtx
expand_builtin_memcmp(tree exp,rtx target,bool result_eq)4405*38fd1498Szrj expand_builtin_memcmp (tree exp, rtx target, bool result_eq)
4406*38fd1498Szrj {
4407*38fd1498Szrj   if (!validate_arglist (exp,
4408*38fd1498Szrj  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
4409*38fd1498Szrj     return NULL_RTX;
4410*38fd1498Szrj 
4411*38fd1498Szrj   tree arg1 = CALL_EXPR_ARG (exp, 0);
4412*38fd1498Szrj   tree arg2 = CALL_EXPR_ARG (exp, 1);
4413*38fd1498Szrj   tree len = CALL_EXPR_ARG (exp, 2);
4414*38fd1498Szrj 
4415*38fd1498Szrj   /* Diagnose calls where the specified length exceeds the size of either
4416*38fd1498Szrj      object.  */
4417*38fd1498Szrj   if (warn_stringop_overflow)
4418*38fd1498Szrj     {
4419*38fd1498Szrj       tree size = compute_objsize (arg1, 0);
4420*38fd1498Szrj       if (check_access (exp, /*dst=*/NULL_TREE, /*src=*/NULL_TREE, len,
4421*38fd1498Szrj 			/*maxread=*/NULL_TREE, size, /*objsize=*/NULL_TREE))
4422*38fd1498Szrj 	{
4423*38fd1498Szrj 	  size = compute_objsize (arg2, 0);
4424*38fd1498Szrj 	  check_access (exp, /*dst=*/NULL_TREE, /*src=*/NULL_TREE, len,
4425*38fd1498Szrj 			/*maxread=*/NULL_TREE, size, /*objsize=*/NULL_TREE);
4426*38fd1498Szrj 	}
4427*38fd1498Szrj     }
4428*38fd1498Szrj 
4429*38fd1498Szrj   machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
4430*38fd1498Szrj   location_t loc = EXPR_LOCATION (exp);
4431*38fd1498Szrj 
4432*38fd1498Szrj   unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
4433*38fd1498Szrj   unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
4434*38fd1498Szrj 
4435*38fd1498Szrj   /* If we don't have POINTER_TYPE, call the function.  */
4436*38fd1498Szrj   if (arg1_align == 0 || arg2_align == 0)
4437*38fd1498Szrj     return NULL_RTX;
4438*38fd1498Szrj 
4439*38fd1498Szrj   rtx arg1_rtx = get_memory_rtx (arg1, len);
4440*38fd1498Szrj   rtx arg2_rtx = get_memory_rtx (arg2, len);
4441*38fd1498Szrj   rtx len_rtx = expand_normal (fold_convert_loc (loc, sizetype, len));
4442*38fd1498Szrj 
4443*38fd1498Szrj   /* Set MEM_SIZE as appropriate.  */
4444*38fd1498Szrj   if (CONST_INT_P (len_rtx))
4445*38fd1498Szrj     {
4446*38fd1498Szrj       set_mem_size (arg1_rtx, INTVAL (len_rtx));
4447*38fd1498Szrj       set_mem_size (arg2_rtx, INTVAL (len_rtx));
4448*38fd1498Szrj     }
4449*38fd1498Szrj 
4450*38fd1498Szrj   by_pieces_constfn constfn = NULL;
4451*38fd1498Szrj 
4452*38fd1498Szrj   const char *src_str = c_getstr (arg2);
4453*38fd1498Szrj   if (result_eq && src_str == NULL)
4454*38fd1498Szrj     {
4455*38fd1498Szrj       src_str = c_getstr (arg1);
4456*38fd1498Szrj       if (src_str != NULL)
4457*38fd1498Szrj 	std::swap (arg1_rtx, arg2_rtx);
4458*38fd1498Szrj     }
4459*38fd1498Szrj 
4460*38fd1498Szrj   /* If SRC is a string constant and block move would be done
4461*38fd1498Szrj      by pieces, we can avoid loading the string from memory
4462*38fd1498Szrj      and only stored the computed constants.  */
4463*38fd1498Szrj   if (src_str
4464*38fd1498Szrj       && CONST_INT_P (len_rtx)
4465*38fd1498Szrj       && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1)
4466*38fd1498Szrj     constfn = builtin_memcpy_read_str;
4467*38fd1498Szrj 
4468*38fd1498Szrj   rtx result = emit_block_cmp_hints (arg1_rtx, arg2_rtx, len_rtx,
4469*38fd1498Szrj 				     TREE_TYPE (len), target,
4470*38fd1498Szrj 				     result_eq, constfn,
4471*38fd1498Szrj 				     CONST_CAST (char *, src_str));
4472*38fd1498Szrj 
4473*38fd1498Szrj   if (result)
4474*38fd1498Szrj     {
4475*38fd1498Szrj       /* Return the value in the proper mode for this function.  */
4476*38fd1498Szrj       if (GET_MODE (result) == mode)
4477*38fd1498Szrj 	return result;
4478*38fd1498Szrj 
4479*38fd1498Szrj       if (target != 0)
4480*38fd1498Szrj 	{
4481*38fd1498Szrj 	  convert_move (target, result, 0);
4482*38fd1498Szrj 	  return target;
4483*38fd1498Szrj 	}
4484*38fd1498Szrj 
4485*38fd1498Szrj       return convert_to_mode (mode, result, 0);
4486*38fd1498Szrj     }
4487*38fd1498Szrj 
4488*38fd1498Szrj   return NULL_RTX;
4489*38fd1498Szrj }
4490*38fd1498Szrj 
4491*38fd1498Szrj /* Expand expression EXP, which is a call to the strcmp builtin.  Return NULL_RTX
4492*38fd1498Szrj    if we failed the caller should emit a normal call, otherwise try to get
4493*38fd1498Szrj    the result in TARGET, if convenient.  */
4494*38fd1498Szrj 
4495*38fd1498Szrj static rtx
expand_builtin_strcmp(tree exp,ATTRIBUTE_UNUSED rtx target)4496*38fd1498Szrj expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
4497*38fd1498Szrj {
4498*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
4499*38fd1498Szrj     return NULL_RTX;
4500*38fd1498Szrj 
4501*38fd1498Szrj   insn_code cmpstr_icode = direct_optab_handler (cmpstr_optab, SImode);
4502*38fd1498Szrj   insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
4503*38fd1498Szrj   if (cmpstr_icode == CODE_FOR_nothing && cmpstrn_icode == CODE_FOR_nothing)
4504*38fd1498Szrj     return NULL_RTX;
4505*38fd1498Szrj 
4506*38fd1498Szrj   tree arg1 = CALL_EXPR_ARG (exp, 0);
4507*38fd1498Szrj   tree arg2 = CALL_EXPR_ARG (exp, 1);
4508*38fd1498Szrj 
4509*38fd1498Szrj   unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
4510*38fd1498Szrj   unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
4511*38fd1498Szrj 
4512*38fd1498Szrj   /* If we don't have POINTER_TYPE, call the function.  */
4513*38fd1498Szrj   if (arg1_align == 0 || arg2_align == 0)
4514*38fd1498Szrj     return NULL_RTX;
4515*38fd1498Szrj 
4516*38fd1498Szrj   /* Stabilize the arguments in case gen_cmpstr(n)si fail.  */
4517*38fd1498Szrj   arg1 = builtin_save_expr (arg1);
4518*38fd1498Szrj   arg2 = builtin_save_expr (arg2);
4519*38fd1498Szrj 
4520*38fd1498Szrj   rtx arg1_rtx = get_memory_rtx (arg1, NULL);
4521*38fd1498Szrj   rtx arg2_rtx = get_memory_rtx (arg2, NULL);
4522*38fd1498Szrj 
4523*38fd1498Szrj   rtx result = NULL_RTX;
4524*38fd1498Szrj   /* Try to call cmpstrsi.  */
4525*38fd1498Szrj   if (cmpstr_icode != CODE_FOR_nothing)
4526*38fd1498Szrj     result = expand_cmpstr (cmpstr_icode, target, arg1_rtx, arg2_rtx,
4527*38fd1498Szrj 			    MIN (arg1_align, arg2_align));
4528*38fd1498Szrj 
4529*38fd1498Szrj   /* Try to determine at least one length and call cmpstrnsi.  */
4530*38fd1498Szrj   if (!result && cmpstrn_icode != CODE_FOR_nothing)
4531*38fd1498Szrj     {
4532*38fd1498Szrj       tree len;
4533*38fd1498Szrj       rtx arg3_rtx;
4534*38fd1498Szrj 
4535*38fd1498Szrj       tree len1 = c_strlen (arg1, 1);
4536*38fd1498Szrj       tree len2 = c_strlen (arg2, 1);
4537*38fd1498Szrj 
4538*38fd1498Szrj       if (len1)
4539*38fd1498Szrj 	len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
4540*38fd1498Szrj       if (len2)
4541*38fd1498Szrj 	len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
4542*38fd1498Szrj 
4543*38fd1498Szrj       /* If we don't have a constant length for the first, use the length
4544*38fd1498Szrj 	 of the second, if we know it.  We don't require a constant for
4545*38fd1498Szrj 	 this case; some cost analysis could be done if both are available
4546*38fd1498Szrj 	 but neither is constant.  For now, assume they're equally cheap,
4547*38fd1498Szrj 	 unless one has side effects.  If both strings have constant lengths,
4548*38fd1498Szrj 	 use the smaller.  */
4549*38fd1498Szrj 
4550*38fd1498Szrj       if (!len1)
4551*38fd1498Szrj 	len = len2;
4552*38fd1498Szrj       else if (!len2)
4553*38fd1498Szrj 	len = len1;
4554*38fd1498Szrj       else if (TREE_SIDE_EFFECTS (len1))
4555*38fd1498Szrj 	len = len2;
4556*38fd1498Szrj       else if (TREE_SIDE_EFFECTS (len2))
4557*38fd1498Szrj 	len = len1;
4558*38fd1498Szrj       else if (TREE_CODE (len1) != INTEGER_CST)
4559*38fd1498Szrj 	len = len2;
4560*38fd1498Szrj       else if (TREE_CODE (len2) != INTEGER_CST)
4561*38fd1498Szrj 	len = len1;
4562*38fd1498Szrj       else if (tree_int_cst_lt (len1, len2))
4563*38fd1498Szrj 	len = len1;
4564*38fd1498Szrj       else
4565*38fd1498Szrj 	len = len2;
4566*38fd1498Szrj 
4567*38fd1498Szrj       /* If both arguments have side effects, we cannot optimize.  */
4568*38fd1498Szrj       if (len && !TREE_SIDE_EFFECTS (len))
4569*38fd1498Szrj 	{
4570*38fd1498Szrj 	  arg3_rtx = expand_normal (len);
4571*38fd1498Szrj 	  result = expand_cmpstrn_or_cmpmem
4572*38fd1498Szrj 	    (cmpstrn_icode, target, arg1_rtx, arg2_rtx, TREE_TYPE (len),
4573*38fd1498Szrj 	     arg3_rtx, MIN (arg1_align, arg2_align));
4574*38fd1498Szrj 	}
4575*38fd1498Szrj     }
4576*38fd1498Szrj 
4577*38fd1498Szrj   /* Check to see if the argument was declared attribute nonstring
4578*38fd1498Szrj      and if so, issue a warning since at this point it's not known
4579*38fd1498Szrj      to be nul-terminated.  */
4580*38fd1498Szrj   tree fndecl = get_callee_fndecl (exp);
4581*38fd1498Szrj   maybe_warn_nonstring_arg (fndecl, exp);
4582*38fd1498Szrj 
4583*38fd1498Szrj   if (result)
4584*38fd1498Szrj     {
4585*38fd1498Szrj       /* Return the value in the proper mode for this function.  */
4586*38fd1498Szrj       machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
4587*38fd1498Szrj       if (GET_MODE (result) == mode)
4588*38fd1498Szrj 	return result;
4589*38fd1498Szrj       if (target == 0)
4590*38fd1498Szrj 	return convert_to_mode (mode, result, 0);
4591*38fd1498Szrj       convert_move (target, result, 0);
4592*38fd1498Szrj       return target;
4593*38fd1498Szrj     }
4594*38fd1498Szrj 
4595*38fd1498Szrj   /* Expand the library call ourselves using a stabilized argument
4596*38fd1498Szrj      list to avoid re-evaluating the function's arguments twice.  */
4597*38fd1498Szrj   tree fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2);
4598*38fd1498Szrj   gcc_assert (TREE_CODE (fn) == CALL_EXPR);
4599*38fd1498Szrj   CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
4600*38fd1498Szrj   return expand_call (fn, target, target == const0_rtx);
4601*38fd1498Szrj }
4602*38fd1498Szrj 
4603*38fd1498Szrj /* Expand expression EXP, which is a call to the strncmp builtin. Return
4604*38fd1498Szrj    NULL_RTX if we failed the caller should emit a normal call, otherwise try to get
4605*38fd1498Szrj    the result in TARGET, if convenient.  */
4606*38fd1498Szrj 
4607*38fd1498Szrj static rtx
expand_builtin_strncmp(tree exp,ATTRIBUTE_UNUSED rtx target,ATTRIBUTE_UNUSED machine_mode mode)4608*38fd1498Szrj expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
4609*38fd1498Szrj 			ATTRIBUTE_UNUSED machine_mode mode)
4610*38fd1498Szrj {
4611*38fd1498Szrj   if (!validate_arglist (exp,
4612*38fd1498Szrj  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
4613*38fd1498Szrj     return NULL_RTX;
4614*38fd1498Szrj 
4615*38fd1498Szrj   /* If c_strlen can determine an expression for one of the string
4616*38fd1498Szrj      lengths, and it doesn't have side effects, then emit cmpstrnsi
4617*38fd1498Szrj      using length MIN(strlen(string)+1, arg3).  */
4618*38fd1498Szrj   insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
4619*38fd1498Szrj   if (cmpstrn_icode == CODE_FOR_nothing)
4620*38fd1498Szrj     return NULL_RTX;
4621*38fd1498Szrj 
4622*38fd1498Szrj   tree len;
4623*38fd1498Szrj 
4624*38fd1498Szrj   tree arg1 = CALL_EXPR_ARG (exp, 0);
4625*38fd1498Szrj   tree arg2 = CALL_EXPR_ARG (exp, 1);
4626*38fd1498Szrj   tree arg3 = CALL_EXPR_ARG (exp, 2);
4627*38fd1498Szrj 
4628*38fd1498Szrj   unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
4629*38fd1498Szrj   unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
4630*38fd1498Szrj 
4631*38fd1498Szrj   tree len1 = c_strlen (arg1, 1);
4632*38fd1498Szrj   tree len2 = c_strlen (arg2, 1);
4633*38fd1498Szrj 
4634*38fd1498Szrj   location_t loc = EXPR_LOCATION (exp);
4635*38fd1498Szrj 
4636*38fd1498Szrj   if (len1)
4637*38fd1498Szrj     len1 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len1);
4638*38fd1498Szrj   if (len2)
4639*38fd1498Szrj     len2 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len2);
4640*38fd1498Szrj 
4641*38fd1498Szrj   tree len3 = fold_convert_loc (loc, sizetype, arg3);
4642*38fd1498Szrj 
4643*38fd1498Szrj   /* If we don't have a constant length for the first, use the length
4644*38fd1498Szrj      of the second, if we know it.  If neither string is constant length,
4645*38fd1498Szrj      use the given length argument.  We don't require a constant for
4646*38fd1498Szrj      this case; some cost analysis could be done if both are available
4647*38fd1498Szrj      but neither is constant.  For now, assume they're equally cheap,
4648*38fd1498Szrj      unless one has side effects.  If both strings have constant lengths,
4649*38fd1498Szrj      use the smaller.  */
4650*38fd1498Szrj 
4651*38fd1498Szrj   if (!len1 && !len2)
4652*38fd1498Szrj     len = len3;
4653*38fd1498Szrj   else if (!len1)
4654*38fd1498Szrj     len = len2;
4655*38fd1498Szrj   else if (!len2)
4656*38fd1498Szrj     len = len1;
4657*38fd1498Szrj   else if (TREE_SIDE_EFFECTS (len1))
4658*38fd1498Szrj     len = len2;
4659*38fd1498Szrj   else if (TREE_SIDE_EFFECTS (len2))
4660*38fd1498Szrj     len = len1;
4661*38fd1498Szrj   else if (TREE_CODE (len1) != INTEGER_CST)
4662*38fd1498Szrj     len = len2;
4663*38fd1498Szrj   else if (TREE_CODE (len2) != INTEGER_CST)
4664*38fd1498Szrj     len = len1;
4665*38fd1498Szrj   else if (tree_int_cst_lt (len1, len2))
4666*38fd1498Szrj     len = len1;
4667*38fd1498Szrj   else
4668*38fd1498Szrj     len = len2;
4669*38fd1498Szrj 
4670*38fd1498Szrj   /* If we are not using the given length, we must incorporate it here.
4671*38fd1498Szrj      The actual new length parameter will be MIN(len,arg3) in this case.  */
4672*38fd1498Szrj   if (len != len3)
4673*38fd1498Szrj     len = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (len), len, len3);
4674*38fd1498Szrj   rtx arg1_rtx = get_memory_rtx (arg1, len);
4675*38fd1498Szrj   rtx arg2_rtx = get_memory_rtx (arg2, len);
4676*38fd1498Szrj   rtx arg3_rtx = expand_normal (len);
4677*38fd1498Szrj   rtx result = expand_cmpstrn_or_cmpmem (cmpstrn_icode, target, arg1_rtx,
4678*38fd1498Szrj 					 arg2_rtx, TREE_TYPE (len), arg3_rtx,
4679*38fd1498Szrj 					 MIN (arg1_align, arg2_align));
4680*38fd1498Szrj 
4681*38fd1498Szrj   /* Check to see if the argument was declared attribute nonstring
4682*38fd1498Szrj      and if so, issue a warning since at this point it's not known
4683*38fd1498Szrj      to be nul-terminated.  */
4684*38fd1498Szrj   tree fndecl = get_callee_fndecl (exp);
4685*38fd1498Szrj   maybe_warn_nonstring_arg (fndecl, exp);
4686*38fd1498Szrj 
4687*38fd1498Szrj   if (result)
4688*38fd1498Szrj     {
4689*38fd1498Szrj       /* Return the value in the proper mode for this function.  */
4690*38fd1498Szrj       mode = TYPE_MODE (TREE_TYPE (exp));
4691*38fd1498Szrj       if (GET_MODE (result) == mode)
4692*38fd1498Szrj 	return result;
4693*38fd1498Szrj       if (target == 0)
4694*38fd1498Szrj 	return convert_to_mode (mode, result, 0);
4695*38fd1498Szrj       convert_move (target, result, 0);
4696*38fd1498Szrj       return target;
4697*38fd1498Szrj     }
4698*38fd1498Szrj 
4699*38fd1498Szrj   /* Expand the library call ourselves using a stabilized argument
4700*38fd1498Szrj      list to avoid re-evaluating the function's arguments twice.  */
4701*38fd1498Szrj   tree fn = build_call_nofold_loc (loc, fndecl, 3, arg1, arg2, len);
4702*38fd1498Szrj   gcc_assert (TREE_CODE (fn) == CALL_EXPR);
4703*38fd1498Szrj   CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
4704*38fd1498Szrj   return expand_call (fn, target, target == const0_rtx);
4705*38fd1498Szrj }
4706*38fd1498Szrj 
4707*38fd1498Szrj /* Expand a call to __builtin_saveregs, generating the result in TARGET,
4708*38fd1498Szrj    if that's convenient.  */
4709*38fd1498Szrj 
4710*38fd1498Szrj rtx
expand_builtin_saveregs(void)4711*38fd1498Szrj expand_builtin_saveregs (void)
4712*38fd1498Szrj {
4713*38fd1498Szrj   rtx val;
4714*38fd1498Szrj   rtx_insn *seq;
4715*38fd1498Szrj 
4716*38fd1498Szrj   /* Don't do __builtin_saveregs more than once in a function.
4717*38fd1498Szrj      Save the result of the first call and reuse it.  */
4718*38fd1498Szrj   if (saveregs_value != 0)
4719*38fd1498Szrj     return saveregs_value;
4720*38fd1498Szrj 
4721*38fd1498Szrj   /* When this function is called, it means that registers must be
4722*38fd1498Szrj      saved on entry to this function.  So we migrate the call to the
4723*38fd1498Szrj      first insn of this function.  */
4724*38fd1498Szrj 
4725*38fd1498Szrj   start_sequence ();
4726*38fd1498Szrj 
4727*38fd1498Szrj   /* Do whatever the machine needs done in this case.  */
4728*38fd1498Szrj   val = targetm.calls.expand_builtin_saveregs ();
4729*38fd1498Szrj 
4730*38fd1498Szrj   seq = get_insns ();
4731*38fd1498Szrj   end_sequence ();
4732*38fd1498Szrj 
4733*38fd1498Szrj   saveregs_value = val;
4734*38fd1498Szrj 
4735*38fd1498Szrj   /* Put the insns after the NOTE that starts the function.  If this
4736*38fd1498Szrj      is inside a start_sequence, make the outer-level insn chain current, so
4737*38fd1498Szrj      the code is placed at the start of the function.  */
4738*38fd1498Szrj   push_topmost_sequence ();
4739*38fd1498Szrj   emit_insn_after (seq, entry_of_function ());
4740*38fd1498Szrj   pop_topmost_sequence ();
4741*38fd1498Szrj 
4742*38fd1498Szrj   return val;
4743*38fd1498Szrj }
4744*38fd1498Szrj 
4745*38fd1498Szrj /* Expand a call to __builtin_next_arg.  */
4746*38fd1498Szrj 
4747*38fd1498Szrj static rtx
expand_builtin_next_arg(void)4748*38fd1498Szrj expand_builtin_next_arg (void)
4749*38fd1498Szrj {
4750*38fd1498Szrj   /* Checking arguments is already done in fold_builtin_next_arg
4751*38fd1498Szrj      that must be called before this function.  */
4752*38fd1498Szrj   return expand_binop (ptr_mode, add_optab,
4753*38fd1498Szrj 		       crtl->args.internal_arg_pointer,
4754*38fd1498Szrj 		       crtl->args.arg_offset_rtx,
4755*38fd1498Szrj 		       NULL_RTX, 0, OPTAB_LIB_WIDEN);
4756*38fd1498Szrj }
4757*38fd1498Szrj 
4758*38fd1498Szrj /* Make it easier for the backends by protecting the valist argument
4759*38fd1498Szrj    from multiple evaluations.  */
4760*38fd1498Szrj 
4761*38fd1498Szrj static tree
stabilize_va_list_loc(location_t loc,tree valist,int needs_lvalue)4762*38fd1498Szrj stabilize_va_list_loc (location_t loc, tree valist, int needs_lvalue)
4763*38fd1498Szrj {
4764*38fd1498Szrj   tree vatype = targetm.canonical_va_list_type (TREE_TYPE (valist));
4765*38fd1498Szrj 
4766*38fd1498Szrj   /* The current way of determining the type of valist is completely
4767*38fd1498Szrj      bogus.  We should have the information on the va builtin instead.  */
4768*38fd1498Szrj   if (!vatype)
4769*38fd1498Szrj     vatype = targetm.fn_abi_va_list (cfun->decl);
4770*38fd1498Szrj 
4771*38fd1498Szrj   if (TREE_CODE (vatype) == ARRAY_TYPE)
4772*38fd1498Szrj     {
4773*38fd1498Szrj       if (TREE_SIDE_EFFECTS (valist))
4774*38fd1498Szrj 	valist = save_expr (valist);
4775*38fd1498Szrj 
4776*38fd1498Szrj       /* For this case, the backends will be expecting a pointer to
4777*38fd1498Szrj 	 vatype, but it's possible we've actually been given an array
4778*38fd1498Szrj 	 (an actual TARGET_CANONICAL_VA_LIST_TYPE (valist)).
4779*38fd1498Szrj 	 So fix it.  */
4780*38fd1498Szrj       if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
4781*38fd1498Szrj 	{
4782*38fd1498Szrj 	  tree p1 = build_pointer_type (TREE_TYPE (vatype));
4783*38fd1498Szrj 	  valist = build_fold_addr_expr_with_type_loc (loc, valist, p1);
4784*38fd1498Szrj 	}
4785*38fd1498Szrj     }
4786*38fd1498Szrj   else
4787*38fd1498Szrj     {
4788*38fd1498Szrj       tree pt = build_pointer_type (vatype);
4789*38fd1498Szrj 
4790*38fd1498Szrj       if (! needs_lvalue)
4791*38fd1498Szrj 	{
4792*38fd1498Szrj 	  if (! TREE_SIDE_EFFECTS (valist))
4793*38fd1498Szrj 	    return valist;
4794*38fd1498Szrj 
4795*38fd1498Szrj 	  valist = fold_build1_loc (loc, ADDR_EXPR, pt, valist);
4796*38fd1498Szrj 	  TREE_SIDE_EFFECTS (valist) = 1;
4797*38fd1498Szrj 	}
4798*38fd1498Szrj 
4799*38fd1498Szrj       if (TREE_SIDE_EFFECTS (valist))
4800*38fd1498Szrj 	valist = save_expr (valist);
4801*38fd1498Szrj       valist = fold_build2_loc (loc, MEM_REF,
4802*38fd1498Szrj 				vatype, valist, build_int_cst (pt, 0));
4803*38fd1498Szrj     }
4804*38fd1498Szrj 
4805*38fd1498Szrj   return valist;
4806*38fd1498Szrj }
4807*38fd1498Szrj 
4808*38fd1498Szrj /* The "standard" definition of va_list is void*.  */
4809*38fd1498Szrj 
4810*38fd1498Szrj tree
std_build_builtin_va_list(void)4811*38fd1498Szrj std_build_builtin_va_list (void)
4812*38fd1498Szrj {
4813*38fd1498Szrj   return ptr_type_node;
4814*38fd1498Szrj }
4815*38fd1498Szrj 
4816*38fd1498Szrj /* The "standard" abi va_list is va_list_type_node.  */
4817*38fd1498Szrj 
4818*38fd1498Szrj tree
std_fn_abi_va_list(tree fndecl ATTRIBUTE_UNUSED)4819*38fd1498Szrj std_fn_abi_va_list (tree fndecl ATTRIBUTE_UNUSED)
4820*38fd1498Szrj {
4821*38fd1498Szrj   return va_list_type_node;
4822*38fd1498Szrj }
4823*38fd1498Szrj 
4824*38fd1498Szrj /* The "standard" type of va_list is va_list_type_node.  */
4825*38fd1498Szrj 
4826*38fd1498Szrj tree
std_canonical_va_list_type(tree type)4827*38fd1498Szrj std_canonical_va_list_type (tree type)
4828*38fd1498Szrj {
4829*38fd1498Szrj   tree wtype, htype;
4830*38fd1498Szrj 
4831*38fd1498Szrj   wtype = va_list_type_node;
4832*38fd1498Szrj   htype = type;
4833*38fd1498Szrj 
4834*38fd1498Szrj   if (TREE_CODE (wtype) == ARRAY_TYPE)
4835*38fd1498Szrj     {
4836*38fd1498Szrj       /* If va_list is an array type, the argument may have decayed
4837*38fd1498Szrj 	 to a pointer type, e.g. by being passed to another function.
4838*38fd1498Szrj 	 In that case, unwrap both types so that we can compare the
4839*38fd1498Szrj 	 underlying records.  */
4840*38fd1498Szrj       if (TREE_CODE (htype) == ARRAY_TYPE
4841*38fd1498Szrj 	  || POINTER_TYPE_P (htype))
4842*38fd1498Szrj 	{
4843*38fd1498Szrj 	  wtype = TREE_TYPE (wtype);
4844*38fd1498Szrj 	  htype = TREE_TYPE (htype);
4845*38fd1498Szrj 	}
4846*38fd1498Szrj     }
4847*38fd1498Szrj   if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype))
4848*38fd1498Szrj     return va_list_type_node;
4849*38fd1498Szrj 
4850*38fd1498Szrj   return NULL_TREE;
4851*38fd1498Szrj }
4852*38fd1498Szrj 
4853*38fd1498Szrj /* The "standard" implementation of va_start: just assign `nextarg' to
4854*38fd1498Szrj    the variable.  */
4855*38fd1498Szrj 
4856*38fd1498Szrj void
std_expand_builtin_va_start(tree valist,rtx nextarg)4857*38fd1498Szrj std_expand_builtin_va_start (tree valist, rtx nextarg)
4858*38fd1498Szrj {
4859*38fd1498Szrj   rtx va_r = expand_expr (valist, NULL_RTX, VOIDmode, EXPAND_WRITE);
4860*38fd1498Szrj   convert_move (va_r, nextarg, 0);
4861*38fd1498Szrj 
4862*38fd1498Szrj   /* We do not have any valid bounds for the pointer, so
4863*38fd1498Szrj      just store zero bounds for it.  */
4864*38fd1498Szrj   if (chkp_function_instrumented_p (current_function_decl))
4865*38fd1498Szrj     chkp_expand_bounds_reset_for_mem (valist,
4866*38fd1498Szrj 				      make_tree (TREE_TYPE (valist),
4867*38fd1498Szrj 						 nextarg));
4868*38fd1498Szrj }
4869*38fd1498Szrj 
4870*38fd1498Szrj /* Expand EXP, a call to __builtin_va_start.  */
4871*38fd1498Szrj 
4872*38fd1498Szrj static rtx
expand_builtin_va_start(tree exp)4873*38fd1498Szrj expand_builtin_va_start (tree exp)
4874*38fd1498Szrj {
4875*38fd1498Szrj   rtx nextarg;
4876*38fd1498Szrj   tree valist;
4877*38fd1498Szrj   location_t loc = EXPR_LOCATION (exp);
4878*38fd1498Szrj 
4879*38fd1498Szrj   if (call_expr_nargs (exp) < 2)
4880*38fd1498Szrj     {
4881*38fd1498Szrj       error_at (loc, "too few arguments to function %<va_start%>");
4882*38fd1498Szrj       return const0_rtx;
4883*38fd1498Szrj     }
4884*38fd1498Szrj 
4885*38fd1498Szrj   if (fold_builtin_next_arg (exp, true))
4886*38fd1498Szrj     return const0_rtx;
4887*38fd1498Szrj 
4888*38fd1498Szrj   nextarg = expand_builtin_next_arg ();
4889*38fd1498Szrj   valist = stabilize_va_list_loc (loc, CALL_EXPR_ARG (exp, 0), 1);
4890*38fd1498Szrj 
4891*38fd1498Szrj   if (targetm.expand_builtin_va_start)
4892*38fd1498Szrj     targetm.expand_builtin_va_start (valist, nextarg);
4893*38fd1498Szrj   else
4894*38fd1498Szrj     std_expand_builtin_va_start (valist, nextarg);
4895*38fd1498Szrj 
4896*38fd1498Szrj   return const0_rtx;
4897*38fd1498Szrj }
4898*38fd1498Szrj 
4899*38fd1498Szrj /* Expand EXP, a call to __builtin_va_end.  */
4900*38fd1498Szrj 
4901*38fd1498Szrj static rtx
expand_builtin_va_end(tree exp)4902*38fd1498Szrj expand_builtin_va_end (tree exp)
4903*38fd1498Szrj {
4904*38fd1498Szrj   tree valist = CALL_EXPR_ARG (exp, 0);
4905*38fd1498Szrj 
4906*38fd1498Szrj   /* Evaluate for side effects, if needed.  I hate macros that don't
4907*38fd1498Szrj      do that.  */
4908*38fd1498Szrj   if (TREE_SIDE_EFFECTS (valist))
4909*38fd1498Szrj     expand_expr (valist, const0_rtx, VOIDmode, EXPAND_NORMAL);
4910*38fd1498Szrj 
4911*38fd1498Szrj   return const0_rtx;
4912*38fd1498Szrj }
4913*38fd1498Szrj 
4914*38fd1498Szrj /* Expand EXP, a call to __builtin_va_copy.  We do this as a
4915*38fd1498Szrj    builtin rather than just as an assignment in stdarg.h because of the
4916*38fd1498Szrj    nastiness of array-type va_list types.  */
4917*38fd1498Szrj 
4918*38fd1498Szrj static rtx
expand_builtin_va_copy(tree exp)4919*38fd1498Szrj expand_builtin_va_copy (tree exp)
4920*38fd1498Szrj {
4921*38fd1498Szrj   tree dst, src, t;
4922*38fd1498Szrj   location_t loc = EXPR_LOCATION (exp);
4923*38fd1498Szrj 
4924*38fd1498Szrj   dst = CALL_EXPR_ARG (exp, 0);
4925*38fd1498Szrj   src = CALL_EXPR_ARG (exp, 1);
4926*38fd1498Szrj 
4927*38fd1498Szrj   dst = stabilize_va_list_loc (loc, dst, 1);
4928*38fd1498Szrj   src = stabilize_va_list_loc (loc, src, 0);
4929*38fd1498Szrj 
4930*38fd1498Szrj   gcc_assert (cfun != NULL && cfun->decl != NULL_TREE);
4931*38fd1498Szrj 
4932*38fd1498Szrj   if (TREE_CODE (targetm.fn_abi_va_list (cfun->decl)) != ARRAY_TYPE)
4933*38fd1498Szrj     {
4934*38fd1498Szrj       t = build2 (MODIFY_EXPR, targetm.fn_abi_va_list (cfun->decl), dst, src);
4935*38fd1498Szrj       TREE_SIDE_EFFECTS (t) = 1;
4936*38fd1498Szrj       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
4937*38fd1498Szrj     }
4938*38fd1498Szrj   else
4939*38fd1498Szrj     {
4940*38fd1498Szrj       rtx dstb, srcb, size;
4941*38fd1498Szrj 
4942*38fd1498Szrj       /* Evaluate to pointers.  */
4943*38fd1498Szrj       dstb = expand_expr (dst, NULL_RTX, Pmode, EXPAND_NORMAL);
4944*38fd1498Szrj       srcb = expand_expr (src, NULL_RTX, Pmode, EXPAND_NORMAL);
4945*38fd1498Szrj       size = expand_expr (TYPE_SIZE_UNIT (targetm.fn_abi_va_list (cfun->decl)),
4946*38fd1498Szrj       		  NULL_RTX, VOIDmode, EXPAND_NORMAL);
4947*38fd1498Szrj 
4948*38fd1498Szrj       dstb = convert_memory_address (Pmode, dstb);
4949*38fd1498Szrj       srcb = convert_memory_address (Pmode, srcb);
4950*38fd1498Szrj 
4951*38fd1498Szrj       /* "Dereference" to BLKmode memories.  */
4952*38fd1498Szrj       dstb = gen_rtx_MEM (BLKmode, dstb);
4953*38fd1498Szrj       set_mem_alias_set (dstb, get_alias_set (TREE_TYPE (TREE_TYPE (dst))));
4954*38fd1498Szrj       set_mem_align (dstb, TYPE_ALIGN (targetm.fn_abi_va_list (cfun->decl)));
4955*38fd1498Szrj       srcb = gen_rtx_MEM (BLKmode, srcb);
4956*38fd1498Szrj       set_mem_alias_set (srcb, get_alias_set (TREE_TYPE (TREE_TYPE (src))));
4957*38fd1498Szrj       set_mem_align (srcb, TYPE_ALIGN (targetm.fn_abi_va_list (cfun->decl)));
4958*38fd1498Szrj 
4959*38fd1498Szrj       /* Copy.  */
4960*38fd1498Szrj       emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL);
4961*38fd1498Szrj     }
4962*38fd1498Szrj 
4963*38fd1498Szrj   return const0_rtx;
4964*38fd1498Szrj }
4965*38fd1498Szrj 
4966*38fd1498Szrj /* Expand a call to one of the builtin functions __builtin_frame_address or
4967*38fd1498Szrj    __builtin_return_address.  */
4968*38fd1498Szrj 
4969*38fd1498Szrj static rtx
expand_builtin_frame_address(tree fndecl,tree exp)4970*38fd1498Szrj expand_builtin_frame_address (tree fndecl, tree exp)
4971*38fd1498Szrj {
4972*38fd1498Szrj   /* The argument must be a nonnegative integer constant.
4973*38fd1498Szrj      It counts the number of frames to scan up the stack.
4974*38fd1498Szrj      The value is either the frame pointer value or the return
4975*38fd1498Szrj      address saved in that frame.  */
4976*38fd1498Szrj   if (call_expr_nargs (exp) == 0)
4977*38fd1498Szrj     /* Warning about missing arg was already issued.  */
4978*38fd1498Szrj     return const0_rtx;
4979*38fd1498Szrj   else if (! tree_fits_uhwi_p (CALL_EXPR_ARG (exp, 0)))
4980*38fd1498Szrj     {
4981*38fd1498Szrj       error ("invalid argument to %qD", fndecl);
4982*38fd1498Szrj       return const0_rtx;
4983*38fd1498Szrj     }
4984*38fd1498Szrj   else
4985*38fd1498Szrj     {
4986*38fd1498Szrj       /* Number of frames to scan up the stack.  */
4987*38fd1498Szrj       unsigned HOST_WIDE_INT count = tree_to_uhwi (CALL_EXPR_ARG (exp, 0));
4988*38fd1498Szrj 
4989*38fd1498Szrj       rtx tem = expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl), count);
4990*38fd1498Szrj 
4991*38fd1498Szrj       /* Some ports cannot access arbitrary stack frames.  */
4992*38fd1498Szrj       if (tem == NULL)
4993*38fd1498Szrj 	{
4994*38fd1498Szrj 	  warning (0, "unsupported argument to %qD", fndecl);
4995*38fd1498Szrj 	  return const0_rtx;
4996*38fd1498Szrj 	}
4997*38fd1498Szrj 
4998*38fd1498Szrj       if (count)
4999*38fd1498Szrj 	{
5000*38fd1498Szrj 	  /* Warn since no effort is made to ensure that any frame
5001*38fd1498Szrj 	     beyond the current one exists or can be safely reached.  */
5002*38fd1498Szrj 	  warning (OPT_Wframe_address, "calling %qD with "
5003*38fd1498Szrj 		   "a nonzero argument is unsafe", fndecl);
5004*38fd1498Szrj 	}
5005*38fd1498Szrj 
5006*38fd1498Szrj       /* For __builtin_frame_address, return what we've got.  */
5007*38fd1498Szrj       if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
5008*38fd1498Szrj 	return tem;
5009*38fd1498Szrj 
5010*38fd1498Szrj       if (!REG_P (tem)
5011*38fd1498Szrj 	  && ! CONSTANT_P (tem))
5012*38fd1498Szrj 	tem = copy_addr_to_reg (tem);
5013*38fd1498Szrj       return tem;
5014*38fd1498Szrj     }
5015*38fd1498Szrj }
5016*38fd1498Szrj 
5017*38fd1498Szrj /* Expand EXP, a call to the alloca builtin.  Return NULL_RTX if we
5018*38fd1498Szrj    failed and the caller should emit a normal call.  */
5019*38fd1498Szrj 
5020*38fd1498Szrj static rtx
expand_builtin_alloca(tree exp)5021*38fd1498Szrj expand_builtin_alloca (tree exp)
5022*38fd1498Szrj {
5023*38fd1498Szrj   rtx op0;
5024*38fd1498Szrj   rtx result;
5025*38fd1498Szrj   unsigned int align;
5026*38fd1498Szrj   tree fndecl = get_callee_fndecl (exp);
5027*38fd1498Szrj   HOST_WIDE_INT max_size;
5028*38fd1498Szrj   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
5029*38fd1498Szrj   bool alloca_for_var = CALL_ALLOCA_FOR_VAR_P (exp);
5030*38fd1498Szrj   bool valid_arglist
5031*38fd1498Szrj     = (fcode == BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX
5032*38fd1498Szrj        ? validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE,
5033*38fd1498Szrj 			   VOID_TYPE)
5034*38fd1498Szrj        : fcode == BUILT_IN_ALLOCA_WITH_ALIGN
5035*38fd1498Szrj 	 ? validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)
5036*38fd1498Szrj 	 : validate_arglist (exp, INTEGER_TYPE, VOID_TYPE));
5037*38fd1498Szrj 
5038*38fd1498Szrj   if (!valid_arglist)
5039*38fd1498Szrj     return NULL_RTX;
5040*38fd1498Szrj 
5041*38fd1498Szrj   if ((alloca_for_var && !warn_vla_limit)
5042*38fd1498Szrj       || (!alloca_for_var && !warn_alloca_limit))
5043*38fd1498Szrj     {
5044*38fd1498Szrj       /* -Walloca-larger-than and -Wvla-larger-than settings override
5045*38fd1498Szrj 	 the more general -Walloc-size-larger-than so unless either of
5046*38fd1498Szrj 	 the former options is specified check the alloca arguments for
5047*38fd1498Szrj 	 overflow.  */
5048*38fd1498Szrj       tree args[] = { CALL_EXPR_ARG (exp, 0), NULL_TREE };
5049*38fd1498Szrj       int idx[] = { 0, -1 };
5050*38fd1498Szrj       maybe_warn_alloc_args_overflow (fndecl, exp, args, idx);
5051*38fd1498Szrj     }
5052*38fd1498Szrj 
5053*38fd1498Szrj   /* Compute the argument.  */
5054*38fd1498Szrj   op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
5055*38fd1498Szrj 
5056*38fd1498Szrj   /* Compute the alignment.  */
5057*38fd1498Szrj   align = (fcode == BUILT_IN_ALLOCA
5058*38fd1498Szrj 	   ? BIGGEST_ALIGNMENT
5059*38fd1498Szrj 	   : TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 1)));
5060*38fd1498Szrj 
5061*38fd1498Szrj   /* Compute the maximum size.  */
5062*38fd1498Szrj   max_size = (fcode == BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX
5063*38fd1498Szrj               ? TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 2))
5064*38fd1498Szrj               : -1);
5065*38fd1498Szrj 
5066*38fd1498Szrj   /* Allocate the desired space.  If the allocation stems from the declaration
5067*38fd1498Szrj      of a variable-sized object, it cannot accumulate.  */
5068*38fd1498Szrj   result
5069*38fd1498Szrj     = allocate_dynamic_stack_space (op0, 0, align, max_size, alloca_for_var);
5070*38fd1498Szrj   result = convert_memory_address (ptr_mode, result);
5071*38fd1498Szrj 
5072*38fd1498Szrj   return result;
5073*38fd1498Szrj }
5074*38fd1498Szrj 
5075*38fd1498Szrj /* Emit a call to __asan_allocas_unpoison call in EXP.  Add to second argument
5076*38fd1498Szrj    of the call virtual_stack_dynamic_rtx - stack_pointer_rtx, which is the
5077*38fd1498Szrj    STACK_DYNAMIC_OFFSET value.  See motivation for this in comment to
5078*38fd1498Szrj    handle_builtin_stack_restore function.  */
5079*38fd1498Szrj 
5080*38fd1498Szrj static rtx
expand_asan_emit_allocas_unpoison(tree exp)5081*38fd1498Szrj expand_asan_emit_allocas_unpoison (tree exp)
5082*38fd1498Szrj {
5083*38fd1498Szrj   tree arg0 = CALL_EXPR_ARG (exp, 0);
5084*38fd1498Szrj   tree arg1 = CALL_EXPR_ARG (exp, 1);
5085*38fd1498Szrj   rtx top = expand_expr (arg0, NULL_RTX, ptr_mode, EXPAND_NORMAL);
5086*38fd1498Szrj   rtx bot = expand_expr (arg1, NULL_RTX, ptr_mode, EXPAND_NORMAL);
5087*38fd1498Szrj   rtx off = expand_simple_binop (Pmode, MINUS, virtual_stack_dynamic_rtx,
5088*38fd1498Szrj 				 stack_pointer_rtx, NULL_RTX, 0,
5089*38fd1498Szrj 				 OPTAB_LIB_WIDEN);
5090*38fd1498Szrj   off = convert_modes (ptr_mode, Pmode, off, 0);
5091*38fd1498Szrj   bot = expand_simple_binop (ptr_mode, PLUS, bot, off, NULL_RTX, 0,
5092*38fd1498Szrj 			     OPTAB_LIB_WIDEN);
5093*38fd1498Szrj   rtx ret = init_one_libfunc ("__asan_allocas_unpoison");
5094*38fd1498Szrj   ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode,
5095*38fd1498Szrj 				 top, ptr_mode, bot, ptr_mode);
5096*38fd1498Szrj   return ret;
5097*38fd1498Szrj }
5098*38fd1498Szrj 
5099*38fd1498Szrj /* Expand a call to bswap builtin in EXP.
5100*38fd1498Szrj    Return NULL_RTX if a normal call should be emitted rather than expanding the
5101*38fd1498Szrj    function in-line.  If convenient, the result should be placed in TARGET.
5102*38fd1498Szrj    SUBTARGET may be used as the target for computing one of EXP's operands.  */
5103*38fd1498Szrj 
5104*38fd1498Szrj static rtx
expand_builtin_bswap(machine_mode target_mode,tree exp,rtx target,rtx subtarget)5105*38fd1498Szrj expand_builtin_bswap (machine_mode target_mode, tree exp, rtx target,
5106*38fd1498Szrj 		      rtx subtarget)
5107*38fd1498Szrj {
5108*38fd1498Szrj   tree arg;
5109*38fd1498Szrj   rtx op0;
5110*38fd1498Szrj 
5111*38fd1498Szrj   if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE))
5112*38fd1498Szrj     return NULL_RTX;
5113*38fd1498Szrj 
5114*38fd1498Szrj   arg = CALL_EXPR_ARG (exp, 0);
5115*38fd1498Szrj   op0 = expand_expr (arg,
5116*38fd1498Szrj 		     subtarget && GET_MODE (subtarget) == target_mode
5117*38fd1498Szrj 		     ? subtarget : NULL_RTX,
5118*38fd1498Szrj 		     target_mode, EXPAND_NORMAL);
5119*38fd1498Szrj   if (GET_MODE (op0) != target_mode)
5120*38fd1498Szrj     op0 = convert_to_mode (target_mode, op0, 1);
5121*38fd1498Szrj 
5122*38fd1498Szrj   target = expand_unop (target_mode, bswap_optab, op0, target, 1);
5123*38fd1498Szrj 
5124*38fd1498Szrj   gcc_assert (target);
5125*38fd1498Szrj 
5126*38fd1498Szrj   return convert_to_mode (target_mode, target, 1);
5127*38fd1498Szrj }
5128*38fd1498Szrj 
5129*38fd1498Szrj /* Expand a call to a unary builtin in EXP.
5130*38fd1498Szrj    Return NULL_RTX if a normal call should be emitted rather than expanding the
5131*38fd1498Szrj    function in-line.  If convenient, the result should be placed in TARGET.
5132*38fd1498Szrj    SUBTARGET may be used as the target for computing one of EXP's operands.  */
5133*38fd1498Szrj 
5134*38fd1498Szrj static rtx
expand_builtin_unop(machine_mode target_mode,tree exp,rtx target,rtx subtarget,optab op_optab)5135*38fd1498Szrj expand_builtin_unop (machine_mode target_mode, tree exp, rtx target,
5136*38fd1498Szrj 		     rtx subtarget, optab op_optab)
5137*38fd1498Szrj {
5138*38fd1498Szrj   rtx op0;
5139*38fd1498Szrj 
5140*38fd1498Szrj   if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE))
5141*38fd1498Szrj     return NULL_RTX;
5142*38fd1498Szrj 
5143*38fd1498Szrj   /* Compute the argument.  */
5144*38fd1498Szrj   op0 = expand_expr (CALL_EXPR_ARG (exp, 0),
5145*38fd1498Szrj 		     (subtarget
5146*38fd1498Szrj 		      && (TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 0)))
5147*38fd1498Szrj 			  == GET_MODE (subtarget))) ? subtarget : NULL_RTX,
5148*38fd1498Szrj 		     VOIDmode, EXPAND_NORMAL);
5149*38fd1498Szrj   /* Compute op, into TARGET if possible.
5150*38fd1498Szrj      Set TARGET to wherever the result comes back.  */
5151*38fd1498Szrj   target = expand_unop (TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 0))),
5152*38fd1498Szrj 			op_optab, op0, target, op_optab != clrsb_optab);
5153*38fd1498Szrj   gcc_assert (target);
5154*38fd1498Szrj 
5155*38fd1498Szrj   return convert_to_mode (target_mode, target, 0);
5156*38fd1498Szrj }
5157*38fd1498Szrj 
5158*38fd1498Szrj /* Expand a call to __builtin_expect.  We just return our argument
5159*38fd1498Szrj    as the builtin_expect semantic should've been already executed by
5160*38fd1498Szrj    tree branch prediction pass. */
5161*38fd1498Szrj 
5162*38fd1498Szrj static rtx
expand_builtin_expect(tree exp,rtx target)5163*38fd1498Szrj expand_builtin_expect (tree exp, rtx target)
5164*38fd1498Szrj {
5165*38fd1498Szrj   tree arg;
5166*38fd1498Szrj 
5167*38fd1498Szrj   if (call_expr_nargs (exp) < 2)
5168*38fd1498Szrj     return const0_rtx;
5169*38fd1498Szrj   arg = CALL_EXPR_ARG (exp, 0);
5170*38fd1498Szrj 
5171*38fd1498Szrj   target = expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
5172*38fd1498Szrj   /* When guessing was done, the hints should be already stripped away.  */
5173*38fd1498Szrj   gcc_assert (!flag_guess_branch_prob
5174*38fd1498Szrj 	      || optimize == 0 || seen_error ());
5175*38fd1498Szrj   return target;
5176*38fd1498Szrj }
5177*38fd1498Szrj 
5178*38fd1498Szrj /* Expand a call to __builtin_assume_aligned.  We just return our first
5179*38fd1498Szrj    argument as the builtin_assume_aligned semantic should've been already
5180*38fd1498Szrj    executed by CCP.  */
5181*38fd1498Szrj 
5182*38fd1498Szrj static rtx
expand_builtin_assume_aligned(tree exp,rtx target)5183*38fd1498Szrj expand_builtin_assume_aligned (tree exp, rtx target)
5184*38fd1498Szrj {
5185*38fd1498Szrj   if (call_expr_nargs (exp) < 2)
5186*38fd1498Szrj     return const0_rtx;
5187*38fd1498Szrj   target = expand_expr (CALL_EXPR_ARG (exp, 0), target, VOIDmode,
5188*38fd1498Szrj 			EXPAND_NORMAL);
5189*38fd1498Szrj   gcc_assert (!TREE_SIDE_EFFECTS (CALL_EXPR_ARG (exp, 1))
5190*38fd1498Szrj 	      && (call_expr_nargs (exp) < 3
5191*38fd1498Szrj 		  || !TREE_SIDE_EFFECTS (CALL_EXPR_ARG (exp, 2))));
5192*38fd1498Szrj   return target;
5193*38fd1498Szrj }
5194*38fd1498Szrj 
5195*38fd1498Szrj void
expand_builtin_trap(void)5196*38fd1498Szrj expand_builtin_trap (void)
5197*38fd1498Szrj {
5198*38fd1498Szrj   if (targetm.have_trap ())
5199*38fd1498Szrj     {
5200*38fd1498Szrj       rtx_insn *insn = emit_insn (targetm.gen_trap ());
5201*38fd1498Szrj       /* For trap insns when not accumulating outgoing args force
5202*38fd1498Szrj 	 REG_ARGS_SIZE note to prevent crossjumping of calls with
5203*38fd1498Szrj 	 different args sizes.  */
5204*38fd1498Szrj       if (!ACCUMULATE_OUTGOING_ARGS)
5205*38fd1498Szrj 	add_args_size_note (insn, stack_pointer_delta);
5206*38fd1498Szrj     }
5207*38fd1498Szrj   else
5208*38fd1498Szrj     {
5209*38fd1498Szrj       tree fn = builtin_decl_implicit (BUILT_IN_ABORT);
5210*38fd1498Szrj       tree call_expr = build_call_expr (fn, 0);
5211*38fd1498Szrj       expand_call (call_expr, NULL_RTX, false);
5212*38fd1498Szrj     }
5213*38fd1498Szrj 
5214*38fd1498Szrj   emit_barrier ();
5215*38fd1498Szrj }
5216*38fd1498Szrj 
5217*38fd1498Szrj /* Expand a call to __builtin_unreachable.  We do nothing except emit
5218*38fd1498Szrj    a barrier saying that control flow will not pass here.
5219*38fd1498Szrj 
5220*38fd1498Szrj    It is the responsibility of the program being compiled to ensure
5221*38fd1498Szrj    that control flow does never reach __builtin_unreachable.  */
5222*38fd1498Szrj static void
expand_builtin_unreachable(void)5223*38fd1498Szrj expand_builtin_unreachable (void)
5224*38fd1498Szrj {
5225*38fd1498Szrj   emit_barrier ();
5226*38fd1498Szrj }
5227*38fd1498Szrj 
5228*38fd1498Szrj /* Expand EXP, a call to fabs, fabsf or fabsl.
5229*38fd1498Szrj    Return NULL_RTX if a normal call should be emitted rather than expanding
5230*38fd1498Szrj    the function inline.  If convenient, the result should be placed
5231*38fd1498Szrj    in TARGET.  SUBTARGET may be used as the target for computing
5232*38fd1498Szrj    the operand.  */
5233*38fd1498Szrj 
5234*38fd1498Szrj static rtx
expand_builtin_fabs(tree exp,rtx target,rtx subtarget)5235*38fd1498Szrj expand_builtin_fabs (tree exp, rtx target, rtx subtarget)
5236*38fd1498Szrj {
5237*38fd1498Szrj   machine_mode mode;
5238*38fd1498Szrj   tree arg;
5239*38fd1498Szrj   rtx op0;
5240*38fd1498Szrj 
5241*38fd1498Szrj   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
5242*38fd1498Szrj     return NULL_RTX;
5243*38fd1498Szrj 
5244*38fd1498Szrj   arg = CALL_EXPR_ARG (exp, 0);
5245*38fd1498Szrj   CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
5246*38fd1498Szrj   mode = TYPE_MODE (TREE_TYPE (arg));
5247*38fd1498Szrj   op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
5248*38fd1498Szrj   return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
5249*38fd1498Szrj }
5250*38fd1498Szrj 
5251*38fd1498Szrj /* Expand EXP, a call to copysign, copysignf, or copysignl.
5252*38fd1498Szrj    Return NULL is a normal call should be emitted rather than expanding the
5253*38fd1498Szrj    function inline.  If convenient, the result should be placed in TARGET.
5254*38fd1498Szrj    SUBTARGET may be used as the target for computing the operand.  */
5255*38fd1498Szrj 
5256*38fd1498Szrj static rtx
expand_builtin_copysign(tree exp,rtx target,rtx subtarget)5257*38fd1498Szrj expand_builtin_copysign (tree exp, rtx target, rtx subtarget)
5258*38fd1498Szrj {
5259*38fd1498Szrj   rtx op0, op1;
5260*38fd1498Szrj   tree arg;
5261*38fd1498Szrj 
5262*38fd1498Szrj   if (!validate_arglist (exp, REAL_TYPE, REAL_TYPE, VOID_TYPE))
5263*38fd1498Szrj     return NULL_RTX;
5264*38fd1498Szrj 
5265*38fd1498Szrj   arg = CALL_EXPR_ARG (exp, 0);
5266*38fd1498Szrj   op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
5267*38fd1498Szrj 
5268*38fd1498Szrj   arg = CALL_EXPR_ARG (exp, 1);
5269*38fd1498Szrj   op1 = expand_normal (arg);
5270*38fd1498Szrj 
5271*38fd1498Szrj   return expand_copysign (op0, op1, target);
5272*38fd1498Szrj }
5273*38fd1498Szrj 
5274*38fd1498Szrj /* Expand a call to __builtin___clear_cache.  */
5275*38fd1498Szrj 
5276*38fd1498Szrj static rtx
expand_builtin___clear_cache(tree exp)5277*38fd1498Szrj expand_builtin___clear_cache (tree exp)
5278*38fd1498Szrj {
5279*38fd1498Szrj   if (!targetm.code_for_clear_cache)
5280*38fd1498Szrj     {
5281*38fd1498Szrj #ifdef CLEAR_INSN_CACHE
5282*38fd1498Szrj       /* There is no "clear_cache" insn, and __clear_cache() in libgcc
5283*38fd1498Szrj 	 does something.  Just do the default expansion to a call to
5284*38fd1498Szrj 	 __clear_cache().  */
5285*38fd1498Szrj       return NULL_RTX;
5286*38fd1498Szrj #else
5287*38fd1498Szrj       /* There is no "clear_cache" insn, and __clear_cache() in libgcc
5288*38fd1498Szrj 	 does nothing.  There is no need to call it.  Do nothing.  */
5289*38fd1498Szrj       return const0_rtx;
5290*38fd1498Szrj #endif /* CLEAR_INSN_CACHE */
5291*38fd1498Szrj     }
5292*38fd1498Szrj 
5293*38fd1498Szrj   /* We have a "clear_cache" insn, and it will handle everything.  */
5294*38fd1498Szrj   tree begin, end;
5295*38fd1498Szrj   rtx begin_rtx, end_rtx;
5296*38fd1498Szrj 
5297*38fd1498Szrj   /* We must not expand to a library call.  If we did, any
5298*38fd1498Szrj      fallback library function in libgcc that might contain a call to
5299*38fd1498Szrj      __builtin___clear_cache() would recurse infinitely.  */
5300*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
5301*38fd1498Szrj     {
5302*38fd1498Szrj       error ("both arguments to %<__builtin___clear_cache%> must be pointers");
5303*38fd1498Szrj       return const0_rtx;
5304*38fd1498Szrj     }
5305*38fd1498Szrj 
5306*38fd1498Szrj   if (targetm.have_clear_cache ())
5307*38fd1498Szrj     {
5308*38fd1498Szrj       struct expand_operand ops[2];
5309*38fd1498Szrj 
5310*38fd1498Szrj       begin = CALL_EXPR_ARG (exp, 0);
5311*38fd1498Szrj       begin_rtx = expand_expr (begin, NULL_RTX, Pmode, EXPAND_NORMAL);
5312*38fd1498Szrj 
5313*38fd1498Szrj       end = CALL_EXPR_ARG (exp, 1);
5314*38fd1498Szrj       end_rtx = expand_expr (end, NULL_RTX, Pmode, EXPAND_NORMAL);
5315*38fd1498Szrj 
5316*38fd1498Szrj       create_address_operand (&ops[0], begin_rtx);
5317*38fd1498Szrj       create_address_operand (&ops[1], end_rtx);
5318*38fd1498Szrj       if (maybe_expand_insn (targetm.code_for_clear_cache, 2, ops))
5319*38fd1498Szrj 	return const0_rtx;
5320*38fd1498Szrj     }
5321*38fd1498Szrj   return const0_rtx;
5322*38fd1498Szrj }
5323*38fd1498Szrj 
5324*38fd1498Szrj /* Given a trampoline address, make sure it satisfies TRAMPOLINE_ALIGNMENT.  */
5325*38fd1498Szrj 
5326*38fd1498Szrj static rtx
round_trampoline_addr(rtx tramp)5327*38fd1498Szrj round_trampoline_addr (rtx tramp)
5328*38fd1498Szrj {
5329*38fd1498Szrj   rtx temp, addend, mask;
5330*38fd1498Szrj 
5331*38fd1498Szrj   /* If we don't need too much alignment, we'll have been guaranteed
5332*38fd1498Szrj      proper alignment by get_trampoline_type.  */
5333*38fd1498Szrj   if (TRAMPOLINE_ALIGNMENT <= STACK_BOUNDARY)
5334*38fd1498Szrj     return tramp;
5335*38fd1498Szrj 
5336*38fd1498Szrj   /* Round address up to desired boundary.  */
5337*38fd1498Szrj   temp = gen_reg_rtx (Pmode);
5338*38fd1498Szrj   addend = gen_int_mode (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1, Pmode);
5339*38fd1498Szrj   mask = gen_int_mode (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT, Pmode);
5340*38fd1498Szrj 
5341*38fd1498Szrj   temp  = expand_simple_binop (Pmode, PLUS, tramp, addend,
5342*38fd1498Szrj 			       temp, 0, OPTAB_LIB_WIDEN);
5343*38fd1498Szrj   tramp = expand_simple_binop (Pmode, AND, temp, mask,
5344*38fd1498Szrj 			       temp, 0, OPTAB_LIB_WIDEN);
5345*38fd1498Szrj 
5346*38fd1498Szrj   return tramp;
5347*38fd1498Szrj }
5348*38fd1498Szrj 
5349*38fd1498Szrj static rtx
expand_builtin_init_trampoline(tree exp,bool onstack)5350*38fd1498Szrj expand_builtin_init_trampoline (tree exp, bool onstack)
5351*38fd1498Szrj {
5352*38fd1498Szrj   tree t_tramp, t_func, t_chain;
5353*38fd1498Szrj   rtx m_tramp, r_tramp, r_chain, tmp;
5354*38fd1498Szrj 
5355*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE,
5356*38fd1498Szrj 			 POINTER_TYPE, VOID_TYPE))
5357*38fd1498Szrj     return NULL_RTX;
5358*38fd1498Szrj 
5359*38fd1498Szrj   t_tramp = CALL_EXPR_ARG (exp, 0);
5360*38fd1498Szrj   t_func = CALL_EXPR_ARG (exp, 1);
5361*38fd1498Szrj   t_chain = CALL_EXPR_ARG (exp, 2);
5362*38fd1498Szrj 
5363*38fd1498Szrj   r_tramp = expand_normal (t_tramp);
5364*38fd1498Szrj   m_tramp = gen_rtx_MEM (BLKmode, r_tramp);
5365*38fd1498Szrj   MEM_NOTRAP_P (m_tramp) = 1;
5366*38fd1498Szrj 
5367*38fd1498Szrj   /* If ONSTACK, the TRAMP argument should be the address of a field
5368*38fd1498Szrj      within the local function's FRAME decl.  Either way, let's see if
5369*38fd1498Szrj      we can fill in the MEM_ATTRs for this memory.  */
5370*38fd1498Szrj   if (TREE_CODE (t_tramp) == ADDR_EXPR)
5371*38fd1498Szrj     set_mem_attributes (m_tramp, TREE_OPERAND (t_tramp, 0), true);
5372*38fd1498Szrj 
5373*38fd1498Szrj   /* Creator of a heap trampoline is responsible for making sure the
5374*38fd1498Szrj      address is aligned to at least STACK_BOUNDARY.  Normally malloc
5375*38fd1498Szrj      will ensure this anyhow.  */
5376*38fd1498Szrj   tmp = round_trampoline_addr (r_tramp);
5377*38fd1498Szrj   if (tmp != r_tramp)
5378*38fd1498Szrj     {
5379*38fd1498Szrj       m_tramp = change_address (m_tramp, BLKmode, tmp);
5380*38fd1498Szrj       set_mem_align (m_tramp, TRAMPOLINE_ALIGNMENT);
5381*38fd1498Szrj       set_mem_size (m_tramp, TRAMPOLINE_SIZE);
5382*38fd1498Szrj     }
5383*38fd1498Szrj 
5384*38fd1498Szrj   /* The FUNC argument should be the address of the nested function.
5385*38fd1498Szrj      Extract the actual function decl to pass to the hook.  */
5386*38fd1498Szrj   gcc_assert (TREE_CODE (t_func) == ADDR_EXPR);
5387*38fd1498Szrj   t_func = TREE_OPERAND (t_func, 0);
5388*38fd1498Szrj   gcc_assert (TREE_CODE (t_func) == FUNCTION_DECL);
5389*38fd1498Szrj 
5390*38fd1498Szrj   r_chain = expand_normal (t_chain);
5391*38fd1498Szrj 
5392*38fd1498Szrj   /* Generate insns to initialize the trampoline.  */
5393*38fd1498Szrj   targetm.calls.trampoline_init (m_tramp, t_func, r_chain);
5394*38fd1498Szrj 
5395*38fd1498Szrj   if (onstack)
5396*38fd1498Szrj     {
5397*38fd1498Szrj       trampolines_created = 1;
5398*38fd1498Szrj 
5399*38fd1498Szrj       if (targetm.calls.custom_function_descriptors != 0)
5400*38fd1498Szrj 	warning_at (DECL_SOURCE_LOCATION (t_func), OPT_Wtrampolines,
5401*38fd1498Szrj 		    "trampoline generated for nested function %qD", t_func);
5402*38fd1498Szrj     }
5403*38fd1498Szrj 
5404*38fd1498Szrj   return const0_rtx;
5405*38fd1498Szrj }
5406*38fd1498Szrj 
5407*38fd1498Szrj static rtx
expand_builtin_adjust_trampoline(tree exp)5408*38fd1498Szrj expand_builtin_adjust_trampoline (tree exp)
5409*38fd1498Szrj {
5410*38fd1498Szrj   rtx tramp;
5411*38fd1498Szrj 
5412*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
5413*38fd1498Szrj     return NULL_RTX;
5414*38fd1498Szrj 
5415*38fd1498Szrj   tramp = expand_normal (CALL_EXPR_ARG (exp, 0));
5416*38fd1498Szrj   tramp = round_trampoline_addr (tramp);
5417*38fd1498Szrj   if (targetm.calls.trampoline_adjust_address)
5418*38fd1498Szrj     tramp = targetm.calls.trampoline_adjust_address (tramp);
5419*38fd1498Szrj 
5420*38fd1498Szrj   return tramp;
5421*38fd1498Szrj }
5422*38fd1498Szrj 
5423*38fd1498Szrj /* Expand a call to the builtin descriptor initialization routine.
5424*38fd1498Szrj    A descriptor is made up of a couple of pointers to the static
5425*38fd1498Szrj    chain and the code entry in this order.  */
5426*38fd1498Szrj 
5427*38fd1498Szrj static rtx
expand_builtin_init_descriptor(tree exp)5428*38fd1498Szrj expand_builtin_init_descriptor (tree exp)
5429*38fd1498Szrj {
5430*38fd1498Szrj   tree t_descr, t_func, t_chain;
5431*38fd1498Szrj   rtx m_descr, r_descr, r_func, r_chain;
5432*38fd1498Szrj 
5433*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, POINTER_TYPE,
5434*38fd1498Szrj 			 VOID_TYPE))
5435*38fd1498Szrj     return NULL_RTX;
5436*38fd1498Szrj 
5437*38fd1498Szrj   t_descr = CALL_EXPR_ARG (exp, 0);
5438*38fd1498Szrj   t_func = CALL_EXPR_ARG (exp, 1);
5439*38fd1498Szrj   t_chain = CALL_EXPR_ARG (exp, 2);
5440*38fd1498Szrj 
5441*38fd1498Szrj   r_descr = expand_normal (t_descr);
5442*38fd1498Szrj   m_descr = gen_rtx_MEM (BLKmode, r_descr);
5443*38fd1498Szrj   MEM_NOTRAP_P (m_descr) = 1;
5444*38fd1498Szrj 
5445*38fd1498Szrj   r_func = expand_normal (t_func);
5446*38fd1498Szrj   r_chain = expand_normal (t_chain);
5447*38fd1498Szrj 
5448*38fd1498Szrj   /* Generate insns to initialize the descriptor.  */
5449*38fd1498Szrj   emit_move_insn (adjust_address_nv (m_descr, ptr_mode, 0), r_chain);
5450*38fd1498Szrj   emit_move_insn (adjust_address_nv (m_descr, ptr_mode,
5451*38fd1498Szrj 				     POINTER_SIZE / BITS_PER_UNIT), r_func);
5452*38fd1498Szrj 
5453*38fd1498Szrj   return const0_rtx;
5454*38fd1498Szrj }
5455*38fd1498Szrj 
5456*38fd1498Szrj /* Expand a call to the builtin descriptor adjustment routine.  */
5457*38fd1498Szrj 
5458*38fd1498Szrj static rtx
expand_builtin_adjust_descriptor(tree exp)5459*38fd1498Szrj expand_builtin_adjust_descriptor (tree exp)
5460*38fd1498Szrj {
5461*38fd1498Szrj   rtx tramp;
5462*38fd1498Szrj 
5463*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
5464*38fd1498Szrj     return NULL_RTX;
5465*38fd1498Szrj 
5466*38fd1498Szrj   tramp = expand_normal (CALL_EXPR_ARG (exp, 0));
5467*38fd1498Szrj 
5468*38fd1498Szrj   /* Unalign the descriptor to allow runtime identification.  */
5469*38fd1498Szrj   tramp = plus_constant (ptr_mode, tramp,
5470*38fd1498Szrj 			 targetm.calls.custom_function_descriptors);
5471*38fd1498Szrj 
5472*38fd1498Szrj   return force_operand (tramp, NULL_RTX);
5473*38fd1498Szrj }
5474*38fd1498Szrj 
5475*38fd1498Szrj /* Expand the call EXP to the built-in signbit, signbitf or signbitl
5476*38fd1498Szrj    function.  The function first checks whether the back end provides
5477*38fd1498Szrj    an insn to implement signbit for the respective mode.  If not, it
5478*38fd1498Szrj    checks whether the floating point format of the value is such that
5479*38fd1498Szrj    the sign bit can be extracted.  If that is not the case, error out.
5480*38fd1498Szrj    EXP is the expression that is a call to the builtin function; if
5481*38fd1498Szrj    convenient, the result should be placed in TARGET.  */
5482*38fd1498Szrj static rtx
expand_builtin_signbit(tree exp,rtx target)5483*38fd1498Szrj expand_builtin_signbit (tree exp, rtx target)
5484*38fd1498Szrj {
5485*38fd1498Szrj   const struct real_format *fmt;
5486*38fd1498Szrj   scalar_float_mode fmode;
5487*38fd1498Szrj   scalar_int_mode rmode, imode;
5488*38fd1498Szrj   tree arg;
5489*38fd1498Szrj   int word, bitpos;
5490*38fd1498Szrj   enum insn_code icode;
5491*38fd1498Szrj   rtx temp;
5492*38fd1498Szrj   location_t loc = EXPR_LOCATION (exp);
5493*38fd1498Szrj 
5494*38fd1498Szrj   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
5495*38fd1498Szrj     return NULL_RTX;
5496*38fd1498Szrj 
5497*38fd1498Szrj   arg = CALL_EXPR_ARG (exp, 0);
5498*38fd1498Szrj   fmode = SCALAR_FLOAT_TYPE_MODE (TREE_TYPE (arg));
5499*38fd1498Szrj   rmode = SCALAR_INT_TYPE_MODE (TREE_TYPE (exp));
5500*38fd1498Szrj   fmt = REAL_MODE_FORMAT (fmode);
5501*38fd1498Szrj 
5502*38fd1498Szrj   arg = builtin_save_expr (arg);
5503*38fd1498Szrj 
5504*38fd1498Szrj   /* Expand the argument yielding a RTX expression. */
5505*38fd1498Szrj   temp = expand_normal (arg);
5506*38fd1498Szrj 
5507*38fd1498Szrj   /* Check if the back end provides an insn that handles signbit for the
5508*38fd1498Szrj      argument's mode. */
5509*38fd1498Szrj   icode = optab_handler (signbit_optab, fmode);
5510*38fd1498Szrj   if (icode != CODE_FOR_nothing)
5511*38fd1498Szrj     {
5512*38fd1498Szrj       rtx_insn *last = get_last_insn ();
5513*38fd1498Szrj       target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
5514*38fd1498Szrj       if (maybe_emit_unop_insn (icode, target, temp, UNKNOWN))
5515*38fd1498Szrj 	return target;
5516*38fd1498Szrj       delete_insns_since (last);
5517*38fd1498Szrj     }
5518*38fd1498Szrj 
5519*38fd1498Szrj   /* For floating point formats without a sign bit, implement signbit
5520*38fd1498Szrj      as "ARG < 0.0".  */
5521*38fd1498Szrj   bitpos = fmt->signbit_ro;
5522*38fd1498Szrj   if (bitpos < 0)
5523*38fd1498Szrj   {
5524*38fd1498Szrj     /* But we can't do this if the format supports signed zero.  */
5525*38fd1498Szrj     gcc_assert (!fmt->has_signed_zero || !HONOR_SIGNED_ZEROS (fmode));
5526*38fd1498Szrj 
5527*38fd1498Szrj     arg = fold_build2_loc (loc, LT_EXPR, TREE_TYPE (exp), arg,
5528*38fd1498Szrj 		       build_real (TREE_TYPE (arg), dconst0));
5529*38fd1498Szrj     return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
5530*38fd1498Szrj   }
5531*38fd1498Szrj 
5532*38fd1498Szrj   if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
5533*38fd1498Szrj     {
5534*38fd1498Szrj       imode = int_mode_for_mode (fmode).require ();
5535*38fd1498Szrj       temp = gen_lowpart (imode, temp);
5536*38fd1498Szrj     }
5537*38fd1498Szrj   else
5538*38fd1498Szrj     {
5539*38fd1498Szrj       imode = word_mode;
5540*38fd1498Szrj       /* Handle targets with different FP word orders.  */
5541*38fd1498Szrj       if (FLOAT_WORDS_BIG_ENDIAN)
5542*38fd1498Szrj 	word = (GET_MODE_BITSIZE (fmode) - bitpos) / BITS_PER_WORD;
5543*38fd1498Szrj       else
5544*38fd1498Szrj 	word = bitpos / BITS_PER_WORD;
5545*38fd1498Szrj       temp = operand_subword_force (temp, word, fmode);
5546*38fd1498Szrj       bitpos = bitpos % BITS_PER_WORD;
5547*38fd1498Szrj     }
5548*38fd1498Szrj 
5549*38fd1498Szrj   /* Force the intermediate word_mode (or narrower) result into a
5550*38fd1498Szrj      register.  This avoids attempting to create paradoxical SUBREGs
5551*38fd1498Szrj      of floating point modes below.  */
5552*38fd1498Szrj   temp = force_reg (imode, temp);
5553*38fd1498Szrj 
5554*38fd1498Szrj   /* If the bitpos is within the "result mode" lowpart, the operation
5555*38fd1498Szrj      can be implement with a single bitwise AND.  Otherwise, we need
5556*38fd1498Szrj      a right shift and an AND.  */
5557*38fd1498Szrj 
5558*38fd1498Szrj   if (bitpos < GET_MODE_BITSIZE (rmode))
5559*38fd1498Szrj     {
5560*38fd1498Szrj       wide_int mask = wi::set_bit_in_zero (bitpos, GET_MODE_PRECISION (rmode));
5561*38fd1498Szrj 
5562*38fd1498Szrj       if (GET_MODE_SIZE (imode) > GET_MODE_SIZE (rmode))
5563*38fd1498Szrj 	temp = gen_lowpart (rmode, temp);
5564*38fd1498Szrj       temp = expand_binop (rmode, and_optab, temp,
5565*38fd1498Szrj 			   immed_wide_int_const (mask, rmode),
5566*38fd1498Szrj 			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
5567*38fd1498Szrj     }
5568*38fd1498Szrj   else
5569*38fd1498Szrj     {
5570*38fd1498Szrj       /* Perform a logical right shift to place the signbit in the least
5571*38fd1498Szrj 	 significant bit, then truncate the result to the desired mode
5572*38fd1498Szrj 	 and mask just this bit.  */
5573*38fd1498Szrj       temp = expand_shift (RSHIFT_EXPR, imode, temp, bitpos, NULL_RTX, 1);
5574*38fd1498Szrj       temp = gen_lowpart (rmode, temp);
5575*38fd1498Szrj       temp = expand_binop (rmode, and_optab, temp, const1_rtx,
5576*38fd1498Szrj 			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
5577*38fd1498Szrj     }
5578*38fd1498Szrj 
5579*38fd1498Szrj   return temp;
5580*38fd1498Szrj }
5581*38fd1498Szrj 
5582*38fd1498Szrj /* Expand fork or exec calls.  TARGET is the desired target of the
5583*38fd1498Szrj    call.  EXP is the call. FN is the
5584*38fd1498Szrj    identificator of the actual function.  IGNORE is nonzero if the
5585*38fd1498Szrj    value is to be ignored.  */
5586*38fd1498Szrj 
5587*38fd1498Szrj static rtx
expand_builtin_fork_or_exec(tree fn,tree exp,rtx target,int ignore)5588*38fd1498Szrj expand_builtin_fork_or_exec (tree fn, tree exp, rtx target, int ignore)
5589*38fd1498Szrj {
5590*38fd1498Szrj   tree id, decl;
5591*38fd1498Szrj   tree call;
5592*38fd1498Szrj 
5593*38fd1498Szrj   /* If we are not profiling, just call the function.  */
5594*38fd1498Szrj   if (!profile_arc_flag)
5595*38fd1498Szrj     return NULL_RTX;
5596*38fd1498Szrj 
5597*38fd1498Szrj   /* Otherwise call the wrapper.  This should be equivalent for the rest of
5598*38fd1498Szrj      compiler, so the code does not diverge, and the wrapper may run the
5599*38fd1498Szrj      code necessary for keeping the profiling sane.  */
5600*38fd1498Szrj 
5601*38fd1498Szrj   switch (DECL_FUNCTION_CODE (fn))
5602*38fd1498Szrj     {
5603*38fd1498Szrj     case BUILT_IN_FORK:
5604*38fd1498Szrj       id = get_identifier ("__gcov_fork");
5605*38fd1498Szrj       break;
5606*38fd1498Szrj 
5607*38fd1498Szrj     case BUILT_IN_EXECL:
5608*38fd1498Szrj       id = get_identifier ("__gcov_execl");
5609*38fd1498Szrj       break;
5610*38fd1498Szrj 
5611*38fd1498Szrj     case BUILT_IN_EXECV:
5612*38fd1498Szrj       id = get_identifier ("__gcov_execv");
5613*38fd1498Szrj       break;
5614*38fd1498Szrj 
5615*38fd1498Szrj     case BUILT_IN_EXECLP:
5616*38fd1498Szrj       id = get_identifier ("__gcov_execlp");
5617*38fd1498Szrj       break;
5618*38fd1498Szrj 
5619*38fd1498Szrj     case BUILT_IN_EXECLE:
5620*38fd1498Szrj       id = get_identifier ("__gcov_execle");
5621*38fd1498Szrj       break;
5622*38fd1498Szrj 
5623*38fd1498Szrj     case BUILT_IN_EXECVP:
5624*38fd1498Szrj       id = get_identifier ("__gcov_execvp");
5625*38fd1498Szrj       break;
5626*38fd1498Szrj 
5627*38fd1498Szrj     case BUILT_IN_EXECVE:
5628*38fd1498Szrj       id = get_identifier ("__gcov_execve");
5629*38fd1498Szrj       break;
5630*38fd1498Szrj 
5631*38fd1498Szrj     default:
5632*38fd1498Szrj       gcc_unreachable ();
5633*38fd1498Szrj     }
5634*38fd1498Szrj 
5635*38fd1498Szrj   decl = build_decl (DECL_SOURCE_LOCATION (fn),
5636*38fd1498Szrj 		     FUNCTION_DECL, id, TREE_TYPE (fn));
5637*38fd1498Szrj   DECL_EXTERNAL (decl) = 1;
5638*38fd1498Szrj   TREE_PUBLIC (decl) = 1;
5639*38fd1498Szrj   DECL_ARTIFICIAL (decl) = 1;
5640*38fd1498Szrj   TREE_NOTHROW (decl) = 1;
5641*38fd1498Szrj   DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
5642*38fd1498Szrj   DECL_VISIBILITY_SPECIFIED (decl) = 1;
5643*38fd1498Szrj   call = rewrite_call_expr (EXPR_LOCATION (exp), exp, 0, decl, 0);
5644*38fd1498Szrj   return expand_call (call, target, ignore);
5645*38fd1498Szrj  }
5646*38fd1498Szrj 
5647*38fd1498Szrj 
5648*38fd1498Szrj 
5649*38fd1498Szrj /* Reconstitute a mode for a __sync intrinsic operation.  Since the type of
5650*38fd1498Szrj    the pointer in these functions is void*, the tree optimizers may remove
5651*38fd1498Szrj    casts.  The mode computed in expand_builtin isn't reliable either, due
5652*38fd1498Szrj    to __sync_bool_compare_and_swap.
5653*38fd1498Szrj 
5654*38fd1498Szrj    FCODE_DIFF should be fcode - base, where base is the FOO_1 code for the
5655*38fd1498Szrj    group of builtins.  This gives us log2 of the mode size.  */
5656*38fd1498Szrj 
5657*38fd1498Szrj static inline machine_mode
get_builtin_sync_mode(int fcode_diff)5658*38fd1498Szrj get_builtin_sync_mode (int fcode_diff)
5659*38fd1498Szrj {
5660*38fd1498Szrj   /* The size is not negotiable, so ask not to get BLKmode in return
5661*38fd1498Szrj      if the target indicates that a smaller size would be better.  */
5662*38fd1498Szrj   return int_mode_for_size (BITS_PER_UNIT << fcode_diff, 0).require ();
5663*38fd1498Szrj }
5664*38fd1498Szrj 
5665*38fd1498Szrj /* Expand the memory expression LOC and return the appropriate memory operand
5666*38fd1498Szrj    for the builtin_sync operations.  */
5667*38fd1498Szrj 
5668*38fd1498Szrj static rtx
get_builtin_sync_mem(tree loc,machine_mode mode)5669*38fd1498Szrj get_builtin_sync_mem (tree loc, machine_mode mode)
5670*38fd1498Szrj {
5671*38fd1498Szrj   rtx addr, mem;
5672*38fd1498Szrj 
5673*38fd1498Szrj   addr = expand_expr (loc, NULL_RTX, ptr_mode, EXPAND_SUM);
5674*38fd1498Szrj   addr = convert_memory_address (Pmode, addr);
5675*38fd1498Szrj 
5676*38fd1498Szrj   /* Note that we explicitly do not want any alias information for this
5677*38fd1498Szrj      memory, so that we kill all other live memories.  Otherwise we don't
5678*38fd1498Szrj      satisfy the full barrier semantics of the intrinsic.  */
5679*38fd1498Szrj   mem = validize_mem (gen_rtx_MEM (mode, addr));
5680*38fd1498Szrj 
5681*38fd1498Szrj   /* The alignment needs to be at least according to that of the mode.  */
5682*38fd1498Szrj   set_mem_align (mem, MAX (GET_MODE_ALIGNMENT (mode),
5683*38fd1498Szrj 			   get_pointer_alignment (loc)));
5684*38fd1498Szrj   set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER);
5685*38fd1498Szrj   MEM_VOLATILE_P (mem) = 1;
5686*38fd1498Szrj 
5687*38fd1498Szrj   return mem;
5688*38fd1498Szrj }
5689*38fd1498Szrj 
5690*38fd1498Szrj /* Make sure an argument is in the right mode.
5691*38fd1498Szrj    EXP is the tree argument.
5692*38fd1498Szrj    MODE is the mode it should be in.  */
5693*38fd1498Szrj 
5694*38fd1498Szrj static rtx
expand_expr_force_mode(tree exp,machine_mode mode)5695*38fd1498Szrj expand_expr_force_mode (tree exp, machine_mode mode)
5696*38fd1498Szrj {
5697*38fd1498Szrj   rtx val;
5698*38fd1498Szrj   machine_mode old_mode;
5699*38fd1498Szrj 
5700*38fd1498Szrj   val = expand_expr (exp, NULL_RTX, mode, EXPAND_NORMAL);
5701*38fd1498Szrj   /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
5702*38fd1498Szrj      of CONST_INTs, where we know the old_mode only from the call argument.  */
5703*38fd1498Szrj 
5704*38fd1498Szrj   old_mode = GET_MODE (val);
5705*38fd1498Szrj   if (old_mode == VOIDmode)
5706*38fd1498Szrj     old_mode = TYPE_MODE (TREE_TYPE (exp));
5707*38fd1498Szrj   val = convert_modes (mode, old_mode, val, 1);
5708*38fd1498Szrj   return val;
5709*38fd1498Szrj }
5710*38fd1498Szrj 
5711*38fd1498Szrj 
5712*38fd1498Szrj /* Expand the __sync_xxx_and_fetch and __sync_fetch_and_xxx intrinsics.
5713*38fd1498Szrj    EXP is the CALL_EXPR.  CODE is the rtx code
5714*38fd1498Szrj    that corresponds to the arithmetic or logical operation from the name;
5715*38fd1498Szrj    an exception here is that NOT actually means NAND.  TARGET is an optional
5716*38fd1498Szrj    place for us to store the results; AFTER is true if this is the
5717*38fd1498Szrj    fetch_and_xxx form.  */
5718*38fd1498Szrj 
5719*38fd1498Szrj static rtx
expand_builtin_sync_operation(machine_mode mode,tree exp,enum rtx_code code,bool after,rtx target)5720*38fd1498Szrj expand_builtin_sync_operation (machine_mode mode, tree exp,
5721*38fd1498Szrj 			       enum rtx_code code, bool after,
5722*38fd1498Szrj 			       rtx target)
5723*38fd1498Szrj {
5724*38fd1498Szrj   rtx val, mem;
5725*38fd1498Szrj   location_t loc = EXPR_LOCATION (exp);
5726*38fd1498Szrj 
5727*38fd1498Szrj   if (code == NOT && warn_sync_nand)
5728*38fd1498Szrj     {
5729*38fd1498Szrj       tree fndecl = get_callee_fndecl (exp);
5730*38fd1498Szrj       enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
5731*38fd1498Szrj 
5732*38fd1498Szrj       static bool warned_f_a_n, warned_n_a_f;
5733*38fd1498Szrj 
5734*38fd1498Szrj       switch (fcode)
5735*38fd1498Szrj 	{
5736*38fd1498Szrj 	case BUILT_IN_SYNC_FETCH_AND_NAND_1:
5737*38fd1498Szrj 	case BUILT_IN_SYNC_FETCH_AND_NAND_2:
5738*38fd1498Szrj 	case BUILT_IN_SYNC_FETCH_AND_NAND_4:
5739*38fd1498Szrj 	case BUILT_IN_SYNC_FETCH_AND_NAND_8:
5740*38fd1498Szrj 	case BUILT_IN_SYNC_FETCH_AND_NAND_16:
5741*38fd1498Szrj 	  if (warned_f_a_n)
5742*38fd1498Szrj 	    break;
5743*38fd1498Szrj 
5744*38fd1498Szrj 	  fndecl = builtin_decl_implicit (BUILT_IN_SYNC_FETCH_AND_NAND_N);
5745*38fd1498Szrj 	  inform (loc, "%qD changed semantics in GCC 4.4", fndecl);
5746*38fd1498Szrj 	  warned_f_a_n = true;
5747*38fd1498Szrj 	  break;
5748*38fd1498Szrj 
5749*38fd1498Szrj 	case BUILT_IN_SYNC_NAND_AND_FETCH_1:
5750*38fd1498Szrj 	case BUILT_IN_SYNC_NAND_AND_FETCH_2:
5751*38fd1498Szrj 	case BUILT_IN_SYNC_NAND_AND_FETCH_4:
5752*38fd1498Szrj 	case BUILT_IN_SYNC_NAND_AND_FETCH_8:
5753*38fd1498Szrj 	case BUILT_IN_SYNC_NAND_AND_FETCH_16:
5754*38fd1498Szrj 	  if (warned_n_a_f)
5755*38fd1498Szrj 	    break;
5756*38fd1498Szrj 
5757*38fd1498Szrj 	 fndecl = builtin_decl_implicit (BUILT_IN_SYNC_NAND_AND_FETCH_N);
5758*38fd1498Szrj 	  inform (loc, "%qD changed semantics in GCC 4.4", fndecl);
5759*38fd1498Szrj 	  warned_n_a_f = true;
5760*38fd1498Szrj 	  break;
5761*38fd1498Szrj 
5762*38fd1498Szrj 	default:
5763*38fd1498Szrj 	  gcc_unreachable ();
5764*38fd1498Szrj 	}
5765*38fd1498Szrj     }
5766*38fd1498Szrj 
5767*38fd1498Szrj   /* Expand the operands.  */
5768*38fd1498Szrj   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5769*38fd1498Szrj   val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
5770*38fd1498Szrj 
5771*38fd1498Szrj   return expand_atomic_fetch_op (target, mem, val, code, MEMMODEL_SYNC_SEQ_CST,
5772*38fd1498Szrj 				 after);
5773*38fd1498Szrj }
5774*38fd1498Szrj 
5775*38fd1498Szrj /* Expand the __sync_val_compare_and_swap and __sync_bool_compare_and_swap
5776*38fd1498Szrj    intrinsics. EXP is the CALL_EXPR.  IS_BOOL is
5777*38fd1498Szrj    true if this is the boolean form.  TARGET is a place for us to store the
5778*38fd1498Szrj    results; this is NOT optional if IS_BOOL is true.  */
5779*38fd1498Szrj 
5780*38fd1498Szrj static rtx
expand_builtin_compare_and_swap(machine_mode mode,tree exp,bool is_bool,rtx target)5781*38fd1498Szrj expand_builtin_compare_and_swap (machine_mode mode, tree exp,
5782*38fd1498Szrj 				 bool is_bool, rtx target)
5783*38fd1498Szrj {
5784*38fd1498Szrj   rtx old_val, new_val, mem;
5785*38fd1498Szrj   rtx *pbool, *poval;
5786*38fd1498Szrj 
5787*38fd1498Szrj   /* Expand the operands.  */
5788*38fd1498Szrj   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5789*38fd1498Szrj   old_val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
5790*38fd1498Szrj   new_val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 2), mode);
5791*38fd1498Szrj 
5792*38fd1498Szrj   pbool = poval = NULL;
5793*38fd1498Szrj   if (target != const0_rtx)
5794*38fd1498Szrj     {
5795*38fd1498Szrj       if (is_bool)
5796*38fd1498Szrj 	pbool = &target;
5797*38fd1498Szrj       else
5798*38fd1498Szrj 	poval = &target;
5799*38fd1498Szrj     }
5800*38fd1498Szrj   if (!expand_atomic_compare_and_swap (pbool, poval, mem, old_val, new_val,
5801*38fd1498Szrj 				       false, MEMMODEL_SYNC_SEQ_CST,
5802*38fd1498Szrj 				       MEMMODEL_SYNC_SEQ_CST))
5803*38fd1498Szrj     return NULL_RTX;
5804*38fd1498Szrj 
5805*38fd1498Szrj   return target;
5806*38fd1498Szrj }
5807*38fd1498Szrj 
5808*38fd1498Szrj /* Expand the __sync_lock_test_and_set intrinsic.  Note that the most
5809*38fd1498Szrj    general form is actually an atomic exchange, and some targets only
5810*38fd1498Szrj    support a reduced form with the second argument being a constant 1.
5811*38fd1498Szrj    EXP is the CALL_EXPR; TARGET is an optional place for us to store
5812*38fd1498Szrj    the results.  */
5813*38fd1498Szrj 
5814*38fd1498Szrj static rtx
expand_builtin_sync_lock_test_and_set(machine_mode mode,tree exp,rtx target)5815*38fd1498Szrj expand_builtin_sync_lock_test_and_set (machine_mode mode, tree exp,
5816*38fd1498Szrj 				       rtx target)
5817*38fd1498Szrj {
5818*38fd1498Szrj   rtx val, mem;
5819*38fd1498Szrj 
5820*38fd1498Szrj   /* Expand the operands.  */
5821*38fd1498Szrj   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5822*38fd1498Szrj   val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
5823*38fd1498Szrj 
5824*38fd1498Szrj   return expand_sync_lock_test_and_set (target, mem, val);
5825*38fd1498Szrj }
5826*38fd1498Szrj 
5827*38fd1498Szrj /* Expand the __sync_lock_release intrinsic.  EXP is the CALL_EXPR.  */
5828*38fd1498Szrj 
5829*38fd1498Szrj static void
expand_builtin_sync_lock_release(machine_mode mode,tree exp)5830*38fd1498Szrj expand_builtin_sync_lock_release (machine_mode mode, tree exp)
5831*38fd1498Szrj {
5832*38fd1498Szrj   rtx mem;
5833*38fd1498Szrj 
5834*38fd1498Szrj   /* Expand the operands.  */
5835*38fd1498Szrj   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5836*38fd1498Szrj 
5837*38fd1498Szrj   expand_atomic_store (mem, const0_rtx, MEMMODEL_SYNC_RELEASE, true);
5838*38fd1498Szrj }
5839*38fd1498Szrj 
5840*38fd1498Szrj /* Given an integer representing an ``enum memmodel'', verify its
5841*38fd1498Szrj    correctness and return the memory model enum.  */
5842*38fd1498Szrj 
5843*38fd1498Szrj static enum memmodel
get_memmodel(tree exp)5844*38fd1498Szrj get_memmodel (tree exp)
5845*38fd1498Szrj {
5846*38fd1498Szrj   rtx op;
5847*38fd1498Szrj   unsigned HOST_WIDE_INT val;
5848*38fd1498Szrj   source_location loc
5849*38fd1498Szrj     = expansion_point_location_if_in_system_header (input_location);
5850*38fd1498Szrj 
5851*38fd1498Szrj   /* If the parameter is not a constant, it's a run time value so we'll just
5852*38fd1498Szrj      convert it to MEMMODEL_SEQ_CST to avoid annoying runtime checking.  */
5853*38fd1498Szrj   if (TREE_CODE (exp) != INTEGER_CST)
5854*38fd1498Szrj     return MEMMODEL_SEQ_CST;
5855*38fd1498Szrj 
5856*38fd1498Szrj   op = expand_normal (exp);
5857*38fd1498Szrj 
5858*38fd1498Szrj   val = INTVAL (op);
5859*38fd1498Szrj   if (targetm.memmodel_check)
5860*38fd1498Szrj     val = targetm.memmodel_check (val);
5861*38fd1498Szrj   else if (val & ~MEMMODEL_MASK)
5862*38fd1498Szrj     {
5863*38fd1498Szrj       warning_at (loc, OPT_Winvalid_memory_model,
5864*38fd1498Szrj 		  "unknown architecture specifier in memory model to builtin");
5865*38fd1498Szrj       return MEMMODEL_SEQ_CST;
5866*38fd1498Szrj     }
5867*38fd1498Szrj 
5868*38fd1498Szrj   /* Should never see a user explicit SYNC memodel model, so >= LAST works. */
5869*38fd1498Szrj   if (memmodel_base (val) >= MEMMODEL_LAST)
5870*38fd1498Szrj     {
5871*38fd1498Szrj       warning_at (loc, OPT_Winvalid_memory_model,
5872*38fd1498Szrj 		  "invalid memory model argument to builtin");
5873*38fd1498Szrj       return MEMMODEL_SEQ_CST;
5874*38fd1498Szrj     }
5875*38fd1498Szrj 
5876*38fd1498Szrj   /* Workaround for Bugzilla 59448. GCC doesn't track consume properly, so
5877*38fd1498Szrj      be conservative and promote consume to acquire.  */
5878*38fd1498Szrj   if (val == MEMMODEL_CONSUME)
5879*38fd1498Szrj     val = MEMMODEL_ACQUIRE;
5880*38fd1498Szrj 
5881*38fd1498Szrj   return (enum memmodel) val;
5882*38fd1498Szrj }
5883*38fd1498Szrj 
5884*38fd1498Szrj /* Expand the __atomic_exchange intrinsic:
5885*38fd1498Szrj    	TYPE __atomic_exchange (TYPE *object, TYPE desired, enum memmodel)
5886*38fd1498Szrj    EXP is the CALL_EXPR.
5887*38fd1498Szrj    TARGET is an optional place for us to store the results.  */
5888*38fd1498Szrj 
5889*38fd1498Szrj static rtx
expand_builtin_atomic_exchange(machine_mode mode,tree exp,rtx target)5890*38fd1498Szrj expand_builtin_atomic_exchange (machine_mode mode, tree exp, rtx target)
5891*38fd1498Szrj {
5892*38fd1498Szrj   rtx val, mem;
5893*38fd1498Szrj   enum memmodel model;
5894*38fd1498Szrj 
5895*38fd1498Szrj   model = get_memmodel (CALL_EXPR_ARG (exp, 2));
5896*38fd1498Szrj 
5897*38fd1498Szrj   if (!flag_inline_atomics)
5898*38fd1498Szrj     return NULL_RTX;
5899*38fd1498Szrj 
5900*38fd1498Szrj   /* Expand the operands.  */
5901*38fd1498Szrj   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5902*38fd1498Szrj   val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
5903*38fd1498Szrj 
5904*38fd1498Szrj   return expand_atomic_exchange (target, mem, val, model);
5905*38fd1498Szrj }
5906*38fd1498Szrj 
5907*38fd1498Szrj /* Expand the __atomic_compare_exchange intrinsic:
5908*38fd1498Szrj    	bool __atomic_compare_exchange (TYPE *object, TYPE *expect,
5909*38fd1498Szrj 					TYPE desired, BOOL weak,
5910*38fd1498Szrj 					enum memmodel success,
5911*38fd1498Szrj 					enum memmodel failure)
5912*38fd1498Szrj    EXP is the CALL_EXPR.
5913*38fd1498Szrj    TARGET is an optional place for us to store the results.  */
5914*38fd1498Szrj 
5915*38fd1498Szrj static rtx
expand_builtin_atomic_compare_exchange(machine_mode mode,tree exp,rtx target)5916*38fd1498Szrj expand_builtin_atomic_compare_exchange (machine_mode mode, tree exp,
5917*38fd1498Szrj 					rtx target)
5918*38fd1498Szrj {
5919*38fd1498Szrj   rtx expect, desired, mem, oldval;
5920*38fd1498Szrj   rtx_code_label *label;
5921*38fd1498Szrj   enum memmodel success, failure;
5922*38fd1498Szrj   tree weak;
5923*38fd1498Szrj   bool is_weak;
5924*38fd1498Szrj   source_location loc
5925*38fd1498Szrj     = expansion_point_location_if_in_system_header (input_location);
5926*38fd1498Szrj 
5927*38fd1498Szrj   success = get_memmodel (CALL_EXPR_ARG (exp, 4));
5928*38fd1498Szrj   failure = get_memmodel (CALL_EXPR_ARG (exp, 5));
5929*38fd1498Szrj 
5930*38fd1498Szrj   if (failure > success)
5931*38fd1498Szrj     {
5932*38fd1498Szrj       warning_at (loc, OPT_Winvalid_memory_model,
5933*38fd1498Szrj 		  "failure memory model cannot be stronger than success "
5934*38fd1498Szrj 		  "memory model for %<__atomic_compare_exchange%>");
5935*38fd1498Szrj       success = MEMMODEL_SEQ_CST;
5936*38fd1498Szrj     }
5937*38fd1498Szrj 
5938*38fd1498Szrj   if (is_mm_release (failure) || is_mm_acq_rel (failure))
5939*38fd1498Szrj     {
5940*38fd1498Szrj       warning_at (loc, OPT_Winvalid_memory_model,
5941*38fd1498Szrj 		  "invalid failure memory model for "
5942*38fd1498Szrj 		  "%<__atomic_compare_exchange%>");
5943*38fd1498Szrj       failure = MEMMODEL_SEQ_CST;
5944*38fd1498Szrj       success = MEMMODEL_SEQ_CST;
5945*38fd1498Szrj     }
5946*38fd1498Szrj 
5947*38fd1498Szrj 
5948*38fd1498Szrj   if (!flag_inline_atomics)
5949*38fd1498Szrj     return NULL_RTX;
5950*38fd1498Szrj 
5951*38fd1498Szrj   /* Expand the operands.  */
5952*38fd1498Szrj   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
5953*38fd1498Szrj 
5954*38fd1498Szrj   expect = expand_normal (CALL_EXPR_ARG (exp, 1));
5955*38fd1498Szrj   expect = convert_memory_address (Pmode, expect);
5956*38fd1498Szrj   expect = gen_rtx_MEM (mode, expect);
5957*38fd1498Szrj   desired = expand_expr_force_mode (CALL_EXPR_ARG (exp, 2), mode);
5958*38fd1498Szrj 
5959*38fd1498Szrj   weak = CALL_EXPR_ARG (exp, 3);
5960*38fd1498Szrj   is_weak = false;
5961*38fd1498Szrj   if (tree_fits_shwi_p (weak) && tree_to_shwi (weak) != 0)
5962*38fd1498Szrj     is_weak = true;
5963*38fd1498Szrj 
5964*38fd1498Szrj   if (target == const0_rtx)
5965*38fd1498Szrj     target = NULL;
5966*38fd1498Szrj 
5967*38fd1498Szrj   /* Lest the rtl backend create a race condition with an imporoper store
5968*38fd1498Szrj      to memory, always create a new pseudo for OLDVAL.  */
5969*38fd1498Szrj   oldval = NULL;
5970*38fd1498Szrj 
5971*38fd1498Szrj   if (!expand_atomic_compare_and_swap (&target, &oldval, mem, expect, desired,
5972*38fd1498Szrj 				       is_weak, success, failure))
5973*38fd1498Szrj     return NULL_RTX;
5974*38fd1498Szrj 
5975*38fd1498Szrj   /* Conditionally store back to EXPECT, lest we create a race condition
5976*38fd1498Szrj      with an improper store to memory.  */
5977*38fd1498Szrj   /* ??? With a rearrangement of atomics at the gimple level, we can handle
5978*38fd1498Szrj      the normal case where EXPECT is totally private, i.e. a register.  At
5979*38fd1498Szrj      which point the store can be unconditional.  */
5980*38fd1498Szrj   label = gen_label_rtx ();
5981*38fd1498Szrj   emit_cmp_and_jump_insns (target, const0_rtx, NE, NULL,
5982*38fd1498Szrj 			   GET_MODE (target), 1, label);
5983*38fd1498Szrj   emit_move_insn (expect, oldval);
5984*38fd1498Szrj   emit_label (label);
5985*38fd1498Szrj 
5986*38fd1498Szrj   return target;
5987*38fd1498Szrj }
5988*38fd1498Szrj 
5989*38fd1498Szrj /* Helper function for expand_ifn_atomic_compare_exchange - expand
5990*38fd1498Szrj    internal ATOMIC_COMPARE_EXCHANGE call into __atomic_compare_exchange_N
5991*38fd1498Szrj    call.  The weak parameter must be dropped to match the expected parameter
5992*38fd1498Szrj    list and the expected argument changed from value to pointer to memory
5993*38fd1498Szrj    slot.  */
5994*38fd1498Szrj 
5995*38fd1498Szrj static void
expand_ifn_atomic_compare_exchange_into_call(gcall * call,machine_mode mode)5996*38fd1498Szrj expand_ifn_atomic_compare_exchange_into_call (gcall *call, machine_mode mode)
5997*38fd1498Szrj {
5998*38fd1498Szrj   unsigned int z;
5999*38fd1498Szrj   vec<tree, va_gc> *vec;
6000*38fd1498Szrj 
6001*38fd1498Szrj   vec_alloc (vec, 5);
6002*38fd1498Szrj   vec->quick_push (gimple_call_arg (call, 0));
6003*38fd1498Szrj   tree expected = gimple_call_arg (call, 1);
6004*38fd1498Szrj   rtx x = assign_stack_temp_for_type (mode, GET_MODE_SIZE (mode),
6005*38fd1498Szrj 				      TREE_TYPE (expected));
6006*38fd1498Szrj   rtx expd = expand_expr (expected, x, mode, EXPAND_NORMAL);
6007*38fd1498Szrj   if (expd != x)
6008*38fd1498Szrj     emit_move_insn (x, expd);
6009*38fd1498Szrj   tree v = make_tree (TREE_TYPE (expected), x);
6010*38fd1498Szrj   vec->quick_push (build1 (ADDR_EXPR,
6011*38fd1498Szrj 			   build_pointer_type (TREE_TYPE (expected)), v));
6012*38fd1498Szrj   vec->quick_push (gimple_call_arg (call, 2));
6013*38fd1498Szrj   /* Skip the boolean weak parameter.  */
6014*38fd1498Szrj   for (z = 4; z < 6; z++)
6015*38fd1498Szrj     vec->quick_push (gimple_call_arg (call, z));
6016*38fd1498Szrj   /* At present we only have BUILT_IN_ATOMIC_COMPARE_EXCHANGE_{1,2,4,8,16}.  */
6017*38fd1498Szrj   unsigned int bytes_log2 = exact_log2 (GET_MODE_SIZE (mode).to_constant ());
6018*38fd1498Szrj   gcc_assert (bytes_log2 < 5);
6019*38fd1498Szrj   built_in_function fncode
6020*38fd1498Szrj     = (built_in_function) ((int) BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1
6021*38fd1498Szrj 			   + bytes_log2);
6022*38fd1498Szrj   tree fndecl = builtin_decl_explicit (fncode);
6023*38fd1498Szrj   tree fn = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fndecl)),
6024*38fd1498Szrj 		    fndecl);
6025*38fd1498Szrj   tree exp = build_call_vec (boolean_type_node, fn, vec);
6026*38fd1498Szrj   tree lhs = gimple_call_lhs (call);
6027*38fd1498Szrj   rtx boolret = expand_call (exp, NULL_RTX, lhs == NULL_TREE);
6028*38fd1498Szrj   if (lhs)
6029*38fd1498Szrj     {
6030*38fd1498Szrj       rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
6031*38fd1498Szrj       if (GET_MODE (boolret) != mode)
6032*38fd1498Szrj 	boolret = convert_modes (mode, GET_MODE (boolret), boolret, 1);
6033*38fd1498Szrj       x = force_reg (mode, x);
6034*38fd1498Szrj       write_complex_part (target, boolret, true);
6035*38fd1498Szrj       write_complex_part (target, x, false);
6036*38fd1498Szrj     }
6037*38fd1498Szrj }
6038*38fd1498Szrj 
6039*38fd1498Szrj /* Expand IFN_ATOMIC_COMPARE_EXCHANGE internal function.  */
6040*38fd1498Szrj 
6041*38fd1498Szrj void
expand_ifn_atomic_compare_exchange(gcall * call)6042*38fd1498Szrj expand_ifn_atomic_compare_exchange (gcall *call)
6043*38fd1498Szrj {
6044*38fd1498Szrj   int size = tree_to_shwi (gimple_call_arg (call, 3)) & 255;
6045*38fd1498Szrj   gcc_assert (size == 1 || size == 2 || size == 4 || size == 8 || size == 16);
6046*38fd1498Szrj   machine_mode mode = int_mode_for_size (BITS_PER_UNIT * size, 0).require ();
6047*38fd1498Szrj   rtx expect, desired, mem, oldval, boolret;
6048*38fd1498Szrj   enum memmodel success, failure;
6049*38fd1498Szrj   tree lhs;
6050*38fd1498Szrj   bool is_weak;
6051*38fd1498Szrj   source_location loc
6052*38fd1498Szrj     = expansion_point_location_if_in_system_header (gimple_location (call));
6053*38fd1498Szrj 
6054*38fd1498Szrj   success = get_memmodel (gimple_call_arg (call, 4));
6055*38fd1498Szrj   failure = get_memmodel (gimple_call_arg (call, 5));
6056*38fd1498Szrj 
6057*38fd1498Szrj   if (failure > success)
6058*38fd1498Szrj     {
6059*38fd1498Szrj       warning_at (loc, OPT_Winvalid_memory_model,
6060*38fd1498Szrj 		  "failure memory model cannot be stronger than success "
6061*38fd1498Szrj 		  "memory model for %<__atomic_compare_exchange%>");
6062*38fd1498Szrj       success = MEMMODEL_SEQ_CST;
6063*38fd1498Szrj     }
6064*38fd1498Szrj 
6065*38fd1498Szrj   if (is_mm_release (failure) || is_mm_acq_rel (failure))
6066*38fd1498Szrj     {
6067*38fd1498Szrj       warning_at (loc, OPT_Winvalid_memory_model,
6068*38fd1498Szrj 		  "invalid failure memory model for "
6069*38fd1498Szrj 		  "%<__atomic_compare_exchange%>");
6070*38fd1498Szrj       failure = MEMMODEL_SEQ_CST;
6071*38fd1498Szrj       success = MEMMODEL_SEQ_CST;
6072*38fd1498Szrj     }
6073*38fd1498Szrj 
6074*38fd1498Szrj   if (!flag_inline_atomics)
6075*38fd1498Szrj     {
6076*38fd1498Szrj       expand_ifn_atomic_compare_exchange_into_call (call, mode);
6077*38fd1498Szrj       return;
6078*38fd1498Szrj     }
6079*38fd1498Szrj 
6080*38fd1498Szrj   /* Expand the operands.  */
6081*38fd1498Szrj   mem = get_builtin_sync_mem (gimple_call_arg (call, 0), mode);
6082*38fd1498Szrj 
6083*38fd1498Szrj   expect = expand_expr_force_mode (gimple_call_arg (call, 1), mode);
6084*38fd1498Szrj   desired = expand_expr_force_mode (gimple_call_arg (call, 2), mode);
6085*38fd1498Szrj 
6086*38fd1498Szrj   is_weak = (tree_to_shwi (gimple_call_arg (call, 3)) & 256) != 0;
6087*38fd1498Szrj 
6088*38fd1498Szrj   boolret = NULL;
6089*38fd1498Szrj   oldval = NULL;
6090*38fd1498Szrj 
6091*38fd1498Szrj   if (!expand_atomic_compare_and_swap (&boolret, &oldval, mem, expect, desired,
6092*38fd1498Szrj 				       is_weak, success, failure))
6093*38fd1498Szrj     {
6094*38fd1498Szrj       expand_ifn_atomic_compare_exchange_into_call (call, mode);
6095*38fd1498Szrj       return;
6096*38fd1498Szrj     }
6097*38fd1498Szrj 
6098*38fd1498Szrj   lhs = gimple_call_lhs (call);
6099*38fd1498Szrj   if (lhs)
6100*38fd1498Szrj     {
6101*38fd1498Szrj       rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
6102*38fd1498Szrj       if (GET_MODE (boolret) != mode)
6103*38fd1498Szrj 	boolret = convert_modes (mode, GET_MODE (boolret), boolret, 1);
6104*38fd1498Szrj       write_complex_part (target, boolret, true);
6105*38fd1498Szrj       write_complex_part (target, oldval, false);
6106*38fd1498Szrj     }
6107*38fd1498Szrj }
6108*38fd1498Szrj 
6109*38fd1498Szrj /* Expand the __atomic_load intrinsic:
6110*38fd1498Szrj    	TYPE __atomic_load (TYPE *object, enum memmodel)
6111*38fd1498Szrj    EXP is the CALL_EXPR.
6112*38fd1498Szrj    TARGET is an optional place for us to store the results.  */
6113*38fd1498Szrj 
6114*38fd1498Szrj static rtx
expand_builtin_atomic_load(machine_mode mode,tree exp,rtx target)6115*38fd1498Szrj expand_builtin_atomic_load (machine_mode mode, tree exp, rtx target)
6116*38fd1498Szrj {
6117*38fd1498Szrj   rtx mem;
6118*38fd1498Szrj   enum memmodel model;
6119*38fd1498Szrj 
6120*38fd1498Szrj   model = get_memmodel (CALL_EXPR_ARG (exp, 1));
6121*38fd1498Szrj   if (is_mm_release (model) || is_mm_acq_rel (model))
6122*38fd1498Szrj     {
6123*38fd1498Szrj       source_location loc
6124*38fd1498Szrj 	= expansion_point_location_if_in_system_header (input_location);
6125*38fd1498Szrj       warning_at (loc, OPT_Winvalid_memory_model,
6126*38fd1498Szrj 		  "invalid memory model for %<__atomic_load%>");
6127*38fd1498Szrj       model = MEMMODEL_SEQ_CST;
6128*38fd1498Szrj     }
6129*38fd1498Szrj 
6130*38fd1498Szrj   if (!flag_inline_atomics)
6131*38fd1498Szrj     return NULL_RTX;
6132*38fd1498Szrj 
6133*38fd1498Szrj   /* Expand the operand.  */
6134*38fd1498Szrj   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
6135*38fd1498Szrj 
6136*38fd1498Szrj   return expand_atomic_load (target, mem, model);
6137*38fd1498Szrj }
6138*38fd1498Szrj 
6139*38fd1498Szrj 
6140*38fd1498Szrj /* Expand the __atomic_store intrinsic:
6141*38fd1498Szrj    	void __atomic_store (TYPE *object, TYPE desired, enum memmodel)
6142*38fd1498Szrj    EXP is the CALL_EXPR.
6143*38fd1498Szrj    TARGET is an optional place for us to store the results.  */
6144*38fd1498Szrj 
6145*38fd1498Szrj static rtx
expand_builtin_atomic_store(machine_mode mode,tree exp)6146*38fd1498Szrj expand_builtin_atomic_store (machine_mode mode, tree exp)
6147*38fd1498Szrj {
6148*38fd1498Szrj   rtx mem, val;
6149*38fd1498Szrj   enum memmodel model;
6150*38fd1498Szrj 
6151*38fd1498Szrj   model = get_memmodel (CALL_EXPR_ARG (exp, 2));
6152*38fd1498Szrj   if (!(is_mm_relaxed (model) || is_mm_seq_cst (model)
6153*38fd1498Szrj 	|| is_mm_release (model)))
6154*38fd1498Szrj     {
6155*38fd1498Szrj       source_location loc
6156*38fd1498Szrj 	= expansion_point_location_if_in_system_header (input_location);
6157*38fd1498Szrj       warning_at (loc, OPT_Winvalid_memory_model,
6158*38fd1498Szrj 		  "invalid memory model for %<__atomic_store%>");
6159*38fd1498Szrj       model = MEMMODEL_SEQ_CST;
6160*38fd1498Szrj     }
6161*38fd1498Szrj 
6162*38fd1498Szrj   if (!flag_inline_atomics)
6163*38fd1498Szrj     return NULL_RTX;
6164*38fd1498Szrj 
6165*38fd1498Szrj   /* Expand the operands.  */
6166*38fd1498Szrj   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
6167*38fd1498Szrj   val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
6168*38fd1498Szrj 
6169*38fd1498Szrj   return expand_atomic_store (mem, val, model, false);
6170*38fd1498Szrj }
6171*38fd1498Szrj 
6172*38fd1498Szrj /* Expand the __atomic_fetch_XXX intrinsic:
6173*38fd1498Szrj    	TYPE __atomic_fetch_XXX (TYPE *object, TYPE val, enum memmodel)
6174*38fd1498Szrj    EXP is the CALL_EXPR.
6175*38fd1498Szrj    TARGET is an optional place for us to store the results.
6176*38fd1498Szrj    CODE is the operation, PLUS, MINUS, ADD, XOR, or IOR.
6177*38fd1498Szrj    FETCH_AFTER is true if returning the result of the operation.
6178*38fd1498Szrj    FETCH_AFTER is false if returning the value before the operation.
6179*38fd1498Szrj    IGNORE is true if the result is not used.
6180*38fd1498Szrj    EXT_CALL is the correct builtin for an external call if this cannot be
6181*38fd1498Szrj    resolved to an instruction sequence.  */
6182*38fd1498Szrj 
6183*38fd1498Szrj static rtx
expand_builtin_atomic_fetch_op(machine_mode mode,tree exp,rtx target,enum rtx_code code,bool fetch_after,bool ignore,enum built_in_function ext_call)6184*38fd1498Szrj expand_builtin_atomic_fetch_op (machine_mode mode, tree exp, rtx target,
6185*38fd1498Szrj 				enum rtx_code code, bool fetch_after,
6186*38fd1498Szrj 				bool ignore, enum built_in_function ext_call)
6187*38fd1498Szrj {
6188*38fd1498Szrj   rtx val, mem, ret;
6189*38fd1498Szrj   enum memmodel model;
6190*38fd1498Szrj   tree fndecl;
6191*38fd1498Szrj   tree addr;
6192*38fd1498Szrj 
6193*38fd1498Szrj   model = get_memmodel (CALL_EXPR_ARG (exp, 2));
6194*38fd1498Szrj 
6195*38fd1498Szrj   /* Expand the operands.  */
6196*38fd1498Szrj   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
6197*38fd1498Szrj   val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
6198*38fd1498Szrj 
6199*38fd1498Szrj   /* Only try generating instructions if inlining is turned on.  */
6200*38fd1498Szrj   if (flag_inline_atomics)
6201*38fd1498Szrj     {
6202*38fd1498Szrj       ret = expand_atomic_fetch_op (target, mem, val, code, model, fetch_after);
6203*38fd1498Szrj       if (ret)
6204*38fd1498Szrj 	return ret;
6205*38fd1498Szrj     }
6206*38fd1498Szrj 
6207*38fd1498Szrj   /* Return if a different routine isn't needed for the library call.  */
6208*38fd1498Szrj   if (ext_call == BUILT_IN_NONE)
6209*38fd1498Szrj     return NULL_RTX;
6210*38fd1498Szrj 
6211*38fd1498Szrj   /* Change the call to the specified function.  */
6212*38fd1498Szrj   fndecl = get_callee_fndecl (exp);
6213*38fd1498Szrj   addr = CALL_EXPR_FN (exp);
6214*38fd1498Szrj   STRIP_NOPS (addr);
6215*38fd1498Szrj 
6216*38fd1498Szrj   gcc_assert (TREE_OPERAND (addr, 0) == fndecl);
6217*38fd1498Szrj   TREE_OPERAND (addr, 0) = builtin_decl_explicit (ext_call);
6218*38fd1498Szrj 
6219*38fd1498Szrj   /* If we will emit code after the call, the call can not be a tail call.
6220*38fd1498Szrj      If it is emitted as a tail call, a barrier is emitted after it, and
6221*38fd1498Szrj      then all trailing code is removed.  */
6222*38fd1498Szrj   if (!ignore)
6223*38fd1498Szrj     CALL_EXPR_TAILCALL (exp) = 0;
6224*38fd1498Szrj 
6225*38fd1498Szrj   /* Expand the call here so we can emit trailing code.  */
6226*38fd1498Szrj   ret = expand_call (exp, target, ignore);
6227*38fd1498Szrj 
6228*38fd1498Szrj   /* Replace the original function just in case it matters.  */
6229*38fd1498Szrj   TREE_OPERAND (addr, 0) = fndecl;
6230*38fd1498Szrj 
6231*38fd1498Szrj   /* Then issue the arithmetic correction to return the right result.  */
6232*38fd1498Szrj   if (!ignore)
6233*38fd1498Szrj     {
6234*38fd1498Szrj       if (code == NOT)
6235*38fd1498Szrj 	{
6236*38fd1498Szrj 	  ret = expand_simple_binop (mode, AND, ret, val, NULL_RTX, true,
6237*38fd1498Szrj 				     OPTAB_LIB_WIDEN);
6238*38fd1498Szrj 	  ret = expand_simple_unop (mode, NOT, ret, target, true);
6239*38fd1498Szrj 	}
6240*38fd1498Szrj       else
6241*38fd1498Szrj 	ret = expand_simple_binop (mode, code, ret, val, target, true,
6242*38fd1498Szrj 				   OPTAB_LIB_WIDEN);
6243*38fd1498Szrj     }
6244*38fd1498Szrj   return ret;
6245*38fd1498Szrj }
6246*38fd1498Szrj 
6247*38fd1498Szrj /* Expand IFN_ATOMIC_BIT_TEST_AND_* internal function.  */
6248*38fd1498Szrj 
6249*38fd1498Szrj void
expand_ifn_atomic_bit_test_and(gcall * call)6250*38fd1498Szrj expand_ifn_atomic_bit_test_and (gcall *call)
6251*38fd1498Szrj {
6252*38fd1498Szrj   tree ptr = gimple_call_arg (call, 0);
6253*38fd1498Szrj   tree bit = gimple_call_arg (call, 1);
6254*38fd1498Szrj   tree flag = gimple_call_arg (call, 2);
6255*38fd1498Szrj   tree lhs = gimple_call_lhs (call);
6256*38fd1498Szrj   enum memmodel model = MEMMODEL_SYNC_SEQ_CST;
6257*38fd1498Szrj   machine_mode mode = TYPE_MODE (TREE_TYPE (flag));
6258*38fd1498Szrj   enum rtx_code code;
6259*38fd1498Szrj   optab optab;
6260*38fd1498Szrj   struct expand_operand ops[5];
6261*38fd1498Szrj 
6262*38fd1498Szrj   gcc_assert (flag_inline_atomics);
6263*38fd1498Szrj 
6264*38fd1498Szrj   if (gimple_call_num_args (call) == 4)
6265*38fd1498Szrj     model = get_memmodel (gimple_call_arg (call, 3));
6266*38fd1498Szrj 
6267*38fd1498Szrj   rtx mem = get_builtin_sync_mem (ptr, mode);
6268*38fd1498Szrj   rtx val = expand_expr_force_mode (bit, mode);
6269*38fd1498Szrj 
6270*38fd1498Szrj   switch (gimple_call_internal_fn (call))
6271*38fd1498Szrj     {
6272*38fd1498Szrj     case IFN_ATOMIC_BIT_TEST_AND_SET:
6273*38fd1498Szrj       code = IOR;
6274*38fd1498Szrj       optab = atomic_bit_test_and_set_optab;
6275*38fd1498Szrj       break;
6276*38fd1498Szrj     case IFN_ATOMIC_BIT_TEST_AND_COMPLEMENT:
6277*38fd1498Szrj       code = XOR;
6278*38fd1498Szrj       optab = atomic_bit_test_and_complement_optab;
6279*38fd1498Szrj       break;
6280*38fd1498Szrj     case IFN_ATOMIC_BIT_TEST_AND_RESET:
6281*38fd1498Szrj       code = AND;
6282*38fd1498Szrj       optab = atomic_bit_test_and_reset_optab;
6283*38fd1498Szrj       break;
6284*38fd1498Szrj     default:
6285*38fd1498Szrj       gcc_unreachable ();
6286*38fd1498Szrj     }
6287*38fd1498Szrj 
6288*38fd1498Szrj   if (lhs == NULL_TREE)
6289*38fd1498Szrj     {
6290*38fd1498Szrj       val = expand_simple_binop (mode, ASHIFT, const1_rtx,
6291*38fd1498Szrj 				 val, NULL_RTX, true, OPTAB_DIRECT);
6292*38fd1498Szrj       if (code == AND)
6293*38fd1498Szrj 	val = expand_simple_unop (mode, NOT, val, NULL_RTX, true);
6294*38fd1498Szrj       expand_atomic_fetch_op (const0_rtx, mem, val, code, model, false);
6295*38fd1498Szrj       return;
6296*38fd1498Szrj     }
6297*38fd1498Szrj 
6298*38fd1498Szrj   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
6299*38fd1498Szrj   enum insn_code icode = direct_optab_handler (optab, mode);
6300*38fd1498Szrj   gcc_assert (icode != CODE_FOR_nothing);
6301*38fd1498Szrj   create_output_operand (&ops[0], target, mode);
6302*38fd1498Szrj   create_fixed_operand (&ops[1], mem);
6303*38fd1498Szrj   create_convert_operand_to (&ops[2], val, mode, true);
6304*38fd1498Szrj   create_integer_operand (&ops[3], model);
6305*38fd1498Szrj   create_integer_operand (&ops[4], integer_onep (flag));
6306*38fd1498Szrj   if (maybe_expand_insn (icode, 5, ops))
6307*38fd1498Szrj     return;
6308*38fd1498Szrj 
6309*38fd1498Szrj   rtx bitval = val;
6310*38fd1498Szrj   val = expand_simple_binop (mode, ASHIFT, const1_rtx,
6311*38fd1498Szrj 			     val, NULL_RTX, true, OPTAB_DIRECT);
6312*38fd1498Szrj   rtx maskval = val;
6313*38fd1498Szrj   if (code == AND)
6314*38fd1498Szrj     val = expand_simple_unop (mode, NOT, val, NULL_RTX, true);
6315*38fd1498Szrj   rtx result = expand_atomic_fetch_op (gen_reg_rtx (mode), mem, val,
6316*38fd1498Szrj 				       code, model, false);
6317*38fd1498Szrj   if (integer_onep (flag))
6318*38fd1498Szrj     {
6319*38fd1498Szrj       result = expand_simple_binop (mode, ASHIFTRT, result, bitval,
6320*38fd1498Szrj 				    NULL_RTX, true, OPTAB_DIRECT);
6321*38fd1498Szrj       result = expand_simple_binop (mode, AND, result, const1_rtx, target,
6322*38fd1498Szrj 				    true, OPTAB_DIRECT);
6323*38fd1498Szrj     }
6324*38fd1498Szrj   else
6325*38fd1498Szrj     result = expand_simple_binop (mode, AND, result, maskval, target, true,
6326*38fd1498Szrj 				  OPTAB_DIRECT);
6327*38fd1498Szrj   if (result != target)
6328*38fd1498Szrj     emit_move_insn (target, result);
6329*38fd1498Szrj }
6330*38fd1498Szrj 
6331*38fd1498Szrj /* Expand an atomic clear operation.
6332*38fd1498Szrj 	void _atomic_clear (BOOL *obj, enum memmodel)
6333*38fd1498Szrj    EXP is the call expression.  */
6334*38fd1498Szrj 
6335*38fd1498Szrj static rtx
expand_builtin_atomic_clear(tree exp)6336*38fd1498Szrj expand_builtin_atomic_clear (tree exp)
6337*38fd1498Szrj {
6338*38fd1498Szrj   machine_mode mode;
6339*38fd1498Szrj   rtx mem, ret;
6340*38fd1498Szrj   enum memmodel model;
6341*38fd1498Szrj 
6342*38fd1498Szrj   mode = int_mode_for_size (BOOL_TYPE_SIZE, 0).require ();
6343*38fd1498Szrj   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
6344*38fd1498Szrj   model = get_memmodel (CALL_EXPR_ARG (exp, 1));
6345*38fd1498Szrj 
6346*38fd1498Szrj   if (is_mm_consume (model) || is_mm_acquire (model) || is_mm_acq_rel (model))
6347*38fd1498Szrj     {
6348*38fd1498Szrj       source_location loc
6349*38fd1498Szrj 	= expansion_point_location_if_in_system_header (input_location);
6350*38fd1498Szrj       warning_at (loc, OPT_Winvalid_memory_model,
6351*38fd1498Szrj 		  "invalid memory model for %<__atomic_store%>");
6352*38fd1498Szrj       model = MEMMODEL_SEQ_CST;
6353*38fd1498Szrj     }
6354*38fd1498Szrj 
6355*38fd1498Szrj   /* Try issuing an __atomic_store, and allow fallback to __sync_lock_release.
6356*38fd1498Szrj      Failing that, a store is issued by __atomic_store.  The only way this can
6357*38fd1498Szrj      fail is if the bool type is larger than a word size.  Unlikely, but
6358*38fd1498Szrj      handle it anyway for completeness.  Assume a single threaded model since
6359*38fd1498Szrj      there is no atomic support in this case, and no barriers are required.  */
6360*38fd1498Szrj   ret = expand_atomic_store (mem, const0_rtx, model, true);
6361*38fd1498Szrj   if (!ret)
6362*38fd1498Szrj     emit_move_insn (mem, const0_rtx);
6363*38fd1498Szrj   return const0_rtx;
6364*38fd1498Szrj }
6365*38fd1498Szrj 
6366*38fd1498Szrj /* Expand an atomic test_and_set operation.
6367*38fd1498Szrj 	bool _atomic_test_and_set (BOOL *obj, enum memmodel)
6368*38fd1498Szrj    EXP is the call expression.  */
6369*38fd1498Szrj 
6370*38fd1498Szrj static rtx
expand_builtin_atomic_test_and_set(tree exp,rtx target)6371*38fd1498Szrj expand_builtin_atomic_test_and_set (tree exp, rtx target)
6372*38fd1498Szrj {
6373*38fd1498Szrj   rtx mem;
6374*38fd1498Szrj   enum memmodel model;
6375*38fd1498Szrj   machine_mode mode;
6376*38fd1498Szrj 
6377*38fd1498Szrj   mode = int_mode_for_size (BOOL_TYPE_SIZE, 0).require ();
6378*38fd1498Szrj   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
6379*38fd1498Szrj   model = get_memmodel (CALL_EXPR_ARG (exp, 1));
6380*38fd1498Szrj 
6381*38fd1498Szrj   return expand_atomic_test_and_set (target, mem, model);
6382*38fd1498Szrj }
6383*38fd1498Szrj 
6384*38fd1498Szrj 
6385*38fd1498Szrj /* Return true if (optional) argument ARG1 of size ARG0 is always lock free on
6386*38fd1498Szrj    this architecture.  If ARG1 is NULL, use typical alignment for size ARG0.  */
6387*38fd1498Szrj 
6388*38fd1498Szrj static tree
fold_builtin_atomic_always_lock_free(tree arg0,tree arg1)6389*38fd1498Szrj fold_builtin_atomic_always_lock_free (tree arg0, tree arg1)
6390*38fd1498Szrj {
6391*38fd1498Szrj   int size;
6392*38fd1498Szrj   machine_mode mode;
6393*38fd1498Szrj   unsigned int mode_align, type_align;
6394*38fd1498Szrj 
6395*38fd1498Szrj   if (TREE_CODE (arg0) != INTEGER_CST)
6396*38fd1498Szrj     return NULL_TREE;
6397*38fd1498Szrj 
6398*38fd1498Szrj   /* We need a corresponding integer mode for the access to be lock-free.  */
6399*38fd1498Szrj   size = INTVAL (expand_normal (arg0)) * BITS_PER_UNIT;
6400*38fd1498Szrj   if (!int_mode_for_size (size, 0).exists (&mode))
6401*38fd1498Szrj     return boolean_false_node;
6402*38fd1498Szrj 
6403*38fd1498Szrj   mode_align = GET_MODE_ALIGNMENT (mode);
6404*38fd1498Szrj 
6405*38fd1498Szrj   if (TREE_CODE (arg1) == INTEGER_CST)
6406*38fd1498Szrj     {
6407*38fd1498Szrj       unsigned HOST_WIDE_INT val = UINTVAL (expand_normal (arg1));
6408*38fd1498Szrj 
6409*38fd1498Szrj       /* Either this argument is null, or it's a fake pointer encoding
6410*38fd1498Szrj          the alignment of the object.  */
6411*38fd1498Szrj       val = least_bit_hwi (val);
6412*38fd1498Szrj       val *= BITS_PER_UNIT;
6413*38fd1498Szrj 
6414*38fd1498Szrj       if (val == 0 || mode_align < val)
6415*38fd1498Szrj         type_align = mode_align;
6416*38fd1498Szrj       else
6417*38fd1498Szrj         type_align = val;
6418*38fd1498Szrj     }
6419*38fd1498Szrj   else
6420*38fd1498Szrj     {
6421*38fd1498Szrj       tree ttype = TREE_TYPE (arg1);
6422*38fd1498Szrj 
6423*38fd1498Szrj       /* This function is usually invoked and folded immediately by the front
6424*38fd1498Szrj 	 end before anything else has a chance to look at it.  The pointer
6425*38fd1498Szrj 	 parameter at this point is usually cast to a void *, so check for that
6426*38fd1498Szrj 	 and look past the cast.  */
6427*38fd1498Szrj       if (CONVERT_EXPR_P (arg1)
6428*38fd1498Szrj 	  && POINTER_TYPE_P (ttype)
6429*38fd1498Szrj 	  && VOID_TYPE_P (TREE_TYPE (ttype))
6430*38fd1498Szrj 	  && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg1, 0))))
6431*38fd1498Szrj 	arg1 = TREE_OPERAND (arg1, 0);
6432*38fd1498Szrj 
6433*38fd1498Szrj       ttype = TREE_TYPE (arg1);
6434*38fd1498Szrj       gcc_assert (POINTER_TYPE_P (ttype));
6435*38fd1498Szrj 
6436*38fd1498Szrj       /* Get the underlying type of the object.  */
6437*38fd1498Szrj       ttype = TREE_TYPE (ttype);
6438*38fd1498Szrj       type_align = TYPE_ALIGN (ttype);
6439*38fd1498Szrj     }
6440*38fd1498Szrj 
6441*38fd1498Szrj   /* If the object has smaller alignment, the lock free routines cannot
6442*38fd1498Szrj      be used.  */
6443*38fd1498Szrj   if (type_align < mode_align)
6444*38fd1498Szrj     return boolean_false_node;
6445*38fd1498Szrj 
6446*38fd1498Szrj   /* Check if a compare_and_swap pattern exists for the mode which represents
6447*38fd1498Szrj      the required size.  The pattern is not allowed to fail, so the existence
6448*38fd1498Szrj      of the pattern indicates support is present.  Also require that an
6449*38fd1498Szrj      atomic load exists for the required size.  */
6450*38fd1498Szrj   if (can_compare_and_swap_p (mode, true) && can_atomic_load_p (mode))
6451*38fd1498Szrj     return boolean_true_node;
6452*38fd1498Szrj   else
6453*38fd1498Szrj     return boolean_false_node;
6454*38fd1498Szrj }
6455*38fd1498Szrj 
6456*38fd1498Szrj /* Return true if the parameters to call EXP represent an object which will
6457*38fd1498Szrj    always generate lock free instructions.  The first argument represents the
6458*38fd1498Szrj    size of the object, and the second parameter is a pointer to the object
6459*38fd1498Szrj    itself.  If NULL is passed for the object, then the result is based on
6460*38fd1498Szrj    typical alignment for an object of the specified size.  Otherwise return
6461*38fd1498Szrj    false.  */
6462*38fd1498Szrj 
6463*38fd1498Szrj static rtx
expand_builtin_atomic_always_lock_free(tree exp)6464*38fd1498Szrj expand_builtin_atomic_always_lock_free (tree exp)
6465*38fd1498Szrj {
6466*38fd1498Szrj   tree size;
6467*38fd1498Szrj   tree arg0 = CALL_EXPR_ARG (exp, 0);
6468*38fd1498Szrj   tree arg1 = CALL_EXPR_ARG (exp, 1);
6469*38fd1498Szrj 
6470*38fd1498Szrj   if (TREE_CODE (arg0) != INTEGER_CST)
6471*38fd1498Szrj     {
6472*38fd1498Szrj       error ("non-constant argument 1 to __atomic_always_lock_free");
6473*38fd1498Szrj       return const0_rtx;
6474*38fd1498Szrj     }
6475*38fd1498Szrj 
6476*38fd1498Szrj   size = fold_builtin_atomic_always_lock_free (arg0, arg1);
6477*38fd1498Szrj   if (size == boolean_true_node)
6478*38fd1498Szrj     return const1_rtx;
6479*38fd1498Szrj   return const0_rtx;
6480*38fd1498Szrj }
6481*38fd1498Szrj 
6482*38fd1498Szrj /* Return a one or zero if it can be determined that object ARG1 of size ARG
6483*38fd1498Szrj    is lock free on this architecture.  */
6484*38fd1498Szrj 
6485*38fd1498Szrj static tree
fold_builtin_atomic_is_lock_free(tree arg0,tree arg1)6486*38fd1498Szrj fold_builtin_atomic_is_lock_free (tree arg0, tree arg1)
6487*38fd1498Szrj {
6488*38fd1498Szrj   if (!flag_inline_atomics)
6489*38fd1498Szrj     return NULL_TREE;
6490*38fd1498Szrj 
6491*38fd1498Szrj   /* If it isn't always lock free, don't generate a result.  */
6492*38fd1498Szrj   if (fold_builtin_atomic_always_lock_free (arg0, arg1) == boolean_true_node)
6493*38fd1498Szrj     return boolean_true_node;
6494*38fd1498Szrj 
6495*38fd1498Szrj   return NULL_TREE;
6496*38fd1498Szrj }
6497*38fd1498Szrj 
6498*38fd1498Szrj /* Return true if the parameters to call EXP represent an object which will
6499*38fd1498Szrj    always generate lock free instructions.  The first argument represents the
6500*38fd1498Szrj    size of the object, and the second parameter is a pointer to the object
6501*38fd1498Szrj    itself.  If NULL is passed for the object, then the result is based on
6502*38fd1498Szrj    typical alignment for an object of the specified size.  Otherwise return
6503*38fd1498Szrj    NULL*/
6504*38fd1498Szrj 
6505*38fd1498Szrj static rtx
expand_builtin_atomic_is_lock_free(tree exp)6506*38fd1498Szrj expand_builtin_atomic_is_lock_free (tree exp)
6507*38fd1498Szrj {
6508*38fd1498Szrj   tree size;
6509*38fd1498Szrj   tree arg0 = CALL_EXPR_ARG (exp, 0);
6510*38fd1498Szrj   tree arg1 = CALL_EXPR_ARG (exp, 1);
6511*38fd1498Szrj 
6512*38fd1498Szrj   if (!INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
6513*38fd1498Szrj     {
6514*38fd1498Szrj       error ("non-integer argument 1 to __atomic_is_lock_free");
6515*38fd1498Szrj       return NULL_RTX;
6516*38fd1498Szrj     }
6517*38fd1498Szrj 
6518*38fd1498Szrj   if (!flag_inline_atomics)
6519*38fd1498Szrj     return NULL_RTX;
6520*38fd1498Szrj 
6521*38fd1498Szrj   /* If the value is known at compile time, return the RTX for it.  */
6522*38fd1498Szrj   size = fold_builtin_atomic_is_lock_free (arg0, arg1);
6523*38fd1498Szrj   if (size == boolean_true_node)
6524*38fd1498Szrj     return const1_rtx;
6525*38fd1498Szrj 
6526*38fd1498Szrj   return NULL_RTX;
6527*38fd1498Szrj }
6528*38fd1498Szrj 
6529*38fd1498Szrj /* Expand the __atomic_thread_fence intrinsic:
6530*38fd1498Szrj    	void __atomic_thread_fence (enum memmodel)
6531*38fd1498Szrj    EXP is the CALL_EXPR.  */
6532*38fd1498Szrj 
6533*38fd1498Szrj static void
expand_builtin_atomic_thread_fence(tree exp)6534*38fd1498Szrj expand_builtin_atomic_thread_fence (tree exp)
6535*38fd1498Szrj {
6536*38fd1498Szrj   enum memmodel model = get_memmodel (CALL_EXPR_ARG (exp, 0));
6537*38fd1498Szrj   expand_mem_thread_fence (model);
6538*38fd1498Szrj }
6539*38fd1498Szrj 
6540*38fd1498Szrj /* Expand the __atomic_signal_fence intrinsic:
6541*38fd1498Szrj    	void __atomic_signal_fence (enum memmodel)
6542*38fd1498Szrj    EXP is the CALL_EXPR.  */
6543*38fd1498Szrj 
6544*38fd1498Szrj static void
expand_builtin_atomic_signal_fence(tree exp)6545*38fd1498Szrj expand_builtin_atomic_signal_fence (tree exp)
6546*38fd1498Szrj {
6547*38fd1498Szrj   enum memmodel model = get_memmodel (CALL_EXPR_ARG (exp, 0));
6548*38fd1498Szrj   expand_mem_signal_fence (model);
6549*38fd1498Szrj }
6550*38fd1498Szrj 
6551*38fd1498Szrj /* Expand the __sync_synchronize intrinsic.  */
6552*38fd1498Szrj 
6553*38fd1498Szrj static void
expand_builtin_sync_synchronize(void)6554*38fd1498Szrj expand_builtin_sync_synchronize (void)
6555*38fd1498Szrj {
6556*38fd1498Szrj   expand_mem_thread_fence (MEMMODEL_SYNC_SEQ_CST);
6557*38fd1498Szrj }
6558*38fd1498Szrj 
6559*38fd1498Szrj static rtx
expand_builtin_thread_pointer(tree exp,rtx target)6560*38fd1498Szrj expand_builtin_thread_pointer (tree exp, rtx target)
6561*38fd1498Szrj {
6562*38fd1498Szrj   enum insn_code icode;
6563*38fd1498Szrj   if (!validate_arglist (exp, VOID_TYPE))
6564*38fd1498Szrj     return const0_rtx;
6565*38fd1498Szrj   icode = direct_optab_handler (get_thread_pointer_optab, Pmode);
6566*38fd1498Szrj   if (icode != CODE_FOR_nothing)
6567*38fd1498Szrj     {
6568*38fd1498Szrj       struct expand_operand op;
6569*38fd1498Szrj       /* If the target is not sutitable then create a new target. */
6570*38fd1498Szrj       if (target == NULL_RTX
6571*38fd1498Szrj 	  || !REG_P (target)
6572*38fd1498Szrj 	  || GET_MODE (target) != Pmode)
6573*38fd1498Szrj 	target = gen_reg_rtx (Pmode);
6574*38fd1498Szrj       create_output_operand (&op, target, Pmode);
6575*38fd1498Szrj       expand_insn (icode, 1, &op);
6576*38fd1498Szrj       return target;
6577*38fd1498Szrj     }
6578*38fd1498Szrj   error ("__builtin_thread_pointer is not supported on this target");
6579*38fd1498Szrj   return const0_rtx;
6580*38fd1498Szrj }
6581*38fd1498Szrj 
6582*38fd1498Szrj static void
expand_builtin_set_thread_pointer(tree exp)6583*38fd1498Szrj expand_builtin_set_thread_pointer (tree exp)
6584*38fd1498Szrj {
6585*38fd1498Szrj   enum insn_code icode;
6586*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
6587*38fd1498Szrj     return;
6588*38fd1498Szrj   icode = direct_optab_handler (set_thread_pointer_optab, Pmode);
6589*38fd1498Szrj   if (icode != CODE_FOR_nothing)
6590*38fd1498Szrj     {
6591*38fd1498Szrj       struct expand_operand op;
6592*38fd1498Szrj       rtx val = expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX,
6593*38fd1498Szrj 			     Pmode, EXPAND_NORMAL);
6594*38fd1498Szrj       create_input_operand (&op, val, Pmode);
6595*38fd1498Szrj       expand_insn (icode, 1, &op);
6596*38fd1498Szrj       return;
6597*38fd1498Szrj     }
6598*38fd1498Szrj   error ("__builtin_set_thread_pointer is not supported on this target");
6599*38fd1498Szrj }
6600*38fd1498Szrj 
6601*38fd1498Szrj 
6602*38fd1498Szrj /* Emit code to restore the current value of stack.  */
6603*38fd1498Szrj 
6604*38fd1498Szrj static void
expand_stack_restore(tree var)6605*38fd1498Szrj expand_stack_restore (tree var)
6606*38fd1498Szrj {
6607*38fd1498Szrj   rtx_insn *prev;
6608*38fd1498Szrj   rtx sa = expand_normal (var);
6609*38fd1498Szrj 
6610*38fd1498Szrj   sa = convert_memory_address (Pmode, sa);
6611*38fd1498Szrj 
6612*38fd1498Szrj   prev = get_last_insn ();
6613*38fd1498Szrj   emit_stack_restore (SAVE_BLOCK, sa);
6614*38fd1498Szrj 
6615*38fd1498Szrj   record_new_stack_level ();
6616*38fd1498Szrj 
6617*38fd1498Szrj   fixup_args_size_notes (prev, get_last_insn (), 0);
6618*38fd1498Szrj }
6619*38fd1498Szrj 
6620*38fd1498Szrj /* Emit code to save the current value of stack.  */
6621*38fd1498Szrj 
6622*38fd1498Szrj static rtx
expand_stack_save(void)6623*38fd1498Szrj expand_stack_save (void)
6624*38fd1498Szrj {
6625*38fd1498Szrj   rtx ret = NULL_RTX;
6626*38fd1498Szrj 
6627*38fd1498Szrj   emit_stack_save (SAVE_BLOCK, &ret);
6628*38fd1498Szrj   return ret;
6629*38fd1498Szrj }
6630*38fd1498Szrj 
6631*38fd1498Szrj 
6632*38fd1498Szrj /* Expand an expression EXP that calls a built-in function,
6633*38fd1498Szrj    with result going to TARGET if that's convenient
6634*38fd1498Szrj    (and in mode MODE if that's convenient).
6635*38fd1498Szrj    SUBTARGET may be used as the target for computing one of EXP's operands.
6636*38fd1498Szrj    IGNORE is nonzero if the value is to be ignored.  */
6637*38fd1498Szrj 
6638*38fd1498Szrj rtx
expand_builtin(tree exp,rtx target,rtx subtarget,machine_mode mode,int ignore)6639*38fd1498Szrj expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
6640*38fd1498Szrj 		int ignore)
6641*38fd1498Szrj {
6642*38fd1498Szrj   tree fndecl = get_callee_fndecl (exp);
6643*38fd1498Szrj   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
6644*38fd1498Szrj   machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
6645*38fd1498Szrj   int flags;
6646*38fd1498Szrj 
6647*38fd1498Szrj   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
6648*38fd1498Szrj     return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
6649*38fd1498Szrj 
6650*38fd1498Szrj   /* When ASan is enabled, we don't want to expand some memory/string
6651*38fd1498Szrj      builtins and rely on libsanitizer's hooks.  This allows us to avoid
6652*38fd1498Szrj      redundant checks and be sure, that possible overflow will be detected
6653*38fd1498Szrj      by ASan.  */
6654*38fd1498Szrj 
6655*38fd1498Szrj   if ((flag_sanitize & SANITIZE_ADDRESS) && asan_intercepted_p (fcode))
6656*38fd1498Szrj     return expand_call (exp, target, ignore);
6657*38fd1498Szrj 
6658*38fd1498Szrj   /* When not optimizing, generate calls to library functions for a certain
6659*38fd1498Szrj      set of builtins.  */
6660*38fd1498Szrj   if (!optimize
6661*38fd1498Szrj       && !called_as_built_in (fndecl)
6662*38fd1498Szrj       && fcode != BUILT_IN_FORK
6663*38fd1498Szrj       && fcode != BUILT_IN_EXECL
6664*38fd1498Szrj       && fcode != BUILT_IN_EXECV
6665*38fd1498Szrj       && fcode != BUILT_IN_EXECLP
6666*38fd1498Szrj       && fcode != BUILT_IN_EXECLE
6667*38fd1498Szrj       && fcode != BUILT_IN_EXECVP
6668*38fd1498Szrj       && fcode != BUILT_IN_EXECVE
6669*38fd1498Szrj       && !ALLOCA_FUNCTION_CODE_P (fcode)
6670*38fd1498Szrj       && fcode != BUILT_IN_FREE
6671*38fd1498Szrj       && fcode != BUILT_IN_CHKP_SET_PTR_BOUNDS
6672*38fd1498Szrj       && fcode != BUILT_IN_CHKP_INIT_PTR_BOUNDS
6673*38fd1498Szrj       && fcode != BUILT_IN_CHKP_NULL_PTR_BOUNDS
6674*38fd1498Szrj       && fcode != BUILT_IN_CHKP_COPY_PTR_BOUNDS
6675*38fd1498Szrj       && fcode != BUILT_IN_CHKP_NARROW_PTR_BOUNDS
6676*38fd1498Szrj       && fcode != BUILT_IN_CHKP_STORE_PTR_BOUNDS
6677*38fd1498Szrj       && fcode != BUILT_IN_CHKP_CHECK_PTR_LBOUNDS
6678*38fd1498Szrj       && fcode != BUILT_IN_CHKP_CHECK_PTR_UBOUNDS
6679*38fd1498Szrj       && fcode != BUILT_IN_CHKP_CHECK_PTR_BOUNDS
6680*38fd1498Szrj       && fcode != BUILT_IN_CHKP_GET_PTR_LBOUND
6681*38fd1498Szrj       && fcode != BUILT_IN_CHKP_GET_PTR_UBOUND
6682*38fd1498Szrj       && fcode != BUILT_IN_CHKP_BNDRET)
6683*38fd1498Szrj     return expand_call (exp, target, ignore);
6684*38fd1498Szrj 
6685*38fd1498Szrj   /* The built-in function expanders test for target == const0_rtx
6686*38fd1498Szrj      to determine whether the function's result will be ignored.  */
6687*38fd1498Szrj   if (ignore)
6688*38fd1498Szrj     target = const0_rtx;
6689*38fd1498Szrj 
6690*38fd1498Szrj   /* If the result of a pure or const built-in function is ignored, and
6691*38fd1498Szrj      none of its arguments are volatile, we can avoid expanding the
6692*38fd1498Szrj      built-in call and just evaluate the arguments for side-effects.  */
6693*38fd1498Szrj   if (target == const0_rtx
6694*38fd1498Szrj       && ((flags = flags_from_decl_or_type (fndecl)) & (ECF_CONST | ECF_PURE))
6695*38fd1498Szrj       && !(flags & ECF_LOOPING_CONST_OR_PURE))
6696*38fd1498Szrj     {
6697*38fd1498Szrj       bool volatilep = false;
6698*38fd1498Szrj       tree arg;
6699*38fd1498Szrj       call_expr_arg_iterator iter;
6700*38fd1498Szrj 
6701*38fd1498Szrj       FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
6702*38fd1498Szrj 	if (TREE_THIS_VOLATILE (arg))
6703*38fd1498Szrj 	  {
6704*38fd1498Szrj 	    volatilep = true;
6705*38fd1498Szrj 	    break;
6706*38fd1498Szrj 	  }
6707*38fd1498Szrj 
6708*38fd1498Szrj       if (! volatilep)
6709*38fd1498Szrj 	{
6710*38fd1498Szrj 	  FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
6711*38fd1498Szrj 	    expand_expr (arg, const0_rtx, VOIDmode, EXPAND_NORMAL);
6712*38fd1498Szrj 	  return const0_rtx;
6713*38fd1498Szrj 	}
6714*38fd1498Szrj     }
6715*38fd1498Szrj 
6716*38fd1498Szrj   /* expand_builtin_with_bounds is supposed to be used for
6717*38fd1498Szrj      instrumented builtin calls.  */
6718*38fd1498Szrj   gcc_assert (!CALL_WITH_BOUNDS_P (exp));
6719*38fd1498Szrj 
6720*38fd1498Szrj   switch (fcode)
6721*38fd1498Szrj     {
6722*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_FABS):
6723*38fd1498Szrj     CASE_FLT_FN_FLOATN_NX (BUILT_IN_FABS):
6724*38fd1498Szrj     case BUILT_IN_FABSD32:
6725*38fd1498Szrj     case BUILT_IN_FABSD64:
6726*38fd1498Szrj     case BUILT_IN_FABSD128:
6727*38fd1498Szrj       target = expand_builtin_fabs (exp, target, subtarget);
6728*38fd1498Szrj       if (target)
6729*38fd1498Szrj 	return target;
6730*38fd1498Szrj       break;
6731*38fd1498Szrj 
6732*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_COPYSIGN):
6733*38fd1498Szrj     CASE_FLT_FN_FLOATN_NX (BUILT_IN_COPYSIGN):
6734*38fd1498Szrj       target = expand_builtin_copysign (exp, target, subtarget);
6735*38fd1498Szrj       if (target)
6736*38fd1498Szrj 	return target;
6737*38fd1498Szrj       break;
6738*38fd1498Szrj 
6739*38fd1498Szrj       /* Just do a normal library call if we were unable to fold
6740*38fd1498Szrj 	 the values.  */
6741*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_CABS):
6742*38fd1498Szrj       break;
6743*38fd1498Szrj 
6744*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_FMA):
6745*38fd1498Szrj     CASE_FLT_FN_FLOATN_NX (BUILT_IN_FMA):
6746*38fd1498Szrj       target = expand_builtin_mathfn_ternary (exp, target, subtarget);
6747*38fd1498Szrj       if (target)
6748*38fd1498Szrj 	return target;
6749*38fd1498Szrj       break;
6750*38fd1498Szrj 
6751*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_ILOGB):
6752*38fd1498Szrj       if (! flag_unsafe_math_optimizations)
6753*38fd1498Szrj 	break;
6754*38fd1498Szrj       gcc_fallthrough ();
6755*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_ISINF):
6756*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_FINITE):
6757*38fd1498Szrj     case BUILT_IN_ISFINITE:
6758*38fd1498Szrj     case BUILT_IN_ISNORMAL:
6759*38fd1498Szrj       target = expand_builtin_interclass_mathfn (exp, target);
6760*38fd1498Szrj       if (target)
6761*38fd1498Szrj 	return target;
6762*38fd1498Szrj       break;
6763*38fd1498Szrj 
6764*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_ICEIL):
6765*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LCEIL):
6766*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LLCEIL):
6767*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LFLOOR):
6768*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_IFLOOR):
6769*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LLFLOOR):
6770*38fd1498Szrj       target = expand_builtin_int_roundingfn (exp, target);
6771*38fd1498Szrj       if (target)
6772*38fd1498Szrj 	return target;
6773*38fd1498Szrj       break;
6774*38fd1498Szrj 
6775*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_IRINT):
6776*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LRINT):
6777*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LLRINT):
6778*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_IROUND):
6779*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LROUND):
6780*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_LLROUND):
6781*38fd1498Szrj       target = expand_builtin_int_roundingfn_2 (exp, target);
6782*38fd1498Szrj       if (target)
6783*38fd1498Szrj 	return target;
6784*38fd1498Szrj       break;
6785*38fd1498Szrj 
6786*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_POWI):
6787*38fd1498Szrj       target = expand_builtin_powi (exp, target);
6788*38fd1498Szrj       if (target)
6789*38fd1498Szrj 	return target;
6790*38fd1498Szrj       break;
6791*38fd1498Szrj 
6792*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_CEXPI):
6793*38fd1498Szrj       target = expand_builtin_cexpi (exp, target);
6794*38fd1498Szrj       gcc_assert (target);
6795*38fd1498Szrj       return target;
6796*38fd1498Szrj 
6797*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_SIN):
6798*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_COS):
6799*38fd1498Szrj       if (! flag_unsafe_math_optimizations)
6800*38fd1498Szrj 	break;
6801*38fd1498Szrj       target = expand_builtin_mathfn_3 (exp, target, subtarget);
6802*38fd1498Szrj       if (target)
6803*38fd1498Szrj 	return target;
6804*38fd1498Szrj       break;
6805*38fd1498Szrj 
6806*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_SINCOS):
6807*38fd1498Szrj       if (! flag_unsafe_math_optimizations)
6808*38fd1498Szrj 	break;
6809*38fd1498Szrj       target = expand_builtin_sincos (exp);
6810*38fd1498Szrj       if (target)
6811*38fd1498Szrj 	return target;
6812*38fd1498Szrj       break;
6813*38fd1498Szrj 
6814*38fd1498Szrj     case BUILT_IN_APPLY_ARGS:
6815*38fd1498Szrj       return expand_builtin_apply_args ();
6816*38fd1498Szrj 
6817*38fd1498Szrj       /* __builtin_apply (FUNCTION, ARGUMENTS, ARGSIZE) invokes
6818*38fd1498Szrj 	 FUNCTION with a copy of the parameters described by
6819*38fd1498Szrj 	 ARGUMENTS, and ARGSIZE.  It returns a block of memory
6820*38fd1498Szrj 	 allocated on the stack into which is stored all the registers
6821*38fd1498Szrj 	 that might possibly be used for returning the result of a
6822*38fd1498Szrj 	 function.  ARGUMENTS is the value returned by
6823*38fd1498Szrj 	 __builtin_apply_args.  ARGSIZE is the number of bytes of
6824*38fd1498Szrj 	 arguments that must be copied.  ??? How should this value be
6825*38fd1498Szrj 	 computed?  We'll also need a safe worst case value for varargs
6826*38fd1498Szrj 	 functions.  */
6827*38fd1498Szrj     case BUILT_IN_APPLY:
6828*38fd1498Szrj       if (!validate_arglist (exp, POINTER_TYPE,
6829*38fd1498Szrj 			     POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
6830*38fd1498Szrj 	  && !validate_arglist (exp, REFERENCE_TYPE,
6831*38fd1498Szrj 				POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
6832*38fd1498Szrj 	return const0_rtx;
6833*38fd1498Szrj       else
6834*38fd1498Szrj 	{
6835*38fd1498Szrj 	  rtx ops[3];
6836*38fd1498Szrj 
6837*38fd1498Szrj 	  ops[0] = expand_normal (CALL_EXPR_ARG (exp, 0));
6838*38fd1498Szrj 	  ops[1] = expand_normal (CALL_EXPR_ARG (exp, 1));
6839*38fd1498Szrj 	  ops[2] = expand_normal (CALL_EXPR_ARG (exp, 2));
6840*38fd1498Szrj 
6841*38fd1498Szrj 	  return expand_builtin_apply (ops[0], ops[1], ops[2]);
6842*38fd1498Szrj 	}
6843*38fd1498Szrj 
6844*38fd1498Szrj       /* __builtin_return (RESULT) causes the function to return the
6845*38fd1498Szrj 	 value described by RESULT.  RESULT is address of the block of
6846*38fd1498Szrj 	 memory returned by __builtin_apply.  */
6847*38fd1498Szrj     case BUILT_IN_RETURN:
6848*38fd1498Szrj       if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
6849*38fd1498Szrj 	expand_builtin_return (expand_normal (CALL_EXPR_ARG (exp, 0)));
6850*38fd1498Szrj       return const0_rtx;
6851*38fd1498Szrj 
6852*38fd1498Szrj     case BUILT_IN_SAVEREGS:
6853*38fd1498Szrj       return expand_builtin_saveregs ();
6854*38fd1498Szrj 
6855*38fd1498Szrj     case BUILT_IN_VA_ARG_PACK:
6856*38fd1498Szrj       /* All valid uses of __builtin_va_arg_pack () are removed during
6857*38fd1498Szrj 	 inlining.  */
6858*38fd1498Szrj       error ("%Kinvalid use of %<__builtin_va_arg_pack ()%>", exp);
6859*38fd1498Szrj       return const0_rtx;
6860*38fd1498Szrj 
6861*38fd1498Szrj     case BUILT_IN_VA_ARG_PACK_LEN:
6862*38fd1498Szrj       /* All valid uses of __builtin_va_arg_pack_len () are removed during
6863*38fd1498Szrj 	 inlining.  */
6864*38fd1498Szrj       error ("%Kinvalid use of %<__builtin_va_arg_pack_len ()%>", exp);
6865*38fd1498Szrj       return const0_rtx;
6866*38fd1498Szrj 
6867*38fd1498Szrj       /* Return the address of the first anonymous stack arg.  */
6868*38fd1498Szrj     case BUILT_IN_NEXT_ARG:
6869*38fd1498Szrj       if (fold_builtin_next_arg (exp, false))
6870*38fd1498Szrj 	return const0_rtx;
6871*38fd1498Szrj       return expand_builtin_next_arg ();
6872*38fd1498Szrj 
6873*38fd1498Szrj     case BUILT_IN_CLEAR_CACHE:
6874*38fd1498Szrj       target = expand_builtin___clear_cache (exp);
6875*38fd1498Szrj       if (target)
6876*38fd1498Szrj         return target;
6877*38fd1498Szrj       break;
6878*38fd1498Szrj 
6879*38fd1498Szrj     case BUILT_IN_CLASSIFY_TYPE:
6880*38fd1498Szrj       return expand_builtin_classify_type (exp);
6881*38fd1498Szrj 
6882*38fd1498Szrj     case BUILT_IN_CONSTANT_P:
6883*38fd1498Szrj       return const0_rtx;
6884*38fd1498Szrj 
6885*38fd1498Szrj     case BUILT_IN_FRAME_ADDRESS:
6886*38fd1498Szrj     case BUILT_IN_RETURN_ADDRESS:
6887*38fd1498Szrj       return expand_builtin_frame_address (fndecl, exp);
6888*38fd1498Szrj 
6889*38fd1498Szrj     /* Returns the address of the area where the structure is returned.
6890*38fd1498Szrj        0 otherwise.  */
6891*38fd1498Szrj     case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
6892*38fd1498Szrj       if (call_expr_nargs (exp) != 0
6893*38fd1498Szrj 	  || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
6894*38fd1498Szrj 	  || !MEM_P (DECL_RTL (DECL_RESULT (current_function_decl))))
6895*38fd1498Szrj 	return const0_rtx;
6896*38fd1498Szrj       else
6897*38fd1498Szrj 	return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
6898*38fd1498Szrj 
6899*38fd1498Szrj     CASE_BUILT_IN_ALLOCA:
6900*38fd1498Szrj       target = expand_builtin_alloca (exp);
6901*38fd1498Szrj       if (target)
6902*38fd1498Szrj 	return target;
6903*38fd1498Szrj       break;
6904*38fd1498Szrj 
6905*38fd1498Szrj     case BUILT_IN_ASAN_ALLOCAS_UNPOISON:
6906*38fd1498Szrj       return expand_asan_emit_allocas_unpoison (exp);
6907*38fd1498Szrj 
6908*38fd1498Szrj     case BUILT_IN_STACK_SAVE:
6909*38fd1498Szrj       return expand_stack_save ();
6910*38fd1498Szrj 
6911*38fd1498Szrj     case BUILT_IN_STACK_RESTORE:
6912*38fd1498Szrj       expand_stack_restore (CALL_EXPR_ARG (exp, 0));
6913*38fd1498Szrj       return const0_rtx;
6914*38fd1498Szrj 
6915*38fd1498Szrj     case BUILT_IN_BSWAP16:
6916*38fd1498Szrj     case BUILT_IN_BSWAP32:
6917*38fd1498Szrj     case BUILT_IN_BSWAP64:
6918*38fd1498Szrj       target = expand_builtin_bswap (target_mode, exp, target, subtarget);
6919*38fd1498Szrj       if (target)
6920*38fd1498Szrj 	return target;
6921*38fd1498Szrj       break;
6922*38fd1498Szrj 
6923*38fd1498Szrj     CASE_INT_FN (BUILT_IN_FFS):
6924*38fd1498Szrj       target = expand_builtin_unop (target_mode, exp, target,
6925*38fd1498Szrj 				    subtarget, ffs_optab);
6926*38fd1498Szrj       if (target)
6927*38fd1498Szrj 	return target;
6928*38fd1498Szrj       break;
6929*38fd1498Szrj 
6930*38fd1498Szrj     CASE_INT_FN (BUILT_IN_CLZ):
6931*38fd1498Szrj       target = expand_builtin_unop (target_mode, exp, target,
6932*38fd1498Szrj 				    subtarget, clz_optab);
6933*38fd1498Szrj       if (target)
6934*38fd1498Szrj 	return target;
6935*38fd1498Szrj       break;
6936*38fd1498Szrj 
6937*38fd1498Szrj     CASE_INT_FN (BUILT_IN_CTZ):
6938*38fd1498Szrj       target = expand_builtin_unop (target_mode, exp, target,
6939*38fd1498Szrj 				    subtarget, ctz_optab);
6940*38fd1498Szrj       if (target)
6941*38fd1498Szrj 	return target;
6942*38fd1498Szrj       break;
6943*38fd1498Szrj 
6944*38fd1498Szrj     CASE_INT_FN (BUILT_IN_CLRSB):
6945*38fd1498Szrj       target = expand_builtin_unop (target_mode, exp, target,
6946*38fd1498Szrj 				    subtarget, clrsb_optab);
6947*38fd1498Szrj       if (target)
6948*38fd1498Szrj 	return target;
6949*38fd1498Szrj       break;
6950*38fd1498Szrj 
6951*38fd1498Szrj     CASE_INT_FN (BUILT_IN_POPCOUNT):
6952*38fd1498Szrj       target = expand_builtin_unop (target_mode, exp, target,
6953*38fd1498Szrj 				    subtarget, popcount_optab);
6954*38fd1498Szrj       if (target)
6955*38fd1498Szrj 	return target;
6956*38fd1498Szrj       break;
6957*38fd1498Szrj 
6958*38fd1498Szrj     CASE_INT_FN (BUILT_IN_PARITY):
6959*38fd1498Szrj       target = expand_builtin_unop (target_mode, exp, target,
6960*38fd1498Szrj 				    subtarget, parity_optab);
6961*38fd1498Szrj       if (target)
6962*38fd1498Szrj 	return target;
6963*38fd1498Szrj       break;
6964*38fd1498Szrj 
6965*38fd1498Szrj     case BUILT_IN_STRLEN:
6966*38fd1498Szrj       target = expand_builtin_strlen (exp, target, target_mode);
6967*38fd1498Szrj       if (target)
6968*38fd1498Szrj 	return target;
6969*38fd1498Szrj       break;
6970*38fd1498Szrj 
6971*38fd1498Szrj     case BUILT_IN_STRCAT:
6972*38fd1498Szrj       target = expand_builtin_strcat (exp, target);
6973*38fd1498Szrj       if (target)
6974*38fd1498Szrj 	return target;
6975*38fd1498Szrj       break;
6976*38fd1498Szrj 
6977*38fd1498Szrj     case BUILT_IN_STRCPY:
6978*38fd1498Szrj       target = expand_builtin_strcpy (exp, target);
6979*38fd1498Szrj       if (target)
6980*38fd1498Szrj 	return target;
6981*38fd1498Szrj       break;
6982*38fd1498Szrj 
6983*38fd1498Szrj     case BUILT_IN_STRNCAT:
6984*38fd1498Szrj       target = expand_builtin_strncat (exp, target);
6985*38fd1498Szrj       if (target)
6986*38fd1498Szrj 	return target;
6987*38fd1498Szrj       break;
6988*38fd1498Szrj 
6989*38fd1498Szrj     case BUILT_IN_STRNCPY:
6990*38fd1498Szrj       target = expand_builtin_strncpy (exp, target);
6991*38fd1498Szrj       if (target)
6992*38fd1498Szrj 	return target;
6993*38fd1498Szrj       break;
6994*38fd1498Szrj 
6995*38fd1498Szrj     case BUILT_IN_STPCPY:
6996*38fd1498Szrj       target = expand_builtin_stpcpy (exp, target, mode);
6997*38fd1498Szrj       if (target)
6998*38fd1498Szrj 	return target;
6999*38fd1498Szrj       break;
7000*38fd1498Szrj 
7001*38fd1498Szrj     case BUILT_IN_STPNCPY:
7002*38fd1498Szrj       target = expand_builtin_stpncpy (exp, target);
7003*38fd1498Szrj       if (target)
7004*38fd1498Szrj 	return target;
7005*38fd1498Szrj       break;
7006*38fd1498Szrj 
7007*38fd1498Szrj     case BUILT_IN_MEMCHR:
7008*38fd1498Szrj       target = expand_builtin_memchr (exp, target);
7009*38fd1498Szrj       if (target)
7010*38fd1498Szrj 	return target;
7011*38fd1498Szrj       break;
7012*38fd1498Szrj 
7013*38fd1498Szrj     case BUILT_IN_MEMCPY:
7014*38fd1498Szrj       target = expand_builtin_memcpy (exp, target);
7015*38fd1498Szrj       if (target)
7016*38fd1498Szrj 	return target;
7017*38fd1498Szrj       break;
7018*38fd1498Szrj 
7019*38fd1498Szrj     case BUILT_IN_MEMMOVE:
7020*38fd1498Szrj       target = expand_builtin_memmove (exp, target);
7021*38fd1498Szrj       if (target)
7022*38fd1498Szrj 	return target;
7023*38fd1498Szrj       break;
7024*38fd1498Szrj 
7025*38fd1498Szrj     case BUILT_IN_MEMPCPY:
7026*38fd1498Szrj       target = expand_builtin_mempcpy (exp, target);
7027*38fd1498Szrj       if (target)
7028*38fd1498Szrj 	return target;
7029*38fd1498Szrj       break;
7030*38fd1498Szrj 
7031*38fd1498Szrj     case BUILT_IN_MEMSET:
7032*38fd1498Szrj       target = expand_builtin_memset (exp, target, mode);
7033*38fd1498Szrj       if (target)
7034*38fd1498Szrj 	return target;
7035*38fd1498Szrj       break;
7036*38fd1498Szrj 
7037*38fd1498Szrj     case BUILT_IN_BZERO:
7038*38fd1498Szrj       target = expand_builtin_bzero (exp);
7039*38fd1498Szrj       if (target)
7040*38fd1498Szrj 	return target;
7041*38fd1498Szrj       break;
7042*38fd1498Szrj 
7043*38fd1498Szrj     case BUILT_IN_STRCMP:
7044*38fd1498Szrj       target = expand_builtin_strcmp (exp, target);
7045*38fd1498Szrj       if (target)
7046*38fd1498Szrj 	return target;
7047*38fd1498Szrj       break;
7048*38fd1498Szrj 
7049*38fd1498Szrj     case BUILT_IN_STRNCMP:
7050*38fd1498Szrj       target = expand_builtin_strncmp (exp, target, mode);
7051*38fd1498Szrj       if (target)
7052*38fd1498Szrj 	return target;
7053*38fd1498Szrj       break;
7054*38fd1498Szrj 
7055*38fd1498Szrj     case BUILT_IN_BCMP:
7056*38fd1498Szrj     case BUILT_IN_MEMCMP:
7057*38fd1498Szrj     case BUILT_IN_MEMCMP_EQ:
7058*38fd1498Szrj       target = expand_builtin_memcmp (exp, target, fcode == BUILT_IN_MEMCMP_EQ);
7059*38fd1498Szrj       if (target)
7060*38fd1498Szrj 	return target;
7061*38fd1498Szrj       if (fcode == BUILT_IN_MEMCMP_EQ)
7062*38fd1498Szrj 	{
7063*38fd1498Szrj 	  tree newdecl = builtin_decl_explicit (BUILT_IN_MEMCMP);
7064*38fd1498Szrj 	  TREE_OPERAND (exp, 1) = build_fold_addr_expr (newdecl);
7065*38fd1498Szrj 	}
7066*38fd1498Szrj       break;
7067*38fd1498Szrj 
7068*38fd1498Szrj     case BUILT_IN_SETJMP:
7069*38fd1498Szrj       /* This should have been lowered to the builtins below.  */
7070*38fd1498Szrj       gcc_unreachable ();
7071*38fd1498Szrj 
7072*38fd1498Szrj     case BUILT_IN_SETJMP_SETUP:
7073*38fd1498Szrj       /* __builtin_setjmp_setup is passed a pointer to an array of five words
7074*38fd1498Szrj           and the receiver label.  */
7075*38fd1498Szrj       if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
7076*38fd1498Szrj 	{
7077*38fd1498Szrj 	  rtx buf_addr = expand_expr (CALL_EXPR_ARG (exp, 0), subtarget,
7078*38fd1498Szrj 				      VOIDmode, EXPAND_NORMAL);
7079*38fd1498Szrj 	  tree label = TREE_OPERAND (CALL_EXPR_ARG (exp, 1), 0);
7080*38fd1498Szrj 	  rtx_insn *label_r = label_rtx (label);
7081*38fd1498Szrj 
7082*38fd1498Szrj 	  /* This is copied from the handling of non-local gotos.  */
7083*38fd1498Szrj 	  expand_builtin_setjmp_setup (buf_addr, label_r);
7084*38fd1498Szrj 	  nonlocal_goto_handler_labels
7085*38fd1498Szrj 	    = gen_rtx_INSN_LIST (VOIDmode, label_r,
7086*38fd1498Szrj 				 nonlocal_goto_handler_labels);
7087*38fd1498Szrj 	  /* ??? Do not let expand_label treat us as such since we would
7088*38fd1498Szrj 	     not want to be both on the list of non-local labels and on
7089*38fd1498Szrj 	     the list of forced labels.  */
7090*38fd1498Szrj 	  FORCED_LABEL (label) = 0;
7091*38fd1498Szrj 	  return const0_rtx;
7092*38fd1498Szrj 	}
7093*38fd1498Szrj       break;
7094*38fd1498Szrj 
7095*38fd1498Szrj     case BUILT_IN_SETJMP_RECEIVER:
7096*38fd1498Szrj        /* __builtin_setjmp_receiver is passed the receiver label.  */
7097*38fd1498Szrj       if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
7098*38fd1498Szrj 	{
7099*38fd1498Szrj 	  tree label = TREE_OPERAND (CALL_EXPR_ARG (exp, 0), 0);
7100*38fd1498Szrj 	  rtx_insn *label_r = label_rtx (label);
7101*38fd1498Szrj 
7102*38fd1498Szrj 	  expand_builtin_setjmp_receiver (label_r);
7103*38fd1498Szrj 	  return const0_rtx;
7104*38fd1498Szrj 	}
7105*38fd1498Szrj       break;
7106*38fd1498Szrj 
7107*38fd1498Szrj       /* __builtin_longjmp is passed a pointer to an array of five words.
7108*38fd1498Szrj 	 It's similar to the C library longjmp function but works with
7109*38fd1498Szrj 	 __builtin_setjmp above.  */
7110*38fd1498Szrj     case BUILT_IN_LONGJMP:
7111*38fd1498Szrj       if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
7112*38fd1498Szrj 	{
7113*38fd1498Szrj 	  rtx buf_addr = expand_expr (CALL_EXPR_ARG (exp, 0), subtarget,
7114*38fd1498Szrj 				      VOIDmode, EXPAND_NORMAL);
7115*38fd1498Szrj 	  rtx value = expand_normal (CALL_EXPR_ARG (exp, 1));
7116*38fd1498Szrj 
7117*38fd1498Szrj 	  if (value != const1_rtx)
7118*38fd1498Szrj 	    {
7119*38fd1498Szrj 	      error ("%<__builtin_longjmp%> second argument must be 1");
7120*38fd1498Szrj 	      return const0_rtx;
7121*38fd1498Szrj 	    }
7122*38fd1498Szrj 
7123*38fd1498Szrj 	  expand_builtin_longjmp (buf_addr, value);
7124*38fd1498Szrj 	  return const0_rtx;
7125*38fd1498Szrj 	}
7126*38fd1498Szrj       break;
7127*38fd1498Szrj 
7128*38fd1498Szrj     case BUILT_IN_NONLOCAL_GOTO:
7129*38fd1498Szrj       target = expand_builtin_nonlocal_goto (exp);
7130*38fd1498Szrj       if (target)
7131*38fd1498Szrj 	return target;
7132*38fd1498Szrj       break;
7133*38fd1498Szrj 
7134*38fd1498Szrj       /* This updates the setjmp buffer that is its argument with the value
7135*38fd1498Szrj 	 of the current stack pointer.  */
7136*38fd1498Szrj     case BUILT_IN_UPDATE_SETJMP_BUF:
7137*38fd1498Szrj       if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
7138*38fd1498Szrj 	{
7139*38fd1498Szrj 	  rtx buf_addr
7140*38fd1498Szrj 	    = expand_normal (CALL_EXPR_ARG (exp, 0));
7141*38fd1498Szrj 
7142*38fd1498Szrj 	  expand_builtin_update_setjmp_buf (buf_addr);
7143*38fd1498Szrj 	  return const0_rtx;
7144*38fd1498Szrj 	}
7145*38fd1498Szrj       break;
7146*38fd1498Szrj 
7147*38fd1498Szrj     case BUILT_IN_TRAP:
7148*38fd1498Szrj       expand_builtin_trap ();
7149*38fd1498Szrj       return const0_rtx;
7150*38fd1498Szrj 
7151*38fd1498Szrj     case BUILT_IN_UNREACHABLE:
7152*38fd1498Szrj       expand_builtin_unreachable ();
7153*38fd1498Szrj       return const0_rtx;
7154*38fd1498Szrj 
7155*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_SIGNBIT):
7156*38fd1498Szrj     case BUILT_IN_SIGNBITD32:
7157*38fd1498Szrj     case BUILT_IN_SIGNBITD64:
7158*38fd1498Szrj     case BUILT_IN_SIGNBITD128:
7159*38fd1498Szrj       target = expand_builtin_signbit (exp, target);
7160*38fd1498Szrj       if (target)
7161*38fd1498Szrj 	return target;
7162*38fd1498Szrj       break;
7163*38fd1498Szrj 
7164*38fd1498Szrj       /* Various hooks for the DWARF 2 __throw routine.  */
7165*38fd1498Szrj     case BUILT_IN_UNWIND_INIT:
7166*38fd1498Szrj       expand_builtin_unwind_init ();
7167*38fd1498Szrj       return const0_rtx;
7168*38fd1498Szrj     case BUILT_IN_DWARF_CFA:
7169*38fd1498Szrj       return virtual_cfa_rtx;
7170*38fd1498Szrj #ifdef DWARF2_UNWIND_INFO
7171*38fd1498Szrj     case BUILT_IN_DWARF_SP_COLUMN:
7172*38fd1498Szrj       return expand_builtin_dwarf_sp_column ();
7173*38fd1498Szrj     case BUILT_IN_INIT_DWARF_REG_SIZES:
7174*38fd1498Szrj       expand_builtin_init_dwarf_reg_sizes (CALL_EXPR_ARG (exp, 0));
7175*38fd1498Szrj       return const0_rtx;
7176*38fd1498Szrj #endif
7177*38fd1498Szrj     case BUILT_IN_FROB_RETURN_ADDR:
7178*38fd1498Szrj       return expand_builtin_frob_return_addr (CALL_EXPR_ARG (exp, 0));
7179*38fd1498Szrj     case BUILT_IN_EXTRACT_RETURN_ADDR:
7180*38fd1498Szrj       return expand_builtin_extract_return_addr (CALL_EXPR_ARG (exp, 0));
7181*38fd1498Szrj     case BUILT_IN_EH_RETURN:
7182*38fd1498Szrj       expand_builtin_eh_return (CALL_EXPR_ARG (exp, 0),
7183*38fd1498Szrj 				CALL_EXPR_ARG (exp, 1));
7184*38fd1498Szrj       return const0_rtx;
7185*38fd1498Szrj     case BUILT_IN_EH_RETURN_DATA_REGNO:
7186*38fd1498Szrj       return expand_builtin_eh_return_data_regno (exp);
7187*38fd1498Szrj     case BUILT_IN_EXTEND_POINTER:
7188*38fd1498Szrj       return expand_builtin_extend_pointer (CALL_EXPR_ARG (exp, 0));
7189*38fd1498Szrj     case BUILT_IN_EH_POINTER:
7190*38fd1498Szrj       return expand_builtin_eh_pointer (exp);
7191*38fd1498Szrj     case BUILT_IN_EH_FILTER:
7192*38fd1498Szrj       return expand_builtin_eh_filter (exp);
7193*38fd1498Szrj     case BUILT_IN_EH_COPY_VALUES:
7194*38fd1498Szrj       return expand_builtin_eh_copy_values (exp);
7195*38fd1498Szrj 
7196*38fd1498Szrj     case BUILT_IN_VA_START:
7197*38fd1498Szrj       return expand_builtin_va_start (exp);
7198*38fd1498Szrj     case BUILT_IN_VA_END:
7199*38fd1498Szrj       return expand_builtin_va_end (exp);
7200*38fd1498Szrj     case BUILT_IN_VA_COPY:
7201*38fd1498Szrj       return expand_builtin_va_copy (exp);
7202*38fd1498Szrj     case BUILT_IN_EXPECT:
7203*38fd1498Szrj       return expand_builtin_expect (exp, target);
7204*38fd1498Szrj     case BUILT_IN_ASSUME_ALIGNED:
7205*38fd1498Szrj       return expand_builtin_assume_aligned (exp, target);
7206*38fd1498Szrj     case BUILT_IN_PREFETCH:
7207*38fd1498Szrj       expand_builtin_prefetch (exp);
7208*38fd1498Szrj       return const0_rtx;
7209*38fd1498Szrj 
7210*38fd1498Szrj     case BUILT_IN_INIT_TRAMPOLINE:
7211*38fd1498Szrj       return expand_builtin_init_trampoline (exp, true);
7212*38fd1498Szrj     case BUILT_IN_INIT_HEAP_TRAMPOLINE:
7213*38fd1498Szrj       return expand_builtin_init_trampoline (exp, false);
7214*38fd1498Szrj     case BUILT_IN_ADJUST_TRAMPOLINE:
7215*38fd1498Szrj       return expand_builtin_adjust_trampoline (exp);
7216*38fd1498Szrj 
7217*38fd1498Szrj     case BUILT_IN_INIT_DESCRIPTOR:
7218*38fd1498Szrj       return expand_builtin_init_descriptor (exp);
7219*38fd1498Szrj     case BUILT_IN_ADJUST_DESCRIPTOR:
7220*38fd1498Szrj       return expand_builtin_adjust_descriptor (exp);
7221*38fd1498Szrj 
7222*38fd1498Szrj     case BUILT_IN_FORK:
7223*38fd1498Szrj     case BUILT_IN_EXECL:
7224*38fd1498Szrj     case BUILT_IN_EXECV:
7225*38fd1498Szrj     case BUILT_IN_EXECLP:
7226*38fd1498Szrj     case BUILT_IN_EXECLE:
7227*38fd1498Szrj     case BUILT_IN_EXECVP:
7228*38fd1498Szrj     case BUILT_IN_EXECVE:
7229*38fd1498Szrj       target = expand_builtin_fork_or_exec (fndecl, exp, target, ignore);
7230*38fd1498Szrj       if (target)
7231*38fd1498Szrj 	return target;
7232*38fd1498Szrj       break;
7233*38fd1498Szrj 
7234*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_ADD_1:
7235*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_ADD_2:
7236*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_ADD_4:
7237*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_ADD_8:
7238*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_ADD_16:
7239*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_ADD_1);
7240*38fd1498Szrj       target = expand_builtin_sync_operation (mode, exp, PLUS, false, target);
7241*38fd1498Szrj       if (target)
7242*38fd1498Szrj 	return target;
7243*38fd1498Szrj       break;
7244*38fd1498Szrj 
7245*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_SUB_1:
7246*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_SUB_2:
7247*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_SUB_4:
7248*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_SUB_8:
7249*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_SUB_16:
7250*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_SUB_1);
7251*38fd1498Szrj       target = expand_builtin_sync_operation (mode, exp, MINUS, false, target);
7252*38fd1498Szrj       if (target)
7253*38fd1498Szrj 	return target;
7254*38fd1498Szrj       break;
7255*38fd1498Szrj 
7256*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_OR_1:
7257*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_OR_2:
7258*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_OR_4:
7259*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_OR_8:
7260*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_OR_16:
7261*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_OR_1);
7262*38fd1498Szrj       target = expand_builtin_sync_operation (mode, exp, IOR, false, target);
7263*38fd1498Szrj       if (target)
7264*38fd1498Szrj 	return target;
7265*38fd1498Szrj       break;
7266*38fd1498Szrj 
7267*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_AND_1:
7268*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_AND_2:
7269*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_AND_4:
7270*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_AND_8:
7271*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_AND_16:
7272*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_AND_1);
7273*38fd1498Szrj       target = expand_builtin_sync_operation (mode, exp, AND, false, target);
7274*38fd1498Szrj       if (target)
7275*38fd1498Szrj 	return target;
7276*38fd1498Szrj       break;
7277*38fd1498Szrj 
7278*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_XOR_1:
7279*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_XOR_2:
7280*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_XOR_4:
7281*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_XOR_8:
7282*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_XOR_16:
7283*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_XOR_1);
7284*38fd1498Szrj       target = expand_builtin_sync_operation (mode, exp, XOR, false, target);
7285*38fd1498Szrj       if (target)
7286*38fd1498Szrj 	return target;
7287*38fd1498Szrj       break;
7288*38fd1498Szrj 
7289*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_NAND_1:
7290*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_NAND_2:
7291*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_NAND_4:
7292*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_NAND_8:
7293*38fd1498Szrj     case BUILT_IN_SYNC_FETCH_AND_NAND_16:
7294*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_NAND_1);
7295*38fd1498Szrj       target = expand_builtin_sync_operation (mode, exp, NOT, false, target);
7296*38fd1498Szrj       if (target)
7297*38fd1498Szrj 	return target;
7298*38fd1498Szrj       break;
7299*38fd1498Szrj 
7300*38fd1498Szrj     case BUILT_IN_SYNC_ADD_AND_FETCH_1:
7301*38fd1498Szrj     case BUILT_IN_SYNC_ADD_AND_FETCH_2:
7302*38fd1498Szrj     case BUILT_IN_SYNC_ADD_AND_FETCH_4:
7303*38fd1498Szrj     case BUILT_IN_SYNC_ADD_AND_FETCH_8:
7304*38fd1498Szrj     case BUILT_IN_SYNC_ADD_AND_FETCH_16:
7305*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_ADD_AND_FETCH_1);
7306*38fd1498Szrj       target = expand_builtin_sync_operation (mode, exp, PLUS, true, target);
7307*38fd1498Szrj       if (target)
7308*38fd1498Szrj 	return target;
7309*38fd1498Szrj       break;
7310*38fd1498Szrj 
7311*38fd1498Szrj     case BUILT_IN_SYNC_SUB_AND_FETCH_1:
7312*38fd1498Szrj     case BUILT_IN_SYNC_SUB_AND_FETCH_2:
7313*38fd1498Szrj     case BUILT_IN_SYNC_SUB_AND_FETCH_4:
7314*38fd1498Szrj     case BUILT_IN_SYNC_SUB_AND_FETCH_8:
7315*38fd1498Szrj     case BUILT_IN_SYNC_SUB_AND_FETCH_16:
7316*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_SUB_AND_FETCH_1);
7317*38fd1498Szrj       target = expand_builtin_sync_operation (mode, exp, MINUS, true, target);
7318*38fd1498Szrj       if (target)
7319*38fd1498Szrj 	return target;
7320*38fd1498Szrj       break;
7321*38fd1498Szrj 
7322*38fd1498Szrj     case BUILT_IN_SYNC_OR_AND_FETCH_1:
7323*38fd1498Szrj     case BUILT_IN_SYNC_OR_AND_FETCH_2:
7324*38fd1498Szrj     case BUILT_IN_SYNC_OR_AND_FETCH_4:
7325*38fd1498Szrj     case BUILT_IN_SYNC_OR_AND_FETCH_8:
7326*38fd1498Szrj     case BUILT_IN_SYNC_OR_AND_FETCH_16:
7327*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_OR_AND_FETCH_1);
7328*38fd1498Szrj       target = expand_builtin_sync_operation (mode, exp, IOR, true, target);
7329*38fd1498Szrj       if (target)
7330*38fd1498Szrj 	return target;
7331*38fd1498Szrj       break;
7332*38fd1498Szrj 
7333*38fd1498Szrj     case BUILT_IN_SYNC_AND_AND_FETCH_1:
7334*38fd1498Szrj     case BUILT_IN_SYNC_AND_AND_FETCH_2:
7335*38fd1498Szrj     case BUILT_IN_SYNC_AND_AND_FETCH_4:
7336*38fd1498Szrj     case BUILT_IN_SYNC_AND_AND_FETCH_8:
7337*38fd1498Szrj     case BUILT_IN_SYNC_AND_AND_FETCH_16:
7338*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_AND_AND_FETCH_1);
7339*38fd1498Szrj       target = expand_builtin_sync_operation (mode, exp, AND, true, target);
7340*38fd1498Szrj       if (target)
7341*38fd1498Szrj 	return target;
7342*38fd1498Szrj       break;
7343*38fd1498Szrj 
7344*38fd1498Szrj     case BUILT_IN_SYNC_XOR_AND_FETCH_1:
7345*38fd1498Szrj     case BUILT_IN_SYNC_XOR_AND_FETCH_2:
7346*38fd1498Szrj     case BUILT_IN_SYNC_XOR_AND_FETCH_4:
7347*38fd1498Szrj     case BUILT_IN_SYNC_XOR_AND_FETCH_8:
7348*38fd1498Szrj     case BUILT_IN_SYNC_XOR_AND_FETCH_16:
7349*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_XOR_AND_FETCH_1);
7350*38fd1498Szrj       target = expand_builtin_sync_operation (mode, exp, XOR, true, target);
7351*38fd1498Szrj       if (target)
7352*38fd1498Szrj 	return target;
7353*38fd1498Szrj       break;
7354*38fd1498Szrj 
7355*38fd1498Szrj     case BUILT_IN_SYNC_NAND_AND_FETCH_1:
7356*38fd1498Szrj     case BUILT_IN_SYNC_NAND_AND_FETCH_2:
7357*38fd1498Szrj     case BUILT_IN_SYNC_NAND_AND_FETCH_4:
7358*38fd1498Szrj     case BUILT_IN_SYNC_NAND_AND_FETCH_8:
7359*38fd1498Szrj     case BUILT_IN_SYNC_NAND_AND_FETCH_16:
7360*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_NAND_AND_FETCH_1);
7361*38fd1498Szrj       target = expand_builtin_sync_operation (mode, exp, NOT, true, target);
7362*38fd1498Szrj       if (target)
7363*38fd1498Szrj 	return target;
7364*38fd1498Szrj       break;
7365*38fd1498Szrj 
7366*38fd1498Szrj     case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1:
7367*38fd1498Szrj     case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_2:
7368*38fd1498Szrj     case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4:
7369*38fd1498Szrj     case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8:
7370*38fd1498Szrj     case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_16:
7371*38fd1498Szrj       if (mode == VOIDmode)
7372*38fd1498Szrj 	mode = TYPE_MODE (boolean_type_node);
7373*38fd1498Szrj       if (!target || !register_operand (target, mode))
7374*38fd1498Szrj 	target = gen_reg_rtx (mode);
7375*38fd1498Szrj 
7376*38fd1498Szrj       mode = get_builtin_sync_mode
7377*38fd1498Szrj 				(fcode - BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1);
7378*38fd1498Szrj       target = expand_builtin_compare_and_swap (mode, exp, true, target);
7379*38fd1498Szrj       if (target)
7380*38fd1498Szrj 	return target;
7381*38fd1498Szrj       break;
7382*38fd1498Szrj 
7383*38fd1498Szrj     case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_1:
7384*38fd1498Szrj     case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_2:
7385*38fd1498Szrj     case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_4:
7386*38fd1498Szrj     case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_8:
7387*38fd1498Szrj     case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_16:
7388*38fd1498Szrj       mode = get_builtin_sync_mode
7389*38fd1498Szrj 				(fcode - BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_1);
7390*38fd1498Szrj       target = expand_builtin_compare_and_swap (mode, exp, false, target);
7391*38fd1498Szrj       if (target)
7392*38fd1498Szrj 	return target;
7393*38fd1498Szrj       break;
7394*38fd1498Szrj 
7395*38fd1498Szrj     case BUILT_IN_SYNC_LOCK_TEST_AND_SET_1:
7396*38fd1498Szrj     case BUILT_IN_SYNC_LOCK_TEST_AND_SET_2:
7397*38fd1498Szrj     case BUILT_IN_SYNC_LOCK_TEST_AND_SET_4:
7398*38fd1498Szrj     case BUILT_IN_SYNC_LOCK_TEST_AND_SET_8:
7399*38fd1498Szrj     case BUILT_IN_SYNC_LOCK_TEST_AND_SET_16:
7400*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_LOCK_TEST_AND_SET_1);
7401*38fd1498Szrj       target = expand_builtin_sync_lock_test_and_set (mode, exp, target);
7402*38fd1498Szrj       if (target)
7403*38fd1498Szrj 	return target;
7404*38fd1498Szrj       break;
7405*38fd1498Szrj 
7406*38fd1498Szrj     case BUILT_IN_SYNC_LOCK_RELEASE_1:
7407*38fd1498Szrj     case BUILT_IN_SYNC_LOCK_RELEASE_2:
7408*38fd1498Szrj     case BUILT_IN_SYNC_LOCK_RELEASE_4:
7409*38fd1498Szrj     case BUILT_IN_SYNC_LOCK_RELEASE_8:
7410*38fd1498Szrj     case BUILT_IN_SYNC_LOCK_RELEASE_16:
7411*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_LOCK_RELEASE_1);
7412*38fd1498Szrj       expand_builtin_sync_lock_release (mode, exp);
7413*38fd1498Szrj       return const0_rtx;
7414*38fd1498Szrj 
7415*38fd1498Szrj     case BUILT_IN_SYNC_SYNCHRONIZE:
7416*38fd1498Szrj       expand_builtin_sync_synchronize ();
7417*38fd1498Szrj       return const0_rtx;
7418*38fd1498Szrj 
7419*38fd1498Szrj     case BUILT_IN_ATOMIC_EXCHANGE_1:
7420*38fd1498Szrj     case BUILT_IN_ATOMIC_EXCHANGE_2:
7421*38fd1498Szrj     case BUILT_IN_ATOMIC_EXCHANGE_4:
7422*38fd1498Szrj     case BUILT_IN_ATOMIC_EXCHANGE_8:
7423*38fd1498Szrj     case BUILT_IN_ATOMIC_EXCHANGE_16:
7424*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_EXCHANGE_1);
7425*38fd1498Szrj       target = expand_builtin_atomic_exchange (mode, exp, target);
7426*38fd1498Szrj       if (target)
7427*38fd1498Szrj 	return target;
7428*38fd1498Szrj       break;
7429*38fd1498Szrj 
7430*38fd1498Szrj     case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1:
7431*38fd1498Szrj     case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_2:
7432*38fd1498Szrj     case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4:
7433*38fd1498Szrj     case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8:
7434*38fd1498Szrj     case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16:
7435*38fd1498Szrj       {
7436*38fd1498Szrj 	unsigned int nargs, z;
7437*38fd1498Szrj 	vec<tree, va_gc> *vec;
7438*38fd1498Szrj 
7439*38fd1498Szrj 	mode =
7440*38fd1498Szrj 	    get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1);
7441*38fd1498Szrj 	target = expand_builtin_atomic_compare_exchange (mode, exp, target);
7442*38fd1498Szrj 	if (target)
7443*38fd1498Szrj 	  return target;
7444*38fd1498Szrj 
7445*38fd1498Szrj 	/* If this is turned into an external library call, the weak parameter
7446*38fd1498Szrj 	   must be dropped to match the expected parameter list.  */
7447*38fd1498Szrj 	nargs = call_expr_nargs (exp);
7448*38fd1498Szrj 	vec_alloc (vec, nargs - 1);
7449*38fd1498Szrj 	for (z = 0; z < 3; z++)
7450*38fd1498Szrj 	  vec->quick_push (CALL_EXPR_ARG (exp, z));
7451*38fd1498Szrj 	/* Skip the boolean weak parameter.  */
7452*38fd1498Szrj 	for (z = 4; z < 6; z++)
7453*38fd1498Szrj 	  vec->quick_push (CALL_EXPR_ARG (exp, z));
7454*38fd1498Szrj 	exp = build_call_vec (TREE_TYPE (exp), CALL_EXPR_FN (exp), vec);
7455*38fd1498Szrj 	break;
7456*38fd1498Szrj       }
7457*38fd1498Szrj 
7458*38fd1498Szrj     case BUILT_IN_ATOMIC_LOAD_1:
7459*38fd1498Szrj     case BUILT_IN_ATOMIC_LOAD_2:
7460*38fd1498Szrj     case BUILT_IN_ATOMIC_LOAD_4:
7461*38fd1498Szrj     case BUILT_IN_ATOMIC_LOAD_8:
7462*38fd1498Szrj     case BUILT_IN_ATOMIC_LOAD_16:
7463*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_LOAD_1);
7464*38fd1498Szrj       target = expand_builtin_atomic_load (mode, exp, target);
7465*38fd1498Szrj       if (target)
7466*38fd1498Szrj 	return target;
7467*38fd1498Szrj       break;
7468*38fd1498Szrj 
7469*38fd1498Szrj     case BUILT_IN_ATOMIC_STORE_1:
7470*38fd1498Szrj     case BUILT_IN_ATOMIC_STORE_2:
7471*38fd1498Szrj     case BUILT_IN_ATOMIC_STORE_4:
7472*38fd1498Szrj     case BUILT_IN_ATOMIC_STORE_8:
7473*38fd1498Szrj     case BUILT_IN_ATOMIC_STORE_16:
7474*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_STORE_1);
7475*38fd1498Szrj       target = expand_builtin_atomic_store (mode, exp);
7476*38fd1498Szrj       if (target)
7477*38fd1498Szrj 	return const0_rtx;
7478*38fd1498Szrj       break;
7479*38fd1498Szrj 
7480*38fd1498Szrj     case BUILT_IN_ATOMIC_ADD_FETCH_1:
7481*38fd1498Szrj     case BUILT_IN_ATOMIC_ADD_FETCH_2:
7482*38fd1498Szrj     case BUILT_IN_ATOMIC_ADD_FETCH_4:
7483*38fd1498Szrj     case BUILT_IN_ATOMIC_ADD_FETCH_8:
7484*38fd1498Szrj     case BUILT_IN_ATOMIC_ADD_FETCH_16:
7485*38fd1498Szrj       {
7486*38fd1498Szrj 	enum built_in_function lib;
7487*38fd1498Szrj 	mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_ADD_FETCH_1);
7488*38fd1498Szrj 	lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_ADD_1 +
7489*38fd1498Szrj 				       (fcode - BUILT_IN_ATOMIC_ADD_FETCH_1));
7490*38fd1498Szrj 	target = expand_builtin_atomic_fetch_op (mode, exp, target, PLUS, true,
7491*38fd1498Szrj 						 ignore, lib);
7492*38fd1498Szrj 	if (target)
7493*38fd1498Szrj 	  return target;
7494*38fd1498Szrj 	break;
7495*38fd1498Szrj       }
7496*38fd1498Szrj     case BUILT_IN_ATOMIC_SUB_FETCH_1:
7497*38fd1498Szrj     case BUILT_IN_ATOMIC_SUB_FETCH_2:
7498*38fd1498Szrj     case BUILT_IN_ATOMIC_SUB_FETCH_4:
7499*38fd1498Szrj     case BUILT_IN_ATOMIC_SUB_FETCH_8:
7500*38fd1498Szrj     case BUILT_IN_ATOMIC_SUB_FETCH_16:
7501*38fd1498Szrj       {
7502*38fd1498Szrj 	enum built_in_function lib;
7503*38fd1498Szrj 	mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_SUB_FETCH_1);
7504*38fd1498Szrj 	lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_SUB_1 +
7505*38fd1498Szrj 				       (fcode - BUILT_IN_ATOMIC_SUB_FETCH_1));
7506*38fd1498Szrj 	target = expand_builtin_atomic_fetch_op (mode, exp, target, MINUS, true,
7507*38fd1498Szrj 						 ignore, lib);
7508*38fd1498Szrj 	if (target)
7509*38fd1498Szrj 	  return target;
7510*38fd1498Szrj 	break;
7511*38fd1498Szrj       }
7512*38fd1498Szrj     case BUILT_IN_ATOMIC_AND_FETCH_1:
7513*38fd1498Szrj     case BUILT_IN_ATOMIC_AND_FETCH_2:
7514*38fd1498Szrj     case BUILT_IN_ATOMIC_AND_FETCH_4:
7515*38fd1498Szrj     case BUILT_IN_ATOMIC_AND_FETCH_8:
7516*38fd1498Szrj     case BUILT_IN_ATOMIC_AND_FETCH_16:
7517*38fd1498Szrj       {
7518*38fd1498Szrj 	enum built_in_function lib;
7519*38fd1498Szrj 	mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_AND_FETCH_1);
7520*38fd1498Szrj 	lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_AND_1 +
7521*38fd1498Szrj 				       (fcode - BUILT_IN_ATOMIC_AND_FETCH_1));
7522*38fd1498Szrj 	target = expand_builtin_atomic_fetch_op (mode, exp, target, AND, true,
7523*38fd1498Szrj 						 ignore, lib);
7524*38fd1498Szrj 	if (target)
7525*38fd1498Szrj 	  return target;
7526*38fd1498Szrj 	break;
7527*38fd1498Szrj       }
7528*38fd1498Szrj     case BUILT_IN_ATOMIC_NAND_FETCH_1:
7529*38fd1498Szrj     case BUILT_IN_ATOMIC_NAND_FETCH_2:
7530*38fd1498Szrj     case BUILT_IN_ATOMIC_NAND_FETCH_4:
7531*38fd1498Szrj     case BUILT_IN_ATOMIC_NAND_FETCH_8:
7532*38fd1498Szrj     case BUILT_IN_ATOMIC_NAND_FETCH_16:
7533*38fd1498Szrj       {
7534*38fd1498Szrj 	enum built_in_function lib;
7535*38fd1498Szrj 	mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_NAND_FETCH_1);
7536*38fd1498Szrj 	lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_NAND_1 +
7537*38fd1498Szrj 				       (fcode - BUILT_IN_ATOMIC_NAND_FETCH_1));
7538*38fd1498Szrj 	target = expand_builtin_atomic_fetch_op (mode, exp, target, NOT, true,
7539*38fd1498Szrj 						 ignore, lib);
7540*38fd1498Szrj 	if (target)
7541*38fd1498Szrj 	  return target;
7542*38fd1498Szrj 	break;
7543*38fd1498Szrj       }
7544*38fd1498Szrj     case BUILT_IN_ATOMIC_XOR_FETCH_1:
7545*38fd1498Szrj     case BUILT_IN_ATOMIC_XOR_FETCH_2:
7546*38fd1498Szrj     case BUILT_IN_ATOMIC_XOR_FETCH_4:
7547*38fd1498Szrj     case BUILT_IN_ATOMIC_XOR_FETCH_8:
7548*38fd1498Szrj     case BUILT_IN_ATOMIC_XOR_FETCH_16:
7549*38fd1498Szrj       {
7550*38fd1498Szrj 	enum built_in_function lib;
7551*38fd1498Szrj 	mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_XOR_FETCH_1);
7552*38fd1498Szrj 	lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_XOR_1 +
7553*38fd1498Szrj 				       (fcode - BUILT_IN_ATOMIC_XOR_FETCH_1));
7554*38fd1498Szrj 	target = expand_builtin_atomic_fetch_op (mode, exp, target, XOR, true,
7555*38fd1498Szrj 						 ignore, lib);
7556*38fd1498Szrj 	if (target)
7557*38fd1498Szrj 	  return target;
7558*38fd1498Szrj 	break;
7559*38fd1498Szrj       }
7560*38fd1498Szrj     case BUILT_IN_ATOMIC_OR_FETCH_1:
7561*38fd1498Szrj     case BUILT_IN_ATOMIC_OR_FETCH_2:
7562*38fd1498Szrj     case BUILT_IN_ATOMIC_OR_FETCH_4:
7563*38fd1498Szrj     case BUILT_IN_ATOMIC_OR_FETCH_8:
7564*38fd1498Szrj     case BUILT_IN_ATOMIC_OR_FETCH_16:
7565*38fd1498Szrj       {
7566*38fd1498Szrj 	enum built_in_function lib;
7567*38fd1498Szrj 	mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_OR_FETCH_1);
7568*38fd1498Szrj 	lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_OR_1 +
7569*38fd1498Szrj 				       (fcode - BUILT_IN_ATOMIC_OR_FETCH_1));
7570*38fd1498Szrj 	target = expand_builtin_atomic_fetch_op (mode, exp, target, IOR, true,
7571*38fd1498Szrj 						 ignore, lib);
7572*38fd1498Szrj 	if (target)
7573*38fd1498Szrj 	  return target;
7574*38fd1498Szrj 	break;
7575*38fd1498Szrj       }
7576*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_ADD_1:
7577*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_ADD_2:
7578*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_ADD_4:
7579*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_ADD_8:
7580*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_ADD_16:
7581*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_ADD_1);
7582*38fd1498Szrj       target = expand_builtin_atomic_fetch_op (mode, exp, target, PLUS, false,
7583*38fd1498Szrj 					       ignore, BUILT_IN_NONE);
7584*38fd1498Szrj       if (target)
7585*38fd1498Szrj 	return target;
7586*38fd1498Szrj       break;
7587*38fd1498Szrj 
7588*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_SUB_1:
7589*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_SUB_2:
7590*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_SUB_4:
7591*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_SUB_8:
7592*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_SUB_16:
7593*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_SUB_1);
7594*38fd1498Szrj       target = expand_builtin_atomic_fetch_op (mode, exp, target, MINUS, false,
7595*38fd1498Szrj 					       ignore, BUILT_IN_NONE);
7596*38fd1498Szrj       if (target)
7597*38fd1498Szrj 	return target;
7598*38fd1498Szrj       break;
7599*38fd1498Szrj 
7600*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_AND_1:
7601*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_AND_2:
7602*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_AND_4:
7603*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_AND_8:
7604*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_AND_16:
7605*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_AND_1);
7606*38fd1498Szrj       target = expand_builtin_atomic_fetch_op (mode, exp, target, AND, false,
7607*38fd1498Szrj 					       ignore, BUILT_IN_NONE);
7608*38fd1498Szrj       if (target)
7609*38fd1498Szrj 	return target;
7610*38fd1498Szrj       break;
7611*38fd1498Szrj 
7612*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_NAND_1:
7613*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_NAND_2:
7614*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_NAND_4:
7615*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_NAND_8:
7616*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_NAND_16:
7617*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_NAND_1);
7618*38fd1498Szrj       target = expand_builtin_atomic_fetch_op (mode, exp, target, NOT, false,
7619*38fd1498Szrj 					       ignore, BUILT_IN_NONE);
7620*38fd1498Szrj       if (target)
7621*38fd1498Szrj 	return target;
7622*38fd1498Szrj       break;
7623*38fd1498Szrj 
7624*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_XOR_1:
7625*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_XOR_2:
7626*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_XOR_4:
7627*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_XOR_8:
7628*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_XOR_16:
7629*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_XOR_1);
7630*38fd1498Szrj       target = expand_builtin_atomic_fetch_op (mode, exp, target, XOR, false,
7631*38fd1498Szrj 					       ignore, BUILT_IN_NONE);
7632*38fd1498Szrj       if (target)
7633*38fd1498Szrj 	return target;
7634*38fd1498Szrj       break;
7635*38fd1498Szrj 
7636*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_OR_1:
7637*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_OR_2:
7638*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_OR_4:
7639*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_OR_8:
7640*38fd1498Szrj     case BUILT_IN_ATOMIC_FETCH_OR_16:
7641*38fd1498Szrj       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_OR_1);
7642*38fd1498Szrj       target = expand_builtin_atomic_fetch_op (mode, exp, target, IOR, false,
7643*38fd1498Szrj 					       ignore, BUILT_IN_NONE);
7644*38fd1498Szrj       if (target)
7645*38fd1498Szrj 	return target;
7646*38fd1498Szrj       break;
7647*38fd1498Szrj 
7648*38fd1498Szrj     case BUILT_IN_ATOMIC_TEST_AND_SET:
7649*38fd1498Szrj       return expand_builtin_atomic_test_and_set (exp, target);
7650*38fd1498Szrj 
7651*38fd1498Szrj     case BUILT_IN_ATOMIC_CLEAR:
7652*38fd1498Szrj       return expand_builtin_atomic_clear (exp);
7653*38fd1498Szrj 
7654*38fd1498Szrj     case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
7655*38fd1498Szrj       return expand_builtin_atomic_always_lock_free (exp);
7656*38fd1498Szrj 
7657*38fd1498Szrj     case BUILT_IN_ATOMIC_IS_LOCK_FREE:
7658*38fd1498Szrj       target = expand_builtin_atomic_is_lock_free (exp);
7659*38fd1498Szrj       if (target)
7660*38fd1498Szrj         return target;
7661*38fd1498Szrj       break;
7662*38fd1498Szrj 
7663*38fd1498Szrj     case BUILT_IN_ATOMIC_THREAD_FENCE:
7664*38fd1498Szrj       expand_builtin_atomic_thread_fence (exp);
7665*38fd1498Szrj       return const0_rtx;
7666*38fd1498Szrj 
7667*38fd1498Szrj     case BUILT_IN_ATOMIC_SIGNAL_FENCE:
7668*38fd1498Szrj       expand_builtin_atomic_signal_fence (exp);
7669*38fd1498Szrj       return const0_rtx;
7670*38fd1498Szrj 
7671*38fd1498Szrj     case BUILT_IN_OBJECT_SIZE:
7672*38fd1498Szrj       return expand_builtin_object_size (exp);
7673*38fd1498Szrj 
7674*38fd1498Szrj     case BUILT_IN_MEMCPY_CHK:
7675*38fd1498Szrj     case BUILT_IN_MEMPCPY_CHK:
7676*38fd1498Szrj     case BUILT_IN_MEMMOVE_CHK:
7677*38fd1498Szrj     case BUILT_IN_MEMSET_CHK:
7678*38fd1498Szrj       target = expand_builtin_memory_chk (exp, target, mode, fcode);
7679*38fd1498Szrj       if (target)
7680*38fd1498Szrj 	return target;
7681*38fd1498Szrj       break;
7682*38fd1498Szrj 
7683*38fd1498Szrj     case BUILT_IN_STRCPY_CHK:
7684*38fd1498Szrj     case BUILT_IN_STPCPY_CHK:
7685*38fd1498Szrj     case BUILT_IN_STRNCPY_CHK:
7686*38fd1498Szrj     case BUILT_IN_STPNCPY_CHK:
7687*38fd1498Szrj     case BUILT_IN_STRCAT_CHK:
7688*38fd1498Szrj     case BUILT_IN_STRNCAT_CHK:
7689*38fd1498Szrj     case BUILT_IN_SNPRINTF_CHK:
7690*38fd1498Szrj     case BUILT_IN_VSNPRINTF_CHK:
7691*38fd1498Szrj       maybe_emit_chk_warning (exp, fcode);
7692*38fd1498Szrj       break;
7693*38fd1498Szrj 
7694*38fd1498Szrj     case BUILT_IN_SPRINTF_CHK:
7695*38fd1498Szrj     case BUILT_IN_VSPRINTF_CHK:
7696*38fd1498Szrj       maybe_emit_sprintf_chk_warning (exp, fcode);
7697*38fd1498Szrj       break;
7698*38fd1498Szrj 
7699*38fd1498Szrj     case BUILT_IN_FREE:
7700*38fd1498Szrj       if (warn_free_nonheap_object)
7701*38fd1498Szrj 	maybe_emit_free_warning (exp);
7702*38fd1498Szrj       break;
7703*38fd1498Szrj 
7704*38fd1498Szrj     case BUILT_IN_THREAD_POINTER:
7705*38fd1498Szrj       return expand_builtin_thread_pointer (exp, target);
7706*38fd1498Szrj 
7707*38fd1498Szrj     case BUILT_IN_SET_THREAD_POINTER:
7708*38fd1498Szrj       expand_builtin_set_thread_pointer (exp);
7709*38fd1498Szrj       return const0_rtx;
7710*38fd1498Szrj 
7711*38fd1498Szrj     case BUILT_IN_CHKP_INIT_PTR_BOUNDS:
7712*38fd1498Szrj     case BUILT_IN_CHKP_NULL_PTR_BOUNDS:
7713*38fd1498Szrj     case BUILT_IN_CHKP_COPY_PTR_BOUNDS:
7714*38fd1498Szrj     case BUILT_IN_CHKP_CHECK_PTR_LBOUNDS:
7715*38fd1498Szrj     case BUILT_IN_CHKP_CHECK_PTR_UBOUNDS:
7716*38fd1498Szrj     case BUILT_IN_CHKP_CHECK_PTR_BOUNDS:
7717*38fd1498Szrj     case BUILT_IN_CHKP_SET_PTR_BOUNDS:
7718*38fd1498Szrj     case BUILT_IN_CHKP_NARROW_PTR_BOUNDS:
7719*38fd1498Szrj     case BUILT_IN_CHKP_STORE_PTR_BOUNDS:
7720*38fd1498Szrj     case BUILT_IN_CHKP_GET_PTR_LBOUND:
7721*38fd1498Szrj     case BUILT_IN_CHKP_GET_PTR_UBOUND:
7722*38fd1498Szrj       /* We allow user CHKP builtins if Pointer Bounds
7723*38fd1498Szrj 	 Checker is off.  */
7724*38fd1498Szrj       if (!chkp_function_instrumented_p (current_function_decl))
7725*38fd1498Szrj 	{
7726*38fd1498Szrj 	  if (fcode == BUILT_IN_CHKP_SET_PTR_BOUNDS
7727*38fd1498Szrj 	      || fcode == BUILT_IN_CHKP_NARROW_PTR_BOUNDS
7728*38fd1498Szrj 	      || fcode == BUILT_IN_CHKP_INIT_PTR_BOUNDS
7729*38fd1498Szrj 	      || fcode == BUILT_IN_CHKP_NULL_PTR_BOUNDS
7730*38fd1498Szrj 	      || fcode == BUILT_IN_CHKP_COPY_PTR_BOUNDS)
7731*38fd1498Szrj 	    return expand_normal (CALL_EXPR_ARG (exp, 0));
7732*38fd1498Szrj 	  else if (fcode == BUILT_IN_CHKP_GET_PTR_LBOUND)
7733*38fd1498Szrj 	    return expand_normal (size_zero_node);
7734*38fd1498Szrj 	  else if (fcode == BUILT_IN_CHKP_GET_PTR_UBOUND)
7735*38fd1498Szrj 	    return expand_normal (size_int (-1));
7736*38fd1498Szrj 	  else
7737*38fd1498Szrj 	    return const0_rtx;
7738*38fd1498Szrj 	}
7739*38fd1498Szrj       /* FALLTHROUGH */
7740*38fd1498Szrj 
7741*38fd1498Szrj     case BUILT_IN_CHKP_BNDMK:
7742*38fd1498Szrj     case BUILT_IN_CHKP_BNDSTX:
7743*38fd1498Szrj     case BUILT_IN_CHKP_BNDCL:
7744*38fd1498Szrj     case BUILT_IN_CHKP_BNDCU:
7745*38fd1498Szrj     case BUILT_IN_CHKP_BNDLDX:
7746*38fd1498Szrj     case BUILT_IN_CHKP_BNDRET:
7747*38fd1498Szrj     case BUILT_IN_CHKP_INTERSECT:
7748*38fd1498Szrj     case BUILT_IN_CHKP_NARROW:
7749*38fd1498Szrj     case BUILT_IN_CHKP_EXTRACT_LOWER:
7750*38fd1498Szrj     case BUILT_IN_CHKP_EXTRACT_UPPER:
7751*38fd1498Szrj       /* Software implementation of Pointer Bounds Checker is NYI.
7752*38fd1498Szrj 	 Target support is required.  */
7753*38fd1498Szrj       error ("Your target platform does not support -fcheck-pointer-bounds");
7754*38fd1498Szrj       break;
7755*38fd1498Szrj 
7756*38fd1498Szrj     case BUILT_IN_ACC_ON_DEVICE:
7757*38fd1498Szrj       /* Do library call, if we failed to expand the builtin when
7758*38fd1498Szrj 	 folding.  */
7759*38fd1498Szrj       break;
7760*38fd1498Szrj 
7761*38fd1498Szrj     default:	/* just do library call, if unknown builtin */
7762*38fd1498Szrj       break;
7763*38fd1498Szrj     }
7764*38fd1498Szrj 
7765*38fd1498Szrj   /* The switch statement above can drop through to cause the function
7766*38fd1498Szrj      to be called normally.  */
7767*38fd1498Szrj   return expand_call (exp, target, ignore);
7768*38fd1498Szrj }
7769*38fd1498Szrj 
7770*38fd1498Szrj /* Similar to expand_builtin but is used for instrumented calls.  */
7771*38fd1498Szrj 
7772*38fd1498Szrj rtx
expand_builtin_with_bounds(tree exp,rtx target,rtx subtarget ATTRIBUTE_UNUSED,machine_mode mode,int ignore)7773*38fd1498Szrj expand_builtin_with_bounds (tree exp, rtx target,
7774*38fd1498Szrj 			    rtx subtarget ATTRIBUTE_UNUSED,
7775*38fd1498Szrj 			    machine_mode mode, int ignore)
7776*38fd1498Szrj {
7777*38fd1498Szrj   tree fndecl = get_callee_fndecl (exp);
7778*38fd1498Szrj   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
7779*38fd1498Szrj 
7780*38fd1498Szrj   gcc_assert (CALL_WITH_BOUNDS_P (exp));
7781*38fd1498Szrj 
7782*38fd1498Szrj   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
7783*38fd1498Szrj     return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
7784*38fd1498Szrj 
7785*38fd1498Szrj   gcc_assert (fcode > BEGIN_CHKP_BUILTINS
7786*38fd1498Szrj 	      && fcode < END_CHKP_BUILTINS);
7787*38fd1498Szrj 
7788*38fd1498Szrj   switch (fcode)
7789*38fd1498Szrj     {
7790*38fd1498Szrj     case BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK_CHKP:
7791*38fd1498Szrj       target = expand_builtin_memcpy_with_bounds (exp, target);
7792*38fd1498Szrj       if (target)
7793*38fd1498Szrj 	return target;
7794*38fd1498Szrj       break;
7795*38fd1498Szrj 
7796*38fd1498Szrj     case BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK_CHKP:
7797*38fd1498Szrj       target = expand_builtin_mempcpy_with_bounds (exp, target);
7798*38fd1498Szrj       if (target)
7799*38fd1498Szrj 	return target;
7800*38fd1498Szrj       break;
7801*38fd1498Szrj 
7802*38fd1498Szrj     case BUILT_IN_CHKP_MEMSET_NOBND_NOCHK_CHKP:
7803*38fd1498Szrj       target = expand_builtin_memset_with_bounds (exp, target, mode);
7804*38fd1498Szrj       if (target)
7805*38fd1498Szrj 	return target;
7806*38fd1498Szrj       break;
7807*38fd1498Szrj 
7808*38fd1498Szrj     case BUILT_IN_MEMCPY_CHKP:
7809*38fd1498Szrj     case BUILT_IN_MEMMOVE_CHKP:
7810*38fd1498Szrj     case BUILT_IN_MEMPCPY_CHKP:
7811*38fd1498Szrj       if (call_expr_nargs (exp) > 3)
7812*38fd1498Szrj 	{
7813*38fd1498Szrj 	  /* memcpy_chkp (void *dst, size_t dstbnd,
7814*38fd1498Szrj 	                  const void *src, size_t srcbnd, size_t n)
7815*38fd1498Szrj   	     and others take a pointer bound argument just after each
7816*38fd1498Szrj 	     pointer argument.  */
7817*38fd1498Szrj 	  tree dest = CALL_EXPR_ARG (exp, 0);
7818*38fd1498Szrj 	  tree src = CALL_EXPR_ARG (exp, 2);
7819*38fd1498Szrj 	  tree len = CALL_EXPR_ARG (exp, 4);
7820*38fd1498Szrj 
7821*38fd1498Szrj 	  check_memop_access (exp, dest, src, len);
7822*38fd1498Szrj 	  break;
7823*38fd1498Szrj 	}
7824*38fd1498Szrj 
7825*38fd1498Szrj     default:
7826*38fd1498Szrj       break;
7827*38fd1498Szrj     }
7828*38fd1498Szrj 
7829*38fd1498Szrj   /* The switch statement above can drop through to cause the function
7830*38fd1498Szrj      to be called normally.  */
7831*38fd1498Szrj   return expand_call (exp, target, ignore);
7832*38fd1498Szrj  }
7833*38fd1498Szrj 
7834*38fd1498Szrj /* Determine whether a tree node represents a call to a built-in
7835*38fd1498Szrj    function.  If the tree T is a call to a built-in function with
7836*38fd1498Szrj    the right number of arguments of the appropriate types, return
7837*38fd1498Szrj    the DECL_FUNCTION_CODE of the call, e.g. BUILT_IN_SQRT.
7838*38fd1498Szrj    Otherwise the return value is END_BUILTINS.  */
7839*38fd1498Szrj 
7840*38fd1498Szrj enum built_in_function
builtin_mathfn_code(const_tree t)7841*38fd1498Szrj builtin_mathfn_code (const_tree t)
7842*38fd1498Szrj {
7843*38fd1498Szrj   const_tree fndecl, arg, parmlist;
7844*38fd1498Szrj   const_tree argtype, parmtype;
7845*38fd1498Szrj   const_call_expr_arg_iterator iter;
7846*38fd1498Szrj 
7847*38fd1498Szrj   if (TREE_CODE (t) != CALL_EXPR)
7848*38fd1498Szrj     return END_BUILTINS;
7849*38fd1498Szrj 
7850*38fd1498Szrj   fndecl = get_callee_fndecl (t);
7851*38fd1498Szrj   if (fndecl == NULL_TREE
7852*38fd1498Szrj       || TREE_CODE (fndecl) != FUNCTION_DECL
7853*38fd1498Szrj       || ! DECL_BUILT_IN (fndecl)
7854*38fd1498Szrj       || DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
7855*38fd1498Szrj     return END_BUILTINS;
7856*38fd1498Szrj 
7857*38fd1498Szrj   parmlist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
7858*38fd1498Szrj   init_const_call_expr_arg_iterator (t, &iter);
7859*38fd1498Szrj   for (; parmlist; parmlist = TREE_CHAIN (parmlist))
7860*38fd1498Szrj     {
7861*38fd1498Szrj       /* If a function doesn't take a variable number of arguments,
7862*38fd1498Szrj 	 the last element in the list will have type `void'.  */
7863*38fd1498Szrj       parmtype = TREE_VALUE (parmlist);
7864*38fd1498Szrj       if (VOID_TYPE_P (parmtype))
7865*38fd1498Szrj 	{
7866*38fd1498Szrj 	  if (more_const_call_expr_args_p (&iter))
7867*38fd1498Szrj 	    return END_BUILTINS;
7868*38fd1498Szrj 	  return DECL_FUNCTION_CODE (fndecl);
7869*38fd1498Szrj 	}
7870*38fd1498Szrj 
7871*38fd1498Szrj       if (! more_const_call_expr_args_p (&iter))
7872*38fd1498Szrj 	return END_BUILTINS;
7873*38fd1498Szrj 
7874*38fd1498Szrj       arg = next_const_call_expr_arg (&iter);
7875*38fd1498Szrj       argtype = TREE_TYPE (arg);
7876*38fd1498Szrj 
7877*38fd1498Szrj       if (SCALAR_FLOAT_TYPE_P (parmtype))
7878*38fd1498Szrj 	{
7879*38fd1498Szrj 	  if (! SCALAR_FLOAT_TYPE_P (argtype))
7880*38fd1498Szrj 	    return END_BUILTINS;
7881*38fd1498Szrj 	}
7882*38fd1498Szrj       else if (COMPLEX_FLOAT_TYPE_P (parmtype))
7883*38fd1498Szrj 	{
7884*38fd1498Szrj 	  if (! COMPLEX_FLOAT_TYPE_P (argtype))
7885*38fd1498Szrj 	    return END_BUILTINS;
7886*38fd1498Szrj 	}
7887*38fd1498Szrj       else if (POINTER_TYPE_P (parmtype))
7888*38fd1498Szrj 	{
7889*38fd1498Szrj 	  if (! POINTER_TYPE_P (argtype))
7890*38fd1498Szrj 	    return END_BUILTINS;
7891*38fd1498Szrj 	}
7892*38fd1498Szrj       else if (INTEGRAL_TYPE_P (parmtype))
7893*38fd1498Szrj 	{
7894*38fd1498Szrj 	  if (! INTEGRAL_TYPE_P (argtype))
7895*38fd1498Szrj 	    return END_BUILTINS;
7896*38fd1498Szrj 	}
7897*38fd1498Szrj       else
7898*38fd1498Szrj 	return END_BUILTINS;
7899*38fd1498Szrj     }
7900*38fd1498Szrj 
7901*38fd1498Szrj   /* Variable-length argument list.  */
7902*38fd1498Szrj   return DECL_FUNCTION_CODE (fndecl);
7903*38fd1498Szrj }
7904*38fd1498Szrj 
7905*38fd1498Szrj /* Fold a call to __builtin_constant_p, if we know its argument ARG will
7906*38fd1498Szrj    evaluate to a constant.  */
7907*38fd1498Szrj 
7908*38fd1498Szrj static tree
fold_builtin_constant_p(tree arg)7909*38fd1498Szrj fold_builtin_constant_p (tree arg)
7910*38fd1498Szrj {
7911*38fd1498Szrj   /* We return 1 for a numeric type that's known to be a constant
7912*38fd1498Szrj      value at compile-time or for an aggregate type that's a
7913*38fd1498Szrj      literal constant.  */
7914*38fd1498Szrj   STRIP_NOPS (arg);
7915*38fd1498Szrj 
7916*38fd1498Szrj   /* If we know this is a constant, emit the constant of one.  */
7917*38fd1498Szrj   if (CONSTANT_CLASS_P (arg)
7918*38fd1498Szrj       || (TREE_CODE (arg) == CONSTRUCTOR
7919*38fd1498Szrj 	  && TREE_CONSTANT (arg)))
7920*38fd1498Szrj     return integer_one_node;
7921*38fd1498Szrj   if (TREE_CODE (arg) == ADDR_EXPR)
7922*38fd1498Szrj     {
7923*38fd1498Szrj        tree op = TREE_OPERAND (arg, 0);
7924*38fd1498Szrj        if (TREE_CODE (op) == STRING_CST
7925*38fd1498Szrj 	   || (TREE_CODE (op) == ARRAY_REF
7926*38fd1498Szrj 	       && integer_zerop (TREE_OPERAND (op, 1))
7927*38fd1498Szrj 	       && TREE_CODE (TREE_OPERAND (op, 0)) == STRING_CST))
7928*38fd1498Szrj 	 return integer_one_node;
7929*38fd1498Szrj     }
7930*38fd1498Szrj 
7931*38fd1498Szrj   /* If this expression has side effects, show we don't know it to be a
7932*38fd1498Szrj      constant.  Likewise if it's a pointer or aggregate type since in
7933*38fd1498Szrj      those case we only want literals, since those are only optimized
7934*38fd1498Szrj      when generating RTL, not later.
7935*38fd1498Szrj      And finally, if we are compiling an initializer, not code, we
7936*38fd1498Szrj      need to return a definite result now; there's not going to be any
7937*38fd1498Szrj      more optimization done.  */
7938*38fd1498Szrj   if (TREE_SIDE_EFFECTS (arg)
7939*38fd1498Szrj       || AGGREGATE_TYPE_P (TREE_TYPE (arg))
7940*38fd1498Szrj       || POINTER_TYPE_P (TREE_TYPE (arg))
7941*38fd1498Szrj       || cfun == 0
7942*38fd1498Szrj       || folding_initializer
7943*38fd1498Szrj       || force_folding_builtin_constant_p)
7944*38fd1498Szrj     return integer_zero_node;
7945*38fd1498Szrj 
7946*38fd1498Szrj   return NULL_TREE;
7947*38fd1498Szrj }
7948*38fd1498Szrj 
7949*38fd1498Szrj /* Create builtin_expect with PRED and EXPECTED as its arguments and
7950*38fd1498Szrj    return it as a truthvalue.  */
7951*38fd1498Szrj 
7952*38fd1498Szrj static tree
build_builtin_expect_predicate(location_t loc,tree pred,tree expected,tree predictor)7953*38fd1498Szrj build_builtin_expect_predicate (location_t loc, tree pred, tree expected,
7954*38fd1498Szrj 				tree predictor)
7955*38fd1498Szrj {
7956*38fd1498Szrj   tree fn, arg_types, pred_type, expected_type, call_expr, ret_type;
7957*38fd1498Szrj 
7958*38fd1498Szrj   fn = builtin_decl_explicit (BUILT_IN_EXPECT);
7959*38fd1498Szrj   arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
7960*38fd1498Szrj   ret_type = TREE_TYPE (TREE_TYPE (fn));
7961*38fd1498Szrj   pred_type = TREE_VALUE (arg_types);
7962*38fd1498Szrj   expected_type = TREE_VALUE (TREE_CHAIN (arg_types));
7963*38fd1498Szrj 
7964*38fd1498Szrj   pred = fold_convert_loc (loc, pred_type, pred);
7965*38fd1498Szrj   expected = fold_convert_loc (loc, expected_type, expected);
7966*38fd1498Szrj   call_expr = build_call_expr_loc (loc, fn, predictor ? 3 : 2, pred, expected,
7967*38fd1498Szrj 				   predictor);
7968*38fd1498Szrj 
7969*38fd1498Szrj   return build2 (NE_EXPR, TREE_TYPE (pred), call_expr,
7970*38fd1498Szrj 		 build_int_cst (ret_type, 0));
7971*38fd1498Szrj }
7972*38fd1498Szrj 
7973*38fd1498Szrj /* Fold a call to builtin_expect with arguments ARG0 and ARG1.  Return
7974*38fd1498Szrj    NULL_TREE if no simplification is possible.  */
7975*38fd1498Szrj 
7976*38fd1498Szrj tree
fold_builtin_expect(location_t loc,tree arg0,tree arg1,tree arg2)7977*38fd1498Szrj fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2)
7978*38fd1498Szrj {
7979*38fd1498Szrj   tree inner, fndecl, inner_arg0;
7980*38fd1498Szrj   enum tree_code code;
7981*38fd1498Szrj 
7982*38fd1498Szrj   /* Distribute the expected value over short-circuiting operators.
7983*38fd1498Szrj      See through the cast from truthvalue_type_node to long.  */
7984*38fd1498Szrj   inner_arg0 = arg0;
7985*38fd1498Szrj   while (CONVERT_EXPR_P (inner_arg0)
7986*38fd1498Szrj 	 && INTEGRAL_TYPE_P (TREE_TYPE (inner_arg0))
7987*38fd1498Szrj 	 && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (inner_arg0, 0))))
7988*38fd1498Szrj     inner_arg0 = TREE_OPERAND (inner_arg0, 0);
7989*38fd1498Szrj 
7990*38fd1498Szrj   /* If this is a builtin_expect within a builtin_expect keep the
7991*38fd1498Szrj      inner one.  See through a comparison against a constant.  It
7992*38fd1498Szrj      might have been added to create a thruthvalue.  */
7993*38fd1498Szrj   inner = inner_arg0;
7994*38fd1498Szrj 
7995*38fd1498Szrj   if (COMPARISON_CLASS_P (inner)
7996*38fd1498Szrj       && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST)
7997*38fd1498Szrj     inner = TREE_OPERAND (inner, 0);
7998*38fd1498Szrj 
7999*38fd1498Szrj   if (TREE_CODE (inner) == CALL_EXPR
8000*38fd1498Szrj       && (fndecl = get_callee_fndecl (inner))
8001*38fd1498Szrj       && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
8002*38fd1498Szrj       && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT)
8003*38fd1498Szrj     return arg0;
8004*38fd1498Szrj 
8005*38fd1498Szrj   inner = inner_arg0;
8006*38fd1498Szrj   code = TREE_CODE (inner);
8007*38fd1498Szrj   if (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
8008*38fd1498Szrj     {
8009*38fd1498Szrj       tree op0 = TREE_OPERAND (inner, 0);
8010*38fd1498Szrj       tree op1 = TREE_OPERAND (inner, 1);
8011*38fd1498Szrj       arg1 = save_expr (arg1);
8012*38fd1498Szrj 
8013*38fd1498Szrj       op0 = build_builtin_expect_predicate (loc, op0, arg1, arg2);
8014*38fd1498Szrj       op1 = build_builtin_expect_predicate (loc, op1, arg1, arg2);
8015*38fd1498Szrj       inner = build2 (code, TREE_TYPE (inner), op0, op1);
8016*38fd1498Szrj 
8017*38fd1498Szrj       return fold_convert_loc (loc, TREE_TYPE (arg0), inner);
8018*38fd1498Szrj     }
8019*38fd1498Szrj 
8020*38fd1498Szrj   /* If the argument isn't invariant then there's nothing else we can do.  */
8021*38fd1498Szrj   if (!TREE_CONSTANT (inner_arg0))
8022*38fd1498Szrj     return NULL_TREE;
8023*38fd1498Szrj 
8024*38fd1498Szrj   /* If we expect that a comparison against the argument will fold to
8025*38fd1498Szrj      a constant return the constant.  In practice, this means a true
8026*38fd1498Szrj      constant or the address of a non-weak symbol.  */
8027*38fd1498Szrj   inner = inner_arg0;
8028*38fd1498Szrj   STRIP_NOPS (inner);
8029*38fd1498Szrj   if (TREE_CODE (inner) == ADDR_EXPR)
8030*38fd1498Szrj     {
8031*38fd1498Szrj       do
8032*38fd1498Szrj 	{
8033*38fd1498Szrj 	  inner = TREE_OPERAND (inner, 0);
8034*38fd1498Szrj 	}
8035*38fd1498Szrj       while (TREE_CODE (inner) == COMPONENT_REF
8036*38fd1498Szrj 	     || TREE_CODE (inner) == ARRAY_REF);
8037*38fd1498Szrj       if (VAR_OR_FUNCTION_DECL_P (inner) && DECL_WEAK (inner))
8038*38fd1498Szrj 	return NULL_TREE;
8039*38fd1498Szrj     }
8040*38fd1498Szrj 
8041*38fd1498Szrj   /* Otherwise, ARG0 already has the proper type for the return value.  */
8042*38fd1498Szrj   return arg0;
8043*38fd1498Szrj }
8044*38fd1498Szrj 
8045*38fd1498Szrj /* Fold a call to __builtin_classify_type with argument ARG.  */
8046*38fd1498Szrj 
8047*38fd1498Szrj static tree
fold_builtin_classify_type(tree arg)8048*38fd1498Szrj fold_builtin_classify_type (tree arg)
8049*38fd1498Szrj {
8050*38fd1498Szrj   if (arg == 0)
8051*38fd1498Szrj     return build_int_cst (integer_type_node, no_type_class);
8052*38fd1498Szrj 
8053*38fd1498Szrj   return build_int_cst (integer_type_node, type_to_class (TREE_TYPE (arg)));
8054*38fd1498Szrj }
8055*38fd1498Szrj 
8056*38fd1498Szrj /* Fold a call to __builtin_strlen with argument ARG.  */
8057*38fd1498Szrj 
8058*38fd1498Szrj static tree
fold_builtin_strlen(location_t loc,tree type,tree arg)8059*38fd1498Szrj fold_builtin_strlen (location_t loc, tree type, tree arg)
8060*38fd1498Szrj {
8061*38fd1498Szrj   if (!validate_arg (arg, POINTER_TYPE))
8062*38fd1498Szrj     return NULL_TREE;
8063*38fd1498Szrj   else
8064*38fd1498Szrj     {
8065*38fd1498Szrj       tree len = c_strlen (arg, 0);
8066*38fd1498Szrj 
8067*38fd1498Szrj       if (len)
8068*38fd1498Szrj 	return fold_convert_loc (loc, type, len);
8069*38fd1498Szrj 
8070*38fd1498Szrj       return NULL_TREE;
8071*38fd1498Szrj     }
8072*38fd1498Szrj }
8073*38fd1498Szrj 
8074*38fd1498Szrj /* Fold a call to __builtin_inf or __builtin_huge_val.  */
8075*38fd1498Szrj 
8076*38fd1498Szrj static tree
fold_builtin_inf(location_t loc,tree type,int warn)8077*38fd1498Szrj fold_builtin_inf (location_t loc, tree type, int warn)
8078*38fd1498Szrj {
8079*38fd1498Szrj   REAL_VALUE_TYPE real;
8080*38fd1498Szrj 
8081*38fd1498Szrj   /* __builtin_inff is intended to be usable to define INFINITY on all
8082*38fd1498Szrj      targets.  If an infinity is not available, INFINITY expands "to a
8083*38fd1498Szrj      positive constant of type float that overflows at translation
8084*38fd1498Szrj      time", footnote "In this case, using INFINITY will violate the
8085*38fd1498Szrj      constraint in 6.4.4 and thus require a diagnostic." (C99 7.12#4).
8086*38fd1498Szrj      Thus we pedwarn to ensure this constraint violation is
8087*38fd1498Szrj      diagnosed.  */
8088*38fd1498Szrj   if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) && warn)
8089*38fd1498Szrj     pedwarn (loc, 0, "target format does not support infinity");
8090*38fd1498Szrj 
8091*38fd1498Szrj   real_inf (&real);
8092*38fd1498Szrj   return build_real (type, real);
8093*38fd1498Szrj }
8094*38fd1498Szrj 
8095*38fd1498Szrj /* Fold function call to builtin sincos, sincosf, or sincosl.  Return
8096*38fd1498Szrj    NULL_TREE if no simplification can be made.  */
8097*38fd1498Szrj 
8098*38fd1498Szrj static tree
fold_builtin_sincos(location_t loc,tree arg0,tree arg1,tree arg2)8099*38fd1498Szrj fold_builtin_sincos (location_t loc,
8100*38fd1498Szrj 		     tree arg0, tree arg1, tree arg2)
8101*38fd1498Szrj {
8102*38fd1498Szrj   tree type;
8103*38fd1498Szrj   tree fndecl, call = NULL_TREE;
8104*38fd1498Szrj 
8105*38fd1498Szrj   if (!validate_arg (arg0, REAL_TYPE)
8106*38fd1498Szrj       || !validate_arg (arg1, POINTER_TYPE)
8107*38fd1498Szrj       || !validate_arg (arg2, POINTER_TYPE))
8108*38fd1498Szrj     return NULL_TREE;
8109*38fd1498Szrj 
8110*38fd1498Szrj   type = TREE_TYPE (arg0);
8111*38fd1498Szrj 
8112*38fd1498Szrj   /* Calculate the result when the argument is a constant.  */
8113*38fd1498Szrj   built_in_function fn = mathfn_built_in_2 (type, CFN_BUILT_IN_CEXPI);
8114*38fd1498Szrj   if (fn == END_BUILTINS)
8115*38fd1498Szrj     return NULL_TREE;
8116*38fd1498Szrj 
8117*38fd1498Szrj   /* Canonicalize sincos to cexpi.  */
8118*38fd1498Szrj   if (TREE_CODE (arg0) == REAL_CST)
8119*38fd1498Szrj     {
8120*38fd1498Szrj       tree complex_type = build_complex_type (type);
8121*38fd1498Szrj       call = fold_const_call (as_combined_fn (fn), complex_type, arg0);
8122*38fd1498Szrj     }
8123*38fd1498Szrj   if (!call)
8124*38fd1498Szrj     {
8125*38fd1498Szrj       if (!targetm.libc_has_function (function_c99_math_complex)
8126*38fd1498Szrj 	  || !builtin_decl_implicit_p (fn))
8127*38fd1498Szrj 	return NULL_TREE;
8128*38fd1498Szrj       fndecl = builtin_decl_explicit (fn);
8129*38fd1498Szrj       call = build_call_expr_loc (loc, fndecl, 1, arg0);
8130*38fd1498Szrj       call = builtin_save_expr (call);
8131*38fd1498Szrj     }
8132*38fd1498Szrj 
8133*38fd1498Szrj   return build2 (COMPOUND_EXPR, void_type_node,
8134*38fd1498Szrj 		 build2 (MODIFY_EXPR, void_type_node,
8135*38fd1498Szrj 			 build_fold_indirect_ref_loc (loc, arg1),
8136*38fd1498Szrj 			 fold_build1_loc (loc, IMAGPART_EXPR, type, call)),
8137*38fd1498Szrj 		 build2 (MODIFY_EXPR, void_type_node,
8138*38fd1498Szrj 			 build_fold_indirect_ref_loc (loc, arg2),
8139*38fd1498Szrj 			 fold_build1_loc (loc, REALPART_EXPR, type, call)));
8140*38fd1498Szrj }
8141*38fd1498Szrj 
8142*38fd1498Szrj /* Fold function call to builtin memcmp with arguments ARG1 and ARG2.
8143*38fd1498Szrj    Return NULL_TREE if no simplification can be made.  */
8144*38fd1498Szrj 
8145*38fd1498Szrj static tree
fold_builtin_memcmp(location_t loc,tree arg1,tree arg2,tree len)8146*38fd1498Szrj fold_builtin_memcmp (location_t loc, tree arg1, tree arg2, tree len)
8147*38fd1498Szrj {
8148*38fd1498Szrj   if (!validate_arg (arg1, POINTER_TYPE)
8149*38fd1498Szrj       || !validate_arg (arg2, POINTER_TYPE)
8150*38fd1498Szrj       || !validate_arg (len, INTEGER_TYPE))
8151*38fd1498Szrj     return NULL_TREE;
8152*38fd1498Szrj 
8153*38fd1498Szrj   /* If the LEN parameter is zero, return zero.  */
8154*38fd1498Szrj   if (integer_zerop (len))
8155*38fd1498Szrj     return omit_two_operands_loc (loc, integer_type_node, integer_zero_node,
8156*38fd1498Szrj 			      arg1, arg2);
8157*38fd1498Szrj 
8158*38fd1498Szrj   /* If ARG1 and ARG2 are the same (and not volatile), return zero.  */
8159*38fd1498Szrj   if (operand_equal_p (arg1, arg2, 0))
8160*38fd1498Szrj     return omit_one_operand_loc (loc, integer_type_node, integer_zero_node, len);
8161*38fd1498Szrj 
8162*38fd1498Szrj   /* If len parameter is one, return an expression corresponding to
8163*38fd1498Szrj      (*(const unsigned char*)arg1 - (const unsigned char*)arg2).  */
8164*38fd1498Szrj   if (tree_fits_uhwi_p (len) && tree_to_uhwi (len) == 1)
8165*38fd1498Szrj     {
8166*38fd1498Szrj       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
8167*38fd1498Szrj       tree cst_uchar_ptr_node
8168*38fd1498Szrj 	= build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
8169*38fd1498Szrj 
8170*38fd1498Szrj       tree ind1
8171*38fd1498Szrj 	= fold_convert_loc (loc, integer_type_node,
8172*38fd1498Szrj 			    build1 (INDIRECT_REF, cst_uchar_node,
8173*38fd1498Szrj 				    fold_convert_loc (loc,
8174*38fd1498Szrj 						      cst_uchar_ptr_node,
8175*38fd1498Szrj 						      arg1)));
8176*38fd1498Szrj       tree ind2
8177*38fd1498Szrj 	= fold_convert_loc (loc, integer_type_node,
8178*38fd1498Szrj 			    build1 (INDIRECT_REF, cst_uchar_node,
8179*38fd1498Szrj 				    fold_convert_loc (loc,
8180*38fd1498Szrj 						      cst_uchar_ptr_node,
8181*38fd1498Szrj 						      arg2)));
8182*38fd1498Szrj       return fold_build2_loc (loc, MINUS_EXPR, integer_type_node, ind1, ind2);
8183*38fd1498Szrj     }
8184*38fd1498Szrj 
8185*38fd1498Szrj   return NULL_TREE;
8186*38fd1498Szrj }
8187*38fd1498Szrj 
8188*38fd1498Szrj /* Fold a call to builtin isascii with argument ARG.  */
8189*38fd1498Szrj 
8190*38fd1498Szrj static tree
fold_builtin_isascii(location_t loc,tree arg)8191*38fd1498Szrj fold_builtin_isascii (location_t loc, tree arg)
8192*38fd1498Szrj {
8193*38fd1498Szrj   if (!validate_arg (arg, INTEGER_TYPE))
8194*38fd1498Szrj     return NULL_TREE;
8195*38fd1498Szrj   else
8196*38fd1498Szrj     {
8197*38fd1498Szrj       /* Transform isascii(c) -> ((c & ~0x7f) == 0).  */
8198*38fd1498Szrj       arg = fold_build2 (BIT_AND_EXPR, integer_type_node, arg,
8199*38fd1498Szrj 			 build_int_cst (integer_type_node,
8200*38fd1498Szrj 					~ (unsigned HOST_WIDE_INT) 0x7f));
8201*38fd1498Szrj       return fold_build2_loc (loc, EQ_EXPR, integer_type_node,
8202*38fd1498Szrj 			      arg, integer_zero_node);
8203*38fd1498Szrj     }
8204*38fd1498Szrj }
8205*38fd1498Szrj 
8206*38fd1498Szrj /* Fold a call to builtin toascii with argument ARG.  */
8207*38fd1498Szrj 
8208*38fd1498Szrj static tree
fold_builtin_toascii(location_t loc,tree arg)8209*38fd1498Szrj fold_builtin_toascii (location_t loc, tree arg)
8210*38fd1498Szrj {
8211*38fd1498Szrj   if (!validate_arg (arg, INTEGER_TYPE))
8212*38fd1498Szrj     return NULL_TREE;
8213*38fd1498Szrj 
8214*38fd1498Szrj   /* Transform toascii(c) -> (c & 0x7f).  */
8215*38fd1498Szrj   return fold_build2_loc (loc, BIT_AND_EXPR, integer_type_node, arg,
8216*38fd1498Szrj 			  build_int_cst (integer_type_node, 0x7f));
8217*38fd1498Szrj }
8218*38fd1498Szrj 
8219*38fd1498Szrj /* Fold a call to builtin isdigit with argument ARG.  */
8220*38fd1498Szrj 
8221*38fd1498Szrj static tree
fold_builtin_isdigit(location_t loc,tree arg)8222*38fd1498Szrj fold_builtin_isdigit (location_t loc, tree arg)
8223*38fd1498Szrj {
8224*38fd1498Szrj   if (!validate_arg (arg, INTEGER_TYPE))
8225*38fd1498Szrj     return NULL_TREE;
8226*38fd1498Szrj   else
8227*38fd1498Szrj     {
8228*38fd1498Szrj       /* Transform isdigit(c) -> (unsigned)(c) - '0' <= 9.  */
8229*38fd1498Szrj       /* According to the C standard, isdigit is unaffected by locale.
8230*38fd1498Szrj 	 However, it definitely is affected by the target character set.  */
8231*38fd1498Szrj       unsigned HOST_WIDE_INT target_digit0
8232*38fd1498Szrj 	= lang_hooks.to_target_charset ('0');
8233*38fd1498Szrj 
8234*38fd1498Szrj       if (target_digit0 == 0)
8235*38fd1498Szrj 	return NULL_TREE;
8236*38fd1498Szrj 
8237*38fd1498Szrj       arg = fold_convert_loc (loc, unsigned_type_node, arg);
8238*38fd1498Szrj       arg = fold_build2 (MINUS_EXPR, unsigned_type_node, arg,
8239*38fd1498Szrj 			 build_int_cst (unsigned_type_node, target_digit0));
8240*38fd1498Szrj       return fold_build2_loc (loc, LE_EXPR, integer_type_node, arg,
8241*38fd1498Szrj 			  build_int_cst (unsigned_type_node, 9));
8242*38fd1498Szrj     }
8243*38fd1498Szrj }
8244*38fd1498Szrj 
8245*38fd1498Szrj /* Fold a call to fabs, fabsf or fabsl with argument ARG.  */
8246*38fd1498Szrj 
8247*38fd1498Szrj static tree
fold_builtin_fabs(location_t loc,tree arg,tree type)8248*38fd1498Szrj fold_builtin_fabs (location_t loc, tree arg, tree type)
8249*38fd1498Szrj {
8250*38fd1498Szrj   if (!validate_arg (arg, REAL_TYPE))
8251*38fd1498Szrj     return NULL_TREE;
8252*38fd1498Szrj 
8253*38fd1498Szrj   arg = fold_convert_loc (loc, type, arg);
8254*38fd1498Szrj   return fold_build1_loc (loc, ABS_EXPR, type, arg);
8255*38fd1498Szrj }
8256*38fd1498Szrj 
8257*38fd1498Szrj /* Fold a call to abs, labs, llabs or imaxabs with argument ARG.  */
8258*38fd1498Szrj 
8259*38fd1498Szrj static tree
fold_builtin_abs(location_t loc,tree arg,tree type)8260*38fd1498Szrj fold_builtin_abs (location_t loc, tree arg, tree type)
8261*38fd1498Szrj {
8262*38fd1498Szrj   if (!validate_arg (arg, INTEGER_TYPE))
8263*38fd1498Szrj     return NULL_TREE;
8264*38fd1498Szrj 
8265*38fd1498Szrj   arg = fold_convert_loc (loc, type, arg);
8266*38fd1498Szrj   return fold_build1_loc (loc, ABS_EXPR, type, arg);
8267*38fd1498Szrj }
8268*38fd1498Szrj 
8269*38fd1498Szrj /* Fold a call to fma, fmaf, or fmal with arguments ARG[012].  */
8270*38fd1498Szrj 
8271*38fd1498Szrj static tree
fold_builtin_fma(location_t loc,tree arg0,tree arg1,tree arg2,tree type)8272*38fd1498Szrj fold_builtin_fma (location_t loc, tree arg0, tree arg1, tree arg2, tree type)
8273*38fd1498Szrj {
8274*38fd1498Szrj   /* ??? Only expand to FMA_EXPR if it's directly supported.  */
8275*38fd1498Szrj   if (validate_arg (arg0, REAL_TYPE)
8276*38fd1498Szrj       && validate_arg (arg1, REAL_TYPE)
8277*38fd1498Szrj       && validate_arg (arg2, REAL_TYPE)
8278*38fd1498Szrj       && optab_handler (fma_optab, TYPE_MODE (type)) != CODE_FOR_nothing)
8279*38fd1498Szrj     return fold_build3_loc (loc, FMA_EXPR, type, arg0, arg1, arg2);
8280*38fd1498Szrj 
8281*38fd1498Szrj   return NULL_TREE;
8282*38fd1498Szrj }
8283*38fd1498Szrj 
8284*38fd1498Szrj /* Fold a call to builtin carg(a+bi) -> atan2(b,a).  */
8285*38fd1498Szrj 
8286*38fd1498Szrj static tree
fold_builtin_carg(location_t loc,tree arg,tree type)8287*38fd1498Szrj fold_builtin_carg (location_t loc, tree arg, tree type)
8288*38fd1498Szrj {
8289*38fd1498Szrj   if (validate_arg (arg, COMPLEX_TYPE)
8290*38fd1498Szrj       && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE)
8291*38fd1498Szrj     {
8292*38fd1498Szrj       tree atan2_fn = mathfn_built_in (type, BUILT_IN_ATAN2);
8293*38fd1498Szrj 
8294*38fd1498Szrj       if (atan2_fn)
8295*38fd1498Szrj         {
8296*38fd1498Szrj   	  tree new_arg = builtin_save_expr (arg);
8297*38fd1498Szrj 	  tree r_arg = fold_build1_loc (loc, REALPART_EXPR, type, new_arg);
8298*38fd1498Szrj 	  tree i_arg = fold_build1_loc (loc, IMAGPART_EXPR, type, new_arg);
8299*38fd1498Szrj 	  return build_call_expr_loc (loc, atan2_fn, 2, i_arg, r_arg);
8300*38fd1498Szrj 	}
8301*38fd1498Szrj     }
8302*38fd1498Szrj 
8303*38fd1498Szrj   return NULL_TREE;
8304*38fd1498Szrj }
8305*38fd1498Szrj 
8306*38fd1498Szrj /* Fold a call to builtin frexp, we can assume the base is 2.  */
8307*38fd1498Szrj 
8308*38fd1498Szrj static tree
fold_builtin_frexp(location_t loc,tree arg0,tree arg1,tree rettype)8309*38fd1498Szrj fold_builtin_frexp (location_t loc, tree arg0, tree arg1, tree rettype)
8310*38fd1498Szrj {
8311*38fd1498Szrj   if (! validate_arg (arg0, REAL_TYPE) || ! validate_arg (arg1, POINTER_TYPE))
8312*38fd1498Szrj     return NULL_TREE;
8313*38fd1498Szrj 
8314*38fd1498Szrj   STRIP_NOPS (arg0);
8315*38fd1498Szrj 
8316*38fd1498Szrj   if (!(TREE_CODE (arg0) == REAL_CST && ! TREE_OVERFLOW (arg0)))
8317*38fd1498Szrj     return NULL_TREE;
8318*38fd1498Szrj 
8319*38fd1498Szrj   arg1 = build_fold_indirect_ref_loc (loc, arg1);
8320*38fd1498Szrj 
8321*38fd1498Szrj   /* Proceed if a valid pointer type was passed in.  */
8322*38fd1498Szrj   if (TYPE_MAIN_VARIANT (TREE_TYPE (arg1)) == integer_type_node)
8323*38fd1498Szrj     {
8324*38fd1498Szrj       const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg0);
8325*38fd1498Szrj       tree frac, exp;
8326*38fd1498Szrj 
8327*38fd1498Szrj       switch (value->cl)
8328*38fd1498Szrj       {
8329*38fd1498Szrj       case rvc_zero:
8330*38fd1498Szrj 	/* For +-0, return (*exp = 0, +-0).  */
8331*38fd1498Szrj 	exp = integer_zero_node;
8332*38fd1498Szrj 	frac = arg0;
8333*38fd1498Szrj 	break;
8334*38fd1498Szrj       case rvc_nan:
8335*38fd1498Szrj       case rvc_inf:
8336*38fd1498Szrj 	/* For +-NaN or +-Inf, *exp is unspecified, return arg0.  */
8337*38fd1498Szrj 	return omit_one_operand_loc (loc, rettype, arg0, arg1);
8338*38fd1498Szrj       case rvc_normal:
8339*38fd1498Szrj 	{
8340*38fd1498Szrj 	  /* Since the frexp function always expects base 2, and in
8341*38fd1498Szrj 	     GCC normalized significands are already in the range
8342*38fd1498Szrj 	     [0.5, 1.0), we have exactly what frexp wants.  */
8343*38fd1498Szrj 	  REAL_VALUE_TYPE frac_rvt = *value;
8344*38fd1498Szrj 	  SET_REAL_EXP (&frac_rvt, 0);
8345*38fd1498Szrj 	  frac = build_real (rettype, frac_rvt);
8346*38fd1498Szrj 	  exp = build_int_cst (integer_type_node, REAL_EXP (value));
8347*38fd1498Szrj 	}
8348*38fd1498Szrj 	break;
8349*38fd1498Szrj       default:
8350*38fd1498Szrj 	gcc_unreachable ();
8351*38fd1498Szrj       }
8352*38fd1498Szrj 
8353*38fd1498Szrj       /* Create the COMPOUND_EXPR (*arg1 = trunc, frac). */
8354*38fd1498Szrj       arg1 = fold_build2_loc (loc, MODIFY_EXPR, rettype, arg1, exp);
8355*38fd1498Szrj       TREE_SIDE_EFFECTS (arg1) = 1;
8356*38fd1498Szrj       return fold_build2_loc (loc, COMPOUND_EXPR, rettype, arg1, frac);
8357*38fd1498Szrj     }
8358*38fd1498Szrj 
8359*38fd1498Szrj   return NULL_TREE;
8360*38fd1498Szrj }
8361*38fd1498Szrj 
8362*38fd1498Szrj /* Fold a call to builtin modf.  */
8363*38fd1498Szrj 
8364*38fd1498Szrj static tree
fold_builtin_modf(location_t loc,tree arg0,tree arg1,tree rettype)8365*38fd1498Szrj fold_builtin_modf (location_t loc, tree arg0, tree arg1, tree rettype)
8366*38fd1498Szrj {
8367*38fd1498Szrj   if (! validate_arg (arg0, REAL_TYPE) || ! validate_arg (arg1, POINTER_TYPE))
8368*38fd1498Szrj     return NULL_TREE;
8369*38fd1498Szrj 
8370*38fd1498Szrj   STRIP_NOPS (arg0);
8371*38fd1498Szrj 
8372*38fd1498Szrj   if (!(TREE_CODE (arg0) == REAL_CST && ! TREE_OVERFLOW (arg0)))
8373*38fd1498Szrj     return NULL_TREE;
8374*38fd1498Szrj 
8375*38fd1498Szrj   arg1 = build_fold_indirect_ref_loc (loc, arg1);
8376*38fd1498Szrj 
8377*38fd1498Szrj   /* Proceed if a valid pointer type was passed in.  */
8378*38fd1498Szrj   if (TYPE_MAIN_VARIANT (TREE_TYPE (arg1)) == TYPE_MAIN_VARIANT (rettype))
8379*38fd1498Szrj     {
8380*38fd1498Szrj       const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg0);
8381*38fd1498Szrj       REAL_VALUE_TYPE trunc, frac;
8382*38fd1498Szrj 
8383*38fd1498Szrj       switch (value->cl)
8384*38fd1498Szrj       {
8385*38fd1498Szrj       case rvc_nan:
8386*38fd1498Szrj       case rvc_zero:
8387*38fd1498Szrj 	/* For +-NaN or +-0, return (*arg1 = arg0, arg0).  */
8388*38fd1498Szrj 	trunc = frac = *value;
8389*38fd1498Szrj 	break;
8390*38fd1498Szrj       case rvc_inf:
8391*38fd1498Szrj 	/* For +-Inf, return (*arg1 = arg0, +-0).  */
8392*38fd1498Szrj 	frac = dconst0;
8393*38fd1498Szrj 	frac.sign = value->sign;
8394*38fd1498Szrj 	trunc = *value;
8395*38fd1498Szrj 	break;
8396*38fd1498Szrj       case rvc_normal:
8397*38fd1498Szrj 	/* Return (*arg1 = trunc(arg0), arg0-trunc(arg0)).  */
8398*38fd1498Szrj 	real_trunc (&trunc, VOIDmode, value);
8399*38fd1498Szrj 	real_arithmetic (&frac, MINUS_EXPR, value, &trunc);
8400*38fd1498Szrj 	/* If the original number was negative and already
8401*38fd1498Szrj 	   integral, then the fractional part is -0.0.  */
8402*38fd1498Szrj 	if (value->sign && frac.cl == rvc_zero)
8403*38fd1498Szrj 	  frac.sign = value->sign;
8404*38fd1498Szrj 	break;
8405*38fd1498Szrj       }
8406*38fd1498Szrj 
8407*38fd1498Szrj       /* Create the COMPOUND_EXPR (*arg1 = trunc, frac). */
8408*38fd1498Szrj       arg1 = fold_build2_loc (loc, MODIFY_EXPR, rettype, arg1,
8409*38fd1498Szrj 			  build_real (rettype, trunc));
8410*38fd1498Szrj       TREE_SIDE_EFFECTS (arg1) = 1;
8411*38fd1498Szrj       return fold_build2_loc (loc, COMPOUND_EXPR, rettype, arg1,
8412*38fd1498Szrj 			  build_real (rettype, frac));
8413*38fd1498Szrj     }
8414*38fd1498Szrj 
8415*38fd1498Szrj   return NULL_TREE;
8416*38fd1498Szrj }
8417*38fd1498Szrj 
8418*38fd1498Szrj /* Given a location LOC, an interclass builtin function decl FNDECL
8419*38fd1498Szrj    and its single argument ARG, return an folded expression computing
8420*38fd1498Szrj    the same, or NULL_TREE if we either couldn't or didn't want to fold
8421*38fd1498Szrj    (the latter happen if there's an RTL instruction available).  */
8422*38fd1498Szrj 
8423*38fd1498Szrj static tree
fold_builtin_interclass_mathfn(location_t loc,tree fndecl,tree arg)8424*38fd1498Szrj fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg)
8425*38fd1498Szrj {
8426*38fd1498Szrj   machine_mode mode;
8427*38fd1498Szrj 
8428*38fd1498Szrj   if (!validate_arg (arg, REAL_TYPE))
8429*38fd1498Szrj     return NULL_TREE;
8430*38fd1498Szrj 
8431*38fd1498Szrj   if (interclass_mathfn_icode (arg, fndecl) != CODE_FOR_nothing)
8432*38fd1498Szrj     return NULL_TREE;
8433*38fd1498Szrj 
8434*38fd1498Szrj   mode = TYPE_MODE (TREE_TYPE (arg));
8435*38fd1498Szrj 
8436*38fd1498Szrj   bool is_ibm_extended = MODE_COMPOSITE_P (mode);
8437*38fd1498Szrj 
8438*38fd1498Szrj   /* If there is no optab, try generic code.  */
8439*38fd1498Szrj   switch (DECL_FUNCTION_CODE (fndecl))
8440*38fd1498Szrj     {
8441*38fd1498Szrj       tree result;
8442*38fd1498Szrj 
8443*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_ISINF):
8444*38fd1498Szrj       {
8445*38fd1498Szrj 	/* isinf(x) -> isgreater(fabs(x),DBL_MAX).  */
8446*38fd1498Szrj 	tree const isgr_fn = builtin_decl_explicit (BUILT_IN_ISGREATER);
8447*38fd1498Szrj 	tree type = TREE_TYPE (arg);
8448*38fd1498Szrj 	REAL_VALUE_TYPE r;
8449*38fd1498Szrj 	char buf[128];
8450*38fd1498Szrj 
8451*38fd1498Szrj 	if (is_ibm_extended)
8452*38fd1498Szrj 	  {
8453*38fd1498Szrj 	    /* NaN and Inf are encoded in the high-order double value
8454*38fd1498Szrj 	       only.  The low-order value is not significant.  */
8455*38fd1498Szrj 	    type = double_type_node;
8456*38fd1498Szrj 	    mode = DFmode;
8457*38fd1498Szrj 	    arg = fold_build1_loc (loc, NOP_EXPR, type, arg);
8458*38fd1498Szrj 	  }
8459*38fd1498Szrj 	get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
8460*38fd1498Szrj 	real_from_string (&r, buf);
8461*38fd1498Szrj 	result = build_call_expr (isgr_fn, 2,
8462*38fd1498Szrj 				  fold_build1_loc (loc, ABS_EXPR, type, arg),
8463*38fd1498Szrj 				  build_real (type, r));
8464*38fd1498Szrj 	return result;
8465*38fd1498Szrj       }
8466*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_FINITE):
8467*38fd1498Szrj     case BUILT_IN_ISFINITE:
8468*38fd1498Szrj       {
8469*38fd1498Szrj 	/* isfinite(x) -> islessequal(fabs(x),DBL_MAX).  */
8470*38fd1498Szrj 	tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL);
8471*38fd1498Szrj 	tree type = TREE_TYPE (arg);
8472*38fd1498Szrj 	REAL_VALUE_TYPE r;
8473*38fd1498Szrj 	char buf[128];
8474*38fd1498Szrj 
8475*38fd1498Szrj 	if (is_ibm_extended)
8476*38fd1498Szrj 	  {
8477*38fd1498Szrj 	    /* NaN and Inf are encoded in the high-order double value
8478*38fd1498Szrj 	       only.  The low-order value is not significant.  */
8479*38fd1498Szrj 	    type = double_type_node;
8480*38fd1498Szrj 	    mode = DFmode;
8481*38fd1498Szrj 	    arg = fold_build1_loc (loc, NOP_EXPR, type, arg);
8482*38fd1498Szrj 	  }
8483*38fd1498Szrj 	get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
8484*38fd1498Szrj 	real_from_string (&r, buf);
8485*38fd1498Szrj 	result = build_call_expr (isle_fn, 2,
8486*38fd1498Szrj 				  fold_build1_loc (loc, ABS_EXPR, type, arg),
8487*38fd1498Szrj 				  build_real (type, r));
8488*38fd1498Szrj 	/*result = fold_build2_loc (loc, UNGT_EXPR,
8489*38fd1498Szrj 				  TREE_TYPE (TREE_TYPE (fndecl)),
8490*38fd1498Szrj 				  fold_build1_loc (loc, ABS_EXPR, type, arg),
8491*38fd1498Szrj 				  build_real (type, r));
8492*38fd1498Szrj 	result = fold_build1_loc (loc, TRUTH_NOT_EXPR,
8493*38fd1498Szrj 				  TREE_TYPE (TREE_TYPE (fndecl)),
8494*38fd1498Szrj 				  result);*/
8495*38fd1498Szrj 	return result;
8496*38fd1498Szrj       }
8497*38fd1498Szrj     case BUILT_IN_ISNORMAL:
8498*38fd1498Szrj       {
8499*38fd1498Szrj 	/* isnormal(x) -> isgreaterequal(fabs(x),DBL_MIN) &
8500*38fd1498Szrj 	   islessequal(fabs(x),DBL_MAX).  */
8501*38fd1498Szrj 	tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL);
8502*38fd1498Szrj 	tree type = TREE_TYPE (arg);
8503*38fd1498Szrj 	tree orig_arg, max_exp, min_exp;
8504*38fd1498Szrj 	machine_mode orig_mode = mode;
8505*38fd1498Szrj 	REAL_VALUE_TYPE rmax, rmin;
8506*38fd1498Szrj 	char buf[128];
8507*38fd1498Szrj 
8508*38fd1498Szrj 	orig_arg = arg = builtin_save_expr (arg);
8509*38fd1498Szrj 	if (is_ibm_extended)
8510*38fd1498Szrj 	  {
8511*38fd1498Szrj 	    /* Use double to test the normal range of IBM extended
8512*38fd1498Szrj 	       precision.  Emin for IBM extended precision is
8513*38fd1498Szrj 	       different to emin for IEEE double, being 53 higher
8514*38fd1498Szrj 	       since the low double exponent is at least 53 lower
8515*38fd1498Szrj 	       than the high double exponent.  */
8516*38fd1498Szrj 	    type = double_type_node;
8517*38fd1498Szrj 	    mode = DFmode;
8518*38fd1498Szrj 	    arg = fold_build1_loc (loc, NOP_EXPR, type, arg);
8519*38fd1498Szrj 	  }
8520*38fd1498Szrj 	arg = fold_build1_loc (loc, ABS_EXPR, type, arg);
8521*38fd1498Szrj 
8522*38fd1498Szrj 	get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
8523*38fd1498Szrj 	real_from_string (&rmax, buf);
8524*38fd1498Szrj 	sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (orig_mode)->emin - 1);
8525*38fd1498Szrj 	real_from_string (&rmin, buf);
8526*38fd1498Szrj 	max_exp = build_real (type, rmax);
8527*38fd1498Szrj 	min_exp = build_real (type, rmin);
8528*38fd1498Szrj 
8529*38fd1498Szrj 	max_exp = build_call_expr (isle_fn, 2, arg, max_exp);
8530*38fd1498Szrj 	if (is_ibm_extended)
8531*38fd1498Szrj 	  {
8532*38fd1498Szrj 	    /* Testing the high end of the range is done just using
8533*38fd1498Szrj 	       the high double, using the same test as isfinite().
8534*38fd1498Szrj 	       For the subnormal end of the range we first test the
8535*38fd1498Szrj 	       high double, then if its magnitude is equal to the
8536*38fd1498Szrj 	       limit of 0x1p-969, we test whether the low double is
8537*38fd1498Szrj 	       non-zero and opposite sign to the high double.  */
8538*38fd1498Szrj 	    tree const islt_fn = builtin_decl_explicit (BUILT_IN_ISLESS);
8539*38fd1498Szrj 	    tree const isgt_fn = builtin_decl_explicit (BUILT_IN_ISGREATER);
8540*38fd1498Szrj 	    tree gt_min = build_call_expr (isgt_fn, 2, arg, min_exp);
8541*38fd1498Szrj 	    tree eq_min = fold_build2 (EQ_EXPR, integer_type_node,
8542*38fd1498Szrj 				       arg, min_exp);
8543*38fd1498Szrj 	    tree as_complex = build1 (VIEW_CONVERT_EXPR,
8544*38fd1498Szrj 				      complex_double_type_node, orig_arg);
8545*38fd1498Szrj 	    tree hi_dbl = build1 (REALPART_EXPR, type, as_complex);
8546*38fd1498Szrj 	    tree lo_dbl = build1 (IMAGPART_EXPR, type, as_complex);
8547*38fd1498Szrj 	    tree zero = build_real (type, dconst0);
8548*38fd1498Szrj 	    tree hilt = build_call_expr (islt_fn, 2, hi_dbl, zero);
8549*38fd1498Szrj 	    tree lolt = build_call_expr (islt_fn, 2, lo_dbl, zero);
8550*38fd1498Szrj 	    tree logt = build_call_expr (isgt_fn, 2, lo_dbl, zero);
8551*38fd1498Szrj 	    tree ok_lo = fold_build1 (TRUTH_NOT_EXPR, integer_type_node,
8552*38fd1498Szrj 				      fold_build3 (COND_EXPR,
8553*38fd1498Szrj 						   integer_type_node,
8554*38fd1498Szrj 						   hilt, logt, lolt));
8555*38fd1498Szrj 	    eq_min = fold_build2 (TRUTH_ANDIF_EXPR, integer_type_node,
8556*38fd1498Szrj 				  eq_min, ok_lo);
8557*38fd1498Szrj 	    min_exp = fold_build2 (TRUTH_ORIF_EXPR, integer_type_node,
8558*38fd1498Szrj 				   gt_min, eq_min);
8559*38fd1498Szrj 	  }
8560*38fd1498Szrj 	else
8561*38fd1498Szrj 	  {
8562*38fd1498Szrj 	    tree const isge_fn
8563*38fd1498Szrj 	      = builtin_decl_explicit (BUILT_IN_ISGREATEREQUAL);
8564*38fd1498Szrj 	    min_exp = build_call_expr (isge_fn, 2, arg, min_exp);
8565*38fd1498Szrj 	  }
8566*38fd1498Szrj 	result = fold_build2 (BIT_AND_EXPR, integer_type_node,
8567*38fd1498Szrj 			      max_exp, min_exp);
8568*38fd1498Szrj 	return result;
8569*38fd1498Szrj       }
8570*38fd1498Szrj     default:
8571*38fd1498Szrj       break;
8572*38fd1498Szrj     }
8573*38fd1498Szrj 
8574*38fd1498Szrj   return NULL_TREE;
8575*38fd1498Szrj }
8576*38fd1498Szrj 
8577*38fd1498Szrj /* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite.
8578*38fd1498Szrj    ARG is the argument for the call.  */
8579*38fd1498Szrj 
8580*38fd1498Szrj static tree
fold_builtin_classify(location_t loc,tree fndecl,tree arg,int builtin_index)8581*38fd1498Szrj fold_builtin_classify (location_t loc, tree fndecl, tree arg, int builtin_index)
8582*38fd1498Szrj {
8583*38fd1498Szrj   tree type = TREE_TYPE (TREE_TYPE (fndecl));
8584*38fd1498Szrj 
8585*38fd1498Szrj   if (!validate_arg (arg, REAL_TYPE))
8586*38fd1498Szrj     return NULL_TREE;
8587*38fd1498Szrj 
8588*38fd1498Szrj   switch (builtin_index)
8589*38fd1498Szrj     {
8590*38fd1498Szrj     case BUILT_IN_ISINF:
8591*38fd1498Szrj       if (!HONOR_INFINITIES (arg))
8592*38fd1498Szrj 	return omit_one_operand_loc (loc, type, integer_zero_node, arg);
8593*38fd1498Szrj 
8594*38fd1498Szrj       return NULL_TREE;
8595*38fd1498Szrj 
8596*38fd1498Szrj     case BUILT_IN_ISINF_SIGN:
8597*38fd1498Szrj       {
8598*38fd1498Szrj 	/* isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0 */
8599*38fd1498Szrj 	/* In a boolean context, GCC will fold the inner COND_EXPR to
8600*38fd1498Szrj 	   1.  So e.g. "if (isinf_sign(x))" would be folded to just
8601*38fd1498Szrj 	   "if (isinf(x) ? 1 : 0)" which becomes "if (isinf(x))". */
8602*38fd1498Szrj 	tree signbit_fn = builtin_decl_explicit (BUILT_IN_SIGNBIT);
8603*38fd1498Szrj 	tree isinf_fn = builtin_decl_explicit (BUILT_IN_ISINF);
8604*38fd1498Szrj 	tree tmp = NULL_TREE;
8605*38fd1498Szrj 
8606*38fd1498Szrj 	arg = builtin_save_expr (arg);
8607*38fd1498Szrj 
8608*38fd1498Szrj 	if (signbit_fn && isinf_fn)
8609*38fd1498Szrj 	  {
8610*38fd1498Szrj 	    tree signbit_call = build_call_expr_loc (loc, signbit_fn, 1, arg);
8611*38fd1498Szrj 	    tree isinf_call = build_call_expr_loc (loc, isinf_fn, 1, arg);
8612*38fd1498Szrj 
8613*38fd1498Szrj 	    signbit_call = fold_build2_loc (loc, NE_EXPR, integer_type_node,
8614*38fd1498Szrj 					signbit_call, integer_zero_node);
8615*38fd1498Szrj 	    isinf_call = fold_build2_loc (loc, NE_EXPR, integer_type_node,
8616*38fd1498Szrj 				      isinf_call, integer_zero_node);
8617*38fd1498Szrj 
8618*38fd1498Szrj 	    tmp = fold_build3_loc (loc, COND_EXPR, integer_type_node, signbit_call,
8619*38fd1498Szrj 			       integer_minus_one_node, integer_one_node);
8620*38fd1498Szrj 	    tmp = fold_build3_loc (loc, COND_EXPR, integer_type_node,
8621*38fd1498Szrj 			       isinf_call, tmp,
8622*38fd1498Szrj 			       integer_zero_node);
8623*38fd1498Szrj 	  }
8624*38fd1498Szrj 
8625*38fd1498Szrj 	return tmp;
8626*38fd1498Szrj       }
8627*38fd1498Szrj 
8628*38fd1498Szrj     case BUILT_IN_ISFINITE:
8629*38fd1498Szrj       if (!HONOR_NANS (arg)
8630*38fd1498Szrj 	  && !HONOR_INFINITIES (arg))
8631*38fd1498Szrj 	return omit_one_operand_loc (loc, type, integer_one_node, arg);
8632*38fd1498Szrj 
8633*38fd1498Szrj       return NULL_TREE;
8634*38fd1498Szrj 
8635*38fd1498Szrj     case BUILT_IN_ISNAN:
8636*38fd1498Szrj       if (!HONOR_NANS (arg))
8637*38fd1498Szrj 	return omit_one_operand_loc (loc, type, integer_zero_node, arg);
8638*38fd1498Szrj 
8639*38fd1498Szrj       {
8640*38fd1498Szrj 	bool is_ibm_extended = MODE_COMPOSITE_P (TYPE_MODE (TREE_TYPE (arg)));
8641*38fd1498Szrj 	if (is_ibm_extended)
8642*38fd1498Szrj 	  {
8643*38fd1498Szrj 	    /* NaN and Inf are encoded in the high-order double value
8644*38fd1498Szrj 	       only.  The low-order value is not significant.  */
8645*38fd1498Szrj 	    arg = fold_build1_loc (loc, NOP_EXPR, double_type_node, arg);
8646*38fd1498Szrj 	  }
8647*38fd1498Szrj       }
8648*38fd1498Szrj       arg = builtin_save_expr (arg);
8649*38fd1498Szrj       return fold_build2_loc (loc, UNORDERED_EXPR, type, arg, arg);
8650*38fd1498Szrj 
8651*38fd1498Szrj     default:
8652*38fd1498Szrj       gcc_unreachable ();
8653*38fd1498Szrj     }
8654*38fd1498Szrj }
8655*38fd1498Szrj 
8656*38fd1498Szrj /* Fold a call to __builtin_fpclassify(int, int, int, int, int, ...).
8657*38fd1498Szrj    This builtin will generate code to return the appropriate floating
8658*38fd1498Szrj    point classification depending on the value of the floating point
8659*38fd1498Szrj    number passed in.  The possible return values must be supplied as
8660*38fd1498Szrj    int arguments to the call in the following order: FP_NAN, FP_INFINITE,
8661*38fd1498Szrj    FP_NORMAL, FP_SUBNORMAL and FP_ZERO.  The ellipses is for exactly
8662*38fd1498Szrj    one floating point argument which is "type generic".  */
8663*38fd1498Szrj 
8664*38fd1498Szrj static tree
fold_builtin_fpclassify(location_t loc,tree * args,int nargs)8665*38fd1498Szrj fold_builtin_fpclassify (location_t loc, tree *args, int nargs)
8666*38fd1498Szrj {
8667*38fd1498Szrj   tree fp_nan, fp_infinite, fp_normal, fp_subnormal, fp_zero,
8668*38fd1498Szrj     arg, type, res, tmp;
8669*38fd1498Szrj   machine_mode mode;
8670*38fd1498Szrj   REAL_VALUE_TYPE r;
8671*38fd1498Szrj   char buf[128];
8672*38fd1498Szrj 
8673*38fd1498Szrj   /* Verify the required arguments in the original call.  */
8674*38fd1498Szrj   if (nargs != 6
8675*38fd1498Szrj       || !validate_arg (args[0], INTEGER_TYPE)
8676*38fd1498Szrj       || !validate_arg (args[1], INTEGER_TYPE)
8677*38fd1498Szrj       || !validate_arg (args[2], INTEGER_TYPE)
8678*38fd1498Szrj       || !validate_arg (args[3], INTEGER_TYPE)
8679*38fd1498Szrj       || !validate_arg (args[4], INTEGER_TYPE)
8680*38fd1498Szrj       || !validate_arg (args[5], REAL_TYPE))
8681*38fd1498Szrj     return NULL_TREE;
8682*38fd1498Szrj 
8683*38fd1498Szrj   fp_nan = args[0];
8684*38fd1498Szrj   fp_infinite = args[1];
8685*38fd1498Szrj   fp_normal = args[2];
8686*38fd1498Szrj   fp_subnormal = args[3];
8687*38fd1498Szrj   fp_zero = args[4];
8688*38fd1498Szrj   arg = args[5];
8689*38fd1498Szrj   type = TREE_TYPE (arg);
8690*38fd1498Szrj   mode = TYPE_MODE (type);
8691*38fd1498Szrj   arg = builtin_save_expr (fold_build1_loc (loc, ABS_EXPR, type, arg));
8692*38fd1498Szrj 
8693*38fd1498Szrj   /* fpclassify(x) ->
8694*38fd1498Szrj        isnan(x) ? FP_NAN :
8695*38fd1498Szrj          (fabs(x) == Inf ? FP_INFINITE :
8696*38fd1498Szrj 	   (fabs(x) >= DBL_MIN ? FP_NORMAL :
8697*38fd1498Szrj 	     (x == 0 ? FP_ZERO : FP_SUBNORMAL))).  */
8698*38fd1498Szrj 
8699*38fd1498Szrj   tmp = fold_build2_loc (loc, EQ_EXPR, integer_type_node, arg,
8700*38fd1498Szrj 		     build_real (type, dconst0));
8701*38fd1498Szrj   res = fold_build3_loc (loc, COND_EXPR, integer_type_node,
8702*38fd1498Szrj 		     tmp, fp_zero, fp_subnormal);
8703*38fd1498Szrj 
8704*38fd1498Szrj   sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1);
8705*38fd1498Szrj   real_from_string (&r, buf);
8706*38fd1498Szrj   tmp = fold_build2_loc (loc, GE_EXPR, integer_type_node,
8707*38fd1498Szrj 		     arg, build_real (type, r));
8708*38fd1498Szrj   res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp, fp_normal, res);
8709*38fd1498Szrj 
8710*38fd1498Szrj   if (HONOR_INFINITIES (mode))
8711*38fd1498Szrj     {
8712*38fd1498Szrj       real_inf (&r);
8713*38fd1498Szrj       tmp = fold_build2_loc (loc, EQ_EXPR, integer_type_node, arg,
8714*38fd1498Szrj 			 build_real (type, r));
8715*38fd1498Szrj       res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp,
8716*38fd1498Szrj 			 fp_infinite, res);
8717*38fd1498Szrj     }
8718*38fd1498Szrj 
8719*38fd1498Szrj   if (HONOR_NANS (mode))
8720*38fd1498Szrj     {
8721*38fd1498Szrj       tmp = fold_build2_loc (loc, ORDERED_EXPR, integer_type_node, arg, arg);
8722*38fd1498Szrj       res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp, res, fp_nan);
8723*38fd1498Szrj     }
8724*38fd1498Szrj 
8725*38fd1498Szrj   return res;
8726*38fd1498Szrj }
8727*38fd1498Szrj 
8728*38fd1498Szrj /* Fold a call to an unordered comparison function such as
8729*38fd1498Szrj    __builtin_isgreater().  FNDECL is the FUNCTION_DECL for the function
8730*38fd1498Szrj    being called and ARG0 and ARG1 are the arguments for the call.
8731*38fd1498Szrj    UNORDERED_CODE and ORDERED_CODE are comparison codes that give
8732*38fd1498Szrj    the opposite of the desired result.  UNORDERED_CODE is used
8733*38fd1498Szrj    for modes that can hold NaNs and ORDERED_CODE is used for
8734*38fd1498Szrj    the rest.  */
8735*38fd1498Szrj 
8736*38fd1498Szrj 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)8737*38fd1498Szrj fold_builtin_unordered_cmp (location_t loc, tree fndecl, tree arg0, tree arg1,
8738*38fd1498Szrj 			    enum tree_code unordered_code,
8739*38fd1498Szrj 			    enum tree_code ordered_code)
8740*38fd1498Szrj {
8741*38fd1498Szrj   tree type = TREE_TYPE (TREE_TYPE (fndecl));
8742*38fd1498Szrj   enum tree_code code;
8743*38fd1498Szrj   tree type0, type1;
8744*38fd1498Szrj   enum tree_code code0, code1;
8745*38fd1498Szrj   tree cmp_type = NULL_TREE;
8746*38fd1498Szrj 
8747*38fd1498Szrj   type0 = TREE_TYPE (arg0);
8748*38fd1498Szrj   type1 = TREE_TYPE (arg1);
8749*38fd1498Szrj 
8750*38fd1498Szrj   code0 = TREE_CODE (type0);
8751*38fd1498Szrj   code1 = TREE_CODE (type1);
8752*38fd1498Szrj 
8753*38fd1498Szrj   if (code0 == REAL_TYPE && code1 == REAL_TYPE)
8754*38fd1498Szrj     /* Choose the wider of two real types.  */
8755*38fd1498Szrj     cmp_type = TYPE_PRECISION (type0) >= TYPE_PRECISION (type1)
8756*38fd1498Szrj       ? type0 : type1;
8757*38fd1498Szrj   else if (code0 == REAL_TYPE && code1 == INTEGER_TYPE)
8758*38fd1498Szrj     cmp_type = type0;
8759*38fd1498Szrj   else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE)
8760*38fd1498Szrj     cmp_type = type1;
8761*38fd1498Szrj 
8762*38fd1498Szrj   arg0 = fold_convert_loc (loc, cmp_type, arg0);
8763*38fd1498Szrj   arg1 = fold_convert_loc (loc, cmp_type, arg1);
8764*38fd1498Szrj 
8765*38fd1498Szrj   if (unordered_code == UNORDERED_EXPR)
8766*38fd1498Szrj     {
8767*38fd1498Szrj       if (!HONOR_NANS (arg0))
8768*38fd1498Szrj 	return omit_two_operands_loc (loc, type, integer_zero_node, arg0, arg1);
8769*38fd1498Szrj       return fold_build2_loc (loc, UNORDERED_EXPR, type, arg0, arg1);
8770*38fd1498Szrj     }
8771*38fd1498Szrj 
8772*38fd1498Szrj   code = HONOR_NANS (arg0) ? unordered_code : ordered_code;
8773*38fd1498Szrj   return fold_build1_loc (loc, TRUTH_NOT_EXPR, type,
8774*38fd1498Szrj 		      fold_build2_loc (loc, code, type, arg0, arg1));
8775*38fd1498Szrj }
8776*38fd1498Szrj 
8777*38fd1498Szrj /* Fold __builtin_{,s,u}{add,sub,mul}{,l,ll}_overflow, either into normal
8778*38fd1498Szrj    arithmetics if it can never overflow, or into internal functions that
8779*38fd1498Szrj    return both result of arithmetics and overflowed boolean flag in
8780*38fd1498Szrj    a complex integer result, or some other check for overflow.
8781*38fd1498Szrj    Similarly fold __builtin_{add,sub,mul}_overflow_p to just the overflow
8782*38fd1498Szrj    checking part of that.  */
8783*38fd1498Szrj 
8784*38fd1498Szrj static tree
fold_builtin_arith_overflow(location_t loc,enum built_in_function fcode,tree arg0,tree arg1,tree arg2)8785*38fd1498Szrj fold_builtin_arith_overflow (location_t loc, enum built_in_function fcode,
8786*38fd1498Szrj 			     tree arg0, tree arg1, tree arg2)
8787*38fd1498Szrj {
8788*38fd1498Szrj   enum internal_fn ifn = IFN_LAST;
8789*38fd1498Szrj   /* The code of the expression corresponding to the type-generic
8790*38fd1498Szrj      built-in, or ERROR_MARK for the type-specific ones.  */
8791*38fd1498Szrj   enum tree_code opcode = ERROR_MARK;
8792*38fd1498Szrj   bool ovf_only = false;
8793*38fd1498Szrj 
8794*38fd1498Szrj   switch (fcode)
8795*38fd1498Szrj     {
8796*38fd1498Szrj     case BUILT_IN_ADD_OVERFLOW_P:
8797*38fd1498Szrj       ovf_only = true;
8798*38fd1498Szrj       /* FALLTHRU */
8799*38fd1498Szrj     case BUILT_IN_ADD_OVERFLOW:
8800*38fd1498Szrj       opcode = PLUS_EXPR;
8801*38fd1498Szrj       /* FALLTHRU */
8802*38fd1498Szrj     case BUILT_IN_SADD_OVERFLOW:
8803*38fd1498Szrj     case BUILT_IN_SADDL_OVERFLOW:
8804*38fd1498Szrj     case BUILT_IN_SADDLL_OVERFLOW:
8805*38fd1498Szrj     case BUILT_IN_UADD_OVERFLOW:
8806*38fd1498Szrj     case BUILT_IN_UADDL_OVERFLOW:
8807*38fd1498Szrj     case BUILT_IN_UADDLL_OVERFLOW:
8808*38fd1498Szrj       ifn = IFN_ADD_OVERFLOW;
8809*38fd1498Szrj       break;
8810*38fd1498Szrj     case BUILT_IN_SUB_OVERFLOW_P:
8811*38fd1498Szrj       ovf_only = true;
8812*38fd1498Szrj       /* FALLTHRU */
8813*38fd1498Szrj     case BUILT_IN_SUB_OVERFLOW:
8814*38fd1498Szrj       opcode = MINUS_EXPR;
8815*38fd1498Szrj       /* FALLTHRU */
8816*38fd1498Szrj     case BUILT_IN_SSUB_OVERFLOW:
8817*38fd1498Szrj     case BUILT_IN_SSUBL_OVERFLOW:
8818*38fd1498Szrj     case BUILT_IN_SSUBLL_OVERFLOW:
8819*38fd1498Szrj     case BUILT_IN_USUB_OVERFLOW:
8820*38fd1498Szrj     case BUILT_IN_USUBL_OVERFLOW:
8821*38fd1498Szrj     case BUILT_IN_USUBLL_OVERFLOW:
8822*38fd1498Szrj       ifn = IFN_SUB_OVERFLOW;
8823*38fd1498Szrj       break;
8824*38fd1498Szrj     case BUILT_IN_MUL_OVERFLOW_P:
8825*38fd1498Szrj       ovf_only = true;
8826*38fd1498Szrj       /* FALLTHRU */
8827*38fd1498Szrj     case BUILT_IN_MUL_OVERFLOW:
8828*38fd1498Szrj       opcode = MULT_EXPR;
8829*38fd1498Szrj       /* FALLTHRU */
8830*38fd1498Szrj     case BUILT_IN_SMUL_OVERFLOW:
8831*38fd1498Szrj     case BUILT_IN_SMULL_OVERFLOW:
8832*38fd1498Szrj     case BUILT_IN_SMULLL_OVERFLOW:
8833*38fd1498Szrj     case BUILT_IN_UMUL_OVERFLOW:
8834*38fd1498Szrj     case BUILT_IN_UMULL_OVERFLOW:
8835*38fd1498Szrj     case BUILT_IN_UMULLL_OVERFLOW:
8836*38fd1498Szrj       ifn = IFN_MUL_OVERFLOW;
8837*38fd1498Szrj       break;
8838*38fd1498Szrj     default:
8839*38fd1498Szrj       gcc_unreachable ();
8840*38fd1498Szrj     }
8841*38fd1498Szrj 
8842*38fd1498Szrj   /* For the "generic" overloads, the first two arguments can have different
8843*38fd1498Szrj      types and the last argument determines the target type to use to check
8844*38fd1498Szrj      for overflow.  The arguments of the other overloads all have the same
8845*38fd1498Szrj      type.  */
8846*38fd1498Szrj   tree type = ovf_only ? TREE_TYPE (arg2) : TREE_TYPE (TREE_TYPE (arg2));
8847*38fd1498Szrj 
8848*38fd1498Szrj   /* For the __builtin_{add,sub,mul}_overflow_p builtins, when the first two
8849*38fd1498Szrj      arguments are constant, attempt to fold the built-in call into a constant
8850*38fd1498Szrj      expression indicating whether or not it detected an overflow.  */
8851*38fd1498Szrj   if (ovf_only
8852*38fd1498Szrj       && TREE_CODE (arg0) == INTEGER_CST
8853*38fd1498Szrj       && TREE_CODE (arg1) == INTEGER_CST)
8854*38fd1498Szrj     /* Perform the computation in the target type and check for overflow.  */
8855*38fd1498Szrj     return omit_one_operand_loc (loc, boolean_type_node,
8856*38fd1498Szrj 				 arith_overflowed_p (opcode, type, arg0, arg1)
8857*38fd1498Szrj 				 ? boolean_true_node : boolean_false_node,
8858*38fd1498Szrj 				 arg2);
8859*38fd1498Szrj 
8860*38fd1498Szrj   tree ctype = build_complex_type (type);
8861*38fd1498Szrj   tree call = build_call_expr_internal_loc (loc, ifn, ctype,
8862*38fd1498Szrj 					    2, arg0, arg1);
8863*38fd1498Szrj   tree tgt = save_expr (call);
8864*38fd1498Szrj   tree intres = build1_loc (loc, REALPART_EXPR, type, tgt);
8865*38fd1498Szrj   tree ovfres = build1_loc (loc, IMAGPART_EXPR, type, tgt);
8866*38fd1498Szrj   ovfres = fold_convert_loc (loc, boolean_type_node, ovfres);
8867*38fd1498Szrj 
8868*38fd1498Szrj   if (ovf_only)
8869*38fd1498Szrj     return omit_one_operand_loc (loc, boolean_type_node, ovfres, arg2);
8870*38fd1498Szrj 
8871*38fd1498Szrj   tree mem_arg2 = build_fold_indirect_ref_loc (loc, arg2);
8872*38fd1498Szrj   tree store
8873*38fd1498Szrj     = fold_build2_loc (loc, MODIFY_EXPR, void_type_node, mem_arg2, intres);
8874*38fd1498Szrj   return build2_loc (loc, COMPOUND_EXPR, boolean_type_node, store, ovfres);
8875*38fd1498Szrj }
8876*38fd1498Szrj 
8877*38fd1498Szrj /* Fold a call to __builtin_FILE to a constant string.  */
8878*38fd1498Szrj 
8879*38fd1498Szrj static inline tree
fold_builtin_FILE(location_t loc)8880*38fd1498Szrj fold_builtin_FILE (location_t loc)
8881*38fd1498Szrj {
8882*38fd1498Szrj   if (const char *fname = LOCATION_FILE (loc))
8883*38fd1498Szrj     {
8884*38fd1498Szrj       /* The documentation says this builtin is equivalent to the preprocessor
8885*38fd1498Szrj 	 __FILE__ macro so it appears appropriate to use the same file prefix
8886*38fd1498Szrj 	 mappings.  */
8887*38fd1498Szrj       fname = remap_macro_filename (fname);
8888*38fd1498Szrj     return build_string_literal (strlen (fname) + 1, fname);
8889*38fd1498Szrj     }
8890*38fd1498Szrj 
8891*38fd1498Szrj   return build_string_literal (1, "");
8892*38fd1498Szrj }
8893*38fd1498Szrj 
8894*38fd1498Szrj /* Fold a call to __builtin_FUNCTION to a constant string.  */
8895*38fd1498Szrj 
8896*38fd1498Szrj static inline tree
fold_builtin_FUNCTION()8897*38fd1498Szrj fold_builtin_FUNCTION ()
8898*38fd1498Szrj {
8899*38fd1498Szrj   const char *name = "";
8900*38fd1498Szrj 
8901*38fd1498Szrj   if (current_function_decl)
8902*38fd1498Szrj     name = lang_hooks.decl_printable_name (current_function_decl, 0);
8903*38fd1498Szrj 
8904*38fd1498Szrj   return build_string_literal (strlen (name) + 1, name);
8905*38fd1498Szrj }
8906*38fd1498Szrj 
8907*38fd1498Szrj /* Fold a call to __builtin_LINE to an integer constant.  */
8908*38fd1498Szrj 
8909*38fd1498Szrj static inline tree
fold_builtin_LINE(location_t loc,tree type)8910*38fd1498Szrj fold_builtin_LINE (location_t loc, tree type)
8911*38fd1498Szrj {
8912*38fd1498Szrj   return build_int_cst (type, LOCATION_LINE (loc));
8913*38fd1498Szrj }
8914*38fd1498Szrj 
8915*38fd1498Szrj /* Fold a call to built-in function FNDECL with 0 arguments.
8916*38fd1498Szrj    This function returns NULL_TREE if no simplification was possible.  */
8917*38fd1498Szrj 
8918*38fd1498Szrj static tree
fold_builtin_0(location_t loc,tree fndecl)8919*38fd1498Szrj fold_builtin_0 (location_t loc, tree fndecl)
8920*38fd1498Szrj {
8921*38fd1498Szrj   tree type = TREE_TYPE (TREE_TYPE (fndecl));
8922*38fd1498Szrj   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
8923*38fd1498Szrj   switch (fcode)
8924*38fd1498Szrj     {
8925*38fd1498Szrj     case BUILT_IN_FILE:
8926*38fd1498Szrj       return fold_builtin_FILE (loc);
8927*38fd1498Szrj 
8928*38fd1498Szrj     case BUILT_IN_FUNCTION:
8929*38fd1498Szrj       return fold_builtin_FUNCTION ();
8930*38fd1498Szrj 
8931*38fd1498Szrj     case BUILT_IN_LINE:
8932*38fd1498Szrj       return fold_builtin_LINE (loc, type);
8933*38fd1498Szrj 
8934*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_INF):
8935*38fd1498Szrj     CASE_FLT_FN_FLOATN_NX (BUILT_IN_INF):
8936*38fd1498Szrj     case BUILT_IN_INFD32:
8937*38fd1498Szrj     case BUILT_IN_INFD64:
8938*38fd1498Szrj     case BUILT_IN_INFD128:
8939*38fd1498Szrj       return fold_builtin_inf (loc, type, true);
8940*38fd1498Szrj 
8941*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_HUGE_VAL):
8942*38fd1498Szrj     CASE_FLT_FN_FLOATN_NX (BUILT_IN_HUGE_VAL):
8943*38fd1498Szrj       return fold_builtin_inf (loc, type, false);
8944*38fd1498Szrj 
8945*38fd1498Szrj     case BUILT_IN_CLASSIFY_TYPE:
8946*38fd1498Szrj       return fold_builtin_classify_type (NULL_TREE);
8947*38fd1498Szrj 
8948*38fd1498Szrj     default:
8949*38fd1498Szrj       break;
8950*38fd1498Szrj     }
8951*38fd1498Szrj   return NULL_TREE;
8952*38fd1498Szrj }
8953*38fd1498Szrj 
8954*38fd1498Szrj /* Fold a call to built-in function FNDECL with 1 argument, ARG0.
8955*38fd1498Szrj    This function returns NULL_TREE if no simplification was possible.  */
8956*38fd1498Szrj 
8957*38fd1498Szrj static tree
fold_builtin_1(location_t loc,tree fndecl,tree arg0)8958*38fd1498Szrj fold_builtin_1 (location_t loc, tree fndecl, tree arg0)
8959*38fd1498Szrj {
8960*38fd1498Szrj   tree type = TREE_TYPE (TREE_TYPE (fndecl));
8961*38fd1498Szrj   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
8962*38fd1498Szrj 
8963*38fd1498Szrj   if (TREE_CODE (arg0) == ERROR_MARK)
8964*38fd1498Szrj     return NULL_TREE;
8965*38fd1498Szrj 
8966*38fd1498Szrj   if (tree ret = fold_const_call (as_combined_fn (fcode), type, arg0))
8967*38fd1498Szrj     return ret;
8968*38fd1498Szrj 
8969*38fd1498Szrj   switch (fcode)
8970*38fd1498Szrj     {
8971*38fd1498Szrj     case BUILT_IN_CONSTANT_P:
8972*38fd1498Szrj       {
8973*38fd1498Szrj 	tree val = fold_builtin_constant_p (arg0);
8974*38fd1498Szrj 
8975*38fd1498Szrj 	/* Gimplification will pull the CALL_EXPR for the builtin out of
8976*38fd1498Szrj 	   an if condition.  When not optimizing, we'll not CSE it back.
8977*38fd1498Szrj 	   To avoid link error types of regressions, return false now.  */
8978*38fd1498Szrj 	if (!val && !optimize)
8979*38fd1498Szrj 	  val = integer_zero_node;
8980*38fd1498Szrj 
8981*38fd1498Szrj 	return val;
8982*38fd1498Szrj       }
8983*38fd1498Szrj 
8984*38fd1498Szrj     case BUILT_IN_CLASSIFY_TYPE:
8985*38fd1498Szrj       return fold_builtin_classify_type (arg0);
8986*38fd1498Szrj 
8987*38fd1498Szrj     case BUILT_IN_STRLEN:
8988*38fd1498Szrj       return fold_builtin_strlen (loc, type, arg0);
8989*38fd1498Szrj 
8990*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_FABS):
8991*38fd1498Szrj     CASE_FLT_FN_FLOATN_NX (BUILT_IN_FABS):
8992*38fd1498Szrj     case BUILT_IN_FABSD32:
8993*38fd1498Szrj     case BUILT_IN_FABSD64:
8994*38fd1498Szrj     case BUILT_IN_FABSD128:
8995*38fd1498Szrj       return fold_builtin_fabs (loc, arg0, type);
8996*38fd1498Szrj 
8997*38fd1498Szrj     case BUILT_IN_ABS:
8998*38fd1498Szrj     case BUILT_IN_LABS:
8999*38fd1498Szrj     case BUILT_IN_LLABS:
9000*38fd1498Szrj     case BUILT_IN_IMAXABS:
9001*38fd1498Szrj       return fold_builtin_abs (loc, arg0, type);
9002*38fd1498Szrj 
9003*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_CONJ):
9004*38fd1498Szrj       if (validate_arg (arg0, COMPLEX_TYPE)
9005*38fd1498Szrj 	&& TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
9006*38fd1498Szrj 	return fold_build1_loc (loc, CONJ_EXPR, type, arg0);
9007*38fd1498Szrj     break;
9008*38fd1498Szrj 
9009*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_CREAL):
9010*38fd1498Szrj       if (validate_arg (arg0, COMPLEX_TYPE)
9011*38fd1498Szrj 	&& TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
9012*38fd1498Szrj 	return non_lvalue_loc (loc, fold_build1_loc (loc, REALPART_EXPR, type, arg0));
9013*38fd1498Szrj     break;
9014*38fd1498Szrj 
9015*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_CIMAG):
9016*38fd1498Szrj       if (validate_arg (arg0, COMPLEX_TYPE)
9017*38fd1498Szrj 	  && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
9018*38fd1498Szrj 	return non_lvalue_loc (loc, fold_build1_loc (loc, IMAGPART_EXPR, type, arg0));
9019*38fd1498Szrj     break;
9020*38fd1498Szrj 
9021*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_CARG):
9022*38fd1498Szrj       return fold_builtin_carg (loc, arg0, type);
9023*38fd1498Szrj 
9024*38fd1498Szrj     case BUILT_IN_ISASCII:
9025*38fd1498Szrj       return fold_builtin_isascii (loc, arg0);
9026*38fd1498Szrj 
9027*38fd1498Szrj     case BUILT_IN_TOASCII:
9028*38fd1498Szrj       return fold_builtin_toascii (loc, arg0);
9029*38fd1498Szrj 
9030*38fd1498Szrj     case BUILT_IN_ISDIGIT:
9031*38fd1498Szrj       return fold_builtin_isdigit (loc, arg0);
9032*38fd1498Szrj 
9033*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_FINITE):
9034*38fd1498Szrj     case BUILT_IN_FINITED32:
9035*38fd1498Szrj     case BUILT_IN_FINITED64:
9036*38fd1498Szrj     case BUILT_IN_FINITED128:
9037*38fd1498Szrj     case BUILT_IN_ISFINITE:
9038*38fd1498Szrj       {
9039*38fd1498Szrj 	tree ret = fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISFINITE);
9040*38fd1498Szrj 	if (ret)
9041*38fd1498Szrj 	  return ret;
9042*38fd1498Szrj 	return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
9043*38fd1498Szrj       }
9044*38fd1498Szrj 
9045*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_ISINF):
9046*38fd1498Szrj     case BUILT_IN_ISINFD32:
9047*38fd1498Szrj     case BUILT_IN_ISINFD64:
9048*38fd1498Szrj     case BUILT_IN_ISINFD128:
9049*38fd1498Szrj       {
9050*38fd1498Szrj 	tree ret = fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF);
9051*38fd1498Szrj 	if (ret)
9052*38fd1498Szrj 	  return ret;
9053*38fd1498Szrj 	return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
9054*38fd1498Szrj       }
9055*38fd1498Szrj 
9056*38fd1498Szrj     case BUILT_IN_ISNORMAL:
9057*38fd1498Szrj       return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
9058*38fd1498Szrj 
9059*38fd1498Szrj     case BUILT_IN_ISINF_SIGN:
9060*38fd1498Szrj       return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF_SIGN);
9061*38fd1498Szrj 
9062*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_ISNAN):
9063*38fd1498Szrj     case BUILT_IN_ISNAND32:
9064*38fd1498Szrj     case BUILT_IN_ISNAND64:
9065*38fd1498Szrj     case BUILT_IN_ISNAND128:
9066*38fd1498Szrj       return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISNAN);
9067*38fd1498Szrj 
9068*38fd1498Szrj     case BUILT_IN_FREE:
9069*38fd1498Szrj       if (integer_zerop (arg0))
9070*38fd1498Szrj 	return build_empty_stmt (loc);
9071*38fd1498Szrj       break;
9072*38fd1498Szrj 
9073*38fd1498Szrj     default:
9074*38fd1498Szrj       break;
9075*38fd1498Szrj     }
9076*38fd1498Szrj 
9077*38fd1498Szrj   return NULL_TREE;
9078*38fd1498Szrj 
9079*38fd1498Szrj }
9080*38fd1498Szrj 
9081*38fd1498Szrj /* Fold a call to built-in function FNDECL with 2 arguments, ARG0 and ARG1.
9082*38fd1498Szrj    This function returns NULL_TREE if no simplification was possible.  */
9083*38fd1498Szrj 
9084*38fd1498Szrj static tree
fold_builtin_2(location_t loc,tree fndecl,tree arg0,tree arg1)9085*38fd1498Szrj fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1)
9086*38fd1498Szrj {
9087*38fd1498Szrj   tree type = TREE_TYPE (TREE_TYPE (fndecl));
9088*38fd1498Szrj   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
9089*38fd1498Szrj 
9090*38fd1498Szrj   if (TREE_CODE (arg0) == ERROR_MARK
9091*38fd1498Szrj       || TREE_CODE (arg1) == ERROR_MARK)
9092*38fd1498Szrj     return NULL_TREE;
9093*38fd1498Szrj 
9094*38fd1498Szrj   if (tree ret = fold_const_call (as_combined_fn (fcode), type, arg0, arg1))
9095*38fd1498Szrj     return ret;
9096*38fd1498Szrj 
9097*38fd1498Szrj   switch (fcode)
9098*38fd1498Szrj     {
9099*38fd1498Szrj     CASE_FLT_FN_REENT (BUILT_IN_GAMMA): /* GAMMA_R */
9100*38fd1498Szrj     CASE_FLT_FN_REENT (BUILT_IN_LGAMMA): /* LGAMMA_R */
9101*38fd1498Szrj       if (validate_arg (arg0, REAL_TYPE)
9102*38fd1498Szrj 	  && validate_arg (arg1, POINTER_TYPE))
9103*38fd1498Szrj 	return do_mpfr_lgamma_r (arg0, arg1, type);
9104*38fd1498Szrj     break;
9105*38fd1498Szrj 
9106*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_FREXP):
9107*38fd1498Szrj       return fold_builtin_frexp (loc, arg0, arg1, type);
9108*38fd1498Szrj 
9109*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_MODF):
9110*38fd1498Szrj       return fold_builtin_modf (loc, arg0, arg1, type);
9111*38fd1498Szrj 
9112*38fd1498Szrj     case BUILT_IN_STRSPN:
9113*38fd1498Szrj       return fold_builtin_strspn (loc, arg0, arg1);
9114*38fd1498Szrj 
9115*38fd1498Szrj     case BUILT_IN_STRCSPN:
9116*38fd1498Szrj       return fold_builtin_strcspn (loc, arg0, arg1);
9117*38fd1498Szrj 
9118*38fd1498Szrj     case BUILT_IN_STRPBRK:
9119*38fd1498Szrj       return fold_builtin_strpbrk (loc, arg0, arg1, type);
9120*38fd1498Szrj 
9121*38fd1498Szrj     case BUILT_IN_EXPECT:
9122*38fd1498Szrj       return fold_builtin_expect (loc, arg0, arg1, NULL_TREE);
9123*38fd1498Szrj 
9124*38fd1498Szrj     case BUILT_IN_ISGREATER:
9125*38fd1498Szrj       return fold_builtin_unordered_cmp (loc, fndecl,
9126*38fd1498Szrj 					 arg0, arg1, UNLE_EXPR, LE_EXPR);
9127*38fd1498Szrj     case BUILT_IN_ISGREATEREQUAL:
9128*38fd1498Szrj       return fold_builtin_unordered_cmp (loc, fndecl,
9129*38fd1498Szrj 					 arg0, arg1, UNLT_EXPR, LT_EXPR);
9130*38fd1498Szrj     case BUILT_IN_ISLESS:
9131*38fd1498Szrj       return fold_builtin_unordered_cmp (loc, fndecl,
9132*38fd1498Szrj 					 arg0, arg1, UNGE_EXPR, GE_EXPR);
9133*38fd1498Szrj     case BUILT_IN_ISLESSEQUAL:
9134*38fd1498Szrj       return fold_builtin_unordered_cmp (loc, fndecl,
9135*38fd1498Szrj 					 arg0, arg1, UNGT_EXPR, GT_EXPR);
9136*38fd1498Szrj     case BUILT_IN_ISLESSGREATER:
9137*38fd1498Szrj       return fold_builtin_unordered_cmp (loc, fndecl,
9138*38fd1498Szrj 					 arg0, arg1, UNEQ_EXPR, EQ_EXPR);
9139*38fd1498Szrj     case BUILT_IN_ISUNORDERED:
9140*38fd1498Szrj       return fold_builtin_unordered_cmp (loc, fndecl,
9141*38fd1498Szrj 					 arg0, arg1, UNORDERED_EXPR,
9142*38fd1498Szrj 					 NOP_EXPR);
9143*38fd1498Szrj 
9144*38fd1498Szrj       /* We do the folding for va_start in the expander.  */
9145*38fd1498Szrj     case BUILT_IN_VA_START:
9146*38fd1498Szrj       break;
9147*38fd1498Szrj 
9148*38fd1498Szrj     case BUILT_IN_OBJECT_SIZE:
9149*38fd1498Szrj       return fold_builtin_object_size (arg0, arg1);
9150*38fd1498Szrj 
9151*38fd1498Szrj     case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
9152*38fd1498Szrj       return fold_builtin_atomic_always_lock_free (arg0, arg1);
9153*38fd1498Szrj 
9154*38fd1498Szrj     case BUILT_IN_ATOMIC_IS_LOCK_FREE:
9155*38fd1498Szrj       return fold_builtin_atomic_is_lock_free (arg0, arg1);
9156*38fd1498Szrj 
9157*38fd1498Szrj     default:
9158*38fd1498Szrj       break;
9159*38fd1498Szrj     }
9160*38fd1498Szrj   return NULL_TREE;
9161*38fd1498Szrj }
9162*38fd1498Szrj 
9163*38fd1498Szrj /* Fold a call to built-in function FNDECL with 3 arguments, ARG0, ARG1,
9164*38fd1498Szrj    and ARG2.
9165*38fd1498Szrj    This function returns NULL_TREE if no simplification was possible.  */
9166*38fd1498Szrj 
9167*38fd1498Szrj static tree
fold_builtin_3(location_t loc,tree fndecl,tree arg0,tree arg1,tree arg2)9168*38fd1498Szrj fold_builtin_3 (location_t loc, tree fndecl,
9169*38fd1498Szrj 		tree arg0, tree arg1, tree arg2)
9170*38fd1498Szrj {
9171*38fd1498Szrj   tree type = TREE_TYPE (TREE_TYPE (fndecl));
9172*38fd1498Szrj   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
9173*38fd1498Szrj 
9174*38fd1498Szrj   if (TREE_CODE (arg0) == ERROR_MARK
9175*38fd1498Szrj       || TREE_CODE (arg1) == ERROR_MARK
9176*38fd1498Szrj       || TREE_CODE (arg2) == ERROR_MARK)
9177*38fd1498Szrj     return NULL_TREE;
9178*38fd1498Szrj 
9179*38fd1498Szrj   if (tree ret = fold_const_call (as_combined_fn (fcode), type,
9180*38fd1498Szrj 				  arg0, arg1, arg2))
9181*38fd1498Szrj     return ret;
9182*38fd1498Szrj 
9183*38fd1498Szrj   switch (fcode)
9184*38fd1498Szrj     {
9185*38fd1498Szrj 
9186*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_SINCOS):
9187*38fd1498Szrj       return fold_builtin_sincos (loc, arg0, arg1, arg2);
9188*38fd1498Szrj 
9189*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_FMA):
9190*38fd1498Szrj     CASE_FLT_FN_FLOATN_NX (BUILT_IN_FMA):
9191*38fd1498Szrj       return fold_builtin_fma (loc, arg0, arg1, arg2, type);
9192*38fd1498Szrj 
9193*38fd1498Szrj     CASE_FLT_FN (BUILT_IN_REMQUO):
9194*38fd1498Szrj       if (validate_arg (arg0, REAL_TYPE)
9195*38fd1498Szrj 	  && validate_arg (arg1, REAL_TYPE)
9196*38fd1498Szrj 	  && validate_arg (arg2, POINTER_TYPE))
9197*38fd1498Szrj 	return do_mpfr_remquo (arg0, arg1, arg2);
9198*38fd1498Szrj     break;
9199*38fd1498Szrj 
9200*38fd1498Szrj     case BUILT_IN_MEMCMP:
9201*38fd1498Szrj       return fold_builtin_memcmp (loc, arg0, arg1, arg2);
9202*38fd1498Szrj 
9203*38fd1498Szrj     case BUILT_IN_EXPECT:
9204*38fd1498Szrj       return fold_builtin_expect (loc, arg0, arg1, arg2);
9205*38fd1498Szrj 
9206*38fd1498Szrj     case BUILT_IN_ADD_OVERFLOW:
9207*38fd1498Szrj     case BUILT_IN_SUB_OVERFLOW:
9208*38fd1498Szrj     case BUILT_IN_MUL_OVERFLOW:
9209*38fd1498Szrj     case BUILT_IN_ADD_OVERFLOW_P:
9210*38fd1498Szrj     case BUILT_IN_SUB_OVERFLOW_P:
9211*38fd1498Szrj     case BUILT_IN_MUL_OVERFLOW_P:
9212*38fd1498Szrj     case BUILT_IN_SADD_OVERFLOW:
9213*38fd1498Szrj     case BUILT_IN_SADDL_OVERFLOW:
9214*38fd1498Szrj     case BUILT_IN_SADDLL_OVERFLOW:
9215*38fd1498Szrj     case BUILT_IN_SSUB_OVERFLOW:
9216*38fd1498Szrj     case BUILT_IN_SSUBL_OVERFLOW:
9217*38fd1498Szrj     case BUILT_IN_SSUBLL_OVERFLOW:
9218*38fd1498Szrj     case BUILT_IN_SMUL_OVERFLOW:
9219*38fd1498Szrj     case BUILT_IN_SMULL_OVERFLOW:
9220*38fd1498Szrj     case BUILT_IN_SMULLL_OVERFLOW:
9221*38fd1498Szrj     case BUILT_IN_UADD_OVERFLOW:
9222*38fd1498Szrj     case BUILT_IN_UADDL_OVERFLOW:
9223*38fd1498Szrj     case BUILT_IN_UADDLL_OVERFLOW:
9224*38fd1498Szrj     case BUILT_IN_USUB_OVERFLOW:
9225*38fd1498Szrj     case BUILT_IN_USUBL_OVERFLOW:
9226*38fd1498Szrj     case BUILT_IN_USUBLL_OVERFLOW:
9227*38fd1498Szrj     case BUILT_IN_UMUL_OVERFLOW:
9228*38fd1498Szrj     case BUILT_IN_UMULL_OVERFLOW:
9229*38fd1498Szrj     case BUILT_IN_UMULLL_OVERFLOW:
9230*38fd1498Szrj       return fold_builtin_arith_overflow (loc, fcode, arg0, arg1, arg2);
9231*38fd1498Szrj 
9232*38fd1498Szrj     default:
9233*38fd1498Szrj       break;
9234*38fd1498Szrj     }
9235*38fd1498Szrj   return NULL_TREE;
9236*38fd1498Szrj }
9237*38fd1498Szrj 
9238*38fd1498Szrj /* Fold a call to built-in function FNDECL.  ARGS is an array of NARGS
9239*38fd1498Szrj    arguments.  IGNORE is true if the result of the
9240*38fd1498Szrj    function call is ignored.  This function returns NULL_TREE if no
9241*38fd1498Szrj    simplification was possible.  */
9242*38fd1498Szrj 
9243*38fd1498Szrj tree
fold_builtin_n(location_t loc,tree fndecl,tree * args,int nargs,bool)9244*38fd1498Szrj fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool)
9245*38fd1498Szrj {
9246*38fd1498Szrj   tree ret = NULL_TREE;
9247*38fd1498Szrj 
9248*38fd1498Szrj   switch (nargs)
9249*38fd1498Szrj     {
9250*38fd1498Szrj     case 0:
9251*38fd1498Szrj       ret = fold_builtin_0 (loc, fndecl);
9252*38fd1498Szrj       break;
9253*38fd1498Szrj     case 1:
9254*38fd1498Szrj       ret = fold_builtin_1 (loc, fndecl, args[0]);
9255*38fd1498Szrj       break;
9256*38fd1498Szrj     case 2:
9257*38fd1498Szrj       ret = fold_builtin_2 (loc, fndecl, args[0], args[1]);
9258*38fd1498Szrj       break;
9259*38fd1498Szrj     case 3:
9260*38fd1498Szrj       ret = fold_builtin_3 (loc, fndecl, args[0], args[1], args[2]);
9261*38fd1498Szrj       break;
9262*38fd1498Szrj     default:
9263*38fd1498Szrj       ret = fold_builtin_varargs (loc, fndecl, args, nargs);
9264*38fd1498Szrj       break;
9265*38fd1498Szrj     }
9266*38fd1498Szrj   if (ret)
9267*38fd1498Szrj     {
9268*38fd1498Szrj       ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
9269*38fd1498Szrj       SET_EXPR_LOCATION (ret, loc);
9270*38fd1498Szrj       TREE_NO_WARNING (ret) = 1;
9271*38fd1498Szrj       return ret;
9272*38fd1498Szrj     }
9273*38fd1498Szrj   return NULL_TREE;
9274*38fd1498Szrj }
9275*38fd1498Szrj 
9276*38fd1498Szrj /* Construct a new CALL_EXPR to FNDECL using the tail of the argument
9277*38fd1498Szrj    list ARGS along with N new arguments in NEWARGS.  SKIP is the number
9278*38fd1498Szrj    of arguments in ARGS to be omitted.  OLDNARGS is the number of
9279*38fd1498Szrj    elements in ARGS.  */
9280*38fd1498Szrj 
9281*38fd1498Szrj static tree
rewrite_call_expr_valist(location_t loc,int oldnargs,tree * args,int skip,tree fndecl,int n,va_list newargs)9282*38fd1498Szrj rewrite_call_expr_valist (location_t loc, int oldnargs, tree *args,
9283*38fd1498Szrj 			  int skip, tree fndecl, int n, va_list newargs)
9284*38fd1498Szrj {
9285*38fd1498Szrj   int nargs = oldnargs - skip + n;
9286*38fd1498Szrj   tree *buffer;
9287*38fd1498Szrj 
9288*38fd1498Szrj   if (n > 0)
9289*38fd1498Szrj     {
9290*38fd1498Szrj       int i, j;
9291*38fd1498Szrj 
9292*38fd1498Szrj       buffer = XALLOCAVEC (tree, nargs);
9293*38fd1498Szrj       for (i = 0; i < n; i++)
9294*38fd1498Szrj 	buffer[i] = va_arg (newargs, tree);
9295*38fd1498Szrj       for (j = skip; j < oldnargs; j++, i++)
9296*38fd1498Szrj 	buffer[i] = args[j];
9297*38fd1498Szrj     }
9298*38fd1498Szrj   else
9299*38fd1498Szrj     buffer = args + skip;
9300*38fd1498Szrj 
9301*38fd1498Szrj   return build_call_expr_loc_array (loc, fndecl, nargs, buffer);
9302*38fd1498Szrj }
9303*38fd1498Szrj 
9304*38fd1498Szrj /* Return true if FNDECL shouldn't be folded right now.
9305*38fd1498Szrj    If a built-in function has an inline attribute always_inline
9306*38fd1498Szrj    wrapper, defer folding it after always_inline functions have
9307*38fd1498Szrj    been inlined, otherwise e.g. -D_FORTIFY_SOURCE checking
9308*38fd1498Szrj    might not be performed.  */
9309*38fd1498Szrj 
9310*38fd1498Szrj bool
avoid_folding_inline_builtin(tree fndecl)9311*38fd1498Szrj avoid_folding_inline_builtin (tree fndecl)
9312*38fd1498Szrj {
9313*38fd1498Szrj   return (DECL_DECLARED_INLINE_P (fndecl)
9314*38fd1498Szrj 	  && DECL_DISREGARD_INLINE_LIMITS (fndecl)
9315*38fd1498Szrj 	  && cfun
9316*38fd1498Szrj 	  && !cfun->always_inline_functions_inlined
9317*38fd1498Szrj 	  && lookup_attribute ("always_inline", DECL_ATTRIBUTES (fndecl)));
9318*38fd1498Szrj }
9319*38fd1498Szrj 
9320*38fd1498Szrj /* A wrapper function for builtin folding that prevents warnings for
9321*38fd1498Szrj    "statement without effect" and the like, caused by removing the
9322*38fd1498Szrj    call node earlier than the warning is generated.  */
9323*38fd1498Szrj 
9324*38fd1498Szrj tree
fold_call_expr(location_t loc,tree exp,bool ignore)9325*38fd1498Szrj fold_call_expr (location_t loc, tree exp, bool ignore)
9326*38fd1498Szrj {
9327*38fd1498Szrj   tree ret = NULL_TREE;
9328*38fd1498Szrj   tree fndecl = get_callee_fndecl (exp);
9329*38fd1498Szrj   if (fndecl
9330*38fd1498Szrj       && TREE_CODE (fndecl) == FUNCTION_DECL
9331*38fd1498Szrj       && DECL_BUILT_IN (fndecl)
9332*38fd1498Szrj       /* If CALL_EXPR_VA_ARG_PACK is set, the arguments aren't finalized
9333*38fd1498Szrj 	 yet.  Defer folding until we see all the arguments
9334*38fd1498Szrj 	 (after inlining).  */
9335*38fd1498Szrj       && !CALL_EXPR_VA_ARG_PACK (exp))
9336*38fd1498Szrj     {
9337*38fd1498Szrj       int nargs = call_expr_nargs (exp);
9338*38fd1498Szrj 
9339*38fd1498Szrj       /* Before gimplification CALL_EXPR_VA_ARG_PACK is not set, but
9340*38fd1498Szrj 	 instead last argument is __builtin_va_arg_pack ().  Defer folding
9341*38fd1498Szrj 	 even in that case, until arguments are finalized.  */
9342*38fd1498Szrj       if (nargs && TREE_CODE (CALL_EXPR_ARG (exp, nargs - 1)) == CALL_EXPR)
9343*38fd1498Szrj 	{
9344*38fd1498Szrj 	  tree fndecl2 = get_callee_fndecl (CALL_EXPR_ARG (exp, nargs - 1));
9345*38fd1498Szrj 	  if (fndecl2
9346*38fd1498Szrj 	      && TREE_CODE (fndecl2) == FUNCTION_DECL
9347*38fd1498Szrj 	      && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL
9348*38fd1498Szrj 	      && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
9349*38fd1498Szrj 	    return NULL_TREE;
9350*38fd1498Szrj 	}
9351*38fd1498Szrj 
9352*38fd1498Szrj       if (avoid_folding_inline_builtin (fndecl))
9353*38fd1498Szrj 	return NULL_TREE;
9354*38fd1498Szrj 
9355*38fd1498Szrj       if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
9356*38fd1498Szrj         return targetm.fold_builtin (fndecl, call_expr_nargs (exp),
9357*38fd1498Szrj 				     CALL_EXPR_ARGP (exp), ignore);
9358*38fd1498Szrj       else
9359*38fd1498Szrj 	{
9360*38fd1498Szrj 	  tree *args = CALL_EXPR_ARGP (exp);
9361*38fd1498Szrj 	  ret = fold_builtin_n (loc, fndecl, args, nargs, ignore);
9362*38fd1498Szrj 	  if (ret)
9363*38fd1498Szrj 	    return ret;
9364*38fd1498Szrj 	}
9365*38fd1498Szrj     }
9366*38fd1498Szrj   return NULL_TREE;
9367*38fd1498Szrj }
9368*38fd1498Szrj 
9369*38fd1498Szrj /* Fold a CALL_EXPR with type TYPE with FN as the function expression.
9370*38fd1498Szrj    N arguments are passed in the array ARGARRAY.  Return a folded
9371*38fd1498Szrj    expression or NULL_TREE if no simplification was possible.  */
9372*38fd1498Szrj 
9373*38fd1498Szrj tree
fold_builtin_call_array(location_t loc,tree,tree fn,int n,tree * argarray)9374*38fd1498Szrj fold_builtin_call_array (location_t loc, tree,
9375*38fd1498Szrj 			 tree fn,
9376*38fd1498Szrj 			 int n,
9377*38fd1498Szrj 			 tree *argarray)
9378*38fd1498Szrj {
9379*38fd1498Szrj   if (TREE_CODE (fn) != ADDR_EXPR)
9380*38fd1498Szrj     return NULL_TREE;
9381*38fd1498Szrj 
9382*38fd1498Szrj   tree fndecl = TREE_OPERAND (fn, 0);
9383*38fd1498Szrj   if (TREE_CODE (fndecl) == FUNCTION_DECL
9384*38fd1498Szrj       && DECL_BUILT_IN (fndecl))
9385*38fd1498Szrj     {
9386*38fd1498Szrj       /* If last argument is __builtin_va_arg_pack (), arguments to this
9387*38fd1498Szrj 	 function are not finalized yet.  Defer folding until they are.  */
9388*38fd1498Szrj       if (n && TREE_CODE (argarray[n - 1]) == CALL_EXPR)
9389*38fd1498Szrj 	{
9390*38fd1498Szrj 	  tree fndecl2 = get_callee_fndecl (argarray[n - 1]);
9391*38fd1498Szrj 	  if (fndecl2
9392*38fd1498Szrj 	      && TREE_CODE (fndecl2) == FUNCTION_DECL
9393*38fd1498Szrj 	      && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL
9394*38fd1498Szrj 	      && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
9395*38fd1498Szrj 	    return NULL_TREE;
9396*38fd1498Szrj 	}
9397*38fd1498Szrj       if (avoid_folding_inline_builtin (fndecl))
9398*38fd1498Szrj 	return NULL_TREE;
9399*38fd1498Szrj       if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
9400*38fd1498Szrj 	return targetm.fold_builtin (fndecl, n, argarray, false);
9401*38fd1498Szrj       else
9402*38fd1498Szrj 	return fold_builtin_n (loc, fndecl, argarray, n, false);
9403*38fd1498Szrj     }
9404*38fd1498Szrj 
9405*38fd1498Szrj   return NULL_TREE;
9406*38fd1498Szrj }
9407*38fd1498Szrj 
9408*38fd1498Szrj /* Construct a new CALL_EXPR using the tail of the argument list of EXP
9409*38fd1498Szrj    along with N new arguments specified as the "..." parameters.  SKIP
9410*38fd1498Szrj    is the number of arguments in EXP to be omitted.  This function is used
9411*38fd1498Szrj    to do varargs-to-varargs transformations.  */
9412*38fd1498Szrj 
9413*38fd1498Szrj static tree
rewrite_call_expr(location_t loc,tree exp,int skip,tree fndecl,int n,...)9414*38fd1498Szrj rewrite_call_expr (location_t loc, tree exp, int skip, tree fndecl, int n, ...)
9415*38fd1498Szrj {
9416*38fd1498Szrj   va_list ap;
9417*38fd1498Szrj   tree t;
9418*38fd1498Szrj 
9419*38fd1498Szrj   va_start (ap, n);
9420*38fd1498Szrj   t = rewrite_call_expr_valist (loc, call_expr_nargs (exp),
9421*38fd1498Szrj 				CALL_EXPR_ARGP (exp), skip, fndecl, n, ap);
9422*38fd1498Szrj   va_end (ap);
9423*38fd1498Szrj 
9424*38fd1498Szrj   return t;
9425*38fd1498Szrj }
9426*38fd1498Szrj 
9427*38fd1498Szrj /* Validate a single argument ARG against a tree code CODE representing
9428*38fd1498Szrj    a type.  Return true when argument is valid.  */
9429*38fd1498Szrj 
9430*38fd1498Szrj static bool
validate_arg(const_tree arg,enum tree_code code)9431*38fd1498Szrj validate_arg (const_tree arg, enum tree_code code)
9432*38fd1498Szrj {
9433*38fd1498Szrj   if (!arg)
9434*38fd1498Szrj     return false;
9435*38fd1498Szrj   else if (code == POINTER_TYPE)
9436*38fd1498Szrj     return POINTER_TYPE_P (TREE_TYPE (arg));
9437*38fd1498Szrj   else if (code == INTEGER_TYPE)
9438*38fd1498Szrj     return INTEGRAL_TYPE_P (TREE_TYPE (arg));
9439*38fd1498Szrj   return code == TREE_CODE (TREE_TYPE (arg));
9440*38fd1498Szrj }
9441*38fd1498Szrj 
9442*38fd1498Szrj /* This function validates the types of a function call argument list
9443*38fd1498Szrj    against a specified list of tree_codes.  If the last specifier is a 0,
9444*38fd1498Szrj    that represents an ellipses, otherwise the last specifier must be a
9445*38fd1498Szrj    VOID_TYPE.
9446*38fd1498Szrj 
9447*38fd1498Szrj    This is the GIMPLE version of validate_arglist.  Eventually we want to
9448*38fd1498Szrj    completely convert builtins.c to work from GIMPLEs and the tree based
9449*38fd1498Szrj    validate_arglist will then be removed.  */
9450*38fd1498Szrj 
9451*38fd1498Szrj bool
validate_gimple_arglist(const gcall * call,...)9452*38fd1498Szrj validate_gimple_arglist (const gcall *call, ...)
9453*38fd1498Szrj {
9454*38fd1498Szrj   enum tree_code code;
9455*38fd1498Szrj   bool res = 0;
9456*38fd1498Szrj   va_list ap;
9457*38fd1498Szrj   const_tree arg;
9458*38fd1498Szrj   size_t i;
9459*38fd1498Szrj 
9460*38fd1498Szrj   va_start (ap, call);
9461*38fd1498Szrj   i = 0;
9462*38fd1498Szrj 
9463*38fd1498Szrj   do
9464*38fd1498Szrj     {
9465*38fd1498Szrj       code = (enum tree_code) va_arg (ap, int);
9466*38fd1498Szrj       switch (code)
9467*38fd1498Szrj 	{
9468*38fd1498Szrj 	case 0:
9469*38fd1498Szrj 	  /* This signifies an ellipses, any further arguments are all ok.  */
9470*38fd1498Szrj 	  res = true;
9471*38fd1498Szrj 	  goto end;
9472*38fd1498Szrj 	case VOID_TYPE:
9473*38fd1498Szrj 	  /* This signifies an endlink, if no arguments remain, return
9474*38fd1498Szrj 	     true, otherwise return false.  */
9475*38fd1498Szrj 	  res = (i == gimple_call_num_args (call));
9476*38fd1498Szrj 	  goto end;
9477*38fd1498Szrj 	default:
9478*38fd1498Szrj 	  /* If no parameters remain or the parameter's code does not
9479*38fd1498Szrj 	     match the specified code, return false.  Otherwise continue
9480*38fd1498Szrj 	     checking any remaining arguments.  */
9481*38fd1498Szrj 	  arg = gimple_call_arg (call, i++);
9482*38fd1498Szrj 	  if (!validate_arg (arg, code))
9483*38fd1498Szrj 	    goto end;
9484*38fd1498Szrj 	  break;
9485*38fd1498Szrj 	}
9486*38fd1498Szrj     }
9487*38fd1498Szrj   while (1);
9488*38fd1498Szrj 
9489*38fd1498Szrj   /* We need gotos here since we can only have one VA_CLOSE in a
9490*38fd1498Szrj      function.  */
9491*38fd1498Szrj  end: ;
9492*38fd1498Szrj   va_end (ap);
9493*38fd1498Szrj 
9494*38fd1498Szrj   return res;
9495*38fd1498Szrj }
9496*38fd1498Szrj 
9497*38fd1498Szrj /* Default target-specific builtin expander that does nothing.  */
9498*38fd1498Szrj 
9499*38fd1498Szrj rtx
default_expand_builtin(tree exp ATTRIBUTE_UNUSED,rtx target ATTRIBUTE_UNUSED,rtx subtarget ATTRIBUTE_UNUSED,machine_mode mode ATTRIBUTE_UNUSED,int ignore ATTRIBUTE_UNUSED)9500*38fd1498Szrj default_expand_builtin (tree exp ATTRIBUTE_UNUSED,
9501*38fd1498Szrj 			rtx target ATTRIBUTE_UNUSED,
9502*38fd1498Szrj 			rtx subtarget ATTRIBUTE_UNUSED,
9503*38fd1498Szrj 			machine_mode mode ATTRIBUTE_UNUSED,
9504*38fd1498Szrj 			int ignore ATTRIBUTE_UNUSED)
9505*38fd1498Szrj {
9506*38fd1498Szrj   return NULL_RTX;
9507*38fd1498Szrj }
9508*38fd1498Szrj 
9509*38fd1498Szrj /* Returns true is EXP represents data that would potentially reside
9510*38fd1498Szrj    in a readonly section.  */
9511*38fd1498Szrj 
9512*38fd1498Szrj bool
readonly_data_expr(tree exp)9513*38fd1498Szrj readonly_data_expr (tree exp)
9514*38fd1498Szrj {
9515*38fd1498Szrj   STRIP_NOPS (exp);
9516*38fd1498Szrj 
9517*38fd1498Szrj   if (TREE_CODE (exp) != ADDR_EXPR)
9518*38fd1498Szrj     return false;
9519*38fd1498Szrj 
9520*38fd1498Szrj   exp = get_base_address (TREE_OPERAND (exp, 0));
9521*38fd1498Szrj   if (!exp)
9522*38fd1498Szrj     return false;
9523*38fd1498Szrj 
9524*38fd1498Szrj   /* Make sure we call decl_readonly_section only for trees it
9525*38fd1498Szrj      can handle (since it returns true for everything it doesn't
9526*38fd1498Szrj      understand).  */
9527*38fd1498Szrj   if (TREE_CODE (exp) == STRING_CST
9528*38fd1498Szrj       || TREE_CODE (exp) == CONSTRUCTOR
9529*38fd1498Szrj       || (VAR_P (exp) && TREE_STATIC (exp)))
9530*38fd1498Szrj     return decl_readonly_section (exp, 0);
9531*38fd1498Szrj   else
9532*38fd1498Szrj     return false;
9533*38fd1498Szrj }
9534*38fd1498Szrj 
9535*38fd1498Szrj /* Simplify a call to the strpbrk builtin.  S1 and S2 are the arguments
9536*38fd1498Szrj    to the call, and TYPE is its return type.
9537*38fd1498Szrj 
9538*38fd1498Szrj    Return NULL_TREE if no simplification was possible, otherwise return the
9539*38fd1498Szrj    simplified form of the call as a tree.
9540*38fd1498Szrj 
9541*38fd1498Szrj    The simplified form may be a constant or other expression which
9542*38fd1498Szrj    computes the same value, but in a more efficient manner (including
9543*38fd1498Szrj    calls to other builtin functions).
9544*38fd1498Szrj 
9545*38fd1498Szrj    The call may contain arguments which need to be evaluated, but
9546*38fd1498Szrj    which are not useful to determine the result of the call.  In
9547*38fd1498Szrj    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
9548*38fd1498Szrj    COMPOUND_EXPR will be an argument which must be evaluated.
9549*38fd1498Szrj    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
9550*38fd1498Szrj    COMPOUND_EXPR in the chain will contain the tree for the simplified
9551*38fd1498Szrj    form of the builtin function call.  */
9552*38fd1498Szrj 
9553*38fd1498Szrj static tree
fold_builtin_strpbrk(location_t loc,tree s1,tree s2,tree type)9554*38fd1498Szrj fold_builtin_strpbrk (location_t loc, tree s1, tree s2, tree type)
9555*38fd1498Szrj {
9556*38fd1498Szrj   if (!validate_arg (s1, POINTER_TYPE)
9557*38fd1498Szrj       || !validate_arg (s2, POINTER_TYPE))
9558*38fd1498Szrj     return NULL_TREE;
9559*38fd1498Szrj   else
9560*38fd1498Szrj     {
9561*38fd1498Szrj       tree fn;
9562*38fd1498Szrj       const char *p1, *p2;
9563*38fd1498Szrj 
9564*38fd1498Szrj       p2 = c_getstr (s2);
9565*38fd1498Szrj       if (p2 == NULL)
9566*38fd1498Szrj 	return NULL_TREE;
9567*38fd1498Szrj 
9568*38fd1498Szrj       p1 = c_getstr (s1);
9569*38fd1498Szrj       if (p1 != NULL)
9570*38fd1498Szrj 	{
9571*38fd1498Szrj 	  const char *r = strpbrk (p1, p2);
9572*38fd1498Szrj 	  tree tem;
9573*38fd1498Szrj 
9574*38fd1498Szrj 	  if (r == NULL)
9575*38fd1498Szrj 	    return build_int_cst (TREE_TYPE (s1), 0);
9576*38fd1498Szrj 
9577*38fd1498Szrj 	  /* Return an offset into the constant string argument.  */
9578*38fd1498Szrj 	  tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
9579*38fd1498Szrj 	  return fold_convert_loc (loc, type, tem);
9580*38fd1498Szrj 	}
9581*38fd1498Szrj 
9582*38fd1498Szrj       if (p2[0] == '\0')
9583*38fd1498Szrj 	/* strpbrk(x, "") == NULL.
9584*38fd1498Szrj 	   Evaluate and ignore s1 in case it had side-effects.  */
9585*38fd1498Szrj 	return omit_one_operand_loc (loc, type, integer_zero_node, s1);
9586*38fd1498Szrj 
9587*38fd1498Szrj       if (p2[1] != '\0')
9588*38fd1498Szrj 	return NULL_TREE;  /* Really call strpbrk.  */
9589*38fd1498Szrj 
9590*38fd1498Szrj       fn = builtin_decl_implicit (BUILT_IN_STRCHR);
9591*38fd1498Szrj       if (!fn)
9592*38fd1498Szrj 	return NULL_TREE;
9593*38fd1498Szrj 
9594*38fd1498Szrj       /* New argument list transforming strpbrk(s1, s2) to
9595*38fd1498Szrj 	 strchr(s1, s2[0]).  */
9596*38fd1498Szrj       return build_call_expr_loc (loc, fn, 2, s1,
9597*38fd1498Szrj 				  build_int_cst (integer_type_node, p2[0]));
9598*38fd1498Szrj     }
9599*38fd1498Szrj }
9600*38fd1498Szrj 
9601*38fd1498Szrj /* Simplify a call to the strspn builtin.  S1 and S2 are the arguments
9602*38fd1498Szrj    to the call.
9603*38fd1498Szrj 
9604*38fd1498Szrj    Return NULL_TREE if no simplification was possible, otherwise return the
9605*38fd1498Szrj    simplified form of the call as a tree.
9606*38fd1498Szrj 
9607*38fd1498Szrj    The simplified form may be a constant or other expression which
9608*38fd1498Szrj    computes the same value, but in a more efficient manner (including
9609*38fd1498Szrj    calls to other builtin functions).
9610*38fd1498Szrj 
9611*38fd1498Szrj    The call may contain arguments which need to be evaluated, but
9612*38fd1498Szrj    which are not useful to determine the result of the call.  In
9613*38fd1498Szrj    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
9614*38fd1498Szrj    COMPOUND_EXPR will be an argument which must be evaluated.
9615*38fd1498Szrj    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
9616*38fd1498Szrj    COMPOUND_EXPR in the chain will contain the tree for the simplified
9617*38fd1498Szrj    form of the builtin function call.  */
9618*38fd1498Szrj 
9619*38fd1498Szrj static tree
fold_builtin_strspn(location_t loc,tree s1,tree s2)9620*38fd1498Szrj fold_builtin_strspn (location_t loc, tree s1, tree s2)
9621*38fd1498Szrj {
9622*38fd1498Szrj   if (!validate_arg (s1, POINTER_TYPE)
9623*38fd1498Szrj       || !validate_arg (s2, POINTER_TYPE))
9624*38fd1498Szrj     return NULL_TREE;
9625*38fd1498Szrj   else
9626*38fd1498Szrj     {
9627*38fd1498Szrj       const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
9628*38fd1498Szrj 
9629*38fd1498Szrj       /* If either argument is "", return NULL_TREE.  */
9630*38fd1498Szrj       if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
9631*38fd1498Szrj 	/* Evaluate and ignore both arguments in case either one has
9632*38fd1498Szrj 	   side-effects.  */
9633*38fd1498Szrj 	return omit_two_operands_loc (loc, size_type_node, size_zero_node,
9634*38fd1498Szrj 				  s1, s2);
9635*38fd1498Szrj       return NULL_TREE;
9636*38fd1498Szrj     }
9637*38fd1498Szrj }
9638*38fd1498Szrj 
9639*38fd1498Szrj /* Simplify a call to the strcspn builtin.  S1 and S2 are the arguments
9640*38fd1498Szrj    to the call.
9641*38fd1498Szrj 
9642*38fd1498Szrj    Return NULL_TREE if no simplification was possible, otherwise return the
9643*38fd1498Szrj    simplified form of the call as a tree.
9644*38fd1498Szrj 
9645*38fd1498Szrj    The simplified form may be a constant or other expression which
9646*38fd1498Szrj    computes the same value, but in a more efficient manner (including
9647*38fd1498Szrj    calls to other builtin functions).
9648*38fd1498Szrj 
9649*38fd1498Szrj    The call may contain arguments which need to be evaluated, but
9650*38fd1498Szrj    which are not useful to determine the result of the call.  In
9651*38fd1498Szrj    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
9652*38fd1498Szrj    COMPOUND_EXPR will be an argument which must be evaluated.
9653*38fd1498Szrj    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
9654*38fd1498Szrj    COMPOUND_EXPR in the chain will contain the tree for the simplified
9655*38fd1498Szrj    form of the builtin function call.  */
9656*38fd1498Szrj 
9657*38fd1498Szrj static tree
fold_builtin_strcspn(location_t loc,tree s1,tree s2)9658*38fd1498Szrj fold_builtin_strcspn (location_t loc, tree s1, tree s2)
9659*38fd1498Szrj {
9660*38fd1498Szrj   if (!validate_arg (s1, POINTER_TYPE)
9661*38fd1498Szrj       || !validate_arg (s2, POINTER_TYPE))
9662*38fd1498Szrj     return NULL_TREE;
9663*38fd1498Szrj   else
9664*38fd1498Szrj     {
9665*38fd1498Szrj       /* If the first argument is "", return NULL_TREE.  */
9666*38fd1498Szrj       const char *p1 = c_getstr (s1);
9667*38fd1498Szrj       if (p1 && *p1 == '\0')
9668*38fd1498Szrj 	{
9669*38fd1498Szrj 	  /* Evaluate and ignore argument s2 in case it has
9670*38fd1498Szrj 	     side-effects.  */
9671*38fd1498Szrj 	  return omit_one_operand_loc (loc, size_type_node,
9672*38fd1498Szrj 				   size_zero_node, s2);
9673*38fd1498Szrj 	}
9674*38fd1498Szrj 
9675*38fd1498Szrj       /* If the second argument is "", return __builtin_strlen(s1).  */
9676*38fd1498Szrj       const char *p2 = c_getstr (s2);
9677*38fd1498Szrj       if (p2 && *p2 == '\0')
9678*38fd1498Szrj 	{
9679*38fd1498Szrj 	  tree fn = builtin_decl_implicit (BUILT_IN_STRLEN);
9680*38fd1498Szrj 
9681*38fd1498Szrj 	  /* If the replacement _DECL isn't initialized, don't do the
9682*38fd1498Szrj 	     transformation.  */
9683*38fd1498Szrj 	  if (!fn)
9684*38fd1498Szrj 	    return NULL_TREE;
9685*38fd1498Szrj 
9686*38fd1498Szrj 	  return build_call_expr_loc (loc, fn, 1, s1);
9687*38fd1498Szrj 	}
9688*38fd1498Szrj       return NULL_TREE;
9689*38fd1498Szrj     }
9690*38fd1498Szrj }
9691*38fd1498Szrj 
9692*38fd1498Szrj /* Fold the next_arg or va_start call EXP. Returns true if there was an error
9693*38fd1498Szrj    produced.  False otherwise.  This is done so that we don't output the error
9694*38fd1498Szrj    or warning twice or three times.  */
9695*38fd1498Szrj 
9696*38fd1498Szrj bool
fold_builtin_next_arg(tree exp,bool va_start_p)9697*38fd1498Szrj fold_builtin_next_arg (tree exp, bool va_start_p)
9698*38fd1498Szrj {
9699*38fd1498Szrj   tree fntype = TREE_TYPE (current_function_decl);
9700*38fd1498Szrj   int nargs = call_expr_nargs (exp);
9701*38fd1498Szrj   tree arg;
9702*38fd1498Szrj   /* There is good chance the current input_location points inside the
9703*38fd1498Szrj      definition of the va_start macro (perhaps on the token for
9704*38fd1498Szrj      builtin) in a system header, so warnings will not be emitted.
9705*38fd1498Szrj      Use the location in real source code.  */
9706*38fd1498Szrj   source_location current_location =
9707*38fd1498Szrj     linemap_unwind_to_first_non_reserved_loc (line_table, input_location,
9708*38fd1498Szrj 					      NULL);
9709*38fd1498Szrj 
9710*38fd1498Szrj   if (!stdarg_p (fntype))
9711*38fd1498Szrj     {
9712*38fd1498Szrj       error ("%<va_start%> used in function with fixed args");
9713*38fd1498Szrj       return true;
9714*38fd1498Szrj     }
9715*38fd1498Szrj 
9716*38fd1498Szrj   if (va_start_p)
9717*38fd1498Szrj     {
9718*38fd1498Szrj       if (va_start_p && (nargs != 2))
9719*38fd1498Szrj 	{
9720*38fd1498Szrj 	  error ("wrong number of arguments to function %<va_start%>");
9721*38fd1498Szrj 	  return true;
9722*38fd1498Szrj 	}
9723*38fd1498Szrj       arg = CALL_EXPR_ARG (exp, 1);
9724*38fd1498Szrj     }
9725*38fd1498Szrj   /* We use __builtin_va_start (ap, 0, 0) or __builtin_next_arg (0, 0)
9726*38fd1498Szrj      when we checked the arguments and if needed issued a warning.  */
9727*38fd1498Szrj   else
9728*38fd1498Szrj     {
9729*38fd1498Szrj       if (nargs == 0)
9730*38fd1498Szrj 	{
9731*38fd1498Szrj 	  /* Evidently an out of date version of <stdarg.h>; can't validate
9732*38fd1498Szrj 	     va_start's second argument, but can still work as intended.  */
9733*38fd1498Szrj 	  warning_at (current_location,
9734*38fd1498Szrj 		      OPT_Wvarargs,
9735*38fd1498Szrj 		   "%<__builtin_next_arg%> called without an argument");
9736*38fd1498Szrj 	  return true;
9737*38fd1498Szrj 	}
9738*38fd1498Szrj       else if (nargs > 1)
9739*38fd1498Szrj 	{
9740*38fd1498Szrj 	  error ("wrong number of arguments to function %<__builtin_next_arg%>");
9741*38fd1498Szrj 	  return true;
9742*38fd1498Szrj 	}
9743*38fd1498Szrj       arg = CALL_EXPR_ARG (exp, 0);
9744*38fd1498Szrj     }
9745*38fd1498Szrj 
9746*38fd1498Szrj   if (TREE_CODE (arg) == SSA_NAME)
9747*38fd1498Szrj     arg = SSA_NAME_VAR (arg);
9748*38fd1498Szrj 
9749*38fd1498Szrj   /* We destructively modify the call to be __builtin_va_start (ap, 0)
9750*38fd1498Szrj      or __builtin_next_arg (0) the first time we see it, after checking
9751*38fd1498Szrj      the arguments and if needed issuing a warning.  */
9752*38fd1498Szrj   if (!integer_zerop (arg))
9753*38fd1498Szrj     {
9754*38fd1498Szrj       tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
9755*38fd1498Szrj 
9756*38fd1498Szrj       /* Strip off all nops for the sake of the comparison.  This
9757*38fd1498Szrj 	 is not quite the same as STRIP_NOPS.  It does more.
9758*38fd1498Szrj 	 We must also strip off INDIRECT_EXPR for C++ reference
9759*38fd1498Szrj 	 parameters.  */
9760*38fd1498Szrj       while (CONVERT_EXPR_P (arg)
9761*38fd1498Szrj 	     || TREE_CODE (arg) == INDIRECT_REF)
9762*38fd1498Szrj 	arg = TREE_OPERAND (arg, 0);
9763*38fd1498Szrj       if (arg != last_parm)
9764*38fd1498Szrj 	{
9765*38fd1498Szrj 	  /* FIXME: Sometimes with the tree optimizers we can get the
9766*38fd1498Szrj 	     not the last argument even though the user used the last
9767*38fd1498Szrj 	     argument.  We just warn and set the arg to be the last
9768*38fd1498Szrj 	     argument so that we will get wrong-code because of
9769*38fd1498Szrj 	     it.  */
9770*38fd1498Szrj 	  warning_at (current_location,
9771*38fd1498Szrj 		      OPT_Wvarargs,
9772*38fd1498Szrj 		      "second parameter of %<va_start%> not last named argument");
9773*38fd1498Szrj 	}
9774*38fd1498Szrj 
9775*38fd1498Szrj       /* Undefined by C99 7.15.1.4p4 (va_start):
9776*38fd1498Szrj          "If the parameter parmN is declared with the register storage
9777*38fd1498Szrj          class, with a function or array type, or with a type that is
9778*38fd1498Szrj          not compatible with the type that results after application of
9779*38fd1498Szrj          the default argument promotions, the behavior is undefined."
9780*38fd1498Szrj       */
9781*38fd1498Szrj       else if (DECL_REGISTER (arg))
9782*38fd1498Szrj 	{
9783*38fd1498Szrj 	  warning_at (current_location,
9784*38fd1498Szrj 		      OPT_Wvarargs,
9785*38fd1498Szrj 		      "undefined behavior when second parameter of "
9786*38fd1498Szrj 		      "%<va_start%> is declared with %<register%> storage");
9787*38fd1498Szrj 	}
9788*38fd1498Szrj 
9789*38fd1498Szrj       /* We want to verify the second parameter just once before the tree
9790*38fd1498Szrj 	 optimizers are run and then avoid keeping it in the tree,
9791*38fd1498Szrj 	 as otherwise we could warn even for correct code like:
9792*38fd1498Szrj 	 void foo (int i, ...)
9793*38fd1498Szrj 	 { va_list ap; i++; va_start (ap, i); va_end (ap); }  */
9794*38fd1498Szrj       if (va_start_p)
9795*38fd1498Szrj 	CALL_EXPR_ARG (exp, 1) = integer_zero_node;
9796*38fd1498Szrj       else
9797*38fd1498Szrj 	CALL_EXPR_ARG (exp, 0) = integer_zero_node;
9798*38fd1498Szrj     }
9799*38fd1498Szrj   return false;
9800*38fd1498Szrj }
9801*38fd1498Szrj 
9802*38fd1498Szrj 
9803*38fd1498Szrj /* Expand a call EXP to __builtin_object_size.  */
9804*38fd1498Szrj 
9805*38fd1498Szrj static rtx
expand_builtin_object_size(tree exp)9806*38fd1498Szrj expand_builtin_object_size (tree exp)
9807*38fd1498Szrj {
9808*38fd1498Szrj   tree ost;
9809*38fd1498Szrj   int object_size_type;
9810*38fd1498Szrj   tree fndecl = get_callee_fndecl (exp);
9811*38fd1498Szrj 
9812*38fd1498Szrj   if (!validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
9813*38fd1498Szrj     {
9814*38fd1498Szrj       error ("%Kfirst argument of %qD must be a pointer, second integer constant",
9815*38fd1498Szrj 	     exp, fndecl);
9816*38fd1498Szrj       expand_builtin_trap ();
9817*38fd1498Szrj       return const0_rtx;
9818*38fd1498Szrj     }
9819*38fd1498Szrj 
9820*38fd1498Szrj   ost = CALL_EXPR_ARG (exp, 1);
9821*38fd1498Szrj   STRIP_NOPS (ost);
9822*38fd1498Szrj 
9823*38fd1498Szrj   if (TREE_CODE (ost) != INTEGER_CST
9824*38fd1498Szrj       || tree_int_cst_sgn (ost) < 0
9825*38fd1498Szrj       || compare_tree_int (ost, 3) > 0)
9826*38fd1498Szrj     {
9827*38fd1498Szrj       error ("%Klast argument of %qD is not integer constant between 0 and 3",
9828*38fd1498Szrj 	     exp, fndecl);
9829*38fd1498Szrj       expand_builtin_trap ();
9830*38fd1498Szrj       return const0_rtx;
9831*38fd1498Szrj     }
9832*38fd1498Szrj 
9833*38fd1498Szrj   object_size_type = tree_to_shwi (ost);
9834*38fd1498Szrj 
9835*38fd1498Szrj   return object_size_type < 2 ? constm1_rtx : const0_rtx;
9836*38fd1498Szrj }
9837*38fd1498Szrj 
9838*38fd1498Szrj /* Expand EXP, a call to the __mem{cpy,pcpy,move,set}_chk builtin.
9839*38fd1498Szrj    FCODE is the BUILT_IN_* to use.
9840*38fd1498Szrj    Return NULL_RTX if we failed; the caller should emit a normal call,
9841*38fd1498Szrj    otherwise try to get the result in TARGET, if convenient (and in
9842*38fd1498Szrj    mode MODE if that's convenient).  */
9843*38fd1498Szrj 
9844*38fd1498Szrj static rtx
expand_builtin_memory_chk(tree exp,rtx target,machine_mode mode,enum built_in_function fcode)9845*38fd1498Szrj expand_builtin_memory_chk (tree exp, rtx target, machine_mode mode,
9846*38fd1498Szrj 			   enum built_in_function fcode)
9847*38fd1498Szrj {
9848*38fd1498Szrj   if (!validate_arglist (exp,
9849*38fd1498Szrj 			 POINTER_TYPE,
9850*38fd1498Szrj 			 fcode == BUILT_IN_MEMSET_CHK
9851*38fd1498Szrj 			 ? INTEGER_TYPE : POINTER_TYPE,
9852*38fd1498Szrj 			 INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
9853*38fd1498Szrj     return NULL_RTX;
9854*38fd1498Szrj 
9855*38fd1498Szrj   tree dest = CALL_EXPR_ARG (exp, 0);
9856*38fd1498Szrj   tree src = CALL_EXPR_ARG (exp, 1);
9857*38fd1498Szrj   tree len = CALL_EXPR_ARG (exp, 2);
9858*38fd1498Szrj   tree size = CALL_EXPR_ARG (exp, 3);
9859*38fd1498Szrj 
9860*38fd1498Szrj   bool sizes_ok = check_access (exp, dest, src, len, /*maxread=*/NULL_TREE,
9861*38fd1498Szrj 				/*str=*/NULL_TREE, size);
9862*38fd1498Szrj 
9863*38fd1498Szrj   if (!tree_fits_uhwi_p (size))
9864*38fd1498Szrj     return NULL_RTX;
9865*38fd1498Szrj 
9866*38fd1498Szrj   if (tree_fits_uhwi_p (len) || integer_all_onesp (size))
9867*38fd1498Szrj     {
9868*38fd1498Szrj       /* Avoid transforming the checking call to an ordinary one when
9869*38fd1498Szrj 	 an overflow has been detected or when the call couldn't be
9870*38fd1498Szrj 	 validated because the size is not constant.  */
9871*38fd1498Szrj       if (!sizes_ok && !integer_all_onesp (size) && tree_int_cst_lt (size, len))
9872*38fd1498Szrj 	return NULL_RTX;
9873*38fd1498Szrj 
9874*38fd1498Szrj       tree fn = NULL_TREE;
9875*38fd1498Szrj       /* If __builtin_mem{cpy,pcpy,move,set}_chk is used, assume
9876*38fd1498Szrj 	 mem{cpy,pcpy,move,set} is available.  */
9877*38fd1498Szrj       switch (fcode)
9878*38fd1498Szrj 	{
9879*38fd1498Szrj 	case BUILT_IN_MEMCPY_CHK:
9880*38fd1498Szrj 	  fn = builtin_decl_explicit (BUILT_IN_MEMCPY);
9881*38fd1498Szrj 	  break;
9882*38fd1498Szrj 	case BUILT_IN_MEMPCPY_CHK:
9883*38fd1498Szrj 	  fn = builtin_decl_explicit (BUILT_IN_MEMPCPY);
9884*38fd1498Szrj 	  break;
9885*38fd1498Szrj 	case BUILT_IN_MEMMOVE_CHK:
9886*38fd1498Szrj 	  fn = builtin_decl_explicit (BUILT_IN_MEMMOVE);
9887*38fd1498Szrj 	  break;
9888*38fd1498Szrj 	case BUILT_IN_MEMSET_CHK:
9889*38fd1498Szrj 	  fn = builtin_decl_explicit (BUILT_IN_MEMSET);
9890*38fd1498Szrj 	  break;
9891*38fd1498Szrj 	default:
9892*38fd1498Szrj 	  break;
9893*38fd1498Szrj 	}
9894*38fd1498Szrj 
9895*38fd1498Szrj       if (! fn)
9896*38fd1498Szrj 	return NULL_RTX;
9897*38fd1498Szrj 
9898*38fd1498Szrj       fn = build_call_nofold_loc (EXPR_LOCATION (exp), fn, 3, dest, src, len);
9899*38fd1498Szrj       gcc_assert (TREE_CODE (fn) == CALL_EXPR);
9900*38fd1498Szrj       CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
9901*38fd1498Szrj       return expand_expr (fn, target, mode, EXPAND_NORMAL);
9902*38fd1498Szrj     }
9903*38fd1498Szrj   else if (fcode == BUILT_IN_MEMSET_CHK)
9904*38fd1498Szrj     return NULL_RTX;
9905*38fd1498Szrj   else
9906*38fd1498Szrj     {
9907*38fd1498Szrj       unsigned int dest_align = get_pointer_alignment (dest);
9908*38fd1498Szrj 
9909*38fd1498Szrj       /* If DEST is not a pointer type, call the normal function.  */
9910*38fd1498Szrj       if (dest_align == 0)
9911*38fd1498Szrj 	return NULL_RTX;
9912*38fd1498Szrj 
9913*38fd1498Szrj       /* If SRC and DEST are the same (and not volatile), do nothing.  */
9914*38fd1498Szrj       if (operand_equal_p (src, dest, 0))
9915*38fd1498Szrj 	{
9916*38fd1498Szrj 	  tree expr;
9917*38fd1498Szrj 
9918*38fd1498Szrj 	  if (fcode != BUILT_IN_MEMPCPY_CHK)
9919*38fd1498Szrj 	    {
9920*38fd1498Szrj 	      /* Evaluate and ignore LEN in case it has side-effects.  */
9921*38fd1498Szrj 	      expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL);
9922*38fd1498Szrj 	      return expand_expr (dest, target, mode, EXPAND_NORMAL);
9923*38fd1498Szrj 	    }
9924*38fd1498Szrj 
9925*38fd1498Szrj 	  expr = fold_build_pointer_plus (dest, len);
9926*38fd1498Szrj 	  return expand_expr (expr, target, mode, EXPAND_NORMAL);
9927*38fd1498Szrj 	}
9928*38fd1498Szrj 
9929*38fd1498Szrj       /* __memmove_chk special case.  */
9930*38fd1498Szrj       if (fcode == BUILT_IN_MEMMOVE_CHK)
9931*38fd1498Szrj 	{
9932*38fd1498Szrj 	  unsigned int src_align = get_pointer_alignment (src);
9933*38fd1498Szrj 
9934*38fd1498Szrj 	  if (src_align == 0)
9935*38fd1498Szrj 	    return NULL_RTX;
9936*38fd1498Szrj 
9937*38fd1498Szrj 	  /* If src is categorized for a readonly section we can use
9938*38fd1498Szrj 	     normal __memcpy_chk.  */
9939*38fd1498Szrj 	  if (readonly_data_expr (src))
9940*38fd1498Szrj 	    {
9941*38fd1498Szrj 	      tree fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
9942*38fd1498Szrj 	      if (!fn)
9943*38fd1498Szrj 		return NULL_RTX;
9944*38fd1498Szrj 	      fn = build_call_nofold_loc (EXPR_LOCATION (exp), fn, 4,
9945*38fd1498Szrj 					  dest, src, len, size);
9946*38fd1498Szrj 	      gcc_assert (TREE_CODE (fn) == CALL_EXPR);
9947*38fd1498Szrj 	      CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
9948*38fd1498Szrj 	      return expand_expr (fn, target, mode, EXPAND_NORMAL);
9949*38fd1498Szrj 	    }
9950*38fd1498Szrj 	}
9951*38fd1498Szrj       return NULL_RTX;
9952*38fd1498Szrj     }
9953*38fd1498Szrj }
9954*38fd1498Szrj 
9955*38fd1498Szrj /* Emit warning if a buffer overflow is detected at compile time.  */
9956*38fd1498Szrj 
9957*38fd1498Szrj static void
maybe_emit_chk_warning(tree exp,enum built_in_function fcode)9958*38fd1498Szrj maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
9959*38fd1498Szrj {
9960*38fd1498Szrj   /* The source string.  */
9961*38fd1498Szrj   tree srcstr = NULL_TREE;
9962*38fd1498Szrj   /* The size of the destination object.  */
9963*38fd1498Szrj   tree objsize = NULL_TREE;
9964*38fd1498Szrj   /* The string that is being concatenated with (as in __strcat_chk)
9965*38fd1498Szrj      or null if it isn't.  */
9966*38fd1498Szrj   tree catstr = NULL_TREE;
9967*38fd1498Szrj   /* The maximum length of the source sequence in a bounded operation
9968*38fd1498Szrj      (such as __strncat_chk) or null if the operation isn't bounded
9969*38fd1498Szrj      (such as __strcat_chk).  */
9970*38fd1498Szrj   tree maxread = NULL_TREE;
9971*38fd1498Szrj   /* The exact size of the access (such as in __strncpy_chk).  */
9972*38fd1498Szrj   tree size = NULL_TREE;
9973*38fd1498Szrj 
9974*38fd1498Szrj   switch (fcode)
9975*38fd1498Szrj     {
9976*38fd1498Szrj     case BUILT_IN_STRCPY_CHK:
9977*38fd1498Szrj     case BUILT_IN_STPCPY_CHK:
9978*38fd1498Szrj       srcstr = CALL_EXPR_ARG (exp, 1);
9979*38fd1498Szrj       objsize = CALL_EXPR_ARG (exp, 2);
9980*38fd1498Szrj       break;
9981*38fd1498Szrj 
9982*38fd1498Szrj     case BUILT_IN_STRCAT_CHK:
9983*38fd1498Szrj       /* For __strcat_chk the warning will be emitted only if overflowing
9984*38fd1498Szrj 	 by at least strlen (dest) + 1 bytes.  */
9985*38fd1498Szrj       catstr = CALL_EXPR_ARG (exp, 0);
9986*38fd1498Szrj       srcstr = CALL_EXPR_ARG (exp, 1);
9987*38fd1498Szrj       objsize = CALL_EXPR_ARG (exp, 2);
9988*38fd1498Szrj       break;
9989*38fd1498Szrj 
9990*38fd1498Szrj     case BUILT_IN_STRNCAT_CHK:
9991*38fd1498Szrj       catstr = CALL_EXPR_ARG (exp, 0);
9992*38fd1498Szrj       srcstr = CALL_EXPR_ARG (exp, 1);
9993*38fd1498Szrj       maxread = CALL_EXPR_ARG (exp, 2);
9994*38fd1498Szrj       objsize = CALL_EXPR_ARG (exp, 3);
9995*38fd1498Szrj       break;
9996*38fd1498Szrj 
9997*38fd1498Szrj     case BUILT_IN_STRNCPY_CHK:
9998*38fd1498Szrj     case BUILT_IN_STPNCPY_CHK:
9999*38fd1498Szrj       srcstr = CALL_EXPR_ARG (exp, 1);
10000*38fd1498Szrj       size = CALL_EXPR_ARG (exp, 2);
10001*38fd1498Szrj       objsize = CALL_EXPR_ARG (exp, 3);
10002*38fd1498Szrj       break;
10003*38fd1498Szrj 
10004*38fd1498Szrj     case BUILT_IN_SNPRINTF_CHK:
10005*38fd1498Szrj     case BUILT_IN_VSNPRINTF_CHK:
10006*38fd1498Szrj       maxread = CALL_EXPR_ARG (exp, 1);
10007*38fd1498Szrj       objsize = CALL_EXPR_ARG (exp, 3);
10008*38fd1498Szrj       break;
10009*38fd1498Szrj     default:
10010*38fd1498Szrj       gcc_unreachable ();
10011*38fd1498Szrj     }
10012*38fd1498Szrj 
10013*38fd1498Szrj   if (catstr && maxread)
10014*38fd1498Szrj     {
10015*38fd1498Szrj       /* Check __strncat_chk.  There is no way to determine the length
10016*38fd1498Szrj 	 of the string to which the source string is being appended so
10017*38fd1498Szrj 	 just warn when the length of the source string is not known.  */
10018*38fd1498Szrj       check_strncat_sizes (exp, objsize);
10019*38fd1498Szrj       return;
10020*38fd1498Szrj     }
10021*38fd1498Szrj 
10022*38fd1498Szrj   /* The destination argument is the first one for all built-ins above.  */
10023*38fd1498Szrj   tree dst = CALL_EXPR_ARG (exp, 0);
10024*38fd1498Szrj 
10025*38fd1498Szrj   check_access (exp, dst, srcstr, size, maxread, srcstr, objsize);
10026*38fd1498Szrj }
10027*38fd1498Szrj 
10028*38fd1498Szrj /* Emit warning if a buffer overflow is detected at compile time
10029*38fd1498Szrj    in __sprintf_chk/__vsprintf_chk calls.  */
10030*38fd1498Szrj 
10031*38fd1498Szrj static void
maybe_emit_sprintf_chk_warning(tree exp,enum built_in_function fcode)10032*38fd1498Szrj maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
10033*38fd1498Szrj {
10034*38fd1498Szrj   tree size, len, fmt;
10035*38fd1498Szrj   const char *fmt_str;
10036*38fd1498Szrj   int nargs = call_expr_nargs (exp);
10037*38fd1498Szrj 
10038*38fd1498Szrj   /* Verify the required arguments in the original call.  */
10039*38fd1498Szrj 
10040*38fd1498Szrj   if (nargs < 4)
10041*38fd1498Szrj     return;
10042*38fd1498Szrj   size = CALL_EXPR_ARG (exp, 2);
10043*38fd1498Szrj   fmt = CALL_EXPR_ARG (exp, 3);
10044*38fd1498Szrj 
10045*38fd1498Szrj   if (! tree_fits_uhwi_p (size) || integer_all_onesp (size))
10046*38fd1498Szrj     return;
10047*38fd1498Szrj 
10048*38fd1498Szrj   /* Check whether the format is a literal string constant.  */
10049*38fd1498Szrj   fmt_str = c_getstr (fmt);
10050*38fd1498Szrj   if (fmt_str == NULL)
10051*38fd1498Szrj     return;
10052*38fd1498Szrj 
10053*38fd1498Szrj   if (!init_target_chars ())
10054*38fd1498Szrj     return;
10055*38fd1498Szrj 
10056*38fd1498Szrj   /* If the format doesn't contain % args or %%, we know its size.  */
10057*38fd1498Szrj   if (strchr (fmt_str, target_percent) == 0)
10058*38fd1498Szrj     len = build_int_cstu (size_type_node, strlen (fmt_str));
10059*38fd1498Szrj   /* If the format is "%s" and first ... argument is a string literal,
10060*38fd1498Szrj      we know it too.  */
10061*38fd1498Szrj   else if (fcode == BUILT_IN_SPRINTF_CHK
10062*38fd1498Szrj 	   && strcmp (fmt_str, target_percent_s) == 0)
10063*38fd1498Szrj     {
10064*38fd1498Szrj       tree arg;
10065*38fd1498Szrj 
10066*38fd1498Szrj       if (nargs < 5)
10067*38fd1498Szrj 	return;
10068*38fd1498Szrj       arg = CALL_EXPR_ARG (exp, 4);
10069*38fd1498Szrj       if (! POINTER_TYPE_P (TREE_TYPE (arg)))
10070*38fd1498Szrj 	return;
10071*38fd1498Szrj 
10072*38fd1498Szrj       len = c_strlen (arg, 1);
10073*38fd1498Szrj       if (!len || ! tree_fits_uhwi_p (len))
10074*38fd1498Szrj 	return;
10075*38fd1498Szrj     }
10076*38fd1498Szrj   else
10077*38fd1498Szrj     return;
10078*38fd1498Szrj 
10079*38fd1498Szrj   /* Add one for the terminating nul.  */
10080*38fd1498Szrj   len = fold_build2 (PLUS_EXPR, TREE_TYPE (len), len, size_one_node);
10081*38fd1498Szrj 
10082*38fd1498Szrj   check_access (exp, /*dst=*/NULL_TREE, /*src=*/NULL_TREE, /*size=*/NULL_TREE,
10083*38fd1498Szrj 		/*maxread=*/NULL_TREE, len, size);
10084*38fd1498Szrj }
10085*38fd1498Szrj 
10086*38fd1498Szrj /* Emit warning if a free is called with address of a variable.  */
10087*38fd1498Szrj 
10088*38fd1498Szrj static void
maybe_emit_free_warning(tree exp)10089*38fd1498Szrj maybe_emit_free_warning (tree exp)
10090*38fd1498Szrj {
10091*38fd1498Szrj   tree arg = CALL_EXPR_ARG (exp, 0);
10092*38fd1498Szrj 
10093*38fd1498Szrj   STRIP_NOPS (arg);
10094*38fd1498Szrj   if (TREE_CODE (arg) != ADDR_EXPR)
10095*38fd1498Szrj     return;
10096*38fd1498Szrj 
10097*38fd1498Szrj   arg = get_base_address (TREE_OPERAND (arg, 0));
10098*38fd1498Szrj   if (arg == NULL || INDIRECT_REF_P (arg) || TREE_CODE (arg) == MEM_REF)
10099*38fd1498Szrj     return;
10100*38fd1498Szrj 
10101*38fd1498Szrj   if (SSA_VAR_P (arg))
10102*38fd1498Szrj     warning_at (tree_nonartificial_location (exp), OPT_Wfree_nonheap_object,
10103*38fd1498Szrj 		"%Kattempt to free a non-heap object %qD", exp, arg);
10104*38fd1498Szrj   else
10105*38fd1498Szrj     warning_at (tree_nonartificial_location (exp), OPT_Wfree_nonheap_object,
10106*38fd1498Szrj 		"%Kattempt to free a non-heap object", exp);
10107*38fd1498Szrj }
10108*38fd1498Szrj 
10109*38fd1498Szrj /* Fold a call to __builtin_object_size with arguments PTR and OST,
10110*38fd1498Szrj    if possible.  */
10111*38fd1498Szrj 
10112*38fd1498Szrj static tree
fold_builtin_object_size(tree ptr,tree ost)10113*38fd1498Szrj fold_builtin_object_size (tree ptr, tree ost)
10114*38fd1498Szrj {
10115*38fd1498Szrj   unsigned HOST_WIDE_INT bytes;
10116*38fd1498Szrj   int object_size_type;
10117*38fd1498Szrj 
10118*38fd1498Szrj   if (!validate_arg (ptr, POINTER_TYPE)
10119*38fd1498Szrj       || !validate_arg (ost, INTEGER_TYPE))
10120*38fd1498Szrj     return NULL_TREE;
10121*38fd1498Szrj 
10122*38fd1498Szrj   STRIP_NOPS (ost);
10123*38fd1498Szrj 
10124*38fd1498Szrj   if (TREE_CODE (ost) != INTEGER_CST
10125*38fd1498Szrj       || tree_int_cst_sgn (ost) < 0
10126*38fd1498Szrj       || compare_tree_int (ost, 3) > 0)
10127*38fd1498Szrj     return NULL_TREE;
10128*38fd1498Szrj 
10129*38fd1498Szrj   object_size_type = tree_to_shwi (ost);
10130*38fd1498Szrj 
10131*38fd1498Szrj   /* __builtin_object_size doesn't evaluate side-effects in its arguments;
10132*38fd1498Szrj      if there are any side-effects, it returns (size_t) -1 for types 0 and 1
10133*38fd1498Szrj      and (size_t) 0 for types 2 and 3.  */
10134*38fd1498Szrj   if (TREE_SIDE_EFFECTS (ptr))
10135*38fd1498Szrj     return build_int_cst_type (size_type_node, object_size_type < 2 ? -1 : 0);
10136*38fd1498Szrj 
10137*38fd1498Szrj   if (TREE_CODE (ptr) == ADDR_EXPR)
10138*38fd1498Szrj     {
10139*38fd1498Szrj       compute_builtin_object_size (ptr, object_size_type, &bytes);
10140*38fd1498Szrj       if (wi::fits_to_tree_p (bytes, size_type_node))
10141*38fd1498Szrj 	return build_int_cstu (size_type_node, bytes);
10142*38fd1498Szrj     }
10143*38fd1498Szrj   else if (TREE_CODE (ptr) == SSA_NAME)
10144*38fd1498Szrj     {
10145*38fd1498Szrj       /* If object size is not known yet, delay folding until
10146*38fd1498Szrj        later.  Maybe subsequent passes will help determining
10147*38fd1498Szrj        it.  */
10148*38fd1498Szrj       if (compute_builtin_object_size (ptr, object_size_type, &bytes)
10149*38fd1498Szrj 	  && wi::fits_to_tree_p (bytes, size_type_node))
10150*38fd1498Szrj 	return build_int_cstu (size_type_node, bytes);
10151*38fd1498Szrj     }
10152*38fd1498Szrj 
10153*38fd1498Szrj   return NULL_TREE;
10154*38fd1498Szrj }
10155*38fd1498Szrj 
10156*38fd1498Szrj /* Builtins with folding operations that operate on "..." arguments
10157*38fd1498Szrj    need special handling; we need to store the arguments in a convenient
10158*38fd1498Szrj    data structure before attempting any folding.  Fortunately there are
10159*38fd1498Szrj    only a few builtins that fall into this category.  FNDECL is the
10160*38fd1498Szrj    function, EXP is the CALL_EXPR for the call.  */
10161*38fd1498Szrj 
10162*38fd1498Szrj static tree
fold_builtin_varargs(location_t loc,tree fndecl,tree * args,int nargs)10163*38fd1498Szrj fold_builtin_varargs (location_t loc, tree fndecl, tree *args, int nargs)
10164*38fd1498Szrj {
10165*38fd1498Szrj   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
10166*38fd1498Szrj   tree ret = NULL_TREE;
10167*38fd1498Szrj 
10168*38fd1498Szrj   switch (fcode)
10169*38fd1498Szrj     {
10170*38fd1498Szrj     case BUILT_IN_FPCLASSIFY:
10171*38fd1498Szrj       ret = fold_builtin_fpclassify (loc, args, nargs);
10172*38fd1498Szrj       break;
10173*38fd1498Szrj 
10174*38fd1498Szrj     default:
10175*38fd1498Szrj       break;
10176*38fd1498Szrj     }
10177*38fd1498Szrj   if (ret)
10178*38fd1498Szrj     {
10179*38fd1498Szrj       ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
10180*38fd1498Szrj       SET_EXPR_LOCATION (ret, loc);
10181*38fd1498Szrj       TREE_NO_WARNING (ret) = 1;
10182*38fd1498Szrj       return ret;
10183*38fd1498Szrj     }
10184*38fd1498Szrj   return NULL_TREE;
10185*38fd1498Szrj }
10186*38fd1498Szrj 
10187*38fd1498Szrj /* Initialize format string characters in the target charset.  */
10188*38fd1498Szrj 
10189*38fd1498Szrj bool
init_target_chars(void)10190*38fd1498Szrj init_target_chars (void)
10191*38fd1498Szrj {
10192*38fd1498Szrj   static bool init;
10193*38fd1498Szrj   if (!init)
10194*38fd1498Szrj     {
10195*38fd1498Szrj       target_newline = lang_hooks.to_target_charset ('\n');
10196*38fd1498Szrj       target_percent = lang_hooks.to_target_charset ('%');
10197*38fd1498Szrj       target_c = lang_hooks.to_target_charset ('c');
10198*38fd1498Szrj       target_s = lang_hooks.to_target_charset ('s');
10199*38fd1498Szrj       if (target_newline == 0 || target_percent == 0 || target_c == 0
10200*38fd1498Szrj 	  || target_s == 0)
10201*38fd1498Szrj 	return false;
10202*38fd1498Szrj 
10203*38fd1498Szrj       target_percent_c[0] = target_percent;
10204*38fd1498Szrj       target_percent_c[1] = target_c;
10205*38fd1498Szrj       target_percent_c[2] = '\0';
10206*38fd1498Szrj 
10207*38fd1498Szrj       target_percent_s[0] = target_percent;
10208*38fd1498Szrj       target_percent_s[1] = target_s;
10209*38fd1498Szrj       target_percent_s[2] = '\0';
10210*38fd1498Szrj 
10211*38fd1498Szrj       target_percent_s_newline[0] = target_percent;
10212*38fd1498Szrj       target_percent_s_newline[1] = target_s;
10213*38fd1498Szrj       target_percent_s_newline[2] = target_newline;
10214*38fd1498Szrj       target_percent_s_newline[3] = '\0';
10215*38fd1498Szrj 
10216*38fd1498Szrj       init = true;
10217*38fd1498Szrj     }
10218*38fd1498Szrj   return true;
10219*38fd1498Szrj }
10220*38fd1498Szrj 
10221*38fd1498Szrj /* Helper function for do_mpfr_arg*().  Ensure M is a normal number
10222*38fd1498Szrj    and no overflow/underflow occurred.  INEXACT is true if M was not
10223*38fd1498Szrj    exactly calculated.  TYPE is the tree type for the result.  This
10224*38fd1498Szrj    function assumes that you cleared the MPFR flags and then
10225*38fd1498Szrj    calculated M to see if anything subsequently set a flag prior to
10226*38fd1498Szrj    entering this function.  Return NULL_TREE if any checks fail.  */
10227*38fd1498Szrj 
10228*38fd1498Szrj static tree
do_mpfr_ckconv(mpfr_srcptr m,tree type,int inexact)10229*38fd1498Szrj do_mpfr_ckconv (mpfr_srcptr m, tree type, int inexact)
10230*38fd1498Szrj {
10231*38fd1498Szrj   /* Proceed iff we get a normal number, i.e. not NaN or Inf and no
10232*38fd1498Szrj      overflow/underflow occurred.  If -frounding-math, proceed iff the
10233*38fd1498Szrj      result of calling FUNC was exact.  */
10234*38fd1498Szrj   if (mpfr_number_p (m) && !mpfr_overflow_p () && !mpfr_underflow_p ()
10235*38fd1498Szrj       && (!flag_rounding_math || !inexact))
10236*38fd1498Szrj     {
10237*38fd1498Szrj       REAL_VALUE_TYPE rr;
10238*38fd1498Szrj 
10239*38fd1498Szrj       real_from_mpfr (&rr, m, type, GMP_RNDN);
10240*38fd1498Szrj       /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR value,
10241*38fd1498Szrj 	 check for overflow/underflow.  If the REAL_VALUE_TYPE is zero
10242*38fd1498Szrj 	 but the mpft_t is not, then we underflowed in the
10243*38fd1498Szrj 	 conversion.  */
10244*38fd1498Szrj       if (real_isfinite (&rr)
10245*38fd1498Szrj 	  && (rr.cl == rvc_zero) == (mpfr_zero_p (m) != 0))
10246*38fd1498Szrj         {
10247*38fd1498Szrj 	  REAL_VALUE_TYPE rmode;
10248*38fd1498Szrj 
10249*38fd1498Szrj 	  real_convert (&rmode, TYPE_MODE (type), &rr);
10250*38fd1498Szrj 	  /* Proceed iff the specified mode can hold the value.  */
10251*38fd1498Szrj 	  if (real_identical (&rmode, &rr))
10252*38fd1498Szrj 	    return build_real (type, rmode);
10253*38fd1498Szrj 	}
10254*38fd1498Szrj     }
10255*38fd1498Szrj   return NULL_TREE;
10256*38fd1498Szrj }
10257*38fd1498Szrj 
10258*38fd1498Szrj /* Helper function for do_mpc_arg*().  Ensure M is a normal complex
10259*38fd1498Szrj    number and no overflow/underflow occurred.  INEXACT is true if M
10260*38fd1498Szrj    was not exactly calculated.  TYPE is the tree type for the result.
10261*38fd1498Szrj    This function assumes that you cleared the MPFR flags and then
10262*38fd1498Szrj    calculated M to see if anything subsequently set a flag prior to
10263*38fd1498Szrj    entering this function.  Return NULL_TREE if any checks fail, if
10264*38fd1498Szrj    FORCE_CONVERT is true, then bypass the checks.  */
10265*38fd1498Szrj 
10266*38fd1498Szrj static tree
do_mpc_ckconv(mpc_srcptr m,tree type,int inexact,int force_convert)10267*38fd1498Szrj do_mpc_ckconv (mpc_srcptr m, tree type, int inexact, int force_convert)
10268*38fd1498Szrj {
10269*38fd1498Szrj   /* Proceed iff we get a normal number, i.e. not NaN or Inf and no
10270*38fd1498Szrj      overflow/underflow occurred.  If -frounding-math, proceed iff the
10271*38fd1498Szrj      result of calling FUNC was exact.  */
10272*38fd1498Szrj   if (force_convert
10273*38fd1498Szrj       || (mpfr_number_p (mpc_realref (m)) && mpfr_number_p (mpc_imagref (m))
10274*38fd1498Szrj 	  && !mpfr_overflow_p () && !mpfr_underflow_p ()
10275*38fd1498Szrj 	  && (!flag_rounding_math || !inexact)))
10276*38fd1498Szrj     {
10277*38fd1498Szrj       REAL_VALUE_TYPE re, im;
10278*38fd1498Szrj 
10279*38fd1498Szrj       real_from_mpfr (&re, mpc_realref (m), TREE_TYPE (type), GMP_RNDN);
10280*38fd1498Szrj       real_from_mpfr (&im, mpc_imagref (m), TREE_TYPE (type), GMP_RNDN);
10281*38fd1498Szrj       /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR values,
10282*38fd1498Szrj 	 check for overflow/underflow.  If the REAL_VALUE_TYPE is zero
10283*38fd1498Szrj 	 but the mpft_t is not, then we underflowed in the
10284*38fd1498Szrj 	 conversion.  */
10285*38fd1498Szrj       if (force_convert
10286*38fd1498Szrj 	  || (real_isfinite (&re) && real_isfinite (&im)
10287*38fd1498Szrj 	      && (re.cl == rvc_zero) == (mpfr_zero_p (mpc_realref (m)) != 0)
10288*38fd1498Szrj 	      && (im.cl == rvc_zero) == (mpfr_zero_p (mpc_imagref (m)) != 0)))
10289*38fd1498Szrj         {
10290*38fd1498Szrj 	  REAL_VALUE_TYPE re_mode, im_mode;
10291*38fd1498Szrj 
10292*38fd1498Szrj 	  real_convert (&re_mode, TYPE_MODE (TREE_TYPE (type)), &re);
10293*38fd1498Szrj 	  real_convert (&im_mode, TYPE_MODE (TREE_TYPE (type)), &im);
10294*38fd1498Szrj 	  /* Proceed iff the specified mode can hold the value.  */
10295*38fd1498Szrj 	  if (force_convert
10296*38fd1498Szrj 	      || (real_identical (&re_mode, &re)
10297*38fd1498Szrj 		  && real_identical (&im_mode, &im)))
10298*38fd1498Szrj 	    return build_complex (type, build_real (TREE_TYPE (type), re_mode),
10299*38fd1498Szrj 				  build_real (TREE_TYPE (type), im_mode));
10300*38fd1498Szrj 	}
10301*38fd1498Szrj     }
10302*38fd1498Szrj   return NULL_TREE;
10303*38fd1498Szrj }
10304*38fd1498Szrj 
10305*38fd1498Szrj /* If arguments ARG0 and ARG1 are REAL_CSTs, call mpfr_remquo() to set
10306*38fd1498Szrj    the pointer *(ARG_QUO) and return the result.  The type is taken
10307*38fd1498Szrj    from the type of ARG0 and is used for setting the precision of the
10308*38fd1498Szrj    calculation and results.  */
10309*38fd1498Szrj 
10310*38fd1498Szrj static tree
do_mpfr_remquo(tree arg0,tree arg1,tree arg_quo)10311*38fd1498Szrj do_mpfr_remquo (tree arg0, tree arg1, tree arg_quo)
10312*38fd1498Szrj {
10313*38fd1498Szrj   tree const type = TREE_TYPE (arg0);
10314*38fd1498Szrj   tree result = NULL_TREE;
10315*38fd1498Szrj 
10316*38fd1498Szrj   STRIP_NOPS (arg0);
10317*38fd1498Szrj   STRIP_NOPS (arg1);
10318*38fd1498Szrj 
10319*38fd1498Szrj   /* To proceed, MPFR must exactly represent the target floating point
10320*38fd1498Szrj      format, which only happens when the target base equals two.  */
10321*38fd1498Szrj   if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
10322*38fd1498Szrj       && TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0)
10323*38fd1498Szrj       && TREE_CODE (arg1) == REAL_CST && !TREE_OVERFLOW (arg1))
10324*38fd1498Szrj     {
10325*38fd1498Szrj       const REAL_VALUE_TYPE *const ra0 = TREE_REAL_CST_PTR (arg0);
10326*38fd1498Szrj       const REAL_VALUE_TYPE *const ra1 = TREE_REAL_CST_PTR (arg1);
10327*38fd1498Szrj 
10328*38fd1498Szrj       if (real_isfinite (ra0) && real_isfinite (ra1))
10329*38fd1498Szrj         {
10330*38fd1498Szrj 	  const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
10331*38fd1498Szrj 	  const int prec = fmt->p;
10332*38fd1498Szrj 	  const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
10333*38fd1498Szrj 	  tree result_rem;
10334*38fd1498Szrj 	  long integer_quo;
10335*38fd1498Szrj 	  mpfr_t m0, m1;
10336*38fd1498Szrj 
10337*38fd1498Szrj 	  mpfr_inits2 (prec, m0, m1, NULL);
10338*38fd1498Szrj 	  mpfr_from_real (m0, ra0, GMP_RNDN);
10339*38fd1498Szrj 	  mpfr_from_real (m1, ra1, GMP_RNDN);
10340*38fd1498Szrj 	  mpfr_clear_flags ();
10341*38fd1498Szrj 	  mpfr_remquo (m0, &integer_quo, m0, m1, rnd);
10342*38fd1498Szrj 	  /* Remquo is independent of the rounding mode, so pass
10343*38fd1498Szrj 	     inexact=0 to do_mpfr_ckconv().  */
10344*38fd1498Szrj 	  result_rem = do_mpfr_ckconv (m0, type, /*inexact=*/ 0);
10345*38fd1498Szrj 	  mpfr_clears (m0, m1, NULL);
10346*38fd1498Szrj 	  if (result_rem)
10347*38fd1498Szrj 	    {
10348*38fd1498Szrj 	      /* MPFR calculates quo in the host's long so it may
10349*38fd1498Szrj 		 return more bits in quo than the target int can hold
10350*38fd1498Szrj 		 if sizeof(host long) > sizeof(target int).  This can
10351*38fd1498Szrj 		 happen even for native compilers in LP64 mode.  In
10352*38fd1498Szrj 		 these cases, modulo the quo value with the largest
10353*38fd1498Szrj 		 number that the target int can hold while leaving one
10354*38fd1498Szrj 		 bit for the sign.  */
10355*38fd1498Szrj 	      if (sizeof (integer_quo) * CHAR_BIT > INT_TYPE_SIZE)
10356*38fd1498Szrj 		integer_quo %= (long)(1UL << (INT_TYPE_SIZE - 1));
10357*38fd1498Szrj 
10358*38fd1498Szrj 	      /* Dereference the quo pointer argument.  */
10359*38fd1498Szrj 	      arg_quo = build_fold_indirect_ref (arg_quo);
10360*38fd1498Szrj 	      /* Proceed iff a valid pointer type was passed in.  */
10361*38fd1498Szrj 	      if (TYPE_MAIN_VARIANT (TREE_TYPE (arg_quo)) == integer_type_node)
10362*38fd1498Szrj 	        {
10363*38fd1498Szrj 		  /* Set the value. */
10364*38fd1498Szrj 		  tree result_quo
10365*38fd1498Szrj 		    = fold_build2 (MODIFY_EXPR, TREE_TYPE (arg_quo), arg_quo,
10366*38fd1498Szrj 				   build_int_cst (TREE_TYPE (arg_quo),
10367*38fd1498Szrj 						  integer_quo));
10368*38fd1498Szrj 		  TREE_SIDE_EFFECTS (result_quo) = 1;
10369*38fd1498Szrj 		  /* Combine the quo assignment with the rem.  */
10370*38fd1498Szrj 		  result = non_lvalue (fold_build2 (COMPOUND_EXPR, type,
10371*38fd1498Szrj 						    result_quo, result_rem));
10372*38fd1498Szrj 		}
10373*38fd1498Szrj 	    }
10374*38fd1498Szrj 	}
10375*38fd1498Szrj     }
10376*38fd1498Szrj   return result;
10377*38fd1498Szrj }
10378*38fd1498Szrj 
10379*38fd1498Szrj /* If ARG is a REAL_CST, call mpfr_lgamma() on it and return the
10380*38fd1498Szrj    resulting value as a tree with type TYPE.  The mpfr precision is
10381*38fd1498Szrj    set to the precision of TYPE.  We assume that this mpfr function
10382*38fd1498Szrj    returns zero if the result could be calculated exactly within the
10383*38fd1498Szrj    requested precision.  In addition, the integer pointer represented
10384*38fd1498Szrj    by ARG_SG will be dereferenced and set to the appropriate signgam
10385*38fd1498Szrj    (-1,1) value.  */
10386*38fd1498Szrj 
10387*38fd1498Szrj static tree
do_mpfr_lgamma_r(tree arg,tree arg_sg,tree type)10388*38fd1498Szrj do_mpfr_lgamma_r (tree arg, tree arg_sg, tree type)
10389*38fd1498Szrj {
10390*38fd1498Szrj   tree result = NULL_TREE;
10391*38fd1498Szrj 
10392*38fd1498Szrj   STRIP_NOPS (arg);
10393*38fd1498Szrj 
10394*38fd1498Szrj   /* To proceed, MPFR must exactly represent the target floating point
10395*38fd1498Szrj      format, which only happens when the target base equals two.  Also
10396*38fd1498Szrj      verify ARG is a constant and that ARG_SG is an int pointer.  */
10397*38fd1498Szrj   if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
10398*38fd1498Szrj       && TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg)
10399*38fd1498Szrj       && TREE_CODE (TREE_TYPE (arg_sg)) == POINTER_TYPE
10400*38fd1498Szrj       && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (arg_sg))) == integer_type_node)
10401*38fd1498Szrj     {
10402*38fd1498Szrj       const REAL_VALUE_TYPE *const ra = TREE_REAL_CST_PTR (arg);
10403*38fd1498Szrj 
10404*38fd1498Szrj       /* In addition to NaN and Inf, the argument cannot be zero or a
10405*38fd1498Szrj 	 negative integer.  */
10406*38fd1498Szrj       if (real_isfinite (ra)
10407*38fd1498Szrj 	  && ra->cl != rvc_zero
10408*38fd1498Szrj 	  && !(real_isneg (ra) && real_isinteger (ra, TYPE_MODE (type))))
10409*38fd1498Szrj         {
10410*38fd1498Szrj 	  const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
10411*38fd1498Szrj 	  const int prec = fmt->p;
10412*38fd1498Szrj 	  const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
10413*38fd1498Szrj 	  int inexact, sg;
10414*38fd1498Szrj 	  mpfr_t m;
10415*38fd1498Szrj 	  tree result_lg;
10416*38fd1498Szrj 
10417*38fd1498Szrj 	  mpfr_init2 (m, prec);
10418*38fd1498Szrj 	  mpfr_from_real (m, ra, GMP_RNDN);
10419*38fd1498Szrj 	  mpfr_clear_flags ();
10420*38fd1498Szrj 	  inexact = mpfr_lgamma (m, &sg, m, rnd);
10421*38fd1498Szrj 	  result_lg = do_mpfr_ckconv (m, type, inexact);
10422*38fd1498Szrj 	  mpfr_clear (m);
10423*38fd1498Szrj 	  if (result_lg)
10424*38fd1498Szrj 	    {
10425*38fd1498Szrj 	      tree result_sg;
10426*38fd1498Szrj 
10427*38fd1498Szrj 	      /* Dereference the arg_sg pointer argument.  */
10428*38fd1498Szrj 	      arg_sg = build_fold_indirect_ref (arg_sg);
10429*38fd1498Szrj 	      /* Assign the signgam value into *arg_sg. */
10430*38fd1498Szrj 	      result_sg = fold_build2 (MODIFY_EXPR,
10431*38fd1498Szrj 				       TREE_TYPE (arg_sg), arg_sg,
10432*38fd1498Szrj 				       build_int_cst (TREE_TYPE (arg_sg), sg));
10433*38fd1498Szrj 	      TREE_SIDE_EFFECTS (result_sg) = 1;
10434*38fd1498Szrj 	      /* Combine the signgam assignment with the lgamma result.  */
10435*38fd1498Szrj 	      result = non_lvalue (fold_build2 (COMPOUND_EXPR, type,
10436*38fd1498Szrj 						result_sg, result_lg));
10437*38fd1498Szrj 	    }
10438*38fd1498Szrj 	}
10439*38fd1498Szrj     }
10440*38fd1498Szrj 
10441*38fd1498Szrj   return result;
10442*38fd1498Szrj }
10443*38fd1498Szrj 
10444*38fd1498Szrj /* If arguments ARG0 and ARG1 are a COMPLEX_CST, call the two-argument
10445*38fd1498Szrj    mpc function FUNC on it and return the resulting value as a tree
10446*38fd1498Szrj    with type TYPE.  The mpfr precision is set to the precision of
10447*38fd1498Szrj    TYPE.  We assume that function FUNC returns zero if the result
10448*38fd1498Szrj    could be calculated exactly within the requested precision.  If
10449*38fd1498Szrj    DO_NONFINITE is true, then fold expressions containing Inf or NaN
10450*38fd1498Szrj    in the arguments and/or results.  */
10451*38fd1498Szrj 
10452*38fd1498Szrj tree
do_mpc_arg2(tree arg0,tree arg1,tree type,int do_nonfinite,int (* func)(mpc_ptr,mpc_srcptr,mpc_srcptr,mpc_rnd_t))10453*38fd1498Szrj do_mpc_arg2 (tree arg0, tree arg1, tree type, int do_nonfinite,
10454*38fd1498Szrj 	     int (*func)(mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t))
10455*38fd1498Szrj {
10456*38fd1498Szrj   tree result = NULL_TREE;
10457*38fd1498Szrj 
10458*38fd1498Szrj   STRIP_NOPS (arg0);
10459*38fd1498Szrj   STRIP_NOPS (arg1);
10460*38fd1498Szrj 
10461*38fd1498Szrj   /* To proceed, MPFR must exactly represent the target floating point
10462*38fd1498Szrj      format, which only happens when the target base equals two.  */
10463*38fd1498Szrj   if (TREE_CODE (arg0) == COMPLEX_CST && !TREE_OVERFLOW (arg0)
10464*38fd1498Szrj       && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE
10465*38fd1498Szrj       && TREE_CODE (arg1) == COMPLEX_CST && !TREE_OVERFLOW (arg1)
10466*38fd1498Szrj       && TREE_CODE (TREE_TYPE (TREE_TYPE (arg1))) == REAL_TYPE
10467*38fd1498Szrj       && REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0))))->b == 2)
10468*38fd1498Szrj     {
10469*38fd1498Szrj       const REAL_VALUE_TYPE *const re0 = TREE_REAL_CST_PTR (TREE_REALPART (arg0));
10470*38fd1498Szrj       const REAL_VALUE_TYPE *const im0 = TREE_REAL_CST_PTR (TREE_IMAGPART (arg0));
10471*38fd1498Szrj       const REAL_VALUE_TYPE *const re1 = TREE_REAL_CST_PTR (TREE_REALPART (arg1));
10472*38fd1498Szrj       const REAL_VALUE_TYPE *const im1 = TREE_REAL_CST_PTR (TREE_IMAGPART (arg1));
10473*38fd1498Szrj 
10474*38fd1498Szrj       if (do_nonfinite
10475*38fd1498Szrj 	  || (real_isfinite (re0) && real_isfinite (im0)
10476*38fd1498Szrj 	      && real_isfinite (re1) && real_isfinite (im1)))
10477*38fd1498Szrj         {
10478*38fd1498Szrj 	  const struct real_format *const fmt =
10479*38fd1498Szrj 	    REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (type)));
10480*38fd1498Szrj 	  const int prec = fmt->p;
10481*38fd1498Szrj 	  const mp_rnd_t rnd = fmt->round_towards_zero ? GMP_RNDZ : GMP_RNDN;
10482*38fd1498Szrj 	  const mpc_rnd_t crnd = fmt->round_towards_zero ? MPC_RNDZZ : MPC_RNDNN;
10483*38fd1498Szrj 	  int inexact;
10484*38fd1498Szrj 	  mpc_t m0, m1;
10485*38fd1498Szrj 
10486*38fd1498Szrj 	  mpc_init2 (m0, prec);
10487*38fd1498Szrj 	  mpc_init2 (m1, prec);
10488*38fd1498Szrj 	  mpfr_from_real (mpc_realref (m0), re0, rnd);
10489*38fd1498Szrj 	  mpfr_from_real (mpc_imagref (m0), im0, rnd);
10490*38fd1498Szrj 	  mpfr_from_real (mpc_realref (m1), re1, rnd);
10491*38fd1498Szrj 	  mpfr_from_real (mpc_imagref (m1), im1, rnd);
10492*38fd1498Szrj 	  mpfr_clear_flags ();
10493*38fd1498Szrj 	  inexact = func (m0, m0, m1, crnd);
10494*38fd1498Szrj 	  result = do_mpc_ckconv (m0, type, inexact, do_nonfinite);
10495*38fd1498Szrj 	  mpc_clear (m0);
10496*38fd1498Szrj 	  mpc_clear (m1);
10497*38fd1498Szrj 	}
10498*38fd1498Szrj     }
10499*38fd1498Szrj 
10500*38fd1498Szrj   return result;
10501*38fd1498Szrj }
10502*38fd1498Szrj 
10503*38fd1498Szrj /* A wrapper function for builtin folding that prevents warnings for
10504*38fd1498Szrj    "statement without effect" and the like, caused by removing the
10505*38fd1498Szrj    call node earlier than the warning is generated.  */
10506*38fd1498Szrj 
10507*38fd1498Szrj tree
fold_call_stmt(gcall * stmt,bool ignore)10508*38fd1498Szrj fold_call_stmt (gcall *stmt, bool ignore)
10509*38fd1498Szrj {
10510*38fd1498Szrj   tree ret = NULL_TREE;
10511*38fd1498Szrj   tree fndecl = gimple_call_fndecl (stmt);
10512*38fd1498Szrj   location_t loc = gimple_location (stmt);
10513*38fd1498Szrj   if (fndecl
10514*38fd1498Szrj       && TREE_CODE (fndecl) == FUNCTION_DECL
10515*38fd1498Szrj       && DECL_BUILT_IN (fndecl)
10516*38fd1498Szrj       && !gimple_call_va_arg_pack_p (stmt))
10517*38fd1498Szrj     {
10518*38fd1498Szrj       int nargs = gimple_call_num_args (stmt);
10519*38fd1498Szrj       tree *args = (nargs > 0
10520*38fd1498Szrj 		    ? gimple_call_arg_ptr (stmt, 0)
10521*38fd1498Szrj 		    : &error_mark_node);
10522*38fd1498Szrj 
10523*38fd1498Szrj       if (avoid_folding_inline_builtin (fndecl))
10524*38fd1498Szrj 	return NULL_TREE;
10525*38fd1498Szrj       if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
10526*38fd1498Szrj         {
10527*38fd1498Szrj 	  return targetm.fold_builtin (fndecl, nargs, args, ignore);
10528*38fd1498Szrj         }
10529*38fd1498Szrj       else
10530*38fd1498Szrj 	{
10531*38fd1498Szrj 	  ret = fold_builtin_n (loc, fndecl, args, nargs, ignore);
10532*38fd1498Szrj 	  if (ret)
10533*38fd1498Szrj 	    {
10534*38fd1498Szrj 	      /* Propagate location information from original call to
10535*38fd1498Szrj 		 expansion of builtin.  Otherwise things like
10536*38fd1498Szrj 		 maybe_emit_chk_warning, that operate on the expansion
10537*38fd1498Szrj 		 of a builtin, will use the wrong location information.  */
10538*38fd1498Szrj 	      if (gimple_has_location (stmt))
10539*38fd1498Szrj                 {
10540*38fd1498Szrj 		  tree realret = ret;
10541*38fd1498Szrj 		  if (TREE_CODE (ret) == NOP_EXPR)
10542*38fd1498Szrj 		    realret = TREE_OPERAND (ret, 0);
10543*38fd1498Szrj 		  if (CAN_HAVE_LOCATION_P (realret)
10544*38fd1498Szrj 		      && !EXPR_HAS_LOCATION (realret))
10545*38fd1498Szrj 		    SET_EXPR_LOCATION (realret, loc);
10546*38fd1498Szrj                   return realret;
10547*38fd1498Szrj                 }
10548*38fd1498Szrj 	      return ret;
10549*38fd1498Szrj 	    }
10550*38fd1498Szrj 	}
10551*38fd1498Szrj     }
10552*38fd1498Szrj   return NULL_TREE;
10553*38fd1498Szrj }
10554*38fd1498Szrj 
10555*38fd1498Szrj /* Look up the function in builtin_decl that corresponds to DECL
10556*38fd1498Szrj    and set ASMSPEC as its user assembler name.  DECL must be a
10557*38fd1498Szrj    function decl that declares a builtin.  */
10558*38fd1498Szrj 
10559*38fd1498Szrj void
set_builtin_user_assembler_name(tree decl,const char * asmspec)10560*38fd1498Szrj set_builtin_user_assembler_name (tree decl, const char *asmspec)
10561*38fd1498Szrj {
10562*38fd1498Szrj   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
10563*38fd1498Szrj 	      && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
10564*38fd1498Szrj 	      && asmspec != 0);
10565*38fd1498Szrj 
10566*38fd1498Szrj   tree builtin = builtin_decl_explicit (DECL_FUNCTION_CODE (decl));
10567*38fd1498Szrj   set_user_assembler_name (builtin, asmspec);
10568*38fd1498Szrj 
10569*38fd1498Szrj   if (DECL_FUNCTION_CODE (decl) == BUILT_IN_FFS
10570*38fd1498Szrj       && INT_TYPE_SIZE < BITS_PER_WORD)
10571*38fd1498Szrj     {
10572*38fd1498Szrj       scalar_int_mode mode = int_mode_for_size (INT_TYPE_SIZE, 0).require ();
10573*38fd1498Szrj       set_user_assembler_libfunc ("ffs", asmspec);
10574*38fd1498Szrj       set_optab_libfunc (ffs_optab, mode, "ffs");
10575*38fd1498Szrj     }
10576*38fd1498Szrj }
10577*38fd1498Szrj 
10578*38fd1498Szrj /* Return true if DECL is a builtin that expands to a constant or similarly
10579*38fd1498Szrj    simple code.  */
10580*38fd1498Szrj bool
is_simple_builtin(tree decl)10581*38fd1498Szrj is_simple_builtin (tree decl)
10582*38fd1498Szrj {
10583*38fd1498Szrj   if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
10584*38fd1498Szrj     switch (DECL_FUNCTION_CODE (decl))
10585*38fd1498Szrj       {
10586*38fd1498Szrj 	/* Builtins that expand to constants.  */
10587*38fd1498Szrj       case BUILT_IN_CONSTANT_P:
10588*38fd1498Szrj       case BUILT_IN_EXPECT:
10589*38fd1498Szrj       case BUILT_IN_OBJECT_SIZE:
10590*38fd1498Szrj       case BUILT_IN_UNREACHABLE:
10591*38fd1498Szrj 	/* Simple register moves or loads from stack.  */
10592*38fd1498Szrj       case BUILT_IN_ASSUME_ALIGNED:
10593*38fd1498Szrj       case BUILT_IN_RETURN_ADDRESS:
10594*38fd1498Szrj       case BUILT_IN_EXTRACT_RETURN_ADDR:
10595*38fd1498Szrj       case BUILT_IN_FROB_RETURN_ADDR:
10596*38fd1498Szrj       case BUILT_IN_RETURN:
10597*38fd1498Szrj       case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
10598*38fd1498Szrj       case BUILT_IN_FRAME_ADDRESS:
10599*38fd1498Szrj       case BUILT_IN_VA_END:
10600*38fd1498Szrj       case BUILT_IN_STACK_SAVE:
10601*38fd1498Szrj       case BUILT_IN_STACK_RESTORE:
10602*38fd1498Szrj 	/* Exception state returns or moves registers around.  */
10603*38fd1498Szrj       case BUILT_IN_EH_FILTER:
10604*38fd1498Szrj       case BUILT_IN_EH_POINTER:
10605*38fd1498Szrj       case BUILT_IN_EH_COPY_VALUES:
10606*38fd1498Szrj 	return true;
10607*38fd1498Szrj 
10608*38fd1498Szrj       default:
10609*38fd1498Szrj 	return false;
10610*38fd1498Szrj       }
10611*38fd1498Szrj 
10612*38fd1498Szrj   return false;
10613*38fd1498Szrj }
10614*38fd1498Szrj 
10615*38fd1498Szrj /* Return true if DECL is a builtin that is not expensive, i.e., they are
10616*38fd1498Szrj    most probably expanded inline into reasonably simple code.  This is a
10617*38fd1498Szrj    superset of is_simple_builtin.  */
10618*38fd1498Szrj bool
is_inexpensive_builtin(tree decl)10619*38fd1498Szrj is_inexpensive_builtin (tree decl)
10620*38fd1498Szrj {
10621*38fd1498Szrj   if (!decl)
10622*38fd1498Szrj     return false;
10623*38fd1498Szrj   else if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_MD)
10624*38fd1498Szrj     return true;
10625*38fd1498Szrj   else if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
10626*38fd1498Szrj     switch (DECL_FUNCTION_CODE (decl))
10627*38fd1498Szrj       {
10628*38fd1498Szrj       case BUILT_IN_ABS:
10629*38fd1498Szrj       CASE_BUILT_IN_ALLOCA:
10630*38fd1498Szrj       case BUILT_IN_BSWAP16:
10631*38fd1498Szrj       case BUILT_IN_BSWAP32:
10632*38fd1498Szrj       case BUILT_IN_BSWAP64:
10633*38fd1498Szrj       case BUILT_IN_CLZ:
10634*38fd1498Szrj       case BUILT_IN_CLZIMAX:
10635*38fd1498Szrj       case BUILT_IN_CLZL:
10636*38fd1498Szrj       case BUILT_IN_CLZLL:
10637*38fd1498Szrj       case BUILT_IN_CTZ:
10638*38fd1498Szrj       case BUILT_IN_CTZIMAX:
10639*38fd1498Szrj       case BUILT_IN_CTZL:
10640*38fd1498Szrj       case BUILT_IN_CTZLL:
10641*38fd1498Szrj       case BUILT_IN_FFS:
10642*38fd1498Szrj       case BUILT_IN_FFSIMAX:
10643*38fd1498Szrj       case BUILT_IN_FFSL:
10644*38fd1498Szrj       case BUILT_IN_FFSLL:
10645*38fd1498Szrj       case BUILT_IN_IMAXABS:
10646*38fd1498Szrj       case BUILT_IN_FINITE:
10647*38fd1498Szrj       case BUILT_IN_FINITEF:
10648*38fd1498Szrj       case BUILT_IN_FINITEL:
10649*38fd1498Szrj       case BUILT_IN_FINITED32:
10650*38fd1498Szrj       case BUILT_IN_FINITED64:
10651*38fd1498Szrj       case BUILT_IN_FINITED128:
10652*38fd1498Szrj       case BUILT_IN_FPCLASSIFY:
10653*38fd1498Szrj       case BUILT_IN_ISFINITE:
10654*38fd1498Szrj       case BUILT_IN_ISINF_SIGN:
10655*38fd1498Szrj       case BUILT_IN_ISINF:
10656*38fd1498Szrj       case BUILT_IN_ISINFF:
10657*38fd1498Szrj       case BUILT_IN_ISINFL:
10658*38fd1498Szrj       case BUILT_IN_ISINFD32:
10659*38fd1498Szrj       case BUILT_IN_ISINFD64:
10660*38fd1498Szrj       case BUILT_IN_ISINFD128:
10661*38fd1498Szrj       case BUILT_IN_ISNAN:
10662*38fd1498Szrj       case BUILT_IN_ISNANF:
10663*38fd1498Szrj       case BUILT_IN_ISNANL:
10664*38fd1498Szrj       case BUILT_IN_ISNAND32:
10665*38fd1498Szrj       case BUILT_IN_ISNAND64:
10666*38fd1498Szrj       case BUILT_IN_ISNAND128:
10667*38fd1498Szrj       case BUILT_IN_ISNORMAL:
10668*38fd1498Szrj       case BUILT_IN_ISGREATER:
10669*38fd1498Szrj       case BUILT_IN_ISGREATEREQUAL:
10670*38fd1498Szrj       case BUILT_IN_ISLESS:
10671*38fd1498Szrj       case BUILT_IN_ISLESSEQUAL:
10672*38fd1498Szrj       case BUILT_IN_ISLESSGREATER:
10673*38fd1498Szrj       case BUILT_IN_ISUNORDERED:
10674*38fd1498Szrj       case BUILT_IN_VA_ARG_PACK:
10675*38fd1498Szrj       case BUILT_IN_VA_ARG_PACK_LEN:
10676*38fd1498Szrj       case BUILT_IN_VA_COPY:
10677*38fd1498Szrj       case BUILT_IN_TRAP:
10678*38fd1498Szrj       case BUILT_IN_SAVEREGS:
10679*38fd1498Szrj       case BUILT_IN_POPCOUNTL:
10680*38fd1498Szrj       case BUILT_IN_POPCOUNTLL:
10681*38fd1498Szrj       case BUILT_IN_POPCOUNTIMAX:
10682*38fd1498Szrj       case BUILT_IN_POPCOUNT:
10683*38fd1498Szrj       case BUILT_IN_PARITYL:
10684*38fd1498Szrj       case BUILT_IN_PARITYLL:
10685*38fd1498Szrj       case BUILT_IN_PARITYIMAX:
10686*38fd1498Szrj       case BUILT_IN_PARITY:
10687*38fd1498Szrj       case BUILT_IN_LABS:
10688*38fd1498Szrj       case BUILT_IN_LLABS:
10689*38fd1498Szrj       case BUILT_IN_PREFETCH:
10690*38fd1498Szrj       case BUILT_IN_ACC_ON_DEVICE:
10691*38fd1498Szrj 	return true;
10692*38fd1498Szrj 
10693*38fd1498Szrj       default:
10694*38fd1498Szrj 	return is_simple_builtin (decl);
10695*38fd1498Szrj       }
10696*38fd1498Szrj 
10697*38fd1498Szrj   return false;
10698*38fd1498Szrj }
10699*38fd1498Szrj 
10700*38fd1498Szrj /* Return true if T is a constant and the value cast to a target char
10701*38fd1498Szrj    can be represented by a host char.
10702*38fd1498Szrj    Store the casted char constant in *P if so.  */
10703*38fd1498Szrj 
10704*38fd1498Szrj bool
target_char_cst_p(tree t,char * p)10705*38fd1498Szrj target_char_cst_p (tree t, char *p)
10706*38fd1498Szrj {
10707*38fd1498Szrj   if (!tree_fits_uhwi_p (t) || CHAR_TYPE_SIZE != HOST_BITS_PER_CHAR)
10708*38fd1498Szrj     return false;
10709*38fd1498Szrj 
10710*38fd1498Szrj   *p = (char)tree_to_uhwi (t);
10711*38fd1498Szrj   return true;
10712*38fd1498Szrj }
10713*38fd1498Szrj 
10714*38fd1498Szrj /* Return the maximum object size.  */
10715*38fd1498Szrj 
10716*38fd1498Szrj tree
max_object_size(void)10717*38fd1498Szrj max_object_size (void)
10718*38fd1498Szrj {
10719*38fd1498Szrj   /* To do: Make this a configurable parameter.  */
10720*38fd1498Szrj   return TYPE_MAX_VALUE (ptrdiff_type_node);
10721*38fd1498Szrj }
10722