00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "config.h"
00023 #include "system.h"
00024 #include "coretypes.h"
00025 #include "tm.h"
00026 #include "machmode.h"
00027 #include "real.h"
00028 #include "rtl.h"
00029 #include "tree.h"
00030 #include "tree-gimple.h"
00031 #include "flags.h"
00032 #include "regs.h"
00033 #include "hard-reg-set.h"
00034 #include "except.h"
00035 #include "function.h"
00036 #include "insn-config.h"
00037 #include "expr.h"
00038 #include "optabs.h"
00039 #include "libfuncs.h"
00040 #include "recog.h"
00041 #include "output.h"
00042 #include "typeclass.h"
00043 #include "toplev.h"
00044 #include "predict.h"
00045 #include "tm_p.h"
00046 #include "target.h"
00047 #include "langhooks.h"
00048 #include "basic-block.h"
00049 #include "tree-mudflap.h"
00050
00051 #ifndef PAD_VARARGS_DOWN
00052 #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
00053 #endif
00054
00055
00056 const char *const built_in_class_names[4]
00057 = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
00058
00059 #define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT, IM, COND) #X,
00060 const char * built_in_names[(int) END_BUILTINS] =
00061 {
00062 #include "builtins.def"
00063 };
00064 #undef DEF_BUILTIN
00065
00066
00067
00068 tree built_in_decls[(int) END_BUILTINS];
00069
00070
00071
00072 tree implicit_built_in_decls[(int) END_BUILTINS];
00073
00074 static int get_pointer_alignment (tree, unsigned int);
00075 static const char *c_getstr (tree);
00076 static rtx c_readstr (const char *, enum machine_mode);
00077 static int target_char_cast (tree, char *);
00078 static rtx get_memory_rtx (tree, tree);
00079 static int apply_args_size (void);
00080 static int apply_result_size (void);
00081 #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
00082 static rtx result_vector (int, rtx);
00083 #endif
00084 static void expand_builtin_update_setjmp_buf (rtx);
00085 static void expand_builtin_prefetch (tree);
00086 static rtx expand_builtin_apply_args (void);
00087 static rtx expand_builtin_apply_args_1 (void);
00088 static rtx expand_builtin_apply (rtx, rtx, rtx);
00089 static void expand_builtin_return (rtx);
00090 static enum type_class type_to_class (tree);
00091 static rtx expand_builtin_classify_type (tree);
00092 static void expand_errno_check (tree, rtx);
00093 static rtx expand_builtin_mathfn (tree, rtx, rtx);
00094 static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
00095 static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
00096 static rtx expand_builtin_sincos (tree);
00097 static rtx expand_builtin_int_roundingfn (tree, rtx, rtx);
00098 static rtx expand_builtin_args_info (tree);
00099 static rtx expand_builtin_next_arg (void);
00100 static rtx expand_builtin_va_start (tree);
00101 static rtx expand_builtin_va_end (tree);
00102 static rtx expand_builtin_va_copy (tree);
00103 static rtx expand_builtin_memcmp (tree, tree, rtx, enum machine_mode);
00104 static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode);
00105 static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
00106 static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
00107 static rtx expand_builtin_strcat (tree, tree, rtx, enum machine_mode);
00108 static rtx expand_builtin_strncat (tree, rtx, enum machine_mode);
00109 static rtx expand_builtin_strspn (tree, rtx, enum machine_mode);
00110 static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode);
00111 static rtx expand_builtin_memcpy (tree, rtx, enum machine_mode);
00112 static rtx expand_builtin_mempcpy (tree, tree, rtx, enum machine_mode, int);
00113 static rtx expand_builtin_memmove (tree, tree, rtx, enum machine_mode, tree);
00114 static rtx expand_builtin_bcopy (tree);
00115 static rtx expand_builtin_strcpy (tree, tree, rtx, enum machine_mode);
00116 static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
00117 static rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
00118 static rtx expand_builtin_strncpy (tree, rtx, enum machine_mode);
00119 static rtx builtin_memset_read_str (void *, HOST_WIDE_INT, enum machine_mode);
00120 static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, enum machine_mode);
00121 static rtx expand_builtin_memset (tree, rtx, enum machine_mode, tree);
00122 static rtx expand_builtin_bzero (tree);
00123 static rtx expand_builtin_strlen (tree, rtx, enum machine_mode);
00124 static rtx expand_builtin_strstr (tree, tree, rtx, enum machine_mode);
00125 static rtx expand_builtin_strpbrk (tree, tree, rtx, enum machine_mode);
00126 static rtx expand_builtin_strchr (tree, tree, rtx, enum machine_mode);
00127 static rtx expand_builtin_strrchr (tree, tree, rtx, enum machine_mode);
00128 static rtx expand_builtin_alloca (tree, rtx);
00129 static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
00130 static rtx expand_builtin_frame_address (tree, tree);
00131 static rtx expand_builtin_fputs (tree, rtx, bool);
00132 static rtx expand_builtin_printf (tree, rtx, enum machine_mode, bool);
00133 static rtx expand_builtin_fprintf (tree, rtx, enum machine_mode, bool);
00134 static rtx expand_builtin_sprintf (tree, rtx, enum machine_mode);
00135 static tree stabilize_va_list (tree, int);
00136 static rtx expand_builtin_expect (tree, rtx);
00137 static tree fold_builtin_constant_p (tree);
00138 static tree fold_builtin_classify_type (tree);
00139 static tree fold_builtin_strlen (tree);
00140 static tree fold_builtin_inf (tree, int);
00141 static tree fold_builtin_nan (tree, tree, int);
00142 static int validate_arglist (tree, ...);
00143 static bool integer_valued_real_p (tree);
00144 static tree fold_trunc_transparent_mathfn (tree, tree);
00145 static bool readonly_data_expr (tree);
00146 static rtx expand_builtin_fabs (tree, rtx, rtx);
00147 static rtx expand_builtin_signbit (tree, rtx);
00148 static tree fold_builtin_sqrt (tree, tree);
00149 static tree fold_builtin_cbrt (tree, tree);
00150 static tree fold_builtin_pow (tree, tree, tree);
00151 static tree fold_builtin_powi (tree, tree, tree);
00152 static tree fold_builtin_sin (tree);
00153 static tree fold_builtin_cos (tree, tree, tree);
00154 static tree fold_builtin_tan (tree);
00155 static tree fold_builtin_atan (tree, tree);
00156 static tree fold_builtin_trunc (tree, tree);
00157 static tree fold_builtin_floor (tree, tree);
00158 static tree fold_builtin_ceil (tree, tree);
00159 static tree fold_builtin_round (tree, tree);
00160 static tree fold_builtin_int_roundingfn (tree, tree);
00161 static tree fold_builtin_bitop (tree, tree);
00162 static tree fold_builtin_memory_op (tree, tree, bool, int);
00163 static tree fold_builtin_strchr (tree, tree);
00164 static tree fold_builtin_memcmp (tree);
00165 static tree fold_builtin_strcmp (tree);
00166 static tree fold_builtin_strncmp (tree);
00167 static tree fold_builtin_signbit (tree, tree);
00168 static tree fold_builtin_copysign (tree, tree, tree);
00169 static tree fold_builtin_isascii (tree);
00170 static tree fold_builtin_toascii (tree);
00171 static tree fold_builtin_isdigit (tree);
00172 static tree fold_builtin_fabs (tree, tree);
00173 static tree fold_builtin_abs (tree, tree);
00174 static tree fold_builtin_unordered_cmp (tree, tree, enum tree_code,
00175 enum tree_code);
00176 static tree fold_builtin_1 (tree, tree, bool);
00177
00178 static tree fold_builtin_strpbrk (tree, tree);
00179 static tree fold_builtin_strstr (tree, tree);
00180 static tree fold_builtin_strrchr (tree, tree);
00181 static tree fold_builtin_strcat (tree);
00182 static tree fold_builtin_strncat (tree);
00183 static tree fold_builtin_strspn (tree);
00184 static tree fold_builtin_strcspn (tree);
00185 static tree fold_builtin_sprintf (tree, int);
00186
00187 static rtx expand_builtin_object_size (tree);
00188 static rtx expand_builtin_memory_chk (tree, rtx, enum machine_mode,
00189 enum built_in_function);
00190 static void maybe_emit_chk_warning (tree, enum built_in_function);
00191 static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function);
00192 static tree fold_builtin_object_size (tree);
00193 static tree fold_builtin_strcat_chk (tree, tree);
00194 static tree fold_builtin_strncat_chk (tree, tree);
00195 static tree fold_builtin_sprintf_chk (tree, enum built_in_function);
00196 static tree fold_builtin_printf (tree, tree, bool, enum built_in_function);
00197 static tree fold_builtin_fprintf (tree, tree, bool, enum built_in_function);
00198 static bool init_target_chars (void);
00199
00200 static unsigned HOST_WIDE_INT target_newline;
00201 static unsigned HOST_WIDE_INT target_percent;
00202 static unsigned HOST_WIDE_INT target_c;
00203 static unsigned HOST_WIDE_INT target_s;
00204 static char target_percent_c[3];
00205 static char target_percent_s[3];
00206 static char target_percent_s_newline[4];
00207
00208
00209
00210
00211
00212 static bool called_as_built_in (tree node)
00213 {
00214 const char *name = IDENTIFIER_POINTER (DECL_NAME (node));
00215 if (strncmp (name, "__builtin_", 10) == 0)
00216 return true;
00217 if (strncmp (name, "__sync_", 7) == 0)
00218 return true;
00219 return false;
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 static int
00231 get_pointer_alignment (tree exp, unsigned int max_align)
00232 {
00233 unsigned int align, inner;
00234
00235
00236 if (!(optimize && flag_tree_ter))
00237 return 0;
00238
00239 if (!POINTER_TYPE_P (TREE_TYPE (exp)))
00240 return 0;
00241
00242 align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
00243 align = MIN (align, max_align);
00244
00245 while (1)
00246 {
00247 switch (TREE_CODE (exp))
00248 {
00249 case NOP_EXPR:
00250 case CONVERT_EXPR:
00251 case NON_LVALUE_EXPR:
00252 exp = TREE_OPERAND (exp, 0);
00253 if (! POINTER_TYPE_P (TREE_TYPE (exp)))
00254 return align;
00255
00256 inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
00257 align = MIN (inner, max_align);
00258 break;
00259
00260 case PLUS_EXPR:
00261
00262
00263
00264 if (! host_integerp (TREE_OPERAND (exp, 1), 1))
00265 return align;
00266
00267 while (((tree_low_cst (TREE_OPERAND (exp, 1), 1))
00268 & (max_align / BITS_PER_UNIT - 1))
00269 != 0)
00270 max_align >>= 1;
00271
00272 exp = TREE_OPERAND (exp, 0);
00273 break;
00274
00275 case ADDR_EXPR:
00276
00277 exp = TREE_OPERAND (exp, 0);
00278 inner = max_align;
00279 if (handled_component_p (exp))
00280 {
00281 HOST_WIDE_INT bitsize, bitpos;
00282 tree offset;
00283 enum machine_mode mode;
00284 int unsignedp, volatilep;
00285
00286 exp = get_inner_reference (exp, &bitsize, &bitpos, &offset,
00287 &mode, &unsignedp, &volatilep, true);
00288 if (bitpos)
00289 inner = MIN (inner, (unsigned) (bitpos & -bitpos));
00290 if (offset && TREE_CODE (offset) == PLUS_EXPR
00291 && host_integerp (TREE_OPERAND (offset, 1), 1))
00292 {
00293
00294
00295 unsigned offset_bits
00296 = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
00297 * BITS_PER_UNIT);
00298
00299 if (offset_bits)
00300 inner = MIN (inner, (offset_bits & -offset_bits));
00301 offset = TREE_OPERAND (offset, 0);
00302 }
00303 if (offset && TREE_CODE (offset) == MULT_EXPR
00304 && host_integerp (TREE_OPERAND (offset, 1), 1))
00305 {
00306
00307
00308 unsigned offset_factor
00309 = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
00310 * BITS_PER_UNIT);
00311
00312 if (offset_factor)
00313 inner = MIN (inner, (offset_factor & -offset_factor));
00314 }
00315 else if (offset)
00316 inner = MIN (inner, BITS_PER_UNIT);
00317 }
00318 if (TREE_CODE (exp) == FUNCTION_DECL)
00319 align = FUNCTION_BOUNDARY;
00320 else if (DECL_P (exp))
00321 align = MIN (inner, DECL_ALIGN (exp));
00322 #ifdef CONSTANT_ALIGNMENT
00323 else if (CONSTANT_CLASS_P (exp))
00324 align = MIN (inner, (unsigned)CONSTANT_ALIGNMENT (exp, align));
00325 #endif
00326 else if (TREE_CODE (exp) == VIEW_CONVERT_EXPR
00327 || TREE_CODE (exp) == INDIRECT_REF)
00328 align = MIN (TYPE_ALIGN (TREE_TYPE (exp)), inner);
00329 else
00330 align = MIN (align, inner);
00331 return MIN (align, max_align);
00332
00333 default:
00334 return align;
00335 }
00336 }
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355 tree
00356 c_strlen (tree src, int only_value)
00357 {
00358 tree offset_node;
00359 HOST_WIDE_INT offset;
00360 int max;
00361 const char *ptr;
00362
00363 STRIP_NOPS (src);
00364 if (TREE_CODE (src) == COND_EXPR
00365 && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
00366 {
00367 tree len1, len2;
00368
00369 len1 = c_strlen (TREE_OPERAND (src, 1), only_value);
00370 len2 = c_strlen (TREE_OPERAND (src, 2), only_value);
00371 if (tree_int_cst_equal (len1, len2))
00372 return len1;
00373 }
00374
00375 if (TREE_CODE (src) == COMPOUND_EXPR
00376 && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
00377 return c_strlen (TREE_OPERAND (src, 1), only_value);
00378
00379 src = string_constant (src, &offset_node);
00380 if (src == 0)
00381 return 0;
00382
00383 max = TREE_STRING_LENGTH (src) - 1;
00384 ptr = TREE_STRING_POINTER (src);
00385
00386 if (offset_node && TREE_CODE (offset_node) != INTEGER_CST)
00387 {
00388
00389
00390
00391 int i;
00392
00393 for (i = 0; i < max; i++)
00394 if (ptr[i] == 0)
00395 return 0;
00396
00397
00398
00399
00400
00401
00402
00403
00404 return size_diffop (size_int (max), offset_node);
00405 }
00406
00407
00408
00409 if (offset_node == 0)
00410 offset = 0;
00411 else if (! host_integerp (offset_node, 0))
00412 offset = -1;
00413 else
00414 offset = tree_low_cst (offset_node, 0);
00415
00416
00417
00418 if (offset < 0 || offset > max)
00419 {
00420 warning (0, "offset outside bounds of constant string");
00421 return 0;
00422 }
00423
00424
00425
00426
00427
00428
00429
00430 return ssize_int (strlen (ptr + offset));
00431 }
00432
00433
00434
00435
00436 static const char *
00437 c_getstr (tree src)
00438 {
00439 tree offset_node;
00440
00441 src = string_constant (src, &offset_node);
00442 if (src == 0)
00443 return 0;
00444
00445 if (offset_node == 0)
00446 return TREE_STRING_POINTER (src);
00447 else if (!host_integerp (offset_node, 1)
00448 || compare_tree_int (offset_node, TREE_STRING_LENGTH (src) - 1) > 0)
00449 return 0;
00450
00451 return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
00452 }
00453
00454
00455
00456
00457 static rtx
00458 c_readstr (const char *str, enum machine_mode mode)
00459 {
00460 HOST_WIDE_INT c[2];
00461 HOST_WIDE_INT ch;
00462 unsigned int i, j;
00463
00464 gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
00465
00466 c[0] = 0;
00467 c[1] = 0;
00468 ch = 1;
00469 for (i = 0; i < GET_MODE_SIZE (mode); i++)
00470 {
00471 j = i;
00472 if (WORDS_BIG_ENDIAN)
00473 j = GET_MODE_SIZE (mode) - i - 1;
00474 if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
00475 && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
00476 j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
00477 j *= BITS_PER_UNIT;
00478 gcc_assert (j <= 2 * HOST_BITS_PER_WIDE_INT);
00479
00480 if (ch)
00481 ch = (unsigned char) str[i];
00482 c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
00483 }
00484 return immed_double_const (c[0], c[1], mode);
00485 }
00486
00487
00488
00489
00490
00491 static int
00492 target_char_cast (tree cst, char *p)
00493 {
00494 unsigned HOST_WIDE_INT val, hostval;
00495
00496 if (!host_integerp (cst, 1)
00497 || CHAR_TYPE_SIZE > HOST_BITS_PER_WIDE_INT)
00498 return 1;
00499
00500 val = tree_low_cst (cst, 1);
00501 if (CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT)
00502 val &= (((unsigned HOST_WIDE_INT) 1) << CHAR_TYPE_SIZE) - 1;
00503
00504 hostval = val;
00505 if (HOST_BITS_PER_CHAR < HOST_BITS_PER_WIDE_INT)
00506 hostval &= (((unsigned HOST_WIDE_INT) 1) << HOST_BITS_PER_CHAR) - 1;
00507
00508 if (val != hostval)
00509 return 1;
00510
00511 *p = hostval;
00512 return 0;
00513 }
00514
00515
00516
00517
00518
00519 static tree
00520 builtin_save_expr (tree exp)
00521 {
00522 if (TREE_ADDRESSABLE (exp) == 0
00523 && (TREE_CODE (exp) == PARM_DECL
00524 || (TREE_CODE (exp) == VAR_DECL && !TREE_STATIC (exp))))
00525 return exp;
00526
00527 return save_expr (exp);
00528 }
00529
00530
00531
00532
00533
00534 static rtx
00535 expand_builtin_return_addr (enum built_in_function fndecl_code, int count)
00536 {
00537 int i;
00538
00539 #ifdef INITIAL_FRAME_ADDRESS_RTX
00540 rtx tem = INITIAL_FRAME_ADDRESS_RTX;
00541 #else
00542 rtx tem;
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553 if (count == 0 && fndecl_code == BUILT_IN_RETURN_ADDRESS)
00554 tem = frame_pointer_rtx;
00555 else
00556 {
00557 tem = hard_frame_pointer_rtx;
00558
00559
00560 current_function_accesses_prior_frames = 1;
00561 }
00562 #endif
00563
00564
00565
00566
00567 #ifdef SETUP_FRAME_ADDRESSES
00568 if (count > 0)
00569 SETUP_FRAME_ADDRESSES ();
00570 #endif
00571
00572
00573
00574
00575
00576 #ifdef RETURN_ADDR_IN_PREVIOUS_FRAME
00577 if (fndecl_code == BUILT_IN_RETURN_ADDRESS)
00578 count--;
00579 #endif
00580
00581
00582 for (i = 0; i < count; i++)
00583 {
00584
00585
00586 #ifdef DYNAMIC_CHAIN_ADDRESS
00587 tem = DYNAMIC_CHAIN_ADDRESS (tem);
00588 #endif
00589 tem = memory_address (Pmode, tem);
00590 tem = gen_frame_mem (Pmode, tem);
00591 tem = copy_to_reg (tem);
00592 }
00593
00594
00595
00596 if (fndecl_code == BUILT_IN_FRAME_ADDRESS)
00597 #ifdef FRAME_ADDR_RTX
00598 return FRAME_ADDR_RTX (tem);
00599 #else
00600 return tem;
00601 #endif
00602
00603
00604 #ifdef RETURN_ADDR_RTX
00605 tem = RETURN_ADDR_RTX (count, tem);
00606 #else
00607 tem = memory_address (Pmode,
00608 plus_constant (tem, GET_MODE_SIZE (Pmode)));
00609 tem = gen_frame_mem (Pmode, tem);
00610 #endif
00611 return tem;
00612 }
00613
00614
00615 static HOST_WIDE_INT setjmp_alias_set = -1;
00616
00617
00618
00619
00620
00621 void
00622 expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
00623 {
00624 enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
00625 rtx stack_save;
00626 rtx mem;
00627
00628 if (setjmp_alias_set == -1)
00629 setjmp_alias_set = new_alias_set ();
00630
00631 buf_addr = convert_memory_address (Pmode, buf_addr);
00632
00633 buf_addr = force_reg (Pmode, force_operand (buf_addr, NULL_RTX));
00634
00635
00636
00637
00638
00639 mem = gen_rtx_MEM (Pmode, buf_addr);
00640 set_mem_alias_set (mem, setjmp_alias_set);
00641 emit_move_insn (mem, targetm.builtin_setjmp_frame_value ());
00642
00643 mem = gen_rtx_MEM (Pmode, plus_constant (buf_addr, GET_MODE_SIZE (Pmode))),
00644 set_mem_alias_set (mem, setjmp_alias_set);
00645
00646 emit_move_insn (validize_mem (mem),
00647 force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, receiver_label)));
00648
00649 stack_save = gen_rtx_MEM (sa_mode,
00650 plus_constant (buf_addr,
00651 2 * GET_MODE_SIZE (Pmode)));
00652 set_mem_alias_set (stack_save, setjmp_alias_set);
00653 emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
00654
00655
00656 #ifdef HAVE_builtin_setjmp_setup
00657 if (HAVE_builtin_setjmp_setup)
00658 emit_insn (gen_builtin_setjmp_setup (buf_addr));
00659 #endif
00660
00661
00662
00663 current_function_calls_setjmp = 1;
00664
00665
00666
00667 current_function_has_nonlocal_label = 1;
00668 }
00669
00670
00671
00672
00673 void
00674 expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
00675 {
00676
00677
00678 emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
00679
00680
00681
00682 emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx));
00683
00684
00685
00686 #ifdef HAVE_nonlocal_goto
00687 if (! HAVE_nonlocal_goto)
00688 #endif
00689 {
00690 emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
00691
00692
00693 emit_insn (gen_rtx_CLOBBER (VOIDmode, hard_frame_pointer_rtx));
00694 }
00695
00696 #if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
00697 if (fixed_regs[ARG_POINTER_REGNUM])
00698 {
00699 #ifdef ELIMINABLE_REGS
00700 size_t i;
00701 static const struct elims {const int from, to;} elim_regs[] = ELIMINABLE_REGS;
00702
00703 for (i = 0; i < ARRAY_SIZE (elim_regs); i++)
00704 if (elim_regs[i].from == ARG_POINTER_REGNUM
00705 && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
00706 break;
00707
00708 if (i == ARRAY_SIZE (elim_regs))
00709 #endif
00710 {
00711
00712
00713 emit_move_insn (virtual_incoming_args_rtx,
00714 copy_to_reg (get_arg_pointer_save_area (cfun)));
00715 }
00716 }
00717 #endif
00718
00719 #ifdef HAVE_builtin_setjmp_receiver
00720 if (HAVE_builtin_setjmp_receiver)
00721 emit_insn (gen_builtin_setjmp_receiver (receiver_label));
00722 else
00723 #endif
00724 #ifdef HAVE_nonlocal_goto_receiver
00725 if (HAVE_nonlocal_goto_receiver)
00726 emit_insn (gen_nonlocal_goto_receiver ());
00727 else
00728 #endif
00729 { }
00730
00731
00732
00733
00734
00735
00736 emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
00737 }
00738
00739
00740
00741
00742
00743
00744 static void
00745 expand_builtin_longjmp (rtx buf_addr, rtx value)
00746 {
00747 rtx fp, lab, stack, insn, last;
00748 enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
00749
00750 if (setjmp_alias_set == -1)
00751 setjmp_alias_set = new_alias_set ();
00752
00753 buf_addr = convert_memory_address (Pmode, buf_addr);
00754
00755 buf_addr = force_reg (Pmode, buf_addr);
00756
00757
00758
00759
00760
00761
00762 gcc_assert (value == const1_rtx);
00763
00764 last = get_last_insn ();
00765 #ifdef HAVE_builtin_longjmp
00766 if (HAVE_builtin_longjmp)
00767 emit_insn (gen_builtin_longjmp (buf_addr));
00768 else
00769 #endif
00770 {
00771 fp = gen_rtx_MEM (Pmode, buf_addr);
00772 lab = gen_rtx_MEM (Pmode, plus_constant (buf_addr,
00773 GET_MODE_SIZE (Pmode)));
00774
00775 stack = gen_rtx_MEM (sa_mode, plus_constant (buf_addr,
00776 2 * GET_MODE_SIZE (Pmode)));
00777 set_mem_alias_set (fp, setjmp_alias_set);
00778 set_mem_alias_set (lab, setjmp_alias_set);
00779 set_mem_alias_set (stack, setjmp_alias_set);
00780
00781
00782
00783 #ifdef HAVE_nonlocal_goto
00784 if (HAVE_nonlocal_goto)
00785
00786
00787
00788 emit_insn (gen_nonlocal_goto (value, lab, stack, fp));
00789 else
00790 #endif
00791 {
00792 lab = copy_to_reg (lab);
00793
00794 emit_insn (gen_rtx_CLOBBER (VOIDmode,
00795 gen_rtx_MEM (BLKmode,
00796 gen_rtx_SCRATCH (VOIDmode))));
00797 emit_insn (gen_rtx_CLOBBER (VOIDmode,
00798 gen_rtx_MEM (BLKmode,
00799 hard_frame_pointer_rtx)));
00800
00801 emit_move_insn (hard_frame_pointer_rtx, fp);
00802 emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
00803
00804 emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
00805 emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
00806 emit_indirect_jump (lab);
00807 }
00808 }
00809
00810
00811
00812
00813
00814
00815 for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
00816 {
00817 gcc_assert (insn != last);
00818
00819 if (JUMP_P (insn))
00820 {
00821 REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx,
00822 REG_NOTES (insn));
00823 break;
00824 }
00825 else if (CALL_P (insn))
00826 break;
00827 }
00828 }
00829
00830
00831
00832
00833 static rtx
00834 expand_builtin_nonlocal_goto (tree arglist)
00835 {
00836 tree t_label, t_save_area;
00837 rtx r_label, r_save_area, r_fp, r_sp, insn;
00838
00839 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
00840 return NULL_RTX;
00841
00842 t_label = TREE_VALUE (arglist);
00843 arglist = TREE_CHAIN (arglist);
00844 t_save_area = TREE_VALUE (arglist);
00845
00846 r_label = expand_normal (t_label);
00847 r_label = convert_memory_address (Pmode, r_label);
00848 r_save_area = expand_normal (t_save_area);
00849 r_save_area = convert_memory_address (Pmode, r_save_area);
00850 r_fp = gen_rtx_MEM (Pmode, r_save_area);
00851 r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL),
00852 plus_constant (r_save_area, GET_MODE_SIZE (Pmode)));
00853
00854 current_function_has_nonlocal_goto = 1;
00855
00856 #ifdef HAVE_nonlocal_goto
00857
00858 if (HAVE_nonlocal_goto)
00859 emit_insn (gen_nonlocal_goto (const0_rtx, r_label, r_sp, r_fp));
00860 else
00861 #endif
00862 {
00863 r_label = copy_to_reg (r_label);
00864
00865 emit_insn (gen_rtx_CLOBBER (VOIDmode,
00866 gen_rtx_MEM (BLKmode,
00867 gen_rtx_SCRATCH (VOIDmode))));
00868
00869 emit_insn (gen_rtx_CLOBBER (VOIDmode,
00870 gen_rtx_MEM (BLKmode,
00871 hard_frame_pointer_rtx)));
00872
00873
00874
00875
00876
00877
00878 emit_move_insn (hard_frame_pointer_rtx, r_fp);
00879 emit_stack_restore (SAVE_NONLOCAL, r_sp, NULL_RTX);
00880
00881
00882
00883 emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
00884 emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
00885 emit_indirect_jump (r_label);
00886 }
00887
00888
00889
00890 for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
00891 {
00892 if (JUMP_P (insn))
00893 {
00894 REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO,
00895 const0_rtx, REG_NOTES (insn));
00896 break;
00897 }
00898 else if (CALL_P (insn))
00899 break;
00900 }
00901
00902 return const0_rtx;
00903 }
00904
00905
00906
00907
00908
00909
00910 static void
00911 expand_builtin_update_setjmp_buf (rtx buf_addr)
00912 {
00913 enum machine_mode sa_mode = Pmode;
00914 rtx stack_save;
00915
00916
00917 #ifdef HAVE_save_stack_nonlocal
00918 if (HAVE_save_stack_nonlocal)
00919 sa_mode = insn_data[(int) CODE_FOR_save_stack_nonlocal].operand[0].mode;
00920 #endif
00921 #ifdef STACK_SAVEAREA_MODE
00922 sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
00923 #endif
00924
00925 stack_save
00926 = gen_rtx_MEM (sa_mode,
00927 memory_address
00928 (sa_mode,
00929 plus_constant (buf_addr, 2 * GET_MODE_SIZE (Pmode))));
00930
00931 #ifdef HAVE_setjmp
00932 if (HAVE_setjmp)
00933 emit_insn (gen_setjmp ());
00934 #endif
00935
00936 emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
00937 }
00938
00939
00940
00941
00942
00943 static void
00944 expand_builtin_prefetch (tree arglist)
00945 {
00946 tree arg0, arg1, arg2;
00947 rtx op0, op1, op2;
00948
00949 if (!validate_arglist (arglist, POINTER_TYPE, 0))
00950 return;
00951
00952 arg0 = TREE_VALUE (arglist);
00953
00954
00955
00956 if (TREE_CHAIN (arglist))
00957 {
00958 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
00959 if (TREE_CHAIN (TREE_CHAIN (arglist)))
00960 arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
00961 else
00962 arg2 = build_int_cst (NULL_TREE, 3);
00963 }
00964 else
00965 {
00966 arg1 = integer_zero_node;
00967 arg2 = build_int_cst (NULL_TREE, 3);
00968 }
00969
00970
00971 op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
00972
00973
00974 if (TREE_CODE (arg1) != INTEGER_CST)
00975 {
00976 error ("second argument to %<__builtin_prefetch%> must be a constant");
00977 arg1 = integer_zero_node;
00978 }
00979 op1 = expand_normal (arg1);
00980
00981 if (INTVAL (op1) != 0 && INTVAL (op1) != 1)
00982 {
00983 warning (0, "invalid second argument to %<__builtin_prefetch%>;"
00984 " using zero");
00985 op1 = const0_rtx;
00986 }
00987
00988
00989 if (TREE_CODE (arg2) != INTEGER_CST)
00990 {
00991 error ("third argument to %<__builtin_prefetch%> must be a constant");
00992 arg2 = integer_zero_node;
00993 }
00994 op2 = expand_normal (arg2);
00995
00996 if (INTVAL (op2) < 0 || INTVAL (op2) > 3)
00997 {
00998 warning (0, "invalid third argument to %<__builtin_prefetch%>; using zero");
00999 op2 = const0_rtx;
01000 }
01001
01002 #ifdef HAVE_prefetch
01003 if (HAVE_prefetch)
01004 {
01005 if ((! (*insn_data[(int) CODE_FOR_prefetch].operand[0].predicate)
01006 (op0,
01007 insn_data[(int) CODE_FOR_prefetch].operand[0].mode))
01008 || (GET_MODE (op0) != Pmode))
01009 {
01010 op0 = convert_memory_address (Pmode, op0);
01011 op0 = force_reg (Pmode, op0);
01012 }
01013 emit_insn (gen_prefetch (op0, op1, op2));
01014 }
01015 #endif
01016
01017
01018
01019 if (!MEM_P (op0) && side_effects_p (op0))
01020 emit_insn (op0);
01021 }
01022
01023
01024
01025
01026
01027
01028 static rtx
01029 get_memory_rtx (tree exp, tree len)
01030 {
01031 rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_NORMAL);
01032 rtx mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
01033
01034
01035
01036
01037 while ((TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
01038 || TREE_CODE (exp) == NON_LVALUE_EXPR)
01039 && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
01040 exp = TREE_OPERAND (exp, 0);
01041
01042 if (TREE_CODE (exp) == ADDR_EXPR)
01043 exp = TREE_OPERAND (exp, 0);
01044 else if (POINTER_TYPE_P (TREE_TYPE (exp)))
01045 exp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (exp)), exp);
01046 else
01047 exp = NULL;
01048
01049
01050
01051
01052 if (exp)
01053 {
01054 set_mem_attributes (mem, exp, 0);
01055
01056
01057
01058
01059
01060
01061 if (MEM_EXPR (mem) && TREE_CODE (MEM_EXPR (mem)) == COMPONENT_REF)
01062 {
01063 tree mem_expr = MEM_EXPR (mem);
01064 HOST_WIDE_INT offset = -1, length = -1;
01065 tree inner = exp;
01066
01067 while (TREE_CODE (inner) == ARRAY_REF
01068 || TREE_CODE (inner) == NOP_EXPR
01069 || TREE_CODE (inner) == CONVERT_EXPR
01070 || TREE_CODE (inner) == NON_LVALUE_EXPR
01071 || TREE_CODE (inner) == VIEW_CONVERT_EXPR
01072 || TREE_CODE (inner) == SAVE_EXPR)
01073 inner = TREE_OPERAND (inner, 0);
01074
01075 gcc_assert (TREE_CODE (inner) == COMPONENT_REF);
01076
01077 if (MEM_OFFSET (mem)
01078 && GET_CODE (MEM_OFFSET (mem)) == CONST_INT)
01079 offset = INTVAL (MEM_OFFSET (mem));
01080
01081 if (offset >= 0 && len && host_integerp (len, 0))
01082 length = tree_low_cst (len, 0);
01083
01084 while (TREE_CODE (inner) == COMPONENT_REF)
01085 {
01086 tree field = TREE_OPERAND (inner, 1);
01087 gcc_assert (! DECL_BIT_FIELD (field));
01088 gcc_assert (TREE_CODE (mem_expr) == COMPONENT_REF);
01089 gcc_assert (field == TREE_OPERAND (mem_expr, 1));
01090
01091 if (length >= 0
01092 && TYPE_SIZE_UNIT (TREE_TYPE (inner))
01093 && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0))
01094 {
01095 HOST_WIDE_INT size
01096 = tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0);
01097
01098
01099
01100 if (offset <= size
01101 && length <= size
01102 && offset + length <= size)
01103 break;
01104 }
01105
01106 if (offset >= 0
01107 && host_integerp (DECL_FIELD_OFFSET (field), 0))
01108 offset += tree_low_cst (DECL_FIELD_OFFSET (field), 0)
01109 + tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
01110 / BITS_PER_UNIT;
01111 else
01112 {
01113 offset = -1;
01114 length = -1;
01115 }
01116
01117 mem_expr = TREE_OPERAND (mem_expr, 0);
01118 inner = TREE_OPERAND (inner, 0);
01119 }
01120
01121 if (mem_expr == NULL)
01122 offset = -1;
01123 if (mem_expr != MEM_EXPR (mem))
01124 {
01125 set_mem_expr (mem, mem_expr);
01126 set_mem_offset (mem, offset >= 0 ? GEN_INT (offset) : NULL_RTX);
01127 }
01128 }
01129 set_mem_alias_set (mem, 0);
01130 set_mem_size (mem, NULL_RTX);
01131 }
01132
01133 return mem;
01134 }
01135
01136
01137
01138
01139
01140
01141
01142
01143 static enum machine_mode apply_args_mode[FIRST_PSEUDO_REGISTER];
01144
01145
01146
01147
01148
01149
01150 static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER];
01151
01152
01153
01154
01155
01156 static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
01157
01158
01159
01160
01161 static int
01162 apply_args_size (void)
01163 {
01164 static int size = -1;
01165 int align;
01166 unsigned int regno;
01167 enum machine_mode mode;
01168
01169
01170 if (size < 0)
01171 {
01172
01173 size = GET_MODE_SIZE (Pmode);
01174
01175
01176
01177 if (targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 0))
01178 size += GET_MODE_SIZE (Pmode);
01179
01180 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01181 if (FUNCTION_ARG_REGNO_P (regno))
01182 {
01183 mode = reg_raw_mode[regno];
01184
01185 gcc_assert (mode != VOIDmode);
01186
01187 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01188 if (size % align != 0)
01189 size = CEIL (size, align) * align;
01190 apply_args_reg_offset[regno] = size;
01191 size += GET_MODE_SIZE (mode);
01192 apply_args_mode[regno] = mode;
01193 }
01194 else
01195 {
01196 apply_args_mode[regno] = VOIDmode;
01197 apply_args_reg_offset[regno] = 0;
01198 }
01199 }
01200 return size;
01201 }
01202
01203
01204
01205
01206 static int
01207 apply_result_size (void)
01208 {
01209 static int size = -1;
01210 int align, regno;
01211 enum machine_mode mode;
01212
01213
01214 if (size < 0)
01215 {
01216 size = 0;
01217
01218 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01219 if (FUNCTION_VALUE_REGNO_P (regno))
01220 {
01221 mode = reg_raw_mode[regno];
01222
01223 gcc_assert (mode != VOIDmode);
01224
01225 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01226 if (size % align != 0)
01227 size = CEIL (size, align) * align;
01228 size += GET_MODE_SIZE (mode);
01229 apply_result_mode[regno] = mode;
01230 }
01231 else
01232 apply_result_mode[regno] = VOIDmode;
01233
01234
01235
01236 #ifdef APPLY_RESULT_SIZE
01237 size = APPLY_RESULT_SIZE;
01238 #endif
01239 }
01240 return size;
01241 }
01242
01243 #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
01244
01245
01246
01247
01248 static rtx
01249 result_vector (int savep, rtx result)
01250 {
01251 int regno, size, align, nelts;
01252 enum machine_mode mode;
01253 rtx reg, mem;
01254 rtx *savevec = alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
01255
01256 size = nelts = 0;
01257 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01258 if ((mode = apply_result_mode[regno]) != VOIDmode)
01259 {
01260 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01261 if (size % align != 0)
01262 size = CEIL (size, align) * align;
01263 reg = gen_rtx_REG (mode, savep ? regno : INCOMING_REGNO (regno));
01264 mem = adjust_address (result, mode, size);
01265 savevec[nelts++] = (savep
01266 ? gen_rtx_SET (VOIDmode, mem, reg)
01267 : gen_rtx_SET (VOIDmode, reg, mem));
01268 size += GET_MODE_SIZE (mode);
01269 }
01270 return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nelts, savevec));
01271 }
01272 #endif
01273
01274
01275
01276
01277 static rtx
01278 expand_builtin_apply_args_1 (void)
01279 {
01280 rtx registers, tem;
01281 int size, align, regno;
01282 enum machine_mode mode;
01283 rtx struct_incoming_value = targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 1);
01284
01285
01286
01287 registers = assign_stack_local (BLKmode, apply_args_size (), -1);
01288
01289
01290 size = GET_MODE_SIZE (Pmode);
01291 if (targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 0))
01292 size += GET_MODE_SIZE (Pmode);
01293
01294
01295 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01296 if ((mode = apply_args_mode[regno]) != VOIDmode)
01297 {
01298 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01299 if (size % align != 0)
01300 size = CEIL (size, align) * align;
01301
01302 tem = gen_rtx_REG (mode, INCOMING_REGNO (regno));
01303
01304 emit_move_insn (adjust_address (registers, mode, size), tem);
01305 size += GET_MODE_SIZE (mode);
01306 }
01307
01308
01309 tem = copy_to_reg (virtual_incoming_args_rtx);
01310 #ifdef STACK_GROWS_DOWNWARD
01311
01312
01313
01314 tem
01315 = force_operand (plus_constant (tem, current_function_pretend_args_size),
01316 NULL_RTX);
01317 #endif
01318 emit_move_insn (adjust_address (registers, Pmode, 0), tem);
01319
01320 size = GET_MODE_SIZE (Pmode);
01321
01322
01323
01324 if (struct_incoming_value)
01325 {
01326 emit_move_insn (adjust_address (registers, Pmode, size),
01327 copy_to_reg (struct_incoming_value));
01328 size += GET_MODE_SIZE (Pmode);
01329 }
01330
01331
01332 return copy_addr_to_reg (XEXP (registers, 0));
01333 }
01334
01335
01336
01337
01338
01339
01340
01341
01342 static rtx
01343 expand_builtin_apply_args (void)
01344 {
01345
01346
01347 if (apply_args_value != 0)
01348 return apply_args_value;
01349 {
01350
01351
01352
01353 rtx temp;
01354 rtx seq;
01355
01356 start_sequence ();
01357 temp = expand_builtin_apply_args_1 ();
01358 seq = get_insns ();
01359 end_sequence ();
01360
01361 apply_args_value = temp;
01362
01363
01364
01365
01366
01367 push_topmost_sequence ();
01368 emit_insn_before (seq, NEXT_INSN (entry_of_function ()));
01369 pop_topmost_sequence ();
01370 return temp;
01371 }
01372 }
01373
01374
01375
01376
01377 static rtx
01378 expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
01379 {
01380 int size, align, regno;
01381 enum machine_mode mode;
01382 rtx incoming_args, result, reg, dest, src, call_insn;
01383 rtx old_stack_level = 0;
01384 rtx call_fusage = 0;
01385 rtx struct_value = targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 0);
01386
01387 arguments = convert_memory_address (Pmode, arguments);
01388
01389
01390 result = assign_stack_local (BLKmode, apply_result_size (), -1);
01391
01392
01393 incoming_args = gen_reg_rtx (Pmode);
01394 emit_move_insn (incoming_args, gen_rtx_MEM (Pmode, arguments));
01395 #ifndef STACK_GROWS_DOWNWARD
01396 incoming_args = expand_simple_binop (Pmode, MINUS, incoming_args, argsize,
01397 incoming_args, 0, OPTAB_LIB_WIDEN);
01398 #endif
01399
01400
01401
01402
01403 do_pending_stack_adjust ();
01404 NO_DEFER_POP;
01405
01406
01407 #ifdef HAVE_save_stack_nonlocal
01408 if (HAVE_save_stack_nonlocal)
01409 emit_stack_save (SAVE_NONLOCAL, &old_stack_level, NULL_RTX);
01410 else
01411 #endif
01412 emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
01413
01414
01415
01416 allocate_dynamic_stack_space (argsize, 0, BITS_PER_UNIT);
01417 dest = virtual_outgoing_args_rtx;
01418 #ifndef STACK_GROWS_DOWNWARD
01419 if (GET_CODE (argsize) == CONST_INT)
01420 dest = plus_constant (dest, -INTVAL (argsize));
01421 else
01422 dest = gen_rtx_PLUS (Pmode, dest, negate_rtx (Pmode, argsize));
01423 #endif
01424 dest = gen_rtx_MEM (BLKmode, dest);
01425 set_mem_align (dest, PARM_BOUNDARY);
01426 src = gen_rtx_MEM (BLKmode, incoming_args);
01427 set_mem_align (src, PARM_BOUNDARY);
01428 emit_block_move (dest, src, argsize, BLOCK_OP_NORMAL);
01429
01430
01431 apply_args_size ();
01432 arguments = gen_rtx_MEM (BLKmode, arguments);
01433 set_mem_align (arguments, PARM_BOUNDARY);
01434
01435
01436 size = GET_MODE_SIZE (Pmode);
01437 if (struct_value)
01438 size += GET_MODE_SIZE (Pmode);
01439
01440
01441
01442 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01443 if ((mode = apply_args_mode[regno]) != VOIDmode)
01444 {
01445 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01446 if (size % align != 0)
01447 size = CEIL (size, align) * align;
01448 reg = gen_rtx_REG (mode, regno);
01449 emit_move_insn (reg, adjust_address (arguments, mode, size));
01450 use_reg (&call_fusage, reg);
01451 size += GET_MODE_SIZE (mode);
01452 }
01453
01454
01455
01456 size = GET_MODE_SIZE (Pmode);
01457 if (struct_value)
01458 {
01459 rtx value = gen_reg_rtx (Pmode);
01460 emit_move_insn (value, adjust_address (arguments, Pmode, size));
01461 emit_move_insn (struct_value, value);
01462 if (REG_P (struct_value))
01463 use_reg (&call_fusage, struct_value);
01464 size += GET_MODE_SIZE (Pmode);
01465 }
01466
01467
01468 function = prepare_call_address (function, NULL, &call_fusage, 0, 0);
01469
01470
01471
01472
01473 if (GET_CODE (function) != SYMBOL_REF)
01474 function = memory_address (FUNCTION_MODE, function);
01475
01476
01477 #ifdef HAVE_untyped_call
01478 if (HAVE_untyped_call)
01479 emit_call_insn (gen_untyped_call (gen_rtx_MEM (FUNCTION_MODE, function),
01480 result, result_vector (1, result)));
01481 else
01482 #endif
01483 #ifdef HAVE_call_value
01484 if (HAVE_call_value)
01485 {
01486 rtx valreg = 0;
01487
01488
01489
01490
01491
01492 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01493 if ((mode = apply_result_mode[regno]) != VOIDmode)
01494 {
01495 gcc_assert (!valreg);
01496
01497 valreg = gen_rtx_REG (mode, regno);
01498 }
01499
01500 emit_call_insn (GEN_CALL_VALUE (valreg,
01501 gen_rtx_MEM (FUNCTION_MODE, function),
01502 const0_rtx, NULL_RTX, const0_rtx));
01503
01504 emit_move_insn (adjust_address (result, GET_MODE (valreg), 0), valreg);
01505 }
01506 else
01507 #endif
01508 gcc_unreachable ();
01509
01510
01511
01512 call_insn = last_call_insn ();
01513 add_function_usage_to (call_insn, call_fusage);
01514
01515
01516 #ifdef HAVE_save_stack_nonlocal
01517 if (HAVE_save_stack_nonlocal)
01518 emit_stack_restore (SAVE_NONLOCAL, old_stack_level, NULL_RTX);
01519 else
01520 #endif
01521 emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
01522
01523 OK_DEFER_POP;
01524
01525
01526 result = copy_addr_to_reg (XEXP (result, 0));
01527 return convert_memory_address (ptr_mode, result);
01528 }
01529
01530
01531
01532 static void
01533 expand_builtin_return (rtx result)
01534 {
01535 int size, align, regno;
01536 enum machine_mode mode;
01537 rtx reg;
01538 rtx call_fusage = 0;
01539
01540 result = convert_memory_address (Pmode, result);
01541
01542 apply_result_size ();
01543 result = gen_rtx_MEM (BLKmode, result);
01544
01545 #ifdef HAVE_untyped_return
01546 if (HAVE_untyped_return)
01547 {
01548 emit_jump_insn (gen_untyped_return (result, result_vector (0, result)));
01549 emit_barrier ();
01550 return;
01551 }
01552 #endif
01553
01554
01555 size = 0;
01556 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01557 if ((mode = apply_result_mode[regno]) != VOIDmode)
01558 {
01559 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01560 if (size % align != 0)
01561 size = CEIL (size, align) * align;
01562 reg = gen_rtx_REG (mode, INCOMING_REGNO (regno));
01563 emit_move_insn (reg, adjust_address (result, mode, size));
01564
01565 push_to_sequence (call_fusage);
01566 emit_insn (gen_rtx_USE (VOIDmode, reg));
01567 call_fusage = get_insns ();
01568 end_sequence ();
01569 size += GET_MODE_SIZE (mode);
01570 }
01571
01572
01573 emit_insn (call_fusage);
01574
01575
01576
01577 expand_naked_return ();
01578 }
01579
01580
01581
01582 static enum type_class
01583 type_to_class (tree type)
01584 {
01585 switch (TREE_CODE (type))
01586 {
01587 case VOID_TYPE: return void_type_class;
01588 case INTEGER_TYPE: return integer_type_class;
01589 case ENUMERAL_TYPE: return enumeral_type_class;
01590 case BOOLEAN_TYPE: return boolean_type_class;
01591 case POINTER_TYPE: return pointer_type_class;
01592 case REFERENCE_TYPE: return reference_type_class;
01593 case OFFSET_TYPE: return offset_type_class;
01594 case REAL_TYPE: return real_type_class;
01595 case COMPLEX_TYPE: return complex_type_class;
01596 case FUNCTION_TYPE: return function_type_class;
01597 case METHOD_TYPE: return method_type_class;
01598 case RECORD_TYPE: return record_type_class;
01599 case UNION_TYPE:
01600 case QUAL_UNION_TYPE: return union_type_class;
01601 case ARRAY_TYPE: return (TYPE_STRING_FLAG (type)
01602 ? string_type_class : array_type_class);
01603 case LANG_TYPE: return lang_type_class;
01604 default: return no_type_class;
01605 }
01606 }
01607
01608
01609
01610
01611 static rtx
01612 expand_builtin_classify_type (tree arglist)
01613 {
01614 if (arglist != 0)
01615 return GEN_INT (type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
01616 return GEN_INT (no_type_class);
01617 }
01618
01619
01620
01621
01622
01623 #define CASE_MATHFN(BUILT_IN_MATHFN) \
01624 case BUILT_IN_MATHFN: case BUILT_IN_MATHFN##F: case BUILT_IN_MATHFN##L: \
01625 fcode = BUILT_IN_MATHFN; fcodef = BUILT_IN_MATHFN##F ; \
01626 fcodel = BUILT_IN_MATHFN##L ; break;
01627
01628
01629
01630 tree
01631 mathfn_built_in (tree type, enum built_in_function fn)
01632 {
01633 enum built_in_function fcode, fcodef, fcodel;
01634
01635 switch (fn)
01636 {
01637 CASE_MATHFN (BUILT_IN_ACOS)
01638 CASE_MATHFN (BUILT_IN_ACOSH)
01639 CASE_MATHFN (BUILT_IN_ASIN)
01640 CASE_MATHFN (BUILT_IN_ASINH)
01641 CASE_MATHFN (BUILT_IN_ATAN)
01642 CASE_MATHFN (BUILT_IN_ATAN2)
01643 CASE_MATHFN (BUILT_IN_ATANH)
01644 CASE_MATHFN (BUILT_IN_CBRT)
01645 CASE_MATHFN (BUILT_IN_CEIL)
01646 CASE_MATHFN (BUILT_IN_COPYSIGN)
01647 CASE_MATHFN (BUILT_IN_COS)
01648 CASE_MATHFN (BUILT_IN_COSH)
01649 CASE_MATHFN (BUILT_IN_DREM)
01650 CASE_MATHFN (BUILT_IN_ERF)
01651 CASE_MATHFN (BUILT_IN_ERFC)
01652 CASE_MATHFN (BUILT_IN_EXP)
01653 CASE_MATHFN (BUILT_IN_EXP10)
01654 CASE_MATHFN (BUILT_IN_EXP2)
01655 CASE_MATHFN (BUILT_IN_EXPM1)
01656 CASE_MATHFN (BUILT_IN_FABS)
01657 CASE_MATHFN (BUILT_IN_FDIM)
01658 CASE_MATHFN (BUILT_IN_FLOOR)
01659 CASE_MATHFN (BUILT_IN_FMA)
01660 CASE_MATHFN (BUILT_IN_FMAX)
01661 CASE_MATHFN (BUILT_IN_FMIN)
01662 CASE_MATHFN (BUILT_IN_FMOD)
01663 CASE_MATHFN (BUILT_IN_FREXP)
01664 CASE_MATHFN (BUILT_IN_GAMMA)
01665 CASE_MATHFN (BUILT_IN_HUGE_VAL)
01666 CASE_MATHFN (BUILT_IN_HYPOT)
01667 CASE_MATHFN (BUILT_IN_ILOGB)
01668 CASE_MATHFN (BUILT_IN_INF)
01669 CASE_MATHFN (BUILT_IN_J0)
01670 CASE_MATHFN (BUILT_IN_J1)
01671 CASE_MATHFN (BUILT_IN_JN)
01672 CASE_MATHFN (BUILT_IN_LCEIL)
01673 CASE_MATHFN (BUILT_IN_LDEXP)
01674 CASE_MATHFN (BUILT_IN_LFLOOR)
01675 CASE_MATHFN (BUILT_IN_LGAMMA)
01676 CASE_MATHFN (BUILT_IN_LLCEIL)
01677 CASE_MATHFN (BUILT_IN_LLFLOOR)
01678 CASE_MATHFN (BUILT_IN_LLRINT)
01679 CASE_MATHFN (BUILT_IN_LLROUND)
01680 CASE_MATHFN (BUILT_IN_LOG)
01681 CASE_MATHFN (BUILT_IN_LOG10)
01682 CASE_MATHFN (BUILT_IN_LOG1P)
01683 CASE_MATHFN (BUILT_IN_LOG2)
01684 CASE_MATHFN (BUILT_IN_LOGB)
01685 CASE_MATHFN (BUILT_IN_LRINT)
01686 CASE_MATHFN (BUILT_IN_LROUND)
01687 CASE_MATHFN (BUILT_IN_MODF)
01688 CASE_MATHFN (BUILT_IN_NAN)
01689 CASE_MATHFN (BUILT_IN_NANS)
01690 CASE_MATHFN (BUILT_IN_NEARBYINT)
01691 CASE_MATHFN (BUILT_IN_NEXTAFTER)
01692 CASE_MATHFN (BUILT_IN_NEXTTOWARD)
01693 CASE_MATHFN (BUILT_IN_POW)
01694 CASE_MATHFN (BUILT_IN_POWI)
01695 CASE_MATHFN (BUILT_IN_POW10)
01696 CASE_MATHFN (BUILT_IN_REMAINDER)
01697 CASE_MATHFN (BUILT_IN_REMQUO)
01698 CASE_MATHFN (BUILT_IN_RINT)
01699 CASE_MATHFN (BUILT_IN_ROUND)
01700 CASE_MATHFN (BUILT_IN_SCALB)
01701 CASE_MATHFN (BUILT_IN_SCALBLN)
01702 CASE_MATHFN (BUILT_IN_SCALBN)
01703 CASE_MATHFN (BUILT_IN_SIGNIFICAND)
01704 CASE_MATHFN (BUILT_IN_SIN)
01705 CASE_MATHFN (BUILT_IN_SINCOS)
01706 CASE_MATHFN (BUILT_IN_SINH)
01707 CASE_MATHFN (BUILT_IN_SQRT)
01708 CASE_MATHFN (BUILT_IN_TAN)
01709 CASE_MATHFN (BUILT_IN_TANH)
01710 CASE_MATHFN (BUILT_IN_TGAMMA)
01711 CASE_MATHFN (BUILT_IN_TRUNC)
01712 CASE_MATHFN (BUILT_IN_Y0)
01713 CASE_MATHFN (BUILT_IN_Y1)
01714 CASE_MATHFN (BUILT_IN_YN)
01715
01716 default:
01717 return 0;
01718 }
01719
01720 if (TYPE_MAIN_VARIANT (type) == double_type_node)
01721 return implicit_built_in_decls[fcode];
01722 else if (TYPE_MAIN_VARIANT (type) == float_type_node)
01723 return implicit_built_in_decls[fcodef];
01724 else if (TYPE_MAIN_VARIANT (type) == long_double_type_node)
01725 return implicit_built_in_decls[fcodel];
01726 else
01727 return 0;
01728 }
01729
01730
01731
01732
01733
01734 static void
01735 expand_errno_check (tree exp, rtx target)
01736 {
01737 rtx lab = gen_label_rtx ();
01738
01739
01740
01741 emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
01742 0, lab);
01743
01744 #ifdef TARGET_EDOM
01745
01746 if (TREE_NOTHROW (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
01747 {
01748 #ifdef GEN_ERRNO_RTX
01749 rtx errno_rtx = GEN_ERRNO_RTX;
01750 #else
01751 rtx errno_rtx
01752 = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
01753 #endif
01754 emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
01755 emit_label (lab);
01756 return;
01757 }
01758 #endif
01759
01760
01761
01762 NO_DEFER_POP;
01763 expand_call (exp, target, 0);
01764 OK_DEFER_POP;
01765 emit_label (lab);
01766 }
01767
01768
01769
01770
01771
01772
01773
01774
01775 static rtx
01776 expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
01777 {
01778 optab builtin_optab;
01779 rtx op0, insns, before_call;
01780 tree fndecl = get_callee_fndecl (exp);
01781 tree arglist = TREE_OPERAND (exp, 1);
01782 enum machine_mode mode;
01783 bool errno_set = false;
01784 tree arg, narg;
01785
01786 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
01787 return 0;
01788
01789 arg = TREE_VALUE (arglist);
01790
01791 switch (DECL_FUNCTION_CODE (fndecl))
01792 {
01793 CASE_FLT_FN (BUILT_IN_SQRT):
01794 errno_set = ! tree_expr_nonnegative_p (arg);
01795 builtin_optab = sqrt_optab;
01796 break;
01797 CASE_FLT_FN (BUILT_IN_EXP):
01798 errno_set = true; builtin_optab = exp_optab; break;
01799 CASE_FLT_FN (BUILT_IN_EXP10):
01800 CASE_FLT_FN (BUILT_IN_POW10):
01801 errno_set = true; builtin_optab = exp10_optab; break;
01802 CASE_FLT_FN (BUILT_IN_EXP2):
01803 errno_set = true; builtin_optab = exp2_optab; break;
01804 CASE_FLT_FN (BUILT_IN_EXPM1):
01805 errno_set = true; builtin_optab = expm1_optab; break;
01806 CASE_FLT_FN (BUILT_IN_LOGB):
01807 errno_set = true; builtin_optab = logb_optab; break;
01808 CASE_FLT_FN (BUILT_IN_ILOGB):
01809 errno_set = true; builtin_optab = ilogb_optab; break;
01810 CASE_FLT_FN (BUILT_IN_LOG):
01811 errno_set = true; builtin_optab = log_optab; break;
01812 CASE_FLT_FN (BUILT_IN_LOG10):
01813 errno_set = true; builtin_optab = log10_optab; break;
01814 CASE_FLT_FN (BUILT_IN_LOG2):
01815 errno_set = true; builtin_optab = log2_optab; break;
01816 CASE_FLT_FN (BUILT_IN_LOG1P):
01817 errno_set = true; builtin_optab = log1p_optab; break;
01818 CASE_FLT_FN (BUILT_IN_ASIN):
01819 builtin_optab = asin_optab; break;
01820 CASE_FLT_FN (BUILT_IN_ACOS):
01821 builtin_optab = acos_optab; break;
01822 CASE_FLT_FN (BUILT_IN_TAN):
01823 builtin_optab = tan_optab; break;
01824 CASE_FLT_FN (BUILT_IN_ATAN):
01825 builtin_optab = atan_optab; break;
01826 CASE_FLT_FN (BUILT_IN_FLOOR):
01827 builtin_optab = floor_optab; break;
01828 CASE_FLT_FN (BUILT_IN_CEIL):
01829 builtin_optab = ceil_optab; break;
01830 CASE_FLT_FN (BUILT_IN_TRUNC):
01831 builtin_optab = btrunc_optab; break;
01832 CASE_FLT_FN (BUILT_IN_ROUND):
01833 builtin_optab = round_optab; break;
01834 CASE_FLT_FN (BUILT_IN_NEARBYINT):
01835 builtin_optab = nearbyint_optab; break;
01836 CASE_FLT_FN (BUILT_IN_RINT):
01837 builtin_optab = rint_optab; break;
01838 CASE_FLT_FN (BUILT_IN_LRINT):
01839 CASE_FLT_FN (BUILT_IN_LLRINT):
01840 builtin_optab = lrint_optab; break;
01841 default:
01842 gcc_unreachable ();
01843 }
01844
01845
01846 mode = TYPE_MODE (TREE_TYPE (exp));
01847
01848 if (! flag_errno_math || ! HONOR_NANS (mode))
01849 errno_set = false;
01850
01851
01852 if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
01853 {
01854 target = gen_reg_rtx (mode);
01855
01856
01857
01858
01859 narg = builtin_save_expr (arg);
01860 if (narg != arg)
01861 {
01862 arg = narg;
01863 arglist = build_tree_list (NULL_TREE, arg);
01864 exp = build_function_call_expr (fndecl, arglist);
01865 }
01866
01867 op0 = expand_expr (arg, subtarget, VOIDmode, 0);
01868
01869 start_sequence ();
01870
01871
01872
01873 target = expand_unop (mode, builtin_optab, op0, target, 0);
01874
01875 if (target != 0)
01876 {
01877 if (errno_set)
01878 expand_errno_check (exp, target);
01879
01880
01881 insns = get_insns ();
01882 end_sequence ();
01883 emit_insn (insns);
01884 return target;
01885 }
01886
01887
01888
01889
01890 end_sequence ();
01891 }
01892
01893 before_call = get_last_insn ();
01894
01895 target = expand_call (exp, target, target == const0_rtx);
01896
01897
01898
01899
01900
01901 if (builtin_optab == sqrt_optab && !errno_set)
01902 {
01903
01904
01905 rtx last = get_last_insn ();
01906 while (last != before_call)
01907 {
01908 if (find_reg_note (last, REG_RETVAL, NULL))
01909 {
01910 rtx note = find_reg_note (last, REG_EQUAL, NULL);
01911
01912
01913 if (note
01914 && GET_CODE (note) == EXPR_LIST
01915 && GET_CODE (XEXP (note, 0)) == EXPR_LIST
01916 && XEXP (XEXP (note, 0), 1) != NULL_RTX
01917 && XEXP (XEXP (XEXP (note, 0), 1), 1) == NULL_RTX)
01918 {
01919 rtx operand = XEXP (XEXP (XEXP (note, 0), 1), 0);
01920
01921 if (operand
01922 && REG_P (operand)
01923 && GET_MODE (operand) == mode)
01924 {
01925
01926 rtx equiv = gen_rtx_SQRT (mode, operand);
01927 set_unique_reg_note (last, REG_EQUAL, equiv);
01928 }
01929 }
01930 break;
01931 }
01932 last = PREV_INSN (last);
01933 }
01934 }
01935
01936 return target;
01937 }
01938
01939
01940
01941
01942
01943
01944
01945
01946 static rtx
01947 expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
01948 {
01949 optab builtin_optab;
01950 rtx op0, op1, insns;
01951 int op1_type = REAL_TYPE;
01952 tree fndecl = get_callee_fndecl (exp);
01953 tree arglist = TREE_OPERAND (exp, 1);
01954 tree arg0, arg1, temp, narg;
01955 enum machine_mode mode;
01956 bool errno_set = true;
01957 bool stable = true;
01958
01959 if ((DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXP)
01960 || (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXPF)
01961 || (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXPL))
01962 op1_type = INTEGER_TYPE;
01963
01964 if (!validate_arglist (arglist, REAL_TYPE, op1_type, VOID_TYPE))
01965 return 0;
01966
01967 arg0 = TREE_VALUE (arglist);
01968 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
01969
01970 switch (DECL_FUNCTION_CODE (fndecl))
01971 {
01972 CASE_FLT_FN (BUILT_IN_POW):
01973 builtin_optab = pow_optab; break;
01974 CASE_FLT_FN (BUILT_IN_ATAN2):
01975 builtin_optab = atan2_optab; break;
01976 CASE_FLT_FN (BUILT_IN_LDEXP):
01977 builtin_optab = ldexp_optab; break;
01978 CASE_FLT_FN (BUILT_IN_FMOD):
01979 builtin_optab = fmod_optab; break;
01980 CASE_FLT_FN (BUILT_IN_DREM):
01981 builtin_optab = drem_optab; break;
01982 default:
01983 gcc_unreachable ();
01984 }
01985
01986
01987 mode = TYPE_MODE (TREE_TYPE (exp));
01988
01989
01990 if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
01991 return 0;
01992
01993 target = gen_reg_rtx (mode);
01994
01995 if (! flag_errno_math || ! HONOR_NANS (mode))
01996 errno_set = false;
01997
01998
01999 narg = builtin_save_expr (arg1);
02000 if (narg != arg1)
02001 {
02002 arg1 = narg;
02003 temp = build_tree_list (NULL_TREE, narg);
02004 stable = false;
02005 }
02006 else
02007 temp = TREE_CHAIN (arglist);
02008
02009 narg = builtin_save_expr (arg0);
02010 if (narg != arg0)
02011 {
02012 arg0 = narg;
02013 arglist = tree_cons (NULL_TREE, narg, temp);
02014 stable = false;
02015 }
02016 else if (! stable)
02017 arglist = tree_cons (NULL_TREE, arg0, temp);
02018
02019 if (! stable)
02020 exp = build_function_call_expr (fndecl, arglist);
02021
02022 op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
02023 op1 = expand_normal (arg1);
02024
02025 start_sequence ();
02026
02027
02028
02029 target = expand_binop (mode, builtin_optab, op0, op1,
02030 target, 0, OPTAB_DIRECT);
02031
02032
02033
02034
02035 if (target == 0)
02036 {
02037 end_sequence ();
02038 return expand_call (exp, target, target == const0_rtx);
02039 }
02040
02041 if (errno_set)
02042 expand_errno_check (exp, target);
02043
02044
02045 insns = get_insns ();
02046 end_sequence ();
02047 emit_insn (insns);
02048
02049 return target;
02050 }
02051
02052
02053
02054
02055
02056
02057
02058
02059 static rtx
02060 expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
02061 {
02062 optab builtin_optab;
02063 rtx op0, insns;
02064 tree fndecl = get_callee_fndecl (exp);
02065 tree arglist = TREE_OPERAND (exp, 1);
02066 enum machine_mode mode;
02067 tree arg, narg;
02068
02069 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
02070 return 0;
02071
02072 arg = TREE_VALUE (arglist);
02073
02074 switch (DECL_FUNCTION_CODE (fndecl))
02075 {
02076 CASE_FLT_FN (BUILT_IN_SIN):
02077 CASE_FLT_FN (BUILT_IN_COS):
02078 builtin_optab = sincos_optab; break;
02079 default:
02080 gcc_unreachable ();
02081 }
02082
02083
02084 mode = TYPE_MODE (TREE_TYPE (exp));
02085
02086
02087
02088 if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) {
02089 switch (DECL_FUNCTION_CODE (fndecl))
02090 {
02091 CASE_FLT_FN (BUILT_IN_SIN):
02092 builtin_optab = sin_optab; break;
02093 CASE_FLT_FN (BUILT_IN_COS):
02094 builtin_optab = cos_optab; break;
02095 default:
02096 gcc_unreachable ();
02097 }
02098 }
02099
02100
02101 if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
02102 {
02103 target = gen_reg_rtx (mode);
02104
02105
02106
02107
02108 narg = save_expr (arg);
02109 if (narg != arg)
02110 {
02111 arg = narg;
02112 arglist = build_tree_list (NULL_TREE, arg);
02113 exp = build_function_call_expr (fndecl, arglist);
02114 }
02115
02116 op0 = expand_expr (arg, subtarget, VOIDmode, 0);
02117
02118 start_sequence ();
02119
02120
02121
02122 if (builtin_optab == sincos_optab)
02123 {
02124 int result;
02125
02126 switch (DECL_FUNCTION_CODE (fndecl))
02127 {
02128 CASE_FLT_FN (BUILT_IN_SIN):
02129 result = expand_twoval_unop (builtin_optab, op0, 0, target, 0);
02130 break;
02131 CASE_FLT_FN (BUILT_IN_COS):
02132 result = expand_twoval_unop (builtin_optab, op0, target, 0, 0);
02133 break;
02134 default:
02135 gcc_unreachable ();
02136 }
02137 gcc_assert (result);
02138 }
02139 else
02140 {
02141 target = expand_unop (mode, builtin_optab, op0, target, 0);
02142 }
02143
02144 if (target != 0)
02145 {
02146
02147 insns = get_insns ();
02148 end_sequence ();
02149 emit_insn (insns);
02150 return target;
02151 }
02152
02153
02154
02155
02156 end_sequence ();
02157 }
02158
02159 target = expand_call (exp, target, target == const0_rtx);
02160
02161 return target;
02162 }
02163
02164
02165
02166
02167
02168
02169 static rtx
02170 expand_builtin_sincos (tree exp)
02171 {
02172 rtx op0, op1, op2, target1, target2;
02173 tree arglist = TREE_OPERAND (exp, 1);
02174 enum machine_mode mode;
02175 tree arg, sinp, cosp;
02176 int result;
02177
02178 if (!validate_arglist (arglist, REAL_TYPE,
02179 POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
02180 return 0;
02181
02182 arg = TREE_VALUE (arglist);
02183 sinp = TREE_VALUE (TREE_CHAIN (arglist));
02184 cosp = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02185
02186
02187 mode = TYPE_MODE (TREE_TYPE (arg));
02188
02189
02190 if (sincos_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
02191 return NULL_RTX;
02192
02193 target1 = gen_reg_rtx (mode);
02194 target2 = gen_reg_rtx (mode);
02195
02196 op0 = expand_normal (arg);
02197 op1 = expand_normal (build_fold_indirect_ref (sinp));
02198 op2 = expand_normal (build_fold_indirect_ref (cosp));
02199
02200
02201
02202 result = expand_twoval_unop (sincos_optab, op0, target2, target1, 0);
02203 gcc_assert (result);
02204
02205
02206
02207 emit_move_insn (op1, target1);
02208 emit_move_insn (op2, target2);
02209
02210 return const0_rtx;
02211 }
02212
02213
02214
02215
02216
02217
02218
02219 static rtx
02220 expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget)
02221 {
02222 optab builtin_optab;
02223 rtx op0, insns, tmp;
02224 tree fndecl = get_callee_fndecl (exp);
02225 tree arglist = TREE_OPERAND (exp, 1);
02226 enum built_in_function fallback_fn;
02227 tree fallback_fndecl;
02228 enum machine_mode mode;
02229 tree arg, narg;
02230
02231 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
02232 gcc_unreachable ();
02233
02234 arg = TREE_VALUE (arglist);
02235
02236 switch (DECL_FUNCTION_CODE (fndecl))
02237 {
02238 CASE_FLT_FN (BUILT_IN_LCEIL):
02239 CASE_FLT_FN (BUILT_IN_LLCEIL):
02240 builtin_optab = lceil_optab;
02241 fallback_fn = BUILT_IN_CEIL;
02242 break;
02243
02244 CASE_FLT_FN (BUILT_IN_LFLOOR):
02245 CASE_FLT_FN (BUILT_IN_LLFLOOR):
02246 builtin_optab = lfloor_optab;
02247 fallback_fn = BUILT_IN_FLOOR;
02248 break;
02249
02250 default:
02251 gcc_unreachable ();
02252 }
02253
02254
02255 mode = TYPE_MODE (TREE_TYPE (exp));
02256
02257
02258 if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
02259 {
02260 target = gen_reg_rtx (mode);
02261
02262
02263
02264
02265 narg = builtin_save_expr (arg);
02266 if (narg != arg)
02267 {
02268 arg = narg;
02269 arglist = build_tree_list (NULL_TREE, arg);
02270 exp = build_function_call_expr (fndecl, arglist);
02271 }
02272
02273 op0 = expand_expr (arg, subtarget, VOIDmode, 0);
02274
02275 start_sequence ();
02276
02277
02278
02279 target = expand_unop (mode, builtin_optab, op0, target, 0);
02280
02281 if (target != 0)
02282 {
02283
02284 insns = get_insns ();
02285 end_sequence ();
02286 emit_insn (insns);
02287 return target;
02288 }
02289
02290
02291
02292 end_sequence ();
02293 }
02294
02295
02296 fallback_fndecl = mathfn_built_in (TREE_TYPE (arg), fallback_fn);
02297
02298
02299 gcc_assert (fallback_fndecl != NULL_TREE);
02300 exp = build_function_call_expr (fallback_fndecl, arglist);
02301
02302 tmp = expand_normal (exp);
02303
02304
02305
02306 target = gen_reg_rtx (mode);
02307 expand_fix (target, tmp, 0);
02308
02309 return target;
02310 }
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325
02326 #ifndef POWI_MAX_MULTS
02327 #define POWI_MAX_MULTS (2*HOST_BITS_PER_WIDE_INT-2)
02328 #endif
02329
02330
02331
02332
02333
02334 #define POWI_TABLE_SIZE 256
02335
02336
02337
02338
02339 #define POWI_WINDOW_SIZE 3
02340
02341
02342
02343
02344
02345
02346
02347
02348 static const unsigned char powi_table[POWI_TABLE_SIZE] =
02349 {
02350 0, 1, 1, 2, 2, 3, 3, 4,
02351 4, 6, 5, 6, 6, 10, 7, 9,
02352 8, 16, 9, 16, 10, 12, 11, 13,
02353 12, 17, 13, 18, 14, 24, 15, 26,
02354 16, 17, 17, 19, 18, 33, 19, 26,
02355 20, 25, 21, 40, 22, 27, 23, 44,
02356 24, 32, 25, 34, 26, 29, 27, 44,
02357 28, 31, 29, 34, 30, 60, 31, 36,
02358 32, 64, 33, 34, 34, 46, 35, 37,
02359 36, 65, 37, 50, 38, 48, 39, 69,
02360 40, 49, 41, 43, 42, 51, 43, 58,
02361 44, 64, 45, 47, 46, 59, 47, 76,
02362 48, 65, 49, 66, 50, 67, 51, 66,
02363 52, 70, 53, 74, 54, 104, 55, 74,
02364 56, 64, 57, 69, 58, 78, 59, 68,
02365 60, 61, 61, 80, 62, 75, 63, 68,
02366 64, 65, 65, 128, 66, 129, 67, 90,
02367 68, 73, 69, 131, 70, 94, 71, 88,
02368 72, 128, 73, 98, 74, 132, 75, 121,
02369 76, 102, 77, 124, 78, 132, 79, 106,
02370 80, 97, 81, 160, 82, 99, 83, 134,
02371 84, 86, 85, 95, 86, 160, 87, 100,
02372 88, 113, 89, 98, 90, 107, 91, 122,
02373 92, 111, 93, 102, 94, 126, 95, 150,
02374 96, 128, 97, 130, 98, 133, 99, 195,
02375 100, 128, 101, 123, 102, 164, 103, 138,
02376 104, 145, 105, 146, 106, 109, 107, 149,
02377 108, 200, 109, 146, 110, 170, 111, 157,
02378 112, 128, 113, 130, 114, 182, 115, 132,
02379 116, 200, 117, 132, 118, 158, 119, 206,
02380 120, 240, 121, 162, 122, 147, 123, 152,
02381 124, 166, 125, 214, 126, 138, 127, 153,
02382 };
02383
02384
02385
02386
02387
02388
02389
02390 static int
02391 powi_lookup_cost (unsigned HOST_WIDE_INT n, bool *cache)
02392 {
02393
02394
02395 if (cache[n])
02396 return 0;
02397
02398 cache[n] = true;
02399 return powi_lookup_cost (n - powi_table[n], cache)
02400 + powi_lookup_cost (powi_table[n], cache) + 1;
02401 }
02402
02403
02404
02405
02406
02407 static int
02408 powi_cost (HOST_WIDE_INT n)
02409 {
02410 bool cache[POWI_TABLE_SIZE];
02411 unsigned HOST_WIDE_INT digit;
02412 unsigned HOST_WIDE_INT val;
02413 int result;
02414
02415 if (n == 0)
02416 return 0;
02417
02418
02419 val = (n < 0) ? -n : n;
02420
02421
02422 memset (cache, 0, POWI_TABLE_SIZE * sizeof (bool));
02423 cache[1] = true;
02424
02425 result = 0;
02426
02427 while (val >= POWI_TABLE_SIZE)
02428 {
02429 if (val & 1)
02430 {
02431 digit = val & ((1 << POWI_WINDOW_SIZE) - 1);
02432 result += powi_lookup_cost (digit, cache)
02433 + POWI_WINDOW_SIZE + 1;
02434 val >>= POWI_WINDOW_SIZE;
02435 }
02436 else
02437 {
02438 val >>= 1;
02439 result++;
02440 }
02441 }
02442
02443 return result + powi_lookup_cost (val, cache);
02444 }
02445
02446
02447
02448
02449
02450 static rtx
02451 expand_powi_1 (enum machine_mode mode, unsigned HOST_WIDE_INT n, rtx *cache)
02452 {
02453 unsigned HOST_WIDE_INT digit;
02454 rtx target, result;
02455 rtx op0, op1;
02456
02457 if (n < POWI_TABLE_SIZE)
02458 {
02459 if (cache[n])
02460 return cache[n];
02461
02462 target = gen_reg_rtx (mode);
02463 cache[n] = target;
02464
02465 op0 = expand_powi_1 (mode, n - powi_table[n], cache);
02466 op1 = expand_powi_1 (mode, powi_table[n], cache);
02467 }
02468 else if (n & 1)
02469 {
02470 target = gen_reg_rtx (mode);
02471 digit = n & ((1 << POWI_WINDOW_SIZE) - 1);
02472 op0 = expand_powi_1 (mode, n - digit, cache);
02473 op1 = expand_powi_1 (mode, digit, cache);
02474 }
02475 else
02476 {
02477 target = gen_reg_rtx (mode);
02478 op0 = expand_powi_1 (mode, n >> 1, cache);
02479 op1 = op0;
02480 }
02481
02482 result = expand_mult (mode, op0, op1, target, 0);
02483 if (result != target)
02484 emit_move_insn (target, result);
02485 return target;
02486 }
02487
02488
02489
02490
02491
02492 static rtx
02493 expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n)
02494 {
02495 unsigned HOST_WIDE_INT val;
02496 rtx cache[POWI_TABLE_SIZE];
02497 rtx result;
02498
02499 if (n == 0)
02500 return CONST1_RTX (mode);
02501
02502 val = (n < 0) ? -n : n;
02503
02504 memset (cache, 0, sizeof (cache));
02505 cache[1] = x;
02506
02507 result = expand_powi_1 (mode, (n < 0) ? -n : n, cache);
02508
02509
02510 if (n < 0)
02511 result = expand_binop (mode, sdiv_optab, CONST1_RTX (mode),
02512 result, NULL_RTX, 0, OPTAB_LIB_WIDEN);
02513
02514 return result;
02515 }
02516
02517
02518
02519
02520
02521
02522 static rtx
02523 expand_builtin_pow (tree exp, rtx target, rtx subtarget)
02524 {
02525 tree arglist = TREE_OPERAND (exp, 1);
02526 tree arg0, arg1;
02527
02528 if (! validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
02529 return 0;
02530
02531 arg0 = TREE_VALUE (arglist);
02532 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
02533
02534 if (TREE_CODE (arg1) == REAL_CST
02535 && ! TREE_CONSTANT_OVERFLOW (arg1))
02536 {
02537 REAL_VALUE_TYPE cint;
02538 REAL_VALUE_TYPE c;
02539 HOST_WIDE_INT n;
02540
02541 c = TREE_REAL_CST (arg1);
02542 n = real_to_integer (&c);
02543 real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
02544 if (real_identical (&c, &cint))
02545 {
02546
02547
02548
02549 if ((n >= -1 && n <= 2)
02550 || (flag_unsafe_math_optimizations
02551 && ! optimize_size
02552 && powi_cost (n) <= POWI_MAX_MULTS))
02553 {
02554 enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
02555 rtx op = expand_expr (arg0, subtarget, VOIDmode, 0);
02556 op = force_reg (mode, op);
02557 return expand_powi (op, mode, n);
02558 }
02559 }
02560 }
02561
02562 if (! flag_unsafe_math_optimizations)
02563 return NULL_RTX;
02564 return expand_builtin_mathfn_2 (exp, target, subtarget);
02565 }
02566
02567
02568
02569
02570
02571
02572 static rtx
02573 expand_builtin_powi (tree exp, rtx target, rtx subtarget)
02574 {
02575 tree arglist = TREE_OPERAND (exp, 1);
02576 tree arg0, arg1;
02577 rtx op0, op1;
02578 enum machine_mode mode;
02579 enum machine_mode mode2;
02580
02581 if (! validate_arglist (arglist, REAL_TYPE, INTEGER_TYPE, VOID_TYPE))
02582 return 0;
02583
02584 arg0 = TREE_VALUE (arglist);
02585 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
02586 mode = TYPE_MODE (TREE_TYPE (exp));
02587
02588
02589
02590 if (TREE_CODE (arg1) == INTEGER_CST
02591 && ! TREE_CONSTANT_OVERFLOW (arg1))
02592 {
02593 HOST_WIDE_INT n = TREE_INT_CST_LOW (arg1);
02594
02595
02596
02597 if ((TREE_INT_CST_HIGH (arg1) == 0
02598 || TREE_INT_CST_HIGH (arg1) == -1)
02599 && ((n >= -1 && n <= 2)
02600 || (! optimize_size
02601 && powi_cost (n) <= POWI_MAX_MULTS)))
02602 {
02603 op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
02604 op0 = force_reg (mode, op0);
02605 return expand_powi (op0, mode, n);
02606 }
02607 }
02608
02609
02610
02611
02612 mode2 = mode_for_size (INT_TYPE_SIZE, MODE_INT, 0);
02613
02614 if (target == NULL_RTX)
02615 target = gen_reg_rtx (mode);
02616
02617 op0 = expand_expr (arg0, subtarget, mode, 0);
02618 if (GET_MODE (op0) != mode)
02619 op0 = convert_to_mode (mode, op0, 0);
02620 op1 = expand_expr (arg1, 0, mode2, 0);
02621 if (GET_MODE (op1) != mode2)
02622 op1 = convert_to_mode (mode2, op1, 0);
02623
02624 target = emit_library_call_value (powi_optab->handlers[(int) mode].libfunc,
02625 target, LCT_CONST_MAKE_BLOCK, mode, 2,
02626 op0, mode, op1, mode2);
02627
02628 return target;
02629 }
02630
02631
02632
02633
02634
02635 static rtx
02636 expand_builtin_strlen (tree arglist, rtx target,
02637 enum machine_mode target_mode)
02638 {
02639 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
02640 return 0;
02641 else
02642 {
02643 rtx pat;
02644 tree len, src = TREE_VALUE (arglist);
02645 rtx result, src_reg, char_rtx, before_strlen;
02646 enum machine_mode insn_mode = target_mode, char_mode;
02647 enum insn_code icode = CODE_FOR_nothing;
02648 int align;
02649
02650
02651 len = c_strlen (src, 0);
02652 if (len)
02653 return expand_expr (len, target, target_mode, EXPAND_NORMAL);
02654
02655
02656
02657
02658
02659
02660 len = c_strlen (src, 1);
02661 if (len && TREE_CODE (len) == INTEGER_CST)
02662 {
02663 expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
02664 return expand_expr (len, target, target_mode, EXPAND_NORMAL);
02665 }
02666
02667 align = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
02668
02669
02670 if (align == 0)
02671 return 0;
02672
02673
02674 while (insn_mode != VOIDmode)
02675 {
02676 icode = strlen_optab->handlers[(int) insn_mode].insn_code;
02677 if (icode != CODE_FOR_nothing)
02678 break;
02679
02680 insn_mode = GET_MODE_WIDER_MODE (insn_mode);
02681 }
02682 if (insn_mode == VOIDmode)
02683 return 0;
02684
02685
02686 result = target;
02687 if (! (result != 0
02688 && REG_P (result)
02689 && GET_MODE (result) == insn_mode
02690 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
02691 result = gen_reg_rtx (insn_mode);
02692
02693
02694
02695
02696 src_reg = gen_reg_rtx (Pmode);
02697
02698
02699
02700 before_strlen = get_last_insn ();
02701
02702 char_rtx = const0_rtx;
02703 char_mode = insn_data[(int) icode].operand[2].mode;
02704 if (! (*insn_data[(int) icode].operand[2].predicate) (char_rtx,
02705 char_mode))
02706 char_rtx = copy_to_mode_reg (char_mode, char_rtx);
02707
02708 pat = GEN_FCN (icode) (result, gen_rtx_MEM (BLKmode, src_reg),
02709 char_rtx, GEN_INT (align));
02710 if (! pat)
02711 return 0;
02712 emit_insn (pat);
02713
02714
02715 start_sequence ();
02716 pat = expand_expr (src, src_reg, ptr_mode, EXPAND_NORMAL);
02717 if (pat != src_reg)
02718 emit_move_insn (src_reg, pat);
02719 pat = get_insns ();
02720 end_sequence ();
02721
02722 if (before_strlen)
02723 emit_insn_after (pat, before_strlen);
02724 else
02725 emit_insn_before (pat, get_insns ());
02726
02727
02728 if (GET_MODE (result) == target_mode)
02729 target = result;
02730 else if (target != 0)
02731 convert_move (target, result, 0);
02732 else
02733 target = convert_to_mode (target_mode, result, 0);
02734
02735 return target;
02736 }
02737 }
02738
02739
02740
02741
02742
02743 static rtx
02744 expand_builtin_strstr (tree arglist, tree type, rtx target, enum machine_mode mode)
02745 {
02746 if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
02747 {
02748 tree result = fold_builtin_strstr (arglist, type);
02749 if (result)
02750 return expand_expr (result, target, mode, EXPAND_NORMAL);
02751 }
02752 return 0;
02753 }
02754
02755
02756
02757
02758
02759 static rtx
02760 expand_builtin_strchr (tree arglist, tree type, rtx target, enum machine_mode mode)
02761 {
02762 if (validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02763 {
02764 tree result = fold_builtin_strchr (arglist, type);
02765 if (result)
02766 return expand_expr (result, target, mode, EXPAND_NORMAL);
02767
02768
02769 }
02770 return 0;
02771 }
02772
02773
02774
02775
02776
02777 static rtx
02778 expand_builtin_strrchr (tree arglist, tree type, rtx target, enum machine_mode mode)
02779 {
02780 if (validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02781 {
02782 tree result = fold_builtin_strrchr (arglist, type);
02783 if (result)
02784 return expand_expr (result, target, mode, EXPAND_NORMAL);
02785 }
02786 return 0;
02787 }
02788
02789
02790
02791
02792
02793 static rtx
02794 expand_builtin_strpbrk (tree arglist, tree type, rtx target, enum machine_mode mode)
02795 {
02796 if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
02797 {
02798 tree result = fold_builtin_strpbrk (arglist, type);
02799 if (result)
02800 return expand_expr (result, target, mode, EXPAND_NORMAL);
02801 }
02802 return 0;
02803 }
02804
02805
02806
02807
02808
02809 static rtx
02810 builtin_memcpy_read_str (void *data, HOST_WIDE_INT offset,
02811 enum machine_mode mode)
02812 {
02813 const char *str = (const char *) data;
02814
02815 gcc_assert (offset >= 0
02816 && ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode)
02817 <= strlen (str) + 1));
02818
02819 return c_readstr (str + offset, mode);
02820 }
02821
02822
02823
02824
02825
02826 static rtx
02827 expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
02828 {
02829 tree fndecl = get_callee_fndecl (exp);
02830 tree arglist = TREE_OPERAND (exp, 1);
02831 if (!validate_arglist (arglist,
02832 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02833 return 0;
02834 else
02835 {
02836 tree dest = TREE_VALUE (arglist);
02837 tree src = TREE_VALUE (TREE_CHAIN (arglist));
02838 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02839 const char *src_str;
02840 unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
02841 unsigned int dest_align
02842 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
02843 rtx dest_mem, src_mem, dest_addr, len_rtx;
02844 tree result = fold_builtin_memory_op (arglist, TREE_TYPE (TREE_TYPE (fndecl)),
02845 false, 0);
02846
02847 if (result)
02848 {
02849 while (TREE_CODE (result) == COMPOUND_EXPR)
02850 {
02851 expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
02852 EXPAND_NORMAL);
02853 result = TREE_OPERAND (result, 1);
02854 }
02855 return expand_expr (result, target, mode, EXPAND_NORMAL);
02856 }
02857
02858
02859 if (dest_align == 0)
02860 return 0;
02861
02862
02863
02864 if (src_align == 0)
02865 return 0;
02866
02867 dest_mem = get_memory_rtx (dest, len);
02868 set_mem_align (dest_mem, dest_align);
02869 len_rtx = expand_normal (len);
02870 src_str = c_getstr (src);
02871
02872
02873
02874
02875 if (src_str
02876 && GET_CODE (len_rtx) == CONST_INT
02877 && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
02878 && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
02879 (void *) src_str, dest_align))
02880 {
02881 dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
02882 builtin_memcpy_read_str,
02883 (void *) src_str, dest_align, 0);
02884 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02885 dest_mem = convert_memory_address (ptr_mode, dest_mem);
02886 return dest_mem;
02887 }
02888
02889 src_mem = get_memory_rtx (src, len);
02890 set_mem_align (src_mem, src_align);
02891
02892
02893 dest_addr = emit_block_move (dest_mem, src_mem, len_rtx,
02894 CALL_EXPR_TAILCALL (exp)
02895 ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL);
02896
02897 if (dest_addr == 0)
02898 {
02899 dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02900 dest_addr = convert_memory_address (ptr_mode, dest_addr);
02901 }
02902 return dest_addr;
02903 }
02904 }
02905
02906
02907
02908
02909
02910
02911
02912
02913
02914 static rtx
02915 expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode mode,
02916 int endp)
02917 {
02918 if (!validate_arglist (arglist,
02919 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02920 return 0;
02921
02922 else if (target == const0_rtx)
02923 {
02924 tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
02925
02926 if (!fn)
02927 return 0;
02928
02929 return expand_expr (build_function_call_expr (fn, arglist),
02930 target, mode, EXPAND_NORMAL);
02931 }
02932 else
02933 {
02934 tree dest = TREE_VALUE (arglist);
02935 tree src = TREE_VALUE (TREE_CHAIN (arglist));
02936 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02937 const char *src_str;
02938 unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
02939 unsigned int dest_align
02940 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
02941 rtx dest_mem, src_mem, len_rtx;
02942 tree result = fold_builtin_memory_op (arglist, type, false, endp);
02943
02944 if (result)
02945 {
02946 while (TREE_CODE (result) == COMPOUND_EXPR)
02947 {
02948 expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
02949 EXPAND_NORMAL);
02950 result = TREE_OPERAND (result, 1);
02951 }
02952 return expand_expr (result, target, mode, EXPAND_NORMAL);
02953 }
02954
02955
02956
02957 if (dest_align == 0 || src_align == 0)
02958 return 0;
02959
02960
02961 if (! host_integerp (len, 1))
02962 return 0;
02963
02964 len_rtx = expand_normal (len);
02965 src_str = c_getstr (src);
02966
02967
02968
02969
02970 if (src_str
02971 && GET_CODE (len_rtx) == CONST_INT
02972 && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
02973 && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
02974 (void *) src_str, dest_align))
02975 {
02976 dest_mem = get_memory_rtx (dest, len);
02977 set_mem_align (dest_mem, dest_align);
02978 dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
02979 builtin_memcpy_read_str,
02980 (void *) src_str, dest_align, endp);
02981 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02982 dest_mem = convert_memory_address (ptr_mode, dest_mem);
02983 return dest_mem;
02984 }
02985
02986 if (GET_CODE (len_rtx) == CONST_INT
02987 && can_move_by_pieces (INTVAL (len_rtx),
02988 MIN (dest_align, src_align)))
02989 {
02990 dest_mem = get_memory_rtx (dest, len);
02991 set_mem_align (dest_mem, dest_align);
02992 src_mem = get_memory_rtx (src, len);
02993 set_mem_align (src_mem, src_align);
02994 dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx),
02995 MIN (dest_align, src_align), endp);
02996 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02997 dest_mem = convert_memory_address (ptr_mode, dest_mem);
02998 return dest_mem;
02999 }
03000
03001 return 0;
03002 }
03003 }
03004
03005
03006
03007
03008 static rtx
03009 expand_builtin_memmove (tree arglist, tree type, rtx target,
03010 enum machine_mode mode, tree orig_exp)
03011 {
03012 if (!validate_arglist (arglist,
03013 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
03014 return 0;
03015 else
03016 {
03017 tree dest = TREE_VALUE (arglist);
03018 tree src = TREE_VALUE (TREE_CHAIN (arglist));
03019 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
03020
03021 unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
03022 unsigned int dest_align
03023 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
03024 tree result = fold_builtin_memory_op (arglist, type, false, 3);
03025
03026 if (result)
03027 {
03028 while (TREE_CODE (result) == COMPOUND_EXPR)
03029 {
03030 expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
03031 EXPAND_NORMAL);
03032 result = TREE_OPERAND (result, 1);
03033 }
03034 return expand_expr (result, target, mode, EXPAND_NORMAL);
03035 }
03036
03037
03038 if (dest_align == 0)
03039 return 0;
03040
03041
03042
03043 if (src_align == 0)
03044 return 0;
03045
03046
03047
03048 if (readonly_data_expr (src))
03049 {
03050 tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
03051 if (!fn)
03052 return 0;
03053 fn = build_function_call_expr (fn, arglist);
03054 if (TREE_CODE (fn) == CALL_EXPR)
03055 CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp);
03056 return expand_expr (fn, target, mode, EXPAND_NORMAL);
03057 }
03058
03059
03060
03061 if (integer_onep (len))
03062 {
03063 rtx ret = expand_builtin_mempcpy (arglist, type, target, mode,
03064 0);
03065 if (ret)
03066 return ret;
03067 }
03068
03069
03070 return 0;
03071 }
03072 }
03073
03074
03075
03076
03077 static rtx
03078 expand_builtin_bcopy (tree exp)
03079 {
03080 tree arglist = TREE_OPERAND (exp, 1);
03081 tree type = TREE_TYPE (exp);
03082 tree src, dest, size, newarglist;
03083
03084 if (!validate_arglist (arglist,
03085 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
03086 return NULL_RTX;
03087
03088 src = TREE_VALUE (arglist);
03089 dest = TREE_VALUE (TREE_CHAIN (arglist));
03090 size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
03091
03092
03093
03094
03095
03096
03097 newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size));
03098 newarglist = tree_cons (NULL_TREE, src, newarglist);
03099 newarglist = tree_cons (NULL_TREE, dest, newarglist);
03100
03101 return expand_builtin_memmove (newarglist, type, const0_rtx, VOIDmode, exp);
03102 }
03103
03104 #ifndef HAVE_movstr
03105 # define HAVE_movstr 0
03106 # define CODE_FOR_movstr CODE_FOR_nothing
03107 #endif
03108
03109
03110
03111
03112
03113
03114
03115
03116 static rtx
03117 expand_movstr (tree dest, tree src, rtx target, int endp)
03118 {
03119 rtx end;
03120 rtx dest_mem;
03121 rtx src_mem;
03122 rtx insn;
03123 const struct insn_data * data;
03124
03125 if (!HAVE_movstr)
03126 return 0;
03127
03128 dest_mem = get_memory_rtx (dest, NULL);
03129 src_mem = get_memory_rtx (src, NULL);
03130 if (!endp)
03131 {
03132 target = force_reg (Pmode, XEXP (dest_mem, 0));
03133 dest_mem = replace_equiv_address (dest_mem, target);
03134 end = gen_reg_rtx (Pmode);
03135 }
03136 else
03137 {
03138 if (target == 0 || target == const0_rtx)
03139 {
03140 end = gen_reg_rtx (Pmode);
03141 if (target == 0)
03142 target = end;
03143 }
03144 else
03145 end = target;
03146 }
03147
03148 data = insn_data + CODE_FOR_movstr;
03149
03150 if (data->operand[0].mode != VOIDmode)
03151 end = gen_lowpart (data->operand[0].mode, end);
03152
03153 insn = data->genfun (end, dest_mem, src_mem);
03154
03155 gcc_assert (insn);
03156
03157 emit_insn (insn);
03158
03159
03160
03161
03162 if (endp == 1 && target != const0_rtx)
03163 {
03164 rtx tem = plus_constant (gen_lowpart (GET_MODE (target), end), 1);
03165 emit_move_insn (target, force_operand (tem, NULL_RTX));
03166 }
03167
03168 return target;
03169 }
03170
03171
03172
03173
03174
03175
03176 static rtx
03177 expand_builtin_strcpy (tree fndecl, tree arglist, rtx target, enum machine_mode mode)
03178 {
03179 if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03180 {
03181 tree result = fold_builtin_strcpy (fndecl, arglist, 0);
03182 if (result)
03183 {
03184 while (TREE_CODE (result) == COMPOUND_EXPR)
03185 {
03186 expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
03187 EXPAND_NORMAL);
03188 result = TREE_OPERAND (result, 1);
03189 }
03190 return expand_expr (result, target, mode, EXPAND_NORMAL);
03191 }
03192
03193 return expand_movstr (TREE_VALUE (arglist),
03194 TREE_VALUE (TREE_CHAIN (arglist)),
03195 target, 0);
03196 }
03197 return 0;
03198 }
03199
03200
03201
03202
03203
03204
03205 static rtx
03206 expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode)
03207 {
03208 tree arglist = TREE_OPERAND (exp, 1);
03209
03210 if (target == const0_rtx)
03211 {
03212 tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
03213 if (!fn)
03214 return 0;
03215
03216 return expand_expr (build_function_call_expr (fn, arglist),
03217 target, mode, EXPAND_NORMAL);
03218 }
03219
03220 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03221 return 0;
03222 else
03223 {
03224 tree dst, src, len, lenp1;
03225 tree narglist;
03226 rtx ret;
03227
03228
03229
03230
03231
03232 src = TREE_VALUE (TREE_CHAIN (arglist));
03233 if (! c_getstr (src) || ! (len = c_strlen (src, 0)))
03234 return expand_movstr (TREE_VALUE (arglist),
03235 TREE_VALUE (TREE_CHAIN (arglist)),
03236 target, 2);
03237
03238 dst = TREE_VALUE (arglist);
03239 lenp1 = size_binop (PLUS_EXPR, len, ssize_int (1));
03240 narglist = build_tree_list (NULL_TREE, lenp1);
03241 narglist = tree_cons (NULL_TREE, src, narglist);
03242 narglist = tree_cons (NULL_TREE, dst, narglist);
03243 ret = expand_builtin_mempcpy (narglist, TREE_TYPE (exp),
03244 target, mode, 2);
03245
03246 if (ret)
03247 return ret;
03248
03249 if (TREE_CODE (len) == INTEGER_CST)
03250 {
03251 rtx len_rtx = expand_normal (len);
03252
03253 if (GET_CODE (len_rtx) == CONST_INT)
03254 {
03255 ret = expand_builtin_strcpy (get_callee_fndecl (exp),
03256 arglist, target, mode);
03257
03258 if (ret)
03259 {
03260 if (! target)
03261 {
03262 if (mode != VOIDmode)
03263 target = gen_reg_rtx (mode);
03264 else
03265 target = gen_reg_rtx (GET_MODE (ret));
03266 }
03267 if (GET_MODE (target) != GET_MODE (ret))
03268 ret = gen_lowpart (GET_MODE (target), ret);
03269
03270 ret = plus_constant (ret, INTVAL (len_rtx));
03271 ret = emit_move_insn (target, force_operand (ret, NULL_RTX));
03272 gcc_assert (ret);
03273
03274 return target;
03275 }
03276 }
03277 }
03278
03279 return expand_movstr (TREE_VALUE (arglist),
03280 TREE_VALUE (TREE_CHAIN (arglist)),
03281 target, 2);
03282 }
03283 }
03284
03285
03286
03287
03288
03289 static rtx
03290 builtin_strncpy_read_str (void *data, HOST_WIDE_INT offset,
03291 enum machine_mode mode)
03292 {
03293 const char *str = (const char *) data;
03294
03295 if ((unsigned HOST_WIDE_INT) offset > strlen (str))
03296 return const0_rtx;
03297
03298 return c_readstr (str + offset, mode);
03299 }
03300
03301
03302
03303
03304 static rtx
03305 expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode)
03306 {
03307 tree fndecl = get_callee_fndecl (exp);
03308 tree arglist = TREE_OPERAND (exp, 1);
03309 if (validate_arglist (arglist,
03310 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
03311 {
03312 tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)), 1);
03313 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
03314 tree result = fold_builtin_strncpy (fndecl, arglist, slen);
03315
03316 if (result)
03317 {
03318 while (TREE_CODE (result) == COMPOUND_EXPR)
03319 {
03320 expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
03321 EXPAND_NORMAL);
03322 result = TREE_OPERAND (result, 1);
03323 }
03324 return expand_expr (result, target, mode, EXPAND_NORMAL);
03325 }
03326
03327
03328 if (!host_integerp (len, 1) || !slen || !host_integerp (slen, 1))
03329 return 0;
03330
03331 slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
03332
03333
03334
03335
03336 if (tree_int_cst_lt (slen, len))
03337 {
03338 tree dest = TREE_VALUE (arglist);
03339 unsigned int dest_align
03340 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
03341 const char *p = c_getstr (TREE_VALUE (TREE_CHAIN (arglist)));
03342 rtx dest_mem;
03343
03344 if (!p || dest_align == 0 || !host_integerp (len, 1)
03345 || !can_store_by_pieces (tree_low_cst (len, 1),
03346 builtin_strncpy_read_str,
03347 (void *) p, dest_align))
03348 return 0;
03349
03350 dest_mem = get_memory_rtx (dest, len);
03351 store_by_pieces (dest_mem, tree_low_cst (len, 1),
03352 builtin_strncpy_read_str,
03353 (void *) p, dest_align, 0);
03354 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
03355 dest_mem = convert_memory_address (ptr_mode, dest_mem);
03356 return dest_mem;
03357 }
03358 }
03359 return 0;
03360 }
03361
03362
03363
03364
03365
03366 static rtx
03367 builtin_memset_read_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
03368 enum machine_mode mode)
03369 {
03370 const char *c = (const char *) data;
03371 char *p = alloca (GET_MODE_SIZE (mode));
03372
03373 memset (p, *c, GET_MODE_SIZE (mode));
03374
03375 return c_readstr (p, mode);
03376 }
03377
03378
03379
03380
03381
03382
03383 static rtx
03384 builtin_memset_gen_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
03385 enum machine_mode mode)
03386 {
03387 rtx target, coeff;
03388 size_t size;
03389 char *p;
03390
03391 size = GET_MODE_SIZE (mode);
03392 if (size == 1)
03393 return (rtx) data;
03394
03395 p = alloca (size);
03396 memset (p, 1, size);
03397 coeff = c_readstr (p, mode);
03398
03399 target = convert_to_mode (mode, (rtx) data, 1);
03400 target = expand_mult (mode, target, coeff, NULL_RTX, 1);
03401 return force_reg (mode, target);
03402 }
03403
03404
03405
03406
03407
03408
03409 static rtx
03410 expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode,
03411 tree orig_exp)
03412 {
03413 if (!validate_arglist (arglist,
03414 POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
03415 return 0;
03416 else
03417 {
03418 tree dest = TREE_VALUE (arglist);
03419 tree val = TREE_VALUE (TREE_CHAIN (arglist));
03420 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
03421 tree fndecl, fn;
03422 enum built_in_function fcode;
03423 char c;
03424 unsigned int dest_align;
03425 rtx dest_mem, dest_addr, len_rtx;
03426
03427 dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
03428
03429
03430
03431 if (dest_align == 0)
03432 return 0;
03433
03434
03435 if (integer_zerop (len))
03436 {
03437
03438 expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL);
03439 return expand_expr (dest, target, mode, EXPAND_NORMAL);
03440 }
03441
03442
03443 dest = builtin_save_expr (dest);
03444 val = builtin_save_expr (val);
03445 len = builtin_save_expr (len);
03446
03447 len_rtx = expand_normal (len);
03448 dest_mem = get_memory_rtx (dest, len);
03449
03450 if (TREE_CODE (val) != INTEGER_CST)
03451 {
03452 rtx val_rtx;
03453
03454 val_rtx = expand_normal (val);
03455 val_rtx = convert_to_mode (TYPE_MODE (unsigned_char_type_node),
03456 val_rtx, 0);
03457
03458
03459
03460
03461 c = 1;
03462 if (host_integerp (len, 1)
03463 && !(optimize_size && tree_low_cst (len, 1) > 1)
03464 && can_store_by_pieces (tree_low_cst (len, 1),
03465 builtin_memset_read_str, &c, dest_align))
03466 {
03467 val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
03468 val_rtx);
03469 store_by_pieces (dest_mem, tree_low_cst (len, 1),
03470 builtin_memset_gen_str, val_rtx, dest_align, 0);
03471 }
03472 else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx,
03473 dest_align))
03474 goto do_libcall;
03475
03476 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
03477 dest_mem = convert_memory_address (ptr_mode, dest_mem);
03478 return dest_mem;
03479 }
03480
03481 if (target_char_cast (val, &c))
03482 goto do_libcall;
03483
03484 if (c)
03485 {
03486 if (host_integerp (len, 1)
03487 && !(optimize_size && tree_low_cst (len, 1) > 1)
03488 && can_store_by_pieces (tree_low_cst (len, 1),
03489 builtin_memset_read_str, &c, dest_align))
03490 store_by_pieces (dest_mem, tree_low_cst (len, 1),
03491 builtin_memset_read_str, &c, dest_align, 0);
03492 else if (!set_storage_via_setmem (dest_mem, len_rtx, GEN_INT (c),
03493 dest_align))
03494 goto do_libcall;
03495
03496 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
03497 dest_mem = convert_memory_address (ptr_mode, dest_mem);
03498 return dest_mem;
03499 }
03500
03501 set_mem_align (dest_mem, dest_align);
03502 dest_addr = clear_storage (dest_mem, len_rtx,
03503 CALL_EXPR_TAILCALL (orig_exp)
03504 ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL);
03505
03506 if (dest_addr == 0)
03507 {
03508 dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
03509 dest_addr = convert_memory_address (ptr_mode, dest_addr);
03510 }
03511
03512 return dest_addr;
03513
03514 do_libcall:
03515 fndecl = get_callee_fndecl (orig_exp);
03516 fcode = DECL_FUNCTION_CODE (fndecl);
03517 gcc_assert (fcode == BUILT_IN_MEMSET || fcode == BUILT_IN_BZERO);
03518 arglist = build_tree_list (NULL_TREE, len);
03519 if (fcode == BUILT_IN_MEMSET)
03520 arglist = tree_cons (NULL_TREE, val, arglist);
03521 arglist = tree_cons (NULL_TREE, dest, arglist);
03522 fn = build_function_call_expr (fndecl, arglist);
03523 if (TREE_CODE (fn) == CALL_EXPR)
03524 CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp);
03525 return expand_call (fn, target, target == const0_rtx);
03526 }
03527 }
03528
03529
03530
03531
03532 static rtx
03533 expand_builtin_bzero (tree exp)
03534 {
03535 tree arglist = TREE_OPERAND (exp, 1);
03536 tree dest, size, newarglist;
03537
03538 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
03539 return NULL_RTX;
03540
03541 dest = TREE_VALUE (arglist);
03542 size = TREE_VALUE (TREE_CHAIN (arglist));
03543
03544
03545
03546
03547
03548
03549 newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size));
03550 newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
03551 newarglist = tree_cons (NULL_TREE, dest, newarglist);
03552
03553 return expand_builtin_memset (newarglist, const0_rtx, VOIDmode, exp);
03554 }
03555
03556
03557
03558
03559
03560
03561 static rtx
03562 expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target,
03563 enum machine_mode mode)
03564 {
03565 if (!validate_arglist (arglist,
03566 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
03567 return 0;
03568 else
03569 {
03570 tree result = fold_builtin_memcmp (arglist);
03571 if (result)
03572 return expand_expr (result, target, mode, EXPAND_NORMAL);
03573 }
03574
03575 #if defined HAVE_cmpmemsi || defined HAVE_cmpstrnsi
03576 {
03577 tree arg1 = TREE_VALUE (arglist);
03578 tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
03579 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
03580 rtx arg1_rtx, arg2_rtx, arg3_rtx;
03581 rtx result;
03582 rtx insn;
03583
03584 int arg1_align
03585 = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03586 int arg2_align
03587 = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03588 enum machine_mode insn_mode;
03589
03590 #ifdef HAVE_cmpmemsi
03591 if (HAVE_cmpmemsi)
03592 insn_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode;
03593 else
03594 #endif
03595 #ifdef HAVE_cmpstrnsi
03596 if (HAVE_cmpstrnsi)
03597 insn_mode = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
03598 else
03599 #endif
03600 return 0;
03601
03602
03603 if (arg1_align == 0 || arg2_align == 0)
03604 return 0;
03605
03606
03607 result = target;
03608 if (! (result != 0
03609 && REG_P (result) && GET_MODE (result) == insn_mode
03610 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
03611 result = gen_reg_rtx (insn_mode);
03612
03613 arg1_rtx = get_memory_rtx (arg1, len);
03614 arg2_rtx = get_memory_rtx (arg2, len);
03615 arg3_rtx = expand_normal (len);
03616
03617
03618 if (GET_CODE (arg3_rtx) == CONST_INT)
03619 {
03620 set_mem_size (arg1_rtx, arg3_rtx);
03621 set_mem_size (arg2_rtx, arg3_rtx);
03622 }
03623
03624 #ifdef HAVE_cmpmemsi
03625 if (HAVE_cmpmemsi)
03626 insn = gen_cmpmemsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
03627 GEN_INT (MIN (arg1_align, arg2_align)));
03628 else
03629 #endif
03630 #ifdef HAVE_cmpstrnsi
03631 if (HAVE_cmpstrnsi)
03632 insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
03633 GEN_INT (MIN (arg1_align, arg2_align)));
03634 else
03635 #endif
03636 gcc_unreachable ();
03637
03638 if (insn)
03639 emit_insn (insn);
03640 else
03641 emit_library_call_value (memcmp_libfunc, result, LCT_PURE_MAKE_BLOCK,
03642 TYPE_MODE (integer_type_node), 3,
03643 XEXP (arg1_rtx, 0), Pmode,
03644 XEXP (arg2_rtx, 0), Pmode,
03645 convert_to_mode (TYPE_MODE (sizetype), arg3_rtx,
03646 TYPE_UNSIGNED (sizetype)),
03647 TYPE_MODE (sizetype));
03648
03649
03650 mode = TYPE_MODE (TREE_TYPE (exp));
03651 if (GET_MODE (result) == mode)
03652 return result;
03653 else if (target != 0)
03654 {
03655 convert_move (target, result, 0);
03656 return target;
03657 }
03658 else
03659 return convert_to_mode (mode, result, 0);
03660 }
03661 #endif
03662
03663 return 0;
03664 }
03665
03666
03667
03668
03669
03670 static rtx
03671 expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
03672 {
03673 tree arglist = TREE_OPERAND (exp, 1);
03674
03675 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03676 return 0;
03677 else
03678 {
03679 tree result = fold_builtin_strcmp (arglist);
03680 if (result)
03681 return expand_expr (result, target, mode, EXPAND_NORMAL);
03682 }
03683
03684 #if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi
03685 if (cmpstr_optab[SImode] != CODE_FOR_nothing
03686 || cmpstrn_optab[SImode] != CODE_FOR_nothing)
03687 {
03688 rtx arg1_rtx, arg2_rtx;
03689 rtx result, insn = NULL_RTX;
03690 tree fndecl, fn;
03691
03692 tree arg1 = TREE_VALUE (arglist);
03693 tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
03694 int arg1_align
03695 = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03696 int arg2_align
03697 = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03698
03699
03700 if (arg1_align == 0 || arg2_align == 0)
03701 return 0;
03702
03703
03704 arg1 = builtin_save_expr (arg1);
03705 arg2 = builtin_save_expr (arg2);
03706
03707 arg1_rtx = get_memory_rtx (arg1, NULL);
03708 arg2_rtx = get_memory_rtx (arg2, NULL);
03709
03710 #ifdef HAVE_cmpstrsi
03711
03712 if (HAVE_cmpstrsi)
03713 {
03714 enum machine_mode insn_mode
03715 = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
03716
03717
03718 result = target;
03719 if (! (result != 0
03720 && REG_P (result) && GET_MODE (result) == insn_mode
03721 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
03722 result = gen_reg_rtx (insn_mode);
03723
03724 insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx,
03725 GEN_INT (MIN (arg1_align, arg2_align)));
03726 }
03727 #endif
03728 #ifdef HAVE_cmpstrnsi
03729
03730 if (!insn && HAVE_cmpstrnsi)
03731 {
03732 tree len;
03733 rtx arg3_rtx;
03734
03735 enum machine_mode insn_mode
03736 = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
03737 tree len1 = c_strlen (arg1, 1);
03738 tree len2 = c_strlen (arg2, 1);
03739
03740 if (len1)
03741 len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
03742 if (len2)
03743 len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
03744
03745
03746
03747
03748
03749
03750
03751
03752 if (!len1)
03753 len = len2;
03754 else if (!len2)
03755 len = len1;
03756 else if (TREE_SIDE_EFFECTS (len1))
03757 len = len2;
03758 else if (TREE_SIDE_EFFECTS (len2))
03759 len = len1;
03760 else if (TREE_CODE (len1) != INTEGER_CST)
03761 len = len2;
03762 else if (TREE_CODE (len2) != INTEGER_CST)
03763 len = len1;
03764 else if (tree_int_cst_lt (len1, len2))
03765 len = len1;
03766 else
03767 len = len2;
03768
03769
03770 if (!len || TREE_SIDE_EFFECTS (len))
03771 goto do_libcall;
03772
03773 arg3_rtx = expand_normal (len);
03774
03775
03776 result = target;
03777 if (! (result != 0
03778 && REG_P (result) && GET_MODE (result) == insn_mode
03779 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
03780 result = gen_reg_rtx (insn_mode);
03781
03782 insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
03783 GEN_INT (MIN (arg1_align, arg2_align)));
03784 }
03785 #endif
03786
03787 if (insn)
03788 {
03789 emit_insn (insn);
03790
03791
03792 mode = TYPE_MODE (TREE_TYPE (exp));
03793 if (GET_MODE (result) == mode)
03794 return result;
03795 if (target == 0)
03796 return convert_to_mode (mode, result, 0);
03797 convert_move (target, result, 0);
03798 return target;
03799 }
03800
03801
03802
03803 #ifdef HAVE_cmpstrnsi
03804 do_libcall:
03805 #endif
03806 arglist = build_tree_list (NULL_TREE, arg2);
03807 arglist = tree_cons (NULL_TREE, arg1, arglist);
03808 fndecl = get_callee_fndecl (exp);
03809 fn = build_function_call_expr (fndecl, arglist);
03810 if (TREE_CODE (fn) == CALL_EXPR)
03811 CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
03812 return expand_call (fn, target, target == const0_rtx);
03813 }
03814 #endif
03815 return 0;
03816 }
03817
03818
03819
03820
03821
03822 static rtx
03823 expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
03824 {
03825 tree arglist = TREE_OPERAND (exp, 1);
03826
03827 if (!validate_arglist (arglist,
03828 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
03829 return 0;
03830 else
03831 {
03832 tree result = fold_builtin_strncmp (arglist);
03833 if (result)
03834 return expand_expr (result, target, mode, EXPAND_NORMAL);
03835 }
03836
03837
03838
03839
03840 #ifdef HAVE_cmpstrnsi
03841 if (HAVE_cmpstrnsi)
03842 {
03843 tree arg1 = TREE_VALUE (arglist);
03844 tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
03845 tree arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
03846 tree len, len1, len2;
03847 rtx arg1_rtx, arg2_rtx, arg3_rtx;
03848 rtx result, insn;
03849 tree fndecl, fn;
03850
03851 int arg1_align
03852 = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03853 int arg2_align
03854 = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03855 enum machine_mode insn_mode
03856 = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
03857
03858 len1 = c_strlen (arg1, 1);
03859 len2 = c_strlen (arg2, 1);
03860
03861 if (len1)
03862 len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
03863 if (len2)
03864 len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
03865
03866
03867
03868
03869
03870
03871
03872
03873 if (!len1)
03874 len = len2;
03875 else if (!len2)
03876 len = len1;
03877 else if (TREE_SIDE_EFFECTS (len1))
03878 len = len2;
03879 else if (TREE_SIDE_EFFECTS (len2))
03880 len = len1;
03881 else if (TREE_CODE (len1) != INTEGER_CST)
03882 len = len2;
03883 else if (TREE_CODE (len2) != INTEGER_CST)
03884 len = len1;
03885 else if (tree_int_cst_lt (len1, len2))
03886 len = len1;
03887 else
03888 len = len2;
03889
03890
03891 if (!len || TREE_SIDE_EFFECTS (len))
03892 return 0;
03893
03894
03895 len = fold_build2 (MIN_EXPR, TREE_TYPE (len), len,
03896 fold_convert (TREE_TYPE (len), arg3));
03897
03898
03899 if (arg1_align == 0 || arg2_align == 0)
03900 return 0;
03901
03902
03903 result = target;
03904 if (! (result != 0
03905 && REG_P (result) && GET_MODE (result) == insn_mode
03906 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
03907 result = gen_reg_rtx (insn_mode);
03908
03909
03910 arg1 = builtin_save_expr (arg1);
03911 arg2 = builtin_save_expr (arg2);
03912 len = builtin_save_expr (len);
03913
03914 arg1_rtx = get_memory_rtx (arg1, len);
03915 arg2_rtx = get_memory_rtx (arg2, len);
03916 arg3_rtx = expand_normal (len);
03917 insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
03918 GEN_INT (MIN (arg1_align, arg2_align)));
03919 if (insn)
03920 {
03921 emit_insn (insn);
03922
03923
03924 mode = TYPE_MODE (TREE_TYPE (exp));
03925 if (GET_MODE (result) == mode)
03926 return result;
03927 if (target == 0)
03928 return convert_to_mode (mode, result, 0);
03929 convert_move (target, result, 0);
03930 return target;
03931 }
03932
03933
03934
03935 arglist = build_tree_list (NULL_TREE, len);
03936 arglist = tree_cons (NULL_TREE, arg2, arglist);
03937 arglist = tree_cons (NULL_TREE, arg1, arglist);
03938 fndecl = get_callee_fndecl (exp);
03939 fn = build_function_call_expr (fndecl, arglist);
03940 if (TREE_CODE (fn) == CALL_EXPR)
03941 CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
03942 return expand_call (fn, target, target == const0_rtx);
03943 }
03944 #endif
03945 return 0;
03946 }
03947
03948
03949
03950
03951
03952 static rtx
03953 expand_builtin_strcat (tree fndecl, tree arglist, rtx target, enum machine_mode mode)
03954 {
03955 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03956 return 0;
03957 else
03958 {
03959 tree dst = TREE_VALUE (arglist),
03960 src = TREE_VALUE (TREE_CHAIN (arglist));
03961 const char *p = c_getstr (src);
03962
03963
03964 if (p && *p == '\0')
03965 return expand_expr (dst, target, mode, EXPAND_NORMAL);
03966
03967 if (!optimize_size)
03968 {
03969
03970 tree newsrc, newdst,
03971 strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
03972 rtx insns;
03973
03974
03975 newsrc = builtin_save_expr (src);
03976 if (newsrc != src)
03977 arglist = build_tree_list (NULL_TREE, newsrc);
03978 else
03979 arglist = TREE_CHAIN (arglist);
03980
03981 dst = builtin_save_expr (dst);
03982
03983 start_sequence ();
03984
03985
03986 newdst =
03987 build_function_call_expr (strlen_fn,
03988 build_tree_list (NULL_TREE, dst));
03989
03990 newdst = fold_convert (TREE_TYPE (dst), newdst);
03991 newdst = fold_build2 (PLUS_EXPR, TREE_TYPE (dst), dst, newdst);
03992
03993 newdst = builtin_save_expr (newdst);
03994 arglist = tree_cons (NULL_TREE, newdst, arglist);
03995
03996 if (!expand_builtin_strcpy (fndecl, arglist, target, mode))
03997 {
03998 end_sequence ();
03999 return 0;
04000 }
04001
04002
04003 insns = get_insns ();
04004 end_sequence ();
04005 emit_insn (insns);
04006
04007 return expand_expr (dst, target, mode, EXPAND_NORMAL);
04008 }
04009
04010 return 0;
04011 }
04012 }
04013
04014
04015
04016
04017
04018 static rtx
04019 expand_builtin_strncat (tree arglist, rtx target, enum machine_mode mode)
04020 {
04021 if (validate_arglist (arglist,
04022 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
04023 {
04024 tree result = fold_builtin_strncat (arglist);
04025 if (result)
04026 return expand_expr (result, target, mode, EXPAND_NORMAL);
04027 }
04028 return 0;
04029 }
04030
04031
04032
04033
04034
04035 static rtx
04036 expand_builtin_strspn (tree arglist, rtx target, enum machine_mode mode)
04037 {
04038 if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
04039 {
04040 tree result = fold_builtin_strspn (arglist);
04041 if (result)
04042 return expand_expr (result, target, mode, EXPAND_NORMAL);
04043 }
04044 return 0;
04045 }
04046
04047
04048
04049
04050
04051 static rtx
04052 expand_builtin_strcspn (tree arglist, rtx target, enum machine_mode mode)
04053 {
04054 if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
04055 {
04056 tree result = fold_builtin_strcspn (arglist);
04057 if (result)
04058 return expand_expr (result, target, mode, EXPAND_NORMAL);
04059 }
04060 return 0;
04061 }
04062
04063
04064
04065
04066 rtx
04067 expand_builtin_saveregs (void)
04068 {
04069 rtx val, seq;
04070
04071
04072
04073 if (saveregs_value != 0)
04074 return saveregs_value;
04075
04076
04077
04078
04079
04080 start_sequence ();
04081
04082
04083 val = targetm.calls.expand_builtin_saveregs ();
04084
04085 seq = get_insns ();
04086 end_sequence ();
04087
04088 saveregs_value = val;
04089
04090
04091
04092
04093 push_topmost_sequence ();
04094 emit_insn_after (seq, entry_of_function ());
04095 pop_topmost_sequence ();
04096
04097 return val;
04098 }
04099
04100
04101
04102
04103
04104 static rtx
04105 expand_builtin_args_info (tree arglist)
04106 {
04107 int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
04108 int *word_ptr = (int *) ¤t_function_args_info;
04109
04110 gcc_assert (sizeof (CUMULATIVE_ARGS) % sizeof (int) == 0);
04111
04112 if (arglist != 0)
04113 {
04114 if (!host_integerp (TREE_VALUE (arglist), 0))
04115 error ("argument of %<__builtin_args_info%> must be constant");
04116 else
04117 {
04118 HOST_WIDE_INT wordnum = tree_low_cst (TREE_VALUE (arglist), 0);
04119
04120 if (wordnum < 0 || wordnum >= nwords)
04121 error ("argument of %<__builtin_args_info%> out of range");
04122 else
04123 return GEN_INT (word_ptr[wordnum]);
04124 }
04125 }
04126 else
04127 error ("missing argument in %<__builtin_args_info%>");
04128
04129 return const0_rtx;
04130 }
04131
04132
04133
04134 static rtx
04135 expand_builtin_next_arg (void)
04136 {
04137
04138
04139 return expand_binop (Pmode, add_optab,
04140 current_function_internal_arg_pointer,
04141 current_function_arg_offset_rtx,
04142 NULL_RTX, 0, OPTAB_LIB_WIDEN);
04143 }
04144
04145
04146
04147
04148 static tree
04149 stabilize_va_list (tree valist, int needs_lvalue)
04150 {
04151 if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
04152 {
04153 if (TREE_SIDE_EFFECTS (valist))
04154 valist = save_expr (valist);
04155
04156
04157
04158
04159
04160 if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
04161 {
04162 tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
04163 valist = build_fold_addr_expr_with_type (valist, p1);
04164 }
04165 }
04166 else
04167 {
04168 tree pt;
04169
04170 if (! needs_lvalue)
04171 {
04172 if (! TREE_SIDE_EFFECTS (valist))
04173 return valist;
04174
04175 pt = build_pointer_type (va_list_type_node);
04176 valist = fold_build1 (ADDR_EXPR, pt, valist);
04177 TREE_SIDE_EFFECTS (valist) = 1;
04178 }
04179
04180 if (TREE_SIDE_EFFECTS (valist))
04181 valist = save_expr (valist);
04182 valist = build_fold_indirect_ref (valist);
04183 }
04184
04185 return valist;
04186 }
04187
04188
04189
04190 tree
04191 std_build_builtin_va_list (void)
04192 {
04193 return ptr_type_node;
04194 }
04195
04196
04197
04198
04199 void
04200 std_expand_builtin_va_start (tree valist, rtx nextarg)
04201 {
04202 tree t;
04203
04204 t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
04205 make_tree (ptr_type_node, nextarg));
04206 TREE_SIDE_EFFECTS (t) = 1;
04207
04208 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
04209 }
04210
04211
04212
04213 static rtx
04214 expand_builtin_va_start (tree arglist)
04215 {
04216 rtx nextarg;
04217 tree chain, valist;
04218
04219 chain = TREE_CHAIN (arglist);
04220
04221 if (!chain)
04222 {
04223 error ("too few arguments to function %<va_start%>");
04224 return const0_rtx;
04225 }
04226
04227 if (fold_builtin_next_arg (chain))
04228 return const0_rtx;
04229
04230 nextarg = expand_builtin_next_arg ();
04231 valist = stabilize_va_list (TREE_VALUE (arglist), 1);
04232
04233 #ifdef EXPAND_BUILTIN_VA_START
04234 EXPAND_BUILTIN_VA_START (valist, nextarg);
04235 #else
04236 std_expand_builtin_va_start (valist, nextarg);
04237 #endif
04238
04239 return const0_rtx;
04240 }
04241
04242
04243
04244
04245 tree
04246 std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
04247 {
04248 tree addr, t, type_size, rounded_size, valist_tmp;
04249 unsigned HOST_WIDE_INT align, boundary;
04250 bool indirect;
04251
04252 #ifdef ARGS_GROW_DOWNWARD
04253
04254
04255
04256 gcc_unreachable ();
04257 #endif
04258
04259 indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);
04260 if (indirect)
04261 type = build_pointer_type (type);
04262
04263 align = PARM_BOUNDARY / BITS_PER_UNIT;
04264 boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type) / BITS_PER_UNIT;
04265
04266
04267 valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
04268
04269
04270
04271 if (boundary > align
04272 && !integer_zerop (TYPE_SIZE (type)))
04273 {
04274 t = fold_convert (TREE_TYPE (valist), size_int (boundary - 1));
04275 t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
04276 build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t));
04277 gimplify_and_add (t, pre_p);
04278
04279 t = fold_convert (TREE_TYPE (valist), size_int (-boundary));
04280 t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
04281 build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist_tmp, t));
04282 gimplify_and_add (t, pre_p);
04283 }
04284 else
04285 boundary = align;
04286
04287
04288
04289
04290 boundary *= BITS_PER_UNIT;
04291 if (boundary < TYPE_ALIGN (type))
04292 {
04293 type = build_variant_type_copy (type);
04294 TYPE_ALIGN (type) = boundary;
04295 }
04296
04297
04298 type_size = size_in_bytes (type);
04299 rounded_size = round_up (type_size, align);
04300
04301
04302 gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
04303
04304
04305 addr = valist_tmp;
04306 if (PAD_VARARGS_DOWN && !integer_zerop (rounded_size))
04307 {
04308
04309 t = fold_build2 (GT_EXPR, sizetype, rounded_size, size_int (align));
04310 t = fold_build3 (COND_EXPR, sizetype, t, size_zero_node,
04311 size_binop (MINUS_EXPR, rounded_size, type_size));
04312 t = fold_convert (TREE_TYPE (addr), t);
04313 addr = fold_build2 (PLUS_EXPR, TREE_TYPE (addr), addr, t);
04314 }
04315
04316
04317 t = fold_convert (TREE_TYPE (valist), rounded_size);
04318 t = build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t);
04319 t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
04320 gimplify_and_add (t, pre_p);
04321
04322 addr = fold_convert (build_pointer_type (type), addr);
04323
04324 if (indirect)
04325 addr = build_va_arg_indirect_ref (addr);
04326
04327 return build_va_arg_indirect_ref (addr);
04328 }
04329
04330
04331
04332 tree
04333 build_va_arg_indirect_ref (tree addr)
04334 {
04335 addr = build_fold_indirect_ref (addr);
04336
04337 if (flag_mudflap)
04338 mf_mark (addr);
04339
04340 return addr;
04341 }
04342
04343
04344
04345
04346 static tree
04347 dummy_object (tree type)
04348 {
04349 tree t = build_int_cst (build_pointer_type (type), 0);
04350 return build1 (INDIRECT_REF, type, t);
04351 }
04352
04353
04354
04355
04356 enum gimplify_status
04357 gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
04358 {
04359 tree promoted_type, want_va_type, have_va_type;
04360 tree valist = TREE_OPERAND (*expr_p, 0);
04361 tree type = TREE_TYPE (*expr_p);
04362 tree t;
04363
04364
04365 want_va_type = va_list_type_node;
04366 have_va_type = TREE_TYPE (valist);
04367
04368 if (have_va_type == error_mark_node)
04369 return GS_ERROR;
04370
04371 if (TREE_CODE (want_va_type) == ARRAY_TYPE)
04372 {
04373
04374
04375
04376
04377 if (TREE_CODE (have_va_type) == ARRAY_TYPE
04378 || POINTER_TYPE_P (have_va_type))
04379 {
04380 want_va_type = TREE_TYPE (want_va_type);
04381 have_va_type = TREE_TYPE (have_va_type);
04382 }
04383 }
04384
04385 if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type))
04386 {
04387 error ("first argument to %<va_arg%> not of type %<va_list%>");
04388 return GS_ERROR;
04389 }
04390
04391
04392
04393 else if ((promoted_type = lang_hooks.types.type_promotes_to (type))
04394 != type)
04395 {
04396 static bool gave_help;
04397
04398
04399
04400
04401 warning (0, "%qT is promoted to %qT when passed through %<...%>",
04402 type, promoted_type);
04403 if (! gave_help)
04404 {
04405 gave_help = true;
04406 warning (0, "(so you should pass %qT not %qT to %<va_arg%>)",
04407 promoted_type, type);
04408 }
04409
04410
04411
04412 inform ("if this code is reached, the program will abort");
04413 t = build_function_call_expr (implicit_built_in_decls[BUILT_IN_TRAP],
04414 NULL);
04415 append_to_statement_list (t, pre_p);
04416
04417
04418
04419 *expr_p = dummy_object (type);
04420 return GS_ALL_DONE;
04421 }
04422 else
04423 {
04424
04425
04426 if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
04427 {
04428
04429
04430
04431
04432 if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
04433 {
04434 tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
04435 valist = build_fold_addr_expr_with_type (valist, p1);
04436 }
04437 gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
04438 }
04439 else
04440 gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
04441
04442 if (!targetm.gimplify_va_arg_expr)
04443
04444
04445 return GS_ALL_DONE;
04446
04447 *expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p);
04448 return GS_OK;
04449 }
04450 }
04451
04452
04453
04454 static rtx
04455 expand_builtin_va_end (tree arglist)
04456 {
04457 tree valist = TREE_VALUE (arglist);
04458
04459
04460
04461 if (TREE_SIDE_EFFECTS (valist))
04462 expand_expr (valist, const0_rtx, VOIDmode, EXPAND_NORMAL);
04463
04464 return const0_rtx;
04465 }
04466
04467
04468
04469
04470
04471 static rtx
04472 expand_builtin_va_copy (tree arglist)
04473 {
04474 tree dst, src, t;
04475
04476 dst = TREE_VALUE (arglist);
04477 src = TREE_VALUE (TREE_CHAIN (arglist));
04478
04479 dst = stabilize_va_list (dst, 1);
04480 src = stabilize_va_list (src, 0);
04481
04482 if (TREE_CODE (va_list_type_node) != ARRAY_TYPE)
04483 {
04484 t = build2 (MODIFY_EXPR, va_list_type_node, dst, src);
04485 TREE_SIDE_EFFECTS (t) = 1;
04486 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
04487 }
04488 else
04489 {
04490 rtx dstb, srcb, size;
04491
04492
04493 dstb = expand_expr (dst, NULL_RTX, Pmode, EXPAND_NORMAL);
04494 srcb = expand_expr (src, NULL_RTX, Pmode, EXPAND_NORMAL);
04495 size = expand_expr (TYPE_SIZE_UNIT (va_list_type_node), NULL_RTX,
04496 VOIDmode, EXPAND_NORMAL);
04497
04498 dstb = convert_memory_address (Pmode, dstb);
04499 srcb = convert_memory_address (Pmode, srcb);
04500
04501
04502 dstb = gen_rtx_MEM (BLKmode, dstb);
04503 set_mem_alias_set (dstb, get_alias_set (TREE_TYPE (TREE_TYPE (dst))));
04504 set_mem_align (dstb, TYPE_ALIGN (va_list_type_node));
04505 srcb = gen_rtx_MEM (BLKmode, srcb);
04506 set_mem_alias_set (srcb, get_alias_set (TREE_TYPE (TREE_TYPE (src))));
04507 set_mem_align (srcb, TYPE_ALIGN (va_list_type_node));
04508
04509
04510 emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL);
04511 }
04512
04513 return const0_rtx;
04514 }
04515
04516
04517
04518
04519 static rtx
04520 expand_builtin_frame_address (tree fndecl, tree arglist)
04521 {
04522
04523
04524
04525 if (arglist == 0)
04526
04527 return const0_rtx;
04528 else if (! host_integerp (TREE_VALUE (arglist), 1))
04529 {
04530 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
04531 error ("invalid argument to %<__builtin_frame_address%>");
04532 else
04533 error ("invalid argument to %<__builtin_return_address%>");
04534 return const0_rtx;
04535 }
04536 else
04537 {
04538 rtx tem
04539 = expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl),
04540 tree_low_cst (TREE_VALUE (arglist), 1));
04541
04542
04543 if (tem == NULL)
04544 {
04545 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
04546 warning (0, "unsupported argument to %<__builtin_frame_address%>");
04547 else
04548 warning (0, "unsupported argument to %<__builtin_return_address%>");
04549 return const0_rtx;
04550 }
04551
04552
04553 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
04554 return tem;
04555
04556 if (!REG_P (tem)
04557 && ! CONSTANT_P (tem))
04558 tem = copy_to_mode_reg (Pmode, tem);
04559 return tem;
04560 }
04561 }
04562
04563
04564
04565
04566
04567 static rtx
04568 expand_builtin_alloca (tree arglist, rtx target)
04569 {
04570 rtx op0;
04571 rtx result;
04572
04573
04574
04575
04576 if (flag_mudflap)
04577 return 0;
04578
04579 if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
04580 return 0;
04581
04582
04583 op0 = expand_normal (TREE_VALUE (arglist));
04584
04585
04586 result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
04587 result = convert_memory_address (ptr_mode, result);
04588
04589 return result;
04590 }
04591
04592
04593
04594
04595
04596
04597 static rtx
04598 expand_builtin_unop (enum machine_mode target_mode, tree arglist, rtx target,
04599 rtx subtarget, optab op_optab)
04600 {
04601 rtx op0;
04602 if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
04603 return 0;
04604
04605
04606 op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
04607
04608
04609 target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
04610 op_optab, op0, target, 1);
04611 gcc_assert (target);
04612
04613 return convert_to_mode (target_mode, target, 0);
04614 }
04615
04616
04617
04618
04619 static rtx
04620 expand_builtin_fputs (tree arglist, rtx target, bool unlocked)
04621 {
04622
04623 if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
04624 {
04625 tree result = fold_builtin_fputs (arglist, (target == const0_rtx),
04626 unlocked, NULL_TREE);
04627 if (result)
04628 return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
04629 }
04630 return 0;
04631 }
04632
04633
04634
04635
04636
04637 static rtx
04638 expand_builtin_expect (tree arglist, rtx target)
04639 {
04640 tree exp, c;
04641 rtx note, rtx_c;
04642
04643 if (arglist == NULL_TREE
04644 || TREE_CHAIN (arglist) == NULL_TREE)
04645 return const0_rtx;
04646 exp = TREE_VALUE (arglist);
04647 c = TREE_VALUE (TREE_CHAIN (arglist));
04648
04649 if (TREE_CODE (c) != INTEGER_CST)
04650 {
04651 error ("second argument to %<__builtin_expect%> must be a constant");
04652 c = integer_zero_node;
04653 }
04654
04655 target = expand_expr (exp, target, VOIDmode, EXPAND_NORMAL);
04656
04657
04658 if (flag_guess_branch_prob && GET_CODE (target) != CONST_INT)
04659 {
04660
04661
04662
04663 target = force_reg (GET_MODE (target), target);
04664
04665 rtx_c = expand_expr (c, NULL_RTX, GET_MODE (target), EXPAND_NORMAL);
04666
04667 note = emit_note (NOTE_INSN_EXPECTED_VALUE);
04668 NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, target, rtx_c);
04669 }
04670
04671 return target;
04672 }
04673
04674
04675
04676
04677
04678
04679
04680
04681 rtx
04682 expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label)
04683 {
04684 tree arglist = TREE_OPERAND (exp, 1);
04685 tree arg0 = TREE_VALUE (arglist);
04686 tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
04687 rtx ret = NULL_RTX;
04688
04689
04690
04691 if (TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE
04692 && (integer_zerop (arg1) || integer_onep (arg1)))
04693 {
04694 rtx insn, drop_through_label, temp;
04695
04696
04697 start_sequence ();
04698 do_jump (arg0, if_false_label, if_true_label);
04699 ret = get_insns ();
04700
04701 drop_through_label = get_last_insn ();
04702 if (drop_through_label && NOTE_P (drop_through_label))
04703 drop_through_label = prev_nonnote_insn (drop_through_label);
04704 if (drop_through_label && !LABEL_P (drop_through_label))
04705 drop_through_label = NULL_RTX;
04706 end_sequence ();
04707
04708 if (! if_true_label)
04709 if_true_label = drop_through_label;
04710 if (! if_false_label)
04711 if_false_label = drop_through_label;
04712
04713
04714 insn = ret;
04715 while (insn != NULL_RTX)
04716 {
04717 rtx next = NEXT_INSN (insn);
04718
04719 if (JUMP_P (insn) && any_condjump_p (insn))
04720 {
04721 rtx ifelse = SET_SRC (pc_set (insn));
04722 rtx then_dest = XEXP (ifelse, 1);
04723 rtx else_dest = XEXP (ifelse, 2);
04724 int taken = -1;
04725
04726
04727 if (GET_CODE (then_dest) == LABEL_REF
04728 && XEXP (then_dest, 0) == if_true_label)
04729 taken = 1;
04730 else if (GET_CODE (then_dest) == LABEL_REF
04731 && XEXP (then_dest, 0) == if_false_label)
04732 taken = 0;
04733 else if (GET_CODE (else_dest) == LABEL_REF
04734 && XEXP (else_dest, 0) == if_false_label)
04735 taken = 1;
04736 else if (GET_CODE (else_dest) == LABEL_REF
04737 && XEXP (else_dest, 0) == if_true_label)
04738 taken = 0;
04739
04740 else if (else_dest == pc_rtx)
04741 {
04742 if (next && NOTE_P (next))
04743 next = next_nonnote_insn (next);
04744
04745 if (next && JUMP_P (next)
04746 && any_uncondjump_p (next))
04747 temp = XEXP (SET_SRC (pc_set (next)), 0);
04748 else
04749 temp = next;
04750
04751
04752
04753 if (temp == if_false_label)
04754 taken = 1;
04755 else if (temp == if_true_label)
04756 taken = 0;
04757 }
04758 else if (then_dest == pc_rtx)
04759 {
04760 if (next && NOTE_P (next))
04761 next = next_nonnote_insn (next);
04762
04763 if (next && JUMP_P (next)
04764 && any_uncondjump_p (next))
04765 temp = XEXP (SET_SRC (pc_set (next)), 0);
04766 else
04767 temp = next;
04768
04769 if (temp == if_false_label)
04770 taken = 0;
04771 else if (temp == if_true_label)
04772 taken = 1;
04773 }
04774
04775 if (taken != -1)
04776 {
04777
04778
04779 if (integer_zerop (arg1))
04780 taken = 1 - taken;
04781 predict_insn_def (insn, PRED_BUILTIN_EXPECT, taken);
04782 }
04783 }
04784
04785 insn = next;
04786 }
04787 }
04788
04789 return ret;
04790 }
04791
04792 void
04793 expand_builtin_trap (void)
04794 {
04795 #ifdef HAVE_trap
04796 if (HAVE_trap)
04797 emit_insn (gen_trap ());
04798 else
04799 #endif
04800 emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
04801 emit_barrier ();
04802 }
04803
04804
04805
04806
04807
04808
04809
04810 static rtx
04811 expand_builtin_fabs (tree arglist, rtx target, rtx subtarget)
04812 {
04813 enum machine_mode mode;
04814 tree arg;
04815 rtx op0;
04816
04817 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
04818 return 0;
04819
04820 arg = TREE_VALUE (arglist);
04821 mode = TYPE_MODE (TREE_TYPE (arg));
04822 op0 = expand_expr (arg, subtarget, VOIDmode, 0);
04823 return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
04824 }
04825
04826
04827
04828
04829
04830
04831 static rtx
04832 expand_builtin_copysign (tree arglist, rtx target, rtx subtarget)
04833 {
04834 rtx op0, op1;
04835 tree arg;
04836
04837 if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
04838 return 0;
04839
04840 arg = TREE_VALUE (arglist);
04841 op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
04842
04843 arg = TREE_VALUE (TREE_CHAIN (arglist));
04844 op1 = expand_normal (arg);
04845
04846 return expand_copysign (op0, op1, target);
04847 }
04848
04849
04850
04851 tree
04852 build_string_literal (int len, const char *str)
04853 {
04854 tree t, elem, index, type;
04855
04856 t = build_string (len, str);
04857 elem = build_type_variant (char_type_node, 1, 0);
04858 index = build_index_type (build_int_cst (NULL_TREE, len - 1));
04859 type = build_array_type (elem, index);
04860 TREE_TYPE (t) = type;
04861 TREE_CONSTANT (t) = 1;
04862 TREE_INVARIANT (t) = 1;
04863 TREE_READONLY (t) = 1;
04864 TREE_STATIC (t) = 1;
04865
04866 type = build_pointer_type (type);
04867 t = build1 (ADDR_EXPR, type, t);
04868
04869 type = build_pointer_type (elem);
04870 t = build1 (NOP_EXPR, type, t);
04871 return t;
04872 }
04873
04874
04875
04876
04877
04878
04879 static rtx
04880 expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
04881 bool unlocked)
04882 {
04883 tree arglist = TREE_OPERAND (exp, 1);
04884
04885
04886 tree const fn_putchar = unlocked ? built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED]
04887 : implicit_built_in_decls[BUILT_IN_PUTCHAR];
04888 tree const fn_puts = unlocked ? built_in_decls[BUILT_IN_PUTS_UNLOCKED]
04889 : implicit_built_in_decls[BUILT_IN_PUTS];
04890 const char *fmt_str;
04891 tree fn, fmt, arg;
04892
04893
04894 if (target != const0_rtx)
04895 return 0;
04896
04897
04898 if (! arglist)
04899 return 0;
04900 fmt = TREE_VALUE (arglist);
04901 if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
04902 return 0;
04903 arglist = TREE_CHAIN (arglist);
04904
04905
04906 fmt_str = c_getstr (fmt);
04907 if (fmt_str == NULL)
04908 return 0;
04909
04910 if (!init_target_chars())
04911 return 0;
04912
04913
04914 if (strcmp (fmt_str, target_percent_s_newline) == 0)
04915 {
04916 if (! arglist
04917 || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
04918 || TREE_CHAIN (arglist))
04919 return 0;
04920 fn = fn_puts;
04921 }
04922
04923 else if (strcmp (fmt_str, target_percent_c) == 0)
04924 {
04925 if (! arglist
04926 || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
04927 || TREE_CHAIN (arglist))
04928 return 0;
04929 fn = fn_putchar;
04930 }
04931 else
04932 {
04933
04934 if (strchr (fmt_str, target_percent))
04935 return 0;
04936
04937 if (arglist)
04938 return 0;
04939
04940
04941 if (fmt_str[0] == '\0')
04942 return const0_rtx;
04943
04944 if (fmt_str[1] == '\0')
04945 {
04946
04947
04948
04949 arg = build_int_cst (NULL_TREE, fmt_str[0]);
04950 arglist = build_tree_list (NULL_TREE, arg);
04951 fn = fn_putchar;
04952 }
04953 else
04954 {
04955
04956 size_t len = strlen (fmt_str);
04957 if ((unsigned char)fmt_str[len - 1] == target_newline)
04958 {
04959
04960
04961 char *newstr = alloca (len);
04962 memcpy (newstr, fmt_str, len - 1);
04963 newstr[len - 1] = 0;
04964
04965 arg = build_string_literal (len, newstr);
04966 arglist = build_tree_list (NULL_TREE, arg);
04967 fn = fn_puts;
04968 }
04969 else
04970
04971
04972 return 0;
04973 }
04974 }
04975
04976 if (!fn)
04977 return 0;
04978 fn = build_function_call_expr (fn, arglist);
04979 if (TREE_CODE (fn) == CALL_EXPR)
04980 CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
04981 return expand_expr (fn, target, mode, EXPAND_NORMAL);
04982 }
04983
04984
04985
04986
04987
04988
04989 static rtx
04990 expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode,
04991 bool unlocked)
04992 {
04993 tree arglist = TREE_OPERAND (exp, 1);
04994
04995
04996 tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
04997 : implicit_built_in_decls[BUILT_IN_FPUTC];
04998 tree const fn_fputs = unlocked ? built_in_decls[BUILT_IN_FPUTS_UNLOCKED]
04999 : implicit_built_in_decls[BUILT_IN_FPUTS];
05000 const char *fmt_str;
05001 tree fn, fmt, fp, arg;
05002
05003
05004 if (target != const0_rtx)
05005 return 0;
05006
05007
05008 if (! arglist)
05009 return 0;
05010 fp = TREE_VALUE (arglist);
05011 if (! POINTER_TYPE_P (TREE_TYPE (fp)))
05012 return 0;
05013 arglist = TREE_CHAIN (arglist);
05014 if (! arglist)
05015 return 0;
05016 fmt = TREE_VALUE (arglist);
05017 if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
05018 return 0;
05019 arglist = TREE_CHAIN (arglist);
05020
05021
05022 fmt_str = c_getstr (fmt);
05023 if (fmt_str == NULL)
05024 return 0;
05025
05026 if (!init_target_chars())
05027 return 0;
05028
05029
05030 if (strcmp (fmt_str, target_percent_s) == 0)
05031 {
05032 if (! arglist
05033 || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
05034 || TREE_CHAIN (arglist))
05035 return 0;
05036 arg = TREE_VALUE (arglist);
05037 arglist = build_tree_list (NULL_TREE, fp);
05038 arglist = tree_cons (NULL_TREE, arg, arglist);
05039 fn = fn_fputs;
05040 }
05041
05042 else if (strcmp (fmt_str, target_percent_c) == 0)
05043 {
05044 if (! arglist
05045 || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
05046 || TREE_CHAIN (arglist))
05047 return 0;
05048 arg = TREE_VALUE (arglist);
05049 arglist = build_tree_list (NULL_TREE, fp);
05050 arglist = tree_cons (NULL_TREE, arg, arglist);
05051 fn = fn_fputc;
05052 }
05053 else
05054 {
05055
05056 if (strchr (fmt_str, target_percent))
05057 return 0;
05058
05059 if (arglist)
05060 return 0;
05061
05062
05063 if (fmt_str[0] == '\0')
05064 {
05065
05066 expand_expr (fp, const0_rtx, VOIDmode, EXPAND_NORMAL);
05067 return const0_rtx;
05068 }
05069
05070
05071
05072
05073 arglist = build_tree_list (NULL_TREE, fp);
05074 arglist = tree_cons (NULL_TREE, fmt, arglist);
05075 fn = fn_fputs;
05076 }
05077
05078 if (!fn)
05079 return 0;
05080 fn = build_function_call_expr (fn, arglist);
05081 if (TREE_CODE (fn) == CALL_EXPR)
05082 CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
05083 return expand_expr (fn, target, mode, EXPAND_NORMAL);
05084 }
05085
05086
05087
05088
05089
05090
05091 static rtx
05092 expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode)
05093 {
05094 tree orig_arglist, dest, fmt;
05095 const char *fmt_str;
05096
05097 orig_arglist = arglist;
05098
05099
05100 if (! arglist)
05101 return 0;
05102 dest = TREE_VALUE (arglist);
05103 if (! POINTER_TYPE_P (TREE_TYPE (dest)))
05104 return 0;
05105 arglist = TREE_CHAIN (arglist);
05106 if (! arglist)
05107 return 0;
05108 fmt = TREE_VALUE (arglist);
05109 if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
05110 return 0;
05111 arglist = TREE_CHAIN (arglist);
05112
05113
05114 fmt_str = c_getstr (fmt);
05115 if (fmt_str == NULL)
05116 return 0;
05117
05118 if (!init_target_chars())
05119 return 0;
05120
05121
05122 if (strchr (fmt_str, target_percent) == 0)
05123 {
05124 tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
05125 tree exp;
05126
05127 if (arglist || ! fn)
05128 return 0;
05129 expand_expr (build_function_call_expr (fn, orig_arglist),
05130 const0_rtx, VOIDmode, EXPAND_NORMAL);
05131 if (target == const0_rtx)
05132 return const0_rtx;
05133 exp = build_int_cst (NULL_TREE, strlen (fmt_str));
05134 return expand_expr (exp, target, mode, EXPAND_NORMAL);
05135 }
05136
05137 else if (strcmp (fmt_str, target_percent_s) == 0)
05138 {
05139 tree fn, arg, len;
05140 fn = implicit_built_in_decls[BUILT_IN_STRCPY];
05141
05142 if (! fn)
05143 return 0;
05144
05145 if (! arglist || TREE_CHAIN (arglist))
05146 return 0;
05147 arg = TREE_VALUE (arglist);
05148 if (! POINTER_TYPE_P (TREE_TYPE (arg)))
05149 return 0;
05150
05151 if (target != const0_rtx)
05152 {
05153 len = c_strlen (arg, 1);
05154 if (! len || TREE_CODE (len) != INTEGER_CST)
05155 return 0;
05156 }
05157 else
05158 len = NULL_TREE;
05159
05160 arglist = build_tree_list (NULL_TREE, arg);
05161 arglist = tree_cons (NULL_TREE, dest, arglist);
05162 expand_expr (build_function_call_expr (fn, arglist),
05163 const0_rtx, VOIDmode, EXPAND_NORMAL);
05164
05165 if (target == const0_rtx)
05166 return const0_rtx;
05167 return expand_expr (len, target, mode, EXPAND_NORMAL);
05168 }
05169
05170 return 0;
05171 }
05172
05173
05174
05175 static rtx
05176 expand_builtin_profile_func (bool exitp)
05177 {
05178 rtx this, which;
05179
05180 this = DECL_RTL (current_function_decl);
05181 gcc_assert (MEM_P (this));
05182 this = XEXP (this, 0);
05183
05184 if (exitp)
05185 which = profile_function_exit_libfunc;
05186 else
05187 which = profile_function_entry_libfunc;
05188
05189 emit_library_call (which, LCT_NORMAL, VOIDmode, 2, this, Pmode,
05190 expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
05191 0),
05192 Pmode);
05193
05194 return const0_rtx;
05195 }
05196
05197
05198
05199 static rtx
05200 round_trampoline_addr (rtx tramp)
05201 {
05202 rtx temp, addend, mask;
05203
05204
05205
05206 if (TRAMPOLINE_ALIGNMENT <= STACK_BOUNDARY)
05207 return tramp;
05208
05209
05210 temp = gen_reg_rtx (Pmode);
05211 addend = GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1);
05212 mask = GEN_INT (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
05213
05214 temp = expand_simple_binop (Pmode, PLUS, tramp, addend,
05215 temp, 0, OPTAB_LIB_WIDEN);
05216 tramp = expand_simple_binop (Pmode, AND, temp, mask,
05217 temp, 0, OPTAB_LIB_WIDEN);
05218
05219 return tramp;
05220 }
05221
05222 static rtx
05223 expand_builtin_init_trampoline (tree arglist)
05224 {
05225 tree t_tramp, t_func, t_chain;
05226 rtx r_tramp, r_func, r_chain;
05227 #ifdef TRAMPOLINE_TEMPLATE
05228 rtx blktramp;
05229 #endif
05230
05231 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE,
05232 POINTER_TYPE, VOID_TYPE))
05233 return NULL_RTX;
05234
05235 t_tramp = TREE_VALUE (arglist);
05236 arglist = TREE_CHAIN (arglist);
05237 t_func = TREE_VALUE (arglist);
05238 arglist = TREE_CHAIN (arglist);
05239 t_chain = TREE_VALUE (arglist);
05240
05241 r_tramp = expand_normal (t_tramp);
05242 r_func = expand_normal (t_func);
05243 r_chain = expand_normal (t_chain);
05244
05245
05246 r_tramp = round_trampoline_addr (r_tramp);
05247 #ifdef TRAMPOLINE_TEMPLATE
05248 blktramp = gen_rtx_MEM (BLKmode, r_tramp);
05249 set_mem_align (blktramp, TRAMPOLINE_ALIGNMENT);
05250 emit_block_move (blktramp, assemble_trampoline_template (),
05251 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
05252 #endif
05253 trampolines_created = 1;
05254 INITIALIZE_TRAMPOLINE (r_tramp, r_func, r_chain);
05255
05256 return const0_rtx;
05257 }
05258
05259 static rtx
05260 expand_builtin_adjust_trampoline (tree arglist)
05261 {
05262 rtx tramp;
05263
05264 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
05265 return NULL_RTX;
05266
05267 tramp = expand_normal (TREE_VALUE (arglist));
05268 tramp = round_trampoline_addr (tramp);
05269 #ifdef TRAMPOLINE_ADJUST_ADDRESS
05270 TRAMPOLINE_ADJUST_ADDRESS (tramp);
05271 #endif
05272
05273 return tramp;
05274 }
05275
05276
05277
05278
05279
05280
05281 static rtx
05282 expand_builtin_signbit (tree exp, rtx target)
05283 {
05284 const struct real_format *fmt;
05285 enum machine_mode fmode, imode, rmode;
05286 HOST_WIDE_INT hi, lo;
05287 tree arg, arglist;
05288 int word, bitpos;
05289 rtx temp;
05290
05291 arglist = TREE_OPERAND (exp, 1);
05292 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
05293 return 0;
05294
05295 arg = TREE_VALUE (arglist);
05296 fmode = TYPE_MODE (TREE_TYPE (arg));
05297 rmode = TYPE_MODE (TREE_TYPE (exp));
05298 fmt = REAL_MODE_FORMAT (fmode);
05299
05300
05301
05302 bitpos = fmt->signbit_ro;
05303 if (bitpos < 0)
05304 {
05305
05306 if (fmt->has_signed_zero && HONOR_SIGNED_ZEROS (fmode))
05307 return 0;
05308
05309 arg = fold_build2 (LT_EXPR, TREE_TYPE (exp), arg,
05310 build_real (TREE_TYPE (arg), dconst0));
05311 return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
05312 }
05313
05314 temp = expand_normal (arg);
05315 if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
05316 {
05317 imode = int_mode_for_mode (fmode);
05318 if (imode == BLKmode)
05319 return 0;
05320 temp = gen_lowpart (imode, temp);
05321 }
05322 else
05323 {
05324 imode = word_mode;
05325
05326 if (FLOAT_WORDS_BIG_ENDIAN)
05327 word = (GET_MODE_BITSIZE (fmode) - bitpos) / BITS_PER_WORD;
05328 else
05329 word = bitpos / BITS_PER_WORD;
05330 temp = operand_subword_force (temp, word, fmode);
05331 bitpos = bitpos % BITS_PER_WORD;
05332 }
05333
05334
05335
05336
05337 temp = force_reg (imode, temp);
05338
05339
05340
05341
05342
05343 if (bitpos < GET_MODE_BITSIZE (rmode))
05344 {
05345 if (bitpos < HOST_BITS_PER_WIDE_INT)
05346 {
05347 hi = 0;
05348 lo = (HOST_WIDE_INT) 1 << bitpos;
05349 }
05350 else
05351 {
05352 hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
05353 lo = 0;
05354 }
05355
05356 if (imode != rmode)
05357 temp = gen_lowpart (rmode, temp);
05358 temp = expand_binop (rmode, and_optab, temp,
05359 immed_double_const (lo, hi, rmode),
05360 NULL_RTX, 1, OPTAB_LIB_WIDEN);
05361 }
05362 else
05363 {
05364
05365
05366
05367 temp = expand_shift (RSHIFT_EXPR, imode, temp,
05368 build_int_cst (NULL_TREE, bitpos), NULL_RTX, 1);
05369 temp = gen_lowpart (rmode, temp);
05370 temp = expand_binop (rmode, and_optab, temp, const1_rtx,
05371 NULL_RTX, 1, OPTAB_LIB_WIDEN);
05372 }
05373
05374 return temp;
05375 }
05376
05377
05378
05379
05380
05381
05382 static rtx
05383 expand_builtin_fork_or_exec (tree fn, tree arglist, rtx target, int ignore)
05384 {
05385 tree id, decl;
05386 tree call;
05387
05388
05389 if (!profile_arc_flag)
05390 return NULL_RTX;
05391
05392
05393
05394
05395
05396 switch (DECL_FUNCTION_CODE (fn))
05397 {
05398 case BUILT_IN_FORK:
05399 id = get_identifier ("__gcov_fork");
05400 break;
05401
05402 case BUILT_IN_EXECL:
05403 id = get_identifier ("__gcov_execl");
05404 break;
05405
05406 case BUILT_IN_EXECV:
05407 id = get_identifier ("__gcov_execv");
05408 break;
05409
05410 case BUILT_IN_EXECLP:
05411 id = get_identifier ("__gcov_execlp");
05412 break;
05413
05414 case BUILT_IN_EXECLE:
05415 id = get_identifier ("__gcov_execle");
05416 break;
05417
05418 case BUILT_IN_EXECVP:
05419 id = get_identifier ("__gcov_execvp");
05420 break;
05421
05422 case BUILT_IN_EXECVE:
05423 id = get_identifier ("__gcov_execve");
05424 break;
05425
05426 default:
05427 gcc_unreachable ();
05428 }
05429
05430 decl = build_decl (FUNCTION_DECL, id, TREE_TYPE (fn));
05431 DECL_EXTERNAL (decl) = 1;
05432 TREE_PUBLIC (decl) = 1;
05433 DECL_ARTIFICIAL (decl) = 1;
05434 TREE_NOTHROW (decl) = 1;
05435 DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
05436 DECL_VISIBILITY_SPECIFIED (decl) = 1;
05437 call = build_function_call_expr (decl, arglist);
05438
05439 return expand_call (call, target, ignore);
05440 }
05441
05442
05443
05444
05445
05446
05447
05448
05449
05450
05451 static inline enum machine_mode
05452 get_builtin_sync_mode (int fcode_diff)
05453 {
05454
05455
05456 return mode_for_size (BITS_PER_UNIT << fcode_diff, MODE_INT, 0);
05457 }
05458
05459
05460
05461
05462 static rtx
05463 get_builtin_sync_mem (tree loc, enum machine_mode mode)
05464 {
05465 rtx addr, mem;
05466
05467 addr = expand_expr (loc, NULL, Pmode, EXPAND_SUM);
05468
05469
05470
05471
05472 mem = validize_mem (gen_rtx_MEM (mode, addr));
05473
05474 set_mem_align (mem, get_pointer_alignment (loc, BIGGEST_ALIGNMENT));
05475 set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER);
05476 MEM_VOLATILE_P (mem) = 1;
05477
05478 return mem;
05479 }
05480
05481
05482
05483
05484
05485
05486
05487
05488
05489 static rtx
05490 expand_builtin_sync_operation (enum machine_mode mode, tree arglist,
05491 enum rtx_code code, bool after,
05492 rtx target, bool ignore)
05493 {
05494 rtx val, mem;
05495 enum machine_mode old_mode;
05496
05497
05498 mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
05499
05500 arglist = TREE_CHAIN (arglist);
05501 val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
05502
05503
05504 old_mode = GET_MODE (val);
05505 if (old_mode == VOIDmode)
05506 old_mode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
05507 val = convert_modes (mode, old_mode, val, 1);
05508
05509 if (ignore)
05510 return expand_sync_operation (mem, val, code);
05511 else
05512 return expand_sync_fetch_operation (mem, val, code, after, target);
05513 }
05514
05515
05516
05517
05518
05519
05520 static rtx
05521 expand_builtin_compare_and_swap (enum machine_mode mode, tree arglist,
05522 bool is_bool, rtx target)
05523 {
05524 rtx old_val, new_val, mem;
05525 enum machine_mode old_mode;
05526
05527
05528 mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
05529
05530 arglist = TREE_CHAIN (arglist);
05531 old_val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
05532
05533
05534 old_mode = GET_MODE (old_val);
05535 if (old_mode == VOIDmode)
05536 old_mode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
05537 old_val = convert_modes (mode, old_mode, old_val, 1);
05538
05539 arglist = TREE_CHAIN (arglist);
05540 new_val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
05541
05542
05543 old_mode = GET_MODE (new_val);
05544 if (old_mode == VOIDmode)
05545 old_mode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
05546 new_val = convert_modes (mode, old_mode, new_val, 1);
05547
05548 if (is_bool)
05549 return expand_bool_compare_and_swap (mem, old_val, new_val, target);
05550 else
05551 return expand_val_compare_and_swap (mem, old_val, new_val, target);
05552 }
05553
05554
05555
05556
05557
05558
05559
05560 static rtx
05561 expand_builtin_lock_test_and_set (enum machine_mode mode, tree arglist,
05562 rtx target)
05563 {
05564 rtx val, mem;
05565 enum machine_mode old_mode;
05566
05567
05568 mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
05569
05570 arglist = TREE_CHAIN (arglist);
05571 val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
05572
05573
05574 old_mode = GET_MODE (val);
05575 if (old_mode == VOIDmode)
05576 old_mode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
05577 val = convert_modes (mode, old_mode, val, 1);
05578
05579 return expand_sync_lock_test_and_set (mem, val, target);
05580 }
05581
05582
05583
05584 static void
05585 expand_builtin_synchronize (void)
05586 {
05587 tree x;
05588
05589 #ifdef HAVE_memory_barrier
05590 if (HAVE_memory_barrier)
05591 {
05592 emit_insn (gen_memory_barrier ());
05593 return;
05594 }
05595 #endif
05596
05597
05598
05599 x = build4 (ASM_EXPR, void_type_node, build_string (0, ""), NULL, NULL,
05600 tree_cons (NULL, build_string (6, "memory"), NULL));
05601 ASM_VOLATILE_P (x) = 1;
05602 expand_asm_expr (x);
05603 }
05604
05605
05606
05607
05608 static void
05609 expand_builtin_lock_release (enum machine_mode mode, tree arglist)
05610 {
05611 enum insn_code icode;
05612 rtx mem, insn;
05613 rtx val = const0_rtx;
05614
05615
05616 mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
05617
05618
05619 icode = sync_lock_release[mode];
05620 if (icode != CODE_FOR_nothing)
05621 {
05622 if (!insn_data[icode].operand[1].predicate (val, mode))
05623 val = force_reg (mode, val);
05624
05625 insn = GEN_FCN (icode) (mem, val);
05626 if (insn)
05627 {
05628 emit_insn (insn);
05629 return;
05630 }
05631 }
05632
05633
05634
05635 expand_builtin_synchronize ();
05636 emit_move_insn (mem, val);
05637 }
05638
05639
05640
05641
05642
05643
05644
05645 rtx
05646 expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
05647 int ignore)
05648 {
05649 tree fndecl = get_callee_fndecl (exp);
05650 tree arglist = TREE_OPERAND (exp, 1);
05651 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
05652 enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
05653
05654 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
05655 return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
05656
05657
05658
05659 if (!optimize
05660 && !called_as_built_in (fndecl)
05661 && DECL_ASSEMBLER_NAME_SET_P (fndecl)
05662 && fcode != BUILT_IN_ALLOCA)
05663 return expand_call (exp, target, ignore);
05664
05665
05666
05667 if (ignore)
05668 target = const0_rtx;
05669
05670
05671
05672
05673 if (target == const0_rtx
05674 && (DECL_IS_PURE (fndecl) || TREE_READONLY (fndecl)))
05675 {
05676 bool volatilep = false;
05677 tree arg;
05678
05679 for (arg = arglist; arg; arg = TREE_CHAIN (arg))
05680 if (TREE_THIS_VOLATILE (TREE_VALUE (arg)))
05681 {
05682 volatilep = true;
05683 break;
05684 }
05685
05686 if (! volatilep)
05687 {
05688 for (arg = arglist; arg; arg = TREE_CHAIN (arg))
05689 expand_expr (TREE_VALUE (arg), const0_rtx,
05690 VOIDmode, EXPAND_NORMAL);
05691 return const0_rtx;
05692 }
05693 }
05694
05695 switch (fcode)
05696 {
05697 CASE_FLT_FN (BUILT_IN_FABS):
05698 target = expand_builtin_fabs (arglist, target, subtarget);
05699 if (target)
05700 return target;
05701 break;
05702
05703 CASE_FLT_FN (BUILT_IN_COPYSIGN):
05704 target = expand_builtin_copysign (arglist, target, subtarget);
05705 if (target)
05706 return target;
05707 break;
05708
05709
05710
05711 CASE_FLT_FN (BUILT_IN_CABS):
05712 break;
05713
05714 CASE_FLT_FN (BUILT_IN_EXP):
05715 CASE_FLT_FN (BUILT_IN_EXP10):
05716 CASE_FLT_FN (BUILT_IN_POW10):
05717 CASE_FLT_FN (BUILT_IN_EXP2):
05718 CASE_FLT_FN (BUILT_IN_EXPM1):
05719 CASE_FLT_FN (BUILT_IN_LOGB):
05720 CASE_FLT_FN (BUILT_IN_ILOGB):
05721 CASE_FLT_FN (BUILT_IN_LOG):
05722 CASE_FLT_FN (BUILT_IN_LOG10):
05723 CASE_FLT_FN (BUILT_IN_LOG2):
05724 CASE_FLT_FN (BUILT_IN_LOG1P):
05725 CASE_FLT_FN (BUILT_IN_TAN):
05726 CASE_FLT_FN (BUILT_IN_ASIN):
05727 CASE_FLT_FN (BUILT_IN_ACOS):
05728 CASE_FLT_FN (BUILT_IN_ATAN):
05729
05730
05731 if (! flag_unsafe_math_optimizations)
05732 break;
05733 CASE_FLT_FN (BUILT_IN_SQRT):
05734 CASE_FLT_FN (BUILT_IN_FLOOR):
05735 CASE_FLT_FN (BUILT_IN_CEIL):
05736 CASE_FLT_FN (BUILT_IN_TRUNC):
05737 CASE_FLT_FN (BUILT_IN_ROUND):
05738 CASE_FLT_FN (BUILT_IN_NEARBYINT):
05739 CASE_FLT_FN (BUILT_IN_RINT):
05740 CASE_FLT_FN (BUILT_IN_LRINT):
05741 CASE_FLT_FN (BUILT_IN_LLRINT):
05742 target = expand_builtin_mathfn (exp, target, subtarget);
05743 if (target)
05744 return target;
05745 break;
05746
05747 CASE_FLT_FN (BUILT_IN_LCEIL):
05748 CASE_FLT_FN (BUILT_IN_LLCEIL):
05749 CASE_FLT_FN (BUILT_IN_LFLOOR):
05750 CASE_FLT_FN (BUILT_IN_LLFLOOR):
05751 target = expand_builtin_int_roundingfn (exp, target, subtarget);
05752 if (target)
05753 return target;
05754 break;
05755
05756 CASE_FLT_FN (BUILT_IN_POW):
05757 target = expand_builtin_pow (exp, target, subtarget);
05758 if (target)
05759 return target;
05760 break;
05761
05762 CASE_FLT_FN (BUILT_IN_POWI):
05763 target = expand_builtin_powi (exp, target, subtarget);
05764 if (target)
05765 return target;
05766 break;
05767
05768 CASE_FLT_FN (BUILT_IN_ATAN2):
05769 CASE_FLT_FN (BUILT_IN_LDEXP):
05770 CASE_FLT_FN (BUILT_IN_FMOD):
05771 CASE_FLT_FN (BUILT_IN_DREM):
05772 if (! flag_unsafe_math_optimizations)
05773 break;
05774 target = expand_builtin_mathfn_2 (exp, target, subtarget);
05775 if (target)
05776 return target;
05777 break;
05778
05779 CASE_FLT_FN (BUILT_IN_SIN):
05780 CASE_FLT_FN (BUILT_IN_COS):
05781 if (! flag_unsafe_math_optimizations)
05782 break;
05783 target = expand_builtin_mathfn_3 (exp, target, subtarget);
05784 if (target)
05785 return target;
05786 break;
05787
05788 CASE_FLT_FN (BUILT_IN_SINCOS):
05789 if (! flag_unsafe_math_optimizations)
05790 break;
05791 target = expand_builtin_sincos (exp);
05792 if (target)
05793 return target;
05794 break;
05795
05796 case BUILT_IN_APPLY_ARGS:
05797 return expand_builtin_apply_args ();
05798
05799
05800
05801
05802
05803
05804
05805
05806
05807
05808
05809 case BUILT_IN_APPLY:
05810 if (!validate_arglist (arglist, POINTER_TYPE,
05811 POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
05812 && !validate_arglist (arglist, REFERENCE_TYPE,
05813 POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
05814 return const0_rtx;
05815 else
05816 {
05817 int i;
05818 tree t;
05819 rtx ops[3];
05820
05821 for (t = arglist, i = 0; t; t = TREE_CHAIN (t), i++)
05822 ops[i] = expand_normal (TREE_VALUE (t));
05823
05824 return expand_builtin_apply (ops[0], ops[1], ops[2]);
05825 }
05826
05827
05828
05829
05830 case BUILT_IN_RETURN:
05831 if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
05832 expand_builtin_return (expand_normal (TREE_VALUE (arglist)));
05833 return const0_rtx;
05834
05835 case BUILT_IN_SAVEREGS:
05836 return expand_builtin_saveregs ();
05837
05838 case BUILT_IN_ARGS_INFO:
05839 return expand_builtin_args_info (arglist);
05840
05841
05842 case BUILT_IN_NEXT_ARG:
05843 if (fold_builtin_next_arg (arglist))
05844 return const0_rtx;
05845 return expand_builtin_next_arg ();
05846
05847 case BUILT_IN_CLASSIFY_TYPE:
05848 return expand_builtin_classify_type (arglist);
05849
05850 case BUILT_IN_CONSTANT_P:
05851 return const0_rtx;
05852
05853 case BUILT_IN_FRAME_ADDRESS:
05854 case BUILT_IN_RETURN_ADDRESS:
05855 return expand_builtin_frame_address (fndecl, arglist);
05856
05857
05858
05859 case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
05860 if (arglist != 0
05861 || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
05862 || !MEM_P (DECL_RTL (DECL_RESULT (current_function_decl))))
05863 return const0_rtx;
05864 else
05865 return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
05866
05867 case BUILT_IN_ALLOCA:
05868 target = expand_builtin_alloca (arglist, target);
05869 if (target)
05870 return target;
05871 break;
05872
05873 case BUILT_IN_STACK_SAVE:
05874 return expand_stack_save ();
05875
05876 case BUILT_IN_STACK_RESTORE:
05877 expand_stack_restore (TREE_VALUE (arglist));
05878 return const0_rtx;
05879
05880 CASE_INT_FN (BUILT_IN_FFS):
05881 case BUILT_IN_FFSIMAX:
05882 target = expand_builtin_unop (target_mode, arglist, target,
05883 subtarget, ffs_optab);
05884 if (target)
05885 return target;
05886 break;
05887
05888 CASE_INT_FN (BUILT_IN_CLZ):
05889 case BUILT_IN_CLZIMAX:
05890 target = expand_builtin_unop (target_mode, arglist, target,
05891 subtarget, clz_optab);
05892 if (target)
05893 return target;
05894 break;
05895
05896 CASE_INT_FN (BUILT_IN_CTZ):
05897 case BUILT_IN_CTZIMAX:
05898 target = expand_builtin_unop (target_mode, arglist, target,
05899 subtarget, ctz_optab);
05900 if (target)
05901 return target;
05902 break;
05903
05904 CASE_INT_FN (BUILT_IN_POPCOUNT):
05905 case BUILT_IN_POPCOUNTIMAX:
05906 target = expand_builtin_unop (target_mode, arglist, target,
05907 subtarget, popcount_optab);
05908 if (target)
05909 return target;
05910 break;
05911
05912 CASE_INT_FN (BUILT_IN_PARITY):
05913 case BUILT_IN_PARITYIMAX:
05914 target = expand_builtin_unop (target_mode, arglist, target,
05915 subtarget, parity_optab);
05916 if (target)
05917 return target;
05918 break;
05919
05920 case BUILT_IN_STRLEN:
05921 target = expand_builtin_strlen (arglist, target, target_mode);
05922 if (target)
05923 return target;
05924 break;
05925
05926 case BUILT_IN_STRCPY:
05927 target = expand_builtin_strcpy (fndecl, arglist, target, mode);
05928 if (target)
05929 return target;
05930 break;
05931
05932 case BUILT_IN_STRNCPY:
05933 target = expand_builtin_strncpy (exp, target, mode);
05934 if (target)
05935 return target;
05936 break;
05937
05938 case BUILT_IN_STPCPY:
05939 target = expand_builtin_stpcpy (exp, target, mode);
05940 if (target)
05941 return target;
05942 break;
05943
05944 case BUILT_IN_STRCAT:
05945 target = expand_builtin_strcat (fndecl, arglist, target, mode);
05946 if (target)
05947 return target;
05948 break;
05949
05950 case BUILT_IN_STRNCAT:
05951 target = expand_builtin_strncat (arglist, target, mode);
05952 if (target)
05953 return target;
05954 break;
05955
05956 case BUILT_IN_STRSPN:
05957 target = expand_builtin_strspn (arglist, target, mode);
05958 if (target)
05959 return target;
05960 break;
05961
05962 case BUILT_IN_STRCSPN:
05963 target = expand_builtin_strcspn (arglist, target, mode);
05964 if (target)
05965 return target;
05966 break;
05967
05968 case BUILT_IN_STRSTR:
05969 target = expand_builtin_strstr (arglist, TREE_TYPE (exp), target, mode);
05970 if (target)
05971 return target;
05972 break;
05973
05974 case BUILT_IN_STRPBRK:
05975 target = expand_builtin_strpbrk (arglist, TREE_TYPE (exp), target, mode);
05976 if (target)
05977 return target;
05978 break;
05979
05980 case BUILT_IN_INDEX:
05981 case BUILT_IN_STRCHR:
05982 target = expand_builtin_strchr (arglist, TREE_TYPE (exp), target, mode);
05983 if (target)
05984 return target;
05985 break;
05986
05987 case BUILT_IN_RINDEX:
05988 case BUILT_IN_STRRCHR:
05989 target = expand_builtin_strrchr (arglist, TREE_TYPE (exp), target, mode);
05990 if (target)
05991 return target;
05992 break;
05993
05994 case BUILT_IN_MEMCPY:
05995 target = expand_builtin_memcpy (exp, target, mode);
05996 if (target)
05997 return target;
05998 break;
05999
06000 case BUILT_IN_MEMPCPY:
06001 target = expand_builtin_mempcpy (arglist, TREE_TYPE (exp), target, mode, 1);
06002 if (target)
06003 return target;
06004 break;
06005
06006 case BUILT_IN_MEMMOVE:
06007 target = expand_builtin_memmove (arglist, TREE_TYPE (exp), target,
06008 mode, exp);
06009 if (target)
06010 return target;
06011 break;
06012
06013 case BUILT_IN_BCOPY:
06014 target = expand_builtin_bcopy (exp);
06015 if (target)
06016 return target;
06017 break;
06018
06019 case BUILT_IN_MEMSET:
06020 target = expand_builtin_memset (arglist, target, mode, exp);
06021 if (target)
06022 return target;
06023 break;
06024
06025 case BUILT_IN_BZERO:
06026 target = expand_builtin_bzero (exp);
06027 if (target)
06028 return target;
06029 break;
06030
06031 case BUILT_IN_STRCMP:
06032 target = expand_builtin_strcmp (exp, target, mode);
06033 if (target)
06034 return target;
06035 break;
06036
06037 case BUILT_IN_STRNCMP:
06038 target = expand_builtin_strncmp (exp, target, mode);
06039 if (target)
06040 return target;
06041 break;
06042
06043 case BUILT_IN_BCMP:
06044 case BUILT_IN_MEMCMP:
06045 target = expand_builtin_memcmp (exp, arglist, target, mode);
06046 if (target)
06047 return target;
06048 break;
06049
06050 case BUILT_IN_SETJMP:
06051
06052 gcc_unreachable ();
06053
06054 case BUILT_IN_SETJMP_SETUP:
06055
06056
06057 if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
06058 {
06059 rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
06060 VOIDmode, EXPAND_NORMAL);
06061 tree label = TREE_OPERAND (TREE_VALUE (TREE_CHAIN (arglist)), 0);
06062 rtx label_r = label_rtx (label);
06063
06064
06065 expand_builtin_setjmp_setup (buf_addr, label_r);
06066 nonlocal_goto_handler_labels
06067 = gen_rtx_EXPR_LIST (VOIDmode, label_r,
06068 nonlocal_goto_handler_labels);
06069
06070
06071
06072 FORCED_LABEL (label) = 0;
06073 return const0_rtx;
06074 }
06075 break;
06076
06077 case BUILT_IN_SETJMP_DISPATCHER:
06078
06079 if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
06080 {
06081 tree label = TREE_OPERAND (TREE_VALUE (arglist), 0);
06082 rtx label_r = label_rtx (label);
06083
06084
06085
06086 remove_node_from_expr_list (label_r, &nonlocal_goto_handler_labels);
06087 return const0_rtx;
06088 }
06089 break;
06090
06091 case BUILT_IN_SETJMP_RECEIVER:
06092
06093 if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
06094 {
06095 tree label = TREE_OPERAND (TREE_VALUE (arglist), 0);
06096 rtx label_r = label_rtx (label);
06097
06098 expand_builtin_setjmp_receiver (label_r);
06099 return const0_rtx;
06100 }
06101 break;
06102
06103
06104
06105
06106 case BUILT_IN_LONGJMP:
06107 if (validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
06108 {
06109 rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
06110 VOIDmode, EXPAND_NORMAL);
06111 rtx value = expand_normal (TREE_VALUE (TREE_CHAIN (arglist)));
06112
06113 if (value != const1_rtx)
06114 {
06115 error ("%<__builtin_longjmp%> second argument must be 1");
06116 return const0_rtx;
06117 }
06118
06119 expand_builtin_longjmp (buf_addr, value);
06120 return const0_rtx;
06121 }
06122 break;
06123
06124 case BUILT_IN_NONLOCAL_GOTO:
06125 target = expand_builtin_nonlocal_goto (arglist);
06126 if (target)
06127 return target;
06128 break;
06129
06130
06131
06132 case BUILT_IN_UPDATE_SETJMP_BUF:
06133 if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
06134 {
06135 rtx buf_addr
06136 = expand_normal (TREE_VALUE (arglist));
06137
06138 expand_builtin_update_setjmp_buf (buf_addr);
06139 return const0_rtx;
06140 }
06141 break;
06142
06143 case BUILT_IN_TRAP:
06144 expand_builtin_trap ();
06145 return const0_rtx;
06146
06147 case BUILT_IN_PRINTF:
06148 target = expand_builtin_printf (exp, target, mode, false);
06149 if (target)
06150 return target;
06151 break;
06152
06153 case BUILT_IN_PRINTF_UNLOCKED:
06154 target = expand_builtin_printf (exp, target, mode, true);
06155 if (target)
06156 return target;
06157 break;
06158
06159 case BUILT_IN_FPUTS:
06160 target = expand_builtin_fputs (arglist, target, false);
06161 if (target)
06162 return target;
06163 break;
06164 case BUILT_IN_FPUTS_UNLOCKED:
06165 target = expand_builtin_fputs (arglist, target, true);
06166 if (target)
06167 return target;
06168 break;
06169
06170 case BUILT_IN_FPRINTF:
06171 target = expand_builtin_fprintf (exp, target, mode, false);
06172 if (target)
06173 return target;
06174 break;
06175
06176 case BUILT_IN_FPRINTF_UNLOCKED:
06177 target = expand_builtin_fprintf (exp, target, mode, true);
06178 if (target)
06179 return target;
06180 break;
06181
06182 case BUILT_IN_SPRINTF:
06183 target = expand_builtin_sprintf (arglist, target, mode);
06184 if (target)
06185 return target;
06186 break;
06187
06188 CASE_FLT_FN (BUILT_IN_SIGNBIT):
06189 target = expand_builtin_signbit (exp, target);
06190 if (target)
06191 return target;
06192 break;
06193
06194
06195 case BUILT_IN_UNWIND_INIT:
06196 expand_builtin_unwind_init ();
06197 return const0_rtx;
06198 case BUILT_IN_DWARF_CFA:
06199 return virtual_cfa_rtx;
06200 #ifdef DWARF2_UNWIND_INFO
06201 case BUILT_IN_DWARF_SP_COLUMN:
06202 return expand_builtin_dwarf_sp_column ();
06203 case BUILT_IN_INIT_DWARF_REG_SIZES:
06204 expand_builtin_init_dwarf_reg_sizes (TREE_VALUE (arglist));
06205 return const0_rtx;
06206 #endif
06207 case BUILT_IN_FROB_RETURN_ADDR:
06208 return expand_builtin_frob_return_addr (TREE_VALUE (arglist));
06209 case BUILT_IN_EXTRACT_RETURN_ADDR:
06210 return expand_builtin_extract_return_addr (TREE_VALUE (arglist));
06211 case BUILT_IN_EH_RETURN:
06212 expand_builtin_eh_return (TREE_VALUE (arglist),
06213 TREE_VALUE (TREE_CHAIN (arglist)));
06214 return const0_rtx;
06215 #ifdef EH_RETURN_DATA_REGNO
06216 case BUILT_IN_EH_RETURN_DATA_REGNO:
06217 return expand_builtin_eh_return_data_regno (arglist);
06218 #endif
06219 case BUILT_IN_EXTEND_POINTER:
06220 return expand_builtin_extend_pointer (TREE_VALUE (arglist));
06221
06222 case BUILT_IN_VA_START:
06223 case BUILT_IN_STDARG_START:
06224 return expand_builtin_va_start (arglist);
06225 case BUILT_IN_VA_END:
06226 return expand_builtin_va_end (arglist);
06227 case BUILT_IN_VA_COPY:
06228 return expand_builtin_va_copy (arglist);
06229 case BUILT_IN_EXPECT:
06230 return expand_builtin_expect (arglist, target);
06231 case BUILT_IN_PREFETCH:
06232 expand_builtin_prefetch (arglist);
06233 return const0_rtx;
06234
06235 case BUILT_IN_PROFILE_FUNC_ENTER:
06236 return expand_builtin_profile_func (false);
06237 case BUILT_IN_PROFILE_FUNC_EXIT:
06238 return expand_builtin_profile_func (true);
06239
06240 case BUILT_IN_INIT_TRAMPOLINE:
06241 return expand_builtin_init_trampoline (arglist);
06242 case BUILT_IN_ADJUST_TRAMPOLINE:
06243 return expand_builtin_adjust_trampoline (arglist);
06244
06245 case BUILT_IN_FORK:
06246 case BUILT_IN_EXECL:
06247 case BUILT_IN_EXECV:
06248 case BUILT_IN_EXECLP:
06249 case BUILT_IN_EXECLE:
06250 case BUILT_IN_EXECVP:
06251 case BUILT_IN_EXECVE:
06252 target = expand_builtin_fork_or_exec (fndecl, arglist, target, ignore);
06253 if (target)
06254 return target;
06255 break;
06256
06257 case BUILT_IN_FETCH_AND_ADD_1:
06258 case BUILT_IN_FETCH_AND_ADD_2:
06259 case BUILT_IN_FETCH_AND_ADD_4:
06260 case BUILT_IN_FETCH_AND_ADD_8:
06261 case BUILT_IN_FETCH_AND_ADD_16:
06262 mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_ADD_1);
06263 target = expand_builtin_sync_operation (mode, arglist, PLUS,
06264 false, target, ignore);
06265 if (target)
06266 return target;
06267 break;
06268
06269 case BUILT_IN_FETCH_AND_SUB_1:
06270 case BUILT_IN_FETCH_AND_SUB_2:
06271 case BUILT_IN_FETCH_AND_SUB_4:
06272 case BUILT_IN_FETCH_AND_SUB_8:
06273 case BUILT_IN_FETCH_AND_SUB_16:
06274 mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_SUB_1);
06275 target = expand_builtin_sync_operation (mode, arglist, MINUS,
06276 false, target, ignore);
06277 if (target)
06278 return target;
06279 break;
06280
06281 case BUILT_IN_FETCH_AND_OR_1:
06282 case BUILT_IN_FETCH_AND_OR_2:
06283 case BUILT_IN_FETCH_AND_OR_4:
06284 case BUILT_IN_FETCH_AND_OR_8:
06285 case BUILT_IN_FETCH_AND_OR_16:
06286 mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_OR_1);
06287 target = expand_builtin_sync_operation (mode, arglist, IOR,
06288 false, target, ignore);
06289 if (target)
06290 return target;
06291 break;
06292
06293 case BUILT_IN_FETCH_AND_AND_1:
06294 case BUILT_IN_FETCH_AND_AND_2:
06295 case BUILT_IN_FETCH_AND_AND_4:
06296 case BUILT_IN_FETCH_AND_AND_8:
06297 case BUILT_IN_FETCH_AND_AND_16:
06298 mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_AND_1);
06299 target = expand_builtin_sync_operation (mode, arglist, AND,
06300 false, target, ignore);
06301 if (target)
06302 return target;
06303 break;
06304
06305 case BUILT_IN_FETCH_AND_XOR_1:
06306 case BUILT_IN_FETCH_AND_XOR_2:
06307 case BUILT_IN_FETCH_AND_XOR_4:
06308 case BUILT_IN_FETCH_AND_XOR_8:
06309 case BUILT_IN_FETCH_AND_XOR_16:
06310 mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_XOR_1);
06311 target = expand_builtin_sync_operation (mode, arglist, XOR,
06312 false, target, ignore);
06313 if (target)
06314 return target;
06315 break;
06316
06317 case BUILT_IN_FETCH_AND_NAND_1:
06318 case BUILT_IN_FETCH_AND_NAND_2:
06319 case BUILT_IN_FETCH_AND_NAND_4:
06320 case BUILT_IN_FETCH_AND_NAND_8:
06321 case BUILT_IN_FETCH_AND_NAND_16:
06322 mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_NAND_1);
06323 target = expand_builtin_sync_operation (mode, arglist, NOT,
06324 false, target, ignore);
06325 if (target)
06326 return target;
06327 break;
06328
06329 case BUILT_IN_ADD_AND_FETCH_1:
06330 case BUILT_IN_ADD_AND_FETCH_2:
06331 case BUILT_IN_ADD_AND_FETCH_4:
06332 case BUILT_IN_ADD_AND_FETCH_8:
06333 case BUILT_IN_ADD_AND_FETCH_16:
06334 mode = get_builtin_sync_mode (fcode - BUILT_IN_ADD_AND_FETCH_1);
06335 target = expand_builtin_sync_operation (mode, arglist, PLUS,
06336 true, target, ignore);
06337 if (target)
06338 return target;
06339 break;
06340
06341 case BUILT_IN_SUB_AND_FETCH_1:
06342 case BUILT_IN_SUB_AND_FETCH_2:
06343 case BUILT_IN_SUB_AND_FETCH_4:
06344 case BUILT_IN_SUB_AND_FETCH_8:
06345 case BUILT_IN_SUB_AND_FETCH_16:
06346 mode = get_builtin_sync_mode (fcode - BUILT_IN_SUB_AND_FETCH_1);
06347 target = expand_builtin_sync_operation (mode, arglist, MINUS,
06348 true, target, ignore);
06349 if (target)
06350 return target;
06351 break;
06352
06353 case BUILT_IN_OR_AND_FETCH_1:
06354 case BUILT_IN_OR_AND_FETCH_2:
06355 case BUILT_IN_OR_AND_FETCH_4:
06356 case BUILT_IN_OR_AND_FETCH_8:
06357 case BUILT_IN_OR_AND_FETCH_16:
06358 mode = get_builtin_sync_mode (fcode - BUILT_IN_OR_AND_FETCH_1);
06359 target = expand_builtin_sync_operation (mode, arglist, IOR,
06360 true, target, ignore);
06361 if (target)
06362 return target;
06363 break;
06364
06365 case BUILT_IN_AND_AND_FETCH_1:
06366 case BUILT_IN_AND_AND_FETCH_2:
06367 case BUILT_IN_AND_AND_FETCH_4:
06368 case BUILT_IN_AND_AND_FETCH_8:
06369 case BUILT_IN_AND_AND_FETCH_16:
06370 mode = get_builtin_sync_mode (fcode - BUILT_IN_AND_AND_FETCH_1);
06371 target = expand_builtin_sync_operation (mode, arglist, AND,
06372 true, target, ignore);
06373 if (target)
06374 return target;
06375 break;
06376
06377 case BUILT_IN_XOR_AND_FETCH_1:
06378 case BUILT_IN_XOR_AND_FETCH_2:
06379 case BUILT_IN_XOR_AND_FETCH_4:
06380 case BUILT_IN_XOR_AND_FETCH_8:
06381 case BUILT_IN_XOR_AND_FETCH_16:
06382 mode = get_builtin_sync_mode (fcode - BUILT_IN_XOR_AND_FETCH_1);
06383 target = expand_builtin_sync_operation (mode, arglist, XOR,
06384 true, target, ignore);
06385 if (target)
06386 return target;
06387 break;
06388
06389 case BUILT_IN_NAND_AND_FETCH_1:
06390 case BUILT_IN_NAND_AND_FETCH_2:
06391 case BUILT_IN_NAND_AND_FETCH_4:
06392 case BUILT_IN_NAND_AND_FETCH_8:
06393 case BUILT_IN_NAND_AND_FETCH_16:
06394 mode = get_builtin_sync_mode (fcode - BUILT_IN_NAND_AND_FETCH_1);
06395 target = expand_builtin_sync_operation (mode, arglist, NOT,
06396 true, target, ignore);
06397 if (target)
06398 return target;
06399 break;
06400
06401 case BUILT_IN_BOOL_COMPARE_AND_SWAP_1:
06402 case BUILT_IN_BOOL_COMPARE_AND_SWAP_2:
06403 case BUILT_IN_BOOL_COMPARE_AND_SWAP_4:
06404 case BUILT_IN_BOOL_COMPARE_AND_SWAP_8:
06405 case BUILT_IN_BOOL_COMPARE_AND_SWAP_16:
06406 if (mode == VOIDmode)
06407 mode = TYPE_MODE (boolean_type_node);
06408 if (!target || !register_operand (target, mode))
06409 target = gen_reg_rtx (mode);
06410
06411 mode = get_builtin_sync_mode (fcode - BUILT_IN_BOOL_COMPARE_AND_SWAP_1);
06412 target = expand_builtin_compare_and_swap (mode, arglist, true, target);
06413 if (target)
06414 return target;
06415 break;
06416
06417 case BUILT_IN_VAL_COMPARE_AND_SWAP_1:
06418 case BUILT_IN_VAL_COMPARE_AND_SWAP_2:
06419 case BUILT_IN_VAL_COMPARE_AND_SWAP_4:
06420 case BUILT_IN_VAL_COMPARE_AND_SWAP_8:
06421 case BUILT_IN_VAL_COMPARE_AND_SWAP_16:
06422 mode = get_builtin_sync_mode (fcode - BUILT_IN_VAL_COMPARE_AND_SWAP_1);
06423 target = expand_builtin_compare_and_swap (mode, arglist, false, target);
06424 if (target)
06425 return target;
06426 break;
06427
06428 case BUILT_IN_LOCK_TEST_AND_SET_1:
06429 case BUILT_IN_LOCK_TEST_AND_SET_2:
06430 case BUILT_IN_LOCK_TEST_AND_SET_4:
06431 case BUILT_IN_LOCK_TEST_AND_SET_8:
06432 case BUILT_IN_LOCK_TEST_AND_SET_16:
06433 mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_TEST_AND_SET_1);
06434 target = expand_builtin_lock_test_and_set (mode, arglist, target);
06435 if (target)
06436 return target;
06437 break;
06438
06439 case BUILT_IN_LOCK_RELEASE_1:
06440 case BUILT_IN_LOCK_RELEASE_2:
06441 case BUILT_IN_LOCK_RELEASE_4:
06442 case BUILT_IN_LOCK_RELEASE_8:
06443 case BUILT_IN_LOCK_RELEASE_16:
06444 mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_RELEASE_1);
06445 expand_builtin_lock_release (mode, arglist);
06446 return const0_rtx;
06447
06448 case BUILT_IN_SYNCHRONIZE:
06449 expand_builtin_synchronize ();
06450 return const0_rtx;
06451
06452 case BUILT_IN_OBJECT_SIZE:
06453 return expand_builtin_object_size (exp);
06454
06455 case BUILT_IN_MEMCPY_CHK:
06456 case BUILT_IN_MEMPCPY_CHK:
06457 case BUILT_IN_MEMMOVE_CHK:
06458 case BUILT_IN_MEMSET_CHK:
06459 target = expand_builtin_memory_chk (exp, target, mode, fcode);
06460 if (target)
06461 return target;
06462 break;
06463
06464 case BUILT_IN_STRCPY_CHK:
06465 case BUILT_IN_STPCPY_CHK:
06466 case BUILT_IN_STRNCPY_CHK:
06467 case BUILT_IN_STRCAT_CHK:
06468 case BUILT_IN_SNPRINTF_CHK:
06469 case BUILT_IN_VSNPRINTF_CHK:
06470 maybe_emit_chk_warning (exp, fcode);
06471 break;
06472
06473 case BUILT_IN_SPRINTF_CHK:
06474 case BUILT_IN_VSPRINTF_CHK:
06475 maybe_emit_sprintf_chk_warning (exp, fcode);
06476 break;
06477
06478 default:
06479 break;
06480 }
06481
06482
06483
06484 return expand_call (exp, target, ignore);
06485 }
06486
06487
06488
06489
06490
06491
06492
06493 enum built_in_function
06494 builtin_mathfn_code (tree t)
06495 {
06496 tree fndecl, arglist, parmlist;
06497 tree argtype, parmtype;
06498
06499 if (TREE_CODE (t) != CALL_EXPR
06500 || TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR)
06501 return END_BUILTINS;
06502
06503 fndecl = get_callee_fndecl (t);
06504 if (fndecl == NULL_TREE
06505 || TREE_CODE (fndecl) != FUNCTION_DECL
06506 || ! DECL_BUILT_IN (fndecl)
06507 || DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
06508 return END_BUILTINS;
06509
06510 arglist = TREE_OPERAND (t, 1);
06511 parmlist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
06512 for (; parmlist; parmlist = TREE_CHAIN (parmlist))
06513 {
06514
06515
06516 parmtype = TREE_VALUE (parmlist);
06517 if (VOID_TYPE_P (parmtype))
06518 {
06519 if (arglist)
06520 return END_BUILTINS;
06521 return DECL_FUNCTION_CODE (fndecl);
06522 }
06523
06524 if (! arglist)
06525 return END_BUILTINS;
06526
06527 argtype = TREE_TYPE (TREE_VALUE (arglist));
06528
06529 if (SCALAR_FLOAT_TYPE_P (parmtype))
06530 {
06531 if (! SCALAR_FLOAT_TYPE_P (argtype))
06532 return END_BUILTINS;
06533 }
06534 else if (COMPLEX_FLOAT_TYPE_P (parmtype))
06535 {
06536 if (! COMPLEX_FLOAT_TYPE_P (argtype))
06537 return END_BUILTINS;
06538 }
06539 else if (POINTER_TYPE_P (parmtype))
06540 {
06541 if (! POINTER_TYPE_P (argtype))
06542 return END_BUILTINS;
06543 }
06544 else if (INTEGRAL_TYPE_P (parmtype))
06545 {
06546 if (! INTEGRAL_TYPE_P (argtype))
06547 return END_BUILTINS;
06548 }
06549 else
06550 return END_BUILTINS;
06551
06552 arglist = TREE_CHAIN (arglist);
06553 }
06554
06555
06556 return DECL_FUNCTION_CODE (fndecl);
06557 }
06558
06559
06560
06561
06562 static tree
06563 fold_builtin_constant_p (tree arglist)
06564 {
06565 if (arglist == 0)
06566 return 0;
06567
06568 arglist = TREE_VALUE (arglist);
06569
06570
06571
06572
06573 STRIP_NOPS (arglist);
06574
06575
06576 if (CONSTANT_CLASS_P (arglist)
06577 || (TREE_CODE (arglist) == CONSTRUCTOR
06578 && TREE_CONSTANT (arglist)))
06579 return integer_one_node;
06580 if (TREE_CODE (arglist) == ADDR_EXPR)
06581 {
06582 tree op = TREE_OPERAND (arglist, 0);
06583 if (TREE_CODE (op) == STRING_CST
06584 || (TREE_CODE (op) == ARRAY_REF
06585 && integer_zerop (TREE_OPERAND (op, 1))
06586 && TREE_CODE (TREE_OPERAND (op, 0)) == STRING_CST))
06587 return integer_one_node;
06588 }
06589
06590
06591
06592
06593
06594
06595
06596
06597 if (TREE_SIDE_EFFECTS (arglist)
06598 || AGGREGATE_TYPE_P (TREE_TYPE (arglist))
06599 || POINTER_TYPE_P (TREE_TYPE (arglist))
06600 || cfun == 0
06601 || folding_initializer)
06602 return integer_zero_node;
06603
06604 return 0;
06605 }
06606
06607
06608
06609
06610
06611
06612 static tree
06613 fold_builtin_expect (tree arglist)
06614 {
06615 tree arg, inner;
06616
06617 if (arglist == 0)
06618 return 0;
06619
06620 arg = TREE_VALUE (arglist);
06621
06622
06623 if (!TREE_INVARIANT (arg))
06624 return 0;
06625
06626
06627 inner = arg;
06628 STRIP_NOPS (inner);
06629 if (TREE_CODE (inner) == ADDR_EXPR)
06630 {
06631 do
06632 {
06633 inner = TREE_OPERAND (inner, 0);
06634 }
06635 while (TREE_CODE (inner) == COMPONENT_REF
06636 || TREE_CODE (inner) == ARRAY_REF);
06637 if (DECL_P (inner) && DECL_WEAK (inner))
06638 return 0;
06639 }
06640
06641
06642 return arg;
06643 }
06644
06645
06646
06647 static tree
06648 fold_builtin_classify_type (tree arglist)
06649 {
06650 if (arglist == 0)
06651 return build_int_cst (NULL_TREE, no_type_class);
06652
06653 return build_int_cst (NULL_TREE,
06654 type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
06655 }
06656
06657
06658
06659 static tree
06660 fold_builtin_strlen (tree arglist)
06661 {
06662 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
06663 return NULL_TREE;
06664 else
06665 {
06666 tree len = c_strlen (TREE_VALUE (arglist), 0);
06667
06668 if (len)
06669 {
06670
06671 if (size_type_node)
06672 len = fold_convert (size_type_node, len);
06673 return len;
06674 }
06675
06676 return NULL_TREE;
06677 }
06678 }
06679
06680
06681
06682 static tree
06683 fold_builtin_inf (tree type, int warn)
06684 {
06685 REAL_VALUE_TYPE real;
06686
06687
06688
06689
06690
06691
06692
06693
06694 if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) && warn)
06695 pedwarn ("target format does not support infinity");
06696
06697 real_inf (&real);
06698 return build_real (type, real);
06699 }
06700
06701
06702
06703 static tree
06704 fold_builtin_nan (tree arglist, tree type, int quiet)
06705 {
06706 REAL_VALUE_TYPE real;
06707 const char *str;
06708
06709 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
06710 return 0;
06711 str = c_getstr (TREE_VALUE (arglist));
06712 if (!str)
06713 return 0;
06714
06715 if (!real_nan (&real, str, quiet, TYPE_MODE (type)))
06716 return 0;
06717
06718 return build_real (type, real);
06719 }
06720
06721
06722
06723
06724 static bool
06725 integer_valued_real_p (tree t)
06726 {
06727 switch (TREE_CODE (t))
06728 {
06729 case FLOAT_EXPR:
06730 return true;
06731
06732 case ABS_EXPR:
06733 case SAVE_EXPR:
06734 case NON_LVALUE_EXPR:
06735 return integer_valued_real_p (TREE_OPERAND (t, 0));
06736
06737 case COMPOUND_EXPR:
06738 case MODIFY_EXPR:
06739 case BIND_EXPR:
06740 return integer_valued_real_p (TREE_OPERAND (t, 1));
06741
06742 case PLUS_EXPR:
06743 case MINUS_EXPR:
06744 case MULT_EXPR:
06745 case MIN_EXPR:
06746 case MAX_EXPR:
06747 return integer_valued_real_p (TREE_OPERAND (t, 0))
06748 && integer_valued_real_p (TREE_OPERAND (t, 1));
06749
06750 case COND_EXPR:
06751 return integer_valued_real_p (TREE_OPERAND (t, 1))
06752 && integer_valued_real_p (TREE_OPERAND (t, 2));
06753
06754 case REAL_CST:
06755 if (! TREE_CONSTANT_OVERFLOW (t))
06756 {
06757 REAL_VALUE_TYPE c, cint;
06758
06759 c = TREE_REAL_CST (t);
06760 real_trunc (&cint, TYPE_MODE (TREE_TYPE (t)), &c);
06761 return real_identical (&c, &cint);
06762 }
06763 break;
06764
06765 case NOP_EXPR:
06766 {
06767 tree type = TREE_TYPE (TREE_OPERAND (t, 0));
06768 if (TREE_CODE (type) == INTEGER_TYPE)
06769 return true;
06770 if (TREE_CODE (type) == REAL_TYPE)
06771 return integer_valued_real_p (TREE_OPERAND (t, 0));
06772 break;
06773 }
06774
06775 case CALL_EXPR:
06776 switch (builtin_mathfn_code (t))
06777 {
06778 CASE_FLT_FN (BUILT_IN_CEIL):
06779 CASE_FLT_FN (BUILT_IN_FLOOR):
06780 CASE_FLT_FN (BUILT_IN_NEARBYINT):
06781 CASE_FLT_FN (BUILT_IN_RINT):
06782 CASE_FLT_FN (BUILT_IN_ROUND):
06783 CASE_FLT_FN (BUILT_IN_TRUNC):
06784 return true;
06785
06786 default:
06787 break;
06788 }
06789 break;
06790
06791 default:
06792 break;
06793 }
06794 return false;
06795 }
06796
06797
06798
06799
06800
06801 static tree
06802 fold_trunc_transparent_mathfn (tree fndecl, tree arglist)
06803 {
06804 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
06805 tree arg;
06806
06807 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06808 return 0;
06809
06810 arg = TREE_VALUE (arglist);
06811
06812 if (fcode == builtin_mathfn_code (arg))
06813 return arg;
06814
06815
06816
06817 if (! flag_errno_math && integer_valued_real_p (arg))
06818 return arg;
06819
06820 if (optimize)
06821 {
06822 tree arg0 = strip_float_extensions (arg);
06823 tree ftype = TREE_TYPE (TREE_TYPE (fndecl));
06824 tree newtype = TREE_TYPE (arg0);
06825 tree decl;
06826
06827 if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype)
06828 && (decl = mathfn_built_in (newtype, fcode)))
06829 {
06830 arglist =
06831 build_tree_list (NULL_TREE, fold_convert (newtype, arg0));
06832 return fold_convert (ftype,
06833 build_function_call_expr (decl, arglist));
06834 }
06835 }
06836 return 0;
06837 }
06838
06839
06840
06841
06842 static tree
06843 fold_fixed_mathfn (tree fndecl, tree arglist)
06844 {
06845 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
06846 tree arg;
06847
06848 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06849 return 0;
06850
06851 arg = TREE_VALUE (arglist);
06852
06853
06854
06855 if (! flag_errno_math && integer_valued_real_p (arg))
06856 return fold_build1 (FIX_TRUNC_EXPR, TREE_TYPE (TREE_TYPE (fndecl)), arg);
06857
06858 if (optimize)
06859 {
06860 tree ftype = TREE_TYPE (arg);
06861 tree arg0 = strip_float_extensions (arg);
06862 tree newtype = TREE_TYPE (arg0);
06863 tree decl;
06864
06865 if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype)
06866 && (decl = mathfn_built_in (newtype, fcode)))
06867 {
06868 arglist =
06869 build_tree_list (NULL_TREE, fold_convert (newtype, arg0));
06870 return build_function_call_expr (decl, arglist);
06871 }
06872 }
06873
06874
06875
06876 if (TYPE_PRECISION (long_long_integer_type_node)
06877 == TYPE_PRECISION (long_integer_type_node))
06878 {
06879 tree newfn = NULL_TREE;
06880 switch (fcode)
06881 {
06882 CASE_FLT_FN (BUILT_IN_LLCEIL):
06883 newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LCEIL);
06884 break;
06885
06886 CASE_FLT_FN (BUILT_IN_LLFLOOR):
06887 newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LFLOOR);
06888 break;
06889
06890 CASE_FLT_FN (BUILT_IN_LLROUND):
06891 newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LROUND);
06892 break;
06893
06894 CASE_FLT_FN (BUILT_IN_LLRINT):
06895 newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LRINT);
06896 break;
06897
06898 default:
06899 break;
06900 }
06901
06902 if (newfn)
06903 {
06904 tree newcall = build_function_call_expr (newfn, arglist);
06905 return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), newcall);
06906 }
06907 }
06908
06909 return 0;
06910 }
06911
06912
06913
06914
06915
06916
06917 static tree
06918 fold_builtin_cabs (tree arglist, tree type, tree fndecl)
06919 {
06920 tree arg;
06921
06922 if (!arglist || TREE_CHAIN (arglist))
06923 return NULL_TREE;
06924
06925 arg = TREE_VALUE (arglist);
06926 if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE
06927 || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
06928 return NULL_TREE;
06929
06930
06931 if (flag_unsafe_math_optimizations
06932 && TREE_CODE (arg) == COMPLEX_CST
06933 && TREE_CODE (TREE_REALPART (arg)) == REAL_CST
06934 && TREE_CODE (TREE_IMAGPART (arg)) == REAL_CST
06935 && ! TREE_CONSTANT_OVERFLOW (TREE_REALPART (arg))
06936 && ! TREE_CONSTANT_OVERFLOW (TREE_IMAGPART (arg)))
06937 {
06938 REAL_VALUE_TYPE r, i;
06939
06940 r = TREE_REAL_CST (TREE_REALPART (arg));
06941 i = TREE_REAL_CST (TREE_IMAGPART (arg));
06942
06943 real_arithmetic (&r, MULT_EXPR, &r, &r);
06944 real_arithmetic (&i, MULT_EXPR, &i, &i);
06945 real_arithmetic (&r, PLUS_EXPR, &r, &i);
06946 if (real_sqrt (&r, TYPE_MODE (type), &r)
06947 || ! flag_trapping_math)
06948 return build_real (type, r);
06949 }
06950
06951
06952 if (TREE_CODE (arg) == COMPLEX_EXPR
06953 && real_zerop (TREE_OPERAND (arg, 0)))
06954 return fold_build1 (ABS_EXPR, type, TREE_OPERAND (arg, 1));
06955 if (TREE_CODE (arg) == COMPLEX_EXPR
06956 && real_zerop (TREE_OPERAND (arg, 1)))
06957 return fold_build1 (ABS_EXPR, type, TREE_OPERAND (arg, 0));
06958
06959
06960 if (TREE_CODE (arg) == NEGATE_EXPR
06961 || TREE_CODE (arg) == CONJ_EXPR)
06962 {
06963 tree arglist = build_tree_list (NULL_TREE, TREE_OPERAND (arg, 0));
06964 return build_function_call_expr (fndecl, arglist);
06965 }
06966
06967
06968 if (flag_unsafe_math_optimizations
06969 && optimize && !optimize_size)
06970 {
06971 tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
06972
06973 if (sqrtfn != NULL_TREE)
06974 {
06975 tree rpart, ipart, result, arglist;
06976
06977 arg = builtin_save_expr (arg);
06978
06979 rpart = fold_build1 (REALPART_EXPR, type, arg);
06980 ipart = fold_build1 (IMAGPART_EXPR, type, arg);
06981
06982 rpart = builtin_save_expr (rpart);
06983 ipart = builtin_save_expr (ipart);
06984
06985 result = fold_build2 (PLUS_EXPR, type,
06986 fold_build2 (MULT_EXPR, type,
06987 rpart, rpart),
06988 fold_build2 (MULT_EXPR, type,
06989 ipart, ipart));
06990
06991 arglist = build_tree_list (NULL_TREE, result);
06992 return build_function_call_expr (sqrtfn, arglist);
06993 }
06994 }
06995
06996 return NULL_TREE;
06997 }
06998
06999
07000
07001
07002 static tree
07003 fold_builtin_sqrt (tree arglist, tree type)
07004 {
07005
07006 enum built_in_function fcode;
07007 tree arg = TREE_VALUE (arglist);
07008
07009 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
07010 return NULL_TREE;
07011
07012
07013 if (TREE_CODE (arg) == REAL_CST
07014 && ! TREE_CONSTANT_OVERFLOW (arg))
07015 {
07016 REAL_VALUE_TYPE r, x;
07017
07018 x = TREE_REAL_CST (arg);
07019 if (real_sqrt (&r, TYPE_MODE (type), &x)
07020 || (!flag_trapping_math && !flag_errno_math))
07021 return build_real (type, r);
07022 }
07023
07024
07025 fcode = builtin_mathfn_code (arg);
07026 if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
07027 {
07028 tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
07029 arg = fold_build2 (MULT_EXPR, type,
07030 TREE_VALUE (TREE_OPERAND (arg, 1)),
07031 build_real (type, dconsthalf));
07032 arglist = build_tree_list (NULL_TREE, arg);
07033 return build_function_call_expr (expfn, arglist);
07034 }
07035
07036
07037 if (flag_unsafe_math_optimizations && BUILTIN_ROOT_P (fcode))
07038 {
07039 tree powfn = mathfn_built_in (type, BUILT_IN_POW);
07040
07041 if (powfn)
07042 {
07043 tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
07044 tree tree_root;
07045
07046 REAL_VALUE_TYPE dconstroot =
07047 BUILTIN_SQRT_P (fcode) ? dconsthalf : dconstthird;
07048
07049
07050 SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
07051 dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
07052 tree_root = build_real (type, dconstroot);
07053 arglist = tree_cons (NULL_TREE, arg0,
07054 build_tree_list (NULL_TREE, tree_root));
07055 return build_function_call_expr (powfn, arglist);
07056 }
07057 }
07058
07059
07060 if (flag_unsafe_math_optimizations
07061 && (fcode == BUILT_IN_POW
07062 || fcode == BUILT_IN_POWF
07063 || fcode == BUILT_IN_POWL))
07064 {
07065 tree powfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
07066 tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
07067 tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
07068 tree narg1;
07069 if (!tree_expr_nonnegative_p (arg0))
07070 arg0 = build1 (ABS_EXPR, type, arg0);
07071 narg1 = fold_build2 (MULT_EXPR, type, arg1,
07072 build_real (type, dconsthalf));
07073 arglist = tree_cons (NULL_TREE, arg0,
07074 build_tree_list (NULL_TREE, narg1));
07075 return build_function_call_expr (powfn, arglist);
07076 }
07077
07078 return NULL_TREE;
07079 }
07080
07081
07082
07083 static tree
07084 fold_builtin_cbrt (tree arglist, tree type)
07085 {
07086 tree arg = TREE_VALUE (arglist);
07087 const enum built_in_function fcode = builtin_mathfn_code (arg);
07088
07089 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
07090 return NULL_TREE;
07091
07092
07093 if (real_zerop (arg) || real_onep (arg) || real_minus_onep (arg))
07094 return arg;
07095
07096 if (flag_unsafe_math_optimizations)
07097 {
07098
07099 if (BUILTIN_EXPONENT_P (fcode))
07100 {
07101 tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
07102 const REAL_VALUE_TYPE third_trunc =
07103 real_value_truncate (TYPE_MODE (type), dconstthird);
07104 arg = fold_build2 (MULT_EXPR, type,
07105 TREE_VALUE (TREE_OPERAND (arg, 1)),
07106 build_real (type, third_trunc));
07107 arglist = build_tree_list (NULL_TREE, arg);
07108 return build_function_call_expr (expfn, arglist);
07109 }
07110
07111
07112 if (BUILTIN_SQRT_P (fcode))
07113 {
07114 tree powfn = mathfn_built_in (type, BUILT_IN_POW);
07115
07116 if (powfn)
07117 {
07118 tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
07119 tree tree_root;
07120 REAL_VALUE_TYPE dconstroot = dconstthird;
07121
07122 SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
07123 dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
07124 tree_root = build_real (type, dconstroot);
07125 arglist = tree_cons (NULL_TREE, arg0,
07126 build_tree_list (NULL_TREE, tree_root));
07127 return build_function_call_expr (powfn, arglist);
07128 }
07129 }
07130
07131
07132 if (BUILTIN_CBRT_P (fcode))
07133 {
07134 tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
07135 if (tree_expr_nonnegative_p (arg0))
07136 {
07137 tree powfn = mathfn_built_in (type, BUILT_IN_POW);
07138
07139 if (powfn)
07140 {
07141 tree tree_root;
07142 REAL_VALUE_TYPE dconstroot;
07143
07144 real_arithmetic (&dconstroot, MULT_EXPR, &dconstthird, &dconstthird);
07145 dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
07146 tree_root = build_real (type, dconstroot);
07147 arglist = tree_cons (NULL_TREE, arg0,
07148 build_tree_list (NULL_TREE, tree_root));
07149 return build_function_call_expr (powfn, arglist);
07150 }
07151 }
07152 }
07153
07154
07155 if (fcode == BUILT_IN_POW || fcode == BUILT_IN_POWF
07156 || fcode == BUILT_IN_POWL)
07157 {
07158 tree arg00 = TREE_VALUE (TREE_OPERAND (arg, 1));
07159 tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
07160 if (tree_expr_nonnegative_p (arg00))
07161 {
07162 tree powfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
07163 const REAL_VALUE_TYPE dconstroot
07164 = real_value_truncate (TYPE_MODE (type), dconstthird);
07165 tree narg01 = fold_build2 (MULT_EXPR, type, arg01,
07166 build_real (type, dconstroot));
07167 arglist = tree_cons (NULL_TREE, arg00,
07168 build_tree_list (NULL_TREE, narg01));
07169 return build_function_call_expr (powfn, arglist);
07170 }
07171 }
07172 }
07173 return NULL_TREE;
07174 }
07175
07176
07177
07178 static tree
07179 fold_builtin_sin (tree arglist)
07180 {
07181 tree arg = TREE_VALUE (arglist);
07182
07183 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
07184 return NULL_TREE;
07185
07186
07187 if (real_zerop (arg))
07188 return arg;
07189
07190 return NULL_TREE;
07191 }
07192
07193
07194
07195 static tree
07196 fold_builtin_cos (tree arglist, tree type, tree fndecl)
07197 {
07198 tree arg = TREE_VALUE (arglist);
07199
07200 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
07201 return NULL_TREE;
07202
07203
07204 if (real_zerop (arg))
07205 return build_real (type, dconst1);
07206
07207
07208 if (TREE_CODE (arg) == NEGATE_EXPR)
07209 {
07210 tree args = build_tree_list (NULL_TREE,
07211 TREE_OPERAND (arg, 0));
07212 return build_function_call_expr (fndecl, args);
07213 }
07214
07215 return NULL_TREE;
07216 }
07217
07218
07219
07220 static tree
07221 fold_builtin_tan (tree arglist)
07222 {
07223 enum built_in_function fcode;
07224 tree arg = TREE_VALUE (arglist);
07225
07226 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
07227 return NULL_TREE;
07228
07229
07230 if (real_zerop (arg))
07231 return arg;
07232
07233
07234 fcode = builtin_mathfn_code (arg);
07235 if (flag_unsafe_math_optimizations
07236 && (fcode == BUILT_IN_ATAN
07237 || fcode == BUILT_IN_ATANF
07238 || fcode == BUILT_IN_ATANL))
07239 return TREE_VALUE (TREE_OPERAND (arg, 1));
07240
07241 return NULL_TREE;
07242 }
07243
07244
07245
07246
07247 static tree
07248 fold_builtin_atan (tree arglist, tree type)
07249 {
07250
07251 tree arg = TREE_VALUE (arglist);
07252
07253 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
07254 return NULL_TREE;
07255
07256
07257 if (real_zerop (arg))
07258 return arg;
07259
07260
07261 if (real_onep (arg))
07262 {
07263 REAL_VALUE_TYPE cst;
07264
07265 real_convert (&cst, TYPE_MODE (type), &dconstpi);
07266 SET_REAL_EXP (&cst, REAL_EXP (&cst) - 2);
07267 return build_real (type, cst);
07268 }
07269
07270 return NULL_TREE;
07271 }
07272
07273
07274
07275
07276 static tree
07277 fold_builtin_trunc (tree fndecl, tree arglist)
07278 {
07279 tree arg;
07280
07281 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
07282 return 0;
07283
07284
07285 arg = TREE_VALUE (arglist);
07286 if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
07287 {
07288 REAL_VALUE_TYPE r, x;
07289 tree type = TREE_TYPE (TREE_TYPE (fndecl));
07290
07291 x = TREE_REAL_CST (arg);
07292 real_trunc (&r, TYPE_MODE (type), &x);
07293 return build_real (type, r);
07294 }
07295
07296 return fold_trunc_transparent_mathfn (fndecl, arglist);
07297 }
07298
07299
07300
07301
07302 static tree
07303 fold_builtin_floor (tree fndecl, tree arglist)
07304 {
07305 tree arg;
07306
07307 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
07308 return 0;
07309
07310
07311 arg = TREE_VALUE (arglist);
07312 if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
07313 {
07314 REAL_VALUE_TYPE x;
07315
07316 x = TREE_REAL_CST (arg);
07317 if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
07318 {
07319 tree type = TREE_TYPE (TREE_TYPE (fndecl));
07320 REAL_VALUE_TYPE r;
07321
07322 real_floor (&r, TYPE_MODE (type), &x);
07323 return build_real (type, r);
07324 }
07325 }
07326
07327 return fold_trunc_transparent_mathfn (fndecl, arglist);
07328 }
07329
07330
07331
07332
07333 static tree
07334 fold_builtin_ceil (tree fndecl, tree arglist)
07335 {
07336 tree arg;
07337
07338 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
07339 return 0;
07340
07341
07342 arg = TREE_VALUE (arglist);
07343 if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
07344 {
07345 REAL_VALUE_TYPE x;
07346
07347 x = TREE_REAL_CST (arg);
07348 if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
07349 {
07350 tree type = TREE_TYPE (TREE_TYPE (fndecl));
07351 REAL_VALUE_TYPE r;
07352
07353 real_ceil (&r, TYPE_MODE (type), &x);
07354 return build_real (type, r);
07355 }
07356 }
07357
07358 return fold_trunc_transparent_mathfn (fndecl, arglist);
07359 }
07360
07361
07362
07363
07364 static tree
07365 fold_builtin_round (tree fndecl, tree arglist)
07366 {
07367 tree arg;
07368
07369 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
07370 return 0;
07371
07372
07373 arg = TREE_VALUE (arglist);
07374 if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
07375 {
07376 REAL_VALUE_TYPE x;
07377
07378 x = TREE_REAL_CST (arg);
07379 if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
07380 {
07381 tree type = TREE_TYPE (TREE_TYPE (fndecl));
07382 REAL_VALUE_TYPE r;
07383
07384 real_round (&r, TYPE_MODE (type), &x);
07385 return build_real (type, r);
07386 }
07387 }
07388
07389 return fold_trunc_transparent_mathfn (fndecl, arglist);
07390 }
07391
07392
07393
07394
07395
07396 static tree
07397 fold_builtin_int_roundingfn (tree fndecl, tree arglist)
07398 {
07399 tree arg;
07400
07401 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
07402 return 0;
07403
07404
07405 arg = TREE_VALUE (arglist);
07406 if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
07407 {
07408 const REAL_VALUE_TYPE x = TREE_REAL_CST (arg);
07409
07410 if (! REAL_VALUE_ISNAN (x) && ! REAL_VALUE_ISINF (x))
07411 {
07412 tree itype = TREE_TYPE (TREE_TYPE (fndecl));
07413 tree ftype = TREE_TYPE (arg), result;
07414 HOST_WIDE_INT hi, lo;
07415 REAL_VALUE_TYPE r;
07416
07417 switch (DECL_FUNCTION_CODE (fndecl))
07418 {
07419 CASE_FLT_FN (BUILT_IN_LFLOOR):
07420 CASE_FLT_FN (BUILT_IN_LLFLOOR):
07421 real_floor (&r, TYPE_MODE (ftype), &x);
07422 break;
07423
07424 CASE_FLT_FN (BUILT_IN_LCEIL):
07425 CASE_FLT_FN (BUILT_IN_LLCEIL):
07426 real_ceil (&r, TYPE_MODE (ftype), &x);
07427 break;
07428
07429 CASE_FLT_FN (BUILT_IN_LROUND):
07430 CASE_FLT_FN (BUILT_IN_LLROUND):
07431 real_round (&r, TYPE_MODE (ftype), &x);
07432 break;
07433
07434 default:
07435 gcc_unreachable ();
07436 }
07437
07438 REAL_VALUE_TO_INT (&lo, &hi, r);
07439 result = build_int_cst_wide (NULL_TREE, lo, hi);
07440 if (int_fits_type_p (result, itype))
07441 return fold_convert (itype, result);
07442 }
07443 }
07444
07445 return fold_fixed_mathfn (fndecl, arglist);
07446 }
07447
07448
07449
07450
07451
07452 static tree
07453 fold_builtin_bitop (tree fndecl, tree arglist)
07454 {
07455 tree arg;
07456
07457 if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
07458 return NULL_TREE;
07459
07460
07461 arg = TREE_VALUE (arglist);
07462 if (TREE_CODE (arg) == INTEGER_CST && ! TREE_CONSTANT_OVERFLOW (arg))
07463 {
07464 HOST_WIDE_INT hi, width, result;
07465 unsigned HOST_WIDE_INT lo;
07466 tree type;
07467
07468 type = TREE_TYPE (arg);
07469 width = TYPE_PRECISION (type);
07470 lo = TREE_INT_CST_LOW (arg);
07471
07472
07473 if (width > HOST_BITS_PER_WIDE_INT)
07474 {
07475 hi = TREE_INT_CST_HIGH (arg);
07476 if (width < 2 * HOST_BITS_PER_WIDE_INT)
07477 hi &= ~((HOST_WIDE_INT) (-1) >> (width - HOST_BITS_PER_WIDE_INT));
07478 }
07479 else
07480 {
07481 hi = 0;
07482 if (width < HOST_BITS_PER_WIDE_INT)
07483 lo &= ~((unsigned HOST_WIDE_INT) (-1) << width);
07484 }
07485
07486 switch (DECL_FUNCTION_CODE (fndecl))
07487 {
07488 CASE_INT_FN (BUILT_IN_FFS):
07489 if (lo != 0)
07490 result = exact_log2 (lo & -lo) + 1;
07491 else if (hi != 0)
07492 result = HOST_BITS_PER_WIDE_INT + exact_log2 (hi & -hi) + 1;
07493 else
07494 result = 0;
07495 break;
07496
07497 CASE_INT_FN (BUILT_IN_CLZ):
07498 if (hi != 0)
07499 result = width - floor_log2 (hi) - 1 - HOST_BITS_PER_WIDE_INT;
07500 else if (lo != 0)
07501 result = width - floor_log2 (lo) - 1;
07502 else if (! CLZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (type), result))
07503 result = width;
07504 break;
07505
07506 CASE_INT_FN (BUILT_IN_CTZ):
07507 if (lo != 0)
07508 result = exact_log2 (lo & -lo);
07509 else if (hi != 0)
07510 result = HOST_BITS_PER_WIDE_INT + exact_log2 (hi & -hi);
07511 else if (! CTZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (type), result))
07512 result = width;
07513 break;
07514
07515 CASE_INT_FN (BUILT_IN_POPCOUNT):
07516 result = 0;
07517 while (lo)
07518 result++, lo &= lo - 1;
07519 while (hi)
07520 result++, hi &= hi - 1;
07521 break;
07522
07523 CASE_INT_FN (BUILT_IN_PARITY):
07524 result = 0;
07525 while (lo)
07526 result++, lo &= lo - 1;
07527 while (hi)
07528 result++, hi &= hi - 1;
07529 result &= 1;
07530 break;
07531
07532 default:
07533 gcc_unreachable ();
07534 }
07535
07536 return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), result);
07537 }
07538
07539 return NULL_TREE;
07540 }
07541
07542
07543
07544 static bool
07545 real_dconstp (tree expr, const REAL_VALUE_TYPE *value)
07546 {
07547 STRIP_NOPS (expr);
07548
07549 return ((TREE_CODE (expr) == REAL_CST
07550 && ! TREE_CONSTANT_OVERFLOW (expr)
07551 && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), *value))
07552 || (TREE_CODE (expr) == COMPLEX_CST
07553 && real_dconstp (TREE_REALPART (expr), value)
07554 && real_zerop (TREE_IMAGPART (expr))));
07555 }
07556
07557
07558
07559
07560
07561 static tree
07562 fold_builtin_logarithm (tree fndecl, tree arglist,
07563 const REAL_VALUE_TYPE *value)
07564 {
07565 if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
07566 {
07567 tree type = TREE_TYPE (TREE_TYPE (fndecl));
07568 tree arg = TREE_VALUE (arglist);
07569 const enum built_in_function fcode = builtin_mathfn_code (arg);
07570
07571
07572 if (real_onep (arg))
07573 return build_real (type, dconst0);
07574
07575
07576
07577 if (exact_real_truncate (TYPE_MODE (type), value)
07578 || flag_unsafe_math_optimizations)
07579 {
07580 const REAL_VALUE_TYPE value_truncate =
07581 real_value_truncate (TYPE_MODE (type), *value);
07582 if (real_dconstp (arg, &value_truncate))
07583 return build_real (type, dconst1);
07584 }
07585
07586
07587 if (flag_unsafe_math_optimizations
07588 && ((value == &dconste
07589 && (fcode == BUILT_IN_EXP
07590 || fcode == BUILT_IN_EXPF
07591 || fcode == BUILT_IN_EXPL))
07592 || (value == &dconst2
07593 && (fcode == BUILT_IN_EXP2
07594 || fcode == BUILT_IN_EXP2F
07595 || fcode == BUILT_IN_EXP2L))
07596 || (value == &dconst10 && (BUILTIN_EXP10_P (fcode)))))
07597 return fold_convert (type, TREE_VALUE (TREE_OPERAND (arg, 1)));
07598
07599
07600
07601
07602 if (flag_unsafe_math_optimizations)
07603 {
07604 tree exponent = 0, x = 0;
07605
07606 switch (fcode)
07607 {
07608 CASE_FLT_FN (BUILT_IN_EXP):
07609
07610 x = build_real (type,
07611 real_value_truncate (TYPE_MODE (type), dconste));
07612 exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
07613 break;
07614 CASE_FLT_FN (BUILT_IN_EXP2):
07615
07616 x = build_real (type, dconst2);
07617 exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
07618 break;
07619 CASE_FLT_FN (BUILT_IN_EXP10):
07620 CASE_FLT_FN (BUILT_IN_POW10):
07621
07622 x = build_real (type, dconst10);
07623 exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
07624 break;
07625 CASE_FLT_FN (BUILT_IN_SQRT):
07626
07627 x = TREE_VALUE (TREE_OPERAND (arg, 1));
07628 exponent = build_real (type, dconsthalf);
07629 break;
07630 CASE_FLT_FN (BUILT_IN_CBRT):
07631
07632 x = TREE_VALUE (TREE_OPERAND (arg, 1));
07633 exponent = build_real (type, real_value_truncate (TYPE_MODE (type),
07634 dconstthird));
07635 break;
07636 CASE_FLT_FN (BUILT_IN_POW):
07637
07638 x = TREE_VALUE (TREE_OPERAND (arg, 1));
07639 exponent = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
07640 break;
07641 default:
07642 break;
07643 }
07644
07645
07646 if (x && exponent)
07647 {
07648 tree logfn;
07649 arglist = build_tree_list (NULL_TREE, x);
07650 logfn = build_function_call_expr (fndecl, arglist);
07651 return fold_build2 (MULT_EXPR, type, exponent, logfn);
07652 }
07653 }
07654 }
07655
07656 return 0;
07657 }
07658
07659
07660
07661 static tree
07662 fold_builtin_pow (tree fndecl, tree arglist, tree type)
07663 {
07664 tree arg0 = TREE_VALUE (arglist);
07665 tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
07666
07667 if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
07668 return NULL_TREE;
07669
07670
07671 if (real_onep (arg0))
07672 return omit_one_operand (type, build_real (type, dconst1), arg1);
07673
07674 if (TREE_CODE (arg1) == REAL_CST
07675 && ! TREE_CONSTANT_OVERFLOW (arg1))
07676 {
07677 REAL_VALUE_TYPE cint;
07678 REAL_VALUE_TYPE c;
07679 HOST_WIDE_INT n;
07680
07681 c = TREE_REAL_CST (arg1);
07682
07683
07684 if (REAL_VALUES_EQUAL (c, dconst0))
07685 return omit_one_operand (type, build_real (type, dconst1),
07686 arg0);
07687
07688
07689 if (REAL_VALUES_EQUAL (c, dconst1))
07690 return arg0;
07691
07692
07693 if (REAL_VALUES_EQUAL (c, dconstm1))
07694 return fold_build2 (RDIV_EXPR, type,
07695 build_real (type, dconst1), arg0);
07696
07697
07698 if (flag_unsafe_math_optimizations
07699 && REAL_VALUES_EQUAL (c, dconsthalf))
07700 {
07701 tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
07702
07703 if (sqrtfn != NULL_TREE)
07704 {
07705 tree arglist = build_tree_list (NULL_TREE, arg0);
07706 return build_function_call_expr (sqrtfn, arglist);
07707 }
07708 }
07709
07710
07711 n = real_to_integer (&c);
07712 real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
07713 if (real_identical (&c, &cint))
07714 {
07715
07716 if (TREE_CODE (arg0) == REAL_CST
07717 && ! TREE_CONSTANT_OVERFLOW (arg0))
07718 {
07719 REAL_VALUE_TYPE x;
07720 bool inexact;
07721
07722 x = TREE_REAL_CST (arg0);
07723 inexact = real_powi (&x, TYPE_MODE (type), &x, n);
07724 if (flag_unsafe_math_optimizations || !inexact)
07725 return build_real (type, x);
07726 }
07727
07728
07729 if ((n & 1) == 0 && flag_unsafe_math_optimizations)
07730 {
07731 tree narg0 = fold_strip_sign_ops (arg0);
07732 if (narg0)
07733 {
07734 arglist = build_tree_list (NULL_TREE, arg1);
07735 arglist = tree_cons (NULL_TREE, narg0, arglist);
07736 return build_function_call_expr (fndecl, arglist);
07737 }
07738 }
07739 }
07740 }
07741
07742 if (flag_unsafe_math_optimizations)
07743 {
07744 const enum built_in_function fcode = builtin_mathfn_code (arg0);
07745
07746
07747 if (BUILTIN_EXPONENT_P (fcode))
07748 {
07749 tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
07750 tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
07751 arg = fold_build2 (MULT_EXPR, type, arg, arg1);
07752 arglist = build_tree_list (NULL_TREE, arg);
07753 return build_function_call_expr (expfn, arglist);
07754 }
07755
07756
07757 if (BUILTIN_SQRT_P (fcode))
07758 {
07759 tree narg0 = TREE_VALUE (TREE_OPERAND (arg0, 1));
07760 tree narg1 = fold_build2 (MULT_EXPR, type, arg1,
07761 build_real (type, dconsthalf));
07762
07763 arglist = tree_cons (NULL_TREE, narg0,
07764 build_tree_list (NULL_TREE, narg1));
07765 return build_function_call_expr (fndecl, arglist);
07766 }
07767
07768
07769 if (BUILTIN_CBRT_P (fcode))
07770 {
07771 tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
07772 if (tree_expr_nonnegative_p (arg))
07773 {
07774 const REAL_VALUE_TYPE dconstroot
07775 = real_value_truncate (TYPE_MODE (type), dconstthird);
07776 tree narg1 = fold_build2 (MULT_EXPR, type, arg1,
07777 build_real (type, dconstroot));
07778 arglist = tree_cons (NULL_TREE, arg,
07779 build_tree_list (NULL_TREE, narg1));
07780 return build_function_call_expr (fndecl, arglist);
07781 }
07782 }
07783
07784
07785 if (fcode == BUILT_IN_POW || fcode == BUILT_IN_POWF
07786 || fcode == BUILT_IN_POWL)
07787 {
07788 tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
07789 tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
07790 tree narg1 = fold_build2 (MULT_EXPR, type, arg01, arg1);
07791 arglist = tree_cons (NULL_TREE, arg00,
07792 build_tree_list (NULL_TREE, narg1));
07793 return build_function_call_expr (fndecl, arglist);
07794 }
07795 }
07796
07797 return NULL_TREE;
07798 }
07799
07800
07801
07802 static tree
07803 fold_builtin_powi (tree fndecl ATTRIBUTE_UNUSED, tree arglist, tree type)
07804 {
07805 tree arg0 = TREE_VALUE (arglist);
07806 tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
07807
07808 if (!validate_arglist (arglist, REAL_TYPE, INTEGER_TYPE, VOID_TYPE))
07809 return NULL_TREE;
07810
07811
07812 if (real_onep (arg0))
07813 return omit_one_operand (type, build_real (type, dconst1), arg1);
07814
07815 if (host_integerp (arg1, 0))
07816 {
07817 HOST_WIDE_INT c = TREE_INT_CST_LOW (arg1);
07818
07819
07820 if (TREE_CODE (arg0) == REAL_CST
07821 && ! TREE_CONSTANT_OVERFLOW (arg0))
07822 {
07823 REAL_VALUE_TYPE x;
07824 x = TREE_REAL_CST (arg0);
07825 real_powi (&x, TYPE_MODE (type), &x, c);
07826 return build_real (type, x);
07827 }
07828
07829
07830 if (c == 0)
07831 return omit_one_operand (type, build_real (type, dconst1),
07832 arg0);
07833
07834
07835 if (c == 1)
07836 return arg0;
07837
07838
07839 if (c == -1)
07840 return fold_build2 (RDIV_EXPR, type,
07841 build_real (type, dconst1), arg0);
07842 }
07843
07844 return NULL_TREE;
07845 }
07846
07847
07848
07849
07850
07851 static tree
07852 fold_builtin_exponent (tree fndecl, tree arglist,
07853 const REAL_VALUE_TYPE *value)
07854 {
07855 if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
07856 {
07857 tree type = TREE_TYPE (TREE_TYPE (fndecl));
07858 tree arg = TREE_VALUE (arglist);
07859
07860
07861 if (real_zerop (arg))
07862 return build_real (type, dconst1);
07863
07864
07865 if (real_onep (arg))
07866 {
07867 REAL_VALUE_TYPE cst;
07868
07869 real_convert (&cst, TYPE_MODE (type), value);
07870 return build_real (type, cst);
07871 }
07872
07873
07874 if (flag_unsafe_math_optimizations
07875 && TREE_CODE (arg) == REAL_CST
07876 && ! TREE_CONSTANT_OVERFLOW (arg))
07877 {
07878 REAL_VALUE_TYPE cint;
07879 REAL_VALUE_TYPE c;
07880 HOST_WIDE_INT n;
07881
07882 c = TREE_REAL_CST (arg);
07883 n = real_to_integer (&c);
07884 real_from_integer (&cint, VOIDmode, n,
07885 n < 0 ? -1 : 0, 0);
07886 if (real_identical (&c, &cint))
07887 {
07888 REAL_VALUE_TYPE x;
07889
07890 real_powi (&x, TYPE_MODE (type), value, n);
07891 return build_real (type, x);
07892 }
07893 }
07894
07895
07896 if (flag_unsafe_math_optimizations)
07897 {
07898 const enum built_in_function fcode = builtin_mathfn_code (arg);
07899
07900 if ((value == &dconste
07901 && (fcode == BUILT_IN_LOG
07902 || fcode == BUILT_IN_LOGF
07903 || fcode == BUILT_IN_LOGL))
07904 || (value == &dconst2
07905 && (fcode == BUILT_IN_LOG2
07906 || fcode == BUILT_IN_LOG2F
07907 || fcode == BUILT_IN_LOG2L))
07908 || (value == &dconst10
07909 && (fcode == BUILT_IN_LOG10
07910 || fcode == BUILT_IN_LOG10F
07911 || fcode == BUILT_IN_LOG10L)))
07912 return fold_convert (type, TREE_VALUE (TREE_OPERAND (arg, 1)));
07913 }
07914 }
07915
07916 return 0;
07917 }
07918
07919
07920
07921 static bool
07922 var_decl_component_p (tree var)
07923 {
07924 tree inner = var;
07925 while (handled_component_p (inner))
07926 inner = TREE_OPERAND (inner, 0);
07927 return SSA_VAR_P (inner);
07928 }
07929
07930
07931
07932
07933 static tree
07934 fold_builtin_memset (tree arglist, tree type, bool ignore)
07935 {
07936 tree dest, c, len, var, ret;
07937 unsigned HOST_WIDE_INT length, cval;
07938
07939 if (!validate_arglist (arglist,
07940 POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
07941 return 0;
07942
07943 dest = TREE_VALUE (arglist);
07944 c = TREE_VALUE (TREE_CHAIN (arglist));
07945 len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
07946
07947 if (! host_integerp (len, 1))
07948 return 0;
07949
07950
07951 if (integer_zerop (len))
07952 return omit_one_operand (type, dest, c);
07953
07954 if (! host_integerp (c, 1) || TREE_SIDE_EFFECTS (dest))
07955 return 0;
07956
07957 var = dest;
07958 STRIP_NOPS (var);
07959 if (TREE_CODE (var) != ADDR_EXPR)
07960 return 0;
07961
07962 var = TREE_OPERAND (var, 0);
07963 if (TREE_THIS_VOLATILE (var))
07964 return 0;
07965
07966 if (!INTEGRAL_TYPE_P (TREE_TYPE (var))
07967 && !POINTER_TYPE_P (TREE_TYPE (var)))
07968 return 0;
07969
07970 if (! var_decl_component_p (var))
07971 return 0;
07972
07973 length = tree_low_cst (len, 1);
07974 if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (var))) != length
07975 || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
07976 < (int) length)
07977 return 0;
07978
07979 if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT)
07980 return 0;
07981
07982 if (integer_zerop (c))
07983 cval = 0;
07984 else
07985 {
07986 if (CHAR_BIT != 8 || BITS_PER_UNIT != 8 || HOST_BITS_PER_WIDE_INT > 64)
07987 return 0;
07988
07989 cval = tree_low_cst (c, 1);
07990 cval &= 0xff;
07991 cval |= cval << 8;
07992 cval |= cval << 16;
07993 cval |= (cval << 31) << 1;
07994 }
07995
07996 ret = build_int_cst_type (TREE_TYPE (var), cval);
07997 ret = build2 (MODIFY_EXPR, TREE_TYPE (var), var, ret);
07998 if (ignore)
07999 return ret;
08000
08001 return omit_one_operand (type, dest, ret);
08002 }
08003
08004
08005
08006
08007 static tree
08008 fold_builtin_bzero (tree arglist, bool ignore)
08009 {
08010 tree dest, size, newarglist;
08011
08012 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
08013 return 0;
08014
08015 if (!ignore)
08016 return 0;
08017
08018 dest = TREE_VALUE (arglist);
08019 size = TREE_VALUE (TREE_CHAIN (arglist));
08020
08021
08022
08023
08024
08025
08026 newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size));
08027 newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
08028 newarglist = tree_cons (NULL_TREE, dest, newarglist);
08029 return fold_builtin_memset (newarglist, void_type_node, ignore);
08030 }
08031
08032
08033
08034
08035
08036
08037
08038
08039
08040 static tree
08041 fold_builtin_memory_op (tree arglist, tree type, bool ignore, int endp)
08042 {
08043 tree dest, src, len, destvar, srcvar, expr;
08044 unsigned HOST_WIDE_INT length;
08045
08046 if (! validate_arglist (arglist,
08047 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
08048 return 0;
08049
08050 dest = TREE_VALUE (arglist);
08051 src = TREE_VALUE (TREE_CHAIN (arglist));
08052 len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
08053
08054
08055 if (integer_zerop (len))
08056 return omit_one_operand (type, dest, src);
08057
08058
08059
08060 if (operand_equal_p (src, dest, 0))
08061 expr = len;
08062 else
08063 {
08064 if (! host_integerp (len, 1))
08065 return 0;
08066
08067 if (TREE_SIDE_EFFECTS (dest) || TREE_SIDE_EFFECTS (src))
08068 return 0;
08069
08070 destvar = dest;
08071 STRIP_NOPS (destvar);
08072 if (TREE_CODE (destvar) != ADDR_EXPR)
08073 return 0;
08074
08075 destvar = TREE_OPERAND (destvar, 0);
08076 if (TREE_THIS_VOLATILE (destvar))
08077 return 0;
08078
08079 if (!INTEGRAL_TYPE_P (TREE_TYPE (destvar))
08080 && !POINTER_TYPE_P (TREE_TYPE (destvar))
08081 && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (destvar)))
08082 return 0;
08083
08084 if (! var_decl_component_p (destvar))
08085 return 0;
08086
08087 srcvar = src;
08088 STRIP_NOPS (srcvar);
08089 if (TREE_CODE (srcvar) != ADDR_EXPR)
08090 return 0;
08091
08092 srcvar = TREE_OPERAND (srcvar, 0);
08093 if (TREE_THIS_VOLATILE (srcvar))
08094 return 0;
08095
08096 if (!INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
08097 && !POINTER_TYPE_P (TREE_TYPE (srcvar))
08098 && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (srcvar)))
08099 return 0;
08100
08101 if (! var_decl_component_p (srcvar))
08102 return 0;
08103
08104 length = tree_low_cst (len, 1);
08105 if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (destvar))) != length
08106 || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
08107 < (int) length
08108 || GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (srcvar))) != length
08109 || get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
08110 < (int) length)
08111 return 0;
08112
08113 if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
08114 || POINTER_TYPE_P (TREE_TYPE (srcvar)))
08115 && (INTEGRAL_TYPE_P (TREE_TYPE (destvar))
08116 || POINTER_TYPE_P (TREE_TYPE (destvar))))
08117 expr = fold_convert (TREE_TYPE (destvar), srcvar);
08118 else
08119 expr = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (destvar), srcvar);
08120 expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, expr);
08121 }
08122
08123 if (ignore)
08124 return expr;
08125
08126 if (endp == 0 || endp == 3)
08127 return omit_one_operand (type, dest, expr);
08128
08129 if (expr == len)
08130 expr = 0;
08131
08132 if (endp == 2)
08133 len = fold_build2 (MINUS_EXPR, TREE_TYPE (len), len,
08134 ssize_int (1));
08135
08136 len = fold_convert (TREE_TYPE (dest), len);
08137 dest = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len);
08138 dest = fold_convert (type, dest);
08139 if (expr)
08140 dest = omit_one_operand (type, dest, expr);
08141 return dest;
08142 }
08143
08144
08145
08146
08147 static tree
08148 fold_builtin_bcopy (tree arglist, bool ignore)
08149 {
08150 tree src, dest, size, newarglist;
08151
08152 if (!validate_arglist (arglist,
08153 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
08154 return 0;
08155
08156 if (! ignore)
08157 return 0;
08158
08159 src = TREE_VALUE (arglist);
08160 dest = TREE_VALUE (TREE_CHAIN (arglist));
08161 size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
08162
08163
08164
08165
08166
08167
08168 newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size));
08169 newarglist = tree_cons (NULL_TREE, src, newarglist);
08170 newarglist = tree_cons (NULL_TREE, dest, newarglist);
08171
08172 return fold_builtin_memory_op (newarglist, void_type_node, true, 3);
08173 }
08174
08175
08176
08177
08178
08179 tree
08180 fold_builtin_strcpy (tree fndecl, tree arglist, tree len)
08181 {
08182 tree dest, src, fn;
08183
08184 if (!validate_arglist (arglist,
08185 POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
08186 return 0;
08187
08188 dest = TREE_VALUE (arglist);
08189 src = TREE_VALUE (TREE_CHAIN (arglist));
08190
08191
08192 if (operand_equal_p (src, dest, 0))
08193 return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), dest);
08194
08195 if (optimize_size)
08196 return 0;
08197
08198 fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
08199 if (!fn)
08200 return 0;
08201
08202 if (!len)
08203 {
08204 len = c_strlen (src, 1);
08205 if (! len || TREE_SIDE_EFFECTS (len))
08206 return 0;
08207 }
08208
08209 len = size_binop (PLUS_EXPR, len, ssize_int (1));
08210 arglist = build_tree_list (NULL_TREE, len);
08211 arglist = tree_cons (NULL_TREE, src, arglist);
08212 arglist = tree_cons (NULL_TREE, dest, arglist);
08213 return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)),
08214 build_function_call_expr (fn, arglist));
08215 }
08216
08217
08218
08219
08220
08221 tree
08222 fold_builtin_strncpy (tree fndecl, tree arglist, tree slen)
08223 {
08224 tree dest, src, len, fn;
08225
08226 if (!validate_arglist (arglist,
08227 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
08228 return 0;
08229
08230 dest = TREE_VALUE (arglist);
08231 src = TREE_VALUE (TREE_CHAIN (arglist));
08232 len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
08233
08234
08235 if (integer_zerop (len))
08236 return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
08237
08238
08239
08240 if (len == 0 || TREE_CODE (len) != INTEGER_CST)
08241 return 0;
08242
08243 if (!slen)
08244 slen = c_strlen (src, 1);
08245
08246
08247 if (slen == 0 || TREE_CODE (slen) != INTEGER_CST)
08248 return 0;
08249
08250 slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
08251
08252
08253
08254
08255 if (tree_int_cst_lt (slen, len))
08256 return 0;
08257
08258
08259 fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
08260 if (!fn)
08261 return 0;
08262 return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)),
08263 build_function_call_expr (fn, arglist));
08264 }
08265
08266
08267
08268
08269 static tree
08270 fold_builtin_memcmp (tree arglist)
08271 {
08272 tree arg1, arg2, len;
08273 const char *p1, *p2;
08274
08275 if (!validate_arglist (arglist,
08276 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
08277 return 0;
08278
08279 arg1 = TREE_VALUE (arglist);
08280 arg2 = TREE_VALUE (TREE_CHAIN (arglist));
08281 len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
08282
08283
08284 if (integer_zerop (len))
08285 return omit_two_operands (integer_type_node, integer_zero_node,
08286 arg1, arg2);
08287
08288
08289 if (operand_equal_p (arg1, arg2, 0))
08290 return omit_one_operand (integer_type_node, integer_zero_node, len);
08291
08292 p1 = c_getstr (arg1);
08293 p2 = c_getstr (arg2);
08294
08295
08296
08297 if (host_integerp (len, 1) && p1 && p2
08298 && compare_tree_int (len, strlen (p1) + 1) <= 0
08299 && compare_tree_int (len, strlen (p2) + 1) <= 0)
08300 {
08301 const int r = memcmp (p1, p2, tree_low_cst (len, 1));
08302
08303 if (r > 0)
08304 return integer_one_node;
08305 else if (r < 0)
08306 return integer_minus_one_node;
08307 else
08308 return integer_zero_node;
08309 }
08310
08311
08312
08313 if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
08314 {
08315 tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
08316 tree cst_uchar_ptr_node
08317 = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
08318
08319 tree ind1 = fold_convert (integer_type_node,
08320 build1 (INDIRECT_REF, cst_uchar_node,
08321 fold_convert (cst_uchar_ptr_node,
08322 arg1)));
08323 tree ind2 = fold_convert (integer_type_node,
08324 build1 (INDIRECT_REF, cst_uchar_node,
08325 fold_convert (cst_uchar_ptr_node,
08326 arg2)));
08327 return fold_build2 (MINUS_EXPR, integer_type_node, ind1, ind2);
08328 }
08329
08330 return 0;
08331 }
08332
08333
08334
08335
08336 static tree
08337 fold_builtin_strcmp (tree arglist)
08338 {
08339 tree arg1, arg2;
08340 const char *p1, *p2;
08341
08342 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
08343 return 0;
08344
08345 arg1 = TREE_VALUE (arglist);
08346 arg2 = TREE_VALUE (TREE_CHAIN (arglist));
08347
08348
08349 if (operand_equal_p (arg1, arg2, 0))
08350 return integer_zero_node;
08351
08352 p1 = c_getstr (arg1);
08353 p2 = c_getstr (arg2);
08354
08355 if (p1 && p2)
08356 {
08357 const int i = strcmp (p1, p2);
08358 if (i < 0)
08359 return integer_minus_one_node;
08360 else if (i > 0)
08361 return integer_one_node;
08362 else
08363 return integer_zero_node;
08364 }
08365
08366
08367 if (p2 && *p2 == '\0')
08368 {
08369 tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
08370 tree cst_uchar_ptr_node
08371 = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
08372
08373 return fold_convert (integer_type_node,
08374 build1 (INDIRECT_REF, cst_uchar_node,
08375 fold_convert (cst_uchar_ptr_node,
08376 arg1)));
08377 }
08378
08379
08380 if (p1 && *p1 == '\0')
08381 {
08382 tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
08383 tree cst_uchar_ptr_node
08384 = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
08385
08386 tree temp = fold_convert (integer_type_node,
08387 build1 (INDIRECT_REF, cst_uchar_node,
08388 fold_convert (cst_uchar_ptr_node,
08389 arg2)));
08390 return fold_build1 (NEGATE_EXPR, integer_type_node, temp);
08391 }
08392
08393 return 0;
08394 }
08395
08396
08397
08398
08399 static tree
08400 fold_builtin_strncmp (tree arglist)
08401 {
08402 tree arg1, arg2, len;
08403 const char *p1, *p2;
08404
08405 if (!validate_arglist (arglist,
08406 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
08407 return 0;
08408
08409 arg1 = TREE_VALUE (arglist);
08410 arg2 = TREE_VALUE (TREE_CHAIN (arglist));
08411 len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
08412
08413
08414 if (integer_zerop (len))
08415 return omit_two_operands (integer_type_node, integer_zero_node,
08416 arg1, arg2);
08417
08418
08419 if (operand_equal_p (arg1, arg2, 0))
08420 return omit_one_operand (integer_type_node, integer_zero_node, len);
08421
08422 p1 = c_getstr (arg1);
08423 p2 = c_getstr (arg2);
08424
08425 if (host_integerp (len, 1) && p1 && p2)
08426 {
08427 const int i = strncmp (p1, p2, tree_low_cst (len, 1));
08428 if (i > 0)
08429 return integer_one_node;
08430 else if (i < 0)
08431 return integer_minus_one_node;
08432 else
08433 return integer_zero_node;
08434 }
08435
08436
08437
08438 if (p2 && *p2 == '\0'
08439 && TREE_CODE (len) == INTEGER_CST
08440 && tree_int_cst_sgn (len) == 1)
08441 {
08442 tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
08443 tree cst_uchar_ptr_node
08444 = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
08445
08446 return fold_convert (integer_type_node,
08447 build1 (INDIRECT_REF, cst_uchar_node,
08448 fold_convert (cst_uchar_ptr_node,
08449 arg1)));
08450 }
08451
08452
08453
08454 if (p1 && *p1 == '\0'
08455 && TREE_CODE (len) == INTEGER_CST
08456 && tree_int_cst_sgn (len) == 1)
08457 {
08458 tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
08459 tree cst_uchar_ptr_node
08460 = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
08461
08462 tree temp = fold_convert (integer_type_node,
08463 build1 (INDIRECT_REF, cst_uchar_node,
08464 fold_convert (cst_uchar_ptr_node,
08465 arg2)));
08466 return fold_build1 (NEGATE_EXPR, integer_type_node, temp);
08467 }
08468
08469
08470
08471 if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
08472 {
08473 tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
08474 tree cst_uchar_ptr_node
08475 = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
08476
08477 tree ind1 = fold_convert (integer_type_node,
08478 build1 (INDIRECT_REF, cst_uchar_node,
08479 fold_convert (cst_uchar_ptr_node,
08480 arg1)));
08481 tree ind2 = fold_convert (integer_type_node,
08482 build1 (INDIRECT_REF, cst_uchar_node,
08483 fold_convert (cst_uchar_ptr_node,
08484 arg2)));
08485 return fold_build2 (MINUS_EXPR, integer_type_node, ind1, ind2);
08486 }
08487
08488 return 0;
08489 }
08490
08491
08492
08493
08494 static tree
08495 fold_builtin_signbit (tree fndecl, tree arglist)
08496 {
08497 tree type = TREE_TYPE (TREE_TYPE (fndecl));
08498 tree arg, temp;
08499
08500 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
08501 return NULL_TREE;
08502
08503 arg = TREE_VALUE (arglist);
08504
08505
08506 if (TREE_CODE (arg) == REAL_CST
08507 && !TREE_CONSTANT_OVERFLOW (arg))
08508 {
08509 REAL_VALUE_TYPE c;
08510
08511 c = TREE_REAL_CST (arg);
08512 temp = REAL_VALUE_NEGATIVE (c) ? integer_one_node : integer_zero_node;
08513 return fold_convert (type, temp);
08514 }
08515
08516
08517 if (tree_expr_nonnegative_p (arg))
08518 return omit_one_operand (type, integer_zero_node, arg);
08519
08520
08521 if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg))))
08522 return fold_build2 (LT_EXPR, type, arg,
08523 build_real (TREE_TYPE (arg), dconst0));
08524
08525 return NULL_TREE;
08526 }
08527
08528
08529
08530
08531 static tree
08532 fold_builtin_copysign (tree fndecl, tree arglist, tree type)
08533 {
08534 tree arg1, arg2, tem;
08535
08536 if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
08537 return NULL_TREE;
08538
08539 arg1 = TREE_VALUE (arglist);
08540 arg2 = TREE_VALUE (TREE_CHAIN (arglist));
08541
08542
08543 if (operand_equal_p (arg1, arg2, 0))
08544 return fold_convert (type, arg1);
08545
08546
08547 if (TREE_CODE (arg1) == REAL_CST
08548 && TREE_CODE (arg2) == REAL_CST
08549 && !TREE_CONSTANT_OVERFLOW (arg1)
08550 && !TREE_CONSTANT_OVERFLOW (arg2))
08551 {
08552 REAL_VALUE_TYPE c1, c2;
08553
08554 c1 = TREE_REAL_CST (arg1);
08555 c2 = TREE_REAL_CST (arg2);
08556
08557 real_copysign (&c1, &c2);
08558 return build_real (type, c1);
08559 }
08560
08561
08562
08563 if (tree_expr_nonnegative_p (arg2))
08564 return omit_one_operand (type,
08565 fold_build1 (ABS_EXPR, type, arg1),
08566 arg2);
08567
08568
08569 tem = fold_strip_sign_ops (arg1);
08570 if (tem)
08571 {
08572 arglist = tree_cons (NULL_TREE, tem, TREE_CHAIN (arglist));
08573 return build_function_call_expr (fndecl, arglist);
08574 }
08575
08576 return NULL_TREE;
08577 }
08578
08579
08580
08581 static tree
08582 fold_builtin_isascii (tree arglist)
08583 {
08584 if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
08585 return 0;
08586 else
08587 {
08588
08589 tree arg = TREE_VALUE (arglist);
08590
08591 arg = build2 (BIT_AND_EXPR, integer_type_node, arg,
08592 build_int_cst (NULL_TREE,
08593 ~ (unsigned HOST_WIDE_INT) 0x7f));
08594 arg = fold_build2 (EQ_EXPR, integer_type_node,
08595 arg, integer_zero_node);
08596
08597 if (in_gimple_form && !TREE_CONSTANT (arg))
08598 return NULL_TREE;
08599 else
08600 return arg;
08601 }
08602 }
08603
08604
08605
08606 static tree
08607 fold_builtin_toascii (tree arglist)
08608 {
08609 if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
08610 return 0;
08611 else
08612 {
08613
08614 tree arg = TREE_VALUE (arglist);
08615
08616 return fold_build2 (BIT_AND_EXPR, integer_type_node, arg,
08617 build_int_cst (NULL_TREE, 0x7f));
08618 }
08619 }
08620
08621
08622
08623 static tree
08624 fold_builtin_isdigit (tree arglist)
08625 {
08626 if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
08627 return 0;
08628 else
08629 {
08630
08631
08632
08633 tree arg;
08634 unsigned HOST_WIDE_INT target_digit0
08635 = lang_hooks.to_target_charset ('0');
08636
08637 if (target_digit0 == 0)
08638 return NULL_TREE;
08639
08640 arg = fold_convert (unsigned_type_node, TREE_VALUE (arglist));
08641 arg = build2 (MINUS_EXPR, unsigned_type_node, arg,
08642 build_int_cst (unsigned_type_node, target_digit0));
08643 arg = fold_build2 (LE_EXPR, integer_type_node, arg,
08644 build_int_cst (unsigned_type_node, 9));
08645 if (in_gimple_form && !TREE_CONSTANT (arg))
08646 return NULL_TREE;
08647 else
08648 return arg;
08649 }
08650 }
08651
08652
08653
08654 static tree
08655 fold_builtin_fabs (tree arglist, tree type)
08656 {
08657 tree arg;
08658
08659 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
08660 return 0;
08661
08662 arg = TREE_VALUE (arglist);
08663 arg = fold_convert (type, arg);
08664 if (TREE_CODE (arg) == REAL_CST)
08665 return fold_abs_const (arg, type);
08666 return fold_build1 (ABS_EXPR, type, arg);
08667 }
08668
08669
08670
08671 static tree
08672 fold_builtin_abs (tree arglist, tree type)
08673 {
08674 tree arg;
08675
08676 if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
08677 return 0;
08678
08679 arg = TREE_VALUE (arglist);
08680 arg = fold_convert (type, arg);
08681 if (TREE_CODE (arg) == INTEGER_CST)
08682 return fold_abs_const (arg, type);
08683 return fold_build1 (ABS_EXPR, type, arg);
08684 }
08685
08686
08687
08688
08689 static tree
08690 fold_builtin_classify (tree fndecl, tree arglist, int builtin_index)
08691 {
08692 tree type = TREE_TYPE (TREE_TYPE (fndecl));
08693 tree arg;
08694 REAL_VALUE_TYPE r;
08695
08696 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
08697 {
08698
08699 if (arglist == 0)
08700 {
08701 error ("too few arguments to function %qs",
08702 IDENTIFIER_POINTER (DECL_NAME (fndecl)));
08703 return error_mark_node;
08704 }
08705 else if (TREE_CHAIN (arglist) != 0)
08706 {
08707 error ("too many arguments to function %qs",
08708 IDENTIFIER_POINTER (DECL_NAME (fndecl)));
08709 return error_mark_node;
08710 }
08711 else
08712 {
08713 error ("non-floating-point argument to function %qs",
08714 IDENTIFIER_POINTER (DECL_NAME (fndecl)));
08715 return error_mark_node;
08716 }
08717 }
08718
08719 arg = TREE_VALUE (arglist);
08720 switch (builtin_index)
08721 {
08722 case BUILT_IN_ISINF:
08723 if (!MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg))))
08724 return omit_one_operand (type, integer_zero_node, arg);
08725
08726 if (TREE_CODE (arg) == REAL_CST)
08727 {
08728 r = TREE_REAL_CST (arg);
08729 if (real_isinf (&r))
08730 return real_compare (GT_EXPR, &r, &dconst0)
08731 ? integer_one_node : integer_minus_one_node;
08732 else
08733 return integer_zero_node;
08734 }
08735
08736 return NULL_TREE;
08737
08738 case BUILT_IN_FINITE:
08739 if (!MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg)))
08740 && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg))))
08741 return omit_one_operand (type, integer_zero_node, arg);
08742
08743 if (TREE_CODE (arg) == REAL_CST)
08744 {
08745 r = TREE_REAL_CST (arg);
08746 return real_isinf (&r) || real_isnan (&r)
08747 ? integer_zero_node : integer_one_node;
08748 }
08749
08750 return NULL_TREE;
08751
08752 case BUILT_IN_ISNAN:
08753 if (!MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg))))
08754 return omit_one_operand (type, integer_zero_node, arg);
08755
08756 if (TREE_CODE (arg) == REAL_CST)
08757 {
08758 r = TREE_REAL_CST (arg);
08759 return real_isnan (&r) ? integer_one_node : integer_zero_node;
08760 }
08761
08762 arg = builtin_save_expr (arg);
08763 return fold_build2 (UNORDERED_EXPR, type, arg, arg);
08764
08765 default:
08766 gcc_unreachable ();
08767 }
08768 }
08769
08770
08771
08772
08773
08774
08775
08776
08777
08778 static tree
08779 fold_builtin_unordered_cmp (tree fndecl, tree arglist,
08780 enum tree_code unordered_code,
08781 enum tree_code ordered_code)
08782 {
08783 tree type = TREE_TYPE (TREE_TYPE (fndecl));
08784 enum tree_code code;
08785 tree arg0, arg1;
08786 tree type0, type1;
08787 enum tree_code code0, code1;
08788 tree cmp_type = NULL_TREE;
08789
08790 if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
08791 {
08792
08793 if (arglist == 0 || TREE_CHAIN (arglist) == 0)
08794 {
08795 error ("too few arguments to function %qs",
08796 IDENTIFIER_POINTER (DECL_NAME (fndecl)));
08797 return error_mark_node;
08798 }
08799 else if (TREE_CHAIN (TREE_CHAIN (arglist)) != 0)
08800 {
08801 error ("too many arguments to function %qs",
08802 IDENTIFIER_POINTER (DECL_NAME (fndecl)));
08803 return error_mark_node;
08804 }
08805 }
08806
08807 arg0 = TREE_VALUE (arglist);
08808 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
08809
08810 type0 = TREE_TYPE (arg0);
08811 type1 = TREE_TYPE (arg1);
08812
08813 code0 = TREE_CODE (type0);
08814 code1 = TREE_CODE (type1);
08815
08816 if (code0 == REAL_TYPE && code1 == REAL_TYPE)
08817
08818 cmp_type = TYPE_PRECISION (type0) >= TYPE_PRECISION (type1)
08819 ? type0 : type1;
08820 else if (code0 == REAL_TYPE && code1 == INTEGER_TYPE)
08821 cmp_type = type0;
08822 else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE)
08823 cmp_type = type1;
08824 else
08825 {
08826 error ("non-floating-point argument to function %qs",
08827 IDENTIFIER_POINTER (DECL_NAME (fndecl)));
08828 return error_mark_node;
08829 }
08830
08831 arg0 = fold_convert (cmp_type, arg0);
08832 arg1 = fold_convert (cmp_type, arg1);
08833
08834 if (unordered_code == UNORDERED_EXPR)
08835 {
08836 if (!MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg0))))
08837 return omit_two_operands (type, integer_zero_node, arg0, arg1);
08838 return fold_build2 (UNORDERED_EXPR, type, arg0, arg1);
08839 }
08840
08841 code = MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg0))) ? unordered_code
08842 : ordered_code;
08843 return fold_build1 (TRUTH_NOT_EXPR, type,
08844 fold_build2 (code, type, arg0, arg1));
08845 }
08846
08847
08848
08849
08850
08851
08852 static tree
08853 fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
08854 {
08855 tree type = TREE_TYPE (TREE_TYPE (fndecl));
08856 enum built_in_function fcode;
08857
08858 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
08859 return targetm.fold_builtin (fndecl, arglist, ignore);
08860
08861 fcode = DECL_FUNCTION_CODE (fndecl);
08862 switch (fcode)
08863 {
08864 case BUILT_IN_FPUTS:
08865 return fold_builtin_fputs (arglist, ignore, false, NULL_TREE);
08866
08867 case BUILT_IN_FPUTS_UNLOCKED:
08868 return fold_builtin_fputs (arglist, ignore, true, NULL_TREE);
08869
08870 case BUILT_IN_STRSTR:
08871 return fold_builtin_strstr (arglist, type);
08872
08873 case BUILT_IN_STRCAT:
08874 return fold_builtin_strcat (arglist);
08875
08876 case BUILT_IN_STRNCAT:
08877 return fold_builtin_strncat (arglist);
08878
08879 case BUILT_IN_STRSPN:
08880 return fold_builtin_strspn (arglist);
08881
08882 case BUILT_IN_STRCSPN:
08883 return fold_builtin_strcspn (arglist);
08884
08885 case BUILT_IN_STRCHR:
08886 case BUILT_IN_INDEX:
08887 return fold_builtin_strchr (arglist, type);
08888
08889 case BUILT_IN_STRRCHR:
08890 case BUILT_IN_RINDEX:
08891 return fold_builtin_strrchr (arglist, type);
08892
08893 case BUILT_IN_STRCPY:
08894 return fold_builtin_strcpy (fndecl, arglist, NULL_TREE);
08895
08896 case BUILT_IN_STRNCPY:
08897 return fold_builtin_strncpy (fndecl, arglist, NULL_TREE);
08898
08899 case BUILT_IN_STRCMP:
08900 return fold_builtin_strcmp (arglist);
08901
08902 case BUILT_IN_STRNCMP:
08903 return fold_builtin_strncmp (arglist);
08904
08905 case BUILT_IN_STRPBRK:
08906 return fold_builtin_strpbrk (arglist, type);
08907
08908 case BUILT_IN_BCMP:
08909 case BUILT_IN_MEMCMP:
08910 return fold_builtin_memcmp (arglist);
08911
08912 case BUILT_IN_SPRINTF:
08913 return fold_builtin_sprintf (arglist, ignore);
08914
08915 case BUILT_IN_CONSTANT_P:
08916 {
08917 tree val;
08918
08919 val = fold_builtin_constant_p (arglist);
08920
08921
08922
08923 if (!val && !optimize)
08924 val = integer_zero_node;
08925
08926 return val;
08927 }
08928
08929 case BUILT_IN_EXPECT:
08930 return fold_builtin_expect (arglist);
08931
08932 case BUILT_IN_CLASSIFY_TYPE:
08933 return fold_builtin_classify_type (arglist);
08934
08935 case BUILT_IN_STRLEN:
08936 return fold_builtin_strlen (arglist);
08937
08938 CASE_FLT_FN (BUILT_IN_FABS):
08939 return fold_builtin_fabs (arglist, type);
08940
08941 case BUILT_IN_ABS:
08942 case BUILT_IN_LABS:
08943 case BUILT_IN_LLABS:
08944 case BUILT_IN_IMAXABS:
08945 return fold_builtin_abs (arglist, type);
08946
08947 CASE_FLT_FN (BUILT_IN_CONJ):
08948 if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
08949 return fold_build1 (CONJ_EXPR, type, TREE_VALUE (arglist));
08950 break;
08951
08952 CASE_FLT_FN (BUILT_IN_CREAL):
08953 if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
08954 return non_lvalue (fold_build1 (REALPART_EXPR, type,
08955 TREE_VALUE (arglist)));
08956 break;
08957
08958 CASE_FLT_FN (BUILT_IN_CIMAG):
08959 if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
08960 return non_lvalue (fold_build1 (IMAGPART_EXPR, type,
08961 TREE_VALUE (arglist)));
08962 break;
08963
08964 CASE_FLT_FN (BUILT_IN_CABS):
08965 return fold_builtin_cabs (arglist, type, fndecl);
08966
08967 CASE_FLT_FN (BUILT_IN_SQRT):
08968 return fold_builtin_sqrt (arglist, type);
08969
08970 CASE_FLT_FN (BUILT_IN_CBRT):
08971 return fold_builtin_cbrt (arglist, type);
08972
08973 CASE_FLT_FN (BUILT_IN_SIN):
08974 return fold_builtin_sin (arglist);
08975
08976 CASE_FLT_FN (BUILT_IN_COS):
08977 return fold_builtin_cos (arglist, type, fndecl);
08978
08979 CASE_FLT_FN (BUILT_IN_EXP):
08980 return fold_builtin_exponent (fndecl, arglist, &dconste);
08981
08982 CASE_FLT_FN (BUILT_IN_EXP2):
08983 return fold_builtin_exponent (fndecl, arglist, &dconst2);
08984
08985 CASE_FLT_FN (BUILT_IN_EXP10):
08986 CASE_FLT_FN (BUILT_IN_POW10):
08987 return fold_builtin_exponent (fndecl, arglist, &dconst10);
08988
08989 CASE_FLT_FN (BUILT_IN_LOG):
08990 return fold_builtin_logarithm (fndecl, arglist, &dconste);
08991
08992 CASE_FLT_FN (BUILT_IN_LOG2):
08993 return fold_builtin_logarithm (fndecl, arglist, &dconst2);
08994
08995 CASE_FLT_FN (BUILT_IN_LOG10):
08996 return fold_builtin_logarithm (fndecl, arglist, &dconst10);
08997
08998 CASE_FLT_FN (BUILT_IN_TAN):
08999 return fold_builtin_tan (arglist);
09000
09001 CASE_FLT_FN (BUILT_IN_ATAN):
09002 return fold_builtin_atan (arglist, type);
09003
09004 CASE_FLT_FN (BUILT_IN_POW):
09005 return fold_builtin_pow (fndecl, arglist, type);
09006
09007 CASE_FLT_FN (BUILT_IN_POWI):
09008 return fold_builtin_powi (fndecl, arglist, type);
09009
09010 CASE_FLT_FN (BUILT_IN_INF):
09011 case BUILT_IN_INFD32:
09012 case BUILT_IN_INFD64:
09013 case BUILT_IN_INFD128:
09014 return fold_builtin_inf (type, true);
09015
09016 CASE_FLT_FN (BUILT_IN_HUGE_VAL):
09017 return fold_builtin_inf (type, false);
09018
09019 CASE_FLT_FN (BUILT_IN_NAN):
09020 case BUILT_IN_NAND32:
09021 case BUILT_IN_NAND64:
09022 case BUILT_IN_NAND128:
09023 return fold_builtin_nan (arglist, type, true);
09024
09025 CASE_FLT_FN (BUILT_IN_NANS):
09026 return fold_builtin_nan (arglist, type, false);
09027
09028 CASE_FLT_FN (BUILT_IN_FLOOR):
09029 return fold_builtin_floor (fndecl, arglist);
09030
09031 CASE_FLT_FN (BUILT_IN_CEIL):
09032 return fold_builtin_ceil (fndecl, arglist);
09033
09034 CASE_FLT_FN (BUILT_IN_TRUNC):
09035 return fold_builtin_trunc (fndecl, arglist);
09036
09037 CASE_FLT_FN (BUILT_IN_ROUND):
09038 return fold_builtin_round (fndecl, arglist);
09039
09040 CASE_FLT_FN (BUILT_IN_NEARBYINT):
09041 CASE_FLT_FN (BUILT_IN_RINT):
09042 return fold_trunc_transparent_mathfn (fndecl, arglist);
09043
09044 CASE_FLT_FN (BUILT_IN_LCEIL):
09045 CASE_FLT_FN (BUILT_IN_LLCEIL):
09046 CASE_FLT_FN (BUILT_IN_LFLOOR):
09047 CASE_FLT_FN (BUILT_IN_LLFLOOR):
09048 CASE_FLT_FN (BUILT_IN_LROUND):
09049 CASE_FLT_FN (BUILT_IN_LLROUND):
09050 return fold_builtin_int_roundingfn (fndecl, arglist);
09051
09052 CASE_FLT_FN (BUILT_IN_LRINT):
09053 CASE_FLT_FN (BUILT_IN_LLRINT):
09054 return fold_fixed_mathfn (fndecl, arglist);
09055
09056 CASE_INT_FN (BUILT_IN_FFS):
09057 CASE_INT_FN (BUILT_IN_CLZ):
09058 CASE_INT_FN (BUILT_IN_CTZ):
09059 CASE_INT_FN (BUILT_IN_POPCOUNT):
09060 CASE_INT_FN (BUILT_IN_PARITY):
09061 return fold_builtin_bitop (fndecl, arglist);
09062
09063 case BUILT_IN_MEMSET:
09064 return fold_builtin_memset (arglist, type, ignore);
09065
09066 case BUILT_IN_MEMCPY:
09067 return fold_builtin_memory_op (arglist, type, ignore, 0);
09068
09069 case BUILT_IN_MEMPCPY:
09070 return fold_builtin_memory_op (arglist, type, ignore, 1);
09071
09072 case BUILT_IN_MEMMOVE:
09073 return fold_builtin_memory_op (arglist, type, ignore, 3);
09074
09075 case BUILT_IN_BZERO:
09076 return fold_builtin_bzero (arglist, ignore);
09077
09078 case BUILT_IN_BCOPY:
09079 return fold_builtin_bcopy (arglist, ignore);
09080
09081 CASE_FLT_FN (BUILT_IN_SIGNBIT):
09082 return fold_builtin_signbit (fndecl, arglist);
09083
09084 case BUILT_IN_ISASCII:
09085 return fold_builtin_isascii (arglist);
09086
09087 case BUILT_IN_TOASCII:
09088 return fold_builtin_toascii (arglist);
09089
09090 case BUILT_IN_ISDIGIT:
09091 return fold_builtin_isdigit (arglist);
09092
09093 CASE_FLT_FN (BUILT_IN_COPYSIGN):
09094 return fold_builtin_copysign (fndecl, arglist, type);
09095
09096 CASE_FLT_FN (BUILT_IN_FINITE):
09097 case BUILT_IN_FINITED32:
09098 case BUILT_IN_FINITED64:
09099 case BUILT_IN_FINITED128:
09100 return fold_builtin_classify (fndecl, arglist, BUILT_IN_FINITE);
09101
09102 CASE_FLT_FN (BUILT_IN_ISINF):
09103 case BUILT_IN_ISINFD32:
09104 case BUILT_IN_ISINFD64:
09105 case BUILT_IN_ISINFD128:
09106 return fold_builtin_classify (fndecl, arglist, BUILT_IN_ISINF);
09107
09108 CASE_FLT_FN (BUILT_IN_ISNAN):
09109 case BUILT_IN_ISNAND32:
09110 case BUILT_IN_ISNAND64:
09111 case BUILT_IN_ISNAND128:
09112 return fold_builtin_classify (fndecl, arglist, BUILT_IN_ISNAN);
09113
09114 case BUILT_IN_ISGREATER:
09115 return fold_builtin_unordered_cmp (fndecl, arglist, UNLE_EXPR, LE_EXPR);
09116 case BUILT_IN_ISGREATEREQUAL:
09117 return fold_builtin_unordered_cmp (fndecl, arglist, UNLT_EXPR, LT_EXPR);
09118 case BUILT_IN_ISLESS:
09119 return fold_builtin_unordered_cmp (fndecl, arglist, UNGE_EXPR, GE_EXPR);
09120 case BUILT_IN_ISLESSEQUAL:
09121 return fold_builtin_unordered_cmp (fndecl, arglist, UNGT_EXPR, GT_EXPR);
09122 case BUILT_IN_ISLESSGREATER:
09123 return fold_builtin_unordered_cmp (fndecl, arglist, UNEQ_EXPR, EQ_EXPR);
09124 case BUILT_IN_ISUNORDERED:
09125 return fold_builtin_unordered_cmp (fndecl, arglist, UNORDERED_EXPR,
09126 NOP_EXPR);
09127
09128
09129 case BUILT_IN_VA_START:
09130 break;
09131
09132 case BUILT_IN_OBJECT_SIZE:
09133 return fold_builtin_object_size (arglist);
09134 case BUILT_IN_MEMCPY_CHK:
09135 case BUILT_IN_MEMPCPY_CHK:
09136 case BUILT_IN_MEMMOVE_CHK:
09137 case BUILT_IN_MEMSET_CHK:
09138 return fold_builtin_memory_chk (fndecl, arglist, NULL_TREE, ignore,
09139 DECL_FUNCTION_CODE (fndecl));
09140 case BUILT_IN_STRCPY_CHK:
09141 case BUILT_IN_STPCPY_CHK:
09142 return fold_builtin_stxcpy_chk (fndecl, arglist, NULL_TREE, ignore,
09143 DECL_FUNCTION_CODE (fndecl));
09144 case BUILT_IN_STRNCPY_CHK:
09145 return fold_builtin_strncpy_chk (arglist, NULL_TREE);
09146 case BUILT_IN_STRCAT_CHK:
09147 return fold_builtin_strcat_chk (fndecl, arglist);
09148 case BUILT_IN_STRNCAT_CHK:
09149 return fold_builtin_strncat_chk (fndecl, arglist);
09150 case BUILT_IN_SPRINTF_CHK:
09151 case BUILT_IN_VSPRINTF_CHK:
09152 return fold_builtin_sprintf_chk (arglist, DECL_FUNCTION_CODE (fndecl));
09153 case BUILT_IN_SNPRINTF_CHK:
09154 case BUILT_IN_VSNPRINTF_CHK:
09155 return fold_builtin_snprintf_chk (arglist, NULL_TREE,
09156 DECL_FUNCTION_CODE (fndecl));
09157
09158 case BUILT_IN_PRINTF:
09159 case BUILT_IN_PRINTF_UNLOCKED:
09160 case BUILT_IN_VPRINTF:
09161 case BUILT_IN_PRINTF_CHK:
09162 case BUILT_IN_VPRINTF_CHK:
09163 return fold_builtin_printf (fndecl, arglist, ignore,
09164 DECL_FUNCTION_CODE (fndecl));
09165
09166 case BUILT_IN_FPRINTF:
09167 case BUILT_IN_FPRINTF_UNLOCKED:
09168 case BUILT_IN_VFPRINTF:
09169 case BUILT_IN_FPRINTF_CHK:
09170 case BUILT_IN_VFPRINTF_CHK:
09171 return fold_builtin_fprintf (fndecl, arglist, ignore,
09172 DECL_FUNCTION_CODE (fndecl));
09173
09174 default:
09175 break;
09176 }
09177
09178 return 0;
09179 }
09180
09181
09182
09183
09184
09185 tree
09186 fold_builtin (tree fndecl, tree arglist, bool ignore)
09187 {
09188 tree exp = fold_builtin_1 (fndecl, arglist, ignore);
09189 if (exp)
09190 {
09191 exp = build1 (NOP_EXPR, TREE_TYPE (exp), exp);
09192 TREE_NO_WARNING (exp) = 1;
09193 }
09194
09195 return exp;
09196 }
09197
09198
09199
09200 tree
09201 build_function_call_expr (tree fn, tree arglist)
09202 {
09203 tree call_expr;
09204
09205 call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
09206 return fold_build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
09207 call_expr, arglist, NULL_TREE);
09208 }
09209
09210
09211
09212
09213
09214
09215 static int
09216 validate_arglist (tree arglist, ...)
09217 {
09218 enum tree_code code;
09219 int res = 0;
09220 va_list ap;
09221
09222 va_start (ap, arglist);
09223
09224 do
09225 {
09226 code = va_arg (ap, enum tree_code);
09227 switch (code)
09228 {
09229 case 0:
09230
09231 res = 1;
09232 goto end;
09233 case VOID_TYPE:
09234
09235
09236 res = arglist == 0;
09237 goto end;
09238 default:
09239
09240
09241
09242 if (arglist == 0)
09243 goto end;
09244 if (code == POINTER_TYPE)
09245 {
09246 if (! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist))))
09247 goto end;
09248 }
09249 else if (code != TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))))
09250 goto end;
09251 break;
09252 }
09253 arglist = TREE_CHAIN (arglist);
09254 }
09255 while (1);
09256
09257
09258
09259 end: ;
09260 va_end (ap);
09261
09262 return res;
09263 }
09264
09265
09266
09267 rtx
09268 default_expand_builtin (tree exp ATTRIBUTE_UNUSED,
09269 rtx target ATTRIBUTE_UNUSED,
09270 rtx subtarget ATTRIBUTE_UNUSED,
09271 enum machine_mode mode ATTRIBUTE_UNUSED,
09272 int ignore ATTRIBUTE_UNUSED)
09273 {
09274 return NULL_RTX;
09275 }
09276
09277
09278
09279
09280 static bool
09281 readonly_data_expr (tree exp)
09282 {
09283 STRIP_NOPS (exp);
09284
09285 if (TREE_CODE (exp) != ADDR_EXPR)
09286 return false;
09287
09288 exp = get_base_address (TREE_OPERAND (exp, 0));
09289 if (!exp)
09290 return false;
09291
09292
09293
09294
09295 if (TREE_CODE (exp) == STRING_CST
09296 || TREE_CODE (exp) == CONSTRUCTOR
09297 || (TREE_CODE (exp) == VAR_DECL && TREE_STATIC (exp)))
09298 return decl_readonly_section (exp, 0);
09299 else
09300 return false;
09301 }
09302
09303
09304
09305
09306
09307
09308
09309
09310
09311
09312
09313
09314
09315
09316
09317
09318
09319
09320 static tree
09321 fold_builtin_strstr (tree arglist, tree type)
09322 {
09323 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
09324 return 0;
09325 else
09326 {
09327 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
09328 tree fn;
09329 const char *p1, *p2;
09330
09331 p2 = c_getstr (s2);
09332 if (p2 == NULL)
09333 return 0;
09334
09335 p1 = c_getstr (s1);
09336 if (p1 != NULL)
09337 {
09338 const char *r = strstr (p1, p2);
09339 tree tem;
09340
09341 if (r == NULL)
09342 return build_int_cst (TREE_TYPE (s1), 0);
09343
09344
09345 tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1),
09346 s1, build_int_cst (TREE_TYPE (s1), r - p1));
09347 return fold_convert (type, tem);
09348 }
09349
09350
09351
09352 if (p2[0] == '\0')
09353 return fold_convert (type, s1);
09354
09355 if (p2[1] != '\0')
09356 return 0;
09357
09358 fn = implicit_built_in_decls[BUILT_IN_STRCHR];
09359 if (!fn)
09360 return 0;
09361
09362
09363
09364 arglist = build_tree_list (NULL_TREE,
09365 build_int_cst (NULL_TREE, p2[0]));
09366 arglist = tree_cons (NULL_TREE, s1, arglist);
09367 return build_function_call_expr (fn, arglist);
09368 }
09369 }
09370
09371
09372
09373
09374
09375
09376
09377
09378
09379
09380
09381
09382
09383
09384
09385
09386
09387
09388 static tree
09389 fold_builtin_strchr (tree arglist, tree type)
09390 {
09391 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
09392 return 0;
09393 else
09394 {
09395 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
09396 const char *p1;
09397
09398 if (TREE_CODE (s2) != INTEGER_CST)
09399 return 0;
09400
09401 p1 = c_getstr (s1);
09402 if (p1 != NULL)
09403 {
09404 char c;
09405 const char *r;
09406 tree tem;
09407
09408 if (target_char_cast (s2, &c))
09409 return 0;
09410
09411 r = strchr (p1, c);
09412
09413 if (r == NULL)
09414 return build_int_cst (TREE_TYPE (s1), 0);
09415
09416
09417 tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1),
09418 s1, build_int_cst (TREE_TYPE (s1), r - p1));
09419 return fold_convert (type, tem);
09420 }
09421 return 0;
09422 }
09423 }
09424
09425
09426
09427
09428
09429
09430
09431
09432
09433
09434
09435
09436
09437
09438
09439
09440
09441
09442 static tree
09443 fold_builtin_strrchr (tree arglist, tree type)
09444 {
09445 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
09446 return 0;
09447 else
09448 {
09449 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
09450 tree fn;
09451 const char *p1;
09452
09453 if (TREE_CODE (s2) != INTEGER_CST)
09454 return 0;
09455
09456 p1 = c_getstr (s1);
09457 if (p1 != NULL)
09458 {
09459 char c;
09460 const char *r;
09461 tree tem;
09462
09463 if (target_char_cast (s2, &c))
09464 return 0;
09465
09466 r = strrchr (p1, c);
09467
09468 if (r == NULL)
09469 return build_int_cst (TREE_TYPE (s1), 0);
09470
09471
09472 tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1),
09473 s1, build_int_cst (TREE_TYPE (s1), r - p1));
09474 return fold_convert (type, tem);
09475 }
09476
09477 if (! integer_zerop (s2))
09478 return 0;
09479
09480 fn = implicit_built_in_decls[BUILT_IN_STRCHR];
09481 if (!fn)
09482 return 0;
09483
09484
09485 return build_function_call_expr (fn, arglist);
09486 }
09487 }
09488
09489
09490
09491
09492
09493
09494
09495
09496
09497
09498
09499
09500
09501
09502
09503
09504
09505
09506 static tree
09507 fold_builtin_strpbrk (tree arglist, tree type)
09508 {
09509 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
09510 return 0;
09511 else
09512 {
09513 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
09514 tree fn;
09515 const char *p1, *p2;
09516
09517 p2 = c_getstr (s2);
09518 if (p2 == NULL)
09519 return 0;
09520
09521 p1 = c_getstr (s1);
09522 if (p1 != NULL)
09523 {
09524 const char *r = strpbrk (p1, p2);
09525 tree tem;
09526
09527 if (r == NULL)
09528 return build_int_cst (TREE_TYPE (s1), 0);
09529
09530
09531 tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1),
09532 s1, build_int_cst (TREE_TYPE (s1), r - p1));
09533 return fold_convert (type, tem);
09534 }
09535
09536 if (p2[0] == '\0')
09537
09538
09539 return omit_one_operand (TREE_TYPE (s1), integer_zero_node, s1);
09540
09541 if (p2[1] != '\0')
09542 return 0;
09543
09544 fn = implicit_built_in_decls[BUILT_IN_STRCHR];
09545 if (!fn)
09546 return 0;
09547
09548
09549
09550 arglist = build_tree_list (NULL_TREE,
09551 build_int_cst (NULL_TREE, p2[0]));
09552 arglist = tree_cons (NULL_TREE, s1, arglist);
09553 return build_function_call_expr (fn, arglist);
09554 }
09555 }
09556
09557
09558
09559
09560
09561
09562
09563
09564
09565
09566
09567
09568
09569
09570
09571
09572
09573
09574 static tree
09575 fold_builtin_strcat (tree arglist)
09576 {
09577 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
09578 return 0;
09579 else
09580 {
09581 tree dst = TREE_VALUE (arglist),
09582 src = TREE_VALUE (TREE_CHAIN (arglist));
09583 const char *p = c_getstr (src);
09584
09585
09586 if (p && *p == '\0')
09587 return dst;
09588
09589 return 0;
09590 }
09591 }
09592
09593
09594
09595
09596
09597
09598
09599
09600
09601
09602
09603
09604
09605
09606
09607
09608
09609
09610 static tree
09611 fold_builtin_strncat (tree arglist)
09612 {
09613 if (!validate_arglist (arglist,
09614 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
09615 return 0;
09616 else
09617 {
09618 tree dst = TREE_VALUE (arglist);
09619 tree src = TREE_VALUE (TREE_CHAIN (arglist));
09620 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
09621 const char *p = c_getstr (src);
09622
09623
09624
09625 if (integer_zerop (len) || (p && *p == '\0'))
09626 return omit_two_operands (TREE_TYPE (dst), dst, src, len);
09627
09628
09629
09630 if (TREE_CODE (len) == INTEGER_CST && p
09631 && compare_tree_int (len, strlen (p)) >= 0)
09632 {
09633 tree newarglist
09634 = tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src));
09635 tree fn = implicit_built_in_decls[BUILT_IN_STRCAT];
09636
09637
09638
09639 if (!fn)
09640 return 0;
09641
09642 return build_function_call_expr (fn, newarglist);
09643 }
09644 return 0;
09645 }
09646 }
09647
09648
09649
09650
09651
09652
09653
09654
09655
09656
09657
09658
09659
09660
09661
09662
09663
09664
09665 static tree
09666 fold_builtin_strspn (tree arglist)
09667 {
09668 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
09669 return 0;
09670 else
09671 {
09672 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
09673 const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
09674
09675
09676 if (p1 && p2)
09677 {
09678 const size_t r = strspn (p1, p2);
09679 return size_int (r);
09680 }
09681
09682
09683 if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
09684
09685
09686 return omit_two_operands (integer_type_node, integer_zero_node,
09687 s1, s2);
09688 return 0;
09689 }
09690 }
09691
09692
09693
09694
09695
09696
09697
09698
09699
09700
09701
09702
09703
09704
09705
09706
09707
09708
09709 static tree
09710 fold_builtin_strcspn (tree arglist)
09711 {
09712 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
09713 return 0;
09714 else
09715 {
09716 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
09717 const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
09718
09719
09720 if (p1 && p2)
09721 {
09722 const size_t r = strcspn (p1, p2);
09723 return size_int (r);
09724 }
09725
09726
09727 if (p1 && *p1 == '\0')
09728 {
09729
09730
09731 return omit_one_operand (integer_type_node,
09732 integer_zero_node, s2);
09733 }
09734
09735
09736 if (p2 && *p2 == '\0')
09737 {
09738 tree newarglist = build_tree_list (NULL_TREE, s1),
09739 fn = implicit_built_in_decls[BUILT_IN_STRLEN];
09740
09741
09742
09743 if (!fn)
09744 return 0;
09745
09746 return build_function_call_expr (fn, newarglist);
09747 }
09748 return 0;
09749 }
09750 }
09751
09752
09753
09754
09755
09756
09757
09758 tree
09759 fold_builtin_fputs (tree arglist, bool ignore, bool unlocked, tree len)
09760 {
09761 tree fn;
09762
09763
09764 tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
09765 : implicit_built_in_decls[BUILT_IN_FPUTC];
09766 tree const fn_fwrite = unlocked ? built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
09767 : implicit_built_in_decls[BUILT_IN_FWRITE];
09768
09769
09770 if (!ignore)
09771 return 0;
09772
09773
09774 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
09775 return 0;
09776
09777 if (! len)
09778 len = c_strlen (TREE_VALUE (arglist), 0);
09779
09780
09781
09782 if (!len
09783 || TREE_CODE (len) != INTEGER_CST)
09784 return 0;
09785
09786 switch (compare_tree_int (len, 1))
09787 {
09788 case -1:
09789 return omit_one_operand (integer_type_node, integer_zero_node,
09790 TREE_VALUE (TREE_CHAIN (arglist)));
09791
09792 case 0:
09793 {
09794 const char *p = c_getstr (TREE_VALUE (arglist));
09795
09796 if (p != NULL)
09797 {
09798
09799
09800 arglist = build_tree_list (NULL_TREE,
09801 TREE_VALUE (TREE_CHAIN (arglist)));
09802 arglist = tree_cons (NULL_TREE,
09803 build_int_cst (NULL_TREE, p[0]),
09804 arglist);
09805 fn = fn_fputc;
09806 break;
09807 }
09808 }
09809
09810 case 1:
09811 {
09812 tree string_arg;
09813
09814
09815 if (optimize_size)
09816 return 0;
09817 string_arg = TREE_VALUE (arglist);
09818
09819
09820 arglist = build_tree_list (NULL_TREE,
09821 TREE_VALUE (TREE_CHAIN (arglist)));
09822 arglist = tree_cons (NULL_TREE, len, arglist);
09823 arglist = tree_cons (NULL_TREE, size_one_node, arglist);
09824 arglist = tree_cons (NULL_TREE, string_arg, arglist);
09825 fn = fn_fwrite;
09826 break;
09827 }
09828 default:
09829 gcc_unreachable ();
09830 }
09831
09832
09833
09834 if (!fn)
09835 return 0;
09836
09837
09838
09839 return build_function_call_expr (fn, arglist);
09840 }
09841
09842
09843
09844
09845 bool
09846 fold_builtin_next_arg (tree arglist)
09847 {
09848 tree fntype = TREE_TYPE (current_function_decl);
09849
09850 if (TYPE_ARG_TYPES (fntype) == 0
09851 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
09852 == void_type_node))
09853 {
09854 error ("%<va_start%> used in function with fixed args");
09855 return true;
09856 }
09857 else if (!arglist)
09858 {
09859
09860
09861 warning (0, "%<__builtin_next_arg%> called without an argument");
09862 return true;
09863 }
09864
09865
09866 else if (!TREE_CHAIN (arglist)
09867 || !integer_zerop (TREE_VALUE (arglist))
09868 || !integer_zerop (TREE_VALUE (TREE_CHAIN (arglist)))
09869 || TREE_CHAIN (TREE_CHAIN (arglist)))
09870 {
09871 tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
09872 tree arg = TREE_VALUE (arglist);
09873
09874 if (TREE_CHAIN (arglist))
09875 {
09876 error ("%<va_start%> used with too many arguments");
09877 return true;
09878 }
09879
09880
09881
09882
09883
09884 while (TREE_CODE (arg) == NOP_EXPR
09885 || TREE_CODE (arg) == CONVERT_EXPR
09886 || TREE_CODE (arg) == NON_LVALUE_EXPR
09887 || TREE_CODE (arg) == INDIRECT_REF)
09888 arg = TREE_OPERAND (arg, 0);
09889 if (arg != last_parm)
09890 {
09891
09892
09893
09894
09895
09896 warning (0, "second parameter of %<va_start%> not last named argument");
09897 }
09898
09899
09900
09901
09902
09903 TREE_VALUE (arglist) = integer_zero_node;
09904 TREE_CHAIN (arglist) = build_tree_list (NULL, integer_zero_node);
09905 }
09906 return false;
09907 }
09908
09909
09910
09911
09912
09913
09914
09915
09916 static tree
09917 fold_builtin_sprintf (tree arglist, int ignored)
09918 {
09919 tree call, retval, dest, fmt;
09920 const char *fmt_str = NULL;
09921
09922
09923
09924
09925 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)
09926 && !validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, POINTER_TYPE,
09927 VOID_TYPE))
09928 return NULL_TREE;
09929
09930
09931 dest = TREE_VALUE (arglist);
09932 fmt = TREE_VALUE (TREE_CHAIN (arglist));
09933 arglist = TREE_CHAIN (TREE_CHAIN (arglist));
09934
09935
09936 fmt_str = c_getstr (fmt);
09937 if (fmt_str == NULL)
09938 return NULL_TREE;
09939
09940 call = NULL_TREE;
09941 retval = NULL_TREE;
09942
09943 if (!init_target_chars())
09944 return 0;
09945
09946
09947 if (strchr (fmt_str, target_percent) == NULL)
09948 {
09949 tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
09950
09951 if (!fn)
09952 return NULL_TREE;
09953
09954
09955 if (arglist)
09956 return NULL_TREE;
09957
09958
09959
09960 arglist = build_tree_list (NULL_TREE, fmt);
09961 arglist = tree_cons (NULL_TREE, dest, arglist);
09962 call = build_function_call_expr (fn, arglist);
09963 if (!ignored)
09964 retval = build_int_cst (NULL_TREE, strlen (fmt_str));
09965 }
09966
09967
09968 else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
09969 {
09970 tree fn, orig;
09971 fn = implicit_built_in_decls[BUILT_IN_STRCPY];
09972
09973 if (!fn)
09974 return NULL_TREE;
09975
09976
09977 if (!arglist)
09978 return NULL_TREE;
09979
09980
09981 orig = TREE_VALUE (arglist);
09982 arglist = build_tree_list (NULL_TREE, orig);
09983 arglist = tree_cons (NULL_TREE, dest, arglist);
09984 if (!ignored)
09985 {
09986 retval = c_strlen (orig, 1);
09987 if (!retval || TREE_CODE (retval) != INTEGER_CST)
09988 return NULL_TREE;
09989 }
09990 call = build_function_call_expr (fn, arglist);
09991 }
09992
09993 if (call && retval)
09994 {
09995 retval = fold_convert
09996 (TREE_TYPE (TREE_TYPE (implicit_built_in_decls[BUILT_IN_SPRINTF])),
09997 retval);
09998 return build2 (COMPOUND_EXPR, TREE_TYPE (retval), call, retval);
09999 }
10000 else
10001 return call;
10002 }
10003
10004
10005
10006 rtx
10007 expand_builtin_object_size (tree exp)
10008 {
10009 tree ost;
10010 int object_size_type;
10011 tree fndecl = get_callee_fndecl (exp);
10012 tree arglist = TREE_OPERAND (exp, 1);
10013 location_t locus = EXPR_LOCATION (exp);
10014
10015 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
10016 {
10017 error ("%Hfirst argument of %D must be a pointer, second integer constant",
10018 &locus, fndecl);
10019 expand_builtin_trap ();
10020 return const0_rtx;
10021 }
10022
10023 ost = TREE_VALUE (TREE_CHAIN (arglist));
10024 STRIP_NOPS (ost);
10025
10026 if (TREE_CODE (ost) != INTEGER_CST
10027 || tree_int_cst_sgn (ost) < 0
10028 || compare_tree_int (ost, 3) > 0)
10029 {
10030 error ("%Hlast argument of %D is not integer constant between 0 and 3",
10031 &locus, fndecl);
10032 expand_builtin_trap ();
10033 return const0_rtx;
10034 }
10035
10036 object_size_type = tree_low_cst (ost, 0);
10037
10038 return object_size_type < 2 ? constm1_rtx : const0_rtx;
10039 }
10040
10041
10042
10043
10044
10045
10046
10047 static rtx
10048 expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
10049 enum built_in_function fcode)
10050 {
10051 tree arglist = TREE_OPERAND (exp, 1);
10052 tree dest, src, len, size;
10053
10054 if (!validate_arglist (arglist,
10055 POINTER_TYPE,
10056 fcode == BUILT_IN_MEMSET_CHK
10057 ? INTEGER_TYPE : POINTER_TYPE,
10058 INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
10059 return 0;
10060
10061 dest = TREE_VALUE (arglist);
10062 src = TREE_VALUE (TREE_CHAIN (arglist));
10063 len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
10064 size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
10065
10066 if (! host_integerp (size, 1))
10067 return 0;
10068
10069 if (host_integerp (len, 1) || integer_all_onesp (size))
10070 {
10071 tree fn;
10072
10073 if (! integer_all_onesp (size) && tree_int_cst_lt (size, len))
10074 {
10075 location_t locus = EXPR_LOCATION (exp);
10076 warning (0, "%Hcall to %D will always overflow destination buffer",
10077 &locus, get_callee_fndecl (exp));
10078 return 0;
10079 }
10080
10081 arglist = build_tree_list (NULL_TREE, len);
10082 arglist = tree_cons (NULL_TREE, src, arglist);
10083 arglist = tree_cons (NULL_TREE, dest, arglist);
10084
10085 fn = NULL_TREE;
10086
10087
10088 switch (fcode)
10089 {
10090 case BUILT_IN_MEMCPY_CHK:
10091 fn = built_in_decls[BUILT_IN_MEMCPY];
10092 break;
10093 case BUILT_IN_MEMPCPY_CHK:
10094 fn = built_in_decls[BUILT_IN_MEMPCPY];
10095 break;
10096 case BUILT_IN_MEMMOVE_CHK:
10097 fn = built_in_decls[BUILT_IN_MEMMOVE];
10098 break;
10099 case BUILT_IN_MEMSET_CHK:
10100 fn = built_in_decls[BUILT_IN_MEMSET];
10101 break;
10102 default:
10103 break;
10104 }
10105
10106 if (! fn)
10107 return 0;
10108
10109 fn = build_function_call_expr (fn, arglist);
10110 if (TREE_CODE (fn) == CALL_EXPR)
10111 CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
10112 return expand_expr (fn, target, mode, EXPAND_NORMAL);
10113 }
10114 else if (fcode == BUILT_IN_MEMSET_CHK)
10115 return 0;
10116 else
10117 {
10118 unsigned int dest_align
10119 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
10120
10121
10122 if (dest_align == 0)
10123 return 0;
10124
10125
10126 if (operand_equal_p (src, dest, 0))
10127 {
10128 tree expr;
10129
10130 if (fcode != BUILT_IN_MEMPCPY_CHK)
10131 {
10132
10133 expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL);
10134 return expand_expr (dest, target, mode, EXPAND_NORMAL);
10135 }
10136
10137 len = fold_convert (TREE_TYPE (dest), len);
10138 expr = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len);
10139 return expand_expr (expr, target, mode, EXPAND_NORMAL);
10140 }
10141
10142
10143 if (fcode == BUILT_IN_MEMMOVE_CHK)
10144 {
10145 unsigned int src_align
10146 = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
10147
10148 if (src_align == 0)
10149 return 0;
10150
10151
10152
10153 if (readonly_data_expr (src))
10154 {
10155 tree fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
10156 if (!fn)
10157 return 0;
10158 fn = build_function_call_expr (fn, arglist);
10159 if (TREE_CODE (fn) == CALL_EXPR)
10160 CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
10161 return expand_expr (fn, target, mode, EXPAND_NORMAL);
10162 }
10163 }
10164 return 0;
10165 }
10166 }
10167
10168
10169
10170 static void
10171 maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
10172 {
10173 int arg_mask, is_strlen = 0;
10174 tree arglist = TREE_OPERAND (exp, 1), a;
10175 tree len, size;
10176 location_t locus;
10177
10178 switch (fcode)
10179 {
10180 case BUILT_IN_STRCPY_CHK:
10181 case BUILT_IN_STPCPY_CHK:
10182
10183
10184 case BUILT_IN_STRCAT_CHK:
10185 arg_mask = 6;
10186 is_strlen = 1;
10187 break;
10188 case BUILT_IN_STRNCPY_CHK:
10189 arg_mask = 12;
10190 break;
10191 case BUILT_IN_SNPRINTF_CHK:
10192 case BUILT_IN_VSNPRINTF_CHK:
10193 arg_mask = 10;
10194 break;
10195 default:
10196 gcc_unreachable ();
10197 }
10198
10199 len = NULL_TREE;
10200 size = NULL_TREE;
10201 for (a = arglist; a && arg_mask; a = TREE_CHAIN (a), arg_mask >>= 1)
10202 if (arg_mask & 1)
10203 {
10204 if (len)
10205 size = a;
10206 else
10207 len = a;
10208 }
10209
10210 if (!len || !size)
10211 return;
10212
10213 len = TREE_VALUE (len);
10214 size = TREE_VALUE (size);
10215
10216 if (! host_integerp (size, 1) || integer_all_onesp (size))
10217 return;
10218
10219 if (is_strlen)
10220 {
10221 len = c_strlen (len, 1);
10222 if (! len || ! host_integerp (len, 1) || tree_int_cst_lt (len, size))
10223 return;
10224 }
10225 else if (! host_integerp (len, 1) || ! tree_int_cst_lt (size, len))
10226 return;
10227
10228 locus = EXPR_LOCATION (exp);
10229 warning (0, "%Hcall to %D will always overflow destination buffer",
10230 &locus, get_callee_fndecl (exp));
10231 }
10232
10233
10234
10235
10236 static void
10237 maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
10238 {
10239 tree arglist = TREE_OPERAND (exp, 1);
10240 tree dest, size, len, fmt, flag;
10241 const char *fmt_str;
10242
10243
10244 if (! arglist)
10245 return;
10246 dest = TREE_VALUE (arglist);
10247 arglist = TREE_CHAIN (arglist);
10248 if (! arglist)
10249 return;
10250 flag = TREE_VALUE (arglist);
10251 arglist = TREE_CHAIN (arglist);
10252 if (! arglist)
10253 return;
10254 size = TREE_VALUE (arglist);
10255 arglist = TREE_CHAIN (arglist);
10256 if (! arglist)
10257 return;
10258 fmt = TREE_VALUE (arglist);
10259 arglist = TREE_CHAIN (arglist);
10260
10261 if (! host_integerp (size, 1) || integer_all_onesp (size))
10262 return;
10263
10264
10265 fmt_str = c_getstr (fmt);
10266 if (fmt_str == NULL)
10267 return;
10268
10269 if (!init_target_chars())
10270 return;
10271
10272
10273 if (strchr (fmt_str, target_percent) == 0)
10274 len = build_int_cstu (size_type_node, strlen (fmt_str));
10275
10276
10277 else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, target_percent_s) == 0)
10278 {
10279 tree arg;
10280
10281 if (! arglist)
10282 return;
10283 arg = TREE_VALUE (arglist);
10284 if (! POINTER_TYPE_P (TREE_TYPE (arg)))
10285 return;
10286
10287 len = c_strlen (arg, 1);
10288 if (!len || ! host_integerp (len, 1))
10289 return;
10290 }
10291 else
10292 return;
10293
10294 if (! tree_int_cst_lt (len, size))
10295 {
10296 location_t locus = EXPR_LOCATION (exp);
10297 warning (0, "%Hcall to %D will always overflow destination buffer",
10298 &locus, get_callee_fndecl (exp));
10299 }
10300 }
10301
10302
10303
10304 tree
10305 fold_builtin_object_size (tree arglist)
10306 {
10307 tree ptr, ost, ret = 0;
10308 int object_size_type;
10309
10310 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
10311 return 0;
10312
10313 ptr = TREE_VALUE (arglist);
10314 ost = TREE_VALUE (TREE_CHAIN (arglist));
10315 STRIP_NOPS (ost);
10316
10317 if (TREE_CODE (ost) != INTEGER_CST
10318 || tree_int_cst_sgn (ost) < 0
10319 || compare_tree_int (ost, 3) > 0)
10320 return 0;
10321
10322 object_size_type = tree_low_cst (ost, 0);
10323
10324
10325
10326
10327 if (TREE_SIDE_EFFECTS (ptr))
10328 return fold_convert (size_type_node,
10329 object_size_type < 2
10330 ? integer_minus_one_node : integer_zero_node);
10331
10332 if (TREE_CODE (ptr) == ADDR_EXPR)
10333 ret = build_int_cstu (size_type_node,
10334 compute_builtin_object_size (ptr, object_size_type));
10335
10336 else if (TREE_CODE (ptr) == SSA_NAME)
10337 {
10338 unsigned HOST_WIDE_INT bytes;
10339
10340
10341
10342
10343 bytes = compute_builtin_object_size (ptr, object_size_type);
10344 if (bytes != (unsigned HOST_WIDE_INT) (object_size_type < 2
10345 ? -1 : 0))
10346 ret = build_int_cstu (size_type_node, bytes);
10347 }
10348
10349 if (ret)
10350 {
10351 ret = force_fit_type (ret, -1, false, false);
10352 if (TREE_CONSTANT_OVERFLOW (ret))
10353 ret = 0;
10354 }
10355
10356 return ret;
10357 }
10358
10359
10360
10361
10362
10363
10364 tree
10365 fold_builtin_memory_chk (tree fndecl, tree arglist, tree maxlen, bool ignore,
10366 enum built_in_function fcode)
10367 {
10368 tree dest, src, len, size, fn;
10369
10370 if (!validate_arglist (arglist,
10371 POINTER_TYPE,
10372 fcode == BUILT_IN_MEMSET_CHK
10373 ? INTEGER_TYPE : POINTER_TYPE,
10374 INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
10375 return 0;
10376
10377 dest = TREE_VALUE (arglist);
10378
10379 src = TREE_VALUE (TREE_CHAIN (arglist));
10380 len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
10381 size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
10382
10383
10384
10385 if (fcode != BUILT_IN_MEMSET_CHK && operand_equal_p (src, dest, 0))
10386 {
10387 if (fcode != BUILT_IN_MEMPCPY_CHK)
10388 return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, len);
10389 else
10390 {
10391 tree temp = fold_convert (TREE_TYPE (dest), len);
10392 temp = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, temp);
10393 return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), temp);
10394 }
10395 }
10396
10397 if (! host_integerp (size, 1))
10398 return 0;
10399
10400 if (! integer_all_onesp (size))
10401 {
10402 if (! host_integerp (len, 1))
10403 {
10404
10405
10406
10407 if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
10408 {
10409 if (fcode == BUILT_IN_MEMPCPY_CHK && ignore)
10410 {
10411
10412
10413 fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
10414 if (!fn)
10415 return 0;
10416
10417 return build_function_call_expr (fn, arglist);
10418 }
10419 return 0;
10420 }
10421 }
10422 else
10423 maxlen = len;
10424
10425 if (tree_int_cst_lt (size, maxlen))
10426 return 0;
10427 }
10428
10429 arglist = build_tree_list (NULL_TREE, len);
10430 arglist = tree_cons (NULL_TREE, src, arglist);
10431 arglist = tree_cons (NULL_TREE, dest, arglist);
10432
10433 fn = NULL_TREE;
10434
10435
10436 switch (fcode)
10437 {
10438 case BUILT_IN_MEMCPY_CHK:
10439 fn = built_in_decls[BUILT_IN_MEMCPY];
10440 break;
10441 case BUILT_IN_MEMPCPY_CHK:
10442 fn = built_in_decls[BUILT_IN_MEMPCPY];
10443 break;
10444 case BUILT_IN_MEMMOVE_CHK:
10445 fn = built_in_decls[BUILT_IN_MEMMOVE];
10446 break;
10447 case BUILT_IN_MEMSET_CHK:
10448 fn = built_in_decls[BUILT_IN_MEMSET];
10449 break;
10450 default:
10451 break;
10452 }
10453
10454 if (!fn)
10455 return 0;
10456
10457 return build_function_call_expr (fn, arglist);
10458 }
10459
10460
10461
10462
10463
10464
10465 tree
10466 fold_builtin_stxcpy_chk (tree fndecl, tree arglist, tree maxlen, bool ignore,
10467 enum built_in_function fcode)
10468 {
10469 tree dest, src, size, len, fn;
10470
10471 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE,
10472 VOID_TYPE))
10473 return 0;
10474
10475 dest = TREE_VALUE (arglist);
10476 src = TREE_VALUE (TREE_CHAIN (arglist));
10477 size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
10478
10479
10480 if (fcode == BUILT_IN_STRCPY_CHK && operand_equal_p (src, dest, 0))
10481 return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), dest);
10482
10483 if (! host_integerp (size, 1))
10484 return 0;
10485
10486 if (! integer_all_onesp (size))
10487 {
10488 len = c_strlen (src, 1);
10489 if (! len || ! host_integerp (len, 1))
10490 {
10491
10492
10493
10494 if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
10495 {
10496 if (fcode == BUILT_IN_STPCPY_CHK)
10497 {
10498 if (! ignore)
10499 return 0;
10500
10501
10502
10503 fn = built_in_decls[BUILT_IN_STRCPY_CHK];
10504 if (!fn)
10505 return 0;
10506
10507 return build_function_call_expr (fn, arglist);
10508 }
10509
10510 if (! len || TREE_SIDE_EFFECTS (len))
10511 return 0;
10512
10513
10514
10515 fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
10516 if (!fn)
10517 return 0;
10518
10519 len = size_binop (PLUS_EXPR, len, ssize_int (1));
10520 arglist = build_tree_list (NULL_TREE, size);
10521 arglist = tree_cons (NULL_TREE, len, arglist);
10522 arglist = tree_cons (NULL_TREE, src, arglist);
10523 arglist = tree_cons (NULL_TREE, dest, arglist);
10524 return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)),
10525 build_function_call_expr (fn, arglist));
10526 }
10527 }
10528 else
10529 maxlen = len;
10530
10531 if (! tree_int_cst_lt (maxlen, size))
10532 return 0;
10533 }
10534
10535 arglist = build_tree_list (NULL_TREE, src);
10536 arglist = tree_cons (NULL_TREE, dest, arglist);
10537
10538
10539 fn = built_in_decls[fcode == BUILT_IN_STPCPY_CHK
10540 ? BUILT_IN_STPCPY : BUILT_IN_STRCPY];
10541 if (!fn)
10542 return 0;
10543
10544 return build_function_call_expr (fn, arglist);
10545 }
10546
10547
10548
10549
10550 tree
10551 fold_builtin_strncpy_chk (tree arglist, tree maxlen)
10552 {
10553 tree dest, src, size, len, fn;
10554
10555 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE,
10556 INTEGER_TYPE, VOID_TYPE))
10557 return 0;
10558
10559 dest = TREE_VALUE (arglist);
10560 src = TREE_VALUE (TREE_CHAIN (arglist));
10561 len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
10562 size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
10563
10564 if (! host_integerp (size, 1))
10565 return 0;
10566
10567 if (! integer_all_onesp (size))
10568 {
10569 if (! host_integerp (len, 1))
10570 {
10571
10572
10573
10574 if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
10575 return 0;
10576 }
10577 else
10578 maxlen = len;
10579
10580 if (tree_int_cst_lt (size, maxlen))
10581 return 0;
10582 }
10583
10584 arglist = build_tree_list (NULL_TREE, len);
10585 arglist = tree_cons (NULL_TREE, src, arglist);
10586 arglist = tree_cons (NULL_TREE, dest, arglist);
10587
10588
10589 fn = built_in_decls[BUILT_IN_STRNCPY];
10590 if (!fn)
10591 return 0;
10592
10593 return build_function_call_expr (fn, arglist);
10594 }
10595
10596
10597
10598 static tree
10599 fold_builtin_strcat_chk (tree fndecl, tree arglist)
10600 {
10601 tree dest, src, size, fn;
10602 const char *p;
10603
10604 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE,
10605 VOID_TYPE))
10606 return 0;
10607
10608 dest = TREE_VALUE (arglist);
10609 src = TREE_VALUE (TREE_CHAIN (arglist));
10610 size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
10611
10612 p = c_getstr (src);
10613
10614 if (p && *p == '\0')
10615 return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
10616
10617 if (! host_integerp (size, 1) || ! integer_all_onesp (size))
10618 return 0;
10619
10620 arglist = build_tree_list (NULL_TREE, src);
10621 arglist = tree_cons (NULL_TREE, dest, arglist);
10622
10623
10624 fn = built_in_decls[BUILT_IN_STRCAT];
10625 if (!fn)
10626 return 0;
10627
10628 return build_function_call_expr (fn, arglist);
10629 }
10630
10631
10632
10633 static tree
10634 fold_builtin_strncat_chk (tree fndecl, tree arglist)
10635 {
10636 tree dest, src, size, len, fn;
10637 const char *p;
10638
10639 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE,
10640 INTEGER_TYPE, VOID_TYPE))
10641 return 0;
10642
10643 dest = TREE_VALUE (arglist);
10644 src = TREE_VALUE (TREE_CHAIN (arglist));
10645 len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
10646 size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
10647
10648 p = c_getstr (src);
10649
10650 if (p && *p == '\0')
10651 return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, len);
10652 else if (integer_zerop (len))
10653 return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
10654
10655 if (! host_integerp (size, 1))
10656 return 0;
10657
10658 if (! integer_all_onesp (size))
10659 {
10660 tree src_len = c_strlen (src, 1);
10661 if (src_len
10662 && host_integerp (src_len, 1)
10663 && host_integerp (len, 1)
10664 && ! tree_int_cst_lt (len, src_len))
10665 {
10666
10667 fn = built_in_decls[BUILT_IN_STRCAT_CHK];
10668 if (!fn)
10669 return 0;
10670
10671 arglist = build_tree_list (NULL_TREE, size);
10672 arglist = tree_cons (NULL_TREE, src, arglist);
10673 arglist = tree_cons (NULL_TREE, dest, arglist);
10674 return build_function_call_expr (fn, arglist);
10675 }
10676 return 0;
10677 }
10678
10679 arglist = build_tree_list (NULL_TREE, len);
10680 arglist = tree_cons (NULL_TREE, src, arglist);
10681 arglist = tree_cons (NULL_TREE, dest, arglist);
10682
10683
10684 fn = built_in_decls[BUILT_IN_STRNCAT];
10685 if (!fn)
10686 return 0;
10687
10688 return build_function_call_expr (fn, arglist);
10689 }
10690
10691
10692
10693
10694
10695 static tree
10696 fold_builtin_sprintf_chk (tree arglist, enum built_in_function fcode)
10697 {
10698 tree dest, size, len, fn, fmt, flag;
10699 const char *fmt_str;
10700
10701
10702 if (! arglist)
10703 return 0;
10704 dest = TREE_VALUE (arglist);
10705 if (! POINTER_TYPE_P (TREE_TYPE (dest)))
10706 return 0;
10707 arglist = TREE_CHAIN (arglist);
10708 if (! arglist)
10709 return 0;
10710 flag = TREE_VALUE (arglist);
10711 if (TREE_CODE (TREE_TYPE (flag)) != INTEGER_TYPE)
10712 return 0;
10713 arglist = TREE_CHAIN (arglist);
10714 if (! arglist)
10715 return 0;
10716 size = TREE_VALUE (arglist);
10717 if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE)
10718 return 0;
10719 arglist = TREE_CHAIN (arglist);
10720 if (! arglist)
10721 return 0;
10722 fmt = TREE_VALUE (arglist);
10723 if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
10724 return 0;
10725 arglist = TREE_CHAIN (arglist);
10726
10727 if (! host_integerp (size, 1))
10728 return 0;
10729
10730 len = NULL_TREE;
10731
10732 if (!init_target_chars())
10733 return 0;
10734
10735
10736 fmt_str = c_getstr (fmt);
10737 if (fmt_str != NULL)
10738 {
10739
10740 if (strchr (fmt_str, target_percent) == 0)
10741 {
10742 if (fcode != BUILT_IN_SPRINTF_CHK || arglist == NULL_TREE)
10743 len = build_int_cstu (size_type_node, strlen (fmt_str));
10744 }
10745
10746
10747 else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, target_percent_s) == 0)
10748 {
10749 tree arg;
10750
10751 if (arglist && !TREE_CHAIN (arglist))
10752 {
10753 arg = TREE_VALUE (arglist);
10754 if (POINTER_TYPE_P (TREE_TYPE (arg)))
10755 {
10756 len = c_strlen (arg, 1);
10757 if (! len || ! host_integerp (len, 1))
10758 len = NULL_TREE;
10759 }
10760 }
10761 }
10762 }
10763
10764 if (! integer_all_onesp (size))
10765 {
10766 if (! len || ! tree_int_cst_lt (len, size))
10767 return 0;
10768 }
10769
10770
10771
10772 if (! integer_zerop (flag))
10773 {
10774 if (fmt_str == NULL)
10775 return 0;
10776 if (strchr (fmt_str, target_percent) != NULL && strcmp (fmt_str, target_percent_s))
10777 return 0;
10778 }
10779
10780 arglist = tree_cons (NULL_TREE, fmt, arglist);
10781 arglist = tree_cons (NULL_TREE, dest, arglist);
10782
10783
10784 fn = built_in_decls[fcode == BUILT_IN_VSPRINTF_CHK
10785 ? BUILT_IN_VSPRINTF : BUILT_IN_SPRINTF];
10786 if (!fn)
10787 return 0;
10788
10789 return build_function_call_expr (fn, arglist);
10790 }
10791
10792
10793
10794
10795
10796
10797
10798 tree
10799 fold_builtin_snprintf_chk (tree arglist, tree maxlen,
10800 enum built_in_function fcode)
10801 {
10802 tree dest, size, len, fn, fmt, flag;
10803 const char *fmt_str;
10804
10805
10806 if (! arglist)
10807 return 0;
10808 dest = TREE_VALUE (arglist);
10809 if (! POINTER_TYPE_P (TREE_TYPE (dest)))
10810 return 0;
10811 arglist = TREE_CHAIN (arglist);
10812 if (! arglist)
10813 return 0;
10814 len = TREE_VALUE (arglist);
10815 if (TREE_CODE (TREE_TYPE (len)) != INTEGER_TYPE)
10816 return 0;
10817 arglist = TREE_CHAIN (arglist);
10818 if (! arglist)
10819 return 0;
10820 flag = TREE_VALUE (arglist);
10821 if (TREE_CODE (TREE_TYPE (len)) != INTEGER_TYPE)
10822 return 0;
10823 arglist = TREE_CHAIN (arglist);
10824 if (! arglist)
10825 return 0;
10826 size = TREE_VALUE (arglist);
10827 if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE)
10828 return 0;
10829 arglist = TREE_CHAIN (arglist);
10830 if (! arglist)
10831 return 0;
10832 fmt = TREE_VALUE (arglist);
10833 if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
10834 return 0;
10835 arglist = TREE_CHAIN (arglist);
10836
10837 if (! host_integerp (size, 1))
10838 return 0;
10839
10840 if (! integer_all_onesp (size))
10841 {
10842 if (! host_integerp (len, 1))
10843 {
10844
10845
10846
10847 if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
10848 return 0;
10849 }
10850 else
10851 maxlen = len;
10852
10853 if (tree_int_cst_lt (size, maxlen))
10854 return 0;
10855 }
10856
10857 if (!init_target_chars())
10858 return 0;
10859
10860
10861
10862 if (! integer_zerop (flag))
10863 {
10864 fmt_str = c_getstr (fmt);
10865 if (fmt_str == NULL)
10866 return 0;
10867 if (strchr (fmt_str, target_percent) != NULL && strcmp (fmt_str, target_percent_s))
10868 return 0;
10869 }
10870
10871 arglist = tree_cons (NULL_TREE, fmt, arglist);
10872 arglist = tree_cons (NULL_TREE, len, arglist);
10873 arglist = tree_cons (NULL_TREE, dest, arglist);
10874
10875
10876
10877 fn = built_in_decls[fcode == BUILT_IN_VSNPRINTF_CHK
10878 ? BUILT_IN_VSNPRINTF : BUILT_IN_SNPRINTF];
10879 if (!fn)
10880 return 0;
10881
10882 return build_function_call_expr (fn, arglist);
10883 }
10884
10885
10886
10887
10888
10889
10890
10891 static tree
10892 fold_builtin_printf (tree fndecl, tree arglist, bool ignore,
10893 enum built_in_function fcode)
10894 {
10895 tree fmt, fn = NULL_TREE, fn_putchar, fn_puts, arg, call;
10896 const char *fmt_str = NULL;
10897
10898
10899 if (! ignore)
10900 return 0;
10901
10902
10903 if (fcode == BUILT_IN_PRINTF_CHK || fcode == BUILT_IN_VPRINTF_CHK)
10904 {
10905 tree flag;
10906
10907 if (! arglist)
10908 return 0;
10909 flag = TREE_VALUE (arglist);
10910 if (TREE_CODE (TREE_TYPE (flag)) != INTEGER_TYPE
10911 || TREE_SIDE_EFFECTS (flag))
10912 return 0;
10913 arglist = TREE_CHAIN (arglist);
10914 }
10915
10916 if (! arglist)
10917 return 0;
10918 fmt = TREE_VALUE (arglist);
10919 if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
10920 return 0;
10921 arglist = TREE_CHAIN (arglist);
10922
10923
10924 fmt_str = c_getstr (fmt);
10925 if (fmt_str == NULL)
10926 return NULL_TREE;
10927
10928 if (fcode == BUILT_IN_PRINTF_UNLOCKED)
10929 {
10930
10931
10932 fn_putchar = built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED];
10933 fn_puts = built_in_decls[BUILT_IN_PUTS_UNLOCKED];
10934 }
10935 else
10936 {
10937 fn_putchar = implicit_built_in_decls[BUILT_IN_PUTCHAR];
10938 fn_puts = implicit_built_in_decls[BUILT_IN_PUTS];
10939 }
10940
10941 if (!init_target_chars())
10942 return 0;
10943
10944 if (strcmp (fmt_str, target_percent_s) == 0 || strchr (fmt_str, target_percent) == NULL)
10945 {
10946 const char *str;
10947
10948 if (strcmp (fmt_str, target_percent_s) == 0)
10949 {
10950 if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK)
10951 return 0;
10952
10953 if (! arglist
10954 || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
10955 || TREE_CHAIN (arglist))
10956 return 0;
10957
10958 str = c_getstr (TREE_VALUE (arglist));
10959 if (str == NULL)
10960 return 0;
10961 }
10962 else
10963 {
10964
10965 if (fcode != BUILT_IN_VPRINTF && fcode != BUILT_IN_VPRINTF_CHK
10966 && arglist)
10967 return 0;
10968 str = fmt_str;
10969 }
10970
10971
10972 if (str[0] == '\0')
10973 return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), 0);
10974
10975
10976 if (str[1] == '\0')
10977 {
10978
10979
10980
10981 arg = build_int_cst (NULL_TREE, str[0]);
10982 arglist = build_tree_list (NULL_TREE, arg);
10983 fn = fn_putchar;
10984 }
10985 else
10986 {
10987
10988 size_t len = strlen (str);
10989 if ((unsigned char)str[len - 1] == target_newline)
10990 {
10991
10992
10993 char *newstr = alloca (len);
10994 memcpy (newstr, str, len - 1);
10995 newstr[len - 1] = 0;
10996
10997 arg = build_string_literal (len, newstr);
10998 arglist = build_tree_list (NULL_TREE, arg);
10999 fn = fn_puts;
11000 }
11001 else
11002
11003
11004 return 0;
11005 }
11006 }
11007
11008
11009 else if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK)
11010 return 0;
11011
11012
11013 else if (strcmp (fmt_str, target_percent_s_newline) == 0)
11014 {
11015 if (! arglist
11016 || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
11017 || TREE_CHAIN (arglist))
11018 return 0;
11019 fn = fn_puts;
11020 }
11021
11022
11023 else if (strcmp (fmt_str, target_percent_c) == 0)
11024 {
11025 if (! arglist
11026 || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
11027 || TREE_CHAIN (arglist))
11028 return 0;
11029 fn = fn_putchar;
11030 }
11031
11032 if (!fn)
11033 return 0;
11034
11035 call = build_function_call_expr (fn, arglist);
11036 return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), call);
11037 }
11038
11039
11040
11041
11042
11043
11044
11045 static tree
11046 fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore,
11047 enum built_in_function fcode)
11048 {
11049 tree fp, fmt, fn = NULL_TREE, fn_fputc, fn_fputs, arg, call;
11050 const char *fmt_str = NULL;
11051
11052
11053 if (! ignore)
11054 return 0;
11055
11056
11057 if (! arglist)
11058 return 0;
11059 fp = TREE_VALUE (arglist);
11060 if (! POINTER_TYPE_P (TREE_TYPE (fp)))
11061 return 0;
11062 arglist = TREE_CHAIN (arglist);
11063
11064 if (fcode == BUILT_IN_FPRINTF_CHK || fcode == BUILT_IN_VFPRINTF_CHK)
11065 {
11066 tree flag;
11067
11068 if (! arglist)
11069 return 0;
11070 flag = TREE_VALUE (arglist);
11071 if (TREE_CODE (TREE_TYPE (flag)) != INTEGER_TYPE
11072 || TREE_SIDE_EFFECTS (flag))
11073 return 0;
11074 arglist = TREE_CHAIN (arglist);
11075 }
11076
11077 if (! arglist)
11078 return 0;
11079 fmt = TREE_VALUE (arglist);
11080 if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
11081 return 0;
11082 arglist = TREE_CHAIN (arglist);
11083
11084
11085 fmt_str = c_getstr (fmt);
11086 if (fmt_str == NULL)
11087 return NULL_TREE;
11088
11089 if (fcode == BUILT_IN_FPRINTF_UNLOCKED)
11090 {
11091
11092
11093 fn_fputc = built_in_decls[BUILT_IN_FPUTC_UNLOCKED];
11094 fn_fputs = built_in_decls[BUILT_IN_FPUTS_UNLOCKED];
11095 }
11096 else
11097 {
11098 fn_fputc = implicit_built_in_decls[BUILT_IN_FPUTC];
11099 fn_fputs = implicit_built_in_decls[BUILT_IN_FPUTS];
11100 }
11101
11102 if (!init_target_chars())
11103 return 0;
11104
11105
11106 if (strchr (fmt_str, target_percent) == NULL)
11107 {
11108 if (fcode != BUILT_IN_VFPRINTF && fcode != BUILT_IN_VFPRINTF_CHK
11109 && arglist)
11110 return 0;
11111
11112
11113 if (fmt_str[0] == '\0')
11114 {
11115
11116
11117 if (TREE_SIDE_EFFECTS (fp))
11118 return 0;
11119
11120 return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), 0);
11121 }
11122
11123
11124
11125
11126 arglist = build_tree_list (NULL_TREE, fp);
11127 arglist = tree_cons (NULL_TREE, fmt, arglist);
11128 fn = fn_fputs;
11129 }
11130
11131
11132 else if (fcode == BUILT_IN_VFPRINTF || fcode == BUILT_IN_VFPRINTF_CHK)
11133 return 0;
11134
11135
11136 else if (strcmp (fmt_str, target_percent_s) == 0)
11137 {
11138 if (! arglist
11139 || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
11140 || TREE_CHAIN (arglist))
11141 return 0;
11142 arg = TREE_VALUE (arglist);
11143 arglist = build_tree_list (NULL_TREE, fp);
11144 arglist = tree_cons (NULL_TREE, arg, arglist);
11145 fn = fn_fputs;
11146 }
11147
11148
11149 else if (strcmp (fmt_str, target_percent_c) == 0)
11150 {
11151 if (! arglist
11152 || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
11153 || TREE_CHAIN (arglist))
11154 return 0;
11155 arg = TREE_VALUE (arglist);
11156 arglist = build_tree_list (NULL_TREE, fp);
11157 arglist = tree_cons (NULL_TREE, arg, arglist);
11158 fn = fn_fputc;
11159 }
11160
11161 if (!fn)
11162 return 0;
11163
11164 call = build_function_call_expr (fn, arglist);
11165 return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), call);
11166 }
11167
11168
11169
11170 static bool
11171 init_target_chars (void)
11172 {
11173 static bool init;
11174 if (!init)
11175 {
11176 target_newline = lang_hooks.to_target_charset ('\n');
11177 target_percent = lang_hooks.to_target_charset ('%');
11178 target_c = lang_hooks.to_target_charset ('c');
11179 target_s = lang_hooks.to_target_charset ('s');
11180 if (target_newline == 0 || target_percent == 0 || target_c == 0
11181 || target_s == 0)
11182 return false;
11183
11184 target_percent_c[0] = target_percent;
11185 target_percent_c[1] = target_c;
11186 target_percent_c[2] = '\0';
11187
11188 target_percent_s[0] = target_percent;
11189 target_percent_s[1] = target_s;
11190 target_percent_s[2] = '\0';
11191
11192 target_percent_s_newline[0] = target_percent;
11193 target_percent_s_newline[1] = target_s;
11194 target_percent_s_newline[2] = target_newline;
11195 target_percent_s_newline[3] = '\0';
11196
11197 init = true;
11198 }
11199 return true;
11200 }