OSDN Git Service

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