Implement AAPCS64 updates for alignment attribute. 84/134284/3
authorMikhail Kashkarov <m.kashkarov@partner.samsung.com>
Thu, 15 Jun 2017 14:03:07 +0000 (17:03 +0300)
committerDongkyun Son <dongkyun.s@samsung.com>
Wed, 28 Jun 2017 11:32:24 +0000 (11:32 +0000)
        PR target/77728
         gcc/
        * config/aarch64/aarch64.c(aarch64_function_arg_alignmentq):
        Rewrite, looking one level down for records and arrays.
        Ignore TYPE_FIELDS chain decls other than FIELD_DECLs.
        (aarch64_layout_arg): Adjust aarch64_function_arg_alignment caller.
        (aarch64_function_arg_boundary): Likewise.  Simplify using MIN/MAX.
        (aarch64_gimplify_va_arg_expr): Adjust aarch64_function_arg_alignment
         caller.
        testsuite/
        * g++.dg/abi/pr77728-2.C: New test.

        Backported from trunk:
        be35fa06e8f976e1cb880988d5c82813106922fd
        32cb614ad1f60267f914e38da26a73259299d720
        26312b0ea5f3dfc6e3d8d8d18c76d464d6fa328e

Change-Id: I4293167468353e9730dc918b87edda4484af8315

gcc/config/aarch64/aarch64.c
gcc/testsuite/g++.dg/abi/pr77728-2.C [new file with mode: 0644]

index f0970f2..bd75ef2 100644 (file)
@@ -2246,22 +2246,24 @@ aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode,
 static unsigned int
 aarch64_function_arg_alignment (machine_mode mode, const_tree type)
 {
-  unsigned int alignment;
+  if (!type)
+    return GET_MODE_ALIGNMENT (mode);
 
-  if (type)
-    {
-      if (!integer_zerop (TYPE_SIZE (type)))
-       {
-         if (TYPE_MODE (type) == mode)
-           alignment = TYPE_ALIGN (type);
-         else
-           alignment = GET_MODE_ALIGNMENT (mode);
-       }
-      else
-       alignment = 0;
-    }
-  else
-    alignment = GET_MODE_ALIGNMENT (mode);
+  if (integer_zerop (TYPE_SIZE (type)))
+    return 0;
+
+  gcc_assert (TYPE_MODE (type) == mode);
+
+  if (!AGGREGATE_TYPE_P (type))
+    return TYPE_ALIGN (TYPE_MAIN_VARIANT (type));
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    return TYPE_ALIGN (TREE_TYPE (type));
+
+  unsigned int alignment = 0;
+  for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+    if (TREE_CODE (field) == FIELD_DECL)
+      alignment = std::max (alignment, DECL_ALIGN (field));
 
   return alignment;
 }
