diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/i386/i386.c | 65 | ||||
-rw-r--r-- | gcc/testsuite/g++.target/i386/pr102024.C | 12 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr102024.c | 12 |
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 } } } */ +} |