This is a backport of the ARM ABI fix, except that it doesn't change code,
only adds the ABI warning.

So there were four changes, three of them are changing "else if (res < 0)"
to "if (res != 0)" and the fourth was the "res != 0" change in
arm_function_arg_boundary.

I've verified on a testcase that we now get the warning but there are no
changes in .s files.

Bootstrapped/regtested on armv7hl-linux-gnueabi, ok for 6?

2017-04-26  Marek Polacek  <pola...@redhat.com>
            Ramana Radhakrishnan  <ramana.radhakrish...@arm.com>
            Jakub Jelinek  <ja...@redhat.com>

        PR target/77728
        * config/arm/arm.c: Include gimple.h.
        (aapcs_layout_arg): Emit -Wpsabi note if arm_needs_doubleword_align
        returns negative, increment ncrn if it returned non-zero.
        (arm_needs_doubleword_align): Return int instead of bool,
        ignore DECL_ALIGN of non-FIELD_DECL TYPE_FIELDS chain
        members, but if there is any such non-FIELD_DECL
        > PARM_BOUNDARY aligned decl, return -1 instead of false.
        (arm_function_arg): Emit -Wpsabi note if arm_needs_doubleword_align
        returns negative, increment nregs if it returned non-zero.
        (arm_setup_incoming_varargs): Likewise.
        (arm_function_arg_boundary): Emit -Wpsabi note if
        arm_needs_doubleword_align returns negative, return
        DOUBLEWORD_ALIGNMENT if it returned non-zero.

        * g++.dg/abi/pr77728-1.C: New test.

diff --git gcc/config/arm/arm.c gcc/config/arm/arm.c
index 6373103..b3da8c8 100644
--- gcc/config/arm/arm.c
+++ gcc/config/arm/arm.c
@@ -61,6 +61,7 @@
 #include "builtins.h"
 #include "tm-constrs.h"
 #include "rtl-iter.h"
+#include "gimple.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -78,7 +79,7 @@ struct four_ints
 
 /* Forward function declarations.  */
 static bool arm_const_not_ok_for_debug_p (rtx);
-static bool arm_needs_doubleword_align (machine_mode, const_tree);
+static int arm_needs_doubleword_align (machine_mode, const_tree);
 static int arm_compute_static_chain_stack_bytes (void);
 static arm_stack_offsets *arm_get_frame_offsets (void);
 static void arm_add_gc_roots (void);
@@ -6137,8 +6138,20 @@ aapcs_layout_arg (CUMULATIVE_ARGS *pcum, machine_mode 
mode,
   /* C3 - For double-word aligned arguments, round the NCRN up to the
      next even number.  */
   ncrn = pcum->aapcs_ncrn;
-  if ((ncrn & 1) && arm_needs_doubleword_align (mode, type))
-    ncrn++;
+  if (ncrn & 1)
+    {
+      int res = arm_needs_doubleword_align (mode, type);
+      /* Only warn during RTL expansion of call stmts, otherwise we would
+        warn e.g. during gimplification even on functions that will be
+        always inlined, and we'd warn multiple times.  Don't warn when
+        called in expand_function_start either, as we warn instead in
+        arm_function_arg_boundary in that case.  */
+      if (res < 0 && warn_psabi && currently_expanding_gimple_stmt)
+       inform (input_location, "parameter passing for argument of type "
+               "%qT will change in GCC 7.1", type);
+      if (res != 0)
+       ncrn++;
+    }
 
   nregs = ARM_NUM_REGS2(mode, type);
 
@@ -6243,12 +6256,16 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree 
fntype,
     }
 }
 
-/* Return true if mode/type need doubleword alignment.  */
-static bool
+/* Return 1 if double word alignment is required for argument passing.
+   Return -1 if double word alignment used to be required for argument
+   passing before PR77728 ABI fix, but is not required anymore.
+   Return 0 if double word alignment is not required and wasn't requried
+   before either.  */
+static int
 arm_needs_doubleword_align (machine_mode mode, const_tree type)
 {
   if (!type)
-    return PARM_BOUNDARY < GET_MODE_ALIGNMENT (mode);
+    return GET_MODE_ALIGNMENT (mode) > PARM_BOUNDARY;
 
   /* Scalar and vector types: Use natural alignment, i.e. of base type.  */
   if (!AGGREGATE_TYPE_P (type))
@@ -6258,12 +6275,21 @@ arm_needs_doubleword_align (machine_mode mode, 
const_tree type)
   if (TREE_CODE (type) == ARRAY_TYPE)
     return TYPE_ALIGN (TREE_TYPE (type)) > PARM_BOUNDARY;
 
+  int ret = 0;
   /* Record/aggregate types: Use greatest member alignment of any member.  */ 
   for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
     if (DECL_ALIGN (field) > PARM_BOUNDARY)
-      return true;
+      {
+       if (TREE_CODE (field) == FIELD_DECL)
+         return 1;
+       else
+         /* Before PR77728 fix, we were incorrectly considering also
+            other aggregate fields, like VAR_DECLs, TYPE_DECLs etc.
+            Make sure we can warn about that with -Wpsabi.  */
+         ret = -1;
+      }
 
-  return false;
+  return ret;
 }
 
 
@@ -6320,10 +6346,15 @@ arm_function_arg (cumulative_args_t pcum_v, 
machine_mode mode,
     }
 
   /* Put doubleword aligned quantities in even register pairs.  */
