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