OSDN Git Service

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