OSDN Git Service

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