https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127647

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jamborm at gcc dot gnu.org

--- Comment #5 from Richard Biener <rguenth at gcc dot gnu.org> ---
Hmm, no.  Sinking isn't really set up to cross other (non-aliasing) stores.
C++ testcase showing the STLF issue;  the best thing would be to eliminate
'tem' alltogether, but the late memcpy inlining makes this difficult.  SRA
says

Candidate (5305): tem
Allowed ADDR_EXPR of tem because of __builtin_memcpy (x_18(D), &tem, 12);

! Disqualifying tem - No scalar replacements to be created.

Martin?  We seem to have a single outer access from the memcpy and
children for the stores.

Naiively doing

diff --git a/gcc/tree-sra.cc b/gcc/tree-sra.cc
index f951a38442a..33f0a6235a7 100644
--- a/gcc/tree-sra.cc
+++ b/gcc/tree-sra.cc
@@ -1422,7 +1422,10 @@ build_access_from_call_arg (tree expr, gimple *stmt,
bool can_be_returned,
          return false;
        }

-      bool read =  build_access_from_expr (base, stmt, false);
+      auto raccess = build_access_from_expr_1 (base, stmt, false);
+      bool read = raccess != NULL;
+      if (raccess)
+       raccess->grp_total_scalarization = 1;
       bool write =  build_access_from_expr (base, stmt, true);
       if (read || write)
        {

to trigger total scalarization of course "fails" in the sense that SRA
cannot rewrite a __builtin_memcpy.  But with this I see

  MEM <int> [(void *)&tem] = tem$a_24;
  MEM <int> [(void *)&tem + 4B] = tem$b_25;
  MEM <int> [(void *)&tem + 8B] = tem$c_26;
  __builtin_memcpy (x_18(D), &tem, 12);

and thus at least the desired "sinking" done ... but still RTL cannot
recover

        movl    %eax, -12(%rsp)
        movl    %r8d, -8(%rsp)
        movl    %ecx, 8(%rdi)
        movq    -12(%rsp), %rax
        movq    %rax, (%rdi)

That said, I'm still a believer in SRA guiding "larger" memcpy expansion
(as opposed to unleashing fold_stmt).


struct X { int a; int b; int c; };

void foo (int *x, int *p, int stride)
{
  struct X tem;
  int p0, p1, p2;

  tem.a = p0 = p[0];
  tem.b = p1 = p[1];
  tem.c = p2 = p[2];
  if (stride != 1)
    {
      x[0] = p0;
      x[stride] = p1;
      x[stride*2] = p2;
    }
  else
    __builtin_memcpy (x, &tem, sizeof (X));
}

Reply via email to