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


Reply via email to