OSDN Git Service

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