aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/builtins.c27
-rw-r--r--gcc/expr.c73
-rw-r--r--gcc/expr.h3
4 files changed, 87 insertions, 30 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d66b03e..fe14577 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@
+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>
* tree-eh.h (unsplit_eh_edges): Declare.
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 1fd4b88..fa17afd 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -127,7 +127,8 @@ static rtx expand_builtin_memchr (tree, rtx);
static rtx expand_builtin_memcpy (tree, rtx);
static rtx expand_builtin_memory_copy_args (tree dest, tree src, tree len,
rtx target, tree exp,
- memop_ret retmode);
+ memop_ret retmode,
+ bool might_overlap);
static rtx expand_builtin_memmove (tree, rtx);
static rtx expand_builtin_mempcpy (tree, rtx);
static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx, tree, memop_ret);
@@ -3790,14 +3791,14 @@ expand_builtin_memcpy (tree exp, rtx target)
check_memop_access (exp, dest, src, len);
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.
Return NULL_RTX on both success and failure. */
static rtx
-expand_builtin_memmove (tree exp, rtx)
+expand_builtin_memmove (tree exp, rtx target)
{
if (!validate_arglist (exp,
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
@@ -3809,7 +3810,8 @@ expand_builtin_memmove (tree exp, rtx)
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.
@@ -3858,7 +3860,8 @@ expand_builtin_mempcpy (tree exp, rtx target)
static rtx
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;
unsigned int src_align = get_pointer_alignment (src);
@@ -3894,9 +3897,12 @@ expand_builtin_memory_copy_args (tree dest, tree src, tree len,
&probable_max_size);
src_str = c_getstr (src);
- /* If SRC is a string constant and block move would be done
- by pieces, we can avoid loading the string from memory
- and only stored the computed constants. */
+ /* If SRC is a string constant and block move would be done by
+ pieces, we can avoid loading the string from memory and only
+ 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
&& CONST_INT_P (len_rtx)
&& (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,
method = BLOCK_OP_TAILCALL;
bool use_mempcpy_call = (targetm.libc_has_fast_function (BUILT_IN_MEMPCPY)
&& retmode == RETURN_END
+ && !might_overlap
&& target != const0_rtx);
if (use_mempcpy_call)
method = BLOCK_OP_NO_LIBCALL_RET;
dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx, method,
expected_align, expected_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
we have a target that provides a fast implementation
@@ -3962,7 +3969,7 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len,
rtx target, tree orig_exp, memop_ret retmode)
{
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
diff --git a/gcc/expr.c b/gcc/expr.c
index 7a70706..bd6a71a 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -73,9 +73,10 @@ along with GCC; see the file COPYING3. If not see
int cse_not_expected;
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,
- unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT);
+static bool emit_block_move_via_pattern (rtx, rtx, rtx, unsigned, 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 clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
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,
unsigned HOST_WIDE_INT min_size,
unsigned HOST_WIDE_INT 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;
rtx retval = 0;
@@ -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);
}
- if (CONST_INT_P (size) && can_move_by_pieces (INTVAL (size), align))
- move_by_pieces (x, y, INTVAL (size), align, RETURN_BEGIN);
- else if (emit_block_move_via_cpymem (x, y, size, align,
- expected_align, expected_size,
- min_size, max_size, probable_max_size))
+ bool pieces_ok = can_move_by_pieces (INTVAL (size), align);
+ bool pattern_ok = false;
+
+ if (!CONST_INT_P (size) || !pieces_ok || might_overlap)
+ {
+ pattern_ok =
+ emit_block_move_via_pattern (x, y, size, align,
+ expected_align, expected_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 (y)))
{
@@ -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,
method == BLOCK_OP_TAILCALL);
}
-
+ else if (might_overlap)
+ *is_move_done = false;
else
emit_block_move_via_loop (x, y, size, align);
@@ -1721,15 +1741,26 @@ block_move_libcall_safe_for_call_parm (void)
return true;
}
-/* A subroutine of emit_block_move. Expand a cpymem pattern;
- return true if successful. */
+/* A subroutine of emit_block_move. Expand a cpymem or movmem pattern;
+ 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
-emit_block_move_via_cpymem (rtx x, rtx y, rtx size, unsigned int align,
- unsigned int expected_align, HOST_WIDE_INT expected_size,
- unsigned HOST_WIDE_INT min_size,
- unsigned HOST_WIDE_INT max_size,
- unsigned HOST_WIDE_INT probable_max_size)
+emit_block_move_via_pattern (rtx x, rtx y, rtx size, unsigned int align,
+ unsigned int expected_align,
+ HOST_WIDE_INT expected_size,
+ unsigned HOST_WIDE_INT min_size,
+ unsigned HOST_WIDE_INT max_size,
+ unsigned HOST_WIDE_INT probable_max_size,
+ bool might_overlap)
{
if (expected_align < align)
expected_align = 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)
{
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
/* We don't need MODE to be narrower than BITS_PER_HOST_WIDE_INT
diff --git a/gcc/expr.h b/gcc/expr.h
index 6eb70bf..17c9163 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -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,
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,
by_pieces_constfn, void *);
extern bool emit_storent_insn (rtx to, rtx from);