From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31788 invoked by alias); 10 May 2016 20:16:07 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 31773 invoked by uid 89); 10 May 2016 20:16:06 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.6 required=5.0 tests=AWL,BAYES_00,KAM_ASCII_DIVIDERS,KAM_LAZY_DOMAIN_SECURITY,KAM_STOCKGEN,RCVD_IN_DNSWL_NONE autolearn=no version=3.3.2 spammy=2425, ebotcazouadacorecom, ebotcazou@adacore.com, except.h X-HELO: smtp.eu.adacore.com Received: from mel.act-europe.fr (HELO smtp.eu.adacore.com) (194.98.77.210) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Tue, 10 May 2016 20:15:56 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-smtp.eu.adacore.com (Postfix) with ESMTP id D09C081329 for ; Tue, 10 May 2016 22:15:51 +0200 (CEST) Received: from smtp.eu.adacore.com ([127.0.0.1]) by localhost (smtp.eu.adacore.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 9JuAZ6C2FOjy for ; Tue, 10 May 2016 22:15:51 +0200 (CEST) Received: from polaris.localnet (bon31-6-88-161-99-133.fbx.proxad.net [88.161.99.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.eu.adacore.com (Postfix) with ESMTPSA id 5BD97812E1 for ; Tue, 10 May 2016 22:15:51 +0200 (CEST) From: Eric Botcazou To: gcc-patches@gcc.gnu.org Subject: [patch] Tidy up RTL libfunc machinery Date: Tue, 10 May 2016 20:16:00 -0000 Message-ID: <11895702.FiV16380R3@polaris> User-Agent: KMail/4.14.10 (Linux/3.16.7-35-desktop; KDE/4.14.9; x86_64; ; ) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="nextPart3476964.mR1YgYvZPP" Content-Transfer-Encoding: 7Bit X-SW-Source: 2016-05/txt/msg00761.txt.bz2 This is a multi-part message in MIME format. --nextPart3476964.mR1YgYvZPP Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="us-ascii" Content-length: 4466 Hi, this patch is aimed at cleaning up the mess with the RTL libfunc machinery. On the one hand you have comments like these in the RTL expander: /* 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. */ /* 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. */ and on the other hand you have at the end of expand_builtin_memcmp: 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)); so the RTL expander is not allowed to call memcpy & memset libfuncs on its own but it is for __builtin_memcmp, which is rather inconsistent. So the patch eliminates all the RTL libfuncs and replaces them by calls to the corresponding builtins, except for 3 of them: - synchronize_libfunc, which is used by the ARM and MIPS back-ends, - unwind_sjlj_register_libfunc, which is used by the SJLJ machinery, - unwind_sjlj_unregister_libfunc, likewise. abort_libfunc and memcmp_libfunc are set by VMS to something else than the default but this looks like an optimization and can presumably be dropped. Bootstrapped/regtested on x86-64/Linux and PowerPC/Linux, OK for mainline? 2016-05-10 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. -- Eric Botcazou --nextPart3476964.mR1YgYvZPP Content-Disposition: attachment; filename="p.diff" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="UTF-8"; name="p.diff" Content-length: 30006 Index: builtins.c =================================================================== --- builtins.c (revision 236072) +++ builtins.c (working copy) @@ -3757,20 +3757,7 @@ expand_builtin_memcmp (tree exp, rtx tar 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"); } } Index: config/alpha/alpha.c =================================================================== --- config/alpha/alpha.c (revision 236072) +++ config/alpha/alpha.c (working copy) @@ -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 Index: config/i386/i386.c =================================================================== --- config/i386/i386.c (revision 236072) +++ config/i386/i386.c (working copy) @@ -26910,9 +26910,9 @@ ix86_expand_set_or_movmem (rtx dst, rtx 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); } Index: config/ia64/ia64.c =================================================================== --- config/ia64/ia64.c (revision 236072) +++ config/ia64/ia64.c (working copy) @@ -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 Index: dse.c =================================================================== --- dse.c (revision 236072) +++ dse.c (working copy) @@ -2269,6 +2269,7 @@ scan_insn (bb_info_t bb_info, rtx_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 * 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; Index: except.c =================================================================== --- except.c (revision 236072) +++ except.c (working copy) @@ -130,6 +130,7 @@ along with GCC; see the file COPYING3. #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 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 } Index: expr.c =================================================================== --- expr.c (revision 236072) +++ expr.c (working copy) @@ -109,14 +109,12 @@ static bool block_move_libcall_safe_for_ 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 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 (v /* 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 (v 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 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, 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 { 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, b 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" Index: expr.h =================================================================== --- expr.h (revision 236072) +++ expr.h (working copy) @@ -71,8 +71,29 @@ extern rtx convert_to_mode (machine_mode /* 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 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, Index: libfuncs.h =================================================================== --- libfuncs.h (revision 236072) +++ libfuncs.h (working copy) @@ -24,25 +24,9 @@ along with GCC; see the file COPYING3. /* 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_targ /* 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 *); Index: optabs-libfuncs.c =================================================================== --- optabs-libfuncs.c (revision 236072) +++ optabs-libfuncs.c (working copy) @@ -731,14 +731,15 @@ static GTY (()) hash_table