aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/i386/i386.c65
-rw-r--r--gcc/testsuite/g++.target/i386/pr102024.C12
-rw-r--r--gcc/testsuite/gcc.target/i386/pr102024.c12
3 files changed, 82 insertions, 7 deletions
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index c4ed82d..fb9b626 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2065,7 +2065,8 @@ merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
static int
classify_argument (machine_mode mode, const_tree type,
- enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset)
+ enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset,
+ int &zero_width_bitfields)
{
HOST_WIDE_INT bytes
= mode == BLKmode ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
@@ -2123,6 +2124,16 @@ classify_argument (machine_mode mode, const_tree type,
misaligned integers. */
if (DECL_BIT_FIELD (field))
{
+ if (integer_zerop (DECL_SIZE (field)))
+ {
+ if (DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD (field))
+ continue;
+ if (zero_width_bitfields != 2)
+ {
+ zero_width_bitfields = 1;
+ continue;
+ }
+ }
for (i = (int_bit_position (field)
+ (bit_offset % 64)) / 8 / 8;
i < ((int_bit_position (field) + (bit_offset % 64))
@@ -2160,7 +2171,8 @@ classify_argument (machine_mode mode, const_tree type,
num = classify_argument (TYPE_MODE (type), type,
subclasses,
(int_bit_position (field)
- + bit_offset) % 512);
+ + bit_offset) % 512,
+ zero_width_bitfields);
if (!num)
return 0;
pos = (int_bit_position (field)
@@ -2178,7 +2190,8 @@ classify_argument (machine_mode mode, const_tree type,
{
int num;
num = classify_argument (TYPE_MODE (TREE_TYPE (type)),
- TREE_TYPE (type), subclasses, bit_offset);
+ TREE_TYPE (type), subclasses, bit_offset,
+ zero_width_bitfields);
if (!num)
return 0;
@@ -2211,7 +2224,7 @@ classify_argument (machine_mode mode, const_tree type,
num = classify_argument (TYPE_MODE (TREE_TYPE (field)),
TREE_TYPE (field), subclasses,
- bit_offset);
+ bit_offset, zero_width_bitfields);
if (!num)
return 0;
for (i = 0; i < num && i < words; i++)
@@ -2231,7 +2244,7 @@ classify_argument (machine_mode mode, const_tree type,
X86_64_SSEUP_CLASS, everything should be passed in
memory. */
if (classes[0] != X86_64_SSE_CLASS)
- return 0;
+ return 0;
for (i = 1; i < words; i++)
if (classes[i] != X86_64_SSEUP_CLASS)
@@ -2257,8 +2270,8 @@ classify_argument (machine_mode mode, const_tree type,
classes[i] = X86_64_SSE_CLASS;
}
- /* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
- everything should be passed in memory. */
+ /* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
+ everything should be passed in memory. */
if (classes[i] == X86_64_X87UP_CLASS
&& (classes[i - 1] != X86_64_X87_CLASS))
{
@@ -2487,6 +2500,44 @@ classify_argument (machine_mode mode, const_tree type,
}
}
+/* Wrapper around classify_argument with the extra zero_width_bitfields
+ argument, to diagnose GCC 12.1 ABI differences for C. */
+
+static int
+classify_argument (machine_mode mode, const_tree type,
+ enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset)
+{
+ int zero_width_bitfields = 0;
+ static bool warned = false;
+ int n = classify_argument (mode, type, classes, bit_offset,
+ zero_width_bitfields);
+ if (!zero_width_bitfields || warned || !warn_psabi)
+ return n;
+ enum x86_64_reg_class alt_classes[MAX_CLASSES];
+ zero_width_bitfields = 2;
+ if (classify_argument (mode, type, alt_classes, bit_offset,
+ zero_width_bitfields) != n)
+ zero_width_bitfields = 3;
+ else
+ for (int i = 0; i < n; i++)
+ if (classes[i] != alt_classes[i])
+ {
+ zero_width_bitfields = 3;
+ break;
+ }
+ if (zero_width_bitfields == 3)
+ {
+ warned = true;
+ const char *url
+ = CHANGES_ROOT_URL "gcc-12/changes.html#zero_width_bitfields";
+
+ inform (input_location,
+ "the ABI of passing C structures with zero-width bit-fields"
+ " has changed in GCC %{12.1%}", url);
+ }
+ return n;
+}
+
/* Examine the argument and return set number of register required in each
class. Return true iff parameter should be passed in memory. */
diff --git a/gcc/testsuite/g++.target/i386/pr102024.C b/gcc/testsuite/g++.target/i386/pr102024.C
new file mode 100644
index 0000000..0fbc026
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr102024.C
@@ -0,0 +1,12 @@
+// PR target/102024
+// { dg-do compile }
+
+struct S { float a; int : 0; float b; };
+void foo (struct S x);
+
+void
+bar (void)
+{
+ struct S s = { 0.0f, 0.0f };
+ foo (s); // { dg-bogus "the ABI of passing C structures with zero-width bit-fields has changed in GCC 12.1" }
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr102024.c b/gcc/testsuite/gcc.target/i386/pr102024.c
new file mode 100644
index 0000000..703195b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr102024.c
@@ -0,0 +1,12 @@
+/* PR target/102024 */
+/* { dg-do compile } */
+
+struct S { float a; int : 0; float b; };
+void foo (struct S x);
+
+void
+bar (void)
+{
+ struct S s = { 0.0f, 0.0f };
+ foo (s); /* { dg-message "the ABI of passing C structures with zero-width bit-fields has changed in GCC 12.1" "" { target { ! ia32 } } } */
+}