aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Earnshaw <rearnsha@arm.com>2019-01-22 14:03:22 +0000
committerRichard Earnshaw <rearnsha@gcc.gnu.org>2019-01-22 14:03:22 +0000
commit44a7251e1e97caf3b2315f20d48519ff8fced152 (patch)
tree89fa63d90fea36afcd59db535729092fc47a2e5d
parent50d6ec8cff304c6176b58fa1c44c17d057caa058 (diff)
downloadgcc-44a7251e1e97caf3b2315f20d48519ff8fced152.zip
gcc-44a7251e1e97caf3b2315f20d48519ff8fced152.tar.gz
gcc-44a7251e1e97caf3b2315f20d48519ff8fced152.tar.bz2
[arm] PR target/88469 fix incorrect argument passing with 64-bit bitfields
Unfortunately another PCS bug has come to light with the layout of structs whose alignment is dominated by a 64-bit bitfield element. Such fields in the type list appear to have alignment 1, but in reality, for the purposes of alignment of the underlying structure, the alignment is derived from the underlying bitfield's type. We've been getting this wrong since support for over-aligned record types was added several releases back. Worse still, the existing code may generate unaligned memory accesses that may fault on some versions of the architecture. I've taken the opportunity to add a few more tests that check the passing arguments with overalignment in the PCS. Looking through the existing tests it looked like they were really only checking self-consistency and not the precise location of the arguments. PR target/88469 gcc: * config/arm/arm.c (arm_needs_doubleword_align): Return 2 if a record's alignment is dominated by a bitfield with 64-bit aligned base type. (arm_function_arg): Emit a warning if the alignment has changed since earlier GCC releases. (arm_function_arg_boundary): Likewise. (arm_setup_incoming_varargs): Likewise. gcc/testsuite: * gcc.target/arm/aapcs/bitfield1.c: New test. * gcc.target/arm/aapcs/overalign_rec1.c: New test. * gcc.target/arm/aapcs/overalign_rec2.c: New test. * gcc.target/arm/aapcs/overalign_rec3.c: New test. From-SVN: r268151
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/config/arm/arm.c32
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/bitfield1.c24
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/overalign_rec1.c27
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/overalign_rec2.c25
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/overalign_rec3.c28
7 files changed, 150 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 4627efc..2409e7f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2019-01-22 Richard Earnshaw <rearnsha@arm.com>
+
+ PR target/88469
+ * config/arm/arm.c (arm_needs_doubleword_align): Return 2 if a record's
+ alignment is dominated by a bitfield with 64-bit aligned base type.
+ (arm_function_arg): Emit a warning if the alignment has changed since
+ earlier GCC releases.
+ (arm_function_arg_boundary): Likewise.
+ (arm_setup_incoming_varargs): Likewise.
+
2019-01-22 Richard Biener <rguenther@suse.de>
PR tree-optimization/88862
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 73cb8df..c6fbda2 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -6598,7 +6598,9 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
}
}
-/* Return 1 if double word alignment is required for argument passing.
+/* Return 2 if double word alignment is required for argument passing,
+ but wasn't required before the fix for PR88469.
+ 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
@@ -6618,7 +6620,8 @@ arm_needs_doubleword_align (machine_mode mode, const_tree type)
return TYPE_ALIGN (TREE_TYPE (type)) > PARM_BOUNDARY;
int ret = 0;
- /* Record/aggregate types: Use greatest member alignment of any member. */
+ int ret2 = 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)
{
@@ -6630,6 +6633,13 @@ arm_needs_doubleword_align (machine_mode mode, const_tree type)
Make sure we can warn about that with -Wpsabi. */
ret = -1;
}
+ else if (TREE_CODE (field) == FIELD_DECL
+ && DECL_BIT_FIELD (field)
+ && TYPE_ALIGN (DECL_BIT_FIELD_TYPE (field)) > PARM_BOUNDARY)
+ ret2 = 1;
+
+ if (ret2)
+ return 2;
return ret;
}
@@ -6695,7 +6705,12 @@ arm_function_arg (cumulative_args_t pcum_v, machine_mode mode,
inform (input_location, "parameter passing for argument of type "
"%qT changed in GCC 7.1", type);
else if (res > 0)
- pcum->nregs++;
+ {
+ pcum->nregs++;
+ if (res > 1 && warn_psabi)
+ inform (input_location, "parameter passing for argument of type "
+ "%qT changed in GCC 9.1", type);
+ }
}
/* Only allow splitting an arg between regs and memory if all preceding
@@ -6722,6 +6737,9 @@ arm_function_arg_boundary (machine_mode mode, const_tree type)
if (res < 0 && warn_psabi)
inform (input_location, "parameter passing for argument of type %qT "
"changed in GCC 7.1", type);
+ if (res > 1 && warn_psabi)
+ inform (input_location, "parameter passing for argument of type "
+ "%qT changed in GCC 9.1", type);
return res > 0 ? DOUBLEWORD_ALIGNMENT : PARM_BOUNDARY;
}
@@ -26999,7 +27017,13 @@ arm_setup_incoming_varargs (cumulative_args_t pcum_v,
inform (input_location, "parameter passing for argument of "
"type %qT changed in GCC 7.1", type);
else if (res > 0)
- nregs++;
+ {
+ nregs++;
+ if (res > 1 && warn_psabi)
+ inform (input_location,
+ "parameter passing for argument of type "
+ "%qT changed in GCC 9.1", type);
+ }
}
}
else
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1b61a3d..50705fe 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2019-01-22 Richard Earnshaw <rearnsha@arm.com>
+
+ PR target/88469
+ * gcc.target/arm/aapcs/bitfield1.c: New test.
+ * gcc.target/arm/aapcs/overalign_rec1.c: New test.
+ * gcc.target/arm/aapcs/overalign_rec2.c: New test.
+ * gcc.target/arm/aapcs/overalign_rec3.c: New test.
+
2019-01-22 Manfred Schwarb <manfred99@gmx.ch>
* gfortran.dg/array_function_5.f90: Fix a dg directive.
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/bitfield1.c b/gcc/testsuite/gcc.target/arm/aapcs/bitfield1.c
new file mode 100644
index 0000000..cac786e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/aapcs/bitfield1.c
@@ -0,0 +1,24 @@
+/* Test AAPCS layout (alignment). */
+
+/* { dg-do run { target arm_eabi } } */
+/* { dg-require-effective-target arm32 } */
+/* { dg-options "-O" } */
+
+#ifndef IN_FRAMEWORK
+#define TESTFILE "bitfield1.c"
+
+struct bf
+{
+ unsigned long long a: 61;
+ unsigned b: 3;
+} v = {1, 1};
+
+#include "abitest.h"
+#else
+ ARG (int, 7, R0)
+ ARG (int, 9, R1)
+ ARG (int, 11, R2)
+ /* Alignment of the bitfield type should affect alignment of the overall
+ type, so R3 not used. */
+ LAST_ARG (struct bf, v, STACK)
+#endif
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/overalign_rec1.c b/gcc/testsuite/gcc.target/arm/aapcs/overalign_rec1.c
new file mode 100644
index 0000000..1d33da4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/aapcs/overalign_rec1.c
@@ -0,0 +1,27 @@
+/* Test AAPCS layout (alignment). */
+
+/* { dg-do run { target arm_eabi } } */
+/* { dg-require-effective-target arm32 } */
+/* { dg-options "-O" } */
+
+#ifndef IN_FRAMEWORK
+#define TESTFILE "overalign_rec1.c"
+
+typedef struct __attribute__((aligned(8)))
+{
+ int a;
+ int b;
+} overaligned;
+
+overaligned v = {1, 3};
+overaligned w = {33, 99};
+
+#include "abitest.h"
+#else
+ ARG (int, 7, R0)
+ /* Overalignment is ignored for the purposes of parameter passing. */
+ ARG (overaligned, v, R1)
+ ARG (int, 11, R3)
+ ARG (int, 9, STACK)
+ LAST_ARG (overaligned, w, STACK+4)
+#endif
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/overalign_rec2.c b/gcc/testsuite/gcc.target/arm/aapcs/overalign_rec2.c
new file mode 100644
index 0000000..b19fa70
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/aapcs/overalign_rec2.c
@@ -0,0 +1,25 @@
+/* Test AAPCS layout (alignment). */
+
+/* { dg-do run { target arm_eabi } } */
+/* { dg-require-effective-target arm32 } */
+/* { dg-options "-O" } */
+
+#ifndef IN_FRAMEWORK
+#define TESTFILE "overalign_rec2.c"
+
+typedef struct
+{
+ int __attribute__((aligned(8))) a;
+ int b;
+} overaligned;
+
+overaligned v = {1, 3};
+overaligned w = {33, 99};
+
+#include "abitest.h"
+#else
+ ARG (int, 7, R0)
+ ARG (overaligned, v, R2)
+ ARG (int, 9, STACK)
+ LAST_ARG (overaligned, w, STACK+8)
+#endif
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/overalign_rec3.c b/gcc/testsuite/gcc.target/arm/aapcs/overalign_rec3.c
new file mode 100644
index 0000000..b1c793e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/aapcs/overalign_rec3.c
@@ -0,0 +1,28 @@
+/* Test AAPCS layout (alignment). */
+
+/* { dg-do run { target arm_eabi } } */
+/* { dg-require-effective-target arm32 } */
+/* { dg-options "-O" } */
+
+#ifndef IN_FRAMEWORK
+#define TESTFILE "overalign_rec3.c"
+
+typedef struct
+{
+ int __attribute__((aligned(16))) a;
+ int b;
+} overaligned;
+
+overaligned v = {1, 3};
+overaligned w = {33, 99};
+
+#include "abitest.h"
+#else
+ ARG (int, 7, R0)
+ /* Objects with alignment > 8 are passed with alignment 8. */
+ ARG (overaligned, v, R2)
+ ARG (int, 9, STACK+8)
+ ARG (int, 10, STACK+12)
+ ARG (int, 11, STACK+16)
+ LAST_ARG (overaligned, w, STACK+24)
+#endif