xref: /openbsd/gnu/usr.bin/gcc/gcc/builtins.c (revision 06dc6460)
1c87b03e5Sespie /* Expand builtin functions.
2c87b03e5Sespie    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3c87b03e5Sespie    1999, 2000, 2001, 2002 Free Software Foundation, Inc.
4c87b03e5Sespie 
5c87b03e5Sespie This file is part of GCC.
6c87b03e5Sespie 
7c87b03e5Sespie GCC is free software; you can redistribute it and/or modify it under
8c87b03e5Sespie the terms of the GNU General Public License as published by the Free
9c87b03e5Sespie Software Foundation; either version 2, or (at your option) any later
10c87b03e5Sespie version.
11c87b03e5Sespie 
12c87b03e5Sespie GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13c87b03e5Sespie WARRANTY; without even the implied warranty of MERCHANTABILITY or
14c87b03e5Sespie FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15c87b03e5Sespie for more details.
16c87b03e5Sespie 
17c87b03e5Sespie You should have received a copy of the GNU General Public License
18c87b03e5Sespie along with GCC; see the file COPYING.  If not, write to the Free
19c87b03e5Sespie Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20c87b03e5Sespie 02111-1307, USA.  */
21c87b03e5Sespie 
22c87b03e5Sespie #include "config.h"
23c87b03e5Sespie #include "system.h"
24c87b03e5Sespie #include "machmode.h"
25c87b03e5Sespie #include "real.h"
26c87b03e5Sespie #include "rtl.h"
27c87b03e5Sespie #include "tree.h"
28c87b03e5Sespie #include "flags.h"
29c87b03e5Sespie #include "regs.h"
30c87b03e5Sespie #include "hard-reg-set.h"
31c87b03e5Sespie #include "except.h"
32c87b03e5Sespie #include "function.h"
33c87b03e5Sespie #include "insn-config.h"
34c87b03e5Sespie #include "expr.h"
35c87b03e5Sespie #include "optabs.h"
36c87b03e5Sespie #include "libfuncs.h"
37c87b03e5Sespie #include "recog.h"
38c87b03e5Sespie #include "output.h"
39c87b03e5Sespie #include "typeclass.h"
40c87b03e5Sespie #include "toplev.h"
41c87b03e5Sespie #include "predict.h"
42c87b03e5Sespie #include "tm_p.h"
43c87b03e5Sespie #include "target.h"
44c87b03e5Sespie #include "langhooks.h"
45c87b03e5Sespie 
46c87b03e5Sespie #define CALLED_AS_BUILT_IN(NODE) \
47c87b03e5Sespie    (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
48c87b03e5Sespie 
49c87b03e5Sespie /* Register mappings for target machines without register windows.  */
50c87b03e5Sespie #ifndef INCOMING_REGNO
51c87b03e5Sespie #define INCOMING_REGNO(OUT) (OUT)
52c87b03e5Sespie #endif
53c87b03e5Sespie #ifndef OUTGOING_REGNO
54c87b03e5Sespie #define OUTGOING_REGNO(IN) (IN)
55c87b03e5Sespie #endif
56c87b03e5Sespie 
57c87b03e5Sespie #ifndef PAD_VARARGS_DOWN
58c87b03e5Sespie #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
59c87b03e5Sespie #endif
60c87b03e5Sespie 
61c87b03e5Sespie /* Define the names of the builtin function types and codes.  */
62c87b03e5Sespie const char *const built_in_class_names[4]
63c87b03e5Sespie   = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
64c87b03e5Sespie 
65c87b03e5Sespie #define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT) STRINGX(X),
66c87b03e5Sespie const char *const built_in_names[(int) END_BUILTINS] =
67c87b03e5Sespie {
68c87b03e5Sespie #include "builtins.def"
69c87b03e5Sespie };
70c87b03e5Sespie #undef DEF_BUILTIN
71c87b03e5Sespie 
72c87b03e5Sespie /* Setup an array of _DECL trees, make sure each element is
73c87b03e5Sespie    initialized to NULL_TREE.  */
74c87b03e5Sespie tree built_in_decls[(int) END_BUILTINS];
75c87b03e5Sespie 
76c87b03e5Sespie static int get_pointer_alignment	PARAMS ((tree, unsigned int));
77c87b03e5Sespie static tree c_strlen			PARAMS ((tree));
78c87b03e5Sespie static const char *c_getstr		PARAMS ((tree));
79c87b03e5Sespie static rtx c_readstr			PARAMS ((const char *,
80c87b03e5Sespie 						 enum machine_mode));
81c87b03e5Sespie static int target_char_cast		PARAMS ((tree, char *));
82c87b03e5Sespie static rtx get_memory_rtx		PARAMS ((tree));
83c87b03e5Sespie static int apply_args_size		PARAMS ((void));
84c87b03e5Sespie static int apply_result_size		PARAMS ((void));
85c87b03e5Sespie #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
86c87b03e5Sespie static rtx result_vector		PARAMS ((int, rtx));
87c87b03e5Sespie #endif
88c87b03e5Sespie static rtx expand_builtin_setjmp	PARAMS ((tree, rtx));
89c87b03e5Sespie static void expand_builtin_prefetch	PARAMS ((tree));
90c87b03e5Sespie static rtx expand_builtin_apply_args	PARAMS ((void));
91c87b03e5Sespie static rtx expand_builtin_apply_args_1	PARAMS ((void));
92c87b03e5Sespie static rtx expand_builtin_apply		PARAMS ((rtx, rtx, rtx));
93c87b03e5Sespie static void expand_builtin_return	PARAMS ((rtx));
94c87b03e5Sespie static enum type_class type_to_class	PARAMS ((tree));
95c87b03e5Sespie static rtx expand_builtin_classify_type	PARAMS ((tree));
96c87b03e5Sespie static rtx expand_builtin_mathfn	PARAMS ((tree, rtx, rtx));
97c87b03e5Sespie static rtx expand_builtin_constant_p	PARAMS ((tree));
98c87b03e5Sespie static rtx expand_builtin_args_info	PARAMS ((tree));
99c87b03e5Sespie static rtx expand_builtin_next_arg	PARAMS ((tree));
100c87b03e5Sespie static rtx expand_builtin_va_start	PARAMS ((tree));
101c87b03e5Sespie static rtx expand_builtin_va_end	PARAMS ((tree));
102c87b03e5Sespie static rtx expand_builtin_va_copy	PARAMS ((tree));
103c87b03e5Sespie static rtx expand_builtin_memcmp	PARAMS ((tree, tree, rtx,
104c87b03e5Sespie 						 enum machine_mode));
105c87b03e5Sespie static rtx expand_builtin_strcmp	PARAMS ((tree, rtx,
106c87b03e5Sespie 						 enum machine_mode));
107c87b03e5Sespie static rtx expand_builtin_strncmp	PARAMS ((tree, rtx,
108c87b03e5Sespie 						 enum machine_mode));
109c87b03e5Sespie static rtx builtin_memcpy_read_str	PARAMS ((PTR, HOST_WIDE_INT,
110c87b03e5Sespie 						 enum machine_mode));
111c87b03e5Sespie static rtx expand_builtin_strcat	PARAMS ((tree, rtx,
112c87b03e5Sespie 						 enum machine_mode));
113c87b03e5Sespie static rtx expand_builtin_strncat	PARAMS ((tree, rtx,
114c87b03e5Sespie 						 enum machine_mode));
115c87b03e5Sespie static rtx expand_builtin_strspn	PARAMS ((tree, rtx,
116c87b03e5Sespie 						 enum machine_mode));
117c87b03e5Sespie static rtx expand_builtin_strcspn	PARAMS ((tree, rtx,
118c87b03e5Sespie 						 enum machine_mode));
119c87b03e5Sespie static rtx expand_builtin_memcpy	PARAMS ((tree, rtx,
120c87b03e5Sespie 						 enum machine_mode));
121c87b03e5Sespie static rtx expand_builtin_strcpy	PARAMS ((tree, rtx,
122c87b03e5Sespie 						 enum machine_mode));
123c87b03e5Sespie static rtx builtin_strncpy_read_str	PARAMS ((PTR, HOST_WIDE_INT,
124c87b03e5Sespie 						 enum machine_mode));
125c87b03e5Sespie static rtx expand_builtin_strncpy	PARAMS ((tree, rtx,
126c87b03e5Sespie 						 enum machine_mode));
127c87b03e5Sespie static rtx builtin_memset_read_str	PARAMS ((PTR, HOST_WIDE_INT,
128c87b03e5Sespie 						 enum machine_mode));
129c87b03e5Sespie static rtx builtin_memset_gen_str	PARAMS ((PTR, HOST_WIDE_INT,
130c87b03e5Sespie 						 enum machine_mode));
131c87b03e5Sespie static rtx expand_builtin_memset	PARAMS ((tree, rtx,
132c87b03e5Sespie 						 enum machine_mode));
133c87b03e5Sespie static rtx expand_builtin_bzero		PARAMS ((tree));
134c87b03e5Sespie static rtx expand_builtin_strlen	PARAMS ((tree, rtx));
135c87b03e5Sespie static rtx expand_builtin_strstr	PARAMS ((tree, rtx,
136c87b03e5Sespie 						 enum machine_mode));
137c87b03e5Sespie static rtx expand_builtin_strpbrk	PARAMS ((tree, rtx,
138c87b03e5Sespie 						 enum machine_mode));
139c87b03e5Sespie static rtx expand_builtin_strchr	PARAMS ((tree, rtx,
140c87b03e5Sespie 						 enum machine_mode));
141c87b03e5Sespie static rtx expand_builtin_strrchr	PARAMS ((tree, rtx,
142c87b03e5Sespie 						 enum machine_mode));
143c87b03e5Sespie static rtx expand_builtin_alloca	PARAMS ((tree, rtx));
144c87b03e5Sespie static rtx expand_builtin_ffs		PARAMS ((tree, rtx, rtx));
145c87b03e5Sespie static rtx expand_builtin_frame_address	PARAMS ((tree));
146c87b03e5Sespie static rtx expand_builtin_fputs		PARAMS ((tree, int, int));
147c87b03e5Sespie static tree stabilize_va_list		PARAMS ((tree, int));
148c87b03e5Sespie static rtx expand_builtin_expect	PARAMS ((tree, rtx));
149c87b03e5Sespie static tree fold_builtin_constant_p	PARAMS ((tree));
150c87b03e5Sespie static tree fold_builtin_classify_type	PARAMS ((tree));
151c87b03e5Sespie static tree fold_builtin_inf		PARAMS ((tree, int));
152c87b03e5Sespie static tree fold_builtin_nan		PARAMS ((tree, tree, int));
153c87b03e5Sespie static tree build_function_call_expr	PARAMS ((tree, tree));
154c87b03e5Sespie static int validate_arglist		PARAMS ((tree, ...));
155c87b03e5Sespie 
156c87b03e5Sespie /* Return the alignment in bits of EXP, a pointer valued expression.
157c87b03e5Sespie    But don't return more than MAX_ALIGN no matter what.
158c87b03e5Sespie    The alignment returned is, by default, the alignment of the thing that
159c87b03e5Sespie    EXP points to.  If it is not a POINTER_TYPE, 0 is returned.
160c87b03e5Sespie 
161c87b03e5Sespie    Otherwise, look at the expression to see if we can do better, i.e., if the
162c87b03e5Sespie    expression is actually pointing at an object whose alignment is tighter.  */
163c87b03e5Sespie 
164c87b03e5Sespie static int
get_pointer_alignment(exp,max_align)165c87b03e5Sespie get_pointer_alignment (exp, max_align)
166c87b03e5Sespie      tree exp;
167c87b03e5Sespie      unsigned int max_align;
168c87b03e5Sespie {
169c87b03e5Sespie   unsigned int align, inner;
170c87b03e5Sespie 
171c87b03e5Sespie   if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE)
172c87b03e5Sespie     return 0;
173c87b03e5Sespie 
174c87b03e5Sespie   align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
175c87b03e5Sespie   align = MIN (align, max_align);
176c87b03e5Sespie 
177c87b03e5Sespie   while (1)
178c87b03e5Sespie     {
179c87b03e5Sespie       switch (TREE_CODE (exp))
180c87b03e5Sespie 	{
181c87b03e5Sespie 	case NOP_EXPR:
182c87b03e5Sespie 	case CONVERT_EXPR:
183c87b03e5Sespie 	case NON_LVALUE_EXPR:
184c87b03e5Sespie 	  exp = TREE_OPERAND (exp, 0);
185c87b03e5Sespie 	  if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE)
186c87b03e5Sespie 	    return align;
187c87b03e5Sespie 
188c87b03e5Sespie 	  inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
189c87b03e5Sespie 	  align = MIN (inner, max_align);
190c87b03e5Sespie 	  break;
191c87b03e5Sespie 
192c87b03e5Sespie 	case PLUS_EXPR:
193c87b03e5Sespie 	  /* If sum of pointer + int, restrict our maximum alignment to that
194c87b03e5Sespie 	     imposed by the integer.  If not, we can't do any better than
195c87b03e5Sespie 	     ALIGN.  */
196c87b03e5Sespie 	  if (! host_integerp (TREE_OPERAND (exp, 1), 1))
197c87b03e5Sespie 	    return align;
198c87b03e5Sespie 
199c87b03e5Sespie 	  while (((tree_low_cst (TREE_OPERAND (exp, 1), 1))
200c87b03e5Sespie 		  & (max_align / BITS_PER_UNIT - 1))
201c87b03e5Sespie 		 != 0)
202c87b03e5Sespie 	    max_align >>= 1;
203c87b03e5Sespie 
204c87b03e5Sespie 	  exp = TREE_OPERAND (exp, 0);
205c87b03e5Sespie 	  break;
206c87b03e5Sespie 
207c87b03e5Sespie 	case ADDR_EXPR:
208c87b03e5Sespie 	  /* See what we are pointing at and look at its alignment.  */
209c87b03e5Sespie 	  exp = TREE_OPERAND (exp, 0);
210c87b03e5Sespie 	  if (TREE_CODE (exp) == FUNCTION_DECL)
211c87b03e5Sespie 	    align = FUNCTION_BOUNDARY;
212c87b03e5Sespie 	  else if (DECL_P (exp))
213c87b03e5Sespie 	    align = DECL_ALIGN (exp);
214c87b03e5Sespie #ifdef CONSTANT_ALIGNMENT
215c87b03e5Sespie 	  else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c')
216c87b03e5Sespie 	    align = CONSTANT_ALIGNMENT (exp, align);
217c87b03e5Sespie #endif
218c87b03e5Sespie 	  return MIN (align, max_align);
219c87b03e5Sespie 
220c87b03e5Sespie 	default:
221c87b03e5Sespie 	  return align;
222c87b03e5Sespie 	}
223c87b03e5Sespie     }
224c87b03e5Sespie }
225c87b03e5Sespie 
226c87b03e5Sespie /* Compute the length of a C string.  TREE_STRING_LENGTH is not the right
227c87b03e5Sespie    way, because it could contain a zero byte in the middle.
228c87b03e5Sespie    TREE_STRING_LENGTH is the size of the character array, not the string.
229c87b03e5Sespie 
230c87b03e5Sespie    The value returned is of type `ssizetype'.
231c87b03e5Sespie 
232c87b03e5Sespie    Unfortunately, string_constant can't access the values of const char
233c87b03e5Sespie    arrays with initializers, so neither can we do so here.  */
234c87b03e5Sespie 
235c87b03e5Sespie static tree
c_strlen(src)236c87b03e5Sespie c_strlen (src)
237c87b03e5Sespie      tree src;
238c87b03e5Sespie {
239c87b03e5Sespie   tree offset_node;
240c87b03e5Sespie   HOST_WIDE_INT offset;
241c87b03e5Sespie   int max;
242c87b03e5Sespie   const char *ptr;
243c87b03e5Sespie 
244c87b03e5Sespie   src = string_constant (src, &offset_node);
245c87b03e5Sespie   if (src == 0)
246c87b03e5Sespie     return 0;
247c87b03e5Sespie 
248c87b03e5Sespie   max = TREE_STRING_LENGTH (src) - 1;
249c87b03e5Sespie   ptr = TREE_STRING_POINTER (src);
250c87b03e5Sespie 
251c87b03e5Sespie   if (offset_node && TREE_CODE (offset_node) != INTEGER_CST)
252c87b03e5Sespie     {
253c87b03e5Sespie       /* If the string has an internal zero byte (e.g., "foo\0bar"), we can't
254c87b03e5Sespie 	 compute the offset to the following null if we don't know where to
255c87b03e5Sespie 	 start searching for it.  */
256c87b03e5Sespie       int i;
257c87b03e5Sespie 
258c87b03e5Sespie       for (i = 0; i < max; i++)
259c87b03e5Sespie 	if (ptr[i] == 0)
260c87b03e5Sespie 	  return 0;
261c87b03e5Sespie 
262c87b03e5Sespie       /* We don't know the starting offset, but we do know that the string
263c87b03e5Sespie 	 has no internal zero bytes.  We can assume that the offset falls
264c87b03e5Sespie 	 within the bounds of the string; otherwise, the programmer deserves
265c87b03e5Sespie 	 what he gets.  Subtract the offset from the length of the string,
266c87b03e5Sespie 	 and return that.  This would perhaps not be valid if we were dealing
267c87b03e5Sespie 	 with named arrays in addition to literal string constants.  */
268c87b03e5Sespie 
269c87b03e5Sespie       return size_diffop (size_int (max), offset_node);
270c87b03e5Sespie     }
271c87b03e5Sespie 
272c87b03e5Sespie   /* We have a known offset into the string.  Start searching there for
273c87b03e5Sespie      a null character if we can represent it as a single HOST_WIDE_INT.  */
274c87b03e5Sespie   if (offset_node == 0)
275c87b03e5Sespie     offset = 0;
276c87b03e5Sespie   else if (! host_integerp (offset_node, 0))
277c87b03e5Sespie     offset = -1;
278c87b03e5Sespie   else
279c87b03e5Sespie     offset = tree_low_cst (offset_node, 0);
280c87b03e5Sespie 
281c87b03e5Sespie   /* If the offset is known to be out of bounds, warn, and call strlen at
282c87b03e5Sespie      runtime.  */
283c87b03e5Sespie   if (offset < 0 || offset > max)
284c87b03e5Sespie     {
285c87b03e5Sespie       warning ("offset outside bounds of constant string");
286c87b03e5Sespie       return 0;
287c87b03e5Sespie     }
288c87b03e5Sespie 
289c87b03e5Sespie   /* Use strlen to search for the first zero byte.  Since any strings
290c87b03e5Sespie      constructed with build_string will have nulls appended, we win even
291c87b03e5Sespie      if we get handed something like (char[4])"abcd".
292c87b03e5Sespie 
293c87b03e5Sespie      Since OFFSET is our starting index into the string, no further
294c87b03e5Sespie      calculation is needed.  */
295c87b03e5Sespie   return ssize_int (strlen (ptr + offset));
296c87b03e5Sespie }
297c87b03e5Sespie 
298c87b03e5Sespie /* Return a char pointer for a C string if it is a string constant
299c87b03e5Sespie    or sum of string constant and integer constant.  */
300c87b03e5Sespie 
301c87b03e5Sespie static const char *
c_getstr(src)302c87b03e5Sespie c_getstr (src)
303c87b03e5Sespie      tree src;
304c87b03e5Sespie {
305c87b03e5Sespie   tree offset_node;
306c87b03e5Sespie 
307c87b03e5Sespie   src = string_constant (src, &offset_node);
308c87b03e5Sespie   if (src == 0)
309c87b03e5Sespie     return 0;
310c87b03e5Sespie 
311c87b03e5Sespie   if (offset_node == 0)
312c87b03e5Sespie     return TREE_STRING_POINTER (src);
313c87b03e5Sespie   else if (!host_integerp (offset_node, 1)
314c87b03e5Sespie 	   || compare_tree_int (offset_node, TREE_STRING_LENGTH (src) - 1) > 0)
315c87b03e5Sespie     return 0;
316c87b03e5Sespie 
317c87b03e5Sespie   return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
318c87b03e5Sespie }
319c87b03e5Sespie 
320c87b03e5Sespie /* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
321c87b03e5Sespie    GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
322c87b03e5Sespie 
323c87b03e5Sespie static rtx
c_readstr(str,mode)324c87b03e5Sespie c_readstr (str, mode)
325c87b03e5Sespie      const char *str;
326c87b03e5Sespie      enum machine_mode mode;
327c87b03e5Sespie {
328c87b03e5Sespie   HOST_WIDE_INT c[2];
329c87b03e5Sespie   HOST_WIDE_INT ch;
330c87b03e5Sespie   unsigned int i, j;
331c87b03e5Sespie 
332c87b03e5Sespie   if (GET_MODE_CLASS (mode) != MODE_INT)
333c87b03e5Sespie     abort ();
334c87b03e5Sespie   c[0] = 0;
335c87b03e5Sespie   c[1] = 0;
336c87b03e5Sespie   ch = 1;
337c87b03e5Sespie   for (i = 0; i < GET_MODE_SIZE (mode); i++)
338c87b03e5Sespie     {
339c87b03e5Sespie       j = i;
340c87b03e5Sespie       if (WORDS_BIG_ENDIAN)
341c87b03e5Sespie 	j = GET_MODE_SIZE (mode) - i - 1;
342c87b03e5Sespie       if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
343c87b03e5Sespie 	  && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
344c87b03e5Sespie 	j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
345c87b03e5Sespie       j *= BITS_PER_UNIT;
346c87b03e5Sespie       if (j > 2 * HOST_BITS_PER_WIDE_INT)
347c87b03e5Sespie 	abort ();
348c87b03e5Sespie       if (ch)
349c87b03e5Sespie 	ch = (unsigned char) str[i];
350c87b03e5Sespie       c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
351c87b03e5Sespie     }
352c87b03e5Sespie   return immed_double_const (c[0], c[1], mode);
353c87b03e5Sespie }
354c87b03e5Sespie 
355c87b03e5Sespie /* Cast a target constant CST to target CHAR and if that value fits into
356c87b03e5Sespie    host char type, return zero and put that value into variable pointed by
357c87b03e5Sespie    P.  */
358c87b03e5Sespie 
359c87b03e5Sespie static int
target_char_cast(cst,p)360c87b03e5Sespie target_char_cast (cst, p)
361c87b03e5Sespie      tree cst;
362c87b03e5Sespie      char *p;
363c87b03e5Sespie {
364c87b03e5Sespie   unsigned HOST_WIDE_INT val, hostval;
365c87b03e5Sespie 
366c87b03e5Sespie   if (!host_integerp (cst, 1)
367c87b03e5Sespie       || CHAR_TYPE_SIZE > HOST_BITS_PER_WIDE_INT)
368c87b03e5Sespie     return 1;
369c87b03e5Sespie 
370c87b03e5Sespie   val = tree_low_cst (cst, 1);
371c87b03e5Sespie   if (CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT)
372c87b03e5Sespie     val &= (((unsigned HOST_WIDE_INT) 1) << CHAR_TYPE_SIZE) - 1;
373c87b03e5Sespie 
374c87b03e5Sespie   hostval = val;
375c87b03e5Sespie   if (HOST_BITS_PER_CHAR < HOST_BITS_PER_WIDE_INT)
376c87b03e5Sespie     hostval &= (((unsigned HOST_WIDE_INT) 1) << HOST_BITS_PER_CHAR) - 1;
377c87b03e5Sespie 
378c87b03e5Sespie   if (val != hostval)
379c87b03e5Sespie     return 1;
380c87b03e5Sespie 
381c87b03e5Sespie   *p = hostval;
382c87b03e5Sespie   return 0;
383c87b03e5Sespie }
384c87b03e5Sespie 
385c87b03e5Sespie /* Given TEM, a pointer to a stack frame, follow the dynamic chain COUNT
386c87b03e5Sespie    times to get the address of either a higher stack frame, or a return
387c87b03e5Sespie    address located within it (depending on FNDECL_CODE).  */
388c87b03e5Sespie 
389c87b03e5Sespie rtx
expand_builtin_return_addr(fndecl_code,count,tem)390c87b03e5Sespie expand_builtin_return_addr (fndecl_code, count, tem)
391c87b03e5Sespie      enum built_in_function fndecl_code;
392c87b03e5Sespie      int count;
393c87b03e5Sespie      rtx tem;
394c87b03e5Sespie {
395c87b03e5Sespie   int i;
396c87b03e5Sespie 
397c87b03e5Sespie   /* Some machines need special handling before we can access
398c87b03e5Sespie      arbitrary frames.  For example, on the sparc, we must first flush
399c87b03e5Sespie      all register windows to the stack.  */
400c87b03e5Sespie #ifdef SETUP_FRAME_ADDRESSES
401c87b03e5Sespie   if (count > 0)
402c87b03e5Sespie     SETUP_FRAME_ADDRESSES ();
403c87b03e5Sespie #endif
404c87b03e5Sespie 
405c87b03e5Sespie   /* On the sparc, the return address is not in the frame, it is in a
406c87b03e5Sespie      register.  There is no way to access it off of the current frame
407c87b03e5Sespie      pointer, but it can be accessed off the previous frame pointer by
408c87b03e5Sespie      reading the value from the register window save area.  */
409c87b03e5Sespie #ifdef RETURN_ADDR_IN_PREVIOUS_FRAME
410c87b03e5Sespie   if (fndecl_code == BUILT_IN_RETURN_ADDRESS)
411c87b03e5Sespie     count--;
412c87b03e5Sespie #endif
413c87b03e5Sespie 
414c87b03e5Sespie   /* Scan back COUNT frames to the specified frame.  */
415c87b03e5Sespie   for (i = 0; i < count; i++)
416c87b03e5Sespie     {
417c87b03e5Sespie       /* Assume the dynamic chain pointer is in the word that the
418c87b03e5Sespie 	 frame address points to, unless otherwise specified.  */
419c87b03e5Sespie #ifdef DYNAMIC_CHAIN_ADDRESS
420c87b03e5Sespie       tem = DYNAMIC_CHAIN_ADDRESS (tem);
421c87b03e5Sespie #endif
422c87b03e5Sespie       tem = memory_address (Pmode, tem);
423c87b03e5Sespie       tem = gen_rtx_MEM (Pmode, tem);
424c87b03e5Sespie       set_mem_alias_set (tem, get_frame_alias_set ());
425c87b03e5Sespie       tem = copy_to_reg (tem);
426c87b03e5Sespie     }
427c87b03e5Sespie 
428c87b03e5Sespie   /* For __builtin_frame_address, return what we've got.  */
429c87b03e5Sespie   if (fndecl_code == BUILT_IN_FRAME_ADDRESS)
430c87b03e5Sespie     return tem;
431c87b03e5Sespie 
432c87b03e5Sespie   /* For __builtin_return_address, Get the return address from that
433c87b03e5Sespie      frame.  */
434c87b03e5Sespie #ifdef RETURN_ADDR_RTX
435c87b03e5Sespie   tem = RETURN_ADDR_RTX (count, tem);
436c87b03e5Sespie #else
437c87b03e5Sespie   tem = memory_address (Pmode,
438c87b03e5Sespie 			plus_constant (tem, GET_MODE_SIZE (Pmode)));
439c87b03e5Sespie   tem = gen_rtx_MEM (Pmode, tem);
440c87b03e5Sespie   set_mem_alias_set (tem, get_frame_alias_set ());
441c87b03e5Sespie #endif
442c87b03e5Sespie   return tem;
443c87b03e5Sespie }
444c87b03e5Sespie 
445c87b03e5Sespie /* Alias set used for setjmp buffer.  */
446c87b03e5Sespie static HOST_WIDE_INT setjmp_alias_set = -1;
447c87b03e5Sespie 
448c87b03e5Sespie /* Construct the leading half of a __builtin_setjmp call.  Control will
449c87b03e5Sespie    return to RECEIVER_LABEL.  This is used directly by sjlj exception
450c87b03e5Sespie    handling code.  */
451c87b03e5Sespie 
452c87b03e5Sespie void
expand_builtin_setjmp_setup(buf_addr,receiver_label)453c87b03e5Sespie expand_builtin_setjmp_setup (buf_addr, receiver_label)
454c87b03e5Sespie      rtx buf_addr;
455c87b03e5Sespie      rtx receiver_label;
456c87b03e5Sespie {
457c87b03e5Sespie   enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
458c87b03e5Sespie   rtx stack_save;
459c87b03e5Sespie   rtx mem;
460c87b03e5Sespie 
461c87b03e5Sespie   if (setjmp_alias_set == -1)
462c87b03e5Sespie     setjmp_alias_set = new_alias_set ();
463c87b03e5Sespie 
464c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
465c87b03e5Sespie   if (GET_MODE (buf_addr) != Pmode)
466c87b03e5Sespie     buf_addr = convert_memory_address (Pmode, buf_addr);
467c87b03e5Sespie #endif
468c87b03e5Sespie 
469c87b03e5Sespie   buf_addr = force_reg (Pmode, force_operand (buf_addr, NULL_RTX));
470c87b03e5Sespie 
471c87b03e5Sespie   emit_queue ();
472c87b03e5Sespie 
473c87b03e5Sespie   /* We store the frame pointer and the address of receiver_label in
474c87b03e5Sespie      the buffer and use the rest of it for the stack save area, which
475c87b03e5Sespie      is machine-dependent.  */
476c87b03e5Sespie 
477c87b03e5Sespie #ifndef BUILTIN_SETJMP_FRAME_VALUE
478c87b03e5Sespie #define BUILTIN_SETJMP_FRAME_VALUE virtual_stack_vars_rtx
479c87b03e5Sespie #endif
480c87b03e5Sespie 
481c87b03e5Sespie   mem = gen_rtx_MEM (Pmode, buf_addr);
482c87b03e5Sespie   set_mem_alias_set (mem, setjmp_alias_set);
483c87b03e5Sespie   emit_move_insn (mem, BUILTIN_SETJMP_FRAME_VALUE);
484c87b03e5Sespie 
485c87b03e5Sespie   mem = gen_rtx_MEM (Pmode, plus_constant (buf_addr, GET_MODE_SIZE (Pmode))),
486c87b03e5Sespie   set_mem_alias_set (mem, setjmp_alias_set);
487c87b03e5Sespie 
488c87b03e5Sespie   emit_move_insn (validize_mem (mem),
489c87b03e5Sespie 		  force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, receiver_label)));
490c87b03e5Sespie 
491c87b03e5Sespie   stack_save = gen_rtx_MEM (sa_mode,
492c87b03e5Sespie 			    plus_constant (buf_addr,
493c87b03e5Sespie 					   2 * GET_MODE_SIZE (Pmode)));
494c87b03e5Sespie   set_mem_alias_set (stack_save, setjmp_alias_set);
495c87b03e5Sespie   emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
496c87b03e5Sespie 
497c87b03e5Sespie   /* If there is further processing to do, do it.  */
498c87b03e5Sespie #ifdef HAVE_builtin_setjmp_setup
499c87b03e5Sespie   if (HAVE_builtin_setjmp_setup)
500c87b03e5Sespie     emit_insn (gen_builtin_setjmp_setup (buf_addr));
501c87b03e5Sespie #endif
502c87b03e5Sespie 
503c87b03e5Sespie   /* Tell optimize_save_area_alloca that extra work is going to
504c87b03e5Sespie      need to go on during alloca.  */
505c87b03e5Sespie   current_function_calls_setjmp = 1;
506c87b03e5Sespie 
507c87b03e5Sespie   /* Set this so all the registers get saved in our frame; we need to be
508c87b03e5Sespie      able to copy the saved values for any registers from frames we unwind.  */
509c87b03e5Sespie   current_function_has_nonlocal_label = 1;
510c87b03e5Sespie }
511c87b03e5Sespie 
512c87b03e5Sespie /* Construct the trailing part of a __builtin_setjmp call.
513c87b03e5Sespie    This is used directly by sjlj exception handling code.  */
514c87b03e5Sespie 
515c87b03e5Sespie void
expand_builtin_setjmp_receiver(receiver_label)516c87b03e5Sespie expand_builtin_setjmp_receiver (receiver_label)
517c87b03e5Sespie      rtx receiver_label ATTRIBUTE_UNUSED;
518c87b03e5Sespie {
519c87b03e5Sespie   /* Clobber the FP when we get here, so we have to make sure it's
520c87b03e5Sespie      marked as used by this function.  */
521c87b03e5Sespie   emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
522c87b03e5Sespie 
523c87b03e5Sespie   /* Mark the static chain as clobbered here so life information
524c87b03e5Sespie      doesn't get messed up for it.  */
525c87b03e5Sespie   emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx));
526c87b03e5Sespie 
527c87b03e5Sespie   /* Now put in the code to restore the frame pointer, and argument
528c87b03e5Sespie      pointer, if needed.  The code below is from expand_end_bindings
529c87b03e5Sespie      in stmt.c; see detailed documentation there.  */
530c87b03e5Sespie #ifdef HAVE_nonlocal_goto
531c87b03e5Sespie   if (! HAVE_nonlocal_goto)
532c87b03e5Sespie #endif
533c87b03e5Sespie     emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
534c87b03e5Sespie 
535c87b03e5Sespie #if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
536c87b03e5Sespie   if (fixed_regs[ARG_POINTER_REGNUM])
537c87b03e5Sespie     {
538c87b03e5Sespie #ifdef ELIMINABLE_REGS
539c87b03e5Sespie       size_t i;
540c87b03e5Sespie       static const struct elims {const int from, to;} elim_regs[] = ELIMINABLE_REGS;
541c87b03e5Sespie 
542c87b03e5Sespie       for (i = 0; i < ARRAY_SIZE (elim_regs); i++)
543c87b03e5Sespie 	if (elim_regs[i].from == ARG_POINTER_REGNUM
544c87b03e5Sespie 	    && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
545c87b03e5Sespie 	  break;
546c87b03e5Sespie 
547c87b03e5Sespie       if (i == ARRAY_SIZE (elim_regs))
548c87b03e5Sespie #endif
549c87b03e5Sespie 	{
550c87b03e5Sespie 	  /* Now restore our arg pointer from the address at which it
551c87b03e5Sespie 	     was saved in our stack frame.  */
552c87b03e5Sespie 	  emit_move_insn (virtual_incoming_args_rtx,
553c87b03e5Sespie 			  copy_to_reg (get_arg_pointer_save_area (cfun)));
554c87b03e5Sespie 	}
555c87b03e5Sespie     }
556c87b03e5Sespie #endif
557c87b03e5Sespie 
558c87b03e5Sespie #ifdef HAVE_builtin_setjmp_receiver
559c87b03e5Sespie   if (HAVE_builtin_setjmp_receiver)
560c87b03e5Sespie     emit_insn (gen_builtin_setjmp_receiver (receiver_label));
561c87b03e5Sespie   else
562c87b03e5Sespie #endif
563c87b03e5Sespie #ifdef HAVE_nonlocal_goto_receiver
564c87b03e5Sespie     if (HAVE_nonlocal_goto_receiver)
565c87b03e5Sespie       emit_insn (gen_nonlocal_goto_receiver ());
566c87b03e5Sespie     else
567c87b03e5Sespie #endif
568c87b03e5Sespie       { /* Nothing */ }
569c87b03e5Sespie 
570c87b03e5Sespie   /* @@@ This is a kludge.  Not all machine descriptions define a blockage
571c87b03e5Sespie      insn, but we must not allow the code we just generated to be reordered
572c87b03e5Sespie      by scheduling.  Specifically, the update of the frame pointer must
573c87b03e5Sespie      happen immediately, not later.  So emit an ASM_INPUT to act as blockage
574c87b03e5Sespie      insn.  */
575c87b03e5Sespie   emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
576c87b03e5Sespie }
577c87b03e5Sespie 
578c87b03e5Sespie /* __builtin_setjmp is passed a pointer to an array of five words (not
579c87b03e5Sespie    all will be used on all machines).  It operates similarly to the C
580c87b03e5Sespie    library function of the same name, but is more efficient.  Much of
581c87b03e5Sespie    the code below (and for longjmp) is copied from the handling of
582c87b03e5Sespie    non-local gotos.
583c87b03e5Sespie 
584c87b03e5Sespie    NOTE: This is intended for use by GNAT and the exception handling
585c87b03e5Sespie    scheme in the compiler and will only work in the method used by
586c87b03e5Sespie    them.  */
587c87b03e5Sespie 
588c87b03e5Sespie static rtx
expand_builtin_setjmp(arglist,target)589c87b03e5Sespie expand_builtin_setjmp (arglist, target)
590c87b03e5Sespie      tree arglist;
591c87b03e5Sespie      rtx target;
592c87b03e5Sespie {
593c87b03e5Sespie   rtx buf_addr, next_lab, cont_lab;
594c87b03e5Sespie 
595c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
596c87b03e5Sespie     return NULL_RTX;
597c87b03e5Sespie 
598c87b03e5Sespie   if (target == 0 || GET_CODE (target) != REG
599c87b03e5Sespie       || REGNO (target) < FIRST_PSEUDO_REGISTER)
600c87b03e5Sespie     target = gen_reg_rtx (TYPE_MODE (integer_type_node));
601c87b03e5Sespie 
602c87b03e5Sespie   buf_addr = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
603c87b03e5Sespie 
604c87b03e5Sespie   next_lab = gen_label_rtx ();
605c87b03e5Sespie   cont_lab = gen_label_rtx ();
606c87b03e5Sespie 
607c87b03e5Sespie   expand_builtin_setjmp_setup (buf_addr, next_lab);
608c87b03e5Sespie 
609c87b03e5Sespie   /* Set TARGET to zero and branch to the continue label.  */
610c87b03e5Sespie   emit_move_insn (target, const0_rtx);
611c87b03e5Sespie   emit_jump_insn (gen_jump (cont_lab));
612c87b03e5Sespie   emit_barrier ();
613c87b03e5Sespie   emit_label (next_lab);
614c87b03e5Sespie 
615c87b03e5Sespie   expand_builtin_setjmp_receiver (next_lab);
616c87b03e5Sespie 
617c87b03e5Sespie   /* Set TARGET to one.  */
618c87b03e5Sespie   emit_move_insn (target, const1_rtx);
619c87b03e5Sespie   emit_label (cont_lab);
620c87b03e5Sespie 
621c87b03e5Sespie   /* Tell flow about the strange goings on.  Putting `next_lab' on
622c87b03e5Sespie      `nonlocal_goto_handler_labels' to indicates that function
623c87b03e5Sespie      calls may traverse the arc back to this label.  */
624c87b03e5Sespie 
625c87b03e5Sespie   current_function_has_nonlocal_label = 1;
626c87b03e5Sespie   nonlocal_goto_handler_labels
627c87b03e5Sespie     = gen_rtx_EXPR_LIST (VOIDmode, next_lab, nonlocal_goto_handler_labels);
628c87b03e5Sespie 
629c87b03e5Sespie   return target;
630c87b03e5Sespie }
631c87b03e5Sespie 
632c87b03e5Sespie /* __builtin_longjmp is passed a pointer to an array of five words (not
633c87b03e5Sespie    all will be used on all machines).  It operates similarly to the C
634c87b03e5Sespie    library function of the same name, but is more efficient.  Much of
635c87b03e5Sespie    the code below is copied from the handling of non-local gotos.
636c87b03e5Sespie 
637c87b03e5Sespie    NOTE: This is intended for use by GNAT and the exception handling
638c87b03e5Sespie    scheme in the compiler and will only work in the method used by
639c87b03e5Sespie    them.  */
640c87b03e5Sespie 
641c87b03e5Sespie void
expand_builtin_longjmp(buf_addr,value)642c87b03e5Sespie expand_builtin_longjmp (buf_addr, value)
643c87b03e5Sespie      rtx buf_addr, value;
644c87b03e5Sespie {
645c87b03e5Sespie   rtx fp, lab, stack, insn, last;
646c87b03e5Sespie   enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
647c87b03e5Sespie 
648c87b03e5Sespie   if (setjmp_alias_set == -1)
649c87b03e5Sespie     setjmp_alias_set = new_alias_set ();
650c87b03e5Sespie 
651c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
652c87b03e5Sespie   if (GET_MODE (buf_addr) != Pmode)
653c87b03e5Sespie     buf_addr = convert_memory_address (Pmode, buf_addr);
654c87b03e5Sespie #endif
655c87b03e5Sespie 
656c87b03e5Sespie   buf_addr = force_reg (Pmode, buf_addr);
657c87b03e5Sespie 
658c87b03e5Sespie   /* We used to store value in static_chain_rtx, but that fails if pointers
659c87b03e5Sespie      are smaller than integers.  We instead require that the user must pass
660c87b03e5Sespie      a second argument of 1, because that is what builtin_setjmp will
661c87b03e5Sespie      return.  This also makes EH slightly more efficient, since we are no
662c87b03e5Sespie      longer copying around a value that we don't care about.  */
663c87b03e5Sespie   if (value != const1_rtx)
664c87b03e5Sespie     abort ();
665c87b03e5Sespie 
666c87b03e5Sespie   current_function_calls_longjmp = 1;
667c87b03e5Sespie 
668c87b03e5Sespie   last = get_last_insn ();
669c87b03e5Sespie #ifdef HAVE_builtin_longjmp
670c87b03e5Sespie   if (HAVE_builtin_longjmp)
671c87b03e5Sespie     emit_insn (gen_builtin_longjmp (buf_addr));
672c87b03e5Sespie   else
673c87b03e5Sespie #endif
674c87b03e5Sespie     {
675c87b03e5Sespie       fp = gen_rtx_MEM (Pmode, buf_addr);
676c87b03e5Sespie       lab = gen_rtx_MEM (Pmode, plus_constant (buf_addr,
677c87b03e5Sespie 					       GET_MODE_SIZE (Pmode)));
678c87b03e5Sespie 
679c87b03e5Sespie       stack = gen_rtx_MEM (sa_mode, plus_constant (buf_addr,
680c87b03e5Sespie 						   2 * GET_MODE_SIZE (Pmode)));
681c87b03e5Sespie       set_mem_alias_set (fp, setjmp_alias_set);
682c87b03e5Sespie       set_mem_alias_set (lab, setjmp_alias_set);
683c87b03e5Sespie       set_mem_alias_set (stack, setjmp_alias_set);
684c87b03e5Sespie 
685c87b03e5Sespie       /* Pick up FP, label, and SP from the block and jump.  This code is
686c87b03e5Sespie 	 from expand_goto in stmt.c; see there for detailed comments.  */
687c87b03e5Sespie #if HAVE_nonlocal_goto
688c87b03e5Sespie       if (HAVE_nonlocal_goto)
689c87b03e5Sespie 	/* We have to pass a value to the nonlocal_goto pattern that will
690c87b03e5Sespie 	   get copied into the static_chain pointer, but it does not matter
691c87b03e5Sespie 	   what that value is, because builtin_setjmp does not use it.  */
692c87b03e5Sespie 	emit_insn (gen_nonlocal_goto (value, lab, stack, fp));
693c87b03e5Sespie       else
694c87b03e5Sespie #endif
695c87b03e5Sespie 	{
696c87b03e5Sespie 	  lab = copy_to_reg (lab);
697c87b03e5Sespie 
698c87b03e5Sespie 	  emit_move_insn (hard_frame_pointer_rtx, fp);
699c87b03e5Sespie 	  emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
700c87b03e5Sespie 
701c87b03e5Sespie 	  emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
702c87b03e5Sespie 	  emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
703c87b03e5Sespie 	  emit_indirect_jump (lab);
704c87b03e5Sespie 	}
705c87b03e5Sespie     }
706c87b03e5Sespie 
707c87b03e5Sespie   /* Search backwards and mark the jump insn as a non-local goto.
708c87b03e5Sespie      Note that this precludes the use of __builtin_longjmp to a
709c87b03e5Sespie      __builtin_setjmp target in the same function.  However, we've
710c87b03e5Sespie      already cautioned the user that these functions are for
711c87b03e5Sespie      internal exception handling use only.  */
712c87b03e5Sespie   for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
713c87b03e5Sespie     {
714c87b03e5Sespie       if (insn == last)
715c87b03e5Sespie 	abort ();
716c87b03e5Sespie       if (GET_CODE (insn) == JUMP_INSN)
717c87b03e5Sespie 	{
718c87b03e5Sespie 	  REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx,
719c87b03e5Sespie 					      REG_NOTES (insn));
720c87b03e5Sespie 	  break;
721c87b03e5Sespie 	}
722c87b03e5Sespie       else if (GET_CODE (insn) == CALL_INSN)
723c87b03e5Sespie 	break;
724c87b03e5Sespie     }
725c87b03e5Sespie }
726c87b03e5Sespie 
727c87b03e5Sespie /* Expand a call to __builtin_prefetch.  For a target that does not support
728c87b03e5Sespie    data prefetch, evaluate the memory address argument in case it has side
729c87b03e5Sespie    effects.  */
730c87b03e5Sespie 
731c87b03e5Sespie static void
expand_builtin_prefetch(arglist)732c87b03e5Sespie expand_builtin_prefetch (arglist)
733c87b03e5Sespie      tree arglist;
734c87b03e5Sespie {
735c87b03e5Sespie   tree arg0, arg1, arg2;
736c87b03e5Sespie   rtx op0, op1, op2;
737c87b03e5Sespie 
738c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, 0))
739c87b03e5Sespie     return;
740c87b03e5Sespie 
741c87b03e5Sespie   arg0 = TREE_VALUE (arglist);
742c87b03e5Sespie   /* Arguments 1 and 2 are optional; argument 1 (read/write) defaults to
743c87b03e5Sespie      zero (read) and argument 2 (locality) defaults to 3 (high degree of
744c87b03e5Sespie      locality).  */
745c87b03e5Sespie   if (TREE_CHAIN (arglist))
746c87b03e5Sespie     {
747c87b03e5Sespie       arg1 = TREE_VALUE (TREE_CHAIN (arglist));
748c87b03e5Sespie       if (TREE_CHAIN (TREE_CHAIN (arglist)))
749c87b03e5Sespie 	arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
750c87b03e5Sespie       else
751c87b03e5Sespie 	arg2 = build_int_2 (3, 0);
752c87b03e5Sespie     }
753c87b03e5Sespie   else
754c87b03e5Sespie     {
755c87b03e5Sespie       arg1 = integer_zero_node;
756c87b03e5Sespie       arg2 = build_int_2 (3, 0);
757c87b03e5Sespie     }
758c87b03e5Sespie 
759c87b03e5Sespie   /* Argument 0 is an address.  */
760c87b03e5Sespie   op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
761c87b03e5Sespie 
762c87b03e5Sespie   /* Argument 1 (read/write flag) must be a compile-time constant int.  */
763c87b03e5Sespie   if (TREE_CODE (arg1) != INTEGER_CST)
764c87b03e5Sespie     {
765c87b03e5Sespie       error ("second arg to `__builtin_prefetch' must be a constant");
766c87b03e5Sespie       arg1 = integer_zero_node;
767c87b03e5Sespie     }
768c87b03e5Sespie   op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
769c87b03e5Sespie   /* Argument 1 must be either zero or one.  */
770c87b03e5Sespie   if (INTVAL (op1) != 0 && INTVAL (op1) != 1)
771c87b03e5Sespie     {
772c87b03e5Sespie       warning ("invalid second arg to __builtin_prefetch; using zero");
773c87b03e5Sespie       op1 = const0_rtx;
774c87b03e5Sespie     }
775c87b03e5Sespie 
776c87b03e5Sespie   /* Argument 2 (locality) must be a compile-time constant int.  */
777c87b03e5Sespie   if (TREE_CODE (arg2) != INTEGER_CST)
778c87b03e5Sespie     {
779c87b03e5Sespie       error ("third arg to `__builtin_prefetch' must be a constant");
780c87b03e5Sespie       arg2 = integer_zero_node;
781c87b03e5Sespie     }
782c87b03e5Sespie   op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
783c87b03e5Sespie   /* Argument 2 must be 0, 1, 2, or 3.  */
784c87b03e5Sespie   if (INTVAL (op2) < 0 || INTVAL (op2) > 3)
785c87b03e5Sespie     {
786c87b03e5Sespie       warning ("invalid third arg to __builtin_prefetch; using zero");
787c87b03e5Sespie       op2 = const0_rtx;
788c87b03e5Sespie     }
789c87b03e5Sespie 
790c87b03e5Sespie #ifdef HAVE_prefetch
791c87b03e5Sespie   if (HAVE_prefetch)
792c87b03e5Sespie     {
793c87b03e5Sespie       if ((! (*insn_data[(int) CODE_FOR_prefetch].operand[0].predicate)
794c87b03e5Sespie 	     (op0,
795c87b03e5Sespie 	      insn_data[(int) CODE_FOR_prefetch].operand[0].mode))
796c87b03e5Sespie 	  || (GET_MODE(op0) != Pmode))
797c87b03e5Sespie 	{
798c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
799c87b03e5Sespie 	  if (GET_MODE(op0) != Pmode)
800c87b03e5Sespie 	    op0 = convert_memory_address (Pmode, op0);
801c87b03e5Sespie #endif
802c87b03e5Sespie 	  op0 = force_reg (Pmode, op0);
803c87b03e5Sespie 	}
804c87b03e5Sespie       emit_insn (gen_prefetch (op0, op1, op2));
805c87b03e5Sespie     }
806c87b03e5Sespie   else
807c87b03e5Sespie #endif
808c87b03e5Sespie     op0 = protect_from_queue (op0, 0);
809c87b03e5Sespie   /* Don't do anything with direct references to volatile memory, but
810c87b03e5Sespie      generate code to handle other side effects.  */
811c87b03e5Sespie   if (GET_CODE (op0) != MEM && side_effects_p (op0))
812c87b03e5Sespie     emit_insn (op0);
813c87b03e5Sespie }
814c87b03e5Sespie 
815c87b03e5Sespie /* Get a MEM rtx for expression EXP which is the address of an operand
816c87b03e5Sespie    to be used to be used in a string instruction (cmpstrsi, movstrsi, ..).  */
817c87b03e5Sespie 
818c87b03e5Sespie static rtx
get_memory_rtx(exp)819c87b03e5Sespie get_memory_rtx (exp)
820c87b03e5Sespie      tree exp;
821c87b03e5Sespie {
822c87b03e5Sespie   rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_SUM);
823c87b03e5Sespie   rtx mem;
824c87b03e5Sespie 
825c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
826c87b03e5Sespie   if (GET_MODE (addr) != Pmode)
827c87b03e5Sespie     addr = convert_memory_address (Pmode, addr);
828c87b03e5Sespie #endif
829c87b03e5Sespie 
830c87b03e5Sespie   mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
831c87b03e5Sespie 
832c87b03e5Sespie   /* Get an expression we can use to find the attributes to assign to MEM.
833c87b03e5Sespie      If it is an ADDR_EXPR, use the operand.  Otherwise, dereference it if
834c87b03e5Sespie      we can.  First remove any nops.  */
835c87b03e5Sespie   while ((TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
836c87b03e5Sespie 	  || TREE_CODE (exp) == NON_LVALUE_EXPR)
837c87b03e5Sespie 	 && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
838c87b03e5Sespie     exp = TREE_OPERAND (exp, 0);
839c87b03e5Sespie 
840c87b03e5Sespie   if (TREE_CODE (exp) == ADDR_EXPR)
841c87b03e5Sespie     {
842c87b03e5Sespie       exp = TREE_OPERAND (exp, 0);
843c87b03e5Sespie       set_mem_attributes (mem, exp, 0);
844c87b03e5Sespie     }
845c87b03e5Sespie   else if (POINTER_TYPE_P (TREE_TYPE (exp)))
846c87b03e5Sespie     {
847c87b03e5Sespie       exp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (exp)), exp);
848c87b03e5Sespie       /* memcpy, memset and other builtin stringops can alias with anything.  */
849c87b03e5Sespie       set_mem_alias_set (mem, 0);
850c87b03e5Sespie     }
851c87b03e5Sespie 
852c87b03e5Sespie   return mem;
853c87b03e5Sespie }
854c87b03e5Sespie 
855c87b03e5Sespie /* Built-in functions to perform an untyped call and return.  */
856c87b03e5Sespie 
857c87b03e5Sespie /* For each register that may be used for calling a function, this
858c87b03e5Sespie    gives a mode used to copy the register's value.  VOIDmode indicates
859c87b03e5Sespie    the register is not used for calling a function.  If the machine
860c87b03e5Sespie    has register windows, this gives only the outbound registers.
861c87b03e5Sespie    INCOMING_REGNO gives the corresponding inbound register.  */
862c87b03e5Sespie static enum machine_mode apply_args_mode[FIRST_PSEUDO_REGISTER];
863c87b03e5Sespie 
864c87b03e5Sespie /* For each register that may be used for returning values, this gives
865c87b03e5Sespie    a mode used to copy the register's value.  VOIDmode indicates the
866c87b03e5Sespie    register is not used for returning values.  If the machine has
867c87b03e5Sespie    register windows, this gives only the outbound registers.
868c87b03e5Sespie    INCOMING_REGNO gives the corresponding inbound register.  */
869c87b03e5Sespie static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER];
870c87b03e5Sespie 
871c87b03e5Sespie /* For each register that may be used for calling a function, this
872c87b03e5Sespie    gives the offset of that register into the block returned by
873c87b03e5Sespie    __builtin_apply_args.  0 indicates that the register is not
874c87b03e5Sespie    used for calling a function.  */
875c87b03e5Sespie static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
876c87b03e5Sespie 
877c87b03e5Sespie /* Return the offset of register REGNO into the block returned by
878c87b03e5Sespie    __builtin_apply_args.  This is not declared static, since it is
879c87b03e5Sespie    needed in objc-act.c.  */
880c87b03e5Sespie 
881c87b03e5Sespie int
apply_args_register_offset(regno)882c87b03e5Sespie apply_args_register_offset (regno)
883c87b03e5Sespie      int regno;
884c87b03e5Sespie {
885c87b03e5Sespie   apply_args_size ();
886c87b03e5Sespie 
887c87b03e5Sespie   /* Arguments are always put in outgoing registers (in the argument
888c87b03e5Sespie      block) if such make sense.  */
889c87b03e5Sespie #ifdef OUTGOING_REGNO
890c87b03e5Sespie   regno = OUTGOING_REGNO (regno);
891c87b03e5Sespie #endif
892c87b03e5Sespie   return apply_args_reg_offset[regno];
893c87b03e5Sespie }
894c87b03e5Sespie 
895c87b03e5Sespie /* Return the size required for the block returned by __builtin_apply_args,
896c87b03e5Sespie    and initialize apply_args_mode.  */
897c87b03e5Sespie 
898c87b03e5Sespie static int
apply_args_size()899c87b03e5Sespie apply_args_size ()
900c87b03e5Sespie {
901c87b03e5Sespie   static int size = -1;
902c87b03e5Sespie   int align;
903c87b03e5Sespie   unsigned int regno;
904c87b03e5Sespie   enum machine_mode mode;
905c87b03e5Sespie 
906c87b03e5Sespie   /* The values computed by this function never change.  */
907c87b03e5Sespie   if (size < 0)
908c87b03e5Sespie     {
909c87b03e5Sespie       /* The first value is the incoming arg-pointer.  */
910c87b03e5Sespie       size = GET_MODE_SIZE (Pmode);
911c87b03e5Sespie 
912c87b03e5Sespie       /* The second value is the structure value address unless this is
913c87b03e5Sespie 	 passed as an "invisible" first argument.  */
914c87b03e5Sespie       if (struct_value_rtx)
915c87b03e5Sespie 	size += GET_MODE_SIZE (Pmode);
916c87b03e5Sespie 
917c87b03e5Sespie       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
918c87b03e5Sespie 	if (FUNCTION_ARG_REGNO_P (regno))
919c87b03e5Sespie 	  {
920c87b03e5Sespie 	    /* Search for the proper mode for copying this register's
921c87b03e5Sespie 	       value.  I'm not sure this is right, but it works so far.  */
922c87b03e5Sespie 	    enum machine_mode best_mode = VOIDmode;
923c87b03e5Sespie 
924c87b03e5Sespie 	    for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
925c87b03e5Sespie 		 mode != VOIDmode;
926c87b03e5Sespie 		 mode = GET_MODE_WIDER_MODE (mode))
927c87b03e5Sespie 	      if (HARD_REGNO_MODE_OK (regno, mode)
928c87b03e5Sespie 		  && HARD_REGNO_NREGS (regno, mode) == 1)
929c87b03e5Sespie 		best_mode = mode;
930c87b03e5Sespie 
931c87b03e5Sespie 	    if (best_mode == VOIDmode)
932c87b03e5Sespie 	      for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
933c87b03e5Sespie 		   mode != VOIDmode;
934c87b03e5Sespie 		   mode = GET_MODE_WIDER_MODE (mode))
935c87b03e5Sespie 		if (HARD_REGNO_MODE_OK (regno, mode)
936c87b03e5Sespie 		    && have_insn_for (SET, mode))
937c87b03e5Sespie 		  best_mode = mode;
938c87b03e5Sespie 
939c87b03e5Sespie 	    if (best_mode == VOIDmode)
940c87b03e5Sespie 	      for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
941c87b03e5Sespie 		   mode != VOIDmode;
942c87b03e5Sespie 		   mode = GET_MODE_WIDER_MODE (mode))
943c87b03e5Sespie 		if (HARD_REGNO_MODE_OK (regno, mode)
944c87b03e5Sespie 		    && have_insn_for (SET, mode))
945c87b03e5Sespie 		  best_mode = mode;
946c87b03e5Sespie 
947c87b03e5Sespie 	    if (best_mode == VOIDmode)
948c87b03e5Sespie 	      for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
949c87b03e5Sespie 		   mode != VOIDmode;
950c87b03e5Sespie 		   mode = GET_MODE_WIDER_MODE (mode))
951c87b03e5Sespie 		if (HARD_REGNO_MODE_OK (regno, mode)
952c87b03e5Sespie 		    && have_insn_for (SET, mode))
953c87b03e5Sespie 		  best_mode = mode;
954c87b03e5Sespie 
955c87b03e5Sespie 	    mode = best_mode;
956c87b03e5Sespie 	    if (mode == VOIDmode)
957c87b03e5Sespie 	      abort ();
958c87b03e5Sespie 
959c87b03e5Sespie 	    align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
960c87b03e5Sespie 	    if (size % align != 0)
961c87b03e5Sespie 	      size = CEIL (size, align) * align;
962c87b03e5Sespie 	    apply_args_reg_offset[regno] = size;
963c87b03e5Sespie 	    size += GET_MODE_SIZE (mode);
964c87b03e5Sespie 	    apply_args_mode[regno] = mode;
965c87b03e5Sespie 	  }
966c87b03e5Sespie 	else
967c87b03e5Sespie 	  {
968c87b03e5Sespie 	    apply_args_mode[regno] = VOIDmode;
969c87b03e5Sespie 	    apply_args_reg_offset[regno] = 0;
970c87b03e5Sespie 	  }
971c87b03e5Sespie     }
972c87b03e5Sespie   return size;
973c87b03e5Sespie }
974c87b03e5Sespie 
975c87b03e5Sespie /* Return the size required for the block returned by __builtin_apply,
976c87b03e5Sespie    and initialize apply_result_mode.  */
977c87b03e5Sespie 
978c87b03e5Sespie static int
apply_result_size()979c87b03e5Sespie apply_result_size ()
980c87b03e5Sespie {
981c87b03e5Sespie   static int size = -1;
982c87b03e5Sespie   int align, regno;
983c87b03e5Sespie   enum machine_mode mode;
984c87b03e5Sespie 
985c87b03e5Sespie   /* The values computed by this function never change.  */
986c87b03e5Sespie   if (size < 0)
987c87b03e5Sespie     {
988c87b03e5Sespie       size = 0;
989c87b03e5Sespie 
990c87b03e5Sespie       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
991c87b03e5Sespie 	if (FUNCTION_VALUE_REGNO_P (regno))
992c87b03e5Sespie 	  {
993c87b03e5Sespie 	    /* Search for the proper mode for copying this register's
994c87b03e5Sespie 	       value.  I'm not sure this is right, but it works so far.  */
995c87b03e5Sespie 	    enum machine_mode best_mode = VOIDmode;
996c87b03e5Sespie 
997c87b03e5Sespie 	    for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
998c87b03e5Sespie 		 mode != TImode;
999c87b03e5Sespie 		 mode = GET_MODE_WIDER_MODE (mode))
1000c87b03e5Sespie 	      if (HARD_REGNO_MODE_OK (regno, mode))
1001c87b03e5Sespie 		best_mode = mode;
1002c87b03e5Sespie 
1003c87b03e5Sespie 	    if (best_mode == VOIDmode)
1004c87b03e5Sespie 	      for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
1005c87b03e5Sespie 		   mode != VOIDmode;
1006c87b03e5Sespie 		   mode = GET_MODE_WIDER_MODE (mode))
1007c87b03e5Sespie 		if (HARD_REGNO_MODE_OK (regno, mode)
1008c87b03e5Sespie 		    && have_insn_for (SET, mode))
1009c87b03e5Sespie 		  best_mode = mode;
1010c87b03e5Sespie 
1011c87b03e5Sespie 	    if (best_mode == VOIDmode)
1012c87b03e5Sespie 	      for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
1013c87b03e5Sespie 		   mode != VOIDmode;
1014c87b03e5Sespie 		   mode = GET_MODE_WIDER_MODE (mode))
1015c87b03e5Sespie 		if (HARD_REGNO_MODE_OK (regno, mode)
1016c87b03e5Sespie 		    && have_insn_for (SET, mode))
1017c87b03e5Sespie 		  best_mode = mode;
1018c87b03e5Sespie 
1019c87b03e5Sespie 	    if (best_mode == VOIDmode)
1020c87b03e5Sespie 	      for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
1021c87b03e5Sespie 		   mode != VOIDmode;
1022c87b03e5Sespie 		   mode = GET_MODE_WIDER_MODE (mode))
1023c87b03e5Sespie 		if (HARD_REGNO_MODE_OK (regno, mode)
1024c87b03e5Sespie 		    && have_insn_for (SET, mode))
1025c87b03e5Sespie 		  best_mode = mode;
1026c87b03e5Sespie 
1027c87b03e5Sespie 	    mode = best_mode;
1028c87b03e5Sespie 	    if (mode == VOIDmode)
1029c87b03e5Sespie 	      abort ();
1030c87b03e5Sespie 
1031c87b03e5Sespie 	    align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1032c87b03e5Sespie 	    if (size % align != 0)
1033c87b03e5Sespie 	      size = CEIL (size, align) * align;
1034c87b03e5Sespie 	    size += GET_MODE_SIZE (mode);
1035c87b03e5Sespie 	    apply_result_mode[regno] = mode;
1036c87b03e5Sespie 	  }
1037c87b03e5Sespie 	else
1038c87b03e5Sespie 	  apply_result_mode[regno] = VOIDmode;
1039c87b03e5Sespie 
1040c87b03e5Sespie       /* Allow targets that use untyped_call and untyped_return to override
1041c87b03e5Sespie 	 the size so that machine-specific information can be stored here.  */
1042c87b03e5Sespie #ifdef APPLY_RESULT_SIZE
1043c87b03e5Sespie       size = APPLY_RESULT_SIZE;
1044c87b03e5Sespie #endif
1045c87b03e5Sespie     }
1046c87b03e5Sespie   return size;
1047c87b03e5Sespie }
1048c87b03e5Sespie 
1049c87b03e5Sespie #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
1050c87b03e5Sespie /* Create a vector describing the result block RESULT.  If SAVEP is true,
1051c87b03e5Sespie    the result block is used to save the values; otherwise it is used to
1052c87b03e5Sespie    restore the values.  */
1053c87b03e5Sespie 
1054c87b03e5Sespie static rtx
result_vector(savep,result)1055c87b03e5Sespie result_vector (savep, result)
1056c87b03e5Sespie      int savep;
1057c87b03e5Sespie      rtx result;
1058c87b03e5Sespie {
1059c87b03e5Sespie   int regno, size, align, nelts;
1060c87b03e5Sespie   enum machine_mode mode;
1061c87b03e5Sespie   rtx reg, mem;
1062c87b03e5Sespie   rtx *savevec = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
1063c87b03e5Sespie 
1064c87b03e5Sespie   size = nelts = 0;
1065c87b03e5Sespie   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1066c87b03e5Sespie     if ((mode = apply_result_mode[regno]) != VOIDmode)
1067c87b03e5Sespie       {
1068c87b03e5Sespie 	align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1069c87b03e5Sespie 	if (size % align != 0)
1070c87b03e5Sespie 	  size = CEIL (size, align) * align;
1071c87b03e5Sespie 	reg = gen_rtx_REG (mode, savep ? regno : INCOMING_REGNO (regno));
1072c87b03e5Sespie 	mem = adjust_address (result, mode, size);
1073c87b03e5Sespie 	savevec[nelts++] = (savep
1074c87b03e5Sespie 			    ? gen_rtx_SET (VOIDmode, mem, reg)
1075c87b03e5Sespie 			    : gen_rtx_SET (VOIDmode, reg, mem));
1076c87b03e5Sespie 	size += GET_MODE_SIZE (mode);
1077c87b03e5Sespie       }
1078c87b03e5Sespie   return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nelts, savevec));
1079c87b03e5Sespie }
1080c87b03e5Sespie #endif /* HAVE_untyped_call or HAVE_untyped_return */
1081c87b03e5Sespie 
1082c87b03e5Sespie /* Save the state required to perform an untyped call with the same
1083c87b03e5Sespie    arguments as were passed to the current function.  */
1084c87b03e5Sespie 
1085c87b03e5Sespie static rtx
expand_builtin_apply_args_1()1086c87b03e5Sespie expand_builtin_apply_args_1 ()
1087c87b03e5Sespie {
1088c87b03e5Sespie   rtx registers;
1089c87b03e5Sespie   int size, align, regno;
1090c87b03e5Sespie   enum machine_mode mode;
1091c87b03e5Sespie 
1092c87b03e5Sespie   /* Create a block where the arg-pointer, structure value address,
1093c87b03e5Sespie      and argument registers can be saved.  */
1094c87b03e5Sespie   registers = assign_stack_local (BLKmode, apply_args_size (), -1);
1095c87b03e5Sespie 
1096c87b03e5Sespie   /* Walk past the arg-pointer and structure value address.  */
1097c87b03e5Sespie   size = GET_MODE_SIZE (Pmode);
1098c87b03e5Sespie   if (struct_value_rtx)
1099c87b03e5Sespie     size += GET_MODE_SIZE (Pmode);
1100c87b03e5Sespie 
1101c87b03e5Sespie   /* Save each register used in calling a function to the block.  */
1102c87b03e5Sespie   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1103c87b03e5Sespie     if ((mode = apply_args_mode[regno]) != VOIDmode)
1104c87b03e5Sespie       {
1105c87b03e5Sespie 	rtx tem;
1106c87b03e5Sespie 
1107c87b03e5Sespie 	align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1108c87b03e5Sespie 	if (size % align != 0)
1109c87b03e5Sespie 	  size = CEIL (size, align) * align;
1110c87b03e5Sespie 
1111c87b03e5Sespie 	tem = gen_rtx_REG (mode, INCOMING_REGNO (regno));
1112c87b03e5Sespie 
1113c87b03e5Sespie 	emit_move_insn (adjust_address (registers, mode, size), tem);
1114c87b03e5Sespie 	size += GET_MODE_SIZE (mode);
1115c87b03e5Sespie       }
1116c87b03e5Sespie 
1117c87b03e5Sespie   /* Save the arg pointer to the block.  */
1118c87b03e5Sespie   emit_move_insn (adjust_address (registers, Pmode, 0),
1119c87b03e5Sespie 		  copy_to_reg (virtual_incoming_args_rtx));
1120c87b03e5Sespie   size = GET_MODE_SIZE (Pmode);
1121c87b03e5Sespie 
1122c87b03e5Sespie   /* Save the structure value address unless this is passed as an
1123c87b03e5Sespie      "invisible" first argument.  */
1124c87b03e5Sespie   if (struct_value_incoming_rtx)
1125c87b03e5Sespie     {
1126c87b03e5Sespie       emit_move_insn (adjust_address (registers, Pmode, size),
1127c87b03e5Sespie 		      copy_to_reg (struct_value_incoming_rtx));
1128c87b03e5Sespie       size += GET_MODE_SIZE (Pmode);
1129c87b03e5Sespie     }
1130c87b03e5Sespie 
1131c87b03e5Sespie   /* Return the address of the block.  */
1132c87b03e5Sespie   return copy_addr_to_reg (XEXP (registers, 0));
1133c87b03e5Sespie }
1134c87b03e5Sespie 
1135c87b03e5Sespie /* __builtin_apply_args returns block of memory allocated on
1136c87b03e5Sespie    the stack into which is stored the arg pointer, structure
1137c87b03e5Sespie    value address, static chain, and all the registers that might
1138c87b03e5Sespie    possibly be used in performing a function call.  The code is
1139c87b03e5Sespie    moved to the start of the function so the incoming values are
1140c87b03e5Sespie    saved.  */
1141c87b03e5Sespie 
1142c87b03e5Sespie static rtx
expand_builtin_apply_args()1143c87b03e5Sespie expand_builtin_apply_args ()
1144c87b03e5Sespie {
1145c87b03e5Sespie   /* Don't do __builtin_apply_args more than once in a function.
1146c87b03e5Sespie      Save the result of the first call and reuse it.  */
1147c87b03e5Sespie   if (apply_args_value != 0)
1148c87b03e5Sespie     return apply_args_value;
1149c87b03e5Sespie   {
1150c87b03e5Sespie     /* When this function is called, it means that registers must be
1151c87b03e5Sespie        saved on entry to this function.  So we migrate the
1152c87b03e5Sespie        call to the first insn of this function.  */
1153c87b03e5Sespie     rtx temp;
1154c87b03e5Sespie     rtx seq;
1155c87b03e5Sespie 
1156c87b03e5Sespie     start_sequence ();
1157c87b03e5Sespie     temp = expand_builtin_apply_args_1 ();
1158c87b03e5Sespie     seq = get_insns ();
1159c87b03e5Sespie     end_sequence ();
1160c87b03e5Sespie 
1161c87b03e5Sespie     apply_args_value = temp;
1162c87b03e5Sespie 
1163c87b03e5Sespie     /* Put the insns after the NOTE that starts the function.
1164c87b03e5Sespie        If this is inside a start_sequence, make the outer-level insn
1165c87b03e5Sespie        chain current, so the code is placed at the start of the
1166c87b03e5Sespie        function.  */
1167c87b03e5Sespie     push_topmost_sequence ();
1168c87b03e5Sespie     emit_insn_before (seq, NEXT_INSN (get_insns ()));
1169c87b03e5Sespie     pop_topmost_sequence ();
1170c87b03e5Sespie     return temp;
1171c87b03e5Sespie   }
1172c87b03e5Sespie }
1173c87b03e5Sespie 
1174c87b03e5Sespie /* Perform an untyped call and save the state required to perform an
1175c87b03e5Sespie    untyped return of whatever value was returned by the given function.  */
1176c87b03e5Sespie 
1177c87b03e5Sespie static rtx
expand_builtin_apply(function,arguments,argsize)1178c87b03e5Sespie expand_builtin_apply (function, arguments, argsize)
1179c87b03e5Sespie      rtx function, arguments, argsize;
1180c87b03e5Sespie {
1181c87b03e5Sespie   int size, align, regno;
1182c87b03e5Sespie   enum machine_mode mode;
1183c87b03e5Sespie   rtx incoming_args, result, reg, dest, src, call_insn;
1184c87b03e5Sespie   rtx old_stack_level = 0;
1185c87b03e5Sespie   rtx call_fusage = 0;
1186c87b03e5Sespie 
1187c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
1188c87b03e5Sespie   if (GET_MODE (arguments) != Pmode)
1189c87b03e5Sespie     arguments = convert_memory_address (Pmode, arguments);
1190c87b03e5Sespie #endif
1191c87b03e5Sespie 
1192c87b03e5Sespie   /* Create a block where the return registers can be saved.  */
1193c87b03e5Sespie   result = assign_stack_local (BLKmode, apply_result_size (), -1);
1194c87b03e5Sespie 
1195c87b03e5Sespie   /* Fetch the arg pointer from the ARGUMENTS block.  */
1196c87b03e5Sespie   incoming_args = gen_reg_rtx (Pmode);
1197c87b03e5Sespie   emit_move_insn (incoming_args, gen_rtx_MEM (Pmode, arguments));
1198c87b03e5Sespie #ifndef STACK_GROWS_DOWNWARD
1199c87b03e5Sespie   incoming_args = expand_simple_binop (Pmode, MINUS, incoming_args, argsize,
1200c87b03e5Sespie 				       incoming_args, 0, OPTAB_LIB_WIDEN);
1201c87b03e5Sespie #endif
1202c87b03e5Sespie 
1203c87b03e5Sespie   /* Perform postincrements before actually calling the function.  */
1204c87b03e5Sespie   emit_queue ();
1205c87b03e5Sespie 
1206c87b03e5Sespie   /* Push a new argument block and copy the arguments.  Do not allow
1207c87b03e5Sespie      the (potential) memcpy call below to interfere with our stack
1208c87b03e5Sespie      manipulations.  */
1209c87b03e5Sespie   do_pending_stack_adjust ();
1210c87b03e5Sespie   NO_DEFER_POP;
1211c87b03e5Sespie 
1212c87b03e5Sespie   /* Save the stack with nonlocal if available */
1213c87b03e5Sespie #ifdef HAVE_save_stack_nonlocal
1214c87b03e5Sespie   if (HAVE_save_stack_nonlocal)
1215c87b03e5Sespie     emit_stack_save (SAVE_NONLOCAL, &old_stack_level, NULL_RTX);
1216c87b03e5Sespie   else
1217c87b03e5Sespie #endif
1218c87b03e5Sespie     emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
1219c87b03e5Sespie 
1220c87b03e5Sespie   /* Push a block of memory onto the stack to store the memory arguments.
1221c87b03e5Sespie      Save the address in a register, and copy the memory arguments.  ??? I
1222c87b03e5Sespie      haven't figured out how the calling convention macros effect this,
1223c87b03e5Sespie      but it's likely that the source and/or destination addresses in
1224c87b03e5Sespie      the block copy will need updating in machine specific ways.  */
1225c87b03e5Sespie   dest = allocate_dynamic_stack_space (argsize, 0, BITS_PER_UNIT);
1226c87b03e5Sespie   dest = gen_rtx_MEM (BLKmode, dest);
1227c87b03e5Sespie   set_mem_align (dest, PARM_BOUNDARY);
1228c87b03e5Sespie   src = gen_rtx_MEM (BLKmode, incoming_args);
1229c87b03e5Sespie   set_mem_align (src, PARM_BOUNDARY);
1230c87b03e5Sespie   emit_block_move (dest, src, argsize, BLOCK_OP_NORMAL);
1231c87b03e5Sespie 
1232c87b03e5Sespie   /* Refer to the argument block.  */
1233c87b03e5Sespie   apply_args_size ();
1234c87b03e5Sespie   arguments = gen_rtx_MEM (BLKmode, arguments);
1235c87b03e5Sespie   set_mem_align (arguments, PARM_BOUNDARY);
1236c87b03e5Sespie 
1237c87b03e5Sespie   /* Walk past the arg-pointer and structure value address.  */
1238c87b03e5Sespie   size = GET_MODE_SIZE (Pmode);
1239c87b03e5Sespie   if (struct_value_rtx)
1240c87b03e5Sespie     size += GET_MODE_SIZE (Pmode);
1241c87b03e5Sespie 
1242c87b03e5Sespie   /* Restore each of the registers previously saved.  Make USE insns
1243c87b03e5Sespie      for each of these registers for use in making the call.  */
1244c87b03e5Sespie   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1245c87b03e5Sespie     if ((mode = apply_args_mode[regno]) != VOIDmode)
1246c87b03e5Sespie       {
1247c87b03e5Sespie 	align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1248c87b03e5Sespie 	if (size % align != 0)
1249c87b03e5Sespie 	  size = CEIL (size, align) * align;
1250c87b03e5Sespie 	reg = gen_rtx_REG (mode, regno);
1251c87b03e5Sespie 	emit_move_insn (reg, adjust_address (arguments, mode, size));
1252c87b03e5Sespie 	use_reg (&call_fusage, reg);
1253c87b03e5Sespie 	size += GET_MODE_SIZE (mode);
1254c87b03e5Sespie       }
1255c87b03e5Sespie 
1256c87b03e5Sespie   /* Restore the structure value address unless this is passed as an
1257c87b03e5Sespie      "invisible" first argument.  */
1258c87b03e5Sespie   size = GET_MODE_SIZE (Pmode);
1259c87b03e5Sespie   if (struct_value_rtx)
1260c87b03e5Sespie     {
1261c87b03e5Sespie       rtx value = gen_reg_rtx (Pmode);
1262c87b03e5Sespie       emit_move_insn (value, adjust_address (arguments, Pmode, size));
1263c87b03e5Sespie       emit_move_insn (struct_value_rtx, value);
1264c87b03e5Sespie       if (GET_CODE (struct_value_rtx) == REG)
1265c87b03e5Sespie 	use_reg (&call_fusage, struct_value_rtx);
1266c87b03e5Sespie       size += GET_MODE_SIZE (Pmode);
1267c87b03e5Sespie     }
1268c87b03e5Sespie 
1269c87b03e5Sespie   /* All arguments and registers used for the call are set up by now!  */
1270c87b03e5Sespie   function = prepare_call_address (function, NULL_TREE, &call_fusage, 0, 0);
1271c87b03e5Sespie 
1272c87b03e5Sespie   /* Ensure address is valid.  SYMBOL_REF is already valid, so no need,
1273c87b03e5Sespie      and we don't want to load it into a register as an optimization,
1274c87b03e5Sespie      because prepare_call_address already did it if it should be done.  */
1275c87b03e5Sespie   if (GET_CODE (function) != SYMBOL_REF)
1276c87b03e5Sespie     function = memory_address (FUNCTION_MODE, function);
1277c87b03e5Sespie 
1278c87b03e5Sespie   /* Generate the actual call instruction and save the return value.  */
1279c87b03e5Sespie #ifdef HAVE_untyped_call
1280c87b03e5Sespie   if (HAVE_untyped_call)
1281c87b03e5Sespie     emit_call_insn (gen_untyped_call (gen_rtx_MEM (FUNCTION_MODE, function),
1282c87b03e5Sespie 				      result, result_vector (1, result)));
1283c87b03e5Sespie   else
1284c87b03e5Sespie #endif
1285c87b03e5Sespie #ifdef HAVE_call_value
1286c87b03e5Sespie   if (HAVE_call_value)
1287c87b03e5Sespie     {
1288c87b03e5Sespie       rtx valreg = 0;
1289c87b03e5Sespie 
1290c87b03e5Sespie       /* Locate the unique return register.  It is not possible to
1291c87b03e5Sespie 	 express a call that sets more than one return register using
1292c87b03e5Sespie 	 call_value; use untyped_call for that.  In fact, untyped_call
1293c87b03e5Sespie 	 only needs to save the return registers in the given block.  */
1294c87b03e5Sespie       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1295c87b03e5Sespie 	if ((mode = apply_result_mode[regno]) != VOIDmode)
1296c87b03e5Sespie 	  {
1297c87b03e5Sespie 	    if (valreg)
1298c87b03e5Sespie 	      abort (); /* HAVE_untyped_call required.  */
1299c87b03e5Sespie 	    valreg = gen_rtx_REG (mode, regno);
1300c87b03e5Sespie 	  }
1301c87b03e5Sespie 
1302c87b03e5Sespie       emit_call_insn (GEN_CALL_VALUE (valreg,
1303c87b03e5Sespie 				      gen_rtx_MEM (FUNCTION_MODE, function),
1304c87b03e5Sespie 				      const0_rtx, NULL_RTX, const0_rtx));
1305c87b03e5Sespie 
1306c87b03e5Sespie       emit_move_insn (adjust_address (result, GET_MODE (valreg), 0), valreg);
1307c87b03e5Sespie     }
1308c87b03e5Sespie   else
1309c87b03e5Sespie #endif
1310c87b03e5Sespie     abort ();
1311c87b03e5Sespie 
1312c87b03e5Sespie   /* Find the CALL insn we just emitted.  */
1313c87b03e5Sespie   for (call_insn = get_last_insn ();
1314c87b03e5Sespie        call_insn && GET_CODE (call_insn) != CALL_INSN;
1315c87b03e5Sespie        call_insn = PREV_INSN (call_insn))
1316c87b03e5Sespie     ;
1317c87b03e5Sespie 
1318c87b03e5Sespie   if (! call_insn)
1319c87b03e5Sespie     abort ();
1320c87b03e5Sespie 
1321c87b03e5Sespie   /* Put the register usage information on the CALL.  If there is already
1322c87b03e5Sespie      some usage information, put ours at the end.  */
1323c87b03e5Sespie   if (CALL_INSN_FUNCTION_USAGE (call_insn))
1324c87b03e5Sespie     {
1325c87b03e5Sespie       rtx link;
1326c87b03e5Sespie 
1327c87b03e5Sespie       for (link = CALL_INSN_FUNCTION_USAGE (call_insn); XEXP (link, 1) != 0;
1328c87b03e5Sespie 	   link = XEXP (link, 1))
1329c87b03e5Sespie 	;
1330c87b03e5Sespie 
1331c87b03e5Sespie       XEXP (link, 1) = call_fusage;
1332c87b03e5Sespie     }
1333c87b03e5Sespie   else
1334c87b03e5Sespie     CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage;
1335c87b03e5Sespie 
1336c87b03e5Sespie   /* Restore the stack.  */
1337c87b03e5Sespie #ifdef HAVE_save_stack_nonlocal
1338c87b03e5Sespie   if (HAVE_save_stack_nonlocal)
1339c87b03e5Sespie     emit_stack_restore (SAVE_NONLOCAL, old_stack_level, NULL_RTX);
1340c87b03e5Sespie   else
1341c87b03e5Sespie #endif
1342c87b03e5Sespie     emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
1343c87b03e5Sespie 
1344c87b03e5Sespie   OK_DEFER_POP;
1345c87b03e5Sespie 
1346c87b03e5Sespie   /* Return the address of the result block.  */
1347c87b03e5Sespie   result = copy_addr_to_reg (XEXP (result, 0));
1348c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
1349c87b03e5Sespie   if (GET_MODE (result) != ptr_mode)
1350c87b03e5Sespie     result = convert_memory_address (ptr_mode, result);
1351c87b03e5Sespie #endif
1352c87b03e5Sespie   return result;
1353c87b03e5Sespie }
1354c87b03e5Sespie 
1355c87b03e5Sespie /* Perform an untyped return.  */
1356c87b03e5Sespie 
1357c87b03e5Sespie static void
expand_builtin_return(result)1358c87b03e5Sespie expand_builtin_return (result)
1359c87b03e5Sespie      rtx result;
1360c87b03e5Sespie {
1361c87b03e5Sespie   int size, align, regno;
1362c87b03e5Sespie   enum machine_mode mode;
1363c87b03e5Sespie   rtx reg;
1364c87b03e5Sespie   rtx call_fusage = 0;
1365c87b03e5Sespie 
1366c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
1367c87b03e5Sespie   if (GET_MODE (result) != Pmode)
1368c87b03e5Sespie     result = convert_memory_address (Pmode, result);
1369c87b03e5Sespie #endif
1370c87b03e5Sespie 
1371c87b03e5Sespie   apply_result_size ();
1372c87b03e5Sespie   result = gen_rtx_MEM (BLKmode, result);
1373c87b03e5Sespie 
1374c87b03e5Sespie #ifdef HAVE_untyped_return
1375c87b03e5Sespie   if (HAVE_untyped_return)
1376c87b03e5Sespie     {
1377c87b03e5Sespie       emit_jump_insn (gen_untyped_return (result, result_vector (0, result)));
1378c87b03e5Sespie       emit_barrier ();
1379c87b03e5Sespie       return;
1380c87b03e5Sespie     }
1381c87b03e5Sespie #endif
1382c87b03e5Sespie 
1383c87b03e5Sespie   /* Restore the return value and note that each value is used.  */
1384c87b03e5Sespie   size = 0;
1385c87b03e5Sespie   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1386c87b03e5Sespie     if ((mode = apply_result_mode[regno]) != VOIDmode)
1387c87b03e5Sespie       {
1388c87b03e5Sespie 	align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1389c87b03e5Sespie 	if (size % align != 0)
1390c87b03e5Sespie 	  size = CEIL (size, align) * align;
1391c87b03e5Sespie 	reg = gen_rtx_REG (mode, INCOMING_REGNO (regno));
1392c87b03e5Sespie 	emit_move_insn (reg, adjust_address (result, mode, size));
1393c87b03e5Sespie 
1394c87b03e5Sespie 	push_to_sequence (call_fusage);
1395c87b03e5Sespie 	emit_insn (gen_rtx_USE (VOIDmode, reg));
1396c87b03e5Sespie 	call_fusage = get_insns ();
1397c87b03e5Sespie 	end_sequence ();
1398c87b03e5Sespie 	size += GET_MODE_SIZE (mode);
1399c87b03e5Sespie       }
1400c87b03e5Sespie 
1401c87b03e5Sespie   /* Put the USE insns before the return.  */
1402c87b03e5Sespie   emit_insn (call_fusage);
1403c87b03e5Sespie 
1404c87b03e5Sespie   /* Return whatever values was restored by jumping directly to the end
1405c87b03e5Sespie      of the function.  */
1406c87b03e5Sespie   expand_null_return ();
1407c87b03e5Sespie }
1408c87b03e5Sespie 
1409c87b03e5Sespie /* Used by expand_builtin_classify_type and fold_builtin_classify_type.  */
1410c87b03e5Sespie 
1411c87b03e5Sespie static enum type_class
type_to_class(type)1412c87b03e5Sespie type_to_class (type)
1413c87b03e5Sespie      tree type;
1414c87b03e5Sespie {
1415c87b03e5Sespie   switch (TREE_CODE (type))
1416c87b03e5Sespie     {
1417c87b03e5Sespie     case VOID_TYPE:	   return void_type_class;
1418c87b03e5Sespie     case INTEGER_TYPE:	   return integer_type_class;
1419c87b03e5Sespie     case CHAR_TYPE:	   return char_type_class;
1420c87b03e5Sespie     case ENUMERAL_TYPE:	   return enumeral_type_class;
1421c87b03e5Sespie     case BOOLEAN_TYPE:	   return boolean_type_class;
1422c87b03e5Sespie     case POINTER_TYPE:	   return pointer_type_class;
1423c87b03e5Sespie     case REFERENCE_TYPE:   return reference_type_class;
1424c87b03e5Sespie     case OFFSET_TYPE:	   return offset_type_class;
1425c87b03e5Sespie     case REAL_TYPE:	   return real_type_class;
1426c87b03e5Sespie     case COMPLEX_TYPE:	   return complex_type_class;
1427c87b03e5Sespie     case FUNCTION_TYPE:	   return function_type_class;
1428c87b03e5Sespie     case METHOD_TYPE:	   return method_type_class;
1429c87b03e5Sespie     case RECORD_TYPE:	   return record_type_class;
1430c87b03e5Sespie     case UNION_TYPE:
1431c87b03e5Sespie     case QUAL_UNION_TYPE:  return union_type_class;
1432c87b03e5Sespie     case ARRAY_TYPE:	   return (TYPE_STRING_FLAG (type)
1433c87b03e5Sespie 				   ? string_type_class : array_type_class);
1434c87b03e5Sespie     case SET_TYPE:	   return set_type_class;
1435c87b03e5Sespie     case FILE_TYPE:	   return file_type_class;
1436c87b03e5Sespie     case LANG_TYPE:	   return lang_type_class;
1437c87b03e5Sespie     default:		   return no_type_class;
1438c87b03e5Sespie     }
1439c87b03e5Sespie }
1440c87b03e5Sespie 
1441c87b03e5Sespie /* Expand a call to __builtin_classify_type with arguments found in
1442c87b03e5Sespie    ARGLIST.  */
1443c87b03e5Sespie 
1444c87b03e5Sespie static rtx
expand_builtin_classify_type(arglist)1445c87b03e5Sespie expand_builtin_classify_type (arglist)
1446c87b03e5Sespie      tree arglist;
1447c87b03e5Sespie {
1448c87b03e5Sespie   if (arglist != 0)
1449c87b03e5Sespie     return GEN_INT (type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
1450c87b03e5Sespie   return GEN_INT (no_type_class);
1451c87b03e5Sespie }
1452c87b03e5Sespie 
1453c87b03e5Sespie /* Expand expression EXP, which is a call to __builtin_constant_p.  */
1454c87b03e5Sespie 
1455c87b03e5Sespie static rtx
expand_builtin_constant_p(exp)1456c87b03e5Sespie expand_builtin_constant_p (exp)
1457c87b03e5Sespie      tree exp;
1458c87b03e5Sespie {
1459c87b03e5Sespie   tree arglist = TREE_OPERAND (exp, 1);
1460c87b03e5Sespie   enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp));
1461c87b03e5Sespie   rtx tmp;
1462c87b03e5Sespie 
1463c87b03e5Sespie   if (arglist == 0)
1464c87b03e5Sespie     return const0_rtx;
1465c87b03e5Sespie   arglist = TREE_VALUE (arglist);
1466c87b03e5Sespie 
1467c87b03e5Sespie   /* We have taken care of the easy cases during constant folding.  This
1468c87b03e5Sespie      case is not obvious, so emit (constant_p_rtx (ARGLIST)) and let CSE get a
1469c87b03e5Sespie      chance to see if it can deduce whether ARGLIST is constant.  */
1470c87b03e5Sespie 
1471c87b03e5Sespie   tmp = expand_expr (arglist, NULL_RTX, VOIDmode, 0);
1472c87b03e5Sespie   tmp = gen_rtx_CONSTANT_P_RTX (value_mode, tmp);
1473c87b03e5Sespie   return tmp;
1474c87b03e5Sespie }
1475c87b03e5Sespie 
1476c87b03e5Sespie /* Expand a call to one of the builtin math functions (sin, cos, or sqrt).
1477c87b03e5Sespie    Return 0 if a normal call should be emitted rather than expanding the
1478c87b03e5Sespie    function in-line.  EXP is the expression that is a call to the builtin
1479c87b03e5Sespie    function; if convenient, the result should be placed in TARGET.
1480c87b03e5Sespie    SUBTARGET may be used as the target for computing one of EXP's operands.  */
1481c87b03e5Sespie 
1482c87b03e5Sespie static rtx
expand_builtin_mathfn(exp,target,subtarget)1483c87b03e5Sespie expand_builtin_mathfn (exp, target, subtarget)
1484c87b03e5Sespie      tree exp;
1485c87b03e5Sespie      rtx target, subtarget;
1486c87b03e5Sespie {
1487c87b03e5Sespie   optab builtin_optab;
1488c87b03e5Sespie   rtx op0, insns;
1489c87b03e5Sespie   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
1490c87b03e5Sespie   tree arglist = TREE_OPERAND (exp, 1);
1491c87b03e5Sespie   enum machine_mode argmode;
1492c87b03e5Sespie 
1493c87b03e5Sespie   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
1494c87b03e5Sespie     return 0;
1495c87b03e5Sespie 
1496c87b03e5Sespie   /* Stabilize and compute the argument.  */
1497c87b03e5Sespie   if (TREE_CODE (TREE_VALUE (arglist)) != VAR_DECL
1498c87b03e5Sespie       && TREE_CODE (TREE_VALUE (arglist)) != PARM_DECL)
1499c87b03e5Sespie     {
1500c87b03e5Sespie       exp = copy_node (exp);
1501c87b03e5Sespie       TREE_OPERAND (exp, 1) = arglist;
1502c87b03e5Sespie       /* Wrap the computation of the argument in a SAVE_EXPR.  That
1503c87b03e5Sespie 	 way, if we need to expand the argument again (as in the
1504c87b03e5Sespie 	 flag_errno_math case below where we cannot directly set
1505c87b03e5Sespie 	 errno), we will not perform side-effects more than once.
1506c87b03e5Sespie 	 Note that here we're mutating the original EXP as well as the
1507c87b03e5Sespie 	 copy; that's the right thing to do in case the original EXP
1508c87b03e5Sespie 	 is expanded later.  */
1509c87b03e5Sespie       TREE_VALUE (arglist) = save_expr (TREE_VALUE (arglist));
1510c87b03e5Sespie       arglist = copy_node (arglist);
1511c87b03e5Sespie     }
1512c87b03e5Sespie   op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
1513c87b03e5Sespie 
1514c87b03e5Sespie   /* Make a suitable register to place result in.  */
1515c87b03e5Sespie   target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
1516c87b03e5Sespie 
1517c87b03e5Sespie   emit_queue ();
1518c87b03e5Sespie   start_sequence ();
1519c87b03e5Sespie 
1520c87b03e5Sespie   switch (DECL_FUNCTION_CODE (fndecl))
1521c87b03e5Sespie     {
1522c87b03e5Sespie     case BUILT_IN_SIN:
1523c87b03e5Sespie     case BUILT_IN_SINF:
1524c87b03e5Sespie     case BUILT_IN_SINL:
1525c87b03e5Sespie       builtin_optab = sin_optab; break;
1526c87b03e5Sespie     case BUILT_IN_COS:
1527c87b03e5Sespie     case BUILT_IN_COSF:
1528c87b03e5Sespie     case BUILT_IN_COSL:
1529c87b03e5Sespie       builtin_optab = cos_optab; break;
1530c87b03e5Sespie     case BUILT_IN_SQRT:
1531c87b03e5Sespie     case BUILT_IN_SQRTF:
1532c87b03e5Sespie     case BUILT_IN_SQRTL:
1533c87b03e5Sespie       builtin_optab = sqrt_optab; break;
1534c87b03e5Sespie     case BUILT_IN_EXP:
1535c87b03e5Sespie     case BUILT_IN_EXPF:
1536c87b03e5Sespie     case BUILT_IN_EXPL:
1537c87b03e5Sespie       builtin_optab = exp_optab; break;
1538c87b03e5Sespie     case BUILT_IN_LOG:
1539c87b03e5Sespie     case BUILT_IN_LOGF:
1540c87b03e5Sespie     case BUILT_IN_LOGL:
1541c87b03e5Sespie       builtin_optab = log_optab; break;
1542c87b03e5Sespie     default:
1543c87b03e5Sespie       abort ();
1544c87b03e5Sespie     }
1545c87b03e5Sespie 
1546c87b03e5Sespie   /* Compute into TARGET.
1547c87b03e5Sespie      Set TARGET to wherever the result comes back.  */
1548c87b03e5Sespie   argmode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
1549c87b03e5Sespie   target = expand_unop (argmode, builtin_optab, op0, target, 0);
1550c87b03e5Sespie 
1551c87b03e5Sespie   /* If we were unable to expand via the builtin, stop the
1552c87b03e5Sespie      sequence (without outputting the insns) and return 0, causing
1553c87b03e5Sespie      a call to the library function.  */
1554c87b03e5Sespie   if (target == 0)
1555c87b03e5Sespie     {
1556c87b03e5Sespie       end_sequence ();
1557c87b03e5Sespie       return 0;
1558c87b03e5Sespie     }
1559c87b03e5Sespie 
1560c87b03e5Sespie   /* If errno must be maintained, we must set it to EDOM for NaN results.  */
1561c87b03e5Sespie 
1562c87b03e5Sespie   if (flag_errno_math && HONOR_NANS (argmode))
1563c87b03e5Sespie     {
1564c87b03e5Sespie       rtx lab1;
1565c87b03e5Sespie 
1566c87b03e5Sespie       lab1 = gen_label_rtx ();
1567c87b03e5Sespie 
1568c87b03e5Sespie       /* Test the result; if it is NaN, set errno=EDOM because
1569c87b03e5Sespie 	 the argument was not in the domain.  */
1570c87b03e5Sespie       emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
1571c87b03e5Sespie 			       0, lab1);
1572c87b03e5Sespie 
1573c87b03e5Sespie #ifdef TARGET_EDOM
1574c87b03e5Sespie       {
1575c87b03e5Sespie #ifdef GEN_ERRNO_RTX
1576c87b03e5Sespie 	rtx errno_rtx = GEN_ERRNO_RTX;
1577c87b03e5Sespie #else
1578c87b03e5Sespie 	rtx errno_rtx
1579c87b03e5Sespie 	  = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
1580c87b03e5Sespie #endif
1581c87b03e5Sespie 
1582c87b03e5Sespie 	emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
1583c87b03e5Sespie       }
1584c87b03e5Sespie #else
1585c87b03e5Sespie       /* We can't set errno=EDOM directly; let the library call do it.
1586c87b03e5Sespie 	 Pop the arguments right away in case the call gets deleted.  */
1587c87b03e5Sespie       NO_DEFER_POP;
1588c87b03e5Sespie       expand_call (exp, target, 0);
1589c87b03e5Sespie       OK_DEFER_POP;
1590c87b03e5Sespie #endif
1591c87b03e5Sespie 
1592c87b03e5Sespie       emit_label (lab1);
1593c87b03e5Sespie     }
1594c87b03e5Sespie 
1595c87b03e5Sespie   /* Output the entire sequence.  */
1596c87b03e5Sespie   insns = get_insns ();
1597c87b03e5Sespie   end_sequence ();
1598c87b03e5Sespie   emit_insn (insns);
1599c87b03e5Sespie 
1600c87b03e5Sespie   return target;
1601c87b03e5Sespie }
1602c87b03e5Sespie 
1603c87b03e5Sespie /* Expand expression EXP which is a call to the strlen builtin.  Return 0
1604c87b03e5Sespie    if we failed the caller should emit a normal call, otherwise
1605c87b03e5Sespie    try to get the result in TARGET, if convenient.  */
1606c87b03e5Sespie 
1607c87b03e5Sespie static rtx
expand_builtin_strlen(exp,target)1608c87b03e5Sespie expand_builtin_strlen (exp, target)
1609c87b03e5Sespie      tree exp;
1610c87b03e5Sespie      rtx target;
1611c87b03e5Sespie {
1612c87b03e5Sespie   tree arglist = TREE_OPERAND (exp, 1);
1613c87b03e5Sespie   enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp));
1614c87b03e5Sespie 
1615c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
1616c87b03e5Sespie     return 0;
1617c87b03e5Sespie   else
1618c87b03e5Sespie     {
1619c87b03e5Sespie       rtx pat;
1620c87b03e5Sespie       tree src = TREE_VALUE (arglist);
1621c87b03e5Sespie 
1622c87b03e5Sespie       int align
1623c87b03e5Sespie 	= get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
1624c87b03e5Sespie 
1625c87b03e5Sespie       rtx result, src_reg, char_rtx, before_strlen;
1626c87b03e5Sespie       enum machine_mode insn_mode = value_mode, char_mode;
1627c87b03e5Sespie       enum insn_code icode = CODE_FOR_nothing;
1628c87b03e5Sespie 
1629c87b03e5Sespie       /* If SRC is not a pointer type, don't do this operation inline.  */
1630c87b03e5Sespie       if (align == 0)
1631c87b03e5Sespie 	return 0;
1632c87b03e5Sespie 
1633c87b03e5Sespie       /* Bail out if we can't compute strlen in the right mode.  */
1634c87b03e5Sespie       while (insn_mode != VOIDmode)
1635c87b03e5Sespie 	{
1636c87b03e5Sespie 	  icode = strlen_optab->handlers[(int) insn_mode].insn_code;
1637c87b03e5Sespie 	  if (icode != CODE_FOR_nothing)
1638c87b03e5Sespie 	    break;
1639c87b03e5Sespie 
1640c87b03e5Sespie 	  insn_mode = GET_MODE_WIDER_MODE (insn_mode);
1641c87b03e5Sespie 	}
1642c87b03e5Sespie       if (insn_mode == VOIDmode)
1643c87b03e5Sespie 	return 0;
1644c87b03e5Sespie 
1645c87b03e5Sespie       /* Make a place to write the result of the instruction.  */
1646c87b03e5Sespie       result = target;
1647c87b03e5Sespie       if (! (result != 0
1648c87b03e5Sespie 	     && GET_CODE (result) == REG
1649c87b03e5Sespie 	     && GET_MODE (result) == insn_mode
1650c87b03e5Sespie 	     && REGNO (result) >= FIRST_PSEUDO_REGISTER))
1651c87b03e5Sespie 	result = gen_reg_rtx (insn_mode);
1652c87b03e5Sespie 
1653c87b03e5Sespie       /* Make a place to hold the source address.  We will not expand
1654c87b03e5Sespie 	 the actual source until we are sure that the expansion will
1655c87b03e5Sespie 	 not fail -- there are trees that cannot be expanded twice.  */
1656c87b03e5Sespie       src_reg = gen_reg_rtx (Pmode);
1657c87b03e5Sespie 
1658c87b03e5Sespie       /* Mark the beginning of the strlen sequence so we can emit the
1659c87b03e5Sespie 	 source operand later.  */
1660c87b03e5Sespie       before_strlen = get_last_insn ();
1661c87b03e5Sespie 
1662c87b03e5Sespie       char_rtx = const0_rtx;
1663c87b03e5Sespie       char_mode = insn_data[(int) icode].operand[2].mode;
1664c87b03e5Sespie       if (! (*insn_data[(int) icode].operand[2].predicate) (char_rtx,
1665c87b03e5Sespie 							    char_mode))
1666c87b03e5Sespie 	char_rtx = copy_to_mode_reg (char_mode, char_rtx);
1667c87b03e5Sespie 
1668c87b03e5Sespie       pat = GEN_FCN (icode) (result, gen_rtx_MEM (BLKmode, src_reg),
1669c87b03e5Sespie 			     char_rtx, GEN_INT (align));
1670c87b03e5Sespie       if (! pat)
1671c87b03e5Sespie 	return 0;
1672c87b03e5Sespie       emit_insn (pat);
1673c87b03e5Sespie 
1674c87b03e5Sespie       /* Now that we are assured of success, expand the source.  */
1675c87b03e5Sespie       start_sequence ();
1676c87b03e5Sespie       pat = memory_address (BLKmode,
1677c87b03e5Sespie 			    expand_expr (src, src_reg, ptr_mode, EXPAND_SUM));
1678c87b03e5Sespie       if (pat != src_reg)
1679c87b03e5Sespie 	emit_move_insn (src_reg, pat);
1680c87b03e5Sespie       pat = get_insns ();
1681c87b03e5Sespie       end_sequence ();
1682c87b03e5Sespie 
1683c87b03e5Sespie       if (before_strlen)
1684c87b03e5Sespie 	emit_insn_after (pat, before_strlen);
1685c87b03e5Sespie       else
1686c87b03e5Sespie 	emit_insn_before (pat, get_insns ());
1687c87b03e5Sespie 
1688c87b03e5Sespie       /* Return the value in the proper mode for this function.  */
1689c87b03e5Sespie       if (GET_MODE (result) == value_mode)
1690c87b03e5Sespie 	target = result;
1691c87b03e5Sespie       else if (target != 0)
1692c87b03e5Sespie 	convert_move (target, result, 0);
1693c87b03e5Sespie       else
1694c87b03e5Sespie 	target = convert_to_mode (value_mode, result, 0);
1695c87b03e5Sespie 
1696c87b03e5Sespie       return target;
1697c87b03e5Sespie     }
1698c87b03e5Sespie }
1699c87b03e5Sespie 
1700c87b03e5Sespie /* Expand a call to the strstr builtin.  Return 0 if we failed the
1701c87b03e5Sespie    caller should emit a normal call, otherwise try to get the result
1702c87b03e5Sespie    in TARGET, if convenient (and in mode MODE if that's convenient).  */
1703c87b03e5Sespie 
1704c87b03e5Sespie static rtx
expand_builtin_strstr(arglist,target,mode)1705c87b03e5Sespie expand_builtin_strstr (arglist, target, mode)
1706c87b03e5Sespie      tree arglist;
1707c87b03e5Sespie      rtx target;
1708c87b03e5Sespie      enum machine_mode mode;
1709c87b03e5Sespie {
1710c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
1711c87b03e5Sespie     return 0;
1712c87b03e5Sespie   else
1713c87b03e5Sespie     {
1714c87b03e5Sespie       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
1715c87b03e5Sespie       tree fn;
1716c87b03e5Sespie       const char *p1, *p2;
1717c87b03e5Sespie 
1718c87b03e5Sespie       p2 = c_getstr (s2);
1719c87b03e5Sespie       if (p2 == NULL)
1720c87b03e5Sespie 	return 0;
1721c87b03e5Sespie 
1722c87b03e5Sespie       p1 = c_getstr (s1);
1723c87b03e5Sespie       if (p1 != NULL)
1724c87b03e5Sespie 	{
1725c87b03e5Sespie 	  const char *r = strstr (p1, p2);
1726c87b03e5Sespie 
1727c87b03e5Sespie 	  if (r == NULL)
1728c87b03e5Sespie 	    return const0_rtx;
1729c87b03e5Sespie 
1730c87b03e5Sespie 	  /* Return an offset into the constant string argument.  */
1731c87b03e5Sespie 	  return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
1732c87b03e5Sespie 					   s1, ssize_int (r - p1))),
1733c87b03e5Sespie 			      target, mode, EXPAND_NORMAL);
1734c87b03e5Sespie 	}
1735c87b03e5Sespie 
1736c87b03e5Sespie       if (p2[0] == '\0')
1737c87b03e5Sespie 	return expand_expr (s1, target, mode, EXPAND_NORMAL);
1738c87b03e5Sespie 
1739c87b03e5Sespie       if (p2[1] != '\0')
1740c87b03e5Sespie 	return 0;
1741c87b03e5Sespie 
1742c87b03e5Sespie       fn = built_in_decls[BUILT_IN_STRCHR];
1743c87b03e5Sespie       if (!fn)
1744c87b03e5Sespie 	return 0;
1745c87b03e5Sespie 
1746c87b03e5Sespie       /* New argument list transforming strstr(s1, s2) to
1747c87b03e5Sespie 	 strchr(s1, s2[0]).  */
1748c87b03e5Sespie       arglist =
1749c87b03e5Sespie 	build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
1750c87b03e5Sespie       arglist = tree_cons (NULL_TREE, s1, arglist);
1751c87b03e5Sespie       return expand_expr (build_function_call_expr (fn, arglist),
1752c87b03e5Sespie 			  target, mode, EXPAND_NORMAL);
1753c87b03e5Sespie     }
1754c87b03e5Sespie }
1755c87b03e5Sespie 
1756c87b03e5Sespie /* Expand a call to the strchr builtin.  Return 0 if we failed the
1757c87b03e5Sespie    caller should emit a normal call, otherwise try to get the result
1758c87b03e5Sespie    in TARGET, if convenient (and in mode MODE if that's convenient).  */
1759c87b03e5Sespie 
1760c87b03e5Sespie static rtx
expand_builtin_strchr(arglist,target,mode)1761c87b03e5Sespie expand_builtin_strchr (arglist, target, mode)
1762c87b03e5Sespie      tree arglist;
1763c87b03e5Sespie      rtx target;
1764c87b03e5Sespie      enum machine_mode mode;
1765c87b03e5Sespie {
1766c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
1767c87b03e5Sespie     return 0;
1768c87b03e5Sespie   else
1769c87b03e5Sespie     {
1770c87b03e5Sespie       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
1771c87b03e5Sespie       const char *p1;
1772c87b03e5Sespie 
1773c87b03e5Sespie       if (TREE_CODE (s2) != INTEGER_CST)
1774c87b03e5Sespie 	return 0;
1775c87b03e5Sespie 
1776c87b03e5Sespie       p1 = c_getstr (s1);
1777c87b03e5Sespie       if (p1 != NULL)
1778c87b03e5Sespie 	{
1779c87b03e5Sespie 	  char c;
1780c87b03e5Sespie 	  const char *r;
1781c87b03e5Sespie 
1782c87b03e5Sespie 	  if (target_char_cast (s2, &c))
1783c87b03e5Sespie 	    return 0;
1784c87b03e5Sespie 
1785c87b03e5Sespie 	  r = strchr (p1, c);
1786c87b03e5Sespie 
1787c87b03e5Sespie 	  if (r == NULL)
1788c87b03e5Sespie 	    return const0_rtx;
1789c87b03e5Sespie 
1790c87b03e5Sespie 	  /* Return an offset into the constant string argument.  */
1791c87b03e5Sespie 	  return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
1792c87b03e5Sespie 					   s1, ssize_int (r - p1))),
1793c87b03e5Sespie 			      target, mode, EXPAND_NORMAL);
1794c87b03e5Sespie 	}
1795c87b03e5Sespie 
1796c87b03e5Sespie       /* FIXME: Should use here strchrM optab so that ports can optimize
1797c87b03e5Sespie 	 this.  */
1798c87b03e5Sespie       return 0;
1799c87b03e5Sespie     }
1800c87b03e5Sespie }
1801c87b03e5Sespie 
1802c87b03e5Sespie /* Expand a call to the strrchr builtin.  Return 0 if we failed the
1803c87b03e5Sespie    caller should emit a normal call, otherwise try to get the result
1804c87b03e5Sespie    in TARGET, if convenient (and in mode MODE if that's convenient).  */
1805c87b03e5Sespie 
1806c87b03e5Sespie static rtx
expand_builtin_strrchr(arglist,target,mode)1807c87b03e5Sespie expand_builtin_strrchr (arglist, target, mode)
1808c87b03e5Sespie      tree arglist;
1809c87b03e5Sespie      rtx target;
1810c87b03e5Sespie      enum machine_mode mode;
1811c87b03e5Sespie {
1812c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
1813c87b03e5Sespie     return 0;
1814c87b03e5Sespie   else
1815c87b03e5Sespie     {
1816c87b03e5Sespie       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
1817c87b03e5Sespie       tree fn;
1818c87b03e5Sespie       const char *p1;
1819c87b03e5Sespie 
1820c87b03e5Sespie       if (TREE_CODE (s2) != INTEGER_CST)
1821c87b03e5Sespie 	return 0;
1822c87b03e5Sespie 
1823c87b03e5Sespie       p1 = c_getstr (s1);
1824c87b03e5Sespie       if (p1 != NULL)
1825c87b03e5Sespie 	{
1826c87b03e5Sespie 	  char c;
1827c87b03e5Sespie 	  const char *r;
1828c87b03e5Sespie 
1829c87b03e5Sespie 	  if (target_char_cast (s2, &c))
1830c87b03e5Sespie 	    return 0;
1831c87b03e5Sespie 
1832c87b03e5Sespie 	  r = strrchr (p1, c);
1833c87b03e5Sespie 
1834c87b03e5Sespie 	  if (r == NULL)
1835c87b03e5Sespie 	    return const0_rtx;
1836c87b03e5Sespie 
1837c87b03e5Sespie 	  /* Return an offset into the constant string argument.  */
1838c87b03e5Sespie 	  return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
1839c87b03e5Sespie 					   s1, ssize_int (r - p1))),
1840c87b03e5Sespie 			      target, mode, EXPAND_NORMAL);
1841c87b03e5Sespie 	}
1842c87b03e5Sespie 
1843c87b03e5Sespie       if (! integer_zerop (s2))
1844c87b03e5Sespie 	return 0;
1845c87b03e5Sespie 
1846c87b03e5Sespie       fn = built_in_decls[BUILT_IN_STRCHR];
1847c87b03e5Sespie       if (!fn)
1848c87b03e5Sespie 	return 0;
1849c87b03e5Sespie 
1850c87b03e5Sespie       /* Transform strrchr(s1, '\0') to strchr(s1, '\0').  */
1851c87b03e5Sespie       return expand_expr (build_function_call_expr (fn, arglist),
1852c87b03e5Sespie 			  target, mode, EXPAND_NORMAL);
1853c87b03e5Sespie     }
1854c87b03e5Sespie }
1855c87b03e5Sespie 
1856c87b03e5Sespie /* Expand a call to the strpbrk builtin.  Return 0 if we failed the
1857c87b03e5Sespie    caller should emit a normal call, otherwise try to get the result
1858c87b03e5Sespie    in TARGET, if convenient (and in mode MODE if that's convenient).  */
1859c87b03e5Sespie 
1860c87b03e5Sespie static rtx
expand_builtin_strpbrk(arglist,target,mode)1861c87b03e5Sespie expand_builtin_strpbrk (arglist, target, mode)
1862c87b03e5Sespie      tree arglist;
1863c87b03e5Sespie      rtx target;
1864c87b03e5Sespie      enum machine_mode mode;
1865c87b03e5Sespie {
1866c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
1867c87b03e5Sespie     return 0;
1868c87b03e5Sespie   else
1869c87b03e5Sespie     {
1870c87b03e5Sespie       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
1871c87b03e5Sespie       tree fn;
1872c87b03e5Sespie       const char *p1, *p2;
1873c87b03e5Sespie 
1874c87b03e5Sespie       p2 = c_getstr (s2);
1875c87b03e5Sespie       if (p2 == NULL)
1876c87b03e5Sespie 	return 0;
1877c87b03e5Sespie 
1878c87b03e5Sespie       p1 = c_getstr (s1);
1879c87b03e5Sespie       if (p1 != NULL)
1880c87b03e5Sespie 	{
1881c87b03e5Sespie 	  const char *r = strpbrk (p1, p2);
1882c87b03e5Sespie 
1883c87b03e5Sespie 	  if (r == NULL)
1884c87b03e5Sespie 	    return const0_rtx;
1885c87b03e5Sespie 
1886c87b03e5Sespie 	  /* Return an offset into the constant string argument.  */
1887c87b03e5Sespie 	  return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
1888c87b03e5Sespie 					   s1, ssize_int (r - p1))),
1889c87b03e5Sespie 			      target, mode, EXPAND_NORMAL);
1890c87b03e5Sespie 	}
1891c87b03e5Sespie 
1892c87b03e5Sespie       if (p2[0] == '\0')
1893c87b03e5Sespie 	{
1894c87b03e5Sespie 	  /* strpbrk(x, "") == NULL.
1895c87b03e5Sespie 	     Evaluate and ignore the arguments in case they had
1896c87b03e5Sespie 	     side-effects.  */
1897c87b03e5Sespie 	  expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
1898c87b03e5Sespie 	  return const0_rtx;
1899c87b03e5Sespie 	}
1900c87b03e5Sespie 
1901c87b03e5Sespie       if (p2[1] != '\0')
1902c87b03e5Sespie 	return 0;  /* Really call strpbrk.  */
1903c87b03e5Sespie 
1904c87b03e5Sespie       fn = built_in_decls[BUILT_IN_STRCHR];
1905c87b03e5Sespie       if (!fn)
1906c87b03e5Sespie 	return 0;
1907c87b03e5Sespie 
1908c87b03e5Sespie       /* New argument list transforming strpbrk(s1, s2) to
1909c87b03e5Sespie 	 strchr(s1, s2[0]).  */
1910c87b03e5Sespie       arglist =
1911c87b03e5Sespie 	build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
1912c87b03e5Sespie       arglist = tree_cons (NULL_TREE, s1, arglist);
1913c87b03e5Sespie       return expand_expr (build_function_call_expr (fn, arglist),
1914c87b03e5Sespie 			  target, mode, EXPAND_NORMAL);
1915c87b03e5Sespie     }
1916c87b03e5Sespie }
1917c87b03e5Sespie 
1918c87b03e5Sespie /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
1919c87b03e5Sespie    bytes from constant string DATA + OFFSET and return it as target
1920c87b03e5Sespie    constant.  */
1921c87b03e5Sespie 
1922c87b03e5Sespie static rtx
builtin_memcpy_read_str(data,offset,mode)1923c87b03e5Sespie builtin_memcpy_read_str (data, offset, mode)
1924c87b03e5Sespie      PTR data;
1925c87b03e5Sespie      HOST_WIDE_INT offset;
1926c87b03e5Sespie      enum machine_mode mode;
1927c87b03e5Sespie {
1928c87b03e5Sespie   const char *str = (const char *) data;
1929c87b03e5Sespie 
1930c87b03e5Sespie   if (offset < 0
1931c87b03e5Sespie       || ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode)
1932c87b03e5Sespie 	  > strlen (str) + 1))
1933c87b03e5Sespie     abort ();  /* Attempt to read past the end of constant string.  */
1934c87b03e5Sespie 
1935c87b03e5Sespie   return c_readstr (str + offset, mode);
1936c87b03e5Sespie }
1937c87b03e5Sespie 
1938c87b03e5Sespie /* Expand a call to the memcpy builtin, with arguments in ARGLIST.
1939c87b03e5Sespie    Return 0 if we failed, the caller should emit a normal call, otherwise
1940c87b03e5Sespie    try to get the result in TARGET, if convenient (and in mode MODE if
1941c87b03e5Sespie    that's convenient).  */
1942c87b03e5Sespie 
1943c87b03e5Sespie static rtx
expand_builtin_memcpy(arglist,target,mode)1944c87b03e5Sespie expand_builtin_memcpy (arglist, target, mode)
1945c87b03e5Sespie      tree arglist;
1946c87b03e5Sespie      rtx target;
1947c87b03e5Sespie      enum machine_mode mode;
1948c87b03e5Sespie {
1949c87b03e5Sespie   if (!validate_arglist (arglist,
1950c87b03e5Sespie 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
1951c87b03e5Sespie     return 0;
1952c87b03e5Sespie   else
1953c87b03e5Sespie     {
1954c87b03e5Sespie       tree dest = TREE_VALUE (arglist);
1955c87b03e5Sespie       tree src = TREE_VALUE (TREE_CHAIN (arglist));
1956c87b03e5Sespie       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
1957c87b03e5Sespie       const char *src_str;
1958c87b03e5Sespie 
1959c87b03e5Sespie       unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
1960c87b03e5Sespie       unsigned int dest_align
1961c87b03e5Sespie 	= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
1962c87b03e5Sespie       rtx dest_mem, src_mem, dest_addr, len_rtx;
1963c87b03e5Sespie 
1964c87b03e5Sespie       /* If DEST is not a pointer type, call the normal function.  */
1965c87b03e5Sespie       if (dest_align == 0)
1966c87b03e5Sespie 	return 0;
1967c87b03e5Sespie 
1968c87b03e5Sespie       /* If the LEN parameter is zero, return DEST.  */
1969c87b03e5Sespie       if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
1970c87b03e5Sespie 	{
1971c87b03e5Sespie 	  /* Evaluate and ignore SRC in case it has side-effects.  */
1972c87b03e5Sespie 	  expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
1973c87b03e5Sespie 	  return expand_expr (dest, target, mode, EXPAND_NORMAL);
1974c87b03e5Sespie 	}
1975c87b03e5Sespie 
1976c87b03e5Sespie       /* If either SRC is not a pointer type, don't do this
1977c87b03e5Sespie          operation in-line.  */
1978c87b03e5Sespie       if (src_align == 0)
1979c87b03e5Sespie 	return 0;
1980c87b03e5Sespie 
1981c87b03e5Sespie       dest_mem = get_memory_rtx (dest);
1982c87b03e5Sespie       set_mem_align (dest_mem, dest_align);
1983c87b03e5Sespie       len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
1984c87b03e5Sespie       src_str = c_getstr (src);
1985c87b03e5Sespie 
1986c87b03e5Sespie       /* If SRC is a string constant and block move would be done
1987c87b03e5Sespie 	 by pieces, we can avoid loading the string from memory
1988c87b03e5Sespie 	 and only stored the computed constants.  */
1989c87b03e5Sespie       if (src_str
1990c87b03e5Sespie 	  && GET_CODE (len_rtx) == CONST_INT
1991c87b03e5Sespie 	  && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
1992c87b03e5Sespie 	  && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
1993c87b03e5Sespie 				  (PTR) src_str, dest_align))
1994c87b03e5Sespie 	{
1995c87b03e5Sespie 	  store_by_pieces (dest_mem, INTVAL (len_rtx),
1996c87b03e5Sespie 			   builtin_memcpy_read_str,
1997c87b03e5Sespie 			   (PTR) src_str, dest_align);
1998c87b03e5Sespie 	  dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
1999c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
2000c87b03e5Sespie 	  if (GET_MODE (dest_mem) != ptr_mode)
2001c87b03e5Sespie 	    dest_mem = convert_memory_address (ptr_mode, dest_mem);
2002c87b03e5Sespie #endif
2003c87b03e5Sespie 	  return dest_mem;
2004c87b03e5Sespie 	}
2005c87b03e5Sespie 
2006c87b03e5Sespie       src_mem = get_memory_rtx (src);
2007c87b03e5Sespie       set_mem_align (src_mem, src_align);
2008c87b03e5Sespie 
2009c87b03e5Sespie       /* Copy word part most expediently.  */
2010c87b03e5Sespie       dest_addr = emit_block_move (dest_mem, src_mem, len_rtx,
2011c87b03e5Sespie 				   BLOCK_OP_NORMAL);
2012c87b03e5Sespie 
2013c87b03e5Sespie       if (dest_addr == 0)
2014c87b03e5Sespie 	{
2015c87b03e5Sespie 	  dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
2016c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
2017c87b03e5Sespie 	  if (GET_MODE (dest_addr) != ptr_mode)
2018c87b03e5Sespie 	    dest_addr = convert_memory_address (ptr_mode, dest_addr);
2019c87b03e5Sespie #endif
2020c87b03e5Sespie 	}
2021c87b03e5Sespie 
2022c87b03e5Sespie       return dest_addr;
2023c87b03e5Sespie     }
2024c87b03e5Sespie }
2025c87b03e5Sespie 
2026c87b03e5Sespie /* Expand expression EXP, which is a call to the strcpy builtin.  Return 0
2027c87b03e5Sespie    if we failed the caller should emit a normal call, otherwise try to get
2028c87b03e5Sespie    the result in TARGET, if convenient (and in mode MODE if that's
2029c87b03e5Sespie    convenient).  */
2030c87b03e5Sespie 
2031c87b03e5Sespie static rtx
expand_builtin_strcpy(exp,target,mode)2032c87b03e5Sespie expand_builtin_strcpy (exp, target, mode)
2033c87b03e5Sespie      tree exp;
2034c87b03e5Sespie      rtx target;
2035c87b03e5Sespie      enum machine_mode mode;
2036c87b03e5Sespie {
2037c87b03e5Sespie   tree arglist = TREE_OPERAND (exp, 1);
2038c87b03e5Sespie   tree fn, len, src, dst;
2039c87b03e5Sespie 
2040c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
2041c87b03e5Sespie     return 0;
2042c87b03e5Sespie 
2043c87b03e5Sespie   fn = built_in_decls[BUILT_IN_MEMCPY];
2044c87b03e5Sespie   if (!fn)
2045c87b03e5Sespie     return 0;
2046c87b03e5Sespie 
2047c87b03e5Sespie   src = TREE_VALUE (TREE_CHAIN (arglist));
2048c87b03e5Sespie   len = c_strlen (src);
2049c87b03e5Sespie   if (len == 0 || TREE_SIDE_EFFECTS (len))
2050c87b03e5Sespie     return 0;
2051c87b03e5Sespie 
2052c87b03e5Sespie   dst = TREE_VALUE (arglist);
2053c87b03e5Sespie   len = size_binop (PLUS_EXPR, len, ssize_int (1));
2054c87b03e5Sespie   arglist = build_tree_list (NULL_TREE, len);
2055c87b03e5Sespie   arglist = tree_cons (NULL_TREE, src, arglist);
2056c87b03e5Sespie   arglist = tree_cons (NULL_TREE, dst, arglist);
2057c87b03e5Sespie   return expand_expr (build_function_call_expr (fn, arglist),
2058c87b03e5Sespie 		      target, mode, EXPAND_NORMAL);
2059c87b03e5Sespie }
2060c87b03e5Sespie 
2061c87b03e5Sespie /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
2062c87b03e5Sespie    bytes from constant string DATA + OFFSET and return it as target
2063c87b03e5Sespie    constant.  */
2064c87b03e5Sespie 
2065c87b03e5Sespie static rtx
builtin_strncpy_read_str(data,offset,mode)2066c87b03e5Sespie builtin_strncpy_read_str (data, offset, mode)
2067c87b03e5Sespie      PTR data;
2068c87b03e5Sespie      HOST_WIDE_INT offset;
2069c87b03e5Sespie      enum machine_mode mode;
2070c87b03e5Sespie {
2071c87b03e5Sespie   const char *str = (const char *) data;
2072c87b03e5Sespie 
2073c87b03e5Sespie   if ((unsigned HOST_WIDE_INT) offset > strlen (str))
2074c87b03e5Sespie     return const0_rtx;
2075c87b03e5Sespie 
2076c87b03e5Sespie   return c_readstr (str + offset, mode);
2077c87b03e5Sespie }
2078c87b03e5Sespie 
2079c87b03e5Sespie /* Expand expression EXP, which is a call to the strncpy builtin.  Return 0
2080c87b03e5Sespie    if we failed the caller should emit a normal call.  */
2081c87b03e5Sespie 
2082c87b03e5Sespie static rtx
expand_builtin_strncpy(arglist,target,mode)2083c87b03e5Sespie expand_builtin_strncpy (arglist, target, mode)
2084c87b03e5Sespie      tree arglist;
2085c87b03e5Sespie      rtx target;
2086c87b03e5Sespie      enum machine_mode mode;
2087c87b03e5Sespie {
2088c87b03e5Sespie   if (!validate_arglist (arglist,
2089c87b03e5Sespie 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
2090c87b03e5Sespie     return 0;
2091c87b03e5Sespie   else
2092c87b03e5Sespie     {
2093c87b03e5Sespie       tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
2094c87b03e5Sespie       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
2095c87b03e5Sespie       tree fn;
2096c87b03e5Sespie 
2097c87b03e5Sespie       /* We must be passed a constant len parameter.  */
2098c87b03e5Sespie       if (TREE_CODE (len) != INTEGER_CST)
2099c87b03e5Sespie 	return 0;
2100c87b03e5Sespie 
2101c87b03e5Sespie       /* If the len parameter is zero, return the dst parameter.  */
2102c87b03e5Sespie       if (integer_zerop (len))
2103c87b03e5Sespie 	{
2104c87b03e5Sespie 	  /* Evaluate and ignore the src argument in case it has
2105c87b03e5Sespie 	     side-effects.  */
2106c87b03e5Sespie 	  expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx,
2107c87b03e5Sespie 		       VOIDmode, EXPAND_NORMAL);
2108c87b03e5Sespie 	  /* Return the dst parameter.  */
2109c87b03e5Sespie 	  return expand_expr (TREE_VALUE (arglist), target, mode,
2110c87b03e5Sespie 			      EXPAND_NORMAL);
2111c87b03e5Sespie 	}
2112c87b03e5Sespie 
2113c87b03e5Sespie       /* Now, we must be passed a constant src ptr parameter.  */
2114c87b03e5Sespie       if (slen == 0 || TREE_CODE (slen) != INTEGER_CST)
2115c87b03e5Sespie 	return 0;
2116c87b03e5Sespie 
2117c87b03e5Sespie       slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
2118c87b03e5Sespie 
2119c87b03e5Sespie       /* We're required to pad with trailing zeros if the requested
2120c87b03e5Sespie          len is greater than strlen(s2)+1.  In that case try to
2121c87b03e5Sespie 	 use store_by_pieces, if it fails, punt.  */
2122c87b03e5Sespie       if (tree_int_cst_lt (slen, len))
2123c87b03e5Sespie 	{
2124c87b03e5Sespie 	  tree dest = TREE_VALUE (arglist);
2125c87b03e5Sespie 	  unsigned int dest_align
2126c87b03e5Sespie 	    = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
2127c87b03e5Sespie 	  const char *p = c_getstr (TREE_VALUE (TREE_CHAIN (arglist)));
2128c87b03e5Sespie 	  rtx dest_mem;
2129c87b03e5Sespie 
2130c87b03e5Sespie 	  if (!p || dest_align == 0 || !host_integerp (len, 1)
2131c87b03e5Sespie 	      || !can_store_by_pieces (tree_low_cst (len, 1),
2132c87b03e5Sespie 				       builtin_strncpy_read_str,
2133c87b03e5Sespie 				       (PTR) p, dest_align))
2134c87b03e5Sespie 	    return 0;
2135c87b03e5Sespie 
2136c87b03e5Sespie 	  dest_mem = get_memory_rtx (dest);
2137c87b03e5Sespie 	  store_by_pieces (dest_mem, tree_low_cst (len, 1),
2138c87b03e5Sespie 			   builtin_strncpy_read_str,
2139c87b03e5Sespie 			   (PTR) p, dest_align);
2140c87b03e5Sespie 	  dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
2141c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
2142c87b03e5Sespie 	  if (GET_MODE (dest_mem) != ptr_mode)
2143c87b03e5Sespie 	    dest_mem = convert_memory_address (ptr_mode, dest_mem);
2144c87b03e5Sespie #endif
2145c87b03e5Sespie 	  return dest_mem;
2146c87b03e5Sespie 	}
2147c87b03e5Sespie 
2148c87b03e5Sespie       /* OK transform into builtin memcpy.  */
2149c87b03e5Sespie       fn = built_in_decls[BUILT_IN_MEMCPY];
2150c87b03e5Sespie       if (!fn)
2151c87b03e5Sespie 	return 0;
2152c87b03e5Sespie       return expand_expr (build_function_call_expr (fn, arglist),
2153c87b03e5Sespie 			  target, mode, EXPAND_NORMAL);
2154c87b03e5Sespie     }
2155c87b03e5Sespie }
2156c87b03e5Sespie 
2157c87b03e5Sespie /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
2158c87b03e5Sespie    bytes from constant string DATA + OFFSET and return it as target
2159c87b03e5Sespie    constant.  */
2160c87b03e5Sespie 
2161c87b03e5Sespie static rtx
builtin_memset_read_str(data,offset,mode)2162c87b03e5Sespie builtin_memset_read_str (data, offset, mode)
2163c87b03e5Sespie      PTR data;
2164c87b03e5Sespie      HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
2165c87b03e5Sespie      enum machine_mode mode;
2166c87b03e5Sespie {
2167c87b03e5Sespie   const char *c = (const char *) data;
2168c87b03e5Sespie   char *p = alloca (GET_MODE_SIZE (mode));
2169c87b03e5Sespie 
2170c87b03e5Sespie   memset (p, *c, GET_MODE_SIZE (mode));
2171c87b03e5Sespie 
2172c87b03e5Sespie   return c_readstr (p, mode);
2173c87b03e5Sespie }
2174c87b03e5Sespie 
2175c87b03e5Sespie /* Callback routine for store_by_pieces.  Return the RTL of a register
2176c87b03e5Sespie    containing GET_MODE_SIZE (MODE) consecutive copies of the unsigned
2177c87b03e5Sespie    char value given in the RTL register data.  For example, if mode is
2178c87b03e5Sespie    4 bytes wide, return the RTL for 0x01010101*data.  */
2179c87b03e5Sespie 
2180c87b03e5Sespie static rtx
builtin_memset_gen_str(data,offset,mode)2181c87b03e5Sespie builtin_memset_gen_str (data, offset, mode)
2182c87b03e5Sespie      PTR data;
2183c87b03e5Sespie      HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
2184c87b03e5Sespie      enum machine_mode mode;
2185c87b03e5Sespie {
2186c87b03e5Sespie   rtx target, coeff;
2187c87b03e5Sespie   size_t size;
2188c87b03e5Sespie   char *p;
2189c87b03e5Sespie 
2190c87b03e5Sespie   size = GET_MODE_SIZE (mode);
2191c87b03e5Sespie   if (size == 1)
2192c87b03e5Sespie     return (rtx) data;
2193c87b03e5Sespie 
2194c87b03e5Sespie   p = alloca (size);
2195c87b03e5Sespie   memset (p, 1, size);
2196c87b03e5Sespie   coeff = c_readstr (p, mode);
2197c87b03e5Sespie 
2198c87b03e5Sespie   target = convert_to_mode (mode, (rtx) data, 1);
2199c87b03e5Sespie   target = expand_mult (mode, target, coeff, NULL_RTX, 1);
2200c87b03e5Sespie   return force_reg (mode, target);
2201c87b03e5Sespie }
2202c87b03e5Sespie 
2203c87b03e5Sespie /* Expand expression EXP, which is a call to the memset builtin.  Return 0
2204c87b03e5Sespie    if we failed the caller should emit a normal call, otherwise try to get
2205c87b03e5Sespie    the result in TARGET, if convenient (and in mode MODE if that's
2206c87b03e5Sespie    convenient).  */
2207c87b03e5Sespie 
2208c87b03e5Sespie static rtx
expand_builtin_memset(exp,target,mode)2209c87b03e5Sespie expand_builtin_memset (exp, target, mode)
2210c87b03e5Sespie      tree exp;
2211c87b03e5Sespie      rtx target;
2212c87b03e5Sespie      enum machine_mode mode;
2213c87b03e5Sespie {
2214c87b03e5Sespie   tree arglist = TREE_OPERAND (exp, 1);
2215c87b03e5Sespie 
2216c87b03e5Sespie   if (!validate_arglist (arglist,
2217c87b03e5Sespie 			 POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
2218c87b03e5Sespie     return 0;
2219c87b03e5Sespie   else
2220c87b03e5Sespie     {
2221c87b03e5Sespie       tree dest = TREE_VALUE (arglist);
2222c87b03e5Sespie       tree val = TREE_VALUE (TREE_CHAIN (arglist));
2223c87b03e5Sespie       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
2224c87b03e5Sespie       char c;
2225c87b03e5Sespie 
2226c87b03e5Sespie       unsigned int dest_align
2227c87b03e5Sespie 	= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
2228c87b03e5Sespie       rtx dest_mem, dest_addr, len_rtx;
2229c87b03e5Sespie 
2230c87b03e5Sespie       /* If DEST is not a pointer type, don't do this
2231c87b03e5Sespie 	 operation in-line.  */
2232c87b03e5Sespie       if (dest_align == 0)
2233c87b03e5Sespie 	return 0;
2234c87b03e5Sespie 
2235c87b03e5Sespie       /* If the LEN parameter is zero, return DEST.  */
2236c87b03e5Sespie       if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
2237c87b03e5Sespie 	{
2238c87b03e5Sespie 	  /* Evaluate and ignore VAL in case it has side-effects.  */
2239c87b03e5Sespie 	  expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL);
2240c87b03e5Sespie 	  return expand_expr (dest, target, mode, EXPAND_NORMAL);
2241c87b03e5Sespie 	}
2242c87b03e5Sespie 
2243c87b03e5Sespie       if (TREE_CODE (val) != INTEGER_CST)
2244c87b03e5Sespie 	{
2245c87b03e5Sespie 	  rtx val_rtx;
2246c87b03e5Sespie 
2247c87b03e5Sespie 	  if (!host_integerp (len, 1))
2248c87b03e5Sespie 	    return 0;
2249c87b03e5Sespie 
2250c87b03e5Sespie 	  if (optimize_size && tree_low_cst (len, 1) > 1)
2251c87b03e5Sespie 	    return 0;
2252c87b03e5Sespie 
2253c87b03e5Sespie 	  /* Assume that we can memset by pieces if we can store the
2254c87b03e5Sespie 	   * the coefficients by pieces (in the required modes).
2255c87b03e5Sespie 	   * We can't pass builtin_memset_gen_str as that emits RTL.  */
2256c87b03e5Sespie 	  c = 1;
2257c87b03e5Sespie 	  if (!can_store_by_pieces (tree_low_cst (len, 1),
2258c87b03e5Sespie 				    builtin_memset_read_str,
2259c87b03e5Sespie 				    (PTR) &c, dest_align))
2260c87b03e5Sespie 	    return 0;
2261c87b03e5Sespie 
2262c87b03e5Sespie 	  val = fold (build1 (CONVERT_EXPR, unsigned_char_type_node, val));
2263c87b03e5Sespie 	  val_rtx = expand_expr (val, NULL_RTX, VOIDmode, 0);
2264c87b03e5Sespie 	  val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
2265c87b03e5Sespie 			       val_rtx);
2266c87b03e5Sespie 	  dest_mem = get_memory_rtx (dest);
2267c87b03e5Sespie 	  store_by_pieces (dest_mem, tree_low_cst (len, 1),
2268c87b03e5Sespie 			   builtin_memset_gen_str,
2269c87b03e5Sespie 			   (PTR) val_rtx, dest_align);
2270c87b03e5Sespie 	  dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
2271c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
2272c87b03e5Sespie 	  if (GET_MODE (dest_mem) != ptr_mode)
2273c87b03e5Sespie 	    dest_mem = convert_memory_address (ptr_mode, dest_mem);
2274c87b03e5Sespie #endif
2275c87b03e5Sespie 	  return dest_mem;
2276c87b03e5Sespie 	}
2277c87b03e5Sespie 
2278c87b03e5Sespie       if (target_char_cast (val, &c))
2279c87b03e5Sespie 	return 0;
2280c87b03e5Sespie 
2281c87b03e5Sespie       if (c)
2282c87b03e5Sespie 	{
2283c87b03e5Sespie 	  if (!host_integerp (len, 1))
2284c87b03e5Sespie 	    return 0;
2285c87b03e5Sespie 	  if (!can_store_by_pieces (tree_low_cst (len, 1),
2286c87b03e5Sespie 				    builtin_memset_read_str, (PTR) &c,
2287c87b03e5Sespie 				    dest_align))
2288c87b03e5Sespie 	    return 0;
2289c87b03e5Sespie 
2290c87b03e5Sespie 	  dest_mem = get_memory_rtx (dest);
2291c87b03e5Sespie 	  store_by_pieces (dest_mem, tree_low_cst (len, 1),
2292c87b03e5Sespie 			   builtin_memset_read_str,
2293c87b03e5Sespie 			   (PTR) &c, dest_align);
2294c87b03e5Sespie 	  dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
2295c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
2296c87b03e5Sespie 	  if (GET_MODE (dest_mem) != ptr_mode)
2297c87b03e5Sespie 	    dest_mem = convert_memory_address (ptr_mode, dest_mem);
2298c87b03e5Sespie #endif
2299c87b03e5Sespie 	  return dest_mem;
2300c87b03e5Sespie 	}
2301c87b03e5Sespie 
2302c87b03e5Sespie       len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
2303c87b03e5Sespie 
2304c87b03e5Sespie       dest_mem = get_memory_rtx (dest);
2305c87b03e5Sespie       set_mem_align (dest_mem, dest_align);
2306c87b03e5Sespie       dest_addr = clear_storage (dest_mem, len_rtx);
2307c87b03e5Sespie 
2308c87b03e5Sespie       if (dest_addr == 0)
2309c87b03e5Sespie 	{
2310c87b03e5Sespie 	  dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
2311c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
2312c87b03e5Sespie 	  if (GET_MODE (dest_addr) != ptr_mode)
2313c87b03e5Sespie 	    dest_addr = convert_memory_address (ptr_mode, dest_addr);
2314c87b03e5Sespie #endif
2315c87b03e5Sespie 	}
2316c87b03e5Sespie 
2317c87b03e5Sespie       return dest_addr;
2318c87b03e5Sespie     }
2319c87b03e5Sespie }
2320c87b03e5Sespie 
2321c87b03e5Sespie /* Expand expression EXP, which is a call to the bzero builtin.  Return 0
2322c87b03e5Sespie    if we failed the caller should emit a normal call.  */
2323c87b03e5Sespie 
2324c87b03e5Sespie static rtx
expand_builtin_bzero(exp)2325c87b03e5Sespie expand_builtin_bzero (exp)
2326c87b03e5Sespie      tree exp;
2327c87b03e5Sespie {
2328c87b03e5Sespie   tree arglist = TREE_OPERAND (exp, 1);
2329c87b03e5Sespie   tree dest, size, newarglist;
2330c87b03e5Sespie   rtx result;
2331c87b03e5Sespie 
2332c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
2333c87b03e5Sespie     return NULL_RTX;
2334c87b03e5Sespie 
2335c87b03e5Sespie   dest = TREE_VALUE (arglist);
2336c87b03e5Sespie   size = TREE_VALUE (TREE_CHAIN (arglist));
2337c87b03e5Sespie 
2338c87b03e5Sespie   /* New argument list transforming bzero(ptr x, int y) to
2339c87b03e5Sespie      memset(ptr x, int 0, size_t y).   This is done this way
2340c87b03e5Sespie      so that if it isn't expanded inline, we fallback to
2341c87b03e5Sespie      calling bzero instead of memset.  */
2342c87b03e5Sespie 
2343c87b03e5Sespie   newarglist = build_tree_list (NULL_TREE, convert (sizetype, size));
2344c87b03e5Sespie   newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
2345c87b03e5Sespie   newarglist = tree_cons (NULL_TREE, dest, newarglist);
2346c87b03e5Sespie 
2347c87b03e5Sespie   TREE_OPERAND (exp, 1) = newarglist;
2348c87b03e5Sespie   result = expand_builtin_memset (exp, const0_rtx, VOIDmode);
2349c87b03e5Sespie 
2350c87b03e5Sespie   /* Always restore the original arguments.  */
2351c87b03e5Sespie   TREE_OPERAND (exp, 1) = arglist;
2352c87b03e5Sespie 
2353c87b03e5Sespie   return result;
2354c87b03e5Sespie }
2355c87b03e5Sespie 
2356*06dc6460Sespie /* Expand expression EXP, which is a call to the memcmp built-in function.
2357c87b03e5Sespie    ARGLIST is the argument list for this call.  Return 0 if we failed and the
2358c87b03e5Sespie    caller should emit a normal call, otherwise try to get the result in
2359c87b03e5Sespie    TARGET, if convenient (and in mode MODE, if that's convenient).  */
2360c87b03e5Sespie 
2361c87b03e5Sespie static rtx
expand_builtin_memcmp(exp,arglist,target,mode)2362c87b03e5Sespie expand_builtin_memcmp (exp, arglist, target, mode)
2363c87b03e5Sespie      tree exp ATTRIBUTE_UNUSED;
2364c87b03e5Sespie      tree arglist;
2365c87b03e5Sespie      rtx target;
2366c87b03e5Sespie      enum machine_mode mode;
2367c87b03e5Sespie {
2368c87b03e5Sespie   tree arg1, arg2, len;
2369c87b03e5Sespie   const char *p1, *p2;
2370c87b03e5Sespie 
2371c87b03e5Sespie   if (!validate_arglist (arglist,
2372c87b03e5Sespie 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
2373c87b03e5Sespie     return 0;
2374c87b03e5Sespie 
2375c87b03e5Sespie   arg1 = TREE_VALUE (arglist);
2376c87b03e5Sespie   arg2 = TREE_VALUE (TREE_CHAIN (arglist));
2377c87b03e5Sespie   len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
2378c87b03e5Sespie 
2379c87b03e5Sespie   /* If the len parameter is zero, return zero.  */
2380c87b03e5Sespie   if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
2381c87b03e5Sespie     {
2382c87b03e5Sespie       /* Evaluate and ignore arg1 and arg2 in case they have
2383c87b03e5Sespie          side-effects.  */
2384c87b03e5Sespie       expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
2385c87b03e5Sespie       expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
2386c87b03e5Sespie       return const0_rtx;
2387c87b03e5Sespie     }
2388c87b03e5Sespie 
2389c87b03e5Sespie   p1 = c_getstr (arg1);
2390c87b03e5Sespie   p2 = c_getstr (arg2);
2391c87b03e5Sespie 
2392c87b03e5Sespie   /* If all arguments are constant, and the value of len is not greater
2393c87b03e5Sespie      than the lengths of arg1 and arg2, evaluate at compile-time.  */
2394c87b03e5Sespie   if (host_integerp (len, 1) && p1 && p2
2395c87b03e5Sespie       && compare_tree_int (len, strlen (p1) + 1) <= 0
2396c87b03e5Sespie       && compare_tree_int (len, strlen (p2) + 1) <= 0)
2397c87b03e5Sespie     {
2398c87b03e5Sespie       const int r = memcmp (p1, p2, tree_low_cst (len, 1));
2399c87b03e5Sespie 
2400c87b03e5Sespie       return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
2401c87b03e5Sespie     }
2402c87b03e5Sespie 
2403c87b03e5Sespie   /* If len parameter is one, return an expression corresponding to
2404c87b03e5Sespie      (*(const unsigned char*)arg1 - (const unsigned char*)arg2).  */
2405c87b03e5Sespie   if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
2406c87b03e5Sespie     {
2407c87b03e5Sespie       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
2408c87b03e5Sespie       tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
2409c87b03e5Sespie       tree ind1 =
2410c87b03e5Sespie       fold (build1 (CONVERT_EXPR, integer_type_node,
2411c87b03e5Sespie 		    build1 (INDIRECT_REF, cst_uchar_node,
2412c87b03e5Sespie 			    build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
2413c87b03e5Sespie       tree ind2 =
2414c87b03e5Sespie       fold (build1 (CONVERT_EXPR, integer_type_node,
2415c87b03e5Sespie 		    build1 (INDIRECT_REF, cst_uchar_node,
2416c87b03e5Sespie 			    build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
2417c87b03e5Sespie       tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
2418c87b03e5Sespie       return expand_expr (result, target, mode, EXPAND_NORMAL);
2419c87b03e5Sespie     }
2420c87b03e5Sespie 
2421*06dc6460Sespie #if defined HAVE_cmpmemsi || defined HAVE_cmpstrsi
2422c87b03e5Sespie   {
2423c87b03e5Sespie     rtx arg1_rtx, arg2_rtx, arg3_rtx;
2424c87b03e5Sespie     rtx result;
2425c87b03e5Sespie     rtx insn;
2426c87b03e5Sespie 
2427c87b03e5Sespie     int arg1_align
2428c87b03e5Sespie       = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
2429c87b03e5Sespie     int arg2_align
2430c87b03e5Sespie       = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
2431*06dc6460Sespie     enum machine_mode insn_mode;
2432*06dc6460Sespie 
2433*06dc6460Sespie #ifdef HAVE_cmpmemsi
2434*06dc6460Sespie     if (HAVE_cmpmemsi)
2435*06dc6460Sespie       insn_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode;
2436*06dc6460Sespie     else
2437*06dc6460Sespie #endif
2438*06dc6460Sespie #ifdef HAVE_cmpstrsi
2439*06dc6460Sespie     if (HAVE_cmpstrsi)
2440*06dc6460Sespie       insn_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
2441*06dc6460Sespie     else
2442*06dc6460Sespie #endif
2443*06dc6460Sespie       return 0;
2444c87b03e5Sespie 
2445c87b03e5Sespie     /* If we don't have POINTER_TYPE, call the function.  */
2446c87b03e5Sespie     if (arg1_align == 0 || arg2_align == 0)
2447c87b03e5Sespie       return 0;
2448c87b03e5Sespie 
2449c87b03e5Sespie     /* Make a place to write the result of the instruction.  */
2450c87b03e5Sespie     result = target;
2451c87b03e5Sespie     if (! (result != 0
2452c87b03e5Sespie 	   && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
2453c87b03e5Sespie 	   && REGNO (result) >= FIRST_PSEUDO_REGISTER))
2454c87b03e5Sespie       result = gen_reg_rtx (insn_mode);
2455c87b03e5Sespie 
2456c87b03e5Sespie     arg1_rtx = get_memory_rtx (arg1);
2457c87b03e5Sespie     arg2_rtx = get_memory_rtx (arg2);
2458c87b03e5Sespie     arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
2459*06dc6460Sespie #ifdef HAVE_cmpmemsi
2460*06dc6460Sespie     if (HAVE_cmpmemsi)
2461*06dc6460Sespie       insn = gen_cmpmemsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
2462*06dc6460Sespie 			   GEN_INT (MIN (arg1_align, arg2_align)));
2463c87b03e5Sespie     else
2464*06dc6460Sespie #endif
2465*06dc6460Sespie #ifdef HAVE_cmpstrsi
2466*06dc6460Sespie     if (HAVE_cmpstrsi)
2467c87b03e5Sespie       insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
2468c87b03e5Sespie 			   GEN_INT (MIN (arg1_align, arg2_align)));
2469*06dc6460Sespie     else
2470*06dc6460Sespie #endif
2471*06dc6460Sespie       abort ();
2472c87b03e5Sespie 
2473c87b03e5Sespie     if (insn)
2474c87b03e5Sespie       emit_insn (insn);
2475c87b03e5Sespie     else
2476c87b03e5Sespie       emit_library_call_value (memcmp_libfunc, result, LCT_PURE_MAKE_BLOCK,
2477c87b03e5Sespie 			       TYPE_MODE (integer_type_node), 3,
2478c87b03e5Sespie 			       XEXP (arg1_rtx, 0), Pmode,
2479c87b03e5Sespie 			       XEXP (arg2_rtx, 0), Pmode,
2480c87b03e5Sespie 			       convert_to_mode (TYPE_MODE (sizetype), arg3_rtx,
2481c87b03e5Sespie 						TREE_UNSIGNED (sizetype)),
2482c87b03e5Sespie 			       TYPE_MODE (sizetype));
2483c87b03e5Sespie 
2484c87b03e5Sespie     /* Return the value in the proper mode for this function.  */
2485c87b03e5Sespie     mode = TYPE_MODE (TREE_TYPE (exp));
2486c87b03e5Sespie     if (GET_MODE (result) == mode)
2487c87b03e5Sespie       return result;
2488c87b03e5Sespie     else if (target != 0)
2489c87b03e5Sespie       {
2490c87b03e5Sespie 	convert_move (target, result, 0);
2491c87b03e5Sespie 	return target;
2492c87b03e5Sespie       }
2493c87b03e5Sespie     else
2494c87b03e5Sespie       return convert_to_mode (mode, result, 0);
2495c87b03e5Sespie   }
2496c87b03e5Sespie #endif
2497c87b03e5Sespie 
2498c87b03e5Sespie   return 0;
2499c87b03e5Sespie }
2500c87b03e5Sespie 
2501c87b03e5Sespie /* Expand expression EXP, which is a call to the strcmp builtin.  Return 0
2502c87b03e5Sespie    if we failed the caller should emit a normal call, otherwise try to get
2503c87b03e5Sespie    the result in TARGET, if convenient.  */
2504c87b03e5Sespie 
2505c87b03e5Sespie static rtx
expand_builtin_strcmp(exp,target,mode)2506c87b03e5Sespie expand_builtin_strcmp (exp, target, mode)
2507c87b03e5Sespie      tree exp;
2508c87b03e5Sespie      rtx target;
2509c87b03e5Sespie      enum machine_mode mode;
2510c87b03e5Sespie {
2511c87b03e5Sespie   tree arglist = TREE_OPERAND (exp, 1);
2512*06dc6460Sespie   tree arg1, arg2;
2513c87b03e5Sespie   const char *p1, *p2;
2514c87b03e5Sespie 
2515c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
2516c87b03e5Sespie     return 0;
2517c87b03e5Sespie 
2518c87b03e5Sespie   arg1 = TREE_VALUE (arglist);
2519c87b03e5Sespie   arg2 = TREE_VALUE (TREE_CHAIN (arglist));
2520c87b03e5Sespie 
2521c87b03e5Sespie   p1 = c_getstr (arg1);
2522c87b03e5Sespie   p2 = c_getstr (arg2);
2523c87b03e5Sespie 
2524c87b03e5Sespie   if (p1 && p2)
2525c87b03e5Sespie     {
2526c87b03e5Sespie       const int i = strcmp (p1, p2);
2527c87b03e5Sespie       return (i < 0 ? constm1_rtx : (i > 0 ? const1_rtx : const0_rtx));
2528c87b03e5Sespie     }
2529c87b03e5Sespie 
2530c87b03e5Sespie   /* If either arg is "", return an expression corresponding to
2531c87b03e5Sespie      (*(const unsigned char*)arg1 - (const unsigned char*)arg2).  */
2532c87b03e5Sespie   if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
2533c87b03e5Sespie     {
2534c87b03e5Sespie       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
2535c87b03e5Sespie       tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
2536c87b03e5Sespie       tree ind1 =
2537c87b03e5Sespie 	fold (build1 (CONVERT_EXPR, integer_type_node,
2538c87b03e5Sespie 		      build1 (INDIRECT_REF, cst_uchar_node,
2539c87b03e5Sespie 			      build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
2540c87b03e5Sespie       tree ind2 =
2541c87b03e5Sespie 	fold (build1 (CONVERT_EXPR, integer_type_node,
2542c87b03e5Sespie 		      build1 (INDIRECT_REF, cst_uchar_node,
2543c87b03e5Sespie 			      build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
2544c87b03e5Sespie       tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
2545c87b03e5Sespie       return expand_expr (result, target, mode, EXPAND_NORMAL);
2546c87b03e5Sespie     }
2547c87b03e5Sespie 
2548*06dc6460Sespie #ifdef HAVE_cmpstrsi
2549*06dc6460Sespie   if (HAVE_cmpstrsi)
2550*06dc6460Sespie     {
2551*06dc6460Sespie       tree len, len1, len2;
2552*06dc6460Sespie       rtx arg1_rtx, arg2_rtx, arg3_rtx;
2553*06dc6460Sespie       rtx result, insn;
2554*06dc6460Sespie 
2555*06dc6460Sespie       int arg1_align
2556*06dc6460Sespie 	= get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
2557*06dc6460Sespie       int arg2_align
2558*06dc6460Sespie 	= get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
2559*06dc6460Sespie       enum machine_mode insn_mode
2560*06dc6460Sespie 	= insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
2561*06dc6460Sespie 
2562*06dc6460Sespie       len1 = c_strlen (arg1);
2563c87b03e5Sespie       len2 = c_strlen (arg2);
2564c87b03e5Sespie 
2565*06dc6460Sespie       if (len1)
2566*06dc6460Sespie 	len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
2567c87b03e5Sespie       if (len2)
2568c87b03e5Sespie 	len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
2569c87b03e5Sespie 
2570c87b03e5Sespie       /* If we don't have a constant length for the first, use the length
2571c87b03e5Sespie 	 of the second, if we know it.  We don't require a constant for
2572c87b03e5Sespie 	 this case; some cost analysis could be done if both are available
2573c87b03e5Sespie 	 but neither is constant.  For now, assume they're equally cheap
2574*06dc6460Sespie 	 unless one has side effects.  If both strings have constant lengths,
2575*06dc6460Sespie 	 use the smaller.  */
2576c87b03e5Sespie 
2577*06dc6460Sespie       if (!len1)
2578c87b03e5Sespie 	len = len2;
2579*06dc6460Sespie       else if (!len2)
2580*06dc6460Sespie 	len = len1;
2581*06dc6460Sespie       else if (TREE_SIDE_EFFECTS (len1))
2582*06dc6460Sespie 	len = len2;
2583*06dc6460Sespie       else if (TREE_SIDE_EFFECTS (len2))
2584*06dc6460Sespie 	len = len1;
2585*06dc6460Sespie       else if (TREE_CODE (len1) != INTEGER_CST)
2586*06dc6460Sespie 	len = len2;
2587*06dc6460Sespie       else if (TREE_CODE (len2) != INTEGER_CST)
2588*06dc6460Sespie 	len = len1;
2589*06dc6460Sespie       else if (tree_int_cst_lt (len1, len2))
2590*06dc6460Sespie 	len = len1;
2591*06dc6460Sespie       else
2592c87b03e5Sespie 	len = len2;
2593c87b03e5Sespie 
2594c87b03e5Sespie       /* If both arguments have side effects, we cannot optimize.  */
2595*06dc6460Sespie       if (!len || TREE_SIDE_EFFECTS (len))
2596c87b03e5Sespie 	return 0;
2597c87b03e5Sespie 
2598*06dc6460Sespie       /* If we don't have POINTER_TYPE, call the function.  */
2599*06dc6460Sespie       if (arg1_align == 0 || arg2_align == 0)
2600c87b03e5Sespie 	return 0;
2601c87b03e5Sespie 
2602*06dc6460Sespie       /* Make a place to write the result of the instruction.  */
2603*06dc6460Sespie       result = target;
2604*06dc6460Sespie       if (! (result != 0
2605*06dc6460Sespie 	     && GET_CODE (result) == REG
2606*06dc6460Sespie 	     && GET_MODE (result) == insn_mode
2607*06dc6460Sespie 	     && REGNO (result) >= FIRST_PSEUDO_REGISTER))
2608*06dc6460Sespie 	result = gen_reg_rtx (insn_mode);
2609*06dc6460Sespie 
2610*06dc6460Sespie       arg1_rtx = get_memory_rtx (arg1);
2611*06dc6460Sespie       arg2_rtx = get_memory_rtx (arg2);
2612*06dc6460Sespie       arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
2613*06dc6460Sespie       insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
2614*06dc6460Sespie 			   GEN_INT (MIN (arg1_align, arg2_align)));
2615*06dc6460Sespie       if (!insn)
2616*06dc6460Sespie 	return 0;
2617*06dc6460Sespie 
2618*06dc6460Sespie       emit_insn (insn);
2619*06dc6460Sespie 
2620*06dc6460Sespie       /* Return the value in the proper mode for this function.  */
2621*06dc6460Sespie       mode = TYPE_MODE (TREE_TYPE (exp));
2622*06dc6460Sespie       if (GET_MODE (result) == mode)
2623*06dc6460Sespie 	return result;
2624*06dc6460Sespie       if (target == 0)
2625*06dc6460Sespie 	return convert_to_mode (mode, result, 0);
2626*06dc6460Sespie       convert_move (target, result, 0);
2627*06dc6460Sespie       return target;
2628*06dc6460Sespie     }
2629*06dc6460Sespie #endif
2630*06dc6460Sespie   return 0;
2631c87b03e5Sespie }
2632c87b03e5Sespie 
2633c87b03e5Sespie /* Expand expression EXP, which is a call to the strncmp builtin.  Return 0
2634c87b03e5Sespie    if we failed the caller should emit a normal call, otherwise try to get
2635c87b03e5Sespie    the result in TARGET, if convenient.  */
2636c87b03e5Sespie 
2637c87b03e5Sespie static rtx
expand_builtin_strncmp(exp,target,mode)2638c87b03e5Sespie expand_builtin_strncmp (exp, target, mode)
2639c87b03e5Sespie      tree exp;
2640c87b03e5Sespie      rtx target;
2641c87b03e5Sespie      enum machine_mode mode;
2642c87b03e5Sespie {
2643c87b03e5Sespie   tree arglist = TREE_OPERAND (exp, 1);
2644c87b03e5Sespie   tree arg1, arg2, arg3;
2645c87b03e5Sespie   const char *p1, *p2;
2646c87b03e5Sespie 
2647c87b03e5Sespie   if (!validate_arglist (arglist,
2648c87b03e5Sespie 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
2649c87b03e5Sespie     return 0;
2650c87b03e5Sespie 
2651c87b03e5Sespie   arg1 = TREE_VALUE (arglist);
2652c87b03e5Sespie   arg2 = TREE_VALUE (TREE_CHAIN (arglist));
2653c87b03e5Sespie   arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
2654c87b03e5Sespie 
2655c87b03e5Sespie   /* If the len parameter is zero, return zero.  */
2656c87b03e5Sespie   if (host_integerp (arg3, 1) && tree_low_cst (arg3, 1) == 0)
2657c87b03e5Sespie     {
2658c87b03e5Sespie       /* Evaluate and ignore arg1 and arg2 in case they have
2659c87b03e5Sespie 	 side-effects.  */
2660c87b03e5Sespie       expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
2661c87b03e5Sespie       expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
2662c87b03e5Sespie       return const0_rtx;
2663c87b03e5Sespie     }
2664c87b03e5Sespie 
2665c87b03e5Sespie   p1 = c_getstr (arg1);
2666c87b03e5Sespie   p2 = c_getstr (arg2);
2667c87b03e5Sespie 
2668c87b03e5Sespie   /* If all arguments are constant, evaluate at compile-time.  */
2669c87b03e5Sespie   if (host_integerp (arg3, 1) && p1 && p2)
2670c87b03e5Sespie     {
2671c87b03e5Sespie       const int r = strncmp (p1, p2, tree_low_cst (arg3, 1));
2672c87b03e5Sespie       return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
2673c87b03e5Sespie     }
2674c87b03e5Sespie 
2675c87b03e5Sespie   /* If len == 1 or (either string parameter is "" and (len >= 1)),
2676c87b03e5Sespie       return (*(const u_char*)arg1 - *(const u_char*)arg2).  */
2677c87b03e5Sespie   if (host_integerp (arg3, 1)
2678c87b03e5Sespie       && (tree_low_cst (arg3, 1) == 1
2679c87b03e5Sespie 	  || (tree_low_cst (arg3, 1) > 1
2680c87b03e5Sespie 	      && ((p1 && *p1 == '\0') || (p2 && *p2 == '\0')))))
2681c87b03e5Sespie     {
2682c87b03e5Sespie       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
2683c87b03e5Sespie       tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
2684c87b03e5Sespie       tree ind1 =
2685c87b03e5Sespie 	fold (build1 (CONVERT_EXPR, integer_type_node,
2686c87b03e5Sespie 		      build1 (INDIRECT_REF, cst_uchar_node,
2687c87b03e5Sespie 			      build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
2688c87b03e5Sespie       tree ind2 =
2689c87b03e5Sespie 	fold (build1 (CONVERT_EXPR, integer_type_node,
2690c87b03e5Sespie 		      build1 (INDIRECT_REF, cst_uchar_node,
2691c87b03e5Sespie 			      build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
2692c87b03e5Sespie       tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
2693c87b03e5Sespie       return expand_expr (result, target, mode, EXPAND_NORMAL);
2694c87b03e5Sespie     }
2695c87b03e5Sespie 
2696c87b03e5Sespie   /* If c_strlen can determine an expression for one of the string
2697*06dc6460Sespie      lengths, and it doesn't have side effects, then emit cmpstrsi
2698*06dc6460Sespie      using length MIN(strlen(string)+1, arg3).  */
2699*06dc6460Sespie #ifdef HAVE_cmpstrsi
2700*06dc6460Sespie   if (HAVE_cmpstrsi)
2701*06dc6460Sespie     {
2702*06dc6460Sespie       tree len, len1, len2;
2703*06dc6460Sespie       rtx arg1_rtx, arg2_rtx, arg3_rtx;
2704*06dc6460Sespie       rtx result, insn;
2705c87b03e5Sespie 
2706*06dc6460Sespie       int arg1_align
2707*06dc6460Sespie 	= get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
2708*06dc6460Sespie       int arg2_align
2709*06dc6460Sespie 	= get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
2710*06dc6460Sespie       enum machine_mode insn_mode
2711*06dc6460Sespie 	= insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
2712c87b03e5Sespie 
2713*06dc6460Sespie       len1 = c_strlen (arg1);
2714*06dc6460Sespie       len2 = c_strlen (arg2);
2715*06dc6460Sespie 
2716*06dc6460Sespie       if (len1)
2717*06dc6460Sespie 	len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
2718*06dc6460Sespie       if (len2)
2719*06dc6460Sespie 	len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
2720*06dc6460Sespie 
2721*06dc6460Sespie       /* If we don't have a constant length for the first, use the length
2722*06dc6460Sespie 	 of the second, if we know it.  We don't require a constant for
2723*06dc6460Sespie 	 this case; some cost analysis could be done if both are available
2724*06dc6460Sespie 	 but neither is constant.  For now, assume they're equally cheap,
2725*06dc6460Sespie 	 unless one has side effects.  If both strings have constant lengths,
2726*06dc6460Sespie 	 use the smaller.  */
2727*06dc6460Sespie 
2728*06dc6460Sespie       if (!len1)
2729*06dc6460Sespie 	len = len2;
2730*06dc6460Sespie       else if (!len2)
2731*06dc6460Sespie 	len = len1;
2732*06dc6460Sespie       else if (TREE_SIDE_EFFECTS (len1))
2733*06dc6460Sespie 	len = len2;
2734*06dc6460Sespie       else if (TREE_SIDE_EFFECTS (len2))
2735*06dc6460Sespie 	len = len1;
2736*06dc6460Sespie       else if (TREE_CODE (len1) != INTEGER_CST)
2737*06dc6460Sespie 	len = len2;
2738*06dc6460Sespie       else if (TREE_CODE (len2) != INTEGER_CST)
2739*06dc6460Sespie 	len = len1;
2740*06dc6460Sespie       else if (tree_int_cst_lt (len1, len2))
2741*06dc6460Sespie 	len = len1;
2742*06dc6460Sespie       else
2743*06dc6460Sespie 	len = len2;
2744*06dc6460Sespie 
2745*06dc6460Sespie       /* If both arguments have side effects, we cannot optimize.  */
2746*06dc6460Sespie       if (!len || TREE_SIDE_EFFECTS (len))
2747c87b03e5Sespie 	return 0;
2748c87b03e5Sespie 
2749c87b03e5Sespie       /* The actual new length parameter is MIN(len,arg3).  */
2750c87b03e5Sespie       len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));
2751c87b03e5Sespie 
2752*06dc6460Sespie       /* If we don't have POINTER_TYPE, call the function.  */
2753*06dc6460Sespie       if (arg1_align == 0 || arg2_align == 0)
2754*06dc6460Sespie 	return 0;
2755*06dc6460Sespie 
2756*06dc6460Sespie       /* Make a place to write the result of the instruction.  */
2757*06dc6460Sespie       result = target;
2758*06dc6460Sespie       if (! (result != 0
2759*06dc6460Sespie 	     && GET_CODE (result) == REG
2760*06dc6460Sespie 	     && GET_MODE (result) == insn_mode
2761*06dc6460Sespie 	     && REGNO (result) >= FIRST_PSEUDO_REGISTER))
2762*06dc6460Sespie 	result = gen_reg_rtx (insn_mode);
2763*06dc6460Sespie 
2764*06dc6460Sespie       arg1_rtx = get_memory_rtx (arg1);
2765*06dc6460Sespie       arg2_rtx = get_memory_rtx (arg2);
2766*06dc6460Sespie       arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
2767*06dc6460Sespie       insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
2768*06dc6460Sespie 			   GEN_INT (MIN (arg1_align, arg2_align)));
2769*06dc6460Sespie       if (!insn)
2770*06dc6460Sespie 	return 0;
2771*06dc6460Sespie 
2772*06dc6460Sespie       emit_insn (insn);
2773*06dc6460Sespie 
2774*06dc6460Sespie       /* Return the value in the proper mode for this function.  */
2775*06dc6460Sespie       mode = TYPE_MODE (TREE_TYPE (exp));
2776*06dc6460Sespie       if (GET_MODE (result) == mode)
2777*06dc6460Sespie 	return result;
2778*06dc6460Sespie       if (target == 0)
2779*06dc6460Sespie 	return convert_to_mode (mode, result, 0);
2780*06dc6460Sespie       convert_move (target, result, 0);
2781*06dc6460Sespie       return target;
2782*06dc6460Sespie     }
2783*06dc6460Sespie #endif
2784*06dc6460Sespie   return 0;
2785c87b03e5Sespie }
2786c87b03e5Sespie 
2787c87b03e5Sespie /* Expand expression EXP, which is a call to the strcat builtin.
2788c87b03e5Sespie    Return 0 if we failed the caller should emit a normal call,
2789c87b03e5Sespie    otherwise try to get the result in TARGET, if convenient.  */
2790c87b03e5Sespie 
2791c87b03e5Sespie static rtx
expand_builtin_strcat(arglist,target,mode)2792c87b03e5Sespie expand_builtin_strcat (arglist, target, mode)
2793c87b03e5Sespie      tree arglist;
2794c87b03e5Sespie      rtx target;
2795c87b03e5Sespie      enum machine_mode mode;
2796c87b03e5Sespie {
2797c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
2798c87b03e5Sespie     return 0;
2799c87b03e5Sespie   else
2800c87b03e5Sespie     {
2801c87b03e5Sespie       tree dst = TREE_VALUE (arglist),
2802c87b03e5Sespie 	src = TREE_VALUE (TREE_CHAIN (arglist));
2803c87b03e5Sespie       const char *p = c_getstr (src);
2804c87b03e5Sespie 
2805c87b03e5Sespie       /* If the string length is zero, return the dst parameter.  */
2806c87b03e5Sespie       if (p && *p == '\0')
2807c87b03e5Sespie 	return expand_expr (dst, target, mode, EXPAND_NORMAL);
2808c87b03e5Sespie 
2809c87b03e5Sespie       return 0;
2810c87b03e5Sespie     }
2811c87b03e5Sespie }
2812c87b03e5Sespie 
2813c87b03e5Sespie /* Expand expression EXP, which is a call to the strncat builtin.
2814c87b03e5Sespie    Return 0 if we failed the caller should emit a normal call,
2815c87b03e5Sespie    otherwise try to get the result in TARGET, if convenient.  */
2816c87b03e5Sespie 
2817c87b03e5Sespie static rtx
expand_builtin_strncat(arglist,target,mode)2818c87b03e5Sespie expand_builtin_strncat (arglist, target, mode)
2819c87b03e5Sespie      tree arglist;
2820c87b03e5Sespie      rtx target;
2821c87b03e5Sespie      enum machine_mode mode;
2822c87b03e5Sespie {
2823c87b03e5Sespie   if (!validate_arglist (arglist,
2824c87b03e5Sespie 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
2825c87b03e5Sespie     return 0;
2826c87b03e5Sespie   else
2827c87b03e5Sespie     {
2828c87b03e5Sespie       tree dst = TREE_VALUE (arglist),
2829c87b03e5Sespie 	src = TREE_VALUE (TREE_CHAIN (arglist)),
2830c87b03e5Sespie 	len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
2831c87b03e5Sespie       const char *p = c_getstr (src);
2832c87b03e5Sespie 
2833c87b03e5Sespie       /* If the requested length is zero, or the src parameter string
2834c87b03e5Sespie           length is zero, return the dst parameter.  */
2835c87b03e5Sespie       if (integer_zerop (len) || (p && *p == '\0'))
2836c87b03e5Sespie 	{
2837c87b03e5Sespie 	  /* Evaluate and ignore the src and len parameters in case
2838c87b03e5Sespie 	     they have side-effects.  */
2839c87b03e5Sespie 	  expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
2840c87b03e5Sespie 	  expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL);
2841c87b03e5Sespie 	  return expand_expr (dst, target, mode, EXPAND_NORMAL);
2842c87b03e5Sespie 	}
2843c87b03e5Sespie 
2844c87b03e5Sespie       /* If the requested len is greater than or equal to the string
2845c87b03e5Sespie          length, call strcat.  */
2846c87b03e5Sespie       if (TREE_CODE (len) == INTEGER_CST && p
2847c87b03e5Sespie 	  && compare_tree_int (len, strlen (p)) >= 0)
2848c87b03e5Sespie 	{
2849c87b03e5Sespie 	  tree newarglist
2850c87b03e5Sespie 	    = tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src));
2851c87b03e5Sespie 	  tree fn = built_in_decls[BUILT_IN_STRCAT];
2852c87b03e5Sespie 
2853c87b03e5Sespie 	  /* If the replacement _DECL isn't initialized, don't do the
2854c87b03e5Sespie 	     transformation.  */
2855c87b03e5Sespie 	  if (!fn)
2856c87b03e5Sespie 	    return 0;
2857c87b03e5Sespie 
2858c87b03e5Sespie 	  return expand_expr (build_function_call_expr (fn, newarglist),
2859c87b03e5Sespie 			      target, mode, EXPAND_NORMAL);
2860c87b03e5Sespie 	}
2861c87b03e5Sespie       return 0;
2862c87b03e5Sespie     }
2863c87b03e5Sespie }
2864c87b03e5Sespie 
2865c87b03e5Sespie /* Expand expression EXP, which is a call to the strspn builtin.
2866c87b03e5Sespie    Return 0 if we failed the caller should emit a normal call,
2867c87b03e5Sespie    otherwise try to get the result in TARGET, if convenient.  */
2868c87b03e5Sespie 
2869c87b03e5Sespie static rtx
expand_builtin_strspn(arglist,target,mode)2870c87b03e5Sespie expand_builtin_strspn (arglist, target, mode)
2871c87b03e5Sespie      tree arglist;
2872c87b03e5Sespie      rtx target;
2873c87b03e5Sespie      enum machine_mode mode;
2874c87b03e5Sespie {
2875c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
2876c87b03e5Sespie     return 0;
2877c87b03e5Sespie   else
2878c87b03e5Sespie     {
2879c87b03e5Sespie       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
2880c87b03e5Sespie       const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
2881c87b03e5Sespie 
2882c87b03e5Sespie       /* If both arguments are constants, evaluate at compile-time.  */
2883c87b03e5Sespie       if (p1 && p2)
2884c87b03e5Sespie 	{
2885c87b03e5Sespie 	  const size_t r = strspn (p1, p2);
2886c87b03e5Sespie 	  return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
2887c87b03e5Sespie 	}
2888c87b03e5Sespie 
2889c87b03e5Sespie       /* If either argument is "", return 0.  */
2890c87b03e5Sespie       if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
2891c87b03e5Sespie 	{
2892c87b03e5Sespie 	  /* Evaluate and ignore both arguments in case either one has
2893c87b03e5Sespie 	     side-effects.  */
2894c87b03e5Sespie 	  expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
2895c87b03e5Sespie 	  expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL);
2896c87b03e5Sespie 	  return const0_rtx;
2897c87b03e5Sespie 	}
2898c87b03e5Sespie       return 0;
2899c87b03e5Sespie     }
2900c87b03e5Sespie }
2901c87b03e5Sespie 
2902c87b03e5Sespie /* Expand expression EXP, which is a call to the strcspn builtin.
2903c87b03e5Sespie    Return 0 if we failed the caller should emit a normal call,
2904c87b03e5Sespie    otherwise try to get the result in TARGET, if convenient.  */
2905c87b03e5Sespie 
2906c87b03e5Sespie static rtx
expand_builtin_strcspn(arglist,target,mode)2907c87b03e5Sespie expand_builtin_strcspn (arglist, target, mode)
2908c87b03e5Sespie      tree arglist;
2909c87b03e5Sespie      rtx target;
2910c87b03e5Sespie      enum machine_mode mode;
2911c87b03e5Sespie {
2912c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
2913c87b03e5Sespie     return 0;
2914c87b03e5Sespie   else
2915c87b03e5Sespie     {
2916c87b03e5Sespie       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
2917c87b03e5Sespie       const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
2918c87b03e5Sespie 
2919c87b03e5Sespie       /* If both arguments are constants, evaluate at compile-time.  */
2920c87b03e5Sespie       if (p1 && p2)
2921c87b03e5Sespie 	{
2922c87b03e5Sespie 	  const size_t r = strcspn (p1, p2);
2923c87b03e5Sespie 	  return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
2924c87b03e5Sespie 	}
2925c87b03e5Sespie 
2926c87b03e5Sespie       /* If the first argument is "", return 0.  */
2927c87b03e5Sespie       if (p1 && *p1 == '\0')
2928c87b03e5Sespie 	{
2929c87b03e5Sespie 	  /* Evaluate and ignore argument s2 in case it has
2930c87b03e5Sespie 	     side-effects.  */
2931c87b03e5Sespie 	  expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL);
2932c87b03e5Sespie 	  return const0_rtx;
2933c87b03e5Sespie 	}
2934c87b03e5Sespie 
2935c87b03e5Sespie       /* If the second argument is "", return __builtin_strlen(s1).  */
2936c87b03e5Sespie       if (p2 && *p2 == '\0')
2937c87b03e5Sespie 	{
2938c87b03e5Sespie 	  tree newarglist = build_tree_list (NULL_TREE, s1),
2939c87b03e5Sespie 	    fn = built_in_decls[BUILT_IN_STRLEN];
2940c87b03e5Sespie 
2941c87b03e5Sespie 	  /* If the replacement _DECL isn't initialized, don't do the
2942c87b03e5Sespie 	     transformation.  */
2943c87b03e5Sespie 	  if (!fn)
2944c87b03e5Sespie 	    return 0;
2945c87b03e5Sespie 
2946c87b03e5Sespie 	  return expand_expr (build_function_call_expr (fn, newarglist),
2947c87b03e5Sespie 			      target, mode, EXPAND_NORMAL);
2948c87b03e5Sespie 	}
2949c87b03e5Sespie       return 0;
2950c87b03e5Sespie     }
2951c87b03e5Sespie }
2952c87b03e5Sespie 
2953c87b03e5Sespie /* Expand a call to __builtin_saveregs, generating the result in TARGET,
2954c87b03e5Sespie    if that's convenient.  */
2955c87b03e5Sespie 
2956c87b03e5Sespie rtx
expand_builtin_saveregs()2957c87b03e5Sespie expand_builtin_saveregs ()
2958c87b03e5Sespie {
2959c87b03e5Sespie   rtx val, seq;
2960c87b03e5Sespie 
2961c87b03e5Sespie   /* Don't do __builtin_saveregs more than once in a function.
2962c87b03e5Sespie      Save the result of the first call and reuse it.  */
2963c87b03e5Sespie   if (saveregs_value != 0)
2964c87b03e5Sespie     return saveregs_value;
2965c87b03e5Sespie 
2966c87b03e5Sespie   /* When this function is called, it means that registers must be
2967c87b03e5Sespie      saved on entry to this function.  So we migrate the call to the
2968c87b03e5Sespie      first insn of this function.  */
2969c87b03e5Sespie 
2970c87b03e5Sespie   start_sequence ();
2971c87b03e5Sespie 
2972c87b03e5Sespie #ifdef EXPAND_BUILTIN_SAVEREGS
2973c87b03e5Sespie   /* Do whatever the machine needs done in this case.  */
2974c87b03e5Sespie   val = EXPAND_BUILTIN_SAVEREGS ();
2975c87b03e5Sespie #else
2976c87b03e5Sespie   /* ??? We used to try and build up a call to the out of line function,
2977c87b03e5Sespie      guessing about what registers needed saving etc.  This became much
2978c87b03e5Sespie      harder with __builtin_va_start, since we don't have a tree for a
2979c87b03e5Sespie      call to __builtin_saveregs to fall back on.  There was exactly one
2980c87b03e5Sespie      port (i860) that used this code, and I'm unconvinced it could actually
2981c87b03e5Sespie      handle the general case.  So we no longer try to handle anything
2982c87b03e5Sespie      weird and make the backend absorb the evil.  */
2983c87b03e5Sespie 
2984c87b03e5Sespie   error ("__builtin_saveregs not supported by this target");
2985c87b03e5Sespie   val = const0_rtx;
2986c87b03e5Sespie #endif
2987c87b03e5Sespie 
2988c87b03e5Sespie   seq = get_insns ();
2989c87b03e5Sespie   end_sequence ();
2990c87b03e5Sespie 
2991c87b03e5Sespie   saveregs_value = val;
2992c87b03e5Sespie 
2993c87b03e5Sespie   /* Put the insns after the NOTE that starts the function.  If this
2994c87b03e5Sespie      is inside a start_sequence, make the outer-level insn chain current, so
2995c87b03e5Sespie      the code is placed at the start of the function.  */
2996c87b03e5Sespie   push_topmost_sequence ();
2997c87b03e5Sespie   emit_insn_after (seq, get_insns ());
2998c87b03e5Sespie   pop_topmost_sequence ();
2999c87b03e5Sespie 
3000c87b03e5Sespie   return val;
3001c87b03e5Sespie }
3002c87b03e5Sespie 
3003c87b03e5Sespie /* __builtin_args_info (N) returns word N of the arg space info
3004c87b03e5Sespie    for the current function.  The number and meanings of words
3005c87b03e5Sespie    is controlled by the definition of CUMULATIVE_ARGS.  */
3006c87b03e5Sespie 
3007c87b03e5Sespie static rtx
expand_builtin_args_info(exp)3008c87b03e5Sespie expand_builtin_args_info (exp)
3009c87b03e5Sespie      tree exp;
3010c87b03e5Sespie {
3011c87b03e5Sespie   tree arglist = TREE_OPERAND (exp, 1);
3012c87b03e5Sespie   int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
3013c87b03e5Sespie   int *word_ptr = (int *) &current_function_args_info;
3014c87b03e5Sespie #if 0
3015c87b03e5Sespie   /* These are used by the code below that is if 0'ed away */
3016c87b03e5Sespie   int i;
3017c87b03e5Sespie   tree type, elts, result;
3018c87b03e5Sespie #endif
3019c87b03e5Sespie 
3020c87b03e5Sespie   if (sizeof (CUMULATIVE_ARGS) % sizeof (int) != 0)
3021c87b03e5Sespie     abort ();
3022c87b03e5Sespie 
3023c87b03e5Sespie   if (arglist != 0)
3024c87b03e5Sespie     {
3025c87b03e5Sespie       if (!host_integerp (TREE_VALUE (arglist), 0))
3026c87b03e5Sespie 	error ("argument of `__builtin_args_info' must be constant");
3027c87b03e5Sespie       else
3028c87b03e5Sespie 	{
3029c87b03e5Sespie 	  HOST_WIDE_INT wordnum = tree_low_cst (TREE_VALUE (arglist), 0);
3030c87b03e5Sespie 
3031c87b03e5Sespie 	  if (wordnum < 0 || wordnum >= nwords)
3032c87b03e5Sespie 	    error ("argument of `__builtin_args_info' out of range");
3033c87b03e5Sespie 	  else
3034c87b03e5Sespie 	    return GEN_INT (word_ptr[wordnum]);
3035c87b03e5Sespie 	}
3036c87b03e5Sespie     }
3037c87b03e5Sespie   else
3038c87b03e5Sespie     error ("missing argument in `__builtin_args_info'");
3039c87b03e5Sespie 
3040c87b03e5Sespie   return const0_rtx;
3041c87b03e5Sespie 
3042c87b03e5Sespie #if 0
3043c87b03e5Sespie   for (i = 0; i < nwords; i++)
3044c87b03e5Sespie     elts = tree_cons (NULL_TREE, build_int_2 (word_ptr[i], 0));
3045c87b03e5Sespie 
3046c87b03e5Sespie   type = build_array_type (integer_type_node,
3047c87b03e5Sespie 			   build_index_type (build_int_2 (nwords, 0)));
3048c87b03e5Sespie   result = build (CONSTRUCTOR, type, NULL_TREE, nreverse (elts));
3049c87b03e5Sespie   TREE_CONSTANT (result) = 1;
3050c87b03e5Sespie   TREE_STATIC (result) = 1;
3051c87b03e5Sespie   result = build1 (INDIRECT_REF, build_pointer_type (type), result);
3052c87b03e5Sespie   TREE_CONSTANT (result) = 1;
3053c87b03e5Sespie   return expand_expr (result, NULL_RTX, VOIDmode, 0);
3054c87b03e5Sespie #endif
3055c87b03e5Sespie }
3056c87b03e5Sespie 
3057c87b03e5Sespie /* Expand ARGLIST, from a call to __builtin_next_arg.  */
3058c87b03e5Sespie 
3059c87b03e5Sespie static rtx
expand_builtin_next_arg(arglist)3060c87b03e5Sespie expand_builtin_next_arg (arglist)
3061c87b03e5Sespie      tree arglist;
3062c87b03e5Sespie {
3063c87b03e5Sespie   tree fntype = TREE_TYPE (current_function_decl);
3064c87b03e5Sespie 
3065c87b03e5Sespie   if (TYPE_ARG_TYPES (fntype) == 0
3066c87b03e5Sespie       || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
3067c87b03e5Sespie 	  == void_type_node))
3068c87b03e5Sespie     {
3069c87b03e5Sespie       error ("`va_start' used in function with fixed args");
3070c87b03e5Sespie       return const0_rtx;
3071c87b03e5Sespie     }
3072c87b03e5Sespie 
3073c87b03e5Sespie   if (arglist)
3074c87b03e5Sespie     {
3075c87b03e5Sespie       tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
3076c87b03e5Sespie       tree arg = TREE_VALUE (arglist);
3077c87b03e5Sespie 
3078c87b03e5Sespie       /* Strip off all nops for the sake of the comparison.  This
3079c87b03e5Sespie 	 is not quite the same as STRIP_NOPS.  It does more.
3080c87b03e5Sespie 	 We must also strip off INDIRECT_EXPR for C++ reference
3081c87b03e5Sespie 	 parameters.  */
3082c87b03e5Sespie       while (TREE_CODE (arg) == NOP_EXPR
3083c87b03e5Sespie 	     || TREE_CODE (arg) == CONVERT_EXPR
3084c87b03e5Sespie 	     || TREE_CODE (arg) == NON_LVALUE_EXPR
3085c87b03e5Sespie 	     || TREE_CODE (arg) == INDIRECT_REF)
3086c87b03e5Sespie 	arg = TREE_OPERAND (arg, 0);
3087c87b03e5Sespie       if (arg != last_parm)
3088c87b03e5Sespie 	warning ("second parameter of `va_start' not last named argument");
3089c87b03e5Sespie     }
3090c87b03e5Sespie   else
3091c87b03e5Sespie     /* Evidently an out of date version of <stdarg.h>; can't validate
3092c87b03e5Sespie        va_start's second argument, but can still work as intended.  */
3093c87b03e5Sespie     warning ("`__builtin_next_arg' called without an argument");
3094c87b03e5Sespie 
3095c87b03e5Sespie   return expand_binop (Pmode, add_optab,
3096c87b03e5Sespie 		       current_function_internal_arg_pointer,
3097c87b03e5Sespie 		       current_function_arg_offset_rtx,
3098c87b03e5Sespie 		       NULL_RTX, 0, OPTAB_LIB_WIDEN);
3099c87b03e5Sespie }
3100c87b03e5Sespie 
3101c87b03e5Sespie /* Make it easier for the backends by protecting the valist argument
3102c87b03e5Sespie    from multiple evaluations.  */
3103c87b03e5Sespie 
3104c87b03e5Sespie static tree
stabilize_va_list(valist,needs_lvalue)3105c87b03e5Sespie stabilize_va_list (valist, needs_lvalue)
3106c87b03e5Sespie      tree valist;
3107c87b03e5Sespie      int needs_lvalue;
3108c87b03e5Sespie {
3109c87b03e5Sespie   if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
3110c87b03e5Sespie     {
3111c87b03e5Sespie       if (TREE_SIDE_EFFECTS (valist))
3112c87b03e5Sespie 	valist = save_expr (valist);
3113c87b03e5Sespie 
3114c87b03e5Sespie       /* For this case, the backends will be expecting a pointer to
3115c87b03e5Sespie 	 TREE_TYPE (va_list_type_node), but it's possible we've
3116c87b03e5Sespie 	 actually been given an array (an actual va_list_type_node).
3117c87b03e5Sespie 	 So fix it.  */
3118c87b03e5Sespie       if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
3119c87b03e5Sespie 	{
3120c87b03e5Sespie 	  tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
3121c87b03e5Sespie 	  tree p2 = build_pointer_type (va_list_type_node);
3122c87b03e5Sespie 
3123c87b03e5Sespie 	  valist = build1 (ADDR_EXPR, p2, valist);
3124c87b03e5Sespie 	  valist = fold (build1 (NOP_EXPR, p1, valist));
3125c87b03e5Sespie 	}
3126c87b03e5Sespie     }
3127c87b03e5Sespie   else
3128c87b03e5Sespie     {
3129c87b03e5Sespie       tree pt;
3130c87b03e5Sespie 
3131c87b03e5Sespie       if (! needs_lvalue)
3132c87b03e5Sespie 	{
3133c87b03e5Sespie 	  if (! TREE_SIDE_EFFECTS (valist))
3134c87b03e5Sespie 	    return valist;
3135c87b03e5Sespie 
3136c87b03e5Sespie 	  pt = build_pointer_type (va_list_type_node);
3137c87b03e5Sespie 	  valist = fold (build1 (ADDR_EXPR, pt, valist));
3138c87b03e5Sespie 	  TREE_SIDE_EFFECTS (valist) = 1;
3139c87b03e5Sespie 	}
3140c87b03e5Sespie 
3141c87b03e5Sespie       if (TREE_SIDE_EFFECTS (valist))
3142c87b03e5Sespie 	valist = save_expr (valist);
3143c87b03e5Sespie       valist = fold (build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)),
3144c87b03e5Sespie 			     valist));
3145c87b03e5Sespie     }
3146c87b03e5Sespie 
3147c87b03e5Sespie   return valist;
3148c87b03e5Sespie }
3149c87b03e5Sespie 
3150c87b03e5Sespie /* The "standard" implementation of va_start: just assign `nextarg' to
3151c87b03e5Sespie    the variable.  */
3152c87b03e5Sespie 
3153c87b03e5Sespie void
std_expand_builtin_va_start(valist,nextarg)3154c87b03e5Sespie std_expand_builtin_va_start (valist, nextarg)
3155c87b03e5Sespie      tree valist;
3156c87b03e5Sespie      rtx nextarg;
3157c87b03e5Sespie {
3158c87b03e5Sespie   tree t;
3159c87b03e5Sespie 
3160c87b03e5Sespie   t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
3161c87b03e5Sespie 	     make_tree (ptr_type_node, nextarg));
3162c87b03e5Sespie   TREE_SIDE_EFFECTS (t) = 1;
3163c87b03e5Sespie 
3164c87b03e5Sespie   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
3165c87b03e5Sespie }
3166c87b03e5Sespie 
3167c87b03e5Sespie /* Expand ARGLIST, from a call to __builtin_va_start.  */
3168c87b03e5Sespie 
3169c87b03e5Sespie static rtx
expand_builtin_va_start(arglist)3170c87b03e5Sespie expand_builtin_va_start (arglist)
3171c87b03e5Sespie      tree arglist;
3172c87b03e5Sespie {
3173c87b03e5Sespie   rtx nextarg;
3174c87b03e5Sespie   tree chain, valist;
3175c87b03e5Sespie 
3176c87b03e5Sespie   chain = TREE_CHAIN (arglist);
3177c87b03e5Sespie 
3178c87b03e5Sespie   if (TREE_CHAIN (chain))
3179c87b03e5Sespie     error ("too many arguments to function `va_start'");
3180c87b03e5Sespie 
3181c87b03e5Sespie   nextarg = expand_builtin_next_arg (chain);
3182c87b03e5Sespie   valist = stabilize_va_list (TREE_VALUE (arglist), 1);
3183c87b03e5Sespie 
3184c87b03e5Sespie #ifdef EXPAND_BUILTIN_VA_START
3185c87b03e5Sespie   EXPAND_BUILTIN_VA_START (valist, nextarg);
3186c87b03e5Sespie #else
3187c87b03e5Sespie   std_expand_builtin_va_start (valist, nextarg);
3188c87b03e5Sespie #endif
3189c87b03e5Sespie 
3190c87b03e5Sespie   return const0_rtx;
3191c87b03e5Sespie }
3192c87b03e5Sespie 
3193c87b03e5Sespie /* The "standard" implementation of va_arg: read the value from the
3194c87b03e5Sespie    current (padded) address and increment by the (padded) size.  */
3195c87b03e5Sespie 
3196c87b03e5Sespie rtx
std_expand_builtin_va_arg(valist,type)3197c87b03e5Sespie std_expand_builtin_va_arg (valist, type)
3198c87b03e5Sespie      tree valist, type;
3199c87b03e5Sespie {
3200c87b03e5Sespie   tree addr_tree, t, type_size = NULL;
3201c87b03e5Sespie   tree align, alignm1;
3202c87b03e5Sespie   tree rounded_size;
3203c87b03e5Sespie   rtx addr;
3204c87b03e5Sespie 
3205c87b03e5Sespie   /* Compute the rounded size of the type.  */
3206c87b03e5Sespie   align = size_int (PARM_BOUNDARY / BITS_PER_UNIT);
3207c87b03e5Sespie   alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1);
3208c87b03e5Sespie   if (type == error_mark_node
3209c87b03e5Sespie       || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
3210c87b03e5Sespie       || TREE_OVERFLOW (type_size))
3211c87b03e5Sespie     rounded_size = size_zero_node;
3212c87b03e5Sespie   else
3213c87b03e5Sespie     rounded_size = fold (build (MULT_EXPR, sizetype,
3214c87b03e5Sespie 				fold (build (TRUNC_DIV_EXPR, sizetype,
3215c87b03e5Sespie 					     fold (build (PLUS_EXPR, sizetype,
3216c87b03e5Sespie 							  type_size, alignm1)),
3217c87b03e5Sespie 					     align)),
3218c87b03e5Sespie 				align));
3219c87b03e5Sespie 
3220c87b03e5Sespie   /* Get AP.  */
3221c87b03e5Sespie   addr_tree = valist;
3222c87b03e5Sespie   if (PAD_VARARGS_DOWN && ! integer_zerop (rounded_size))
3223c87b03e5Sespie     {
3224c87b03e5Sespie       /* Small args are padded downward.  */
3225c87b03e5Sespie       addr_tree = fold (build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
3226c87b03e5Sespie 			       fold (build (COND_EXPR, sizetype,
3227c87b03e5Sespie 					    fold (build (GT_EXPR, sizetype,
3228c87b03e5Sespie 							 rounded_size,
3229c87b03e5Sespie 							 align)),
3230c87b03e5Sespie 					    size_zero_node,
3231c87b03e5Sespie 					    fold (build (MINUS_EXPR, sizetype,
3232c87b03e5Sespie 							 rounded_size,
3233c87b03e5Sespie 							 type_size))))));
3234c87b03e5Sespie     }
3235c87b03e5Sespie 
3236c87b03e5Sespie   addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
3237c87b03e5Sespie   addr = copy_to_reg (addr);
3238c87b03e5Sespie 
3239c87b03e5Sespie   /* Compute new value for AP.  */
3240c87b03e5Sespie   if (! integer_zerop (rounded_size))
3241c87b03e5Sespie     {
3242c87b03e5Sespie       t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
3243c87b03e5Sespie 		 build (PLUS_EXPR, TREE_TYPE (valist), valist,
3244c87b03e5Sespie 			rounded_size));
3245c87b03e5Sespie       TREE_SIDE_EFFECTS (t) = 1;
3246c87b03e5Sespie       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
3247c87b03e5Sespie     }
3248c87b03e5Sespie 
3249c87b03e5Sespie   return addr;
3250c87b03e5Sespie }
3251c87b03e5Sespie 
3252c87b03e5Sespie /* Expand __builtin_va_arg, which is not really a builtin function, but
3253c87b03e5Sespie    a very special sort of operator.  */
3254c87b03e5Sespie 
3255c87b03e5Sespie rtx
expand_builtin_va_arg(valist,type)3256c87b03e5Sespie expand_builtin_va_arg (valist, type)
3257c87b03e5Sespie      tree valist, type;
3258c87b03e5Sespie {
3259c87b03e5Sespie   rtx addr, result;
3260c87b03e5Sespie   tree promoted_type, want_va_type, have_va_type;
3261c87b03e5Sespie 
3262c87b03e5Sespie   /* Verify that valist is of the proper type.  */
3263c87b03e5Sespie 
3264c87b03e5Sespie   want_va_type = va_list_type_node;
3265c87b03e5Sespie   have_va_type = TREE_TYPE (valist);
3266c87b03e5Sespie   if (TREE_CODE (want_va_type) == ARRAY_TYPE)
3267c87b03e5Sespie     {
3268c87b03e5Sespie       /* If va_list is an array type, the argument may have decayed
3269c87b03e5Sespie 	 to a pointer type, e.g. by being passed to another function.
3270c87b03e5Sespie          In that case, unwrap both types so that we can compare the
3271c87b03e5Sespie 	 underlying records.  */
3272c87b03e5Sespie       if (TREE_CODE (have_va_type) == ARRAY_TYPE
3273c87b03e5Sespie 	  || TREE_CODE (have_va_type) == POINTER_TYPE)
3274c87b03e5Sespie 	{
3275c87b03e5Sespie 	  want_va_type = TREE_TYPE (want_va_type);
3276c87b03e5Sespie 	  have_va_type = TREE_TYPE (have_va_type);
3277c87b03e5Sespie 	}
3278c87b03e5Sespie     }
3279c87b03e5Sespie   if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type))
3280c87b03e5Sespie     {
3281c87b03e5Sespie       error ("first argument to `va_arg' not of type `va_list'");
3282c87b03e5Sespie       addr = const0_rtx;
3283c87b03e5Sespie     }
3284c87b03e5Sespie 
3285c87b03e5Sespie   /* Generate a diagnostic for requesting data of a type that cannot
3286c87b03e5Sespie      be passed through `...' due to type promotion at the call site.  */
3287c87b03e5Sespie   else if ((promoted_type = (*lang_hooks.types.type_promotes_to) (type))
3288c87b03e5Sespie 	   != type)
3289c87b03e5Sespie     {
3290c87b03e5Sespie       const char *name = "<anonymous type>", *pname = 0;
3291c87b03e5Sespie       static bool gave_help;
3292c87b03e5Sespie 
3293c87b03e5Sespie       if (TYPE_NAME (type))
3294c87b03e5Sespie 	{
3295c87b03e5Sespie 	  if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
3296c87b03e5Sespie 	    name = IDENTIFIER_POINTER (TYPE_NAME (type));
3297c87b03e5Sespie 	  else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
3298c87b03e5Sespie 		   && DECL_NAME (TYPE_NAME (type)))
3299c87b03e5Sespie 	    name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
3300c87b03e5Sespie 	}
3301c87b03e5Sespie       if (TYPE_NAME (promoted_type))
3302c87b03e5Sespie 	{
3303c87b03e5Sespie 	  if (TREE_CODE (TYPE_NAME (promoted_type)) == IDENTIFIER_NODE)
3304c87b03e5Sespie 	    pname = IDENTIFIER_POINTER (TYPE_NAME (promoted_type));
3305c87b03e5Sespie 	  else if (TREE_CODE (TYPE_NAME (promoted_type)) == TYPE_DECL
3306c87b03e5Sespie 		   && DECL_NAME (TYPE_NAME (promoted_type)))
3307c87b03e5Sespie 	    pname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (promoted_type)));
3308c87b03e5Sespie 	}
3309c87b03e5Sespie 
3310c87b03e5Sespie       /* Unfortunately, this is merely undefined, rather than a constraint
3311c87b03e5Sespie 	 violation, so we cannot make this an error.  If this call is never
3312c87b03e5Sespie 	 executed, the program is still strictly conforming.  */
3313c87b03e5Sespie       warning ("`%s' is promoted to `%s' when passed through `...'",
3314c87b03e5Sespie 	       name, pname);
3315c87b03e5Sespie       if (! gave_help)
3316c87b03e5Sespie 	{
3317c87b03e5Sespie 	  gave_help = true;
3318c87b03e5Sespie 	  warning ("(so you should pass `%s' not `%s' to `va_arg')",
3319c87b03e5Sespie 		   pname, name);
3320c87b03e5Sespie 	}
3321c87b03e5Sespie 
3322c87b03e5Sespie       /* We can, however, treat "undefined" any way we please.
3323c87b03e5Sespie 	 Call abort to encourage the user to fix the program.  */
3324c87b03e5Sespie       expand_builtin_trap ();
3325c87b03e5Sespie 
3326c87b03e5Sespie       /* This is dead code, but go ahead and finish so that the
3327c87b03e5Sespie 	 mode of the result comes out right.  */
3328c87b03e5Sespie       addr = const0_rtx;
3329c87b03e5Sespie     }
3330c87b03e5Sespie   else
3331c87b03e5Sespie     {
3332c87b03e5Sespie       /* Make it easier for the backends by protecting the valist argument
3333c87b03e5Sespie          from multiple evaluations.  */
3334c87b03e5Sespie       valist = stabilize_va_list (valist, 0);
3335c87b03e5Sespie 
3336c87b03e5Sespie #ifdef EXPAND_BUILTIN_VA_ARG
3337c87b03e5Sespie       addr = EXPAND_BUILTIN_VA_ARG (valist, type);
3338c87b03e5Sespie #else
3339c87b03e5Sespie       addr = std_expand_builtin_va_arg (valist, type);
3340c87b03e5Sespie #endif
3341c87b03e5Sespie     }
3342c87b03e5Sespie 
3343c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
3344c87b03e5Sespie   if (GET_MODE (addr) != Pmode)
3345c87b03e5Sespie     addr = convert_memory_address (Pmode, addr);
3346c87b03e5Sespie #endif
3347c87b03e5Sespie 
3348c87b03e5Sespie   result = gen_rtx_MEM (TYPE_MODE (type), addr);
3349c87b03e5Sespie   set_mem_alias_set (result, get_varargs_alias_set ());
3350c87b03e5Sespie 
3351c87b03e5Sespie   return result;
3352c87b03e5Sespie }
3353c87b03e5Sespie 
3354c87b03e5Sespie /* Expand ARGLIST, from a call to __builtin_va_end.  */
3355c87b03e5Sespie 
3356c87b03e5Sespie static rtx
expand_builtin_va_end(arglist)3357c87b03e5Sespie expand_builtin_va_end (arglist)
3358c87b03e5Sespie      tree arglist;
3359c87b03e5Sespie {
3360c87b03e5Sespie   tree valist = TREE_VALUE (arglist);
3361c87b03e5Sespie 
3362c87b03e5Sespie #ifdef EXPAND_BUILTIN_VA_END
3363c87b03e5Sespie   valist = stabilize_va_list (valist, 0);
3364c87b03e5Sespie   EXPAND_BUILTIN_VA_END (arglist);
3365c87b03e5Sespie #else
3366c87b03e5Sespie   /* Evaluate for side effects, if needed.  I hate macros that don't
3367c87b03e5Sespie      do that.  */
3368c87b03e5Sespie   if (TREE_SIDE_EFFECTS (valist))
3369c87b03e5Sespie     expand_expr (valist, const0_rtx, VOIDmode, EXPAND_NORMAL);
3370c87b03e5Sespie #endif
3371c87b03e5Sespie 
3372c87b03e5Sespie   return const0_rtx;
3373c87b03e5Sespie }
3374c87b03e5Sespie 
3375c87b03e5Sespie /* Expand ARGLIST, from a call to __builtin_va_copy.  We do this as a
3376c87b03e5Sespie    builtin rather than just as an assignment in stdarg.h because of the
3377c87b03e5Sespie    nastiness of array-type va_list types.  */
3378c87b03e5Sespie 
3379c87b03e5Sespie static rtx
expand_builtin_va_copy(arglist)3380c87b03e5Sespie expand_builtin_va_copy (arglist)
3381c87b03e5Sespie      tree arglist;
3382c87b03e5Sespie {
3383c87b03e5Sespie   tree dst, src, t;
3384c87b03e5Sespie 
3385c87b03e5Sespie   dst = TREE_VALUE (arglist);
3386c87b03e5Sespie   src = TREE_VALUE (TREE_CHAIN (arglist));
3387c87b03e5Sespie 
3388c87b03e5Sespie   dst = stabilize_va_list (dst, 1);
3389c87b03e5Sespie   src = stabilize_va_list (src, 0);
3390c87b03e5Sespie 
3391c87b03e5Sespie   if (TREE_CODE (va_list_type_node) != ARRAY_TYPE)
3392c87b03e5Sespie     {
3393c87b03e5Sespie       t = build (MODIFY_EXPR, va_list_type_node, dst, src);
3394c87b03e5Sespie       TREE_SIDE_EFFECTS (t) = 1;
3395c87b03e5Sespie       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
3396c87b03e5Sespie     }
3397c87b03e5Sespie   else
3398c87b03e5Sespie     {
3399c87b03e5Sespie       rtx dstb, srcb, size;
3400c87b03e5Sespie 
3401c87b03e5Sespie       /* Evaluate to pointers.  */
3402c87b03e5Sespie       dstb = expand_expr (dst, NULL_RTX, Pmode, EXPAND_NORMAL);
3403c87b03e5Sespie       srcb = expand_expr (src, NULL_RTX, Pmode, EXPAND_NORMAL);
3404c87b03e5Sespie       size = expand_expr (TYPE_SIZE_UNIT (va_list_type_node), NULL_RTX,
3405c87b03e5Sespie 			  VOIDmode, EXPAND_NORMAL);
3406c87b03e5Sespie 
3407c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
3408c87b03e5Sespie       if (GET_MODE (dstb) != Pmode)
3409c87b03e5Sespie 	dstb = convert_memory_address (Pmode, dstb);
3410c87b03e5Sespie 
3411c87b03e5Sespie       if (GET_MODE (srcb) != Pmode)
3412c87b03e5Sespie 	srcb = convert_memory_address (Pmode, srcb);
3413c87b03e5Sespie #endif
3414c87b03e5Sespie 
3415c87b03e5Sespie       /* "Dereference" to BLKmode memories.  */
3416c87b03e5Sespie       dstb = gen_rtx_MEM (BLKmode, dstb);
3417c87b03e5Sespie       set_mem_alias_set (dstb, get_alias_set (TREE_TYPE (TREE_TYPE (dst))));
3418c87b03e5Sespie       set_mem_align (dstb, TYPE_ALIGN (va_list_type_node));
3419c87b03e5Sespie       srcb = gen_rtx_MEM (BLKmode, srcb);
3420c87b03e5Sespie       set_mem_alias_set (srcb, get_alias_set (TREE_TYPE (TREE_TYPE (src))));
3421c87b03e5Sespie       set_mem_align (srcb, TYPE_ALIGN (va_list_type_node));
3422c87b03e5Sespie 
3423c87b03e5Sespie       /* Copy.  */
3424c87b03e5Sespie       emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL);
3425c87b03e5Sespie     }
3426c87b03e5Sespie 
3427c87b03e5Sespie   return const0_rtx;
3428c87b03e5Sespie }
3429c87b03e5Sespie 
3430c87b03e5Sespie /* Expand a call to one of the builtin functions __builtin_frame_address or
3431c87b03e5Sespie    __builtin_return_address.  */
3432c87b03e5Sespie 
3433c87b03e5Sespie static rtx
expand_builtin_frame_address(exp)3434c87b03e5Sespie expand_builtin_frame_address (exp)
3435c87b03e5Sespie      tree exp;
3436c87b03e5Sespie {
3437c87b03e5Sespie   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
3438c87b03e5Sespie   tree arglist = TREE_OPERAND (exp, 1);
3439c87b03e5Sespie 
3440c87b03e5Sespie   /* The argument must be a nonnegative integer constant.
3441c87b03e5Sespie      It counts the number of frames to scan up the stack.
3442c87b03e5Sespie      The value is the return address saved in that frame.  */
3443c87b03e5Sespie   if (arglist == 0)
3444c87b03e5Sespie     /* Warning about missing arg was already issued.  */
3445c87b03e5Sespie     return const0_rtx;
3446c87b03e5Sespie   else if (! host_integerp (TREE_VALUE (arglist), 1))
3447c87b03e5Sespie     {
3448c87b03e5Sespie       if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
3449c87b03e5Sespie 	error ("invalid arg to `__builtin_frame_address'");
3450c87b03e5Sespie       else
3451c87b03e5Sespie 	error ("invalid arg to `__builtin_return_address'");
3452c87b03e5Sespie       return const0_rtx;
3453c87b03e5Sespie     }
3454c87b03e5Sespie   else
3455c87b03e5Sespie     {
3456c87b03e5Sespie       rtx tem
3457c87b03e5Sespie 	= expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl),
3458c87b03e5Sespie 				      tree_low_cst (TREE_VALUE (arglist), 1),
3459c87b03e5Sespie 				      hard_frame_pointer_rtx);
3460c87b03e5Sespie 
3461c87b03e5Sespie       /* Some ports cannot access arbitrary stack frames.  */
3462c87b03e5Sespie       if (tem == NULL)
3463c87b03e5Sespie 	{
3464c87b03e5Sespie 	  if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
3465c87b03e5Sespie 	    warning ("unsupported arg to `__builtin_frame_address'");
3466c87b03e5Sespie 	  else
3467c87b03e5Sespie 	    warning ("unsupported arg to `__builtin_return_address'");
3468c87b03e5Sespie 	  return const0_rtx;
3469c87b03e5Sespie 	}
3470c87b03e5Sespie 
3471c87b03e5Sespie       /* For __builtin_frame_address, return what we've got.  */
3472c87b03e5Sespie       if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
3473c87b03e5Sespie 	return tem;
3474c87b03e5Sespie 
3475c87b03e5Sespie       if (GET_CODE (tem) != REG
3476c87b03e5Sespie 	  && ! CONSTANT_P (tem))
3477c87b03e5Sespie 	tem = copy_to_mode_reg (Pmode, tem);
3478c87b03e5Sespie       return tem;
3479c87b03e5Sespie     }
3480c87b03e5Sespie }
3481c87b03e5Sespie 
3482c87b03e5Sespie /* Expand a call to the alloca builtin, with arguments ARGLIST.  Return 0 if
3483c87b03e5Sespie    we failed and the caller should emit a normal call, otherwise try to get
3484c87b03e5Sespie    the result in TARGET, if convenient.  */
3485c87b03e5Sespie 
3486c87b03e5Sespie static rtx
expand_builtin_alloca(arglist,target)3487c87b03e5Sespie expand_builtin_alloca (arglist, target)
3488c87b03e5Sespie      tree arglist;
3489c87b03e5Sespie      rtx target;
3490c87b03e5Sespie {
3491c87b03e5Sespie   rtx op0;
3492c87b03e5Sespie   rtx result;
3493c87b03e5Sespie 
3494c87b03e5Sespie   if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
3495c87b03e5Sespie     return 0;
3496c87b03e5Sespie 
3497c87b03e5Sespie   /* Compute the argument.  */
3498c87b03e5Sespie   op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
3499c87b03e5Sespie 
3500c87b03e5Sespie   /* Allocate the desired space.  */
3501c87b03e5Sespie   result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
3502c87b03e5Sespie 
3503c87b03e5Sespie #ifdef POINTERS_EXTEND_UNSIGNED
3504c87b03e5Sespie   if (GET_MODE (result) != ptr_mode)
3505c87b03e5Sespie     result = convert_memory_address (ptr_mode, result);
3506c87b03e5Sespie #endif
3507c87b03e5Sespie 
3508c87b03e5Sespie   return result;
3509c87b03e5Sespie }
3510c87b03e5Sespie 
3511c87b03e5Sespie /* Expand a call to the ffs builtin.  The arguments are in ARGLIST.
3512c87b03e5Sespie    Return 0 if a normal call should be emitted rather than expanding the
3513c87b03e5Sespie    function in-line.  If convenient, the result should be placed in TARGET.
3514c87b03e5Sespie    SUBTARGET may be used as the target for computing one of EXP's operands.  */
3515c87b03e5Sespie 
3516c87b03e5Sespie static rtx
expand_builtin_ffs(arglist,target,subtarget)3517c87b03e5Sespie expand_builtin_ffs (arglist, target, subtarget)
3518c87b03e5Sespie      tree arglist;
3519c87b03e5Sespie      rtx target, subtarget;
3520c87b03e5Sespie {
3521c87b03e5Sespie   rtx op0;
3522c87b03e5Sespie   if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
3523c87b03e5Sespie     return 0;
3524c87b03e5Sespie 
3525c87b03e5Sespie   /* Compute the argument.  */
3526c87b03e5Sespie   op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
3527c87b03e5Sespie   /* Compute ffs, into TARGET if possible.
3528c87b03e5Sespie      Set TARGET to wherever the result comes back.  */
3529c87b03e5Sespie   target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
3530c87b03e5Sespie 			ffs_optab, op0, target, 1);
3531c87b03e5Sespie   if (target == 0)
3532c87b03e5Sespie     abort ();
3533c87b03e5Sespie   return target;
3534c87b03e5Sespie }
3535c87b03e5Sespie 
3536c87b03e5Sespie /* If the string passed to fputs is a constant and is one character
3537c87b03e5Sespie    long, we attempt to transform this call into __builtin_fputc().  */
3538c87b03e5Sespie 
3539c87b03e5Sespie static rtx
expand_builtin_fputs(arglist,ignore,unlocked)3540c87b03e5Sespie expand_builtin_fputs (arglist, ignore, unlocked)
3541c87b03e5Sespie      tree arglist;
3542c87b03e5Sespie      int ignore;
3543c87b03e5Sespie      int unlocked;
3544c87b03e5Sespie {
3545c87b03e5Sespie   tree len, fn;
3546c87b03e5Sespie   tree fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
3547c87b03e5Sespie     : built_in_decls[BUILT_IN_FPUTC];
3548c87b03e5Sespie   tree fn_fwrite = unlocked ? built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
3549c87b03e5Sespie     : built_in_decls[BUILT_IN_FWRITE];
3550c87b03e5Sespie 
3551c87b03e5Sespie   /* If the return value is used, or the replacement _DECL isn't
3552c87b03e5Sespie      initialized, don't do the transformation.  */
3553c87b03e5Sespie   if (!ignore || !fn_fputc || !fn_fwrite)
3554c87b03e5Sespie     return 0;
3555c87b03e5Sespie 
3556c87b03e5Sespie   /* Verify the arguments in the original call.  */
3557c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
3558c87b03e5Sespie     return 0;
3559c87b03e5Sespie 
3560c87b03e5Sespie   /* Get the length of the string passed to fputs.  If the length
3561c87b03e5Sespie      can't be determined, punt.  */
3562c87b03e5Sespie   if (!(len = c_strlen (TREE_VALUE (arglist)))
3563c87b03e5Sespie       || TREE_CODE (len) != INTEGER_CST)
3564c87b03e5Sespie     return 0;
3565c87b03e5Sespie 
3566c87b03e5Sespie   switch (compare_tree_int (len, 1))
3567c87b03e5Sespie     {
3568c87b03e5Sespie     case -1: /* length is 0, delete the call entirely .  */
3569c87b03e5Sespie       {
3570c87b03e5Sespie 	/* Evaluate and ignore the argument in case it has
3571c87b03e5Sespie            side-effects.  */
3572c87b03e5Sespie 	expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx,
3573c87b03e5Sespie 		     VOIDmode, EXPAND_NORMAL);
3574c87b03e5Sespie 	return const0_rtx;
3575c87b03e5Sespie       }
3576c87b03e5Sespie     case 0: /* length is 1, call fputc.  */
3577c87b03e5Sespie       {
3578c87b03e5Sespie 	const char *p = c_getstr (TREE_VALUE (arglist));
3579c87b03e5Sespie 
3580c87b03e5Sespie 	if (p != NULL)
3581c87b03e5Sespie 	  {
3582c87b03e5Sespie 	    /* New argument list transforming fputs(string, stream) to
3583c87b03e5Sespie 	       fputc(string[0], stream).  */
3584c87b03e5Sespie 	    arglist =
3585c87b03e5Sespie 	      build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)));
3586c87b03e5Sespie 	    arglist =
3587c87b03e5Sespie 	      tree_cons (NULL_TREE, build_int_2 (p[0], 0), arglist);
3588c87b03e5Sespie 	    fn = fn_fputc;
3589c87b03e5Sespie 	    break;
3590c87b03e5Sespie 	  }
3591c87b03e5Sespie       }
3592c87b03e5Sespie       /* FALLTHROUGH */
3593c87b03e5Sespie     case 1: /* length is greater than 1, call fwrite.  */
3594c87b03e5Sespie       {
3595c87b03e5Sespie 	tree string_arg;
3596c87b03e5Sespie 
3597c87b03e5Sespie 	/* If optimizing for size keep fputs. */
3598c87b03e5Sespie 	if (optimize_size)
3599c87b03e5Sespie 	  return 0;
3600c87b03e5Sespie 	string_arg = TREE_VALUE (arglist);
3601c87b03e5Sespie 	/* New argument list transforming fputs(string, stream) to
3602c87b03e5Sespie 	   fwrite(string, 1, len, stream).  */
3603c87b03e5Sespie 	arglist = build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)));
3604c87b03e5Sespie 	arglist = tree_cons (NULL_TREE, len, arglist);
3605c87b03e5Sespie 	arglist = tree_cons (NULL_TREE, size_one_node, arglist);
3606c87b03e5Sespie 	arglist = tree_cons (NULL_TREE, string_arg, arglist);
3607c87b03e5Sespie 	fn = fn_fwrite;
3608c87b03e5Sespie 	break;
3609c87b03e5Sespie       }
3610c87b03e5Sespie     default:
3611c87b03e5Sespie       abort ();
3612c87b03e5Sespie     }
3613c87b03e5Sespie 
3614c87b03e5Sespie   return expand_expr (build_function_call_expr (fn, arglist),
3615c87b03e5Sespie 		      (ignore ? const0_rtx : NULL_RTX),
3616c87b03e5Sespie 		      VOIDmode, EXPAND_NORMAL);
3617c87b03e5Sespie }
3618c87b03e5Sespie 
3619c87b03e5Sespie /* Expand a call to __builtin_expect.  We return our argument and emit a
3620c87b03e5Sespie    NOTE_INSN_EXPECTED_VALUE note.  This is the expansion of __builtin_expect in
3621c87b03e5Sespie    a non-jump context.  */
3622c87b03e5Sespie 
3623c87b03e5Sespie static rtx
expand_builtin_expect(arglist,target)3624c87b03e5Sespie expand_builtin_expect (arglist, target)
3625c87b03e5Sespie      tree arglist;
3626c87b03e5Sespie      rtx target;
3627c87b03e5Sespie {
3628c87b03e5Sespie   tree exp, c;
3629c87b03e5Sespie   rtx note, rtx_c;
3630c87b03e5Sespie 
3631c87b03e5Sespie   if (arglist == NULL_TREE
3632c87b03e5Sespie       || TREE_CHAIN (arglist) == NULL_TREE)
3633c87b03e5Sespie     return const0_rtx;
3634c87b03e5Sespie   exp = TREE_VALUE (arglist);
3635c87b03e5Sespie   c = TREE_VALUE (TREE_CHAIN (arglist));
3636c87b03e5Sespie 
3637c87b03e5Sespie   if (TREE_CODE (c) != INTEGER_CST)
3638c87b03e5Sespie     {
3639c87b03e5Sespie       error ("second arg to `__builtin_expect' must be a constant");
3640c87b03e5Sespie       c = integer_zero_node;
3641c87b03e5Sespie     }
3642c87b03e5Sespie 
3643c87b03e5Sespie   target = expand_expr (exp, target, VOIDmode, EXPAND_NORMAL);
3644c87b03e5Sespie 
3645c87b03e5Sespie   /* Don't bother with expected value notes for integral constants.  */
3646c87b03e5Sespie   if (flag_guess_branch_prob && GET_CODE (target) != CONST_INT)
3647c87b03e5Sespie     {
3648c87b03e5Sespie       /* We do need to force this into a register so that we can be
3649c87b03e5Sespie 	 moderately sure to be able to correctly interpret the branch
3650c87b03e5Sespie 	 condition later.  */
3651c87b03e5Sespie       target = force_reg (GET_MODE (target), target);
3652c87b03e5Sespie 
3653c87b03e5Sespie       rtx_c = expand_expr (c, NULL_RTX, GET_MODE (target), EXPAND_NORMAL);
3654c87b03e5Sespie 
3655c87b03e5Sespie       note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE);
3656c87b03e5Sespie       NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, target, rtx_c);
3657c87b03e5Sespie     }
3658c87b03e5Sespie 
3659c87b03e5Sespie   return target;
3660c87b03e5Sespie }
3661c87b03e5Sespie 
3662c87b03e5Sespie /* Like expand_builtin_expect, except do this in a jump context.  This is
3663c87b03e5Sespie    called from do_jump if the conditional is a __builtin_expect.  Return either
3664c87b03e5Sespie    a list of insns to emit the jump or NULL if we cannot optimize
3665c87b03e5Sespie    __builtin_expect.  We need to optimize this at jump time so that machines
3666c87b03e5Sespie    like the PowerPC don't turn the test into a SCC operation, and then jump
3667c87b03e5Sespie    based on the test being 0/1.  */
3668c87b03e5Sespie 
3669c87b03e5Sespie rtx
expand_builtin_expect_jump(exp,if_false_label,if_true_label)3670c87b03e5Sespie expand_builtin_expect_jump (exp, if_false_label, if_true_label)
3671c87b03e5Sespie      tree exp;
3672c87b03e5Sespie      rtx if_false_label;
3673c87b03e5Sespie      rtx if_true_label;
3674c87b03e5Sespie {
3675c87b03e5Sespie   tree arglist = TREE_OPERAND (exp, 1);
3676c87b03e5Sespie   tree arg0 = TREE_VALUE (arglist);
3677c87b03e5Sespie   tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
3678c87b03e5Sespie   rtx ret = NULL_RTX;
3679c87b03e5Sespie 
3680c87b03e5Sespie   /* Only handle __builtin_expect (test, 0) and
3681c87b03e5Sespie      __builtin_expect (test, 1).  */
3682c87b03e5Sespie   if (TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE
3683c87b03e5Sespie       && (integer_zerop (arg1) || integer_onep (arg1)))
3684c87b03e5Sespie     {
3685*06dc6460Sespie       rtx insn, drop_through_label;
3686c87b03e5Sespie 
3687c87b03e5Sespie       /* Expand the jump insns.  */
3688c87b03e5Sespie       start_sequence ();
3689c87b03e5Sespie       do_jump (arg0, if_false_label, if_true_label);
3690c87b03e5Sespie       ret = get_insns ();
3691*06dc6460Sespie 
3692*06dc6460Sespie       drop_through_label = get_last_insn ();
3693*06dc6460Sespie       if (drop_through_label && GET_CODE (drop_through_label) == NOTE)
3694*06dc6460Sespie 	drop_through_label = prev_nonnote_insn (drop_through_label);
3695*06dc6460Sespie       if (drop_through_label && GET_CODE (drop_through_label) != CODE_LABEL)
3696*06dc6460Sespie 	drop_through_label = NULL_RTX;
3697c87b03e5Sespie       end_sequence ();
3698c87b03e5Sespie 
3699*06dc6460Sespie       if (! if_true_label)
3700*06dc6460Sespie 	if_true_label = drop_through_label;
3701*06dc6460Sespie       if (! if_false_label)
3702*06dc6460Sespie 	if_false_label = drop_through_label;
3703*06dc6460Sespie 
3704c87b03e5Sespie       /* Now that the __builtin_expect has been validated, go through and add
3705c87b03e5Sespie 	 the expect's to each of the conditional jumps.  If we run into an
3706c87b03e5Sespie 	 error, just give up and generate the 'safe' code of doing a SCC
3707c87b03e5Sespie 	 operation and then doing a branch on that.  */
3708c87b03e5Sespie       insn = ret;
3709c87b03e5Sespie       while (insn != NULL_RTX)
3710c87b03e5Sespie 	{
3711c87b03e5Sespie 	  rtx next = NEXT_INSN (insn);
3712c87b03e5Sespie 	  rtx pattern;
3713c87b03e5Sespie 
3714c87b03e5Sespie 	  if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn)
3715c87b03e5Sespie 	      && (pattern = pc_set (insn)) != NULL_RTX)
3716c87b03e5Sespie 	    {
3717c87b03e5Sespie 	      rtx ifelse = SET_SRC (pattern);
3718c87b03e5Sespie 	      rtx label;
3719c87b03e5Sespie 	      int taken;
3720c87b03e5Sespie 
3721c87b03e5Sespie 	      if (GET_CODE (ifelse) != IF_THEN_ELSE)
3722c87b03e5Sespie 		goto do_next_insn;
3723c87b03e5Sespie 
3724c87b03e5Sespie 	      if (GET_CODE (XEXP (ifelse, 1)) == LABEL_REF)
3725c87b03e5Sespie 		{
3726c87b03e5Sespie 		  taken = 1;
3727c87b03e5Sespie 		  label = XEXP (XEXP (ifelse, 1), 0);
3728c87b03e5Sespie 		}
3729c87b03e5Sespie 	      /* An inverted jump reverses the probabilities.  */
3730c87b03e5Sespie 	      else if (GET_CODE (XEXP (ifelse, 2)) == LABEL_REF)
3731c87b03e5Sespie 		{
3732c87b03e5Sespie 		  taken = 0;
3733c87b03e5Sespie 		  label = XEXP (XEXP (ifelse, 2), 0);
3734c87b03e5Sespie 		}
3735c87b03e5Sespie 	      /* We shouldn't have to worry about conditional returns during
3736c87b03e5Sespie 		 the expansion stage, but handle it gracefully anyway.  */
3737c87b03e5Sespie 	      else if (GET_CODE (XEXP (ifelse, 1)) == RETURN)
3738c87b03e5Sespie 		{
3739c87b03e5Sespie 		  taken = 1;
3740c87b03e5Sespie 		  label = NULL_RTX;
3741c87b03e5Sespie 		}
3742c87b03e5Sespie 	      /* An inverted return reverses the probabilities.  */
3743c87b03e5Sespie 	      else if (GET_CODE (XEXP (ifelse, 2)) == RETURN)
3744c87b03e5Sespie 		{
3745c87b03e5Sespie 		  taken = 0;
3746c87b03e5Sespie 		  label = NULL_RTX;
3747c87b03e5Sespie 		}
3748c87b03e5Sespie 	      else
3749c87b03e5Sespie 		goto do_next_insn;
3750c87b03e5Sespie 
3751c87b03e5Sespie 	      /* If the test is expected to fail, reverse the
3752c87b03e5Sespie 		 probabilities.  */
3753c87b03e5Sespie 	      if (integer_zerop (arg1))
3754c87b03e5Sespie 		taken = 1 - taken;
3755c87b03e5Sespie 
3756c87b03e5Sespie 	      /* If we are jumping to the false label, reverse the
3757c87b03e5Sespie 		 probabilities.  */
3758c87b03e5Sespie 	      if (label == NULL_RTX)
3759c87b03e5Sespie 		;		/* conditional return */
3760c87b03e5Sespie 	      else if (label == if_false_label)
3761c87b03e5Sespie 		taken = 1 - taken;
3762c87b03e5Sespie 	      else if (label != if_true_label)
3763c87b03e5Sespie 		goto do_next_insn;
3764c87b03e5Sespie 
3765c87b03e5Sespie 	      predict_insn_def (insn, PRED_BUILTIN_EXPECT, taken);
3766c87b03e5Sespie 	    }
3767c87b03e5Sespie 
3768c87b03e5Sespie 	do_next_insn:
3769c87b03e5Sespie 	  insn = next;
3770c87b03e5Sespie 	}
3771c87b03e5Sespie     }
3772c87b03e5Sespie 
3773c87b03e5Sespie   return ret;
3774c87b03e5Sespie }
3775c87b03e5Sespie 
3776c87b03e5Sespie void
expand_builtin_trap()3777c87b03e5Sespie expand_builtin_trap ()
3778c87b03e5Sespie {
3779c87b03e5Sespie #ifdef HAVE_trap
3780c87b03e5Sespie   if (HAVE_trap)
3781c87b03e5Sespie     emit_insn (gen_trap ());
3782c87b03e5Sespie   else
3783c87b03e5Sespie #endif
3784c87b03e5Sespie     emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
3785c87b03e5Sespie   emit_barrier ();
3786c87b03e5Sespie }
3787c87b03e5Sespie 
3788c87b03e5Sespie /* Expand an expression EXP that calls a built-in function,
3789c87b03e5Sespie    with result going to TARGET if that's convenient
3790c87b03e5Sespie    (and in mode MODE if that's convenient).
3791c87b03e5Sespie    SUBTARGET may be used as the target for computing one of EXP's operands.
3792c87b03e5Sespie    IGNORE is nonzero if the value is to be ignored.  */
3793c87b03e5Sespie 
3794c87b03e5Sespie rtx
expand_builtin(exp,target,subtarget,mode,ignore)3795c87b03e5Sespie expand_builtin (exp, target, subtarget, mode, ignore)
3796c87b03e5Sespie      tree exp;
3797c87b03e5Sespie      rtx target;
3798c87b03e5Sespie      rtx subtarget;
3799c87b03e5Sespie      enum machine_mode mode;
3800c87b03e5Sespie      int ignore;
3801c87b03e5Sespie {
3802c87b03e5Sespie   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
3803c87b03e5Sespie   tree arglist = TREE_OPERAND (exp, 1);
3804c87b03e5Sespie   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
3805c87b03e5Sespie 
3806c87b03e5Sespie   /* Perform postincrements before expanding builtin functions. �*/
3807c87b03e5Sespie   emit_queue ();
3808c87b03e5Sespie 
3809c87b03e5Sespie   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
3810c87b03e5Sespie     return (*targetm.expand_builtin) (exp, target, subtarget, mode, ignore);
3811c87b03e5Sespie 
3812c87b03e5Sespie   /* When not optimizing, generate calls to library functions for a certain
3813c87b03e5Sespie      set of builtins.  */
3814c87b03e5Sespie   if (!optimize && !CALLED_AS_BUILT_IN (fndecl))
3815c87b03e5Sespie     switch (fcode)
3816c87b03e5Sespie       {
3817c87b03e5Sespie       case BUILT_IN_SQRT:
3818c87b03e5Sespie       case BUILT_IN_SQRTF:
3819c87b03e5Sespie       case BUILT_IN_SQRTL:
3820c87b03e5Sespie       case BUILT_IN_SIN:
3821c87b03e5Sespie       case BUILT_IN_SINF:
3822c87b03e5Sespie       case BUILT_IN_SINL:
3823c87b03e5Sespie       case BUILT_IN_COS:
3824c87b03e5Sespie       case BUILT_IN_COSF:
3825c87b03e5Sespie       case BUILT_IN_COSL:
3826c87b03e5Sespie       case BUILT_IN_EXP:
3827c87b03e5Sespie       case BUILT_IN_EXPF:
3828c87b03e5Sespie       case BUILT_IN_EXPL:
3829c87b03e5Sespie       case BUILT_IN_MEMSET:
3830c87b03e5Sespie       case BUILT_IN_MEMCPY:
3831c87b03e5Sespie       case BUILT_IN_MEMCMP:
3832c87b03e5Sespie       case BUILT_IN_BCMP:
3833c87b03e5Sespie       case BUILT_IN_BZERO:
3834c87b03e5Sespie       case BUILT_IN_INDEX:
3835c87b03e5Sespie       case BUILT_IN_RINDEX:
3836c87b03e5Sespie       case BUILT_IN_STRCHR:
3837c87b03e5Sespie       case BUILT_IN_STRRCHR:
3838c87b03e5Sespie       case BUILT_IN_STRLEN:
3839c87b03e5Sespie       case BUILT_IN_STRCPY:
3840c87b03e5Sespie       case BUILT_IN_STRNCPY:
3841c87b03e5Sespie       case BUILT_IN_STRNCMP:
3842c87b03e5Sespie       case BUILT_IN_STRSTR:
3843c87b03e5Sespie       case BUILT_IN_STRPBRK:
3844c87b03e5Sespie       case BUILT_IN_STRCAT:
3845c87b03e5Sespie       case BUILT_IN_STRNCAT:
3846c87b03e5Sespie       case BUILT_IN_STRSPN:
3847c87b03e5Sespie       case BUILT_IN_STRCSPN:
3848c87b03e5Sespie       case BUILT_IN_STRCMP:
3849c87b03e5Sespie       case BUILT_IN_FFS:
3850c87b03e5Sespie       case BUILT_IN_PUTCHAR:
3851c87b03e5Sespie       case BUILT_IN_PUTS:
3852c87b03e5Sespie       case BUILT_IN_PRINTF:
3853c87b03e5Sespie       case BUILT_IN_FPUTC:
3854c87b03e5Sespie       case BUILT_IN_FPUTS:
3855c87b03e5Sespie       case BUILT_IN_FWRITE:
3856c87b03e5Sespie       case BUILT_IN_PUTCHAR_UNLOCKED:
3857c87b03e5Sespie       case BUILT_IN_PUTS_UNLOCKED:
3858c87b03e5Sespie       case BUILT_IN_PRINTF_UNLOCKED:
3859c87b03e5Sespie       case BUILT_IN_FPUTC_UNLOCKED:
3860c87b03e5Sespie       case BUILT_IN_FPUTS_UNLOCKED:
3861c87b03e5Sespie       case BUILT_IN_FWRITE_UNLOCKED:
3862c87b03e5Sespie 	return expand_call (exp, target, ignore);
3863c87b03e5Sespie 
3864c87b03e5Sespie       default:
3865c87b03e5Sespie 	break;
3866c87b03e5Sespie       }
3867c87b03e5Sespie 
3868c87b03e5Sespie   switch (fcode)
3869c87b03e5Sespie     {
3870c87b03e5Sespie     case BUILT_IN_ABS:
3871c87b03e5Sespie     case BUILT_IN_LABS:
3872c87b03e5Sespie     case BUILT_IN_LLABS:
3873c87b03e5Sespie     case BUILT_IN_IMAXABS:
3874c87b03e5Sespie     case BUILT_IN_FABS:
3875c87b03e5Sespie     case BUILT_IN_FABSF:
3876c87b03e5Sespie     case BUILT_IN_FABSL:
3877c87b03e5Sespie       /* build_function_call changes these into ABS_EXPR.  */
3878c87b03e5Sespie       abort ();
3879c87b03e5Sespie 
3880c87b03e5Sespie     case BUILT_IN_CONJ:
3881c87b03e5Sespie     case BUILT_IN_CONJF:
3882c87b03e5Sespie     case BUILT_IN_CONJL:
3883c87b03e5Sespie     case BUILT_IN_CREAL:
3884c87b03e5Sespie     case BUILT_IN_CREALF:
3885c87b03e5Sespie     case BUILT_IN_CREALL:
3886c87b03e5Sespie     case BUILT_IN_CIMAG:
3887c87b03e5Sespie     case BUILT_IN_CIMAGF:
3888c87b03e5Sespie     case BUILT_IN_CIMAGL:
3889c87b03e5Sespie       /* expand_tree_builtin changes these into CONJ_EXPR, REALPART_EXPR
3890c87b03e5Sespie 	 and IMAGPART_EXPR.  */
3891c87b03e5Sespie       abort ();
3892c87b03e5Sespie 
3893c87b03e5Sespie     case BUILT_IN_SIN:
3894c87b03e5Sespie     case BUILT_IN_SINF:
3895c87b03e5Sespie     case BUILT_IN_SINL:
3896c87b03e5Sespie     case BUILT_IN_COS:
3897c87b03e5Sespie     case BUILT_IN_COSF:
3898c87b03e5Sespie     case BUILT_IN_COSL:
3899c87b03e5Sespie     case BUILT_IN_EXP:
3900c87b03e5Sespie     case BUILT_IN_EXPF:
3901c87b03e5Sespie     case BUILT_IN_EXPL:
3902c87b03e5Sespie     case BUILT_IN_LOG:
3903c87b03e5Sespie     case BUILT_IN_LOGF:
3904c87b03e5Sespie     case BUILT_IN_LOGL:
3905c87b03e5Sespie       /* Treat these like sqrt only if unsafe math optimizations are allowed,
3906c87b03e5Sespie 	 because of possible accuracy problems.  */
3907c87b03e5Sespie       if (! flag_unsafe_math_optimizations)
3908c87b03e5Sespie 	break;
3909c87b03e5Sespie     case BUILT_IN_SQRT:
3910c87b03e5Sespie     case BUILT_IN_SQRTF:
3911c87b03e5Sespie     case BUILT_IN_SQRTL:
3912c87b03e5Sespie       target = expand_builtin_mathfn (exp, target, subtarget);
3913c87b03e5Sespie       if (target)
3914c87b03e5Sespie 	return target;
3915c87b03e5Sespie       break;
3916c87b03e5Sespie 
3917c87b03e5Sespie     case BUILT_IN_APPLY_ARGS:
3918c87b03e5Sespie       return expand_builtin_apply_args ();
3919c87b03e5Sespie 
3920c87b03e5Sespie       /* __builtin_apply (FUNCTION, ARGUMENTS, ARGSIZE) invokes
3921c87b03e5Sespie 	 FUNCTION with a copy of the parameters described by
3922c87b03e5Sespie 	 ARGUMENTS, and ARGSIZE.  It returns a block of memory
3923c87b03e5Sespie 	 allocated on the stack into which is stored all the registers
3924c87b03e5Sespie 	 that might possibly be used for returning the result of a
3925c87b03e5Sespie 	 function.  ARGUMENTS is the value returned by
3926c87b03e5Sespie 	 __builtin_apply_args.  ARGSIZE is the number of bytes of
3927c87b03e5Sespie 	 arguments that must be copied.  ??? How should this value be
3928c87b03e5Sespie 	 computed?  We'll also need a safe worst case value for varargs
3929c87b03e5Sespie 	 functions.  */
3930c87b03e5Sespie     case BUILT_IN_APPLY:
3931c87b03e5Sespie       if (!validate_arglist (arglist, POINTER_TYPE,
3932c87b03e5Sespie 			     POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
3933c87b03e5Sespie 	  && !validate_arglist (arglist, REFERENCE_TYPE,
3934c87b03e5Sespie 				POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
3935c87b03e5Sespie 	return const0_rtx;
3936c87b03e5Sespie       else
3937c87b03e5Sespie 	{
3938c87b03e5Sespie 	  int i;
3939c87b03e5Sespie 	  tree t;
3940c87b03e5Sespie 	  rtx ops[3];
3941c87b03e5Sespie 
3942c87b03e5Sespie 	  for (t = arglist, i = 0; t; t = TREE_CHAIN (t), i++)
3943c87b03e5Sespie 	    ops[i] = expand_expr (TREE_VALUE (t), NULL_RTX, VOIDmode, 0);
3944c87b03e5Sespie 
3945c87b03e5Sespie 	  return expand_builtin_apply (ops[0], ops[1], ops[2]);
3946c87b03e5Sespie 	}
3947c87b03e5Sespie 
3948c87b03e5Sespie       /* __builtin_return (RESULT) causes the function to return the
3949c87b03e5Sespie 	 value described by RESULT.  RESULT is address of the block of
3950c87b03e5Sespie 	 memory returned by __builtin_apply.  */
3951c87b03e5Sespie     case BUILT_IN_RETURN:
3952c87b03e5Sespie       if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
3953c87b03e5Sespie 	expand_builtin_return (expand_expr (TREE_VALUE (arglist),
3954c87b03e5Sespie 					    NULL_RTX, VOIDmode, 0));
3955c87b03e5Sespie       return const0_rtx;
3956c87b03e5Sespie 
3957c87b03e5Sespie     case BUILT_IN_SAVEREGS:
3958c87b03e5Sespie       return expand_builtin_saveregs ();
3959c87b03e5Sespie 
3960c87b03e5Sespie     case BUILT_IN_ARGS_INFO:
3961c87b03e5Sespie       return expand_builtin_args_info (exp);
3962c87b03e5Sespie 
3963c87b03e5Sespie       /* Return the address of the first anonymous stack arg.  */
3964c87b03e5Sespie     case BUILT_IN_NEXT_ARG:
3965c87b03e5Sespie       return expand_builtin_next_arg (arglist);
3966c87b03e5Sespie 
3967c87b03e5Sespie     case BUILT_IN_CLASSIFY_TYPE:
3968c87b03e5Sespie       return expand_builtin_classify_type (arglist);
3969c87b03e5Sespie 
3970c87b03e5Sespie     case BUILT_IN_CONSTANT_P:
3971c87b03e5Sespie       return expand_builtin_constant_p (exp);
3972c87b03e5Sespie 
3973c87b03e5Sespie     case BUILT_IN_FRAME_ADDRESS:
3974c87b03e5Sespie     case BUILT_IN_RETURN_ADDRESS:
3975c87b03e5Sespie       return expand_builtin_frame_address (exp);
3976c87b03e5Sespie 
3977c87b03e5Sespie     /* Returns the address of the area where the structure is returned.
3978c87b03e5Sespie        0 otherwise.  */
3979c87b03e5Sespie     case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
3980c87b03e5Sespie       if (arglist != 0
3981c87b03e5Sespie 	  || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
3982c87b03e5Sespie 	  || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM)
3983c87b03e5Sespie 	return const0_rtx;
3984c87b03e5Sespie       else
3985c87b03e5Sespie 	return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
3986c87b03e5Sespie 
3987c87b03e5Sespie     case BUILT_IN_ALLOCA:
3988c87b03e5Sespie       target = expand_builtin_alloca (arglist, target);
3989c87b03e5Sespie       if (target)
3990c87b03e5Sespie 	return target;
3991c87b03e5Sespie       break;
3992c87b03e5Sespie 
3993c87b03e5Sespie     case BUILT_IN_FFS:
3994c87b03e5Sespie       target = expand_builtin_ffs (arglist, target, subtarget);
3995c87b03e5Sespie       if (target)
3996c87b03e5Sespie 	return target;
3997c87b03e5Sespie       break;
3998c87b03e5Sespie 
3999c87b03e5Sespie     case BUILT_IN_STRLEN:
4000c87b03e5Sespie       target = expand_builtin_strlen (exp, target);
4001c87b03e5Sespie       if (target)
4002c87b03e5Sespie 	return target;
4003c87b03e5Sespie       break;
4004c87b03e5Sespie 
4005c87b03e5Sespie     case BUILT_IN_STRCPY:
400619064bd8Smiod #ifndef NO_UNSAFE_BUILTINS
4007c87b03e5Sespie       target = expand_builtin_strcpy (exp, target, mode);
4008c87b03e5Sespie       if (target)
4009c87b03e5Sespie 	return target;
401019064bd8Smiod #endif
4011c87b03e5Sespie       break;
4012c87b03e5Sespie 
4013c87b03e5Sespie     case BUILT_IN_STRNCPY:
4014c87b03e5Sespie       target = expand_builtin_strncpy (arglist, target, mode);
4015c87b03e5Sespie       if (target)
4016c87b03e5Sespie 	return target;
4017c87b03e5Sespie       break;
4018c87b03e5Sespie 
4019c87b03e5Sespie     case BUILT_IN_STRCAT:
402019064bd8Smiod #ifndef NO_UNSAFE_BUILTINS
4021c87b03e5Sespie       target = expand_builtin_strcat (arglist, target, mode);
4022c87b03e5Sespie       if (target)
4023c87b03e5Sespie 	return target;
402419064bd8Smiod #endif
4025c87b03e5Sespie       break;
4026c87b03e5Sespie 
4027c87b03e5Sespie     case BUILT_IN_STRNCAT:
4028c87b03e5Sespie       target = expand_builtin_strncat (arglist, target, mode);
4029c87b03e5Sespie       if (target)
4030c87b03e5Sespie 	return target;
4031c87b03e5Sespie       break;
4032c87b03e5Sespie 
4033c87b03e5Sespie     case BUILT_IN_STRSPN:
4034c87b03e5Sespie       target = expand_builtin_strspn (arglist, target, mode);
4035c87b03e5Sespie       if (target)
4036c87b03e5Sespie 	return target;
4037c87b03e5Sespie       break;
4038c87b03e5Sespie 
4039c87b03e5Sespie     case BUILT_IN_STRCSPN:
4040c87b03e5Sespie       target = expand_builtin_strcspn (arglist, target, mode);
4041c87b03e5Sespie       if (target)
4042c87b03e5Sespie 	return target;
4043c87b03e5Sespie       break;
4044c87b03e5Sespie 
4045c87b03e5Sespie     case BUILT_IN_STRSTR:
4046c87b03e5Sespie       target = expand_builtin_strstr (arglist, target, mode);
4047c87b03e5Sespie       if (target)
4048c87b03e5Sespie 	return target;
4049c87b03e5Sespie       break;
4050c87b03e5Sespie 
4051c87b03e5Sespie     case BUILT_IN_STRPBRK:
4052c87b03e5Sespie       target = expand_builtin_strpbrk (arglist, target, mode);
4053c87b03e5Sespie       if (target)
4054c87b03e5Sespie 	return target;
4055c87b03e5Sespie       break;
4056c87b03e5Sespie 
4057c87b03e5Sespie     case BUILT_IN_INDEX:
4058c87b03e5Sespie     case BUILT_IN_STRCHR:
4059c87b03e5Sespie       target = expand_builtin_strchr (arglist, target, mode);
4060c87b03e5Sespie       if (target)
4061c87b03e5Sespie 	return target;
4062c87b03e5Sespie       break;
4063c87b03e5Sespie 
4064c87b03e5Sespie     case BUILT_IN_RINDEX:
4065c87b03e5Sespie     case BUILT_IN_STRRCHR:
4066c87b03e5Sespie       target = expand_builtin_strrchr (arglist, target, mode);
4067c87b03e5Sespie       if (target)
4068c87b03e5Sespie 	return target;
4069c87b03e5Sespie       break;
4070c87b03e5Sespie 
4071c87b03e5Sespie     case BUILT_IN_MEMCPY:
4072c87b03e5Sespie       target = expand_builtin_memcpy (arglist, target, mode);
4073c87b03e5Sespie       if (target)
4074c87b03e5Sespie 	return target;
4075c87b03e5Sespie       break;
4076c87b03e5Sespie 
4077c87b03e5Sespie     case BUILT_IN_MEMSET:
4078c87b03e5Sespie       target = expand_builtin_memset (exp, target, mode);
4079c87b03e5Sespie       if (target)
4080c87b03e5Sespie 	return target;
4081c87b03e5Sespie       break;
4082c87b03e5Sespie 
4083c87b03e5Sespie     case BUILT_IN_BZERO:
4084c87b03e5Sespie       target = expand_builtin_bzero (exp);
4085c87b03e5Sespie       if (target)
4086c87b03e5Sespie 	return target;
4087c87b03e5Sespie       break;
4088c87b03e5Sespie 
4089c87b03e5Sespie     case BUILT_IN_STRCMP:
4090c87b03e5Sespie       target = expand_builtin_strcmp (exp, target, mode);
4091c87b03e5Sespie       if (target)
4092c87b03e5Sespie 	return target;
4093c87b03e5Sespie       break;
4094c87b03e5Sespie 
4095c87b03e5Sespie     case BUILT_IN_STRNCMP:
4096c87b03e5Sespie       target = expand_builtin_strncmp (exp, target, mode);
4097c87b03e5Sespie       if (target)
4098c87b03e5Sespie 	return target;
4099c87b03e5Sespie       break;
4100c87b03e5Sespie 
4101c87b03e5Sespie     case BUILT_IN_BCMP:
4102c87b03e5Sespie     case BUILT_IN_MEMCMP:
4103c87b03e5Sespie       target = expand_builtin_memcmp (exp, arglist, target, mode);
4104c87b03e5Sespie       if (target)
4105c87b03e5Sespie 	return target;
4106c87b03e5Sespie       break;
4107c87b03e5Sespie 
4108c87b03e5Sespie     case BUILT_IN_SETJMP:
4109c87b03e5Sespie       target = expand_builtin_setjmp (arglist, target);
4110c87b03e5Sespie       if (target)
4111c87b03e5Sespie 	return target;
4112c87b03e5Sespie       break;
4113c87b03e5Sespie 
4114c87b03e5Sespie       /* __builtin_longjmp is passed a pointer to an array of five words.
4115c87b03e5Sespie 	 It's similar to the C library longjmp function but works with
4116c87b03e5Sespie 	 __builtin_setjmp above.  */
4117c87b03e5Sespie     case BUILT_IN_LONGJMP:
4118c87b03e5Sespie       if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
4119c87b03e5Sespie 	break;
4120c87b03e5Sespie       else
4121c87b03e5Sespie 	{
4122c87b03e5Sespie 	  rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
4123c87b03e5Sespie 				      VOIDmode, 0);
4124c87b03e5Sespie 	  rtx value = expand_expr (TREE_VALUE (TREE_CHAIN (arglist)),
4125c87b03e5Sespie 				   NULL_RTX, VOIDmode, 0);
4126c87b03e5Sespie 
4127c87b03e5Sespie 	  if (value != const1_rtx)
4128c87b03e5Sespie 	    {
4129c87b03e5Sespie 	      error ("__builtin_longjmp second argument must be 1");
4130c87b03e5Sespie 	      return const0_rtx;
4131c87b03e5Sespie 	    }
4132c87b03e5Sespie 
4133c87b03e5Sespie 	  expand_builtin_longjmp (buf_addr, value);
4134c87b03e5Sespie 	  return const0_rtx;
4135c87b03e5Sespie 	}
4136c87b03e5Sespie 
4137c87b03e5Sespie     case BUILT_IN_TRAP:
4138c87b03e5Sespie       expand_builtin_trap ();
4139c87b03e5Sespie       return const0_rtx;
4140c87b03e5Sespie 
4141c87b03e5Sespie     case BUILT_IN_FPUTS:
4142c87b03e5Sespie       target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 0);
4143c87b03e5Sespie       if (target)
4144c87b03e5Sespie 	return target;
4145c87b03e5Sespie       break;
4146c87b03e5Sespie     case BUILT_IN_FPUTS_UNLOCKED:
4147c87b03e5Sespie       target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 1);
4148c87b03e5Sespie       if (target)
4149c87b03e5Sespie 	return target;
4150c87b03e5Sespie       break;
4151c87b03e5Sespie 
4152c87b03e5Sespie       /* Various hooks for the DWARF 2 __throw routine.  */
4153c87b03e5Sespie     case BUILT_IN_UNWIND_INIT:
4154c87b03e5Sespie       expand_builtin_unwind_init ();
4155c87b03e5Sespie       return const0_rtx;
4156c87b03e5Sespie     case BUILT_IN_DWARF_CFA:
4157c87b03e5Sespie       return virtual_cfa_rtx;
4158c87b03e5Sespie #ifdef DWARF2_UNWIND_INFO
4159c87b03e5Sespie     case BUILT_IN_DWARF_SP_COLUMN:
4160c87b03e5Sespie       return expand_builtin_dwarf_sp_column ();
4161c87b03e5Sespie     case BUILT_IN_INIT_DWARF_REG_SIZES:
4162c87b03e5Sespie       expand_builtin_init_dwarf_reg_sizes (TREE_VALUE (arglist));
4163c87b03e5Sespie       return const0_rtx;
4164c87b03e5Sespie #endif
4165c87b03e5Sespie     case BUILT_IN_FROB_RETURN_ADDR:
4166c87b03e5Sespie       return expand_builtin_frob_return_addr (TREE_VALUE (arglist));
4167c87b03e5Sespie     case BUILT_IN_EXTRACT_RETURN_ADDR:
4168c87b03e5Sespie       return expand_builtin_extract_return_addr (TREE_VALUE (arglist));
4169c87b03e5Sespie     case BUILT_IN_EH_RETURN:
4170c87b03e5Sespie       expand_builtin_eh_return (TREE_VALUE (arglist),
4171c87b03e5Sespie 				TREE_VALUE (TREE_CHAIN (arglist)));
4172c87b03e5Sespie       return const0_rtx;
4173c87b03e5Sespie #ifdef EH_RETURN_DATA_REGNO
4174c87b03e5Sespie     case BUILT_IN_EH_RETURN_DATA_REGNO:
4175c87b03e5Sespie       return expand_builtin_eh_return_data_regno (arglist);
4176c87b03e5Sespie #endif
4177c87b03e5Sespie     case BUILT_IN_VA_START:
4178c87b03e5Sespie     case BUILT_IN_STDARG_START:
4179c87b03e5Sespie       return expand_builtin_va_start (arglist);
4180c87b03e5Sespie     case BUILT_IN_VA_END:
4181c87b03e5Sespie       return expand_builtin_va_end (arglist);
4182c87b03e5Sespie     case BUILT_IN_VA_COPY:
4183c87b03e5Sespie       return expand_builtin_va_copy (arglist);
4184c87b03e5Sespie     case BUILT_IN_EXPECT:
4185c87b03e5Sespie       return expand_builtin_expect (arglist, target);
4186c87b03e5Sespie     case BUILT_IN_PREFETCH:
4187c87b03e5Sespie       expand_builtin_prefetch (arglist);
4188c87b03e5Sespie       return const0_rtx;
4189c87b03e5Sespie 
4190c87b03e5Sespie 
4191c87b03e5Sespie     default:	/* just do library call, if unknown builtin */
4192c87b03e5Sespie       if (!DECL_ASSEMBLER_NAME_SET_P (fndecl))
4193c87b03e5Sespie 	error ("built-in function `%s' not currently supported",
4194c87b03e5Sespie 	       IDENTIFIER_POINTER (DECL_NAME (fndecl)));
4195c87b03e5Sespie     }
4196c87b03e5Sespie 
4197c87b03e5Sespie   /* The switch statement above can drop through to cause the function
4198c87b03e5Sespie      to be called normally.  */
4199c87b03e5Sespie   return expand_call (exp, target, ignore);
4200c87b03e5Sespie }
4201c87b03e5Sespie 
4202c87b03e5Sespie /* Fold a call to __builtin_constant_p, if we know it will evaluate to a
4203c87b03e5Sespie    constant.  ARGLIST is the argument list of the call.  */
4204c87b03e5Sespie 
4205c87b03e5Sespie static tree
fold_builtin_constant_p(arglist)4206c87b03e5Sespie fold_builtin_constant_p (arglist)
4207c87b03e5Sespie      tree arglist;
4208c87b03e5Sespie {
4209c87b03e5Sespie   if (arglist == 0)
4210c87b03e5Sespie     return 0;
4211c87b03e5Sespie 
4212c87b03e5Sespie   arglist = TREE_VALUE (arglist);
4213c87b03e5Sespie 
4214c87b03e5Sespie   /* We return 1 for a numeric type that's known to be a constant
4215c87b03e5Sespie      value at compile-time or for an aggregate type that's a
4216c87b03e5Sespie      literal constant.  */
4217c87b03e5Sespie   STRIP_NOPS (arglist);
4218c87b03e5Sespie 
4219c87b03e5Sespie   /* If we know this is a constant, emit the constant of one.  */
4220c87b03e5Sespie   if (TREE_CODE_CLASS (TREE_CODE (arglist)) == 'c'
4221c87b03e5Sespie       || (TREE_CODE (arglist) == CONSTRUCTOR
4222c87b03e5Sespie 	  && TREE_CONSTANT (arglist))
4223c87b03e5Sespie       || (TREE_CODE (arglist) == ADDR_EXPR
4224c87b03e5Sespie 	  && TREE_CODE (TREE_OPERAND (arglist, 0)) == STRING_CST))
4225c87b03e5Sespie     return integer_one_node;
4226c87b03e5Sespie 
4227c87b03e5Sespie   /* If we aren't going to be running CSE or this expression
4228c87b03e5Sespie      has side effects, show we don't know it to be a constant.
4229c87b03e5Sespie      Likewise if it's a pointer or aggregate type since in those
4230c87b03e5Sespie      case we only want literals, since those are only optimized
4231c87b03e5Sespie      when generating RTL, not later.
4232c87b03e5Sespie      And finally, if we are compiling an initializer, not code, we
4233c87b03e5Sespie      need to return a definite result now; there's not going to be any
4234c87b03e5Sespie      more optimization done.  */
4235c87b03e5Sespie   if (TREE_SIDE_EFFECTS (arglist) || cse_not_expected
4236c87b03e5Sespie       || AGGREGATE_TYPE_P (TREE_TYPE (arglist))
4237c87b03e5Sespie       || POINTER_TYPE_P (TREE_TYPE (arglist))
4238c87b03e5Sespie       || cfun == 0)
4239c87b03e5Sespie     return integer_zero_node;
4240c87b03e5Sespie 
4241c87b03e5Sespie   return 0;
4242c87b03e5Sespie }
4243c87b03e5Sespie 
4244c87b03e5Sespie /* Fold a call to __builtin_classify_type.  */
4245c87b03e5Sespie 
4246c87b03e5Sespie static tree
fold_builtin_classify_type(arglist)4247c87b03e5Sespie fold_builtin_classify_type (arglist)
4248c87b03e5Sespie      tree arglist;
4249c87b03e5Sespie {
4250c87b03e5Sespie   if (arglist == 0)
4251c87b03e5Sespie     return build_int_2 (no_type_class, 0);
4252c87b03e5Sespie 
4253c87b03e5Sespie   return build_int_2 (type_to_class (TREE_TYPE (TREE_VALUE (arglist))), 0);
4254c87b03e5Sespie }
4255c87b03e5Sespie 
4256c87b03e5Sespie /* Fold a call to __builtin_inf or __builtin_huge_val.  */
4257c87b03e5Sespie 
4258c87b03e5Sespie static tree
fold_builtin_inf(type,warn)4259c87b03e5Sespie fold_builtin_inf (type, warn)
4260c87b03e5Sespie      tree type;
4261c87b03e5Sespie      int warn;
4262c87b03e5Sespie {
4263c87b03e5Sespie   REAL_VALUE_TYPE real;
4264c87b03e5Sespie 
4265c87b03e5Sespie   if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) && warn)
4266c87b03e5Sespie     warning ("target format does not support infinity");
4267c87b03e5Sespie 
4268c87b03e5Sespie   real_inf (&real);
4269c87b03e5Sespie   return build_real (type, real);
4270c87b03e5Sespie }
4271c87b03e5Sespie 
4272c87b03e5Sespie /* Fold a call to __builtin_nan or __builtin_nans.  */
4273c87b03e5Sespie 
4274c87b03e5Sespie static tree
fold_builtin_nan(arglist,type,quiet)4275c87b03e5Sespie fold_builtin_nan (arglist, type, quiet)
4276c87b03e5Sespie      tree arglist, type;
4277c87b03e5Sespie      int quiet;
4278c87b03e5Sespie {
4279c87b03e5Sespie   REAL_VALUE_TYPE real;
4280c87b03e5Sespie   const char *str;
4281c87b03e5Sespie 
4282c87b03e5Sespie   if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
4283c87b03e5Sespie     return 0;
4284c87b03e5Sespie   str = c_getstr (TREE_VALUE (arglist));
4285c87b03e5Sespie   if (!str)
4286c87b03e5Sespie     return 0;
4287c87b03e5Sespie 
4288c87b03e5Sespie   if (!real_nan (&real, str, quiet, TYPE_MODE (type)))
4289c87b03e5Sespie     return 0;
4290c87b03e5Sespie 
4291c87b03e5Sespie   return build_real (type, real);
4292c87b03e5Sespie }
4293c87b03e5Sespie 
4294c87b03e5Sespie /* Used by constant folding to eliminate some builtin calls early.  EXP is
4295c87b03e5Sespie    the CALL_EXPR of a call to a builtin function.  */
4296c87b03e5Sespie 
4297c87b03e5Sespie tree
fold_builtin(exp)4298c87b03e5Sespie fold_builtin (exp)
4299c87b03e5Sespie      tree exp;
4300c87b03e5Sespie {
4301c87b03e5Sespie   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
4302c87b03e5Sespie   tree arglist = TREE_OPERAND (exp, 1);
4303c87b03e5Sespie   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
4304c87b03e5Sespie 
4305c87b03e5Sespie   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
4306c87b03e5Sespie     return 0;
4307c87b03e5Sespie 
4308c87b03e5Sespie   switch (fcode)
4309c87b03e5Sespie     {
4310c87b03e5Sespie     case BUILT_IN_CONSTANT_P:
4311c87b03e5Sespie       return fold_builtin_constant_p (arglist);
4312c87b03e5Sespie 
4313c87b03e5Sespie     case BUILT_IN_CLASSIFY_TYPE:
4314c87b03e5Sespie       return fold_builtin_classify_type (arglist);
4315c87b03e5Sespie 
4316c87b03e5Sespie     case BUILT_IN_STRLEN:
4317c87b03e5Sespie       if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
4318c87b03e5Sespie 	{
4319c87b03e5Sespie 	  tree len = c_strlen (TREE_VALUE (arglist));
4320c87b03e5Sespie 	  if (len)
4321c87b03e5Sespie 	    {
4322c87b03e5Sespie 	      /* Convert from the internal "sizetype" type to "size_t".  */
4323c87b03e5Sespie 	      if (size_type_node)
4324c87b03e5Sespie 		len = convert (size_type_node, len);
4325c87b03e5Sespie 	      return len;
4326c87b03e5Sespie 	    }
4327c87b03e5Sespie 	}
4328c87b03e5Sespie       break;
4329c87b03e5Sespie 
4330c87b03e5Sespie     case BUILT_IN_INF:
4331c87b03e5Sespie     case BUILT_IN_INFF:
4332c87b03e5Sespie     case BUILT_IN_INFL:
4333c87b03e5Sespie       return fold_builtin_inf (TREE_TYPE (TREE_TYPE (fndecl)), true);
4334c87b03e5Sespie 
4335c87b03e5Sespie     case BUILT_IN_HUGE_VAL:
4336c87b03e5Sespie     case BUILT_IN_HUGE_VALF:
4337c87b03e5Sespie     case BUILT_IN_HUGE_VALL:
4338c87b03e5Sespie       return fold_builtin_inf (TREE_TYPE (TREE_TYPE (fndecl)), false);
4339c87b03e5Sespie 
4340c87b03e5Sespie     case BUILT_IN_NAN:
4341c87b03e5Sespie     case BUILT_IN_NANF:
4342c87b03e5Sespie     case BUILT_IN_NANL:
4343c87b03e5Sespie       return fold_builtin_nan (arglist, TREE_TYPE (TREE_TYPE (fndecl)), true);
4344c87b03e5Sespie 
4345c87b03e5Sespie     case BUILT_IN_NANS:
4346c87b03e5Sespie     case BUILT_IN_NANSF:
4347c87b03e5Sespie     case BUILT_IN_NANSL:
4348c87b03e5Sespie       return fold_builtin_nan (arglist, TREE_TYPE (TREE_TYPE (fndecl)), false);
4349c87b03e5Sespie 
4350c87b03e5Sespie     default:
4351c87b03e5Sespie       break;
4352c87b03e5Sespie     }
4353c87b03e5Sespie 
4354c87b03e5Sespie   return 0;
4355c87b03e5Sespie }
4356c87b03e5Sespie 
4357c87b03e5Sespie static tree
build_function_call_expr(fn,arglist)4358c87b03e5Sespie build_function_call_expr (fn, arglist)
4359c87b03e5Sespie      tree fn, arglist;
4360c87b03e5Sespie {
4361c87b03e5Sespie   tree call_expr;
4362c87b03e5Sespie 
4363c87b03e5Sespie   call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
4364c87b03e5Sespie   call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
4365c87b03e5Sespie 		     call_expr, arglist);
4366c87b03e5Sespie   TREE_SIDE_EFFECTS (call_expr) = 1;
4367c87b03e5Sespie   return fold (call_expr);
4368c87b03e5Sespie }
4369c87b03e5Sespie 
4370c87b03e5Sespie /* This function validates the types of a function call argument list
4371c87b03e5Sespie    represented as a tree chain of parameters against a specified list
4372c87b03e5Sespie    of tree_codes.  If the last specifier is a 0, that represents an
4373c87b03e5Sespie    ellipses, otherwise the last specifier must be a VOID_TYPE.  */
4374c87b03e5Sespie 
4375c87b03e5Sespie static int
validate_arglist(tree arglist,...)4376c87b03e5Sespie validate_arglist VPARAMS ((tree arglist, ...))
4377c87b03e5Sespie {
4378c87b03e5Sespie   enum tree_code code;
4379c87b03e5Sespie   int res = 0;
4380c87b03e5Sespie 
4381c87b03e5Sespie   VA_OPEN (ap, arglist);
4382c87b03e5Sespie   VA_FIXEDARG (ap, tree, arglist);
4383c87b03e5Sespie 
4384c87b03e5Sespie   do
4385c87b03e5Sespie     {
4386c87b03e5Sespie       code = va_arg (ap, enum tree_code);
4387c87b03e5Sespie       switch (code)
4388c87b03e5Sespie 	{
4389c87b03e5Sespie 	case 0:
4390c87b03e5Sespie 	  /* This signifies an ellipses, any further arguments are all ok.  */
4391c87b03e5Sespie 	  res = 1;
4392c87b03e5Sespie 	  goto end;
4393c87b03e5Sespie 	case VOID_TYPE:
4394c87b03e5Sespie 	  /* This signifies an endlink, if no arguments remain, return
4395c87b03e5Sespie 	     true, otherwise return false.  */
4396c87b03e5Sespie 	  res = arglist == 0;
4397c87b03e5Sespie 	  goto end;
4398c87b03e5Sespie 	default:
4399c87b03e5Sespie 	  /* If no parameters remain or the parameter's code does not
4400c87b03e5Sespie 	     match the specified code, return false.  Otherwise continue
4401c87b03e5Sespie 	     checking any remaining arguments.  */
4402c87b03e5Sespie 	  if (arglist == 0
4403c87b03e5Sespie 	      || code != TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))))
4404c87b03e5Sespie 	    goto end;
4405c87b03e5Sespie 	  break;
4406c87b03e5Sespie 	}
4407c87b03e5Sespie       arglist = TREE_CHAIN (arglist);
4408c87b03e5Sespie     }
4409c87b03e5Sespie   while (1);
4410c87b03e5Sespie 
4411c87b03e5Sespie   /* We need gotos here since we can only have one VA_CLOSE in a
4412c87b03e5Sespie      function.  */
4413c87b03e5Sespie  end: ;
4414c87b03e5Sespie   VA_CLOSE (ap);
4415c87b03e5Sespie 
4416c87b03e5Sespie   return res;
4417c87b03e5Sespie }
4418c87b03e5Sespie 
4419c87b03e5Sespie /* Default version of target-specific builtin setup that does nothing.  */
4420c87b03e5Sespie 
4421c87b03e5Sespie void
default_init_builtins()4422c87b03e5Sespie default_init_builtins ()
4423c87b03e5Sespie {
4424c87b03e5Sespie }
4425c87b03e5Sespie 
4426c87b03e5Sespie /* Default target-specific builtin expander that does nothing.  */
4427c87b03e5Sespie 
4428c87b03e5Sespie rtx
default_expand_builtin(exp,target,subtarget,mode,ignore)4429c87b03e5Sespie default_expand_builtin (exp, target, subtarget, mode, ignore)
4430c87b03e5Sespie      tree exp ATTRIBUTE_UNUSED;
4431c87b03e5Sespie      rtx target ATTRIBUTE_UNUSED;
4432c87b03e5Sespie      rtx subtarget ATTRIBUTE_UNUSED;
4433c87b03e5Sespie      enum machine_mode mode ATTRIBUTE_UNUSED;
4434c87b03e5Sespie      int ignore ATTRIBUTE_UNUSED;
4435c87b03e5Sespie {
4436c87b03e5Sespie   return NULL_RTX;
4437c87b03e5Sespie }
4438