]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: Fix the ABI of empty unions and zero length array in struct
authorKito Cheng <kito.cheng@sifive.com>
Wed, 22 Oct 2025 09:06:03 +0000 (17:06 +0800)
committerKito Cheng <kito.cheng@sifive.com>
Mon, 3 Nov 2025 10:08:33 +0000 (18:08 +0800)
The RISC-V ABI currently defines that empty unions and zero length array
in struct should be ignored, but the implementation in GCC is not
correct.

e.g. for the following code:
```
struct S2eu_2f {
    union{} e1;
    float f;
    float g;
};
```

The RISC-V ABI defines that the layout of S2eu_2f should be equivalent
to:
```
struct S2eu_2f {
float f;
float g;
};
```

However, the current GCC implementation passes S2eu_2f in a0 (lp64d)
rather than fa0 and fa1 (lp64d).

Also for the following code:
```
struct S0ae_2f {
    struct{} e1[0];
    float f;
    float g;
};
```
The RISC-V ABI defines that the layout of S0ae_2f should be equivalent
to:
```
struct S0ae_2f {
float f;
float g;
};
```

And again, the current GCC implementation passes S0ae_2f in a0 (lp64d)
rather than fa0 and fa1 (lp64d).

This patch fixes the issue by updating the relevant functions to correctly
handle empty unions, also we have implemented the ABI change warning to
notify user that the ABI of empty unions and zero length array in struct
has been changed/fixed.

Generally ABI should not be changed, but the psABI is defined there for
long time and clang/LLVM has already implemented it correctly, so we
decide to fix it in GCC as well to maintain compatibility, and another
reason to fix that in GCC is zero length array and empty union in struct
should be rarely used in practice, so the impact should be limited.

References:
[1] https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/464

gcc/ChangeLog:

* config/riscv/riscv.cc (riscv_flatten_aggregate_field): Skip
empty unions and zero-length arrays when flattening aggregate
fields for ABI classification.
(riscv_pass_aggregate_in_fpr_pair_p): Refactor to use separate
field parsing and emit ABI change warning for affected types.
(riscv_pass_aggregate_in_fpr_and_gpr_p): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/abi/param2.C: Add -Wno-psabi option for RISC-V.
* g++.target/riscv/abi/empty-struct+union-1.cc: New test.
* g++.target/riscv/abi/empty-struct+union-2.cc: New test.
* g++.target/riscv/abi/empty-struct+union-3.cc: New test.
* g++.target/riscv/abi/empty-struct+union-4.cc: New test.
* g++.target/riscv/abi/empty-struct-1.cc: New test.
* g++.target/riscv/abi/empty-struct-2.cc: New test.
* g++.target/riscv/abi/empty-struct-3.cc: New test.
* g++.target/riscv/abi/empty-struct-4.cc: New test.
* g++.target/riscv/abi/empty-struct-5.cc: New test.
* g++.target/riscv/abi/empty-struct-6.cc: New test.
* g++.target/riscv/abi/empty-struct-7.cc: New test.
* g++.target/riscv/abi/empty-struct-8.cc: New test.
* g++.target/riscv/abi/empty-struct-9.cc: New test.
* g++.target/riscv/abi/empty-struct-10.cc: New test.
* g++.target/riscv/abi/empty-struct-11.cc: New test.
* g++.target/riscv/abi/empty-struct-12.cc: New test.
* g++.target/riscv/abi/empty-union-1.cc: New test.
* g++.target/riscv/abi/empty-union-2.cc: New test.
* g++.target/riscv/abi/empty-union-3.cc: New test.
* g++.target/riscv/abi/empty-union-4.cc: New test.
* g++.target/riscv/riscv.exp: Add abi subdirectory.
* gcc.dg/compat/pr83487-1_x.c: Add -Wno-psabi option for RISC-V.
* gcc.dg/compat/pr83487-1_y.c: Likewise.
* gcc.dg/compat/pr83487-2_x.c: Likewise.
* gcc.dg/compat/pr83487-2_y.c: Likewise.
* gcc.dg/torture/pr28814.c: Likewise.
* gcc.target/riscv/abi/empty-struct+union-1.c: New test.
* gcc.target/riscv/abi/empty-struct+union-2.c: New test.
* gcc.target/riscv/abi/empty-struct+union-3.c: New test.
* gcc.target/riscv/abi/empty-struct+union-4.c: New test.
* gcc.target/riscv/abi/empty-struct-1.c: New test.
* gcc.target/riscv/abi/empty-struct-2.c: New test.
* gcc.target/riscv/abi/empty-struct-3.c: New test.
* gcc.target/riscv/abi/empty-struct-4.c: New test.
* gcc.target/riscv/abi/empty-struct-5.c: New test.
* gcc.target/riscv/abi/empty-struct-6.c: New test.
* gcc.target/riscv/abi/empty-struct-7.c: New test.
* gcc.target/riscv/abi/empty-struct-8.c: New test.
* gcc.target/riscv/abi/empty-struct-9.c: New test.
* gcc.target/riscv/abi/empty-struct-10.c: New test.
* gcc.target/riscv/abi/empty-struct-11.c: New test.
* gcc.target/riscv/abi/empty-struct-12.c: New test.
* gcc.target/riscv/abi/empty-union-1.c: New test.
* gcc.target/riscv/abi/empty-union-2.c: New test.
* gcc.target/riscv/abi/empty-union-3.c: New test.
* gcc.target/riscv/abi/empty-union-4.c: New test.
* gcc.target/riscv/riscv.exp: Add abi subdirectory.

