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 #define CALLED_AS_BUILT_IN(NODE) \
00052 (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
00053
00054 #ifndef PAD_VARARGS_DOWN
00055 #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
00056 #endif
00057
00058
00059 const char *const built_in_class_names[4]
00060 = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
00061
00062 #define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT, IM, COND) #X,
00063 const char * built_in_names[(int) END_BUILTINS] =
00064 {
00065 #include "builtins.def"
00066 };
00067 #undef DEF_BUILTIN
00068
00069
00070
00071 tree built_in_decls[(int) END_BUILTINS];
00072
00073
00074
00075 tree implicit_built_in_decls[(int) END_BUILTINS];
00076
00077 static int get_pointer_alignment (tree, unsigned int);
00078 static const char *c_getstr (tree);
00079 static rtx c_readstr (const char *, enum machine_mode);
00080 static int target_char_cast (tree, char *);
00081 static rtx get_memory_rtx (tree, tree);
00082 static tree build_string_literal (int, const char *);
00083 static int apply_args_size (void);
00084 static int apply_result_size (void);
00085 #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
00086 static rtx result_vector (int, rtx);
00087 #endif
00088 static rtx expand_builtin_setjmp (tree, rtx);
00089 static void expand_builtin_update_setjmp_buf (rtx);
00090 static void expand_builtin_prefetch (tree);
00091 static rtx expand_builtin_apply_args (void);
00092 static rtx expand_builtin_apply_args_1 (void);
00093 static rtx expand_builtin_apply (rtx, rtx, rtx);
00094 static void expand_builtin_return (rtx);
00095 static enum type_class type_to_class (tree);
00096 static rtx expand_builtin_classify_type (tree);
00097 static void expand_errno_check (tree, rtx);
00098 static rtx expand_builtin_mathfn (tree, rtx, rtx);
00099 static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
00100 static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
00101 static rtx expand_builtin_args_info (tree);
00102 static rtx expand_builtin_next_arg (void);
00103 static rtx expand_builtin_va_start (tree);
00104 static rtx expand_builtin_va_end (tree);
00105 static rtx expand_builtin_va_copy (tree);
00106 static rtx expand_builtin_memcmp (tree, tree, rtx, enum machine_mode);
00107 static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode);
00108 static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
00109 static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
00110 static rtx expand_builtin_strcat (tree, tree, rtx, enum machine_mode);
00111 static rtx expand_builtin_strncat (tree, rtx, enum machine_mode);
00112 static rtx expand_builtin_strspn (tree, rtx, enum machine_mode);
00113 static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode);
00114 static rtx expand_builtin_memcpy (tree, rtx, enum machine_mode);
00115 static rtx expand_builtin_mempcpy (tree, tree, rtx, enum machine_mode, int);
00116 static rtx expand_builtin_memmove (tree, tree, rtx, enum machine_mode, tree);
00117 static rtx expand_builtin_bcopy (tree);
00118 static rtx expand_builtin_strcpy (tree, rtx, enum machine_mode);
00119 static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
00120 static rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
00121 static rtx expand_builtin_strncpy (tree, rtx, enum machine_mode);
00122 static rtx builtin_memset_read_str (void *, HOST_WIDE_INT, enum machine_mode);
00123 static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, enum machine_mode);
00124 static rtx expand_builtin_memset (tree, rtx, enum machine_mode, tree);
00125 static rtx expand_builtin_bzero (tree);
00126 static rtx expand_builtin_strlen (tree, rtx, enum machine_mode);
00127 static rtx expand_builtin_strstr (tree, tree, rtx, enum machine_mode);
00128 static rtx expand_builtin_strpbrk (tree, tree, rtx, enum machine_mode);
00129 static rtx expand_builtin_strchr (tree, tree, rtx, enum machine_mode);
00130 static rtx expand_builtin_strrchr (tree, tree, rtx, enum machine_mode);
00131 static rtx expand_builtin_alloca (tree, rtx);
00132 static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
00133 static rtx expand_builtin_frame_address (tree, tree);
00134 static rtx expand_builtin_fputs (tree, rtx, bool);
00135 static rtx expand_builtin_printf (tree, rtx, enum machine_mode, bool);
00136 static rtx expand_builtin_fprintf (tree, rtx, enum machine_mode, bool);
00137 static rtx expand_builtin_sprintf (tree, rtx, enum machine_mode);
00138 static tree stabilize_va_list (tree, int);
00139 static rtx expand_builtin_expect (tree, rtx);
00140 static tree fold_builtin_constant_p (tree);
00141 static tree fold_builtin_classify_type (tree);
00142 static tree fold_builtin_strlen (tree);
00143 static tree fold_builtin_inf (tree, int);
00144 static tree fold_builtin_nan (tree, tree, int);
00145 static int validate_arglist (tree, ...);
00146 static bool integer_valued_real_p (tree);
00147 static tree fold_trunc_transparent_mathfn (tree);
00148 static bool readonly_data_expr (tree);
00149 static rtx expand_builtin_fabs (tree, rtx, rtx);
00150 static rtx expand_builtin_signbit (tree, rtx);
00151 static tree fold_builtin_cabs (tree, tree);
00152 static tree fold_builtin_sqrt (tree, tree);
00153 static tree fold_builtin_cbrt (tree, tree);
00154 static tree fold_builtin_pow (tree, tree, tree);
00155 static tree fold_builtin_powi (tree, tree, tree);
00156 static tree fold_builtin_sin (tree);
00157 static tree fold_builtin_cos (tree, tree, tree);
00158 static tree fold_builtin_tan (tree);
00159 static tree fold_builtin_atan (tree, tree);
00160 static tree fold_builtin_trunc (tree);
00161 static tree fold_builtin_floor (tree);
00162 static tree fold_builtin_ceil (tree);
00163 static tree fold_builtin_round (tree);
00164 static tree fold_builtin_bitop (tree);
00165 static tree fold_builtin_memcpy (tree);
00166 static tree fold_builtin_mempcpy (tree, tree, int);
00167 static tree fold_builtin_memmove (tree, tree);
00168 static tree fold_builtin_strchr (tree, tree);
00169 static tree fold_builtin_memcmp (tree);
00170 static tree fold_builtin_strcmp (tree);
00171 static tree fold_builtin_strncmp (tree);
00172 static tree fold_builtin_signbit (tree);
00173 static tree fold_builtin_copysign (tree, tree, tree);
00174 static tree fold_builtin_isascii (tree);
00175 static tree fold_builtin_toascii (tree);
00176 static tree fold_builtin_isdigit (tree);
00177 static tree fold_builtin_fabs (tree, tree);
00178 static tree fold_builtin_abs (tree, tree);
00179 static tree fold_builtin_unordered_cmp (tree, enum tree_code, enum tree_code);
00180 static tree fold_builtin_1 (tree, bool);
00181
00182 static tree fold_builtin_strpbrk (tree, tree);
00183 static tree fold_builtin_strstr (tree, tree);
00184 static tree fold_builtin_strrchr (tree, tree);
00185 static tree fold_builtin_strcat (tree);
00186 static tree fold_builtin_strncat (tree);
00187 static tree fold_builtin_strspn (tree);
00188 static tree fold_builtin_strcspn (tree);
00189 static tree fold_builtin_sprintf (tree, int);
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 static int
00201 get_pointer_alignment (tree exp, unsigned int max_align)
00202 {
00203 unsigned int align, inner;
00204
00205 if (! POINTER_TYPE_P (TREE_TYPE (exp)))
00206 return 0;
00207
00208 align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
00209 align = MIN (align, max_align);
00210
00211 while (1)
00212 {
00213 switch (TREE_CODE (exp))
00214 {
00215 case NOP_EXPR:
00216 case CONVERT_EXPR:
00217 case NON_LVALUE_EXPR:
00218 exp = TREE_OPERAND (exp, 0);
00219 if (! POINTER_TYPE_P (TREE_TYPE (exp)))
00220 return align;
00221
00222 inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
00223 align = MIN (inner, max_align);
00224 break;
00225
00226 case PLUS_EXPR:
00227
00228
00229
00230 if (! host_integerp (TREE_OPERAND (exp, 1), 1))
00231 return align;
00232
00233 while (((tree_low_cst (TREE_OPERAND (exp, 1), 1))
00234 & (max_align / BITS_PER_UNIT - 1))
00235 != 0)
00236 max_align >>= 1;
00237
00238 exp = TREE_OPERAND (exp, 0);
00239 break;
00240
00241 case ADDR_EXPR:
00242
00243 exp = TREE_OPERAND (exp, 0);
00244 if (TREE_CODE (exp) == FUNCTION_DECL)
00245 align = FUNCTION_BOUNDARY;
00246 else if (DECL_P (exp))
00247 align = DECL_ALIGN (exp);
00248 #ifdef CONSTANT_ALIGNMENT
00249 else if (CONSTANT_CLASS_P (exp))
00250 align = CONSTANT_ALIGNMENT (exp, align);
00251 #endif
00252 return MIN (align, max_align);
00253
00254 default:
00255 return align;
00256 }
00257 }
00258 }
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276 tree
00277 c_strlen (tree src, int only_value)
00278 {
00279 tree offset_node;
00280 HOST_WIDE_INT offset;
00281 int max;
00282 const char *ptr;
00283
00284 STRIP_NOPS (src);
00285 if (TREE_CODE (src) == COND_EXPR
00286 && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
00287 {
00288 tree len1, len2;
00289
00290 len1 = c_strlen (TREE_OPERAND (src, 1), only_value);
00291 len2 = c_strlen (TREE_OPERAND (src, 2), only_value);
00292 if (tree_int_cst_equal (len1, len2))
00293 return len1;
00294 }
00295
00296 if (TREE_CODE (src) == COMPOUND_EXPR
00297 && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
00298 return c_strlen (TREE_OPERAND (src, 1), only_value);
00299
00300 src = string_constant (src, &offset_node);
00301 if (src == 0)
00302 return 0;
00303
00304 max = TREE_STRING_LENGTH (src) - 1;
00305 ptr = TREE_STRING_POINTER (src);
00306
00307 if (offset_node && TREE_CODE (offset_node) != INTEGER_CST)
00308 {
00309
00310
00311
00312 int i;
00313
00314 for (i = 0; i < max; i++)
00315 if (ptr[i] == 0)
00316 return 0;
00317
00318
00319
00320
00321
00322
00323
00324
00325 return size_diffop (size_int (max), offset_node);
00326 }
00327
00328
00329
00330 if (offset_node == 0)
00331 offset = 0;
00332 else if (! host_integerp (offset_node, 0))
00333 offset = -1;
00334 else
00335 offset = tree_low_cst (offset_node, 0);
00336
00337
00338
00339 if (offset < 0 || offset > max)
00340 {
00341 warning ("offset outside bounds of constant string");
00342 return 0;
00343 }
00344
00345
00346
00347
00348
00349
00350
00351 return ssize_int (strlen (ptr + offset));
00352 }
00353
00354
00355
00356
00357 static const char *
00358 c_getstr (tree src)
00359 {
00360 tree offset_node;
00361
00362 src = string_constant (src, &offset_node);
00363 if (src == 0)
00364 return 0;
00365
00366 if (offset_node == 0)
00367 return TREE_STRING_POINTER (src);
00368 else if (!host_integerp (offset_node, 1)
00369 || compare_tree_int (offset_node, TREE_STRING_LENGTH (src) - 1) > 0)
00370 return 0;
00371
00372 return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
00373 }
00374
00375
00376
00377
00378 static rtx
00379 c_readstr (const char *str, enum machine_mode mode)
00380 {
00381 HOST_WIDE_INT c[2];
00382 HOST_WIDE_INT ch;
00383 unsigned int i, j;
00384
00385 gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
00386
00387 c[0] = 0;
00388 c[1] = 0;
00389 ch = 1;
00390 for (i = 0; i < GET_MODE_SIZE (mode); i++)
00391 {
00392 j = i;
00393 if (WORDS_BIG_ENDIAN)
00394 j = GET_MODE_SIZE (mode) - i - 1;
00395 if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
00396 && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
00397 j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
00398 j *= BITS_PER_UNIT;
00399 gcc_assert (j <= 2 * HOST_BITS_PER_WIDE_INT);
00400
00401 if (ch)
00402 ch = (unsigned char) str[i];
00403 c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
00404 }
00405 return immed_double_const (c[0], c[1], mode);
00406 }
00407
00408
00409
00410
00411
00412 static int
00413 target_char_cast (tree cst, char *p)
00414 {
00415 unsigned HOST_WIDE_INT val, hostval;
00416
00417 if (!host_integerp (cst, 1)
00418 || CHAR_TYPE_SIZE > HOST_BITS_PER_WIDE_INT)
00419 return 1;
00420
00421 val = tree_low_cst (cst, 1);
00422 if (CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT)
00423 val &= (((unsigned HOST_WIDE_INT) 1) << CHAR_TYPE_SIZE) - 1;
00424
00425 hostval = val;
00426 if (HOST_BITS_PER_CHAR < HOST_BITS_PER_WIDE_INT)
00427 hostval &= (((unsigned HOST_WIDE_INT) 1) << HOST_BITS_PER_CHAR) - 1;
00428
00429 if (val != hostval)
00430 return 1;
00431
00432 *p = hostval;
00433 return 0;
00434 }
00435
00436
00437
00438
00439
00440 static tree
00441 builtin_save_expr (tree exp)
00442 {
00443 if (TREE_ADDRESSABLE (exp) == 0
00444 && (TREE_CODE (exp) == PARM_DECL
00445 || (TREE_CODE (exp) == VAR_DECL && !TREE_STATIC (exp))))
00446 return exp;
00447
00448 return save_expr (exp);
00449 }
00450
00451
00452
00453
00454
00455 static rtx
00456 expand_builtin_return_addr (enum built_in_function fndecl_code, int count)
00457 {
00458 int i;
00459
00460 #ifdef INITIAL_FRAME_ADDRESS_RTX
00461 rtx tem = INITIAL_FRAME_ADDRESS_RTX;
00462 #else
00463 rtx tem = hard_frame_pointer_rtx;
00464 #endif
00465
00466
00467
00468
00469 #ifdef SETUP_FRAME_ADDRESSES
00470 if (count > 0)
00471 SETUP_FRAME_ADDRESSES ();
00472 #endif
00473
00474
00475
00476
00477
00478 #ifdef RETURN_ADDR_IN_PREVIOUS_FRAME
00479 if (fndecl_code == BUILT_IN_RETURN_ADDRESS)
00480 count--;
00481 #endif
00482
00483
00484 for (i = 0; i < count; i++)
00485 {
00486
00487
00488 #ifdef DYNAMIC_CHAIN_ADDRESS
00489 tem = DYNAMIC_CHAIN_ADDRESS (tem);
00490 #endif
00491 tem = memory_address (Pmode, tem);
00492 tem = gen_rtx_MEM (Pmode, tem);
00493 set_mem_alias_set (tem, get_frame_alias_set ());
00494 tem = copy_to_reg (tem);
00495 }
00496
00497
00498 if (fndecl_code == BUILT_IN_FRAME_ADDRESS)
00499 return tem;
00500
00501
00502
00503 #ifdef RETURN_ADDR_RTX
00504 tem = RETURN_ADDR_RTX (count, tem);
00505 #else
00506 tem = memory_address (Pmode,
00507 plus_constant (tem, GET_MODE_SIZE (Pmode)));
00508 tem = gen_rtx_MEM (Pmode, tem);
00509 set_mem_alias_set (tem, get_frame_alias_set ());
00510 #endif
00511 return tem;
00512 }
00513
00514
00515 static HOST_WIDE_INT setjmp_alias_set = -1;
00516
00517
00518
00519
00520
00521 void
00522 expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
00523 {
00524 enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
00525 rtx stack_save;
00526 rtx mem;
00527
00528 if (setjmp_alias_set == -1)
00529 setjmp_alias_set = new_alias_set ();
00530
00531 buf_addr = convert_memory_address (Pmode, buf_addr);
00532
00533 buf_addr = force_reg (Pmode, force_operand (buf_addr, NULL_RTX));
00534
00535
00536
00537
00538
00539 mem = gen_rtx_MEM (Pmode, buf_addr);
00540 set_mem_alias_set (mem, setjmp_alias_set);
00541 emit_move_insn (mem, targetm.builtin_setjmp_frame_value ());
00542
00543 mem = gen_rtx_MEM (Pmode, plus_constant (buf_addr, GET_MODE_SIZE (Pmode))),
00544 set_mem_alias_set (mem, setjmp_alias_set);
00545
00546 emit_move_insn (validize_mem (mem),
00547 force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, receiver_label)));
00548
00549 stack_save = gen_rtx_MEM (sa_mode,
00550 plus_constant (buf_addr,
00551 2 * GET_MODE_SIZE (Pmode)));
00552 set_mem_alias_set (stack_save, setjmp_alias_set);
00553 emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
00554
00555
00556 #ifdef HAVE_builtin_setjmp_setup
00557 if (HAVE_builtin_setjmp_setup)
00558 emit_insn (gen_builtin_setjmp_setup (buf_addr));
00559 #endif
00560
00561
00562
00563 current_function_calls_setjmp = 1;
00564
00565
00566
00567 current_function_has_nonlocal_label = 1;
00568 }
00569
00570
00571
00572
00573 void
00574 expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
00575 {
00576
00577
00578 emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
00579
00580
00581
00582 emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx));
00583
00584
00585
00586 #ifdef HAVE_nonlocal_goto
00587 if (! HAVE_nonlocal_goto)
00588 #endif
00589 emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
00590
00591 #if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
00592 if (fixed_regs[ARG_POINTER_REGNUM])
00593 {
00594 #ifdef ELIMINABLE_REGS
00595 size_t i;
00596 static const struct elims {const int from, to;} elim_regs[] = ELIMINABLE_REGS;
00597
00598 for (i = 0; i < ARRAY_SIZE (elim_regs); i++)
00599 if (elim_regs[i].from == ARG_POINTER_REGNUM
00600 && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
00601 break;
00602
00603 if (i == ARRAY_SIZE (elim_regs))
00604 #endif
00605 {
00606
00607
00608 emit_move_insn (virtual_incoming_args_rtx,
00609 copy_to_reg (get_arg_pointer_save_area (cfun)));
00610 }
00611 }
00612 #endif
00613
00614 #ifdef HAVE_builtin_setjmp_receiver
00615 if (HAVE_builtin_setjmp_receiver)
00616 emit_insn (gen_builtin_setjmp_receiver (receiver_label));
00617 else
00618 #endif
00619 #ifdef HAVE_nonlocal_goto_receiver
00620 if (HAVE_nonlocal_goto_receiver)
00621 emit_insn (gen_nonlocal_goto_receiver ());
00622 else
00623 #endif
00624 { }
00625
00626
00627
00628
00629
00630
00631 emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
00632 }
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644 static rtx
00645 expand_builtin_setjmp (tree arglist, rtx target)
00646 {
00647 rtx buf_addr, next_lab, cont_lab;
00648
00649 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
00650 return NULL_RTX;
00651
00652 if (target == 0 || !REG_P (target)
00653 || REGNO (target) < FIRST_PSEUDO_REGISTER)
00654 target = gen_reg_rtx (TYPE_MODE (integer_type_node));
00655
00656 buf_addr = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
00657
00658 next_lab = gen_label_rtx ();
00659 cont_lab = gen_label_rtx ();
00660
00661 expand_builtin_setjmp_setup (buf_addr, next_lab);
00662
00663
00664
00665 emit_move_insn (target, const0_rtx);
00666 emit_jump (cont_lab);
00667
00668 emit_label (next_lab);
00669
00670 expand_builtin_setjmp_receiver (next_lab);
00671
00672
00673 emit_move_insn (target, const1_rtx);
00674 emit_label (cont_lab);
00675
00676
00677
00678
00679
00680 current_function_has_nonlocal_label = 1;
00681 nonlocal_goto_handler_labels
00682 = gen_rtx_EXPR_LIST (VOIDmode, next_lab, nonlocal_goto_handler_labels);
00683
00684 return target;
00685 }
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696 static void
00697 expand_builtin_longjmp (rtx buf_addr, rtx value)
00698 {
00699 rtx fp, lab, stack, insn, last;
00700 enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
00701
00702 if (setjmp_alias_set == -1)
00703 setjmp_alias_set = new_alias_set ();
00704
00705 buf_addr = convert_memory_address (Pmode, buf_addr);
00706
00707 buf_addr = force_reg (Pmode, buf_addr);
00708
00709
00710
00711
00712
00713
00714 gcc_assert (value == const1_rtx);
00715
00716 last = get_last_insn ();
00717 #ifdef HAVE_builtin_longjmp
00718 if (HAVE_builtin_longjmp)
00719 emit_insn (gen_builtin_longjmp (buf_addr));
00720 else
00721 #endif
00722 {
00723 fp = gen_rtx_MEM (Pmode, buf_addr);
00724 lab = gen_rtx_MEM (Pmode, plus_constant (buf_addr,
00725 GET_MODE_SIZE (Pmode)));
00726
00727 stack = gen_rtx_MEM (sa_mode, plus_constant (buf_addr,
00728 2 * GET_MODE_SIZE (Pmode)));
00729 set_mem_alias_set (fp, setjmp_alias_set);
00730 set_mem_alias_set (lab, setjmp_alias_set);
00731 set_mem_alias_set (stack, setjmp_alias_set);
00732
00733
00734
00735 #if HAVE_nonlocal_goto
00736 if (HAVE_nonlocal_goto)
00737
00738
00739
00740 emit_insn (gen_nonlocal_goto (value, lab, stack, fp));
00741 else
00742 #endif
00743 {
00744 lab = copy_to_reg (lab);
00745
00746 emit_insn (gen_rtx_CLOBBER (VOIDmode,
00747 gen_rtx_MEM (BLKmode,
00748 gen_rtx_SCRATCH (VOIDmode))));
00749 emit_insn (gen_rtx_CLOBBER (VOIDmode,
00750 gen_rtx_MEM (BLKmode,
00751 hard_frame_pointer_rtx)));
00752
00753 emit_move_insn (hard_frame_pointer_rtx, fp);
00754 emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
00755
00756 emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
00757 emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
00758 emit_indirect_jump (lab);
00759 }
00760 }
00761
00762
00763
00764
00765
00766
00767 for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
00768 {
00769 gcc_assert (insn != last);
00770
00771 if (JUMP_P (insn))
00772 {
00773 REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx,
00774 REG_NOTES (insn));
00775 break;
00776 }
00777 else if (CALL_P (insn))
00778 break;
00779 }
00780 }
00781
00782
00783
00784
00785 static rtx
00786 expand_builtin_nonlocal_goto (tree arglist)
00787 {
00788 tree t_label, t_save_area;
00789 rtx r_label, r_save_area, r_fp, r_sp, insn;
00790
00791 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
00792 return NULL_RTX;
00793
00794 t_label = TREE_VALUE (arglist);
00795 arglist = TREE_CHAIN (arglist);
00796 t_save_area = TREE_VALUE (arglist);
00797
00798 r_label = expand_expr (t_label, NULL_RTX, VOIDmode, 0);
00799 r_label = convert_memory_address (Pmode, r_label);
00800 r_save_area = expand_expr (t_save_area, NULL_RTX, VOIDmode, 0);
00801 r_save_area = convert_memory_address (Pmode, r_save_area);
00802 r_fp = gen_rtx_MEM (Pmode, r_save_area);
00803 r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL),
00804 plus_constant (r_save_area, GET_MODE_SIZE (Pmode)));
00805
00806 current_function_has_nonlocal_goto = 1;
00807
00808 #if HAVE_nonlocal_goto
00809
00810 if (HAVE_nonlocal_goto)
00811 emit_insn (gen_nonlocal_goto (const0_rtx, r_label, r_sp, r_fp));
00812 else
00813 #endif
00814 {
00815 r_label = copy_to_reg (r_label);
00816
00817 emit_insn (gen_rtx_CLOBBER (VOIDmode,
00818 gen_rtx_MEM (BLKmode,
00819 gen_rtx_SCRATCH (VOIDmode))));
00820
00821 emit_insn (gen_rtx_CLOBBER (VOIDmode,
00822 gen_rtx_MEM (BLKmode,
00823 hard_frame_pointer_rtx)));
00824
00825
00826
00827
00828
00829
00830 emit_move_insn (hard_frame_pointer_rtx, r_fp);
00831 emit_stack_restore (SAVE_NONLOCAL, r_sp, NULL_RTX);
00832
00833
00834
00835 emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
00836 emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
00837 emit_indirect_jump (r_label);
00838 }
00839
00840
00841
00842 for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
00843 {
00844 if (JUMP_P (insn))
00845 {
00846 REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO,
00847 const0_rtx, REG_NOTES (insn));
00848 break;
00849 }
00850 else if (CALL_P (insn))
00851 break;
00852 }
00853
00854 return const0_rtx;
00855 }
00856
00857
00858
00859
00860
00861
00862 static void
00863 expand_builtin_update_setjmp_buf (rtx buf_addr)
00864 {
00865 enum machine_mode sa_mode = Pmode;
00866 rtx stack_save;
00867
00868
00869 #ifdef HAVE_save_stack_nonlocal
00870 if (HAVE_save_stack_nonlocal)
00871 sa_mode = insn_data[(int) CODE_FOR_save_stack_nonlocal].operand[0].mode;
00872 #endif
00873 #ifdef STACK_SAVEAREA_MODE
00874 sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
00875 #endif
00876
00877 stack_save
00878 = gen_rtx_MEM (sa_mode,
00879 memory_address
00880 (sa_mode,
00881 plus_constant (buf_addr, 2 * GET_MODE_SIZE (Pmode))));
00882
00883 #ifdef HAVE_setjmp
00884 if (HAVE_setjmp)
00885 emit_insn (gen_setjmp ());
00886 #endif
00887
00888 emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
00889 }
00890
00891
00892
00893
00894
00895 static void
00896 expand_builtin_prefetch (tree arglist)
00897 {
00898 tree arg0, arg1, arg2;
00899 rtx op0, op1, op2;
00900
00901 if (!validate_arglist (arglist, POINTER_TYPE, 0))
00902 return;
00903
00904 arg0 = TREE_VALUE (arglist);
00905
00906
00907
00908 if (TREE_CHAIN (arglist))
00909 {
00910 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
00911 if (TREE_CHAIN (TREE_CHAIN (arglist)))
00912 arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
00913 else
00914 arg2 = build_int_cst (NULL_TREE, 3);
00915 }
00916 else
00917 {
00918 arg1 = integer_zero_node;
00919 arg2 = build_int_cst (NULL_TREE, 3);
00920 }
00921
00922
00923 op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
00924
00925
00926 if (TREE_CODE (arg1) != INTEGER_CST)
00927 {
00928 error ("second argument to %<__builtin_prefetch%> must be a constant");
00929 arg1 = integer_zero_node;
00930 }
00931 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
00932
00933 if (INTVAL (op1) != 0 && INTVAL (op1) != 1)
00934 {
00935 warning ("invalid second argument to %<__builtin_prefetch%>;"
00936 " using zero");
00937 op1 = const0_rtx;
00938 }
00939
00940
00941 if (TREE_CODE (arg2) != INTEGER_CST)
00942 {
00943 error ("third argument to %<__builtin_prefetch%> must be a constant");
00944 arg2 = integer_zero_node;
00945 }
00946 op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
00947
00948 if (INTVAL (op2) < 0 || INTVAL (op2) > 3)
00949 {
00950 warning ("invalid third argument to %<__builtin_prefetch%>; using zero");
00951 op2 = const0_rtx;
00952 }
00953
00954 #ifdef HAVE_prefetch
00955 if (HAVE_prefetch)
00956 {
00957 if ((! (*insn_data[(int) CODE_FOR_prefetch].operand[0].predicate)
00958 (op0,
00959 insn_data[(int) CODE_FOR_prefetch].operand[0].mode))
00960 || (GET_MODE (op0) != Pmode))
00961 {
00962 op0 = convert_memory_address (Pmode, op0);
00963 op0 = force_reg (Pmode, op0);
00964 }
00965 emit_insn (gen_prefetch (op0, op1, op2));
00966 }
00967 #endif
00968
00969
00970
00971 if (!MEM_P (op0) && side_effects_p (op0))
00972 emit_insn (op0);
00973 }
00974
00975
00976
00977
00978
00979
00980 static rtx
00981 get_memory_rtx (tree exp, tree len)
00982 {
00983 rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_NORMAL);
00984 rtx mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
00985
00986
00987
00988
00989 while ((TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
00990 || TREE_CODE (exp) == NON_LVALUE_EXPR)
00991 && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
00992 exp = TREE_OPERAND (exp, 0);
00993
00994 if (TREE_CODE (exp) == ADDR_EXPR)
00995 exp = TREE_OPERAND (exp, 0);
00996 else if (POINTER_TYPE_P (TREE_TYPE (exp)))
00997 exp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (exp)), exp);
00998 else
00999 exp = NULL;
01000
01001
01002
01003
01004 if (exp)
01005 {
01006 set_mem_attributes (mem, exp, 0);
01007
01008
01009
01010
01011
01012
01013 if (MEM_EXPR (mem) && TREE_CODE (MEM_EXPR (mem)) == COMPONENT_REF)
01014 {
01015 tree mem_expr = MEM_EXPR (mem);
01016 HOST_WIDE_INT offset = -1, length = -1;
01017 tree inner = exp;
01018
01019 while (TREE_CODE (inner) == ARRAY_REF
01020 || TREE_CODE (inner) == NOP_EXPR
01021 || TREE_CODE (inner) == CONVERT_EXPR
01022 || TREE_CODE (inner) == NON_LVALUE_EXPR
01023 || TREE_CODE (inner) == VIEW_CONVERT_EXPR
01024 || TREE_CODE (inner) == SAVE_EXPR)
01025 inner = TREE_OPERAND (inner, 0);
01026
01027 gcc_assert (TREE_CODE (inner) == COMPONENT_REF);
01028
01029 if (MEM_OFFSET (mem)
01030 && GET_CODE (MEM_OFFSET (mem)) == CONST_INT)
01031 offset = INTVAL (MEM_OFFSET (mem));
01032
01033 if (offset >= 0 && len && host_integerp (len, 0))
01034 length = tree_low_cst (len, 0);
01035
01036 while (TREE_CODE (inner) == COMPONENT_REF)
01037 {
01038 tree field = TREE_OPERAND (inner, 1);
01039 gcc_assert (! DECL_BIT_FIELD (field));
01040 gcc_assert (TREE_CODE (mem_expr) == COMPONENT_REF);
01041 gcc_assert (field == TREE_OPERAND (mem_expr, 1));
01042
01043 if (length >= 0
01044 && TYPE_SIZE_UNIT (TREE_TYPE (inner))
01045 && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0))
01046 {
01047 HOST_WIDE_INT size
01048 = tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0);
01049
01050
01051
01052 if (offset <= size
01053 && length <= size
01054 && offset + length <= size)
01055 break;
01056 }
01057
01058 if (offset >= 0
01059 && host_integerp (DECL_FIELD_OFFSET (field), 0))
01060 offset += tree_low_cst (DECL_FIELD_OFFSET (field), 0)
01061 + tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
01062 / BITS_PER_UNIT;
01063 else
01064 {
01065 offset = -1;
01066 length = -1;
01067 }
01068
01069 mem_expr = TREE_OPERAND (mem_expr, 0);
01070 inner = TREE_OPERAND (inner, 0);
01071 }
01072
01073 if (mem_expr == NULL)
01074 offset = -1;
01075 if (mem_expr != MEM_EXPR (mem))
01076 {
01077 set_mem_expr (mem, mem_expr);
01078 set_mem_offset (mem, offset >= 0 ? GEN_INT (offset) : NULL_RTX);
01079 }
01080 }
01081 set_mem_alias_set (mem, 0);
01082 set_mem_size (mem, NULL_RTX);
01083 }
01084
01085 return mem;
01086 }
01087
01088
01089
01090
01091
01092
01093
01094
01095 static enum machine_mode apply_args_mode[FIRST_PSEUDO_REGISTER];
01096
01097
01098
01099
01100
01101
01102 static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER];
01103
01104
01105
01106
01107
01108 static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
01109
01110
01111
01112
01113 static int
01114 apply_args_size (void)
01115 {
01116 static int size = -1;
01117 int align;
01118 unsigned int regno;
01119 enum machine_mode mode;
01120
01121
01122 if (size < 0)
01123 {
01124
01125 size = GET_MODE_SIZE (Pmode);
01126
01127
01128
01129 if (targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 0))
01130 size += GET_MODE_SIZE (Pmode);
01131
01132 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01133 if (FUNCTION_ARG_REGNO_P (regno))
01134 {
01135 mode = reg_raw_mode[regno];
01136
01137 gcc_assert (mode != VOIDmode);
01138
01139 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01140 if (size % align != 0)
01141 size = CEIL (size, align) * align;
01142 apply_args_reg_offset[regno] = size;
01143 size += GET_MODE_SIZE (mode);
01144 apply_args_mode[regno] = mode;
01145 }
01146 else
01147 {
01148 apply_args_mode[regno] = VOIDmode;
01149 apply_args_reg_offset[regno] = 0;
01150 }
01151 }
01152 return size;
01153 }
01154
01155
01156
01157
01158 static int
01159 apply_result_size (void)
01160 {
01161 static int size = -1;
01162 int align, regno;
01163 enum machine_mode mode;
01164
01165
01166 if (size < 0)
01167 {
01168 size = 0;
01169
01170 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01171 if (FUNCTION_VALUE_REGNO_P (regno))
01172 {
01173 mode = reg_raw_mode[regno];
01174
01175 gcc_assert (mode != VOIDmode);
01176
01177 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01178 if (size % align != 0)
01179 size = CEIL (size, align) * align;
01180 size += GET_MODE_SIZE (mode);
01181 apply_result_mode[regno] = mode;
01182 }
01183 else
01184 apply_result_mode[regno] = VOIDmode;
01185
01186
01187
01188 #ifdef APPLY_RESULT_SIZE
01189 size = APPLY_RESULT_SIZE;
01190 #endif
01191 }
01192 return size;
01193 }
01194
01195 #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
01196
01197
01198
01199
01200 static rtx
01201 result_vector (int savep, rtx result)
01202 {
01203 int regno, size, align, nelts;
01204 enum machine_mode mode;
01205 rtx reg, mem;
01206 rtx *savevec = alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
01207
01208 size = nelts = 0;
01209 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01210 if ((mode = apply_result_mode[regno]) != VOIDmode)
01211 {
01212 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01213 if (size % align != 0)
01214 size = CEIL (size, align) * align;
01215 reg = gen_rtx_REG (mode, savep ? regno : INCOMING_REGNO (regno));
01216 mem = adjust_address (result, mode, size);
01217 savevec[nelts++] = (savep
01218 ? gen_rtx_SET (VOIDmode, mem, reg)
01219 : gen_rtx_SET (VOIDmode, reg, mem));
01220 size += GET_MODE_SIZE (mode);
01221 }
01222 return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nelts, savevec));
01223 }
01224 #endif
01225
01226
01227
01228
01229 static rtx
01230 expand_builtin_apply_args_1 (void)
01231 {
01232 rtx registers, tem;
01233 int size, align, regno;
01234 enum machine_mode mode;
01235 rtx struct_incoming_value = targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 1);
01236
01237
01238
01239 registers = assign_stack_local (BLKmode, apply_args_size (), -1);
01240
01241
01242 size = GET_MODE_SIZE (Pmode);
01243 if (targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 0))
01244 size += GET_MODE_SIZE (Pmode);
01245
01246
01247 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01248 if ((mode = apply_args_mode[regno]) != VOIDmode)
01249 {
01250 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01251 if (size % align != 0)
01252 size = CEIL (size, align) * align;
01253
01254 tem = gen_rtx_REG (mode, INCOMING_REGNO (regno));
01255
01256 emit_move_insn (adjust_address (registers, mode, size), tem);
01257 size += GET_MODE_SIZE (mode);
01258 }
01259
01260
01261 tem = copy_to_reg (virtual_incoming_args_rtx);
01262 #ifdef STACK_GROWS_DOWNWARD
01263
01264
01265
01266 tem
01267 = force_operand (plus_constant (tem, current_function_pretend_args_size),
01268 NULL_RTX);
01269 #endif
01270 emit_move_insn (adjust_address (registers, Pmode, 0), tem);
01271
01272 size = GET_MODE_SIZE (Pmode);
01273
01274
01275
01276 if (struct_incoming_value)
01277 {
01278 emit_move_insn (adjust_address (registers, Pmode, size),
01279 copy_to_reg (struct_incoming_value));
01280 size += GET_MODE_SIZE (Pmode);
01281 }
01282
01283
01284 return copy_addr_to_reg (XEXP (registers, 0));
01285 }
01286
01287
01288
01289
01290
01291
01292
01293
01294 static rtx
01295 expand_builtin_apply_args (void)
01296 {
01297
01298
01299 if (apply_args_value != 0)
01300 return apply_args_value;
01301 {
01302
01303
01304
01305 rtx temp;
01306 rtx seq;
01307
01308 start_sequence ();
01309 temp = expand_builtin_apply_args_1 ();
01310 seq = get_insns ();
01311 end_sequence ();
01312
01313 apply_args_value = temp;
01314
01315
01316
01317
01318
01319 push_topmost_sequence ();
01320 emit_insn_before (seq, NEXT_INSN (entry_of_function ()));
01321 pop_topmost_sequence ();
01322 return temp;
01323 }
01324 }
01325
01326
01327
01328
01329 static rtx
01330 expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
01331 {
01332 int size, align, regno;
01333 enum machine_mode mode;
01334 rtx incoming_args, result, reg, dest, src, call_insn;
01335 rtx old_stack_level = 0;
01336 rtx call_fusage = 0;
01337 rtx struct_value = targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 0);
01338
01339 arguments = convert_memory_address (Pmode, arguments);
01340
01341
01342 result = assign_stack_local (BLKmode, apply_result_size (), -1);
01343
01344
01345 incoming_args = gen_reg_rtx (Pmode);
01346 emit_move_insn (incoming_args, gen_rtx_MEM (Pmode, arguments));
01347 #ifndef STACK_GROWS_DOWNWARD
01348 incoming_args = expand_simple_binop (Pmode, MINUS, incoming_args, argsize,
01349 incoming_args, 0, OPTAB_LIB_WIDEN);
01350 #endif
01351
01352
01353
01354
01355 do_pending_stack_adjust ();
01356 NO_DEFER_POP;
01357
01358
01359 #ifdef HAVE_save_stack_nonlocal
01360 if (HAVE_save_stack_nonlocal)
01361 emit_stack_save (SAVE_NONLOCAL, &old_stack_level, NULL_RTX);
01362 else
01363 #endif
01364 emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
01365
01366
01367
01368 allocate_dynamic_stack_space (argsize, 0, BITS_PER_UNIT);
01369 dest = virtual_outgoing_args_rtx;
01370 #ifndef STACK_GROWS_DOWNWARD
01371 if (GET_CODE (argsize) == CONST_INT)
01372 dest = plus_constant (dest, -INTVAL (argsize));
01373 else
01374 dest = gen_rtx_PLUS (Pmode, dest, negate_rtx (Pmode, argsize));
01375 #endif
01376 dest = gen_rtx_MEM (BLKmode, dest);
01377 set_mem_align (dest, PARM_BOUNDARY);
01378 src = gen_rtx_MEM (BLKmode, incoming_args);
01379 set_mem_align (src, PARM_BOUNDARY);
01380 emit_block_move (dest, src, argsize, BLOCK_OP_NORMAL);
01381
01382
01383 apply_args_size ();
01384 arguments = gen_rtx_MEM (BLKmode, arguments);
01385 set_mem_align (arguments, PARM_BOUNDARY);
01386
01387
01388 size = GET_MODE_SIZE (Pmode);
01389 if (struct_value)
01390 size += GET_MODE_SIZE (Pmode);
01391
01392
01393
01394 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01395 if ((mode = apply_args_mode[regno]) != VOIDmode)
01396 {
01397 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01398 if (size % align != 0)
01399 size = CEIL (size, align) * align;
01400 reg = gen_rtx_REG (mode, regno);
01401 emit_move_insn (reg, adjust_address (arguments, mode, size));
01402 use_reg (&call_fusage, reg);
01403 size += GET_MODE_SIZE (mode);
01404 }
01405
01406
01407
01408 size = GET_MODE_SIZE (Pmode);
01409 if (struct_value)
01410 {
01411 rtx value = gen_reg_rtx (Pmode);
01412 emit_move_insn (value, adjust_address (arguments, Pmode, size));
01413 emit_move_insn (struct_value, value);
01414 if (REG_P (struct_value))
01415 use_reg (&call_fusage, struct_value);
01416 size += GET_MODE_SIZE (Pmode);
01417 }
01418
01419
01420 function = prepare_call_address (function, NULL, &call_fusage, 0, 0);
01421
01422
01423
01424
01425 if (GET_CODE (function) != SYMBOL_REF)
01426 function = memory_address (FUNCTION_MODE, function);
01427
01428
01429 #ifdef HAVE_untyped_call
01430 if (HAVE_untyped_call)
01431 emit_call_insn (gen_untyped_call (gen_rtx_MEM (FUNCTION_MODE, function),
01432 result, result_vector (1, result)));
01433 else
01434 #endif
01435 #ifdef HAVE_call_value
01436 if (HAVE_call_value)
01437 {
01438 rtx valreg = 0;
01439
01440
01441
01442
01443
01444 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01445 if ((mode = apply_result_mode[regno]) != VOIDmode)
01446 {
01447 gcc_assert (!valreg);
01448
01449 valreg = gen_rtx_REG (mode, regno);
01450 }
01451
01452 emit_call_insn (GEN_CALL_VALUE (valreg,
01453 gen_rtx_MEM (FUNCTION_MODE, function),
01454 const0_rtx, NULL_RTX, const0_rtx));
01455
01456 emit_move_insn (adjust_address (result, GET_MODE (valreg), 0), valreg);
01457 }
01458 else
01459 #endif
01460 gcc_unreachable ();
01461
01462
01463
01464 call_insn = last_call_insn ();
01465 add_function_usage_to (call_insn, call_fusage);
01466
01467
01468 #ifdef HAVE_save_stack_nonlocal
01469 if (HAVE_save_stack_nonlocal)
01470 emit_stack_restore (SAVE_NONLOCAL, old_stack_level, NULL_RTX);
01471 else
01472 #endif
01473 emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
01474
01475 OK_DEFER_POP;
01476
01477
01478 result = copy_addr_to_reg (XEXP (result, 0));
01479 return convert_memory_address (ptr_mode, result);
01480 }
01481
01482
01483
01484 static void
01485 expand_builtin_return (rtx result)
01486 {
01487 int size, align, regno;
01488 enum machine_mode mode;
01489 rtx reg;
01490 rtx call_fusage = 0;
01491
01492 result = convert_memory_address (Pmode, result);
01493
01494 apply_result_size ();
01495 result = gen_rtx_MEM (BLKmode, result);
01496
01497 #ifdef HAVE_untyped_return
01498 if (HAVE_untyped_return)
01499 {
01500 emit_jump_insn (gen_untyped_return (result, result_vector (0, result)));
01501 emit_barrier ();
01502 return;
01503 }
01504 #endif
01505
01506
01507 size = 0;
01508 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01509 if ((mode = apply_result_mode[regno]) != VOIDmode)
01510 {
01511 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01512 if (size % align != 0)
01513 size = CEIL (size, align) * align;
01514 reg = gen_rtx_REG (mode, INCOMING_REGNO (regno));
01515 emit_move_insn (reg, adjust_address (result, mode, size));
01516
01517 push_to_sequence (call_fusage);
01518 emit_insn (gen_rtx_USE (VOIDmode, reg));
01519 call_fusage = get_insns ();
01520 end_sequence ();
01521 size += GET_MODE_SIZE (mode);
01522 }
01523
01524
01525 emit_insn (call_fusage);
01526
01527
01528
01529 expand_naked_return ();
01530 }
01531
01532
01533
01534 static enum type_class
01535 type_to_class (tree type)
01536 {
01537 switch (TREE_CODE (type))
01538 {
01539 case VOID_TYPE: return void_type_class;
01540 case INTEGER_TYPE: return integer_type_class;
01541 case CHAR_TYPE: return char_type_class;
01542 case ENUMERAL_TYPE: return enumeral_type_class;
01543 case BOOLEAN_TYPE: return boolean_type_class;
01544 case POINTER_TYPE: return pointer_type_class;
01545 case REFERENCE_TYPE: return reference_type_class;
01546 case OFFSET_TYPE: return offset_type_class;
01547 case REAL_TYPE: return real_type_class;
01548 case COMPLEX_TYPE: return complex_type_class;
01549 case FUNCTION_TYPE: return function_type_class;
01550 case METHOD_TYPE: return method_type_class;
01551 case RECORD_TYPE: return record_type_class;
01552 case UNION_TYPE:
01553 case QUAL_UNION_TYPE: return union_type_class;
01554 case ARRAY_TYPE: return (TYPE_STRING_FLAG (type)
01555 ? string_type_class : array_type_class);
01556 case FILE_TYPE: return file_type_class;
01557 case LANG_TYPE: return lang_type_class;
01558 default: return no_type_class;
01559 }
01560 }
01561
01562
01563
01564
01565 static rtx
01566 expand_builtin_classify_type (tree arglist)
01567 {
01568 if (arglist != 0)
01569 return GEN_INT (type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
01570 return GEN_INT (no_type_class);
01571 }
01572
01573
01574
01575
01576
01577 #define CASE_MATHFN(BUILT_IN_MATHFN) \
01578 case BUILT_IN_MATHFN: case BUILT_IN_MATHFN##F: case BUILT_IN_MATHFN##L: \
01579 fcode = BUILT_IN_MATHFN; fcodef = BUILT_IN_MATHFN##F ; \
01580 fcodel = BUILT_IN_MATHFN##L ; break;
01581
01582
01583
01584 tree
01585 mathfn_built_in (tree type, enum built_in_function fn)
01586 {
01587 enum built_in_function fcode, fcodef, fcodel;
01588
01589 switch (fn)
01590 {
01591 CASE_MATHFN (BUILT_IN_ACOS)
01592 CASE_MATHFN (BUILT_IN_ACOSH)
01593 CASE_MATHFN (BUILT_IN_ASIN)
01594 CASE_MATHFN (BUILT_IN_ASINH)
01595 CASE_MATHFN (BUILT_IN_ATAN)
01596 CASE_MATHFN (BUILT_IN_ATAN2)
01597 CASE_MATHFN (BUILT_IN_ATANH)
01598 CASE_MATHFN (BUILT_IN_CBRT)
01599 CASE_MATHFN (BUILT_IN_CEIL)
01600 CASE_MATHFN (BUILT_IN_COPYSIGN)
01601 CASE_MATHFN (BUILT_IN_COS)
01602 CASE_MATHFN (BUILT_IN_COSH)
01603 CASE_MATHFN (BUILT_IN_DREM)
01604 CASE_MATHFN (BUILT_IN_ERF)
01605 CASE_MATHFN (BUILT_IN_ERFC)
01606 CASE_MATHFN (BUILT_IN_EXP)
01607 CASE_MATHFN (BUILT_IN_EXP10)
01608 CASE_MATHFN (BUILT_IN_EXP2)
01609 CASE_MATHFN (BUILT_IN_EXPM1)
01610 CASE_MATHFN (BUILT_IN_FABS)
01611 CASE_MATHFN (BUILT_IN_FDIM)
01612 CASE_MATHFN (BUILT_IN_FLOOR)
01613 CASE_MATHFN (BUILT_IN_FMA)
01614 CASE_MATHFN (BUILT_IN_FMAX)
01615 CASE_MATHFN (BUILT_IN_FMIN)
01616 CASE_MATHFN (BUILT_IN_FMOD)
01617 CASE_MATHFN (BUILT_IN_FREXP)
01618 CASE_MATHFN (BUILT_IN_GAMMA)
01619 CASE_MATHFN (BUILT_IN_HUGE_VAL)
01620 CASE_MATHFN (BUILT_IN_HYPOT)
01621 CASE_MATHFN (BUILT_IN_ILOGB)
01622 CASE_MATHFN (BUILT_IN_INF)
01623 CASE_MATHFN (BUILT_IN_J0)
01624 CASE_MATHFN (BUILT_IN_J1)
01625 CASE_MATHFN (BUILT_IN_JN)
01626 CASE_MATHFN (BUILT_IN_LDEXP)
01627 CASE_MATHFN (BUILT_IN_LGAMMA)
01628 CASE_MATHFN (BUILT_IN_LLRINT)
01629 CASE_MATHFN (BUILT_IN_LLROUND)
01630 CASE_MATHFN (BUILT_IN_LOG)
01631 CASE_MATHFN (BUILT_IN_LOG10)
01632 CASE_MATHFN (BUILT_IN_LOG1P)
01633 CASE_MATHFN (BUILT_IN_LOG2)
01634 CASE_MATHFN (BUILT_IN_LOGB)
01635 CASE_MATHFN (BUILT_IN_LRINT)
01636 CASE_MATHFN (BUILT_IN_LROUND)
01637 CASE_MATHFN (BUILT_IN_MODF)
01638 CASE_MATHFN (BUILT_IN_NAN)
01639 CASE_MATHFN (BUILT_IN_NANS)
01640 CASE_MATHFN (BUILT_IN_NEARBYINT)
01641 CASE_MATHFN (BUILT_IN_NEXTAFTER)
01642 CASE_MATHFN (BUILT_IN_NEXTTOWARD)
01643 CASE_MATHFN (BUILT_IN_POW)
01644 CASE_MATHFN (BUILT_IN_POWI)
01645 CASE_MATHFN (BUILT_IN_POW10)
01646 CASE_MATHFN (BUILT_IN_REMAINDER)
01647 CASE_MATHFN (BUILT_IN_REMQUO)
01648 CASE_MATHFN (BUILT_IN_RINT)
01649 CASE_MATHFN (BUILT_IN_ROUND)
01650 CASE_MATHFN (BUILT_IN_SCALB)
01651 CASE_MATHFN (BUILT_IN_SCALBLN)
01652 CASE_MATHFN (BUILT_IN_SCALBN)
01653 CASE_MATHFN (BUILT_IN_SIGNIFICAND)
01654 CASE_MATHFN (BUILT_IN_SIN)
01655 CASE_MATHFN (BUILT_IN_SINCOS)
01656 CASE_MATHFN (BUILT_IN_SINH)
01657 CASE_MATHFN (BUILT_IN_SQRT)
01658 CASE_MATHFN (BUILT_IN_TAN)
01659 CASE_MATHFN (BUILT_IN_TANH)
01660 CASE_MATHFN (BUILT_IN_TGAMMA)
01661 CASE_MATHFN (BUILT_IN_TRUNC)
01662 CASE_MATHFN (BUILT_IN_Y0)
01663 CASE_MATHFN (BUILT_IN_Y1)
01664 CASE_MATHFN (BUILT_IN_YN)
01665
01666 default:
01667 return 0;
01668 }
01669
01670 if (TYPE_MAIN_VARIANT (type) == double_type_node)
01671 return implicit_built_in_decls[fcode];
01672 else if (TYPE_MAIN_VARIANT (type) == float_type_node)
01673 return implicit_built_in_decls[fcodef];
01674 else if (TYPE_MAIN_VARIANT (type) == long_double_type_node)
01675 return implicit_built_in_decls[fcodel];
01676 else
01677 return 0;
01678 }
01679
01680
01681
01682
01683
01684 static void
01685 expand_errno_check (tree exp, rtx target)
01686 {
01687 rtx lab = gen_label_rtx ();
01688
01689
01690
01691 emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
01692 0, lab);
01693
01694 #ifdef TARGET_EDOM
01695
01696 if (TREE_NOTHROW (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
01697 {
01698 #ifdef GEN_ERRNO_RTX
01699 rtx errno_rtx = GEN_ERRNO_RTX;
01700 #else
01701 rtx errno_rtx
01702 = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
01703 #endif
01704 emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
01705 emit_label (lab);
01706 return;
01707 }
01708 #endif
01709
01710
01711
01712 NO_DEFER_POP;
01713 expand_call (exp, target, 0);
01714 OK_DEFER_POP;
01715 emit_label (lab);
01716 }
01717
01718
01719
01720
01721
01722
01723
01724
01725 static rtx
01726 expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
01727 {
01728 optab builtin_optab;
01729 rtx op0, insns, before_call;
01730 tree fndecl = get_callee_fndecl (exp);
01731 tree arglist = TREE_OPERAND (exp, 1);
01732 enum machine_mode mode;
01733 bool errno_set = false;
01734 tree arg, narg;
01735
01736 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
01737 return 0;
01738
01739 arg = TREE_VALUE (arglist);
01740
01741 switch (DECL_FUNCTION_CODE (fndecl))
01742 {
01743 case BUILT_IN_SQRT:
01744 case BUILT_IN_SQRTF:
01745 case BUILT_IN_SQRTL:
01746 errno_set = ! tree_expr_nonnegative_p (arg);
01747 builtin_optab = sqrt_optab;
01748 break;
01749 case BUILT_IN_EXP:
01750 case BUILT_IN_EXPF:
01751 case BUILT_IN_EXPL:
01752 errno_set = true; builtin_optab = exp_optab; break;
01753 case BUILT_IN_EXP10:
01754 case BUILT_IN_EXP10F:
01755 case BUILT_IN_EXP10L:
01756 case BUILT_IN_POW10:
01757 case BUILT_IN_POW10F:
01758 case BUILT_IN_POW10L:
01759 errno_set = true; builtin_optab = exp10_optab; break;
01760 case BUILT_IN_EXP2:
01761 case BUILT_IN_EXP2F:
01762 case BUILT_IN_EXP2L:
01763 errno_set = true; builtin_optab = exp2_optab; break;
01764 case BUILT_IN_EXPM1:
01765 case BUILT_IN_EXPM1F:
01766 case BUILT_IN_EXPM1L:
01767 errno_set = true; builtin_optab = expm1_optab; break;
01768 case BUILT_IN_LOGB:
01769 case BUILT_IN_LOGBF:
01770 case BUILT_IN_LOGBL:
01771 errno_set = true; builtin_optab = logb_optab; break;
01772 case BUILT_IN_ILOGB:
01773 case BUILT_IN_ILOGBF:
01774 case BUILT_IN_ILOGBL:
01775 errno_set = true; builtin_optab = ilogb_optab; break;
01776 case BUILT_IN_LOG:
01777 case BUILT_IN_LOGF:
01778 case BUILT_IN_LOGL:
01779 errno_set = true; builtin_optab = log_optab; break;
01780 case BUILT_IN_LOG10:
01781 case BUILT_IN_LOG10F:
01782 case BUILT_IN_LOG10L:
01783 errno_set = true; builtin_optab = log10_optab; break;
01784 case BUILT_IN_LOG2:
01785 case BUILT_IN_LOG2F:
01786 case BUILT_IN_LOG2L:
01787 errno_set = true; builtin_optab = log2_optab; break;
01788 case BUILT_IN_LOG1P:
01789 case BUILT_IN_LOG1PF:
01790 case BUILT_IN_LOG1PL:
01791 errno_set = true; builtin_optab = log1p_optab; break;
01792 case BUILT_IN_ASIN:
01793 case BUILT_IN_ASINF:
01794 case BUILT_IN_ASINL:
01795 builtin_optab = asin_optab; break;
01796 case BUILT_IN_ACOS:
01797 case BUILT_IN_ACOSF:
01798 case BUILT_IN_ACOSL:
01799 builtin_optab = acos_optab; break;
01800 case BUILT_IN_TAN:
01801 case BUILT_IN_TANF:
01802 case BUILT_IN_TANL:
01803 builtin_optab = tan_optab; break;
01804 case BUILT_IN_ATAN:
01805 case BUILT_IN_ATANF:
01806 case BUILT_IN_ATANL:
01807 builtin_optab = atan_optab; break;
01808 case BUILT_IN_FLOOR:
01809 case BUILT_IN_FLOORF:
01810 case BUILT_IN_FLOORL:
01811 builtin_optab = floor_optab; break;
01812 case BUILT_IN_CEIL:
01813 case BUILT_IN_CEILF:
01814 case BUILT_IN_CEILL:
01815 builtin_optab = ceil_optab; break;
01816 case BUILT_IN_TRUNC:
01817 case BUILT_IN_TRUNCF:
01818 case BUILT_IN_TRUNCL:
01819 builtin_optab = btrunc_optab; break;
01820 case BUILT_IN_ROUND:
01821 case BUILT_IN_ROUNDF:
01822 case BUILT_IN_ROUNDL:
01823 builtin_optab = round_optab; break;
01824 case BUILT_IN_NEARBYINT:
01825 case BUILT_IN_NEARBYINTF:
01826 case BUILT_IN_NEARBYINTL:
01827 builtin_optab = nearbyint_optab; break;
01828 case BUILT_IN_RINT:
01829 case BUILT_IN_RINTF:
01830 case BUILT_IN_RINTL:
01831 builtin_optab = rint_optab; break;
01832 default:
01833 gcc_unreachable ();
01834 }
01835
01836
01837 mode = TYPE_MODE (TREE_TYPE (exp));
01838
01839 if (! flag_errno_math || ! HONOR_NANS (mode))
01840 errno_set = false;
01841
01842
01843 if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
01844 {
01845 target = gen_reg_rtx (mode);
01846
01847
01848
01849
01850 narg = builtin_save_expr (arg);
01851 if (narg != arg)
01852 {
01853 arg = narg;
01854 arglist = build_tree_list (NULL_TREE, arg);
01855 exp = build_function_call_expr (fndecl, arglist);
01856 }
01857
01858 op0 = expand_expr (arg, subtarget, VOIDmode, 0);
01859
01860 start_sequence ();
01861
01862
01863
01864 target = expand_unop (mode, builtin_optab, op0, target, 0);
01865
01866 if (target != 0)
01867 {
01868 if (errno_set)
01869 expand_errno_check (exp, target);
01870
01871
01872 insns = get_insns ();
01873 end_sequence ();
01874 emit_insn (insns);
01875 return target;
01876 }
01877
01878
01879
01880
01881 end_sequence ();
01882 }
01883
01884 before_call = get_last_insn ();
01885
01886 target = expand_call (exp, target, target == const0_rtx);
01887
01888
01889
01890
01891
01892 if (builtin_optab == sqrt_optab && !errno_set)
01893 {
01894
01895
01896 rtx last = get_last_insn ();
01897 while (last != before_call)
01898 {
01899 if (find_reg_note (last, REG_RETVAL, NULL))
01900 {
01901 rtx note = find_reg_note (last, REG_EQUAL, NULL);
01902
01903
01904 if (note
01905 && GET_CODE (note) == EXPR_LIST
01906 && GET_CODE (XEXP (note, 0)) == EXPR_LIST
01907 && XEXP (XEXP (note, 0), 1) != NULL_RTX
01908 && XEXP (XEXP (XEXP (note, 0), 1), 1) == NULL_RTX)
01909 {
01910 rtx operand = XEXP (XEXP (XEXP (note, 0), 1), 0);
01911
01912 if (operand
01913 && REG_P (operand)
01914 && GET_MODE (operand) == mode)
01915 {
01916
01917 rtx equiv = gen_rtx_SQRT (mode, operand);
01918 set_unique_reg_note (last, REG_EQUAL, equiv);
01919 }
01920 }
01921 break;
01922 }
01923 last = PREV_INSN (last);
01924 }
01925 }
01926
01927 return target;
01928 }
01929
01930
01931
01932
01933
01934
01935
01936
01937 static rtx
01938 expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
01939 {
01940 optab builtin_optab;
01941 rtx op0, op1, insns;
01942 int op1_type = REAL_TYPE;
01943 tree fndecl = get_callee_fndecl (exp);
01944 tree arglist = TREE_OPERAND (exp, 1);
01945 tree arg0, arg1, temp, narg;
01946 enum machine_mode mode;
01947 bool errno_set = true;
01948 bool stable = true;
01949
01950 if ((DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXP)
01951 || (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXPF)
01952 || (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXPL))
01953 op1_type = INTEGER_TYPE;
01954
01955 if (!validate_arglist (arglist, REAL_TYPE, op1_type, VOID_TYPE))
01956 return 0;
01957
01958 arg0 = TREE_VALUE (arglist);
01959 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
01960
01961 switch (DECL_FUNCTION_CODE (fndecl))
01962 {
01963 case BUILT_IN_POW:
01964 case BUILT_IN_POWF:
01965 case BUILT_IN_POWL:
01966 builtin_optab = pow_optab; break;
01967 case BUILT_IN_ATAN2:
01968 case BUILT_IN_ATAN2F:
01969 case BUILT_IN_ATAN2L:
01970 builtin_optab = atan2_optab; break;
01971 case BUILT_IN_LDEXP:
01972 case BUILT_IN_LDEXPF:
01973 case BUILT_IN_LDEXPL:
01974 builtin_optab = ldexp_optab; break;
01975 case BUILT_IN_FMOD:
01976 case BUILT_IN_FMODF:
01977 case BUILT_IN_FMODL:
01978 builtin_optab = fmod_optab; break;
01979 case BUILT_IN_DREM:
01980 case BUILT_IN_DREMF:
01981 case BUILT_IN_DREML:
01982 builtin_optab = drem_optab; break;
01983 default:
01984 gcc_unreachable ();
01985 }
01986
01987
01988 mode = TYPE_MODE (TREE_TYPE (exp));
01989
01990
01991 if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
01992 return 0;
01993
01994 target = gen_reg_rtx (mode);
01995
01996 if (! flag_errno_math || ! HONOR_NANS (mode))
01997 errno_set = false;
01998
01999
02000 narg = builtin_save_expr (arg1);
02001 if (narg != arg1)
02002 {
02003 arg1 = narg;
02004 temp = build_tree_list (NULL_TREE, narg);
02005 stable = false;
02006 }
02007 else
02008 temp = TREE_CHAIN (arglist);
02009
02010 narg = builtin_save_expr (arg0);
02011 if (narg != arg0)
02012 {
02013 arg0 = narg;
02014 arglist = tree_cons (NULL_TREE, narg, temp);
02015 stable = false;
02016 }
02017 else if (! stable)
02018 arglist = tree_cons (NULL_TREE, arg0, temp);
02019
02020 if (! stable)
02021 exp = build_function_call_expr (fndecl, arglist);
02022
02023 op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
02024 op1 = expand_expr (arg1, 0, VOIDmode, 0);
02025
02026 start_sequence ();
02027
02028
02029
02030 target = expand_binop (mode, builtin_optab, op0, op1,
02031 target, 0, OPTAB_DIRECT);
02032
02033
02034
02035
02036 if (target == 0)
02037 {
02038 end_sequence ();
02039 return expand_call (exp, target, target == const0_rtx);
02040 }
02041
02042 if (errno_set)
02043 expand_errno_check (exp, target);
02044
02045
02046 insns = get_insns ();
02047 end_sequence ();
02048 emit_insn (insns);
02049
02050 return target;
02051 }
02052
02053
02054
02055
02056
02057
02058
02059
02060 static rtx
02061 expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
02062 {
02063 optab builtin_optab;
02064 rtx op0, insns, before_call;
02065 tree fndecl = get_callee_fndecl (exp);
02066 tree arglist = TREE_OPERAND (exp, 1);
02067 enum machine_mode mode;
02068 bool errno_set = false;
02069 tree arg, narg;
02070
02071 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
02072 return 0;
02073
02074 arg = TREE_VALUE (arglist);
02075
02076 switch (DECL_FUNCTION_CODE (fndecl))
02077 {
02078 case BUILT_IN_SIN:
02079 case BUILT_IN_SINF:
02080 case BUILT_IN_SINL:
02081 case BUILT_IN_COS:
02082 case BUILT_IN_COSF:
02083 case BUILT_IN_COSL:
02084 builtin_optab = sincos_optab; break;
02085 default:
02086 gcc_unreachable ();
02087 }
02088
02089
02090 mode = TYPE_MODE (TREE_TYPE (exp));
02091
02092 if (! flag_errno_math || ! HONOR_NANS (mode))
02093 errno_set = false;
02094
02095
02096
02097 if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) {
02098 switch (DECL_FUNCTION_CODE (fndecl))
02099 {
02100 case BUILT_IN_SIN:
02101 case BUILT_IN_SINF:
02102 case BUILT_IN_SINL:
02103 builtin_optab = sin_optab; break;
02104 case BUILT_IN_COS:
02105 case BUILT_IN_COSF:
02106 case BUILT_IN_COSL:
02107 builtin_optab = cos_optab; break;
02108 default:
02109 gcc_unreachable ();
02110 }
02111 }
02112
02113
02114 if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
02115 {
02116 target = gen_reg_rtx (mode);
02117
02118
02119
02120
02121 narg = save_expr (arg);
02122 if (narg != arg)
02123 {
02124 arg = narg;
02125 arglist = build_tree_list (NULL_TREE, arg);
02126 exp = build_function_call_expr (fndecl, arglist);
02127 }
02128
02129 op0 = expand_expr (arg, subtarget, VOIDmode, 0);
02130
02131 start_sequence ();
02132
02133
02134
02135 if (builtin_optab == sincos_optab)
02136 {
02137 int result;
02138
02139 switch (DECL_FUNCTION_CODE (fndecl))
02140 {
02141 case BUILT_IN_SIN:
02142 case BUILT_IN_SINF:
02143 case BUILT_IN_SINL:
02144 result = expand_twoval_unop (builtin_optab, op0, 0, target, 0);
02145 break;
02146 case BUILT_IN_COS:
02147 case BUILT_IN_COSF:
02148 case BUILT_IN_COSL:
02149 result = expand_twoval_unop (builtin_optab, op0, target, 0, 0);
02150 break;
02151 default:
02152 gcc_unreachable ();
02153 }
02154 gcc_assert (result);
02155 }
02156 else
02157 {
02158 target = expand_unop (mode, builtin_optab, op0, target, 0);
02159 }
02160
02161 if (target != 0)
02162 {
02163 if (errno_set)
02164 expand_errno_check (exp, target);
02165
02166
02167 insns = get_insns ();
02168 end_sequence ();
02169 emit_insn (insns);
02170 return target;
02171 }
02172
02173
02174
02175
02176 end_sequence ();
02177 }
02178
02179 before_call = get_last_insn ();
02180
02181 target = expand_call (exp, target, target == const0_rtx);
02182
02183 return target;
02184 }
02185
02186
02187
02188
02189
02190
02191
02192
02193
02194
02195
02196
02197
02198
02199
02200 #ifndef POWI_MAX_MULTS
02201 #define POWI_MAX_MULTS (2*HOST_BITS_PER_WIDE_INT-2)
02202 #endif
02203
02204
02205
02206
02207
02208 #define POWI_TABLE_SIZE 256
02209
02210
02211
02212
02213 #define POWI_WINDOW_SIZE 3
02214
02215
02216
02217
02218
02219
02220
02221
02222 static const unsigned char powi_table[POWI_TABLE_SIZE] =
02223 {
02224 0, 1, 1, 2, 2, 3, 3, 4,
02225 4, 6, 5, 6, 6, 10, 7, 9,
02226 8, 16, 9, 16, 10, 12, 11, 13,
02227 12, 17, 13, 18, 14, 24, 15, 26,
02228 16, 17, 17, 19, 18, 33, 19, 26,
02229 20, 25, 21, 40, 22, 27, 23, 44,
02230 24, 32, 25, 34, 26, 29, 27, 44,
02231 28, 31, 29, 34, 30, 60, 31, 36,
02232 32, 64, 33, 34, 34, 46, 35, 37,
02233 36, 65, 37, 50, 38, 48, 39, 69,
02234 40, 49, 41, 43, 42, 51, 43, 58,
02235 44, 64, 45, 47, 46, 59, 47, 76,
02236 48, 65, 49, 66, 50, 67, 51, 66,
02237 52, 70, 53, 74, 54, 104, 55, 74,
02238 56, 64, 57, 69, 58, 78, 59, 68,
02239 60, 61, 61, 80, 62, 75, 63, 68,
02240 64, 65, 65, 128, 66, 129, 67, 90,
02241 68, 73, 69, 131, 70, 94, 71, 88,
02242 72, 128, 73, 98, 74, 132, 75, 121,
02243 76, 102, 77, 124, 78, 132, 79, 106,
02244 80, 97, 81, 160, 82, 99, 83, 134,
02245 84, 86, 85, 95, 86, 160, 87, 100,
02246 88, 113, 89, 98, 90, 107, 91, 122,
02247 92, 111, 93, 102, 94, 126, 95, 150,
02248 96, 128, 97, 130, 98, 133, 99, 195,
02249 100, 128, 101, 123, 102, 164, 103, 138,
02250 104, 145, 105, 146, 106, 109, 107, 149,
02251 108, 200, 109, 146, 110, 170, 111, 157,
02252 112, 128, 113, 130, 114, 182, 115, 132,
02253 116, 200, 117, 132, 118, 158, 119, 206,
02254 120, 240, 121, 162, 122, 147, 123, 152,
02255 124, 166, 125, 214, 126, 138, 127, 153,
02256 };
02257
02258
02259
02260
02261
02262
02263
02264 static int
02265 powi_lookup_cost (unsigned HOST_WIDE_INT n, bool *cache)
02266 {
02267
02268
02269 if (cache[n])
02270 return 0;
02271
02272 cache[n] = true;
02273 return powi_lookup_cost (n - powi_table[n], cache)
02274 + powi_lookup_cost (powi_table[n], cache) + 1;
02275 }
02276
02277
02278
02279
02280
02281 static int
02282 powi_cost (HOST_WIDE_INT n)
02283 {
02284 bool cache[POWI_TABLE_SIZE];
02285 unsigned HOST_WIDE_INT digit;
02286 unsigned HOST_WIDE_INT val;
02287 int result;
02288
02289 if (n == 0)
02290 return 0;
02291
02292
02293 val = (n < 0) ? -n : n;
02294
02295
02296 memset (cache, 0, POWI_TABLE_SIZE * sizeof (bool));
02297 cache[1] = true;
02298
02299 result = 0;
02300
02301 while (val >= POWI_TABLE_SIZE)
02302 {
02303 if (val & 1)
02304 {
02305 digit = val & ((1 << POWI_WINDOW_SIZE) - 1);
02306 result += powi_lookup_cost (digit, cache)
02307 + POWI_WINDOW_SIZE + 1;
02308 val >>= POWI_WINDOW_SIZE;
02309 }
02310 else
02311 {
02312 val >>= 1;
02313 result++;
02314 }
02315 }
02316
02317 return result + powi_lookup_cost (val, cache);
02318 }
02319
02320
02321
02322
02323
02324 static rtx
02325 expand_powi_1 (enum machine_mode mode, unsigned HOST_WIDE_INT n, rtx *cache)
02326 {
02327 unsigned HOST_WIDE_INT digit;
02328 rtx target, result;
02329 rtx op0, op1;
02330
02331 if (n < POWI_TABLE_SIZE)
02332 {
02333 if (cache[n])
02334 return cache[n];
02335
02336 target = gen_reg_rtx (mode);
02337 cache[n] = target;
02338
02339 op0 = expand_powi_1 (mode, n - powi_table[n], cache);
02340 op1 = expand_powi_1 (mode, powi_table[n], cache);
02341 }
02342 else if (n & 1)
02343 {
02344 target = gen_reg_rtx (mode);
02345 digit = n & ((1 << POWI_WINDOW_SIZE) - 1);
02346 op0 = expand_powi_1 (mode, n - digit, cache);
02347 op1 = expand_powi_1 (mode, digit, cache);
02348 }
02349 else
02350 {
02351 target = gen_reg_rtx (mode);
02352 op0 = expand_powi_1 (mode, n >> 1, cache);
02353 op1 = op0;
02354 }
02355
02356 result = expand_mult (mode, op0, op1, target, 0);
02357 if (result != target)
02358 emit_move_insn (target, result);
02359 return target;
02360 }
02361
02362
02363
02364
02365
02366 static rtx
02367 expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n)
02368 {
02369 unsigned HOST_WIDE_INT val;
02370 rtx cache[POWI_TABLE_SIZE];
02371 rtx result;
02372
02373 if (n == 0)
02374 return CONST1_RTX (mode);
02375
02376 val = (n < 0) ? -n : n;
02377
02378 memset (cache, 0, sizeof (cache));
02379 cache[1] = x;
02380
02381 result = expand_powi_1 (mode, (n < 0) ? -n : n, cache);
02382
02383
02384 if (n < 0)
02385 result = expand_binop (mode, sdiv_optab, CONST1_RTX (mode),
02386 result, NULL_RTX, 0, OPTAB_LIB_WIDEN);
02387
02388 return result;
02389 }
02390
02391
02392
02393
02394
02395
02396 static rtx
02397 expand_builtin_pow (tree exp, rtx target, rtx subtarget)
02398 {
02399 tree arglist = TREE_OPERAND (exp, 1);
02400 tree arg0, arg1;
02401
02402 if (! validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
02403 return 0;
02404
02405 arg0 = TREE_VALUE (arglist);
02406 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
02407
02408 if (TREE_CODE (arg1) == REAL_CST
02409 && ! TREE_CONSTANT_OVERFLOW (arg1))
02410 {
02411 REAL_VALUE_TYPE cint;
02412 REAL_VALUE_TYPE c;
02413 HOST_WIDE_INT n;
02414
02415 c = TREE_REAL_CST (arg1);
02416 n = real_to_integer (&c);
02417 real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
02418 if (real_identical (&c, &cint))
02419 {
02420
02421
02422
02423 if ((n >= -1 && n <= 2)
02424 || (flag_unsafe_math_optimizations
02425 && ! optimize_size
02426 && powi_cost (n) <= POWI_MAX_MULTS))
02427 {
02428 enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
02429 rtx op = expand_expr (arg0, subtarget, VOIDmode, 0);
02430 op = force_reg (mode, op);
02431 return expand_powi (op, mode, n);
02432 }
02433 }
02434 }
02435
02436 if (! flag_unsafe_math_optimizations)
02437 return NULL_RTX;
02438 return expand_builtin_mathfn_2 (exp, target, subtarget);
02439 }
02440
02441
02442
02443
02444
02445
02446 static rtx
02447 expand_builtin_powi (tree exp, rtx target, rtx subtarget)
02448 {
02449 tree arglist = TREE_OPERAND (exp, 1);
02450 tree arg0, arg1;
02451 rtx op0, op1;
02452 enum machine_mode mode;
02453
02454 if (! validate_arglist (arglist, REAL_TYPE, INTEGER_TYPE, VOID_TYPE))
02455 return 0;
02456
02457 arg0 = TREE_VALUE (arglist);
02458 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
02459 mode = TYPE_MODE (TREE_TYPE (exp));
02460
02461
02462
02463 if (TREE_CODE (arg1) == INTEGER_CST
02464 && ! TREE_CONSTANT_OVERFLOW (arg1))
02465 {
02466 HOST_WIDE_INT n = TREE_INT_CST_LOW (arg1);
02467
02468
02469
02470 if ((TREE_INT_CST_HIGH (arg1) == 0
02471 || TREE_INT_CST_HIGH (arg1) == -1)
02472 && ((n >= -1 && n <= 2)
02473 || (! optimize_size
02474 && powi_cost (n) <= POWI_MAX_MULTS)))
02475 {
02476 op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
02477 op0 = force_reg (mode, op0);
02478 return expand_powi (op0, mode, n);
02479 }
02480 }
02481
02482
02483
02484 if (target == NULL_RTX)
02485 target = gen_reg_rtx (mode);
02486
02487 op0 = expand_expr (arg0, subtarget, mode, 0);
02488 if (GET_MODE (op0) != mode)
02489 op0 = convert_to_mode (mode, op0, 0);
02490 op1 = expand_expr (arg1, 0, word_mode, 0);
02491 if (GET_MODE (op1) != word_mode)
02492 op1 = convert_to_mode (word_mode, op1, 0);
02493
02494 target = emit_library_call_value (powi_optab->handlers[(int) mode].libfunc,
02495 target, LCT_CONST_MAKE_BLOCK, mode, 2,
02496 op0, mode, op1, word_mode);
02497
02498 return target;
02499 }
02500
02501
02502
02503
02504
02505 static rtx
02506 expand_builtin_strlen (tree arglist, rtx target,
02507 enum machine_mode target_mode)
02508 {
02509 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
02510 return 0;
02511 else
02512 {
02513 rtx pat;
02514 tree len, src = TREE_VALUE (arglist);
02515 rtx result, src_reg, char_rtx, before_strlen;
02516 enum machine_mode insn_mode = target_mode, char_mode;
02517 enum insn_code icode = CODE_FOR_nothing;
02518 int align;
02519
02520
02521 len = c_strlen (src, 0);
02522 if (len)
02523 return expand_expr (len, target, target_mode, EXPAND_NORMAL);
02524
02525
02526
02527
02528
02529
02530 len = c_strlen (src, 1);
02531 if (len && TREE_CODE (len) == INTEGER_CST)
02532 {
02533 expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
02534 return expand_expr (len, target, target_mode, EXPAND_NORMAL);
02535 }
02536
02537 align = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
02538
02539
02540 if (align == 0)
02541 return 0;
02542
02543
02544 while (insn_mode != VOIDmode)
02545 {
02546 icode = strlen_optab->handlers[(int) insn_mode].insn_code;
02547 if (icode != CODE_FOR_nothing)
02548 break;
02549
02550 insn_mode = GET_MODE_WIDER_MODE (insn_mode);
02551 }
02552 if (insn_mode == VOIDmode)
02553 return 0;
02554
02555
02556 result = target;
02557 if (! (result != 0
02558 && REG_P (result)
02559 && GET_MODE (result) == insn_mode
02560 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
02561 result = gen_reg_rtx (insn_mode);
02562
02563
02564
02565
02566 src_reg = gen_reg_rtx (Pmode);
02567
02568
02569
02570 before_strlen = get_last_insn ();
02571
02572 char_rtx = const0_rtx;
02573 char_mode = insn_data[(int) icode].operand[2].mode;
02574 if (! (*insn_data[(int) icode].operand[2].predicate) (char_rtx,
02575 char_mode))
02576 char_rtx = copy_to_mode_reg (char_mode, char_rtx);
02577
02578 pat = GEN_FCN (icode) (result, gen_rtx_MEM (BLKmode, src_reg),
02579 char_rtx, GEN_INT (align));
02580 if (! pat)
02581 return 0;
02582 emit_insn (pat);
02583
02584
02585 start_sequence ();
02586 pat = expand_expr (src, src_reg, ptr_mode, EXPAND_NORMAL);
02587 if (pat != src_reg)
02588 emit_move_insn (src_reg, pat);
02589 pat = get_insns ();
02590 end_sequence ();
02591
02592 if (before_strlen)
02593 emit_insn_after (pat, before_strlen);
02594 else
02595 emit_insn_before (pat, get_insns ());
02596
02597
02598 if (GET_MODE (result) == target_mode)
02599 target = result;
02600 else if (target != 0)
02601 convert_move (target, result, 0);
02602 else
02603 target = convert_to_mode (target_mode, result, 0);
02604
02605 return target;
02606 }
02607 }
02608
02609
02610
02611
02612
02613 static rtx
02614 expand_builtin_strstr (tree arglist, tree type, rtx target, enum machine_mode mode)
02615 {
02616 if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
02617 {
02618 tree result = fold_builtin_strstr (arglist, type);
02619 if (result)
02620 return expand_expr (result, target, mode, EXPAND_NORMAL);
02621 }
02622 return 0;
02623 }
02624
02625
02626
02627
02628
02629 static rtx
02630 expand_builtin_strchr (tree arglist, tree type, rtx target, enum machine_mode mode)
02631 {
02632 if (validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02633 {
02634 tree result = fold_builtin_strchr (arglist, type);
02635 if (result)
02636 return expand_expr (result, target, mode, EXPAND_NORMAL);
02637
02638
02639 }
02640 return 0;
02641 }
02642
02643
02644
02645
02646
02647 static rtx
02648 expand_builtin_strrchr (tree arglist, tree type, rtx target, enum machine_mode mode)
02649 {
02650 if (validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02651 {
02652 tree result = fold_builtin_strrchr (arglist, type);
02653 if (result)
02654 return expand_expr (result, target, mode, EXPAND_NORMAL);
02655 }
02656 return 0;
02657 }
02658
02659
02660
02661
02662
02663 static rtx
02664 expand_builtin_strpbrk (tree arglist, tree type, rtx target, enum machine_mode mode)
02665 {
02666 if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
02667 {
02668 tree result = fold_builtin_strpbrk (arglist, type);
02669 if (result)
02670 return expand_expr (result, target, mode, EXPAND_NORMAL);
02671 }
02672 return 0;
02673 }
02674
02675
02676
02677
02678
02679 static rtx
02680 builtin_memcpy_read_str (void *data, HOST_WIDE_INT offset,
02681 enum machine_mode mode)
02682 {
02683 const char *str = (const char *) data;
02684
02685 gcc_assert (offset >= 0
02686 && ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode)
02687 <= strlen (str) + 1));
02688
02689 return c_readstr (str + offset, mode);
02690 }
02691
02692
02693
02694
02695
02696 static rtx
02697 expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
02698 {
02699 tree arglist = TREE_OPERAND (exp, 1);
02700 if (!validate_arglist (arglist,
02701 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02702 return 0;
02703 else
02704 {
02705 tree dest = TREE_VALUE (arglist);
02706 tree src = TREE_VALUE (TREE_CHAIN (arglist));
02707 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02708 const char *src_str;
02709 unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
02710 unsigned int dest_align
02711 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
02712 rtx dest_mem, src_mem, dest_addr, len_rtx;
02713 tree result = fold_builtin_memcpy (exp);
02714
02715 if (result)
02716 return expand_expr (result, target, mode, EXPAND_NORMAL);
02717
02718
02719 if (dest_align == 0)
02720 return 0;
02721
02722
02723
02724 if (src_align == 0)
02725 return 0;
02726
02727 dest_mem = get_memory_rtx (dest, len);
02728 set_mem_align (dest_mem, dest_align);
02729 len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
02730 src_str = c_getstr (src);
02731
02732
02733
02734
02735 if (src_str
02736 && GET_CODE (len_rtx) == CONST_INT
02737 && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
02738 && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
02739 (void *) src_str, dest_align))
02740 {
02741 dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
02742 builtin_memcpy_read_str,
02743 (void *) src_str, dest_align, 0);
02744 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02745 dest_mem = convert_memory_address (ptr_mode, dest_mem);
02746 return dest_mem;
02747 }
02748
02749 src_mem = get_memory_rtx (src, len);
02750 set_mem_align (src_mem, src_align);
02751
02752
02753 dest_addr = emit_block_move (dest_mem, src_mem, len_rtx,
02754 CALL_EXPR_TAILCALL (exp)
02755 ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL);
02756
02757 if (dest_addr == 0)
02758 {
02759 dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02760 dest_addr = convert_memory_address (ptr_mode, dest_addr);
02761 }
02762 return dest_addr;
02763 }
02764 }
02765
02766
02767
02768
02769
02770
02771
02772
02773
02774 static rtx
02775 expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode mode,
02776 int endp)
02777 {
02778 if (!validate_arglist (arglist,
02779 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02780 return 0;
02781
02782 else if (target == const0_rtx)
02783 {
02784 tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
02785
02786 if (!fn)
02787 return 0;
02788
02789 return expand_expr (build_function_call_expr (fn, arglist),
02790 target, mode, EXPAND_NORMAL);
02791 }
02792 else
02793 {
02794 tree dest = TREE_VALUE (arglist);
02795 tree src = TREE_VALUE (TREE_CHAIN (arglist));
02796 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02797 const char *src_str;
02798 unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
02799 unsigned int dest_align
02800 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
02801 rtx dest_mem, src_mem, len_rtx;
02802 tree result = fold_builtin_mempcpy (arglist, type, endp);
02803
02804 if (result)
02805 return expand_expr (result, target, mode, EXPAND_NORMAL);
02806
02807
02808
02809 if (dest_align == 0 || src_align == 0)
02810 return 0;
02811
02812
02813 if (! host_integerp (len, 1))
02814 return 0;
02815
02816 len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
02817 src_str = c_getstr (src);
02818
02819
02820
02821
02822 if (src_str
02823 && GET_CODE (len_rtx) == CONST_INT
02824 && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
02825 && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
02826 (void *) src_str, dest_align))
02827 {
02828 dest_mem = get_memory_rtx (dest, len);
02829 set_mem_align (dest_mem, dest_align);
02830 dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
02831 builtin_memcpy_read_str,
02832 (void *) src_str, dest_align, endp);
02833 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02834 dest_mem = convert_memory_address (ptr_mode, dest_mem);
02835 return dest_mem;
02836 }
02837
02838 if (GET_CODE (len_rtx) == CONST_INT
02839 && can_move_by_pieces (INTVAL (len_rtx),
02840 MIN (dest_align, src_align)))
02841 {
02842 dest_mem = get_memory_rtx (dest, len);
02843 set_mem_align (dest_mem, dest_align);
02844 src_mem = get_memory_rtx (src, len);
02845 set_mem_align (src_mem, src_align);
02846 dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx),
02847 MIN (dest_align, src_align), endp);
02848 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02849 dest_mem = convert_memory_address (ptr_mode, dest_mem);
02850 return dest_mem;
02851 }
02852
02853 return 0;
02854 }
02855 }
02856
02857
02858
02859
02860 static rtx
02861 expand_builtin_memmove (tree arglist, tree type, rtx target,
02862 enum machine_mode mode, tree orig_exp)
02863 {
02864 if (!validate_arglist (arglist,
02865 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02866 return 0;
02867 else
02868 {
02869 tree dest = TREE_VALUE (arglist);
02870 tree src = TREE_VALUE (TREE_CHAIN (arglist));
02871 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02872
02873 unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
02874 unsigned int dest_align
02875 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
02876 tree result = fold_builtin_memmove (arglist, type);
02877
02878 if (result)
02879 return expand_expr (result, target, mode, EXPAND_NORMAL);
02880
02881
02882 if (dest_align == 0)
02883 return 0;
02884
02885
02886
02887 if (src_align == 0)
02888 return 0;
02889
02890
02891
02892 if (readonly_data_expr (src))
02893 {
02894 tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
02895 if (!fn)
02896 return 0;
02897 fn = build_function_call_expr (fn, arglist);
02898 if (TREE_CODE (fn) == CALL_EXPR)
02899 CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp);
02900 return expand_expr (fn, target, mode, EXPAND_NORMAL);
02901 }
02902
02903
02904
02905 if (integer_onep (len))
02906 {
02907 rtx ret = expand_builtin_mempcpy (arglist, type, target, mode,
02908 0);
02909 if (ret)
02910 return ret;
02911 }
02912
02913
02914 return 0;
02915 }
02916 }
02917
02918
02919
02920
02921 static rtx
02922 expand_builtin_bcopy (tree exp)
02923 {
02924 tree arglist = TREE_OPERAND (exp, 1);
02925 tree type = TREE_TYPE (exp);
02926 tree src, dest, size, newarglist;
02927
02928 if (!validate_arglist (arglist,
02929 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02930 return NULL_RTX;
02931
02932 src = TREE_VALUE (arglist);
02933 dest = TREE_VALUE (TREE_CHAIN (arglist));
02934 size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02935
02936
02937
02938
02939
02940
02941 newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size));
02942 newarglist = tree_cons (NULL_TREE, src, newarglist);
02943 newarglist = tree_cons (NULL_TREE, dest, newarglist);
02944
02945 return expand_builtin_memmove (newarglist, type, const0_rtx, VOIDmode, exp);
02946 }
02947
02948 #ifndef HAVE_movstr
02949 # define HAVE_movstr 0
02950 # define CODE_FOR_movstr CODE_FOR_nothing
02951 #endif
02952
02953
02954
02955
02956
02957
02958
02959
02960 static rtx
02961 expand_movstr (tree dest, tree src, rtx target, int endp)
02962 {
02963 rtx end;
02964 rtx dest_mem;
02965 rtx src_mem;
02966 rtx insn;
02967 const struct insn_data * data;
02968
02969 if (!HAVE_movstr)
02970 return 0;
02971
02972 dest_mem = get_memory_rtx (dest, NULL);
02973 src_mem = get_memory_rtx (src, NULL);
02974 if (!endp)
02975 {
02976 target = force_reg (Pmode, XEXP (dest_mem, 0));
02977 dest_mem = replace_equiv_address (dest_mem, target);
02978 end = gen_reg_rtx (Pmode);
02979 }
02980 else
02981 {
02982 if (target == 0 || target == const0_rtx)
02983 {
02984 end = gen_reg_rtx (Pmode);
02985 if (target == 0)
02986 target = end;
02987 }
02988 else
02989 end = target;
02990 }
02991
02992 data = insn_data + CODE_FOR_movstr;
02993
02994 if (data->operand[0].mode != VOIDmode)
02995 end = gen_lowpart (data->operand[0].mode, end);
02996
02997 insn = data->genfun (end, dest_mem, src_mem);
02998
02999 gcc_assert (insn);
03000
03001 emit_insn (insn);
03002
03003
03004
03005
03006 if (endp == 1 && target != const0_rtx)
03007 {
03008 rtx tem = plus_constant (gen_lowpart (GET_MODE (target), end), 1);
03009 emit_move_insn (target, force_operand (tem, NULL_RTX));
03010 }
03011
03012 return target;
03013 }
03014
03015
03016
03017
03018
03019
03020 static rtx
03021 expand_builtin_strcpy (tree exp, rtx target, enum machine_mode mode)
03022 {
03023 tree arglist = TREE_OPERAND (exp, 1);
03024 if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03025 {
03026 tree result = fold_builtin_strcpy (exp, 0);
03027 if (result)
03028 return expand_expr (result, target, mode, EXPAND_NORMAL);
03029
03030 return expand_movstr (TREE_VALUE (arglist),
03031 TREE_VALUE (TREE_CHAIN (arglist)),
03032 target, 0);
03033 }
03034 return 0;
03035 }
03036
03037
03038
03039
03040
03041
03042 static rtx
03043 expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode)
03044 {
03045 tree arglist = TREE_OPERAND (exp, 1);
03046
03047 if (target == const0_rtx)
03048 {
03049 tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
03050 if (!fn)
03051 return 0;
03052
03053 return expand_expr (build_function_call_expr (fn, arglist),
03054 target, mode, EXPAND_NORMAL);
03055 }
03056
03057 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03058 return 0;
03059 else
03060 {
03061 tree dst, src, len, lenp1;
03062 tree narglist;
03063 rtx ret;
03064
03065
03066
03067
03068
03069 src = TREE_VALUE (TREE_CHAIN (arglist));
03070 if (! c_getstr (src) || ! (len = c_strlen (src, 0)))
03071 return expand_movstr (TREE_VALUE (arglist),
03072 TREE_VALUE (TREE_CHAIN (arglist)),
03073 target, 2);
03074
03075 dst = TREE_VALUE (arglist);
03076 lenp1 = size_binop (PLUS_EXPR, len, ssize_int (1));
03077 narglist = build_tree_list (NULL_TREE, lenp1);
03078 narglist = tree_cons (NULL_TREE, src, narglist);
03079 narglist = tree_cons (NULL_TREE, dst, narglist);
03080 ret = expand_builtin_mempcpy (narglist, TREE_TYPE (exp),
03081 target, mode, 2);
03082
03083 if (ret)
03084 return ret;
03085
03086 if (TREE_CODE (len) == INTEGER_CST)
03087 {
03088 rtx len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
03089
03090 if (GET_CODE (len_rtx) == CONST_INT)
03091 {
03092 ret = expand_builtin_strcpy (exp, target, mode);
03093
03094 if (ret)
03095 {
03096 if (! target)
03097 {
03098 if (mode != VOIDmode)
03099 target = gen_reg_rtx (mode);
03100 else
03101 target = gen_reg_rtx (GET_MODE (ret));
03102 }
03103 if (GET_MODE (target) != GET_MODE (ret))
03104 ret = gen_lowpart (GET_MODE (target), ret);
03105
03106 ret = plus_constant (ret, INTVAL (len_rtx));
03107 ret = emit_move_insn (target, force_operand (ret, NULL_RTX));
03108 gcc_assert (ret);
03109
03110 return target;
03111 }
03112 }
03113 }
03114
03115 return expand_movstr (TREE_VALUE (arglist),
03116 TREE_VALUE (TREE_CHAIN (arglist)),
03117 target, 2);
03118 }
03119 }
03120
03121
03122
03123
03124
03125 static rtx
03126 builtin_strncpy_read_str (void *data, HOST_WIDE_INT offset,
03127 enum machine_mode mode)
03128 {
03129 const char *str = (const char *) data;
03130
03131 if ((unsigned HOST_WIDE_INT) offset > strlen (str))
03132 return const0_rtx;
03133
03134 return c_readstr (str + offset, mode);
03135 }
03136
03137
03138
03139
03140 static rtx
03141 expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode)
03142 {
03143 tree arglist = TREE_OPERAND (exp, 1);
03144 if (validate_arglist (arglist,
03145 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
03146 {
03147 tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)), 1);
03148 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
03149 tree result = fold_builtin_strncpy (exp, slen);
03150
03151 if (result)
03152 return expand_expr (result, target, mode, EXPAND_NORMAL);
03153
03154
03155 if (!host_integerp (len, 1) || !slen || !host_integerp (slen, 1))
03156 return 0;
03157
03158 slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
03159
03160
03161
03162
03163 if (tree_int_cst_lt (slen, len))
03164 {
03165 tree dest = TREE_VALUE (arglist);
03166 unsigned int dest_align
03167 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
03168 const char *p = c_getstr (TREE_VALUE (TREE_CHAIN (arglist)));
03169 rtx dest_mem;
03170
03171 if (!p || dest_align == 0 || !host_integerp (len, 1)
03172 || !can_store_by_pieces (tree_low_cst (len, 1),
03173 builtin_strncpy_read_str,
03174 (void *) p, dest_align))
03175 return 0;
03176
03177 dest_mem = get_memory_rtx (dest, len);
03178 store_by_pieces (dest_mem, tree_low_cst (len, 1),
03179 builtin_strncpy_read_str,
03180 (void *) p, dest_align, 0);
03181 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
03182 dest_mem = convert_memory_address (ptr_mode, dest_mem);
03183 return dest_mem;
03184 }
03185 }
03186 return 0;
03187 }
03188
03189
03190
03191
03192
03193 static rtx
03194 builtin_memset_read_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
03195 enum machine_mode mode)
03196 {
03197 const char *c = (const char *) data;
03198 char *p = alloca (GET_MODE_SIZE (mode));
03199
03200 memset (p, *c, GET_MODE_SIZE (mode));
03201
03202 return c_readstr (p, mode);
03203 }
03204
03205
03206
03207
03208
03209
03210 static rtx
03211 builtin_memset_gen_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
03212 enum machine_mode mode)
03213 {
03214 rtx target, coeff;
03215 size_t size;
03216 char *p;
03217
03218 size = GET_MODE_SIZE (mode);
03219 if (size == 1)
03220 return (rtx) data;
03221
03222 p = alloca (size);
03223 memset (p, 1, size);
03224 coeff = c_readstr (p, mode);
03225
03226 target = convert_to_mode (mode, (rtx) data, 1);
03227 target = expand_mult (mode, target, coeff, NULL_RTX, 1);
03228 return force_reg (mode, target);
03229 }
03230
03231
03232
03233
03234
03235
03236 static rtx
03237 expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode,
03238 tree orig_exp)
03239 {
03240 if (!validate_arglist (arglist,
03241 POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
03242 return 0;
03243 else
03244 {
03245 tree dest = TREE_VALUE (arglist);
03246 tree val = TREE_VALUE (TREE_CHAIN (arglist));
03247 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
03248 char c;
03249
03250 unsigned int dest_align
03251 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
03252 rtx dest_mem, dest_addr, len_rtx;
03253
03254
03255
03256 if (dest_align == 0)
03257 return 0;
03258
03259
03260 if (integer_zerop (len))
03261 {
03262
03263 expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL);
03264 return expand_expr (dest, target, mode, EXPAND_NORMAL);
03265 }
03266
03267 if (TREE_CODE (val) != INTEGER_CST)
03268 {
03269 rtx val_rtx;
03270
03271 if (!host_integerp (len, 1))
03272 return 0;
03273
03274 if (optimize_size && tree_low_cst (len, 1) > 1)
03275 return 0;
03276
03277
03278
03279
03280 c = 1;
03281 if (!can_store_by_pieces (tree_low_cst (len, 1),
03282 builtin_memset_read_str,
03283 &c, dest_align))
03284 return 0;
03285
03286 val = fold (build1 (CONVERT_EXPR, unsigned_char_type_node, val));
03287 val_rtx = expand_expr (val, NULL_RTX, VOIDmode, 0);
03288 val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
03289 val_rtx);
03290 dest_mem = get_memory_rtx (dest, len);
03291 store_by_pieces (dest_mem, tree_low_cst (len, 1),
03292 builtin_memset_gen_str,
03293 val_rtx, dest_align, 0);
03294 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
03295 dest_mem = convert_memory_address (ptr_mode, dest_mem);
03296 return dest_mem;
03297 }
03298
03299 if (target_char_cast (val, &c))
03300 return 0;
03301
03302 if (c)
03303 {
03304 if (!host_integerp (len, 1))
03305 return 0;
03306 if (!can_store_by_pieces (tree_low_cst (len, 1),
03307 builtin_memset_read_str, &c,
03308 dest_align))
03309 return 0;
03310
03311 dest_mem = get_memory_rtx (dest, len);
03312 store_by_pieces (dest_mem, tree_low_cst (len, 1),
03313 builtin_memset_read_str,
03314 &c, dest_align, 0);
03315 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
03316 dest_mem = convert_memory_address (ptr_mode, dest_mem);
03317 return dest_mem;
03318 }
03319
03320 len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
03321
03322 dest_mem = get_memory_rtx (dest, len);
03323 set_mem_align (dest_mem, dest_align);
03324 dest_addr = clear_storage (dest_mem, len_rtx,
03325 CALL_EXPR_TAILCALL (orig_exp)
03326 ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL);
03327
03328 if (dest_addr == 0)
03329 {
03330 dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
03331 dest_addr = convert_memory_address (ptr_mode, dest_addr);
03332 }
03333
03334 return dest_addr;
03335 }
03336 }
03337
03338
03339
03340
03341 static rtx
03342 expand_builtin_bzero (tree exp)
03343 {
03344 tree arglist = TREE_OPERAND (exp, 1);
03345 tree dest, size, newarglist;
03346
03347 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
03348 return NULL_RTX;
03349
03350 dest = TREE_VALUE (arglist);
03351 size = TREE_VALUE (TREE_CHAIN (arglist));
03352
03353
03354
03355
03356
03357
03358 newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size));
03359 newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
03360 newarglist = tree_cons (NULL_TREE, dest, newarglist);
03361
03362 return expand_builtin_memset (newarglist, const0_rtx, VOIDmode, exp);
03363 }
03364
03365
03366
03367
03368
03369
03370 static rtx
03371 expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target,
03372 enum machine_mode mode)
03373 {
03374 if (!validate_arglist (arglist,
03375 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
03376 return 0;
03377 else
03378 {
03379 tree result = fold_builtin_memcmp (arglist);
03380 if (result)
03381 return expand_expr (result, target, mode, EXPAND_NORMAL);
03382 }
03383
03384 #if defined HAVE_cmpmemsi || defined HAVE_cmpstrsi
03385 {
03386 tree arg1 = TREE_VALUE (arglist);
03387 tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
03388 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
03389 rtx arg1_rtx, arg2_rtx, arg3_rtx;
03390 rtx result;
03391 rtx insn;
03392
03393 int arg1_align
03394 = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03395 int arg2_align
03396 = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03397 enum machine_mode insn_mode;
03398
03399 #ifdef HAVE_cmpmemsi
03400 if (HAVE_cmpmemsi)
03401 insn_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode;
03402 else
03403 #endif
03404 #ifdef HAVE_cmpstrsi
03405 if (HAVE_cmpstrsi)
03406 insn_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
03407 else
03408 #endif
03409 return 0;
03410
03411
03412 if (arg1_align == 0 || arg2_align == 0)
03413 return 0;
03414
03415
03416 result = target;
03417 if (! (result != 0
03418 && REG_P (result) && GET_MODE (result) == insn_mode
03419 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
03420 result = gen_reg_rtx (insn_mode);
03421
03422 arg1_rtx = get_memory_rtx (arg1, len);
03423 arg2_rtx = get_memory_rtx (arg2, len);
03424 arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
03425
03426
03427 if (GET_CODE (arg3_rtx) == CONST_INT)
03428 {
03429 set_mem_size (arg1_rtx, arg3_rtx);
03430 set_mem_size (arg2_rtx, arg3_rtx);
03431 }
03432
03433 #ifdef HAVE_cmpmemsi
03434 if (HAVE_cmpmemsi)
03435 insn = gen_cmpmemsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
03436 GEN_INT (MIN (arg1_align, arg2_align)));
03437 else
03438 #endif
03439 #ifdef HAVE_cmpstrsi
03440 if (HAVE_cmpstrsi)
03441 insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
03442 GEN_INT (MIN (arg1_align, arg2_align)));
03443 else
03444 #endif
03445 gcc_unreachable ();
03446
03447 if (insn)
03448 emit_insn (insn);
03449 else
03450 emit_library_call_value (memcmp_libfunc, result, LCT_PURE_MAKE_BLOCK,
03451 TYPE_MODE (integer_type_node), 3,
03452 XEXP (arg1_rtx, 0), Pmode,
03453 XEXP (arg2_rtx, 0), Pmode,
03454 convert_to_mode (TYPE_MODE (sizetype), arg3_rtx,
03455 TYPE_UNSIGNED (sizetype)),
03456 TYPE_MODE (sizetype));
03457
03458
03459 mode = TYPE_MODE (TREE_TYPE (exp));
03460 if (GET_MODE (result) == mode)
03461 return result;
03462 else if (target != 0)
03463 {
03464 convert_move (target, result, 0);
03465 return target;
03466 }
03467 else
03468 return convert_to_mode (mode, result, 0);
03469 }
03470 #endif
03471
03472 return 0;
03473 }
03474
03475
03476
03477
03478
03479 static rtx
03480 expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
03481 {
03482 tree arglist = TREE_OPERAND (exp, 1);
03483
03484 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03485 return 0;
03486 else
03487 {
03488 tree result = fold_builtin_strcmp (arglist);
03489 if (result)
03490 return expand_expr (result, target, mode, EXPAND_NORMAL);
03491 }
03492
03493 #ifdef HAVE_cmpstrsi
03494 if (HAVE_cmpstrsi)
03495 {
03496 tree arg1 = TREE_VALUE (arglist);
03497 tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
03498 tree len, len1, len2;
03499 rtx arg1_rtx, arg2_rtx, arg3_rtx;
03500 rtx result, insn;
03501 tree fndecl, fn;
03502
03503 int arg1_align
03504 = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03505 int arg2_align
03506 = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03507 enum machine_mode insn_mode
03508 = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
03509
03510 len1 = c_strlen (arg1, 1);
03511 len2 = c_strlen (arg2, 1);
03512
03513 if (len1)
03514 len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
03515 if (len2)
03516 len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
03517
03518
03519
03520
03521
03522
03523
03524
03525 if (!len1)
03526 len = len2;
03527 else if (!len2)
03528 len = len1;
03529 else if (TREE_SIDE_EFFECTS (len1))
03530 len = len2;
03531 else if (TREE_SIDE_EFFECTS (len2))
03532 len = len1;
03533 else if (TREE_CODE (len1) != INTEGER_CST)
03534 len = len2;
03535 else if (TREE_CODE (len2) != INTEGER_CST)
03536 len = len1;
03537 else if (tree_int_cst_lt (len1, len2))
03538 len = len1;
03539 else
03540 len = len2;
03541
03542
03543 if (!len || TREE_SIDE_EFFECTS (len))
03544 return 0;
03545
03546
03547 if (arg1_align == 0 || arg2_align == 0)
03548 return 0;
03549
03550
03551 result = target;
03552 if (! (result != 0
03553 && REG_P (result) && GET_MODE (result) == insn_mode
03554 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
03555 result = gen_reg_rtx (insn_mode);
03556
03557
03558 arg1 = builtin_save_expr (arg1);
03559 arg2 = builtin_save_expr (arg2);
03560
03561 arg1_rtx = get_memory_rtx (arg1, NULL);
03562 arg2_rtx = get_memory_rtx (arg2, NULL);
03563 arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
03564 insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
03565 GEN_INT (MIN (arg1_align, arg2_align)));
03566 if (insn)
03567 {
03568 emit_insn (insn);
03569
03570
03571 mode = TYPE_MODE (TREE_TYPE (exp));
03572 if (GET_MODE (result) == mode)
03573 return result;
03574 if (target == 0)
03575 return convert_to_mode (mode, result, 0);
03576 convert_move (target, result, 0);
03577 return target;
03578 }
03579
03580
03581
03582 arglist = build_tree_list (NULL_TREE, arg2);
03583 arglist = tree_cons (NULL_TREE, arg1, arglist);
03584 fndecl = get_callee_fndecl (exp);
03585 fn = build_function_call_expr (fndecl, arglist);
03586 if (TREE_CODE (fn) == CALL_EXPR)
03587 CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
03588 return expand_call (fn, target, target == const0_rtx);
03589 }
03590 #endif
03591 return 0;
03592 }
03593
03594
03595
03596
03597
03598 static rtx
03599 expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
03600 {
03601 tree arglist = TREE_OPERAND (exp, 1);
03602
03603 if (!validate_arglist (arglist,
03604 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
03605 return 0;
03606 else
03607 {
03608 tree result = fold_builtin_strncmp (arglist);
03609 if (result)
03610 return expand_expr (result, target, mode, EXPAND_NORMAL);
03611 }
03612
03613
03614
03615
03616 #ifdef HAVE_cmpstrsi
03617 if (HAVE_cmpstrsi)
03618 {
03619 tree arg1 = TREE_VALUE (arglist);
03620 tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
03621 tree arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
03622 tree len, len1, len2;
03623 rtx arg1_rtx, arg2_rtx, arg3_rtx;
03624 rtx result, insn;
03625 tree fndecl, fn;
03626
03627 int arg1_align
03628 = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03629 int arg2_align
03630 = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03631 enum machine_mode insn_mode
03632 = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
03633
03634 len1 = c_strlen (arg1, 1);
03635 len2 = c_strlen (arg2, 1);
03636
03637 if (len1)
03638 len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
03639 if (len2)
03640 len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
03641
03642
03643
03644
03645
03646
03647
03648
03649 if (!len1)
03650 len = len2;
03651 else if (!len2)
03652 len = len1;
03653 else if (TREE_SIDE_EFFECTS (len1))
03654 len = len2;
03655 else if (TREE_SIDE_EFFECTS (len2))
03656 len = len1;
03657 else if (TREE_CODE (len1) != INTEGER_CST)
03658 len = len2;
03659 else if (TREE_CODE (len2) != INTEGER_CST)
03660 len = len1;
03661 else if (tree_int_cst_lt (len1, len2))
03662 len = len1;
03663 else
03664 len = len2;
03665
03666
03667 if (!len || TREE_SIDE_EFFECTS (len))
03668 return 0;
03669
03670
03671 len = fold (build2 (MIN_EXPR, TREE_TYPE (len), len,
03672 fold_convert (TREE_TYPE (len), arg3)));
03673
03674
03675 if (arg1_align == 0 || arg2_align == 0)
03676 return 0;
03677
03678
03679 result = target;
03680 if (! (result != 0
03681 && REG_P (result) && GET_MODE (result) == insn_mode
03682 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
03683 result = gen_reg_rtx (insn_mode);
03684
03685
03686 arg1 = builtin_save_expr (arg1);
03687 arg2 = builtin_save_expr (arg2);
03688 len = builtin_save_expr (len);
03689
03690 arg1_rtx = get_memory_rtx (arg1, len);
03691 arg2_rtx = get_memory_rtx (arg2, len);
03692 arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
03693 insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
03694 GEN_INT (MIN (arg1_align, arg2_align)));
03695 if (insn)
03696 {
03697 emit_insn (insn);
03698
03699
03700 mode = TYPE_MODE (TREE_TYPE (exp));
03701 if (GET_MODE (result) == mode)
03702 return result;
03703 if (target == 0)
03704 return convert_to_mode (mode, result, 0);
03705 convert_move (target, result, 0);
03706 return target;
03707 }
03708
03709
03710
03711 arglist = build_tree_list (NULL_TREE, len);
03712 arglist = tree_cons (NULL_TREE, arg2, arglist);
03713 arglist = tree_cons (NULL_TREE, arg1, arglist);
03714 fndecl = get_callee_fndecl (exp);
03715 fn = build_function_call_expr (fndecl, arglist);
03716 if (TREE_CODE (fn) == CALL_EXPR)
03717 CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
03718 return expand_call (fn, target, target == const0_rtx);
03719 }
03720 #endif
03721 return 0;
03722 }
03723
03724
03725
03726
03727
03728 static rtx
03729 expand_builtin_strcat (tree arglist, tree type, rtx target, enum machine_mode mode)
03730 {
03731 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03732 return 0;
03733 else
03734 {
03735 tree dst = TREE_VALUE (arglist),
03736 src = TREE_VALUE (TREE_CHAIN (arglist));
03737 const char *p = c_getstr (src);
03738
03739 if (p)
03740 {
03741
03742 if (*p == '\0')
03743 return expand_expr (dst, target, mode, EXPAND_NORMAL);
03744 else if (!optimize_size)
03745 {
03746
03747
03748 tree newdst, arglist,
03749 strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
03750
03751
03752 arglist = build_tree_list (NULL_TREE,
03753 fold (size_binop (PLUS_EXPR,
03754 c_strlen (src, 0),
03755 ssize_int (1))));
03756
03757 arglist = tree_cons (NULL_TREE, src, arglist);
03758
03759
03760 dst = builtin_save_expr (dst);
03761
03762
03763 newdst =
03764 fold (build_function_call_expr (strlen_fn,
03765 build_tree_list (NULL_TREE,
03766 dst)));
03767
03768 newdst = fold (build2 (PLUS_EXPR, TREE_TYPE (dst), dst, newdst));
03769
03770
03771 arglist = tree_cons (NULL_TREE, newdst, arglist);
03772
03773
03774
03775
03776
03777
03778
03779 if (expand_builtin_mempcpy (arglist, type, 0, mode, 0))
03780 return expand_expr (dst, target, mode, EXPAND_NORMAL);
03781 else
03782 return 0;
03783 }
03784 }
03785
03786 return 0;
03787 }
03788 }
03789
03790
03791
03792
03793
03794 static rtx
03795 expand_builtin_strncat (tree arglist, rtx target, enum machine_mode mode)
03796 {
03797 if (validate_arglist (arglist,
03798 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
03799 {
03800 tree result = fold_builtin_strncat (arglist);
03801 if (result)
03802 return expand_expr (result, target, mode, EXPAND_NORMAL);
03803 }
03804 return 0;
03805 }
03806
03807
03808
03809
03810
03811 static rtx
03812 expand_builtin_strspn (tree arglist, rtx target, enum machine_mode mode)
03813 {
03814 if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03815 {
03816 tree result = fold_builtin_strspn (arglist);
03817 if (result)
03818 return expand_expr (result, target, mode, EXPAND_NORMAL);
03819 }
03820 return 0;
03821 }
03822
03823
03824
03825
03826
03827 static rtx
03828 expand_builtin_strcspn (tree arglist, rtx target, enum machine_mode mode)
03829 {
03830 if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03831 {
03832 tree result = fold_builtin_strcspn (arglist);
03833 if (result)
03834 return expand_expr (result, target, mode, EXPAND_NORMAL);
03835 }
03836 return 0;
03837 }
03838
03839
03840
03841
03842 rtx
03843 expand_builtin_saveregs (void)
03844 {
03845 rtx val, seq;
03846
03847
03848
03849 if (saveregs_value != 0)
03850 return saveregs_value;
03851
03852
03853
03854
03855
03856 start_sequence ();
03857
03858
03859 val = targetm.calls.expand_builtin_saveregs ();
03860
03861 seq = get_insns ();
03862 end_sequence ();
03863
03864 saveregs_value = val;
03865
03866
03867
03868
03869 push_topmost_sequence ();
03870 emit_insn_after (seq, entry_of_function ());
03871 pop_topmost_sequence ();
03872
03873 return val;
03874 }
03875
03876
03877
03878
03879
03880 static rtx
03881 expand_builtin_args_info (tree arglist)
03882 {
03883 int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
03884 int *word_ptr = (int *) ¤t_function_args_info;
03885
03886 gcc_assert (sizeof (CUMULATIVE_ARGS) % sizeof (int) == 0);
03887
03888 if (arglist != 0)
03889 {
03890 if (!host_integerp (TREE_VALUE (arglist), 0))
03891 error ("argument of %<__builtin_args_info%> must be constant");
03892 else
03893 {
03894 HOST_WIDE_INT wordnum = tree_low_cst (TREE_VALUE (arglist), 0);
03895
03896 if (wordnum < 0 || wordnum >= nwords)
03897 error ("argument of %<__builtin_args_info%> out of range");
03898 else
03899 return GEN_INT (word_ptr[wordnum]);
03900 }
03901 }
03902 else
03903 error ("missing argument in %<__builtin_args_info%>");
03904
03905 return const0_rtx;
03906 }
03907
03908
03909
03910 static rtx
03911 expand_builtin_next_arg (void)
03912 {
03913
03914
03915 return expand_binop (Pmode, add_optab,
03916 current_function_internal_arg_pointer,
03917 current_function_arg_offset_rtx,
03918 NULL_RTX, 0, OPTAB_LIB_WIDEN);
03919 }
03920
03921
03922
03923
03924 static tree
03925 stabilize_va_list (tree valist, int needs_lvalue)
03926 {
03927 if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
03928 {
03929 if (TREE_SIDE_EFFECTS (valist))
03930 valist = save_expr (valist);
03931
03932
03933
03934
03935
03936 if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
03937 {
03938 tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
03939 valist = build_fold_addr_expr_with_type (valist, p1);
03940 }
03941 }
03942 else
03943 {
03944 tree pt;
03945
03946 if (! needs_lvalue)
03947 {
03948 if (! TREE_SIDE_EFFECTS (valist))
03949 return valist;
03950
03951 pt = build_pointer_type (va_list_type_node);
03952 valist = fold (build1 (ADDR_EXPR, pt, valist));
03953 TREE_SIDE_EFFECTS (valist) = 1;
03954 }
03955
03956 if (TREE_SIDE_EFFECTS (valist))
03957 valist = save_expr (valist);
03958 valist = build_fold_indirect_ref (valist);
03959 }
03960
03961 return valist;
03962 }
03963
03964
03965
03966 tree
03967 std_build_builtin_va_list (void)
03968 {
03969 return ptr_type_node;
03970 }
03971
03972
03973
03974
03975 void
03976 std_expand_builtin_va_start (tree valist, rtx nextarg)
03977 {
03978 tree t;
03979
03980 t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
03981 make_tree (ptr_type_node, nextarg));
03982 TREE_SIDE_EFFECTS (t) = 1;
03983
03984 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
03985 }
03986
03987
03988
03989 static rtx
03990 expand_builtin_va_start (tree arglist)
03991 {
03992 rtx nextarg;
03993 tree chain, valist;
03994
03995 chain = TREE_CHAIN (arglist);
03996
03997 if (!chain)
03998 {
03999 error ("too few arguments to function %<va_start%>");
04000 return const0_rtx;
04001 }
04002
04003 if (fold_builtin_next_arg (chain))
04004 return const0_rtx;
04005
04006 nextarg = expand_builtin_next_arg ();
04007 valist = stabilize_va_list (TREE_VALUE (arglist), 1);
04008
04009 #ifdef EXPAND_BUILTIN_VA_START
04010 EXPAND_BUILTIN_VA_START (valist, nextarg);
04011 #else
04012 std_expand_builtin_va_start (valist, nextarg);
04013 #endif
04014
04015 return const0_rtx;
04016 }
04017
04018
04019
04020
04021 tree
04022 std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
04023 {
04024 tree addr, t, type_size, rounded_size, valist_tmp;
04025 unsigned HOST_WIDE_INT align, boundary;
04026 bool indirect;
04027
04028 #ifdef ARGS_GROW_DOWNWARD
04029
04030
04031
04032 gcc_unreachable ();
04033 #endif
04034
04035 indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);
04036 if (indirect)
04037 type = build_pointer_type (type);
04038
04039 align = PARM_BOUNDARY / BITS_PER_UNIT;
04040 boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type) / BITS_PER_UNIT;
04041
04042
04043 valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
04044
04045
04046
04047 if (boundary > align)
04048 {
04049 t = fold_convert (TREE_TYPE (valist), size_int (boundary - 1));
04050 t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
04051 build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t));
04052 gimplify_and_add (t, pre_p);
04053
04054 t = fold_convert (TREE_TYPE (valist), size_int (-boundary));
04055 t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
04056 build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist_tmp, t));
04057 gimplify_and_add (t, pre_p);
04058 }
04059 else
04060 boundary = align;
04061
04062
04063
04064
04065 boundary *= BITS_PER_UNIT;
04066 if (boundary < TYPE_ALIGN (type))
04067 {
04068 type = build_variant_type_copy (type);
04069 TYPE_ALIGN (type) = boundary;
04070 }
04071
04072
04073 type_size = size_in_bytes (type);
04074 rounded_size = round_up (type_size, align);
04075
04076
04077 gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
04078
04079
04080 addr = valist_tmp;
04081 if (PAD_VARARGS_DOWN && !integer_zerop (rounded_size))
04082 {
04083
04084 t = fold (build2 (GT_EXPR, sizetype, rounded_size, size_int (align)));
04085 t = fold (build3 (COND_EXPR, sizetype, t, size_zero_node,
04086 size_binop (MINUS_EXPR, rounded_size, type_size)));
04087 t = fold_convert (TREE_TYPE (addr), t);
04088 addr = fold (build2 (PLUS_EXPR, TREE_TYPE (addr), addr, t));
04089 }
04090
04091
04092 t = fold_convert (TREE_TYPE (valist), rounded_size);
04093 t = build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t);
04094 t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
04095 gimplify_and_add (t, pre_p);
04096
04097 addr = fold_convert (build_pointer_type (type), addr);
04098
04099 if (indirect)
04100 addr = build_va_arg_indirect_ref (addr);
04101
04102 return build_va_arg_indirect_ref (addr);
04103 }
04104
04105
04106
04107 tree
04108 build_va_arg_indirect_ref (tree addr)
04109 {
04110 addr = build_fold_indirect_ref (addr);
04111
04112 if (flag_mudflap)
04113 mf_mark (addr);
04114
04115 return addr;
04116 }
04117
04118
04119
04120
04121 static tree
04122 dummy_object (tree type)
04123 {
04124 tree t = convert (build_pointer_type (type), null_pointer_node);
04125 return build1 (INDIRECT_REF, type, t);
04126 }
04127
04128
04129
04130
04131 enum gimplify_status
04132 gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
04133 {
04134 tree promoted_type, want_va_type, have_va_type;
04135 tree valist = TREE_OPERAND (*expr_p, 0);
04136 tree type = TREE_TYPE (*expr_p);
04137 tree t;
04138
04139
04140 want_va_type = va_list_type_node;
04141 have_va_type = TREE_TYPE (valist);
04142
04143 if (have_va_type == error_mark_node)
04144 return GS_ERROR;
04145
04146 if (TREE_CODE (want_va_type) == ARRAY_TYPE)
04147 {
04148
04149
04150
04151
04152 if (TREE_CODE (have_va_type) == ARRAY_TYPE
04153 || POINTER_TYPE_P (have_va_type))
04154 {
04155 want_va_type = TREE_TYPE (want_va_type);
04156 have_va_type = TREE_TYPE (have_va_type);
04157 }
04158 }
04159
04160 if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type))
04161 {
04162 error ("first argument to %<va_arg%> not of type %<va_list%>");
04163 return GS_ERROR;
04164 }
04165
04166
04167
04168 else if ((promoted_type = lang_hooks.types.type_promotes_to (type))
04169 != type)
04170 {
04171 static bool gave_help;
04172
04173
04174
04175
04176 warning ("%qT is promoted to %qT when passed through %<...%>",
04177 type, promoted_type);
04178 if (! gave_help)
04179 {
04180 gave_help = true;
04181 warning ("(so you should pass %qT not %qT to %<va_arg%>)",
04182 promoted_type, type);
04183 }
04184
04185
04186
04187 inform ("if this code is reached, the program will abort");
04188 t = build_function_call_expr (implicit_built_in_decls[BUILT_IN_TRAP],
04189 NULL);
04190 append_to_statement_list (t, pre_p);
04191
04192
04193
04194 *expr_p = dummy_object (type);
04195 return GS_ALL_DONE;
04196 }
04197 else
04198 {
04199
04200
04201 if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
04202 {
04203
04204
04205
04206
04207 if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
04208 {
04209 tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
04210 valist = build_fold_addr_expr_with_type (valist, p1);
04211 }
04212 gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
04213 }
04214 else
04215 gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
04216
04217 if (!targetm.gimplify_va_arg_expr)
04218
04219 return GS_ALL_DONE;
04220
04221 *expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p);
04222 return GS_OK;
04223 }
04224 }
04225
04226
04227
04228 static rtx
04229 expand_builtin_va_end (tree arglist)
04230 {
04231 tree valist = TREE_VALUE (arglist);
04232
04233
04234
04235 if (TREE_SIDE_EFFECTS (valist))
04236 expand_expr (valist, const0_rtx, VOIDmode, EXPAND_NORMAL);
04237
04238 return const0_rtx;
04239 }
04240
04241
04242
04243
04244
04245 static rtx
04246 expand_builtin_va_copy (tree arglist)
04247 {
04248 tree dst, src, t;
04249
04250 dst = TREE_VALUE (arglist);
04251 src = TREE_VALUE (TREE_CHAIN (arglist));
04252
04253 dst = stabilize_va_list (dst, 1);
04254 src = stabilize_va_list (src, 0);
04255
04256 if (TREE_CODE (va_list_type_node) != ARRAY_TYPE)
04257 {
04258 t = build2 (MODIFY_EXPR, va_list_type_node, dst, src);
04259 TREE_SIDE_EFFECTS (t) = 1;
04260 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
04261 }
04262 else
04263 {
04264 rtx dstb, srcb, size;
04265
04266
04267 dstb = expand_expr (dst, NULL_RTX, Pmode, EXPAND_NORMAL);
04268 srcb = expand_expr (src, NULL_RTX, Pmode, EXPAND_NORMAL);
04269 size = expand_expr (TYPE_SIZE_UNIT (va_list_type_node), NULL_RTX,
04270 VOIDmode, EXPAND_NORMAL);
04271
04272 dstb = convert_memory_address (Pmode, dstb);
04273 srcb = convert_memory_address (Pmode, srcb);
04274
04275
04276 dstb = gen_rtx_MEM (BLKmode, dstb);
04277 set_mem_alias_set (dstb, get_alias_set (TREE_TYPE (TREE_TYPE (dst))));
04278 set_mem_align (dstb, TYPE_ALIGN (va_list_type_node));
04279 srcb = gen_rtx_MEM (BLKmode, srcb);
04280 set_mem_alias_set (srcb, get_alias_set (TREE_TYPE (TREE_TYPE (src))));
04281 set_mem_align (srcb, TYPE_ALIGN (va_list_type_node));
04282
04283
04284 emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL);
04285 }
04286
04287 return const0_rtx;
04288 }
04289
04290
04291
04292
04293 static rtx
04294 expand_builtin_frame_address (tree fndecl, tree arglist)
04295 {
04296
04297
04298
04299 if (arglist == 0)
04300
04301 return const0_rtx;
04302 else if (! host_integerp (TREE_VALUE (arglist), 1))
04303 {
04304 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
04305 error ("invalid argument to %<__builtin_frame_address%>");
04306 else
04307 error ("invalid argument to %<__builtin_return_address%>");
04308 return const0_rtx;
04309 }
04310 else
04311 {
04312 rtx tem
04313 = expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl),
04314 tree_low_cst (TREE_VALUE (arglist), 1));
04315
04316
04317 if (tem == NULL)
04318 {
04319 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
04320 warning ("unsupported argument to %<__builtin_frame_address%>");
04321 else
04322 warning ("unsupported argument to %<__builtin_return_address%>");
04323 return const0_rtx;
04324 }
04325
04326
04327 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
04328 return tem;
04329
04330 if (!REG_P (tem)
04331 && ! CONSTANT_P (tem))
04332 tem = copy_to_mode_reg (Pmode, tem);
04333 return tem;
04334 }
04335 }
04336
04337
04338
04339
04340
04341 static rtx
04342 expand_builtin_alloca (tree arglist, rtx target)
04343 {
04344 rtx op0;
04345 rtx result;
04346
04347
04348
04349
04350 if (flag_mudflap)
04351 return 0;
04352
04353 if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
04354 return 0;
04355
04356
04357 op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
04358
04359
04360 result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
04361 result = convert_memory_address (ptr_mode, result);
04362
04363 return result;
04364 }
04365
04366
04367
04368
04369
04370
04371 static rtx
04372 expand_builtin_unop (enum machine_mode target_mode, tree arglist, rtx target,
04373 rtx subtarget, optab op_optab)
04374 {
04375 rtx op0;
04376 if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
04377 return 0;
04378
04379
04380 op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
04381
04382
04383 target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
04384 op_optab, op0, target, 1);
04385 gcc_assert (target);
04386
04387 return convert_to_mode (target_mode, target, 0);
04388 }
04389
04390
04391
04392
04393 static rtx
04394 expand_builtin_fputs (tree arglist, rtx target, bool unlocked)
04395 {
04396
04397 if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
04398 {
04399 tree result = fold_builtin_fputs (arglist, (target == const0_rtx),
04400 unlocked, NULL_TREE);
04401 if (result)
04402 return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
04403 }
04404 return 0;
04405 }
04406
04407
04408
04409
04410
04411 static rtx
04412 expand_builtin_expect (tree arglist, rtx target)
04413 {
04414 tree exp, c;
04415 rtx note, rtx_c;
04416
04417 if (arglist == NULL_TREE
04418 || TREE_CHAIN (arglist) == NULL_TREE)
04419 return const0_rtx;
04420 exp = TREE_VALUE (arglist);
04421 c = TREE_VALUE (TREE_CHAIN (arglist));
04422
04423 if (TREE_CODE (c) != INTEGER_CST)
04424 {
04425 error ("second argument to %<__builtin_expect%> must be a constant");
04426 c = integer_zero_node;
04427 }
04428
04429 target = expand_expr (exp, target, VOIDmode, EXPAND_NORMAL);
04430
04431
04432 if (flag_guess_branch_prob && GET_CODE (target) != CONST_INT)
04433 {
04434
04435
04436
04437 target = force_reg (GET_MODE (target), target);
04438
04439 rtx_c = expand_expr (c, NULL_RTX, GET_MODE (target), EXPAND_NORMAL);
04440
04441 note = emit_note (NOTE_INSN_EXPECTED_VALUE);
04442 NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, target, rtx_c);
04443 }
04444
04445 return target;
04446 }
04447
04448
04449
04450
04451
04452
04453
04454
04455 rtx
04456 expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label)
04457 {
04458 tree arglist = TREE_OPERAND (exp, 1);
04459 tree arg0 = TREE_VALUE (arglist);
04460 tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
04461 rtx ret = NULL_RTX;
04462
04463
04464
04465 if (TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE
04466 && (integer_zerop (arg1) || integer_onep (arg1)))
04467 {
04468 rtx insn, drop_through_label, temp;
04469
04470
04471 start_sequence ();
04472 do_jump (arg0, if_false_label, if_true_label);
04473 ret = get_insns ();
04474
04475 drop_through_label = get_last_insn ();
04476 if (drop_through_label && NOTE_P (drop_through_label))
04477 drop_through_label = prev_nonnote_insn (drop_through_label);
04478 if (drop_through_label && !LABEL_P (drop_through_label))
04479 drop_through_label = NULL_RTX;
04480 end_sequence ();
04481
04482 if (! if_true_label)
04483 if_true_label = drop_through_label;
04484 if (! if_false_label)
04485 if_false_label = drop_through_label;
04486
04487
04488 insn = ret;
04489 while (insn != NULL_RTX)
04490 {
04491 rtx next = NEXT_INSN (insn);
04492
04493 if (JUMP_P (insn) && any_condjump_p (insn))
04494 {
04495 rtx ifelse = SET_SRC (pc_set (insn));
04496 rtx then_dest = XEXP (ifelse, 1);
04497 rtx else_dest = XEXP (ifelse, 2);
04498 int taken = -1;
04499
04500
04501 if (GET_CODE (then_dest) == LABEL_REF
04502 && XEXP (then_dest, 0) == if_true_label)
04503 taken = 1;
04504 else if (GET_CODE (then_dest) == LABEL_REF
04505 && XEXP (then_dest, 0) == if_false_label)
04506 taken = 0;
04507 else if (GET_CODE (else_dest) == LABEL_REF
04508 && XEXP (else_dest, 0) == if_false_label)
04509 taken = 1;
04510 else if (GET_CODE (else_dest) == LABEL_REF
04511 && XEXP (else_dest, 0) == if_true_label)
04512 taken = 0;
04513
04514 else if (else_dest == pc_rtx)
04515 {
04516 if (next && NOTE_P (next))
04517 next = next_nonnote_insn (next);
04518
04519 if (next && JUMP_P (next)
04520 && any_uncondjump_p (next))
04521 temp = XEXP (SET_SRC (pc_set (next)), 0);
04522 else
04523 temp = next;
04524
04525
04526
04527 if (temp == if_false_label)
04528 taken = 1;
04529 else if (temp == if_true_label)
04530 taken = 0;
04531 }
04532 else if (then_dest == pc_rtx)
04533 {
04534 if (next && NOTE_P (next))
04535 next = next_nonnote_insn (next);
04536
04537 if (next && JUMP_P (next)
04538 && any_uncondjump_p (next))
04539 temp = XEXP (SET_SRC (pc_set (next)), 0);
04540 else
04541 temp = next;
04542
04543 if (temp == if_false_label)
04544 taken = 0;
04545 else if (temp == if_true_label)
04546 taken = 1;
04547 }
04548
04549 if (taken != -1)
04550 {
04551
04552
04553 if (integer_zerop (arg1))
04554 taken = 1 - taken;
04555 predict_insn_def (insn, PRED_BUILTIN_EXPECT, taken);
04556 }
04557 }
04558
04559 insn = next;
04560 }
04561 }
04562
04563 return ret;
04564 }
04565
04566 static void
04567 expand_builtin_trap (void)
04568 {
04569 #ifdef HAVE_trap
04570 if (HAVE_trap)
04571 emit_insn (gen_trap ());
04572 else
04573 #endif
04574 emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
04575 emit_barrier ();
04576 }
04577
04578
04579
04580
04581
04582
04583
04584 static rtx
04585 expand_builtin_fabs (tree arglist, rtx target, rtx subtarget)
04586 {
04587 enum machine_mode mode;
04588 tree arg;
04589 rtx op0;
04590
04591 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
04592 return 0;
04593
04594 arg = TREE_VALUE (arglist);
04595 mode = TYPE_MODE (TREE_TYPE (arg));
04596 op0 = expand_expr (arg, subtarget, VOIDmode, 0);
04597 return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
04598 }
04599
04600
04601
04602
04603
04604
04605 static rtx
04606 expand_builtin_copysign (tree arglist, rtx target, rtx subtarget)
04607 {
04608 rtx op0, op1;
04609 tree arg;
04610
04611 if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
04612 return 0;
04613
04614 arg = TREE_VALUE (arglist);
04615 op0 = expand_expr (arg, subtarget, VOIDmode, 0);
04616
04617 arg = TREE_VALUE (TREE_CHAIN (arglist));
04618 op1 = expand_expr (arg, NULL, VOIDmode, 0);
04619
04620 return expand_copysign (op0, op1, target);
04621 }
04622
04623
04624
04625 static tree
04626 build_string_literal (int len, const char *str)
04627 {
04628 tree t, elem, index, type;
04629
04630 t = build_string (len, str);
04631 elem = build_type_variant (char_type_node, 1, 0);
04632 index = build_index_type (build_int_cst (NULL_TREE, len - 1));
04633 type = build_array_type (elem, index);
04634 TREE_TYPE (t) = type;
04635 TREE_CONSTANT (t) = 1;
04636 TREE_INVARIANT (t) = 1;
04637 TREE_READONLY (t) = 1;
04638 TREE_STATIC (t) = 1;
04639
04640 type = build_pointer_type (type);
04641 t = build1 (ADDR_EXPR, type, t);
04642
04643 type = build_pointer_type (elem);
04644 t = build1 (NOP_EXPR, type, t);
04645 return t;
04646 }
04647
04648
04649
04650
04651
04652
04653 static rtx
04654 expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
04655 bool unlocked)
04656 {
04657 tree arglist = TREE_OPERAND (exp, 1);
04658 tree fn_putchar = unlocked
04659 ? implicit_built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED]
04660 : implicit_built_in_decls[BUILT_IN_PUTCHAR];
04661 tree fn_puts = unlocked ? implicit_built_in_decls[BUILT_IN_PUTS_UNLOCKED]
04662 : implicit_built_in_decls[BUILT_IN_PUTS];
04663 const char *fmt_str;
04664 tree fn, fmt, arg;
04665
04666
04667 if (target != const0_rtx)
04668 return 0;
04669
04670
04671 if (! arglist)
04672 return 0;
04673 fmt = TREE_VALUE (arglist);
04674 if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
04675 return 0;
04676 arglist = TREE_CHAIN (arglist);
04677
04678
04679 fmt_str = c_getstr (fmt);
04680 if (fmt_str == NULL)
04681 return 0;
04682
04683
04684 if (strcmp (fmt_str, "%s\n") == 0)
04685 {
04686 if (! arglist
04687 || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
04688 || TREE_CHAIN (arglist))
04689 return 0;
04690 fn = fn_puts;
04691 }
04692
04693 else if (strcmp (fmt_str, "%c") == 0)
04694 {
04695 if (! arglist
04696 || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
04697 || TREE_CHAIN (arglist))
04698 return 0;
04699 fn = fn_putchar;
04700 }
04701 else
04702 {
04703
04704 if (strchr (fmt_str, '%'))
04705 return 0;
04706
04707 if (arglist)
04708 return 0;
04709
04710
04711 if (fmt_str[0] == '\0')
04712 return const0_rtx;
04713
04714 if (fmt_str[1] == '\0')
04715 {
04716
04717
04718
04719 arg = build_int_cst (NULL_TREE, fmt_str[0]);
04720 arglist = build_tree_list (NULL_TREE, arg);
04721 fn = fn_putchar;
04722 }
04723 else
04724 {
04725
04726 size_t len = strlen (fmt_str);
04727 if (fmt_str[len - 1] == '\n')
04728 {
04729
04730
04731 char *newstr = alloca (len);
04732 memcpy (newstr, fmt_str, len - 1);
04733 newstr[len - 1] = 0;
04734
04735 arg = build_string_literal (len, newstr);
04736 arglist = build_tree_list (NULL_TREE, arg);
04737 fn = fn_puts;
04738 }
04739 else
04740
04741
04742 return 0;
04743 }
04744 }
04745
04746 if (!fn)
04747 return 0;
04748 fn = build_function_call_expr (fn, arglist);
04749 if (TREE_CODE (fn) == CALL_EXPR)
04750 CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
04751 return expand_expr (fn, target, mode, EXPAND_NORMAL);
04752 }
04753
04754
04755
04756
04757
04758
04759 static rtx
04760 expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode,
04761 bool unlocked)
04762 {
04763 tree arglist = TREE_OPERAND (exp, 1);
04764 tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
04765 : implicit_built_in_decls[BUILT_IN_FPUTC];
04766 tree fn_fputs = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTS_UNLOCKED]
04767 : implicit_built_in_decls[BUILT_IN_FPUTS];
04768 const char *fmt_str;
04769 tree fn, fmt, fp, arg;
04770
04771
04772 if (target != const0_rtx)
04773 return 0;
04774
04775
04776 if (! arglist)
04777 return 0;
04778 fp = TREE_VALUE (arglist);
04779 if (! POINTER_TYPE_P (TREE_TYPE (fp)))
04780 return 0;
04781 arglist = TREE_CHAIN (arglist);
04782 if (! arglist)
04783 return 0;
04784 fmt = TREE_VALUE (arglist);
04785 if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
04786 return 0;
04787 arglist = TREE_CHAIN (arglist);
04788
04789
04790 fmt_str = c_getstr (fmt);
04791 if (fmt_str == NULL)
04792 return 0;
04793
04794
04795 if (strcmp (fmt_str, "%s") == 0)
04796 {
04797 if (! arglist
04798 || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
04799 || TREE_CHAIN (arglist))
04800 return 0;
04801 arg = TREE_VALUE (arglist);
04802 arglist = build_tree_list (NULL_TREE, fp);
04803 arglist = tree_cons (NULL_TREE, arg, arglist);
04804 fn = fn_fputs;
04805 }
04806
04807 else if (strcmp (fmt_str, "%c") == 0)
04808 {
04809 if (! arglist
04810 || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
04811 || TREE_CHAIN (arglist))
04812 return 0;
04813 arg = TREE_VALUE (arglist);
04814 arglist = build_tree_list (NULL_TREE, fp);
04815 arglist = tree_cons (NULL_TREE, arg, arglist);
04816 fn = fn_fputc;
04817 }
04818 else
04819 {
04820
04821 if (strchr (fmt_str, '%'))
04822 return 0;
04823
04824 if (arglist)
04825 return 0;
04826
04827
04828 if (fmt_str[0] == '\0')
04829 {
04830
04831 expand_expr (fp, const0_rtx, VOIDmode, EXPAND_NORMAL);
04832 return const0_rtx;
04833 }
04834
04835
04836
04837
04838 arglist = build_tree_list (NULL_TREE, fp);
04839 arglist = tree_cons (NULL_TREE, fmt, arglist);
04840 fn = fn_fputs;
04841 }
04842
04843 if (!fn)
04844 return 0;
04845 fn = build_function_call_expr (fn, arglist);
04846 if (TREE_CODE (fn) == CALL_EXPR)
04847 CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
04848 return expand_expr (fn, target, mode, EXPAND_NORMAL);
04849 }
04850
04851
04852
04853
04854
04855
04856 static rtx
04857 expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode)
04858 {
04859 tree orig_arglist, dest, fmt;
04860 const char *fmt_str;
04861
04862 orig_arglist = arglist;
04863
04864
04865 if (! arglist)
04866 return 0;
04867 dest = TREE_VALUE (arglist);
04868 if (! POINTER_TYPE_P (TREE_TYPE (dest)))
04869 return 0;
04870 arglist = TREE_CHAIN (arglist);
04871 if (! arglist)
04872 return 0;
04873 fmt = TREE_VALUE (arglist);
04874 if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
04875 return 0;
04876 arglist = TREE_CHAIN (arglist);
04877
04878
04879 fmt_str = c_getstr (fmt);
04880 if (fmt_str == NULL)
04881 return 0;
04882
04883
04884 if (strchr (fmt_str, '%') == 0)
04885 {
04886 tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
04887 tree exp;
04888
04889 if (arglist || ! fn)
04890 return 0;
04891 expand_expr (build_function_call_expr (fn, orig_arglist),
04892 const0_rtx, VOIDmode, EXPAND_NORMAL);
04893 if (target == const0_rtx)
04894 return const0_rtx;
04895 exp = build_int_cst (NULL_TREE, strlen (fmt_str));
04896 return expand_expr (exp, target, mode, EXPAND_NORMAL);
04897 }
04898
04899 else if (strcmp (fmt_str, "%s") == 0)
04900 {
04901 tree fn, arg, len;
04902 fn = implicit_built_in_decls[BUILT_IN_STRCPY];
04903
04904 if (! fn)
04905 return 0;
04906
04907 if (! arglist || TREE_CHAIN (arglist))
04908 return 0;
04909 arg = TREE_VALUE (arglist);
04910 if (! POINTER_TYPE_P (TREE_TYPE (arg)))
04911 return 0;
04912
04913 if (target != const0_rtx)
04914 {
04915 len = c_strlen (arg, 1);
04916 if (! len || TREE_CODE (len) != INTEGER_CST)
04917 return 0;
04918 }
04919 else
04920 len = NULL_TREE;
04921
04922 arglist = build_tree_list (NULL_TREE, arg);
04923 arglist = tree_cons (NULL_TREE, dest, arglist);
04924 expand_expr (build_function_call_expr (fn, arglist),
04925 const0_rtx, VOIDmode, EXPAND_NORMAL);
04926
04927 if (target == const0_rtx)
04928 return const0_rtx;
04929 return expand_expr (len, target, mode, EXPAND_NORMAL);
04930 }
04931
04932 return 0;
04933 }
04934
04935
04936
04937 static rtx
04938 expand_builtin_profile_func (bool exitp)
04939 {
04940 rtx this, which;
04941
04942 this = DECL_RTL (current_function_decl);
04943 gcc_assert (MEM_P (this));
04944 this = XEXP (this, 0);
04945
04946 if (exitp)
04947 which = profile_function_exit_libfunc;
04948 else
04949 which = profile_function_entry_libfunc;
04950
04951 emit_library_call (which, LCT_NORMAL, VOIDmode, 2, this, Pmode,
04952 expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
04953 0),
04954 Pmode);
04955
04956 return const0_rtx;
04957 }
04958
04959
04960
04961 static rtx
04962 round_trampoline_addr (rtx tramp)
04963 {
04964 rtx temp, addend, mask;
04965
04966
04967
04968 if (TRAMPOLINE_ALIGNMENT <= STACK_BOUNDARY)
04969 return tramp;
04970
04971
04972 temp = gen_reg_rtx (Pmode);
04973 addend = GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1);
04974 mask = GEN_INT (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
04975
04976 temp = expand_simple_binop (Pmode, PLUS, tramp, addend,
04977 temp, 0, OPTAB_LIB_WIDEN);
04978 tramp = expand_simple_binop (Pmode, AND, temp, mask,
04979 temp, 0, OPTAB_LIB_WIDEN);
04980
04981 return tramp;
04982 }
04983
04984 static rtx
04985 expand_builtin_init_trampoline (tree arglist)
04986 {
04987 tree t_tramp, t_func, t_chain;
04988 rtx r_tramp, r_func, r_chain;
04989 #ifdef TRAMPOLINE_TEMPLATE
04990 rtx blktramp;
04991 #endif
04992
04993 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE,
04994 POINTER_TYPE, VOID_TYPE))
04995 return NULL_RTX;
04996
04997 t_tramp = TREE_VALUE (arglist);
04998 arglist = TREE_CHAIN (arglist);
04999 t_func = TREE_VALUE (arglist);
05000 arglist = TREE_CHAIN (arglist);
05001 t_chain = TREE_VALUE (arglist);
05002
05003 r_tramp = expand_expr (t_tramp, NULL_RTX, VOIDmode, 0);
05004 r_func = expand_expr (t_func, NULL_RTX, VOIDmode, 0);
05005 r_chain = expand_expr (t_chain, NULL_RTX, VOIDmode, 0);
05006
05007
05008 r_tramp = round_trampoline_addr (r_tramp);
05009 #ifdef TRAMPOLINE_TEMPLATE
05010 blktramp = gen_rtx_MEM (BLKmode, r_tramp);
05011 set_mem_align (blktramp, TRAMPOLINE_ALIGNMENT);
05012 emit_block_move (blktramp, assemble_trampoline_template (),
05013 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
05014 #endif
05015 trampolines_created = 1;
05016 INITIALIZE_TRAMPOLINE (r_tramp, r_func, r_chain);
05017
05018 return const0_rtx;
05019 }
05020
05021 static rtx
05022 expand_builtin_adjust_trampoline (tree arglist)
05023 {
05024 rtx tramp;
05025
05026 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
05027 return NULL_RTX;
05028
05029 tramp = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
05030 tramp = round_trampoline_addr (tramp);
05031 #ifdef TRAMPOLINE_ADJUST_ADDRESS
05032 TRAMPOLINE_ADJUST_ADDRESS (tramp);
05033 #endif
05034
05035 return tramp;
05036 }
05037
05038
05039
05040
05041
05042
05043 static rtx
05044 expand_builtin_signbit (tree exp, rtx target)
05045 {
05046 const struct real_format *fmt;
05047 enum machine_mode fmode, imode, rmode;
05048 HOST_WIDE_INT hi, lo;
05049 tree arg, arglist;
05050 int bitpos;
05051 rtx temp;
05052
05053 arglist = TREE_OPERAND (exp, 1);
05054 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
05055 return 0;
05056
05057 arg = TREE_VALUE (arglist);
05058 fmode = TYPE_MODE (TREE_TYPE (arg));
05059 rmode = TYPE_MODE (TREE_TYPE (exp));
05060 fmt = REAL_MODE_FORMAT (fmode);
05061
05062
05063
05064 if (fmt->signbit < 0)
05065 {
05066
05067 if (fmt->has_signed_zero && HONOR_SIGNED_ZEROS (fmode))
05068 return 0;
05069
05070 arg = fold (build2 (LT_EXPR, TREE_TYPE (exp), arg,
05071 build_real (TREE_TYPE (arg), dconst0)));
05072 return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
05073 }
05074
05075 imode = int_mode_for_mode (fmode);
05076 if (imode == BLKmode)
05077 return 0;
05078
05079 bitpos = fmt->signbit;
05080
05081 if (FLOAT_WORDS_BIG_ENDIAN != WORDS_BIG_ENDIAN)
05082 {
05083 int nwords = GET_MODE_BITSIZE (fmode) / BITS_PER_WORD;
05084 int word = nwords - (bitpos / BITS_PER_WORD) - 1;
05085 bitpos = word * BITS_PER_WORD + bitpos % BITS_PER_WORD;
05086 }
05087
05088
05089
05090
05091 if (bitpos >= GET_MODE_BITSIZE (rmode)
05092 && GET_MODE_BITSIZE (imode) != 2 * GET_MODE_BITSIZE (rmode))
05093 return 0;
05094
05095 temp = expand_expr (arg, NULL_RTX, VOIDmode, 0);
05096 temp = gen_lowpart (imode, temp);
05097
05098 if (GET_MODE_BITSIZE (imode) > GET_MODE_BITSIZE (rmode))
05099 {
05100 if (BYTES_BIG_ENDIAN)
05101 bitpos = GET_MODE_BITSIZE (imode) - 1 - bitpos;
05102 temp = copy_to_mode_reg (imode, temp);
05103 temp = extract_bit_field (temp, 1, bitpos, 1,
05104 NULL_RTX, rmode, rmode);
05105 }
05106 else
05107 {
05108 if (GET_MODE_BITSIZE (imode) < GET_MODE_BITSIZE (rmode))
05109 temp = gen_lowpart (rmode, temp);
05110 if (bitpos < HOST_BITS_PER_WIDE_INT)
05111 {
05112 hi = 0;
05113 lo = (HOST_WIDE_INT) 1 << bitpos;
05114 }
05115 else
05116 {
05117 hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
05118 lo = 0;
05119 }
05120
05121 temp = force_reg (rmode, temp);
05122 temp = expand_binop (rmode, and_optab, temp,
05123 immed_double_const (lo, hi, rmode),
05124 target, 1, OPTAB_LIB_WIDEN);
05125 }
05126 return temp;
05127 }
05128
05129
05130
05131
05132
05133
05134 static rtx
05135 expand_builtin_fork_or_exec (tree fn, tree arglist, rtx target, int ignore)
05136 {
05137 tree id, decl;
05138 tree call;
05139
05140
05141 if (!profile_arc_flag)
05142 return NULL_RTX;
05143
05144
05145
05146
05147
05148 switch (DECL_FUNCTION_CODE (fn))
05149 {
05150 case BUILT_IN_FORK:
05151 id = get_identifier ("__gcov_fork");
05152 break;
05153
05154 case BUILT_IN_EXECL:
05155 id = get_identifier ("__gcov_execl");
05156 break;
05157
05158 case BUILT_IN_EXECV:
05159 id = get_identifier ("__gcov_execv");
05160 break;
05161
05162 case BUILT_IN_EXECLP:
05163 id = get_identifier ("__gcov_execlp");
05164 break;
05165
05166 case BUILT_IN_EXECLE:
05167 id = get_identifier ("__gcov_execle");
05168 break;
05169
05170 case BUILT_IN_EXECVP:
05171 id = get_identifier ("__gcov_execvp");
05172 break;
05173
05174 case BUILT_IN_EXECVE:
05175 id = get_identifier ("__gcov_execve");
05176 break;
05177
05178 default:
05179 gcc_unreachable ();
05180 }
05181
05182 decl = build_decl (FUNCTION_DECL, id, TREE_TYPE (fn));
05183 DECL_EXTERNAL (decl) = 1;
05184 TREE_PUBLIC (decl) = 1;
05185 DECL_ARTIFICIAL (decl) = 1;
05186 TREE_NOTHROW (decl) = 1;
05187 call = build_function_call_expr (decl, arglist);
05188
05189 return expand_call (call, target, ignore);
05190 }
05191
05192
05193
05194
05195
05196
05197
05198 rtx
05199 expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
05200 int ignore)
05201 {
05202 tree fndecl = get_callee_fndecl (exp);
05203 tree arglist = TREE_OPERAND (exp, 1);
05204 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
05205 enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
05206
05207 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
05208 return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
05209
05210
05211
05212 if (!optimize
05213 && !CALLED_AS_BUILT_IN (fndecl)
05214 && DECL_ASSEMBLER_NAME_SET_P (fndecl)
05215 && fcode != BUILT_IN_ALLOCA)
05216 return expand_call (exp, target, ignore);
05217
05218
05219
05220 if (ignore)
05221 target = const0_rtx;
05222
05223
05224
05225
05226 if (target == const0_rtx
05227 && (DECL_IS_PURE (fndecl) || TREE_READONLY (fndecl)))
05228 {
05229 bool volatilep = false;
05230 tree arg;
05231
05232 for (arg = arglist; arg; arg = TREE_CHAIN (arg))
05233 if (TREE_THIS_VOLATILE (TREE_VALUE (arg)))
05234 {
05235 volatilep = true;
05236 break;
05237 }
05238
05239 if (! volatilep)
05240 {
05241 for (arg = arglist; arg; arg = TREE_CHAIN (arg))
05242 expand_expr (TREE_VALUE (arg), const0_rtx,
05243 VOIDmode, EXPAND_NORMAL);
05244 return const0_rtx;
05245 }
05246 }
05247
05248 switch (fcode)
05249 {
05250 case BUILT_IN_FABS:
05251 case BUILT_IN_FABSF:
05252 case BUILT_IN_FABSL:
05253 target = expand_builtin_fabs (arglist, target, subtarget);
05254 if (target)
05255 return target;
05256 break;
05257
05258 case BUILT_IN_COPYSIGN:
05259 case BUILT_IN_COPYSIGNF:
05260 case BUILT_IN_COPYSIGNL:
05261 target = expand_builtin_copysign (arglist, target, subtarget);
05262 if (target)
05263 return target;
05264 break;
05265
05266
05267
05268 case BUILT_IN_CABS:
05269 case BUILT_IN_CABSF:
05270 case BUILT_IN_CABSL:
05271 break;
05272
05273 case BUILT_IN_EXP:
05274 case BUILT_IN_EXPF:
05275 case BUILT_IN_EXPL:
05276 case BUILT_IN_EXP10:
05277 case BUILT_IN_EXP10F:
05278 case BUILT_IN_EXP10L:
05279 case BUILT_IN_POW10:
05280 case BUILT_IN_POW10F:
05281 case BUILT_IN_POW10L:
05282 case BUILT_IN_EXP2:
05283 case BUILT_IN_EXP2F:
05284 case BUILT_IN_EXP2L:
05285 case BUILT_IN_EXPM1:
05286 case BUILT_IN_EXPM1F:
05287 case BUILT_IN_EXPM1L:
05288 case BUILT_IN_LOGB:
05289 case BUILT_IN_LOGBF:
05290 case BUILT_IN_LOGBL:
05291 case BUILT_IN_ILOGB:
05292 case BUILT_IN_ILOGBF:
05293 case BUILT_IN_ILOGBL:
05294 case BUILT_IN_LOG:
05295 case BUILT_IN_LOGF:
05296 case BUILT_IN_LOGL:
05297 case BUILT_IN_LOG10:
05298 case BUILT_IN_LOG10F:
05299 case BUILT_IN_LOG10L:
05300 case BUILT_IN_LOG2:
05301 case BUILT_IN_LOG2F:
05302 case BUILT_IN_LOG2L:
05303 case BUILT_IN_LOG1P:
05304 case BUILT_IN_LOG1PF:
05305 case BUILT_IN_LOG1PL:
05306 case BUILT_IN_TAN:
05307 case BUILT_IN_TANF:
05308 case BUILT_IN_TANL:
05309 case BUILT_IN_ASIN:
05310 case BUILT_IN_ASINF:
05311 case BUILT_IN_ASINL:
05312 case BUILT_IN_ACOS:
05313 case BUILT_IN_ACOSF:
05314 case BUILT_IN_ACOSL:
05315 case BUILT_IN_ATAN:
05316 case BUILT_IN_ATANF:
05317 case BUILT_IN_ATANL:
05318
05319
05320 if (! flag_unsafe_math_optimizations)
05321 break;
05322 case BUILT_IN_SQRT:
05323 case BUILT_IN_SQRTF:
05324 case BUILT_IN_SQRTL:
05325 case BUILT_IN_FLOOR:
05326 case BUILT_IN_FLOORF:
05327 case BUILT_IN_FLOORL:
05328 case BUILT_IN_CEIL:
05329 case BUILT_IN_CEILF:
05330 case BUILT_IN_CEILL:
05331 case BUILT_IN_TRUNC:
05332 case BUILT_IN_TRUNCF:
05333 case BUILT_IN_TRUNCL:
05334 case BUILT_IN_ROUND:
05335 case BUILT_IN_ROUNDF:
05336 case BUILT_IN_ROUNDL:
05337 case BUILT_IN_NEARBYINT:
05338 case BUILT_IN_NEARBYINTF:
05339 case BUILT_IN_NEARBYINTL:
05340 case BUILT_IN_RINT:
05341 case BUILT_IN_RINTF:
05342 case BUILT_IN_RINTL:
05343 target = expand_builtin_mathfn (exp, target, subtarget);
05344 if (target)
05345 return target;
05346 break;
05347
05348 case BUILT_IN_POW:
05349 case BUILT_IN_POWF:
05350 case BUILT_IN_POWL:
05351 target = expand_builtin_pow (exp, target, subtarget);
05352 if (target)
05353 return target;
05354 break;
05355
05356 case BUILT_IN_POWI:
05357 case BUILT_IN_POWIF:
05358 case BUILT_IN_POWIL:
05359 target = expand_builtin_powi (exp, target, subtarget);
05360 if (target)
05361 return target;
05362 break;
05363
05364 case BUILT_IN_ATAN2:
05365 case BUILT_IN_ATAN2F:
05366 case BUILT_IN_ATAN2L:
05367 case BUILT_IN_LDEXP:
05368 case BUILT_IN_LDEXPF:
05369 case BUILT_IN_LDEXPL:
05370 case BUILT_IN_FMOD:
05371 case BUILT_IN_FMODF:
05372 case BUILT_IN_FMODL:
05373 case BUILT_IN_DREM:
05374 case BUILT_IN_DREMF:
05375 case BUILT_IN_DREML:
05376 if (! flag_unsafe_math_optimizations)
05377 break;
05378 target = expand_builtin_mathfn_2 (exp, target, subtarget);
05379 if (target)
05380 return target;
05381 break;
05382
05383 case BUILT_IN_SIN:
05384 case BUILT_IN_SINF:
05385 case BUILT_IN_SINL:
05386 case BUILT_IN_COS:
05387 case BUILT_IN_COSF:
05388 case BUILT_IN_COSL:
05389 if (! flag_unsafe_math_optimizations)
05390 break;
05391 target = expand_builtin_mathfn_3 (exp, target, subtarget);
05392 if (target)
05393 return target;
05394 break;
05395
05396 case BUILT_IN_APPLY_ARGS:
05397 return expand_builtin_apply_args ();
05398
05399
05400
05401
05402
05403
05404
05405
05406
05407
05408
05409 case BUILT_IN_APPLY:
05410 if (!validate_arglist (arglist, POINTER_TYPE,
05411 POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
05412 && !validate_arglist (arglist, REFERENCE_TYPE,
05413 POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
05414 return const0_rtx;
05415 else
05416 {
05417 int i;
05418 tree t;
05419 rtx ops[3];
05420
05421 for (t = arglist, i = 0; t; t = TREE_CHAIN (t), i++)
05422 ops[i] = expand_expr (TREE_VALUE (t), NULL_RTX, VOIDmode, 0);
05423
05424 return expand_builtin_apply (ops[0], ops[1], ops[2]);
05425 }
05426
05427
05428
05429
05430 case BUILT_IN_RETURN:
05431 if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
05432 expand_builtin_return (expand_expr (TREE_VALUE (arglist),
05433 NULL_RTX, VOIDmode, 0));
05434 return const0_rtx;
05435
05436 case BUILT_IN_SAVEREGS:
05437 return expand_builtin_saveregs ();
05438
05439 case BUILT_IN_ARGS_INFO:
05440 return expand_builtin_args_info (arglist);
05441
05442
05443 case BUILT_IN_NEXT_ARG:
05444 if (fold_builtin_next_arg (arglist))
05445 return const0_rtx;
05446 return expand_builtin_next_arg ();
05447
05448 case BUILT_IN_CLASSIFY_TYPE:
05449 return expand_builtin_classify_type (arglist);
05450
05451 case BUILT_IN_CONSTANT_P:
05452 return const0_rtx;
05453
05454 case BUILT_IN_FRAME_ADDRESS:
05455 case BUILT_IN_RETURN_ADDRESS:
05456 return expand_builtin_frame_address (fndecl, arglist);
05457
05458
05459
05460 case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
05461 if (arglist != 0
05462 || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
05463 || !MEM_P (DECL_RTL (DECL_RESULT (current_function_decl))))
05464 return const0_rtx;
05465 else
05466 return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
05467
05468 case BUILT_IN_ALLOCA:
05469 target = expand_builtin_alloca (arglist, target);
05470 if (target)
05471 return target;
05472 break;
05473
05474 case BUILT_IN_STACK_SAVE:
05475 return expand_stack_save ();
05476
05477 case BUILT_IN_STACK_RESTORE:
05478 expand_stack_restore (TREE_VALUE (arglist));
05479 return const0_rtx;
05480
05481 case BUILT_IN_FFS:
05482 case BUILT_IN_FFSL:
05483 case BUILT_IN_FFSLL:
05484 case BUILT_IN_FFSIMAX:
05485 target = expand_builtin_unop (target_mode, arglist, target,
05486 subtarget, ffs_optab);
05487 if (target)
05488 return target;
05489 break;
05490
05491 case BUILT_IN_CLZ:
05492 case BUILT_IN_CLZL:
05493 case BUILT_IN_CLZLL:
05494 case BUILT_IN_CLZIMAX:
05495 target = expand_builtin_unop (target_mode, arglist, target,
05496 subtarget, clz_optab);
05497 if (target)
05498 return target;
05499 break;
05500
05501 case BUILT_IN_CTZ:
05502 case BUILT_IN_CTZL:
05503 case BUILT_IN_CTZLL:
05504 case BUILT_IN_CTZIMAX:
05505 target = expand_builtin_unop (target_mode, arglist, target,
05506 subtarget, ctz_optab);
05507 if (target)
05508 return target;
05509 break;
05510
05511 case BUILT_IN_POPCOUNT:
05512 case BUILT_IN_POPCOUNTL:
05513 case BUILT_IN_POPCOUNTLL:
05514 case BUILT_IN_POPCOUNTIMAX:
05515 target = expand_builtin_unop (target_mode, arglist, target,
05516 subtarget, popcount_optab);
05517 if (target)
05518 return target;
05519 break;
05520
05521 case BUILT_IN_PARITY:
05522 case BUILT_IN_PARITYL:
05523 case BUILT_IN_PARITYLL:
05524 case BUILT_IN_PARITYIMAX:
05525 target = expand_builtin_unop (target_mode, arglist, target,
05526 subtarget, parity_optab);
05527 if (target)
05528 return target;
05529 break;
05530
05531 case BUILT_IN_STRLEN:
05532 target = expand_builtin_strlen (arglist, target, target_mode);
05533 if (target)
05534 return target;
05535 break;
05536
05537 case BUILT_IN_STRCPY:
05538 target = expand_builtin_strcpy (exp, target, mode);
05539 if (target)
05540 return target;
05541 break;
05542
05543 case BUILT_IN_STRNCPY:
05544 target = expand_builtin_strncpy (exp, target, mode);
05545 if (target)
05546 return target;
05547 break;
05548
05549 case BUILT_IN_STPCPY:
05550 target = expand_builtin_stpcpy (exp, target, mode);
05551 if (target)
05552 return target;
05553 break;
05554
05555 case BUILT_IN_STRCAT:
05556 target = expand_builtin_strcat (arglist, TREE_TYPE (exp), target, mode);
05557 if (target)
05558 return target;
05559 break;
05560
05561 case BUILT_IN_STRNCAT:
05562 target = expand_builtin_strncat (arglist, target, mode);
05563 if (target)
05564 return target;
05565 break;
05566
05567 case BUILT_IN_STRSPN:
05568 target = expand_builtin_strspn (arglist, target, mode);
05569 if (target)
05570 return target;
05571 break;
05572
05573 case BUILT_IN_STRCSPN:
05574 target = expand_builtin_strcspn (arglist, target, mode);
05575 if (target)
05576 return target;
05577 break;
05578
05579 case BUILT_IN_STRSTR:
05580 target = expand_builtin_strstr (arglist, TREE_TYPE (exp), target, mode);
05581 if (target)
05582 return target;
05583 break;
05584
05585 case BUILT_IN_STRPBRK:
05586 target = expand_builtin_strpbrk (arglist, TREE_TYPE (exp), target, mode);
05587 if (target)
05588 return target;
05589 break;
05590
05591 case BUILT_IN_INDEX:
05592 case BUILT_IN_STRCHR:
05593 target = expand_builtin_strchr (arglist, TREE_TYPE (exp), target, mode);
05594 if (target)
05595 return target;
05596 break;
05597
05598 case BUILT_IN_RINDEX:
05599 case BUILT_IN_STRRCHR:
05600 target = expand_builtin_strrchr (arglist, TREE_TYPE (exp), target, mode);
05601 if (target)
05602 return target;
05603 break;
05604
05605 case BUILT_IN_MEMCPY:
05606 target = expand_builtin_memcpy (exp, target, mode);
05607 if (target)
05608 return target;
05609 break;
05610
05611 case BUILT_IN_MEMPCPY:
05612 target = expand_builtin_mempcpy (arglist, TREE_TYPE (exp), target, mode, 1);
05613 if (target)
05614 return target;
05615 break;
05616
05617 case BUILT_IN_MEMMOVE:
05618 target = expand_builtin_memmove (arglist, TREE_TYPE (exp), target,
05619 mode, exp);
05620 if (target)
05621 return target;
05622 break;
05623
05624 case BUILT_IN_BCOPY:
05625 target = expand_builtin_bcopy (exp);
05626 if (target)
05627 return target;
05628 break;
05629
05630 case BUILT_IN_MEMSET:
05631 target = expand_builtin_memset (arglist, target, mode, exp);
05632 if (target)
05633 return target;
05634 break;
05635
05636 case BUILT_IN_BZERO:
05637 target = expand_builtin_bzero (exp);
05638 if (target)
05639 return target;
05640 break;
05641
05642 case BUILT_IN_STRCMP:
05643 target = expand_builtin_strcmp (exp, target, mode);
05644 if (target)
05645 return target;
05646 break;
05647
05648 case BUILT_IN_STRNCMP:
05649 target = expand_builtin_strncmp (exp, target, mode);
05650 if (target)
05651 return target;
05652 break;
05653
05654 case BUILT_IN_BCMP:
05655 case BUILT_IN_MEMCMP:
05656 target = expand_builtin_memcmp (exp, arglist, target, mode);
05657 if (target)
05658 return target;
05659 break;
05660
05661 case BUILT_IN_SETJMP:
05662 target = expand_builtin_setjmp (arglist, target);
05663 if (target)
05664 return target;
05665 break;
05666
05667
05668
05669
05670 case BUILT_IN_LONGJMP:
05671 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
05672 break;
05673 else
05674 {
05675 rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
05676 VOIDmode, 0);
05677 rtx value = expand_expr (TREE_VALUE (TREE_CHAIN (arglist)),
05678 NULL_RTX, VOIDmode, 0);
05679
05680 if (value != const1_rtx)
05681 {
05682 error ("%<__builtin_longjmp%> second argument must be 1");
05683 return const0_rtx;
05684 }
05685
05686 expand_builtin_longjmp (buf_addr, value);
05687 return const0_rtx;
05688 }
05689
05690 case BUILT_IN_NONLOCAL_GOTO:
05691 target = expand_builtin_nonlocal_goto (arglist);
05692 if (target)
05693 return target;
05694 break;
05695
05696
05697
05698 case BUILT_IN_UPDATE_SETJMP_BUF:
05699 if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
05700 {
05701 rtx buf_addr
05702 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
05703
05704 expand_builtin_update_setjmp_buf (buf_addr);
05705 return const0_rtx;
05706 }
05707 break;
05708
05709 case BUILT_IN_TRAP:
05710 expand_builtin_trap ();
05711 return const0_rtx;
05712
05713 case BUILT_IN_PRINTF:
05714 target = expand_builtin_printf (exp, target, mode, false);
05715 if (target)
05716 return target;
05717 break;
05718
05719 case BUILT_IN_PRINTF_UNLOCKED:
05720 target = expand_builtin_printf (exp, target, mode, true);
05721 if (target)
05722 return target;
05723 break;
05724
05725 case BUILT_IN_FPUTS:
05726 target = expand_builtin_fputs (arglist, target, false);
05727 if (target)
05728 return target;
05729 break;
05730 case BUILT_IN_FPUTS_UNLOCKED:
05731 target = expand_builtin_fputs (arglist, target, true);
05732 if (target)
05733 return target;
05734 break;
05735
05736 case BUILT_IN_FPRINTF:
05737 target = expand_builtin_fprintf (exp, target, mode, false);
05738 if (target)
05739 return target;
05740 break;
05741
05742 case BUILT_IN_FPRINTF_UNLOCKED:
05743 target = expand_builtin_fprintf (exp, target, mode, true);
05744 if (target)
05745 return target;
05746 break;
05747
05748 case BUILT_IN_SPRINTF:
05749 target = expand_builtin_sprintf (arglist, target, mode);
05750 if (target)
05751 return target;
05752 break;
05753
05754 case BUILT_IN_SIGNBIT:
05755 case BUILT_IN_SIGNBITF:
05756 case BUILT_IN_SIGNBITL:
05757 target = expand_builtin_signbit (exp, target);
05758 if (target)
05759 return target;
05760 break;
05761
05762
05763 case BUILT_IN_UNWIND_INIT:
05764 expand_builtin_unwind_init ();
05765 return const0_rtx;
05766 case BUILT_IN_DWARF_CFA:
05767 return virtual_cfa_rtx;
05768 #ifdef DWARF2_UNWIND_INFO
05769 case BUILT_IN_DWARF_SP_COLUMN:
05770 return expand_builtin_dwarf_sp_column ();
05771 case BUILT_IN_INIT_DWARF_REG_SIZES:
05772 expand_builtin_init_dwarf_reg_sizes (TREE_VALUE (arglist));
05773 return const0_rtx;
05774 #endif
05775 case BUILT_IN_FROB_RETURN_ADDR:
05776 return expand_builtin_frob_return_addr (TREE_VALUE (arglist));
05777 case BUILT_IN_EXTRACT_RETURN_ADDR:
05778 return expand_builtin_extract_return_addr (TREE_VALUE (arglist));
05779 case BUILT_IN_EH_RETURN:
05780 expand_builtin_eh_return (TREE_VALUE (arglist),
05781 TREE_VALUE (TREE_CHAIN (arglist)));
05782 return const0_rtx;
05783 #ifdef EH_RETURN_DATA_REGNO
05784 case BUILT_IN_EH_RETURN_DATA_REGNO:
05785 return expand_builtin_eh_return_data_regno (arglist);
05786 #endif
05787 case BUILT_IN_EXTEND_POINTER:
05788 return expand_builtin_extend_pointer (TREE_VALUE (arglist));
05789
05790 case BUILT_IN_VA_START:
05791 case BUILT_IN_STDARG_START:
05792 return expand_builtin_va_start (arglist);
05793 case BUILT_IN_VA_END:
05794 return expand_builtin_va_end (arglist);
05795 case BUILT_IN_VA_COPY:
05796 return expand_builtin_va_copy (arglist);
05797 case BUILT_IN_EXPECT:
05798 return expand_builtin_expect (arglist, target);
05799 case BUILT_IN_PREFETCH:
05800 expand_builtin_prefetch (arglist);
05801 return const0_rtx;
05802
05803 case BUILT_IN_PROFILE_FUNC_ENTER:
05804 return expand_builtin_profile_func (false);
05805 case BUILT_IN_PROFILE_FUNC_EXIT:
05806 return expand_builtin_profile_func (true);
05807
05808 case BUILT_IN_INIT_TRAMPOLINE:
05809 return expand_builtin_init_trampoline (arglist);
05810 case BUILT_IN_ADJUST_TRAMPOLINE:
05811 return expand_builtin_adjust_trampoline (arglist);
05812
05813 case BUILT_IN_FORK:
05814 case BUILT_IN_EXECL:
05815 case BUILT_IN_EXECV:
05816 case BUILT_IN_EXECLP:
05817 case BUILT_IN_EXECLE:
05818 case BUILT_IN_EXECVP:
05819 case BUILT_IN_EXECVE:
05820 target = expand_builtin_fork_or_exec (fndecl, arglist, target, ignore);
05821 if (target)
05822 return target;
05823 break;
05824
05825 default:
05826 break;
05827 }
05828
05829
05830
05831 return expand_call (exp, target, ignore);
05832 }
05833
05834
05835
05836
05837
05838
05839
05840 enum built_in_function
05841 builtin_mathfn_code (tree t)
05842 {
05843 tree fndecl, arglist, parmlist;
05844 tree argtype, parmtype;
05845
05846 if (TREE_CODE (t) != CALL_EXPR
05847 || TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR)
05848 return END_BUILTINS;
05849
05850 fndecl = get_callee_fndecl (t);
05851 if (fndecl == NULL_TREE
05852 || TREE_CODE (fndecl) != FUNCTION_DECL
05853 || ! DECL_BUILT_IN (fndecl)
05854 || DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
05855 return END_BUILTINS;
05856
05857 arglist = TREE_OPERAND (t, 1);
05858 parmlist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
05859 for (; parmlist; parmlist = TREE_CHAIN (parmlist))
05860 {
05861
05862
05863 parmtype = TREE_VALUE (parmlist);
05864 if (VOID_TYPE_P (parmtype))
05865 {
05866 if (arglist)
05867 return END_BUILTINS;
05868 return DECL_FUNCTION_CODE (fndecl);
05869 }
05870
05871 if (! arglist)
05872 return END_BUILTINS;
05873
05874 argtype = TREE_TYPE (TREE_VALUE (arglist));
05875
05876 if (SCALAR_FLOAT_TYPE_P (parmtype))
05877 {
05878 if (! SCALAR_FLOAT_TYPE_P (argtype))
05879 return END_BUILTINS;
05880 }
05881 else if (COMPLEX_FLOAT_TYPE_P (parmtype))
05882 {
05883 if (! COMPLEX_FLOAT_TYPE_P (argtype))
05884 return END_BUILTINS;
05885 }
05886 else if (POINTER_TYPE_P (parmtype))
05887 {
05888 if (! POINTER_TYPE_P (argtype))
05889 return END_BUILTINS;
05890 }
05891 else if (INTEGRAL_TYPE_P (parmtype))
05892 {
05893 if (! INTEGRAL_TYPE_P (argtype))
05894 return END_BUILTINS;
05895 }
05896 else
05897 return END_BUILTINS;
05898
05899 arglist = TREE_CHAIN (arglist);
05900 }
05901
05902
05903 return DECL_FUNCTION_CODE (fndecl);
05904 }
05905
05906
05907
05908
05909 static tree
05910 fold_builtin_constant_p (tree arglist)
05911 {
05912 if (arglist == 0)
05913 return 0;
05914
05915 arglist = TREE_VALUE (arglist);
05916
05917
05918
05919
05920 STRIP_NOPS (arglist);
05921
05922
05923 if (CONSTANT_CLASS_P (arglist)
05924 || (TREE_CODE (arglist) == CONSTRUCTOR
05925 && TREE_CONSTANT (arglist)))
05926 return integer_one_node;
05927 if (TREE_CODE (arglist) == ADDR_EXPR)
05928 {
05929 tree op = TREE_OPERAND (arglist, 0);
05930 if (TREE_CODE (op) == STRING_CST
05931 || (TREE_CODE (op) == ARRAY_REF
05932 && integer_zerop (TREE_OPERAND (op, 1))
05933 && TREE_CODE (TREE_OPERAND (op, 0)) == STRING_CST))
05934 return integer_one_node;
05935 }
05936
05937
05938
05939
05940
05941
05942
05943
05944 if (TREE_SIDE_EFFECTS (arglist)
05945 || AGGREGATE_TYPE_P (TREE_TYPE (arglist))
05946 || POINTER_TYPE_P (TREE_TYPE (arglist))
05947 || cfun == 0)
05948 return integer_zero_node;
05949
05950 return 0;
05951 }
05952
05953
05954
05955
05956
05957
05958 static tree
05959 fold_builtin_expect (tree arglist)
05960 {
05961 tree arg, inner;
05962
05963 if (arglist == 0)
05964 return 0;
05965
05966 arg = TREE_VALUE (arglist);
05967
05968
05969 if (!TREE_INVARIANT (arg))
05970 return 0;
05971
05972
05973 inner = arg;
05974 STRIP_NOPS (inner);
05975 if (TREE_CODE (inner) == ADDR_EXPR)
05976 {
05977 do
05978 {
05979 inner = TREE_OPERAND (inner, 0);
05980 }
05981 while (TREE_CODE (inner) == COMPONENT_REF
05982 || TREE_CODE (inner) == ARRAY_REF);
05983 if (DECL_P (inner) && DECL_WEAK (inner))
05984 return 0;
05985 }
05986
05987
05988 return arg;
05989 }
05990
05991
05992
05993 static tree
05994 fold_builtin_classify_type (tree arglist)
05995 {
05996 if (arglist == 0)
05997 return build_int_cst (NULL_TREE, no_type_class);
05998
05999 return build_int_cst (NULL_TREE,
06000 type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
06001 }
06002
06003
06004
06005 static tree
06006 fold_builtin_strlen (tree arglist)
06007 {
06008 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
06009 return NULL_TREE;
06010 else
06011 {
06012 tree len = c_strlen (TREE_VALUE (arglist), 0);
06013
06014 if (len)
06015 {
06016
06017 if (size_type_node)
06018 len = fold_convert (size_type_node, len);
06019 return len;
06020 }
06021
06022 return NULL_TREE;
06023 }
06024 }
06025
06026
06027
06028 static tree
06029 fold_builtin_inf (tree type, int warn)
06030 {
06031 REAL_VALUE_TYPE real;
06032
06033
06034
06035
06036
06037
06038
06039
06040 if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) && warn)
06041 pedwarn ("target format does not support infinity");
06042
06043 real_inf (&real);
06044 return build_real (type, real);
06045 }
06046
06047
06048
06049 static tree
06050 fold_builtin_nan (tree arglist, tree type, int quiet)
06051 {
06052 REAL_VALUE_TYPE real;
06053 const char *str;
06054
06055 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
06056 return 0;
06057 str = c_getstr (TREE_VALUE (arglist));
06058 if (!str)
06059 return 0;
06060
06061 if (!real_nan (&real, str, quiet, TYPE_MODE (type)))
06062 return 0;
06063
06064 return build_real (type, real);
06065 }
06066
06067
06068
06069
06070 static bool
06071 integer_valued_real_p (tree t)
06072 {
06073 switch (TREE_CODE (t))
06074 {
06075 case FLOAT_EXPR:
06076 return true;
06077
06078 case ABS_EXPR:
06079 case SAVE_EXPR:
06080 case NON_LVALUE_EXPR:
06081 return integer_valued_real_p (TREE_OPERAND (t, 0));
06082
06083 case COMPOUND_EXPR:
06084 case MODIFY_EXPR:
06085 case BIND_EXPR:
06086 return integer_valued_real_p (TREE_OPERAND (t, 1));
06087
06088 case PLUS_EXPR:
06089 case MINUS_EXPR:
06090 case MULT_EXPR:
06091 case MIN_EXPR:
06092 case MAX_EXPR:
06093 return integer_valued_real_p (TREE_OPERAND (t, 0))
06094 && integer_valued_real_p (TREE_OPERAND (t, 1));
06095
06096 case COND_EXPR:
06097 return integer_valued_real_p (TREE_OPERAND (t, 1))
06098 && integer_valued_real_p (TREE_OPERAND (t, 2));
06099
06100 case REAL_CST:
06101 if (! TREE_CONSTANT_OVERFLOW (t))
06102 {
06103 REAL_VALUE_TYPE c, cint;
06104
06105 c = TREE_REAL_CST (t);
06106 real_trunc (&cint, TYPE_MODE (TREE_TYPE (t)), &c);
06107 return real_identical (&c, &cint);
06108 }
06109
06110 case NOP_EXPR:
06111 {
06112 tree type = TREE_TYPE (TREE_OPERAND (t, 0));
06113 if (TREE_CODE (type) == INTEGER_TYPE)
06114 return true;
06115 if (TREE_CODE (type) == REAL_TYPE)
06116 return integer_valued_real_p (TREE_OPERAND (t, 0));
06117 break;
06118 }
06119
06120 case CALL_EXPR:
06121 switch (builtin_mathfn_code (t))
06122 {
06123 case BUILT_IN_CEIL:
06124 case BUILT_IN_CEILF:
06125 case BUILT_IN_CEILL:
06126 case BUILT_IN_FLOOR:
06127 case BUILT_IN_FLOORF:
06128 case BUILT_IN_FLOORL:
06129 case BUILT_IN_NEARBYINT:
06130 case BUILT_IN_NEARBYINTF:
06131 case BUILT_IN_NEARBYINTL:
06132 case BUILT_IN_RINT:
06133 case BUILT_IN_RINTF:
06134 case BUILT_IN_RINTL:
06135 case BUILT_IN_ROUND:
06136 case BUILT_IN_ROUNDF:
06137 case BUILT_IN_ROUNDL:
06138 case BUILT_IN_TRUNC:
06139 case BUILT_IN_TRUNCF:
06140 case BUILT_IN_TRUNCL:
06141 return true;
06142
06143 default:
06144 break;
06145 }
06146 break;
06147
06148 default:
06149 break;
06150 }
06151 return false;
06152 }
06153
06154
06155
06156
06157
06158 static tree
06159 fold_trunc_transparent_mathfn (tree exp)
06160 {
06161 tree fndecl = get_callee_fndecl (exp);
06162 tree arglist = TREE_OPERAND (exp, 1);
06163 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
06164 tree arg;
06165
06166 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06167 return 0;
06168
06169 arg = TREE_VALUE (arglist);
06170
06171 if (fcode == builtin_mathfn_code (arg))
06172 return arg;
06173
06174
06175
06176 if (! flag_errno_math && integer_valued_real_p (arg))
06177 return arg;
06178
06179 if (optimize)
06180 {
06181 tree arg0 = strip_float_extensions (arg);
06182 tree ftype = TREE_TYPE (exp);
06183 tree newtype = TREE_TYPE (arg0);
06184 tree decl;
06185
06186 if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype)
06187 && (decl = mathfn_built_in (newtype, fcode)))
06188 {
06189 arglist =
06190 build_tree_list (NULL_TREE, fold_convert (newtype, arg0));
06191 return fold_convert (ftype,
06192 build_function_call_expr (decl, arglist));
06193 }
06194 }
06195 return 0;
06196 }
06197
06198
06199
06200
06201 static tree
06202 fold_fixed_mathfn (tree exp)
06203 {
06204 tree fndecl = get_callee_fndecl (exp);
06205 tree arglist = TREE_OPERAND (exp, 1);
06206 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
06207 tree arg;
06208
06209 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06210 return 0;
06211
06212 arg = TREE_VALUE (arglist);
06213
06214
06215
06216 if (! flag_errno_math && integer_valued_real_p (arg))
06217 return fold (build1 (FIX_TRUNC_EXPR, TREE_TYPE (exp), arg));
06218
06219 if (optimize)
06220 {
06221 tree ftype = TREE_TYPE (arg);
06222 tree arg0 = strip_float_extensions (arg);
06223 tree newtype = TREE_TYPE (arg0);
06224 tree decl;
06225
06226 if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype)
06227 && (decl = mathfn_built_in (newtype, fcode)))
06228 {
06229 arglist =
06230 build_tree_list (NULL_TREE, fold_convert (newtype, arg0));
06231 return build_function_call_expr (decl, arglist);
06232 }
06233 }
06234 return 0;
06235 }
06236
06237
06238
06239
06240
06241 static tree
06242 fold_builtin_cabs (tree arglist, tree type)
06243 {
06244 tree arg;
06245
06246 if (!arglist || TREE_CHAIN (arglist))
06247 return NULL_TREE;
06248
06249 arg = TREE_VALUE (arglist);
06250 if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE
06251 || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
06252 return NULL_TREE;
06253
06254
06255 if (flag_unsafe_math_optimizations
06256 && TREE_CODE (arg) == COMPLEX_CST
06257 && TREE_CODE (TREE_REALPART (arg)) == REAL_CST
06258 && TREE_CODE (TREE_IMAGPART (arg)) == REAL_CST
06259 && ! TREE_CONSTANT_OVERFLOW (TREE_REALPART (arg))
06260 && ! TREE_CONSTANT_OVERFLOW (TREE_IMAGPART (arg)))
06261 {
06262 REAL_VALUE_TYPE r, i;
06263
06264 r = TREE_REAL_CST (TREE_REALPART (arg));
06265 i = TREE_REAL_CST (TREE_IMAGPART (arg));
06266
06267 real_arithmetic (&r, MULT_EXPR, &r, &r);
06268 real_arithmetic (&i, MULT_EXPR, &i, &i);
06269 real_arithmetic (&r, PLUS_EXPR, &r, &i);
06270 if (real_sqrt (&r, TYPE_MODE (type), &r)
06271 || ! flag_trapping_math)
06272 return build_real (type, r);
06273 }
06274
06275
06276 if (TREE_CODE (arg) == COMPLEX_EXPR
06277 && real_zerop (TREE_OPERAND (arg, 0)))
06278 return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg, 1)));
06279 if (TREE_CODE (arg) == COMPLEX_EXPR
06280 && real_zerop (TREE_OPERAND (arg, 1)))
06281 return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg, 0)));
06282
06283
06284 if (flag_unsafe_math_optimizations
06285 && optimize && !optimize_size)
06286 {
06287 tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
06288
06289 if (sqrtfn != NULL_TREE)
06290 {
06291 tree rpart, ipart, result, arglist;
06292
06293 arg = builtin_save_expr (arg);
06294
06295 rpart = fold (build1 (REALPART_EXPR, type, arg));
06296 ipart = fold (build1 (IMAGPART_EXPR, type, arg));
06297
06298 rpart = builtin_save_expr (rpart);
06299 ipart = builtin_save_expr (ipart);
06300
06301 result = fold (build2 (PLUS_EXPR, type,
06302 fold (build2 (MULT_EXPR, type,
06303 rpart, rpart)),
06304 fold (build2 (MULT_EXPR, type,
06305 ipart, ipart))));
06306
06307 arglist = build_tree_list (NULL_TREE, result);
06308 return build_function_call_expr (sqrtfn, arglist);
06309 }
06310 }
06311
06312 return NULL_TREE;
06313 }
06314
06315
06316
06317
06318 static tree
06319 fold_builtin_sqrt (tree arglist, tree type)
06320 {
06321
06322 enum built_in_function fcode;
06323 tree arg = TREE_VALUE (arglist);
06324
06325 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06326 return NULL_TREE;
06327
06328
06329 if (TREE_CODE (arg) == REAL_CST
06330 && ! TREE_CONSTANT_OVERFLOW (arg))
06331 {
06332 REAL_VALUE_TYPE r, x;
06333
06334 x = TREE_REAL_CST (arg);
06335 if (real_sqrt (&r, TYPE_MODE (type), &x)
06336 || (!flag_trapping_math && !flag_errno_math))
06337 return build_real (type, r);
06338 }
06339
06340
06341 fcode = builtin_mathfn_code (arg);
06342 if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
06343 {
06344 tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
06345 arg = fold (build2 (MULT_EXPR, type,
06346 TREE_VALUE (TREE_OPERAND (arg, 1)),
06347 build_real (type, dconsthalf)));
06348 arglist = build_tree_list (NULL_TREE, arg);
06349 return build_function_call_expr (expfn, arglist);
06350 }
06351
06352
06353 if (flag_unsafe_math_optimizations && BUILTIN_ROOT_P (fcode))
06354 {
06355 tree powfn = mathfn_built_in (type, BUILT_IN_POW);
06356
06357 if (powfn)
06358 {
06359 tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
06360 tree tree_root;
06361
06362 REAL_VALUE_TYPE dconstroot =
06363 BUILTIN_SQRT_P (fcode) ? dconsthalf : dconstthird;
06364
06365
06366 SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
06367 dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
06368 tree_root = build_real (type, dconstroot);
06369 arglist = tree_cons (NULL_TREE, arg0,
06370 build_tree_list (NULL_TREE, tree_root));
06371 return build_function_call_expr (powfn, arglist);
06372 }
06373 }
06374
06375
06376 if (flag_unsafe_math_optimizations
06377 && (fcode == BUILT_IN_POW
06378 || fcode == BUILT_IN_POWF
06379 || fcode == BUILT_IN_POWL))
06380 {
06381 tree powfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
06382 tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
06383 tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
06384 tree narg1;
06385 if (!tree_expr_nonnegative_p (arg0))
06386 arg0 = build1 (ABS_EXPR, type, arg0);
06387 narg1 = fold (build2 (MULT_EXPR, type, arg1,
06388 build_real (type, dconsthalf)));
06389 arglist = tree_cons (NULL_TREE, arg0,
06390 build_tree_list (NULL_TREE, narg1));
06391 return build_function_call_expr (powfn, arglist);
06392 }
06393
06394 return NULL_TREE;
06395 }
06396
06397
06398
06399 static tree
06400 fold_builtin_cbrt (tree arglist, tree type)
06401 {
06402 tree arg = TREE_VALUE (arglist);
06403 const enum built_in_function fcode = builtin_mathfn_code (arg);
06404
06405 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06406 return NULL_TREE;
06407
06408
06409 if (real_zerop (arg) || real_onep (arg) || real_minus_onep (arg))
06410 return arg;
06411
06412
06413 if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
06414 {
06415 tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
06416 const REAL_VALUE_TYPE third_trunc =
06417 real_value_truncate (TYPE_MODE (type), dconstthird);
06418 arg = fold (build2 (MULT_EXPR, type,
06419 TREE_VALUE (TREE_OPERAND (arg, 1)),
06420 build_real (type, third_trunc)));
06421 arglist = build_tree_list (NULL_TREE, arg);
06422 return build_function_call_expr (expfn, arglist);
06423 }
06424
06425
06426
06427
06428 if (flag_unsafe_math_optimizations && BUILTIN_SQRT_P (fcode))
06429 {
06430 tree powfn = mathfn_built_in (type, BUILT_IN_POW);
06431
06432 if (powfn)
06433 {
06434 tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
06435 tree tree_root;
06436 REAL_VALUE_TYPE dconstroot = dconstthird;
06437
06438 SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
06439 dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
06440 tree_root = build_real (type, dconstroot);
06441 arglist = tree_cons (NULL_TREE, arg0,
06442 build_tree_list (NULL_TREE, tree_root));
06443 return build_function_call_expr (powfn, arglist);
06444 }
06445
06446 }
06447 return NULL_TREE;
06448 }
06449
06450
06451
06452 static tree
06453 fold_builtin_sin (tree arglist)
06454 {
06455 tree arg = TREE_VALUE (arglist);
06456
06457 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06458 return NULL_TREE;
06459
06460
06461 if (real_zerop (arg))
06462 return arg;
06463
06464 return NULL_TREE;
06465 }
06466
06467
06468
06469 static tree
06470 fold_builtin_cos (tree arglist, tree type, tree fndecl)
06471 {
06472 tree arg = TREE_VALUE (arglist);
06473
06474 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06475 return NULL_TREE;
06476
06477
06478 if (real_zerop (arg))
06479 return build_real (type, dconst1);
06480
06481
06482 if (TREE_CODE (arg) == NEGATE_EXPR)
06483 {
06484 tree args = build_tree_list (NULL_TREE,
06485 TREE_OPERAND (arg, 0));
06486 return build_function_call_expr (fndecl, args);
06487 }
06488
06489 return NULL_TREE;
06490 }
06491
06492
06493
06494 static tree
06495 fold_builtin_tan (tree arglist)
06496 {
06497 enum built_in_function fcode;
06498 tree arg = TREE_VALUE (arglist);
06499
06500 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06501 return NULL_TREE;
06502
06503
06504 if (real_zerop (arg))
06505 return arg;
06506
06507
06508 fcode = builtin_mathfn_code (arg);
06509 if (flag_unsafe_math_optimizations
06510 && (fcode == BUILT_IN_ATAN
06511 || fcode == BUILT_IN_ATANF
06512 || fcode == BUILT_IN_ATANL))
06513 return TREE_VALUE (TREE_OPERAND (arg, 1));
06514
06515 return NULL_TREE;
06516 }
06517
06518
06519
06520
06521 static tree
06522 fold_builtin_atan (tree arglist, tree type)
06523 {
06524
06525 tree arg = TREE_VALUE (arglist);
06526
06527 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06528 return NULL_TREE;
06529
06530
06531 if (real_zerop (arg))
06532 return arg;
06533
06534
06535 if (real_onep (arg))
06536 {
06537 REAL_VALUE_TYPE cst;
06538
06539 real_convert (&cst, TYPE_MODE (type), &dconstpi);
06540 SET_REAL_EXP (&cst, REAL_EXP (&cst) - 2);
06541 return build_real (type, cst);
06542 }
06543
06544 return NULL_TREE;
06545 }
06546
06547
06548
06549
06550 static tree
06551 fold_builtin_trunc (tree exp)
06552 {
06553 tree arglist = TREE_OPERAND (exp, 1);
06554 tree arg;
06555
06556 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06557 return 0;
06558
06559
06560 arg = TREE_VALUE (arglist);
06561 if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
06562 {
06563 REAL_VALUE_TYPE r, x;
06564 tree type = TREE_TYPE (exp);
06565
06566 x = TREE_REAL_CST (arg);
06567 real_trunc (&r, TYPE_MODE (type), &x);
06568 return build_real (type, r);
06569 }
06570
06571 return fold_trunc_transparent_mathfn (exp);
06572 }
06573
06574
06575
06576
06577 static tree
06578 fold_builtin_floor (tree exp)
06579 {
06580 tree arglist = TREE_OPERAND (exp, 1);
06581 tree arg;
06582
06583 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06584 return 0;
06585
06586
06587 arg = TREE_VALUE (arglist);
06588 if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
06589 {
06590 REAL_VALUE_TYPE x;
06591
06592 x = TREE_REAL_CST (arg);
06593 if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
06594 {
06595 tree type = TREE_TYPE (exp);
06596 REAL_VALUE_TYPE r;
06597
06598 real_floor (&r, TYPE_MODE (type), &x);
06599 return build_real (type, r);
06600 }
06601 }
06602
06603 return fold_trunc_transparent_mathfn (exp);
06604 }
06605
06606
06607
06608
06609 static tree
06610 fold_builtin_ceil (tree exp)
06611 {
06612 tree arglist = TREE_OPERAND (exp, 1);
06613 tree arg;
06614
06615 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06616 return 0;
06617
06618
06619 arg = TREE_VALUE (arglist);
06620 if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
06621 {
06622 REAL_VALUE_TYPE x;
06623
06624 x = TREE_REAL_CST (arg);
06625 if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
06626 {
06627 tree type = TREE_TYPE (exp);
06628 REAL_VALUE_TYPE r;
06629
06630 real_ceil (&r, TYPE_MODE (type), &x);
06631 return build_real (type, r);
06632 }
06633 }
06634
06635 return fold_trunc_transparent_mathfn (exp);
06636 }
06637
06638
06639
06640
06641 static tree
06642 fold_builtin_round (tree exp)
06643 {
06644 tree arglist = TREE_OPERAND (exp, 1);
06645 tree arg;
06646
06647 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06648 return 0;
06649
06650
06651 arg = TREE_VALUE (arglist);
06652 if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
06653 {
06654 REAL_VALUE_TYPE x;
06655
06656 x = TREE_REAL_CST (arg);
06657 if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
06658 {
06659 tree type = TREE_TYPE (exp);
06660 REAL_VALUE_TYPE r;
06661
06662 real_round (&r, TYPE_MODE (type), &x);
06663 return build_real (type, r);
06664 }
06665 }
06666
06667 return fold_trunc_transparent_mathfn (exp);
06668 }
06669
06670
06671
06672
06673
06674 static tree
06675 fold_builtin_lround (tree exp)
06676 {
06677 tree arglist = TREE_OPERAND (exp, 1);
06678 tree arg;
06679
06680 if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06681 return 0;
06682
06683
06684 arg = TREE_VALUE (arglist);
06685 if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
06686 {
06687 const REAL_VALUE_TYPE x = TREE_REAL_CST (arg);
06688
06689 if (! REAL_VALUE_ISNAN (x) && ! REAL_VALUE_ISINF (x))
06690 {
06691 tree itype = TREE_TYPE (exp), ftype = TREE_TYPE (arg), result;
06692 HOST_WIDE_INT hi, lo;
06693 REAL_VALUE_TYPE r;
06694
06695 real_round (&r, TYPE_MODE (ftype), &x);
06696 REAL_VALUE_TO_INT (&lo, &hi, r);
06697 result = build_int_cst_wide (NULL_TREE, lo, hi);
06698 if (int_fits_type_p (result, itype))
06699 return fold_convert (itype, result);
06700 }
06701 }
06702
06703 return fold_fixed_mathfn (exp);
06704 }
06705
06706
06707
06708
06709
06710 static tree
06711 fold_builtin_bitop (tree exp)
06712 {
06713 tree fndecl = get_callee_fndecl (exp);
06714 tree arglist = TREE_OPERAND (exp, 1);
06715 tree arg;
06716
06717 if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
06718 return NULL_TREE;
06719
06720
06721 arg = TREE_VALUE (arglist);
06722 if (TREE_CODE (arg) == INTEGER_CST && ! TREE_CONSTANT_OVERFLOW (arg))
06723 {
06724 HOST_WIDE_INT hi, width, result;
06725 unsigned HOST_WIDE_INT lo;
06726 tree type;
06727
06728 type = TREE_TYPE (arg);
06729 width = TYPE_PRECISION (type);
06730 lo = TREE_INT_CST_LOW (arg);
06731
06732
06733 if (width > HOST_BITS_PER_WIDE_INT)
06734 {
06735 hi = TREE_INT_CST_HIGH (arg);
06736 if (width < 2 * HOST_BITS_PER_WIDE_INT)
06737 hi &= ~((HOST_WIDE_INT) (-1) >> (width - HOST_BITS_PER_WIDE_INT));
06738 }
06739 else
06740 {
06741 hi = 0;
06742 if (width < HOST_BITS_PER_WIDE_INT)
06743 lo &= ~((unsigned HOST_WIDE_INT) (-1) << width);
06744 }
06745
06746 switch (DECL_FUNCTION_CODE (fndecl))
06747 {
06748 case BUILT_IN_FFS:
06749 case BUILT_IN_FFSL:
06750 case BUILT_IN_FFSLL:
06751 if (lo != 0)
06752 result = exact_log2 (lo & -lo) + 1;
06753 else if (hi != 0)
06754 result = HOST_BITS_PER_WIDE_INT + exact_log2 (hi & -hi) + 1;
06755 else
06756 result = 0;
06757 break;
06758
06759 case BUILT_IN_CLZ:
06760 case BUILT_IN_CLZL:
06761 case BUILT_IN_CLZLL:
06762 if (hi != 0)
06763 result = width - floor_log2 (hi) - 1 - HOST_BITS_PER_WIDE_INT;
06764 else if (lo != 0)
06765 result = width - floor_log2 (lo) - 1;
06766 else if (! CLZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (type), result))
06767 result = width;
06768 break;
06769
06770 case BUILT_IN_CTZ:
06771 case BUILT_IN_CTZL:
06772 case BUILT_IN_CTZLL:
06773 if (lo != 0)
06774 result = exact_log2 (lo & -lo);
06775 else if (hi != 0)
06776 result = HOST_BITS_PER_WIDE_INT + exact_log2 (hi & -hi);
06777 else if (! CTZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (type), result))
06778 result = width;
06779 break;
06780
06781 case BUILT_IN_POPCOUNT:
06782 case BUILT_IN_POPCOUNTL:
06783 case BUILT_IN_POPCOUNTLL:
06784 result = 0;
06785 while (lo)
06786 result++, lo &= lo - 1;
06787 while (hi)
06788 result++, hi &= hi - 1;
06789 break;
06790
06791 case BUILT_IN_PARITY:
06792 case BUILT_IN_PARITYL:
06793 case BUILT_IN_PARITYLL:
06794 result = 0;
06795 while (lo)
06796 result++, lo &= lo - 1;
06797 while (hi)
06798 result++, hi &= hi - 1;
06799 result &= 1;
06800 break;
06801
06802 default:
06803 gcc_unreachable ();
06804 }
06805
06806 return build_int_cst (TREE_TYPE (exp), result);
06807 }
06808
06809 return NULL_TREE;
06810 }
06811
06812
06813
06814 static bool
06815 real_dconstp (tree expr, const REAL_VALUE_TYPE *value)
06816 {
06817 STRIP_NOPS (expr);
06818
06819 return ((TREE_CODE (expr) == REAL_CST
06820 && ! TREE_CONSTANT_OVERFLOW (expr)
06821 && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), *value))
06822 || (TREE_CODE (expr) == COMPLEX_CST
06823 && real_dconstp (TREE_REALPART (expr), value)
06824 && real_zerop (TREE_IMAGPART (expr))));
06825 }
06826
06827
06828
06829
06830
06831 static tree
06832 fold_builtin_logarithm (tree exp, const REAL_VALUE_TYPE *value)
06833 {
06834 tree arglist = TREE_OPERAND (exp, 1);
06835
06836 if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
06837 {
06838 tree fndecl = get_callee_fndecl (exp);
06839 tree type = TREE_TYPE (TREE_TYPE (fndecl));
06840 tree arg = TREE_VALUE (arglist);
06841 const enum built_in_function fcode = builtin_mathfn_code (arg);
06842
06843
06844 if (real_onep (arg))
06845 return build_real (type, dconst0);
06846
06847
06848
06849 if (exact_real_truncate (TYPE_MODE (type), value)
06850 || flag_unsafe_math_optimizations)
06851 {
06852 const REAL_VALUE_TYPE value_truncate =
06853 real_value_truncate (TYPE_MODE (type), *value);
06854 if (real_dconstp (arg, &value_truncate))
06855 return build_real (type, dconst1);
06856 }
06857
06858
06859 if (flag_unsafe_math_optimizations
06860 && ((value == &dconste
06861 && (fcode == BUILT_IN_EXP
06862 || fcode == BUILT_IN_EXPF
06863 || fcode == BUILT_IN_EXPL))
06864 || (value == &dconst2
06865 && (fcode == BUILT_IN_EXP2
06866 || fcode == BUILT_IN_EXP2F
06867 || fcode == BUILT_IN_EXP2L))
06868 || (value == &dconst10 && (BUILTIN_EXP10_P (fcode)))))
06869 return fold_convert (type, TREE_VALUE (TREE_OPERAND (arg, 1)));
06870
06871
06872
06873
06874 if (flag_unsafe_math_optimizations)
06875 {
06876 tree exponent = 0, x = 0;
06877
06878 switch (fcode)
06879 {
06880 case BUILT_IN_EXP:
06881 case BUILT_IN_EXPF:
06882 case BUILT_IN_EXPL:
06883
06884 x = build_real (type,
06885 real_value_truncate (TYPE_MODE (type), dconste));
06886 exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
06887 break;
06888 case BUILT_IN_EXP2:
06889 case BUILT_IN_EXP2F:
06890 case BUILT_IN_EXP2L:
06891
06892 x = build_real (type, dconst2);
06893 exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
06894 break;
06895 case BUILT_IN_EXP10:
06896 case BUILT_IN_EXP10F:
06897 case BUILT_IN_EXP10L:
06898 case BUILT_IN_POW10:
06899 case BUILT_IN_POW10F:
06900 case BUILT_IN_POW10L:
06901
06902 x = build_real (type, dconst10);
06903 exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
06904 break;
06905 case BUILT_IN_SQRT:
06906 case BUILT_IN_SQRTF:
06907 case BUILT_IN_SQRTL:
06908
06909 x = TREE_VALUE (TREE_OPERAND (arg, 1));
06910 exponent = build_real (type, dconsthalf);
06911 break;
06912 case BUILT_IN_CBRT:
06913 case BUILT_IN_CBRTF:
06914 case BUILT_IN_CBRTL:
06915
06916 x = TREE_VALUE (TREE_OPERAND (arg, 1));
06917 exponent = build_real (type, real_value_truncate (TYPE_MODE (type),
06918 dconstthird));
06919 break;
06920 case BUILT_IN_POW:
06921 case BUILT_IN_POWF:
06922 case BUILT_IN_POWL:
06923
06924 x = TREE_VALUE (TREE_OPERAND (arg, 1));
06925 exponent = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
06926 break;
06927 default:
06928 break;
06929 }
06930
06931
06932 if (x && exponent)
06933 {
06934 tree logfn;
06935 arglist = build_tree_list (NULL_TREE, x);
06936 logfn = build_function_call_expr (fndecl, arglist);
06937 return fold (build2 (MULT_EXPR, type, exponent, logfn));
06938 }
06939 }
06940 }
06941
06942 return 0;
06943 }
06944
06945
06946
06947 static tree
06948 fold_builtin_pow (tree fndecl, tree arglist, tree type)
06949 {
06950 enum built_in_function fcode;
06951 tree arg0 = TREE_VALUE (arglist);
06952 tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
06953
06954 if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
06955 return NULL_TREE;
06956
06957
06958 if (real_onep (arg0))
06959 return omit_one_operand (type, build_real (type, dconst1), arg1);
06960
06961 if (TREE_CODE (arg1) == REAL_CST
06962 && ! TREE_CONSTANT_OVERFLOW (arg1))
06963 {
06964 REAL_VALUE_TYPE cint;
06965 REAL_VALUE_TYPE c;
06966 HOST_WIDE_INT n;
06967
06968 c = TREE_REAL_CST (arg1);
06969
06970
06971 if (REAL_VALUES_EQUAL (c, dconst0))
06972 return omit_one_operand (type, build_real (type, dconst1),
06973 arg0);
06974
06975
06976 if (REAL_VALUES_EQUAL (c, dconst1))
06977 return arg0;
06978
06979
06980 if (REAL_VALUES_EQUAL (c, dconstm1))
06981 return fold (build2 (RDIV_EXPR, type,
06982 build_real (type, dconst1), arg0));
06983
06984
06985 if (flag_unsafe_math_optimizations
06986 && REAL_VALUES_EQUAL (c, dconsthalf))
06987 {
06988 tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
06989
06990 if (sqrtfn != NULL_TREE)
06991 {
06992 tree arglist = build_tree_list (NULL_TREE, arg0);
06993 return build_function_call_expr (sqrtfn, arglist);
06994 }
06995 }
06996
06997
06998 n = real_to_integer (&c);
06999 real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
07000 if (real_identical (&c, &cint))
07001 {
07002
07003 if (TREE_CODE (arg0) == REAL_CST
07004 && ! TREE_CONSTANT_OVERFLOW (arg0))
07005 {
07006 REAL_VALUE_TYPE x;
07007 bool inexact;
07008
07009 x = TREE_REAL_CST (arg0);
07010 inexact = real_powi (&x, TYPE_MODE (type), &x, n);
07011 if (flag_unsafe_math_optimizations || !inexact)
07012 return build_real (type, x);
07013 }
07014
07015
07016 if ((n & 1) == 0 && flag_unsafe_math_optimizations)
07017 {
07018 tree narg0 = fold_strip_sign_ops (arg0);
07019 if (narg0)
07020 {
07021 arglist = build_tree_list (NULL_TREE, arg1);
07022 arglist = tree_cons (NULL_TREE, narg0, arglist);
07023 return build_function_call_expr (fndecl, arglist);
07024 }
07025 }
07026 }
07027 }
07028
07029
07030 fcode = builtin_mathfn_code (arg0);
07031 if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
07032 {
07033 tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
07034 tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
07035 arg = fold (build2 (MULT_EXPR, type, arg, arg1));
07036 arglist = build_tree_list (NULL_TREE, arg);
07037 return build_function_call_expr (expfn, arglist);
07038 }
07039
07040
07041 if (flag_unsafe_math_optimizations && BUILTIN_SQRT_P (fcode))
07042 {
07043 tree narg0 = TREE_VALUE (TREE_OPERAND (arg0, 1));
07044 tree narg1 = fold (build2 (MULT_EXPR, type, arg1,
07045 build_real (type, dconsthalf)));
07046
07047 arglist = tree_cons (NULL_TREE, narg0,
07048 build_tree_list (NULL_TREE, narg1));
07049 return build_function_call_expr (fndecl, arglist);
07050 }
07051
07052
07053 if (flag_unsafe_math_optimizations
07054 && (fcode == BUILT_IN_POW
07055 || fcode == BUILT_IN_POWF
07056 || fcode == BUILT_IN_POWL))
07057 {
07058 tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
07059 tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
07060 tree narg1 = fold (build2 (MULT_EXPR, type, arg01, arg1));
07061 arglist = tree_cons (NULL_TREE, arg00,
07062 build_tree_list (NULL_TREE, narg1));
07063 return build_function_call_expr (fndecl, arglist);
07064 }
07065 return NULL_TREE;
07066 }
07067
07068
07069
07070 static tree
07071