OSDN Git Service

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