Commit 03a9b90a by Aaron Sawdey Committed by Aaron Sawdey

builtins.c (expand_builtin_memory_copy_args): Add might_overlap parm.

2019-10-02  Aaron Sawdey <acsawdey@linux.ibm.com>

	* builtins.c (expand_builtin_memory_copy_args): Add might_overlap parm.
	(expand_builtin_memcpy): Use might_overlap parm.
	(expand_builtin_mempcpy_args): Use might_overlap parm.
	(expand_builtin_memmove): Call expand_builtin_memory_copy_args.
	(expand_builtin_memory_copy_args): Add might_overlap parm.
	* expr.c (emit_block_move_via_cpymem): Rename to
	emit_block_move_via_pattern, add might_overlap parm, use cpymem
	or movmem optab as appropriate.
	(emit_block_move_hints): Add might_overlap parm, do the right
	thing for might_overlap==true.
	* expr.h (emit_block_move_hints): Update prototype.

From-SVN: r276461
parent 629387a6
2019-10-02 Aaron Sawdey <acsawdey@linux.ibm.com>
* builtins.c (expand_builtin_memory_copy_args): Add might_overlap parm.
(expand_builtin_memcpy): Use might_overlap parm.
(expand_builtin_mempcpy_args): Use might_overlap parm.
(expand_builtin_memmove): Call expand_builtin_memory_copy_args.
(expand_builtin_memory_copy_args): Add might_overlap parm.
* expr.c (emit_block_move_via_cpymem): Rename to
emit_block_move_via_pattern, add might_overlap parm, use cpymem
or movmem optab as appropriate.
(emit_block_move_hints): Add might_overlap parm, do the right
thing for might_overlap==true.
* expr.h (emit_block_move_hints): Update prototype.
2019-10-02 Eric Botcazou <ebotcazou@adacore.com> 2019-10-02 Eric Botcazou <ebotcazou@adacore.com>
* tree-eh.h (unsplit_eh_edges): Declare. * tree-eh.h (unsplit_eh_edges): Declare.
......
...@@ -127,7 +127,8 @@ static rtx expand_builtin_memchr (tree, rtx); ...@@ -127,7 +127,8 @@ static rtx expand_builtin_memchr (tree, rtx);
static rtx expand_builtin_memcpy (tree, rtx); static rtx expand_builtin_memcpy (tree, rtx);
static rtx expand_builtin_memory_copy_args (tree dest, tree src, tree len, static rtx expand_builtin_memory_copy_args (tree dest, tree src, tree len,
rtx target, tree exp, rtx target, tree exp,
memop_ret retmode); memop_ret retmode,
bool might_overlap);
static rtx expand_builtin_memmove (tree, rtx); static rtx expand_builtin_memmove (tree, rtx);
static rtx expand_builtin_mempcpy (tree, rtx); static rtx expand_builtin_mempcpy (tree, rtx);
static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx, tree, memop_ret); static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx, tree, memop_ret);
...@@ -3790,14 +3791,14 @@ expand_builtin_memcpy (tree exp, rtx target) ...@@ -3790,14 +3791,14 @@ expand_builtin_memcpy (tree exp, rtx target)
check_memop_access (exp, dest, src, len); check_memop_access (exp, dest, src, len);
return expand_builtin_memory_copy_args (dest, src, len, target, exp, return expand_builtin_memory_copy_args (dest, src, len, target, exp,
/*retmode=*/ RETURN_BEGIN); /*retmode=*/ RETURN_BEGIN, false);
} }
/* Check a call EXP to the memmove built-in for validity. /* Check a call EXP to the memmove built-in for validity.
Return NULL_RTX on both success and failure. */ Return NULL_RTX on both success and failure. */
static rtx static rtx
expand_builtin_memmove (tree exp, rtx) expand_builtin_memmove (tree exp, rtx target)
{ {
if (!validate_arglist (exp, if (!validate_arglist (exp,
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
...@@ -3809,7 +3810,8 @@ expand_builtin_memmove (tree exp, rtx) ...@@ -3809,7 +3810,8 @@ expand_builtin_memmove (tree exp, rtx)
check_memop_access (exp, dest, src, len); check_memop_access (exp, dest, src, len);
return NULL_RTX; return expand_builtin_memory_copy_args (dest, src, len, target, exp,
/*retmode=*/ RETURN_BEGIN, true);
} }
/* Expand a call EXP to the mempcpy builtin. /* Expand a call EXP to the mempcpy builtin.
...@@ -3858,7 +3860,8 @@ expand_builtin_mempcpy (tree exp, rtx target) ...@@ -3858,7 +3860,8 @@ expand_builtin_mempcpy (tree exp, rtx target)
static rtx static rtx
expand_builtin_memory_copy_args (tree dest, tree src, tree len, expand_builtin_memory_copy_args (tree dest, tree src, tree len,
rtx target, tree exp, memop_ret retmode) rtx target, tree exp, memop_ret retmode,
bool might_overlap)
{ {
const char *src_str; const char *src_str;
unsigned int src_align = get_pointer_alignment (src); unsigned int src_align = get_pointer_alignment (src);
...@@ -3894,9 +3897,12 @@ expand_builtin_memory_copy_args (tree dest, tree src, tree len, ...@@ -3894,9 +3897,12 @@ expand_builtin_memory_copy_args (tree dest, tree src, tree len,
&probable_max_size); &probable_max_size);
src_str = c_getstr (src); src_str = c_getstr (src);
/* If SRC is a string constant and block move would be done /* If SRC is a string constant and block move would be done by
by pieces, we can avoid loading the string from memory pieces, we can avoid loading the string from memory and only
and only stored the computed constants. */ stored the computed constants. This works in the overlap
(memmove) case as well because store_by_pieces just generates a
series of stores of constants from the string constant returned
by c_getstr(). */
if (src_str if (src_str
&& CONST_INT_P (len_rtx) && CONST_INT_P (len_rtx)
&& (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1 && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
...@@ -3923,13 +3929,14 @@ expand_builtin_memory_copy_args (tree dest, tree src, tree len, ...@@ -3923,13 +3929,14 @@ expand_builtin_memory_copy_args (tree dest, tree src, tree len,
method = BLOCK_OP_TAILCALL; method = BLOCK_OP_TAILCALL;
bool use_mempcpy_call = (targetm.libc_has_fast_function (BUILT_IN_MEMPCPY) bool use_mempcpy_call = (targetm.libc_has_fast_function (BUILT_IN_MEMPCPY)
&& retmode == RETURN_END && retmode == RETURN_END
&& !might_overlap
&& target != const0_rtx); && target != const0_rtx);
if (use_mempcpy_call) if (use_mempcpy_call)
method = BLOCK_OP_NO_LIBCALL_RET; method = BLOCK_OP_NO_LIBCALL_RET;
dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx, method, dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx, method,
expected_align, expected_size, expected_align, expected_size,
min_size, max_size, probable_max_size, min_size, max_size, probable_max_size,
use_mempcpy_call, &is_move_done); use_mempcpy_call, &is_move_done, might_overlap);
/* Bail out when a mempcpy call would be expanded as libcall and when /* Bail out when a mempcpy call would be expanded as libcall and when
we have a target that provides a fast implementation we have a target that provides a fast implementation
...@@ -3962,7 +3969,7 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len, ...@@ -3962,7 +3969,7 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len,
rtx target, tree orig_exp, memop_ret retmode) rtx target, tree orig_exp, memop_ret retmode)
{ {
return expand_builtin_memory_copy_args (dest, src, len, target, orig_exp, return expand_builtin_memory_copy_args (dest, src, len, target, orig_exp,
retmode); retmode, false);
} }
/* Expand into a movstr instruction, if one is available. Return NULL_RTX if /* Expand into a movstr instruction, if one is available. Return NULL_RTX if
......
...@@ -73,9 +73,10 @@ along with GCC; see the file COPYING3. If not see ...@@ -73,9 +73,10 @@ along with GCC; see the file COPYING3. If not see
int cse_not_expected; int cse_not_expected;
static bool block_move_libcall_safe_for_call_parm (void); static bool block_move_libcall_safe_for_call_parm (void);
static bool emit_block_move_via_cpymem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT, static bool emit_block_move_via_pattern (rtx, rtx, rtx, unsigned, unsigned,
unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, HOST_WIDE_INT, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT); unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, bool);
static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned); static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int); static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
static rtx_insn *compress_float_constant (rtx, rtx); static rtx_insn *compress_float_constant (rtx, rtx);
...@@ -1562,7 +1563,8 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, ...@@ -1562,7 +1563,8 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
unsigned HOST_WIDE_INT min_size, unsigned HOST_WIDE_INT min_size,
unsigned HOST_WIDE_INT max_size, unsigned HOST_WIDE_INT max_size,
unsigned HOST_WIDE_INT probable_max_size, unsigned HOST_WIDE_INT probable_max_size,
bool bail_out_libcall, bool *is_move_done) bool bail_out_libcall, bool *is_move_done,
bool might_overlap)
{ {
int may_use_call; int may_use_call;
rtx retval = 0; rtx retval = 0;
...@@ -1622,13 +1624,30 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, ...@@ -1622,13 +1624,30 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
set_mem_size (y, const_size); set_mem_size (y, const_size);
} }
if (CONST_INT_P (size) && can_move_by_pieces (INTVAL (size), align)) bool pieces_ok = can_move_by_pieces (INTVAL (size), align);
move_by_pieces (x, y, INTVAL (size), align, RETURN_BEGIN); bool pattern_ok = false;
else if (emit_block_move_via_cpymem (x, y, size, align,
if (!CONST_INT_P (size) || !pieces_ok || might_overlap)
{
pattern_ok =
emit_block_move_via_pattern (x, y, size, align,
expected_align, expected_size, expected_align, expected_size,
min_size, max_size, probable_max_size)) min_size, max_size, probable_max_size,
might_overlap);
if (!pattern_ok && might_overlap)
{
/* Do not try any of the other methods below as they are not safe
for overlapping moves. */
*is_move_done = false;
return retval;
}
}
if (pattern_ok)
; ;
else if (may_use_call else if (CONST_INT_P (size) && pieces_ok)
move_by_pieces (x, y, INTVAL (size), align, RETURN_BEGIN);
else if (may_use_call && !might_overlap
&& ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x)) && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x))
&& ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (y))) && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (y)))
{ {
...@@ -1645,7 +1664,8 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, ...@@ -1645,7 +1664,8 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
retval = emit_block_copy_via_libcall (x, y, size, retval = emit_block_copy_via_libcall (x, y, size,
method == BLOCK_OP_TAILCALL); method == BLOCK_OP_TAILCALL);
} }
else if (might_overlap)
*is_move_done = false;
else else
emit_block_move_via_loop (x, y, size, align); emit_block_move_via_loop (x, y, size, align);
...@@ -1721,15 +1741,26 @@ block_move_libcall_safe_for_call_parm (void) ...@@ -1721,15 +1741,26 @@ block_move_libcall_safe_for_call_parm (void)
return true; return true;
} }
/* A subroutine of emit_block_move. Expand a cpymem pattern; /* A subroutine of emit_block_move. Expand a cpymem or movmem pattern;
return true if successful. */ return true if successful.
X is the destination of the copy or move.
Y is the source of the copy or move.
SIZE is the size of the block to be moved.
MIGHT_OVERLAP indicates this originated with expansion of a
builtin_memmove() and the source and destination blocks may
overlap.
*/
static bool static bool
emit_block_move_via_cpymem (rtx x, rtx y, rtx size, unsigned int align, emit_block_move_via_pattern (rtx x, rtx y, rtx size, unsigned int align,
unsigned int expected_align, HOST_WIDE_INT expected_size, unsigned int expected_align,
HOST_WIDE_INT expected_size,
unsigned HOST_WIDE_INT min_size, unsigned HOST_WIDE_INT min_size,
unsigned HOST_WIDE_INT max_size, unsigned HOST_WIDE_INT max_size,
unsigned HOST_WIDE_INT probable_max_size) unsigned HOST_WIDE_INT probable_max_size,
bool might_overlap)
{ {
if (expected_align < align) if (expected_align < align)
expected_align = align; expected_align = align;
...@@ -1752,7 +1783,11 @@ emit_block_move_via_cpymem (rtx x, rtx y, rtx size, unsigned int align, ...@@ -1752,7 +1783,11 @@ emit_block_move_via_cpymem (rtx x, rtx y, rtx size, unsigned int align,
FOR_EACH_MODE_IN_CLASS (mode_iter, MODE_INT) FOR_EACH_MODE_IN_CLASS (mode_iter, MODE_INT)
{ {
scalar_int_mode mode = mode_iter.require (); scalar_int_mode mode = mode_iter.require ();
enum insn_code code = direct_optab_handler (cpymem_optab, mode); enum insn_code code;
if (might_overlap)
code = direct_optab_handler (movmem_optab, mode);
else
code = direct_optab_handler (cpymem_optab, mode);
if (code != CODE_FOR_nothing if (code != CODE_FOR_nothing
/* We don't need MODE to be narrower than BITS_PER_HOST_WIDE_INT /* We don't need MODE to be narrower than BITS_PER_HOST_WIDE_INT
......
...@@ -116,7 +116,8 @@ extern rtx emit_block_move_hints (rtx, rtx, rtx, enum block_op_methods, ...@@ -116,7 +116,8 @@ extern rtx emit_block_move_hints (rtx, rtx, rtx, enum block_op_methods,
unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
bool bail_out_libcall = false, bool bail_out_libcall = false,
bool *is_move_done = NULL); bool *is_move_done = NULL,
bool might_overlap = false);
extern rtx emit_block_cmp_hints (rtx, rtx, rtx, tree, rtx, bool, extern rtx emit_block_cmp_hints (rtx, rtx, rtx, tree, rtx, bool,
by_pieces_constfn, void *); by_pieces_constfn, void *);
extern bool emit_storent_insn (rtx to, rtx from); extern bool emit_storent_insn (rtx to, rtx from);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment