diff --git a/gcc/expr.c b/gcc/expr.c index ebf0c9e4797d..2406f9039eab 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -1637,6 +1637,12 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, x = adjust_address (x, BLKmode, 0); y = adjust_address (y, BLKmode, 0); + /* If source and destination are the same, no need to copy anything. */ + if (rtx_equal_p (x, y) + && !MEM_VOLATILE_P (x) + && !MEM_VOLATILE_P (y)) + return 0; + /* Set MEM_SIZE as appropriate for this block copy. The main place this can be incorrect is coming from __builtin_memcpy. */ poly_int64 const_size; diff --git a/gcc/testsuite/gcc.target/i386/pr96539.c b/gcc/testsuite/gcc.target/i386/pr96539.c new file mode 100644 index 000000000000..fc164f8b8898 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr96539.c @@ -0,0 +1,16 @@ +/* PR rtl-optimization/96539 */ +/* { dg-do compile } * +/* { dg-options "-Os" } */ +/* { dg-final { scan-assembler-not "rep\[^\n\r]\*movs" } } */ + +struct A { int a, b, c, d, e, f; void *g, *h, *i, *j, *k, *l, *m; }; + +int bar (int a); +int baz (int a, int b, int c, void *p, struct A s); + +int +foo (int a, int b, int c, void *p, struct A s) +{ + bar (a); + return baz (a, b, c, p, s); +}