@@ -2350,24 +2352,28 @@ aarch64_layout_arg (cumulative_args_t pcum_v, machine_mode mode,
      entirely general registers.  */
   if (allocate_ncrn && (ncrn + nregs <= NUM_ARG_REGS))
     {
-      unsigned int alignment = aarch64_function_arg_alignment (mode, type);
 
       gcc_assert (nregs == 0 || nregs == 1 || nregs == 2);
 
       /* C.8 if the argument has an alignment of 16 then the NGRN is
          rounded up to the next even number.  */
-      if (nregs == 2 && alignment == 16 * BITS_PER_UNIT && ncrn % 2)
+      if (nregs == 2
+         && ncrn % 2
+         /* The == 16 * BITS_PER_UNIT instead of >= 16 * BITS_PER_UNIT
+            comparison is there because for > 16 * BITS_PER_UNIT
+            alignment nregs should be > 2 and therefore it should be
+            passed by reference rather than value.  */
+         && aarch64_function_arg_alignment (mode, type) == 16 * BITS_PER_UNIT)
        {
          ++ncrn;
          gcc_assert (ncrn + nregs <= NUM_ARG_REGS);
        }
+
       /* NREGS can be 0 when e.g. an empty structure is to be passed.
          A reg is still generated for it, but the caller should be smart
         enough not to use it.  */
       if (nregs == 0 || nregs == 1 || GET_MODE_CLASS (mode) == MODE_INT)
-       {
-         pcum->aapcs_reg = gen_rtx_REG (mode, R0_REGNUM + ncrn);
-       }
+       pcum->aapcs_reg = gen_rtx_REG (mode, R0_REGNUM + ncrn);
       else
        {
          rtx par;
@@ -2395,6 +2401,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, machine_mode mode,
      this argument and align the total size if necessary.  */
 on_stack:
   pcum->aapcs_stack_words = size / UNITS_PER_WORD;
+
   if (aarch64_function_arg_alignment (mode, type) == 16 * BITS_PER_UNIT)
     pcum->aapcs_stack_size = ROUND_UP (pcum->aapcs_stack_size,
                                       16 / UNITS_PER_WORD);
@@ -2487,12 +2494,7 @@ static unsigned int
 aarch64_function_arg_boundary (machine_mode mode, const_tree type)
 {
   unsigned int alignment = aarch64_function_arg_alignment (mode, type);
-
-  if (alignment < PARM_BOUNDARY)
-    alignment = PARM_BOUNDARY;
-  if (alignment > STACK_BOUNDARY)
-    alignment = STACK_BOUNDARY;
-  return alignment;
+  return MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY);
 }
 
 /* For use by FUNCTION_ARG_PADDING (MODE, TYPE).
diff --git a/gcc/testsuite/g++.dg/abi/pr77728-2.C b/gcc/testsuite/g++.dg/abi/pr77728-2.C
new file mode 100644 (file)
index 0000000..ffe6910
--- /dev/null
@@ -0,0 +1,165 @@
+// { dg-do compile { target { { aarch64-*-* } && c++11 } } }
+// { dg-options "" }
+
+#include <stdarg.h>
+
+template <int N>
+struct alignas (16) A { char p[16]; };
+
+A<0> v;
+
+template <int N>
+struct B
+{
+  typedef A<N> T;
+  int i, j, k, l;
+};
+
+struct C : public B<0> {};
+struct D {};
+struct E : public D, C {};
+struct F : public B<1> {};
+struct G : public F { static int y alignas (16); };
+struct H : public G {};
+struct I : public D { int z alignas (16); };
+struct J : public D { static int z alignas (16); int i, j, k, l; };
+
+template <int N>
+struct K : public D { typedef A<N> T; int i, j; };
+
+struct L { static int h alignas (16); int i, j, k, l; };
+
+int
+fn1 (int a, B<0> b)
+{
+  return a + b.i;
+}
+
+int
+fn2 (int a, B<1> b)
+{
+  return a + b.i;
+}
+
+int
+fn3 (int a, L b)
+{
+  return a + b.i;
+}
+
+int
+fn4 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, B<0> n, ...)
+{
+  va_list ap;
+  va_start (ap, n);
+  int x = va_arg (ap, int);
+  va_end (ap);
+  return x;
+}
+
+int
+fn5 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, B<1> n, ...)
+{
+  va_list ap;
+  va_start (ap, n);
+  int x = va_arg (ap, int);
+  va_end (ap);
+  return x;
+}
+
+int
+fn6 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, C n, ...)
+{
+  va_list ap;
+  va_start (ap, n);
+  int x = va_arg (ap, int);
+  va_end (ap);
+  return x;
+}
+
+int
+fn7 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, E n, ...)
+{
+  va_list ap;
+  va_start (ap, n);
+  int x = va_arg (ap, int);
+  va_end (ap);
+  return x;
+}
+
+int
+fn8 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, H n, ...)
+{
+  va_list ap;
+  va_start (ap, n);
+  int x = va_arg (ap, int);
+  va_end (ap);
+  return x;
+}
+
+int
+fn9 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, I n, ...)
+{
+  va_list ap;
+  va_start (ap, n);
+  int x = va_arg (ap, int);
+  va_end (ap);
+  return x;
+}
+
+int
+fn10 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, J n, ...)
+{
+  va_list ap;
+  va_start (ap, n);
+  int x = va_arg (ap, int);
+  va_end (ap);
+  return x;
+}
+
+int
+fn11 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, K<0> n, ...)
+{
+  va_list ap;
+  va_start (ap, n);
+  int x = va_arg (ap, int);
+  va_end (ap);
+  return x;
+}
+
+int
+fn12 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, K<2> n, ...)
+{
+  va_list ap;
+  va_start (ap, n);
+  int x = va_arg (ap, int);
+  va_end (ap);
+  return x;
+}
+
+void
+test ()
+{
+  static B<0> b0;
+  static B<1> b1;
+  static L l;
+  static C c;
+  static E e;
+  static H h;
+  static I i;
+  static J j;
+  static K<0> k0;
+  static K<2> k2;
+  fn1 (1, b0);
+  fn2 (1, b1);
+  fn3 (1, l);
+  fn4 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, b0, 1, 2, 3, 4);
+  fn5 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, b1, 1, 2, 3, 4);
+  fn6 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, c, 1, 2, 3, 4);
+  fn7 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, e, 1, 2, 3, 4);
+  fn8 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, h, 1, 2, 3, 4);
+  fn9 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, i, 1, 2, 3, 4);
+  fn10 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, j, 1, 2, 3, 4);
+  fn11 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, k0, 1, 2, 3, 4);
+  fn12 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, k2, 1, 2, 3, 4);
+}