An empty struct type that is not non-trivial for the purposes of calls will be treated as though it were the following C type:
struct { char c; }; Before this patch was added, a structure parameter containing an empty structure and less than three floating-point members was passed through one or two floating-point registers, while nested empty structures are ignored. Which did not conform to the calling convention. After adding this patch, empty structs will always be passed. gcc/ChangeLog: * config/loongarch/loongarch.cc (loongarch_flatten_aggregate_field): Mark out nested empty structs. (loongarch_pass_aggregate_in_fpr_and_gpr_p): If an empty structure exists, increment the number of fixed-point registers required. gcc/testsuite/ChangeLog: * g++.target/loongarch/empty1.C: New test. * g++.target/loongarch/empty2.C: New test. * g++.target/loongarch/empty3.C: New test. --- gcc/config/loongarch/loongarch.cc | 13 +++++++++++++ gcc/testsuite/g++.target/loongarch/empty1.C | 18 ++++++++++++++++++ gcc/testsuite/g++.target/loongarch/empty2.C | 20 ++++++++++++++++++++ gcc/testsuite/g++.target/loongarch/empty3.C | 19 +++++++++++++++++++ 4 files changed, 70 insertions(+) create mode 100644 gcc/testsuite/g++.target/loongarch/empty1.C create mode 100644 gcc/testsuite/g++.target/loongarch/empty2.C create mode 100644 gcc/testsuite/g++.target/loongarch/empty3.C diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index 7f4e0e59573..77506410501 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -321,6 +321,18 @@ loongarch_flatten_aggregate_field (const_tree type, || !tree_fits_uhwi_p (TYPE_SIZE (type))) return -1; + if (default_is_empty_record (type)) + { + if (n < 2) + { + fields[n].type = type; + fields[n].offset = offset; + return n + 1; + } + else + return -1; + } + for (tree f = TYPE_FIELDS (type); f; f = DECL_CHAIN (f)) if (TREE_CODE (f) == FIELD_DECL) { @@ -458,6 +470,7 @@ loongarch_pass_aggregate_in_fpr_and_gpr_p (const_tree type, { num_float += SCALAR_FLOAT_TYPE_P (fields[i].type); num_int += INTEGRAL_TYPE_P (fields[i].type); + num_int += (TREE_CODE (fields[i].type) == RECORD_TYPE); } return num_int == 1 && num_float == 1; diff --git a/gcc/testsuite/g++.target/loongarch/empty1.C b/gcc/testsuite/g++.target/loongarch/empty1.C new file mode 100644 index 00000000000..059e6774158 --- /dev/null +++ b/gcc/testsuite/g++.target/loongarch/empty1.C @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mabi=lp64d" } */ +/* { dg-final { scan-assembler-times "ld.bu\t\\\$r4,\\\$r12,0" 1 } } */ + +struct E {}; +struct s1 +{ + struct E {} e1; + float f0; +}; + +extern void fun (struct s1); + +struct s1 s1_1 = {{}, 1.0}; +void test (void) +{ + fun (s1_1); +} diff --git a/gcc/testsuite/g++.target/loongarch/empty2.C b/gcc/testsuite/g++.target/loongarch/empty2.C new file mode 100644 index 00000000000..abf01de751a --- /dev/null +++ b/gcc/testsuite/g++.target/loongarch/empty2.C @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mabi=lp64d" } */ +/* { dg-final { scan-assembler-not "fld.s" } } */ +/* { dg-final { scan-assembler-not "fld.d" } } */ + +struct E {}; +struct s1 +{ + struct E {} e1; + float f0; + double f1; +}; + +extern void fun (struct s1); + +struct s1 s1_1 = {{}, 1.0, 2.0}; +void test (void) +{ + fun (s1_1); +} diff --git a/gcc/testsuite/g++.target/loongarch/empty3.C b/gcc/testsuite/g++.target/loongarch/empty3.C new file mode 100644 index 00000000000..8c40963238b --- /dev/null +++ b/gcc/testsuite/g++.target/loongarch/empty3.C @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mabi=lp64d" } */ +/* { dg-final { scan-assembler-not "fld.d" } } */ + +struct E {}; +struct s1 +{ + struct E {} e1; + double f0; + double f1; +}; + +extern void fun (struct s1); + +struct s1 s1_1 = {{}, 1.0, 2.0}; +void test (void) +{ + fun (s1_1); +} -- 2.31.1