RISC-V: Fix C ABI for flattened struct with 0-length bitfield.
authorJim Wilson <jimw@sifive.com>
Thu, 8 Aug 2019 19:04:56 +0000 (19:04 +0000)
committerJim Wilson <wilson@gcc.gnu.org>
Thu, 8 Aug 2019 19:04:56 +0000 (12:04 -0700)
gcc/
PR target/91229
* config/riscv/riscv.c (riscv_flatten_aggregate_field): New arg
ignore_zero_width_bit_field_p.  Skip zero size bitfields when true.
Pass into recursive call.
(riscv_flatten_aggregate_argument): New arg.  Pass to
riscv_flatten_aggregate_field.
(riscv_pass_aggregate_in_fpr_pair_p): New local warned.  Call
riscv_flatten_aggregate_argument twice, with false and true as last
arg.  Process result twice.  Compare results and warn if different.
(riscv_pass_aggregate_in_fpr_and_gpr_p): Likewise.

gcc/testsuite/
* gcc.target/riscv/flattened-struct-abi-1.c: New test.
* gcc.target/riscv/flattened-struct-abi-2.c: New test.

From-SVN: r274215

gcc/ChangeLog
gcc/config/riscv/riscv.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/riscv/flattened-struct-abi-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/flattened-struct-abi-2.c [new file with mode: 0644]

index 54f7d974821e0c0a1fc338c81f465fac90750bcf..9b939c1024a9e03505efb40d48e5dd1d0ead8abd 100644 (file)
@@ -1,3 +1,16 @@
+2019-08-08  Jim Wilson  <jimw@sifive.com>
+
+       PR target/91229
+       * config/riscv/riscv.c (riscv_flatten_aggregate_field): New arg
+       ignore_zero_width_bit_field_p.  Skip zero size bitfields when true.
+       Pass into recursive call.
+       (riscv_flatten_aggregate_argument): New arg.  Pass to
+       riscv_flatten_aggregate_field.
+       (riscv_pass_aggregate_in_fpr_pair_p): New local warned.  Call
+       riscv_flatten_aggregate_argument twice, with false and true as last
+       arg.  Process result twice.  Compare results and warn if different.
+       (riscv_pass_aggregate_in_fpr_and_gpr_p): Likewise.
+
 2019-08-08  Martin Liska  <mliska@suse.cz>
 
        PR bootstrap/91352
