diff options
-rw-r--r-- | gcc/ChangeLog | 52 | ||||
-rw-r--r-- | gcc/builtins.c | 977 | ||||
-rw-r--r-- | gcc/fold-const.c | 5 | ||||
-rw-r--r-- | gcc/passes.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/builtins-44.c | 10 | ||||
-rw-r--r-- | gcc/tree-inline.c | 46 | ||||
-rw-r--r-- | gcc/tree-ssa-ccp.c | 11 | ||||
-rw-r--r-- | gcc/tree-ssa-dom.c | 14 | ||||
-rw-r--r-- | gcc/tree-ssa-propagate.c | 18 |
10 files changed, 456 insertions, 689 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7099995..74c6d06 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,55 @@ +2009-09-28 Michael Matz <matz@suse.de> + + * builtins.c (interclass_mathfn_icode): New helper. + (expand_builtin_interclass_mathfn): Use it here, and split folding + into ... + (fold_builtin_interclass_mathfn): ... this new folder. + (build_call_nofold_loc): New static helper. + (build_call_nofold): New wrapper macro for above. + (expand_builtin_int_roundingfn): Use it instead of build_call_expr. + (expand_builtin_pow): Ditto. + (expand_builtin_memset_args): Ditto. + (expand_builtin_printf): Ditto. + (expand_builtin_fprintf): Ditto. + (expand_builtin_sprintf): Ditto. + (expand_builtin_memory_chk): Ditto. + (expand_builtin_mempcpy_args): Ditto and don't call folders. + (expand_builtin_stpcpy): Ditto. + (expand_builtin_strcmp): Ditto. + (expand_builtin_strncmp): Ditto. + (expand_builtin_strcpy): Remove FNDECL and MODE arguments. + (expand_builtin_strcpy_args): Don't call folders. + (expand_builtin_memcmp): Ditto. + (expand_builtin_strncpy): Ditto, and use target. + (expand_builtin_memcpy): Ditto. + (expand_builtin_strstr, expand_builtin_strchr, expand_builtin_strrchr, + expand_builtin_strpbrk, expand_builtin_memmove, + expand_builtin_memmove_args, expand_builtin_bcopy, + expand_builtin_memchr, expand_builtin_strcat, expand_builtin_strncat, + expand_builtin_strspn, expand_builtin_strcspn, + expand_builtin_fputs): Remove these. + (expand_builtin): Don't call the above, change calls to other + expanders that changed prototype. + (fold_builtin_stpcpy): New folder split out from expand_builtin_stpcpy. + (fold_builtin_1 <ISFINITE, ISINF, ISNORMAL>): Call + fold_builtin_interclass_mathfn. + (fold_builtin_2 <STPCPY>): Call fold_builtin_stpcpy. + (fold_builtin_strcat): Add folding split from expand_builtin_strcat. + + * fold-const.c (fold_binary_loc <NE_EXPR>): Add !exp != 0 -> !exp. + * passes.c (init_optimization_passes): Move pass_fold_builtins + after last phiopt pass. + * tree-inline.c (fold_marked_statements): When folding builtins + iterate over all instruction potentially generated. + * tree-ssa-ccp.c (gimplify_and_update_call_from_tree): Declare + earlier. + (fold_gimple_call): Use it to always fold calls (into potentially + multiple instructions). + * tree-ssa-dom.c (optimize_stmt): Resolve __builtin_constant_p + calls into zero at this time. + * tree-ssa-propagate.c (substitute_and_fold): Ignore multiple + statements generated by builtin folding. + 2009-09-28 Nick Clifton <nickc@redhat.com> * config/m32r/m32r.c (m32r_is_insn): Return false for debugging diff --git a/gcc/builtins.c b/gcc/builtins.c index 7227481..64840e1 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -112,40 +112,26 @@ static rtx expand_builtin_next_arg (void); static rtx expand_builtin_va_start (tree); static rtx expand_builtin_va_end (tree); static rtx expand_builtin_va_copy (tree); -static rtx expand_builtin_memchr (tree, rtx, enum machine_mode); static rtx expand_builtin_memcmp (tree, rtx, enum machine_mode); -static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode); +static rtx expand_builtin_strcmp (tree, rtx); static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode); static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, enum machine_mode); -static rtx expand_builtin_strcat (tree, tree, rtx, enum machine_mode); -static rtx expand_builtin_strncat (tree, rtx, enum machine_mode); -static rtx expand_builtin_strspn (tree, rtx, enum machine_mode); -static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode); -static rtx expand_builtin_memcpy (tree, rtx, enum machine_mode); +static rtx expand_builtin_memcpy (tree, rtx); static rtx expand_builtin_mempcpy (tree, rtx, enum machine_mode); -static rtx expand_builtin_mempcpy_args (tree, tree, tree, tree, rtx, +static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx, enum machine_mode, int); -static rtx expand_builtin_memmove (tree, rtx, enum machine_mode, int); -static rtx expand_builtin_memmove_args (tree, tree, tree, tree, rtx, - enum machine_mode, int); -static rtx expand_builtin_bcopy (tree, int); -static rtx expand_builtin_strcpy (tree, tree, rtx, enum machine_mode); -static rtx expand_builtin_strcpy_args (tree, tree, tree, rtx, enum machine_mode); +static rtx expand_builtin_strcpy (tree, rtx); +static rtx expand_builtin_strcpy_args (tree, tree, rtx); static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode); -static rtx expand_builtin_strncpy (tree, rtx, enum machine_mode); +static rtx expand_builtin_strncpy (tree, rtx); static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, enum machine_mode); static rtx expand_builtin_memset (tree, rtx, enum machine_mode); static rtx expand_builtin_memset_args (tree, tree, tree, rtx, enum machine_mode, tree); static rtx expand_builtin_bzero (tree); static rtx expand_builtin_strlen (tree, rtx, enum machine_mode); -static rtx expand_builtin_strstr (tree, rtx, enum machine_mode); -static rtx expand_builtin_strpbrk (tree, rtx, enum machine_mode); -static rtx expand_builtin_strchr (tree, rtx, enum machine_mode); -static rtx expand_builtin_strrchr (tree, rtx, enum machine_mode); static rtx expand_builtin_alloca (tree, rtx); static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab); static rtx expand_builtin_frame_address (tree, tree); -static rtx expand_builtin_fputs (tree, rtx, bool); static rtx expand_builtin_printf (tree, rtx, enum machine_mode, bool); static rtx expand_builtin_fprintf (tree, rtx, enum machine_mode, bool); static rtx expand_builtin_sprintf (tree, rtx, enum machine_mode); @@ -2248,30 +2234,16 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget) return target; } -/* Expand a call to one of the builtin math functions that operate on - floating point argument and output an integer result (ilogb, isinf, - isnan, etc). - Return 0 if a normal call should be emitted rather than expanding the - function in-line. EXP is the expression that is a call to the builtin - function; if convenient, the result should be placed in TARGET. - SUBTARGET may be used as the target for computing one of EXP's operands. */ +/* Given an interclass math builtin decl FNDECL and it's argument ARG + return an RTL instruction code that implements the functionality. + If that isn't possible or available return CODE_FOR_nothing. */ -static rtx -expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget) +static enum insn_code +interclass_mathfn_icode (tree arg, tree fndecl) { + bool errno_set = false; optab builtin_optab = 0; - enum insn_code icode = CODE_FOR_nothing; - rtx op0; - tree fndecl = get_callee_fndecl (exp); enum machine_mode mode; - bool errno_set = false; - tree arg; - location_t loc = EXPR_LOCATION (exp); - - if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE)) - return NULL_RTX; - - arg = CALL_EXPR_ARG (exp, 0); switch (DECL_FUNCTION_CODE (fndecl)) { @@ -2282,6 +2254,12 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget) case BUILT_IN_ISNORMAL: case BUILT_IN_ISFINITE: CASE_FLT_FN (BUILT_IN_FINITE): + case BUILT_IN_FINITED32: + case BUILT_IN_FINITED64: + case BUILT_IN_FINITED128: + case BUILT_IN_ISINFD32: + case BUILT_IN_ISINFD64: + case BUILT_IN_ISINFD128: /* These builtins have no optabs (yet). */ break; default: @@ -2290,15 +2268,40 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget) /* There's no easy way to detect the case we need to set EDOM. */ if (flag_errno_math && errno_set) - return NULL_RTX; + return CODE_FOR_nothing; /* Optab mode depends on the mode of the input argument. */ mode = TYPE_MODE (TREE_TYPE (arg)); if (builtin_optab) - icode = optab_handler (builtin_optab, mode)->insn_code; - - /* Before working hard, check whether the instruction is available. */ + return optab_handler (builtin_optab, mode)->insn_code; + return CODE_FOR_nothing; +} + +/* Expand a call to one of the builtin math functions that operate on + floating point argument and output an integer result (ilogb, isinf, + isnan, etc). + Return 0 if a normal call should be emitted rather than expanding the + function in-line. EXP is the expression that is a call to the builtin + function; if convenient, the result should be placed in TARGET. + SUBTARGET may be used as the target for computing one of EXP's operands. */ + +static rtx +expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget) +{ + enum insn_code icode = CODE_FOR_nothing; + rtx op0; + tree fndecl = get_callee_fndecl (exp); + enum machine_mode mode; + tree arg; + + if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE)) + return NULL_RTX; + + arg = CALL_EXPR_ARG (exp, 0); + icode = interclass_mathfn_icode (arg, fndecl); + mode = TYPE_MODE (TREE_TYPE (arg)); + if (icode != CODE_FOR_nothing) { /* Make a suitable register to place result in. */ @@ -2325,71 +2328,7 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget) return target; } - /* If there is no optab, try generic code. */ - switch (DECL_FUNCTION_CODE (fndecl)) - { - tree result; - - CASE_FLT_FN (BUILT_IN_ISINF): - { - /* isinf(x) -> isgreater(fabs(x),DBL_MAX). */ - tree const isgr_fn = built_in_decls[BUILT_IN_ISGREATER]; - tree const type = TREE_TYPE (arg); - REAL_VALUE_TYPE r; - char buf[128]; - - get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf)); - real_from_string (&r, buf); - result = build_call_expr (isgr_fn, 2, - fold_build1_loc (loc, ABS_EXPR, type, arg), - build_real (type, r)); - return expand_expr (result, target, VOIDmode, EXPAND_NORMAL); - } - CASE_FLT_FN (BUILT_IN_FINITE): - case BUILT_IN_ISFINITE: - { - /* isfinite(x) -> islessequal(fabs(x),DBL_MAX). */ - tree const isle_fn = built_in_decls[BUILT_IN_ISLESSEQUAL]; - tree const type = TREE_TYPE (arg); - REAL_VALUE_TYPE r; - char buf[128]; - - get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf)); - real_from_string (&r, buf); - result = build_call_expr (isle_fn, 2, - fold_build1_loc (loc, ABS_EXPR, type, arg), - build_real (type, r)); - return expand_expr (result, target, VOIDmode, EXPAND_NORMAL); - } - case BUILT_IN_ISNORMAL: - { - /* isnormal(x) -> isgreaterequal(fabs(x),DBL_MIN) & - islessequal(fabs(x),DBL_MAX). */ - tree const isle_fn = built_in_decls[BUILT_IN_ISLESSEQUAL]; - tree const isge_fn = built_in_decls[BUILT_IN_ISGREATEREQUAL]; - tree const type = TREE_TYPE (arg); - REAL_VALUE_TYPE rmax, rmin; - char buf[128]; - - get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf)); - real_from_string (&rmax, buf); - sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1); - real_from_string (&rmin, buf); - arg = builtin_save_expr (fold_build1_loc (loc, ABS_EXPR, type, arg)); - result = build_call_expr (isle_fn, 2, arg, - build_real (type, rmax)); - result = fold_build2 (BIT_AND_EXPR, integer_type_node, result, - build_call_expr (isge_fn, 2, arg, - build_real (type, rmin))); - return expand_expr (result, target, VOIDmode, EXPAND_NORMAL); - } - default: - break; - } - - target = expand_call (exp, target, target == const0_rtx); - - return target; + return NULL_RTX; } /* Expand a call to the builtin sincos math function. @@ -2551,6 +2490,27 @@ expand_builtin_cexpi (tree exp, rtx target, rtx subtarget) target, VOIDmode, EXPAND_NORMAL); } +/* Conveniently construct a function call expression. FNDECL names the + function to be called, N is the number of arguments, and the "..." + parameters are the argument expressions. Unlike build_call_exr + this doesn't fold the call, hence it will always return a CALL_EXPR. */ + +static tree +build_call_nofold_loc (location_t loc, tree fndecl, int n, ...) +{ + va_list ap; + tree fntype = TREE_TYPE (fndecl); + tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl); + + va_start (ap, n); + fn = build_call_valist (TREE_TYPE (fntype), fn, n, ap); + va_end (ap); + SET_EXPR_LOCATION (fn, loc); + return fn; +} +#define build_call_nofold(...) \ + build_call_nofold_loc (UNKNOWN_LOCATION, __VA_ARGS__) + /* Expand a call to one of the builtin rounding functions gcc defines as an extension (lfloor and lceil). As these are gcc extensions we do not need to worry about setting errno to EDOM. @@ -2667,7 +2627,7 @@ expand_builtin_int_roundingfn (tree exp, rtx target) fallback_fndecl = build_fn_decl (name, fntype); } - exp = build_call_expr (fallback_fndecl, 1, arg); + exp = build_call_nofold (fallback_fndecl, 1, arg); tmp = expand_normal (exp); @@ -3017,7 +2977,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget) && powi_cost (n/2) <= POWI_MAX_MULTS) || n == 1)) { - tree call_expr = build_call_expr (fn, 1, narg0); + tree call_expr = build_call_nofold (fn, 1, narg0); /* Use expand_expr in case the newly built call expression was folded to a non-call. */ op = expand_expr (call_expr, subtarget, mode, EXPAND_NORMAL); @@ -3062,7 +3022,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget) && powi_cost (n/3) <= POWI_MAX_MULTS) || n == 1)) { - tree call_expr = build_call_expr (fn, 1,narg0); + tree call_expr = build_call_nofold (fn, 1,narg0); op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0); if (abs (n) % 3 == 2) op = expand_simple_binop (mode, MULT, op, op, op, @@ -3260,84 +3220,6 @@ expand_builtin_strlen (tree exp, rtx target, } } -/* Expand a call to the strstr builtin. Return NULL_RTX 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_strstr (tree exp, rtx target, enum machine_mode mode) -{ - if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - { - tree type = TREE_TYPE (exp); - tree result = fold_builtin_strstr (EXPR_LOCATION (exp), - CALL_EXPR_ARG (exp, 0), - CALL_EXPR_ARG (exp, 1), type); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); - } - return NULL_RTX; -} - -/* Expand a call to the strchr builtin. Return NULL_RTX 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_strchr (tree exp, rtx target, enum machine_mode mode) -{ - if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - { - tree type = TREE_TYPE (exp); - tree result = fold_builtin_strchr (EXPR_LOCATION (exp), - CALL_EXPR_ARG (exp, 0), - CALL_EXPR_ARG (exp, 1), type); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); - - /* FIXME: Should use strchrM optab so that ports can optimize this. */ - } - return NULL_RTX; -} - -/* Expand a call to the strrchr builtin. Return NULL_RTX 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_strrchr (tree exp, rtx target, enum machine_mode mode) -{ - if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - { - tree type = TREE_TYPE (exp); - tree result = fold_builtin_strrchr (EXPR_LOCATION (exp), - CALL_EXPR_ARG (exp, 0), - CALL_EXPR_ARG (exp, 1), type); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); - } - return NULL_RTX; -} - -/* Expand a call to the strpbrk builtin. Return NULL_RTX 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_strpbrk (tree exp, rtx target, enum machine_mode mode) -{ - if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - { - tree type = TREE_TYPE (exp); - tree result = fold_builtin_strpbrk (EXPR_LOCATION (exp), - CALL_EXPR_ARG (exp, 0), - CALL_EXPR_ARG (exp, 1), type); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); - } - return NULL_RTX; -} - /* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE) bytes from constant string DATA + OFFSET and return it as target constant. */ @@ -3361,10 +3243,8 @@ builtin_memcpy_read_str (void *data, HOST_WIDE_INT offset, mode MODE if that's convenient). */ static rtx -expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode) +expand_builtin_memcpy (tree exp, rtx target) { - tree fndecl = get_callee_fndecl (exp); - if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return NULL_RTX; @@ -3378,25 +3258,10 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode) unsigned int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); rtx dest_mem, src_mem, dest_addr, len_rtx; - tree result = fold_builtin_memory_op (EXPR_LOCATION (exp), - dest, src, len, - TREE_TYPE (TREE_TYPE (fndecl)), - false, /*endp=*/0); HOST_WIDE_INT expected_size = -1; unsigned int expected_align = 0; tree_ann_common_t ann; - if (result) - { - while (TREE_CODE (result) == COMPOUND_EXPR) - { - expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode, - EXPAND_NORMAL); - result = TREE_OPERAND (result, 1); - } - return expand_expr (result, target, mode, EXPAND_NORMAL); - } - /* If DEST is not a pointer type, call the normal function. */ if (dest_align == 0) return NULL_RTX; @@ -3431,7 +3296,7 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode) builtin_memcpy_read_str, CONST_CAST (char *, src_str), dest_align, false, 0); - dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX); + dest_mem = force_operand (XEXP (dest_mem, 0), target); dest_mem = convert_memory_address (ptr_mode, dest_mem); return dest_mem; } @@ -3447,7 +3312,7 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode) if (dest_addr == 0) { - dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX); + dest_addr = force_operand (XEXP (dest_mem, 0), target); dest_addr = convert_memory_address (ptr_mode, dest_addr); } return dest_addr; @@ -3474,7 +3339,6 @@ expand_builtin_mempcpy (tree exp, rtx target, enum machine_mode mode) tree src = CALL_EXPR_ARG (exp, 1); tree len = CALL_EXPR_ARG (exp, 2); return expand_builtin_mempcpy_args (dest, src, len, - TREE_TYPE (exp), target, mode, /*endp=*/ 1); } } @@ -3482,25 +3346,18 @@ expand_builtin_mempcpy (tree exp, rtx target, enum machine_mode mode) /* Helper function to do the actual work for expand_builtin_mempcpy. The arguments to the builtin_mempcpy call DEST, SRC, and LEN are broken out so that this can also be called without constructing an actual CALL_EXPR. - TYPE is the return type of the call. The other arguments and return value - are the same as for expand_builtin_mempcpy. */ + The other arguments and return value are the same as for + expand_builtin_mempcpy. */ static rtx -expand_builtin_mempcpy_args (tree dest, tree src, tree len, tree type, +expand_builtin_mempcpy_args (tree dest, tree src, tree len, rtx target, enum machine_mode mode, int endp) { /* If return value is ignored, transform mempcpy into memcpy. */ if (target == const0_rtx && implicit_built_in_decls[BUILT_IN_MEMCPY]) { tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; - tree result = build_call_expr (fn, 3, dest, src, len); - - while (TREE_CODE (result) == COMPOUND_EXPR) - { - expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode, - EXPAND_NORMAL); - result = TREE_OPERAND (result, 1); - } + tree result = build_call_nofold (fn, 3, dest, src, len); return expand_expr (result, target, mode, EXPAND_NORMAL); } else @@ -3510,19 +3367,6 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len, tree type, unsigned int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); rtx dest_mem, src_mem, len_rtx; - tree result = fold_builtin_memory_op (UNKNOWN_LOCATION, - dest, src, len, type, false, endp); - - if (result) - { - while (TREE_CODE (result) == COMPOUND_EXPR) - { - expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode, - EXPAND_NORMAL); - result = TREE_OPERAND (result, 1); - } - return expand_expr (result, target, mode, EXPAND_NORMAL); - } /* If either SRC or DEST is not a pointer type, don't do this operation in-line. */ @@ -3576,82 +3420,6 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len, tree type, } } -/* Expand expression EXP, which is a call to the memmove builtin. Return - NULL_RTX if we failed; the caller should emit a normal call. */ - -static rtx -expand_builtin_memmove (tree exp, rtx target, enum machine_mode mode, int ignore) -{ - if (!validate_arglist (exp, - POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - return NULL_RTX; - else - { - tree dest = CALL_EXPR_ARG (exp, 0); - tree src = CALL_EXPR_ARG (exp, 1); - tree len = CALL_EXPR_ARG (exp, 2); - return expand_builtin_memmove_args (dest, src, len, TREE_TYPE (exp), - target, mode, ignore); - } -} - -/* Helper function to do the actual work for expand_builtin_memmove. The - arguments to the builtin_memmove call DEST, SRC, and LEN are broken out - so that this can also be called without constructing an actual CALL_EXPR. - TYPE is the return type of the call. The other arguments and return value - are the same as for expand_builtin_memmove. */ - -static rtx -expand_builtin_memmove_args (tree dest, tree src, tree len, - tree type, rtx target, enum machine_mode mode, - int ignore) -{ - tree result = fold_builtin_memory_op (UNKNOWN_LOCATION, - dest, src, len, type, ignore, /*endp=*/3); - - if (result) - { - STRIP_TYPE_NOPS (result); - while (TREE_CODE (result) == COMPOUND_EXPR) - { - expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode, - EXPAND_NORMAL); - result = TREE_OPERAND (result, 1); - } - return expand_expr (result, target, mode, EXPAND_NORMAL); - } - - /* Otherwise, call the normal function. */ - return NULL_RTX; -} - -/* Expand expression EXP, which is a call to the bcopy builtin. Return - NULL_RTX if we failed the caller should emit a normal call. */ - -static rtx -expand_builtin_bcopy (tree exp, int ignore) -{ - tree type = TREE_TYPE (exp); - tree src, dest, size; - location_t loc = EXPR_LOCATION (exp); - - if (!validate_arglist (exp, - POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - return NULL_RTX; - - src = CALL_EXPR_ARG (exp, 0); - dest = CALL_EXPR_ARG (exp, 1); - size = CALL_EXPR_ARG (exp, 2); - - /* Transform bcopy(ptr x, ptr y, int z) to memmove(ptr y, ptr x, size_t z). - This is done this way so that if it isn't expanded inline, we fall - back to calling bcopy instead of memmove. */ - return expand_builtin_memmove_args (dest, src, - fold_convert_loc (loc, sizetype, size), - type, const0_rtx, VOIDmode, - ignore); -} - #ifndef HAVE_movstr # define HAVE_movstr 0 # define CODE_FOR_movstr CODE_FOR_nothing @@ -3725,13 +3493,13 @@ expand_movstr (tree dest, tree src, rtx target, int endp) convenient). */ static rtx -expand_builtin_strcpy (tree fndecl, tree exp, rtx target, enum machine_mode mode) +expand_builtin_strcpy (tree exp, rtx target) { if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) { tree dest = CALL_EXPR_ARG (exp, 0); tree src = CALL_EXPR_ARG (exp, 1); - return expand_builtin_strcpy_args (fndecl, dest, src, target, mode); + return expand_builtin_strcpy_args (dest, src, target); } return NULL_RTX; } @@ -3743,15 +3511,9 @@ expand_builtin_strcpy (tree fndecl, tree exp, rtx target, enum machine_mode mode expand_builtin_strcpy. */ static rtx -expand_builtin_strcpy_args (tree fndecl, tree dest, tree src, - rtx target, enum machine_mode mode) +expand_builtin_strcpy_args (tree dest, tree src, rtx target) { - tree result = fold_builtin_strcpy (UNKNOWN_LOCATION, - fndecl, dest, src, 0); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); return expand_movstr (dest, src, target, /*endp=*/0); - } /* Expand a call EXP to the stpcpy builtin. @@ -3775,15 +3537,7 @@ expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode) if (target == const0_rtx && implicit_built_in_decls[BUILT_IN_STRCPY]) { tree fn = implicit_built_in_decls[BUILT_IN_STRCPY]; - tree result = build_call_expr (fn, 2, dst, src); - - STRIP_NOPS (result); - while (TREE_CODE (result) == COMPOUND_EXPR) - { - expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode, - EXPAND_NORMAL); - result = TREE_OPERAND (result, 1); - } + tree result = build_call_nofold (fn, 2, dst, src); return expand_expr (result, target, mode, EXPAND_NORMAL); } else @@ -3799,7 +3553,7 @@ expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode) return expand_movstr (dst, src, target, /*endp=*/2); lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1)); - ret = expand_builtin_mempcpy_args (dst, src, lenp1, TREE_TYPE (exp), + ret = expand_builtin_mempcpy_args (dst, src, lenp1, target, mode, /*endp=*/2); if (ret) @@ -3811,8 +3565,7 @@ expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode) if (CONST_INT_P (len_rtx)) { - ret = expand_builtin_strcpy_args (get_callee_fndecl (exp), - dst, src, target, mode); + ret = expand_builtin_strcpy_args (dst, src, target); if (ret) { @@ -3859,9 +3612,8 @@ builtin_strncpy_read_str (void *data, HOST_WIDE_INT offset, NULL_RTX if we failed the caller should emit a normal call. */ static rtx -expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode) +expand_builtin_strncpy (tree exp, rtx target) { - tree fndecl = get_callee_fndecl (exp); location_t loc = EXPR_LOCATION (exp); if (validate_arglist (exp, @@ -3871,19 +3623,6 @@ expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode) tree src = CALL_EXPR_ARG (exp, 1); tree len = CALL_EXPR_ARG (exp, 2); tree slen = c_strlen (src, 1); - tree result = fold_builtin_strncpy (EXPR_LOCATION (exp), - fndecl, dest, src, len, slen); - - if (result) - { - while (TREE_CODE (result) == COMPOUND_EXPR) - { - expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode, - EXPAND_NORMAL); - result = TREE_OPERAND (result, 1); - } - return expand_expr (result, target, mode, EXPAND_NORMAL); - } /* We must be passed a constant len and src parameter. */ if (!host_integerp (len, 1) || !slen || !host_integerp (slen, 1)) @@ -3912,7 +3651,7 @@ expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode) store_by_pieces (dest_mem, tree_low_cst (len, 1), builtin_strncpy_read_str, CONST_CAST (char *, p), dest_align, false, 0); - dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX); + dest_mem = force_operand (XEXP (dest_mem, 0), target); dest_mem = convert_memory_address (ptr_mode, dest_mem); return dest_mem; } @@ -4102,13 +3841,13 @@ expand_builtin_memset_args (tree dest, tree val, tree len, fndecl = get_callee_fndecl (orig_exp); fcode = DECL_FUNCTION_CODE (fndecl); if (fcode == BUILT_IN_MEMSET) - fn = build_call_expr (fndecl, 3, dest, val, len); + fn = build_call_nofold (fndecl, 3, dest, val, len); else if (fcode == BUILT_IN_BZERO) - fn = build_call_expr (fndecl, 2, dest, len); + fn = build_call_nofold (fndecl, 2, dest, len); else gcc_unreachable (); - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp); + gcc_assert (TREE_CODE (fn) == CALL_EXPR); + CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp); return expand_call (fn, target, target == const0_rtx); } @@ -4137,49 +3876,20 @@ expand_builtin_bzero (tree exp) const0_rtx, VOIDmode, exp); } -/* Expand a call to the memchr builtin. Return NULL_RTX 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_memchr (tree exp, rtx target, enum machine_mode mode) -{ - if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, - INTEGER_TYPE, VOID_TYPE)) - { - tree type = TREE_TYPE (exp); - tree result = fold_builtin_memchr (EXPR_LOCATION (exp), - CALL_EXPR_ARG (exp, 0), - CALL_EXPR_ARG (exp, 1), - CALL_EXPR_ARG (exp, 2), type); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); - } - return NULL_RTX; -} - /* Expand expression EXP, which is a call to the memcmp built-in function. Return NULL_RTX if we failed and 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_memcmp (tree exp, rtx target, enum machine_mode mode) +expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target, + ATTRIBUTE_UNUSED enum machine_mode mode) { - location_t loc = EXPR_LOCATION (exp); + location_t loc ATTRIBUTE_UNUSED = EXPR_LOCATION (exp); if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return NULL_RTX; - else - { - tree result = fold_builtin_memcmp (loc, - CALL_EXPR_ARG (exp, 0), - CALL_EXPR_ARG (exp, 1), - CALL_EXPR_ARG (exp, 2)); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); - } #if defined HAVE_cmpmemsi || defined HAVE_cmpstrnsi { @@ -4277,20 +3987,10 @@ expand_builtin_memcmp (tree exp, rtx target, enum machine_mode mode) the result in TARGET, if convenient. */ static rtx -expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode) +expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target) { - location_t loc = EXPR_LOCATION (exp); - if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return NULL_RTX; - else - { - tree result = fold_builtin_strcmp (loc, - CALL_EXPR_ARG (exp, 0), - CALL_EXPR_ARG (exp, 1)); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); - } #if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi if (cmpstr_optab[SImode] != CODE_FOR_nothing @@ -4397,6 +4097,7 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode) if (insn) { + enum machine_mode mode; emit_insn (insn); /* Return the value in the proper mode for this function. */ @@ -4415,9 +4116,9 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode) do_libcall: #endif fndecl = get_callee_fndecl (exp); - fn = build_call_expr (fndecl, 2, arg1, arg2); - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); + fn = build_call_nofold (fndecl, 2, arg1, arg2); + gcc_assert (TREE_CODE (fn) == CALL_EXPR); + CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); return expand_call (fn, target, target == const0_rtx); } #endif @@ -4429,22 +4130,14 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode) the result in TARGET, if convenient. */ static rtx -expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) +expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target, + ATTRIBUTE_UNUSED enum machine_mode mode) { - location_t loc = EXPR_LOCATION (exp); + location_t loc ATTRIBUTE_UNUSED = EXPR_LOCATION (exp); if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return NULL_RTX; - else - { - tree result = fold_builtin_strncmp (loc, - CALL_EXPR_ARG (exp, 0), - CALL_EXPR_ARG (exp, 1), - CALL_EXPR_ARG (exp, 2)); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); - } /* If c_strlen can determine an expression for one of the string lengths, and it doesn't have side effects, then emit cmpstrnsi @@ -4545,131 +4238,15 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) /* Expand the library call ourselves using a stabilized argument list to avoid re-evaluating the function's arguments twice. */ fndecl = get_callee_fndecl (exp); - fn = build_call_expr (fndecl, 3, arg1, arg2, len); - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); + fn = build_call_nofold (fndecl, 3, arg1, arg2, len); + gcc_assert (TREE_CODE (fn) == CALL_EXPR); + CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); return expand_call (fn, target, target == const0_rtx); } #endif return NULL_RTX; } -/* Expand expression EXP, which is a call to the strcat builtin. - Return NULL_RTX if we failed the caller should emit a normal call, - otherwise try to get the result in TARGET, if convenient. */ - -static rtx -expand_builtin_strcat (tree fndecl, tree exp, rtx target, enum machine_mode mode) -{ - location_t loc = EXPR_LOCATION (exp); - - if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - return NULL_RTX; - else - { - tree dst = CALL_EXPR_ARG (exp, 0); - tree src = CALL_EXPR_ARG (exp, 1); - const char *p = c_getstr (src); - - /* If the string length is zero, return the dst parameter. */ - if (p && *p == '\0') - return expand_expr (dst, target, mode, EXPAND_NORMAL); - - if (optimize_insn_for_speed_p ()) - { - /* See if we can store by pieces into (dst + strlen(dst)). */ - tree newsrc, newdst, - strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN]; - rtx insns; - - /* Stabilize the argument list. */ - newsrc = builtin_save_expr (src); - dst = builtin_save_expr (dst); - - start_sequence (); - - /* Create strlen (dst). */ - newdst = build_call_expr (strlen_fn, 1, dst); - /* Create (dst p+ strlen (dst)). */ - - newdst = fold_build2_loc (loc, POINTER_PLUS_EXPR, - TREE_TYPE (dst), dst, newdst); - newdst = builtin_save_expr (newdst); - - if (!expand_builtin_strcpy_args (fndecl, newdst, newsrc, target, mode)) - { - end_sequence (); /* Stop sequence. */ - return NULL_RTX; - } - - /* Output the entire sequence. */ - insns = get_insns (); - end_sequence (); - emit_insn (insns); - - return expand_expr (dst, target, mode, EXPAND_NORMAL); - } - - return NULL_RTX; - } -} - -/* Expand expression EXP, which is a call to the strncat builtin. - Return NULL_RTX if we failed the caller should emit a normal call, - otherwise try to get the result in TARGET, if convenient. */ - -static rtx -expand_builtin_strncat (tree exp, rtx target, enum machine_mode mode) -{ - if (validate_arglist (exp, - POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - { - tree result = fold_builtin_strncat (EXPR_LOCATION (exp), - CALL_EXPR_ARG (exp, 0), - CALL_EXPR_ARG (exp, 1), - CALL_EXPR_ARG (exp, 2)); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); - } - return NULL_RTX; -} - -/* Expand expression EXP, which is a call to the strspn builtin. - Return NULL_RTX if we failed the caller should emit a normal call, - otherwise try to get the result in TARGET, if convenient. */ - -static rtx -expand_builtin_strspn (tree exp, rtx target, enum machine_mode mode) -{ - if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - { - tree result = fold_builtin_strspn (EXPR_LOCATION (exp), - CALL_EXPR_ARG (exp, 0), - CALL_EXPR_ARG (exp, 1)); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); - } - return NULL_RTX; -} - -/* Expand expression EXP, which is a call to the strcspn builtin. - Return NULL_RTX if we failed the caller should emit a normal call, - otherwise try to get the result in TARGET, if convenient. */ - -static rtx -expand_builtin_strcspn (tree exp, rtx target, enum machine_mode mode) -{ - if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - { - tree result = fold_builtin_strcspn (EXPR_LOCATION (exp), - CALL_EXPR_ARG (exp, 0), - CALL_EXPR_ARG (exp, 1)); - if (result) - return expand_expr (result, target, mode, EXPAND_NORMAL); - } - return NULL_RTX; -} - /* Expand a call to __builtin_saveregs, generating the result in TARGET, if that's convenient. */ @@ -5297,26 +4874,6 @@ expand_builtin_unop (enum machine_mode target_mode, tree exp, rtx target, return convert_to_mode (target_mode, target, 0); } -/* If the string passed to fputs is a constant and is one character - long, we attempt to transform this call into __builtin_fputc(). */ - -static rtx -expand_builtin_fputs (tree exp, rtx target, bool unlocked) -{ - /* Verify the arguments in the original call. */ - if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - { - tree result = fold_builtin_fputs (EXPR_LOCATION (exp), - CALL_EXPR_ARG (exp, 0), - CALL_EXPR_ARG (exp, 1), - (target == const0_rtx), - unlocked, NULL_TREE); - if (result) - return expand_expr (result, target, VOIDmode, EXPAND_NORMAL); - } - return NULL_RTX; -} - /* Expand a call to __builtin_expect. We just return our argument as the builtin_expect semantic should've been already executed by tree branch prediction pass. */ @@ -5476,7 +5033,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, || ! POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_ARG (exp, 1)))) return NULL_RTX; if (fn_puts) - fn = build_call_expr (fn_puts, 1, CALL_EXPR_ARG (exp, 1)); + fn = build_call_nofold (fn_puts, 1, CALL_EXPR_ARG (exp, 1)); } /* If the format specifier was "%c", call __builtin_putchar(arg). */ else if (strcmp (fmt_str, target_percent_c) == 0) @@ -5485,7 +5042,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, || TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1))) != INTEGER_TYPE) return NULL_RTX; if (fn_putchar) - fn = build_call_expr (fn_putchar, 1, CALL_EXPR_ARG (exp, 1)); + fn = build_call_nofold (fn_putchar, 1, CALL_EXPR_ARG (exp, 1)); } else { @@ -5507,7 +5064,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, function. */ arg = build_int_cst (NULL_TREE, fmt_str[0]); if (fn_putchar) - fn = build_call_expr (fn_putchar, 1, arg); + fn = build_call_nofold (fn_putchar, 1, arg); } else { @@ -5522,7 +5079,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, newstr[len - 1] = 0; arg = build_string_literal (len, newstr); if (fn_puts) - fn = build_call_expr (fn_puts, 1, arg); + fn = build_call_nofold (fn_puts, 1, arg); } else /* We'd like to arrange to call fputs(string,stdout) here, @@ -5533,8 +5090,8 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, if (!fn) return NULL_RTX; - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); + gcc_assert (TREE_CODE (fn) == CALL_EXPR); + CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); return expand_expr (fn, target, mode, EXPAND_NORMAL); } @@ -5588,7 +5145,7 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode, return NULL_RTX; arg = CALL_EXPR_ARG (exp, 2); if (fn_fputs) - fn = build_call_expr (fn_fputs, 2, arg, fp); + fn = build_call_nofold (fn_fputs, 2, arg, fp); } /* If the format specifier was "%c", call __builtin_fputc(arg,fp). */ else if (strcmp (fmt_str, target_percent_c) == 0) @@ -5598,7 +5155,7 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode, return NULL_RTX; arg = CALL_EXPR_ARG (exp, 2); if (fn_fputc) - fn = build_call_expr (fn_fputc, 2, arg, fp); + fn = build_call_nofold (fn_fputc, 2, arg, fp); } else { @@ -5621,13 +5178,13 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode, fprintf(stream,string) with fputs(string,stream). The fputs builtin will take care of special cases like length == 1. */ if (fn_fputs) - fn = build_call_expr (fn_fputs, 2, fmt, fp); + fn = build_call_nofold (fn_fputs, 2, fmt, fp); } if (!fn) return NULL_RTX; - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); + gcc_assert (TREE_CODE (fn) == CALL_EXPR); + CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); return expand_expr (fn, target, mode, EXPAND_NORMAL); } @@ -5669,7 +5226,7 @@ expand_builtin_sprintf (tree exp, rtx target, enum machine_mode mode) if ((nargs > 2) || ! fn) return NULL_RTX; - expand_expr (build_call_expr (fn, 2, dest, fmt), + expand_expr (build_call_nofold (fn, 2, dest, fmt), const0_rtx, VOIDmode, EXPAND_NORMAL); if (target == const0_rtx) return const0_rtx; @@ -5699,7 +5256,7 @@ expand_builtin_sprintf (tree exp, rtx target, enum machine_mode mode) else len = NULL_TREE; - expand_expr (build_call_expr (fn, 2, dest, arg), + expand_expr (build_call_nofold (fn, 2, dest, arg), const0_rtx, VOIDmode, EXPAND_NORMAL); if (target == const0_rtx) @@ -6650,13 +6207,13 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, break; case BUILT_IN_STRCPY: - target = expand_builtin_strcpy (fndecl, exp, target, mode); + target = expand_builtin_strcpy (exp, target); if (target) return target; break; case BUILT_IN_STRNCPY: - target = expand_builtin_strncpy (exp, target, mode); + target = expand_builtin_strncpy (exp, target); if (target) return target; break; @@ -6667,58 +6224,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, return target; break; - case BUILT_IN_STRCAT: - target = expand_builtin_strcat (fndecl, exp, target, mode); - if (target) - return target; - break; - - case BUILT_IN_STRNCAT: - target = expand_builtin_strncat (exp, target, mode); - if (target) - return target; - break; - - case BUILT_IN_STRSPN: - target = expand_builtin_strspn (exp, target, mode); - if (target) - return target; - break; - - case BUILT_IN_STRCSPN: - target = expand_builtin_strcspn (exp, target, mode); - if (target) - return target; - break; - - case BUILT_IN_STRSTR: - target = expand_builtin_strstr (exp, target, mode); - if (target) - return target; - break; - - case BUILT_IN_STRPBRK: - target = expand_builtin_strpbrk (exp, target, mode); - if (target) - return target; - break; - - case BUILT_IN_INDEX: - case BUILT_IN_STRCHR: - target = expand_builtin_strchr (exp, target, mode); - if (target) - return target; - break; - - case BUILT_IN_RINDEX: - case BUILT_IN_STRRCHR: - target = expand_builtin_strrchr (exp, target, mode); - if (target) - return target; - break; - case BUILT_IN_MEMCPY: - target = expand_builtin_memcpy (exp, target, mode); + target = expand_builtin_memcpy (exp, target); if (target) return target; break; @@ -6729,18 +6236,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, return target; break; - case BUILT_IN_MEMMOVE: - target = expand_builtin_memmove (exp, target, mode, ignore); - if (target) - return target; - break; - - case BUILT_IN_BCOPY: - target = expand_builtin_bcopy (exp, ignore); - if (target) - return target; - break; - case BUILT_IN_MEMSET: target = expand_builtin_memset (exp, target, mode); if (target) @@ -6754,7 +6249,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, break; case BUILT_IN_STRCMP: - target = expand_builtin_strcmp (exp, target, mode); + target = expand_builtin_strcmp (exp, target); if (target) return target; break; @@ -6765,12 +6260,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, return target; break; - case BUILT_IN_MEMCHR: - target = expand_builtin_memchr (exp, target, mode); - if (target) - return target; - break; - case BUILT_IN_BCMP: case BUILT_IN_MEMCMP: target = expand_builtin_memcmp (exp, target, mode); @@ -6891,17 +6380,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, return target; break; - case BUILT_IN_FPUTS: - target = expand_builtin_fputs (exp, target, false); - if (target) - return target; - break; - case BUILT_IN_FPUTS_UNLOCKED: - target = expand_builtin_fputs (exp, target, true); - if (target) - return target; - break; - case BUILT_IN_FPRINTF: target = expand_builtin_fprintf (exp, target, mode, false); if (target) @@ -9302,6 +8780,46 @@ fold_builtin_strcpy (location_t loc, tree fndecl, tree dest, tree src, tree len) build_call_expr_loc (loc, fn, 3, dest, src, len)); } +/* Fold function call to builtin stpcpy with arguments DEST and SRC. + Return NULL_TREE if no simplification can be made. */ + +static tree +fold_builtin_stpcpy (location_t loc, tree fndecl, tree dest, tree src) +{ + tree fn, len, lenp1, call, type; + + if (!validate_arg (dest, POINTER_TYPE) + || !validate_arg (src, POINTER_TYPE)) + return NULL_TREE; + + len = c_strlen (src, 1); + if (!len + || TREE_CODE (len) != INTEGER_CST) + return NULL_TREE; + + if (optimize_function_for_size_p (cfun) + /* If length is zero it's small enough. */ + && !integer_zerop (len)) + return NULL_TREE; + + fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; + if (!fn) + return NULL_TREE; + + lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1)); + /* We use dest twice in building our expression. Save it from + multiple expansions. */ + dest = builtin_save_expr (dest); + call = build_call_expr_loc (loc, fn, 3, dest, src, lenp1); + + type = TREE_TYPE (TREE_TYPE (fndecl)); + len = fold_convert_loc (loc, sizetype, len); + dest = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (dest), dest, len); + dest = fold_convert_loc (loc, type, dest); + dest = omit_one_operand_loc (loc, type, dest, call); + return dest; +} + /* Fold function call to builtin strncpy with arguments DEST, SRC, and LEN. If SLEN is not NULL, it represents the length of the source string. Return NULL_TREE if no simplification can be made. */ @@ -10104,6 +9622,96 @@ fold_builtin_modf (location_t loc, tree arg0, tree arg1, tree rettype) return NULL_TREE; } +/* Given a location LOC, an interclass builtin function decl FNDECL + and its single argument ARG, return an folded expression computing + the same, or NULL_TREE if we either couldn't or didn't want to fold + (the latter happen if there's an RTL instruction available). */ + +static tree +fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg) +{ + enum machine_mode mode; + + if (!validate_arg (arg, REAL_TYPE)) + return NULL_TREE; + + if (interclass_mathfn_icode (arg, fndecl) != CODE_FOR_nothing) + return NULL_TREE; + + mode = TYPE_MODE (TREE_TYPE (arg)); + + /* If there is no optab, try generic code. */ + switch (DECL_FUNCTION_CODE (fndecl)) + { + tree result; + + CASE_FLT_FN (BUILT_IN_ISINF): + { + /* isinf(x) -> isgreater(fabs(x),DBL_MAX). */ + tree const isgr_fn = built_in_decls[BUILT_IN_ISGREATER]; + tree const type = TREE_TYPE (arg); + REAL_VALUE_TYPE r; + char buf[128]; + + get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf)); + real_from_string (&r, buf); + result = build_call_expr (isgr_fn, 2, + fold_build1_loc (loc, ABS_EXPR, type, arg), + build_real (type, r)); + return result; + } + CASE_FLT_FN (BUILT_IN_FINITE): + case BUILT_IN_ISFINITE: + { + /* isfinite(x) -> islessequal(fabs(x),DBL_MAX). */ + tree const isle_fn = built_in_decls[BUILT_IN_ISLESSEQUAL]; + tree const type = TREE_TYPE (arg); + REAL_VALUE_TYPE r; + char buf[128]; + + get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf)); + real_from_string (&r, buf); + result = build_call_expr (isle_fn, 2, + fold_build1_loc (loc, ABS_EXPR, type, arg), + build_real (type, r)); + /*result = fold_build2_loc (loc, UNGT_EXPR, + TREE_TYPE (TREE_TYPE (fndecl)), + fold_build1_loc (loc, ABS_EXPR, type, arg), + build_real (type, r)); + result = fold_build1_loc (loc, TRUTH_NOT_EXPR, + TREE_TYPE (TREE_TYPE (fndecl)), + result);*/ + return result; + } + case BUILT_IN_ISNORMAL: + { + /* isnormal(x) -> isgreaterequal(fabs(x),DBL_MIN) & + islessequal(fabs(x),DBL_MAX). */ + tree const isle_fn = built_in_decls[BUILT_IN_ISLESSEQUAL]; + tree const isge_fn = built_in_decls[BUILT_IN_ISGREATEREQUAL]; + tree const type = TREE_TYPE (arg); + REAL_VALUE_TYPE rmax, rmin; + char buf[128]; + + get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf)); + real_from_string (&rmax, buf); + sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1); + real_from_string (&rmin, buf); + arg = builtin_save_expr (fold_build1_loc (loc, ABS_EXPR, type, arg)); + result = build_call_expr (isle_fn, 2, arg, + build_real (type, rmax)); + result = fold_build2 (BIT_AND_EXPR, integer_type_node, result, + build_call_expr (isge_fn, 2, arg, + build_real (type, rmin))); + return result; + } + default: + break; + } + + return NULL_TREE; +} + /* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite. ARG is the argument for the call. */ @@ -10664,13 +10272,26 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore) case BUILT_IN_FINITED64: case BUILT_IN_FINITED128: case BUILT_IN_ISFINITE: - return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISFINITE); + { + tree ret = fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISFINITE); + if (ret) + return ret; + return fold_builtin_interclass_mathfn (loc, fndecl, arg0); + } CASE_FLT_FN (BUILT_IN_ISINF): case BUILT_IN_ISINFD32: case BUILT_IN_ISINFD64: case BUILT_IN_ISINFD128: - return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF); + { + tree ret = fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF); + if (ret) + return ret; + return fold_builtin_interclass_mathfn (loc, fndecl, arg0); + } + + case BUILT_IN_ISNORMAL: + return fold_builtin_interclass_mathfn (loc, fndecl, arg0); case BUILT_IN_ISINF_SIGN: return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF_SIGN); @@ -10812,6 +10433,8 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1, bool ignore) return build_call_expr_loc (loc, fn, 2, arg0, arg1); } + else + return fold_builtin_stpcpy (loc, fndecl, arg0, arg1); break; case BUILT_IN_STRCMP: @@ -11777,6 +11400,42 @@ fold_builtin_strcat (location_t loc ATTRIBUTE_UNUSED, tree dst, tree src) if (p && *p == '\0') return dst; + if (optimize_insn_for_speed_p ()) + { + /* See if we can store by pieces into (dst + strlen(dst)). */ + tree newdst, call; + tree strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN]; + tree strcpy_fn = implicit_built_in_decls[BUILT_IN_STRCPY]; + + if (!strlen_fn || !strcpy_fn) + return NULL_TREE; + + /* If we don't have a movstr we don't want to emit an strcpy + call. We have to do that if the length of the source string + isn't computable (in that case we can use memcpy probably + later expanding to a sequence of mov instructions). If we + have movstr instructions we can emit strcpy calls. */ + if (!HAVE_movstr) + { + tree len = c_strlen (src, 1); + if (! len || TREE_SIDE_EFFECTS (len)) + return NULL_TREE; + } + + /* Stabilize the argument list. */ + dst = builtin_save_expr (dst); + + /* Create strlen (dst). */ + newdst = build_call_expr_loc (loc, strlen_fn, 1, dst); + /* Create (dst p+ strlen (dst)). */ + + newdst = fold_build2_loc (loc, POINTER_PLUS_EXPR, + TREE_TYPE (dst), dst, newdst); + newdst = builtin_save_expr (newdst); + + call = build_call_expr_loc (loc, strcpy_fn, 2, newdst, src); + return build2 (COMPOUND_EXPR, TREE_TYPE (dst), call, dst); + } return NULL_TREE; } } @@ -12297,16 +11956,9 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode, if (! fn) return NULL_RTX; - fn = build_call_expr (fn, 3, dest, src, len); - STRIP_TYPE_NOPS (fn); - while (TREE_CODE (fn) == COMPOUND_EXPR) - { - expand_expr (TREE_OPERAND (fn, 0), const0_rtx, VOIDmode, - EXPAND_NORMAL); - fn = TREE_OPERAND (fn, 1); - } - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); + fn = build_call_nofold (fn, 3, dest, src, len); + gcc_assert (TREE_CODE (fn) == CALL_EXPR); + CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); return expand_expr (fn, target, mode, EXPAND_NORMAL); } else if (fcode == BUILT_IN_MEMSET_CHK) @@ -12352,16 +12004,9 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode, tree fn = built_in_decls[BUILT_IN_MEMCPY_CHK]; if (!fn) return NULL_RTX; - fn = build_call_expr (fn, 4, dest, src, len, size); - STRIP_TYPE_NOPS (fn); - while (TREE_CODE (fn) == COMPOUND_EXPR) - { - expand_expr (TREE_OPERAND (fn, 0), const0_rtx, VOIDmode, - EXPAND_NORMAL); - fn = TREE_OPERAND (fn, 1); - } - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); + fn = build_call_nofold (fn, 4, dest, src, len, size); + gcc_assert (TREE_CODE (fn) == CALL_EXPR); + CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); return expand_expr (fn, target, mode, EXPAND_NORMAL); } } diff --git a/gcc/fold-const.c b/gcc/fold-const.c index b080d85..1539ad2 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -12614,6 +12614,11 @@ fold_binary_loc (location_t loc, return fold_build1_loc (loc, TRUTH_NOT_EXPR, type, fold_convert_loc (loc, type, arg0)); + /* !exp != 0 becomes !exp */ + if (TREE_CODE (arg0) == TRUTH_NOT_EXPR && integer_zerop (arg1) + && code == NE_EXPR) + return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0)); + /* If this is an equality comparison of the address of two non-weak, unaliased symbols neither of which are extern (since we do not have access to attributes for externs), then we know the result. */ diff --git a/gcc/passes.c b/gcc/passes.c index abfa04b..bcc966c 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -626,6 +626,11 @@ init_optimization_passes (void) NEXT_PASS (pass_lower_complex); NEXT_PASS (pass_sra); NEXT_PASS (pass_rename_ssa_copies); + /* The dom pass will also resolve all __builtin_constant_p calls + that are still there to 0. This has to be done after some + propagations have already run, but before some more dead code + is removed, and this place fits nicely. Remember this when + trying to move or duplicate pass_dominator somewhere earlier. */ NEXT_PASS (pass_dominator); /* The only const/copy propagation opportunities left after DOM should be due to degenerate PHI nodes. So rather than @@ -641,7 +646,6 @@ init_optimization_passes (void) NEXT_PASS (pass_object_sizes); NEXT_PASS (pass_ccp); NEXT_PASS (pass_copy_prop); - NEXT_PASS (pass_fold_builtins); NEXT_PASS (pass_cse_sincos); NEXT_PASS (pass_optimize_bswap); NEXT_PASS (pass_split_crit_edges); @@ -709,6 +713,7 @@ init_optimization_passes (void) NEXT_PASS (pass_dse); NEXT_PASS (pass_forwprop); NEXT_PASS (pass_phiopt); + NEXT_PASS (pass_fold_builtins); NEXT_PASS (pass_tail_calls); NEXT_PASS (pass_rename_ssa_copies); NEXT_PASS (pass_uncprop); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e7550e7..a58e42e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2009-09-28 Michael Matz <matz@suse.de> + + * gcc.dg/builtins-44.c: Use __builtin_isinf_sign when checking + for sign of -Inf. + 2009-09-27 Richard Henderson <rth@redhat.com> * gcc.c-torture/compile/pr41469.c: Add -fexceptions. diff --git a/gcc/testsuite/gcc.dg/builtins-44.c b/gcc/testsuite/gcc.dg/builtins-44.c index 9e19d77..1f1eaf0 100644 --- a/gcc/testsuite/gcc.dg/builtins-44.c +++ b/gcc/testsuite/gcc.dg/builtins-44.c @@ -31,17 +31,13 @@ main () if (__builtin_isinfl (pinfl) != 1) link_error (); - if (__builtin_isinf (-pinf) != -1) + if (__builtin_isinf_sign (-pinf) != -1) link_error (); #ifndef __SPU__ - if (__builtin_isinf (-pinff) != -1) - link_error (); - if (__builtin_isinff (-pinff) != -1) + if (__builtin_isinf_sign (-pinff) != -1) link_error (); #endif - if (__builtin_isinf (-pinfl) != -1) - link_error (); - if (__builtin_isinfl (-pinfl) != -1) + if (__builtin_isinf_sign (-pinfl) != -1) link_error (); if (__builtin_isinf (4.0)) diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index feb7499..6e1ea39 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -3873,7 +3873,48 @@ fold_marked_statements (int first, struct pointer_set_t *statements) gimple old_stmt = gsi_stmt (gsi); tree old_decl = is_gimple_call (old_stmt) ? gimple_call_fndecl (old_stmt) : 0; - if (fold_stmt (&gsi)) + if (old_decl && DECL_BUILT_IN (old_decl)) + { + /* Folding builtins can create multiple instructions, + we need to look at all of them. */ + gimple_stmt_iterator i2 = gsi; + gsi_prev (&i2); + if (fold_stmt (&gsi)) + { + gimple new_stmt; + if (gsi_end_p (i2)) + i2 = gsi_start_bb (BASIC_BLOCK (first)); + else + gsi_next (&i2); + while (1) + { + new_stmt = gsi_stmt (i2); + update_stmt (new_stmt); + cgraph_update_edges_for_call_stmt (old_stmt, old_decl, + new_stmt); + + if (new_stmt == gsi_stmt (gsi)) + { + /* It is okay to check only for the very last + of these statements. If it is a throwing + statement nothing will change. If it isn't + this can remove EH edges. If that weren't + correct then because some intermediate stmts + throw, but not the last one. That would mean + we'd have to split the block, which we can't + here and we'd loose anyway. And as builtins + probably never throw, this all + is mood anyway. */ + if (maybe_clean_or_replace_eh_stmt (old_stmt, + new_stmt)) + gimple_purge_dead_eh_edges (BASIC_BLOCK (first)); + break; + } + gsi_next (&i2); + } + } + } + else if (fold_stmt (&gsi)) { /* Re-read the statement from GSI as fold_stmt() may have changed it. */ @@ -3882,7 +3923,8 @@ fold_marked_statements (int first, struct pointer_set_t *statements) if (is_gimple_call (old_stmt) || is_gimple_call (new_stmt)) - cgraph_update_edges_for_call_stmt (old_stmt, old_decl, new_stmt); + cgraph_update_edges_for_call_stmt (old_stmt, old_decl, + new_stmt); if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt)) gimple_purge_dead_eh_edges (BASIC_BLOCK (first)); diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 85159b2..76ea0e4 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -1424,8 +1424,8 @@ evaluate_stmt (gimple stmt) else if (code == GIMPLE_SWITCH) simplified = gimple_switch_index (stmt); else - /* These cannot satisfy is_gimple_min_invariant without folding. */ - gcc_assert (code == GIMPLE_CALL || code == GIMPLE_COND); + /* These cannot satisfy is_gimple_min_invariant without folding. */ + gcc_assert (code == GIMPLE_CALL || code == GIMPLE_COND); } is_constant = simplified && is_gimple_min_invariant (simplified); @@ -2895,6 +2895,7 @@ fold_gimple_cond (gimple stmt) return false; } +static void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree); /* Attempt to fold a call statement referenced by the statement iterator GSI. The statement may be replaced by another statement, e.g., if the call @@ -2915,7 +2916,11 @@ fold_gimple_call (gimple_stmt_iterator *gsi) tree result = ccp_fold_builtin (stmt); if (result) - return update_call_from_tree (gsi, result); + { + if (!update_call_from_tree (gsi, result)) + gimplify_and_update_call_from_tree (gsi, result); + return true; + } } else { diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index 067a911..05a8d92 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -2133,6 +2133,20 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si) { eliminate_redundant_computations (&si); stmt = gsi_stmt (si); + if (gimple_code (stmt) == GIMPLE_CALL) + { + /* Resolve __builtin_constant_p. If it hasn't been + folded to integer_one_node by now, it's fairly + certain that the value simply isn't constant. */ + tree callee = gimple_call_fndecl (stmt); + if (callee + && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (callee) == BUILT_IN_CONSTANT_P) + { + propagate_tree_value_into_stmt (&si, integer_zero_node); + stmt = gsi_stmt (si); + } + } } /* Record any additional equivalences created by this statement. */ diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c index ec0ecf3..1491238 100644 --- a/gcc/tree-ssa-propagate.c +++ b/gcc/tree-ssa-propagate.c @@ -1001,6 +1001,10 @@ substitute_and_fold (prop_value_t *prop_value, ssa_prop_fold_stmt_fn fold_fn) gimple stmt = gsi_stmt (i); gimple old_stmt; enum gimple_code code = gimple_code (stmt); + gimple_stmt_iterator oldi; + + oldi = i; + gsi_prev (&i); /* Ignore ASSERT_EXPRs. They are used by VRP to generate range information for names and they are discarded @@ -1008,10 +1012,7 @@ substitute_and_fold (prop_value_t *prop_value, ssa_prop_fold_stmt_fn fold_fn) if (code == GIMPLE_ASSIGN && TREE_CODE (gimple_assign_rhs1 (stmt)) == ASSERT_EXPR) - { - gsi_prev (&i); - continue; - } + continue; /* No point propagating into a stmt whose result is not used, but instead we might be able to remove a trivially dead stmt. */ @@ -1030,7 +1031,6 @@ substitute_and_fold (prop_value_t *prop_value, ssa_prop_fold_stmt_fn fold_fn) fprintf (dump_file, "\n"); } prop_stats.num_dce++; - gsi_prev (&i); i2 = gsi_for_stmt (stmt); gsi_remove (&i2, true); release_defs (stmt); @@ -1052,7 +1052,7 @@ substitute_and_fold (prop_value_t *prop_value, ssa_prop_fold_stmt_fn fold_fn) specific information. Do this before propagating into the stmt to not disturb pass specific information. */ if (fold_fn - && (*fold_fn)(&i)) + && (*fold_fn)(&oldi)) { did_replace = true; prop_stats.num_stmts_folded++; @@ -1066,12 +1066,12 @@ substitute_and_fold (prop_value_t *prop_value, ssa_prop_fold_stmt_fn fold_fn) /* If we made a replacement, fold the statement. */ if (did_replace) - fold_stmt (&i); + fold_stmt (&oldi); /* Now cleanup. */ if (did_replace) { - stmt = gsi_stmt (i); + stmt = gsi_stmt (oldi); /* If we cleaned up EH information from the statement, remove EH edges. */ @@ -1105,8 +1105,6 @@ substitute_and_fold (prop_value_t *prop_value, ssa_prop_fold_stmt_fn fold_fn) else fprintf (dump_file, "Not folded\n"); } - - gsi_prev (&i); } } |