]> gcc.gnu.org Git - gcc.git/blame - gcc/builtins.c
re PR fortran/8485 (g77 doesn't accept INTEGER*8 constant in PARAMETER multiplication)
[gcc.git] / gcc / builtins.c
Content-type: text/html ]> gcc.gnu.org Git - gcc.git/blame - gcc/builtins.c


500 - Internal Server Error

Malformed UTF-8 character (fatal) at (eval 5) line 1, <$fd> line 10087.
This page took 1.260385 seconds and 5 git commands to generate.
CommitLineData
28f4ec01 1/* Expand builtin functions.
03cd8aba
RS
2 Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
28f4ec01 4
1322177d 5This file is part of GCC.
28f4ec01 6
1322177d
LB
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
28f4ec01 11
1322177d
LB
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
28f4ec01
BS
16
17You should have received a copy of the GNU General Public License
1322177d
LB
18along with GCC; see the file COPYING. If not, write to the Free
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2002111-1307, USA. */
28f4ec01
BS
21
22#include "config.h"
23#include "system.h"
4977bab6
ZW
24#include "coretypes.h"
25#include "tm.h"
28f4ec01 26#include "machmode.h"
11ad4784 27#include "real.h"
28f4ec01
BS
28#include "rtl.h"
29#include "tree.h"
28f4ec01
BS
30#include "flags.h"
31#include "regs.h"
32#include "hard-reg-set.h"
33#include "except.h"
34#include "function.h"
28f4ec01
BS
35#include "insn-config.h"
36#include "expr.h"
e78d8e51
ZW
37#include "optabs.h"
38#include "libfuncs.h"
28f4ec01
BS
39#include "recog.h"
40#include "output.h"
41#include "typeclass.h"
28f4ec01 42#include "toplev.h"
5f2d6cfa 43#include "predict.h"
aa388f29 44#include "tm_p.h"
f6155fda 45#include "target.h"
ab393bf1 46#include "langhooks.h"
28f4ec01
BS
47
48#define CALLED_AS_BUILT_IN(NODE) \
49 (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
50
28f4ec01
BS
51/* Register mappings for target machines without register windows. */
52#ifndef INCOMING_REGNO
53#define INCOMING_REGNO(OUT) (OUT)
54#endif
55#ifndef OUTGOING_REGNO
56#define OUTGOING_REGNO(IN) (IN)
57#endif
58
5e4f6244
CP
59#ifndef PAD_VARARGS_DOWN
60#define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
61#endif
62
9df2c88c 63/* Define the names of the builtin function types and codes. */
fd05eb80 64const char *const built_in_class_names[4]
9df2c88c
RK
65 = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
66
272f51a3 67#define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT, IM) STRINGX(X),
fd05eb80 68const char *const built_in_names[(int) END_BUILTINS] =
cb1072f4
KG
69{
70#include "builtins.def"
71};
72#undef DEF_BUILTIN
9df2c88c 73
3ff5f682
KG
74/* Setup an array of _DECL trees, make sure each element is
75 initialized to NULL_TREE. */
10841285 76tree built_in_decls[(int) END_BUILTINS];
272f51a3
JH
77/* Declarations used when constructing the builtin implicitly in the compiler.
78 It may be NULL_TREE when this is invalid (for instance runtime is not
79 required to implement the function call in all cases. */
80tree implicit_built_in_decls[(int) END_BUILTINS];
3ff5f682 81
5197bd50 82static int get_pointer_alignment PARAMS ((tree, unsigned int));
3d994c6b 83static tree c_strlen PARAMS ((tree));
2dee4af1 84static const char *c_getstr PARAMS ((tree));
57814e5e
JJ
85static rtx c_readstr PARAMS ((const char *,
86 enum machine_mode));
8d51ecf8 87static int target_char_cast PARAMS ((tree, char *));
3d994c6b
KG
88static rtx get_memory_rtx PARAMS ((tree));
89static int apply_args_size PARAMS ((void));
90static int apply_result_size PARAMS ((void));
7bdb32b9 91#if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
3d994c6b 92static rtx result_vector PARAMS ((int, rtx));
7bdb32b9 93#endif
250d07b6 94static rtx expand_builtin_setjmp PARAMS ((tree, rtx));
a9ccbb60 95static void expand_builtin_prefetch PARAMS ((tree));
3d994c6b
KG
96static rtx expand_builtin_apply_args PARAMS ((void));
97static rtx expand_builtin_apply_args_1 PARAMS ((void));
98static rtx expand_builtin_apply PARAMS ((rtx, rtx, rtx));
99static void expand_builtin_return PARAMS ((rtx));
91db4a92 100static enum type_class type_to_class PARAMS ((tree));
3d994c6b 101static rtx expand_builtin_classify_type PARAMS ((tree));
b5e01d4b 102static void expand_errno_check PARAMS ((tree, rtx));
3d994c6b 103static rtx expand_builtin_mathfn PARAMS ((tree, rtx, rtx));
b5e01d4b 104static rtx expand_builtin_mathfn_2 PARAMS ((tree, rtx, rtx));
8c9b38d7 105static rtx expand_builtin_constant_p PARAMS ((tree, enum machine_mode));
3d994c6b
KG
106static rtx expand_builtin_args_info PARAMS ((tree));
107static rtx expand_builtin_next_arg PARAMS ((tree));
6c535c69 108static rtx expand_builtin_va_start PARAMS ((tree));
3d994c6b
KG
109static rtx expand_builtin_va_end PARAMS ((tree));
110static rtx expand_builtin_va_copy PARAMS ((tree));
c2bd38e8 111static rtx expand_builtin_memcmp PARAMS ((tree, tree, rtx,
ca7fd9cd 112 enum machine_mode));
2dee4af1
JJ
113static rtx expand_builtin_strcmp PARAMS ((tree, rtx,
114 enum machine_mode));
da9e9f08
KG
115static rtx expand_builtin_strncmp PARAMS ((tree, rtx,
116 enum machine_mode));
57814e5e
JJ
117static rtx builtin_memcpy_read_str PARAMS ((PTR, HOST_WIDE_INT,
118 enum machine_mode));
d118937d
KG
119static rtx expand_builtin_strcat PARAMS ((tree, rtx,
120 enum machine_mode));
121static rtx expand_builtin_strncat PARAMS ((tree, rtx,
122 enum machine_mode));
123static rtx expand_builtin_strspn PARAMS ((tree, rtx,
124 enum machine_mode));
125static rtx expand_builtin_strcspn PARAMS ((tree, rtx,
126 enum machine_mode));
c2bd38e8 127static rtx expand_builtin_memcpy PARAMS ((tree, rtx,
9cb65f92 128 enum machine_mode, int));
e3e9f108
JJ
129static rtx expand_builtin_mempcpy PARAMS ((tree, rtx,
130 enum machine_mode));
e31603c4
JJ
131static rtx expand_builtin_memmove PARAMS ((tree, rtx,
132 enum machine_mode));
133static rtx expand_builtin_bcopy PARAMS ((tree));
c2bd38e8 134static rtx expand_builtin_strcpy PARAMS ((tree, rtx,
ca7fd9cd 135 enum machine_mode));
9cb65f92
KG
136static rtx expand_builtin_stpcpy PARAMS ((tree, rtx,
137 enum machine_mode));
57814e5e
JJ
138static rtx builtin_strncpy_read_str PARAMS ((PTR, HOST_WIDE_INT,
139 enum machine_mode));
da9e9f08
KG
140static rtx expand_builtin_strncpy PARAMS ((tree, rtx,
141 enum machine_mode));
ab937357
JJ
142static rtx builtin_memset_read_str PARAMS ((PTR, HOST_WIDE_INT,
143 enum machine_mode));
1a887f86
RS
144static rtx builtin_memset_gen_str PARAMS ((PTR, HOST_WIDE_INT,
145 enum machine_mode));
c2bd38e8 146static rtx expand_builtin_memset PARAMS ((tree, rtx,
ca7fd9cd 147 enum machine_mode));
e3a709be 148static rtx expand_builtin_bzero PARAMS ((tree));
8c9b38d7 149static rtx expand_builtin_strlen PARAMS ((tree, rtx, enum machine_mode));
78e7629e
KG
150static rtx expand_builtin_strstr PARAMS ((tree, rtx,
151 enum machine_mode));
26a87cab
KG
152static rtx expand_builtin_strpbrk PARAMS ((tree, rtx,
153 enum machine_mode));
2dee4af1
JJ
154static rtx expand_builtin_strchr PARAMS ((tree, rtx,
155 enum machine_mode));
156static rtx expand_builtin_strrchr PARAMS ((tree, rtx,
157 enum machine_mode));
3d994c6b 158static rtx expand_builtin_alloca PARAMS ((tree, rtx));
6c537d03
RH
159static rtx expand_builtin_unop PARAMS ((enum machine_mode,
160 tree, rtx, rtx, optab));
8c9b38d7 161static rtx expand_builtin_frame_address PARAMS ((tree, tree));
b4c984fb 162static rtx expand_builtin_fputs PARAMS ((tree, int, int));
3d994c6b 163static tree stabilize_va_list PARAMS ((tree, int));
994a57cd 164static rtx expand_builtin_expect PARAMS ((tree, rtx));
b0b3afb2 165static tree fold_builtin_constant_p PARAMS ((tree));
ad82abb8 166static tree fold_builtin_classify_type PARAMS ((tree));
ab5e2615 167static tree fold_builtin_inf PARAMS ((tree, int));
1472e41c 168static tree fold_builtin_nan PARAMS ((tree, tree, int));
019fa094 169static int validate_arglist PARAMS ((tree, ...));
27a6aa72 170static tree fold_trunc_transparent_mathfn PARAMS ((tree));
28f4ec01
BS
171
172/* Return the alignment in bits of EXP, a pointer valued expression.
173 But don't return more than MAX_ALIGN no matter what.
174 The alignment returned is, by default, the alignment of the thing that
5197bd50 175 EXP points to. If it is not a POINTER_TYPE, 0 is returned.
28f4ec01
BS
176
177 Otherwise, look at the expression to see if we can do better, i.e., if the
178 expression is actually pointing at an object whose alignment is tighter. */
179
180static int
181get_pointer_alignment (exp, max_align)
182 tree exp;
5197bd50 183 unsigned int max_align;
28f4ec01 184{
5197bd50 185 unsigned int align, inner;
28f4ec01
BS
186
187 if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE)
188 return 0;
189
190 align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
191 align = MIN (align, max_align);
192
193 while (1)
194 {
195 switch (TREE_CODE (exp))
196 {
197 case NOP_EXPR:
198 case CONVERT_EXPR:
199 case NON_LVALUE_EXPR:
200 exp = TREE_OPERAND (exp, 0);
201 if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE)
202 return align;
19caa751 203
28f4ec01
BS
204 inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
205 align = MIN (inner, max_align);
206 break;
207
208 case PLUS_EXPR:
209 /* If sum of pointer + int, restrict our maximum alignment to that
210 imposed by the integer. If not, we can't do any better than
211 ALIGN. */
19caa751 212 if (! host_integerp (TREE_OPERAND (exp, 1), 1))
28f4ec01
BS
213 return align;
214
0c237688
LB
215 while (((tree_low_cst (TREE_OPERAND (exp, 1), 1))
216 & (max_align / BITS_PER_UNIT - 1))
28f4ec01
BS
217 != 0)
218 max_align >>= 1;
219
220 exp = TREE_OPERAND (exp, 0);
221 break;
222
223 case ADDR_EXPR:
224 /* See what we are pointing at and look at its alignment. */
225 exp = TREE_OPERAND (exp, 0);
226 if (TREE_CODE (exp) == FUNCTION_DECL)
227 align = FUNCTION_BOUNDARY;
2f939d94 228 else if (DECL_P (exp))
28f4ec01
BS
229 align = DECL_ALIGN (exp);
230#ifdef CONSTANT_ALIGNMENT
231 else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c')
232 align = CONSTANT_ALIGNMENT (exp, align);
233#endif
234 return MIN (align, max_align);
235
236 default:
237 return align;
238 }
239 }
240}
241
242/* Compute the length of a C string. TREE_STRING_LENGTH is not the right
243 way, because it could contain a zero byte in the middle.
244 TREE_STRING_LENGTH is the size of the character array, not the string.
245
fed3cef0
RK
246 The value returned is of type `ssizetype'.
247
28f4ec01
BS
248 Unfortunately, string_constant can't access the values of const char
249 arrays with initializers, so neither can we do so here. */
250
251static tree
252c_strlen (src)
253 tree src;
254{
255 tree offset_node;
5197bd50
RK
256 HOST_WIDE_INT offset;
257 int max;
520a57c8 258 const char *ptr;
28f4ec01
BS
259
260 src = string_constant (src, &offset_node);
261 if (src == 0)
262 return 0;
fed3cef0 263
2dee4af1 264 max = TREE_STRING_LENGTH (src) - 1;
28f4ec01 265 ptr = TREE_STRING_POINTER (src);
fed3cef0 266
28f4ec01
BS
267 if (offset_node && TREE_CODE (offset_node) != INTEGER_CST)
268 {
269 /* If the string has an internal zero byte (e.g., "foo\0bar"), we can't
270 compute the offset to the following null if we don't know where to
271 start searching for it. */
272 int i;
fed3cef0 273
28f4ec01
BS
274 for (i = 0; i < max; i++)
275 if (ptr[i] == 0)
276 return 0;
fed3cef0 277
28f4ec01
BS
278 /* We don't know the starting offset, but we do know that the string
279 has no internal zero bytes. We can assume that the offset falls
280 within the bounds of the string; otherwise, the programmer deserves
281 what he gets. Subtract the offset from the length of the string,
fed3cef0
RK
282 and return that. This would perhaps not be valid if we were dealing
283 with named arrays in addition to literal string constants. */
284
285 return size_diffop (size_int (max), offset_node);
28f4ec01
BS
286 }
287
288 /* We have a known offset into the string. Start searching there for
5197bd50 289 a null character if we can represent it as a single HOST_WIDE_INT. */
1de3d877 290 if (offset_node == 0)
28f4ec01 291 offset = 0;
1de3d877
MK
292 else if (! host_integerp (offset_node, 0))
293 offset = -1;
28f4ec01 294 else
5197bd50 295 offset = tree_low_cst (offset_node, 0);
fed3cef0 296
28f4ec01
BS
297 /* If the offset is known to be out of bounds, warn, and call strlen at
298 runtime. */
299 if (offset < 0 || offset > max)
300 {
301 warning ("offset outside bounds of constant string");
302 return 0;
303 }
fed3cef0 304
28f4ec01
BS
305 /* Use strlen to search for the first zero byte. Since any strings
306 constructed with build_string will have nulls appended, we win even
307 if we get handed something like (char[4])"abcd".
308
309 Since OFFSET is our starting index into the string, no further
310 calculation is needed. */
fed3cef0 311 return ssize_int (strlen (ptr + offset));
28f4ec01
BS
312}
313
2dee4af1
JJ
314/* Return a char pointer for a C string if it is a string constant
315 or sum of string constant and integer constant. */
316
317static const char *
318c_getstr (src)
319 tree src;
320{
321 tree offset_node;
2dee4af1
JJ
322
323 src = string_constant (src, &offset_node);
324 if (src == 0)
325 return 0;
326
bf06b5d8
RK
327 if (offset_node == 0)
328 return TREE_STRING_POINTER (src);
329 else if (!host_integerp (offset_node, 1)
330 || compare_tree_int (offset_node, TREE_STRING_LENGTH (src) - 1) > 0)
2dee4af1 331 return 0;
2dee4af1 332
bf06b5d8 333 return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
2dee4af1
JJ
334}
335
bf06b5d8
RK
336/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
337 GET_MODE_BITSIZE (MODE) bits from string constant STR. */
ab937357 338
57814e5e
JJ
339static rtx
340c_readstr (str, mode)
341 const char *str;
342 enum machine_mode mode;
343{
344 HOST_WIDE_INT c[2];
345 HOST_WIDE_INT ch;
346 unsigned int i, j;
347
348 if (GET_MODE_CLASS (mode) != MODE_INT)
349 abort ();
350 c[0] = 0;
351 c[1] = 0;
352 ch = 1;
353 for (i = 0; i < GET_MODE_SIZE (mode); i++)
354 {
355 j = i;
356 if (WORDS_BIG_ENDIAN)
357 j = GET_MODE_SIZE (mode) - i - 1;
358 if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
359 && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
360 j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
361 j *= BITS_PER_UNIT;
362 if (j > 2 * HOST_BITS_PER_WIDE_INT)
363 abort ();
364 if (ch)
365 ch = (unsigned char) str[i];
366 c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
367 }
368 return immed_double_const (c[0], c[1], mode);
369}
370
ab937357
JJ
371/* Cast a target constant CST to target CHAR and if that value fits into
372 host char type, return zero and put that value into variable pointed by
373 P. */
374
375static int
376target_char_cast (cst, p)
377 tree cst;
378 char *p;
379{
380 unsigned HOST_WIDE_INT val, hostval;
381
5197bd50 382 if (!host_integerp (cst, 1)
ab937357
JJ
383 || CHAR_TYPE_SIZE > HOST_BITS_PER_WIDE_INT)
384 return 1;
385
5197bd50 386 val = tree_low_cst (cst, 1);
ab937357
JJ
387 if (CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT)
388 val &= (((unsigned HOST_WIDE_INT) 1) << CHAR_TYPE_SIZE) - 1;
389
390 hostval = val;
391 if (HOST_BITS_PER_CHAR < HOST_BITS_PER_WIDE_INT)
392 hostval &= (((unsigned HOST_WIDE_INT) 1) << HOST_BITS_PER_CHAR) - 1;
393
394 if (val != hostval)
395 return 1;
396
397 *p = hostval;
398 return 0;
399}
400
28f4ec01
BS
401/* Given TEM, a pointer to a stack frame, follow the dynamic chain COUNT
402 times to get the address of either a higher stack frame, or a return
403 address located within it (depending on FNDECL_CODE). */
fed3cef0 404
28f4ec01
BS
405rtx
406expand_builtin_return_addr (fndecl_code, count, tem)
407 enum built_in_function fndecl_code;
408 int count;
409 rtx tem;
410{
411 int i;
412
413 /* Some machines need special handling before we can access
414 arbitrary frames. For example, on the sparc, we must first flush
415 all register windows to the stack. */
416#ifdef SETUP_FRAME_ADDRESSES
417 if (count > 0)
418 SETUP_FRAME_ADDRESSES ();
419#endif
420
421 /* On the sparc, the return address is not in the frame, it is in a
422 register. There is no way to access it off of the current frame
423 pointer, but it can be accessed off the previous frame pointer by
424 reading the value from the register window save area. */
425#ifdef RETURN_ADDR_IN_PREVIOUS_FRAME
426 if (fndecl_code == BUILT_IN_RETURN_ADDRESS)
427 count--;
428#endif
429
430 /* Scan back COUNT frames to the specified frame. */
431 for (i = 0; i < count; i++)
432 {
433 /* Assume the dynamic chain pointer is in the word that the
434 frame address points to, unless otherwise specified. */
435#ifdef DYNAMIC_CHAIN_ADDRESS
436 tem = DYNAMIC_CHAIN_ADDRESS (tem);
437#endif
438 tem = memory_address (Pmode, tem);
432fd734 439 tem = gen_rtx_MEM (Pmode, tem);
ba4828e0 440 set_mem_alias_set (tem, get_frame_alias_set ());
432fd734 441 tem = copy_to_reg (tem);
28f4ec01
BS
442 }
443
444 /* For __builtin_frame_address, return what we've got. */
445 if (fndecl_code == BUILT_IN_FRAME_ADDRESS)
446 return tem;
447
448 /* For __builtin_return_address, Get the return address from that
449 frame. */
450#ifdef RETURN_ADDR_RTX
451 tem = RETURN_ADDR_RTX (count, tem);
452#else
453 tem = memory_address (Pmode,
454 plus_constant (tem, GET_MODE_SIZE (Pmode)));
455 tem = gen_rtx_MEM (Pmode, tem);
ba4828e0 456 set_mem_alias_set (tem, get_frame_alias_set ());
28f4ec01
BS
457#endif
458 return tem;
459}
460
3bdf5ad1
RK
461/* Alias set used for setjmp buffer. */
462static HOST_WIDE_INT setjmp_alias_set = -1;
463
250d07b6
RH
464/* Construct the leading half of a __builtin_setjmp call. Control will
465 return to RECEIVER_LABEL. This is used directly by sjlj exception
466 handling code. */
28f4ec01 467
250d07b6
RH
468void
469expand_builtin_setjmp_setup (buf_addr, receiver_label)
28f4ec01 470 rtx buf_addr;
250d07b6 471 rtx receiver_label;
28f4ec01 472{
28f4ec01 473 enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
28f4ec01 474 rtx stack_save;
3bdf5ad1 475 rtx mem;
28f4ec01 476
3bdf5ad1
RK
477 if (setjmp_alias_set == -1)
478 setjmp_alias_set = new_alias_set ();
479
28f4ec01 480#ifdef POINTERS_EXTEND_UNSIGNED
4b6c1672
RK
481 if (GET_MODE (buf_addr) != Pmode)
482 buf_addr = convert_memory_address (Pmode, buf_addr);
28f4ec01
BS
483#endif
484
7d505b82 485 buf_addr = force_reg (Pmode, force_operand (buf_addr, NULL_RTX));
28f4ec01 486
28f4ec01
BS
487 emit_queue ();
488
250d07b6
RH
489 /* We store the frame pointer and the address of receiver_label in
490 the buffer and use the rest of it for the stack save area, which
491 is machine-dependent. */
28f4ec01
BS
492
493#ifndef BUILTIN_SETJMP_FRAME_VALUE
494#define BUILTIN_SETJMP_FRAME_VALUE virtual_stack_vars_rtx
495#endif
496
3bdf5ad1 497 mem = gen_rtx_MEM (Pmode, buf_addr);
ba4828e0 498 set_mem_alias_set (mem, setjmp_alias_set);
3bdf5ad1
RK
499 emit_move_insn (mem, BUILTIN_SETJMP_FRAME_VALUE);
500
501 mem = gen_rtx_MEM (Pmode, plus_constant (buf_addr, GET_MODE_SIZE (Pmode))),
ba4828e0 502 set_mem_alias_set (mem, setjmp_alias_set);
3bdf5ad1
RK
503
504 emit_move_insn (validize_mem (mem),
250d07b6 505 force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, receiver_label)));
28f4ec01
BS
506
507 stack_save = gen_rtx_MEM (sa_mode,
508 plus_constant (buf_addr,
509 2 * GET_MODE_SIZE (Pmode)));
ba4828e0 510 set_mem_alias_set (stack_save, setjmp_alias_set);
28f4ec01
BS
511 emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
512
513 /* If there is further processing to do, do it. */
514#ifdef HAVE_builtin_setjmp_setup
515 if (HAVE_builtin_setjmp_setup)
516 emit_insn (gen_builtin_setjmp_setup (buf_addr));
517#endif
518
250d07b6
RH
519 /* Tell optimize_save_area_alloca that extra work is going to
520 need to go on during alloca. */
f36d6244 521 current_function_calls_setjmp = 1;
dfb2c798
JL
522
523 /* Set this so all the registers get saved in our frame; we need to be
ec5c56db 524 able to copy the saved values for any registers from frames we unwind. */
dfb2c798 525 current_function_has_nonlocal_label = 1;
250d07b6 526}
28f4ec01 527
250d07b6
RH
528/* Construct the trailing part of a __builtin_setjmp call.
529 This is used directly by sjlj exception handling code. */
530
531void
532expand_builtin_setjmp_receiver (receiver_label)
ca7fd9cd 533 rtx receiver_label ATTRIBUTE_UNUSED;
250d07b6 534{
28f4ec01
BS
535 /* Clobber the FP when we get here, so we have to make sure it's
536 marked as used by this function. */
537 emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
538
539 /* Mark the static chain as clobbered here so life information
540 doesn't get messed up for it. */
541 emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx));
542
543 /* Now put in the code to restore the frame pointer, and argument
544 pointer, if needed. The code below is from expand_end_bindings
545 in stmt.c; see detailed documentation there. */
546#ifdef HAVE_nonlocal_goto
547 if (! HAVE_nonlocal_goto)
548#endif
549 emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
550
551#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
552 if (fixed_regs[ARG_POINTER_REGNUM])
553 {
554#ifdef ELIMINABLE_REGS
555 size_t i;
8b60264b 556 static const struct elims {const int from, to;} elim_regs[] = ELIMINABLE_REGS;
28f4ec01 557
b6a1cbae 558 for (i = 0; i < ARRAY_SIZE (elim_regs); i++)
28f4ec01
BS
559 if (elim_regs[i].from == ARG_POINTER_REGNUM
560 && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
561 break;
562
b6a1cbae 563 if (i == ARRAY_SIZE (elim_regs))
28f4ec01
BS
564#endif
565 {
566 /* Now restore our arg pointer from the address at which it
278ed218 567 was saved in our stack frame. */
28f4ec01 568 emit_move_insn (virtual_incoming_args_rtx,
278ed218 569 copy_to_reg (get_arg_pointer_save_area (cfun)));
28f4ec01
BS
570 }
571 }
572#endif
573
574#ifdef HAVE_builtin_setjmp_receiver
575 if (HAVE_builtin_setjmp_receiver)
250d07b6 576 emit_insn (gen_builtin_setjmp_receiver (receiver_label));
28f4ec01
BS
577 else
578#endif
579#ifdef HAVE_nonlocal_goto_receiver
580 if (HAVE_nonlocal_goto_receiver)
581 emit_insn (gen_nonlocal_goto_receiver ());
582 else
583#endif
250d07b6 584 { /* Nothing */ }
bcd7edfe
BS
585
586 /* @@@ This is a kludge. Not all machine descriptions define a blockage
587 insn, but we must not allow the code we just generated to be reordered
588 by scheduling. Specifically, the update of the frame pointer must
589 happen immediately, not later. So emit an ASM_INPUT to act as blockage
590 insn. */
591 emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
250d07b6 592}
28f4ec01 593
250d07b6
RH
594/* __builtin_setjmp is passed a pointer to an array of five words (not
595 all will be used on all machines). It operates similarly to the C
596 library function of the same name, but is more efficient. Much of
597 the code below (and for longjmp) is copied from the handling of
598 non-local gotos.
599
600 NOTE: This is intended for use by GNAT and the exception handling
601 scheme in the compiler and will only work in the method used by
602 them. */
603
604static rtx
605expand_builtin_setjmp (arglist, target)
606 tree arglist;
607 rtx target;
608{
609 rtx buf_addr, next_lab, cont_lab;
610
019fa094 611 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
250d07b6
RH
612 return NULL_RTX;
613
614 if (target == 0 || GET_CODE (target) != REG
615 || REGNO (target) < FIRST_PSEUDO_REGISTER)
616 target = gen_reg_rtx (TYPE_MODE (integer_type_node));
617
618 buf_addr = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
619
620 next_lab = gen_label_rtx ();
621 cont_lab = gen_label_rtx ();
622
623 expand_builtin_setjmp_setup (buf_addr, next_lab);
624
625 /* Set TARGET to zero and branch to the continue label. */
626 emit_move_insn (target, const0_rtx);
627 emit_jump_insn (gen_jump (cont_lab));
28f4ec01 628 emit_barrier ();
250d07b6
RH
629 emit_label (next_lab);
630
631 expand_builtin_setjmp_receiver (next_lab);
632
633 /* Set TARGET to one. */
634 emit_move_insn (target, const1_rtx);
635 emit_label (cont_lab);
636
637 /* Tell flow about the strange goings on. Putting `next_lab' on
638 `nonlocal_goto_handler_labels' to indicates that function
639 calls may traverse the arc back to this label. */
640
641 current_function_has_nonlocal_label = 1;
642 nonlocal_goto_handler_labels
643 = gen_rtx_EXPR_LIST (VOIDmode, next_lab, nonlocal_goto_handler_labels);
28f4ec01
BS
644
645 return target;
646}
647
648/* __builtin_longjmp is passed a pointer to an array of five words (not
649 all will be used on all machines). It operates similarly to the C
650 library function of the same name, but is more efficient. Much of
651 the code below is copied from the handling of non-local gotos.
652
653 NOTE: This is intended for use by GNAT and the exception handling
654 scheme in the compiler and will only work in the method used by
655 them. */
656
657void
658expand_builtin_longjmp (buf_addr, value)
659 rtx buf_addr, value;
660{
d337d653 661 rtx fp, lab, stack, insn, last;
28f4ec01
BS
662 enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
663
3bdf5ad1
RK
664 if (setjmp_alias_set == -1)
665 setjmp_alias_set = new_alias_set ();
666
28f4ec01 667#ifdef POINTERS_EXTEND_UNSIGNED
4b6c1672
RK
668 if (GET_MODE (buf_addr) != Pmode)
669 buf_addr = convert_memory_address (Pmode, buf_addr);
28f4ec01 670#endif
4b6c1672 671
28f4ec01
BS
672 buf_addr = force_reg (Pmode, buf_addr);
673
674 /* We used to store value in static_chain_rtx, but that fails if pointers
675 are smaller than integers. We instead require that the user must pass
676 a second argument of 1, because that is what builtin_setjmp will
677 return. This also makes EH slightly more efficient, since we are no
678 longer copying around a value that we don't care about. */
679 if (value != const1_rtx)
680 abort ();
681
f36d6244
JJ
682 current_function_calls_longjmp = 1;
683
d337d653 684 last = get_last_insn ();
28f4ec01
BS
685#ifdef HAVE_builtin_longjmp
686 if (HAVE_builtin_longjmp)
687 emit_insn (gen_builtin_longjmp (buf_addr));
688 else
689#endif
690 {
691 fp = gen_rtx_MEM (Pmode, buf_addr);
692 lab = gen_rtx_MEM (Pmode, plus_constant (buf_addr,
693 GET_MODE_SIZE (Pmode)));
694
695 stack = gen_rtx_MEM (sa_mode, plus_constant (buf_addr,
696 2 * GET_MODE_SIZE (Pmode)));
ba4828e0
RK
697 set_mem_alias_set (fp, setjmp_alias_set);
698 set_mem_alias_set (lab, setjmp_alias_set);
699 set_mem_alias_set (stack, setjmp_alias_set);
28f4ec01
BS
700
701 /* Pick up FP, label, and SP from the block and jump. This code is
702 from expand_goto in stmt.c; see there for detailed comments. */
703#if HAVE_nonlocal_goto
704 if (HAVE_nonlocal_goto)
705 /* We have to pass a value to the nonlocal_goto pattern that will
706 get copied into the static_chain pointer, but it does not matter
707 what that value is, because builtin_setjmp does not use it. */
7c2b017c 708 emit_insn (gen_nonlocal_goto (value, lab, stack, fp));
28f4ec01
BS
709 else
710#endif
711 {
712 lab = copy_to_reg (lab);
713
714 emit_move_insn (hard_frame_pointer_rtx, fp);
715 emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
716
717 emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
718 emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
719 emit_indirect_jump (lab);
720 }
721 }
4b01bd16
RH
722
723 /* Search backwards and mark the jump insn as a non-local goto.
724 Note that this precludes the use of __builtin_longjmp to a
725 __builtin_setjmp target in the same function. However, we've
726 already cautioned the user that these functions are for
727 internal exception handling use only. */
8206fc89
AM
728 for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
729 {
d337d653
JH
730 if (insn == last)
731 abort ();
8206fc89
AM
732 if (GET_CODE (insn) == JUMP_INSN)
733 {
734 REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx,
735 REG_NOTES (insn));
736 break;
737 }
738 else if (GET_CODE (insn) == CALL_INSN)
ca7fd9cd 739 break;
8206fc89 740 }
28f4ec01
BS
741}
742
a9ccbb60
JJ
743/* Expand a call to __builtin_prefetch. For a target that does not support
744 data prefetch, evaluate the memory address argument in case it has side
745 effects. */
746
747static void
748expand_builtin_prefetch (arglist)
749 tree arglist;
750{
751 tree arg0, arg1, arg2;
752 rtx op0, op1, op2;
753
e83d297b
JJ
754 if (!validate_arglist (arglist, POINTER_TYPE, 0))
755 return;
756
a9ccbb60 757 arg0 = TREE_VALUE (arglist);
e83d297b
JJ
758 /* Arguments 1 and 2 are optional; argument 1 (read/write) defaults to
759 zero (read) and argument 2 (locality) defaults to 3 (high degree of
760 locality). */
761 if (TREE_CHAIN (arglist))
762 {
763 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
764 if (TREE_CHAIN (TREE_CHAIN (arglist)))
ca7fd9cd 765 arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
e83d297b
JJ
766 else
767 arg2 = build_int_2 (3, 0);
768 }
769 else
770 {
771 arg1 = integer_zero_node;
772 arg2 = build_int_2 (3, 0);
773 }
a9ccbb60
JJ
774
775 /* Argument 0 is an address. */
776 op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
777
778 /* Argument 1 (read/write flag) must be a compile-time constant int. */
779 if (TREE_CODE (arg1) != INTEGER_CST)
780 {
ca7fd9cd
KH
781 error ("second arg to `__builtin_prefetch' must be a constant");
782 arg1 = integer_zero_node;
a9ccbb60 783 }
8d51ecf8 784 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
a9ccbb60
JJ
785 /* Argument 1 must be either zero or one. */
786 if (INTVAL (op1) != 0 && INTVAL (op1) != 1)
787 {
788 warning ("invalid second arg to __builtin_prefetch; using zero");
789 op1 = const0_rtx;
790 }
791
792 /* Argument 2 (locality) must be a compile-time constant int. */
793 if (TREE_CODE (arg2) != INTEGER_CST)
794 {
795 error ("third arg to `__builtin_prefetch' must be a constant");
796 arg2 = integer_zero_node;
797 }
8d51ecf8 798 op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
a9ccbb60
JJ
799 /* Argument 2 must be 0, 1, 2, or 3. */
800 if (INTVAL (op2) < 0 || INTVAL (op2) > 3)
801 {
802 warning ("invalid third arg to __builtin_prefetch; using zero");
803 op2 = const0_rtx;
804 }
805
806#ifdef HAVE_prefetch
807 if (HAVE_prefetch)
808 {
5ab2f7b7 809 if ((! (*insn_data[(int) CODE_FOR_prefetch].operand[0].predicate)
1e533e4b 810 (op0,
5ab2f7b7
KH
811 insn_data[(int) CODE_FOR_prefetch].operand[0].mode))
812 || (GET_MODE(op0) != Pmode))
ca7fd9cd 813 {
1e533e4b
SE
814#ifdef POINTERS_EXTEND_UNSIGNED
815 if (GET_MODE(op0) != Pmode)
816 op0 = convert_memory_address (Pmode, op0);
817#endif
ca7fd9cd
KH
818 op0 = force_reg (Pmode, op0);
819 }
a9ccbb60
JJ
820 emit_insn (gen_prefetch (op0, op1, op2));
821 }
822 else
823#endif
824 op0 = protect_from_queue (op0, 0);
5ab2f7b7
KH
825 /* Don't do anything with direct references to volatile memory, but
826 generate code to handle other side effects. */
827 if (GET_CODE (op0) != MEM && side_effects_p (op0))
828 emit_insn (op0);
a9ccbb60
JJ
829}
830
3bdf5ad1
RK
831/* Get a MEM rtx for expression EXP which is the address of an operand
832 to be used to be used in a string instruction (cmpstrsi, movstrsi, ..). */
833
28f4ec01
BS
834static rtx
835get_memory_rtx (exp)
836 tree exp;
837{
ce2d32cd
RK
838 rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_SUM);
839 rtx mem;
3bdf5ad1 840
ce2d32cd
RK
841#ifdef POINTERS_EXTEND_UNSIGNED
842 if (GET_MODE (addr) != Pmode)
843 addr = convert_memory_address (Pmode, addr);
844#endif
845
846 mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
8ac61af7 847
3bdf5ad1
RK
848 /* Get an expression we can use to find the attributes to assign to MEM.
849 If it is an ADDR_EXPR, use the operand. Otherwise, dereference it if
850 we can. First remove any nops. */
851 while ((TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
5ab2f7b7 852 || TREE_CODE (exp) == NON_LVALUE_EXPR)
3bdf5ad1
RK
853 && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
854 exp = TREE_OPERAND (exp, 0);
855
856 if (TREE_CODE (exp) == ADDR_EXPR)
343fb412
RK
857 {
858 exp = TREE_OPERAND (exp, 0);
859 set_mem_attributes (mem, exp, 0);
860 }
3bdf5ad1 861 else if (POINTER_TYPE_P (TREE_TYPE (exp)))
343fb412
RK
862 {
863 exp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (exp)), exp);
864 /* memcpy, memset and other builtin stringops can alias with anything. */
865 set_mem_alias_set (mem, 0);
866 }
28f4ec01 867
28f4ec01
BS
868 return mem;
869}
870\f
871/* Built-in functions to perform an untyped call and return. */
872
873/* For each register that may be used for calling a function, this
874 gives a mode used to copy the register's value. VOIDmode indicates
875 the register is not used for calling a function. If the machine
876 has register windows, this gives only the outbound registers.
877 INCOMING_REGNO gives the corresponding inbound register. */
878static enum machine_mode apply_args_mode[FIRST_PSEUDO_REGISTER];
879
880/* For each register that may be used for returning values, this gives
881 a mode used to copy the register's value. VOIDmode indicates the
882 register is not used for returning values. If the machine has
883 register windows, this gives only the outbound registers.
884 INCOMING_REGNO gives the corresponding inbound register. */
885static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER];
886
887/* For each register that may be used for calling a function, this
888 gives the offset of that register into the block returned by
889 __builtin_apply_args. 0 indicates that the register is not
890 used for calling a function. */
891static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
892
8d51ecf8 893/* Return the offset of register REGNO into the block returned by
28f4ec01
BS
894 __builtin_apply_args. This is not declared static, since it is
895 needed in objc-act.c. */
896
8d51ecf8 897int
28f4ec01
BS
898apply_args_register_offset (regno)
899 int regno;
900{
901 apply_args_size ();
902
903 /* Arguments are always put in outgoing registers (in the argument
904 block) if such make sense. */
905#ifdef OUTGOING_REGNO
5ab2f7b7 906 regno = OUTGOING_REGNO (regno);
28f4ec01
BS
907#endif
908 return apply_args_reg_offset[regno];
909}
910
911/* Return the size required for the block returned by __builtin_apply_args,
912 and initialize apply_args_mode. */
913
914static int
915apply_args_size ()
916{
917 static int size = -1;
cbf5468f
AH
918 int align;
919 unsigned int regno;
28f4ec01
BS
920 enum machine_mode mode;
921
922 /* The values computed by this function never change. */
923 if (size < 0)
924 {
925 /* The first value is the incoming arg-pointer. */
926 size = GET_MODE_SIZE (Pmode);
927
928 /* The second value is the structure value address unless this is
929 passed as an "invisible" first argument. */
930 if (struct_value_rtx)
931 size += GET_MODE_SIZE (Pmode);
932
933 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
934 if (FUNCTION_ARG_REGNO_P (regno))
935 {
936 /* Search for the proper mode for copying this register's
937 value. I'm not sure this is right, but it works so far. */
938 enum machine_mode best_mode = VOIDmode;
939
940 for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
941 mode != VOIDmode;
942 mode = GET_MODE_WIDER_MODE (mode))
943 if (HARD_REGNO_MODE_OK (regno, mode)
944 && HARD_REGNO_NREGS (regno, mode) == 1)
945 best_mode = mode;
946
947 if (best_mode == VOIDmode)
948 for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
949 mode != VOIDmode;
950 mode = GET_MODE_WIDER_MODE (mode))
951 if (HARD_REGNO_MODE_OK (regno, mode)
ef89d648 952 && have_insn_for (SET, mode))
28f4ec01
BS
953 best_mode = mode;
954
9016e543
AH
955 if (best_mode == VOIDmode)
956 for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
957 mode != VOIDmode;
958 mode = GET_MODE_WIDER_MODE (mode))
959 if (HARD_REGNO_MODE_OK (regno, mode)
960 && have_insn_for (SET, mode))
961 best_mode = mode;
962
963 if (best_mode == VOIDmode)
964 for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
965 mode != VOIDmode;
966 mode = GET_MODE_WIDER_MODE (mode))
967 if (HARD_REGNO_MODE_OK (regno, mode)
968 && have_insn_for (SET, mode))
969 best_mode = mode;
970
28f4ec01
BS
971 mode = best_mode;
972 if (mode == VOIDmode)
973 abort ();
974
975 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
976 if (size % align != 0)
977 size = CEIL (size, align) * align;
978 apply_args_reg_offset[regno] = size;
979 size += GET_MODE_SIZE (mode);
980 apply_args_mode[regno] = mode;
981 }
982 else
983 {
984 apply_args_mode[regno] = VOIDmode;
985 apply_args_reg_offset[regno] = 0;
986 }
987 }
988 return size;
989}
990
991/* Return the size required for the block returned by __builtin_apply,
992 and initialize apply_result_mode. */
993
994static int
995apply_result_size ()
996{
997 static int size = -1;
998 int align, regno;
999 enum machine_mode mode;
1000
1001 /* The values computed by this function never change. */
1002 if (size < 0)
1003 {
1004 size = 0;
1005
1006 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1007 if (FUNCTION_VALUE_REGNO_P (regno))
1008 {
1009 /* Search for the proper mode for copying this register's
1010 value. I'm not sure this is right, but it works so far. */
1011 enum machine_mode best_mode = VOIDmode;
1012
1013 for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
1014 mode != TImode;
1015 mode = GET_MODE_WIDER_MODE (mode))
1016 if (HARD_REGNO_MODE_OK (regno, mode))
1017 best_mode = mode;
1018
1019 if (best_mode == VOIDmode)
1020 for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
1021 mode != VOIDmode;
1022 mode = GET_MODE_WIDER_MODE (mode))
1023 if (HARD_REGNO_MODE_OK (regno, mode)
ef89d648 1024 && have_insn_for (SET, mode))
28f4ec01
BS
1025 best_mode = mode;
1026
9016e543
AH
1027 if (best_mode == VOIDmode)
1028 for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
1029 mode != VOIDmode;
1030 mode = GET_MODE_WIDER_MODE (mode))
1031 if (HARD_REGNO_MODE_OK (regno, mode)
1032 && have_insn_for (SET, mode))
5ab2f7b7 1033 best_mode = mode;
9016e543
AH
1034
1035 if (best_mode == VOIDmode)
1036 for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
1037 mode != VOIDmode;
1038 mode = GET_MODE_WIDER_MODE (mode))
1039 if (HARD_REGNO_MODE_OK (regno, mode)
1040 && have_insn_for (SET, mode))
1041 best_mode = mode;
1042
28f4ec01
BS
1043 mode = best_mode;
1044 if (mode == VOIDmode)
1045 abort ();
1046
1047 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1048 if (size % align != 0)
1049 size = CEIL (size, align) * align;
1050 size += GET_MODE_SIZE (mode);
1051 apply_result_mode[regno] = mode;
1052 }
1053 else
1054 apply_result_mode[regno] = VOIDmode;
1055
1056 /* Allow targets that use untyped_call and untyped_return to override
1057 the size so that machine-specific information can be stored here. */
1058#ifdef APPLY_RESULT_SIZE
1059 size = APPLY_RESULT_SIZE;
1060#endif
1061 }
1062 return size;
1063}
1064
1065#if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
1066/* Create a vector describing the result block RESULT. If SAVEP is true,
1067 the result block is used to save the values; otherwise it is used to
1068 restore the values. */
1069
1070static rtx
1071result_vector (savep, result)
1072 int savep;
1073 rtx result;
1074{
1075 int regno, size, align, nelts;
1076 enum machine_mode mode;
1077 rtx reg, mem;
1078 rtx *savevec = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
8d51ecf8 1079
28f4ec01
BS
1080 size = nelts = 0;
1081 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1082 if ((mode = apply_result_mode[regno]) != VOIDmode)
1083 {
1084 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1085 if (size % align != 0)
1086 size = CEIL (size, align) * align;
1087 reg = gen_rtx_REG (mode, savep ? regno : INCOMING_REGNO (regno));
f4ef873c 1088 mem = adjust_address (result, mode, size);
28f4ec01
BS
1089 savevec[nelts++] = (savep
1090 ? gen_rtx_SET (VOIDmode, mem, reg)
1091 : gen_rtx_SET (VOIDmode, reg, mem));
1092 size += GET_MODE_SIZE (mode);
1093 }
1094 return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nelts, savevec));
1095}
1096#endif /* HAVE_untyped_call or HAVE_untyped_return */
1097
1098/* Save the state required to perform an untyped call with the same
1099 arguments as were passed to the current function. */
1100
1101static rtx
1102expand_builtin_apply_args_1 ()
1103{
1104 rtx registers;
1105 int size, align, regno;
1106 enum machine_mode mode;
1107
1108 /* Create a block where the arg-pointer, structure value address,
1109 and argument registers can be saved. */
1110 registers = assign_stack_local (BLKmode, apply_args_size (), -1);
1111
1112 /* Walk past the arg-pointer and structure value address. */
1113 size = GET_MODE_SIZE (Pmode);
1114 if (struct_value_rtx)
1115 size += GET_MODE_SIZE (Pmode);
1116
1117 /* Save each register used in calling a function to the block. */
1118 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1119 if ((mode = apply_args_mode[regno]) != VOIDmode)
1120 {
1121 rtx tem;
1122
1123 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1124 if (size % align != 0)
1125 size = CEIL (size, align) * align;
1126
1127 tem = gen_rtx_REG (mode, INCOMING_REGNO (regno));
1128
f4ef873c 1129 emit_move_insn (adjust_address (registers, mode, size), tem);
28f4ec01
BS
1130 size += GET_MODE_SIZE (mode);
1131 }
1132
1133 /* Save the arg pointer to the block. */
f4ef873c 1134 emit_move_insn (adjust_address (registers, Pmode, 0),
28f4ec01
BS
1135 copy_to_reg (virtual_incoming_args_rtx));
1136 size = GET_MODE_SIZE (Pmode);
1137
1138 /* Save the structure value address unless this is passed as an
1139 "invisible" first argument. */
1140 if (struct_value_incoming_rtx)
1141 {
f4ef873c 1142 emit_move_insn (adjust_address (registers, Pmode, size),
28f4ec01
BS
1143 copy_to_reg (struct_value_incoming_rtx));
1144 size += GET_MODE_SIZE (Pmode);
1145 }
1146
1147 /* Return the address of the block. */
1148 return copy_addr_to_reg (XEXP (registers, 0));
1149}
1150
1151/* __builtin_apply_args returns block of memory allocated on
1152 the stack into which is stored the arg pointer, structure
1153 value address, static chain, and all the registers that might
1154 possibly be used in performing a function call. The code is
1155 moved to the start of the function so the incoming values are
1156 saved. */
5197bd50 1157
28f4ec01
BS
1158static rtx
1159expand_builtin_apply_args ()
1160{
1161 /* Don't do __builtin_apply_args more than once in a function.
1162 Save the result of the first call and reuse it. */
1163 if (apply_args_value != 0)
1164 return apply_args_value;
1165 {
1166 /* When this function is called, it means that registers must be
1167 saved on entry to this function. So we migrate the
1168 call to the first insn of this function. */
1169 rtx temp;
1170 rtx seq;
1171
1172 start_sequence ();
1173 temp = expand_builtin_apply_args_1 ();
1174 seq = get_insns ();
1175 end_sequence ();
1176
1177 apply_args_value = temp;
1178
2f937369
DM
1179 /* Put the insns after the NOTE that starts the function.
1180 If this is inside a start_sequence, make the outer-level insn
28f4ec01
BS
1181 chain current, so the code is placed at the start of the
1182 function. */
1183 push_topmost_sequence ();
2f937369 1184 emit_insn_before (seq, NEXT_INSN (get_insns ()));
28f4ec01
BS
1185 pop_topmost_sequence ();
1186 return temp;
1187 }
1188}
1189
1190/* Perform an untyped call and save the state required to perform an
1191 untyped return of whatever value was returned by the given function. */
1192
1193static rtx
1194expand_builtin_apply (function, arguments, argsize)
1195 rtx function, arguments, argsize;
1196{
1197 int size, align, regno;
1198 enum machine_mode mode;
8ac61af7 1199 rtx incoming_args, result, reg, dest, src, call_insn;
28f4ec01
BS
1200 rtx old_stack_level = 0;
1201 rtx call_fusage = 0;
1202
ce2d32cd
RK
1203#ifdef POINTERS_EXTEND_UNSIGNED
1204 if (GET_MODE (arguments) != Pmode)
1205 arguments = convert_memory_address (Pmode, arguments);
1206#endif
1207
28f4ec01
BS
1208 /* Create a block where the return registers can be saved. */
1209 result = assign_stack_local (BLKmode, apply_result_size (), -1);
1210
28f4ec01
BS
1211 /* Fetch the arg pointer from the ARGUMENTS block. */
1212 incoming_args = gen_reg_rtx (Pmode);
ce2d32cd 1213 emit_move_insn (incoming_args, gen_rtx_MEM (Pmode, arguments));
28f4ec01 1214#ifndef STACK_GROWS_DOWNWARD
ef89d648
ZW
1215 incoming_args = expand_simple_binop (Pmode, MINUS, incoming_args, argsize,
1216 incoming_args, 0, OPTAB_LIB_WIDEN);
28f4ec01
BS
1217#endif
1218
1219 /* Perform postincrements before actually calling the function. */
1220 emit_queue ();
1221
9d53e585
JM
1222 /* Push a new argument block and copy the arguments. Do not allow
1223 the (potential) memcpy call below to interfere with our stack
1224 manipulations. */
28f4ec01 1225 do_pending_stack_adjust ();
9d53e585 1226 NO_DEFER_POP;
28f4ec01
BS
1227
1228 /* Save the stack with nonlocal if available */
1229#ifdef HAVE_save_stack_nonlocal
1230 if (HAVE_save_stack_nonlocal)
1231 emit_stack_save (SAVE_NONLOCAL, &old_stack_level, NULL_RTX);
1232 else
1233#endif
1234 emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
1235
1236 /* Push a block of memory onto the stack to store the memory arguments.
1237 Save the address in a register, and copy the memory arguments. ??? I
1238 haven't figured out how the calling convention macros effect this,
1239 but it's likely that the source and/or destination addresses in
1240 the block copy will need updating in machine specific ways. */
1503a7ec 1241 dest = allocate_dynamic_stack_space (argsize, 0, BITS_PER_UNIT);
8ac61af7
RK
1242 dest = gen_rtx_MEM (BLKmode, dest);
1243 set_mem_align (dest, PARM_BOUNDARY);
1244 src = gen_rtx_MEM (BLKmode, incoming_args);
1245 set_mem_align (src, PARM_BOUNDARY);
44bb111a 1246 emit_block_move (dest, src, argsize, BLOCK_OP_NORMAL);
28f4ec01
BS
1247
1248 /* Refer to the argument block. */
1249 apply_args_size ();
1250 arguments = gen_rtx_MEM (BLKmode, arguments);
8ac61af7 1251 set_mem_align (arguments, PARM_BOUNDARY);
28f4ec01
BS
1252
1253 /* Walk past the arg-pointer and structure value address. */
1254 size = GET_MODE_SIZE (Pmode);
1255 if (struct_value_rtx)
1256 size += GET_MODE_SIZE (Pmode);
1257
1258 /* Restore each of the registers previously saved. Make USE insns
1259 for each of these registers for use in making the call. */
1260 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1261 if ((mode = apply_args_mode[regno]) != VOIDmode)
1262 {
1263 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1264 if (size % align != 0)
1265 size = CEIL (size, align) * align;
1266 reg = gen_rtx_REG (mode, regno);
f4ef873c 1267 emit_move_insn (reg, adjust_address (arguments, mode, size));
28f4ec01
BS
1268 use_reg (&call_fusage, reg);
1269 size += GET_MODE_SIZE (mode);
1270 }
1271
1272 /* Restore the structure value address unless this is passed as an
1273 "invisible" first argument. */
1274 size = GET_MODE_SIZE (Pmode);
1275 if (struct_value_rtx)
1276 {
1277 rtx value = gen_reg_rtx (Pmode);
f4ef873c 1278 emit_move_insn (value, adjust_address (arguments, Pmode, size));
28f4ec01
BS
1279 emit_move_insn (struct_value_rtx, value);
1280 if (GET_CODE (struct_value_rtx) == REG)
5ab2f7b7 1281 use_reg (&call_fusage, struct_value_rtx);
28f4ec01
BS
1282 size += GET_MODE_SIZE (Pmode);
1283 }
1284
1285 /* All arguments and registers used for the call are set up by now! */
3affaf29 1286 function = prepare_call_address (function, NULL_TREE, &call_fusage, 0, 0);
28f4ec01
BS
1287
1288 /* Ensure address is valid. SYMBOL_REF is already valid, so no need,
1289 and we don't want to load it into a register as an optimization,
1290 because prepare_call_address already did it if it should be done. */
1291 if (GET_CODE (function) != SYMBOL_REF)
1292 function = memory_address (FUNCTION_MODE, function);
1293
1294 /* Generate the actual call instruction and save the return value. */
1295#ifdef HAVE_untyped_call
1296 if (HAVE_untyped_call)
1297 emit_call_insn (gen_untyped_call (gen_rtx_MEM (FUNCTION_MODE, function),
1298 result, result_vector (1, result)));
1299 else
1300#endif
1301#ifdef HAVE_call_value
1302 if (HAVE_call_value)
1303 {
1304 rtx valreg = 0;
1305
1306 /* Locate the unique return register. It is not possible to
1307 express a call that sets more than one return register using
1308 call_value; use untyped_call for that. In fact, untyped_call
1309 only needs to save the return registers in the given block. */
1310 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1311 if ((mode = apply_result_mode[regno]) != VOIDmode)
1312 {
1313 if (valreg)
1314 abort (); /* HAVE_untyped_call required. */
1315 valreg = gen_rtx_REG (mode, regno);
1316 }
1317
f45c9d95 1318 emit_call_insn (GEN_CALL_VALUE (valreg,
28f4ec01
BS
1319 gen_rtx_MEM (FUNCTION_MODE, function),
1320 const0_rtx, NULL_RTX, const0_rtx));
1321
f4ef873c 1322 emit_move_insn (adjust_address (result, GET_MODE (valreg), 0), valreg);
28f4ec01
BS
1323 }
1324 else
1325#endif
1326 abort ();
1327
ee960939
OH
1328 /* Find the CALL insn we just emitted, and attach the register usage
1329 information. */
1330 call_insn = last_call_insn ();
1331 add_function_usage_to (call_insn, call_fusage);
28f4ec01
BS
1332
1333 /* Restore the stack. */
1334#ifdef HAVE_save_stack_nonlocal
1335 if (HAVE_save_stack_nonlocal)
1336 emit_stack_restore (SAVE_NONLOCAL, old_stack_level, NULL_RTX);
1337 else
1338#endif
1339 emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
1340
9d53e585
JM
1341 OK_DEFER_POP;
1342
28f4ec01
BS
1343 /* Return the address of the result block. */
1344 return copy_addr_to_reg (XEXP (result, 0));
1345}
1346
1347/* Perform an untyped return. */
1348
1349static void
1350expand_builtin_return (result)
1351 rtx result;
1352{
1353 int size, align, regno;
1354 enum machine_mode mode;
1355 rtx reg;
1356 rtx call_fusage = 0;
1357
ce2d32cd
RK
1358#ifdef POINTERS_EXTEND_UNSIGNED
1359 if (GET_MODE (result) != Pmode)
1360 result = convert_memory_address (Pmode, result);
1361#endif
1362
28f4ec01
BS
1363 apply_result_size ();
1364 result = gen_rtx_MEM (BLKmode, result);
1365
1366#ifdef HAVE_untyped_return
1367 if (HAVE_untyped_return)
1368 {
1369 emit_jump_insn (gen_untyped_return (result, result_vector (0, result)));
1370 emit_barrier ();
1371 return;
1372 }
1373#endif
1374
1375 /* Restore the return value and note that each value is used. */
1376 size = 0;
1377 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1378 if ((mode = apply_result_mode[regno]) != VOIDmode)
1379 {
1380 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
1381 if (size % align != 0)
1382 size = CEIL (size, align) * align;
1383 reg = gen_rtx_REG (mode, INCOMING_REGNO (regno));
f4ef873c 1384 emit_move_insn (reg, adjust_address (result, mode, size));
28f4ec01
BS
1385
1386 push_to_sequence (call_fusage);
1387 emit_insn (gen_rtx_USE (VOIDmode, reg));
1388 call_fusage = get_insns ();
1389 end_sequence ();
1390 size += GET_MODE_SIZE (mode);
1391 }
1392
1393 /* Put the USE insns before the return. */
2f937369 1394 emit_insn (call_fusage);
28f4ec01
BS
1395
1396 /* Return whatever values was restored by jumping directly to the end
1397 of the function. */
1398 expand_null_return ();
1399}
1400
ad82abb8 1401/* Used by expand_builtin_classify_type and fold_builtin_classify_type. */
5197bd50 1402
ad82abb8
ZW
1403static enum type_class
1404type_to_class (type)
1405 tree type;
1406{
1407 switch (TREE_CODE (type))
1408 {
1409 case VOID_TYPE: return void_type_class;
1410 case INTEGER_TYPE: return integer_type_class;
1411 case CHAR_TYPE: return char_type_class;
1412 case ENUMERAL_TYPE: return enumeral_type_class;
1413 case BOOLEAN_TYPE: return boolean_type_class;
1414 case POINTER_TYPE: return pointer_type_class;
1415 case REFERENCE_TYPE: return reference_type_class;
1416 case OFFSET_TYPE: return offset_type_class;
1417 case REAL_TYPE: return real_type_class;
1418 case COMPLEX_TYPE: return complex_type_class;
1419 case FUNCTION_TYPE: return function_type_class;
1420 case METHOD_TYPE: return method_type_class;
1421 case RECORD_TYPE: return record_type_class;
1422 case UNION_TYPE:
1423 case QUAL_UNION_TYPE: return union_type_class;
1424 case ARRAY_TYPE: return (TYPE_STRING_FLAG (type)
1425 ? string_type_class : array_type_class);
1426 case SET_TYPE: return set_type_class;
1427 case FILE_TYPE: return file_type_class;
1428 case LANG_TYPE: return lang_type_class;
1429 default: return no_type_class;
1430 }
1431}
8d51ecf8 1432
28f4ec01
BS
1433/* Expand a call to __builtin_classify_type with arguments found in
1434 ARGLIST. */
5197bd50 1435
28f4ec01
BS
1436static rtx
1437expand_builtin_classify_type (arglist)
1438 tree arglist;
1439{
1440 if (arglist != 0)
ad82abb8 1441 return GEN_INT (type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
28f4ec01
BS
1442 return GEN_INT (no_type_class);
1443}
1444
1445/* Expand expression EXP, which is a call to __builtin_constant_p. */
5197bd50 1446
28f4ec01 1447static rtx
8c9b38d7
KG
1448expand_builtin_constant_p (arglist, target_mode)
1449 tree arglist;
1450 enum machine_mode target_mode;
28f4ec01 1451{
b0b3afb2 1452 rtx tmp;
28f4ec01
BS
1453
1454 if (arglist == 0)
1455 return const0_rtx;
b0b3afb2 1456 arglist = TREE_VALUE (arglist);
28f4ec01 1457
b0b3afb2 1458 /* We have taken care of the easy cases during constant folding. This
34ee7f82
RS
1459 case is not obvious, so emit (constant_p_rtx (ARGLIST)) and let CSE
1460 get a chance to see if it can deduce whether ARGLIST is constant. */
28f4ec01 1461
07d9b20d
RS
1462 current_function_calls_constant_p = 1;
1463
b0b3afb2 1464 tmp = expand_expr (arglist, NULL_RTX, VOIDmode, 0);
8c9b38d7 1465 tmp = gen_rtx_CONSTANT_P_RTX (target_mode, tmp);
b0b3afb2 1466 return tmp;
28f4ec01
BS
1467}
1468
272f51a3
JH
1469/* Return mathematic function equivalent to FN but operating directly on TYPE,
1470 if available. */
1471tree
1472mathfn_built_in (type, fn)
1473 tree type;
1474 enum built_in_function fn;
1475{
1476 enum built_in_function fcode = NOT_BUILT_IN;
1477 if (TYPE_MODE (type) == TYPE_MODE (double_type_node))
1478 switch (fn)
1479 {
1480 case BUILT_IN_SQRT:
1481 case BUILT_IN_SQRTF:
1482 case BUILT_IN_SQRTL:
1483 fcode = BUILT_IN_SQRT;
1484 break;
1485 case BUILT_IN_SIN:
1486 case BUILT_IN_SINF:
1487 case BUILT_IN_SINL:
1488 fcode = BUILT_IN_SIN;
1489 break;
1490 case BUILT_IN_COS:
1491 case BUILT_IN_COSF:
1492 case BUILT_IN_COSL:
1493 fcode = BUILT_IN_COS;
1494 break;
1495 case BUILT_IN_EXP:
1496 case BUILT_IN_EXPF:
1497 case BUILT_IN_EXPL:
1498 fcode = BUILT_IN_EXP;
1499 break;
46847aa6
RS
1500 case BUILT_IN_LOG:
1501 case BUILT_IN_LOGF:
1502 case BUILT_IN_LOGL:
1503 fcode = BUILT_IN_LOG;
1504 break;
272f51a3
JH
1505 case BUILT_IN_FLOOR:
1506 case BUILT_IN_FLOORF:
1507 case BUILT_IN_FLOORL:
1508 fcode = BUILT_IN_FLOOR;
1509 break;
1510 case BUILT_IN_CEIL:
1511 case BUILT_IN_CEILF:
1512 case BUILT_IN_CEILL:
1513 fcode = BUILT_IN_CEIL;
1514 break;
1515 case BUILT_IN_TRUNC:
1516 case BUILT_IN_TRUNCF:
1517 case BUILT_IN_TRUNCL:
1518 fcode = BUILT_IN_TRUNC;
1519 break;
1520 case BUILT_IN_ROUND:
1521 case BUILT_IN_ROUNDF:
1522 case BUILT_IN_ROUNDL:
1523 fcode = BUILT_IN_ROUND;
1524 break;
1525 case BUILT_IN_NEARBYINT:
1526 case BUILT_IN_NEARBYINTF:
1527 case BUILT_IN_NEARBYINTL:
1528 fcode = BUILT_IN_NEARBYINT;
1529 break;
1530 default:
1531 abort ();
1532 }
1533 else if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
1534 switch (fn)
1535 {
1536 case BUILT_IN_SQRT:
1537 case BUILT_IN_SQRTF:
1538 case BUILT_IN_SQRTL:
1539 fcode = BUILT_IN_SQRTF;
1540 break;
1541 case BUILT_IN_SIN:
1542 case BUILT_IN_SINF:
1543 case BUILT_IN_SINL:
1544 fcode = BUILT_IN_SINF;
1545 break;
1546 case BUILT_IN_COS:
1547 case BUILT_IN_COSF:
1548 case BUILT_IN_COSL:
1549 fcode = BUILT_IN_COSF;
1550 break;
1551 case BUILT_IN_EXP:
1552 case BUILT_IN_EXPF:
1553 case BUILT_IN_EXPL:
1554 fcode = BUILT_IN_EXPF;
1555 break;
46847aa6
RS
1556 case BUILT_IN_LOG:
1557 case BUILT_IN_LOGF:
1558 case BUILT_IN_LOGL:
1559 fcode = BUILT_IN_LOGF;
1560 break;
272f51a3
JH
1561 case BUILT_IN_FLOOR:
1562 case BUILT_IN_FLOORF:
1563 case BUILT_IN_FLOORL:
1564 fcode = BUILT_IN_FLOORF;
1565 break;
1566 case BUILT_IN_CEIL:
1567 case BUILT_IN_CEILF:
1568 case BUILT_IN_CEILL:
1569 fcode = BUILT_IN_CEILF;
1570 break;
1571 case BUILT_IN_TRUNC:
1572 case BUILT_IN_TRUNCF:
1573 case BUILT_IN_TRUNCL:
1574 fcode = BUILT_IN_TRUNCF;
1575 break;
1576 case BUILT_IN_ROUND:
1577 case BUILT_IN_ROUNDF:
1578 case BUILT_IN_ROUNDL:
1579 fcode = BUILT_IN_ROUNDF;
1580 break;
1581 case BUILT_IN_NEARBYINT:
1582 case BUILT_IN_NEARBYINTF:
1583 case BUILT_IN_NEARBYINTL:
1584 fcode = BUILT_IN_NEARBYINTF;
1585 break;
1586 default:
1587 abort ();
1588 }
1589 else if (TYPE_MODE (type) == TYPE_MODE (long_double_type_node))
1590 switch (fn)
1591 {
1592 case BUILT_IN_SQRT:
1593 case BUILT_IN_SQRTF:
1594 case BUILT_IN_SQRTL:
1595 fcode = BUILT_IN_SQRTL;
1596 break;
1597 case BUILT_IN_SIN:
1598 case BUILT_IN_SINF:
1599 case BUILT_IN_SINL:
1600 fcode = BUILT_IN_SINL;
1601 break;
1602 case BUILT_IN_COS:
1603 case BUILT_IN_COSF:
1604 case BUILT_IN_COSL:
1605 fcode = BUILT_IN_COSL;
1606 break;
1607 case BUILT_IN_EXP:
1608 case BUILT_IN_EXPF:
1609 case BUILT_IN_EXPL:
1610 fcode = BUILT_IN_EXPL;
1611 break;
46847aa6
RS
1612 case BUILT_IN_LOG:
1613 case BUILT_IN_LOGF:
1614 case BUILT_IN_LOGL:
1615 fcode = BUILT_IN_LOGL;
1616 break;
272f51a3
JH
1617 case BUILT_IN_FLOOR:
1618 case BUILT_IN_FLOORF:
1619 case BUILT_IN_FLOORL:
1620 fcode = BUILT_IN_FLOORL;
1621 break;
1622 case BUILT_IN_CEIL:
1623 case BUILT_IN_CEILF:
1624 case BUILT_IN_CEILL:
1625 fcode = BUILT_IN_CEILL;
1626 break;
1627 case BUILT_IN_TRUNC:
1628 case BUILT_IN_TRUNCF:
1629 case BUILT_IN_TRUNCL:
1630 fcode = BUILT_IN_TRUNCL;
1631 break;
1632 case BUILT_IN_ROUND:
1633 case BUILT_IN_ROUNDF:
1634 case BUILT_IN_ROUNDL:
1635 fcode = BUILT_IN_ROUNDL;
1636 break;
1637 case BUILT_IN_NEARBYINT:
1638 case BUILT_IN_NEARBYINTF:
1639 case BUILT_IN_NEARBYINTL:
1640 fcode = BUILT_IN_NEARBYINTL;
1641 break;
1642 default:
1643 abort ();
1644 }
1645 return implicit_built_in_decls[fcode];
1646}
1647
b5e01d4b
RS
1648/* If errno must be maintained, expand the RTL to check if the result,
1649 TARGET, of a built-in function call, EXP, is NaN, and if so set
1650 errno to EDOM. */
1651
1652static void
1653expand_errno_check (exp, target)
1654 tree exp;
1655 rtx target;
1656{
1657 rtx lab;
1658
da52a069 1659 if (flag_errno_math && HONOR_NANS (GET_MODE (target)))
b5e01d4b
RS
1660 {
1661 lab = gen_label_rtx ();
1662
1663 /* Test the result; if it is NaN, set errno=EDOM because
1664 the argument was not in the domain. */
1665 emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
1666 0, lab);
1667
1668#ifdef TARGET_EDOM
1669 {
1670#ifdef GEN_ERRNO_RTX
1671 rtx errno_rtx = GEN_ERRNO_RTX;
1672#else
1673 rtx errno_rtx
1674 = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
1675#endif
1676
1677 emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
1678 }
1679#else
1680 /* We can't set errno=EDOM directly; let the library call do it.
1681 Pop the arguments right away in case the call gets deleted. */
1682 NO_DEFER_POP;
1683 expand_call (exp, target, 0);
1684 OK_DEFER_POP;
1685#endif
1686
1687 emit_label (lab);
1688 }
1689}
1690
1691
28f4ec01
BS
1692/* Expand a call to one of the builtin math functions (sin, cos, or sqrt).
1693 Return 0 if a normal call should be emitted rather than expanding the
1694 function in-line. EXP is the expression that is a call to the builtin
1695 function; if convenient, the result should be placed in TARGET.
1696 SUBTARGET may be used as the target for computing one of EXP's operands. */
5197bd50 1697
28f4ec01
BS
1698static rtx
1699expand_builtin_mathfn (exp, target, subtarget)
1700 tree exp;
1701 rtx target, subtarget;
1702{
8d51ecf8 1703 optab builtin_optab;
28f4ec01
BS
1704 rtx op0, insns;
1705 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
1706 tree arglist = TREE_OPERAND (exp, 1);
71925bc0 1707 enum machine_mode argmode;
4977bab6 1708 bool errno_set = true;
28f4ec01 1709
019fa094 1710 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
28f4ec01
BS
1711 return 0;
1712
1713 /* Stabilize and compute the argument. */
1714 if (TREE_CODE (TREE_VALUE (arglist)) != VAR_DECL
1715 && TREE_CODE (TREE_VALUE (arglist)) != PARM_DECL)
1716 {
1717 exp = copy_node (exp);
28f4ec01 1718 TREE_OPERAND (exp, 1) = arglist;
5a626f11
MM
1719 /* Wrap the computation of the argument in a SAVE_EXPR. That
1720 way, if we need to expand the argument again (as in the
1721 flag_errno_math case below where we cannot directly set
1722 errno), we will not perform side-effects more than once.
1723 Note that here we're mutating the original EXP as well as the
1724 copy; that's the right thing to do in case the original EXP
1725 is expanded later. */
28f4ec01 1726 TREE_VALUE (arglist) = save_expr (TREE_VALUE (arglist));
5a626f11 1727 arglist = copy_node (arglist);
28f4ec01
BS
1728 }
1729 op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
1730
1731 /* Make a suitable register to place result in. */
1732 target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
1733
1734 emit_queue ();
1735 start_sequence ();
1736
1737 switch (DECL_FUNCTION_CODE (fndecl))
1738 {
10841285
MM
1739 case BUILT_IN_SIN:
1740 case BUILT_IN_SINF:
1741 case BUILT_IN_SINL:
28f4ec01 1742 builtin_optab = sin_optab; break;
10841285
MM
1743 case BUILT_IN_COS:
1744 case BUILT_IN_COSF:
1745 case BUILT_IN_COSL:
28f4ec01 1746 builtin_optab = cos_optab; break;
dc6f4158 1747 case BUILT_IN_SQRT:
10841285
MM
1748 case BUILT_IN_SQRTF:
1749 case BUILT_IN_SQRTL:
28f4ec01 1750 builtin_optab = sqrt_optab; break;
e7b489c8
RS
1751 case BUILT_IN_EXP:
1752 case BUILT_IN_EXPF:
1753 case BUILT_IN_EXPL:
1754 builtin_optab = exp_optab; break;
1755 case BUILT_IN_LOG:
1756 case BUILT_IN_LOGF:
1757 case BUILT_IN_LOGL:
1758 builtin_optab = log_optab; break;
4977bab6
ZW
1759 case BUILT_IN_FLOOR:
1760 case BUILT_IN_FLOORF:
1761 case BUILT_IN_FLOORL:
1762 errno_set = false ; builtin_optab = floor_optab; break;
1763 case BUILT_IN_CEIL:
1764 case BUILT_IN_CEILF:
1765 case BUILT_IN_CEILL:
1766 errno_set = false ; builtin_optab = ceil_optab; break;
1767 case BUILT_IN_TRUNC:
1768 case BUILT_IN_TRUNCF:
1769 case BUILT_IN_TRUNCL:
1770 errno_set = false ; builtin_optab = trunc_optab; break;
1771 case BUILT_IN_ROUND:
1772 case BUILT_IN_ROUNDF:
1773 case BUILT_IN_ROUNDL:
1774 errno_set = false ; builtin_optab = round_optab; break;
1775 case BUILT_IN_NEARBYINT:
1776 case BUILT_IN_NEARBYINTF:
1777 case BUILT_IN_NEARBYINTL:
1778 errno_set = false ; builtin_optab = nearbyint_optab; break;
e7b489c8 1779 default:
28f4ec01
BS
1780 abort ();
1781 }
1782
1783 /* Compute into TARGET.
1784 Set TARGET to wherever the result comes back. */
71925bc0
RS
1785 argmode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
1786 target = expand_unop (argmode, builtin_optab, op0, target, 0);
28f4ec01
BS
1787
1788 /* If we were unable to expand via the builtin, stop the
1789 sequence (without outputting the insns) and return 0, causing
1790 a call to the library function. */
1791 if (target == 0)
1792 {
1793 end_sequence ();
1794 return 0;
1795 }
1796
da52a069
RS
1797 if (errno_set)
1798 expand_errno_check (exp, target);
28f4ec01 1799
b5e01d4b
RS
1800 /* Output the entire sequence. */
1801 insns = get_insns ();
1802 end_sequence ();
1803 emit_insn (insns);
1804
1805 return target;
1806}
1807
1808/* Expand a call to the builtin binary math functions (pow and atan2).
1809 Return 0 if a normal call should be emitted rather than expanding the
1810 function in-line. EXP is the expression that is a call to the builtin
1811 function; if convenient, the result should be placed in TARGET.
1812 SUBTARGET may be used as the target for computing one of EXP's
1813 operands. */
1814
1815static rtx
1816expand_builtin_mathfn_2 (exp, target, subtarget)
1817 tree exp;
1818 rtx target, subtarget;
1819{
1820 optab builtin_optab;
1821 rtx op0, op1, insns;
1822 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
1823 tree arglist = TREE_OPERAND (exp, 1);
1824 tree arg0, arg1;
1825 enum machine_mode argmode;
1826 bool errno_set = true;
1827 bool stable = true;
1828
1829 if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
1830 return 0;
1831
1832 arg0 = TREE_VALUE (arglist);
1833 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
1834
1835 /* Stabilize the arguments. */
1836 if (TREE_CODE (arg0) != VAR_DECL && TREE_CODE (arg0) != PARM_DECL)
1837 {
1838 arg0 = save_expr (arg0);
1839 TREE_VALUE (arglist) = arg0;
1840 stable = false;
1841 }
1842 if (TREE_CODE (arg1) != VAR_DECL && TREE_CODE (arg1) != PARM_DECL)
28f4ec01 1843 {
b5e01d4b
RS
1844 arg1 = save_expr (arg1);
1845 TREE_VALUE (TREE_CHAIN (arglist)) = arg1;
1846 stable = false;
1847 }
28f4ec01 1848
b5e01d4b
RS
1849 if (! stable)
1850 {
1851 exp = copy_node (exp);
1852 arglist = tree_cons (NULL_TREE, arg0,
1853 build_tree_list (NULL_TREE, arg1));
1854 TREE_OPERAND (exp, 1) = arglist;
1855 }
28f4ec01 1856
b5e01d4b
RS
1857 op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
1858 op1 = expand_expr (arg1, 0, VOIDmode, 0);
28f4ec01 1859
b5e01d4b
RS
1860 /* Make a suitable register to place result in. */
1861 target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
28f4ec01 1862
b5e01d4b
RS
1863 emit_queue ();
1864 start_sequence ();
1865
1866 switch (DECL_FUNCTION_CODE (fndecl))
1867 {
1868 case BUILT_IN_POW:
1869 case BUILT_IN_POWF:
1870 case BUILT_IN_POWL:
1871 builtin_optab = pow_optab; break;
1872 case BUILT_IN_ATAN2:
1873 case BUILT_IN_ATAN2F:
1874 case BUILT_IN_ATAN2L:
1875 builtin_optab = atan2_optab; break;
1876 default:
1877 abort ();
1878 }
1879
1880 /* Compute into TARGET.
1881 Set TARGET to wherever the result comes back. */
1882 argmode = TYPE_MODE (TREE_TYPE (arg0));
1883 target = expand_binop (argmode, builtin_optab, op0, op1,
1884 target, 0, OPTAB_DIRECT);
28f4ec01 1885
b5e01d4b
RS
1886 /* If we were unable to expand via the builtin, stop the
1887 sequence (without outputting the insns) and return 0, causing
1888 a call to the library function. */
1889 if (target == 0)
1890 {
1891 end_sequence ();
1892 return 0;
28f4ec01
BS
1893 }
1894
da52a069
RS
1895 if (errno_set)
1896 expand_errno_check (exp, target);
b5e01d4b 1897
28f4ec01
BS
1898 /* Output the entire sequence. */
1899 insns = get_insns ();
1900 end_sequence ();
2f937369 1901 emit_insn (insns);
8d51ecf8 1902
28f4ec01
BS
1903 return target;
1904}
1905
1906/* Expand expression EXP which is a call to the strlen builtin. Return 0
1907 if we failed the caller should emit a normal call, otherwise
0e9295cf 1908 try to get the result in TARGET, if convenient. */
3bdf5ad1 1909
28f4ec01 1910static rtx
8c9b38d7
KG
1911expand_builtin_strlen (arglist, target, target_mode)
1912 tree arglist;
28f4ec01 1913 rtx target;
8c9b38d7 1914 enum machine_mode target_mode;
28f4ec01 1915{
019fa094 1916 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
28f4ec01
BS
1917 return 0;
1918 else
1919 {
dd05e4fa 1920 rtx pat;
712b7a05 1921 tree len, src = TREE_VALUE (arglist);
dd05e4fa 1922 rtx result, src_reg, char_rtx, before_strlen;
8c9b38d7 1923 enum machine_mode insn_mode = target_mode, char_mode;
a544cfd2 1924 enum insn_code icode = CODE_FOR_nothing;
712b7a05
RS
1925 int align;
1926
1927 /* If the length can be computed at compile-time, return it. */
1928 len = c_strlen (src);
1929 if (len)
8c9b38d7 1930 return expand_expr (len, target, target_mode, EXPAND_NORMAL);
712b7a05
RS
1931
1932 align = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
28f4ec01 1933
28f4ec01
BS
1934 /* If SRC is not a pointer type, don't do this operation inline. */
1935 if (align == 0)
1936 return 0;
1937
dd05e4fa 1938 /* Bail out if we can't compute strlen in the right mode. */
28f4ec01
BS
1939 while (insn_mode != VOIDmode)
1940 {
1941 icode = strlen_optab->handlers[(int) insn_mode].insn_code;
1942 if (icode != CODE_FOR_nothing)
54e43c67 1943 break;
28f4ec01
BS
1944
1945 insn_mode = GET_MODE_WIDER_MODE (insn_mode);
1946 }
1947 if (insn_mode == VOIDmode)
1948 return 0;
1949
1950 /* Make a place to write the result of the instruction. */
1951 result = target;
1952 if (! (result != 0
1953 && GET_CODE (result) == REG
1954 && GET_MODE (result) == insn_mode
1955 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
1956 result = gen_reg_rtx (insn_mode);
1957
dd05e4fa
RH
1958 /* Make a place to hold the source address. We will not expand
1959 the actual source until we are sure that the expansion will
1960 not fail -- there are trees that cannot be expanded twice. */
1961 src_reg = gen_reg_rtx (Pmode);
28f4ec01 1962
dd05e4fa
RH
1963 /* Mark the beginning of the strlen sequence so we can emit the
1964 source operand later. */
5ab2f7b7 1965 before_strlen = get_last_insn ();
28f4ec01 1966
28f4ec01 1967 char_rtx = const0_rtx;
3bdf5ad1
RK
1968 char_mode = insn_data[(int) icode].operand[2].mode;
1969 if (! (*insn_data[(int) icode].operand[2].predicate) (char_rtx,
1970 char_mode))
28f4ec01
BS
1971 char_rtx = copy_to_mode_reg (char_mode, char_rtx);
1972
dd05e4fa
RH
1973 pat = GEN_FCN (icode) (result, gen_rtx_MEM (BLKmode, src_reg),
1974 char_rtx, GEN_INT (align));
1975 if (! pat)
1976 return 0;
1977 emit_insn (pat);
1978
1979 /* Now that we are assured of success, expand the source. */
1980 start_sequence ();
8d51ecf8 1981 pat = memory_address (BLKmode,
3bdf5ad1 1982 expand_expr (src, src_reg, ptr_mode, EXPAND_SUM));
dd05e4fa
RH
1983 if (pat != src_reg)
1984 emit_move_insn (src_reg, pat);
2f937369 1985 pat = get_insns ();
dd05e4fa 1986 end_sequence ();
fca9f642
RH
1987
1988 if (before_strlen)
1989 emit_insn_after (pat, before_strlen);
1990 else
1991 emit_insn_before (pat, get_insns ());
28f4ec01
BS
1992
1993 /* Return the value in the proper mode for this function. */
8c9b38d7 1994 if (GET_MODE (result) == target_mode)
dd05e4fa 1995 target = result;
28f4ec01 1996 else if (target != 0)
dd05e4fa 1997 convert_move (target, result, 0);
28f4ec01 1998 else
8c9b38d7 1999 target = convert_to_mode (target_mode, result, 0);
dd05e4fa
RH
2000
2001 return target;
28f4ec01
BS
2002 }
2003}
2004
78e7629e
KG
2005/* Expand a call to the strstr builtin. Return 0 if we failed the
2006 caller should emit a normal call, otherwise try to get the result
2007 in TARGET, if convenient (and in mode MODE if that's convenient). */
2008
2009static rtx
2010expand_builtin_strstr (arglist, target, mode)
2011 tree arglist;
2012 rtx target;
2013 enum machine_mode mode;
2014{
37a08a29 2015 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
78e7629e
KG
2016 return 0;
2017 else
2018 {
2019 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
6385a28f 2020 tree fn;
2dee4af1 2021 const char *p1, *p2;
78e7629e 2022
2dee4af1
JJ
2023 p2 = c_getstr (s2);
2024 if (p2 == NULL)
78e7629e
KG
2025 return 0;
2026
2dee4af1
JJ
2027 p1 = c_getstr (s1);
2028 if (p1 != NULL)
2029 {
2030 const char *r = strstr (p1, p2);
78e7629e 2031
2dee4af1
JJ
2032 if (r == NULL)
2033 return const0_rtx;
78e7629e 2034
2dee4af1
JJ
2035 /* Return an offset into the constant string argument. */
2036 return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
2037 s1, ssize_int (r - p1))),
2038 target, mode, EXPAND_NORMAL);
78e7629e 2039 }
2dee4af1
JJ
2040
2041 if (p2[0] == '\0')
2042 return expand_expr (s1, target, mode, EXPAND_NORMAL);
2043
2044 if (p2[1] != '\0')
2045 return 0;
2046
272f51a3 2047 fn = implicit_built_in_decls[BUILT_IN_STRCHR];
2dee4af1
JJ
2048 if (!fn)
2049 return 0;
2050
2051 /* New argument list transforming strstr(s1, s2) to
2052 strchr(s1, s2[0]). */
2053 arglist =
2054 build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
2055 arglist = tree_cons (NULL_TREE, s1, arglist);
6385a28f
KG
2056 return expand_expr (build_function_call_expr (fn, arglist),
2057 target, mode, EXPAND_NORMAL);
78e7629e
KG
2058 }
2059}
2060
2dee4af1 2061/* Expand a call to the strchr builtin. Return 0 if we failed the
26a87cab
KG
2062 caller should emit a normal call, otherwise try to get the result
2063 in TARGET, if convenient (and in mode MODE if that's convenient). */
2064
2065static rtx
2dee4af1 2066expand_builtin_strchr (arglist, target, mode)
26a87cab
KG
2067 tree arglist;
2068 rtx target;
2069 enum machine_mode mode;
2070{
37a08a29 2071 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
26a87cab
KG
2072 return 0;
2073 else
2074 {
2075 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
2dee4af1 2076 const char *p1;
26a87cab 2077
2dee4af1
JJ
2078 if (TREE_CODE (s2) != INTEGER_CST)
2079 return 0;
2080
2081 p1 = c_getstr (s1);
2082 if (p1 != NULL)
2083 {
ab937357
JJ
2084 char c;
2085 const char *r;
2086
2087 if (target_char_cast (s2, &c))
2088 return 0;
2089
2090 r = strchr (p1, c);
2dee4af1
JJ
2091
2092 if (r == NULL)
26a87cab 2093 return const0_rtx;
2dee4af1
JJ
2094
2095 /* Return an offset into the constant string argument. */
2096 return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
2097 s1, ssize_int (r - p1))),
2098 target, mode, EXPAND_NORMAL);
26a87cab
KG
2099 }
2100
2dee4af1
JJ
2101 /* FIXME: Should use here strchrM optab so that ports can optimize
2102 this. */
2103 return 0;
2104 }
2105}
2106
2107/* Expand a call to the strrchr builtin. Return 0 if we failed the
2108 caller should emit a normal call, otherwise try to get the result
2109 in TARGET, if convenient (and in mode MODE if that's convenient). */
2110
2111static rtx
2112expand_builtin_strrchr (arglist, target, mode)
2113 tree arglist;
2114 rtx target;
2115 enum machine_mode mode;
2116{
37a08a29 2117 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
2dee4af1
JJ
2118 return 0;
2119 else
2120 {
2121 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
6385a28f 2122 tree fn;
2dee4af1
JJ
2123 const char *p1;
2124
2125 if (TREE_CODE (s2) != INTEGER_CST)
26a87cab
KG
2126 return 0;
2127
2dee4af1
JJ
2128 p1 = c_getstr (s1);
2129 if (p1 != NULL)
2130 {
ab937357
JJ
2131 char c;
2132 const char *r;
2133
2134 if (target_char_cast (s2, &c))
2135 return 0;
2136
2137 r = strrchr (p1, c);
2dee4af1
JJ
2138
2139 if (r == NULL)
26a87cab 2140 return const0_rtx;
26a87cab 2141
2dee4af1
JJ
2142 /* Return an offset into the constant string argument. */
2143 return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
2144 s1, ssize_int (r - p1))),
2145 target, mode, EXPAND_NORMAL);
2146 }
26a87cab 2147
2dee4af1
JJ
2148 if (! integer_zerop (s2))
2149 return 0;
2150
272f51a3 2151 fn = implicit_built_in_decls[BUILT_IN_STRCHR];
2dee4af1
JJ
2152 if (!fn)
2153 return 0;
2154
2155 /* Transform strrchr(s1, '\0') to strchr(s1, '\0'). */
6385a28f
KG
2156 return expand_expr (build_function_call_expr (fn, arglist),
2157 target, mode, EXPAND_NORMAL);
2dee4af1
JJ
2158 }
2159}
2160
2161/* Expand a call to the strpbrk builtin. Return 0 if we failed the
2162 caller should emit a normal call, otherwise try to get the result
2163 in TARGET, if convenient (and in mode MODE if that's convenient). */
2164
2165static rtx
2166expand_builtin_strpbrk (arglist, target, mode)
2167 tree arglist;
2168 rtx target;
2169 enum machine_mode mode;
2170{
37a08a29 2171 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
2dee4af1
JJ
2172 return 0;
2173 else
2174 {
2175 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
6385a28f 2176 tree fn;
2dee4af1
JJ
2177 const char *p1, *p2;
2178
2179 p2 = c_getstr (s2);
2180 if (p2 == NULL)
2181 return 0;
2182
2183 p1 = c_getstr (s1);
2184 if (p1 != NULL)
2185 {
2186 const char *r = strpbrk (p1, p2);
2187
2188 if (r == NULL)
2189 return const0_rtx;
2190
2191 /* Return an offset into the constant string argument. */
2192 return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
2193 s1, ssize_int (r - p1))),
2194 target, mode, EXPAND_NORMAL);
26a87cab 2195 }
2dee4af1
JJ
2196
2197 if (p2[0] == '\0')
2198 {
2199 /* strpbrk(x, "") == NULL.
2200 Evaluate and ignore the arguments in case they had
2201 side-effects. */
2202 expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
2203 return const0_rtx;
2204 }
2205
2206 if (p2[1] != '\0')
2207 return 0; /* Really call strpbrk. */
2208
272f51a3 2209 fn = implicit_built_in_decls[BUILT_IN_STRCHR];
2dee4af1
JJ
2210 if (!fn)
2211 return 0;
2212
2213 /* New argument list transforming strpbrk(s1, s2) to
2214 strchr(s1, s2[0]). */
2215 arglist =
2216 build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
2217 arglist = tree_cons (NULL_TREE, s1, arglist);
6385a28f
KG
2218 return expand_expr (build_function_call_expr (fn, arglist),
2219 target, mode, EXPAND_NORMAL);
26a87cab
KG
2220 }
2221}
2222
57814e5e
JJ
2223/* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
2224 bytes from constant string DATA + OFFSET and return it as target
2225 constant. */
2226
2227static rtx
2228builtin_memcpy_read_str (data, offset, mode)
2229 PTR data;
2230 HOST_WIDE_INT offset;
2231 enum machine_mode mode;
2232{
2233 const char *str = (const char *) data;
2234
5197bd50
RK
2235 if (offset < 0
2236 || ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode)
2237 > strlen (str) + 1))
57814e5e
JJ
2238 abort (); /* Attempt to read past the end of constant string. */
2239
2240 return c_readstr (str + offset, mode);
2241}
2242
c2bd38e8 2243/* Expand a call to the memcpy builtin, with arguments in ARGLIST.
9cb65f92
KG
2244 Return 0 if we failed, the caller should emit a normal call,
2245 otherwise try to get the result in TARGET, if convenient (and in
2246 mode MODE if that's convenient). If ENDP is 0 return the
2247 destination pointer, if ENDP is 1 return the end pointer ala
2248 mempcpy, and if ENDP is 2 return the end pointer minus one ala
2249 stpcpy. */
28f4ec01 2250static rtx
9cb65f92 2251expand_builtin_memcpy (arglist, target, mode, endp)
28f4ec01 2252 tree arglist;
c2bd38e8
RS
2253 rtx target;
2254 enum machine_mode mode;
9cb65f92 2255 int endp;
28f4ec01 2256{
019fa094
KG
2257 if (!validate_arglist (arglist,
2258 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
28f4ec01
BS
2259 return 0;
2260 else
2261 {
2262 tree dest = TREE_VALUE (arglist);
2263 tree src = TREE_VALUE (TREE_CHAIN (arglist));
2264 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
57814e5e 2265 const char *src_str;
28f4ec01 2266
5197bd50
RK
2267 unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
2268 unsigned int dest_align
2269 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
28f4ec01
BS
2270 rtx dest_mem, src_mem, dest_addr, len_rtx;
2271
c2bd38e8
RS
2272 /* If DEST is not a pointer type, call the normal function. */
2273 if (dest_align == 0)
ca7fd9cd 2274 return 0;
c2bd38e8
RS
2275
2276 /* If the LEN parameter is zero, return DEST. */
2277 if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
ca7fd9cd
KH
2278 {
2279 /* Evaluate and ignore SRC in case it has side-effects. */
2280 expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
2281 return expand_expr (dest, target, mode, EXPAND_NORMAL);
2282 }
c2bd38e8
RS
2283
2284 /* If either SRC is not a pointer type, don't do this
2285 operation in-line. */
2286 if (src_align == 0)
ca7fd9cd 2287 return 0;
28f4ec01
BS
2288
2289 dest_mem = get_memory_rtx (dest);
8ac61af7 2290 set_mem_align (dest_mem, dest_align);
28f4ec01 2291 len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
57814e5e
JJ
2292 src_str = c_getstr (src);
2293
2294 /* If SRC is a string constant and block move would be done
2295 by pieces, we can avoid loading the string from memory
2296 and only stored the computed constants. */
2297 if (src_str
57814e5e
JJ
2298 && GET_CODE (len_rtx) == CONST_INT
2299 && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
2300 && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
2301 (PTR) src_str, dest_align))
2302 {
2303 store_by_pieces (dest_mem, INTVAL (len_rtx),
2304 builtin_memcpy_read_str,
2305 (PTR) src_str, dest_align);
aa0f70e6
SE
2306 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
2307#ifdef POINTERS_EXTEND_UNSIGNED
2308 if (GET_MODE (dest_mem) != ptr_mode)
2309 dest_mem = convert_memory_address (ptr_mode, dest_mem);
2310#endif
9cb65f92
KG
2311 if (endp)
2312 {
e235df1f 2313 rtx result = gen_rtx_PLUS (GET_MODE (dest_mem), dest_mem, len_rtx);
9cb65f92 2314 if (endp == 2)
e235df1f 2315 result = simplify_gen_binary (MINUS, GET_MODE (result), result, const1_rtx);
9cb65f92
KG
2316 return result;
2317 }
2318 else
2319 return dest_mem;
57814e5e
JJ
2320 }
2321
2322 src_mem = get_memory_rtx (src);
8ac61af7 2323 set_mem_align (src_mem, src_align);
28f4ec01 2324
28f4ec01 2325 /* Copy word part most expediently. */
44bb111a
RH
2326 dest_addr = emit_block_move (dest_mem, src_mem, len_rtx,
2327 BLOCK_OP_NORMAL);
28f4ec01
BS
2328
2329 if (dest_addr == 0)
aa0f70e6
SE
2330 {
2331 dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
2332#ifdef POINTERS_EXTEND_UNSIGNED
2333 if (GET_MODE (dest_addr) != ptr_mode)
2334 dest_addr = convert_memory_address (ptr_mode, dest_addr);
2335#endif
2336 }
28f4ec01 2337
9cb65f92
KG
2338 if (endp)
2339 {
2340 rtx result = gen_rtx_PLUS (GET_MODE (dest_addr), dest_addr, len_rtx);
2341 if (endp == 2)
e235df1f 2342 result = simplify_gen_binary (MINUS, GET_MODE (result), result, const1_rtx);
9cb65f92
KG
2343 return result;
2344 }
2345 else
2346 return dest_addr;
28f4ec01
BS
2347 }
2348}
2349
e3e9f108
JJ
2350/* Expand a call to the mempcpy builtin, with arguments in ARGLIST.
2351 Return 0 if we failed the caller should emit a normal call,
2352 otherwise try to get the result in TARGET, if convenient (and in
2353 mode MODE if that's convenient). */
2354
2355static rtx
2356expand_builtin_mempcpy (arglist, target, mode)
2357 tree arglist;
2358 rtx target;
2359 enum machine_mode mode;
2360{
2361 if (!validate_arglist (arglist,
2362 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
2363 return 0;
2364 else
2365 {
2366 /* If return value is ignored, transform mempcpy into memcpy. */
2367 if (target == const0_rtx)
2368 {
2369 tree fn;
2370 rtx ret = expand_builtin_memcpy (arglist, target, mode, /*endp=*/0);
2371
2372 if (ret)
2373 return ret;
2374
2375 fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
2376 if (!fn)
2377 return 0;
2378
2379 return expand_expr (build_function_call_expr (fn, arglist),
2380 target, mode, EXPAND_NORMAL);
2381 }
2382
2383 return expand_builtin_memcpy (arglist, target, mode, /*endp=*/1);
2384 }
2385}
2386
e31603c4
JJ
2387/* Expand expression EXP, which is a call to the memmove builtin. Return 0
2388 if we failed the caller should emit a normal call. */
2389
2390static rtx
2391expand_builtin_memmove (arglist, target, mode)
2392 tree arglist;
2393 rtx target;
2394 enum machine_mode mode;
2395{
2396 if (!validate_arglist (arglist,
2397 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
2398 return 0;
2399 else
2400 {
2401 tree dest = TREE_VALUE (arglist);
2402 tree src = TREE_VALUE (TREE_CHAIN (arglist));
2403 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
2404
2405 unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
2406 unsigned int dest_align
2407 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
2408
2409 /* If DEST is not a pointer type, call the normal function. */
2410 if (dest_align == 0)
2411 return 0;
2412
2413 /* If the LEN parameter is zero, return DEST. */
2414 if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
2415 {
2416 /* Evaluate and ignore SRC in case it has side-effects. */
2417 expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
2418 return expand_expr (dest, target, mode, EXPAND_NORMAL);
2419 }
2420
2421 /* If either SRC is not a pointer type, don't do this
2422 operation in-line. */
2423 if (src_align == 0)
2424 return 0;
2425
2426 /* If src is a string constant and strings are not writable,
2427 we can use normal memcpy. */
2428 if (!flag_writable_strings && c_getstr (src))
2429 return expand_builtin_memcpy (arglist, target, mode, 0);
2430
2431 /* Otherwise, call the normal function. */
2432 return 0;
2433 }
2434}
2435
2436/* Expand expression EXP, which is a call to the bcopy builtin. Return 0
2437 if we failed the caller should emit a normal call. */
2438
2439static rtx
2440expand_builtin_bcopy (arglist)
2441 tree arglist;
2442{
2443 tree src, dest, size, newarglist;
2444
2445 if (!validate_arglist (arglist,
2446 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
2447 return NULL_RTX;
2448
2449 src = TREE_VALUE (arglist);
2450 dest = TREE_VALUE (TREE_CHAIN (arglist));
2451 size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
2452
2453 /* New argument list transforming bcopy(ptr x, ptr y, int z) to
2454 memmove(ptr y, ptr x, size_t z). This is done this way
2455 so that if it isn't expanded inline, we fallback to
2456 calling bcopy instead of memmove. */
2457
2458 newarglist = build_tree_list (NULL_TREE, convert (sizetype, size));
2459 newarglist = tree_cons (NULL_TREE, src, newarglist);
2460 newarglist = tree_cons (NULL_TREE, dest, newarglist);
2461
2462 return expand_builtin_memmove (newarglist, const0_rtx, VOIDmode);
2463}
2464
28f4ec01 2465/* Expand expression EXP, which is a call to the strcpy builtin. Return 0
c2bd38e8
RS
2466 if we failed the caller should emit a normal call, otherwise try to get
2467 the result in TARGET, if convenient (and in mode MODE if that's
2468 convenient). */
fed3cef0 2469
28f4ec01 2470static rtx
8c9b38d7
KG
2471expand_builtin_strcpy (arglist, target, mode)
2472 tree arglist;
c2bd38e8
RS
2473 rtx target;
2474 enum machine_mode mode;
28f4ec01 2475{
c2bd38e8 2476 tree fn, len;
28f4ec01 2477
019fa094 2478 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
28f4ec01 2479 return 0;
28f4ec01 2480
272f51a3 2481 fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
c2bd38e8
RS
2482 if (!fn)
2483 return 0;
fed3cef0 2484
c2bd38e8
RS
2485 len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
2486 if (len == 0)
2487 return 0;
fed3cef0 2488
c2bd38e8
RS
2489 len = size_binop (PLUS_EXPR, len, ssize_int (1));
2490 chainon (arglist, build_tree_list (NULL_TREE, len));
2491 return expand_expr (build_function_call_expr (fn, arglist),
ca7fd9cd 2492 target, mode, EXPAND_NORMAL);
28f4ec01
BS
2493}
2494
9cb65f92
KG
2495/* Expand a call to the stpcpy builtin, with arguments in ARGLIST.
2496 Return 0 if we failed the caller should emit a normal call,
2497 otherwise try to get the result in TARGET, if convenient (and in
2498 mode MODE if that's convenient). */
2499
2500static rtx
2501expand_builtin_stpcpy (arglist, target, mode)
2502 tree arglist;
2503 rtx target;
2504 enum machine_mode mode;
2505{
2506 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
2507 return 0;
2508 else
2509 {
685828f7 2510 tree newarglist;
68ef8841 2511 tree src, len;
e3e9f108
JJ
2512
2513 /* If return value is ignored, transform stpcpy into strcpy. */
2514 if (target == const0_rtx)
2515 {
2516 tree fn;
2517 rtx ret = expand_builtin_strcpy (arglist, target, mode);
2518
2519 if (ret)
2520 return ret;
2521
2522 fn = implicit_built_in_decls[BUILT_IN_STRCPY];
2523 if (!fn)
2524 return 0;
2525
2526 return expand_expr (build_function_call_expr (fn, arglist),
2527 target, mode, EXPAND_NORMAL);
2528 }
2529
68ef8841
KG
2530 /* Ensure we get an actual string who length can be evaluated at
2531 compile-time, not an expression containing a string. This is
2532 because the latter will potentially produce pessimized code
2533 when used to produce the return value. */
2534 src = TREE_VALUE (TREE_CHAIN (arglist));
2535 if (! c_getstr (src) || ! (len = c_strlen (src)))
9cb65f92
KG
2536 return 0;
2537
2538 len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
685828f7
KG
2539 newarglist = copy_list (arglist);
2540 chainon (newarglist, build_tree_list (NULL_TREE, len));
2541 return expand_builtin_memcpy (newarglist, target, mode, /*endp=*/2);
9cb65f92
KG
2542 }
2543}
2544
57814e5e
JJ
2545/* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
2546 bytes from constant string DATA + OFFSET and return it as target
2547 constant. */
2548
2549static rtx
2550builtin_strncpy_read_str (data, offset, mode)
2551 PTR data;
2552 HOST_WIDE_INT offset;
2553 enum machine_mode mode;
2554{
2555 const char *str = (const char *) data;
2556
2557 if ((unsigned HOST_WIDE_INT) offset > strlen (str))
2558 return const0_rtx;
2559
2560 return c_readstr (str + offset, mode);
2561}
2562
da9e9f08
KG
2563/* Expand expression EXP, which is a call to the strncpy builtin. Return 0
2564 if we failed the caller should emit a normal call. */
2565
2566static rtx
2567expand_builtin_strncpy (arglist, target, mode)
2568 tree arglist;
2569 rtx target;
2570 enum machine_mode mode;
2571{
019fa094
KG
2572 if (!validate_arglist (arglist,
2573 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
da9e9f08
KG
2574 return 0;
2575 else
2576 {
2577 tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
2578 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
c2bd38e8 2579 tree fn;
da9e9f08
KG
2580
2581 /* We must be passed a constant len parameter. */
2582 if (TREE_CODE (len) != INTEGER_CST)
2583 return 0;
2584
2585 /* If the len parameter is zero, return the dst parameter. */
995b5904 2586 if (integer_zerop (len))
ca7fd9cd
KH
2587 {
2588 /* Evaluate and ignore the src argument in case it has
2589 side-effects. */
da9e9f08
KG
2590 expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx,
2591 VOIDmode, EXPAND_NORMAL);
8d51ecf8 2592 /* Return the dst parameter. */
da9e9f08
KG
2593 return expand_expr (TREE_VALUE (arglist), target, mode,
2594 EXPAND_NORMAL);
2595 }
57814e5e 2596
da9e9f08 2597 /* Now, we must be passed a constant src ptr parameter. */
57814e5e 2598 if (slen == 0 || TREE_CODE (slen) != INTEGER_CST)
da9e9f08
KG
2599 return 0;
2600
2601 slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
2602
2603 /* We're required to pad with trailing zeros if the requested
57814e5e
JJ
2604 len is greater than strlen(s2)+1. In that case try to
2605 use store_by_pieces, if it fails, punt. */
da9e9f08 2606 if (tree_int_cst_lt (slen, len))
57814e5e
JJ
2607 {
2608 tree dest = TREE_VALUE (arglist);
5197bd50
RK
2609 unsigned int dest_align
2610 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
57814e5e
JJ
2611 const char *p = c_getstr (TREE_VALUE (TREE_CHAIN (arglist)));
2612 rtx dest_mem;
2613
5197bd50
RK
2614 if (!p || dest_align == 0 || !host_integerp (len, 1)
2615 || !can_store_by_pieces (tree_low_cst (len, 1),
57814e5e
JJ
2616 builtin_strncpy_read_str,
2617 (PTR) p, dest_align))
2618 return 0;
2619
2620 dest_mem = get_memory_rtx (dest);
5197bd50 2621 store_by_pieces (dest_mem, tree_low_cst (len, 1),
57814e5e
JJ
2622 builtin_strncpy_read_str,
2623 (PTR) p, dest_align);
aa0f70e6
SE
2624 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
2625#ifdef POINTERS_EXTEND_UNSIGNED
2626 if (GET_MODE (dest_mem) != ptr_mode)
2627 dest_mem = convert_memory_address (ptr_mode, dest_mem);
2628#endif
2629 return dest_mem;
57814e5e 2630 }
8d51ecf8 2631
da9e9f08 2632 /* OK transform into builtin memcpy. */
272f51a3 2633 fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
c2bd38e8 2634 if (!fn)
ca7fd9cd 2635 return 0;
c2bd38e8 2636 return expand_expr (build_function_call_expr (fn, arglist),
ca7fd9cd 2637 target, mode, EXPAND_NORMAL);
da9e9f08
KG
2638 }
2639}
2640
ab937357
JJ
2641/* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
2642 bytes from constant string DATA + OFFSET and return it as target
2643 constant. */
2644
2645static rtx
2646builtin_memset_read_str (data, offset, mode)
2647 PTR data;
2648 HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
2649 enum machine_mode mode;
2650{
2651 const char *c = (const char *) data;
2652 char *p = alloca (GET_MODE_SIZE (mode));
2653
2654 memset (p, *c, GET_MODE_SIZE (mode));
2655
2656 return c_readstr (p, mode);
2657}
2658
1a887f86
RS
2659/* Callback routine for store_by_pieces. Return the RTL of a register
2660 containing GET_MODE_SIZE (MODE) consecutive copies of the unsigned
2661 char value given in the RTL register data. For example, if mode is
2662 4 bytes wide, return the RTL for 0x01010101*data. */
2663
2664static rtx
2665builtin_memset_gen_str (data, offset, mode)
2666 PTR data;
2667 HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
2668 enum machine_mode mode;
2669{
2670 rtx target, coeff;
2671 size_t size;
2672 char *p;
2673
2674 size = GET_MODE_SIZE (mode);
5ab2f7b7
KH
2675 if (size == 1)
2676 return (rtx) data;
1a887f86
RS
2677
2678 p = alloca (size);
2679 memset (p, 1, size);
2680 coeff = c_readstr (p, mode);
2681
5ab2f7b7 2682 target = convert_to_mode (mode, (rtx) data, 1);
1a887f86
RS
2683 target = expand_mult (mode, target, coeff, NULL_RTX, 1);
2684 return force_reg (mode, target);
2685}
2686
28f4ec01 2687/* Expand expression EXP, which is a call to the memset builtin. Return 0
c2bd38e8
RS
2688 if we failed the caller should emit a normal call, otherwise try to get
2689 the result in TARGET, if convenient (and in mode MODE if that's
2690 convenient). */
fed3cef0 2691
28f4ec01 2692static rtx
8c9b38d7
KG
2693expand_builtin_memset (arglist, target, mode)
2694 tree arglist;
c2bd38e8
RS
2695 rtx target;
2696 enum machine_mode mode;
28f4ec01 2697{
019fa094
KG
2698 if (!validate_arglist (arglist,
2699 POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
28f4ec01
BS
2700 return 0;
2701 else
2702 {
2703 tree dest = TREE_VALUE (arglist);
2704 tree val = TREE_VALUE (TREE_CHAIN (arglist));
2705 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
ab937357 2706 char c;
28f4ec01 2707
5197bd50
RK
2708 unsigned int dest_align
2709 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
28f4ec01
BS
2710 rtx dest_mem, dest_addr, len_rtx;
2711
8d51ecf8 2712 /* If DEST is not a pointer type, don't do this
28f4ec01
BS
2713 operation in-line. */
2714 if (dest_align == 0)
2715 return 0;
2716
c2bd38e8
RS
2717 /* If the LEN parameter is zero, return DEST. */
2718 if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
ca7fd9cd
KH
2719 {
2720 /* Evaluate and ignore VAL in case it has side-effects. */
2721 expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL);
2722 return expand_expr (dest, target, mode, EXPAND_NORMAL);
2723 }
c2bd38e8 2724
ab937357 2725 if (TREE_CODE (val) != INTEGER_CST)
ca7fd9cd
KH
2726 {
2727 rtx val_rtx;
1a887f86 2728
ca7fd9cd
KH
2729 if (!host_integerp (len, 1))
2730 return 0;
1a887f86 2731
ca7fd9cd
KH
2732 if (optimize_size && tree_low_cst (len, 1) > 1)
2733 return 0;
1a887f86 2734
ca7fd9cd
KH
2735 /* Assume that we can memset by pieces if we can store the
2736 * the coefficients by pieces (in the required modes).
2737 * We can't pass builtin_memset_gen_str as that emits RTL. */
2738 c = 1;
1a887f86
RS
2739 if (!can_store_by_pieces (tree_low_cst (len, 1),
2740 builtin_memset_read_str,
ca7fd9cd 2741 (PTR) &c, dest_align))
1a887f86
RS
2742 return 0;
2743
ca7fd9cd
KH
2744 val = fold (build1 (CONVERT_EXPR, unsigned_char_type_node, val));
2745 val_rtx = expand_expr (val, NULL_RTX, VOIDmode, 0);
2746 val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
2747 val_rtx);
1a887f86
RS
2748 dest_mem = get_memory_rtx (dest);
2749 store_by_pieces (dest_mem, tree_low_cst (len, 1),
2750 builtin_memset_gen_str,
5ab2f7b7 2751 (PTR) val_rtx, dest_align);
aa0f70e6
SE
2752 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
2753#ifdef POINTERS_EXTEND_UNSIGNED
2754 if (GET_MODE (dest_mem) != ptr_mode)
2755 dest_mem = convert_memory_address (ptr_mode, dest_mem);
2756#endif
2757 return dest_mem;
ca7fd9cd 2758 }
28f4ec01 2759
ab937357 2760 if (target_char_cast (val, &c))
28f4ec01
BS
2761 return 0;
2762
ab937357
JJ
2763 if (c)
2764 {
5197bd50 2765 if (!host_integerp (len, 1))
ab937357 2766 return 0;
37a08a29
RK
2767 if (!can_store_by_pieces (tree_low_cst (len, 1),
2768 builtin_memset_read_str, (PTR) &c,
2769 dest_align))
ab937357
JJ
2770 return 0;
2771
2772 dest_mem = get_memory_rtx (dest);
5197bd50 2773 store_by_pieces (dest_mem, tree_low_cst (len, 1),
ab937357
JJ
2774 builtin_memset_read_str,
2775 (PTR) &c, dest_align);
aa0f70e6
SE
2776 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
2777#ifdef POINTERS_EXTEND_UNSIGNED
2778 if (GET_MODE (dest_mem) != ptr_mode)
2779 dest_mem = convert_memory_address (ptr_mode, dest_mem);
2780#endif
2781 return dest_mem;
ab937357
JJ
2782 }
2783
28f4ec01 2784 len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
28f4ec01
BS
2785
2786 dest_mem = get_memory_rtx (dest);
8ac61af7 2787 set_mem_align (dest_mem, dest_align);
8ac61af7 2788 dest_addr = clear_storage (dest_mem, len_rtx);
28f4ec01
BS
2789
2790 if (dest_addr == 0)
aa0f70e6
SE
2791 {
2792 dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
2793#ifdef POINTERS_EXTEND_UNSIGNED
2794 if (GET_MODE (dest_addr) != ptr_mode)
2795 dest_addr = convert_memory_address (ptr_mode, dest_addr);
2796#endif
2797 }
28f4ec01
BS
2798
2799 return dest_addr;
2800 }
2801}
2802
e3a709be
KG
2803/* Expand expression EXP, which is a call to the bzero builtin. Return 0
2804 if we failed the caller should emit a normal call. */
5197bd50 2805
e3a709be 2806static rtx
8c9b38d7
KG
2807expand_builtin_bzero (arglist)
2808 tree arglist;
e3a709be 2809{
3477addf 2810 tree dest, size, newarglist;
e3a709be 2811
019fa094 2812 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
3477addf 2813 return NULL_RTX;
e3a709be 2814
019fa094
KG
2815 dest = TREE_VALUE (arglist);
2816 size = TREE_VALUE (TREE_CHAIN (arglist));
8d51ecf8 2817
3477addf 2818 /* New argument list transforming bzero(ptr x, int y) to
c2bd38e8
RS
2819 memset(ptr x, int 0, size_t y). This is done this way
2820 so that if it isn't expanded inline, we fallback to
2821 calling bzero instead of memset. */
8d51ecf8 2822
3477addf
RH
2823 newarglist = build_tree_list (NULL_TREE, convert (sizetype, size));
2824 newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
2825 newarglist = tree_cons (NULL_TREE, dest, newarglist);
e3a709be 2826
8c9b38d7 2827 return expand_builtin_memset (newarglist, const0_rtx, VOIDmode);
e3a709be
KG
2828}
2829
2be3b5ce 2830/* Expand expression EXP, which is a call to the memcmp built-in function.
28f4ec01
BS
2831 ARGLIST is the argument list for this call. Return 0 if we failed and the
2832 caller should emit a normal call, otherwise try to get the result in
c2bd38e8 2833 TARGET, if convenient (and in mode MODE, if that's convenient). */
5197bd50 2834
28f4ec01 2835static rtx
c2bd38e8 2836expand_builtin_memcmp (exp, arglist, target, mode)
88f92c0f 2837 tree exp ATTRIBUTE_UNUSED;
28f4ec01
BS
2838 tree arglist;
2839 rtx target;
c2bd38e8 2840 enum machine_mode mode;
28f4ec01 2841{
c2bd38e8 2842 tree arg1, arg2, len;
fe85f179 2843 const char *p1, *p2;
c2bd38e8 2844
019fa094 2845 if (!validate_arglist (arglist,
ca7fd9cd 2846 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
28f4ec01 2847 return 0;
28f4ec01 2848
c2bd38e8
RS
2849 arg1 = TREE_VALUE (arglist);
2850 arg2 = TREE_VALUE (TREE_CHAIN (arglist));
2851 len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
2852
2853 /* If the len parameter is zero, return zero. */
2854 if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
2855 {
2856 /* Evaluate and ignore arg1 and arg2 in case they have
2857 side-effects. */
2858 expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
2859 expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
2860 return const0_rtx;
2861 }
2862
fe85f179
RS
2863 p1 = c_getstr (arg1);
2864 p2 = c_getstr (arg2);
2865
2866 /* If all arguments are constant, and the value of len is not greater
2867 than the lengths of arg1 and arg2, evaluate at compile-time. */
2868 if (host_integerp (len, 1) && p1 && p2
995b5904
RK
2869 && compare_tree_int (len, strlen (p1) + 1) <= 0
2870 && compare_tree_int (len, strlen (p2) + 1) <= 0)
fe85f179
RS
2871 {
2872 const int r = memcmp (p1, p2, tree_low_cst (len, 1));
995b5904 2873
fe85f179
RS
2874 return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
2875 }
2876
c2bd38e8
RS
2877 /* If len parameter is one, return an expression corresponding to
2878 (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */
2879 if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
2880 {
2881 tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
2882 tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
2883 tree ind1 =
2884 fold (build1 (CONVERT_EXPR, integer_type_node,
ca7fd9cd
KH
2885 build1 (INDIRECT_REF, cst_uchar_node,
2886 build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
c2bd38e8
RS
2887 tree ind2 =
2888 fold (build1 (CONVERT_EXPR, integer_type_node,
ca7fd9cd
KH
2889 build1 (INDIRECT_REF, cst_uchar_node,
2890 build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
c2bd38e8
RS
2891 tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
2892 return expand_expr (result, target, mode, EXPAND_NORMAL);
2893 }
2894
2895#ifdef HAVE_cmpstrsi
28f4ec01 2896 {
8878e913 2897 rtx arg1_rtx, arg2_rtx, arg3_rtx;
28f4ec01 2898 rtx result;
8878e913 2899 rtx insn;
28f4ec01
BS
2900
2901 int arg1_align
2902 = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
2903 int arg2_align
2904 = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
2905 enum machine_mode insn_mode
a995e389 2906 = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
28f4ec01
BS
2907
2908 /* If we don't have POINTER_TYPE, call the function. */
2909 if (arg1_align == 0 || arg2_align == 0)
2910 return 0;
2911
2912 /* Make a place to write the result of the instruction. */
2913 result = target;
2914 if (! (result != 0
2915 && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
2916 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
2917 result = gen_reg_rtx (insn_mode);
2918
8878e913
JH
2919 arg1_rtx = get_memory_rtx (arg1);
2920 arg2_rtx = get_memory_rtx (arg2);
2921 arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
2922 if (!HAVE_cmpstrsi)
2923 insn = NULL_RTX;
2924 else
2925 insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
2926 GEN_INT (MIN (arg1_align, arg2_align)));
2927
2928 if (insn)
2929 emit_insn (insn);
2930 else
ebb1b59a 2931 emit_library_call_value (memcmp_libfunc, result, LCT_PURE_MAKE_BLOCK,
8878e913
JH
2932 TYPE_MODE (integer_type_node), 3,
2933 XEXP (arg1_rtx, 0), Pmode,
2934 XEXP (arg2_rtx, 0), Pmode,
2935 convert_to_mode (TYPE_MODE (sizetype), arg3_rtx,
2936 TREE_UNSIGNED (sizetype)),
2937 TYPE_MODE (sizetype));
28f4ec01
BS
2938
2939 /* Return the value in the proper mode for this function. */
2940 mode = TYPE_MODE (TREE_TYPE (exp));
2941 if (GET_MODE (result) == mode)
2942 return result;
2943 else if (target != 0)
2944 {
2945 convert_move (target, result, 0);
2946 return target;
2947 }
2948 else
2949 return convert_to_mode (mode, result, 0);
2950 }
2dee4af1 2951#endif
28f4ec01 2952
c2bd38e8
RS
2953 return 0;
2954}
2955
28f4ec01
BS
2956/* Expand expression EXP, which is a call to the strcmp builtin. Return 0
2957 if we failed the caller should emit a normal call, otherwise try to get
2958 the result in TARGET, if convenient. */
fed3cef0 2959
28f4ec01 2960static rtx
2dee4af1 2961expand_builtin_strcmp (exp, target, mode)
28f4ec01
BS
2962 tree exp;
2963 rtx target;
2dee4af1 2964 enum machine_mode mode;
28f4ec01
BS
2965{
2966 tree arglist = TREE_OPERAND (exp, 1);
2be3b5ce 2967 tree arg1, arg2;
2dee4af1 2968 const char *p1, *p2;
28f4ec01 2969
019fa094 2970 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
28f4ec01 2971 return 0;
fed3cef0 2972
2dee4af1
JJ
2973 arg1 = TREE_VALUE (arglist);
2974 arg2 = TREE_VALUE (TREE_CHAIN (arglist));
2975
2976 p1 = c_getstr (arg1);
2977 p2 = c_getstr (arg2);
2978
2979 if (p1 && p2)
2980 {
ca8034a0
KG
2981 const int i = strcmp (p1, p2);
2982 return (i < 0 ? constm1_rtx : (i > 0 ? const1_rtx : const0_rtx));
2dee4af1
JJ
2983 }
2984
ca8034a0
KG
2985 /* If either arg is "", return an expression corresponding to
2986 (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */
2987 if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
2988 {
2989 tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
2990 tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
2991 tree ind1 =
2992 fold (build1 (CONVERT_EXPR, integer_type_node,
2993 build1 (INDIRECT_REF, cst_uchar_node,
2994 build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
2995 tree ind2 =
2996 fold (build1 (CONVERT_EXPR, integer_type_node,
2997 build1 (INDIRECT_REF, cst_uchar_node,
2998 build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
2999 tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
3000 return expand_expr (result, target, mode, EXPAND_NORMAL);
3001 }
8d51ecf8 3002
2be3b5ce
RS
3003#ifdef HAVE_cmpstrsi
3004 if (HAVE_cmpstrsi)
3005 {
3006 tree len, len1, len2;
3007 rtx arg1_rtx, arg2_rtx, arg3_rtx;
3008 rtx result, insn;
fed3cef0 3009
2be3b5ce
RS
3010 int arg1_align
3011 = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
3012 int arg2_align
3013 = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
3014 enum machine_mode insn_mode
3015 = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
fed3cef0 3016
2be3b5ce
RS
3017 len1 = c_strlen (arg1);
3018 len2 = c_strlen (arg2);
3019
3020 if (len1)
3021 len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
3022 if (len2)
3023 len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
3024
3025 /* If we don't have a constant length for the first, use the length
3026 of the second, if we know it. We don't require a constant for
3027 this case; some cost analysis could be done if both are available
3028 but neither is constant. For now, assume they're equally cheap,
3029 unless one has side effects. If both strings have constant lengths,
3030 use the smaller. */
3031
3032 if (!len1)
3033 len = len2;
3034 else if (!len2)
3035 len = len1;
3036 else if (TREE_SIDE_EFFECTS (len1))
3037 len = len2;
3038 else if (TREE_SIDE_EFFECTS (len2))
3039 len = len1;
3040 else if (TREE_CODE (len1) != INTEGER_CST)
3041 len = len2;
3042 else if (TREE_CODE (len2) != INTEGER_CST)
3043 len = len1;
3044 else if (tree_int_cst_lt (len1, len2))
3045 len = len1;
3046 else
3047 len = len2;
28f4ec01 3048
2be3b5ce
RS
3049 /* If both arguments have side effects, we cannot optimize. */
3050 if (!len || TREE_SIDE_EFFECTS (len))
3051 return 0;
28f4ec01 3052
2be3b5ce
RS
3053 /* If we don't have POINTER_TYPE, call the function. */
3054 if (arg1_align == 0 || arg2_align == 0)
3055 return 0;
fed3cef0 3056
2be3b5ce
RS
3057 /* Make a place to write the result of the instruction. */
3058 result = target;
3059 if (! (result != 0
3060 && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
3061 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
3062 result = gen_reg_rtx (insn_mode);
28f4ec01 3063
2be3b5ce
RS
3064 arg1_rtx = get_memory_rtx (arg1);
3065 arg2_rtx = get_memory_rtx (arg2);
3066 arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
3067 insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
3068 GEN_INT (MIN (arg1_align, arg2_align)));
3069 if (!insn)
3070 return 0;
57814e5e 3071
2be3b5ce 3072 emit_insn (insn);
fed3cef0 3073
2be3b5ce
RS
3074 /* Return the value in the proper mode for this function. */
3075 mode = TYPE_MODE (TREE_TYPE (exp));
3076 if (GET_MODE (result) == mode)
3077 return result;
3078 if (target == 0)
3079 return convert_to_mode (mode, result, 0);
3080 convert_move (target, result, 0);
3081 return target;
3082 }
3083#endif
3084 return 0;
2dee4af1 3085}
28f4ec01 3086
da9e9f08
KG
3087/* Expand expression EXP, which is a call to the strncmp builtin. Return 0
3088 if we failed the caller should emit a normal call, otherwise try to get
3089 the result in TARGET, if convenient. */
5197bd50 3090
da9e9f08
KG
3091static rtx
3092expand_builtin_strncmp (exp, target, mode)
3093 tree exp;
3094 rtx target;
3095 enum machine_mode mode;
3096{
3097 tree arglist = TREE_OPERAND (exp, 1);
3098 tree arg1, arg2, arg3;
3099 const char *p1, *p2;
3100
019fa094
KG
3101 if (!validate_arglist (arglist,
3102 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
da9e9f08
KG
3103 return 0;
3104
3105 arg1 = TREE_VALUE (arglist);
3106 arg2 = TREE_VALUE (TREE_CHAIN (arglist));
3107 arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
3108
da9e9f08 3109 /* If the len parameter is zero, return zero. */
819c1488 3110 if (host_integerp (arg3, 1) && tree_low_cst (arg3, 1) == 0)
ca7fd9cd
KH
3111 {
3112 /* Evaluate and ignore arg1 and arg2 in case they have
3113 side-effects. */
3114 expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
3115 expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
3116 return const0_rtx;
3117 }
da9e9f08
KG
3118
3119 p1 = c_getstr (arg1);
3120 p2 = c_getstr (arg2);
3121
3122 /* If all arguments are constant, evaluate at compile-time. */
819c1488 3123 if (host_integerp (arg3, 1) && p1 && p2)
ca7fd9cd
KH
3124 {
3125 const int r = strncmp (p1, p2, tree_low_cst (arg3, 1));
3126 return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
3127 }
da9e9f08 3128
ca8034a0 3129 /* If len == 1 or (either string parameter is "" and (len >= 1)),
819c1488
KG
3130 return (*(const u_char*)arg1 - *(const u_char*)arg2). */
3131 if (host_integerp (arg3, 1)
3132 && (tree_low_cst (arg3, 1) == 1
3133 || (tree_low_cst (arg3, 1) > 1
3134 && ((p1 && *p1 == '\0') || (p2 && *p2 == '\0')))))
ca8034a0
KG
3135 {
3136 tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
3137 tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
3138 tree ind1 =
3139 fold (build1 (CONVERT_EXPR, integer_type_node,
3140 build1 (INDIRECT_REF, cst_uchar_node,
3141 build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
3142 tree ind2 =
3143 fold (build1 (CONVERT_EXPR, integer_type_node,
3144 build1 (INDIRECT_REF, cst_uchar_node,
3145 build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
3146 tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
3147 return expand_expr (result, target, mode, EXPAND_NORMAL);
3148 }
da9e9f08 3149
819c1488 3150 /* If c_strlen can determine an expression for one of the string
2be3b5ce
RS
3151 lengths, and it doesn't have side effects, then emit cmpstrsi
3152 using length MIN(strlen(string)+1, arg3). */
3153#ifdef HAVE_cmpstrsi
3154 if (HAVE_cmpstrsi)
3155 {
3156 tree len, len1, len2;
3157 rtx arg1_rtx, arg2_rtx, arg3_rtx;
3158 rtx result, insn;
c2bd38e8 3159
2be3b5ce
RS
3160 int arg1_align
3161 = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
3162 int arg2_align
3163 = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
3164 enum machine_mode insn_mode
3165 = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
8d51ecf8 3166
2be3b5ce
RS
3167 len1 = c_strlen (arg1);
3168 len2 = c_strlen (arg2);
3169
3170 if (len1)
3171 len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
3172 if (len2)
3173 len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
3174
3175 /* If we don't have a constant length for the first, use the length
3176 of the second, if we know it. We don't require a constant for
3177 this case; some cost analysis could be done if both are available
3178 but neither is constant. For now, assume they're equally cheap,
3179 unless one has side effects. If both strings have constant lengths,
3180 use the smaller. */
3181
3182 if (!len1)
3183 len = len2;
3184 else if (!len2)
3185 len = len1;
3186 else if (TREE_SIDE_EFFECTS (len1))
3187 len = len2;
3188 else if (TREE_SIDE_EFFECTS (len2))
3189 len = len1;
3190 else if (TREE_CODE (len1) != INTEGER_CST)
3191 len = len2;
3192 else if (TREE_CODE (len2) != INTEGER_CST)
3193 len = len1;
3194 else if (tree_int_cst_lt (len1, len2))
3195 len = len1;
3196 else
3197 len = len2;
819c1488 3198
2be3b5ce
RS
3199 /* If both arguments have side effects, we cannot optimize. */
3200 if (!len || TREE_SIDE_EFFECTS (len))
3201 return 0;
8d51ecf8 3202
2be3b5ce
RS
3203 /* The actual new length parameter is MIN(len,arg3). */
3204 len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));
3205
3206 /* If we don't have POINTER_TYPE, call the function. */
3207 if (arg1_align == 0 || arg2_align == 0)
3208 return 0;
3209
3210 /* Make a place to write the result of the instruction. */
3211 result = target;
3212 if (! (result != 0
3213 && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
3214 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
3215 result = gen_reg_rtx (insn_mode);
3216
3217 arg1_rtx = get_memory_rtx (arg1);
3218 arg2_rtx = get_memory_rtx (arg2);
3219 arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
3220 insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
3221 GEN_INT (MIN (arg1_align, arg2_align)));
3222 if (!insn)
3223 return 0;
3224
3225 emit_insn (insn);
3226
3227 /* Return the value in the proper mode for this function. */
3228 mode = TYPE_MODE (TREE_TYPE (exp));
3229 if (GET_MODE (result) == mode)
3230 return result;
3231 if (target == 0)
3232 return convert_to_mode (mode, result, 0);
3233 convert_move (target, result, 0);
3234 return target;
3235 }
3236#endif
3237 return 0;
da9e9f08
KG
3238}
3239
d118937d
KG
3240/* Expand expression EXP, which is a call to the strcat builtin.
3241 Return 0 if we failed the caller should emit a normal call,
3242 otherwise try to get the result in TARGET, if convenient. */
5197bd50 3243
d118937d
KG
3244static rtx
3245expand_builtin_strcat (arglist, target, mode)
3246 tree arglist;
3247 rtx target;
3248 enum machine_mode mode;
3249{
019fa094 3250 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
d118937d
KG
3251 return 0;
3252 else
3253 {
3254 tree dst = TREE_VALUE (arglist),
3255 src = TREE_VALUE (TREE_CHAIN (arglist));
3256 const char *p = c_getstr (src);
3257
3258 /* If the string length is zero, return the dst parameter. */
3259 if (p && *p == '\0')
3260 return expand_expr (dst, target, mode, EXPAND_NORMAL);
3261
3262 return 0;
3263 }
3264}
3265
3266/* Expand expression EXP, which is a call to the strncat builtin.
3267 Return 0 if we failed the caller should emit a normal call,
3268 otherwise try to get the result in TARGET, if convenient. */
5197bd50 3269
d118937d
KG
3270static rtx
3271expand_builtin_strncat (arglist, target, mode)
3272 tree arglist;
3273 rtx target;
3274 enum machine_mode mode;
3275{
019fa094
KG
3276 if (!validate_arglist (arglist,
3277 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
d118937d
KG
3278 return 0;
3279 else
3280 {
3281 tree dst = TREE_VALUE (arglist),
3282 src = TREE_VALUE (TREE_CHAIN (arglist)),
3283 len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
3284 const char *p = c_getstr (src);
3285
3286 /* If the requested length is zero, or the src parameter string
3287 length is zero, return the dst parameter. */
93051e0f 3288 if (integer_zerop (len) || (p && *p == '\0'))
ca7fd9cd 3289 {
d118937d
KG
3290 /* Evaluate and ignore the src and len parameters in case
3291 they have side-effects. */
3292 expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
3293 expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL);
3294 return expand_expr (dst, target, mode, EXPAND_NORMAL);
3295 }
3296
3297 /* If the requested len is greater than or equal to the string
3298 length, call strcat. */
3299 if (TREE_CODE (len) == INTEGER_CST && p
3300 && compare_tree_int (len, strlen (p)) >= 0)
ca7fd9cd 3301 {
995b5904
RK
3302 tree newarglist
3303 = tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src));
272f51a3 3304 tree fn = implicit_built_in_decls[BUILT_IN_STRCAT];
8d51ecf8 3305
d118937d 3306 /* If the replacement _DECL isn't initialized, don't do the
ec5c56db 3307 transformation. */
d118937d
KG
3308 if (!fn)
3309 return 0;
3310
6385a28f
KG
3311 return expand_expr (build_function_call_expr (fn, newarglist),
3312 target, mode, EXPAND_NORMAL);
d118937d
KG
3313 }
3314 return 0;
3315 }
3316}
3317
3318/* Expand expression EXP, which is a call to the strspn builtin.
3319 Return 0 if we failed the caller should emit a normal call,
3320 otherwise try to get the result in TARGET, if convenient. */
5197bd50 3321
d118937d
KG
3322static rtx
3323expand_builtin_strspn (arglist, target, mode)
3324 tree arglist;
3325 rtx target;
3326 enum machine_mode mode;
3327{
019fa094 3328 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
d118937d
KG
3329 return 0;
3330 else
3331 {
3332 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
3333 const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
8d51ecf8 3334
d118937d
KG
3335 /* If both arguments are constants, evaluate at compile-time. */
3336 if (p1 && p2)
ca7fd9cd 3337 {
d118937d
KG
3338 const size_t r = strspn (p1, p2);
3339 return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
3340 }
8d51ecf8 3341
611b1df4
KG
3342 /* If either argument is "", return 0. */
3343 if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
ca7fd9cd 3344 {
611b1df4 3345 /* Evaluate and ignore both arguments in case either one has
d118937d
KG
3346 side-effects. */
3347 expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
611b1df4 3348 expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL);
d118937d
KG
3349 return const0_rtx;
3350 }
3351 return 0;
3352 }
3353}
3354
3355/* Expand expression EXP, which is a call to the strcspn builtin.
3356 Return 0 if we failed the caller should emit a normal call,
3357 otherwise try to get the result in TARGET, if convenient. */
5197bd50 3358
d118937d
KG
3359static rtx
3360expand_builtin_strcspn (arglist, target, mode)
3361 tree arglist;
3362 rtx target;
3363 enum machine_mode mode;
3364{
019fa094 3365 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
d118937d
KG
3366 return 0;
3367 else
3368 {
3369 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
3370 const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
8d51ecf8 3371
d118937d
KG
3372 /* If both arguments are constants, evaluate at compile-time. */
3373 if (p1 && p2)
ca7fd9cd 3374 {
d118937d
KG
3375 const size_t r = strcspn (p1, p2);
3376 return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
3377 }
8d51ecf8 3378
611b1df4
KG
3379 /* If the first argument is "", return 0. */
3380 if (p1 && *p1 == '\0')
ca7fd9cd 3381 {
611b1df4
KG
3382 /* Evaluate and ignore argument s2 in case it has
3383 side-effects. */
3384 expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL);
3385 return const0_rtx;
3386 }
3387
d118937d
KG
3388 /* If the second argument is "", return __builtin_strlen(s1). */
3389 if (p2 && *p2 == '\0')
ca7fd9cd 3390 {
6385a28f 3391 tree newarglist = build_tree_list (NULL_TREE, s1),
272f51a3 3392 fn = implicit_built_in_decls[BUILT_IN_STRLEN];
8d51ecf8 3393
d118937d 3394 /* If the replacement _DECL isn't initialized, don't do the
ec5c56db 3395 transformation. */
d118937d
KG
3396 if (!fn)
3397 return 0;
3398
6385a28f
KG
3399 return expand_expr (build_function_call_expr (fn, newarglist),
3400 target, mode, EXPAND_NORMAL);
d118937d
KG
3401 }
3402 return 0;
3403 }
3404}
3405
d3707adb
RH
3406/* Expand a call to __builtin_saveregs, generating the result in TARGET,
3407 if that's convenient. */
fed3cef0 3408
d3707adb
RH
3409rtx
3410expand_builtin_saveregs ()
28f4ec01 3411{
d3707adb 3412 rtx val, seq;
28f4ec01
BS
3413
3414 /* Don't do __builtin_saveregs more than once in a function.
3415 Save the result of the first call and reuse it. */
3416 if (saveregs_value != 0)
3417 return saveregs_value;
28f4ec01 3418
d3707adb
RH
3419 /* When this function is called, it means that registers must be
3420 saved on entry to this function. So we migrate the call to the
3421 first insn of this function. */
3422
3423 start_sequence ();
28f4ec01
BS
3424
3425#ifdef EXPAND_BUILTIN_SAVEREGS
d3707adb
RH
3426 /* Do whatever the machine needs done in this case. */
3427 val = EXPAND_BUILTIN_SAVEREGS ();
28f4ec01 3428#else
d3707adb
RH
3429 /* ??? We used to try and build up a call to the out of line function,
3430 guessing about what registers needed saving etc. This became much
3431 harder with __builtin_va_start, since we don't have a tree for a
3432 call to __builtin_saveregs to fall back on. There was exactly one
3433 port (i860) that used this code, and I'm unconvinced it could actually
3434 handle the general case. So we no longer try to handle anything
3435 weird and make the backend absorb the evil. */
3436
3437 error ("__builtin_saveregs not supported by this target");
3438 val = const0_rtx;
28f4ec01
BS
3439#endif
3440
d3707adb
RH
3441 seq = get_insns ();
3442 end_sequence ();
28f4ec01 3443
d3707adb 3444 saveregs_value = val;
28f4ec01 3445
2f937369
DM
3446 /* Put the insns after the NOTE that starts the function. If this
3447 is inside a start_sequence, make the outer-level insn chain current, so
d3707adb
RH
3448 the code is placed at the start of the function. */
3449 push_topmost_sequence ();
2f937369 3450 emit_insn_after (seq, get_insns ());
d3707adb
RH
3451 pop_topmost_sequence ();
3452
3453 return val;
28f4ec01
BS
3454}
3455
3456/* __builtin_args_info (N) returns word N of the arg space info
3457 for the current function. The number and meanings of words
3458 is controlled by the definition of CUMULATIVE_ARGS. */
3bdf5ad1 3459
28f4ec01 3460static rtx
8c9b38d7
KG
3461expand_builtin_args_info (arglist)
3462 tree arglist;
28f4ec01 3463{
28f4ec01
BS
3464 int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
3465 int *word_ptr = (int *) &current_function_args_info;
28f4ec01
BS
3466
3467 if (sizeof (CUMULATIVE_ARGS) % sizeof (int) != 0)
987009bf 3468 abort ();
28f4ec01
BS
3469
3470 if (arglist != 0)
3471 {
5197bd50 3472 if (!host_integerp (TREE_VALUE (arglist), 0))
28f4ec01
BS
3473 error ("argument of `__builtin_args_info' must be constant");
3474 else
3475 {
5197bd50 3476 HOST_WIDE_INT wordnum = tree_low_cst (TREE_VALUE (arglist), 0);
28f4ec01 3477
5197bd50 3478 if (wordnum < 0 || wordnum >= nwords)
28f4ec01
BS
3479 error ("argument of `__builtin_args_info' out of range");
3480 else
3481 return GEN_INT (word_ptr[wordnum]);
3482 }
3483 }
3484 else
3485 error ("missing argument in `__builtin_args_info'");
3486
3487 return const0_rtx;
28f4ec01
BS
3488}
3489
d3707adb 3490/* Expand ARGLIST, from a call to __builtin_next_arg. */
5197bd50 3491
28f4ec01 3492static rtx
d3707adb
RH
3493expand_builtin_next_arg (arglist)
3494 tree arglist;
28f4ec01 3495{
28f4ec01
BS
3496 tree fntype = TREE_TYPE (current_function_decl);
3497
6c535c69
ZW
3498 if (TYPE_ARG_TYPES (fntype) == 0
3499 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
3500 == void_type_node))
28f4ec01
BS
3501 {
3502 error ("`va_start' used in function with fixed args");
3503 return const0_rtx;
3504 }
3505
3506 if (arglist)
3507 {
3508 tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
3509 tree arg = TREE_VALUE (arglist);
3510
3511 /* Strip off all nops for the sake of the comparison. This
8d51ecf8 3512 is not quite the same as STRIP_NOPS. It does more.
28f4ec01
BS
3513 We must also strip off INDIRECT_EXPR for C++ reference
3514 parameters. */
3515 while (TREE_CODE (arg) == NOP_EXPR
3516 || TREE_CODE (arg) == CONVERT_EXPR
3517 || TREE_CODE (arg) == NON_LVALUE_EXPR
3518 || TREE_CODE (arg) == INDIRECT_REF)
3519 arg = TREE_OPERAND (arg, 0);
3520 if (arg != last_parm)
3521 warning ("second parameter of `va_start' not last named argument");
3522 }
6c535c69 3523 else
28f4ec01
BS
3524 /* Evidently an out of date version of <stdarg.h>; can't validate
3525 va_start's second argument, but can still work as intended. */
3526 warning ("`__builtin_next_arg' called without an argument");
3527
3528 return expand_binop (Pmode, add_optab,
3529 current_function_internal_arg_pointer,
3530 current_function_arg_offset_rtx,
3531 NULL_RTX, 0, OPTAB_LIB_WIDEN);
3532}
3533
d3707adb
RH
3534/* Make it easier for the backends by protecting the valist argument
3535 from multiple evaluations. */
3536
3537static tree
9f720c3e 3538stabilize_va_list (valist, needs_lvalue)
d3707adb 3539 tree valist;
9f720c3e 3540 int needs_lvalue;
d3707adb 3541{
8ebecc3b 3542 if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
d3707adb 3543 {
9f720c3e
GK
3544 if (TREE_SIDE_EFFECTS (valist))
3545 valist = save_expr (valist);
8ebecc3b 3546
9f720c3e
GK
3547 /* For this case, the backends will be expecting a pointer to
3548 TREE_TYPE (va_list_type_node), but it's possible we've
3549 actually been given an array (an actual va_list_type_node).
3550 So fix it. */
3551 if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
daf68dd7 3552 {
8d51ecf8
RS
3553 tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
3554 tree p2 = build_pointer_type (va_list_type_node);
19caa751 3555
8d51ecf8 3556 valist = build1 (ADDR_EXPR, p2, valist);
9f720c3e 3557 valist = fold (build1 (NOP_EXPR, p1, valist));
daf68dd7 3558 }
d3707adb 3559 }
8ebecc3b 3560 else
d3707adb 3561 {
9f720c3e 3562 tree pt;
8ebecc3b 3563
9f720c3e
GK
3564 if (! needs_lvalue)
3565 {
8ebecc3b
RH
3566 if (! TREE_SIDE_EFFECTS (valist))
3567 return valist;
8d51ecf8 3568
8ebecc3b 3569 pt = build_pointer_type (va_list_type_node);
9f720c3e 3570 valist = fold (build1 (ADDR_EXPR, pt, valist));
d3707adb 3571 TREE_SIDE_EFFECTS (valist) = 1;
d3707adb 3572 }
9f720c3e 3573
8ebecc3b 3574 if (TREE_SIDE_EFFECTS (valist))
9f720c3e 3575 valist = save_expr (valist);
8ebecc3b
RH
3576 valist = fold (build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)),
3577 valist));
d3707adb
RH
3578 }
3579
3580 return valist;
3581}
3582
3583/* The "standard" implementation of va_start: just assign `nextarg' to
3584 the variable. */
5197bd50 3585
d3707adb 3586void
e5faf155 3587std_expand_builtin_va_start (valist, nextarg)
d3707adb
RH
3588 tree valist;
3589 rtx nextarg;
3590{
3591 tree t;
3592
3593 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
3594 make_tree (ptr_type_node, nextarg));
3595 TREE_SIDE_EFFECTS (t) = 1;
3596
3597 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
3598}
3599
6c535c69 3600/* Expand ARGLIST, from a call to __builtin_va_start. */
5197bd50 3601
d3707adb 3602static rtx
6c535c69 3603expand_builtin_va_start (arglist)
d3707adb
RH
3604 tree arglist;
3605{
3606 rtx nextarg;
6c535c69 3607 tree chain, valist;
d3707adb 3608
6c535c69 3609 chain = TREE_CHAIN (arglist);
d3707adb
RH
3610
3611 if (TREE_CHAIN (chain))
3612 error ("too many arguments to function `va_start'");
3613
6c535c69 3614 nextarg = expand_builtin_next_arg (chain);
d3707adb
RH
3615 valist = stabilize_va_list (TREE_VALUE (arglist), 1);
3616
3617#ifdef EXPAND_BUILTIN_VA_START
e5faf155 3618 EXPAND_BUILTIN_VA_START (valist, nextarg);
d3707adb 3619#else
e5faf155 3620 std_expand_builtin_va_start (valist, nextarg);
d3707adb
RH
3621#endif
3622
3623 return const0_rtx;
3624}
3625
d3707adb
RH
3626/* The "standard" implementation of va_arg: read the value from the
3627 current (padded) address and increment by the (padded) size. */
3bdf5ad1 3628
d3707adb
RH
3629rtx
3630std_expand_builtin_va_arg (valist, type)
3631 tree valist, type;
3632{
71db7d03
JJ
3633 tree addr_tree, t, type_size = NULL;
3634 tree align, alignm1;
3635 tree rounded_size;
d3707adb
RH
3636 rtx addr;
3637
3638 /* Compute the rounded size of the type. */
71db7d03
JJ
3639 align = size_int (PARM_BOUNDARY / BITS_PER_UNIT);
3640 alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1);
3641 if (type == error_mark_node
3642 || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
3643 || TREE_OVERFLOW (type_size))
3644 rounded_size = size_zero_node;
3645 else
3646 rounded_size = fold (build (MULT_EXPR, sizetype,
3647 fold (build (TRUNC_DIV_EXPR, sizetype,
3648 fold (build (PLUS_EXPR, sizetype,
3649 type_size, alignm1)),
3650 align)),
3651 align));
d3707adb
RH
3652
3653 /* Get AP. */
3654 addr_tree = valist;
71db7d03 3655 if (PAD_VARARGS_DOWN && ! integer_zerop (rounded_size))
d3707adb
RH
3656 {
3657 /* Small args are padded downward. */
71db7d03
JJ
3658 addr_tree = fold (build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
3659 fold (build (COND_EXPR, sizetype,
3660 fold (build (GT_EXPR, sizetype,
3661 rounded_size,
3662 align)),
3663 size_zero_node,
3664 fold (build (MINUS_EXPR, sizetype,
3665 rounded_size,
3666 type_size))))));
d3707adb
RH
3667 }
3668
3669 addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
3670 addr = copy_to_reg (addr);
3671
3672 /* Compute new value for AP. */
71db7d03
JJ
3673 if (! integer_zerop (rounded_size))
3674 {
3675 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
3676 build (PLUS_EXPR, TREE_TYPE (valist), valist,
3677 rounded_size));
3678 TREE_SIDE_EFFECTS (t) = 1;
3679 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
3680 }
d3707adb
RH
3681
3682 return addr;
3683}
3684
3685/* Expand __builtin_va_arg, which is not really a builtin function, but
3686 a very special sort of operator. */
3bdf5ad1 3687
d3707adb
RH
3688rtx
3689expand_builtin_va_arg (valist, type)
3690 tree valist, type;
3691{
3692 rtx addr, result;
973a648b 3693 tree promoted_type, want_va_type, have_va_type;
d3707adb 3694
973a648b
RH
3695 /* Verify that valist is of the proper type. */
3696
3697 want_va_type = va_list_type_node;
3698 have_va_type = TREE_TYPE (valist);
3699 if (TREE_CODE (want_va_type) == ARRAY_TYPE)
3700 {
8d51ecf8 3701 /* If va_list is an array type, the argument may have decayed
973a648b
RH
3702 to a pointer type, e.g. by being passed to another function.
3703 In that case, unwrap both types so that we can compare the
3704 underlying records. */
3705 if (TREE_CODE (have_va_type) == ARRAY_TYPE
3706 || TREE_CODE (have_va_type) == POINTER_TYPE)
3707 {
3708 want_va_type = TREE_TYPE (want_va_type);
3709 have_va_type = TREE_TYPE (have_va_type);
3710 }
3711 }
3712 if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type))
d3707adb 3713 {
c530479e
RH
3714 error ("first argument to `va_arg' not of type `va_list'");
3715 addr = const0_rtx;
3716 }
973a648b
RH
3717
3718 /* Generate a diagnostic for requesting data of a type that cannot
3719 be passed through `...' due to type promotion at the call site. */
ab393bf1
NB
3720 else if ((promoted_type = (*lang_hooks.types.type_promotes_to) (type))
3721 != type)
c530479e 3722 {
93868d11 3723 const char *name = "<anonymous type>", *pname = 0;
9602f5a0 3724 static bool gave_help;
c530479e
RH
3725
3726 if (TYPE_NAME (type))
3727 {
3728 if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
3729 name = IDENTIFIER_POINTER (TYPE_NAME (type));
3730 else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
3731 && DECL_NAME (TYPE_NAME (type)))
3732 name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
3733 }
3734 if (TYPE_NAME (promoted_type))
3735 {
3736 if (TREE_CODE (TYPE_NAME (promoted_type)) == IDENTIFIER_NODE)
3737 pname = IDENTIFIER_POINTER (TYPE_NAME (promoted_type));
3738 else if (TREE_CODE (TYPE_NAME (promoted_type)) == TYPE_DECL
3739 && DECL_NAME (TYPE_NAME (promoted_type)))
3740 pname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (promoted_type)));
3741 }
3742
9602f5a0
RH
3743 /* Unfortunately, this is merely undefined, rather than a constraint
3744 violation, so we cannot make this an error. If this call is never
3745 executed, the program is still strictly conforming. */
3746 warning ("`%s' is promoted to `%s' when passed through `...'",
3747 name, pname);
c530479e
RH
3748 if (! gave_help)
3749 {
9602f5a0
RH
3750 gave_help = true;
3751 warning ("(so you should pass `%s' not `%s' to `va_arg')",
3752 pname, name);
c530479e
RH
3753 }
3754
9602f5a0
RH
3755 /* We can, however, treat "undefined" any way we please.
3756 Call abort to encourage the user to fix the program. */
3757 expand_builtin_trap ();
3758
3759 /* This is dead code, but go ahead and finish so that the
3760 mode of the result comes out right. */
d3707adb
RH
3761 addr = const0_rtx;
3762 }
3763 else
3764 {
3765 /* Make it easier for the backends by protecting the valist argument
3766 from multiple evaluations. */
3767 valist = stabilize_va_list (valist, 0);
3768
3769#ifdef EXPAND_BUILTIN_VA_ARG
3770 addr = EXPAND_BUILTIN_VA_ARG (valist, type);
3771#else
3772 addr = std_expand_builtin_va_arg (valist, type);
3773#endif
3774 }
3775
ce2d32cd
RK
3776#ifdef POINTERS_EXTEND_UNSIGNED
3777 if (GET_MODE (addr) != Pmode)
3778 addr = convert_memory_address (Pmode, addr);
3779#endif
3780
d3707adb 3781 result = gen_rtx_MEM (TYPE_MODE (type), addr);
ba4828e0 3782 set_mem_alias_set (result, get_varargs_alias_set ());
d3707adb
RH
3783
3784 return result;
3785}
3786
3787/* Expand ARGLIST, from a call to __builtin_va_end. */
3bdf5ad1 3788
d3707adb
RH
3789static rtx
3790expand_builtin_va_end (arglist)
daf68dd7 3791 tree arglist;
d3707adb 3792{
daf68dd7
RH
3793 tree valist = TREE_VALUE (arglist);
3794
d3707adb 3795#ifdef EXPAND_BUILTIN_VA_END
d3707adb 3796 valist = stabilize_va_list (valist, 0);
5ab2f7b7 3797 EXPAND_BUILTIN_VA_END (arglist);
daf68dd7
RH
3798#else
3799 /* Evaluate for side effects, if needed. I hate macros that don't
3800 do that. */
3801 if (TREE_SIDE_EFFECTS (valist))
3802 expand_expr (valist, const0_rtx, VOIDmode, EXPAND_NORMAL);
d3707adb
RH
3803#endif
3804
3805 return const0_rtx;
3806}
3807
8d51ecf8 3808/* Expand ARGLIST, from a call to __builtin_va_copy. We do this as a
d3707adb
RH
3809 builtin rather than just as an assignment in stdarg.h because of the
3810 nastiness of array-type va_list types. */
3bdf5ad1 3811
d3707adb
RH
3812static rtx
3813expand_builtin_va_copy (arglist)
3814 tree arglist;
3815{
3816 tree dst, src, t;
3817
3818 dst = TREE_VALUE (arglist);
3819 src = TREE_VALUE (TREE_CHAIN (arglist));
3820
3821 dst = stabilize_va_list (dst, 1);
3822 src = stabilize_va_list (src, 0);
3823
3824 if (TREE_CODE (va_list_type_node) != ARRAY_TYPE)
3825 {
3826 t = build (MODIFY_EXPR, va_list_type_node, dst, src);
3827 TREE_SIDE_EFFECTS (t) = 1;
3828 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
3829 }
3830 else
3831 {
8ebecc3b
RH
3832 rtx dstb, srcb, size;
3833
3834 /* Evaluate to pointers. */
3835 dstb = expand_expr (dst, NULL_RTX, Pmode, EXPAND_NORMAL);
3836 srcb = expand_expr (src, NULL_RTX, Pmode, EXPAND_NORMAL);
3837 size = expand_expr (TYPE_SIZE_UNIT (va_list_type_node), NULL_RTX,
3838 VOIDmode, EXPAND_NORMAL);
3839
ce2d32cd
RK
3840#ifdef POINTERS_EXTEND_UNSIGNED
3841 if (GET_MODE (dstb) != Pmode)
3842 dstb = convert_memory_address (Pmode, dstb);
3843
3844 if (GET_MODE (srcb) != Pmode)
3845 srcb = convert_memory_address (Pmode, srcb);
3846#endif
3847
8ebecc3b
RH
3848 /* "Dereference" to BLKmode memories. */
3849 dstb = gen_rtx_MEM (BLKmode, dstb);
ba4828e0 3850 set_mem_alias_set (dstb, get_alias_set (TREE_TYPE (TREE_TYPE (dst))));
8ac61af7 3851 set_mem_align (dstb, TYPE_ALIGN (va_list_type_node));
8ebecc3b 3852 srcb = gen_rtx_MEM (BLKmode, srcb);
ba4828e0 3853 set_mem_alias_set (srcb, get_alias_set (TREE_TYPE (TREE_TYPE (src))));
8ac61af7 3854 set_mem_align (srcb, TYPE_ALIGN (va_list_type_node));
8ebecc3b
RH
3855
3856 /* Copy. */
44bb111a 3857 emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL);
d3707adb
RH
3858 }
3859
3860 return const0_rtx;
3861}
3862
28f4ec01
BS
3863/* Expand a call to one of the builtin functions __builtin_frame_address or
3864 __builtin_return_address. */
5197bd50 3865
28f4ec01 3866static rtx
8c9b38d7
KG
3867expand_builtin_frame_address (fndecl, arglist)
3868 tree fndecl, arglist;
28f4ec01 3869{
28f4ec01
BS
3870 /* The argument must be a nonnegative integer constant.
3871 It counts the number of frames to scan up the stack.
3872 The value is the return address saved in that frame. */
3873 if (arglist == 0)
3874 /* Warning about missing arg was already issued. */
3875 return const0_rtx;
5197bd50 3876 else if (! host_integerp (TREE_VALUE (arglist), 1))
28f4ec01
BS
3877 {
3878 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
3879 error ("invalid arg to `__builtin_frame_address'");
3880 else
3881 error ("invalid arg to `__builtin_return_address'");
3882 return const0_rtx;
3883 }
3884 else
3885 {
5197bd50
RK
3886 rtx tem
3887 = expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl),
3888 tree_low_cst (TREE_VALUE (arglist), 1),
3889 hard_frame_pointer_rtx);
28f4ec01
BS
3890
3891 /* Some ports cannot access arbitrary stack frames. */
3892 if (tem == NULL)
3893 {
3894 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
3895 warning ("unsupported arg to `__builtin_frame_address'");
3896 else
3897 warning ("unsupported arg to `__builtin_return_address'");
3898 return const0_rtx;
3899 }
3900
3901 /* For __builtin_frame_address, return what we've got. */
3902 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
3903 return tem;
3904
3905 if (GET_CODE (tem) != REG
3906 && ! CONSTANT_P (tem))
3907 tem = copy_to_mode_reg (Pmode, tem);
3908 return tem;
3909 }
3910}
3911
3912/* Expand a call to the alloca builtin, with arguments ARGLIST. Return 0 if
3913 we failed and the caller should emit a normal call, otherwise try to get
3914 the result in TARGET, if convenient. */
d5457140 3915
28f4ec01
BS
3916static rtx
3917expand_builtin_alloca (arglist, target)
3918 tree arglist;
3919 rtx target;
3920{
3921 rtx op0;
d5457140 3922 rtx result;
28f4ec01 3923
019fa094 3924 if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
28f4ec01
BS
3925 return 0;
3926
3927 /* Compute the argument. */
3928 op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
3929
3930 /* Allocate the desired space. */
d5457140
RK
3931 result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
3932
3933#ifdef POINTERS_EXTEND_UNSIGNED
4b6c1672
RK
3934 if (GET_MODE (result) != ptr_mode)
3935 result = convert_memory_address (ptr_mode, result);
d5457140
RK
3936#endif
3937
3938 return result;
28f4ec01
BS
3939}
3940
2928cd7a 3941/* Expand a call to a unary builtin. The arguments are in ARGLIST.
28f4ec01
BS
3942 Return 0 if a normal call should be emitted rather than expanding the
3943 function in-line. If convenient, the result should be placed in TARGET.
3944 SUBTARGET may be used as the target for computing one of EXP's operands. */
d5457140 3945
28f4ec01 3946static rtx
6c537d03
RH
3947expand_builtin_unop (target_mode, arglist, target, subtarget, op_optab)
3948 enum machine_mode target_mode;
28f4ec01
BS
3949 tree arglist;
3950 rtx target, subtarget;
2928cd7a 3951 optab op_optab;
28f4ec01
BS
3952{
3953 rtx op0;
019fa094 3954 if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
28f4ec01
BS
3955 return 0;
3956
3957 /* Compute the argument. */
3958 op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
2928cd7a 3959 /* Compute op, into TARGET if possible.
28f4ec01
BS
3960 Set TARGET to wherever the result comes back. */
3961 target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
2928cd7a 3962 op_optab, op0, target, 1);
28f4ec01
BS
3963 if (target == 0)
3964 abort ();
6c537d03
RH
3965
3966 return convert_to_mode (target_mode, target, 0);
28f4ec01 3967}
994a57cd 3968
3ff5f682 3969/* If the string passed to fputs is a constant and is one character
ec5c56db 3970 long, we attempt to transform this call into __builtin_fputc(). */
d5457140 3971
3ff5f682 3972static rtx
b4c984fb 3973expand_builtin_fputs (arglist, ignore, unlocked)
3ff5f682
KG
3974 tree arglist;
3975 int ignore;
b4c984fb 3976 int unlocked;
3ff5f682 3977{
b4c984fb 3978 tree len, fn;
272f51a3
JH
3979 tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
3980 : implicit_built_in_decls[BUILT_IN_FPUTC];
3981 tree fn_fwrite = unlocked ? implicit_built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
3982 : implicit_built_in_decls[BUILT_IN_FWRITE];
3ff5f682
KG
3983
3984 /* If the return value is used, or the replacement _DECL isn't
ec5c56db 3985 initialized, don't do the transformation. */
07328167 3986 if (!ignore || !fn_fputc || !fn_fwrite)
3ff5f682
KG
3987 return 0;
3988
ec5c56db 3989 /* Verify the arguments in the original call. */
37a08a29 3990 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
3ff5f682
KG
3991 return 0;
3992
07328167
KG
3993 /* Get the length of the string passed to fputs. If the length
3994 can't be determined, punt. */
57814e5e
JJ
3995 if (!(len = c_strlen (TREE_VALUE (arglist)))
3996 || TREE_CODE (len) != INTEGER_CST)
3ff5f682
KG
3997 return 0;
3998
07328167
KG
3999 switch (compare_tree_int (len, 1))
4000 {
4001 case -1: /* length is 0, delete the call entirely . */
bcb38cc1
KG
4002 {
4003 /* Evaluate and ignore the argument in case it has
4004 side-effects. */
4005 expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx,
4006 VOIDmode, EXPAND_NORMAL);
4007 return const0_rtx;
4008 }
07328167
KG
4009 case 0: /* length is 1, call fputc. */
4010 {
2dee4af1 4011 const char *p = c_getstr (TREE_VALUE (arglist));
3ff5f682 4012
2dee4af1 4013 if (p != NULL)
8d51ecf8 4014 {
2dee4af1
JJ
4015 /* New argument list transforming fputs(string, stream) to
4016 fputc(string[0], stream). */
4017 arglist =
4018 build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)));
4019 arglist =
4020 tree_cons (NULL_TREE, build_int_2 (p[0], 0), arglist);
4021 fn = fn_fputc;
4022 break;
4023 }
07328167 4024 }
2dee4af1 4025 /* FALLTHROUGH */
07328167
KG
4026 case 1: /* length is greater than 1, call fwrite. */
4027 {
fa9b4904 4028 tree string_arg;
8d51ecf8 4029
fa9b4904
AB
4030 /* If optimizing for size keep fputs. */
4031 if (optimize_size)
4032 return 0;
4033 string_arg = TREE_VALUE (arglist);
07328167
KG
4034 /* New argument list transforming fputs(string, stream) to
4035 fwrite(string, 1, len, stream). */
4036 arglist = build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)));
4037 arglist = tree_cons (NULL_TREE, len, arglist);
013dea40 4038 arglist = tree_cons (NULL_TREE, size_one_node, arglist);
07328167
KG
4039 arglist = tree_cons (NULL_TREE, string_arg, arglist);
4040 fn = fn_fwrite;
4041 break;
4042 }
4043 default:
505ddab6 4044 abort ();
07328167 4045 }
8d51ecf8 4046
6385a28f
KG
4047 return expand_expr (build_function_call_expr (fn, arglist),
4048 (ignore ? const0_rtx : NULL_RTX),
ad3fd36f
KG
4049 VOIDmode, EXPAND_NORMAL);
4050}
4051
5f2d6cfa
MM
4052/* Expand a call to __builtin_expect. We return our argument and emit a
4053 NOTE_INSN_EXPECTED_VALUE note. This is the expansion of __builtin_expect in
4054 a non-jump context. */
994a57cd
RH
4055
4056static rtx
4057expand_builtin_expect (arglist, target)
4058 tree arglist;
4059 rtx target;
4060{
4061 tree exp, c;
4062 rtx note, rtx_c;
4063
4064 if (arglist == NULL_TREE
4065 || TREE_CHAIN (arglist) == NULL_TREE)
4066 return const0_rtx;
4067 exp = TREE_VALUE (arglist);
4068 c = TREE_VALUE (TREE_CHAIN (arglist));
4069
4070 if (TREE_CODE (c) != INTEGER_CST)
4071 {
4072 error ("second arg to `__builtin_expect' must be a constant");
4073 c = integer_zero_node;
4074 }
4075
4076 target = expand_expr (exp, target, VOIDmode, EXPAND_NORMAL);
4077
4078 /* Don't bother with expected value notes for integral constants. */
d50672ef 4079 if (flag_guess_branch_prob && GET_CODE (target) != CONST_INT)
994a57cd
RH
4080 {
4081 /* We do need to force this into a register so that we can be
4082 moderately sure to be able to correctly interpret the branch
4083 condition later. */
4084 target = force_reg (GET_MODE (target), target);
8d51ecf8 4085
994a57cd
RH
4086 rtx_c = expand_expr (c, NULL_RTX, GET_MODE (target), EXPAND_NORMAL);
4087
4088 note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE);
4089 NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, target, rtx_c);
4090 }
4091
4092 return target;
4093}
5f2d6cfa
MM
4094
4095/* Like expand_builtin_expect, except do this in a jump context. This is
4096 called from do_jump if the conditional is a __builtin_expect. Return either
2f937369 4097 a list of insns to emit the jump or NULL if we cannot optimize
5f2d6cfa
MM
4098 __builtin_expect. We need to optimize this at jump time so that machines
4099 like the PowerPC don't turn the test into a SCC operation, and then jump
4100 based on the test being 0/1. */
4101
4102rtx
4103expand_builtin_expect_jump (exp, if_false_label, if_true_label)
4104 tree exp;
4105 rtx if_false_label;
4106 rtx if_true_label;
4107{
4108 tree arglist = TREE_OPERAND (exp, 1);
4109 tree arg0 = TREE_VALUE (arglist);
4110 tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
4111 rtx ret = NULL_RTX;
4112
4113 /* Only handle __builtin_expect (test, 0) and
4114 __builtin_expect (test, 1). */
4115 if (TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE
5197bd50 4116 && (integer_zerop (arg1) || integer_onep (arg1)))
5f2d6cfa 4117 {
5f2d6cfa 4118 int num_jumps = 0;
2f937369 4119 rtx insn;
5f2d6cfa 4120
c1c455a7
RH
4121 /* If we fail to locate an appropriate conditional jump, we'll
4122 fall back to normal evaluation. Ensure that the expression
4123 can be re-evaluated. */
4124 switch (unsafe_for_reeval (arg0))
4125 {
4126 case 0: /* Safe. */
4127 break;
4128
4129 case 1: /* Mildly unsafe. */
4130 arg0 = unsave_expr (arg0);
4131 break;
4132
4133 case 2: /* Wildly unsafe. */
4134 return NULL_RTX;
4135 }
4136
5f2d6cfa
MM
4137 /* Expand the jump insns. */
4138 start_sequence ();
4139 do_jump (arg0, if_false_label, if_true_label);
2f937369 4140 ret = get_insns ();
5f2d6cfa
MM
4141 end_sequence ();
4142
4143 /* Now that the __builtin_expect has been validated, go through and add
4144 the expect's to each of the conditional jumps. If we run into an
4145 error, just give up and generate the 'safe' code of doing a SCC
4146 operation and then doing a branch on that. */
2f937369
DM
4147 insn = ret;
4148 while (insn != NULL_RTX)
5f2d6cfa 4149 {
2f937369 4150 rtx next = NEXT_INSN (insn);
5f2d6cfa
MM
4151 rtx pattern;
4152
4153 if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn)
4154 && (pattern = pc_set (insn)) != NULL_RTX)
4155 {
4156 rtx ifelse = SET_SRC (pattern);
4157 rtx label;
4158 int taken;
4159
4160 if (GET_CODE (ifelse) != IF_THEN_ELSE)
2f937369 4161 goto do_next_insn;
5f2d6cfa
MM
4162
4163 if (GET_CODE (XEXP (ifelse, 1)) == LABEL_REF)
4164 {
4165 taken = 1;
4166 label = XEXP (XEXP (ifelse, 1), 0);
4167 }
4168 /* An inverted jump reverses the probabilities. */
4169 else if (GET_CODE (XEXP (ifelse, 2)) == LABEL_REF)
4170 {
4171 taken = 0;
4172 label = XEXP (XEXP (ifelse, 2), 0);
4173 }
4174 /* We shouldn't have to worry about conditional returns during
4175 the expansion stage, but handle it gracefully anyway. */
4176 else if (GET_CODE (XEXP (ifelse, 1)) == RETURN)
4177 {
4178 taken = 1;
4179 label = NULL_RTX;
4180 }
4181 /* An inverted return reverses the probabilities. */
4182 else if (GET_CODE (XEXP (ifelse, 2)) == RETURN)
4183 {
4184 taken = 0;
4185 label = NULL_RTX;
4186 }
4187 else
2f937369 4188 goto do_next_insn;
5f2d6cfa
MM
4189
4190 /* If the test is expected to fail, reverse the
4191 probabilities. */
5197bd50 4192 if (integer_zerop (arg1))
5f2d6cfa
MM
4193 taken = 1 - taken;
4194
4195 /* If we are jumping to the false label, reverse the
4196 probabilities. */
4197 if (label == NULL_RTX)
4198 ; /* conditional return */
4199 else if (label == if_false_label)
4200 taken = 1 - taken;
4201 else if (label != if_true_label)
2f937369 4202 goto do_next_insn;
5f2d6cfa
MM
4203
4204 num_jumps++;
4205 predict_insn_def (insn, PRED_BUILTIN_EXPECT, taken);
4206 }
2f937369
DM
4207
4208 do_next_insn:
4209 insn = next;
5f2d6cfa
MM
4210 }
4211
4212 /* If no jumps were modified, fail and do __builtin_expect the normal
4213 way. */
4214 if (num_jumps == 0)
4215 ret = NULL_RTX;
4216 }
4217
4218 return ret;
4219}
9602f5a0
RH
4220
4221void
4222expand_builtin_trap ()
4223{
4224#ifdef HAVE_trap
4225 if (HAVE_trap)
4226 emit_insn (gen_trap ());
4227 else
4228#endif
4229 emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
4230 emit_barrier ();
4231}
28f4ec01
BS
4232\f
4233/* Expand an expression EXP that calls a built-in function,
4234 with result going to TARGET if that's convenient
4235 (and in mode MODE if that's convenient).
4236 SUBTARGET may be used as the target for computing one of EXP's operands.
4237 IGNORE is nonzero if the value is to be ignored. */
4238
4239rtx
4240expand_builtin (exp, target, subtarget, mode, ignore)
4241 tree exp;
4242 rtx target;
4243 rtx subtarget;
4244 enum machine_mode mode;
4245 int ignore;
4246{
4247 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
4248 tree arglist = TREE_OPERAND (exp, 1);
4249 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
6c537d03 4250 enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
28f4ec01 4251
9e7d0b92
GN
4252