index 431e90a89572fa1edeee2548b2abc0e7c37c8766..c12b26f0dc40d4fae7651f5907b5f83d586b4c33 100644 (file)
@@ -2383,7 +2383,8 @@ typedef struct {
 static int
 riscv_flatten_aggregate_field (const_tree type,
                               riscv_aggregate_field fields[2],
-                              int n, HOST_WIDE_INT offset)
+                              int n, HOST_WIDE_INT offset,
+                              bool ignore_zero_width_bit_field_p)
 {
   switch (TREE_CODE (type))
     {
@@ -2400,8 +2401,21 @@ riscv_flatten_aggregate_field (const_tree type,
            if (!TYPE_P (TREE_TYPE (f)))
              return -1;
 
-           HOST_WIDE_INT pos = offset + int_byte_position (f);
-           n = riscv_flatten_aggregate_field (TREE_TYPE (f), fields, n, pos);
+           /* The C++ front end strips zero-length bit-fields from structs.
+              So we need to ignore them in the C front end to make C code
+              compatible with C++ code.  */
+           if (ignore_zero_width_bit_field_p
+               && DECL_BIT_FIELD (f)
+               && (DECL_SIZE (f) == NULL_TREE
+                   || integer_zerop (DECL_SIZE (f))))
+             ;
+           else
+             {
+               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);
+             }
            if (n < 0)
              return -1;
          }
@@ -2414,7 +2428,8 @@ riscv_flatten_aggregate_field (const_tree type,
        tree index = TYPE_DOMAIN (type);
        tree elt_size = TYPE_SIZE_UNIT (TREE_TYPE (type));
        int n_subfields = riscv_flatten_aggregate_field (TREE_TYPE (type),
-                                                        subfields, 0, offset);
+                                                        subfields, 0, offset,
+                                                        ignore_zero_width_bit_field_p);
 
        /* Can't handle incomplete types nor sizes that are not fixed.  */
        if (n_subfields <= 0
@@ -2487,12 +2502,14 @@ riscv_flatten_aggregate_field (const_tree type,
 
 static int
 riscv_flatten_aggregate_argument (const_tree type,
-                                 riscv_aggregate_field fields[2])
+                                 riscv_aggregate_field fields[2],
+                                 bool ignore_zero_width_bit_field_p)
 {
   if (!type || TREE_CODE (type) != RECORD_TYPE)
     return -1;
 
-  return riscv_flatten_aggregate_field (type, fields, 0, 0);
+  return riscv_flatten_aggregate_field (type, fields, 0, 0,
+                                       ignore_zero_width_bit_field_p);
 }
 
 /* See whether TYPE is a record whose fields should be returned in one or
@@ -2502,13 +2519,34 @@ static unsigned
 riscv_pass_aggregate_in_fpr_pair_p (const_tree type,
                                    riscv_aggregate_field fields[2])
 {
-  int n = riscv_flatten_aggregate_argument (type, fields);
+  static int warned = 0;
 
-  for (int i = 0; i < n; i++)
+  /* 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))
-      return 0;
+      {
+       n_old = -1;
+       break;
+      }
+
+  /* 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;
+      }
 
-  return n > 0 ? n : 0;
+  if ((n_old != n_new) && (warned == 0))
+    {
+      warning (0, "ABI for flattened struct with zero-length bit-fields "
+              "changed in GCC 10");
+      warned = 1;
+    }
+
+  return n_new > 0 ? n_new : 0;
 }
 
 /* See whether TYPE is a record whose fields should be returned in one or
@@ -2519,16 +2557,38 @@ static bool
 riscv_pass_aggregate_in_fpr_and_gpr_p (const_tree type,
                                       riscv_aggregate_field fields[2])
 {
-  unsigned num_int = 0, num_float = 0;
-  int n = riscv_flatten_aggregate_argument (type, fields);
+  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);
+    }
+
+  /* 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);
+    }
 
-  for (int i = 0; i < n; i++)
+  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))
     {
-      num_float += SCALAR_FLOAT_TYPE_P (fields[i].type);
-      num_int += INTEGRAL_TYPE_P (fields[i].type);
+      warning (0, "ABI for flattened struct with zero-length bit-fields "
+              "changed in GCC 10");
+      warned = 1;
     }
 
-  return num_int == 1 && num_float == 1;
+  return num_int_new == 1 && num_float_new == 1;
 }
 
 /* Return the representation of an argument passed or returned in an FPR
index c44e3795099ffacfbc2d36aecc62401d8596705c..94b8852d7a6962fdf07624d12ee903ee629db752 100644 (file)
@@ -1,3 +1,9 @@
+2019-08-08  Jim Wilson  <jimw@sifive.com>
+
+       PR target/91229
+       * gcc.target/riscv/flattened-struct-abi-1.c: New test.
+       * gcc.target/riscv/flattened-struct-abi-2.c: New test.
+
 2019-08-08  Marek Polacek  <polacek@redhat.com>
 
        PR c++/79520
diff --git a/gcc/testsuite/gcc.target/riscv/flattened-struct-abi-1.c b/gcc/testsuite/gcc.target/riscv/flattened-struct-abi-1.c
new file mode 100644 (file)
index 0000000..f6a3c51
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc -mabi=ilp32d" } */
+struct s1 { int : 0; float f; int i; int : 0; };
+
+void dummy(float, int);
+
+void f(struct s1 s) { /* { dg-warning "flattened struct" } */
+  dummy(s.f + 1.0, s.i + 1);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/flattened-struct-abi-2.c b/gcc/testsuite/gcc.target/riscv/flattened-struct-abi-2.c
new file mode 100644 (file)
index 0000000..760826a
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc -mabi=ilp32d" } */
+struct s1 { int : 0; float f; float g; int : 0; };
+
+void dummy(float, float);
+
+void f(struct s1 s) { /* { dg-warning "flattened struct" } */
+  dummy(s.f + 1.0, s.g + 2.0);
+}