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
This commit is contained in:
Eric Botcazou 2016-05-13 08:49:20 +00:00 committed by Eric Botcazou
parent fff9b5ddb7
commit ee516de9b3
14 changed files with 206 additions and 356 deletions

View File

@ -1,3 +1,63 @@
2016-05-13 Eric Botcazou <ebotcazou@adacore.com>
* 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 <ubizjak@gmail.com>
* config/i386/i386.md (*call_got_x32): Change operand 0 to

View File

@ -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");
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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
}

View File

@ -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"

View File

@ -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,

View File

@ -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 *);

View File

@ -731,14 +731,15 @@ static GTY (()) hash_table<libfunc_decl_hasher> *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 ();
}

View File

@ -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));
/* Otherwise call a library function. */
result = emit_block_comp_via_libcall (XEXP (x, 0), XEXP (y, 0), size);
result = emit_library_call_value (libfunc, 0, LCT_PURE,
result_mode, 3,
XEXP (x, 0), Pmode,
XEXP (y, 0), Pmode,
size, cmp_mode);
x = result;
y = const0_rtx;
mode = result_mode;
mode = TYPE_MODE (integer_type_node);
methods = OPTAB_LIB_WIDEN;
unsignedp = false;
}

View File

@ -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

View File

@ -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,