On Wed, Mar 13, 2019 at 11:40 AM Andrew Burgess
<[email protected]> wrote:
>
> Jim,
>
> Sorry for the delay in sending this patch.
>
> Thanks,
> Andrew
>
> ---
>
> This fixes PR target/89627.
>
> The RISC-V ABI document[1] says:
>
> For the purposes of this section, "struct" refers to a C struct
> with its hierarchy flattened, including any array fields. That is,
> struct { struct { float f[1]; } g[2]; } and struct { float f; float
> g; } are treated the same. Fields containing empty structs or
> unions are ignored while flattening, even in C++, unless they have
> nontrivial copy constructors or destructors.
>
> However, this flattening only applies when one of the fields of the
> flattened structure can be placed into a floating point register,
> otherwise no flattening occurs.
>
> Currently GCC fails to correctly consider that empty C++ structures
> have a non-zero size when constructing the arguments from a flattened
> structure, and as a result, trying to pass a C++ structure like this:
>
> struct sf { struct {} e; float f; };
>
> Doesn't work correctly, GCC fails to take the offset of 'f' within
> 'sf' into account and will actually pass the space backing 'e' as the
> contents of 'f'.
>
> This patch fixes this so that 'f' will be passed correctly. A couple
> of new tests are added to cover this functionality.
>
> [1] https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md
>
> gcc/ChangeLog:
>
> PR target/89627
> * config/riscv/riscv.c (riscv_pass_fpr_single): Add offset
> parameter, and make use of it.
> (riscv_get_arg_info): Pass offset to riscv_pass_fpr_single.
>
> gcc/testsuite/ChangeLog:
>
> PR target/89627
> * g++.target/riscv/call-with-empty-struct-float.C: New file.
> * g++.target/riscv/call-with-empty-struct-int.C: New file.
> * g++.target/riscv/call-with-empty-struct.H: New file.
> * g++.target/riscv/riscv.exp: New file.
This testcase seems generic, that is it has no ABI dependent values
attached to it.
Can it be moved to a more generic location instead? Maybe there are
other targets which get this incorrect also.
Thanks,
Andrew Pinski
> ---
> gcc/ChangeLog | 7 +++++
> gcc/config/riscv/riscv.c | 8 +++--
> gcc/testsuite/ChangeLog | 8 +++++
> .../riscv/call-with-empty-struct-float.C | 6 ++++
> .../g++.target/riscv/call-with-empty-struct-int.C | 6 ++++
> .../g++.target/riscv/call-with-empty-struct.H | 19 ++++++++++++
> gcc/testsuite/g++.target/riscv/riscv.exp | 34
> ++++++++++++++++++++++
> 7 files changed, 85 insertions(+), 3 deletions(-)
> create mode 100644
> gcc/testsuite/g++.target/riscv/call-with-empty-struct-float.C
> create mode 100644
> gcc/testsuite/g++.target/riscv/call-with-empty-struct-int.C
> create mode 100644 gcc/testsuite/g++.target/riscv/call-with-empty-struct.H
> create mode 100644 gcc/testsuite/g++.target/riscv/riscv.exp
>
> diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
> index 8881f80e18f..8e78ab76375 100644
> --- a/gcc/config/riscv/riscv.c
> +++ b/gcc/config/riscv/riscv.c
> @@ -2449,13 +2449,14 @@ riscv_pass_aggregate_in_fpr_and_gpr_p (const_tree
> type,
>
> static rtx
> riscv_pass_fpr_single (machine_mode type_mode, unsigned regno,
> - machine_mode value_mode)
> + machine_mode value_mode,
> + HOST_WIDE_INT offset)
> {
> rtx x = gen_rtx_REG (value_mode, regno);
>
> if (type_mode != value_mode)
> {
> - x = gen_rtx_EXPR_LIST (VOIDmode, x, const0_rtx);
> + x = gen_rtx_EXPR_LIST (VOIDmode, x, GEN_INT (offset));
> x = gen_rtx_PARALLEL (type_mode, gen_rtvec (1, x));
> }
> return x;
> @@ -2517,7 +2518,8 @@ riscv_get_arg_info (struct riscv_arg_info *info, const
> CUMULATIVE_ARGS *cum,
> {
> case 1:
> return riscv_pass_fpr_single (mode, fregno,
> - TYPE_MODE (fields[0].type));
> + TYPE_MODE (fields[0].type),
> + fields[0].offset);
>
> case 2:
> return riscv_pass_fpr_pair (mode, fregno,
> diff --git a/gcc/testsuite/g++.target/riscv/call-with-empty-struct-float.C
> b/gcc/testsuite/g++.target/riscv/call-with-empty-struct-float.C
> new file mode 100644
> index 00000000000..76d0dc6d93d
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/riscv/call-with-empty-struct-float.C
> @@ -0,0 +1,6 @@
> +// { dg-do run }
> +
> +#include "call-with-empty-struct.H"
> +
> +MAKE_STRUCT_PASSING_TEST(float,2.5)
> +
> diff --git a/gcc/testsuite/g++.target/riscv/call-with-empty-struct-int.C
> b/gcc/testsuite/g++.target/riscv/call-with-empty-struct-int.C
> new file mode 100644
> index 00000000000..cc82912dc3e
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/riscv/call-with-empty-struct-int.C
> @@ -0,0 +1,6 @@
> +/* { dg-do run } */
> +
> +#include "call-with-empty-struct.H"
> +
> +MAKE_STRUCT_PASSING_TEST(int,2)
> +
> diff --git a/gcc/testsuite/g++.target/riscv/call-with-empty-struct.H
> b/gcc/testsuite/g++.target/riscv/call-with-empty-struct.H
> new file mode 100644
> index 00000000000..d2a46e78619
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/riscv/call-with-empty-struct.H
> @@ -0,0 +1,19 @@
> +#define MAKE_STRUCT_PASSING_TEST(type,val) \
> + static struct struct_ ## type ## _t \
> + { \
> + struct { } e; \
> + struct { type f; } s; \
> + } global_struct_ ## type = { {}, { val } }; \
> + \
> + static bool \
> + check_struct_ ## type (struct_ ## type ## _t obj) \
> + { \
> + return (obj.s.f == global_struct_ ## type .s.f); \
> + } \
> + \
> + int \
> + main () \
> + { \
> + bool result = check_struct_ ## type ( global_struct_ ## type ); \
> + return result ? 0 : 1; \
> + }
> diff --git a/gcc/testsuite/g++.target/riscv/riscv.exp
> b/gcc/testsuite/g++.target/riscv/riscv.exp
> new file mode 100644
> index 00000000000..a339b5cc56d
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/riscv/riscv.exp
> @@ -0,0 +1,34 @@
> +# Copyright (C) 2019 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with GCC; see the file COPYING3. If not see
> +# <http://www.gnu.org/licenses/>.
> +
> +# GCC testsuite that uses the `dg.exp' driver.
> +
> +# Exit immediately if this isn't a RISC-V target.
> +if ![istarget riscv*-*-*] then {
> + return
> +}
> +
> +# Load support procs.
> +load_lib g++-dg.exp
> +
> +# Initialize `dg'.
> +dg-init
> +
> +# Main loop.
> +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" ""
> +
> +# All done.
> +dg-finish
> --
> 2.14.5
>