-  if (pcum->nregs & 1
-      && ARM_DOUBLEWORD_ALIGN
-      && arm_needs_doubleword_align (mode, type))
-    pcum->nregs++;
+  if ((pcum->nregs & 1) && ARM_DOUBLEWORD_ALIGN)
+    {
+      int res = arm_needs_doubleword_align (mode, type);
+      if (res < 0 && warn_psabi)
+       inform (input_location, "parameter passing for argument of type "
+               "%qT will change in GCC 7.1", type);
+      if (res != 0)
+       pcum->nregs++;
+    }
 
   /* Only allow splitting an arg between regs and memory if all preceding
      args were allocated to regs.  For args passed by reference we only count
@@ -6342,9 +6373,15 @@ arm_function_arg (cumulative_args_t pcum_v, machine_mode 
mode,
 static unsigned int
 arm_function_arg_boundary (machine_mode mode, const_tree type)
 {
-  return (ARM_DOUBLEWORD_ALIGN && arm_needs_doubleword_align (mode, type)
-         ? DOUBLEWORD_ALIGNMENT
-         : PARM_BOUNDARY);
+  if (!ARM_DOUBLEWORD_ALIGN)
+    return PARM_BOUNDARY;
+
+  int res = arm_needs_doubleword_align (mode, type);
+  if (res < 0 && warn_psabi)
+    inform (input_location, "parameter passing for argument of type %qT "
+           "will change in GCC 7.1", type);
+
+  return res != 0 ? DOUBLEWORD_ALIGNMENT : PARM_BOUNDARY;
 }
 
 static int
@@ -26402,8 +26439,15 @@ arm_setup_incoming_varargs (cumulative_args_t pcum_v,
   if (pcum->pcs_variant <= ARM_PCS_AAPCS_LOCAL)
     {
       nregs = pcum->aapcs_ncrn;
-      if ((nregs & 1) && arm_needs_doubleword_align (mode, type))
-       nregs++;
+      if (nregs & 1)
+       {
+         int res = arm_needs_doubleword_align (mode, type);
+         if (res < 0 && warn_psabi)
+           inform (input_location, "parameter passing for argument of "
+                   "type %qT will change in GCC 7.1", type);
+         if (res != 0)
+           nregs++;
+       }
     }
   else
     nregs = pcum->nregs;
diff --git gcc/testsuite/g++.dg/abi/pr77728-1.C 
gcc/testsuite/g++.dg/abi/pr77728-1.C
index e69de29..05f08c9 100644
--- gcc/testsuite/g++.dg/abi/pr77728-1.C
+++ gcc/testsuite/g++.dg/abi/pr77728-1.C
@@ -0,0 +1,171 @@
+// { dg-do compile { target arm_eabi } }
+// { dg-options "-Wpsabi" }
+
+#include <stdarg.h>
+
+template <int N>
+struct A { double p; };
+
+A<0> v;
+
+template <int N>
+struct B
+{
+  typedef A<N> T;
+  int i, j;
+};
+
+struct C : public B<0> {};
+struct D {};
+struct E : public D, C {};
+struct F : public B<1> {};
+struct G : public F { static double y; };
+struct H : public G {};
+struct I : public D { long long z; };
+struct J : public D { static double z; int i, j; };
+
+template <int N>
+struct K : public D { typedef A<N> T; int i, j; };
+
+struct L { static double h; int i, j; };
+
+int
+fn1 (int a, B<0> b)    // { dg-message "note: parameter passing for argument 
of type \[^\n\r]* will change in GCC 7\.1" }
+{
+  return a + b.i;
+}
+
+int
+fn2 (int a, B<1> b)
+{
+  return a + b.i;
+}
+
+int
+fn3 (int a, L b)       // { dg-message "note: parameter passing for argument 
of type \[^\n\r]* will change in GCC 7\.1" }
+{
+  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, ...)
+// { dg-message "note: parameter passing for argument of type \[^\n\r]* will 
change in GCC 7\.1" "" { target *-*-* } .-1 }
+{
+  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, ...)
+// { dg-message "note: parameter passing for argument of type \[^\n\r]* will 
change in GCC 7\.1" "" { target *-*-* } .-1 }
+{
+  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, ...)
+// { dg-message "note: parameter passing for argument of type \[^\n\r]* will 
change in GCC 7\.1" "" { target *-*-* } .-1 }
+{
+  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); // { dg-message "note: parameter passing for argument of type 
\[^\n\r]* will change in GCC 7\.1" }
+  fn2 (1, b1);
+  fn3 (1, l);  // { dg-message "note: parameter passing for argument of type 
\[^\n\r]* will change in GCC 7\.1" }
+  fn4 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, b0, 1, 2, 3, 4);
+  // { dg-message "note: parameter passing for argument of type \[^\n\r]* will 
change in GCC 7\.1" "" { target *-*-* } .-1 }
+  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);
+  // { dg-message "note: parameter passing for argument of type \[^\n\r]* will 
change in GCC 7\.1" "" { target *-*-* } .-1 }
+  fn11 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, k0, 1, 2, 3, 4);
+  // { dg-message "note: parameter passing for argument of type \[^\n\r]* will 
change in GCC 7\.1" "" { target *-*-* } .-1 }
+  fn12 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, k2, 1, 2, 3, 4);
+}

        Marek

Reply via email to