Part 2/2 of PR 102024 fix for MIPS. The ABI says:
"Regardless of the struct field structure, it is treated as a sequence of 64-bit chunks. If a chunk consists solely of a double float field (but not a double, which is part of a union), it is passed in a floating point register. Any other chunk is passed in an integer register." It's not clear that if a zero-width field is a part of any 64-bit chunk, and which 64-bit chunk it shall belong to when its on the boundary of two chunks. In previous GCC releases, the C++ FE removes all zero-width bit-fields but otherwise a zero-width field is considered a part of the next 64-bit chunk: struct A { /* first chunk */ double a; /* into FPR */ /* second chunk */ int : 0; double b; /* into GPR with current GCC trunk because "the chunk contains a bit-field" */ }; But clang does not account a zero-width bit-field on the boundary into any "64-bit chunk", so its behavior is same as the C++ FE of previous GCC releases. I think we should not make an arbitary assumption like "a zero-width bit-field is a part of the next chunk, but not a part of the previous chunk". So a consistent behavior is either consider it a part of both chunks, or consider it not a part of any chunks. As we are changing psABI anyway, it seems OK to be compatible with clang. gcc/ PR target/102024 * mips.cc (mips_function_arg): Ignore zero-width bit-fields, and inform if it causes a psABI change. gcc/testsuite/ PR target/102024 * gcc.target/mips/pr102024.c: New test. --- gcc/config/mips/mips.cc | 45 +++++++++++++++++++++--- gcc/testsuite/gcc.target/mips/pr102024.c | 20 +++++++++++ 2 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.target/mips/pr102024.c diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc index 3284cf71f6f..5d1637e7b2f 100644 --- a/gcc/config/mips/mips.cc +++ b/gcc/config/mips/mips.cc @@ -6042,11 +6042,26 @@ mips_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) for (i = 0; i < info.reg_words; i++) { rtx reg; + int has_zero_width_bf_abi_change = 0; for (; field; field = DECL_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL - && int_bit_position (field) >= bitpos) - break; + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + /* Ignore zero-width bit-fields. And, if the ignored + field is not from C++, it may be an ABI change. */ + if (DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD (field)) + continue; + if (integer_zerop (DECL_SIZE (field))) + { + has_zero_width_bf_abi_change = 1; + continue; + } + + if (int_bit_position (field) >= bitpos) + break; + } if (field && int_bit_position (field) == bitpos @@ -6054,7 +6069,29 @@ mips_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) && TYPE_PRECISION (TREE_TYPE (field)) == BITS_PER_WORD) reg = gen_rtx_REG (DFmode, FP_ARG_FIRST + info.reg_offset + i); else - reg = gen_rtx_REG (DImode, GP_ARG_FIRST + info.reg_offset + i); + { + reg = gen_rtx_REG (DImode, + GP_ARG_FIRST + info.reg_offset + i); + has_zero_width_bf_abi_change = 0; + } + + if (has_zero_width_bf_abi_change && warn_psabi) + { + static unsigned last_reported_type_uid; + unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (arg.type)); + if (uid != last_reported_type_uid) + { + static const char *url = + CHANGES_ROOT_URL + "gcc-12/changes.html#zero_width_bitfields"; + inform (input_location, + "the ABI for passing a value containing " + "zero-width bit-fields before an adjacent " + "64-bit floating-point field was retconned " + "in GCC %{12.1%}", url); + last_reported_type_uid = uid; + } + } XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (VOIDmode, reg, diff --git a/gcc/testsuite/gcc.target/mips/pr102024.c b/gcc/testsuite/gcc.target/mips/pr102024.c new file mode 100644 index 00000000000..c45d01315d6 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/pr102024.c @@ -0,0 +1,20 @@ +// PR target/102024 +// { dg-do compile } +// { dg-options "-mabi=64 -mhard-float" } +// { dg-final { scan-assembler "\\\$f12" } } + +struct foo +{ + int : 0; + double a; +}; + +extern void func(struct foo); + +void +pass_foo(void) +{ + struct foo test; + test.a = 114; + func(test); // { dg-message "the ABI for passing a value containing zero-width bit-fields before an adjacent 64-bit floating-point field was retconned in GCC 12.1" } +} -- 2.35.1