expr: Optimize noop copies [PR96539]
authorJakub Jelinek <jakub@redhat.com>
Tue, 11 Aug 2020 11:47:29 +0000 (13:47 +0200)
committerJakub Jelinek <jakub@redhat.com>
Tue, 11 Aug 2020 11:51:59 +0000 (13:51 +0200)
At GIMPLE e.g. for __builtin_memmove we optimize away (to just the return
value) noop copies where src == dest, but at the RTL we don't, and as the
testcase shows, in some cases such copies can appear only at the RTL level
e.g. from trying to copy an aggregate by value argument to the same location
as it already has.  If the block move is expanded e.g. piecewise, we
actually manage to optimize it away, as the individual memory copies are
seen as noop moves, but if the target optabs are used, often the sequences
stay until final.

2020-08-11  Jakub Jelinek  <jakub@redhat.com>

PR rtl-optimization/96539
* expr.c (emit_block_move_hints): Don't copy anything if x and y
are the same and neither is MEM_VOLATILE_P.

* gcc.target/i386/pr96539.c: New test.

gcc/expr.c
gcc/testsuite/gcc.target/i386/pr96539.c [new file with mode: 0644]

index ebf0c9e4797d5a4b6c46bef5c4419497df13c3d4..2406f9039eabd7f0c5bd16124eadb486b460b5eb 100644 (file)
@@ -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 (file)
index 0000000..fc164f8
--- /dev/null
@@ -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);
+}