00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "config.h"
00027 #include "system.h"
00028 #include "machmode.h"
00029 #include "real.h"
00030 #include "rtl.h"
00031 #include "tree.h"
00032 #include "flags.h"
00033 #include "regs.h"
00034 #include "hard-reg-set.h"
00035 #include "except.h"
00036 #include "function.h"
00037 #include "insn-config.h"
00038 #include "expr.h"
00039 #include "optabs.h"
00040 #include "libfuncs.h"
00041 #include "recog.h"
00042 #include "output.h"
00043 #include "typeclass.h"
00044 #include "toplev.h"
00045 #include "predict.h"
00046 #include "tm_p.h"
00047 #include "target.h"
00048 #include "langhooks.h"
00049
00050 #define CALLED_AS_BUILT_IN(NODE) \
00051 (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
00052
00053
00054 #ifndef INCOMING_REGNO
00055 #define INCOMING_REGNO(OUT) (OUT)
00056 #endif
00057 #ifndef OUTGOING_REGNO
00058 #define OUTGOING_REGNO(IN) (IN)
00059 #endif
00060
00061 #ifndef PAD_VARARGS_DOWN
00062 #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
00063 #endif
00064
00065
00066 const char *const built_in_class_names[4]
00067 = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
00068
00069 #define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT) STRINGX(X),
00070 const char *const built_in_names[(int) END_BUILTINS] =
00071 {
00072 #include "builtins.def"
00073 };
00074 #undef DEF_BUILTIN
00075
00076
00077
00078 tree built_in_decls[(int) END_BUILTINS];
00079
00080 static int get_pointer_alignment PARAMS ((tree, unsigned int));
00081 static tree c_strlen PARAMS ((tree, int));
00082 static const char *c_getstr PARAMS ((tree));
00083 static rtx c_readstr PARAMS ((const char *,
00084 enum machine_mode));
00085 static int target_char_cast PARAMS ((tree, char *));
00086 static rtx get_memory_rtx PARAMS ((tree));
00087 static int apply_args_size PARAMS ((void));
00088 static int apply_result_size PARAMS ((void));
00089 #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
00090 static rtx result_vector PARAMS ((int, rtx));
00091 #endif
00092 static rtx expand_builtin_setjmp PARAMS ((tree, rtx));
00093 static void expand_builtin_prefetch PARAMS ((tree));
00094 static rtx expand_builtin_apply_args PARAMS ((void));
00095 static rtx expand_builtin_apply_args_1 PARAMS ((void));
00096 static rtx expand_builtin_apply PARAMS ((rtx, rtx, rtx));
00097 static void expand_builtin_return PARAMS ((rtx));
00098 static enum type_class type_to_class PARAMS ((tree));
00099 static rtx expand_builtin_classify_type PARAMS ((tree));
00100 static rtx expand_builtin_mathfn PARAMS ((tree, rtx, rtx));
00101 static rtx expand_builtin_constant_p PARAMS ((tree));
00102 static rtx expand_builtin_args_info PARAMS ((tree));
00103 static rtx expand_builtin_next_arg PARAMS ((tree));
00104 static rtx expand_builtin_va_start PARAMS ((tree));
00105 static rtx expand_builtin_va_end PARAMS ((tree));
00106 static rtx expand_builtin_va_copy PARAMS ((tree));
00107 static rtx expand_builtin_memcmp PARAMS ((tree, tree, rtx,
00108 enum machine_mode));
00109 static rtx expand_builtin_strcmp PARAMS ((tree, rtx,
00110 enum machine_mode));
00111 static rtx expand_builtin_strncmp PARAMS ((tree, rtx,
00112 enum machine_mode));
00113 static rtx builtin_memcpy_read_str PARAMS ((PTR, HOST_WIDE_INT,
00114 enum machine_mode));
00115 static rtx expand_builtin_strcat PARAMS ((tree, rtx,
00116 enum machine_mode));
00117 static rtx expand_builtin_strncat PARAMS ((tree, rtx,
00118 enum machine_mode));
00119 static rtx expand_builtin_strspn PARAMS ((tree, rtx,
00120 enum machine_mode));
00121 static rtx expand_builtin_strcspn PARAMS ((tree, rtx,
00122 enum machine_mode));
00123 static rtx expand_builtin_memcpy PARAMS ((tree, rtx,
00124 enum machine_mode));
00125 static rtx expand_builtin_mempcpy PARAMS ((tree, rtx,
00126 enum machine_mode, int));
00127 static rtx expand_builtin_memmove PARAMS ((tree, rtx,
00128 enum machine_mode));
00129 static rtx expand_builtin_bcopy PARAMS ((tree));
00130 static rtx expand_builtin_strcpy PARAMS ((tree, rtx,
00131 enum machine_mode));
00132 static rtx expand_builtin_stpcpy PARAMS ((tree, rtx,
00133 enum machine_mode));
00134 static rtx builtin_strncpy_read_str PARAMS ((PTR, HOST_WIDE_INT,
00135 enum machine_mode));
00136 static rtx expand_builtin_strncpy PARAMS ((tree, rtx,
00137 enum machine_mode));
00138 static rtx builtin_memset_read_str PARAMS ((PTR, HOST_WIDE_INT,
00139 enum machine_mode));
00140 static rtx builtin_memset_gen_str PARAMS ((PTR, HOST_WIDE_INT,
00141 enum machine_mode));
00142 static rtx expand_builtin_memset PARAMS ((tree, rtx,
00143 enum machine_mode));
00144 static rtx expand_builtin_bzero PARAMS ((tree));
00145 static rtx expand_builtin_strlen PARAMS ((tree, rtx));
00146 static rtx expand_builtin_strstr PARAMS ((tree, rtx,
00147 enum machine_mode));
00148 static rtx expand_builtin_strpbrk PARAMS ((tree, rtx,
00149 enum machine_mode));
00150 static rtx expand_builtin_strchr PARAMS ((tree, rtx,
00151 enum machine_mode));
00152 static rtx expand_builtin_strrchr PARAMS ((tree, rtx,
00153 enum machine_mode));
00154 static rtx expand_builtin_alloca PARAMS ((tree, rtx));
00155 static rtx expand_builtin_ffs PARAMS ((tree, rtx, rtx));
00156 static rtx expand_builtin_frame_address PARAMS ((tree));
00157 static rtx expand_builtin_fputs PARAMS ((tree, int, int));
00158 static rtx expand_builtin_sprintf PARAMS ((tree, rtx, enum machine_mode));
00159 static tree stabilize_va_list PARAMS ((tree, int));
00160 static rtx expand_builtin_expect PARAMS ((tree, rtx));
00161 static tree fold_builtin_constant_p PARAMS ((tree));
00162 static tree fold_builtin_classify_type PARAMS ((tree));
00163 static tree fold_builtin_inf PARAMS ((tree, int));
00164 static tree fold_builtin_nan PARAMS ((tree, tree, int));
00165 static tree build_function_call_expr PARAMS ((tree, tree));
00166 static int validate_arglist PARAMS ((tree, ...));
00167 static bool readonly_data_expr PARAMS ((tree));
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 static int
00178 get_pointer_alignment (exp, max_align)
00179 tree exp;
00180 unsigned int max_align;
00181 {
00182 unsigned int align, inner;
00183
00184 if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE)
00185 return 0;
00186
00187 align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
00188 align = MIN (align, max_align);
00189
00190 while (1)
00191 {
00192 switch (TREE_CODE (exp))
00193 {
00194 case NOP_EXPR:
00195 case CONVERT_EXPR:
00196 case NON_LVALUE_EXPR:
00197 exp = TREE_OPERAND (exp, 0);
00198 if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE)
00199 return align;
00200
00201 inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
00202 align = MIN (inner, max_align);
00203 break;
00204
00205 case PLUS_EXPR:
00206
00207
00208
00209 if (! host_integerp (TREE_OPERAND (exp, 1), 1))
00210 return align;
00211
00212 while (((tree_low_cst (TREE_OPERAND (exp, 1), 1))
00213 & (max_align / BITS_PER_UNIT - 1))
00214 != 0)
00215 max_align >>= 1;
00216
00217 exp = TREE_OPERAND (exp, 0);
00218 break;
00219
00220 case ADDR_EXPR:
00221
00222 exp = TREE_OPERAND (exp, 0);
00223 if (TREE_CODE (exp) == FUNCTION_DECL)
00224 align = FUNCTION_BOUNDARY;
00225 else if (DECL_P (exp))
00226 align = DECL_ALIGN (exp);
00227 #ifdef CONSTANT_ALIGNMENT
00228 else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c')
00229 align = CONSTANT_ALIGNMENT (exp, align);
00230 #endif
00231 return MIN (align, max_align);
00232
00233 default:
00234 return align;
00235 }
00236 }
00237 }
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 static tree
00256 c_strlen (src, only_value)
00257 tree src;
00258 int only_value;
00259 {
00260 tree offset_node;
00261 HOST_WIDE_INT offset;
00262 int max;
00263 const char *ptr;
00264
00265 STRIP_NOPS (src);
00266 if (TREE_CODE (src) == COND_EXPR
00267 && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
00268 {
00269 tree len1, len2;
00270
00271 len1 = c_strlen (TREE_OPERAND (src, 1), only_value);
00272 len2 = c_strlen (TREE_OPERAND (src, 2), only_value);
00273 if (tree_int_cst_equal (len1, len2))
00274 return len1;
00275 }
00276
00277 if (TREE_CODE (src) == COMPOUND_EXPR
00278 && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
00279 src = TREE_OPERAND (src, 1);
00280
00281 src = string_constant (src, &offset_node);
00282 if (src == 0)
00283 return 0;
00284
00285 max = TREE_STRING_LENGTH (src) - 1;
00286 ptr = TREE_STRING_POINTER (src);
00287
00288 if (offset_node && TREE_CODE (offset_node) != INTEGER_CST)
00289 {
00290
00291
00292
00293 int i;
00294
00295 for (i = 0; i < max; i++)
00296 if (ptr[i] == 0)
00297 return 0;
00298
00299
00300
00301
00302
00303
00304
00305
00306 return size_diffop (size_int (max), offset_node);
00307 }
00308
00309
00310
00311 if (offset_node == 0)
00312 offset = 0;
00313 else if (! host_integerp (offset_node, 0))
00314 offset = -1;
00315 else
00316 offset = tree_low_cst (offset_node, 0);
00317
00318
00319
00320 if (offset < 0 || offset > max)
00321 {
00322 warning ("offset outside bounds of constant string");
00323 return 0;
00324 }
00325
00326
00327
00328
00329
00330
00331
00332 return ssize_int (strlen (ptr + offset));
00333 }
00334
00335
00336
00337
00338 static const char *
00339 c_getstr (src)
00340 tree src;
00341 {
00342 tree offset_node;
00343
00344 src = string_constant (src, &offset_node);
00345 if (src == 0)
00346 return 0;
00347
00348 if (offset_node == 0)
00349 return TREE_STRING_POINTER (src);
00350 else if (!host_integerp (offset_node, 1)
00351 || compare_tree_int (offset_node, TREE_STRING_LENGTH (src) - 1) > 0)
00352 return 0;
00353
00354 return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
00355 }
00356
00357
00358
00359
00360 static rtx
00361 c_readstr (str, mode)
00362 const char *str;
00363 enum machine_mode mode;
00364 {
00365 HOST_WIDE_INT c[2];
00366 HOST_WIDE_INT ch;
00367 unsigned int i, j;
00368
00369 if (GET_MODE_CLASS (mode) != MODE_INT)
00370 abort ();
00371 c[0] = 0;
00372 c[1] = 0;
00373 ch = 1;
00374 for (i = 0; i < GET_MODE_SIZE (mode); i++)
00375 {
00376 j = i;
00377 if (WORDS_BIG_ENDIAN)
00378 j = GET_MODE_SIZE (mode) - i - 1;
00379 if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
00380 && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
00381 j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
00382 j *= BITS_PER_UNIT;
00383 if (j > 2 * HOST_BITS_PER_WIDE_INT)
00384 abort ();
00385 if (ch)
00386 ch = (unsigned char) str[i];
00387 c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
00388 }
00389 return immed_double_const (c[0], c[1], mode);
00390 }
00391
00392
00393
00394
00395
00396 static int
00397 target_char_cast (cst, p)
00398 tree cst;
00399 char *p;
00400 {
00401 unsigned HOST_WIDE_INT val, hostval;
00402
00403 if (!host_integerp (cst, 1)
00404 || CHAR_TYPE_SIZE > HOST_BITS_PER_WIDE_INT)
00405 return 1;
00406
00407 val = tree_low_cst (cst, 1);
00408 if (CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT)
00409 val &= (((unsigned HOST_WIDE_INT) 1) << CHAR_TYPE_SIZE) - 1;
00410
00411 hostval = val;
00412 if (HOST_BITS_PER_CHAR < HOST_BITS_PER_WIDE_INT)
00413 hostval &= (((unsigned HOST_WIDE_INT) 1) << HOST_BITS_PER_CHAR) - 1;
00414
00415 if (val != hostval)
00416 return 1;
00417
00418 *p = hostval;
00419 return 0;
00420 }
00421
00422
00423
00424
00425
00426 rtx
00427 expand_builtin_return_addr (fndecl_code, count, tem)
00428 enum built_in_function fndecl_code;
00429 int count;
00430 rtx tem;
00431 {
00432 int i;
00433
00434
00435
00436
00437 #ifdef SETUP_FRAME_ADDRESSES
00438 if (count > 0)
00439 SETUP_FRAME_ADDRESSES ();
00440 #endif
00441
00442
00443
00444
00445
00446 #ifdef RETURN_ADDR_IN_PREVIOUS_FRAME
00447 if (fndecl_code == BUILT_IN_RETURN_ADDRESS)
00448 count--;
00449 #endif
00450
00451
00452 for (i = 0; i < count; i++)
00453 {
00454
00455
00456 #ifdef DYNAMIC_CHAIN_ADDRESS
00457 tem = DYNAMIC_CHAIN_ADDRESS (tem);
00458 #endif
00459 tem = memory_address (Pmode, tem);
00460 tem = gen_rtx_MEM (Pmode, tem);
00461 set_mem_alias_set (tem, get_frame_alias_set ());
00462 tem = copy_to_reg (tem);
00463 }
00464
00465
00466 if (fndecl_code == BUILT_IN_FRAME_ADDRESS)
00467 return tem;
00468
00469
00470
00471 #ifdef RETURN_ADDR_RTX
00472 tem = RETURN_ADDR_RTX (count, tem);
00473 #else
00474 tem = memory_address (Pmode,
00475 plus_constant (tem, GET_MODE_SIZE (Pmode)));
00476 tem = gen_rtx_MEM (Pmode, tem);
00477 set_mem_alias_set (tem, get_frame_alias_set ());
00478 #endif
00479 return tem;
00480 }
00481
00482
00483 static HOST_WIDE_INT setjmp_alias_set = -1;
00484
00485
00486
00487
00488
00489 void
00490 expand_builtin_setjmp_setup (buf_addr, receiver_label)
00491 rtx buf_addr;
00492 rtx receiver_label;
00493 {
00494 enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
00495 rtx stack_save;
00496 rtx mem;
00497
00498 if (setjmp_alias_set == -1)
00499 setjmp_alias_set = new_alias_set ();
00500
00501 #ifdef POINTERS_EXTEND_UNSIGNED
00502 if (GET_MODE (buf_addr) != Pmode)
00503 buf_addr = convert_memory_address (Pmode, buf_addr);
00504 #endif
00505
00506 buf_addr = force_reg (Pmode, force_operand (buf_addr, NULL_RTX));
00507
00508 emit_queue ();
00509
00510
00511
00512
00513
00514 #ifndef BUILTIN_SETJMP_FRAME_VALUE
00515 #define BUILTIN_SETJMP_FRAME_VALUE virtual_stack_vars_rtx
00516 #endif
00517
00518 mem = gen_rtx_MEM (Pmode, buf_addr);
00519 set_mem_alias_set (mem, setjmp_alias_set);
00520 emit_move_insn (mem, BUILTIN_SETJMP_FRAME_VALUE);
00521
00522 mem = gen_rtx_MEM (Pmode, plus_constant (buf_addr, GET_MODE_SIZE (Pmode))),
00523 set_mem_alias_set (mem, setjmp_alias_set);
00524
00525 emit_move_insn (validize_mem (mem),
00526 force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, receiver_label)));
00527
00528 stack_save = gen_rtx_MEM (sa_mode,
00529 plus_constant (buf_addr,
00530 2 * GET_MODE_SIZE (Pmode)));
00531 set_mem_alias_set (stack_save, setjmp_alias_set);
00532 emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
00533
00534
00535 #ifdef HAVE_builtin_setjmp_setup
00536 if (HAVE_builtin_setjmp_setup)
00537 emit_insn (gen_builtin_setjmp_setup (buf_addr));
00538 #endif
00539
00540
00541
00542 current_function_calls_setjmp = 1;
00543
00544
00545
00546 current_function_has_nonlocal_label = 1;
00547 }
00548
00549
00550
00551
00552 void
00553 expand_builtin_setjmp_receiver (receiver_label)
00554 rtx receiver_label ATTRIBUTE_UNUSED;
00555 {
00556
00557
00558 emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
00559
00560
00561
00562 emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx));
00563
00564
00565
00566
00567 #ifdef HAVE_nonlocal_goto
00568 if (! HAVE_nonlocal_goto)
00569 #endif
00570 emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
00571
00572 #if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
00573 if (fixed_regs[ARG_POINTER_REGNUM])
00574 {
00575 #ifdef ELIMINABLE_REGS
00576 size_t i;
00577 static const struct elims {const int from, to;} elim_regs[] = ELIMINABLE_REGS;
00578
00579 for (i = 0; i < ARRAY_SIZE (elim_regs); i++)
00580 if (elim_regs[i].from == ARG_POINTER_REGNUM
00581 && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
00582 break;
00583
00584 if (i == ARRAY_SIZE (elim_regs))
00585 #endif
00586 {
00587
00588
00589 emit_move_insn (virtual_incoming_args_rtx,
00590 copy_to_reg (get_arg_pointer_save_area (cfun)));
00591 }
00592 }
00593 #endif
00594
00595 #ifdef HAVE_builtin_setjmp_receiver
00596 if (HAVE_builtin_setjmp_receiver)
00597 emit_insn (gen_builtin_setjmp_receiver (receiver_label));
00598 else
00599 #endif
00600 #ifdef HAVE_nonlocal_goto_receiver
00601 if (HAVE_nonlocal_goto_receiver)
00602 emit_insn (gen_nonlocal_goto_receiver ());
00603 else
00604 #endif
00605 { }
00606
00607
00608
00609
00610
00611
00612 emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
00613 }
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625 static rtx
00626 expand_builtin_setjmp (arglist, target)
00627 tree arglist;
00628 rtx target;
00629 {
00630 rtx buf_addr, next_lab, cont_lab;
00631
00632 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
00633 return NULL_RTX;
00634
00635 if (target == 0 || GET_CODE (target) != REG
00636 || REGNO (target) < FIRST_PSEUDO_REGISTER)
00637 target = gen_reg_rtx (TYPE_MODE (integer_type_node));
00638
00639 buf_addr = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
00640
00641 next_lab = gen_label_rtx ();
00642 cont_lab = gen_label_rtx ();
00643
00644 expand_builtin_setjmp_setup (buf_addr, next_lab);
00645
00646
00647 emit_move_insn (target, const0_rtx);
00648 emit_jump_insn (gen_jump (cont_lab));
00649 emit_barrier ();
00650 emit_label (next_lab);
00651
00652 expand_builtin_setjmp_receiver (next_lab);
00653
00654
00655 emit_move_insn (target, const1_rtx);
00656 emit_label (cont_lab);
00657
00658
00659
00660
00661
00662 current_function_has_nonlocal_label = 1;
00663 nonlocal_goto_handler_labels
00664 = gen_rtx_EXPR_LIST (VOIDmode, next_lab, nonlocal_goto_handler_labels);
00665
00666 return target;
00667 }
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678 void
00679 expand_builtin_longjmp (buf_addr, value)
00680 rtx buf_addr, value;
00681 {
00682 rtx fp, lab, stack, insn, last;
00683 enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
00684
00685 if (setjmp_alias_set == -1)
00686 setjmp_alias_set = new_alias_set ();
00687
00688 #ifdef POINTERS_EXTEND_UNSIGNED
00689 if (GET_MODE (buf_addr) != Pmode)
00690 buf_addr = convert_memory_address (Pmode, buf_addr);
00691 #endif
00692
00693 buf_addr = force_reg (Pmode, buf_addr);
00694
00695
00696
00697
00698
00699
00700 if (value != const1_rtx)
00701 abort ();
00702
00703 current_function_calls_longjmp = 1;
00704
00705 last = get_last_insn ();
00706 #ifdef HAVE_builtin_longjmp
00707 if (HAVE_builtin_longjmp)
00708 emit_insn (gen_builtin_longjmp (buf_addr));
00709 else
00710 #endif
00711 {
00712 fp = gen_rtx_MEM (Pmode, buf_addr);
00713 lab = gen_rtx_MEM (Pmode, plus_constant (buf_addr,
00714 GET_MODE_SIZE (Pmode)));
00715
00716 stack = gen_rtx_MEM (sa_mode, plus_constant (buf_addr,
00717 2 * GET_MODE_SIZE (Pmode)));
00718 set_mem_alias_set (fp, setjmp_alias_set);
00719 set_mem_alias_set (lab, setjmp_alias_set);
00720 set_mem_alias_set (stack, setjmp_alias_set);
00721
00722
00723
00724 #if HAVE_nonlocal_goto
00725 if (HAVE_nonlocal_goto)
00726
00727
00728
00729 emit_insn (gen_nonlocal_goto (value, lab, stack, fp));
00730 else
00731 #endif
00732 {
00733 lab = copy_to_reg (lab);
00734
00735 emit_move_insn (hard_frame_pointer_rtx, fp);
00736 emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
00737
00738 emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
00739 emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
00740 emit_indirect_jump (lab);
00741 }
00742 }
00743
00744
00745
00746
00747
00748
00749 for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
00750 {
00751 if (insn == last)
00752 abort ();
00753 if (GET_CODE (insn) == JUMP_INSN)
00754 {
00755 REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx,
00756 REG_NOTES (insn));
00757 break;
00758 }
00759 else if (GET_CODE (insn) == CALL_INSN)
00760 break;
00761 }
00762 }
00763
00764
00765
00766
00767
00768 static void
00769 expand_builtin_prefetch (arglist)
00770 tree arglist;
00771 {
00772 tree arg0, arg1, arg2;
00773 rtx op0, op1, op2;
00774
00775 if (!validate_arglist (arglist, POINTER_TYPE, 0))
00776 return;
00777
00778 arg0 = TREE_VALUE (arglist);
00779
00780
00781
00782 if (TREE_CHAIN (arglist))
00783 {
00784 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
00785 if (TREE_CHAIN (TREE_CHAIN (arglist)))
00786 arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
00787 else
00788 arg2 = build_int_2 (3, 0);
00789 }
00790 else
00791 {
00792 arg1 = integer_zero_node;
00793 arg2 = build_int_2 (3, 0);
00794 }
00795
00796
00797 op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
00798
00799
00800 if (TREE_CODE (arg1) != INTEGER_CST)
00801 {
00802 error ("second arg to `__builtin_prefetch' must be a constant");
00803 arg1 = integer_zero_node;
00804 }
00805 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
00806
00807 if (INTVAL (op1) != 0 && INTVAL (op1) != 1)
00808 {
00809 warning ("invalid second arg to __builtin_prefetch; using zero");
00810 op1 = const0_rtx;
00811 }
00812
00813
00814 if (TREE_CODE (arg2) != INTEGER_CST)
00815 {
00816 error ("third arg to `__builtin_prefetch' must be a constant");
00817 arg2 = integer_zero_node;
00818 }
00819 op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
00820
00821 if (INTVAL (op2) < 0 || INTVAL (op2) > 3)
00822 {
00823 warning ("invalid third arg to __builtin_prefetch; using zero");
00824 op2 = const0_rtx;
00825 }
00826
00827 #ifdef HAVE_prefetch
00828 if (HAVE_prefetch)
00829 {
00830 if ((! (*insn_data[(int) CODE_FOR_prefetch].operand[0].predicate)
00831 (op0,
00832 insn_data[(int) CODE_FOR_prefetch].operand[0].mode))
00833 || (GET_MODE(op0) != Pmode))
00834 {
00835 #ifdef POINTERS_EXTEND_UNSIGNED
00836 if (GET_MODE(op0) != Pmode)
00837 op0 = convert_memory_address (Pmode, op0);
00838 #endif
00839 op0 = force_reg (Pmode, op0);
00840 }
00841 emit_insn (gen_prefetch (op0, op1, op2));
00842 }
00843 else
00844 #endif
00845 op0 = protect_from_queue (op0, 0);
00846
00847
00848 if (GET_CODE (op0) != MEM && side_effects_p (op0))
00849 emit_insn (op0);
00850 }
00851
00852
00853
00854
00855 static rtx
00856 get_memory_rtx (exp)
00857 tree exp;
00858 {
00859 rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_SUM);
00860 rtx mem;
00861
00862 #ifdef POINTERS_EXTEND_UNSIGNED
00863 if (GET_MODE (addr) != Pmode)
00864 addr = convert_memory_address (Pmode, addr);
00865 #endif
00866
00867 mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
00868
00869
00870
00871
00872 while ((TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
00873 || TREE_CODE (exp) == NON_LVALUE_EXPR)
00874 && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
00875 exp = TREE_OPERAND (exp, 0);
00876
00877 if (TREE_CODE (exp) == ADDR_EXPR)
00878 {
00879 exp = TREE_OPERAND (exp, 0);
00880 set_mem_attributes (mem, exp, 0);
00881 }
00882 else if (POINTER_TYPE_P (TREE_TYPE (exp)))
00883 {
00884 exp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (exp)), exp);
00885
00886 set_mem_alias_set (mem, 0);
00887 }
00888
00889 return mem;
00890 }
00891
00892
00893
00894
00895
00896
00897
00898
00899 static enum machine_mode apply_args_mode[FIRST_PSEUDO_REGISTER];
00900
00901
00902
00903
00904
00905
00906 static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER];
00907
00908
00909
00910
00911
00912 static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
00913
00914
00915
00916
00917
00918 int
00919 apply_args_register_offset (regno)
00920 int regno;
00921 {
00922 apply_args_size ();
00923
00924
00925
00926 #ifdef OUTGOING_REGNO
00927 regno = OUTGOING_REGNO (regno);
00928 #endif
00929 return apply_args_reg_offset[regno];
00930 }
00931
00932
00933
00934
00935 static int
00936 apply_args_size ()
00937 {
00938 static int size = -1;
00939 int align;
00940 unsigned int regno;
00941 enum machine_mode mode;
00942
00943
00944 if (size < 0)
00945 {
00946
00947 size = GET_MODE_SIZE (Pmode);
00948
00949
00950
00951 if (struct_value_rtx)
00952 size += GET_MODE_SIZE (Pmode);
00953
00954 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
00955 if (FUNCTION_ARG_REGNO_P (regno))
00956 {
00957
00958
00959 enum machine_mode best_mode = VOIDmode;
00960
00961 for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
00962 mode != VOIDmode;
00963 mode = GET_MODE_WIDER_MODE (mode))
00964 if (HARD_REGNO_MODE_OK (regno, mode)
00965 && HARD_REGNO_NREGS (regno, mode) == 1)
00966 best_mode = mode;
00967
00968 if (best_mode == VOIDmode)
00969 for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
00970 mode != VOIDmode;
00971 mode = GET_MODE_WIDER_MODE (mode))
00972 if (HARD_REGNO_MODE_OK (regno, mode)
00973 && have_insn_for (SET, mode))
00974 best_mode = mode;
00975
00976 if (best_mode == VOIDmode)
00977 for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
00978 mode != VOIDmode;
00979 mode = GET_MODE_WIDER_MODE (mode))
00980 if (HARD_REGNO_MODE_OK (regno, mode)
00981 && have_insn_for (SET, mode))
00982 best_mode = mode;
00983
00984 if (best_mode == VOIDmode)
00985 for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
00986 mode != VOIDmode;
00987 mode = GET_MODE_WIDER_MODE (mode))
00988 if (HARD_REGNO_MODE_OK (regno, mode)
00989 && have_insn_for (SET, mode))
00990 best_mode = mode;
00991
00992 mode = best_mode;
00993 if (mode == VOIDmode)
00994 abort ();
00995
00996 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
00997 if (size % align != 0)
00998 size = CEIL (size, align) * align;
00999 apply_args_reg_offset[regno] = size;
01000 size += GET_MODE_SIZE (mode);
01001 apply_args_mode[regno] = mode;
01002 }
01003 else
01004 {
01005 apply_args_mode[regno] = VOIDmode;
01006 apply_args_reg_offset[regno] = 0;
01007 }
01008 }
01009 return size;
01010 }
01011
01012
01013
01014
01015 static int
01016 apply_result_size ()
01017 {
01018 static int size = -1;
01019 int align, regno;
01020 enum machine_mode mode;
01021
01022
01023 if (size < 0)
01024 {
01025 size = 0;
01026
01027 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01028 if (FUNCTION_VALUE_REGNO_P (regno))
01029 {
01030
01031
01032 enum machine_mode best_mode = VOIDmode;
01033
01034 for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
01035 mode != TImode;
01036 mode = GET_MODE_WIDER_MODE (mode))
01037 if (HARD_REGNO_MODE_OK (regno, mode))
01038 best_mode = mode;
01039
01040 if (best_mode == VOIDmode)
01041 for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
01042 mode != VOIDmode;
01043 mode = GET_MODE_WIDER_MODE (mode))
01044 if (HARD_REGNO_MODE_OK (regno, mode)
01045 && have_insn_for (SET, mode))
01046 best_mode = mode;
01047
01048 if (best_mode == VOIDmode)
01049 for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
01050 mode != VOIDmode;
01051 mode = GET_MODE_WIDER_MODE (mode))
01052 if (HARD_REGNO_MODE_OK (regno, mode)
01053 && have_insn_for (SET, mode))
01054 best_mode = mode;
01055
01056 if (best_mode == VOIDmode)
01057 for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
01058 mode != VOIDmode;
01059 mode = GET_MODE_WIDER_MODE (mode))
01060 if (HARD_REGNO_MODE_OK (regno, mode)
01061 && have_insn_for (SET, mode))
01062 best_mode = mode;
01063
01064 mode = best_mode;
01065 if (mode == VOIDmode)
01066 abort ();
01067
01068 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01069 if (size % align != 0)
01070 size = CEIL (size, align) * align;
01071 size += GET_MODE_SIZE (mode);
01072 apply_result_mode[regno] = mode;
01073 }
01074 else
01075 apply_result_mode[regno] = VOIDmode;
01076
01077
01078
01079 #ifdef APPLY_RESULT_SIZE
01080 size = APPLY_RESULT_SIZE;
01081 #endif
01082 }
01083 return size;
01084 }
01085
01086 #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
01087
01088
01089
01090
01091 static rtx
01092 result_vector (savep, result)
01093 int savep;
01094 rtx result;
01095 {
01096 int regno, size, align, nelts;
01097 enum machine_mode mode;
01098 rtx reg, mem;
01099 rtx *savevec = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
01100
01101 size = nelts = 0;
01102 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01103 if ((mode = apply_result_mode[regno]) != VOIDmode)
01104 {
01105 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01106 if (size % align != 0)
01107 size = CEIL (size, align) * align;
01108 reg = gen_rtx_REG (mode, savep ? regno : INCOMING_REGNO (regno));
01109 mem = adjust_address (result, mode, size);
01110 savevec[nelts++] = (savep
01111 ? gen_rtx_SET (VOIDmode, mem, reg)
01112 : gen_rtx_SET (VOIDmode, reg, mem));
01113 size += GET_MODE_SIZE (mode);
01114 }
01115 return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nelts, savevec));
01116 }
01117 #endif
01118
01119
01120
01121
01122 static rtx
01123 expand_builtin_apply_args_1 ()
01124 {
01125 rtx registers;
01126 int size, align, regno;
01127 enum machine_mode mode;
01128
01129
01130
01131 registers = assign_stack_local (BLKmode, apply_args_size (), -1);
01132
01133
01134 size = GET_MODE_SIZE (Pmode);
01135 if (struct_value_rtx)
01136 size += GET_MODE_SIZE (Pmode);
01137
01138
01139 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01140 if ((mode = apply_args_mode[regno]) != VOIDmode)
01141 {
01142 rtx tem;
01143
01144 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01145 if (size % align != 0)
01146 size = CEIL (size, align) * align;
01147
01148 tem = gen_rtx_REG (mode, INCOMING_REGNO (regno));
01149
01150 emit_move_insn (adjust_address (registers, mode, size), tem);
01151 size += GET_MODE_SIZE (mode);
01152 }
01153
01154
01155 emit_move_insn (adjust_address (registers, Pmode, 0),
01156 copy_to_reg (virtual_incoming_args_rtx));
01157 size = GET_MODE_SIZE (Pmode);
01158
01159
01160
01161 if (struct_value_incoming_rtx)
01162 {
01163 emit_move_insn (adjust_address (registers, Pmode, size),
01164 copy_to_reg (struct_value_incoming_rtx));
01165 size += GET_MODE_SIZE (Pmode);
01166 }
01167
01168
01169 return copy_addr_to_reg (XEXP (registers, 0));
01170 }
01171
01172
01173
01174
01175
01176
01177
01178
01179 static rtx
01180 expand_builtin_apply_args ()
01181 {
01182
01183
01184 if (apply_args_value != 0)
01185 return apply_args_value;
01186 {
01187
01188
01189
01190 rtx temp;
01191 rtx seq;
01192
01193 start_sequence ();
01194 temp = expand_builtin_apply_args_1 ();
01195 seq = get_insns ();
01196 end_sequence ();
01197
01198 apply_args_value = temp;
01199
01200
01201
01202
01203
01204 push_topmost_sequence ();
01205 emit_insn_before (seq, NEXT_INSN (get_insns ()));
01206 pop_topmost_sequence ();
01207 return temp;
01208 }
01209 }
01210
01211
01212
01213
01214 static rtx
01215 expand_builtin_apply (function, arguments, argsize)
01216 rtx function, arguments, argsize;
01217 {
01218 int size, align, regno;
01219 enum machine_mode mode;
01220 rtx incoming_args, result, reg, dest, src, call_insn;
01221 rtx old_stack_level = 0;
01222 rtx call_fusage = 0;
01223
01224 #ifdef POINTERS_EXTEND_UNSIGNED
01225 if (GET_MODE (arguments) != Pmode)
01226 arguments = convert_memory_address (Pmode, arguments);
01227 #endif
01228
01229
01230 result = assign_stack_local (BLKmode, apply_result_size (), -1);
01231
01232
01233 incoming_args = gen_reg_rtx (Pmode);
01234 emit_move_insn (incoming_args, gen_rtx_MEM (Pmode, arguments));
01235 #ifndef STACK_GROWS_DOWNWARD
01236 incoming_args = expand_simple_binop (Pmode, MINUS, incoming_args, argsize,
01237 incoming_args, 0, OPTAB_LIB_WIDEN);
01238 #endif
01239
01240
01241 emit_queue ();
01242
01243
01244
01245
01246 do_pending_stack_adjust ();
01247 NO_DEFER_POP;
01248
01249
01250 #ifdef HAVE_save_stack_nonlocal
01251 if (HAVE_save_stack_nonlocal)
01252 emit_stack_save (SAVE_NONLOCAL, &old_stack_level, NULL_RTX);
01253 else
01254 #endif
01255 emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
01256
01257
01258
01259
01260
01261
01262 dest = allocate_dynamic_stack_space (argsize, 0, BITS_PER_UNIT);
01263 dest = gen_rtx_MEM (BLKmode, dest);
01264 set_mem_align (dest, PARM_BOUNDARY);
01265 src = gen_rtx_MEM (BLKmode, incoming_args);
01266 set_mem_align (src, PARM_BOUNDARY);
01267 emit_block_move (dest, src, argsize, BLOCK_OP_NORMAL);
01268
01269
01270 apply_args_size ();
01271 arguments = gen_rtx_MEM (BLKmode, arguments);
01272 set_mem_align (arguments, PARM_BOUNDARY);
01273
01274
01275 size = GET_MODE_SIZE (Pmode);
01276 if (struct_value_rtx)
01277 size += GET_MODE_SIZE (Pmode);
01278
01279
01280
01281 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01282 if ((mode = apply_args_mode[regno]) != VOIDmode)
01283 {
01284 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01285 if (size % align != 0)
01286 size = CEIL (size, align) * align;
01287 reg = gen_rtx_REG (mode, regno);
01288 emit_move_insn (reg, adjust_address (arguments, mode, size));
01289 use_reg (&call_fusage, reg);
01290 size += GET_MODE_SIZE (mode);
01291 }
01292
01293
01294
01295 size = GET_MODE_SIZE (Pmode);
01296 if (struct_value_rtx)
01297 {
01298 rtx value = gen_reg_rtx (Pmode);
01299 emit_move_insn (value, adjust_address (arguments, Pmode, size));
01300 emit_move_insn (struct_value_rtx, value);
01301 if (GET_CODE (struct_value_rtx) == REG)
01302 use_reg (&call_fusage, struct_value_rtx);
01303 size += GET_MODE_SIZE (Pmode);
01304 }
01305
01306
01307 function = prepare_call_address (function, NULL_TREE, &call_fusage, 0, 0);
01308
01309
01310
01311
01312 if (GET_CODE (function) != SYMBOL_REF)
01313 function = memory_address (FUNCTION_MODE, function);
01314
01315
01316 #ifdef HAVE_untyped_call
01317 if (HAVE_untyped_call)
01318 emit_call_insn (gen_untyped_call (gen_rtx_MEM (FUNCTION_MODE, function),
01319 result, result_vector (1, result)));
01320 else
01321 #endif
01322 #ifdef HAVE_call_value
01323 if (HAVE_call_value)
01324 {
01325 rtx valreg = 0;
01326
01327
01328
01329
01330
01331 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01332 if ((mode = apply_result_mode[regno]) != VOIDmode)
01333 {
01334 if (valreg)
01335 abort ();
01336 valreg = gen_rtx_REG (mode, regno);
01337 }
01338
01339 emit_call_insn (GEN_CALL_VALUE (valreg,
01340 gen_rtx_MEM (FUNCTION_MODE, function),
01341 const0_rtx, NULL_RTX, const0_rtx));
01342
01343 emit_move_insn (adjust_address (result, GET_MODE (valreg), 0), valreg);
01344 }
01345 else
01346 #endif
01347 abort ();
01348
01349
01350 for (call_insn = get_last_insn ();
01351 call_insn && GET_CODE (call_insn) != CALL_INSN;
01352 call_insn = PREV_INSN (call_insn))
01353 ;
01354
01355 if (! call_insn)
01356 abort ();
01357
01358
01359
01360 if (CALL_INSN_FUNCTION_USAGE (call_insn))
01361 {
01362 rtx link;
01363
01364 for (link = CALL_INSN_FUNCTION_USAGE (call_insn); XEXP (link, 1) != 0;
01365 link = XEXP (link, 1))
01366 ;
01367
01368 XEXP (link, 1) = call_fusage;
01369 }
01370 else
01371 CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage;
01372
01373
01374 #ifdef HAVE_save_stack_nonlocal
01375 if (HAVE_save_stack_nonlocal)
01376 emit_stack_restore (SAVE_NONLOCAL, old_stack_level, NULL_RTX);
01377 else
01378 #endif
01379 emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
01380
01381 OK_DEFER_POP;
01382
01383
01384 return copy_addr_to_reg (XEXP (result, 0));
01385 }
01386
01387
01388
01389 static void
01390 expand_builtin_return (result)
01391 rtx result;
01392 {
01393 int size, align, regno;
01394 enum machine_mode mode;
01395 rtx reg;
01396 rtx call_fusage = 0;
01397
01398 #ifdef POINTERS_EXTEND_UNSIGNED
01399 if (GET_MODE (result) != Pmode)
01400 result = convert_memory_address (Pmode, result);
01401 #endif
01402
01403 apply_result_size ();
01404 result = gen_rtx_MEM (BLKmode, result);
01405
01406 #ifdef HAVE_untyped_return
01407 if (HAVE_untyped_return)
01408 {
01409 emit_jump_insn (gen_untyped_return (result, result_vector (0, result)));
01410 emit_barrier ();
01411 return;
01412 }
01413 #endif
01414
01415
01416 size = 0;
01417 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
01418 if ((mode = apply_result_mode[regno]) != VOIDmode)
01419 {
01420 align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
01421 if (size % align != 0)
01422 size = CEIL (size, align) * align;
01423 reg = gen_rtx_REG (mode, INCOMING_REGNO (regno));
01424 emit_move_insn (reg, adjust_address (result, mode, size));
01425
01426 push_to_sequence (call_fusage);
01427 emit_insn (gen_rtx_USE (VOIDmode, reg));
01428 call_fusage = get_insns ();
01429 end_sequence ();
01430 size += GET_MODE_SIZE (mode);
01431 }
01432
01433
01434 emit_insn (call_fusage);
01435
01436
01437
01438 expand_null_return ();
01439 }
01440
01441
01442
01443 static enum type_class
01444 type_to_class (type)
01445 tree type;
01446 {
01447 switch (TREE_CODE (type))
01448 {
01449 case VOID_TYPE: return void_type_class;
01450 case INTEGER_TYPE: return integer_type_class;
01451 case CHAR_TYPE: return char_type_class;
01452 case ENUMERAL_TYPE: return enumeral_type_class;
01453 case BOOLEAN_TYPE: return boolean_type_class;
01454 case POINTER_TYPE: return pointer_type_class;
01455 case REFERENCE_TYPE: return reference_type_class;
01456 case OFFSET_TYPE: return offset_type_class;
01457 case REAL_TYPE: return real_type_class;
01458 case COMPLEX_TYPE: return complex_type_class;
01459 case FUNCTION_TYPE: return function_type_class;
01460 case METHOD_TYPE: return method_type_class;
01461 case RECORD_TYPE: return record_type_class;
01462 case UNION_TYPE:
01463 case QUAL_UNION_TYPE: return union_type_class;
01464 case ARRAY_TYPE: return (TYPE_STRING_FLAG (type)
01465 ? string_type_class : array_type_class);
01466 case SET_TYPE: return set_type_class;
01467 case FILE_TYPE: return file_type_class;
01468 case LANG_TYPE: return lang_type_class;
01469 default: return no_type_class;
01470 }
01471 }
01472
01473
01474
01475
01476 static rtx
01477 expand_builtin_classify_type (arglist)
01478 tree arglist;
01479 {
01480 if (arglist != 0)
01481 return GEN_INT (type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
01482 return GEN_INT (no_type_class);
01483 }
01484
01485
01486
01487 static rtx
01488 expand_builtin_constant_p (exp)
01489 tree exp;
01490 {
01491 tree arglist = TREE_OPERAND (exp, 1);
01492 enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp));
01493 rtx tmp;
01494
01495 if (arglist == 0)
01496 return const0_rtx;
01497 arglist = TREE_VALUE (arglist);
01498
01499
01500
01501
01502
01503 tmp = expand_expr (arglist, NULL_RTX, VOIDmode, 0);
01504 tmp = gen_rtx_CONSTANT_P_RTX (value_mode, tmp);
01505 return tmp;
01506 }
01507
01508
01509
01510
01511
01512
01513
01514 static rtx
01515 expand_builtin_mathfn (exp, target, subtarget)
01516 tree exp;
01517 rtx target, subtarget;
01518 {
01519 optab builtin_optab;
01520 rtx op0, insns;
01521 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
01522 tree arglist = TREE_OPERAND (exp, 1);
01523 enum machine_mode argmode;
01524
01525 if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
01526 return 0;
01527
01528
01529 if (TREE_CODE (TREE_VALUE (arglist)) != VAR_DECL
01530 && TREE_CODE (TREE_VALUE (arglist)) != PARM_DECL)
01531 {
01532 exp = copy_node (exp);
01533 TREE_OPERAND (exp, 1) = arglist;
01534
01535
01536
01537
01538
01539
01540
01541 TREE_VALUE (arglist) = save_expr (TREE_VALUE (arglist));
01542 arglist = copy_node (arglist);
01543 }
01544 op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
01545
01546
01547 target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
01548
01549 emit_queue ();
01550 start_sequence ();
01551
01552 switch (DECL_FUNCTION_CODE (fndecl))
01553 {
01554 case BUILT_IN_SIN:
01555 case BUILT_IN_SINF:
01556 case BUILT_IN_SINL:
01557 builtin_optab = sin_optab; break;
01558 case BUILT_IN_COS:
01559 case BUILT_IN_COSF:
01560 case BUILT_IN_COSL:
01561 builtin_optab = cos_optab; break;
01562 #ifdef KEY
01563 case BUILT_IN_FLOOR:
01564 case BUILT_IN_FLOORF:
01565 case BUILT_IN_FLOORL:
01566 case BUILT_IN_POW:
01567 case BUILT_IN_TAN:
01568 #endif
01569 case BUILT_IN_SQRT:
01570 case BUILT_IN_SQRTF:
01571 case BUILT_IN_SQRTL:
01572 builtin_optab = sqrt_optab; break;
01573 case BUILT_IN_EXP:
01574 case BUILT_IN_EXPF:
01575 case BUILT_IN_EXPL:
01576 builtin_optab = exp_optab; break;
01577 case BUILT_IN_LOG:
01578 case BUILT_IN_LOGF:
01579 case BUILT_IN_LOGL:
01580 builtin_optab = log_optab; break;
01581 default:
01582 abort ();
01583 }
01584
01585
01586
01587 argmode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
01588 target = expand_unop (argmode, builtin_optab, op0, target, 0);
01589
01590
01591
01592
01593 if (target == 0)
01594 {
01595 end_sequence ();
01596 return 0;
01597 }
01598
01599
01600
01601 if (flag_errno_math && HONOR_NANS (argmode))
01602 {
01603 rtx lab1;
01604
01605 lab1 = gen_label_rtx ();
01606
01607
01608
01609 emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
01610 0, lab1);
01611
01612 #ifdef TARGET_EDOM
01613 {
01614 #ifdef GEN_ERRNO_RTX
01615 rtx errno_rtx = GEN_ERRNO_RTX;
01616 #else
01617 rtx errno_rtx
01618 = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
01619 #endif
01620
01621 emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
01622 }
01623 #else
01624
01625
01626 NO_DEFER_POP;
01627 expand_call (exp, target, 0);
01628 OK_DEFER_POP;
01629 #endif
01630
01631 emit_label (lab1);
01632 }
01633
01634
01635 insns = get_insns ();
01636 end_sequence ();
01637 emit_insn (insns);
01638
01639 return target;
01640 }
01641
01642
01643
01644
01645
01646 static rtx
01647 expand_builtin_strlen (exp, target)
01648 tree exp;
01649 rtx target;
01650 {
01651 tree arglist = TREE_OPERAND (exp, 1);
01652 enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp));
01653
01654 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
01655 return 0;
01656 else
01657 {
01658 rtx pat;
01659 tree len, src = TREE_VALUE (arglist);
01660 rtx result, src_reg, char_rtx, before_strlen;
01661 enum machine_mode insn_mode = value_mode, char_mode;
01662 enum insn_code icode = CODE_FOR_nothing;
01663 int align;
01664
01665
01666 len = c_strlen (src, 0);
01667 if (len)
01668 return expand_expr (len, target, value_mode, EXPAND_NORMAL);
01669
01670
01671
01672
01673
01674
01675 len = c_strlen (src, 1);
01676 if (len && TREE_CODE (len) == INTEGER_CST)
01677 {
01678 expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
01679 return expand_expr (len, target, value_mode, EXPAND_NORMAL);
01680 }
01681
01682 align = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
01683
01684
01685 if (align == 0)
01686 return 0;
01687
01688
01689 while (insn_mode != VOIDmode)
01690 {
01691 icode = strlen_optab->handlers[(int) insn_mode].insn_code;
01692 if (icode != CODE_FOR_nothing)
01693 break;
01694
01695 insn_mode = GET_MODE_WIDER_MODE (insn_mode);
01696 }
01697 if (insn_mode == VOIDmode)
01698 return 0;
01699
01700
01701 result = target;
01702 if (! (result != 0
01703 && GET_CODE (result) == REG
01704 && GET_MODE (result) == insn_mode
01705 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
01706 result = gen_reg_rtx (insn_mode);
01707
01708
01709
01710
01711 src_reg = gen_reg_rtx (Pmode);
01712
01713
01714
01715 before_strlen = get_last_insn ();
01716
01717 char_rtx = const0_rtx;
01718 char_mode = insn_data[(int) icode].operand[2].mode;
01719 if (! (*insn_data[(int) icode].operand[2].predicate) (char_rtx,
01720 char_mode))
01721 char_rtx = copy_to_mode_reg (char_mode, char_rtx);
01722
01723 pat = GEN_FCN (icode) (result, gen_rtx_MEM (BLKmode, src_reg),
01724 char_rtx, GEN_INT (align));
01725 if (! pat)
01726 return 0;
01727 emit_insn (pat);
01728
01729
01730 start_sequence ();
01731 pat = memory_address (BLKmode,
01732 expand_expr (src, src_reg, ptr_mode, EXPAND_SUM));
01733 if (pat != src_reg)
01734 emit_move_insn (src_reg, pat);
01735 pat = get_insns ();
01736 end_sequence ();
01737
01738 if (before_strlen)
01739 emit_insn_after (pat, before_strlen);
01740 else
01741 emit_insn_before (pat, get_insns ());
01742
01743
01744 if (GET_MODE (result) == value_mode)
01745 target = result;
01746 else if (target != 0)
01747 convert_move (target, result, 0);
01748 else
01749 target = convert_to_mode (value_mode, result, 0);
01750
01751 return target;
01752 }
01753 }
01754
01755
01756
01757
01758
01759 static rtx
01760 expand_builtin_strstr (arglist, target, mode)
01761 tree arglist;
01762 rtx target;
01763 enum machine_mode mode;
01764 {
01765 #ifndef SGI_MONGOOSE
01766 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
01767 return 0;
01768 else
01769 {
01770 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
01771 tree fn;
01772 const char *p1, *p2;
01773
01774 p2 = c_getstr (s2);
01775 if (p2 == NULL)
01776 return 0;
01777
01778 p1 = c_getstr (s1);
01779 if (p1 != NULL)
01780 {
01781 const char *r = strstr (p1, p2);
01782
01783 if (r == NULL)
01784 return const0_rtx;
01785
01786
01787 return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
01788 s1, ssize_int (r - p1))),
01789 target, mode, EXPAND_NORMAL);
01790 }
01791
01792 if (p2[0] == '\0')
01793 return expand_expr (s1, target, mode, EXPAND_NORMAL);
01794
01795 if (p2[1] != '\0')
01796 return 0;
01797
01798 fn = built_in_decls[BUILT_IN_STRCHR];
01799 if (!fn)
01800 return 0;
01801
01802
01803
01804 arglist =
01805 build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
01806 arglist = tree_cons (NULL_TREE, s1, arglist);
01807 return expand_expr (build_function_call_expr (fn, arglist),
01808 target, mode, EXPAND_NORMAL);
01809 }
01810 #else
01811 return 0;
01812 #endif
01813 }
01814
01815
01816
01817
01818
01819 static rtx
01820 expand_builtin_strchr (arglist, target, mode)
01821 tree arglist;
01822 rtx target;
01823 enum machine_mode mode;
01824 {
01825 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
01826 return 0;
01827 else
01828 {
01829 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
01830 const char *p1;
01831
01832 if (TREE_CODE (s2) != INTEGER_CST)
01833 return 0;
01834
01835 p1 = c_getstr (s1);
01836 if (p1 != NULL)
01837 {
01838 char c;
01839 const char *r;
01840
01841 if (target_char_cast (s2, &c))
01842 return 0;
01843
01844 r = strchr (p1, c);
01845
01846 if (r == NULL)
01847 return const0_rtx;
01848
01849
01850 return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
01851 s1, ssize_int (r - p1))),
01852 target, mode, EXPAND_NORMAL);
01853 }
01854
01855
01856
01857 return 0;
01858 }
01859 }
01860
01861
01862
01863
01864
01865 static rtx
01866 expand_builtin_strrchr (arglist, target, mode)
01867 tree arglist;
01868 rtx target;
01869 enum machine_mode mode;
01870 {
01871 #ifndef SGI_MONGOOSE
01872 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
01873 return 0;
01874 else
01875 {
01876 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
01877 tree fn;
01878 const char *p1;
01879
01880 if (TREE_CODE (s2) != INTEGER_CST)
01881 return 0;
01882
01883 p1 = c_getstr (s1);
01884 if (p1 != NULL)
01885 {
01886 char c;
01887 const char *r;
01888
01889 if (target_char_cast (s2, &c))
01890 return 0;
01891
01892 r = strrchr (p1, c);
01893
01894 if (r == NULL)
01895 return const0_rtx;
01896
01897
01898 return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
01899 s1, ssize_int (r - p1))),
01900 target, mode, EXPAND_NORMAL);
01901 }
01902
01903 if (! integer_zerop (s2))
01904 return 0;
01905
01906 fn = built_in_decls[BUILT_IN_STRCHR];
01907 if (!fn)
01908 return 0;
01909
01910
01911 return expand_expr (build_function_call_expr (fn, arglist),
01912 target, mode, EXPAND_NORMAL);
01913 }
01914 #else
01915 return 0;
01916 #endif
01917 }
01918
01919
01920
01921
01922
01923 static rtx
01924 expand_builtin_strpbrk (arglist, target, mode)
01925 tree arglist;
01926 rtx target;
01927 enum machine_mode mode;
01928 {
01929 #ifndef SGI_MONGOOSE
01930 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
01931 return 0;
01932 else
01933 {
01934 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
01935 tree fn;
01936 const char *p1, *p2;
01937
01938 p2 = c_getstr (s2);
01939 if (p2 == NULL)
01940 return 0;
01941
01942 p1 = c_getstr (s1);
01943 if (p1 != NULL)
01944 {
01945 const char *r = strpbrk (p1, p2);
01946
01947 if (r == NULL)
01948 return const0_rtx;
01949
01950
01951 return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
01952 s1, ssize_int (r - p1))),
01953 target, mode, EXPAND_NORMAL);
01954 }
01955
01956 if (p2[0] == '\0')
01957 {
01958
01959
01960
01961 expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
01962 return const0_rtx;
01963 }
01964
01965 if (p2[1] != '\0')
01966 return 0;
01967
01968 fn = built_in_decls[BUILT_IN_STRCHR];
01969 if (!fn)
01970 return 0;
01971
01972
01973
01974 arglist =
01975 build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
01976 arglist = tree_cons (NULL_TREE, s1, arglist);
01977 return expand_expr (build_function_call_expr (fn, arglist),
01978 target, mode, EXPAND_NORMAL);
01979 }
01980 #else
01981 return 0;
01982 #endif
01983 }
01984
01985
01986
01987
01988
01989 static rtx
01990 builtin_memcpy_read_str (data, offset, mode)
01991 PTR data;
01992 HOST_WIDE_INT offset;
01993 enum machine_mode mode;
01994 {
01995 const char *str = (const char *) data;
01996
01997 if (offset < 0
01998 || ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode)
01999 > strlen (str) + 1))
02000 abort ();
02001
02002 return c_readstr (str + offset, mode);
02003 }
02004
02005
02006
02007
02008
02009 static rtx
02010 expand_builtin_memcpy (arglist, target, mode)
02011 tree arglist;
02012 rtx target;
02013 enum machine_mode mode;
02014 {
02015 if (!validate_arglist (arglist,
02016 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02017 return 0;
02018 else
02019 {
02020 tree dest = TREE_VALUE (arglist);
02021 tree src = TREE_VALUE (TREE_CHAIN (arglist));
02022 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02023 const char *src_str;
02024 unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
02025 unsigned int dest_align
02026 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
02027 rtx dest_mem, src_mem, dest_addr, len_rtx;
02028
02029
02030 if (dest_align == 0)
02031 return 0;
02032
02033
02034 if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
02035 {
02036
02037 expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
02038 return expand_expr (dest, target, mode, EXPAND_NORMAL);
02039 }
02040
02041
02042
02043 if (src_align == 0)
02044 return 0;
02045
02046 dest_mem = get_memory_rtx (dest);
02047 set_mem_align (dest_mem, dest_align);
02048 len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
02049 src_str = c_getstr (src);
02050
02051
02052
02053
02054 if (src_str
02055 && GET_CODE (len_rtx) == CONST_INT
02056 && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
02057 && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
02058 (PTR) src_str, dest_align))
02059 {
02060 dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
02061 builtin_memcpy_read_str,
02062 (PTR) src_str, dest_align, 0);
02063 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02064 #ifdef POINTERS_EXTEND_UNSIGNED
02065 if (GET_MODE (dest_mem) != ptr_mode)
02066 dest_mem = convert_memory_address (ptr_mode, dest_mem);
02067 #endif
02068 return dest_mem;
02069 }
02070
02071 src_mem = get_memory_rtx (src);
02072 set_mem_align (src_mem, src_align);
02073
02074
02075 dest_addr = emit_block_move (dest_mem, src_mem, len_rtx,
02076 BLOCK_OP_NORMAL);
02077
02078 if (dest_addr == 0)
02079 {
02080 dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02081 #ifdef POINTERS_EXTEND_UNSIGNED
02082 if (GET_MODE (dest_addr) != ptr_mode)
02083 dest_addr = convert_memory_address (ptr_mode, dest_addr);
02084 #endif
02085 }
02086 return dest_addr;
02087 }
02088 }
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098 static rtx
02099 expand_builtin_mempcpy (arglist, target, mode, endp)
02100 tree arglist;
02101 rtx target;
02102 enum machine_mode mode;
02103 int endp;
02104 {
02105 if (!validate_arglist (arglist,
02106 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02107 return 0;
02108
02109 else if (target == const0_rtx)
02110 {
02111 tree fn = built_in_decls[BUILT_IN_MEMCPY];
02112
02113 if (!fn)
02114 return 0;
02115
02116 return expand_expr (build_function_call_expr (fn, arglist),
02117 target, mode, EXPAND_NORMAL);
02118 }
02119 else
02120 {
02121 tree dest = TREE_VALUE (arglist);
02122 tree src = TREE_VALUE (TREE_CHAIN (arglist));
02123 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02124 const char *src_str;
02125 unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
02126 unsigned int dest_align
02127 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
02128 rtx dest_mem, src_mem, len_rtx;
02129
02130
02131
02132 if (dest_align == 0 || !host_integerp (len, 1))
02133 return 0;
02134
02135
02136 if (tree_low_cst (len, 1) == 0)
02137 {
02138
02139 expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
02140 return expand_expr (dest, target, mode, EXPAND_NORMAL);
02141 }
02142
02143
02144
02145 if (src_align == 0)
02146 return 0;
02147
02148 len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
02149 src_str = c_getstr (src);
02150
02151
02152
02153
02154 if (src_str
02155 && GET_CODE (len_rtx) == CONST_INT
02156 && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
02157 && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
02158 (PTR) src_str, dest_align))
02159 {
02160 dest_mem = get_memory_rtx (dest);
02161 set_mem_align (dest_mem, dest_align);
02162 dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
02163 builtin_memcpy_read_str,
02164 (PTR) src_str, dest_align, endp);
02165 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02166 #ifdef POINTERS_EXTEND_UNSIGNED
02167 if (GET_MODE (dest_mem) != ptr_mode)
02168 dest_mem = convert_memory_address (ptr_mode, dest_mem);
02169 #endif
02170 return dest_mem;
02171 }
02172
02173 if (GET_CODE (len_rtx) == CONST_INT
02174 && can_move_by_pieces (INTVAL (len_rtx),
02175 MIN (dest_align, src_align)))
02176 {
02177 dest_mem = get_memory_rtx (dest);
02178 set_mem_align (dest_mem, dest_align);
02179 src_mem = get_memory_rtx (src);
02180 set_mem_align (src_mem, src_align);
02181 dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx),
02182 MIN (dest_align, src_align), endp);
02183 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02184 #ifdef POINTERS_EXTEND_UNSIGNED
02185 if (GET_MODE (dest_mem) != ptr_mode)
02186 dest_mem = convert_memory_address (ptr_mode, dest_mem);
02187 #endif
02188 return dest_mem;
02189 }
02190
02191 return 0;
02192 }
02193 }
02194
02195
02196
02197
02198 static rtx
02199 expand_builtin_memmove (arglist, target, mode)
02200 tree arglist;
02201 rtx target;
02202 enum machine_mode mode;
02203 {
02204 if (!validate_arglist (arglist,
02205 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02206 return 0;
02207 else
02208 {
02209 tree dest = TREE_VALUE (arglist);
02210 tree src = TREE_VALUE (TREE_CHAIN (arglist));
02211 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02212
02213 unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
02214 unsigned int dest_align
02215 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
02216
02217
02218 if (dest_align == 0)
02219 return 0;
02220
02221
02222 if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
02223 {
02224
02225 expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
02226 return expand_expr (dest, target, mode, EXPAND_NORMAL);
02227 }
02228
02229
02230
02231 if (src_align == 0)
02232 return 0;
02233
02234
02235
02236 if (readonly_data_expr (src))
02237 {
02238 tree const fn = built_in_decls[BUILT_IN_MEMCPY];
02239 if (!fn)
02240 return 0;
02241 return expand_expr (build_function_call_expr (fn, arglist),
02242 target, mode, EXPAND_NORMAL);
02243 }
02244
02245
02246 return 0;
02247 }
02248 }
02249
02250
02251
02252
02253 static rtx
02254 expand_builtin_bcopy (arglist)
02255 tree arglist;
02256 {
02257 tree src, dest, size, newarglist;
02258
02259 if (!validate_arglist (arglist,
02260 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02261 return NULL_RTX;
02262
02263 src = TREE_VALUE (arglist);
02264 dest = TREE_VALUE (TREE_CHAIN (arglist));
02265 size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02266
02267
02268
02269
02270
02271
02272 newarglist = build_tree_list (NULL_TREE, convert (sizetype, size));
02273 newarglist = tree_cons (NULL_TREE, src, newarglist);
02274 newarglist = tree_cons (NULL_TREE, dest, newarglist);
02275
02276 return expand_builtin_memmove (newarglist, const0_rtx, VOIDmode);
02277 }
02278
02279
02280
02281
02282
02283
02284 static rtx
02285 expand_builtin_strcpy (exp, target, mode)
02286 tree exp;
02287 rtx target;
02288 enum machine_mode mode;
02289 {
02290 tree arglist = TREE_OPERAND (exp, 1);
02291 tree fn, len, src, dst;
02292
02293 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
02294 return 0;
02295
02296 fn = built_in_decls[BUILT_IN_MEMCPY];
02297 if (!fn)
02298 return 0;
02299
02300 src = TREE_VALUE (TREE_CHAIN (arglist));
02301 len = c_strlen (src, 1);
02302 if (len == 0 || TREE_SIDE_EFFECTS (len))
02303 return 0;
02304
02305 dst = TREE_VALUE (arglist);
02306 len = size_binop (PLUS_EXPR, len, ssize_int (1));
02307 arglist = build_tree_list (NULL_TREE, len);
02308 arglist = tree_cons (NULL_TREE, src, arglist);
02309 arglist = tree_cons (NULL_TREE, dst, arglist);
02310 return expand_expr (build_function_call_expr (fn, arglist),
02311 target, mode, EXPAND_NORMAL);
02312 }
02313
02314
02315
02316
02317
02318
02319 static rtx
02320 expand_builtin_stpcpy (arglist, target, mode)
02321 tree arglist;
02322 rtx target;
02323 enum machine_mode mode;
02324 {
02325 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
02326 return 0;
02327 else
02328 {
02329 tree newarglist;
02330 tree src, len;
02331
02332
02333 if (target == const0_rtx)
02334 {
02335 tree fn = built_in_decls[BUILT_IN_STRCPY];
02336 if (!fn)
02337 return 0;
02338
02339 return expand_expr (build_function_call_expr (fn, arglist),
02340 target, mode, EXPAND_NORMAL);
02341 }
02342
02343
02344
02345
02346
02347 src = TREE_VALUE (TREE_CHAIN (arglist));
02348 if (! c_getstr (src) || ! (len = c_strlen (src, 0)))
02349 return 0;
02350
02351 len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
02352 newarglist = copy_list (arglist);
02353 chainon (newarglist, build_tree_list (NULL_TREE, len));
02354 return expand_builtin_mempcpy (newarglist, target, mode, 2);
02355 }
02356 }
02357
02358
02359
02360
02361
02362 static rtx
02363 builtin_strncpy_read_str (data, offset, mode)
02364 PTR data;
02365 HOST_WIDE_INT offset;
02366 enum machine_mode mode;
02367 {
02368 const char *str = (const char *) data;
02369
02370 if ((unsigned HOST_WIDE_INT) offset > strlen (str))
02371 return const0_rtx;
02372
02373 return c_readstr (str + offset, mode);
02374 }
02375
02376
02377
02378
02379 static rtx
02380 expand_builtin_strncpy (arglist, target, mode)
02381 tree arglist;
02382 rtx target;
02383 enum machine_mode mode;
02384 {
02385 if (!validate_arglist (arglist,
02386 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02387 return 0;
02388 else
02389 {
02390 tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)), 1);
02391 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02392 tree fn;
02393
02394
02395 if (TREE_CODE (len) != INTEGER_CST)
02396 return 0;
02397
02398
02399 if (integer_zerop (len))
02400 {
02401
02402
02403 expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx,
02404 VOIDmode, EXPAND_NORMAL);
02405
02406 return expand_expr (TREE_VALUE (arglist), target, mode,
02407 EXPAND_NORMAL);
02408 }
02409
02410
02411 if (slen == 0 || TREE_CODE (slen) != INTEGER_CST)
02412 return 0;
02413
02414 slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
02415
02416
02417
02418
02419 if (tree_int_cst_lt (slen, len))
02420 {
02421 tree dest = TREE_VALUE (arglist);
02422 unsigned int dest_align
02423 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
02424 const char *p = c_getstr (TREE_VALUE (TREE_CHAIN (arglist)));
02425 rtx dest_mem;
02426
02427 if (!p || dest_align == 0 || !host_integerp (len, 1)
02428 || !can_store_by_pieces (tree_low_cst (len, 1),
02429 builtin_strncpy_read_str,
02430 (PTR) p, dest_align))
02431 return 0;
02432
02433 dest_mem = get_memory_rtx (dest);
02434 store_by_pieces (dest_mem, tree_low_cst (len, 1),
02435 builtin_strncpy_read_str,
02436 (PTR) p, dest_align, 0);
02437 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02438 #ifdef POINTERS_EXTEND_UNSIGNED
02439 if (GET_MODE (dest_mem) != ptr_mode)
02440 dest_mem = convert_memory_address (ptr_mode, dest_mem);
02441 #endif
02442 return dest_mem;
02443 }
02444
02445
02446 fn = built_in_decls[BUILT_IN_MEMCPY];
02447 if (!fn)
02448 return 0;
02449 return expand_expr (build_function_call_expr (fn, arglist),
02450 target, mode, EXPAND_NORMAL);
02451 }
02452 }
02453
02454
02455
02456
02457
02458 static rtx
02459 builtin_memset_read_str (data, offset, mode)
02460 PTR data;
02461 HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
02462 enum machine_mode mode;
02463 {
02464 const char *c = (const char *) data;
02465 char *p = alloca (GET_MODE_SIZE (mode));
02466
02467 memset (p, *c, GET_MODE_SIZE (mode));
02468
02469 return c_readstr (p, mode);
02470 }
02471
02472
02473
02474
02475
02476
02477 static rtx
02478 builtin_memset_gen_str (data, offset, mode)
02479 PTR data;
02480 HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
02481 enum machine_mode mode;
02482 {
02483 rtx target, coeff;
02484 size_t size;
02485 char *p;
02486
02487 size = GET_MODE_SIZE (mode);
02488 if (size == 1)
02489 return (rtx) data;
02490
02491 p = alloca (size);
02492 memset (p, 1, size);
02493 coeff = c_readstr (p, mode);
02494
02495 target = convert_to_mode (mode, (rtx) data, 1);
02496 target = expand_mult (mode, target, coeff, NULL_RTX, 1);
02497 return force_reg (mode, target);
02498 }
02499
02500
02501
02502
02503
02504
02505 static rtx
02506 expand_builtin_memset (exp, target, mode)
02507 tree exp;
02508 rtx target;
02509 enum machine_mode mode;
02510 {
02511 tree arglist = TREE_OPERAND (exp, 1);
02512
02513 if (!validate_arglist (arglist,
02514 POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
02515 return 0;
02516 else
02517 {
02518 tree dest = TREE_VALUE (arglist);
02519 tree val = TREE_VALUE (TREE_CHAIN (arglist));
02520 tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02521 char c;
02522
02523 unsigned int dest_align
02524 = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
02525 rtx dest_mem, dest_addr, len_rtx;
02526
02527
02528
02529 if (dest_align == 0)
02530 return 0;
02531
02532
02533 if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
02534 {
02535
02536 expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL);
02537 return expand_expr (dest, target, mode, EXPAND_NORMAL);
02538 }
02539
02540 if (TREE_CODE (val) != INTEGER_CST)
02541 {
02542 rtx val_rtx;
02543
02544 if (!host_integerp (len, 1))
02545 return 0;
02546
02547 if (optimize_size && tree_low_cst (len, 1) > 1)
02548 return 0;
02549
02550
02551
02552
02553 c = 1;
02554 if (!can_store_by_pieces (tree_low_cst (len, 1),
02555 builtin_memset_read_str,
02556 (PTR) &c, dest_align))
02557 return 0;
02558
02559 val = fold (build1 (CONVERT_EXPR, unsigned_char_type_node, val));
02560 val_rtx = expand_expr (val, NULL_RTX, VOIDmode, 0);
02561 val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
02562 val_rtx);
02563 dest_mem = get_memory_rtx (dest);
02564 store_by_pieces (dest_mem, tree_low_cst (len, 1),
02565 builtin_memset_gen_str,
02566 (PTR) val_rtx, dest_align, 0);
02567 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02568 #ifdef POINTERS_EXTEND_UNSIGNED
02569 if (GET_MODE (dest_mem) != ptr_mode)
02570 dest_mem = convert_memory_address (ptr_mode, dest_mem);
02571 #endif
02572 return dest_mem;
02573 }
02574
02575 if (target_char_cast (val, &c))
02576 return 0;
02577
02578 if (c)
02579 {
02580 if (!host_integerp (len, 1))
02581 return 0;
02582 if (!can_store_by_pieces (tree_low_cst (len, 1),
02583 builtin_memset_read_str, (PTR) &c,
02584 dest_align))
02585 return 0;
02586
02587 dest_mem = get_memory_rtx (dest);
02588 store_by_pieces (dest_mem, tree_low_cst (len, 1),
02589 builtin_memset_read_str,
02590 (PTR) &c, dest_align, 0);
02591 dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02592 #ifdef POINTERS_EXTEND_UNSIGNED
02593 if (GET_MODE (dest_mem) != ptr_mode)
02594 dest_mem = convert_memory_address (ptr_mode, dest_mem);
02595 #endif
02596 return dest_mem;
02597 }
02598
02599 len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
02600
02601 dest_mem = get_memory_rtx (dest);
02602 set_mem_align (dest_mem, dest_align);
02603 dest_addr = clear_storage (dest_mem, len_rtx);
02604
02605 if (dest_addr == 0)
02606 {
02607 dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
02608 #ifdef POINTERS_EXTEND_UNSIGNED
02609 if (GET_MODE (dest_addr) != ptr_mode)
02610 dest_addr = convert_memory_address (ptr_mode, dest_addr);
02611 #endif
02612 }
02613
02614 return dest_addr;
02615 }
02616 }
02617
02618
02619
02620
02621 static rtx
02622 expand_builtin_bzero (exp)
02623 tree exp;
02624 {
02625 tree arglist = TREE_OPERAND (exp, 1);
02626 tree dest, size, newarglist;
02627 rtx result;
02628
02629 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02630 return NULL_RTX;
02631
02632 dest = TREE_VALUE (arglist);
02633 size = TREE_VALUE (TREE_CHAIN (arglist));
02634
02635
02636
02637
02638
02639
02640 newarglist = build_tree_list (NULL_TREE, convert (sizetype, size));
02641 newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
02642 newarglist = tree_cons (NULL_TREE, dest, newarglist);
02643
02644 TREE_OPERAND (exp, 1) = newarglist;
02645 result = expand_builtin_memset (exp, const0_rtx, VOIDmode);
02646
02647
02648 TREE_OPERAND (exp, 1) = arglist;
02649
02650 return result;
02651 }
02652
02653
02654
02655
02656
02657
02658 static rtx
02659 expand_builtin_memcmp (exp, arglist, target, mode)
02660 tree exp ATTRIBUTE_UNUSED;
02661 tree arglist;
02662 rtx target;
02663 enum machine_mode mode;
02664 {
02665 tree arg1, arg2, len;
02666 const char *p1, *p2;
02667
02668 if (!validate_arglist (arglist,
02669 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02670 return 0;
02671
02672 arg1 = TREE_VALUE (arglist);
02673 arg2 = TREE_VALUE (TREE_CHAIN (arglist));
02674 len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02675
02676
02677 if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
02678 {
02679
02680
02681 expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
02682 expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
02683 return const0_rtx;
02684 }
02685
02686 p1 = c_getstr (arg1);
02687 p2 = c_getstr (arg2);
02688
02689
02690
02691 if (host_integerp (len, 1) && p1 && p2
02692 && compare_tree_int (len, strlen (p1) + 1) <= 0
02693 && compare_tree_int (len, strlen (p2) + 1) <= 0)
02694 {
02695 const int r = memcmp (p1, p2, tree_low_cst (len, 1));
02696
02697 return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
02698 }
02699
02700
02701
02702 if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
02703 {
02704 tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
02705 tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
02706 tree ind1 =
02707 fold (build1 (CONVERT_EXPR, integer_type_node,
02708 build1 (INDIRECT_REF, cst_uchar_node,
02709 build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
02710 tree ind2 =
02711 fold (build1 (CONVERT_EXPR, integer_type_node,
02712 build1 (INDIRECT_REF, cst_uchar_node,
02713 build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
02714 tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
02715 return expand_expr (result, target, mode, EXPAND_NORMAL);
02716 }
02717
02718 #if defined HAVE_cmpmemsi || defined HAVE_cmpstrsi
02719 {
02720 rtx arg1_rtx, arg2_rtx, arg3_rtx;
02721 rtx result;
02722 rtx insn;
02723
02724 int arg1_align
02725 = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
02726 int arg2_align
02727 = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
02728 enum machine_mode insn_mode;
02729
02730 #ifdef HAVE_cmpmemsi
02731 if (HAVE_cmpmemsi)
02732 insn_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode;
02733 else
02734 #endif
02735 #ifdef HAVE_cmpstrsi
02736 if (HAVE_cmpstrsi)
02737 insn_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
02738 else
02739 #endif
02740 return 0;
02741
02742
02743 if (arg1_align == 0 || arg2_align == 0)
02744 return 0;
02745
02746
02747 result = target;
02748 if (! (result != 0
02749 && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
02750 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
02751 result = gen_reg_rtx (insn_mode);
02752
02753 arg1_rtx = get_memory_rtx (arg1);
02754 arg2_rtx = get_memory_rtx (arg2);
02755 arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
02756 #ifdef HAVE_cmpmemsi
02757 if (HAVE_cmpmemsi)
02758 insn = gen_cmpmemsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
02759 GEN_INT (MIN (arg1_align, arg2_align)));
02760 else
02761 #endif
02762 #ifdef HAVE_cmpstrsi
02763 if (HAVE_cmpstrsi)
02764 insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
02765 GEN_INT (MIN (arg1_align, arg2_align)));
02766 else
02767 #endif
02768 abort ();
02769
02770 if (insn)
02771 emit_insn (insn);
02772 else
02773 emit_library_call_value (memcmp_libfunc, result, LCT_PURE_MAKE_BLOCK,
02774 TYPE_MODE (integer_type_node), 3,
02775 XEXP (arg1_rtx, 0), Pmode,
02776 XEXP (arg2_rtx, 0), Pmode,
02777 convert_to_mode (TYPE_MODE (sizetype), arg3_rtx,
02778 TREE_UNSIGNED (sizetype)),
02779 TYPE_MODE (sizetype));
02780
02781
02782 mode = TYPE_MODE (TREE_TYPE (exp));
02783 if (GET_MODE (result) == mode)
02784 return result;
02785 else if (target != 0)
02786 {
02787 convert_move (target, result, 0);
02788 return target;
02789 }
02790 else
02791 return convert_to_mode (mode, result, 0);
02792 }
02793 #endif
02794
02795 return 0;
02796 }
02797
02798
02799
02800
02801
02802 static rtx
02803 expand_builtin_strcmp (exp, target, mode)
02804 tree exp;
02805 rtx target;
02806 enum machine_mode mode;
02807 {
02808 tree arglist = TREE_OPERAND (exp, 1);
02809 tree arg1, arg2;
02810 const char *p1, *p2;
02811
02812 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
02813 return 0;
02814
02815 arg1 = TREE_VALUE (arglist);
02816 arg2 = TREE_VALUE (TREE_CHAIN (arglist));
02817
02818 p1 = c_getstr (arg1);
02819 p2 = c_getstr (arg2);
02820
02821 if (p1 && p2)
02822 {
02823 const int i = strcmp (p1, p2);
02824 return (i < 0 ? constm1_rtx : (i > 0 ? const1_rtx : const0_rtx));
02825 }
02826
02827
02828
02829 if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
02830 {
02831 tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
02832 tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
02833 tree ind1 =
02834 fold (build1 (CONVERT_EXPR, integer_type_node,
02835 build1 (INDIRECT_REF, cst_uchar_node,
02836 build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
02837 tree ind2 =
02838 fold (build1 (CONVERT_EXPR, integer_type_node,
02839 build1 (INDIRECT_REF, cst_uchar_node,
02840 build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
02841 tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
02842 return expand_expr (result, target, mode, EXPAND_NORMAL);
02843 }
02844
02845 #ifdef HAVE_cmpstrsi
02846 if (HAVE_cmpstrsi)
02847 {
02848 tree len, len1, len2;
02849 rtx arg1_rtx, arg2_rtx, arg3_rtx;
02850 rtx result, insn;
02851
02852 int arg1_align
02853 = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
02854 int arg2_align
02855 = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
02856 enum machine_mode insn_mode
02857 = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
02858
02859 len1 = c_strlen (arg1, 1);
02860 len2 = c_strlen (arg2, 1);
02861
02862 if (len1)
02863 len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
02864 if (len2)
02865 len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
02866
02867
02868
02869
02870
02871
02872
02873
02874 if (!len1)
02875 len = len2;
02876 else if (!len2)
02877 len = len1;
02878 else if (TREE_SIDE_EFFECTS (len1))
02879 len = len2;
02880 else if (TREE_SIDE_EFFECTS (len2))
02881 len = len1;
02882 else if (TREE_CODE (len1) != INTEGER_CST)
02883 len = len2;
02884 else if (TREE_CODE (len2) != INTEGER_CST)
02885 len = len1;
02886 else if (tree_int_cst_lt (len1, len2))
02887 len = len1;
02888 else
02889 len = len2;
02890
02891
02892 if (!len || TREE_SIDE_EFFECTS (len))
02893 return 0;
02894
02895
02896 if (arg1_align == 0 || arg2_align == 0)
02897 return 0;
02898
02899
02900 result = target;
02901 if (! (result != 0
02902 && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
02903 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
02904 result = gen_reg_rtx (insn_mode);
02905
02906 arg1_rtx = get_memory_rtx (arg1);
02907 arg2_rtx = get_memory_rtx (arg2);
02908 arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
02909 insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
02910 GEN_INT (MIN (arg1_align, arg2_align)));
02911 if (!insn)
02912 return 0;
02913
02914 emit_insn (insn);
02915
02916
02917 mode = TYPE_MODE (TREE_TYPE (exp));
02918 if (GET_MODE (result) == mode)
02919 return result;
02920 if (target == 0)
02921 return convert_to_mode (mode, result, 0);
02922 convert_move (target, result, 0);
02923 return target;
02924 }
02925 #endif
02926 return 0;
02927 }
02928
02929
02930
02931
02932
02933 static rtx
02934 expand_builtin_strncmp (exp, target, mode)
02935 tree exp;
02936 rtx target;
02937 enum machine_mode mode;
02938 {
02939 tree arglist = TREE_OPERAND (exp, 1);
02940 tree arg1, arg2, arg3;
02941 const char *p1, *p2;
02942
02943 if (!validate_arglist (arglist,
02944 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
02945 return 0;
02946
02947 arg1 = TREE_VALUE (arglist);
02948 arg2 = TREE_VALUE (TREE_CHAIN (arglist));
02949 arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
02950
02951
02952 if (host_integerp (arg3, 1) && tree_low_cst (arg3, 1) == 0)
02953 {
02954
02955
02956 expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
02957 expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
02958 return const0_rtx;
02959 }
02960
02961 p1 = c_getstr (arg1);
02962 p2 = c_getstr (arg2);
02963
02964
02965 if (host_integerp (arg3, 1) && p1 && p2)
02966 {
02967 const int r = strncmp (p1, p2, tree_low_cst (arg3, 1));
02968 return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
02969 }
02970
02971
02972
02973 if (host_integerp (arg3, 1)
02974 && (tree_low_cst (arg3, 1) == 1
02975 || (tree_low_cst (arg3, 1) > 1
02976 && ((p1 && *p1 == '\0') || (p2 && *p2 == '\0')))))
02977 {
02978 tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
02979 tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
02980 tree ind1 =
02981 fold (build1 (CONVERT_EXPR, integer_type_node,
02982 build1 (INDIRECT_REF, cst_uchar_node,
02983 build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
02984 tree ind2 =
02985 fold (build1 (CONVERT_EXPR, integer_type_node,
02986 build1 (INDIRECT_REF, cst_uchar_node,
02987 build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
02988 tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
02989 return expand_expr (result, target, mode, EXPAND_NORMAL);
02990 }
02991
02992
02993
02994
02995 #ifdef HAVE_cmpstrsi
02996 if (HAVE_cmpstrsi)
02997 {
02998 tree len, len1, len2;
02999 rtx arg1_rtx, arg2_rtx, arg3_rtx;
03000 rtx result, insn;
03001
03002 int arg1_align
03003 = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03004 int arg2_align
03005 = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
03006 enum machine_mode insn_mode
03007 = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
03008
03009 len1 = c_strlen (arg1, 1);
03010 len2 = c_strlen (arg2, 1);
03011
03012 if (len1)
03013 len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
03014 if (len2)
03015 len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
03016
03017
03018
03019
03020
03021
03022
03023
03024 if (!len1)
03025 len = len2;
03026 else if (!len2)
03027 len = len1;
03028 else if (TREE_SIDE_EFFECTS (len1))
03029 len = len2;
03030 else if (TREE_SIDE_EFFECTS (len2))
03031 len = len1;
03032 else if (TREE_CODE (len1) != INTEGER_CST)
03033 len = len2;
03034 else if (TREE_CODE (len2) != INTEGER_CST)
03035 len = len1;
03036 else if (tree_int_cst_lt (len1, len2))
03037 len = len1;
03038 else
03039 len = len2;
03040
03041
03042 if (!len || TREE_SIDE_EFFECTS (len))
03043 return 0;
03044
03045
03046 len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));
03047
03048
03049 if (arg1_align == 0 || arg2_align == 0)
03050 return 0;
03051
03052
03053 result = target;
03054 if (! (result != 0
03055 && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
03056 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
03057 result = gen_reg_rtx (insn_mode);
03058
03059 arg1_rtx = get_memory_rtx (arg1);
03060 arg2_rtx = get_memory_rtx (arg2);
03061 arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
03062 insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
03063 GEN_INT (MIN (arg1_align, arg2_align)));
03064 if (!insn)
03065 return 0;
03066
03067 emit_insn (insn);
03068
03069
03070 mode = TYPE_MODE (TREE_TYPE (exp));
03071 if (GET_MODE (result) == mode)
03072 return result;
03073 if (target == 0)
03074 return convert_to_mode (mode, result, 0);
03075 convert_move (target, result, 0);
03076 return target;
03077 }
03078 #endif
03079 return 0;
03080 }
03081
03082
03083
03084
03085
03086 static rtx
03087 expand_builtin_strcat (arglist, target, mode)
03088 tree arglist;
03089 rtx target;
03090 enum machine_mode mode;
03091 {
03092 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03093 return 0;
03094 else
03095 {
03096 tree dst = TREE_VALUE (arglist),
03097 src = TREE_VALUE (TREE_CHAIN (arglist));
03098 const char *p = c_getstr (src);
03099
03100
03101 if (p && *p == '\0')
03102 return expand_expr (dst, target, mode, EXPAND_NORMAL);
03103
03104 return 0;
03105 }
03106 }
03107
03108
03109
03110
03111
03112 static rtx
03113 expand_builtin_strncat (arglist, target, mode)
03114 tree arglist;
03115 rtx target;
03116 enum machine_mode mode;
03117 {
03118 #ifndef SGI_MONGOOSE
03119 if (!validate_arglist (arglist,
03120 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
03121 return 0;
03122 else
03123 {
03124 tree dst = TREE_VALUE (arglist),
03125 src = TREE_VALUE (TREE_CHAIN (arglist)),
03126 len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
03127 const char *p = c_getstr (src);
03128
03129
03130
03131 if (integer_zerop (len) || (p && *p == '\0'))
03132 {
03133
03134
03135 expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
03136 expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL);
03137 return expand_expr (dst, target, mode, EXPAND_NORMAL);
03138 }
03139
03140
03141
03142 if (TREE_CODE (len) == INTEGER_CST && p
03143 && compare_tree_int (len, strlen (p)) >= 0)
03144 {
03145 tree newarglist
03146 = tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src));
03147 tree fn = built_in_decls[BUILT_IN_STRCAT];
03148
03149
03150
03151 if (!fn)
03152 return 0;
03153
03154 return expand_expr (build_function_call_expr (fn, newarglist),
03155 target, mode, EXPAND_NORMAL);
03156 }
03157 return 0;
03158 }
03159 #else
03160 return 0;
03161 #endif
03162 }
03163
03164
03165
03166
03167
03168 static rtx
03169 expand_builtin_strspn (arglist, target, mode)
03170 tree arglist;
03171 rtx target;
03172 enum machine_mode mode;
03173 {
03174 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03175 return 0;
03176 else
03177 {
03178 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
03179 const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
03180
03181
03182 if (p1 && p2)
03183 {
03184 const size_t r = strspn (p1, p2);
03185 return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
03186 }
03187
03188
03189 if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
03190 {
03191
03192
03193 expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
03194 expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL);
03195 return const0_rtx;
03196 }
03197 return 0;
03198 }
03199 }
03200
03201
03202
03203
03204
03205 static rtx
03206 expand_builtin_strcspn (arglist, target, mode)
03207 tree arglist;
03208 rtx target;
03209 enum machine_mode mode;
03210 {
03211 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03212 return 0;
03213 else
03214 {
03215 tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
03216 const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
03217
03218
03219 if (p1 && p2)
03220 {
03221 const size_t r = strcspn (p1, p2);
03222 return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
03223 }
03224
03225
03226 if (p1 && *p1 == '\0')
03227 {
03228
03229
03230 expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL);
03231 return const0_rtx;
03232 }
03233
03234
03235 if (p2 && *p2 == '\0')
03236 {
03237 tree newarglist = build_tree_list (NULL_TREE, s1),
03238 fn = built_in_decls[BUILT_IN_STRLEN];
03239
03240
03241
03242 if (!fn)
03243 return 0;
03244
03245 return expand_expr (build_function_call_expr (fn, newarglist),
03246 target, mode, EXPAND_NORMAL);
03247 }
03248 return 0;
03249 }
03250 }
03251
03252
03253
03254
03255 rtx
03256 expand_builtin_saveregs ()
03257 {
03258 rtx val, seq;
03259
03260
03261
03262 if (saveregs_value != 0)
03263 return saveregs_value;
03264
03265
03266
03267
03268
03269 start_sequence ();
03270
03271 #ifdef EXPAND_BUILTIN_SAVEREGS
03272
03273 val = EXPAND_BUILTIN_SAVEREGS ();
03274 #else
03275
03276
03277
03278
03279
03280
03281
03282
03283 error ("__builtin_saveregs not supported by this target");
03284 val = const0_rtx;
03285 #endif
03286
03287 seq = get_insns ();
03288 end_sequence ();
03289
03290 saveregs_value = val;
03291
03292
03293
03294
03295 push_topmost_sequence ();
03296 emit_insn_after (seq, get_insns ());
03297 pop_topmost_sequence ();
03298
03299 return val;
03300 }
03301
03302
03303
03304
03305
03306 static rtx
03307 expand_builtin_args_info (exp)
03308 tree exp;
03309 {
03310 tree arglist = TREE_OPERAND (exp, 1);
03311 int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
03312 int *word_ptr = (int *) ¤t_function_args_info;
03313 #if 0
03314
03315 int i;
03316 tree type, elts, result;
03317 #endif
03318
03319 if (sizeof (CUMULATIVE_ARGS) % sizeof (int) != 0)
03320 abort ();
03321
03322 if (arglist != 0)
03323 {
03324 if (!host_integerp (TREE_VALUE (arglist), 0))
03325 error ("argument of `__builtin_args_info' must be constant");
03326 else
03327 {
03328 HOST_WIDE_INT wordnum = tree_low_cst (TREE_VALUE (arglist), 0);
03329
03330 if (wordnum < 0 || wordnum >= nwords)
03331 error ("argument of `__builtin_args_info' out of range");
03332 else
03333 return GEN_INT (word_ptr[wordnum]);
03334 }
03335 }
03336 else
03337 error ("missing argument in `__builtin_args_info'");
03338
03339 return const0_rtx;
03340
03341 #if 0
03342 for (i = 0; i < nwords; i++)
03343 elts = tree_cons (NULL_TREE, build_int_2 (word_ptr[i], 0));
03344
03345 type = build_array_type (integer_type_node,
03346 build_index_type (build_int_2 (nwords, 0)));
03347 result = build (CONSTRUCTOR, type, NULL_TREE, nreverse (elts));
03348 TREE_CONSTANT (result) = 1;
03349 TREE_STATIC (result) = 1;
03350 result = build1 (INDIRECT_REF, build_pointer_type (type), result);
03351 TREE_CONSTANT (result) = 1;
03352 return expand_expr (result, NULL_RTX, VOIDmode, 0);
03353 #endif
03354 }
03355
03356
03357
03358 static rtx
03359 expand_builtin_next_arg (arglist)
03360 tree arglist;
03361 {
03362 tree fntype = TREE_TYPE (current_function_decl);
03363
03364 if (TYPE_ARG_TYPES (fntype) == 0
03365 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
03366 == void_type_node))
03367 {
03368 error ("`va_start' used in function with fixed args");
03369 return const0_rtx;
03370 }
03371
03372 if (arglist)
03373 {
03374 tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
03375 tree arg = TREE_VALUE (arglist);
03376
03377
03378
03379
03380
03381 while (TREE_CODE (arg) == NOP_EXPR
03382 || TREE_CODE (arg) == CONVERT_EXPR
03383 || TREE_CODE (arg) == NON_LVALUE_EXPR
03384 || TREE_CODE (arg) == INDIRECT_REF)
03385 arg = TREE_OPERAND (arg, 0);
03386 if (arg != last_parm)
03387 warning ("second parameter of `va_start' not last named argument");
03388 }
03389 else
03390
03391
03392 warning ("`__builtin_next_arg' called without an argument");
03393
03394 return expand_binop (Pmode, add_optab,
03395 current_function_internal_arg_pointer,
03396 current_function_arg_offset_rtx,
03397 NULL_RTX, 0, OPTAB_LIB_WIDEN);
03398 }
03399
03400
03401
03402
03403 static tree
03404 stabilize_va_list (valist, needs_lvalue)
03405 tree valist;
03406 int needs_lvalue;
03407 {
03408 if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
03409 {
03410 if (TREE_SIDE_EFFECTS (valist))
03411 valist = save_expr (valist);
03412
03413
03414
03415
03416
03417 if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
03418 {
03419 tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
03420 tree p2 = build_pointer_type (va_list_type_node);
03421
03422 valist = build1 (ADDR_EXPR, p2, valist);
03423 valist = fold (build1 (NOP_EXPR, p1, valist));
03424 }
03425 }
03426 else
03427 {
03428 tree pt;
03429
03430 if (! needs_lvalue)
03431 {
03432 if (! TREE_SIDE_EFFECTS (valist))
03433 return valist;
03434
03435 pt = build_pointer_type (va_list_type_node);
03436 valist = fold (build1 (ADDR_EXPR, pt, valist));
03437 TREE_SIDE_EFFECTS (valist) = 1;
03438 }
03439
03440 if (TREE_SIDE_EFFECTS (valist))
03441 valist = save_expr (valist);
03442 valist = fold (build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)),
03443 valist));
03444 }
03445
03446 return valist;
03447 }
03448
03449
03450
03451
03452 void
03453 std_expand_builtin_va_start (valist, nextarg)
03454 tree valist;
03455 rtx nextarg;
03456 {
03457 tree t;
03458
03459 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
03460 make_tree (ptr_type_node, nextarg));
03461 TREE_SIDE_EFFECTS (t) = 1;
03462
03463 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
03464 }
03465
03466
03467
03468 static rtx
03469 expand_builtin_va_start (arglist)
03470 tree arglist;
03471 {
03472 rtx nextarg;
03473 tree chain, valist;
03474
03475 chain = TREE_CHAIN (arglist);
03476
03477 if (TREE_CHAIN (chain))
03478 error ("too many arguments to function `va_start'");
03479
03480 nextarg = expand_builtin_next_arg (chain);
03481 valist = stabilize_va_list (TREE_VALUE (arglist), 1);
03482
03483 #ifdef EXPAND_BUILTIN_VA_START
03484 EXPAND_BUILTIN_VA_START (valist, nextarg);
03485 #else
03486 std_expand_builtin_va_start (valist, nextarg);
03487 #endif
03488
03489 return const0_rtx;
03490 }
03491
03492
03493
03494
03495 rtx
03496 std_expand_builtin_va_arg (valist, type)
03497 tree valist, type;
03498 {
03499 tree addr_tree, t, type_size = NULL;
03500 tree align, alignm1;
03501 tree rounded_size;
03502 rtx addr;
03503
03504
03505 align = size_int (PARM_BOUNDARY / BITS_PER_UNIT);
03506 alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1);
03507 if (type == error_mark_node
03508 || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
03509 || TREE_OVERFLOW (type_size))
03510 rounded_size = size_zero_node;
03511 else
03512 rounded_size = fold (build (MULT_EXPR, sizetype,
03513 fold (build (TRUNC_DIV_EXPR, sizetype,
03514 fold (build (PLUS_EXPR, sizetype,
03515 type_size, alignm1)),
03516 align)),
03517 align));
03518
03519
03520 addr_tree = valist;
03521 if (PAD_VARARGS_DOWN && ! integer_zerop (rounded_size))
03522 {
03523
03524 addr_tree = fold (build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
03525 fold (build (COND_EXPR, sizetype,
03526 fold (build (GT_EXPR, sizetype,
03527 rounded_size,
03528 align)),
03529 size_zero_node,
03530 fold (build (MINUS_EXPR, sizetype,
03531 rounded_size,
03532 type_size))))));
03533 }
03534
03535 addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
03536 addr = copy_to_reg (addr);
03537
03538
03539 if (! integer_zerop (rounded_size))
03540 {
03541 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
03542 build (PLUS_EXPR, TREE_TYPE (valist), valist,
03543 rounded_size));
03544 TREE_SIDE_EFFECTS (t) = 1;
03545 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
03546 }
03547
03548 return addr;
03549 }
03550
03551
03552
03553
03554 rtx
03555 expand_builtin_va_arg (valist, type)
03556 tree valist, type;
03557 {
03558 rtx addr, result;
03559 tree promoted_type, want_va_type, have_va_type;
03560
03561
03562
03563 want_va_type = va_list_type_node;
03564 have_va_type = TREE_TYPE (valist);
03565 if (TREE_CODE (want_va_type) == ARRAY_TYPE)
03566 {
03567
03568
03569
03570
03571 if (TREE_CODE (have_va_type) == ARRAY_TYPE
03572 || TREE_CODE (have_va_type) == POINTER_TYPE)
03573 {
03574 want_va_type = TREE_TYPE (want_va_type);
03575 have_va_type = TREE_TYPE (have_va_type);
03576 }
03577 }
03578 if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type))
03579 {
03580 error ("first argument to `va_arg' not of type `va_list'");
03581 addr = const0_rtx;
03582 }
03583
03584
03585
03586 else if ((promoted_type = (*lang_hooks.types.type_promotes_to) (type))
03587 != type)
03588 {
03589 const char *name = "<anonymous type>", *pname = 0;
03590 static bool gave_help;
03591
03592 if (TYPE_NAME (type))
03593 {
03594 if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
03595 name = IDENTIFIER_POINTER (TYPE_NAME (type));
03596 else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
03597 && DECL_NAME (TYPE_NAME (type)))
03598 name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
03599 }
03600 if (TYPE_NAME (promoted_type))
03601 {
03602 if (TREE_CODE (TYPE_NAME (promoted_type)) == IDENTIFIER_NODE)
03603 pname = IDENTIFIER_POINTER (TYPE_NAME (promoted_type));
03604 else if (TREE_CODE (TYPE_NAME (promoted_type)) == TYPE_DECL
03605 && DECL_NAME (TYPE_NAME (promoted_type)))
03606 pname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (promoted_type)));
03607 }
03608
03609
03610
03611
03612 warning ("`%s' is promoted to `%s' when passed through `...'",
03613 name, pname);
03614 if (! gave_help)
03615 {
03616 gave_help = true;
03617 warning ("(so you should pass `%s' not `%s' to `va_arg')",
03618 pname, name);
03619 }
03620
03621
03622
03623 expand_builtin_trap ();
03624
03625
03626
03627 addr = const0_rtx;
03628 }
03629 else
03630 {
03631
03632
03633 valist = stabilize_va_list (valist, 0);
03634
03635 #ifdef EXPAND_BUILTIN_VA_ARG
03636 addr = EXPAND_BUILTIN_VA_ARG (valist, type);
03637 #else
03638 addr = std_expand_builtin_va_arg (valist, type);
03639 #endif
03640 }
03641
03642 #ifdef POINTERS_EXTEND_UNSIGNED
03643 if (GET_MODE (addr) != Pmode)
03644 addr = convert_memory_address (Pmode, addr);
03645 #endif
03646
03647 result = gen_rtx_MEM (TYPE_MODE (type), addr);
03648 set_mem_alias_set (result, get_varargs_alias_set ());
03649
03650 return result;
03651 }
03652
03653
03654
03655 static rtx
03656 expand_builtin_va_end (arglist)
03657 tree arglist;
03658 {
03659 tree valist = TREE_VALUE (arglist);
03660
03661 #ifdef EXPAND_BUILTIN_VA_END
03662 valist = stabilize_va_list (valist, 0);
03663 EXPAND_BUILTIN_VA_END (arglist);
03664 #else
03665
03666
03667 if (TREE_SIDE_EFFECTS (valist))
03668 expand_expr (valist, const0_rtx, VOIDmode, EXPAND_NORMAL);
03669 #endif
03670
03671 return const0_rtx;
03672 }
03673
03674
03675
03676
03677
03678 static rtx
03679 expand_builtin_va_copy (arglist)
03680 tree arglist;
03681 {
03682 tree dst, src, t;
03683
03684 dst = TREE_VALUE (arglist);
03685 src = TREE_VALUE (TREE_CHAIN (arglist));
03686
03687 dst = stabilize_va_list (dst, 1);
03688 src = stabilize_va_list (src, 0);
03689
03690 if (TREE_CODE (va_list_type_node) != ARRAY_TYPE)
03691 {
03692 t = build (MODIFY_EXPR, va_list_type_node, dst, src);
03693 TREE_SIDE_EFFECTS (t) = 1;
03694 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
03695 }
03696 else
03697 {
03698 rtx dstb, srcb, size;
03699
03700
03701 dstb = expand_expr (dst, NULL_RTX, Pmode, EXPAND_NORMAL);
03702 srcb = expand_expr (src, NULL_RTX, Pmode, EXPAND_NORMAL);
03703 size = expand_expr (TYPE_SIZE_UNIT (va_list_type_node), NULL_RTX,
03704 VOIDmode, EXPAND_NORMAL);
03705
03706 #ifdef POINTERS_EXTEND_UNSIGNED
03707 if (GET_MODE (dstb) != Pmode)
03708 dstb = convert_memory_address (Pmode, dstb);
03709
03710 if (GET_MODE (srcb) != Pmode)
03711 srcb = convert_memory_address (Pmode, srcb);
03712 #endif
03713
03714
03715 dstb = gen_rtx_MEM (BLKmode, dstb);
03716 set_mem_alias_set (dstb, get_alias_set (TREE_TYPE (TREE_TYPE (dst))));
03717 set_mem_align (dstb, TYPE_ALIGN (va_list_type_node));
03718 srcb = gen_rtx_MEM (BLKmode, srcb);
03719 set_mem_alias_set (srcb, get_alias_set (TREE_TYPE (TREE_TYPE (src))));
03720 set_mem_align (srcb, TYPE_ALIGN (va_list_type_node));
03721
03722
03723 emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL);
03724 }
03725
03726 return const0_rtx;
03727 }
03728
03729
03730
03731
03732 static rtx
03733 expand_builtin_frame_address (exp)
03734 tree exp;
03735 {
03736 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
03737 tree arglist = TREE_OPERAND (exp, 1);
03738
03739
03740
03741
03742 if (arglist == 0)
03743
03744 return const0_rtx;
03745 else if (! host_integerp (TREE_VALUE (arglist), 1))
03746 {
03747 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
03748 error ("invalid arg to `__builtin_frame_address'");
03749 else
03750 error ("invalid arg to `__builtin_return_address'");
03751 return const0_rtx;
03752 }
03753 else
03754 {
03755 rtx tem
03756 = expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl),
03757 tree_low_cst (TREE_VALUE (arglist), 1),
03758 hard_frame_pointer_rtx);
03759
03760
03761 if (tem == NULL)
03762 {
03763 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
03764 warning ("unsupported arg to `__builtin_frame_address'");
03765 else
03766 warning ("unsupported arg to `__builtin_return_address'");
03767 return const0_rtx;
03768 }
03769
03770
03771 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
03772 return tem;
03773
03774 if (GET_CODE (tem) != REG
03775 && ! CONSTANT_P (tem))
03776 tem = copy_to_mode_reg (Pmode, tem);
03777 return tem;
03778 }
03779 }
03780
03781
03782
03783
03784
03785 static rtx
03786 expand_builtin_alloca (arglist, target)
03787 tree arglist;
03788 rtx target;
03789 {
03790 rtx op0;
03791 rtx result;
03792
03793 if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
03794 return 0;
03795
03796
03797 op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
03798
03799
03800 result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
03801
03802 #ifdef POINTERS_EXTEND_UNSIGNED
03803 if (GET_MODE (result) != ptr_mode)
03804 result = convert_memory_address (ptr_mode, result);
03805 #endif
03806
03807 return result;
03808 }
03809
03810
03811
03812
03813
03814
03815 static rtx
03816 expand_builtin_ffs (arglist, target, subtarget)
03817 tree arglist;
03818 rtx target, subtarget;
03819 {
03820 rtx op0;
03821 if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
03822 return 0;
03823
03824
03825 op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
03826
03827
03828 target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
03829 ffs_optab, op0, target, 1);
03830 if (target == 0)
03831 abort ();
03832 return target;
03833 }
03834
03835 #ifndef SGI_MONGOOSE
03836
03837
03838
03839 static rtx
03840 expand_builtin_fputs (arglist, ignore, unlocked)
03841 tree arglist;
03842 int ignore;
03843 int unlocked;
03844 {
03845 tree len, fn;
03846 tree fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
03847 : built_in_decls[BUILT_IN_FPUTC];
03848 tree fn_fwrite = unlocked ? built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
03849 : built_in_decls[BUILT_IN_FWRITE];
03850
03851
03852
03853 if (!ignore || !fn_fputc || !fn_fwrite)
03854 return 0;
03855
03856
03857 if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
03858 return 0;
03859
03860
03861
03862 if (!(len = c_strlen (TREE_VALUE (arglist), 1))
03863 || TREE_CODE (len) != INTEGER_CST)
03864 return 0;
03865
03866 switch (compare_tree_int (len, 1))
03867 {
03868 case -1:
03869 {
03870
03871
03872 expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx,
03873 VOIDmode, EXPAND_NORMAL);
03874 return const0_rtx;
03875 }
03876 case 0:
03877 {
03878 const char *p = c_getstr (TREE_VALUE (arglist));
03879
03880 if (p != NULL)
03881 {
03882
03883
03884 arglist =
03885 build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)));
03886 arglist =
03887 tree_cons (NULL_TREE, build_int_2 (p[0], 0), arglist);
03888 fn = fn_fputc;
03889 break;
03890 }
03891 }
03892
03893 case 1:
03894 {
03895 tree string_arg;
03896
03897
03898 if (optimize_size)
03899 return 0;
03900 string_arg = TREE_VALUE (arglist);
03901
03902
03903 arglist = build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)));
03904 arglist = tree_cons (NULL_TREE, len, arglist);
03905 arglist = tree_cons (NULL_TREE, size_one_node, arglist);
03906 arglist = tree_cons (NULL_TREE, string_arg, arglist);
03907 fn = fn_fwrite;
03908 break;
03909 }
03910 default:
03911 abort ();
03912 }
03913
03914 return expand_expr (build_function_call_expr (fn, arglist),
03915 (ignore ? const0_rtx : NULL_RTX),
03916 VOIDmode, EXPAND_NORMAL);
03917 }
03918 #endif
03919
03920
03921
03922
03923
03924 static rtx
03925 expand_builtin_expect (arglist, target)
03926 tree arglist;
03927 rtx target;
03928 {
03929 tree exp, c;
03930 rtx note, rtx_c;
03931
03932 if (arglist == NULL_TREE
03933 || TREE_CHAIN (arglist) == NULL_TREE)
03934 return const0_rtx;
03935 exp = TREE_VALUE (arglist);
03936 c = TREE_VALUE (TREE_CHAIN (arglist));
03937
03938 if (TREE_CODE (c) != INTEGER_CST)
03939 {
03940 error ("second arg to `__builtin_expect' must be a constant");
03941 c = integer_zero_node;
03942 }
03943
03944 target = expand_expr (exp, target, VOIDmode, EXPAND_NORMAL);
03945
03946
03947 if (flag_guess_branch_prob && GET_CODE (target) != CONST_INT)
03948 {
03949
03950
03951
03952 target = force_reg (GET_MODE (target), target);
03953
03954 rtx_c = expand_expr (c, NULL_RTX, GET_MODE (target), EXPAND_NORMAL);
03955
03956 note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE);
03957 NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, target, rtx_c);
03958 }
03959
03960 return target;
03961 }
03962
03963
03964
03965
03966
03967
03968
03969
03970 rtx
03971 expand_builtin_expect_jump (exp, if_false_label, if_true_label)
03972 tree exp;
03973 rtx if_false_label;
03974 rtx if_true_label;
03975 {
03976 tree arglist = TREE_OPERAND (exp, 1);
03977 tree arg0 = TREE_VALUE (arglist);
03978 tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
03979 rtx ret = NULL_RTX;
03980
03981
03982
03983 if (TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE
03984 && (integer_zerop (arg1) || integer_onep (arg1)))
03985 {
03986 int num_jumps = 0;
03987 rtx insn;
03988 int save_pending_stack_adjust = pending_stack_adjust;
03989
03990
03991
03992
03993 switch (unsafe_for_reeval (arg0))
03994 {
03995 case 0:
03996 break;
03997
03998 case 1:
03999 arg0 = unsave_expr (arg0);
04000 break;
04001
04002 case 2:
04003 return NULL_RTX;
04004 }
04005
04006
04007 start_sequence ();
04008 do_jump (arg0, if_false_label, if_true_label);
04009 ret = get_insns ();
04010 end_sequence ();
04011
04012
04013
04014
04015
04016 insn = ret;
04017 while (insn != NULL_RTX)
04018 {
04019 rtx next = NEXT_INSN (insn);
04020 rtx pattern;
04021
04022 if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn)
04023 && (pattern = pc_set (insn)) != NULL_RTX)
04024 {
04025 rtx ifelse = SET_SRC (pattern);
04026 rtx label;
04027 int taken;
04028
04029 if (GET_CODE (ifelse) != IF_THEN_ELSE)
04030 goto do_next_insn;
04031
04032 if (GET_CODE (XEXP (ifelse, 1)) == LABEL_REF)
04033 {
04034 taken = 1;
04035 label = XEXP (XEXP (ifelse, 1), 0);
04036 }
04037
04038 else if (GET_CODE (XEXP (ifelse, 2)) == LABEL_REF)
04039 {
04040 taken = 0;
04041 label = XEXP (XEXP (ifelse, 2), 0);
04042 }
04043
04044
04045 else if (GET_CODE (XEXP (ifelse, 1)) == RETURN)
04046 {
04047 taken = 1;
04048 label = NULL_RTX;
04049 }
04050
04051 else if (GET_CODE (XEXP (ifelse, 2)) == RETURN)
04052 {
04053 taken = 0;
04054 label = NULL_RTX;
04055 }
04056 else
04057 goto do_next_insn;
04058
04059
04060
04061 if (integer_zerop (arg1))
04062 taken = 1 - taken;
04063
04064
04065
04066 if (label == NULL_RTX)
04067 ;
04068 else if (label == if_false_label)
04069 taken = 1 - taken;
04070 else if (label != if_true_label)
04071 goto do_next_insn;
04072
04073 num_jumps++;
04074 predict_insn_def (insn, PRED_BUILTIN_EXPECT, taken);
04075 }
04076
04077 do_next_insn:
04078 insn = next;
04079 }
04080
04081
04082
04083 if (num_jumps == 0)
04084 {
04085 ret = NULL_RTX;
04086 pending_stack_adjust = save_pending_stack_adjust;
04087 }
04088 }
04089
04090 return ret;
04091 }
04092
04093 void
04094 expand_builtin_trap ()
04095 {
04096 #ifdef HAVE_trap
04097 if (HAVE_trap)
04098 emit_insn (gen_trap ());
04099 else
04100 #endif
04101 emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
04102 emit_barrier ();
04103 }
04104
04105
04106
04107
04108
04109
04110 static rtx
04111 expand_builtin_sprintf (arglist, target, mode)
04112 tree arglist;
04113 rtx target;
04114 enum machine_mode mode;
04115 {
04116 tree orig_arglist, dest, fmt;
04117 const char *fmt_str;
04118
04119 orig_arglist = arglist;
04120
04121
04122 if (! arglist)
04123 return 0;
04124 dest = TREE_VALUE (arglist);
04125 if (TREE_CODE (TREE_TYPE (dest)) != POINTER_TYPE)
04126 return 0;
04127 arglist = TREE_CHAIN (arglist);
04128 if (! arglist)
04129 return 0;
04130 fmt = TREE_VALUE (arglist);
04131 if (TREE_CODE (TREE_TYPE (dest)) != POINTER_TYPE)
04132 return 0;
04133 arglist = TREE_CHAIN (arglist);
04134
04135
04136 fmt_str = c_getstr (fmt);
04137 if (fmt_str == NULL)
04138 return 0;
04139
04140
04141 if (strchr (fmt_str, '%') == 0)
04142 {
04143 tree fn = built_in_decls[BUILT_IN_STRCPY];
04144 tree exp;
04145
04146 if (arglist || ! fn)
04147 return 0;
04148 expand_expr (build_function_call_expr (fn, orig_arglist),
04149 const0_rtx, VOIDmode, EXPAND_NORMAL);
04150 if (target == const0_rtx)
04151 return const0_rtx;
04152 exp = build_int_2 (strlen (fmt_str), 0);
04153 exp = fold (build1 (NOP_EXPR, integer_type_node, exp));
04154 return expand_expr (exp, target, mode, EXPAND_NORMAL);
04155 }
04156
04157 else if (strcmp (fmt_str, "%s") == 0)
04158 {
04159 tree fn, arg, len;
04160 fn = built_in_decls[BUILT_IN_STRCPY];
04161
04162 if (! fn)
04163 return 0;
04164
04165 if (! arglist || TREE_CHAIN (arglist))
04166 return 0;
04167 arg = TREE_VALUE (arglist);
04168 if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
04169 return 0;
04170
04171 if (target != const0_rtx)
04172 {
04173 len = c_strlen (arg, 1);
04174 if (! len || TREE_CODE (len) != INTEGER_CST)
04175 return 0;
04176 }
04177 else
04178 len = NULL_TREE;
04179
04180 arglist = build_tree_list (NULL_TREE, arg);
04181 arglist = tree_cons (NULL_TREE, dest, arglist);
04182 expand_expr (build_function_call_expr (fn, arglist),
04183 const0_rtx, VOIDmode, EXPAND_NORMAL);
04184
04185 if (target == const0_rtx)
04186 return const0_rtx;
04187 return expand_expr (len, target, mode, EXPAND_NORMAL);
04188 }
04189
04190 return 0;
04191 }
04192
04193
04194
04195
04196
04197
04198
04199 rtx
04200 expand_builtin (exp, target, subtarget, mode, ignore)
04201 tree exp;
04202 rtx target;
04203 rtx subtarget;
04204 enum machine_mode mode;
04205 int ignore;
04206 {
04207 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
04208 tree arglist = TREE_OPERAND (exp, 1);
04209 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
04210
04211
04212 emit_queue ();
04213
04214 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
04215 return (*targetm.expand_builtin) (exp, target, subtarget, mode, ignore);
04216
04217 #ifdef KEY
04218
04219
04220 switch (fcode) {
04221 case BUILT_IN_STRCHR:
04222 case BUILT_IN_STRRCHR:
04223 case BUILT_IN_STRSTR:
04224 case BUILT_IN_STRPBRK:
04225 case BUILT_IN_MEMSET:
04226 return expand_call (exp, target, ignore);
04227
04228 default:
04229 break;
04230 }
04231 #endif
04232
04233
04234
04235 if (!optimize && !CALLED_AS_BUILT_IN (fndecl))
04236 switch (fcode)
04237 {
04238 #ifdef KEY
04239 case BUILT_IN_FLOOR:
04240 case BUILT_IN_FLOORF:
04241 case BUILT_IN_FLOORL:
04242 case BUILT_IN_POW:
04243 case BUILT_IN_TAN:
04244 #endif
04245 case BUILT_IN_SQRT:
04246 case BUILT_IN_SQRTF:
04247 case BUILT_IN_SQRTL:
04248 case BUILT_IN_SIN:
04249 case BUILT_IN_SINF:
04250 case BUILT_IN_SINL:
04251 case BUILT_IN_COS:
04252 case BUILT_IN_COSF:
04253 case BUILT_IN_COSL:
04254 case BUILT_IN_EXP:
04255 case BUILT_IN_EXPF:
04256 case BUILT_IN_EXPL:
04257 case BUILT_IN_MEMSET:
04258 case BUILT_IN_MEMCPY:
04259 case BUILT_IN_MEMCMP:
04260 case BUILT_IN_MEMPCPY:
04261 case BUILT_IN_MEMMOVE:
04262 case BUILT_IN_BCMP:
04263 case BUILT_IN_BZERO:
04264 case BUILT_IN_BCOPY:
04265 #ifndef SGI_MONGOOSE
04266 case BUILT_IN_INDEX:
04267 case BUILT_IN_RINDEX:
04268 #endif
04269 case BUILT_IN_SPRINTF:
04270 case BUILT_IN_STPCPY:
04271 #ifndef SGI_MONGOOSE
04272 case BUILT_IN_STRCHR:
04273 case BUILT_IN_STRRCHR:
04274 #endif
04275 case BUILT_IN_STRLEN:
04276 case BUILT_IN_STRCPY:
04277 #ifndef SGI_MONGOOSE
04278 case BUILT_IN_STRNCPY:
04279 case BUILT_IN_STRNCMP:
04280 case BUILT_IN_STRSTR:
04281 case BUILT_IN_STRPBRK:
04282 case BUILT_IN_STRCAT:
04283 case BUILT_IN_STRNCAT:
04284 case BUILT_IN_STRSPN:
04285 case BUILT_IN_STRCSPN:
04286 #endif
04287 case BUILT_IN_STRCMP:
04288 case BUILT_IN_FFS:
04289 #ifndef SGI_MONGOOSE
04290 case BUILT_IN_PUTCHAR:
04291 case BUILT_IN_PUTS:
04292 case BUILT_IN_PRINTF:
04293 case BUILT_IN_FPUTC:
04294 case BUILT_IN_FPUTS:
04295 case BUILT_IN_FWRITE:
04296 #endif
04297 case BUILT_IN_PUTCHAR_UNLOCKED:
04298 case BUILT_IN_PUTS_UNLOCKED:
04299 case BUILT_IN_PRINTF_UNLOCKED:
04300 case BUILT_IN_FPUTC_UNLOCKED:
04301 case BUILT_IN_FPUTS_UNLOCKED:
04302 case BUILT_IN_FWRITE_UNLOCKED:
04303 return expand_call (exp, target, ignore);
04304
04305 default:
04306 break;
04307 }
04308
04309
04310
04311 if (ignore)
04312 target = const0_rtx;
04313
04314
04315
04316
04317 if (target == const0_rtx
04318 && (DECL_IS_PURE (fndecl) || TREE_READONLY (fndecl)))
04319 {
04320 bool volatilep = false;
04321 tree arg;
04322
04323 for (arg = arglist; arg; arg = TREE_CHAIN (arg))
04324 if (TREE_THIS_VOLATILE (TREE_VALUE (arg)))
04325 {
04326 volatilep = true;
04327 break;
04328 }
04329
04330 if (! volatilep)
04331 {
04332 for (arg = arglist; arg; arg = TREE_CHAIN (arg))
04333 expand_expr (TREE_VALUE (arg), const0_rtx,
04334 VOIDmode, EXPAND_NORMAL);
04335 return const0_rtx;
04336 }
04337 }
04338
04339 switch (fcode)
04340 {
04341 case BUILT_IN_ABS:
04342 case BUILT_IN_LABS:
04343 case BUILT_IN_LLABS:
04344 case BUILT_IN_IMAXABS:
04345 case BUILT_IN_FABS:
04346 case BUILT_IN_FABSF:
04347 case BUILT_IN_FABSL:
04348
04349 abort ();
04350
04351 case BUILT_IN_CONJ:
04352 case BUILT_IN_CONJF:
04353 case BUILT_IN_CONJL:
04354 case BUILT_IN_CREAL:
04355 case BUILT_IN_CREALF:
04356 case BUILT_IN_CREALL:
04357 case BUILT_IN_CIMAG:
04358 case BUILT_IN_CIMAGF:
04359 case BUILT_IN_CIMAGL:
04360
04361
04362 abort ();
04363
04364 case BUILT_IN_SIN:
04365 case BUILT_IN_SINF:
04366 case BUILT_IN_SINL:
04367 case BUILT_IN_COS:
04368 case BUILT_IN_COSF:
04369 case BUILT_IN_COSL:
04370 case BUILT_IN_EXP:
04371 case BUILT_IN_EXPF:
04372 case BUILT_IN_EXPL:
04373 case BUILT_IN_LOG:
04374 case BUILT_IN_LOGF:
04375 case BUILT_IN_LOGL:
04376
04377
04378 if (! flag_unsafe_math_optimizations)
04379 break;
04380 #ifdef KEY
04381 case BUILT_IN_FLOOR:
04382 case BUILT_IN_FLOORF:
04383 case BUILT_IN_FLOORL:
04384 case BUILT_IN_POW:
04385 case BUILT_IN_TAN:
04386 #endif
04387 case BUILT_IN_SQRT:
04388 case BUILT_IN_SQRTF:
04389 case BUILT_IN_SQRTL:
04390 target = expand_builtin_mathfn (exp, target, subtarget);
04391 if (target)
04392 return target;
04393 break;
04394
04395 case BUILT_IN_APPLY_ARGS:
04396 return expand_builtin_apply_args ();
04397
04398
04399
04400
04401
04402
04403
04404
04405
04406
04407
04408 case BUILT_IN_APPLY:
04409 if (!validate_arglist (arglist, POINTER_TYPE,
04410 POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
04411 && !validate_arglist (arglist, REFERENCE_TYPE,
04412 POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
04413 return const0_rtx;
04414 else
04415 {
04416 int i;
04417 tree t;
04418 rtx ops[3];
04419
04420 for (t = arglist, i = 0; t; t = TREE_CHAIN (t), i++)
04421 ops[i] = expand_expr (TREE_VALUE (t), NULL_RTX, VOIDmode, 0);
04422
04423 return expand_builtin_apply (ops[0], ops[1], ops[2]);
04424 }
04425
04426
04427
04428
04429 case BUILT_IN_RETURN:
04430 if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
04431 expand_builtin_return (expand_expr (TREE_VALUE (arglist),
04432 NULL_RTX, VOIDmode, 0));
04433 return const0_rtx;
04434
04435 case BUILT_IN_SAVEREGS:
04436 return expand_builtin_saveregs ();
04437
04438 case BUILT_IN_ARGS_INFO:
04439 return expand_builtin_args_info (exp);
04440
04441
04442 case BUILT_IN_NEXT_ARG:
04443 return expand_builtin_next_arg (arglist);
04444
04445 case BUILT_IN_CLASSIFY_TYPE:
04446 return expand_builtin_classify_type (arglist);
04447
04448 case BUILT_IN_CONSTANT_P:
04449 return expand_builtin_constant_p (exp);
04450
04451 case BUILT_IN_FRAME_ADDRESS:
04452 case BUILT_IN_RETURN_ADDRESS:
04453 return expand_builtin_frame_address (exp);
04454
04455
04456
04457 case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
04458 if (arglist != 0
04459 || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
04460 || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM)
04461 return const0_rtx;
04462 else
04463 return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
04464
04465 case BUILT_IN_ALLOCA:
04466 target = expand_builtin_alloca (arglist, target);
04467 if (target)
04468 return target;
04469 break;
04470
04471 case BUILT_IN_FFS:
04472 target = expand_builtin_ffs (arglist, target, subtarget);
04473 if (target)
04474 return target;
04475 break;
04476
04477 case BUILT_IN_STRLEN:
04478 target = expand_builtin_strlen (exp, target);
04479 if (target)
04480 return target;
04481 break;
04482
04483 case BUILT_IN_STRCPY:
04484 target = expand_builtin_strcpy (exp, target, mode);
04485 if (target)
04486 return target;
04487 break;
04488
04489 #ifndef SGI_MONGOOSE
04490 case BUILT_IN_STRNCPY:
04491 target = expand_builtin_strncpy (arglist, target, mode);
04492 if (target)
04493 return target;
04494 break;
04495 #endif
04496
04497 case BUILT_IN_STPCPY:
04498 target = expand_builtin_stpcpy (arglist, target, mode);
04499 if (target)
04500 return target;
04501 break;
04502
04503 #ifndef SGI_MONGOOSE
04504 case BUILT_IN_STRCAT:
04505 target = expand_builtin_strcat (arglist, target, mode);
04506 if (target)
04507 return target;
04508 break;
04509
04510 case BUILT_IN_STRNCAT:
04511 target = expand_builtin_strncat (arglist, target, mode);
04512 if (target)
04513 return target;
04514 break;
04515
04516 case BUILT_IN_STRSPN:
04517 target = expand_builtin_strspn (arglist, target, mode);
04518 if (target)
04519 return target;
04520 break;
04521
04522 case BUILT_IN_STRCSPN:
04523 target = expand_builtin_strcspn (arglist, target, mode);
04524 if (target)
04525 return target;
04526 break;
04527
04528 case BUILT_IN_STRSTR:
04529 target = expand_builtin_strstr (arglist, target, mode);
04530 if (target)
04531 return target;
04532 break;
04533
04534 case BUILT_IN_STRPBRK:
04535 target = expand_builtin_strpbrk (arglist, target, mode);
04536 if (target)
04537 return target;
04538 break;
04539
04540 case BUILT_IN_INDEX:
04541 case BUILT_IN_STRCHR:
04542 target = expand_builtin_strchr (arglist, target, mode);
04543 if (target)
04544 return target;
04545 break;
04546
04547 case BUILT_IN_RINDEX:
04548 case BUILT_IN_STRRCHR:
04549 target = expand_builtin_strrchr (arglist, target, mode);
04550 if (target)
04551 return target;
04552 break;
04553 #endif
04554
04555 case BUILT_IN_MEMCPY:
04556 target = expand_builtin_memcpy (arglist, target, mode);
04557 if (target)
04558 return target;
04559 break;
04560
04561 case BUILT_IN_MEMPCPY:
04562 target = expand_builtin_mempcpy (arglist, target, mode, 1);
04563 if (target)
04564 return target;
04565 break;
04566
04567 case BUILT_IN_MEMMOVE:
04568 target = expand_builtin_memmove (arglist, target, mode);
04569 if (target)
04570 return target;
04571 break;
04572
04573 case BUILT_IN_BCOPY:
04574 target = expand_builtin_bcopy (arglist);
04575 if (target)
04576 return target;
04577 break;
04578
04579 case BUILT_IN_MEMSET:
04580 target = expand_builtin_memset (exp, target, mode);
04581 if (target)
04582 return target;
04583 break;
04584
04585 case BUILT_IN_BZERO:
04586 target = expand_builtin_bzero (exp);
04587 if (target)
04588 return target;
04589 break;
04590
04591 case BUILT_IN_STRCMP:
04592 target = expand_builtin_strcmp (exp, target, mode);
04593 if (target)
04594 return target;
04595 break;
04596
04597 #ifndef SGI_MONGOOSE
04598 case BUILT_IN_STRNCMP:
04599 target = expand_builtin_strncmp (exp, target, mode);
04600 if (target)
04601 return target;
04602 break;
04603 #endif
04604
04605 case BUILT_IN_BCMP:
04606 case BUILT_IN_MEMCMP:
04607 target = expand_builtin_memcmp (exp, arglist, target, mode);
04608 if (target)
04609 return target;
04610 break;
04611
04612 #ifndef SGI_MONGOOSE
04613 case BUILT_IN_SETJMP:
04614 target = expand_builtin_setjmp (arglist, target);
04615 if (target)
04616 return target;
04617 break;
04618 #endif
04619
04620
04621
04622
04623 case BUILT_IN_LONGJMP:
04624 if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
04625 break;
04626 else
04627 {
04628 #ifndef KEY
04629 rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
04630 VOIDmode, 0);
04631 rtx value = expand_expr (TREE_VALUE (TREE_CHAIN (arglist)),
04632 NULL_RTX, VOIDmode, 0);
04633
04634 if (value != const1_rtx)
04635 {
04636 error ("__builtin_longjmp second argument must be 1");
04637 return const0_rtx;
04638 }
04639
04640 expand_builtin_longjmp (buf_addr, value);
04641 #endif
04642 return const0_rtx;
04643 }
04644
04645 case BUILT_IN_TRAP:
04646 expand_builtin_trap ();
04647 return const0_rtx;
04648
04649 #ifndef SGI_MONGOOSE
04650 case BUILT_IN_FPUTS:
04651 target = expand_builtin_fputs (arglist, ignore, 0);
04652 if (target)
04653 return target;
04654 break;
04655 case BUILT_IN_FPUTS_UNLOCKED:
04656 target = expand_builtin_fputs (arglist, ignore, 1);
04657 if (target)
04658 return target;
04659 break;
04660 #endif
04661
04662 case BUILT_IN_SPRINTF:
04663 target = expand_builtin_sprintf (arglist, target, mode);
04664 if (target)
04665 return target;
04666 break;
04667
04668
04669 case BUILT_IN_UNWIND_INIT:
04670 expand_builtin_unwind_init ();
04671 return const0_rtx;
04672 case BUILT_IN_DWARF_CFA:
04673 return virtual_cfa_rtx;
04674 #ifdef DWARF2_UNWIND_INFO
04675 case BUILT_IN_DWARF_SP_COLUMN:
04676 return expand_builtin_dwarf_sp_column ();
04677 case BUILT_IN_INIT_DWARF_REG_SIZES:
04678 expand_builtin_init_dwarf_reg_sizes (TREE_VALUE (arglist));
04679 return const0_rtx;
04680 #endif
04681 case BUILT_IN_FROB_RETURN_ADDR:
04682 return expand_builtin_frob_return_addr (TREE_VALUE (arglist));
04683 case BUILT_IN_EXTRACT_RETURN_ADDR:
04684 return expand_builtin_extract_return_addr (TREE_VALUE (arglist));
04685 case BUILT_IN_EH_RETURN:
04686 expand_builtin_eh_return (TREE_VALUE (arglist),
04687 TREE_VALUE (TREE_CHAIN (arglist)));
04688 return const0_rtx;
04689 #ifdef EH_RETURN_DATA_REGNO
04690 case BUILT_IN_EH_RETURN_DATA_REGNO:
04691 return expand_builtin_eh_return_data_regno (arglist);
04692 #endif
04693
04694 case BUILT_IN_EXTEND_POINTER:
04695 return expand_builtin_extend_pointer (TREE_VALUE (arglist));
04696 case BUILT_IN_VA_START:
04697 case BUILT_IN_STDARG_START:
04698 return expand_builtin_va_start (arglist);
04699 case BUILT_IN_VA_END:
04700 return expand_builtin_va_end (arglist);
04701 case BUILT_IN_VA_COPY:
04702 return expand_builtin_va_copy (arglist);
04703 case BUILT_IN_EXPECT:
04704 return expand_builtin_expect (arglist, target);
04705 #ifndef SGI_MONGOOSE
04706 case BUILT_IN_PREFETCH:
04707 expand_builtin_prefetch (arglist);
04708 return const0_rtx;
04709 #endif
04710
04711 default:
04712 if (!DECL_ASSEMBLER_NAME_SET_P (fndecl))
04713 error ("built-in function `%s' not currently supported",
04714 IDENTIFIER_POINTER (DECL_NAME (fndecl)));
04715 }
04716
04717
04718
04719 return expand_call (exp, target, ignore);
04720 }
04721
04722
04723
04724
04725 static tree
04726 fold_builtin_constant_p (arglist)
04727 tree arglist;
04728 {
04729 if (arglist == 0)
04730 return 0;
04731
04732 arglist = TREE_VALUE (arglist);
04733
04734
04735
04736
04737 STRIP_NOPS (arglist);
04738
04739
04740 if (TREE_CODE_CLASS (TREE_CODE (arglist)) == 'c'
04741 || (TREE_CODE (arglist) == CONSTRUCTOR
04742 && TREE_CONSTANT (arglist))
04743 || (TREE_CODE (arglist) == ADDR_EXPR
04744 && TREE_CODE (TREE_OPERAND (arglist, 0)) == STRING_CST))
04745 return integer_one_node;
04746
04747
04748
04749
04750
04751
04752
04753
04754
04755 if (TREE_SIDE_EFFECTS (arglist) || cse_not_expected
04756 || AGGREGATE_TYPE_P (TREE_TYPE (arglist))
04757 || POINTER_TYPE_P (TREE_TYPE (arglist))
04758 || cfun == 0)
04759 return integer_zero_node;
04760
04761 return 0;
04762 }
04763
04764
04765
04766 static tree
04767 fold_builtin_classify_type (arglist)
04768 tree arglist;
04769 {
04770 if (arglist == 0)
04771 return build_int_2 (no_type_class, 0);
04772
04773 return build_int_2 (type_to_class (TREE_TYPE (TREE_VALUE (arglist))), 0);
04774 }
04775
04776
04777
04778 static tree
04779 fold_builtin_inf (type, warn)
04780 tree type;
04781 int warn;
04782 {
04783 REAL_VALUE_TYPE real;
04784
04785 if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) && warn)
04786 warning ("target format does not support infinity");
04787
04788 real_inf (&real);
04789 return build_real (type, real);
04790 }
04791
04792
04793
04794 static tree
04795 fold_builtin_nan (arglist, type, quiet)
04796 tree arglist, type;
04797 int quiet;
04798 {
04799 REAL_VALUE_TYPE real;
04800 const char *str;
04801
04802 if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
04803 return 0;
04804 str = c_getstr (TREE_VALUE (arglist));
04805 if (!str)
04806 return 0;
04807
04808 if (!real_nan (&real, str, quiet, TYPE_MODE (type)))
04809 return 0;
04810
04811 return build_real (type, real);
04812 }
04813
04814
04815
04816
04817 tree
04818 fold_builtin (exp)
04819 tree exp;
04820 {
04821 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
04822 tree arglist = TREE_OPERAND (exp, 1);
04823 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
04824
04825 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
04826 return 0;
04827
04828 switch (fcode)
04829 {
04830 case BUILT_IN_CONSTANT_P:
04831 return fold_builtin_constant_p (arglist);
04832
04833 case BUILT_IN_CLASSIFY_TYPE:
04834 return fold_builtin_classify_type (arglist);
04835
04836 case BUILT_IN_STRLEN:
04837 if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
04838 {
04839 tree len = c_strlen (TREE_VALUE (arglist), 0);
04840 if (len)
04841 {
04842
04843 if (size_type_node)
04844 len = convert (size_type_node, len);
04845 return len;
04846 }
04847 }
04848 break;
04849
04850 case BUILT_IN_INF:
04851 case BUILT_IN_INFF:
04852 case BUILT_IN_INFL:
04853 return fold_builtin_inf (TREE_TYPE (TREE_TYPE (fndecl)), true);
04854
04855 case BUILT_IN_HUGE_VAL:
04856 case BUILT_IN_HUGE_VALF:
04857 case BUILT_IN_HUGE_VALL:
04858 return fold_builtin_inf (TREE_TYPE (TREE_TYPE (fndecl)), false);
04859
04860 case BUILT_IN_NAN:
04861 case BUILT_IN_NANF:
04862 case BUILT_IN_NANL:
04863 return fold_builtin_nan (arglist, TREE_TYPE (TREE_TYPE (fndecl)), true);
04864
04865 case BUILT_IN_NANS:
04866 case BUILT_IN_NANSF:
04867 case BUILT_IN_NANSL:
04868 return fold_builtin_nan (arglist, TREE_TYPE (TREE_TYPE (fndecl)), false);
04869
04870 default:
04871 break;
04872 }
04873
04874 return 0;
04875 }
04876
04877 static tree
04878 build_function_call_expr (fn, arglist)
04879 tree fn, arglist;
04880 {
04881 tree call_expr;
04882
04883 call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
04884 call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
04885 call_expr, arglist);
04886 TREE_SIDE_EFFECTS (call_expr) = 1;
04887 return fold (call_expr);
04888 }
04889
04890
04891
04892
04893
04894
04895 static int
04896 validate_arglist VPARAMS ((tree arglist, ...))
04897 {
04898 enum tree_code code;
04899 int res = 0;
04900
04901 #ifndef SGI_MONGOOSE
04902 VA_OPEN (ap, arglist);
04903 VA_FIXEDARG (ap, tree, arglist);
04904 #else
04905 va_list ap;
04906
04907 VA_START (ap, arglist);
04908 #endif
04909
04910 do
04911 {
04912 code = va_arg (ap, enum tree_code);
04913 switch (code)
04914 {
04915 case 0:
04916
04917 res = 1;
04918 goto end;
04919 case VOID_TYPE:
04920
04921
04922 res = arglist == 0;
04923 goto end;
04924 default:
04925
04926
04927
04928 if (arglist == 0
04929 || code != TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))))
04930 goto end;
04931 break;
04932 }
04933 arglist = TREE_CHAIN (arglist);
04934 }
04935 while (1);
04936
04937
04938
04939 end: ;
04940 #ifndef SGI_MONGOOSE
04941 VA_CLOSE (ap);
04942 #else
04943 va_end (ap);
04944 #endif
04945
04946 return res;
04947 }
04948
04949
04950
04951 void
04952 default_init_builtins ()
04953 {
04954 }
04955
04956
04957
04958 rtx
04959 default_expand_builtin (exp, target, subtarget, mode, ignore)
04960 tree exp ATTRIBUTE_UNUSED;
04961 rtx target ATTRIBUTE_UNUSED;
04962 rtx subtarget ATTRIBUTE_UNUSED;
04963 enum machine_mode mode ATTRIBUTE_UNUSED;
04964 int ignore ATTRIBUTE_UNUSED;
04965 {
04966 return NULL_RTX;
04967 }
04968
04969
04970
04971
04972 static bool
04973 readonly_data_expr (exp)
04974 tree exp;
04975 {
04976 STRIP_NOPS (exp);
04977
04978 if (TREE_CODE (exp) == ADDR_EXPR)
04979 return decl_readonly_section (TREE_OPERAND (exp, 0), 0);
04980 else
04981 return false;
04982 }
04983
04984 #ifdef SGI_MONGOOSE
04985 tree
04986 c_strlen_exported (src)
04987 tree src;
04988 {
04989 #ifdef KEY
04990 return c_strlen(src, 0);
04991 #else
04992 return c_strlen(src);
04993 #endif // KEY
04994 }
04995 #endif