OSDN Git Service

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