OSDN Git Service

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