This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix eipa_sra AAPCS issue (PR target/65956)


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  <jakub@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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]