Hi!

This is an attempt to fix the following testcase (reduced from gsoap)
similarly how you've fixed another issue with r221795 other AAPCS
regressions introduced with r221348 change.
This patch passed bootstrap/regtest on
{x86_64,i686,armv7hl,aarch64,powerpc64{,le},s390{,x}}-linux.

Though, it still doesn't fix profiledbootstrap on armv7hl that is broken
since r221348, so other issues are lurking in there, and I must say
I'm not entirely sure about this, because it changes alignment even when
the original access had higher alignment.

I was trying something like:
struct B { char *a, *b; };
typedef struct B C __attribute__((aligned (8)));
struct A { C a; int b; long long c; };
char v[3];

__attribute__((noinline, noclone)) void
fn1 (C x, C y)
{
  if (x.a != &v[1] || y.a != &v[2])
    __builtin_abort ();
  v[1]++;
}

__attribute__((noinline, noclone)) int
fn2 (C x)
{
  asm volatile ("" : "+g" (x.a) : : "memory");
  asm volatile ("" : "+g" (x.b) : : "memory");
  return x.a == &v[0];
}

__attribute__((noinline, noclone)) void
fn3 (const char *x)
{
  if (x[0] != 0)
    __builtin_abort ();
}

static struct A
foo (const char *x, struct A y, struct A z)
{
  struct A r = { { 0, 0 }, 0, 0 };
  if (y.b && z.b)
    {
      if (fn2 (y.a) && fn2 (z.a))
        switch (x[0])
          {
          case '|':
            break;
          default:
            fn3 (x);
          }
      fn1 (y.a, z.a);
    }
  return r;
}

__attribute__((noinline, noclone)) int
bar (int x, struct A *y)
{
  switch (x)
    {
    case 219:
      foo ("+", y[-2], y[0]);
    case 220:
      foo ("-", y[-2], y[0]);
    }
}

int
main ()
{
  struct A a[3] = { { { &v[1], &v[0] }, 1, 1LL },
                    { { &v[0], &v[0] }, 0, 0LL },
                    { { &v[2], &v[0] }, 2, 2LL } };
  bar (220, a + 2);
  if (v[1] != 1)
    __builtin_abort ();
  return 0;
}

and this patch indeed changes the register passing, eventhough it probably
shouldn't (though, the testcase doesn't fail).  Wouldn't it be possible to
preserve the original type (before we call build_aligned_type on it)
somewhere in SRA data structures, perhaps keep expr (the new MEM_REF) use
the aligned type, but type field be the non-aligned one?

2015-05-02  Jakub Jelinek  <ja...@redhat.com>

        PR target/65956
        * tree-sra.c (turn_representatives_into_adjustments): For
        adj.type, use TYPE_MAIN_VARIANT of repr->type with TYPE_QUALS.

        * gcc.c-torture/execute/pr65956.c: New test.

--- gcc/tree-sra.c.jj   2015-04-20 14:35:47.000000000 +0200
+++ gcc/tree-sra.c      2015-05-01 01:08:34.092636496 +0200
@@ -4427,7 +4427,11 @@ turn_representatives_into_adjustments (v
              gcc_assert (repr->base == parm);
              adj.base_index = index;
              adj.base = repr->base;
-             adj.type = repr->type;
+             /* Drop any special alignment on the type if it's not on the
+                main variant.  This avoids issues with weirdo ABIs like
+                AAPCS.  */
+             adj.type = build_qualified_type (TYPE_MAIN_VARIANT (repr->type),
+                                              TYPE_QUALS (repr->type));
              adj.alias_ptr_type = reference_alias_ptr_type (repr->expr);
              adj.offset = repr->offset;
              adj.by_ref = (POINTER_TYPE_P (TREE_TYPE (repr->base))
--- gcc/testsuite/gcc.c-torture/execute/pr65956.c.jj    2015-05-01 
10:32:34.730150257 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr65956.c       2015-05-01 
10:32:13.000000000 +0200
@@ -0,0 +1,67 @@
+/* PR target/65956 */
+
+struct A { char *a; int b; long long c; };
+char v[3];
+
+__attribute__((noinline, noclone)) void
+fn1 (char *x, char *y)
+{
+  if (x != &v[1] || y != &v[2])
+    __builtin_abort ();
+  v[1]++;
+}
+
+__attribute__((noinline, noclone)) int
+fn2 (char *x)
+{
+  asm volatile ("" : "+g" (x) : : "memory");
+  return x == &v[0];
+}
+
+__attribute__((noinline, noclone)) void
+fn3 (const char *x)
+{
+  if (x[0] != 0)
+    __builtin_abort ();
+}
+
+static struct A
+foo (const char *x, struct A y, struct A z)
+{
+  struct A r = { 0, 0, 0 };
+  if (y.b && z.b)
+    {
+      if (fn2 (y.a) && fn2 (z.a))
+       switch (x[0])
+         {
+         case '|':
+           break;
+         default:
+           fn3 (x);
+         }
+      fn1 (y.a, z.a);
+    }
+  return r;
+}
+
+__attribute__((noinline, noclone)) int
+bar (int x, struct A *y)
+{
+  switch (x)
+    {
+    case 219:
+      foo ("+", y[-2], y[0]);
+    case 220:
+      foo ("-", y[-2], y[0]);
+    }
+}
+
+int
+main ()
+{
+  struct A a[3] = { { &v[1], 1, 1LL }, { &v[0], 0, 0LL }, { &v[2], 2, 2LL } };
+  bar (220, a + 2);
+  if (v[1] != 1)
+    __builtin_abort ();
+  return 0;
+}

        Jakub

Reply via email to