X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fbuiltins.c;h=65028cf51d96fa08a354e76f24db9ade83209e1c;hp=384173f2bd20914254d519746055ab442f4cbd71;hb=f0ed0e8a52bc2aada0e3f4b71c157aa6442cc43c;hpb=e0eca1faa59e48259a0f4b84c9392a226a0b6802 diff --git a/gcc/builtins.c b/gcc/builtins.c index 384173f2bd2..65028cf51d9 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -45,6 +45,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tm_p.h" #include "target.h" #include "langhooks.h" +#include "basic-block.h" #define CALLED_AS_BUILT_IN(NODE) \ (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10)) @@ -155,8 +156,6 @@ static tree fold_builtin_bitop (tree); static tree fold_builtin_memcpy (tree); static tree fold_builtin_mempcpy (tree); static tree fold_builtin_memmove (tree); -static tree fold_builtin_strcpy (tree); -static tree fold_builtin_strncpy (tree); static tree fold_builtin_strchr (tree, bool); static tree fold_builtin_memcmp (tree); static tree fold_builtin_strcmp (tree); @@ -168,10 +167,9 @@ static tree fold_builtin_toascii (tree); static tree fold_builtin_isdigit (tree); static tree fold_builtin_fabs (tree, tree); static tree fold_builtin_abs (tree, tree); +static tree fold_builtin_unordered_cmp (tree, enum tree_code, enum tree_code); +static tree fold_builtin_1 (tree, bool); -static tree simplify_builtin_memcmp (tree); -static tree simplify_builtin_strcmp (tree); -static tree simplify_builtin_strncmp (tree); static tree simplify_builtin_strpbrk (tree); static tree simplify_builtin_strstr (tree); static tree simplify_builtin_strchr (tree); @@ -523,8 +521,6 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label) buf_addr = force_reg (Pmode, force_operand (buf_addr, NULL_RTX)); - emit_queue (); - /* We store the frame pointer and the address of receiver_label in the buffer and use the rest of it for the stack save area, which is machine-dependent. */ @@ -575,8 +571,7 @@ expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED) emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx)); /* Now put in the code to restore the frame pointer, and argument - pointer, if needed. The code below is from expand_end_bindings - in stmt.c; see detailed documentation there. */ + pointer, if needed. */ #ifdef HAVE_nonlocal_goto if (! HAVE_nonlocal_goto) #endif @@ -643,7 +638,7 @@ expand_builtin_setjmp (tree arglist, rtx target) if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE)) return NULL_RTX; - if (target == 0 || GET_CODE (target) != REG + if (target == 0 || !REG_P (target) || REGNO (target) < FIRST_PSEUDO_REGISTER) target = gen_reg_rtx (TYPE_MODE (integer_type_node)); @@ -765,13 +760,13 @@ expand_builtin_longjmp (rtx buf_addr, rtx value) { if (insn == last) abort (); - if (GET_CODE (insn) == JUMP_INSN) + if (JUMP_P (insn)) { REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx, REG_NOTES (insn)); break; } - else if (GET_CODE (insn) == CALL_INSN) + else if (CALL_P (insn)) break; } } @@ -793,7 +788,9 @@ expand_builtin_nonlocal_goto (tree arglist) t_save_area = TREE_VALUE (arglist); r_label = expand_expr (t_label, NULL_RTX, VOIDmode, 0); + r_label = convert_memory_address (Pmode, r_label); r_save_area = expand_expr (t_save_area, NULL_RTX, VOIDmode, 0); + r_save_area = convert_memory_address (Pmode, r_save_area); r_fp = gen_rtx_MEM (Pmode, r_save_area); r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL), plus_constant (r_save_area, GET_MODE_SIZE (Pmode))); @@ -816,7 +813,7 @@ expand_builtin_nonlocal_goto (tree arglist) emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx))); - + /* Restore frame pointer for containing function. This sets the actual hard register used for the frame pointer to the location of the function's incoming static chain info. @@ -824,25 +821,25 @@ expand_builtin_nonlocal_goto (tree arglist) proper value and reload the argument pointer, if needed. */ emit_move_insn (hard_frame_pointer_rtx, r_fp); emit_stack_restore (SAVE_NONLOCAL, r_sp, NULL_RTX); - + /* USE of hard_frame_pointer_rtx added for consistency; not clear if really needed. */ emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); emit_indirect_jump (r_label); } - + /* Search backwards to the jump insn and mark it as a non-local goto. */ for (insn = get_last_insn (); insn; insn = PREV_INSN (insn)) { - if (GET_CODE (insn) == JUMP_INSN) + if (JUMP_P (insn)) { REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx, REG_NOTES (insn)); break; } - else if (GET_CODE (insn) == CALL_INSN) + else if (CALL_P (insn)) break; } @@ -906,12 +903,12 @@ expand_builtin_prefetch (tree arglist) if (TREE_CHAIN (TREE_CHAIN (arglist))) arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); else - arg2 = build_int_2 (3, 0); + arg2 = build_int_cst (NULL_TREE, 3, 0); } else { arg1 = integer_zero_node; - arg2 = build_int_2 (3, 0); + arg2 = build_int_cst (NULL_TREE, 3, 0); } /* Argument 0 is an address. */ @@ -958,17 +955,16 @@ expand_builtin_prefetch (tree arglist) } emit_insn (gen_prefetch (op0, op1, op2)); } - else #endif - op0 = protect_from_queue (op0, 0); + /* Don't do anything with direct references to volatile memory, but generate code to handle other side effects. */ - if (GET_CODE (op0) != MEM && side_effects_p (op0)) + if (!MEM_P (op0) && side_effects_p (op0)) emit_insn (op0); } /* Get a MEM rtx for expression EXP which is the address of an operand - to be used to be used in a string instruction (cmpstrsi, movstrsi, ..). */ + to be used to be used in a string instruction (cmpstrsi, movmemsi, ..). */ static rtx get_memory_rtx (tree exp) @@ -1237,7 +1233,7 @@ expand_builtin_apply_args (void) chain current, so the code is placed at the start of the function. */ push_topmost_sequence (); - emit_insn_before (seq, NEXT_INSN (get_insns ())); + emit_insn_before (seq, NEXT_INSN (entry_of_function ())); pop_topmost_sequence (); return temp; } @@ -1269,9 +1265,6 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize) incoming_args, 0, OPTAB_LIB_WIDEN); #endif - /* Perform postincrements before actually calling the function. */ - emit_queue (); - /* Push a new argument block and copy the arguments. Do not allow the (potential) memcpy call below to interfere with our stack manipulations. */ @@ -1334,7 +1327,7 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize) rtx value = gen_reg_rtx (Pmode); emit_move_insn (value, adjust_address (arguments, Pmode, size)); emit_move_insn (struct_value, value); - if (GET_CODE (struct_value) == REG) + if (REG_P (struct_value)) use_reg (&call_fusage, struct_value); size += GET_MODE_SIZE (Pmode); } @@ -1775,7 +1768,6 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) op0 = expand_expr (arg, subtarget, VOIDmode, 0); - emit_queue (); start_sequence (); /* Compute into TARGET. @@ -1829,7 +1821,7 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) rtx operand = XEXP (XEXP (XEXP (note, 0), 1), 0); /* Check operand is a register with expected mode. */ if (operand - && GET_CODE (operand) == REG + && REG_P (operand) && GET_MODE (operand) == mode) { /* Replace the REG_EQUAL note with a SQRT rtx. */ @@ -1930,7 +1922,6 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) op0 = expand_expr (arg0, subtarget, VOIDmode, 0); op1 = expand_expr (arg1, 0, VOIDmode, 0); - emit_queue (); start_sequence (); /* Compute into TARGET. @@ -2035,7 +2026,6 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget) op0 = expand_expr (arg, subtarget, VOIDmode, 0); - emit_queue (); start_sequence (); /* Compute into TARGET. @@ -2047,7 +2037,7 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget) case BUILT_IN_SIN: case BUILT_IN_SINF: case BUILT_IN_SINL: - if (!expand_twoval_unop (builtin_optab, op0, 0, target, 0)) + if (!expand_twoval_unop (builtin_optab, op0, 0, target, 0)) abort(); break; case BUILT_IN_COS: @@ -2402,7 +2392,7 @@ expand_builtin_strlen (tree arglist, rtx target, /* Make a place to write the result of the instruction. */ result = target; if (! (result != 0 - && GET_CODE (result) == REG + && REG_P (result) && GET_MODE (result) == insn_mode && REGNO (result) >= FIRST_PSEUDO_REGISTER)) result = gen_reg_rtx (insn_mode); @@ -2500,8 +2490,8 @@ expand_builtin_strstr (tree arglist, rtx target, enum machine_mode mode) /* New argument list transforming strstr(s1, s2) to strchr(s1, s2[0]). */ - arglist = - build_tree_list (NULL_TREE, build_int_2 (p2[0], 0)); + arglist = build_tree_list (NULL_TREE, + build_int_cst (NULL_TREE, p2[0], 0)); arglist = tree_cons (NULL_TREE, s1, arglist); return expand_expr (build_function_call_expr (fn, arglist), target, mode, EXPAND_NORMAL); @@ -2657,8 +2647,8 @@ expand_builtin_strpbrk (tree arglist, rtx target, enum machine_mode mode) /* New argument list transforming strpbrk(s1, s2) to strchr(s1, s2[0]). */ - arglist = - build_tree_list (NULL_TREE, build_int_2 (p2[0], 0)); + arglist = build_tree_list (NULL_TREE, + build_int_cst (NULL_TREE, p2[0], 0)); arglist = tree_cons (NULL_TREE, s1, arglist); return expand_expr (build_function_call_expr (fn, arglist), target, mode, EXPAND_NORMAL); @@ -2974,6 +2964,72 @@ expand_builtin_bcopy (tree arglist) return expand_builtin_memmove (newarglist, const0_rtx, VOIDmode); } +#ifndef HAVE_movstr +# define HAVE_movstr 0 +# define CODE_FOR_movstr CODE_FOR_nothing +#endif + +/* Expand into a movstr instruction, if one is available. Return 0 if + we failed, the caller should emit a normal call, otherwise try to + get the result in TARGET, if convenient. If ENDP is 0 return the + destination pointer, if ENDP is 1 return the end pointer ala + mempcpy, and if ENDP is 2 return the end pointer minus one ala + stpcpy. */ + +static rtx +expand_movstr (tree dest, tree src, rtx target, int endp) +{ + rtx end; + rtx dest_mem; + rtx src_mem; + rtx insn; + const struct insn_data * data; + + if (!HAVE_movstr) + return 0; + + dest_mem = get_memory_rtx (dest); + src_mem = get_memory_rtx (src); + if (!endp) + { + target = force_reg (Pmode, XEXP (dest_mem, 0)); + dest_mem = replace_equiv_address (dest_mem, target); + end = gen_reg_rtx (Pmode); + } + else + { + if (target == 0 || target == const0_rtx) + { + end = gen_reg_rtx (Pmode); + if (target == 0) + target = end; + } + else + end = target; + } + + data = insn_data + CODE_FOR_movstr; + + if (data->operand[0].mode != VOIDmode) + end = gen_lowpart (data->operand[0].mode, end); + + insn = data->genfun (end, dest_mem, src_mem); + + if (insn == 0) + abort (); + + emit_insn (insn); + + /* movstr is supposed to set end to the address of the NUL + terminator. If the caller requested a mempcpy-like return value, + adjust it. */ + if (endp == 1 && target != const0_rtx) + emit_move_insn (target, plus_constant (gen_lowpart (GET_MODE (target), + end), 1)); + + return target; +} + /* Expand expression EXP, which is a call to the strcpy builtin. 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 @@ -2994,12 +3050,14 @@ expand_builtin_strcpy (tree arglist, rtx target, enum machine_mode mode) if (operand_equal_p (src, dst, 0)) return expand_expr (dst, target, mode, EXPAND_NORMAL); - fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; - if (!fn) - return 0; - len = c_strlen (src, 1); if (len == 0 || TREE_SIDE_EFFECTS (len)) + return expand_movstr (TREE_VALUE (arglist), + TREE_VALUE (TREE_CHAIN (arglist)), + target, /*endp=*/0); + + fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; + if (!fn) return 0; len = size_binop (PLUS_EXPR, len, ssize_int (1)); @@ -3018,22 +3076,24 @@ expand_builtin_strcpy (tree arglist, rtx target, enum machine_mode mode) static rtx expand_builtin_stpcpy (tree arglist, rtx target, enum machine_mode mode) { + /* If return value is ignored, transform stpcpy into strcpy. */ + if (target == const0_rtx) + { + tree fn = implicit_built_in_decls[BUILT_IN_STRCPY]; + if (!fn) + return 0; + + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); + } + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; else { - tree dst, src, len; - - /* If return value is ignored, transform stpcpy into strcpy. */ - if (target == const0_rtx) - { - tree fn = implicit_built_in_decls[BUILT_IN_STRCPY]; - if (!fn) - return 0; - - return expand_expr (build_function_call_expr (fn, arglist), - target, mode, EXPAND_NORMAL); - } + tree dst, src, len, lenp1; + tree narglist; + rtx ret; /* Ensure we get an actual string whose length can be evaluated at compile-time, not an expression containing a string. This is @@ -3041,14 +3101,54 @@ expand_builtin_stpcpy (tree arglist, rtx target, enum machine_mode mode) when used to produce the return value. */ src = TREE_VALUE (TREE_CHAIN (arglist)); if (! c_getstr (src) || ! (len = c_strlen (src, 0))) - return 0; + return expand_movstr (TREE_VALUE (arglist), + TREE_VALUE (TREE_CHAIN (arglist)), + target, /*endp=*/2); dst = TREE_VALUE (arglist); - len = fold (size_binop (PLUS_EXPR, len, ssize_int (1))); - arglist = build_tree_list (NULL_TREE, len); - arglist = tree_cons (NULL_TREE, src, arglist); - arglist = tree_cons (NULL_TREE, dst, arglist); - return expand_builtin_mempcpy (arglist, target, mode, /*endp=*/2); + lenp1 = size_binop (PLUS_EXPR, len, ssize_int (1)); + narglist = build_tree_list (NULL_TREE, lenp1); + narglist = tree_cons (NULL_TREE, src, narglist); + narglist = tree_cons (NULL_TREE, dst, narglist); + ret = expand_builtin_mempcpy (narglist, target, mode, /*endp=*/2); + + if (ret) + return ret; + + if (TREE_CODE (len) == INTEGER_CST) + { + rtx len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); + + if (GET_CODE (len_rtx) == CONST_INT) + { + ret = expand_builtin_strcpy (arglist, target, mode); + + if (ret) + { + if (! target) + { + if (mode != VOIDmode) + target = gen_reg_rtx (mode); + else + target = gen_reg_rtx (GET_MODE (ret)); + } + if (GET_MODE (target) != GET_MODE (ret)) + ret = gen_lowpart (GET_MODE (target), ret); + + ret = emit_move_insn (target, + plus_constant (ret, + INTVAL (len_rtx))); + if (! ret) + abort (); + + return target; + } + } + } + + return expand_movstr (TREE_VALUE (arglist), + TREE_VALUE (TREE_CHAIN (arglist)), + target, /*endp=*/2); } } @@ -3413,7 +3513,7 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target, /* Make a place to write the result of the instruction. */ result = target; if (! (result != 0 - && GET_CODE (result) == REG && GET_MODE (result) == insn_mode + && REG_P (result) && GET_MODE (result) == insn_mode && REGNO (result) >= FIRST_PSEUDO_REGISTER)) result = gen_reg_rtx (insn_mode); @@ -3568,7 +3668,7 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode) /* Make a place to write the result of the instruction. */ result = target; if (! (result != 0 - && GET_CODE (result) == REG && GET_MODE (result) == insn_mode + && REG_P (result) && GET_MODE (result) == insn_mode && REGNO (result) >= FIRST_PSEUDO_REGISTER)) result = gen_reg_rtx (insn_mode); @@ -3730,7 +3830,8 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) return 0; /* The actual new length parameter is MIN(len,arg3). */ - len = fold (build2 (MIN_EXPR, TREE_TYPE (len), len, arg3)); + len = fold (build2 (MIN_EXPR, TREE_TYPE (len), len, + fold_convert (TREE_TYPE (len), arg3))); /* If we don't have POINTER_TYPE, call the function. */ if (arg1_align == 0 || arg2_align == 0) @@ -3739,7 +3840,7 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) /* Make a place to write the result of the instruction. */ result = target; if (! (result != 0 - && GET_CODE (result) == REG && GET_MODE (result) == insn_mode + && REG_P (result) && GET_MODE (result) == insn_mode && REGNO (result) >= FIRST_PSEUDO_REGISTER)) result = gen_reg_rtx (insn_mode); @@ -4008,7 +4109,7 @@ expand_builtin_saveregs (void) is inside a start_sequence, make the outer-level insn chain current, so the code is placed at the start of the function. */ push_topmost_sequence (); - emit_insn_after (seq, get_insns ()); + emit_insn_after (seq, entry_of_function ()); pop_topmost_sequence (); return val; @@ -4184,262 +4285,75 @@ expand_builtin_va_start (tree arglist) /* The "standard" implementation of va_arg: read the value from the current (padded) address and increment by the (padded) size. */ -rtx -std_expand_builtin_va_arg (tree valist, tree type) -{ - tree addr_tree, t, type_size = NULL; - tree align, alignm1; - tree rounded_size; - rtx addr; - HOST_WIDE_INT boundary; - - /* Compute the rounded size of the type. */ - align = size_int (PARM_BOUNDARY / BITS_PER_UNIT); - alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1); - boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type); - - /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually - requires greater alignment, we must perform dynamic alignment. */ - - if (boundary > PARM_BOUNDARY) - { - if (!PAD_VARARGS_DOWN) - { - t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, - build2 (PLUS_EXPR, TREE_TYPE (valist), valist, - build_int_2 (boundary / BITS_PER_UNIT - 1, 0))); - TREE_SIDE_EFFECTS (t) = 1; - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - } - t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, - build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist, - build_int_2 (~(boundary / BITS_PER_UNIT - 1), -1))); - TREE_SIDE_EFFECTS (t) = 1; - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - } - if (type == error_mark_node - || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL - || TREE_OVERFLOW (type_size)) - rounded_size = size_zero_node; - else - { - rounded_size = fold (build2 (PLUS_EXPR, sizetype, type_size, alignm1)); - rounded_size = fold (build2 (TRUNC_DIV_EXPR, sizetype, - rounded_size, align)); - rounded_size = fold (build2 (MULT_EXPR, sizetype, - rounded_size, align)); - } - - /* Get AP. */ - addr_tree = valist; - if (PAD_VARARGS_DOWN && ! integer_zerop (rounded_size)) - { - /* Small args are padded downward. */ - addr_tree = fold (build2 (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree, - fold (build3 (COND_EXPR, sizetype, - fold (build2 (GT_EXPR, sizetype, - rounded_size, - align)), - size_zero_node, - fold (build2 (MINUS_EXPR, - sizetype, - rounded_size, - type_size)))))); - } - - addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL); - addr = copy_to_reg (addr); - - /* Compute new value for AP. */ - if (! integer_zerop (rounded_size)) - { - t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, - build2 (PLUS_EXPR, TREE_TYPE (valist), valist, - rounded_size)); - TREE_SIDE_EFFECTS (t) = 1; - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - } - - return addr; -} - -/* Expand __builtin_va_arg, which is not really a builtin function, but - a very special sort of operator. */ - -rtx -expand_builtin_va_arg (tree valist, tree type) +tree +std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p) { - rtx addr, result; - tree promoted_type, want_va_type, have_va_type; - - /* Verify that valist is of the proper type. */ - - want_va_type = va_list_type_node; - 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 - 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. */ - if (TREE_CODE (have_va_type) == ARRAY_TYPE - || TREE_CODE (have_va_type) == POINTER_TYPE) - { - want_va_type = TREE_TYPE (want_va_type); - have_va_type = TREE_TYPE (have_va_type); - } - } - if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type)) - { - error ("first argument to `va_arg' not of type `va_list'"); - addr = const0_rtx; - } - - /* Generate a diagnostic for requesting data of a type that cannot - be passed through `...' due to type promotion at the call site. */ - else if ((promoted_type = lang_hooks.types.type_promotes_to (type)) - != type) - { - const char *name = "", *pname = 0; - static bool gave_help; - - if (TYPE_NAME (type)) - { - if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) - name = IDENTIFIER_POINTER (TYPE_NAME (type)); - else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - && DECL_NAME (TYPE_NAME (type))) - name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); - } - if (TYPE_NAME (promoted_type)) - { - if (TREE_CODE (TYPE_NAME (promoted_type)) == IDENTIFIER_NODE) - pname = IDENTIFIER_POINTER (TYPE_NAME (promoted_type)); - else if (TREE_CODE (TYPE_NAME (promoted_type)) == TYPE_DECL - && DECL_NAME (TYPE_NAME (promoted_type))) - pname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (promoted_type))); - } - - /* Unfortunately, this is merely undefined, rather than a constraint - violation, so we cannot make this an error. If this call is never - executed, the program is still strictly conforming. */ - warning ("`%s' is promoted to `%s' when passed through `...'", - name, pname); - if (! gave_help) - { - gave_help = true; - warning ("(so you should pass `%s' not `%s' to `va_arg')", - pname, name); - } - - /* We can, however, treat "undefined" any way we please. - Call abort to encourage the user to fix the program. */ - inform ("if this code is reached, the program will abort"); - expand_builtin_trap (); - - /* This is dead code, but go ahead and finish so that the - mode of the result comes out right. */ - addr = const0_rtx; - } - else - { - /* Make it easier for the backends by protecting the valist argument - from multiple evaluations. */ - valist = stabilize_va_list (valist, 0); + tree addr, t, type_size, rounded_size, valist_tmp; + unsigned HOST_WIDE_INT align, boundary; + bool indirect; -#ifdef EXPAND_BUILTIN_VA_ARG - addr = EXPAND_BUILTIN_VA_ARG (valist, type); -#else - addr = std_expand_builtin_va_arg (valist, type); +#ifdef ARGS_GROW_DOWNWARD + /* All of the alignment and movement below is for args-grow-up machines. + As of 2004, there are only 3 ARGS_GROW_DOWNWARD targets, and they all + implement their own specialized gimplify_va_arg_expr routines. */ + abort (); #endif - } - - addr = convert_memory_address (Pmode, addr); - - result = gen_rtx_MEM (TYPE_MODE (type), addr); - set_mem_alias_set (result, get_varargs_alias_set ()); - - return result; -} -/* Like std_expand_builtin_va_arg, but gimplify instead of expanding. */ + indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false); + if (indirect) + type = build_pointer_type (type); -tree -std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p) -{ - tree addr, t, type_size = NULL; - tree align, alignm1; - tree rounded_size; - HOST_WIDE_INT boundary; + align = PARM_BOUNDARY / BITS_PER_UNIT; + boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type) / BITS_PER_UNIT; - /* Compute the rounded size of the type. */ - align = size_int (PARM_BOUNDARY / BITS_PER_UNIT); - alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1); - boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type); + /* Hoist the valist value into a temporary for the moment. */ + valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL); /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually requires greater alignment, we must perform dynamic alignment. */ - - if (boundary > PARM_BOUNDARY) - { - if (!PAD_VARARGS_DOWN) - { - t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, - build2 (PLUS_EXPR, TREE_TYPE (valist), valist, - build_int_2 (boundary / BITS_PER_UNIT - 1, 0))); - gimplify_stmt (&t); - append_to_statement_list (t, pre_p); - } - t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, - build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist, - build_int_2 (~(boundary / BITS_PER_UNIT - 1), -1))); - gimplify_stmt (&t); - append_to_statement_list (t, pre_p); - } - if (type == error_mark_node - || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL - || TREE_OVERFLOW (type_size)) - rounded_size = size_zero_node; - else + if (boundary > align) { - rounded_size = fold (build2 (PLUS_EXPR, sizetype, type_size, alignm1)); - rounded_size = fold (build2 (TRUNC_DIV_EXPR, sizetype, - rounded_size, align)); - rounded_size = fold (build2 (MULT_EXPR, sizetype, - rounded_size, align)); + t = fold_convert (TREE_TYPE (valist), size_int (boundary - 1)); + t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp, + build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t)); + gimplify_and_add (t, pre_p); + + t = fold_convert (TREE_TYPE (valist), size_int (-boundary)); + t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp, + build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist_tmp, t)); + gimplify_and_add (t, pre_p); } + /* Compute the rounded size of the type. */ + type_size = size_in_bytes (type); + rounded_size = round_up (type_size, align); + /* Reduce rounded_size so it's sharable with the postqueue. */ gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue); /* Get AP. */ - addr = valist; - if (PAD_VARARGS_DOWN && ! integer_zerop (rounded_size)) + addr = valist_tmp; + if (PAD_VARARGS_DOWN && !integer_zerop (rounded_size)) { /* Small args are padded downward. */ - addr = fold (build2 (PLUS_EXPR, TREE_TYPE (addr), addr, - fold (build3 (COND_EXPR, sizetype, - fold (build2 (GT_EXPR, sizetype, - rounded_size, - align)), - size_zero_node, - fold (build2 (MINUS_EXPR, - sizetype, - rounded_size, - type_size)))))); + t = fold (build2 (GT_EXPR, sizetype, rounded_size, size_int (align))); + t = fold (build3 (COND_EXPR, sizetype, t, size_zero_node, + size_binop (MINUS_EXPR, rounded_size, type_size))); + t = fold_convert (TREE_TYPE (addr), t); + addr = fold (build2 (PLUS_EXPR, TREE_TYPE (addr), addr, t)); } /* Compute new value for AP. */ - if (! integer_zerop (rounded_size)) - { - t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, - build2 (PLUS_EXPR, TREE_TYPE (valist), valist, - rounded_size)); - gimplify_stmt (&t); - append_to_statement_list (t, post_p); - } + t = fold_convert (TREE_TYPE (valist), rounded_size); + t = build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t); + t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t); + gimplify_and_add (t, pre_p); addr = fold_convert (build_pointer_type (type), addr); + + if (indirect) + addr = build_fold_indirect_ref (addr); + return build_fold_indirect_ref (addr); } @@ -4453,7 +4367,8 @@ dummy_object (tree type) return build1 (INDIRECT_REF, type, t); } -/* Like expand_builtin_va_arg, but gimplify instead of expanding. */ +/* Gimplify __builtin_va_arg, aka VA_ARG_EXPR, which is not really a + builtin function, but a very special sort of operator. */ enum gimplify_status gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p) @@ -4464,9 +4379,12 @@ gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p) tree t; /* Verify that valist is of the proper type. */ - want_va_type = va_list_type_node; have_va_type = TREE_TYPE (valist); + + if (have_va_type == error_mark_node) + return GS_ERROR; + if (TREE_CODE (want_va_type) == ARRAY_TYPE) { /* If va_list is an array type, the argument may have decayed @@ -4538,11 +4456,11 @@ gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p) else gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue); - if (!targetm.calls.gimplify_va_arg_expr) + if (!targetm.gimplify_va_arg_expr) /* Once most targets are converted this should abort. */ return GS_ALL_DONE; - *expr_p = targetm.calls.gimplify_va_arg_expr (valist, type, pre_p, post_p); + *expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p); return GS_OK; } } @@ -4652,7 +4570,7 @@ expand_builtin_frame_address (tree fndecl, tree arglist) if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS) return tem; - if (GET_CODE (tem) != REG + if (!REG_P (tem) && ! CONSTANT_P (tem)) tem = copy_to_mode_reg (Pmode, tem); return tem; @@ -4758,10 +4676,11 @@ expand_builtin_fputs (tree arglist, rtx target, bool unlocked) { /* New argument list transforming fputs(string, stream) to fputc(string[0], stream). */ - arglist = - build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist))); - arglist = - tree_cons (NULL_TREE, build_int_2 (p[0], 0), arglist); + arglist = build_tree_list (NULL_TREE, + TREE_VALUE (TREE_CHAIN (arglist))); + arglist = tree_cons (NULL_TREE, + build_int_cst (NULL_TREE, p[0], 0), + arglist); fn = fn_fputc; break; } @@ -4861,9 +4780,9 @@ expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label) ret = get_insns (); drop_through_label = get_last_insn (); - if (drop_through_label && GET_CODE (drop_through_label) == NOTE) + if (drop_through_label && NOTE_P (drop_through_label)) drop_through_label = prev_nonnote_insn (drop_through_label); - if (drop_through_label && GET_CODE (drop_through_label) != CODE_LABEL) + if (drop_through_label && !LABEL_P (drop_through_label)) drop_through_label = NULL_RTX; end_sequence (); @@ -4878,7 +4797,7 @@ expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label) { rtx next = NEXT_INSN (insn); - if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn)) + if (JUMP_P (insn) && any_condjump_p (insn)) { rtx ifelse = SET_SRC (pc_set (insn)); rtx then_dest = XEXP (ifelse, 1); @@ -4901,10 +4820,10 @@ expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label) /* Otherwise check where we drop through. */ else if (else_dest == pc_rtx) { - if (next && GET_CODE (next) == NOTE) + if (next && NOTE_P (next)) next = next_nonnote_insn (next); - if (next && GET_CODE (next) == JUMP_INSN + if (next && JUMP_P (next) && any_uncondjump_p (next)) temp = XEXP (SET_SRC (pc_set (next)), 0); else @@ -4919,10 +4838,10 @@ expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label) } else if (then_dest == pc_rtx) { - if (next && GET_CODE (next) == NOTE) + if (next && NOTE_P (next)) next = next_nonnote_insn (next); - if (next && GET_CODE (next) == JUMP_INSN + if (next && JUMP_P (next) && any_uncondjump_p (next)) temp = XEXP (SET_SRC (pc_set (next)), 0); else @@ -5018,7 +4937,7 @@ build_string_literal (int len, const char *str) t = build_string (len, str); elem = build_type_variant (char_type_node, 1, 0); - index = build_index_type (build_int_2 (len - 1, 0)); + index = build_index_type (build_int_cst (NULL_TREE, len - 1, 0)); type = build_array_type (elem, index); TREE_TYPE (t) = type; TREE_CONSTANT (t) = 1; @@ -5104,7 +5023,7 @@ expand_builtin_printf (tree arglist, rtx target, enum machine_mode mode, /* Given printf("c"), (where c is any one character,) convert "c"[0] to an int and pass that to the replacement function. */ - arg = build_int_2 (fmt_str[0], 0); + arg = build_int_cst (NULL_TREE, fmt_str[0], 0); arglist = build_tree_list (NULL_TREE, arg); fn = fn_putchar; } @@ -5275,8 +5194,7 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode) const0_rtx, VOIDmode, EXPAND_NORMAL); if (target == const0_rtx) return const0_rtx; - exp = build_int_2 (strlen (fmt_str), 0); - exp = fold_convert (integer_type_node, exp); + exp = build_int_cst (NULL_TREE, strlen (fmt_str), 0); return expand_expr (exp, target, mode, EXPAND_NORMAL); } /* If the format is "%s", use strcpy if the result isn't used. */ @@ -5324,7 +5242,7 @@ expand_builtin_profile_func (bool exitp) rtx this, which; this = DECL_RTL (current_function_decl); - if (GET_CODE (this) == MEM) + if (MEM_P (this)) this = XEXP (this, 0); else abort (); @@ -5487,8 +5405,7 @@ expand_builtin_signbit (tree exp, rtx target) bitpos = GET_MODE_BITSIZE (imode) - 1 - bitpos; temp = copy_to_mode_reg (imode, temp); temp = extract_bit_field (temp, 1, bitpos, 1, - NULL_RTX, rmode, rmode, - GET_MODE_SIZE (imode)); + NULL_RTX, rmode, rmode); } else { @@ -5591,9 +5508,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp)); - /* Perform postincrements before expanding builtin functions. */ - emit_queue (); - if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) return targetm.expand_builtin (exp, target, subtarget, mode, ignore); @@ -5656,19 +5570,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, } break; - case BUILT_IN_CONJ: - case BUILT_IN_CONJF: - case BUILT_IN_CONJL: - case BUILT_IN_CREAL: - case BUILT_IN_CREALF: - case BUILT_IN_CREALL: - case BUILT_IN_CIMAG: - case BUILT_IN_CIMAGF: - case BUILT_IN_CIMAGL: - /* expand_tree_builtin changes these into CONJ_EXPR, REALPART_EXPR - and IMAGPART_EXPR. */ - abort (); - case BUILT_IN_EXP: case BUILT_IN_EXPF: case BUILT_IN_EXPL: @@ -5844,7 +5745,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, case BUILT_IN_AGGREGATE_INCOMING_ADDRESS: if (arglist != 0 || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))) - || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM) + || !MEM_P (DECL_RTL (DECL_RESULT (current_function_decl)))) return const0_rtx; else return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0); @@ -5855,11 +5756,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, return target; break; - case BUILT_IN_STACK_ALLOC: - expand_stack_alloc (TREE_VALUE (arglist), - TREE_VALUE (TREE_CHAIN (arglist))); - return const0_rtx; - case BUILT_IN_STACK_SAVE: return expand_stack_save (); @@ -5870,6 +5766,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, case BUILT_IN_FFS: case BUILT_IN_FFSL: case BUILT_IN_FFSLL: + case BUILT_IN_FFSIMAX: target = expand_builtin_unop (target_mode, arglist, target, subtarget, ffs_optab); if (target) @@ -5879,6 +5776,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, case BUILT_IN_CLZ: case BUILT_IN_CLZL: case BUILT_IN_CLZLL: + case BUILT_IN_CLZIMAX: target = expand_builtin_unop (target_mode, arglist, target, subtarget, clz_optab); if (target) @@ -5888,6 +5786,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, case BUILT_IN_CTZ: case BUILT_IN_CTZL: case BUILT_IN_CTZLL: + case BUILT_IN_CTZIMAX: target = expand_builtin_unop (target_mode, arglist, target, subtarget, ctz_optab); if (target) @@ -5897,6 +5796,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, case BUILT_IN_POPCOUNT: case BUILT_IN_POPCOUNTL: case BUILT_IN_POPCOUNTLL: + case BUILT_IN_POPCOUNTIMAX: target = expand_builtin_unop (target_mode, arglist, target, subtarget, popcount_optab); if (target) @@ -5906,6 +5806,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, case BUILT_IN_PARITY: case BUILT_IN_PARITYL: case BUILT_IN_PARITYLL: + case BUILT_IN_PARITYIMAX: target = expand_builtin_unop (target_mode, arglist, target, subtarget, parity_optab); if (target) @@ -6206,9 +6107,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, break; default: /* just do library call, if unknown builtin */ - if (!DECL_ASSEMBLER_NAME_SET_P (fndecl)) - error ("built-in function `%s' not currently supported", - IDENTIFIER_POINTER (DECL_NAME (fndecl))); + break; } /* The switch statement above can drop through to cause the function @@ -6372,9 +6271,10 @@ static tree fold_builtin_classify_type (tree arglist) { if (arglist == 0) - return build_int_2 (no_type_class, 0); + return build_int_cst (NULL_TREE, no_type_class, 0); - return build_int_2 (type_to_class (TREE_TYPE (TREE_VALUE (arglist))), 0); + return build_int_cst (NULL_TREE, + type_to_class (TREE_TYPE (TREE_VALUE (arglist))), 0); } /* Fold a call to __builtin_inf or __builtin_huge_val. */ @@ -6807,7 +6707,7 @@ fold_builtin_lround (tree exp) real_round (&r, TYPE_MODE (ftype), &x); REAL_VALUE_TO_INT (&lo, &hi, r); - result = build_int_2 (lo, hi); + result = build_int_cst (NULL_TREE, lo, hi); if (int_fits_type_p (result, itype)) return fold_convert (itype, result); } @@ -6836,7 +6736,7 @@ fold_builtin_bitop (tree exp) { HOST_WIDE_INT hi, width, result; unsigned HOST_WIDE_INT lo; - tree type, t; + tree type; type = TREE_TYPE (arg); width = TYPE_PRECISION (type); @@ -6916,9 +6816,7 @@ fold_builtin_bitop (tree exp) abort(); } - t = build_int_2 (result, 0); - TREE_TYPE (t) = TREE_TYPE (exp); - return t; + return build_int_cst (TREE_TYPE (exp), result, 0); } return NULL_TREE; @@ -7219,14 +7117,15 @@ fold_builtin_memmove (tree exp) return 0; } -/* Fold function call to builtin strcpy. Return - NULL_TREE if no simplification can be made. */ +/* Fold function call to builtin strcpy. If LEN is not NULL, it represents + the length of the string to be copied. Return NULL_TREE if no + simplification can be made. */ -static tree -fold_builtin_strcpy (tree exp) +tree +fold_builtin_strcpy (tree exp, tree len) { tree arglist = TREE_OPERAND (exp, 1); - tree dest, src; + tree dest, src, fn; if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) @@ -7239,17 +7138,37 @@ fold_builtin_strcpy (tree exp) if (operand_equal_p (src, dest, 0)) return fold_convert (TREE_TYPE (exp), dest); - return 0; + if (optimize_size) + return 0; + + fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; + if (!fn) + return 0; + + if (!len) + { + len = c_strlen (src, 1); + if (! len || TREE_SIDE_EFFECTS (len)) + return 0; + } + + len = size_binop (PLUS_EXPR, len, ssize_int (1)); + arglist = build_tree_list (NULL_TREE, len); + arglist = tree_cons (NULL_TREE, src, arglist); + arglist = tree_cons (NULL_TREE, dest, arglist); + return fold_convert (TREE_TYPE (exp), + build_function_call_expr (fn, arglist)); } -/* Fold function call to builtin strncpy. Return - NULL_TREE if no simplification can be made. */ +/* Fold function call to builtin strncpy. If SLEN is not NULL, it represents + the length of the source string. Return NULL_TREE if no simplification + can be made. */ -static tree -fold_builtin_strncpy (tree exp) +tree +fold_builtin_strncpy (tree exp, tree slen) { tree arglist = TREE_OPERAND (exp, 1); - tree dest, src, len; + tree dest, src, len, fn; if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) @@ -7263,7 +7182,32 @@ fold_builtin_strncpy (tree exp) if (integer_zerop (len)) return omit_one_operand (TREE_TYPE (exp), dest, src); - return 0; + /* We can't compare slen with len as constants below if len is not a + constant. */ + if (len == 0 || TREE_CODE (len) != INTEGER_CST) + return 0; + + if (!slen) + slen = c_strlen (src, 1); + + /* Now, we must be passed a constant src ptr parameter. */ + if (slen == 0 || TREE_CODE (slen) != INTEGER_CST) + return 0; + + slen = size_binop (PLUS_EXPR, slen, ssize_int (1)); + + /* We do not support simplification of this case, though we do + support it when expanding trees into RTL. */ + /* FIXME: generate a call to __builtin_memset. */ + if (tree_int_cst_lt (slen, len)) + return 0; + + /* OK transform into builtin memcpy. */ + fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; + if (!fn) + return 0; + return fold_convert (TREE_TYPE (exp), + build_function_call_expr (fn, arglist)); } /* Fold function call to builtin strchr and strrchr. @@ -7326,10 +7270,10 @@ fold_builtin_strchr (tree exp, bool actually_strrchr) NULL_TREE if no simplification can be made. */ static tree -fold_builtin_memcmp (tree exp) +fold_builtin_memcmp (tree arglist) { - tree arglist = TREE_OPERAND (exp, 1); tree arg1, arg2, len; + const char *p1, *p2; if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) @@ -7341,30 +7285,62 @@ fold_builtin_memcmp (tree exp) /* If the LEN parameter is zero, return zero. */ if (integer_zerop (len)) - { - tree temp = omit_one_operand (TREE_TYPE (exp), integer_zero_node, arg2); - return omit_one_operand (TREE_TYPE (exp), temp, arg1); - } + return omit_two_operands (integer_type_node, integer_zero_node, + arg1, arg2); /* If ARG1 and ARG2 are the same (and not volatile), return zero. */ if (operand_equal_p (arg1, arg2, 0)) - return omit_one_operand (TREE_TYPE (exp), integer_zero_node, len); + return omit_one_operand (integer_type_node, integer_zero_node, len); - return 0; -} + p1 = c_getstr (arg1); + p2 = c_getstr (arg2); + + /* If all arguments are constant, and the value of len is not greater + than the lengths of arg1 and arg2, evaluate at compile-time. */ + if (host_integerp (len, 1) && p1 && p2 + && compare_tree_int (len, strlen (p1) + 1) <= 0 + && compare_tree_int (len, strlen (p2) + 1) <= 0) + { + const int r = memcmp (p1, p2, tree_low_cst (len, 1)); + + if (r > 0) + return integer_one_node; + else if (r < 0) + return integer_minus_one_node; + else + return integer_zero_node; + } + + /* 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_convert (integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + fold_convert (cst_uchar_ptr_node, + arg1))); + tree ind2 = fold_convert (integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + fold_convert (cst_uchar_ptr_node, + arg2))); + return fold (build2 (MINUS_EXPR, integer_type_node, ind1, ind2)); + } + + return 0; +} /* Fold function call to builtin strcmp. Return NULL_TREE if no simplification can be made. */ static tree -fold_builtin_strcmp (tree exp) +fold_builtin_strcmp (tree arglist) { - tree arglist = TREE_OPERAND (exp, 1); tree arg1, arg2; const char *p1, *p2; - if (!validate_arglist (arglist, - POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; arg1 = TREE_VALUE (arglist); @@ -7372,22 +7348,43 @@ fold_builtin_strcmp (tree exp) /* If ARG1 and ARG2 are the same (and not volatile), return zero. */ if (operand_equal_p (arg1, arg2, 0)) - return fold_convert (TREE_TYPE (exp), integer_zero_node); + return integer_zero_node; p1 = c_getstr (arg1); p2 = c_getstr (arg2); if (p1 && p2) { - tree temp; const int i = strcmp (p1, p2); if (i < 0) - temp = integer_minus_one_node; + return integer_minus_one_node; else if (i > 0) - temp = integer_one_node; + return integer_one_node; else - temp = integer_zero_node; - return fold_convert (TREE_TYPE (exp), temp); + return integer_zero_node; + } + + /* If the second arg is "", return *(const unsigned char*)arg1. */ + if (p2 && *p2 == '\0') + { + tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); + tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node); + return fold_convert (integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + fold_convert (cst_uchar_ptr_node, + arg1))); + } + + /* If the first arg is "", return -*(const unsigned char*)arg2. */ + if (p1 && *p1 == '\0') + { + 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 temp = fold_convert (integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + fold_convert (cst_uchar_ptr_node, + arg2))); + return fold (build1 (NEGATE_EXPR, integer_type_node, temp)); } return 0; @@ -7397,9 +7394,8 @@ fold_builtin_strcmp (tree exp) NULL_TREE if no simplification can be made. */ static tree -fold_builtin_strncmp (tree exp) +fold_builtin_strncmp (tree arglist) { - tree arglist = TREE_OPERAND (exp, 1); tree arg1, arg2, len; const char *p1, *p2; @@ -7413,29 +7409,71 @@ fold_builtin_strncmp (tree exp) /* If the LEN parameter is zero, return zero. */ if (integer_zerop (len)) - { - tree temp = omit_one_operand (TREE_TYPE (exp), integer_zero_node, arg2); - return omit_one_operand (TREE_TYPE (exp), temp, arg1); - } + return omit_two_operands (integer_type_node, integer_zero_node, + arg1, arg2); /* If ARG1 and ARG2 are the same (and not volatile), return zero. */ if (operand_equal_p (arg1, arg2, 0)) - return omit_one_operand (TREE_TYPE (exp), integer_zero_node, len); + return omit_one_operand (integer_type_node, integer_zero_node, len); p1 = c_getstr (arg1); p2 = c_getstr (arg2); if (host_integerp (len, 1) && p1 && p2) { - tree temp; const int i = strncmp (p1, p2, tree_low_cst (len, 1)); - if (i < 0) - temp = integer_minus_one_node; - else if (i > 0) - temp = integer_one_node; + if (i > 0) + return integer_one_node; + else if (i < 0) + return integer_minus_one_node; else - temp = integer_zero_node; - return fold_convert (TREE_TYPE (exp), temp); + return integer_zero_node; + } + + /* If the second arg is "", and the length is greater than zero, + return *(const unsigned char*)arg1. */ + if (p2 && *p2 == '\0' + && TREE_CODE (len) == INTEGER_CST + && tree_int_cst_sgn (len) == 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); + return fold_convert (integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + fold_convert (cst_uchar_ptr_node, + arg1))); + } + + /* If the first arg is "", and the length is greater than zero, + return -*(const unsigned char*)arg2. */ + if (p1 && *p1 == '\0' + && TREE_CODE (len) == INTEGER_CST + && tree_int_cst_sgn (len) == 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 temp = fold_convert (integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + fold_convert (cst_uchar_ptr_node, + arg2))); + return fold (build1 (NEGATE_EXPR, integer_type_node, temp)); + } + + /* 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_convert (integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + fold_convert (cst_uchar_ptr_node, + arg1))); + tree ind2 = fold_convert (integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + fold_convert (cst_uchar_ptr_node, + arg2))); + return fold (build2 (MINUS_EXPR, integer_type_node, ind1, ind2)); } return 0; @@ -7532,13 +7570,14 @@ fold_builtin_isascii (tree arglist) { /* Transform isascii(c) -> ((c & ~0x7f) == 0). */ tree arg = TREE_VALUE (arglist); - + + arg = build2 (BIT_AND_EXPR, integer_type_node, arg, + build_int_cst (NULL_TREE, + ~ (unsigned HOST_WIDE_INT) 0x7f, + ~ (HOST_WIDE_INT) 0)); arg = fold (build2 (EQ_EXPR, integer_type_node, - build2 (BIT_AND_EXPR, integer_type_node, arg, - build_int_2 (~ (unsigned HOST_WIDE_INT) 0x7f, - ~ (HOST_WIDE_INT) 0)), - integer_zero_node)); - + arg, integer_zero_node)); + if (in_gimple_form && !TREE_CONSTANT (arg)) return NULL_TREE; else @@ -7557,9 +7596,9 @@ fold_builtin_toascii (tree arglist) { /* Transform toascii(c) -> (c & 0x7f). */ tree arg = TREE_VALUE (arglist); - + return fold (build2 (BIT_AND_EXPR, integer_type_node, arg, - build_int_2 (0x7f, 0))); + build_int_cst (NULL_TREE, 0x7f, 0))); } } @@ -7577,10 +7616,9 @@ fold_builtin_isdigit (tree arglist) tree arg = TREE_VALUE (arglist); arg = fold_convert (unsigned_type_node, arg); arg = build2 (MINUS_EXPR, unsigned_type_node, arg, - fold_convert (unsigned_type_node, - build_int_2 (TARGET_DIGIT0, 0))); + build_int_cst (unsigned_type_node, TARGET_DIGIT0, 0)); arg = build2 (LE_EXPR, integer_type_node, arg, - fold_convert (unsigned_type_node, build_int_2 (9, 0))); + build_int_cst (unsigned_type_node, 9, 0)); arg = fold (arg); if (in_gimple_form && !TREE_CONSTANT (arg)) return NULL_TREE; @@ -7621,11 +7659,183 @@ fold_builtin_abs (tree arglist, tree type) return fold (build1 (ABS_EXPR, type, arg)); } -/* Used by constant folding to eliminate some builtin calls early. EXP is - the CALL_EXPR of a call to a builtin function. */ +/* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite. + EXP is the CALL_EXPR for the call. */ + +static tree +fold_builtin_classify (tree exp, int builtin_index) +{ + tree fndecl = get_callee_fndecl (exp); + tree arglist = TREE_OPERAND (exp, 1); + tree type = TREE_TYPE (TREE_TYPE (fndecl)); + tree arg; + REAL_VALUE_TYPE r; + + if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + { + /* Check that we have exactly one argument. */ + if (arglist == 0) + { + error ("too few arguments to function `%s'", + IDENTIFIER_POINTER (DECL_NAME (fndecl))); + return error_mark_node; + } + else if (TREE_CHAIN (arglist) != 0) + { + error ("too many arguments to function `%s'", + IDENTIFIER_POINTER (DECL_NAME (fndecl))); + return error_mark_node; + } + else + { + error ("non-floating-point argument to function `%s'", + IDENTIFIER_POINTER (DECL_NAME (fndecl))); + return error_mark_node; + } + } + + arg = TREE_VALUE (arglist); + switch (builtin_index) + { + case BUILT_IN_ISINF: + if (!MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg)))) + return omit_one_operand (type, integer_zero_node, arg); + + if (TREE_CODE (arg) == REAL_CST) + { + r = TREE_REAL_CST (arg); + if (real_isinf (&r)) + return real_compare (GT_EXPR, &r, &dconst0) + ? integer_one_node : integer_minus_one_node; + else + return integer_zero_node; + } + + return NULL_TREE; + + case BUILT_IN_FINITE: + if (!MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg))) + && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg)))) + return omit_one_operand (type, integer_zero_node, arg); + + if (TREE_CODE (arg) == REAL_CST) + { + r = TREE_REAL_CST (arg); + return real_isinf (&r) || real_isnan (&r) + ? integer_zero_node : integer_one_node; + } + + return NULL_TREE; + + case BUILT_IN_ISNAN: + if (!MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg)))) + return omit_one_operand (type, integer_zero_node, arg); + + if (TREE_CODE (arg) == REAL_CST) + { + r = TREE_REAL_CST (arg); + return real_isnan (&r) ? integer_one_node : integer_zero_node; + } + + arg = builtin_save_expr (arg); + return fold (build2 (UNORDERED_EXPR, type, arg, arg)); + + default: + abort (); + } +} + +/* Fold a call to an unordered comparison function such as + __builtin_isgreater(). EXP is the CALL_EXPR for the call. + UNORDERED_CODE and ORDERED_CODE are comparison codes that give + the opposite of the desired result. UNORDERED_CODE is used + for modes that can hold NaNs and ORDERED_CODE is used for + the rest. */ + +static tree +fold_builtin_unordered_cmp (tree exp, + enum tree_code unordered_code, + enum tree_code ordered_code) +{ + tree fndecl = get_callee_fndecl (exp); + tree arglist = TREE_OPERAND (exp, 1); + tree type = TREE_TYPE (TREE_TYPE (fndecl)); + enum tree_code code; + tree arg0, arg1; + + if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE)) + { + enum tree_code code0, code1; + tree type0, type1; + tree cmp_type = 0; + + /* Check that we have exactly two arguments. */ + if (arglist == 0 || TREE_CHAIN (arglist) == 0) + { + error ("too few arguments to function `%s'", + IDENTIFIER_POINTER (DECL_NAME (fndecl))); + return error_mark_node; + } + else if (TREE_CHAIN (TREE_CHAIN (arglist)) != 0) + { + error ("too many arguments to function `%s'", + IDENTIFIER_POINTER (DECL_NAME (fndecl))); + return error_mark_node; + } + + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + + type0 = TREE_TYPE (arg0); + type1 = TREE_TYPE (arg1); + + code0 = TREE_CODE (type0); + code1 = TREE_CODE (type1); + + if (code0 == REAL_TYPE && code1 == REAL_TYPE) + /* Choose the wider of two real types. */ + cmp_type = TYPE_PRECISION (type0) >= TYPE_PRECISION (type1) + ? type0 : type1; + else if (code0 == REAL_TYPE && code1 == INTEGER_TYPE) + cmp_type = type0; + else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE) + cmp_type = type1; + else + { + error ("non-floating-point argument to function `%s'", + IDENTIFIER_POINTER (DECL_NAME (fndecl))); + return error_mark_node; + } + + arg0 = fold_convert (cmp_type, arg0); + arg1 = fold_convert (cmp_type, arg1); + } + else + { + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + } + + if (unordered_code == UNORDERED_EXPR) + { + if (!MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg0)))) + return omit_two_operands (type, integer_zero_node, arg0, arg1); + return fold (build2 (UNORDERED_EXPR, type, arg0, arg1)); + } + + code = MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg0))) ? unordered_code + : ordered_code; + return fold (build1 (TRUTH_NOT_EXPR, type, + fold (build2 (code, type, arg0, arg1)))); +} + +/* Used by constant folding to simplify calls to builtin functions. EXP is + the CALL_EXPR of a call to a builtin function. IGNORE is true if the + result of the function call is ignored. This function returns NULL_TREE + if no simplification was possible. */ static tree -fold_builtin_1 (tree exp) +fold_builtin_1 (tree exp, bool ignore) { tree fndecl = get_callee_fndecl (exp); tree arglist = TREE_OPERAND (exp, 1); @@ -7670,6 +7880,29 @@ fold_builtin_1 (tree exp) case BUILT_IN_IMAXABS: return fold_builtin_abs (arglist, type); + case BUILT_IN_CONJ: + case BUILT_IN_CONJF: + case BUILT_IN_CONJL: + if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE)) + return fold (build1 (CONJ_EXPR, type, TREE_VALUE (arglist))); + break; + + case BUILT_IN_CREAL: + case BUILT_IN_CREALF: + case BUILT_IN_CREALL: + if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE)) + return non_lvalue (fold (build1 (REALPART_EXPR, type, + TREE_VALUE (arglist)))); + break; + + case BUILT_IN_CIMAG: + case BUILT_IN_CIMAGF: + case BUILT_IN_CIMAGL: + if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE)) + return non_lvalue (fold (build1 (IMAGPART_EXPR, type, + TREE_VALUE (arglist)))); + break; + case BUILT_IN_CABS: case BUILT_IN_CABSF: case BUILT_IN_CABSL: @@ -7711,7 +7944,7 @@ fold_builtin_1 (tree exp) if (flag_unsafe_math_optimizations && BUILTIN_ROOT_P (fcode)) { tree powfn = mathfn_built_in (type, BUILT_IN_POW); - + if (powfn) { tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1)); @@ -7719,7 +7952,7 @@ fold_builtin_1 (tree exp) /* The inner root was either sqrt or cbrt. */ REAL_VALUE_TYPE dconstroot = BUILTIN_SQRT_P (fcode) ? dconsthalf : dconstthird; - + /* Adjust for the outer root. */ SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1); dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot); @@ -7793,7 +8026,7 @@ fold_builtin_1 (tree exp) build_tree_list (NULL_TREE, tree_root)); return build_function_call_expr (powfn, arglist); } - + } } break; @@ -8109,10 +8342,10 @@ fold_builtin_1 (tree exp) return fold_builtin_memmove (exp); case BUILT_IN_STRCPY: - return fold_builtin_strcpy (exp); + return fold_builtin_strcpy (exp, NULL_TREE); case BUILT_IN_STRNCPY: - return fold_builtin_strncpy (exp); + return fold_builtin_strncpy (exp, NULL_TREE); case BUILT_IN_INDEX: case BUILT_IN_STRCHR: @@ -8123,13 +8356,13 @@ fold_builtin_1 (tree exp) return fold_builtin_strchr (exp, true); case BUILT_IN_MEMCMP: - return fold_builtin_memcmp (exp); + return fold_builtin_memcmp (arglist); case BUILT_IN_STRCMP: - return fold_builtin_strcmp (exp); + return fold_builtin_strcmp (arglist); case BUILT_IN_STRNCMP: - return fold_builtin_strncmp (exp); + return fold_builtin_strncmp (arglist); case BUILT_IN_SIGNBIT: case BUILT_IN_SIGNBITF: @@ -8150,6 +8383,40 @@ fold_builtin_1 (tree exp) case BUILT_IN_COPYSIGNL: return fold_builtin_copysign (arglist, type); + case BUILT_IN_FINITE: + case BUILT_IN_FINITEF: + case BUILT_IN_FINITEL: + return fold_builtin_classify (exp, BUILT_IN_FINITE); + + case BUILT_IN_ISINF: + case BUILT_IN_ISINFF: + case BUILT_IN_ISINFL: + return fold_builtin_classify (exp, BUILT_IN_ISINF); + + case BUILT_IN_ISNAN: + case BUILT_IN_ISNANF: + case BUILT_IN_ISNANL: + return fold_builtin_classify (exp, BUILT_IN_ISNAN); + + case BUILT_IN_ISGREATER: + return fold_builtin_unordered_cmp (exp, UNLE_EXPR, LE_EXPR); + case BUILT_IN_ISGREATEREQUAL: + return fold_builtin_unordered_cmp (exp, UNLT_EXPR, LT_EXPR); + case BUILT_IN_ISLESS: + return fold_builtin_unordered_cmp (exp, UNGE_EXPR, GE_EXPR); + case BUILT_IN_ISLESSEQUAL: + return fold_builtin_unordered_cmp (exp, UNGT_EXPR, GT_EXPR); + case BUILT_IN_ISLESSGREATER: + return fold_builtin_unordered_cmp (exp, UNEQ_EXPR, EQ_EXPR); + case BUILT_IN_ISUNORDERED: + return fold_builtin_unordered_cmp (exp, UNORDERED_EXPR, NOP_EXPR); + + case BUILT_IN_FPUTS: + return fold_builtin_fputs (arglist, ignore, false, NULL_TREE); + + case BUILT_IN_FPUTS_UNLOCKED: + return fold_builtin_fputs (arglist, ignore, true, NULL_TREE); + default: break; } @@ -8158,13 +8425,13 @@ fold_builtin_1 (tree exp) } /* A wrapper function for builtin folding that prevents warnings for - "statement without effect" and the like, caused by removing the + "statement without effect" and the like, caused by removing the call node earlier than the warning is generated. */ tree -fold_builtin (tree exp) +fold_builtin (tree exp, bool ignore) { - exp = fold_builtin_1 (exp); + exp = fold_builtin_1 (exp, ignore); if (exp) { /* ??? Don't clobber shared nodes such as integer_zero_node. */ @@ -8267,7 +8534,7 @@ readonly_data_expr (tree exp) /* Make sure we call decl_readonly_section only for trees it can handle (since it returns true for everything it doesn't understand). */ - if (TREE_CODE (exp) == STRING_CST + if (TREE_CODE (exp) == STRING_CST || TREE_CODE (exp) == CONSTRUCTOR || (TREE_CODE (exp) == VAR_DECL && TREE_STATIC (exp))) return decl_readonly_section (exp, 0); @@ -8298,10 +8565,10 @@ simplify_builtin (tree exp, int ignore) switch (fcode) { case BUILT_IN_FPUTS: - val = simplify_builtin_fputs (arglist, ignore, 0, NULL_TREE); + val = fold_builtin_fputs (arglist, ignore, false, NULL_TREE); break; case BUILT_IN_FPUTS_UNLOCKED: - val = simplify_builtin_fputs (arglist, ignore, 1, NULL_TREE); + val = fold_builtin_fputs (arglist, ignore, true, NULL_TREE); break; case BUILT_IN_STRSTR: val = simplify_builtin_strstr (arglist); @@ -8327,23 +8594,23 @@ simplify_builtin (tree exp, int ignore) val = simplify_builtin_strrchr (arglist); break; case BUILT_IN_STRCPY: - val = simplify_builtin_strcpy (arglist, NULL_TREE); + val = fold_builtin_strcpy (exp, NULL_TREE); break; case BUILT_IN_STRNCPY: - val = simplify_builtin_strncpy (arglist, NULL_TREE); + val = fold_builtin_strncpy (exp, NULL_TREE); break; case BUILT_IN_STRCMP: - val = simplify_builtin_strcmp (arglist); + val = fold_builtin_strcmp (arglist); break; case BUILT_IN_STRNCMP: - val = simplify_builtin_strncmp (arglist); + val = fold_builtin_strncmp (arglist); break; case BUILT_IN_STRPBRK: val = simplify_builtin_strpbrk (arglist); break; case BUILT_IN_BCMP: case BUILT_IN_MEMCMP: - val = simplify_builtin_memcmp (arglist); + val = fold_builtin_memcmp (arglist); break; case BUILT_IN_VA_START: simplify_builtin_va_start (arglist); @@ -8428,7 +8695,8 @@ simplify_builtin_strstr (tree arglist) /* New argument list transforming strstr(s1, s2) to strchr(s1, s2[0]). */ - arglist = build_tree_list (NULL_TREE, build_int_2 (p2[0], 0)); + arglist = build_tree_list (NULL_TREE, + build_int_cst (NULL_TREE, p2[0], 0)); arglist = tree_cons (NULL_TREE, s1, arglist); return build_function_call_expr (fn, arglist); } @@ -8613,344 +8881,13 @@ simplify_builtin_strpbrk (tree arglist) /* New argument list transforming strpbrk(s1, s2) to strchr(s1, s2[0]). */ - arglist = - build_tree_list (NULL_TREE, build_int_2 (p2[0], 0)); + arglist = build_tree_list (NULL_TREE, + build_int_cst (NULL_TREE, p2[0], 0)); arglist = tree_cons (NULL_TREE, s1, arglist); return build_function_call_expr (fn, arglist); } } -/* Simplify a call to the strcpy builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. */ - -tree -simplify_builtin_strcpy (tree arglist, tree len) -{ - tree fn, src, dst; - - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - return 0; - - fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; - if (!fn) - return 0; - - src = TREE_VALUE (TREE_CHAIN (arglist)); - dst = TREE_VALUE (arglist); - - if (!len) - { - len = c_strlen (src, 1); - if (!len || TREE_SIDE_EFFECTS (len)) - return 0; - } - - len = size_binop (PLUS_EXPR, len, ssize_int (1)); - arglist = build_tree_list (NULL_TREE, len); - arglist = tree_cons (NULL_TREE, src, arglist); - arglist = tree_cons (NULL_TREE, dst, arglist); - return build_function_call_expr (fn, arglist); -} - -/* Simplify a call to the strncpy builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. */ - -tree -simplify_builtin_strncpy (tree arglist, tree slen) -{ - if (!validate_arglist (arglist, - POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - return 0; - else - { - 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) - return 0; - - /* If the len parameter is zero, return the dst parameter. */ - if (integer_zerop (len)) - /* Evaluate and ignore the src argument in case it has - side-effects and return the dst parameter. */ - return omit_one_operand (TREE_TYPE (TREE_VALUE (arglist)), - TREE_VALUE (arglist), - TREE_VALUE (TREE_CHAIN (arglist))); - - if (!slen) - slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)), 0); - - /* Now, we must be passed a constant src ptr parameter. */ - if (slen == 0 || TREE_CODE (slen) != INTEGER_CST) - return 0; - - slen = size_binop (PLUS_EXPR, slen, ssize_int (1)); - - /* We do not support simplification of this case, though we do - support it when expanding trees into RTL. */ - /* FIXME: generate a call to __builtin_memset. */ - if (tree_int_cst_lt (slen, len)) - return 0; - - /* OK transform into builtin memcpy. */ - fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; - if (!fn) - return 0; - return build_function_call_expr (fn, arglist); - } -} - -/* Simplify a call to the memcmp builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. */ - -static tree -simplify_builtin_memcmp (tree arglist) -{ - tree arg1, arg2, len; - const char *p1, *p2; - - 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. */ - return build2 (COMPOUND_EXPR, integer_type_node, arg1, - build2 (COMPOUND_EXPR, integer_type_node, - arg2, integer_zero_node)); - } - - p1 = c_getstr (arg1); - p2 = c_getstr (arg2); - - /* If all arguments are constant, and the value of len is not greater - than the lengths of arg1 and arg2, evaluate at compile-time. */ - if (host_integerp (len, 1) && p1 && p2 - && compare_tree_int (len, strlen (p1) + 1) <= 0 - && compare_tree_int (len, strlen (p2) + 1) <= 0) - { - const int r = memcmp (p1, p2, tree_low_cst (len, 1)); - - return (r < 0 - ? integer_minus_one_node - : (r > 0 ? integer_one_node : integer_zero_node)); - } - - /* 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)))); - return fold (build2 (MINUS_EXPR, integer_type_node, ind1, ind2)); - } - - return 0; -} - -/* Simplify a call to the strcmp builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. */ - -static tree -simplify_builtin_strcmp (tree arglist) -{ - tree arg1, arg2; - const char *p1, *p2; - - if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - return 0; - - arg1 = TREE_VALUE (arglist); - arg2 = TREE_VALUE (TREE_CHAIN (arglist)); - - /* If both arguments are equal (and not volatile), return zero. */ - if (operand_equal_p (arg1, arg2, 0)) - return integer_zero_node; - - p1 = c_getstr (arg1); - p2 = c_getstr (arg2); - - if (p1 && p2) - { - const int i = strcmp (p1, p2); - return (i < 0 - ? integer_minus_one_node - : (i > 0 ? integer_one_node : integer_zero_node)); - } - - /* If either arg is "", return an expression corresponding to - (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */ - if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0')) - { - 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)))); - return fold (build2 (MINUS_EXPR, integer_type_node, ind1, ind2)); - } - - return 0; -} - -/* Simplify a call to the strncmp builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. */ - -static tree -simplify_builtin_strncmp (tree arglist) -{ - tree arg1, arg2, arg3; - const char *p1, *p2; - - if (!validate_arglist (arglist, - POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - return 0; - - arg1 = TREE_VALUE (arglist); - arg2 = TREE_VALUE (TREE_CHAIN (arglist)); - arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - - /* If the len parameter is zero, return zero. */ - if (integer_zerop (arg3)) - { - /* Evaluate and ignore arg1 and arg2 in case they have - side-effects. */ - return build2 (COMPOUND_EXPR, integer_type_node, arg1, - build2 (COMPOUND_EXPR, integer_type_node, - arg2, integer_zero_node)); - } - - /* If arg1 and arg2 are equal (and not volatile), return zero. */ - if (operand_equal_p (arg1, arg2, 0)) - /* Evaluate and ignore arg3 in case it has side-effects. */ - return omit_one_operand (integer_type_node, integer_zero_node, arg3); - - p1 = c_getstr (arg1); - p2 = c_getstr (arg2); - - /* If all arguments are constant, evaluate at compile-time. */ - if (host_integerp (arg3, 1) && p1 && p2) - { - const int r = strncmp (p1, p2, tree_low_cst (arg3, 1)); - return (r < 0 - ? integer_minus_one_node - : (r > 0 ? integer_one_node : integer_zero_node)); - } - - /* If len == 1 or (either string parameter is "" and (len >= 1)), - return (*(const u_char*)arg1 - *(const u_char*)arg2). */ - if (host_integerp (arg3, 1) - && (tree_low_cst (arg3, 1) == 1 - || (tree_low_cst (arg3, 1) > 1 - && ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))))) - { - 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)))); - return fold (build2 (MINUS_EXPR, integer_type_node, ind1, ind2)); - } - - return 0; -} - /* Simplify a call to the strcat builtin. Return 0 if no simplification was possible, otherwise return the @@ -9020,8 +8957,7 @@ simplify_builtin_strncat (tree arglist) /* If the requested length is zero, or the src parameter string length is zero, return the dst parameter. */ if (integer_zerop (len) || (p && *p == '\0')) - return build2 (COMPOUND_EXPR, TREE_TYPE (dst), src, - build2 (COMPOUND_EXPR, integer_type_node, len, dst)); + return omit_two_operands (TREE_TYPE (dst), dst, src, len); /* If the requested len is greater than or equal to the string length, call strcat. */ @@ -9079,13 +9015,10 @@ simplify_builtin_strspn (tree arglist) /* If either argument is "", return 0. */ if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0')) - { - /* Evaluate and ignore both arguments in case either one has - side-effects. */ - return build2 (COMPOUND_EXPR, integer_type_node, s1, - build2 (COMPOUND_EXPR, integer_type_node, - s2, integer_zero_node)); - } + /* Evaluate and ignore both arguments in case either one has + side-effects. */ + return omit_two_operands (integer_type_node, integer_zero_node, + s1, s2); return 0; } } @@ -9150,31 +9083,16 @@ simplify_builtin_strcspn (tree arglist) } } -/* Simplify a call to the fputs builtin. - - Return 0 if no simplification was possible, otherwise return the - simplified form of the call as a tree. - - The simplified form may be a constant or other expression which - computes the same value, but in a more efficient manner (including - calls to other builtin functions). - - The call may contain arguments which need to be evaluated, but - which are not useful to determine the result of the call. In - this case we return a chain of COMPOUND_EXPRs. The LHS of each - COMPOUND_EXPR will be an argument which must be evaluated. - COMPOUND_EXPRs are chained through their RHS. The RHS of the last - COMPOUND_EXPR in the chain will contain the tree for the simplified - form of the builtin function call. - - If KNOWN_LEN is non-NULL, it represents the known length of the string. - This is determined by SSA-CCP in cases where the string itself is not - known to be constant but its length is always the same constant. */ +/* Fold a call to the fputs builtin. IGNORE is true if the value returned + by the builtin will be ignored. UNLOCKED is true is true if this + actually a call to fputs_unlocked. If LEN in non-NULL, it represents + the known length of the string. Return NULL_TREE if no simplification + was possible. */ tree -simplify_builtin_fputs (tree arglist, int ignore, int unlocked, tree known_len) +fold_builtin_fputs (tree arglist, bool ignore, bool unlocked, tree len) { - tree len, fn; + tree fn; tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED] : implicit_built_in_decls[BUILT_IN_FPUTC]; tree fn_fwrite = unlocked ? implicit_built_in_decls[BUILT_IN_FWRITE_UNLOCKED] @@ -9189,7 +9107,8 @@ simplify_builtin_fputs (tree arglist, int ignore, int unlocked, tree known_len) if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return 0; - len = (known_len) ? known_len : c_strlen (TREE_VALUE (arglist), 0); + if (! len) + len = c_strlen (TREE_VALUE (arglist), 0); /* Get the length of the string passed to fputs. If the length can't be determined, punt. */ @@ -9211,10 +9130,11 @@ simplify_builtin_fputs (tree arglist, int ignore, int unlocked, tree known_len) { /* New argument list transforming fputs(string, stream) to fputc(string[0], stream). */ - arglist = - build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist))); - arglist = - tree_cons (NULL_TREE, build_int_2 (p[0], 0), arglist); + arglist = build_tree_list (NULL_TREE, + TREE_VALUE (TREE_CHAIN (arglist))); + arglist = tree_cons (NULL_TREE, + build_int_cst (NULL_TREE, p[0], 0), + arglist); fn = fn_fputc; break; } @@ -9230,7 +9150,8 @@ simplify_builtin_fputs (tree arglist, int ignore, int unlocked, tree known_len) 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))); + arglist = build_tree_list (NULL_TREE, + TREE_VALUE (TREE_CHAIN (arglist))); arglist = tree_cons (NULL_TREE, len, arglist); arglist = tree_cons (NULL_TREE, size_one_node, arglist); arglist = tree_cons (NULL_TREE, string_arg, arglist); @@ -9241,6 +9162,8 @@ simplify_builtin_fputs (tree arglist, int ignore, int unlocked, tree known_len) abort (); } + /* These optimizations are only performed when the result is ignored, + hence there's no need to cast the result to integer_type_node. */ return build_function_call_expr (fn, arglist); } @@ -9335,7 +9258,7 @@ simplify_builtin_sprintf (tree arglist, int ignored) arglist = tree_cons (NULL_TREE, dest, arglist); call = build_function_call_expr (fn, arglist); if (!ignored) - retval = build_int_2 (strlen (fmt_str), 0); + retval = build_int_cst (NULL_TREE, strlen (fmt_str), 0); } /* If the format is "%s", use strcpy if the result isn't used. */