OSDN Git Service

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