From: Jim Wilson Date: Thu, 8 Aug 2019 19:04:56 +0000 (+0000) Subject: RISC-V: Fix C ABI for flattened struct with 0-length bitfield. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e98c3ee9712a360b4f470f930ac0c68863db1d3f;p=gcc.git RISC-V: Fix C ABI for flattened struct with 0-length bitfield. 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 54f7d974821..9b939c1024a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2019-08-08 Jim Wilson + + 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 PR bootstrap/91352 diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c index 431e90a8957..c12b26f0dc4 100644 --- a/gcc/config/riscv/riscv.c +++ b/gcc/config/riscv/riscv.c @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c44e3795099..94b8852d7a6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-08-08 Jim Wilson + + 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 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 index 00000000000..f6a3c51b3fb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/flattened-struct-abi-1.c @@ -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 index 00000000000..760826a42f1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/flattened-struct-abi-2.c @@ -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); +}