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 *) ¤t_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