X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fbuiltins.c;h=8d86cc47511218c9b13eeb3aafe25ea7f6083b84;hb=bb9594ed71fc9d4d347495ae70cb925196c0da46;hp=6785ce546581fc43eb5ccde6a4724eb35df254e2;hpb=5e3608d85425f61a96a3ffb8cec184a80d2621e7;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/builtins.c b/gcc/builtins.c index 6785ce54658..8d86cc47511 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -79,7 +79,7 @@ static tree c_strlen PARAMS ((tree)); static const char *c_getstr PARAMS ((tree)); static rtx c_readstr PARAMS ((const char *, enum machine_mode)); -static int target_char_cast PARAMS ((tree, char *)); +static int target_char_cast PARAMS ((tree, char *)); static rtx get_memory_rtx PARAMS ((tree)); static int apply_args_size PARAMS ((void)); static int apply_result_size PARAMS ((void)); @@ -101,9 +101,8 @@ static rtx expand_builtin_next_arg PARAMS ((tree)); static rtx expand_builtin_va_start PARAMS ((int, tree)); static rtx expand_builtin_va_end PARAMS ((tree)); static rtx expand_builtin_va_copy PARAMS ((tree)); -#ifdef HAVE_cmpstrsi -static rtx expand_builtin_memcmp PARAMS ((tree, tree, rtx)); -#endif +static rtx expand_builtin_memcmp PARAMS ((tree, tree, rtx, + enum machine_mode)); static rtx expand_builtin_strcmp PARAMS ((tree, rtx, enum machine_mode)); static rtx expand_builtin_strncmp PARAMS ((tree, rtx, @@ -118,15 +117,18 @@ static rtx expand_builtin_strspn PARAMS ((tree, rtx, enum machine_mode)); static rtx expand_builtin_strcspn PARAMS ((tree, rtx, enum machine_mode)); -static rtx expand_builtin_memcpy PARAMS ((tree)); -static rtx expand_builtin_strcpy PARAMS ((tree)); +static rtx expand_builtin_memcpy PARAMS ((tree, rtx, + enum machine_mode)); +static rtx expand_builtin_strcpy PARAMS ((tree, rtx, + enum machine_mode)); static rtx builtin_strncpy_read_str PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode)); static rtx expand_builtin_strncpy PARAMS ((tree, rtx, enum machine_mode)); static rtx builtin_memset_read_str PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode)); -static rtx expand_builtin_memset PARAMS ((tree)); +static rtx expand_builtin_memset PARAMS ((tree, rtx, + enum machine_mode)); static rtx expand_builtin_bzero PARAMS ((tree)); static rtx expand_builtin_strlen PARAMS ((tree, rtx)); static rtx expand_builtin_strstr PARAMS ((tree, rtx, @@ -727,9 +729,26 @@ expand_builtin_prefetch (arglist) tree arg0, arg1, arg2; rtx op0, op1, op2; + if (!validate_arglist (arglist, POINTER_TYPE, 0)) + return; + arg0 = TREE_VALUE (arglist); - arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + /* Arguments 1 and 2 are optional; argument 1 (read/write) defaults to + zero (read) and argument 2 (locality) defaults to 3 (high degree of + locality). */ + if (TREE_CHAIN (arglist)) + { + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + if (TREE_CHAIN (TREE_CHAIN (arglist))) + arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + else + arg2 = build_int_2 (3, 0); + } + else + { + arg1 = integer_zero_node; + arg2 = build_int_2 (3, 0); + } /* Argument 0 is an address. */ op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL); @@ -740,7 +759,7 @@ expand_builtin_prefetch (arglist) error ("second arg to `__builtin_prefetch' must be a constant"); arg1 = integer_zero_node; } - op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); /* Argument 1 must be either zero or one. */ if (INTVAL (op1) != 0 && INTVAL (op1) != 1) { @@ -754,7 +773,7 @@ expand_builtin_prefetch (arglist) error ("third arg to `__builtin_prefetch' must be a constant"); arg2 = integer_zero_node; } - op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); + op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); /* Argument 2 must be 0, 1, 2, or 3. */ if (INTVAL (op2) < 0 || INTVAL (op2) > 3) { @@ -841,11 +860,11 @@ static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER]; used for calling a function. */ static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER]; -/* Return the offset of register REGNO into the block returned by +/* Return the offset of register REGNO into the block returned by __builtin_apply_args. This is not declared static, since it is needed in objc-act.c. */ -int +int apply_args_register_offset (regno) int regno; { @@ -866,7 +885,8 @@ static int apply_args_size () { static int size = -1; - int align, regno; + int align; + unsigned int regno; enum machine_mode mode; /* The values computed by this function never change. */ @@ -1026,7 +1046,7 @@ result_vector (savep, result) enum machine_mode mode; rtx reg, mem; rtx *savevec = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx)); - + size = nelts = 0; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if ((mode = apply_result_mode[regno]) != VOIDmode) @@ -1398,7 +1418,7 @@ type_to_class (type) default: return no_type_class; } } - + /* Expand a call to __builtin_classify_type with arguments found in ARGLIST. */ @@ -1445,7 +1465,7 @@ expand_builtin_mathfn (exp, target, subtarget) tree exp; rtx target, subtarget; { - optab builtin_optab; + optab builtin_optab; rtx op0, insns; tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); tree arglist = TREE_OPERAND (exp, 1); @@ -1487,7 +1507,7 @@ expand_builtin_mathfn (exp, target, subtarget) case BUILT_IN_COSF: case BUILT_IN_COSL: builtin_optab = cos_optab; break; - case BUILT_IN_FSQRT: + case BUILT_IN_SQRT: case BUILT_IN_SQRTF: case BUILT_IN_SQRTL: builtin_optab = sqrt_optab; break; @@ -1554,7 +1574,7 @@ expand_builtin_mathfn (exp, target, subtarget) insns = get_insns (); end_sequence (); emit_insns (insns); - + return target; } @@ -1617,13 +1637,6 @@ expand_builtin_strlen (exp, target) source operand later. */ before_strlen = get_last_insn(); - /* Check the string is readable and has an end. */ - if (current_function_check_memory_usage) - emit_library_call (chkr_check_str_libfunc, LCT_CONST_MAKE_BLOCK, - VOIDmode, 2, src_reg, Pmode, - GEN_INT (MEMORY_USE_RO), - TYPE_MODE (integer_type_node)); - char_rtx = const0_rtx; char_mode = insn_data[(int) icode].operand[2].mode; if (! (*insn_data[(int) icode].operand[2].predicate) (char_rtx, @@ -1638,7 +1651,7 @@ expand_builtin_strlen (exp, target) /* Now that we are assured of success, expand the source. */ start_sequence (); - pat = memory_address (BLKmode, + pat = memory_address (BLKmode, expand_expr (src, src_reg, ptr_mode, EXPAND_SUM)); if (pat != src_reg) emit_move_insn (src_reg, pat); @@ -1672,8 +1685,7 @@ expand_builtin_strstr (arglist, target, mode) rtx target; enum machine_mode mode; { - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE) - || current_function_check_memory_usage) + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; else { @@ -1729,8 +1741,7 @@ expand_builtin_strchr (arglist, target, mode) rtx target; enum machine_mode mode; { - if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE) - || current_function_check_memory_usage) + if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return 0; else { @@ -1776,8 +1787,7 @@ expand_builtin_strrchr (arglist, target, mode) rtx target; enum machine_mode mode; { - if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE) - || current_function_check_memory_usage) + if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return 0; else { @@ -1831,8 +1841,7 @@ expand_builtin_strpbrk (arglist, target, mode) rtx target; enum machine_mode mode; { - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE) - || current_function_check_memory_usage) + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; else { @@ -1904,11 +1913,16 @@ builtin_memcpy_read_str (data, offset, mode) return c_readstr (str + offset, mode); } -/* Expand a call to the memcpy builtin, with arguments in ARGLIST. */ +/* Expand a call to the memcpy builtin, with arguments in ARGLIST. + Return 0 if we failed, the caller should emit a normal call, otherwise + try to get the result in TARGET, if convenient (and in mode MODE if + that's convenient). */ static rtx -expand_builtin_memcpy (arglist) +expand_builtin_memcpy (arglist, target, mode) tree arglist; + rtx target; + enum machine_mode mode; { if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) @@ -1925,10 +1939,22 @@ expand_builtin_memcpy (arglist) = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); rtx dest_mem, src_mem, dest_addr, len_rtx; - /* If either SRC or DEST is not a pointer type, don't do - this operation in-line. */ - if (src_align == 0 || dest_align == 0) - return 0; + /* If DEST is not a pointer type, call the normal function. */ + if (dest_align == 0) + return 0; + + /* If the LEN parameter is zero, return DEST. */ + if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0) + { + /* Evaluate and ignore SRC in case it has side-effects. */ + expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL); + return expand_expr (dest, target, mode, EXPAND_NORMAL); + } + + /* If either SRC is not a pointer type, don't do this + operation in-line. */ + if (src_align == 0) + return 0; dest_mem = get_memory_rtx (dest); set_mem_align (dest_mem, dest_align); @@ -1939,7 +1965,6 @@ expand_builtin_memcpy (arglist) by pieces, we can avoid loading the string from memory and only stored the computed constants. */ if (src_str - && !current_function_check_memory_usage && GET_CODE (len_rtx) == CONST_INT && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1 && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str, @@ -1954,13 +1979,6 @@ expand_builtin_memcpy (arglist) src_mem = get_memory_rtx (src); set_mem_align (src_mem, src_align); - /* Just copy the rights of SRC to the rights of DEST. */ - if (current_function_check_memory_usage) - emit_library_call (chkr_copy_bitmap_libfunc, LCT_CONST_MAKE_BLOCK, - VOIDmode, 3, XEXP (dest_mem, 0), Pmode, - XEXP (src_mem, 0), Pmode, - len_rtx, TYPE_MODE (sizetype)); - /* Copy word part most expediently. */ dest_addr = emit_block_move (dest_mem, src_mem, len_rtx); @@ -1972,33 +1990,34 @@ expand_builtin_memcpy (arglist) } /* Expand expression EXP, which is a call to the strcpy builtin. Return 0 - if we failed the caller should emit a normal call. */ + if we failed the caller should emit a normal call, otherwise try to get + the result in TARGET, if convenient (and in mode MODE if that's + convenient). */ static rtx -expand_builtin_strcpy (exp) +expand_builtin_strcpy (exp, target, mode) tree exp; + rtx target; + enum machine_mode mode; { tree arglist = TREE_OPERAND (exp, 1); - rtx result; + tree fn, len; if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; - else - { - tree len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist))); - if (len == 0) - return 0; - - len = size_binop (PLUS_EXPR, len, ssize_int (1)); - chainon (arglist, build_tree_list (NULL_TREE, len)); - } + fn = built_in_decls[BUILT_IN_MEMCPY]; + if (!fn) + return 0; - result = expand_builtin_memcpy (arglist); + len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist))); + if (len == 0) + return 0; - if (! result) - TREE_CHAIN (TREE_CHAIN (arglist)) = 0; - return result; + len = size_binop (PLUS_EXPR, len, ssize_int (1)); + chainon (arglist, build_tree_list (NULL_TREE, len)); + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); } /* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE) @@ -2035,6 +2054,7 @@ expand_builtin_strncpy (arglist, target, mode) { tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist))); tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + tree fn; /* We must be passed a constant len parameter. */ if (TREE_CODE (len) != INTEGER_CST) @@ -2047,7 +2067,7 @@ expand_builtin_strncpy (arglist, target, mode) side-effects. */ expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx, VOIDmode, EXPAND_NORMAL); - /* Return the dst parameter. */ + /* Return the dst parameter. */ return expand_expr (TREE_VALUE (arglist), target, mode, EXPAND_NORMAL); } @@ -2081,9 +2101,13 @@ expand_builtin_strncpy (arglist, target, mode) (PTR) p, dest_align); return force_operand (XEXP (dest_mem, 0), NULL_RTX); } - + /* OK transform into builtin memcpy. */ - return expand_builtin_memcpy (arglist); + fn = built_in_decls[BUILT_IN_MEMCPY]; + if (!fn) + return 0; + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); } } @@ -2106,11 +2130,15 @@ builtin_memset_read_str (data, offset, mode) } /* Expand expression EXP, which is a call to the memset builtin. Return 0 - if we failed the caller should emit a normal call. */ + if we failed the caller should emit a normal call, otherwise try to get + the result in TARGET, if convenient (and in mode MODE if that's + convenient). */ static rtx -expand_builtin_memset (exp) +expand_builtin_memset (exp, target, mode) tree exp; + rtx target; + enum machine_mode mode; { tree arglist = TREE_OPERAND (exp, 1); @@ -2128,11 +2156,19 @@ expand_builtin_memset (exp) = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); rtx dest_mem, dest_addr, len_rtx; - /* If DEST is not a pointer type, don't do this + /* If DEST is not a pointer type, don't do this operation in-line. */ if (dest_align == 0) return 0; + /* If the LEN parameter is zero, return DEST. */ + if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0) + { + /* Evaluate and ignore VAL in case it has side-effects. */ + expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL); + return expand_expr (dest, target, mode, EXPAND_NORMAL); + } + if (TREE_CODE (val) != INTEGER_CST) return 0; @@ -2143,10 +2179,9 @@ expand_builtin_memset (exp) { if (!host_integerp (len, 1)) return 0; - if (current_function_check_memory_usage - || !can_store_by_pieces (tree_low_cst (len, 1), - builtin_memset_read_str, - (PTR) &c, dest_align)) + if (!can_store_by_pieces (tree_low_cst (len, 1), + builtin_memset_read_str, (PTR) &c, + dest_align)) return 0; dest_mem = get_memory_rtx (dest); @@ -2160,16 +2195,6 @@ expand_builtin_memset (exp) dest_mem = get_memory_rtx (dest); set_mem_align (dest_mem, dest_align); - - /* Just check DST is writable and mark it as readable. */ - if (current_function_check_memory_usage) - emit_library_call (chkr_check_addr_libfunc, LCT_CONST_MAKE_BLOCK, - VOIDmode, 3, XEXP (dest_mem, 0), Pmode, - len_rtx, TYPE_MODE (sizetype), - GEN_INT (MEMORY_USE_WO), - TYPE_MODE (integer_type_node)); - - dest_addr = clear_storage (dest_mem, len_rtx); if (dest_addr == 0) @@ -2195,49 +2220,77 @@ expand_builtin_bzero (exp) dest = TREE_VALUE (arglist); size = TREE_VALUE (TREE_CHAIN (arglist)); - + /* New argument list transforming bzero(ptr x, int y) to - memset(ptr x, int 0, size_t y). */ - + memset(ptr x, int 0, size_t y). This is done this way + so that if it isn't expanded inline, we fallback to + calling bzero instead of memset. */ + newarglist = build_tree_list (NULL_TREE, convert (sizetype, size)); newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist); newarglist = tree_cons (NULL_TREE, dest, newarglist); TREE_OPERAND (exp, 1) = newarglist; - result = expand_builtin_memset(exp); - + result = expand_builtin_memset (exp, const0_rtx, VOIDmode); + /* Always restore the original arguments. */ TREE_OPERAND (exp, 1) = arglist; return result; } -#ifdef HAVE_cmpstrsi - /* Expand expression EXP, which is a call to the memcmp or the strcmp builtin. ARGLIST is the argument list for this call. Return 0 if we failed and the caller should emit a normal call, otherwise try to get the result in - TARGET, if convenient. */ + TARGET, if convenient (and in mode MODE, if that's convenient). */ static rtx -expand_builtin_memcmp (exp, arglist, target) - tree exp; +expand_builtin_memcmp (exp, arglist, target, mode) + tree exp ATTRIBUTE_UNUSED; tree arglist; rtx target; + enum machine_mode mode; { - /* If we need to check memory accesses, call the library function. */ - if (current_function_check_memory_usage) - return 0; + tree arg1, arg2, len; if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return 0; + arg1 = TREE_VALUE (arglist); + arg2 = TREE_VALUE (TREE_CHAIN (arglist)); + len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + + /* If the len parameter is zero, return zero. */ + if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0) + { + /* Evaluate and ignore arg1 and arg2 in case they have + side-effects. */ + expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL); + expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL); + return const0_rtx; + } + + /* If len parameter is one, return an expression corresponding to + (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */ + if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1) + { + tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); + tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node); + tree ind1 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg1)))); + tree ind2 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg2)))); + tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2)); + return expand_expr (result, target, mode, EXPAND_NORMAL); + } + +#ifdef HAVE_cmpstrsi { - enum machine_mode mode; - tree arg1 = TREE_VALUE (arglist); - tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); - tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); rtx arg1_rtx, arg2_rtx, arg3_rtx; rtx result; rtx insn; @@ -2292,9 +2345,11 @@ expand_builtin_memcmp (exp, arglist, target) else return convert_to_mode (mode, result, 0); } -} #endif + return 0; +} + /* Expand expression EXP, which is a call to the strcmp builtin. Return 0 if we failed the caller should emit a normal call, otherwise try to get the result in TARGET, if convenient. */ @@ -2306,13 +2361,9 @@ expand_builtin_strcmp (exp, target, mode) enum machine_mode mode; { tree arglist = TREE_OPERAND (exp, 1); - tree arg1, arg2; + tree arg1, arg2, len, len2, fn; const char *p1, *p2; - /* If we need to check memory accesses, call the library function. */ - if (current_function_check_memory_usage) - return 0; - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; @@ -2345,59 +2396,50 @@ expand_builtin_strcmp (exp, target, mode) tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2)); return expand_expr (result, target, mode, EXPAND_NORMAL); } - -#ifdef HAVE_cmpstrsi - if (! HAVE_cmpstrsi) - return 0; - { - tree len = c_strlen (arg1); - tree len2 = c_strlen (arg2); - rtx result; + len = c_strlen (arg1); + len2 = c_strlen (arg2); - if (len) - len = size_binop (PLUS_EXPR, ssize_int (1), len); + if (len) + len = size_binop (PLUS_EXPR, ssize_int (1), len); - if (len2) - len2 = size_binop (PLUS_EXPR, ssize_int (1), len2); + if (len2) + len2 = size_binop (PLUS_EXPR, ssize_int (1), len2); - /* If we don't have a constant length for the first, use the length - of the second, if we know it. We don't require a constant for - this case; some cost analysis could be done if both are available - but neither is constant. For now, assume they're equally cheap - unless one has side effects. + /* If we don't have a constant length for the first, use the length + of the second, if we know it. We don't require a constant for + this case; some cost analysis could be done if both are available + but neither is constant. For now, assume they're equally cheap + unless one has side effects. - If both strings have constant lengths, use the smaller. This - could arise if optimization results in strcpy being called with - two fixed strings, or if the code was machine-generated. We should - add some code to the `memcmp' handler below to deal with such - situations, someday. */ + If both strings have constant lengths, use the smaller. This + could arise if optimization results in strcpy being called with + two fixed strings, or if the code was machine-generated. We should + add some code to the `memcmp' handler below to deal with such + situations, someday. */ - if (!len || TREE_CODE (len) != INTEGER_CST) - { - if (len2 && !TREE_SIDE_EFFECTS (len2)) - len = len2; - else if (len == 0) - return 0; - } - else if (len2 && TREE_CODE (len2) == INTEGER_CST - && tree_int_cst_lt (len2, len)) - len = len2; + if (!len || TREE_CODE (len) != INTEGER_CST) + { + if (len2 && !TREE_SIDE_EFFECTS (len2)) + len = len2; + else if (len == 0) + return 0; + } + else if (len2 && TREE_CODE (len2) == INTEGER_CST + && tree_int_cst_lt (len2, len)) + len = len2; - /* If both arguments have side effects, we cannot optimize. */ - if (TREE_SIDE_EFFECTS (len)) - return 0; + /* If both arguments have side effects, we cannot optimize. */ + if (TREE_SIDE_EFFECTS (len)) + return 0; - chainon (arglist, build_tree_list (NULL_TREE, len)); - result = expand_builtin_memcmp (exp, arglist, target); - if (! result) - TREE_CHAIN (TREE_CHAIN (arglist)) = 0; + fn = built_in_decls[BUILT_IN_MEMCMP]; + if (!fn) + return 0; - return result; - } -#else - return 0; -#endif + chainon (arglist, build_tree_list (NULL_TREE, len)); + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); } /* Expand expression EXP, which is a call to the strncmp builtin. Return 0 @@ -2411,13 +2453,10 @@ expand_builtin_strncmp (exp, target, mode) enum machine_mode mode; { tree arglist = TREE_OPERAND (exp, 1); + tree fn, newarglist, len = 0; tree arg1, arg2, arg3; const char *p1, *p2; - /* If we need to check memory accesses, call the library function. */ - if (current_function_check_memory_usage) - return 0; - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return 0; @@ -2467,45 +2506,42 @@ expand_builtin_strncmp (exp, target, mode) return expand_expr (result, target, mode, EXPAND_NORMAL); } -#ifdef HAVE_cmpstrsi /* If c_strlen can determine an expression for one of the string lengths, and it doesn't have side effects, then call expand_builtin_memcmp() using length MIN(strlen(string)+1, arg3). */ - if (HAVE_cmpstrsi) - { - tree newarglist, len = 0; - - /* Perhaps one of the strings is really constant, if so prefer - that constant length over the other string's length. */ - if (p1) - len = c_strlen (arg1); - else if (p2) - len = c_strlen (arg2); - - /* If we still don't have a len, try either string arg as long - as they don't have side effects. */ - if (!len && !TREE_SIDE_EFFECTS (arg1)) - len = c_strlen (arg1); - if (!len && !TREE_SIDE_EFFECTS (arg2)) - len = c_strlen (arg2); - /* If we still don't have a length, punt. */ - if (!len) - return 0; - - /* Add one to the string length. */ - len = fold (size_binop (PLUS_EXPR, len, ssize_int (1))); - - /* The actual new length parameter is MIN(len,arg3). */ - len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3)); - - newarglist = build_tree_list (NULL_TREE, len); - newarglist = tree_cons (NULL_TREE, arg2, newarglist); - newarglist = tree_cons (NULL_TREE, arg1, newarglist); - return expand_builtin_memcmp (exp, newarglist, target); - } -#endif - - return 0; + + /* Perhaps one of the strings is really constant, if so prefer + that constant length over the other string's length. */ + if (p1) + len = c_strlen (arg1); + else if (p2) + len = c_strlen (arg2); + + /* If we still don't have a len, try either string arg as long + as they don't have side effects. */ + if (!len && !TREE_SIDE_EFFECTS (arg1)) + len = c_strlen (arg1); + if (!len && !TREE_SIDE_EFFECTS (arg2)) + len = c_strlen (arg2); + /* If we still don't have a length, punt. */ + if (!len) + return 0; + + fn = built_in_decls[BUILT_IN_MEMCMP]; + if (!fn) + return 0; + + /* Add one to the string length. */ + len = fold (size_binop (PLUS_EXPR, len, ssize_int (1))); + + /* The actual new length parameter is MIN(len,arg3). */ + len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3)); + + newarglist = build_tree_list (NULL_TREE, len); + newarglist = tree_cons (NULL_TREE, arg2, newarglist); + newarglist = tree_cons (NULL_TREE, arg1, newarglist); + return expand_expr (build_function_call_expr (fn, newarglist), + target, mode, EXPAND_NORMAL); } /* Expand expression EXP, which is a call to the strcat builtin. @@ -2518,10 +2554,6 @@ expand_builtin_strcat (arglist, target, mode) rtx target; enum machine_mode mode; { - /* If we need to check memory accesses, call the library function. */ - if (current_function_check_memory_usage) - return 0; - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; else @@ -2548,10 +2580,6 @@ expand_builtin_strncat (arglist, target, mode) rtx target; enum machine_mode mode; { - /* If we need to check memory accesses, call the library function. */ - if (current_function_check_memory_usage) - return 0; - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return 0; @@ -2582,7 +2610,7 @@ expand_builtin_strncat (arglist, target, mode) tree newarglist = tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src)), fn = built_in_decls[BUILT_IN_STRCAT]; - + /* If the replacement _DECL isn't initialized, don't do the transformation. */ if (!fn) @@ -2605,24 +2633,20 @@ expand_builtin_strspn (arglist, target, mode) rtx target; enum machine_mode mode; { - /* If we need to check memory accesses, call the library function. */ - if (current_function_check_memory_usage) - return 0; - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; else { tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); const char *p1 = c_getstr (s1), *p2 = c_getstr (s2); - + /* If both arguments are constants, evaluate at compile-time. */ if (p1 && p2) { const size_t r = strspn (p1, p2); return expand_expr (size_int (r), target, mode, EXPAND_NORMAL); } - + /* If either argument is "", return 0. */ if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0')) { @@ -2646,24 +2670,20 @@ expand_builtin_strcspn (arglist, target, mode) rtx target; enum machine_mode mode; { - /* If we need to check memory accesses, call the library function. */ - if (current_function_check_memory_usage) - return 0; - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; else { tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); const char *p1 = c_getstr (s1), *p2 = c_getstr (s2); - + /* If both arguments are constants, evaluate at compile-time. */ if (p1 && p2) { const size_t r = strcspn (p1, p2); return expand_expr (size_int (r), target, mode, EXPAND_NORMAL); } - + /* If the first argument is "", return 0. */ if (p1 && *p1 == '\0') { @@ -2678,7 +2698,7 @@ expand_builtin_strcspn (arglist, target, mode) { tree newarglist = build_tree_list (NULL_TREE, s1), fn = built_in_decls[BUILT_IN_STRLEN]; - + /* If the replacement _DECL isn't initialized, don't do the transformation. */ if (!fn) @@ -2752,7 +2772,7 @@ expand_builtin_args_info (exp) tree arglist = TREE_OPERAND (exp, 1); int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int); int *word_ptr = (int *) ¤t_function_args_info; -#if 0 +#if 0 /* These are used by the code below that is if 0'ed away */ int i; tree type, elts, result; @@ -2791,7 +2811,7 @@ expand_builtin_args_info (exp) TREE_STATIC (result) = 1; result = build1 (INDIRECT_REF, build_pointer_type (type), result); TREE_CONSTANT (result) = 1; - return expand_expr (result, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_BAD); + return expand_expr (result, NULL_RTX, VOIDmode, 0); #endif } @@ -2818,7 +2838,7 @@ expand_builtin_next_arg (arglist) tree arg = TREE_VALUE (arglist); /* Strip off all nops for the sake of the comparison. This - is not quite the same as STRIP_NOPS. It does more. + is not quite the same as STRIP_NOPS. It does more. We must also strip off INDIRECT_EXPR for C++ reference parameters. */ while (TREE_CODE (arg) == NOP_EXPR @@ -2859,10 +2879,10 @@ stabilize_va_list (valist, needs_lvalue) So fix it. */ if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE) { - tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node)); - tree p2 = build_pointer_type (va_list_type_node); + tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node)); + tree p2 = build_pointer_type (va_list_type_node); - valist = build1 (ADDR_EXPR, p2, valist); + valist = build1 (ADDR_EXPR, p2, valist); valist = fold (build1 (NOP_EXPR, p1, valist)); } } @@ -2874,7 +2894,7 @@ stabilize_va_list (valist, needs_lvalue) { if (! TREE_SIDE_EFFECTS (valist)) return valist; - + pt = build_pointer_type (va_list_type_node); valist = fold (build1 (ADDR_EXPR, pt, valist)); TREE_SIDE_EFFECTS (valist) = 1; @@ -3007,7 +3027,7 @@ expand_builtin_va_arg (valist, type) have_va_type = TREE_TYPE (valist); if (TREE_CODE (want_va_type) == ARRAY_TYPE) { - /* If va_list is an array type, the argument may have decayed + /* If va_list is an array type, the argument may have decayed to a pointer type, e.g. by being passed to another function. In that case, unwrap both types so that we can compare the underlying records. */ @@ -3102,7 +3122,7 @@ expand_builtin_va_end (arglist) return const0_rtx; } -/* Expand ARGLIST, from a call to __builtin_va_copy. We do this as a +/* Expand ARGLIST, from a call to __builtin_va_copy. We do this as a builtin rather than just as an assignment in stdarg.h because of the nastiness of array-type va_list types. */ @@ -3280,8 +3300,7 @@ expand_builtin_fputs (arglist, ignore) return 0; /* Verify the arguments in the original call. */ - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE) - || current_function_check_memory_usage) + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; /* Get the length of the string passed to fputs. If the length @@ -3305,7 +3324,7 @@ expand_builtin_fputs (arglist, ignore) const char *p = c_getstr (TREE_VALUE (arglist)); if (p != NULL) - { + { /* New argument list transforming fputs(string, stream) to fputc(string[0], stream). */ arglist = @@ -3320,7 +3339,7 @@ expand_builtin_fputs (arglist, ignore) case 1: /* length is greater than 1, call fwrite. */ { tree string_arg = TREE_VALUE (arglist); - + /* New argument list transforming fputs(string, stream) to fwrite(string, 1, len, stream). */ arglist = build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist))); @@ -3333,7 +3352,7 @@ expand_builtin_fputs (arglist, ignore) default: abort(); } - + return expand_expr (build_function_call_expr (fn, arglist), (ignore ? const0_rtx : NULL_RTX), VOIDmode, EXPAND_NORMAL); @@ -3372,7 +3391,7 @@ expand_builtin_expect (arglist, target) moderately sure to be able to correctly interpret the branch condition later. */ target = force_reg (GET_MODE (target), target); - + rtx_c = expand_expr (c, NULL_RTX, GET_MODE (target), EXPAND_NORMAL); note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE); @@ -3524,27 +3543,49 @@ expand_builtin (exp, target, subtarget, mode, ignore) if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) return (*targetm.expand_builtin) (exp, target, subtarget, mode, ignore); - + /* When not optimizing, generate calls to library functions for a certain set of builtins. */ - if (! optimize && ! CALLED_AS_BUILT_IN (fndecl) - && (fcode == BUILT_IN_SIN || fcode == BUILT_IN_COS - || fcode == BUILT_IN_FSQRT || fcode == BUILT_IN_SQRTF - || fcode == BUILT_IN_SQRTL || fcode == BUILT_IN_MEMSET - || fcode == BUILT_IN_MEMCPY || fcode == BUILT_IN_MEMCMP - || fcode == BUILT_IN_BCMP || fcode == BUILT_IN_BZERO - || fcode == BUILT_IN_INDEX || fcode == BUILT_IN_RINDEX - || fcode == BUILT_IN_STRCHR || fcode == BUILT_IN_STRRCHR - || fcode == BUILT_IN_STRLEN || fcode == BUILT_IN_STRCPY - || fcode == BUILT_IN_STRNCPY || fcode == BUILT_IN_STRNCMP - || fcode == BUILT_IN_STRSTR || fcode == BUILT_IN_STRPBRK - || fcode == BUILT_IN_STRCAT || fcode == BUILT_IN_STRNCAT - || fcode == BUILT_IN_STRSPN || fcode == BUILT_IN_STRCSPN - || fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_FFS - || fcode == BUILT_IN_PUTCHAR || fcode == BUILT_IN_PUTS - || fcode == BUILT_IN_PRINTF || fcode == BUILT_IN_FPUTC - || fcode == BUILT_IN_FPUTS || fcode == BUILT_IN_FWRITE)) - return expand_call (exp, target, ignore); + if (!optimize && !CALLED_AS_BUILT_IN (fndecl)) + switch (fcode) + { + case BUILT_IN_SIN: + case BUILT_IN_COS: + case BUILT_IN_SQRT: + case BUILT_IN_SQRTF: + case BUILT_IN_SQRTL: + case BUILT_IN_MEMSET: + case BUILT_IN_MEMCPY: + case BUILT_IN_MEMCMP: + case BUILT_IN_BCMP: + case BUILT_IN_BZERO: + case BUILT_IN_INDEX: + case BUILT_IN_RINDEX: + case BUILT_IN_STRCHR: + case BUILT_IN_STRRCHR: + case BUILT_IN_STRLEN: + case BUILT_IN_STRCPY: + case BUILT_IN_STRNCPY: + case BUILT_IN_STRNCMP: + case BUILT_IN_STRSTR: + case BUILT_IN_STRPBRK: + case BUILT_IN_STRCAT: + case BUILT_IN_STRNCAT: + case BUILT_IN_STRSPN: + case BUILT_IN_STRCSPN: + case BUILT_IN_STRCMP: + case BUILT_IN_FFS: + case BUILT_IN_PUTCHAR: + case BUILT_IN_PUTS: + case BUILT_IN_PRINTF: + case BUILT_IN_FPUTC: + case BUILT_IN_FPUTS: + case BUILT_IN_FWRITE: + return expand_call (exp, target, ignore); + + default: + break; + } switch (fcode) { @@ -3581,7 +3622,7 @@ expand_builtin (exp, target, subtarget, mode, ignore) because of possible accuracy problems. */ if (! flag_unsafe_math_optimizations) break; - case BUILT_IN_FSQRT: + case BUILT_IN_SQRT: case BUILT_IN_SQRTF: case BUILT_IN_SQRTL: target = expand_builtin_mathfn (exp, target, subtarget); @@ -3681,53 +3722,53 @@ expand_builtin (exp, target, subtarget, mode, ignore) break; case BUILT_IN_STRCPY: - target = expand_builtin_strcpy (exp); + target = expand_builtin_strcpy (exp, target, mode); if (target) return target; break; - + case BUILT_IN_STRNCPY: target = expand_builtin_strncpy (arglist, target, mode); if (target) return target; break; - + case BUILT_IN_STRCAT: target = expand_builtin_strcat (arglist, target, mode); if (target) return target; break; - + case BUILT_IN_STRNCAT: target = expand_builtin_strncat (arglist, target, mode); if (target) return target; break; - + case BUILT_IN_STRSPN: target = expand_builtin_strspn (arglist, target, mode); if (target) return target; break; - + case BUILT_IN_STRCSPN: target = expand_builtin_strcspn (arglist, target, mode); if (target) return target; break; - + case BUILT_IN_STRSTR: target = expand_builtin_strstr (arglist, target, mode); if (target) return target; break; - + case BUILT_IN_STRPBRK: target = expand_builtin_strpbrk (arglist, target, mode); if (target) return target; break; - + case BUILT_IN_INDEX: case BUILT_IN_STRCHR: target = expand_builtin_strchr (arglist, target, mode); @@ -3743,13 +3784,13 @@ expand_builtin (exp, target, subtarget, mode, ignore) break; case BUILT_IN_MEMCPY: - target = expand_builtin_memcpy (arglist); + target = expand_builtin_memcpy (arglist, target, mode); if (target) return target; break; case BUILT_IN_MEMSET: - target = expand_builtin_memset (exp); + target = expand_builtin_memset (exp, target, mode); if (target) return target; break; @@ -3772,21 +3813,12 @@ expand_builtin (exp, target, subtarget, mode, ignore) return target; break; -/* These comparison functions need an instruction that returns an actual - index. An ordinary compare that just sets the condition codes - is not enough. */ -#ifdef HAVE_cmpstrsi case BUILT_IN_BCMP: case BUILT_IN_MEMCMP: - target = expand_builtin_memcmp (exp, arglist, target); + target = expand_builtin_memcmp (exp, arglist, target, mode); if (target) return target; break; -#else - case BUILT_IN_BCMP: - case BUILT_IN_MEMCMP: - break; -#endif case BUILT_IN_SETJMP: target = expand_builtin_setjmp (arglist, target); @@ -3837,7 +3869,7 @@ expand_builtin (exp, target, subtarget, mode, ignore) if (target) return target; break; - + /* Various hooks for the DWARF 2 __throw routine. */ case BUILT_IN_UNWIND_INIT: expand_builtin_unwind_init ();