OSDN Git Service

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