OSDN Git Service

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