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