OSDN Git Service

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