49 files changed:
gcc/config/riscv/riscv.cc
gcc/testsuite/g++.dg/abi/param2.C
gcc/testsuite/g++.target/riscv/abi/empty-struct+union-1.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct+union-2.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct+union-3.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct+union-4.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct-1.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct-10.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct-11.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct-12.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct-2.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct-3.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct-4.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct-5.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct-6.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct-7.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct-8.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-struct-9.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-union-1.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-union-2.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-union-3.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/abi/empty-union-4.cc [new file with mode: 0644]
gcc/testsuite/g++.target/riscv/riscv.exp
gcc/testsuite/gcc.dg/compat/pr83487-1_x.c
gcc/testsuite/gcc.dg/compat/pr83487-1_y.c
gcc/testsuite/gcc.dg/compat/pr83487-2_x.c
gcc/testsuite/gcc.dg/compat/pr83487-2_y.c
gcc/testsuite/gcc.dg/torture/pr28814.c
gcc/testsuite/gcc.target/riscv/abi/empty-struct+union-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct+union-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct+union-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct+union-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct-10.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct-11.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct-12.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct-8.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-struct-9.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-union-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-union-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-union-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/abi/empty-union-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/riscv.exp

index e978f9209ed7277975a514d767c0c90088c3d87d..e186c6a99e9de9cfd8fd7f9312b8172d28570ee9 100644 (file)
@@ -5886,11 +5886,47 @@ static int
 riscv_flatten_aggregate_field (const_tree type, riscv_aggregate_field *fields,
                               int n, HOST_WIDE_INT offset,
                               bool ignore_zero_width_bit_field_p,
+                              bool ignore_empty_union_and_zero_len_array_p,
                               bool vls_p = false, unsigned abi_vlen = 0)
 {
   int max_aggregate_field = vls_p ? 8 : 2;
   switch (TREE_CODE (type))
     {
+    case UNION_TYPE:
+      {
+       if (!ignore_empty_union_and_zero_len_array_p)
+         return -1;
+       /* Empty union should ignore.  */
+       if (TYPE_SIZE (type) == NULL || integer_zerop (TYPE_SIZE (type)))
+         return n;
+       /* Or all union member are empty union or empty struct. */
+       for (tree f = TYPE_FIELDS (type); f; f = DECL_CHAIN (f))
+         {
+           if (TREE_CODE (f) != FIELD_DECL)
+             continue;
+           int m;
+           HOST_WIDE_INT pos = offset + int_byte_position (f);
+           switch (TREE_CODE (TREE_TYPE (f)))
+             {
+             case ARRAY_TYPE:
+             case UNION_TYPE:
+             case RECORD_TYPE:
+               m = riscv_flatten_aggregate_field (
+                     TREE_TYPE (f), fields, n, pos,
+                     ignore_zero_width_bit_field_p,
+                     true);
+               /* Any non-empty struct/union/array will stop the flatten.  */
+               if (m != n)
+                 return -1;
+               break;
+             default:
+               /* Any member are not struct, union or array will stop the
+                  flatten.  */
+             return -1;
+           }
+       }
+      return n;
+      }
     case RECORD_TYPE:
      /* Can't handle incomplete types nor sizes that are not fixed.  */
      if (!COMPLETE_TYPE_P (type)
@@ -5916,7 +5952,9 @@ riscv_flatten_aggregate_field (const_tree type, riscv_aggregate_field *fields,
              {
                HOST_WIDE_INT pos = offset + int_byte_position (f);
                n = riscv_flatten_aggregate_field (
-                 TREE_TYPE (f), fields, n, pos, ignore_zero_width_bit_field_p,
+                 TREE_TYPE (f), fields, n, pos,
+                 ignore_zero_width_bit_field_p,
+                 ignore_empty_union_and_zero_len_array_p,
                  vls_p, abi_vlen);
              }
            if (n < 0)
@@ -5930,14 +5968,20 @@ riscv_flatten_aggregate_field (const_tree type, riscv_aggregate_field *fields,
        riscv_aggregate_field subfields[8];
        tree index = TYPE_DOMAIN (type);
        tree elt_size = TYPE_SIZE_UNIT (TREE_TYPE (type));
+
+       /* Array with zero size member should be ignored.  */
+       if (ignore_empty_union_and_zero_len_array_p && integer_zerop (elt_size))
+         return n;
+
        int n_subfields
-         = riscv_flatten_aggregate_field (TREE_TYPE (type), subfields, 0,
-                                          offset,
-                                          ignore_zero_width_bit_field_p, vls_p,
-                                          abi_vlen);
+         = riscv_flatten_aggregate_field (
+             TREE_TYPE (type), subfields, 0,
+             offset,
+             ignore_zero_width_bit_field_p,
+             ignore_empty_union_and_zero_len_array_p,
+             vls_p, abi_vlen);
        /* Can't handle incomplete types nor sizes that are not fixed.  */
-       if (n_subfields <= 0
-           || !COMPLETE_TYPE_P (type)
+       if (!COMPLETE_TYPE_P (type)
            || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
            || !index
            || !TYPE_MAX_VALUE (index)
@@ -5947,6 +5991,15 @@ riscv_flatten_aggregate_field (const_tree type, riscv_aggregate_field *fields,
            || !tree_fits_uhwi_p (elt_size))
          return -1;
 
+       /* Zero-length array with empty union/struct should be ignored.  */
+       if (ignore_empty_union_and_zero_len_array_p && n_subfields == 0
+           && integer_zerop (TYPE_MIN_VALUE (index))
+           && integer_all_onesp (TYPE_MAX_VALUE (index)))
+         return n;
+
+       if (n_subfields <= 0)
+         return -1;
+
        n_elts = 1 + tree_to_uhwi (TYPE_MAX_VALUE (index))
                   - tree_to_uhwi (TYPE_MIN_VALUE (index));
        gcc_assert (n_elts >= 0);
@@ -6026,14 +6079,25 @@ static int
 riscv_flatten_aggregate_argument (const_tree type,
                                  riscv_aggregate_field *fields,
                                  bool ignore_zero_width_bit_field_p,
+                                 bool ignore_empty_union_and_zero_len_array_p,
                                  bool vls_p = false, unsigned abi_vlen = 0)
 {
   if (!type || TREE_CODE (type) != RECORD_TYPE)
     return -1;
 
   return riscv_flatten_aggregate_field (type, fields, 0, 0,
-                                       ignore_zero_width_bit_field_p, vls_p,
-                                       abi_vlen);
+                                       ignore_zero_width_bit_field_p,
+                                       ignore_empty_union_and_zero_len_array_p,
+                                       vls_p, abi_vlen);
+}
+
+static bool
+riscv_any_non_float_type_field (riscv_aggregate_field *fields, int n)
+{
+  for (int i = 0; i < n; i++)
+    if (!SCALAR_FLOAT_TYPE_P (fields[i].type))
+      return true;
+  return false;
 }
 
 /* See whether TYPE is a record whose fields should be returned in one or
@@ -6044,24 +6108,18 @@ riscv_pass_aggregate_in_fpr_pair_p (const_tree type,
                                    riscv_aggregate_field fields[2])
 {
   static int warned = 0;
+  if (!type)
+    return 0;
 
   /* This is the old ABI, which differs for C++ and C.  */
-  int n_old = riscv_flatten_aggregate_argument (type, fields, false);
-  for (int i = 0; i < n_old; i++)
-    if (!SCALAR_FLOAT_TYPE_P (fields[i].type))
-      {
-       n_old = -1;
-       break;
-      }
+  int n_old = riscv_flatten_aggregate_argument (type, fields, false, false);
+  if (riscv_any_non_float_type_field (fields, n_old))
+    n_old = -1;
 
   /* This is the new ABI, which is the same for C++ and C.  */
-  int n_new = riscv_flatten_aggregate_argument (type, fields, true);
-  for (int i = 0; i < n_new; i++)
-    if (!SCALAR_FLOAT_TYPE_P (fields[i].type))
-      {
-       n_new = -1;
-       break;
-      }
+  int n_new = riscv_flatten_aggregate_argument (type, fields, true, false);
+  if (riscv_any_non_float_type_field (fields, n_new))
+    n_new = -1;
 
   if ((n_old != n_new) && (warned == 0))
     {
@@ -6070,7 +6128,58 @@ riscv_pass_aggregate_in_fpr_pair_p (const_tree type,
       warned = 1;
     }
 
-  return n_new > 0 ? n_new : 0;
+  /* ABI with fixing flatten empty union.  */
+  int n_new2 = riscv_flatten_aggregate_argument (type, fields, true, true);
+  if (riscv_any_non_float_type_field (fields, n_new2))
+    n_new2 = -1;
+
+  bool num_fpr = riscv_pass_mode_in_fpr_p (TYPE_MODE (type));
+
+  /* There is a special case for struct with zero length array with struct and a
+     floating point member.
+     e.g:
+     struct S0ae_1f {
+       struct {
+       } e1[0];
+       float f;
+     };
+
+     This case we will got 1, but legacy ABI will got -1, however legacy ABI
+     will got 1 in later logic, so we should consider this case as compatible.
+  */
+  bool compatible_p = n_new2 == 1 && n_new == -1 && num_fpr == 1;
+
+  if ((n_new2 != n_new)
+      && !compatible_p && (warned == 0))
+    {
+      warning (OPT_Wpsabi, "ABI for flattened empty union and zero "
+              "length array changed in GCC 16");
+      warned = 1;
+    }
+
+  return n_new2 > 0 ? n_new2 : 0;
+}
+
+struct riscv_aggregate_field_info_t {
+  unsigned num_fpr;
+  unsigned num_gpr;
+
+  riscv_aggregate_field_info_t ()
+    : num_fpr (0), num_gpr (0)
+  {}
+};
+
+static riscv_aggregate_field_info_t
+riscv_parse_aggregate_field_info (riscv_aggregate_field *fields, int n)
+{
+  riscv_aggregate_field_info_t info;
+  for (int i = 0; i < n; i++)
+    {
+      info.num_fpr += SCALAR_FLOAT_TYPE_P (fields[i].type);
+      info.num_gpr += INTEGRAL_TYPE_P (fields[i].type);
+    }
+
+  return info;
 }
 
 /* See whether TYPE is a record whose fields should be returned in one or
@@ -6084,35 +6193,48 @@ riscv_pass_aggregate_in_fpr_and_gpr_p (const_tree type,
   static int warned = 0;
 
   /* This is the old ABI, which differs for C++ and C.  */
-  unsigned num_int_old = 0, num_float_old = 0;
-  int n_old = riscv_flatten_aggregate_argument (type, fields, false);
-  for (int i = 0; i < n_old; i++)
-    {
-      num_float_old += SCALAR_FLOAT_TYPE_P (fields[i].type);
-      num_int_old += INTEGRAL_TYPE_P (fields[i].type);
-    }
+  int n_old = riscv_flatten_aggregate_argument (type, fields, false, false);
+  riscv_aggregate_field_info_t old_info;
+  old_info = riscv_parse_aggregate_field_info (fields, n_old);
 
   /* This is the new ABI, which is the same for C++ and C.  */
-  unsigned num_int_new = 0, num_float_new = 0;
-  int n_new = riscv_flatten_aggregate_argument (type, fields, true);
-  for (int i = 0; i < n_new; i++)
-    {
-      num_float_new += SCALAR_FLOAT_TYPE_P (fields[i].type);
-      num_int_new += INTEGRAL_TYPE_P (fields[i].type);
-    }
+  int n_new = riscv_flatten_aggregate_argument (type, fields, true, false);
+  riscv_aggregate_field_info_t new_info;
+  new_info = riscv_parse_aggregate_field_info (fields, n_new);
 
-  if (((num_int_old == 1 && num_float_old == 1
-       && (num_int_old != num_int_new || num_float_old != num_float_new))
-       || (num_int_new == 1 && num_float_new == 1
-          && (num_int_old != num_int_new || num_float_old != num_float_new)))
-      && (warned == 0))
+  bool values_changed = old_info.num_fpr != new_info.num_fpr
+                       || old_info.num_gpr != new_info.num_gpr;
+  bool old_is_one_one = old_info.num_fpr == 1 && old_info.num_gpr == 1;
+  bool new_is_one_one = new_info.num_fpr == 1 && new_info.num_gpr == 1;
+
+  if (values_changed
+      && (old_is_one_one || new_is_one_one)
+      && warned == 0)
     {
       warning (OPT_Wpsabi, "ABI for flattened struct with zero-length "
                           "bit-fields changed in GCC 10");
       warned = 1;
     }
 
-  return num_int_new == 1 && num_float_new == 1;
+  /* ABI with fixing flatten empty union.  */
+  int n_new2 = riscv_flatten_aggregate_argument (type, fields, true, true);
+  riscv_aggregate_field_info_t new2_info;
+  new2_info = riscv_parse_aggregate_field_info (fields, n_new2);
+
+  values_changed = new_info.num_fpr != new2_info.num_fpr
+                  || new_info.num_gpr != new2_info.num_gpr;
+  bool new2_is_one_one = new2_info.num_fpr == 1 && new2_info.num_gpr == 1;
+
+  if (values_changed
+      && (new_is_one_one || new2_is_one_one)
+      && warned == 0)
+    {
+      warning (OPT_Wpsabi, "ABI for flattened empty union and zero "
+              "length array changed in GCC 16");
+      warned = 1;
+    }
+
+  return new2_is_one_one;
 }
 
 /* Return the representation of an argument passed or returned in an FPR
@@ -6466,7 +6588,7 @@ riscv_pass_aggregate_in_vr (struct riscv_arg_info *info,
   riscv_aggregate_field fields[8];
   unsigned int abi_vlen = riscv_get_cc_abi_vlen (cum->variant_cc);
   int i;
-  int n = riscv_flatten_aggregate_argument (type, fields, true,
+  int n = riscv_flatten_aggregate_argument (type, fields, true, true,
                                            /* vls_p */ true, abi_vlen);
 
   if (n == -1)
index d28387ab3ccfb7ea67be0fb4ebe6e0b3f6757978..4752717bfe0d8946bfa9d4b03bd0779a09757a9f 100644 (file)
@@ -1,7 +1,7 @@
 // PR target/20795
 // Test passing aligned empty aggregate
 // { dg-do compile }
-// { dg-options "-Wno-psabi" { target { { i?86-*-* x86_64-*-* } && ilp32 } } }
+// { dg-options "-Wno-psabi" { target { { { i?86-*-* x86_64-*-* } && ilp32 } || { riscv*-*-* } } } }
 
 struct S { union {} a; } __attribute__((aligned));
 
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct+union-1.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct+union-1.cc
new file mode 100644 (file)
index 0000000..69a1350
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Su2e_1f {
+  union {
+    struct {
+    } e1, e2;
+  } u;
+  float f;
+};
+struct Su2e_1f echo_Su2e_1f(int i, float f, struct Su2e_1f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct+union-2.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct+union-2.cc
new file mode 100644 (file)
index 0000000..763477c
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Su2e_2f {
+  union {
+    struct {
+    } e1, e2;
+  } u;
+  float f;
+  float g;
+};
+struct Su2e_2f echo_Su2e_2f(int i, float f, struct Su2e_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+8 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+8 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct+union-3.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct+union-3.cc
new file mode 100644 (file)
index 0000000..5c9ce31
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Smu2e_1f {
+  union {
+    struct {
+    } e1, e2;
+  } u1;
+  struct {
+    float f;
+    union {
+      struct {
+      } e1, e2;
+    } u;
+  } ue;
+  union {
+    struct {
+    } e1, e2;
+  } u2;
+};
+struct Smu2e_1f echo_Smu2e_1f(int i, float f, struct Smu2e_1f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct+union-4.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct+union-4.cc
new file mode 100644 (file)
index 0000000..ecefc94
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Smu2e_2f {
+  union {
+    struct {
+    } e1, e2;
+  } u1;
+  struct {
+    float f;
+    float g;
+    union {
+      struct {
+      } e1, e2;
+    } u;
+  } ue;
+  union {
+    struct {
+    } e1, e2;
+  } u2;
+};
+struct Smu2e_2f echo_Smu2e_2f(int i, float f, struct Smu2e_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+8 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+8 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct-1.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct-1.cc
new file mode 100644 (file)
index 0000000..81f563e
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Se_1f {
+  struct {
+  } e1;
+  float f;
+};
+struct Se_1f echo_Se_1f(int i, float f, struct Se_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct-10.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct-10.cc
new file mode 100644 (file)
index 0000000..167f54c
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct S1ae_2f {
+  struct {
+  } e1[1];
+  float f;
+  float g;
+};
+struct S1ae_2f echo_S1ae_2f(int i, float f, struct S1ae_2f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(mem.*:DI .*\[.* s\+0 .*\]\)[[:space:]]+\(reg.*:DI \d+ a1\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(mem.*:DI .*\[.* s\+8 .*\]\)[[:space:]]+\(reg.*:DI \d+ a2\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:DI \d+ a0 .*\)[[:space:]]+\(subreg:DI \(reg.*:TI \d+ \[ <retval> \]\) 0\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:DI \d+ a1 .*\)[[:space:]]+\(subreg:DI \(reg.*:TI \d+ \[ <retval> \]\) 8\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct-11.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct-11.cc
new file mode 100644 (file)
index 0000000..057994d
--- /dev/null
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Sm1ae_1f {
+  struct {
+  } e1[1];
+  struct {
+    float f;
+    struct {
+    } e[1];
+  } fe;
+  struct {
+  } e2[1];
+};
+struct Sm1ae_1f echo_Sm1ae_1f(int i, float f, struct Sm1ae_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(mem.*:DI .*\[.* s\+0 .*\]\)[[:space:]]+\(reg.*:DI \d+ a1\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(mem.*:DI .*\[.* s\+8 .*\]\)[[:space:]]+\(reg.*:DI \d+ a2\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:DI \d+ a0 .*\)[[:space:]]+\(subreg:DI \(reg.*:TI \d+ \[ <retval> \]\) 0\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:DI \d+ a1 .*\)[[:space:]]+\(subreg:DI \(reg.*:TI \d+ \[ <retval> \]\) 8\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct-12.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct-12.cc
new file mode 100644 (file)
index 0000000..d8f0154
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Sm1ae_2f {
+  struct {
+  } e1[1];
+  struct {
+    float f;
+    float g;
+    struct {
+    } e[1];
+  } fe;
+  struct {
+  } e2[1];
+};
+struct Sm1ae_2f echo_Sm1ae_2f(int i, float f, struct Sm1ae_2f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\[.* \.result_ptr\+0 .*\]} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct-2.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct-2.cc
new file mode 100644 (file)
index 0000000..9d5669c
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Se_2f {
+  struct {
+  } e1;
+  float f;
+  float g;
+};
+struct Se_2f echo_Se_2f(int i, float f, struct Se_2f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+8 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+8 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct-3.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct-3.cc
new file mode 100644 (file)
index 0000000..7b9e71a
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Sme_1f {
+  struct {
+  } e1;
+  struct {
+    float f;
+    struct {
+    } e;
+  } fe;
+  struct {
+  } e2;
+};
+struct Sme_1f echo_Sme_1f(int i, float f, struct Sme_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct-4.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct-4.cc
new file mode 100644 (file)
index 0000000..aaec892
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Sme_2f {
+  struct {
+  } e1;
+  struct {
+    float f;
+    float g;
+    struct {
+    } e;
+  } fe;
+  struct {
+  } e2;
+};
+struct Sme_2f echo_Sme_2f(int i, float f, struct Sme_2f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+8 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+8 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct-5.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct-5.cc
new file mode 100644 (file)
index 0000000..0ae1e41
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct S0ae_1f {
+  struct {
+  } e1[0];
+  float f;
+};
+struct S0ae_1f echo_S0ae_1f(int i, float f, struct S0ae_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct-6.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct-6.cc
new file mode 100644 (file)
index 0000000..d3d0b65
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct S0ae_2f {
+  struct {
+  } e1[0];
+  float f;
+  float g;
+};
+struct S0ae_2f echo_S0ae_2f(int i, float f, struct S0ae_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct-7.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct-7.cc
new file mode 100644 (file)
index 0000000..9eae13d
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Sm0ae_1f {
+  struct {
+  } e1[0];
+  struct {
+    float f;
+    struct {
+    } e[0];
+  } fe;
+  struct {
+  } e2[0];
+};
+struct Sm0ae_1f echo_Sm0ae_1f(int i, float f, struct Sm0ae_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct-8.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct-8.cc
new file mode 100644 (file)
index 0000000..e7c81f4
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Sm0ae_2f {
+  struct {
+  } e1[0];
+  struct {
+    float f;
+    float g;
+    struct {
+    } e[0];
+  } fe;
+  struct {
+  } e2[0];
+};
+struct Sm0ae_2f echo_Sm0ae_2f(int i, float f, struct Sm0ae_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-struct-9.cc b/gcc/testsuite/g++.target/riscv/abi/empty-struct-9.cc
new file mode 100644 (file)
index 0000000..d36d50b
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct S1ae_1f {
+  struct {
+  } e1[1];
+  float f;
+};
+struct S1ae_1f echo_S1ae_1f(int i, float f, struct S1ae_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(mem.*:DI .*\[.* s\+0 .*\]\)[[:space:]]+\(reg.*:DI \d+ a1\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:DI \d+ a0\)[[:space:]]+\(reg.*:DI \d+ \[ <retval> \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-union-1.cc b/gcc/testsuite/g++.target/riscv/abi/empty-union-1.cc
new file mode 100644 (file)
index 0000000..e3c2376
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Seu_1f {
+  union {
+  } e1;
+  float f;
+};
+struct Seu_1f echo_Seu_1f(int i, float f, struct Seu_1f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-union-2.cc b/gcc/testsuite/g++.target/riscv/abi/empty-union-2.cc
new file mode 100644 (file)
index 0000000..d7b7d05
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct S2eu_2f {
+  union {
+  } e1;
+  float f;
+  float g;
+};
+struct S2eu_2f echo_S2eu_2f(int i, float f, struct S2eu_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+8 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+8 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-union-3.cc b/gcc/testsuite/g++.target/riscv/abi/empty-union-3.cc
new file mode 100644 (file)
index 0000000..f12af7a
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Smeu_1f {
+  union {
+  } e1;
+  struct {
+    float f;
+    union {
+    } e;
+  } fe;
+  union {
+  } e2;
+};
+struct Smeu_1f echo_Smeu_1f(int i, float f, struct Smeu_1f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/g++.target/riscv/abi/empty-union-4.cc b/gcc/testsuite/g++.target/riscv/abi/empty-union-4.cc
new file mode 100644 (file)
index 0000000..ab8c56e
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Smeu_2f {
+  union {
+  } e1;
+  struct {
+    float f;
+    float g;
+    union {
+    } e;
+  } fe;
+  union {
+  } e2;
+};
+struct Smeu_2f echo_Smeu_2f(int i, float f, struct Smeu_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+8 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+8 \]\)\)} "expand" } } */
index f58e6884ba884bd38057e0ca52e4af9389a37d5d..e268bd81412939fd5db351cf24b16ee6ed70d6a2 100644 (file)
@@ -29,6 +29,7 @@ dg-init
 
 # Main loop.
 dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" ""
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/abi/*.cc]] "" ""
 
 # All done.
 dg-finish
index b5b208f7d93e3e09a4dd2cefd89dfee7acdd3745..22b71cf185629b823cb48c746ba67a2e1d2130bd 100644 (file)
@@ -1,4 +1,5 @@
 /* { dg-options "-fno-common" { target { hppa*-*-hpux* } } } */
+/* { dg-options "-Wno-psabi" { target { riscv*-*-* } } } */
 #include "pr83487-1.h"
 
 extern
index ad336dd99367c34c4fcd902822a59794183550f1..cf275d8f33cf7dc5505d66e2a8c6d2fbe1826efc 100644 (file)
@@ -1,4 +1,5 @@
 /* { dg-options "-fno-common" { target { hppa*-*-hpux* } } } */
+/* { dg-options "-Wno-psabi" { target { riscv*-*-* } } } */
 #include "pr83487-1.h"
 
 struct A a;
index 71031948c78601cb6245cfd1166dd27d5e1d6a58..399ac86f1d322297e5416eacc9ea97fa61169631 100644 (file)
@@ -1,3 +1,4 @@
 /* { dg-options "-fno-common" { target { hppa*-*-hpux* } } } */
+/* { dg-options "-Wno-psabi" { target { riscv*-*-* } } } */
 #define PR83487_LARGE
 #include "pr83487-1_x.c"
index e1767839418c41e08a307c316fe0ace7e8f6136d..dc6c1f836189e0debed99a5ee3bb334ecb222ce5 100644 (file)
@@ -1,3 +1,4 @@
 /* { dg-options "-fno-common" { target { hppa*-*-hpux* } } } */
+/* { dg-options "-Wno-psabi" { target { riscv*-*-* } } } */
 #define PR83487_LARGE
 #include "pr83487-1_y.c"
index cf641ca90582edae519c5e4c662cd18be85eefc5..e835ff5520b4f61f06b7d580be20dd5300b2528d 100644 (file)
@@ -1,4 +1,5 @@
 /* { dg-do compile { target { ilp32 || lp64 } } } */
+/* { dg-options "-Wno-psabi" { target { riscv*-*-* } } } */
 
 struct w49
 {
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct+union-1.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct+union-1.c
new file mode 100644 (file)
index 0000000..4cea38e
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Su2e_1f {
+  union {
+    struct {
+    } e1, e2;
+  } u;
+  float f;
+};
+struct Su2e_1f echo_Su2e_1f(int i, float f, struct Su2e_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct+union-2.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct+union-2.c
new file mode 100644 (file)
index 0000000..e7271e2
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Su2e_2f {
+  union {
+    struct {
+    } e1, e2;
+  } u;
+  float f;
+  float g;
+};
+struct Su2e_2f echo_Su2e_2f(int i, float f, struct Su2e_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct+union-3.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct+union-3.c
new file mode 100644 (file)
index 0000000..9743d4a
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Smu2e_1f {
+  union {
+    struct {
+    } e1, e2;
+  } u1;
+  struct {
+    float f;
+    union {
+      struct {
+      } e1, e2;
+    } u;
+  } ue;
+  union {
+    struct {
+    } e1, e2;
+  } u2;
+};
+struct Smu2e_1f echo_Smu2e_1f(int i, float f, struct Smu2e_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct+union-4.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct+union-4.c
new file mode 100644 (file)
index 0000000..081ea68
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Smu2e_2f {
+  union {
+    struct {
+    } e1, e2;
+  } u1;
+  struct {
+    float f;
+    float g;
+    union {
+      struct {
+      } e1, e2;
+    } u;
+  } ue;
+  union {
+    struct {
+    } e1, e2;
+  } u2;
+};
+struct Smu2e_2f echo_Smu2e_2f(int i, float f, struct Smu2e_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct-1.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct-1.c
new file mode 100644 (file)
index 0000000..a0a4866
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Se_1f {
+  struct {
+  } e1;
+  float f;
+};
+struct Se_1f echo_Se_1f(int i, float f, struct Se_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct-10.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct-10.c
new file mode 100644 (file)
index 0000000..de8ad02
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct S1ae_2f {
+  struct {
+  } e1[1];
+  float f;
+  float g;
+};
+struct S1ae_2f echo_S1ae_2f(int i, float f, struct S1ae_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct-11.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct-11.c
new file mode 100644 (file)
index 0000000..c99bb22
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Sm1ae_1f {
+  struct {
+  } e1[1];
+  struct {
+    float f;
+    struct {
+    } e[1];
+  } fe;
+  struct {
+  } e2[1];
+};
+struct Sm1ae_1f echo_Sm1ae_1f(int i, float f, struct Sm1ae_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct-12.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct-12.c
new file mode 100644 (file)
index 0000000..065ff02
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Sm1ae_2f {
+  struct {
+  } e1[1];
+  struct {
+    float f;
+    float g;
+    struct {
+    } e[1];
+  } fe;
+  struct {
+  } e2[1];
+};
+struct Sm1ae_2f echo_Sm1ae_2f(int i, float f, struct Sm1ae_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct-2.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct-2.c
new file mode 100644 (file)
index 0000000..93210fe
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Se_2f {
+  struct {
+  } e1;
+  float f;
+  float g;
+};
+struct Se_2f echo_Se_2f(int i, float f, struct Se_2f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct-3.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct-3.c
new file mode 100644 (file)
index 0000000..b8c3362
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Sme_1f {
+  struct {
+  } e1;
+  struct {
+    float f;
+    struct {
+    } e;
+  } fe;
+  struct {
+  } e2;
+};
+struct Sme_1f echo_Sme_1f(int i, float f, struct Sme_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct-4.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct-4.c
new file mode 100644 (file)
index 0000000..0ce36d1
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Sme_2f {
+  struct {
+  } e1;
+  struct {
+    float f;
+    float g;
+    struct {
+    } e;
+  } fe;
+  struct {
+  } e2;
+};
+struct Sme_2f echo_Sme_2f(int i, float f, struct Sme_2f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct-5.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct-5.c
new file mode 100644 (file)
index 0000000..0ae1e41
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct S0ae_1f {
+  struct {
+  } e1[0];
+  float f;
+};
+struct S0ae_1f echo_S0ae_1f(int i, float f, struct S0ae_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct-6.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct-6.c
new file mode 100644 (file)
index 0000000..d3d0b65
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct S0ae_2f {
+  struct {
+  } e1[0];
+  float f;
+  float g;
+};
+struct S0ae_2f echo_S0ae_2f(int i, float f, struct S0ae_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct-7.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct-7.c
new file mode 100644 (file)
index 0000000..9eae13d
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Sm0ae_1f {
+  struct {
+  } e1[0];
+  struct {
+    float f;
+    struct {
+    } e[0];
+  } fe;
+  struct {
+  } e2[0];
+};
+struct Sm0ae_1f echo_Sm0ae_1f(int i, float f, struct Sm0ae_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct-8.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct-8.c
new file mode 100644 (file)
index 0000000..e7c81f4
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Sm0ae_2f {
+  struct {
+  } e1[0];
+  struct {
+    float f;
+    float g;
+    struct {
+    } e[0];
+  } fe;
+  struct {
+  } e2[0];
+};
+struct Sm0ae_2f echo_Sm0ae_2f(int i, float f, struct Sm0ae_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-struct-9.c b/gcc/testsuite/gcc.target/riscv/abi/empty-struct-9.c
new file mode 100644 (file)
index 0000000..55c4be4
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct S1ae_1f {
+  struct {
+  } e1[1];
+  float f;
+};
+struct S1ae_1f echo_S1ae_1f(int i, float f, struct S1ae_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-union-1.c b/gcc/testsuite/gcc.target/riscv/abi/empty-union-1.c
new file mode 100644 (file)
index 0000000..17beb0d
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Seu_1f {
+  union {
+  } e1;
+  float f;
+};
+struct Seu_1f echo_Seu_1f(int i, float f, struct Seu_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-union-2.c b/gcc/testsuite/gcc.target/riscv/abi/empty-union-2.c
new file mode 100644 (file)
index 0000000..c583186
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct S2eu_2f {
+  union {
+  } e1;
+  float f;
+  float g;
+};
+struct S2eu_2f echo_S2eu_2f(int i, float f, struct S2eu_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-union-3.c b/gcc/testsuite/gcc.target/riscv/abi/empty-union-3.c
new file mode 100644 (file)
index 0000000..e9e189b
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Smeu_1f {
+  union {
+  } e1;
+  struct {
+    float f;
+    union {
+    } e;
+  } fe;
+  union {
+  } e2;
+};
+struct Smeu_1f echo_Smeu_1f(int i, float f, struct Smeu_1f s) {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/abi/empty-union-4.c b/gcc/testsuite/gcc.target/riscv/abi/empty-union-4.c
new file mode 100644 (file)
index 0000000..91c2d89
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g -mabi=lp64d -fdump-rtl-expand" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+struct Smeu_2f {
+  union {
+  } e1;
+  struct {
+    float f;
+    float g;
+    union {
+    } e;
+  } fe;
+  union {
+  } e2;
+};
+struct Smeu_2f echo_Smeu_2f(int i, float f, struct Smeu_2f s) /* { dg-warning "ABI for flattened empty union and zero length array changed in GCC 16" } */ {
+  return s;
+}
+
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa1 \[ s \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ .*\)[[:space:]]+\(reg.*:SF \d+ fa2 \[ s\+4 \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa0\)[[:space:]]+\(reg.*:SF \d+ \[ <retval> \]\)\)} "expand" } } */
+/* { dg-final { scan-rtl-dump {\(set \(reg.*:SF \d+ fa1\)[[:space:]]+\(reg.*:SF \d+ \[ <retval>\+4 \]\)\)} "expand" } } */
index b5e7618f704555fd54b81caefa72d8cb398fd819..dd8443df189c1b37b0bd8044aaf5de23114a762a 100644 (file)
@@ -42,6 +42,8 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/sched1-spills/*.{\[cS\],
        "" $DEFAULT_CFLAGS
 gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/xandes/*.\[cS\]]] \
        "" $DEFAULT_CFLAGS
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/abi/*.\[cS\]]] \
+       "" $DEFAULT_CFLAGS
 
 # Saturation alu
 foreach opt {