From: Eric Botcazou Date: Fri, 13 May 2016 08:49:20 +0000 (+0000) Subject: builtins.c (expand_builtin_memcmp): Do not emit the call here. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ee516de9b3b1aab35e4b21e9058c6176ee30901b;p=gcc.git builtins.c (expand_builtin_memcmp): Do not emit the call here. * builtins.c (expand_builtin_memcmp): Do not emit the call here. (expand_builtin_trap): Emit a regular call. (set_builtin_user_assembler_name): Remove obsolete cases. * dse.c (scan_insn): Adjust. * except.c: Include calls.h. (sjlj_emit_function_enter): If DONT_USE_BUILTIN_SETJMP is defined, emit a regular call to setjmp. * expr.c (emit_block_move_hints): Call emit_block_copy_via_libcall. (block_move_libcall_safe_for_call_parm): Use memcpy builtin. (emit_block_move_via_libcall): Delete. (block_move_fn): Delete. (init_block_move_fn): Likewise. (emit_block_move_libcall_fn): Likewise. (emit_block_op_via_libcall): New function. (set_storage_via_libcall): Tidy up and use memset builtin. (block_clear_fn): Delete. (init_block_clear_fn): Likewise. (clear_storage_libcall_fn): Likewise. (expand_assignment): Call emit_block_move_via_libcall. Do not include gt-expr.h. * expr.h (emit_block_op_via_libcall): Declare. (emit_block_copy_via_libcall): New inline function. (emit_block_move_via_libcall): Likewise. (emit_block_comp_via_libcall): Likewise. (block_clear_fn): Delete. (init_block_move_fn): Likewise. (init_block_clear_fn): Likewise. (emit_block_move_via_libcall): Likewise. (set_storage_via_libcall): Add default parameter value. * libfuncs.h (enum libfunc_index): Remove obsolete values. (abort_libfunc): Delete. (memcpy_libfunc): Likewise. (memmove_libfunc): Likewise. (memcmp_libfunc): Likewise. (memset_libfunc): Likewise. (setbits_libfunc): Likewise. (setjmp_libfunc): Likewise. (longjmp_libfunc): Likewise. (profile_function_entry_libfunc): Likewise. (profile_function_exit_libfunc): Likewise. (gcov_flush_libfunc): Likewise. * optabs-libfuncs.c (build_libfunc_function): Set DECL_ARTIFICIAL and DECL_VISIBILITY on the declaration. (init_optabs): Do not initialize obsolete libfuncs. * optabs.c (prepare_cmp_insn): Call emit_block_comp_via_libcall. * tree-core.h (ECF_RET1): Define. (ECF_TM_PURE): Adjust. (ECF_TM_BUILTIN): Likewise. * tree.c (set_call_expr_flags): Deal with ECF_RET1. (build_common_builtin_nodes): Initialize abort builtin. Add ECF_RET1 on memcpy, memmove and memset builtins. Pass final flags for alloca and alloca_with_align builtins. * config/alpha/alpha.c (alpha_init_libfuncs): Do not initialize obsolete builtins. * config/ia64/ia64.c (ia64_vms_init_libfuncs): Likewise. * config/i386/i386.c (ix86_expand_set_or_movmem): Adjust call to set_storage_via_libcall and call emit_block_copy_via_libcall. From-SVN: r236195 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 65014e939bf..d21e5da7715 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,63 @@ +2016-05-13 Eric Botcazou + + * builtins.c (expand_builtin_memcmp): Do not emit the call here. + (expand_builtin_trap): Emit a regular call. + (set_builtin_user_assembler_name): Remove obsolete cases. + * dse.c (scan_insn): Adjust. + * except.c: Include calls.h. + (sjlj_emit_function_enter): If DONT_USE_BUILTIN_SETJMP is defined, + emit a regular call to setjmp. + * expr.c (emit_block_move_hints): Call emit_block_copy_via_libcall. + (block_move_libcall_safe_for_call_parm): Use memcpy builtin. + (emit_block_move_via_libcall): Delete. + (block_move_fn): Delete. + (init_block_move_fn): Likewise. + (emit_block_move_libcall_fn): Likewise. + (emit_block_op_via_libcall): New function. + (set_storage_via_libcall): Tidy up and use memset builtin. + (block_clear_fn): Delete. + (init_block_clear_fn): Likewise. + (clear_storage_libcall_fn): Likewise. + (expand_assignment): Call emit_block_move_via_libcall. + Do not include gt-expr.h. + * expr.h (emit_block_op_via_libcall): Declare. + (emit_block_copy_via_libcall): New inline function. + (emit_block_move_via_libcall): Likewise. + (emit_block_comp_via_libcall): Likewise. + (block_clear_fn): Delete. + (init_block_move_fn): Likewise. + (init_block_clear_fn): Likewise. + (emit_block_move_via_libcall): Likewise. + (set_storage_via_libcall): Add default parameter value. + * libfuncs.h (enum libfunc_index): Remove obsolete values. + (abort_libfunc): Delete. + (memcpy_libfunc): Likewise. + (memmove_libfunc): Likewise. + (memcmp_libfunc): Likewise. + (memset_libfunc): Likewise. + (setbits_libfunc): Likewise. + (setjmp_libfunc): Likewise. + (longjmp_libfunc): Likewise. + (profile_function_entry_libfunc): Likewise. + (profile_function_exit_libfunc): Likewise. + (gcov_flush_libfunc): Likewise. + * optabs-libfuncs.c (build_libfunc_function): Set DECL_ARTIFICIAL + and DECL_VISIBILITY on the declaration. + (init_optabs): Do not initialize obsolete libfuncs. + * optabs.c (prepare_cmp_insn): Call emit_block_comp_via_libcall. + * tree-core.h (ECF_RET1): Define. + (ECF_TM_PURE): Adjust. + (ECF_TM_BUILTIN): Likewise. + * tree.c (set_call_expr_flags): Deal with ECF_RET1. + (build_common_builtin_nodes): Initialize abort builtin. + Add ECF_RET1 on memcpy, memmove and memset builtins. + Pass final flags for alloca and alloca_with_align builtins. + * config/alpha/alpha.c (alpha_init_libfuncs): Do not initialize + obsolete builtins. + * config/ia64/ia64.c (ia64_vms_init_libfuncs): Likewise. + * config/i386/i386.c (ix86_expand_set_or_movmem): Adjust call to + set_storage_via_libcall and call emit_block_copy_via_libcall. + 2016-05-12 Uros Bizjak * config/i386/i386.md (*call_got_x32): Change operand 0 to diff --git a/gcc/builtins.c b/gcc/builtins.c index 476feb1eb16..931d4a6b7bc 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -3757,20 +3757,7 @@ expand_builtin_memcmp (tree exp, rtx target) return convert_to_mode (mode, result, 0); } - result = target; - if (! (result != 0 - && REG_P (result) && GET_MODE (result) == mode - && REGNO (result) >= FIRST_PSEUDO_REGISTER)) - result = gen_reg_rtx (mode); - - emit_library_call_value (memcmp_libfunc, result, LCT_PURE, - TYPE_MODE (integer_type_node), 3, - XEXP (arg1_rtx, 0), Pmode, - XEXP (arg2_rtx, 0), Pmode, - convert_to_mode (TYPE_MODE (sizetype), arg3_rtx, - TYPE_UNSIGNED (sizetype)), - TYPE_MODE (sizetype)); - return result; + return NULL_RTX; } /* Expand expression EXP, which is a call to the strcmp builtin. Return NULL_RTX @@ -4455,7 +4442,12 @@ expand_builtin_trap (void) add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta)); } else - emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0); + { + tree fn = builtin_decl_implicit (BUILT_IN_ABORT); + tree call_expr = build_call_expr (fn, 0); + expand_call (call_expr, NULL_RTX, false); + } + emit_barrier (); } @@ -9888,42 +9880,19 @@ fold_call_stmt (gcall *stmt, bool ignore) void set_builtin_user_assembler_name (tree decl, const char *asmspec) { - tree builtin; gcc_assert (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL && asmspec != 0); - builtin = builtin_decl_explicit (DECL_FUNCTION_CODE (decl)); + tree builtin = builtin_decl_explicit (DECL_FUNCTION_CODE (decl)); set_user_assembler_name (builtin, asmspec); - switch (DECL_FUNCTION_CODE (decl)) + + if (DECL_FUNCTION_CODE (decl) == BUILT_IN_FFS + && INT_TYPE_SIZE < BITS_PER_WORD) { - case BUILT_IN_MEMCPY: - init_block_move_fn (asmspec); - memcpy_libfunc = set_user_assembler_libfunc ("memcpy", asmspec); - break; - case BUILT_IN_MEMSET: - init_block_clear_fn (asmspec); - memset_libfunc = set_user_assembler_libfunc ("memset", asmspec); - break; - case BUILT_IN_MEMMOVE: - memmove_libfunc = set_user_assembler_libfunc ("memmove", asmspec); - break; - case BUILT_IN_MEMCMP: - memcmp_libfunc = set_user_assembler_libfunc ("memcmp", asmspec); - break; - case BUILT_IN_ABORT: - abort_libfunc = set_user_assembler_libfunc ("abort", asmspec); - break; - case BUILT_IN_FFS: - if (INT_TYPE_SIZE < BITS_PER_WORD) - { - set_user_assembler_libfunc ("ffs", asmspec); - set_optab_libfunc (ffs_optab, mode_for_size (INT_TYPE_SIZE, - MODE_INT, 0), "ffs"); - } - break; - default: - break; + set_user_assembler_libfunc ("ffs", asmspec); + set_optab_libfunc (ffs_optab, mode_for_size (INT_TYPE_SIZE, MODE_INT, 0), + "ffs"); } } diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index e023d3bc278..94fed1029ba 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -9752,8 +9752,6 @@ alpha_init_libfuncs (void) set_optab_libfunc (smod_optab, DImode, "OTS$REM_L"); set_optab_libfunc (umod_optab, SImode, "OTS$REM_UI"); set_optab_libfunc (umod_optab, DImode, "OTS$REM_UL"); - abort_libfunc = init_one_libfunc ("decc$abort"); - memcmp_libfunc = init_one_libfunc ("decc$memcmp"); #ifdef MEM_LIBFUNCS_INIT MEM_LIBFUNCS_INIT; #endif diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 046717bae45..44580149f39 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -26908,7 +26908,7 @@ ix86_expand_set_or_movmem (rtx dst, rtx src, rtx count_exp, rtx val_exp, { if (UINTVAL (count_exp) >= (unsigned HOST_WIDE_INT)dynamic_check) { - emit_block_move_via_libcall (dst, src, count_exp, false); + emit_block_copy_via_libcall (dst, src, count_exp); count_exp = const0_rtx; goto epilogue; } @@ -26923,9 +26923,9 @@ ix86_expand_set_or_movmem (rtx dst, rtx src, rtx count_exp, rtx val_exp, 1, hot_label); predict_jump (REG_BR_PROB_BASE * 90 / 100); if (issetmem) - set_storage_via_libcall (dst, count_exp, val_exp, false); + set_storage_via_libcall (dst, count_exp, val_exp); else - emit_block_move_via_libcall (dst, src, count_exp, false); + emit_block_copy_via_libcall (dst, src, count_exp); emit_jump (jump_around_label); emit_label (hot_label); } diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 3fcc3b5385d..742123f401e 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -10624,8 +10624,6 @@ ia64_vms_init_libfuncs (void) set_optab_libfunc (smod_optab, DImode, "OTS$REM_L"); set_optab_libfunc (umod_optab, SImode, "OTS$REM_UI"); set_optab_libfunc (umod_optab, DImode, "OTS$REM_UL"); - abort_libfunc = init_one_libfunc ("decc$abort"); - memcmp_libfunc = init_one_libfunc ("decc$memcmp"); #ifdef MEM_LIBFUNCS_INIT MEM_LIBFUNCS_INIT; #endif diff --git a/gcc/dse.c b/gcc/dse.c index b03616102b5..68d06bb444f 100644 --- a/gcc/dse.c +++ b/gcc/dse.c @@ -2269,6 +2269,7 @@ scan_insn (bb_info_t bb_info, rtx_insn *insn) if (CALL_P (insn)) { bool const_call; + rtx call, sym; tree memset_call = NULL_TREE; insn_info->cannot_delete = true; @@ -2278,24 +2279,16 @@ scan_insn (bb_info_t bb_info, rtx_insn *insn) been pushed onto the stack. memset and bzero don't read memory either. */ const_call = RTL_CONST_CALL_P (insn); - if (!const_call) - { - rtx call = get_call_rtx_from (insn); - if (call && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF) - { - rtx symbol = XEXP (XEXP (call, 0), 0); - if (SYMBOL_REF_DECL (symbol) - && TREE_CODE (SYMBOL_REF_DECL (symbol)) == FUNCTION_DECL) - { - if ((DECL_BUILT_IN_CLASS (SYMBOL_REF_DECL (symbol)) - == BUILT_IN_NORMAL - && (DECL_FUNCTION_CODE (SYMBOL_REF_DECL (symbol)) - == BUILT_IN_MEMSET)) - || SYMBOL_REF_DECL (symbol) == block_clear_fn) - memset_call = SYMBOL_REF_DECL (symbol); - } - } - } + if (!const_call + && (call = get_call_rtx_from (insn)) + && (sym = XEXP (XEXP (call, 0), 0)) + && GET_CODE (sym) == SYMBOL_REF + && SYMBOL_REF_DECL (sym) + && TREE_CODE (SYMBOL_REF_DECL (sym)) == FUNCTION_DECL + && DECL_BUILT_IN_CLASS (SYMBOL_REF_DECL (sym)) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (SYMBOL_REF_DECL (sym)) == BUILT_IN_MEMSET) + memset_call = SYMBOL_REF_DECL (sym); + if (const_call || memset_call) { insn_info_t i_ptr = active_local_stores; diff --git a/gcc/except.c b/gcc/except.c index cf1df8cc6ec..e494915514f 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -130,6 +130,7 @@ along with GCC; see the file COPYING3. If not see #include "explow.h" #include "stmt.h" #include "expr.h" +#include "calls.h" #include "libfuncs.h" #include "except.h" #include "output.h" @@ -1173,20 +1174,22 @@ sjlj_emit_function_enter (rtx_code_label *dispatch_label) if (dispatch_label) { + rtx addr = plus_constant (Pmode, XEXP (fc, 0), sjlj_fc_jbuf_ofs); + #ifdef DONT_USE_BUILTIN_SETJMP - rtx x; - x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_RETURNS_TWICE, - TYPE_MODE (integer_type_node), 1, - plus_constant (Pmode, XEXP (fc, 0), - sjlj_fc_jbuf_ofs), Pmode); + addr = copy_addr_to_reg (addr); + addr = convert_memory_address (ptr_mode, addr); + tree addr_tree = make_tree (ptr_type_node, addr); + + tree fn = builtin_decl_implicit (BUILT_IN_SETJMP); + tree call_expr = build_call_expr (fn, 1, addr_tree); + rtx x = expand_call (call_expr, NULL_RTX, false); emit_cmp_and_jump_insns (x, const0_rtx, NE, 0, TYPE_MODE (integer_type_node), 0, dispatch_label, REG_BR_PROB_BASE / 100); #else - expand_builtin_setjmp_setup (plus_constant (Pmode, XEXP (fc, 0), - sjlj_fc_jbuf_ofs), - dispatch_label); + expand_builtin_setjmp_setup (addr, dispatch_label); #endif } diff --git a/gcc/expr.c b/gcc/expr.c index 812c5445278..2f5a895015a 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -109,14 +109,12 @@ static bool block_move_libcall_safe_for_call_parm (void); static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT); -static tree emit_block_move_libcall_fn (int); static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned); static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, machine_mode); static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int); static void store_by_pieces_1 (struct store_by_pieces_d *, unsigned int); static void store_by_pieces_2 (insn_gen_fn, machine_mode, struct store_by_pieces_d *); -static tree clear_storage_libcall_fn (int); static rtx_insn *compress_float_constant (rtx, rtx); static rtx get_subtarget (rtx); static void store_constructor_field (rtx, unsigned HOST_WIDE_INT, @@ -1132,7 +1130,7 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, mark_addressable (y_expr); if (x_expr) mark_addressable (x_expr); - retval = emit_block_move_via_libcall (x, y, size, + retval = emit_block_copy_via_libcall (x, y, size, method == BLOCK_OP_TAILCALL); } @@ -1175,7 +1173,7 @@ block_move_libcall_safe_for_call_parm (void) /* If registers go on the stack anyway, any argument is sure to clobber an outgoing argument. */ #if defined (REG_PARM_STACK_SPACE) - fn = emit_block_move_libcall_fn (false); + fn = builtin_decl_implicit (BUILT_IN_MEMCPY); /* Avoid set but not used warning if *REG_PARM_STACK_SPACE doesn't depend on its argument. */ (void) fn; @@ -1191,7 +1189,7 @@ block_move_libcall_safe_for_call_parm (void) cumulative_args_t args_so_far; tree fn, arg; - fn = emit_block_move_libcall_fn (false); + fn = builtin_decl_implicit (BUILT_IN_MEMCPY); INIT_CUMULATIVE_ARGS (args_so_far_v, TREE_TYPE (fn), NULL_RTX, 0, 3); args_so_far = pack_cumulative_args (&args_so_far_v); @@ -1310,106 +1308,6 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align, return false; } -/* A subroutine of emit_block_move. Expand a call to memcpy. - Return the return value from memcpy, 0 otherwise. */ - -rtx -emit_block_move_via_libcall (rtx dst, rtx src, rtx size, bool tailcall) -{ - rtx dst_addr, src_addr; - tree call_expr, fn, src_tree, dst_tree, size_tree; - machine_mode size_mode; - rtx retval; - - /* Emit code to copy the addresses of DST and SRC and SIZE into new - pseudos. We can then place those new pseudos into a VAR_DECL and - use them later. */ - - dst_addr = copy_addr_to_reg (XEXP (dst, 0)); - src_addr = copy_addr_to_reg (XEXP (src, 0)); - - dst_addr = convert_memory_address (ptr_mode, dst_addr); - src_addr = convert_memory_address (ptr_mode, src_addr); - - dst_tree = make_tree (ptr_type_node, dst_addr); - src_tree = make_tree (ptr_type_node, src_addr); - - size_mode = TYPE_MODE (sizetype); - - size = convert_to_mode (size_mode, size, 1); - size = copy_to_mode_reg (size_mode, size); - - /* It is incorrect to use the libcall calling conventions to call - memcpy in this context. This could be a user call to memcpy and - the user may wish to examine the return value from memcpy. For - targets where libcalls and normal calls have different conventions - for returning pointers, we could end up generating incorrect code. */ - - size_tree = make_tree (sizetype, size); - - fn = emit_block_move_libcall_fn (true); - call_expr = build_call_expr (fn, 3, dst_tree, src_tree, size_tree); - CALL_EXPR_TAILCALL (call_expr) = tailcall; - - retval = expand_normal (call_expr); - - return retval; -} - -/* A subroutine of emit_block_move_via_libcall. Create the tree node - for the function we use for block copies. */ - -static GTY(()) tree block_move_fn; - -void -init_block_move_fn (const char *asmspec) -{ - if (!block_move_fn) - { - tree args, fn, attrs, attr_args; - - fn = get_identifier ("memcpy"); - args = build_function_type_list (ptr_type_node, ptr_type_node, - const_ptr_type_node, sizetype, - NULL_TREE); - - fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, fn, args); - DECL_EXTERNAL (fn) = 1; - TREE_PUBLIC (fn) = 1; - DECL_ARTIFICIAL (fn) = 1; - TREE_NOTHROW (fn) = 1; - DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT; - DECL_VISIBILITY_SPECIFIED (fn) = 1; - - attr_args = build_tree_list (NULL_TREE, build_string (1, "1")); - attrs = tree_cons (get_identifier ("fn spec"), attr_args, NULL); - - decl_attributes (&fn, attrs, ATTR_FLAG_BUILT_IN); - - block_move_fn = fn; - } - - if (asmspec) - set_user_assembler_name (block_move_fn, asmspec); -} - -static tree -emit_block_move_libcall_fn (int for_call) -{ - static bool emitted_extern; - - if (!block_move_fn) - init_block_move_fn (NULL); - - if (for_call && !emitted_extern) - { - emitted_extern = true; - make_decl_rtl (block_move_fn); - } - - return block_move_fn; -} - /* A subroutine of emit_block_move. Copy the data via an explicit loop. This is used only when libcalls are forbidden. */ /* ??? It'd be nice to copy in hunks larger than QImode. */ @@ -1464,6 +1362,39 @@ emit_block_move_via_loop (rtx x, rtx y, rtx size, true, top_label, REG_BR_PROB_BASE * 90 / 100); } +/* Expand a call to memcpy or memmove or memcmp, and return the result. + TAILCALL is true if this is a tail call. */ + +rtx +emit_block_op_via_libcall (enum built_in_function fncode, rtx dst, rtx src, + rtx size, bool tailcall) +{ + rtx dst_addr, src_addr; + tree call_expr, dst_tree, src_tree, size_tree; + machine_mode size_mode; + + dst_addr = copy_addr_to_reg (XEXP (dst, 0)); + dst_addr = convert_memory_address (ptr_mode, dst_addr); + dst_tree = make_tree (ptr_type_node, dst_addr); + + src_addr = copy_addr_to_reg (XEXP (src, 0)); + src_addr = convert_memory_address (ptr_mode, src_addr); + src_tree = make_tree (ptr_type_node, src_addr); + + size_mode = TYPE_MODE (sizetype); + size = convert_to_mode (size_mode, size, 1); + size = copy_to_mode_reg (size_mode, size); + size_tree = make_tree (sizetype, size); + + /* It is incorrect to use the libcall calling conventions for calls to + memcpy/memmove/memcmp because they can be provided by the user. */ + tree fn = builtin_decl_implicit (fncode); + call_expr = build_call_expr (fn, 3, dst_tree, src_tree, size_tree); + CALL_EXPR_TAILCALL (call_expr) = tailcall; + + return expand_call (call_expr, NULL_RTX, false); +} + /* Copy all or part of a value X into registers starting at REGNO. The number of registers to be filled is NREGS. */ @@ -2784,85 +2715,26 @@ set_storage_via_libcall (rtx object, rtx size, rtx val, bool tailcall) { tree call_expr, fn, object_tree, size_tree, val_tree; machine_mode size_mode; - rtx retval; - - /* Emit code to copy OBJECT and SIZE into new pseudos. We can then - place those into new pseudos into a VAR_DECL and use them later. */ object = copy_addr_to_reg (XEXP (object, 0)); + object_tree = make_tree (ptr_type_node, object); + + if (!CONST_INT_P (val)) + val = convert_to_mode (TYPE_MODE (integer_type_node), val, 1); + val_tree = make_tree (integer_type_node, val); size_mode = TYPE_MODE (sizetype); size = convert_to_mode (size_mode, size, 1); size = copy_to_mode_reg (size_mode, size); - - /* It is incorrect to use the libcall calling conventions to call - memset in this context. This could be a user call to memset and - the user may wish to examine the return value from memset. For - targets where libcalls and normal calls have different conventions - for returning pointers, we could end up generating incorrect code. */ - - object_tree = make_tree (ptr_type_node, object); - if (!CONST_INT_P (val)) - val = convert_to_mode (TYPE_MODE (integer_type_node), val, 1); size_tree = make_tree (sizetype, size); - val_tree = make_tree (integer_type_node, val); - fn = clear_storage_libcall_fn (true); + /* It is incorrect to use the libcall calling conventions for calls to + memset because it can be provided by the user. */ + fn = builtin_decl_implicit (BUILT_IN_MEMSET); call_expr = build_call_expr (fn, 3, object_tree, val_tree, size_tree); CALL_EXPR_TAILCALL (call_expr) = tailcall; - retval = expand_normal (call_expr); - - return retval; -} - -/* A subroutine of set_storage_via_libcall. Create the tree node - for the function we use for block clears. */ - -tree block_clear_fn; - -void -init_block_clear_fn (const char *asmspec) -{ - if (!block_clear_fn) - { - tree fn, args; - - fn = get_identifier ("memset"); - args = build_function_type_list (ptr_type_node, ptr_type_node, - integer_type_node, sizetype, - NULL_TREE); - - fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, fn, args); - DECL_EXTERNAL (fn) = 1; - TREE_PUBLIC (fn) = 1; - DECL_ARTIFICIAL (fn) = 1; - TREE_NOTHROW (fn) = 1; - DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT; - DECL_VISIBILITY_SPECIFIED (fn) = 1; - - block_clear_fn = fn; - } - - if (asmspec) - set_user_assembler_name (block_clear_fn, asmspec); -} - -static tree -clear_storage_libcall_fn (int for_call) -{ - static bool emitted_extern; - - if (!block_clear_fn) - init_block_clear_fn (NULL); - - if (for_call && !emitted_extern) - { - emitted_extern = true; - make_decl_rtl (block_clear_fn); - } - - return block_clear_fn; + return expand_call (call_expr, NULL_RTX, false); } /* Expand a setmem pattern; return true if successful. */ @@ -5157,12 +5029,7 @@ expand_assignment (tree to, tree from, bool nontemporal) size = expr_size (from); from_rtx = expand_normal (from); - emit_library_call (memmove_libfunc, LCT_NORMAL, - VOIDmode, 3, XEXP (to_rtx, 0), Pmode, - XEXP (from_rtx, 0), Pmode, - convert_to_mode (TYPE_MODE (sizetype), - size, TYPE_UNSIGNED (sizetype)), - TYPE_MODE (sizetype)); + emit_block_move_via_libcall (XEXP (to_rtx, 0), XEXP (from_rtx, 0), size); preserve_temp_slots (to_rtx); pop_temp_slots (); @@ -11653,5 +11520,3 @@ int_expr_size (tree exp) return tree_to_shwi (size); } - -#include "gt-expr.h" diff --git a/gcc/expr.h b/gcc/expr.h index c5b302a383b..fea69a27e3a 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -71,8 +71,29 @@ extern rtx convert_to_mode (machine_mode, rtx, int); /* Convert an rtx to MODE from OLDMODE and return the result. */ extern rtx convert_modes (machine_mode, machine_mode, rtx, int); -/* Emit code to move a block Y to a block X. */ +/* Expand a call to memcpy or memmove or memcmp, and return the result. */ +extern rtx emit_block_op_via_libcall (enum built_in_function, rtx, rtx, rtx, + bool); + +static inline rtx +emit_block_copy_via_libcall (rtx dst, rtx src, rtx size, bool tailcall = false) +{ + return emit_block_op_via_libcall (BUILT_IN_MEMCPY, dst, src, size, tailcall); +} +static inline rtx +emit_block_move_via_libcall (rtx dst, rtx src, rtx size, bool tailcall = false) +{ + return emit_block_op_via_libcall (BUILT_IN_MEMMOVE, dst, src, size, tailcall); +} + +static inline rtx +emit_block_comp_via_libcall (rtx dst, rtx src, rtx size, bool tailcall = false) +{ + return emit_block_op_via_libcall (BUILT_IN_MEMCMP, dst, src, size, tailcall); +} + +/* Emit code to move a block Y to a block X. */ enum block_op_methods { BLOCK_OP_NORMAL, @@ -82,12 +103,7 @@ enum block_op_methods BLOCK_OP_TAILCALL }; -extern GTY(()) tree block_clear_fn; -extern void init_block_move_fn (const char *); -extern void init_block_clear_fn (const char *); - extern rtx emit_block_move (rtx, rtx, rtx, enum block_op_methods); -extern rtx emit_block_move_via_libcall (rtx, rtx, rtx, bool); extern rtx emit_block_move_hints (rtx, rtx, rtx, enum block_op_methods, unsigned int, HOST_WIDE_INT, unsigned HOST_WIDE_INT, @@ -166,7 +182,7 @@ extern rtx clear_storage_hints (rtx, rtx, enum block_op_methods, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT); /* The same, but always output an library call. */ -rtx set_storage_via_libcall (rtx, rtx, rtx, bool); +extern rtx set_storage_via_libcall (rtx, rtx, rtx, bool = false); /* Expand a setmem pattern; return true if successful. */ extern bool set_storage_via_setmem (rtx, rtx, rtx, unsigned int, diff --git a/gcc/libfuncs.h b/gcc/libfuncs.h index 4211a457df5..8250d5b0017 100644 --- a/gcc/libfuncs.h +++ b/gcc/libfuncs.h @@ -24,25 +24,9 @@ along with GCC; see the file COPYING3. If not see /* Enumeration of indexes into libfunc_table. */ enum libfunc_index { - LTI_abort, - LTI_memcpy, - LTI_memmove, - LTI_memcmp, - LTI_memset, - LTI_setbits, - - LTI_setjmp, - LTI_longjmp, LTI_unwind_sjlj_register, LTI_unwind_sjlj_unregister, - - LTI_profile_function_entry, - LTI_profile_function_exit, - LTI_synchronize, - - LTI_gcov_flush, - LTI_MAX }; @@ -89,26 +73,11 @@ extern struct target_libfuncs *this_target_libfuncs; /* Accessor macros for libfunc_table. */ -#define abort_libfunc (libfunc_table[LTI_abort]) -#define memcpy_libfunc (libfunc_table[LTI_memcpy]) -#define memmove_libfunc (libfunc_table[LTI_memmove]) -#define memcmp_libfunc (libfunc_table[LTI_memcmp]) -#define memset_libfunc (libfunc_table[LTI_memset]) -#define setbits_libfunc (libfunc_table[LTI_setbits]) - -#define setjmp_libfunc (libfunc_table[LTI_setjmp]) -#define longjmp_libfunc (libfunc_table[LTI_longjmp]) #define unwind_sjlj_register_libfunc (libfunc_table[LTI_unwind_sjlj_register]) #define unwind_sjlj_unregister_libfunc \ (libfunc_table[LTI_unwind_sjlj_unregister]) - -#define profile_function_entry_libfunc (libfunc_table[LTI_profile_function_entry]) -#define profile_function_exit_libfunc (libfunc_table[LTI_profile_function_exit]) - #define synchronize_libfunc (libfunc_table[LTI_synchronize]) -#define gcov_flush_libfunc (libfunc_table[LTI_gcov_flush]) - /* In explow.c */ extern void set_stack_check_libfunc (const char *); diff --git a/gcc/optabs-libfuncs.c b/gcc/optabs-libfuncs.c index b300096baa0..79a07d68b2c 100644 --- a/gcc/optabs-libfuncs.c +++ b/gcc/optabs-libfuncs.c @@ -731,14 +731,15 @@ static GTY (()) hash_table *libfunc_decls; tree build_libfunc_function (const char *name) { + /* ??? We don't have any type information; pretend this is "int foo ()". */ tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, get_identifier (name), build_function_type (integer_type_node, NULL_TREE)); - /* ??? We don't have any type information except for this is - a function. Pretend this is "int foo ()". */ - DECL_ARTIFICIAL (decl) = 1; DECL_EXTERNAL (decl) = 1; TREE_PUBLIC (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; + DECL_VISIBILITY_SPECIFIED (decl) = 1; gcc_assert (DECL_ASSEMBLER_NAME (decl)); /* Zap the nonsensical SYMBOL_REF_DECL for this. What we're left with @@ -887,32 +888,10 @@ init_optabs (void) set_optab_libfunc (abs_optab, TYPE_MODE (complex_double_type_node), "cabs"); - abort_libfunc = init_one_libfunc ("abort"); - memcpy_libfunc = init_one_libfunc ("memcpy"); - memmove_libfunc = init_one_libfunc ("memmove"); - memcmp_libfunc = init_one_libfunc ("memcmp"); - memset_libfunc = init_one_libfunc ("memset"); - setbits_libfunc = init_one_libfunc ("__setbits"); - -#ifndef DONT_USE_BUILTIN_SETJMP - setjmp_libfunc = init_one_libfunc ("__builtin_setjmp"); - longjmp_libfunc = init_one_libfunc ("__builtin_longjmp"); -#else - setjmp_libfunc = init_one_libfunc ("setjmp"); - longjmp_libfunc = init_one_libfunc ("longjmp"); -#endif unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register"); unwind_sjlj_unregister_libfunc = init_one_libfunc ("_Unwind_SjLj_Unregister"); - /* For function entry/exit instrumentation. */ - profile_function_entry_libfunc - = init_one_libfunc ("__cyg_profile_func_enter"); - profile_function_exit_libfunc - = init_one_libfunc ("__cyg_profile_func_exit"); - - gcov_flush_libfunc = init_one_libfunc ("__gcov_flush"); - /* Allow the target to add more libcalls or rename some, etc. */ targetm.init_libfuncs (); } diff --git a/gcc/optabs.c b/gcc/optabs.c index a6d8822b87e..2bd81db5166 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -3776,8 +3776,6 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size, { machine_mode result_mode; enum insn_code cmp_code; - tree length_type; - rtx libfunc; rtx result; rtx opalign = GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT); @@ -3818,22 +3816,12 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size, if (methods != OPTAB_LIB && methods != OPTAB_LIB_WIDEN) goto fail; - /* Otherwise call a library function, memcmp. */ - libfunc = memcmp_libfunc; - length_type = sizetype; - result_mode = TYPE_MODE (integer_type_node); - cmp_mode = TYPE_MODE (length_type); - size = convert_to_mode (TYPE_MODE (length_type), size, - TYPE_UNSIGNED (length_type)); - - result = emit_library_call_value (libfunc, 0, LCT_PURE, - result_mode, 3, - XEXP (x, 0), Pmode, - XEXP (y, 0), Pmode, - size, cmp_mode); + /* Otherwise call a library function. */ + result = emit_block_comp_via_libcall (XEXP (x, 0), XEXP (y, 0), size); + x = result; y = const0_rtx; - mode = result_mode; + mode = TYPE_MODE (integer_type_node); methods = OPTAB_LIB_WIDEN; unsignedp = false; } diff --git a/gcc/tree-core.h b/gcc/tree-core.h index ea832fa5344..e4c5068241b 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -81,11 +81,14 @@ struct die_struct; /* The function does not lead to calls within current function unit. */ #define ECF_LEAF (1 << 10) +/* Nonzero if this call returns its first argument. */ +#define ECF_RET1 (1 << 11) + /* Nonzero if this call does not affect transactions. */ -#define ECF_TM_PURE (1 << 11) +#define ECF_TM_PURE (1 << 12) /* Nonzero if this call is into the transaction runtime library. */ -#define ECF_TM_BUILTIN (1 << 12) +#define ECF_TM_BUILTIN (1 << 13) /* Call argument flags. */ /* Nonzero if the argument is not dereferenced recursively, thus only diff --git a/gcc/tree.c b/gcc/tree.c index b63f64cd96d..4e0000416d8 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -10451,6 +10451,11 @@ set_call_expr_flags (tree decl, int flags) if (flags & ECF_LEAF) DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("leaf"), NULL, DECL_ATTRIBUTES (decl)); + if (flags & ECF_RET1) + DECL_ATTRIBUTES (decl) + = tree_cons (get_identifier ("fn spec"), + build_tree_list (NULL_TREE, build_string (1, "1")), + DECL_ATTRIBUTES (decl)); if ((flags & ECF_TM_PURE) && flag_tm) apply_tm_attr (decl, get_identifier ("transaction_pure")); /* Looping const or pure is implied by noreturn. @@ -10486,13 +10491,20 @@ build_common_builtin_nodes (void) tree tmp, ftype; int ecf_flags; - if (!builtin_decl_explicit_p (BUILT_IN_UNREACHABLE)) + if (!builtin_decl_explicit_p (BUILT_IN_UNREACHABLE) + || !builtin_decl_explicit_p (BUILT_IN_ABORT)) { ftype = build_function_type (void_type_node, void_list_node); - local_define_builtin ("__builtin_unreachable", ftype, BUILT_IN_UNREACHABLE, - "__builtin_unreachable", - ECF_NOTHROW | ECF_LEAF | ECF_NORETURN - | ECF_CONST); + if (!builtin_decl_explicit_p (BUILT_IN_UNREACHABLE)) + local_define_builtin ("__builtin_unreachable", ftype, + BUILT_IN_UNREACHABLE, + "__builtin_unreachable", + ECF_NOTHROW | ECF_LEAF | ECF_NORETURN + | ECF_CONST); + if (!builtin_decl_explicit_p (BUILT_IN_ABORT)) + local_define_builtin ("__builtin_abort", ftype, BUILT_IN_ABORT, + "abort", + ECF_LEAF | ECF_NORETURN | ECF_CONST); } if (!builtin_decl_explicit_p (BUILT_IN_MEMCPY) @@ -10504,10 +10516,10 @@ build_common_builtin_nodes (void) if (!builtin_decl_explicit_p (BUILT_IN_MEMCPY)) local_define_builtin ("__builtin_memcpy", ftype, BUILT_IN_MEMCPY, - "memcpy", ECF_NOTHROW | ECF_LEAF); + "memcpy", ECF_NOTHROW | ECF_LEAF | ECF_RET1); if (!builtin_decl_explicit_p (BUILT_IN_MEMMOVE)) local_define_builtin ("__builtin_memmove", ftype, BUILT_IN_MEMMOVE, - "memmove", ECF_NOTHROW | ECF_LEAF); + "memmove", ECF_NOTHROW | ECF_LEAF | ECF_RET1); } if (!builtin_decl_explicit_p (BUILT_IN_MEMCMP)) @@ -10525,15 +10537,19 @@ build_common_builtin_nodes (void) ptr_type_node, integer_type_node, size_type_node, NULL_TREE); local_define_builtin ("__builtin_memset", ftype, BUILT_IN_MEMSET, - "memset", ECF_NOTHROW | ECF_LEAF); + "memset", ECF_NOTHROW | ECF_LEAF | ECF_RET1); } + /* If we're checking the stack, `alloca' can throw. */ + const int alloca_flags + = ECF_MALLOC | ECF_LEAF | (flag_stack_check ? 0 : ECF_NOTHROW); + if (!builtin_decl_explicit_p (BUILT_IN_ALLOCA)) { ftype = build_function_type_list (ptr_type_node, size_type_node, NULL_TREE); local_define_builtin ("__builtin_alloca", ftype, BUILT_IN_ALLOCA, - "alloca", ECF_MALLOC | ECF_NOTHROW | ECF_LEAF); + "alloca", alloca_flags); } ftype = build_function_type_list (ptr_type_node, size_type_node, @@ -10541,14 +10557,7 @@ build_common_builtin_nodes (void) local_define_builtin ("__builtin_alloca_with_align", ftype, BUILT_IN_ALLOCA_WITH_ALIGN, "__builtin_alloca_with_align", - ECF_MALLOC | ECF_NOTHROW | ECF_LEAF); - - /* If we're checking the stack, `alloca' can throw. */ - if (flag_stack_check) - { - TREE_NOTHROW (builtin_decl_explicit (BUILT_IN_ALLOCA)) = 0; - TREE_NOTHROW (builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN)) = 0; - } + alloca_flags); ftype = build_function_type_list (void_type_node, ptr_type_node, ptr_type_node,