diff mbox series

[v9] RISC-V: Add the 'zfa' extension, version 0.2

Message ID 20230515131628.953-1-jinma@linux.alibaba.com
State New
Headers show
Series [v9] RISC-V: Add the 'zfa' extension, version 0.2 | expand

Commit Message

Jin Ma May 15, 2023, 1:16 p.m. UTC
This patch adds the 'Zfa' extension for riscv, which is based on:
https://github.com/riscv/riscv-isa-manual/commits/zfb

The binutils-gdb for 'Zfa' extension:
https://sourceware.org/pipermail/binutils/2023-April/127060.html

What needs special explanation is:
1, The immediate number of the instructions FLI.H/S/D is represented in the assembly as a
  floating-point value, with scientific counting when rs1 is 2,3, and decimal numbers for
  the rest.

  Related llvm link:
    https://reviews.llvm.org/D145645
  Related discussion link:
    https://github.com/riscv/riscv-isa-manual/issues/980

2, According to riscv-spec, "The FCVTMO D.W.D instruction was added principally to
  accelerate the processing of JavaScript Numbers.", so it seems that no implementation
  is required.

3, The instructions FMINM and FMAXM correspond to C23 library function fminimum and fmaximum.
  Therefore, this patch has simply implemented the pattern of fminm<hf\sf\df>3 and
  fmaxm<hf\sf\df>3 to prepare for later.

gcc/ChangeLog:

	* common/config/riscv/riscv-common.cc: Add zfa extension version.
	* config/riscv/constraints.md (zfli): Constrain the floating point number that the
	instructions FLI.H/S/D can load.
	* config/riscv/iterators.md (ceil): New.
	(rup): New.
	* config/riscv/riscv-opts.h (MASK_ZFA): New.
	(TARGET_ZFA): New.
	* config/riscv/riscv-protos.h (riscv_float_const_rtx_index_for_fli): New.
	* config/riscv/riscv.cc (riscv_float_const_rtx_index_for_fli): New.
	(riscv_cannot_force_const_mem): If instruction FLI.H/S/D can be used, memory is not applicable.
	(riscv_const_insns): Likewise.
	(riscv_legitimize_const_move): Likewise.
	(riscv_split_64bit_move_p): If instruction FLI.H/S/D can be used, no split is required.
	(riscv_split_doubleword_move): Likewise.
	(riscv_output_move): Output the mov instructions in zfa extension.
	(riscv_print_operand): Output the floating-point value of the FLI.H/S/D immediate in assembly
	(riscv_secondary_memory_needed): Likewise.
	* config/riscv/riscv.md (fminm<mode>3): New.
	(fmaxm<mode>3): New.
	(movsidf2_low_rv32): New.
	(movsidf2_high_rv32): New.
	(movdfsisi3_rv32): New.
	(f<quiet_pattern>_quiet<ANYF:mode><X:mode>4_zfa): Likewise.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/zfa-fleq-fltq-rv32.c: New test.
	* gcc.target/riscv/zfa-fleq-fltq.c: New test.
	* gcc.target/riscv/zfa-fli-rv32.c: New test.
	* gcc.target/riscv/zfa-fli-zfh-rv32.c: New test.
	* gcc.target/riscv/zfa-fli-zfh.c: New test.
	* gcc.target/riscv/zfa-fli.c: New test.
	* gcc.target/riscv/zfa-fmovh-fmovp-rv32.c: New test.
	* gcc.target/riscv/zfa-fround-rv32.c: New test.
	* gcc.target/riscv/zfa-fround.c: New test.
---
 gcc/common/config/riscv/riscv-common.cc       |   4 +
 gcc/config/riscv/constraints.md               |  21 +-
 gcc/config/riscv/iterators.md                 |   5 +
 gcc/config/riscv/riscv-opts.h                 |   3 +
 gcc/config/riscv/riscv-protos.h               |   1 +
 gcc/config/riscv/riscv.cc                     | 204 +++++++++++++++++-
 gcc/config/riscv/riscv.md                     | 145 +++++++++++--
 .../gcc.target/riscv/zfa-fleq-fltq-rv32.c     |  19 ++
 .../gcc.target/riscv/zfa-fleq-fltq.c          |  19 ++
 gcc/testsuite/gcc.target/riscv/zfa-fli-rv32.c |  79 +++++++
 .../gcc.target/riscv/zfa-fli-zfh-rv32.c       |  41 ++++
 gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c  |  41 ++++
 gcc/testsuite/gcc.target/riscv/zfa-fli.c      |  79 +++++++
 .../gcc.target/riscv/zfa-fmovh-fmovp-rv32.c   |  10 +
 .../gcc.target/riscv/zfa-fround-rv32.c        |  42 ++++
 gcc/testsuite/gcc.target/riscv/zfa-fround.c   |  42 ++++
 16 files changed, 719 insertions(+), 36 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq-rv32.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-rv32.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-zfh-rv32.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp-rv32.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fround-rv32.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fround.c

Comments

jinma May 15, 2023, 1:30 p.m. UTC | #1
According to Jeff's review feedback, the issues regarding UNSPEC's implementation of round, ceil, nearbyint, etc. still need to be determined:
https://gcc.gnu.org/pipermail/gcc-patches/2023-May/617706.html

source: 
https://github.com/majin2020/gcc-mirror/commit/93d7a2d995cee588d494d1839f56e8151c6cb057
Jeff Law May 16, 2023, 4 a.m. UTC | #2
On 5/15/23 07:30, jinma wrote:
> According to Jeff's review feedback, the issues regarding UNSPEC's implementation of round, ceil, nearbyint, etc. still need to be determined:
> https://gcc.gnu.org/pipermail/gcc-patches/2023-May/617706.html
> 
> source:
> https://github.com/majin2020/gcc-mirror/commit/93d7a2d995cee588d494d1839f56e8151c6cb057
After double-checking I was incorrect.  We have named patterns for those 
operations, but the RTL for them are UNSPECs.  So this is a non-issue 
for this patch.

jeff
Jeff Law May 16, 2023, 4:16 a.m. UTC | #3
On 5/15/23 07:16, Jin Ma wrote:
> This patch adds the 'Zfa' extension for riscv, which is based on:
> https://github.com/riscv/riscv-isa-manual/commits/zfb
> 
> The binutils-gdb for 'Zfa' extension:
> https://sourceware.org/pipermail/binutils/2023-April/127060.html
> 
> What needs special explanation is:
> 1, The immediate number of the instructions FLI.H/S/D is represented in the assembly as a
>    floating-point value, with scientific counting when rs1 is 2,3, and decimal numbers for
>    the rest.
> 
>    Related llvm link:
>      https://reviews.llvm.org/D145645
>    Related discussion link:
>      https://github.com/riscv/riscv-isa-manual/issues/980
> 
> 2, According to riscv-spec, "The FCVTMO D.W.D instruction was added principally to
>    accelerate the processing of JavaScript Numbers.", so it seems that no implementation
>    is required.
> 
> 3, The instructions FMINM and FMAXM correspond to C23 library function fminimum and fmaximum.
>    Therefore, this patch has simply implemented the pattern of fminm<hf\sf\df>3 and
>    fmaxm<hf\sf\df>3 to prepare for later.
> 
> gcc/ChangeLog:
> 
> 	* common/config/riscv/riscv-common.cc: Add zfa extension version.
> 	* config/riscv/constraints.md (zfli): Constrain the floating point number that the
> 	instructions FLI.H/S/D can load.
> 	* config/riscv/iterators.md (ceil): New.
> 	(rup): New.
> 	* config/riscv/riscv-opts.h (MASK_ZFA): New.
> 	(TARGET_ZFA): New.
> 	* config/riscv/riscv-protos.h (riscv_float_const_rtx_index_for_fli): New.
> 	* config/riscv/riscv.cc (riscv_float_const_rtx_index_for_fli): New.
> 	(riscv_cannot_force_const_mem): If instruction FLI.H/S/D can be used, memory is not applicable.
> 	(riscv_const_insns): Likewise.
> 	(riscv_legitimize_const_move): Likewise.
> 	(riscv_split_64bit_move_p): If instruction FLI.H/S/D can be used, no split is required.
> 	(riscv_split_doubleword_move): Likewise.
> 	(riscv_output_move): Output the mov instructions in zfa extension.
> 	(riscv_print_operand): Output the floating-point value of the FLI.H/S/D immediate in assembly
> 	(riscv_secondary_memory_needed): Likewise.
> 	* config/riscv/riscv.md (fminm<mode>3): New.
> 	(fmaxm<mode>3): New.
> 	(movsidf2_low_rv32): New.
> 	(movsidf2_high_rv32): New.
> 	(movdfsisi3_rv32): New.
> 	(f<quiet_pattern>_quiet<ANYF:mode><X:mode>4_zfa): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/zfa-fleq-fltq-rv32.c: New test.
> 	* gcc.target/riscv/zfa-fleq-fltq.c: New test.
> 	* gcc.target/riscv/zfa-fli-rv32.c: New test.
> 	* gcc.target/riscv/zfa-fli-zfh-rv32.c: New test.
> 	* gcc.target/riscv/zfa-fli-zfh.c: New test.
> 	* gcc.target/riscv/zfa-fli.c: New test.
> 	* gcc.target/riscv/zfa-fmovh-fmovp-rv32.c: New test.
> 	* gcc.target/riscv/zfa-fround-rv32.c: New test.
> 	* gcc.target/riscv/zfa-fround.c: New test.
> ---
>   gcc/common/config/riscv/riscv-common.cc       |   4 +
>   gcc/config/riscv/constraints.md               |  21 +-
>   gcc/config/riscv/iterators.md                 |   5 +
>   gcc/config/riscv/riscv-opts.h                 |   3 +
>   gcc/config/riscv/riscv-protos.h               |   1 +
>   gcc/config/riscv/riscv.cc                     | 204 +++++++++++++++++-
>   gcc/config/riscv/riscv.md                     | 145 +++++++++++--
>   .../gcc.target/riscv/zfa-fleq-fltq-rv32.c     |  19 ++
>   .../gcc.target/riscv/zfa-fleq-fltq.c          |  19 ++
>   gcc/testsuite/gcc.target/riscv/zfa-fli-rv32.c |  79 +++++++
>   .../gcc.target/riscv/zfa-fli-zfh-rv32.c       |  41 ++++
>   gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c  |  41 ++++
>   gcc/testsuite/gcc.target/riscv/zfa-fli.c      |  79 +++++++
>   .../gcc.target/riscv/zfa-fmovh-fmovp-rv32.c   |  10 +
>   .../gcc.target/riscv/zfa-fround-rv32.c        |  42 ++++
>   gcc/testsuite/gcc.target/riscv/zfa-fround.c   |  42 ++++
>   16 files changed, 719 insertions(+), 36 deletions(-)
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq-rv32.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-rv32.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-zfh-rv32.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp-rv32.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fround-rv32.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fround.c
> 


> +
> +/* Return index of the FLI instruction table if rtx X is an immediate constant that can
> +   be moved using a single FLI instruction in zfa extension. Return -1 if not found.  */
> +
> +int
> +riscv_float_const_rtx_index_for_fli (rtx x)
> +{
> +  unsigned HOST_WIDE_INT *fli_value_array;
> +
> +  machine_mode mode = GET_MODE (x);
> +
> +  if (!TARGET_ZFA
> +      || !CONST_DOUBLE_P(x)
> +      || mode == VOIDmode
> +      || (mode == HFmode && !TARGET_ZFH)
> +      || (mode == SFmode && !TARGET_HARD_FLOAT)
> +      || (mode == DFmode && !TARGET_DOUBLE_FLOAT))
> +    return -1;
Do we also need to check Z[FDH]INX too?

Otherwise it looks pretty good.  We just need to wait for everything to 
freeze and finalization on the assembler interface.

jeff
jinma May 16, 2023, 7:06 a.m. UTC | #4
On 5/15/23 07:16, Jin Ma wrote:
> > This patch adds the 'Zfa' extension for riscv, which is based on:
> > https://github.com/riscv/riscv-isa-manual/commits/zfb
> > 
> > The binutils-gdb for 'Zfa' extension:
> > https://sourceware.org/pipermail/binutils/2023-April/127060.html
> > 
> > What needs special explanation is:
> > 1, The immediate number of the instructions FLI.H/S/D is represented in the assembly as a
> >    floating-point value, with scientific counting when rs1 is 2,3, and decimal numbers for
> >    the rest.
> > 
> >    Related llvm link:
> >      https://reviews.llvm.org/D145645
> >    Related discussion link:
> >      https://github.com/riscv/riscv-isa-manual/issues/980
> > 
> > 2, According to riscv-spec, "The FCVTMO D.W.D instruction was added principally to
> >    accelerate the processing of JavaScript Numbers.", so it seems that no implementation
> >    is required.
> > 
> > 3, The instructions FMINM and FMAXM correspond to C23 library function fminimum and fmaximum.
> >    Therefore, this patch has simply implemented the pattern of fminm<hf\sf\df>3 and
> >    fmaxm<hf\sf\df>3 to prepare for later.
> > 
> > gcc/ChangeLog:
> > 
> >  * common/config/riscv/riscv-common.cc: Add zfa extension version.
> >  * config/riscv/constraints.md (zfli): Constrain the floating point number that the
> >  instructions FLI.H/S/D can load.
> >  * config/riscv/iterators.md (ceil): New.
> >  (rup): New.
> >  * config/riscv/riscv-opts.h (MASK_ZFA): New.
> >  (TARGET_ZFA): New.
> >  * config/riscv/riscv-protos.h (riscv_float_const_rtx_index_for_fli): New.
> >  * config/riscv/riscv.cc (riscv_float_const_rtx_index_for_fli): New.
> >  (riscv_cannot_force_const_mem): If instruction FLI.H/S/D can be used, memory is not applicable.
> >  (riscv_const_insns): Likewise.
> >  (riscv_legitimize_const_move): Likewise.
> >  (riscv_split_64bit_move_p): If instruction FLI.H/S/D can be used, no split is required.
> >  (riscv_split_doubleword_move): Likewise.
> >  (riscv_output_move): Output the mov instructions in zfa extension.
> >  (riscv_print_operand): Output the floating-point value of the FLI.H/S/D immediate in assembly
> >  (riscv_secondary_memory_needed): Likewise.
> >  * config/riscv/riscv.md (fminm<mode>3): New.
> >  (fmaxm<mode>3): New.
> >  (movsidf2_low_rv32): New.
> >  (movsidf2_high_rv32): New.
> >  (movdfsisi3_rv32): New.
> >  (f<quiet_pattern>_quiet<ANYF:mode><X:mode>4_zfa): Likewise.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >  * gcc.target/riscv/zfa-fleq-fltq-rv32.c: New test.
> >  * gcc.target/riscv/zfa-fleq-fltq.c: New test.
> >  * gcc.target/riscv/zfa-fli-rv32.c: New test.
> >  * gcc.target/riscv/zfa-fli-zfh-rv32.c: New test.
> >  * gcc.target/riscv/zfa-fli-zfh.c: New test.
> >  * gcc.target/riscv/zfa-fli.c: New test.
> >  * gcc.target/riscv/zfa-fmovh-fmovp-rv32.c: New test.
> >  * gcc.target/riscv/zfa-fround-rv32.c: New test.
> >  * gcc.target/riscv/zfa-fround.c: New test.
> > ---
> >   gcc/common/config/riscv/riscv-common.cc       |   4 +
> >   gcc/config/riscv/constraints.md               |  21 +-
> >   gcc/config/riscv/iterators.md                 |   5 +
> >   gcc/config/riscv/riscv-opts.h                 |   3 +
> >   gcc/config/riscv/riscv-protos.h               |   1 +
> >   gcc/config/riscv/riscv.cc                     | 204 +++++++++++++++++-
> >   gcc/config/riscv/riscv.md                     | 145 +++++++++++--
> >   .../gcc.target/riscv/zfa-fleq-fltq-rv32.c     |  19 ++
> >   .../gcc.target/riscv/zfa-fleq-fltq.c          |  19 ++
> >   gcc/testsuite/gcc.target/riscv/zfa-fli-rv32.c |  79 +++++++
> >   .../gcc.target/riscv/zfa-fli-zfh-rv32.c       |  41 ++++
> >   gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c  |  41 ++++
> >   gcc/testsuite/gcc.target/riscv/zfa-fli.c      |  79 +++++++
> >   .../gcc.target/riscv/zfa-fmovh-fmovp-rv32.c   |  10 +
> >   .../gcc.target/riscv/zfa-fround-rv32.c        |  42 ++++
> >   gcc/testsuite/gcc.target/riscv/zfa-fround.c   |  42 ++++
> >   16 files changed, 719 insertions(+), 36 deletions(-)
> >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq-rv32.c
> >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c
> >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-rv32.c
> >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-zfh-rv32.c
> >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c
> >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli.c
> >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp-rv32.c
> >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fround-rv32.c
> >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fround.c
> > 
> 
> 
> > +
> > +/* Return index of the FLI instruction table if rtx X is an immediate constant that can
> > +   be moved using a single FLI instruction in zfa extension. Return -1 if not found.  */
> > +
> > +int
> > +riscv_float_const_rtx_index_for_fli (rtx x)
> > +{
> > +  unsigned HOST_WIDE_INT *fli_value_array;
> > +
> > +  machine_mode mode = GET_MODE (x);
> > +
> > +  if (!TARGET_ZFA
> > +      || !CONST_DOUBLE_P(x)
> > +      || mode == VOIDmode
> > +      || (mode == HFmode && !TARGET_ZFH)
> > +      || (mode == SFmode && !TARGET_HARD_FLOAT)
> > +      || (mode == DFmode && !TARGET_DOUBLE_FLOAT))
> > +    return -1;
> Do we also need to check Z[FDH]INX too?
> 
> Otherwise it looks pretty good.  We just need to wait for everything to 
> freeze and finalization on the assembler interface.
> 
> jeff

Yes, you are right, we also need to check Z[FDH]INX. I will send a patch
again to fix it after others give some review comments.

Jin
Kito Cheng May 16, 2023, 7:53 a.m. UTC | #5
zfa requires/depend f, it means zfa implies f in current toolchain
implementation, could you add that into riscv-common.cc?

Also that means zfa is exclusive with Z[FDH]INX.

Ref: https://github.com/riscv/riscv-isa-manual/issues/1020

On Tue, May 16, 2023 at 3:06 PM jinma <jinma@linux.alibaba.com> wrote:
>
> On 5/15/23 07:16, Jin Ma wrote:
> > > This patch adds the 'Zfa' extension for riscv, which is based on:
> > > https://github.com/riscv/riscv-isa-manual/commits/zfb
> > >
> > > The binutils-gdb for 'Zfa' extension:
> > > https://sourceware.org/pipermail/binutils/2023-April/127060.html
> > >
> > > What needs special explanation is:
> > > 1, The immediate number of the instructions FLI.H/S/D is represented in the assembly as a
> > >    floating-point value, with scientific counting when rs1 is 2,3, and decimal numbers for
> > >    the rest.
> > >
> > >    Related llvm link:
> > >      https://reviews.llvm.org/D145645
> > >    Related discussion link:
> > >      https://github.com/riscv/riscv-isa-manual/issues/980
> > >
> > > 2, According to riscv-spec, "The FCVTMO D.W.D instruction was added principally to
> > >    accelerate the processing of JavaScript Numbers.", so it seems that no implementation
> > >    is required.
> > >
> > > 3, The instructions FMINM and FMAXM correspond to C23 library function fminimum and fmaximum.
> > >    Therefore, this patch has simply implemented the pattern of fminm<hf\sf\df>3 and
> > >    fmaxm<hf\sf\df>3 to prepare for later.
> > >
> > > gcc/ChangeLog:
> > >
> > >  * common/config/riscv/riscv-common.cc: Add zfa extension version.
> > >  * config/riscv/constraints.md (zfli): Constrain the floating point number that the
> > >  instructions FLI.H/S/D can load.
> > >  * config/riscv/iterators.md (ceil): New.
> > >  (rup): New.
> > >  * config/riscv/riscv-opts.h (MASK_ZFA): New.
> > >  (TARGET_ZFA): New.
> > >  * config/riscv/riscv-protos.h (riscv_float_const_rtx_index_for_fli): New.
> > >  * config/riscv/riscv.cc (riscv_float_const_rtx_index_for_fli): New.
> > >  (riscv_cannot_force_const_mem): If instruction FLI.H/S/D can be used, memory is not applicable.
> > >  (riscv_const_insns): Likewise.
> > >  (riscv_legitimize_const_move): Likewise.
> > >  (riscv_split_64bit_move_p): If instruction FLI.H/S/D can be used, no split is required.
> > >  (riscv_split_doubleword_move): Likewise.
> > >  (riscv_output_move): Output the mov instructions in zfa extension.
> > >  (riscv_print_operand): Output the floating-point value of the FLI.H/S/D immediate in assembly
> > >  (riscv_secondary_memory_needed): Likewise.
> > >  * config/riscv/riscv.md (fminm<mode>3): New.
> > >  (fmaxm<mode>3): New.
> > >  (movsidf2_low_rv32): New.
> > >  (movsidf2_high_rv32): New.
> > >  (movdfsisi3_rv32): New.
> > >  (f<quiet_pattern>_quiet<ANYF:mode><X:mode>4_zfa): Likewise.
> > >
> > > gcc/testsuite/ChangeLog:
> > >
> > >  * gcc.target/riscv/zfa-fleq-fltq-rv32.c: New test.
> > >  * gcc.target/riscv/zfa-fleq-fltq.c: New test.
> > >  * gcc.target/riscv/zfa-fli-rv32.c: New test.
> > >  * gcc.target/riscv/zfa-fli-zfh-rv32.c: New test.
> > >  * gcc.target/riscv/zfa-fli-zfh.c: New test.
> > >  * gcc.target/riscv/zfa-fli.c: New test.
> > >  * gcc.target/riscv/zfa-fmovh-fmovp-rv32.c: New test.
> > >  * gcc.target/riscv/zfa-fround-rv32.c: New test.
> > >  * gcc.target/riscv/zfa-fround.c: New test.
> > > ---
> > >   gcc/common/config/riscv/riscv-common.cc       |   4 +
> > >   gcc/config/riscv/constraints.md               |  21 +-
> > >   gcc/config/riscv/iterators.md                 |   5 +
> > >   gcc/config/riscv/riscv-opts.h                 |   3 +
> > >   gcc/config/riscv/riscv-protos.h               |   1 +
> > >   gcc/config/riscv/riscv.cc                     | 204 +++++++++++++++++-
> > >   gcc/config/riscv/riscv.md                     | 145 +++++++++++--
> > >   .../gcc.target/riscv/zfa-fleq-fltq-rv32.c     |  19 ++
> > >   .../gcc.target/riscv/zfa-fleq-fltq.c          |  19 ++
> > >   gcc/testsuite/gcc.target/riscv/zfa-fli-rv32.c |  79 +++++++
> > >   .../gcc.target/riscv/zfa-fli-zfh-rv32.c       |  41 ++++
> > >   gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c  |  41 ++++
> > >   gcc/testsuite/gcc.target/riscv/zfa-fli.c      |  79 +++++++
> > >   .../gcc.target/riscv/zfa-fmovh-fmovp-rv32.c   |  10 +
> > >   .../gcc.target/riscv/zfa-fround-rv32.c        |  42 ++++
> > >   gcc/testsuite/gcc.target/riscv/zfa-fround.c   |  42 ++++
> > >   16 files changed, 719 insertions(+), 36 deletions(-)
> > >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq-rv32.c
> > >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c
> > >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-rv32.c
> > >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-zfh-rv32.c
> > >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c
> > >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fli.c
> > >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp-rv32.c
> > >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fround-rv32.c
> > >   create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fround.c
> > >
> >
> >
> > > +
> > > +/* Return index of the FLI instruction table if rtx X is an immediate constant that can
> > > +   be moved using a single FLI instruction in zfa extension. Return -1 if not found.  */
> > > +
> > > +int
> > > +riscv_float_const_rtx_index_for_fli (rtx x)
> > > +{
> > > +  unsigned HOST_WIDE_INT *fli_value_array;
> > > +
> > > +  machine_mode mode = GET_MODE (x);
> > > +
> > > +  if (!TARGET_ZFA
> > > +      || !CONST_DOUBLE_P(x)
> > > +      || mode == VOIDmode
> > > +      || (mode == HFmode && !TARGET_ZFH)
> > > +      || (mode == SFmode && !TARGET_HARD_FLOAT)
> > > +      || (mode == DFmode && !TARGET_DOUBLE_FLOAT))
> > > +    return -1;
> > Do we also need to check Z[FDH]INX too?
> >
> > Otherwise it looks pretty good.  We just need to wait for everything to
> > freeze and finalization on the assembler interface.
> >
> > jeff
>
> Yes, you are right, we also need to check Z[FDH]INX. I will send a patch
> again to fix it after others give some review comments.
>
> Jin
Vineet Gupta Aug. 9, 2023, 6:11 p.m. UTC | #6
Hi Jin Ma,

On 5/16/23 00:06, jinma via Gcc-patches wrote:
> On 5/15/23 07:16, Jin Ma wrote:
>>
>> Do we also need to check Z[FDH]INX too?
>>
>> Otherwise it looks pretty good.  We just need to wait for everything to
>> freeze and finalization on the assembler interface.
>>
>> jeff
> Yes, you are right, we also need to check Z[FDH]INX. I will send a patch
> again to fix it after others give some review comments.

Can we please revisit this and get this merged upstream.
Seems like gcc is supporting frozen but not ratified extensions.

Thx,
-Vineet
Jin Ma Aug. 11, 2023, 3:49 p.m. UTC | #7
> Hi Jin Ma,
> 
> On 5/16/23 00:06, jinma via Gcc-patches wrote:
> > On 5/15/23 07:16, Jin Ma wrote:
> >>
> >> Do we also need to check Z[FDH]INX too?
> >>
> >> Otherwise it looks pretty good.  We just need to wait for everything to
> >> freeze and finalization on the assembler interface.
> >>
> >> jeff
> > Yes, you are right, we also need to check Z[FDH]INX. I will send a patch
> > again to fix it after others give some review comments.
> 
> Can we please revisit this and get this merged upstream.
> Seems like gcc is supporting frozen but not ratified extensions.
> 
> Thx,
> -Vineet

OK, I will check and resend a patch about this in a few days.

Thanks,
Jin
Jin Ma Aug. 14, 2023, 6 a.m. UTC | #8
> > Hi Jin Ma,
> > 
> > On 5/16/23 00:06, jinma via Gcc-patches wrote:
> > > On 5/15/23 07:16, Jin Ma wrote:
> > >>
> > >> Do we also need to check Z[FDH]INX too?
> > >>
> > >> Otherwise it looks pretty good.  We just need to wait for everything to
> > >> freeze and finalization on the assembler interface.
> > >>
> > >> jeff
> > > Yes, you are right, we also need to check Z[FDH]INX. I will send a patch
> > > again to fix it after others give some review comments.
> > 
> > Can we please revisit this and get this merged upstream.
> > Seems like gcc is supporting frozen but not ratified extensions.
> > 
> > Thx,
> > -Vineet
> 
> OK, I will check and resend a patch about this in a few days.
> 
> Thanks,
> Jin

Done, and please review again. Compared with the v9 version two months ago,
the previous review comments have been modified. At the same time, the variable
riscv_zfa_subext have been added to riscv.opt to enable zfa extension.
Jin Ma Aug. 14, 2023, 6:10 a.m. UTC | #9
Additional links:
v10, the patch that needs to be reviewed again:
http://patchwork.ozlabs.org/project/gcc/patch/20230814055033.1995-1-jinma@linux.alibaba.com/

v9 and the previous review comments:
http://patchwork.ozlabs.org/project/gcc/patch/20230515131628.953-1-jinma@linux.alibaba.com/

Zfa patch in master branch of binutils-gdb
https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=1f3fc45bddc7147a2e59346a59290094137ef1e1
Jeff Law Aug. 14, 2023, 10:11 p.m. UTC | #10
On 8/14/23 00:10, Jin Ma wrote:
> Additional links:
> v10, the patch that needs to be reviewed again:
> http://patchwork.ozlabs.org/project/gcc/patch/20230814055033.1995-1-jinma@linux.alibaba.com/
> 
> v9 and the previous review comments:
> http://patchwork.ozlabs.org/project/gcc/patch/20230515131628.953-1-jinma@linux.alibaba.com/
> 
> Zfa patch in master branch of binutils-gdb
> https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=1f3fc45bddc7147a2e59346a59290094137ef1e1
Will do.  We'll also have to evaluate against Tsukasa's work.  As we saw 
with Zicond there may be cases that are better handled by one vs the 
other and we may end up taking pieces from both.

jeff
diff mbox series

Patch

diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index 3a285dfbff0..550f6796e98 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -217,6 +217,8 @@  static const struct riscv_ext_version riscv_ext_version_table[] =
   {"zfh",       ISA_SPEC_CLASS_NONE, 1, 0},
   {"zfhmin",    ISA_SPEC_CLASS_NONE, 1, 0},
 
+  {"zfa",     ISA_SPEC_CLASS_NONE, 0, 2},
+
   {"zmmul", ISA_SPEC_CLASS_NONE, 1, 0},
 
   {"svinval", ISA_SPEC_CLASS_NONE, 1, 0},
@@ -1260,6 +1262,8 @@  static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
   {"zfhmin",    &gcc_options::x_riscv_zf_subext, MASK_ZFHMIN},
   {"zfh",       &gcc_options::x_riscv_zf_subext, MASK_ZFH},
 
+  {"zfa",       &gcc_options::x_riscv_zf_subext, MASK_ZFA},
+
   {"zmmul", &gcc_options::x_riscv_zm_subext, MASK_ZMMUL},
 
   {"svinval", &gcc_options::x_riscv_sv_subext, MASK_SVINVAL},
diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index c448e6b37e9..06d0cd47c3c 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -118,6 +118,19 @@  (define_constraint "T"
   (and (match_operand 0 "move_operand")
        (match_test "CONSTANT_P (op)")))
 
+;; Zfa constraints.
+
+(define_constraint "zfli"
+  "A floating point number that can be loaded using instruction `fli` in zfa."
+  (and (match_code "const_double")
+       (match_test "(riscv_float_const_rtx_index_for_fli (op) != -1)")))
+
+(define_register_constraint "zmvf" "(TARGET_ZFA || TARGET_XTHEADFMV) ? FP_REGS : NO_REGS"
+  "A floating-point register for ZFA or XTheadFmv.")
+
+(define_register_constraint "zmvr" "(TARGET_ZFA || TARGET_XTHEADFMV) ? GR_REGS : NO_REGS"
+  "An integer register for  ZFA or XTheadFmv.")
+
 ;; Vector constraints.
 
 (define_register_constraint "vr" "TARGET_VECTOR ? V_REGS : NO_REGS"
@@ -180,11 +193,3 @@  (define_memory_constraint "Wdm"
   "Vector duplicate memory operand"
   (and (match_code "mem")
        (match_code "reg" "0")))
-
-;; Vendor ISA extension constraints.
-
-(define_register_constraint "th_f_fmv" "TARGET_XTHEADFMV ? FP_REGS : NO_REGS"
-  "A floating-point register for XTheadFmv.")
-
-(define_register_constraint "th_r_fmv" "TARGET_XTHEADFMV ? GR_REGS : NO_REGS"
-  "An integer register for XTheadFmv.")
diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md
index 1d56324df03..1a15999f9e4 100644
--- a/gcc/config/riscv/iterators.md
+++ b/gcc/config/riscv/iterators.md
@@ -294,3 +294,8 @@  (define_int_iterator QUIET_COMPARISON [UNSPEC_FLT_QUIET UNSPEC_FLE_QUIET])
 (define_int_attr quiet_pattern [(UNSPEC_FLT_QUIET "lt") (UNSPEC_FLE_QUIET "le")])
 (define_int_attr QUIET_PATTERN [(UNSPEC_FLT_QUIET "LT") (UNSPEC_FLE_QUIET "LE")])
 
+(define_int_iterator ROUND [UNSPEC_ROUND UNSPEC_FLOOR UNSPEC_CEIL UNSPEC_BTRUNC UNSPEC_ROUNDEVEN UNSPEC_NEARBYINT])
+(define_int_attr round_pattern [(UNSPEC_ROUND "round") (UNSPEC_FLOOR "floor") (UNSPEC_CEIL "ceil")
+				(UNSPEC_BTRUNC "btrunc") (UNSPEC_ROUNDEVEN "roundeven") (UNSPEC_NEARBYINT "nearbyint")])
+(define_int_attr round_rm [(UNSPEC_ROUND "rmm") (UNSPEC_FLOOR "rdn") (UNSPEC_CEIL "rup")
+			   (UNSPEC_BTRUNC "rtz") (UNSPEC_ROUNDEVEN "rne") (UNSPEC_NEARBYINT "dyn")])
diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index 1b2e6de5e1b..7fe02208c58 100644
--- a/gcc/config/riscv/riscv-opts.h
+++ b/gcc/config/riscv/riscv-opts.h
@@ -196,6 +196,9 @@  enum riscv_multilib_select_kind {
 #define TARGET_ZFHMIN ((riscv_zf_subext & MASK_ZFHMIN) != 0)
 #define TARGET_ZFH    ((riscv_zf_subext & MASK_ZFH) != 0)
 
+#define MASK_ZFA   (1 << 0)
+#define TARGET_ZFA    ((riscv_zf_subext & MASK_ZFA) != 0)
+
 #define MASK_ZMMUL      (1 << 0)
 #define TARGET_ZMMUL    ((riscv_zm_subext & MASK_ZMMUL) != 0)
 
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index bc71f9cbbba..b62ba9562b0 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -40,6 +40,7 @@  enum riscv_symbol_type {
 /* Routines implemented in riscv.cc.  */
 extern enum riscv_symbol_type riscv_classify_symbolic_expression (rtx);
 extern bool riscv_symbolic_constant_p (rtx, enum riscv_symbol_type *);
+extern int riscv_float_const_rtx_index_for_fli (rtx);
 extern int riscv_regno_mode_ok_for_base_p (int, machine_mode, bool);
 extern int riscv_address_insns (rtx, machine_mode, bool);
 extern int riscv_const_insns (rtx);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index a770fdfaa0e..2d5e1bf4c40 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -813,6 +813,137 @@  static int riscv_symbol_insns (enum riscv_symbol_type type)
     }
 }
 
+/* Immediate values loaded by the FLI.S instruction in Chapter 25 of the latest RISC-V ISA
+   Manual draft. For details, please see:
+   https://github.com/riscv/riscv-isa-manual/releases/tag/isa-449cd0c  */
+
+static unsigned HOST_WIDE_INT fli_value_hf[32] =
+{
+  0xbcp8, 0x4p8, 0x1p8, 0x2p8, 0x1cp8, 0x20p8, 0x2cp8, 0x30p8,
+  0x34p8, 0x35p8, 0x36p8, 0x37p8, 0x38p8, 0x39p8, 0x3ap8, 0x3bp8,
+  0x3cp8, 0x3dp8, 0x3ep8, 0x3fp8, 0x40p8, 0x41p8, 0x42p8, 0x44p8,
+  0x48p8, 0x4cp8, 0x58p8, 0x5cp8, 0x78p8,
+  /* Only used for filling, ensuring that 29 and 30 of HF are the same.  */
+  0x78p8,
+  0x7cp8, 0x7ep8
+};
+
+static unsigned HOST_WIDE_INT fli_value_sf[32] =
+{
+  0xbf8p20, 0x008p20, 0x378p20, 0x380p20, 0x3b8p20, 0x3c0p20, 0x3d8p20, 0x3e0p20,
+  0x3e8p20, 0x3eap20, 0x3ecp20, 0x3eep20, 0x3f0p20, 0x3f2p20, 0x3f4p20, 0x3f6p20,
+  0x3f8p20, 0x3fap20, 0x3fcp20, 0x3fep20, 0x400p20, 0x402p20, 0x404p20, 0x408p20,
+  0x410p20, 0x418p20, 0x430p20, 0x438p20, 0x470p20, 0x478p20, 0x7f8p20, 0x7fcp20
+};
+
+static unsigned HOST_WIDE_INT fli_value_df[32] =
+{
+  0xbff0p48, 0x10p48, 0x3ef0p48, 0x3f00p48,
+  0x3f70p48, 0x3f80p48, 0x3fb0p48, 0x3fc0p48,
+  0x3fd0p48, 0x3fd4p48, 0x3fd8p48, 0x3fdcp48,
+  0x3fe0p48, 0x3fe4p48, 0x3fe8p48, 0x3fecp48,
+  0x3ff0p48, 0x3ff4p48, 0x3ff8p48, 0x3ffcp48,
+  0x4000p48, 0x4004p48, 0x4008p48, 0x4010p48,
+  0x4020p48, 0x4030p48, 0x4060p48, 0x4070p48,
+  0x40e0p48, 0x40f0p48, 0x7ff0p48, 0x7ff8p48
+};
+
+/* Display floating-point values at the assembly level, which is consistent
+   with the zfa extension of llvm:   */
+
+const char *fli_value_print[32] =
+{
+  "-1.0", "min", "1.52587890625e-05", "3.0517578125e-05", "0.00390625", "0.0078125", "0.0625", "0.125",
+  "0.25", "0.3125", "0.375", "0.4375", "0.5", "0.625", "0.75", "0.875",
+  "1.0", "1.25", "1.5", "1.75", "2.0", "2.5", "3.0", "4.0",
+  "8.0", "16.0", "128.0", "256.0", "32768.0", "65536.0", "inf", "nan"
+};
+
+/* Return index of the FLI instruction table if rtx X is an immediate constant that can
+   be moved using a single FLI instruction in zfa extension. Return -1 if not found.  */
+
+int
+riscv_float_const_rtx_index_for_fli (rtx x)
+{
+  unsigned HOST_WIDE_INT *fli_value_array;
+
+  machine_mode mode = GET_MODE (x);
+
+  if (!TARGET_ZFA
+      || !CONST_DOUBLE_P(x)
+      || mode == VOIDmode
+      || (mode == HFmode && !TARGET_ZFH)
+      || (mode == SFmode && !TARGET_HARD_FLOAT)
+      || (mode == DFmode && !TARGET_DOUBLE_FLOAT))
+    return -1;
+
+  if (!SCALAR_FLOAT_MODE_P (mode)
+      || GET_MODE_BITSIZE (mode).to_constant () > HOST_BITS_PER_WIDE_INT
+      /* Only support up to DF mode.  */
+      || GET_MODE_BITSIZE (mode).to_constant () > GET_MODE_BITSIZE (DFmode))
+    return -1;
+
+  unsigned HOST_WIDE_INT ival = 0;
+
+  long res[2];
+  real_to_target (res,
+		  CONST_DOUBLE_REAL_VALUE (x),
+		  REAL_MODE_FORMAT (mode));
+
+  if (mode == DFmode)
+    {
+      int order = BYTES_BIG_ENDIAN ? 1 : 0;
+      ival = zext_hwi (res[order], 32);
+      ival |= (zext_hwi (res[1 - order], 32) << 32);
+
+      /* When the lower 32 bits are not all 0, it is impossible to be in the table.  */
+      if (ival & 0xffffffff)
+	return -1;
+    }
+  else
+      ival = zext_hwi (res[0], 32);
+
+  switch (mode)
+    {
+      case E_HFmode:
+	fli_value_array = fli_value_hf;
+	break;
+      case E_SFmode:
+	fli_value_array = fli_value_sf;
+	break;
+      case E_DFmode:
+	fli_value_array = fli_value_df;
+	break;
+      default:
+	return -1;
+    }
+
+  if (fli_value_array[0] == ival)
+    return 0;
+
+  if (fli_value_array[1] == ival)
+    return 1;
+
+  /* Perform a binary search to find target index.  */
+  unsigned l, r, m;
+
+  l = 2;
+  r = 31;
+
+  while (l <= r)
+    {
+      m = (l + r) / 2;
+      if (fli_value_array[m] == ival)
+	return m;
+      else if (fli_value_array[m] < ival)
+	l = m+1;
+      else
+	r = m-1;
+    }
+
+  return -1;
+}
+
 /* Implement TARGET_LEGITIMATE_CONSTANT_P.  */
 
 static bool
@@ -840,6 +971,9 @@  riscv_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
   if (GET_CODE (x) == HIGH)
     return true;
 
+  if (satisfies_constraint_zfli (x))
+   return true;
+
   split_const (x, &base, &offset);
   if (riscv_symbolic_constant_p (base, &type))
     {
@@ -1266,6 +1400,10 @@  riscv_const_insns (rtx x)
       }
 
     case CONST_DOUBLE:
+      /* See if we can use FMV directly.  */
+      if (satisfies_constraint_zfli (x))
+	return 1;
+
       /* We can use x0 to load floating-point zero.  */
       return x == CONST0_RTX (GET_MODE (x)) ? 1 : 0;
     case CONST_VECTOR:
@@ -1824,6 +1962,12 @@  riscv_legitimize_const_move (machine_mode mode, rtx dest, rtx src)
       return;
     }
 
+  if (satisfies_constraint_zfli (src))
+    {
+      riscv_emit_set (dest, src);
+      return;
+    }
+
   /* Split moves of symbolic constants into high/low pairs.  */
   if (riscv_split_symbol (dest, src, MAX_MACHINE_MODE, &src))
     {
@@ -2847,6 +2991,10 @@  riscv_split_64bit_move_p (rtx dest, rtx src)
   if (TARGET_64BIT)
     return false;
 
+  /* There is no need to split if the FLI instruction in the `Zfa` extension can be used.  */
+  if (satisfies_constraint_zfli (src))
+    return false;
+
   /* Allow FPR <-> FPR and FPR <-> MEM moves, and permit the special case
      of zeroing an FPR with FCVT.D.W.  */
   if (TARGET_DOUBLE_FLOAT
@@ -2866,22 +3014,36 @@  riscv_split_64bit_move_p (rtx dest, rtx src)
 void
 riscv_split_doubleword_move (rtx dest, rtx src)
 {
-  /* XTheadFmv has instructions for accessing the upper bits of a double.  */
-  if (!TARGET_64BIT && TARGET_XTHEADFMV)
+  /* ZFA or XTheadFmv has instructions for accessing the upper bits of a double.  */
+  if (!TARGET_64BIT && (TARGET_ZFA || TARGET_XTHEADFMV))
     {
       if (FP_REG_RTX_P (dest))
 	{
 	  rtx low_src = riscv_subword (src, false);
 	  rtx high_src = riscv_subword (src, true);
-	  emit_insn (gen_th_fmv_hw_w_x (dest, high_src, low_src));
+
+	  if (TARGET_ZFA)
+	    emit_insn (gen_movdfsisi3_rv32 (dest, high_src, low_src));
+	  else
+	    emit_insn (gen_th_fmv_hw_w_x (dest, high_src, low_src));
 	  return;
 	}
       if (FP_REG_RTX_P (src))
 	{
 	  rtx low_dest = riscv_subword (dest, false);
 	  rtx high_dest = riscv_subword (dest, true);
-	  emit_insn (gen_th_fmv_x_w (low_dest, src));
-	  emit_insn (gen_th_fmv_x_hw (high_dest, src));
+
+	  if (TARGET_ZFA)
+	    {
+	      emit_insn (gen_movsidf2_low_rv32 (low_dest, src));
+	      emit_insn (gen_movsidf2_high_rv32 (high_dest, src));
+	      return;
+	    }
+	  else
+	    {
+	      emit_insn (gen_th_fmv_x_w (low_dest, src));
+	      emit_insn (gen_th_fmv_x_hw (high_dest, src));
+	    }
 	  return;
 	}
     }
@@ -3045,6 +3207,17 @@  riscv_output_move (rtx dest, rtx src)
 	  case 8:
 	    return "fld\t%0,%1";
 	  }
+
+      if (src_code == CONST_DOUBLE && satisfies_constraint_zfli (src))
+	switch (width)
+	  {
+	    case 2:
+	      return "fli.h\t%0,%1";
+	    case 4:
+	      return "fli.s\t%0,%1";
+	    case 8:
+	      return "fli.d\t%0,%1";
+	  }
     }
   if (dest_code == REG && GP_REG_P (REGNO (dest)) && src_code == CONST_POLY_INT)
     {
@@ -4671,6 +4844,24 @@  riscv_print_operand (FILE *file, rtx op, int letter)
 	    output_address (mode, XEXP (op, 0));
 	  break;
 
+	case CONST_DOUBLE:
+	  {
+	    if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
+	      {
+		fputs (reg_names[GP_REG_FIRST], file);
+		break;
+	      }
+
+	    int fli_index = riscv_float_const_rtx_index_for_fli (op);
+	    if (fli_index == -1 || fli_index > 31)
+	      {
+		output_operand_lossage ("invalid use of '%%%c'", letter);
+		break;
+	      }
+	    asm_fprintf (file, "%s", fli_value_print[fli_index]);
+	    break;
+	  }
+
 	default:
 	  if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
 	    fputs (reg_names[GP_REG_FIRST], file);
@@ -6033,7 +6224,8 @@  riscv_secondary_memory_needed (machine_mode mode, reg_class_t class1,
   return (!riscv_v_ext_mode_p (mode)
 	  && GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD
 	  && (class1 == FP_REGS) != (class2 == FP_REGS)
-	  && !TARGET_XTHEADFMV);
+	  && !TARGET_XTHEADFMV
+	  && !TARGET_ZFA);
 }
 
 /* Implement TARGET_REGISTER_MOVE_COST.  */
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 7065e68c0b7..6f95a5c1b4a 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -55,10 +55,19 @@  (define_c_enum "unspec" [
   UNSPEC_FLT_QUIET
   UNSPEC_FLE_QUIET
   UNSPEC_COPYSIGN
+  UNSPEC_RINT
+  UNSPEC_ROUND
+  UNSPEC_FLOOR
+  UNSPEC_CEIL
+  UNSPEC_BTRUNC
+  UNSPEC_ROUNDEVEN
+  UNSPEC_NEARBYINT
   UNSPEC_LRINT
   UNSPEC_LROUND
   UNSPEC_FMIN
   UNSPEC_FMAX
+  UNSPEC_FMINM
+  UNSPEC_FMAXM
 
   ;; Stack tie
   UNSPEC_TIE
@@ -1290,6 +1299,26 @@  (define_insn "neg<mode>2"
 ;;
 ;;  ....................
 
+(define_insn "fminm<mode>3"
+  [(set (match_operand:ANYF                    0 "register_operand" "=f")
+	(unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f"))
+		      (use (match_operand:ANYF 2 "register_operand" " f"))]
+		     UNSPEC_FMINM))]
+  "TARGET_HARD_FLOAT && TARGET_ZFA"
+  "fminm.<fmt>\t%0,%1,%2"
+  [(set_attr "type" "fmove")
+   (set_attr "mode" "<UNITMODE>")])
+
+(define_insn "fmaxm<mode>3"
+  [(set (match_operand:ANYF                    0 "register_operand" "=f")
+	(unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f"))
+		      (use (match_operand:ANYF 2 "register_operand" " f"))]
+		     UNSPEC_FMAXM))]
+  "TARGET_HARD_FLOAT && TARGET_ZFA"
+  "fmaxm.<fmt>\t%0,%1,%2"
+  [(set_attr "type" "fmove")
+   (set_attr "mode" "<UNITMODE>")])
+
 (define_insn "fmin<mode>3"
   [(set (match_operand:ANYF                    0 "register_operand" "=f")
 	(unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f"))
@@ -1566,13 +1595,13 @@  (define_expand "movhf"
 })
 
 (define_insn "*movhf_hardfloat"
-  [(set (match_operand:HF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*r,  *r,*r,*m")
-	(match_operand:HF 1 "move_operand"         " f,G,m,f,G,*r,*f,*G*r,*m,*r"))]
+  [(set (match_operand:HF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
+	(match_operand:HF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
   "TARGET_ZFHMIN
    && (register_operand (operands[0], HFmode)
        || reg_or_0_operand (operands[1], HFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
    (set_attr "mode" "HF")])
 
 (define_insn "*movhf_softfloat"
@@ -1638,6 +1667,26 @@  (define_insn "l<rint_pattern><ANYF:mode><GPR:mode>2"
   [(set_attr "type" "fcvt")
    (set_attr "mode" "<ANYF:MODE>")])
 
+(define_insn "<round_pattern><ANYF:mode>2"
+  [(set (match_operand:ANYF     0 "register_operand" "=f")
+	(unspec:ANYF
+	    [(match_operand:ANYF 1 "register_operand" " f")]
+	ROUND))]
+  "TARGET_HARD_FLOAT && TARGET_ZFA"
+  "fround.<ANYF:fmt>\t%0,%1,<round_rm>"
+  [(set_attr "type" "fcvt")
+   (set_attr "mode" "<ANYF:MODE>")])
+
+(define_insn "rint<ANYF:mode>2"
+  [(set (match_operand:ANYF     0 "register_operand" "=f")
+	(unspec:ANYF
+	    [(match_operand:ANYF 1 "register_operand" " f")]
+	UNSPEC_RINT))]
+  "TARGET_HARD_FLOAT && TARGET_ZFA"
+  "froundnx.<ANYF:fmt>\t%0,%1"
+  [(set_attr "type" "fcvt")
+   (set_attr "mode" "<ANYF:MODE>")])
+
 ;;
 ;;  ....................
 ;;
@@ -1897,13 +1946,13 @@  (define_expand "movsf"
 })
 
 (define_insn "*movsf_hardfloat"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*r,  *r,*r,*m")
-	(match_operand:SF 1 "move_operand"         " f,G,m,f,G,*r,*f,*G*r,*m,*r"))]
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
+	(match_operand:SF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
   "TARGET_HARD_FLOAT
    && (register_operand (operands[0], SFmode)
        || reg_or_0_operand (operands[1], SFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
    (set_attr "mode" "SF")])
 
 (define_insn "*movsf_softfloat"
@@ -1931,23 +1980,23 @@  (define_expand "movdf"
 ;; In RV32, we lack fmv.x.d and fmv.d.x.  Go through memory instead.
 ;; (However, we can still use fcvt.d.w to zero a floating-point register.)
 (define_insn "*movdf_hardfloat_rv32"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*th_f_fmv,*th_r_fmv,  *r,*r,*m")
-	(match_operand:DF 1 "move_operand"         " f,G,m,f,G,*th_r_fmv,*th_f_fmv,*r*G,*m,*r"))]
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*zmvf,*zmvr,  *r,*r,*m")
+	(match_operand:DF 1 "move_operand"         " f,zfli,G,m,f,G,*zmvr,*zmvf,*r*G,*m,*r"))]
   "!TARGET_64BIT && TARGET_DOUBLE_FLOAT
    && (register_operand (operands[0], DFmode)
        || reg_or_0_operand (operands[1], DFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
    (set_attr "mode" "DF")])
 
 (define_insn "*movdf_hardfloat_rv64"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*r,  *r,*r,*m")
-	(match_operand:DF 1 "move_operand"         " f,G,m,f,G,*r,*f,*r*G,*m,*r"))]
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
+	(match_operand:DF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*r*G,*m,*r"))]
   "TARGET_64BIT && TARGET_DOUBLE_FLOAT
    && (register_operand (operands[0], DFmode)
        || reg_or_0_operand (operands[1], DFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
    (set_attr "mode" "DF")])
 
 (define_insn "*movdf_softfloat"
@@ -1960,6 +2009,39 @@  (define_insn "*movdf_softfloat"
   [(set_attr "move_type" "move,load,store")
    (set_attr "mode" "DF")])
 
+(define_insn "movsidf2_low_rv32"
+  [(set (match_operand:SI      0 "register_operand" "=  r")
+	(truncate:SI
+	    (match_operand:DF 1 "register_operand"  "zmvf")))]
+  "TARGET_HARD_FLOAT && !TARGET_64BIT && TARGET_ZFA"
+  "fmv.x.w\t%0,%1"
+  [(set_attr "move_type" "fmove")
+   (set_attr "mode" "DF")])
+
+
+(define_insn "movsidf2_high_rv32"
+  [(set (match_operand:SI      0 "register_operand"    "=  r")
+	(truncate:SI
+            (lshiftrt:DF
+                (match_operand:DF 1 "register_operand" "zmvf")
+                (const_int 32))))]
+  "TARGET_HARD_FLOAT && !TARGET_64BIT && TARGET_ZFA"
+  "fmvh.x.d\t%0,%1"
+  [(set_attr "move_type" "fmove")
+   (set_attr "mode" "DF")])
+
+(define_insn "movdfsisi3_rv32"
+  [(set (match_operand:DF      0 "register_operand"    "=  f")
+	(plus:DF
+            (match_operand:SI 2 "register_operand"     "zmvr")
+            (ashift:SI
+                (match_operand:SI 1 "register_operand" "zmvr")
+                (const_int 32))))]
+  "TARGET_HARD_FLOAT && !TARGET_64BIT && TARGET_ZFA"
+  "fmvp.d.x\t%0,%2,%1"
+  [(set_attr "move_type" "fmove")
+   (set_attr "mode" "DF")])
+
 (define_split
   [(set (match_operand:MOVE64 0 "nonimmediate_operand")
 	(match_operand:MOVE64 1 "move_operand"))]
@@ -2552,16 +2634,23 @@  (define_expand "f<quiet_pattern>_quiet<ANYF:mode><X:mode>4"
   rtx op0 = operands[0];
   rtx op1 = operands[1];
   rtx op2 = operands[2];
-  rtx tmp = gen_reg_rtx (SImode);
-  rtx cmp = gen_rtx_<QUIET_PATTERN> (<X:MODE>mode, op1, op2);
-  rtx frflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, const0_rtx),
-					 UNSPECV_FRFLAGS);
-  rtx fsflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, tmp),
-					 UNSPECV_FSFLAGS);
-
-  emit_insn (gen_rtx_SET (tmp, frflags));
-  emit_insn (gen_rtx_SET (op0, cmp));
-  emit_insn (fsflags);
+
+  if (TARGET_ZFA)
+    emit_insn (gen_f<quiet_pattern>_quiet<ANYF:mode><X:mode>4_zfa(op0, op1, op2));
+  else
+    {
+      rtx tmp = gen_reg_rtx (SImode);
+      rtx cmp = gen_rtx_<QUIET_PATTERN> (<X:MODE>mode, op1, op2);
+      rtx frflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, const0_rtx),
+					     UNSPECV_FRFLAGS);
+      rtx fsflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, tmp),
+					     UNSPECV_FSFLAGS);
+
+      emit_insn (gen_rtx_SET (tmp, frflags));
+      emit_insn (gen_rtx_SET (op0, cmp));
+      emit_insn (fsflags);
+    }
+
   if (HONOR_SNANS (<ANYF:MODE>mode))
     emit_insn (gen_rtx_UNSPEC_VOLATILE (<ANYF:MODE>mode,
 					gen_rtvec (2, op1, op2),
@@ -2569,6 +2658,18 @@  (define_expand "f<quiet_pattern>_quiet<ANYF:mode><X:mode>4"
   DONE;
 })
 
+(define_insn "f<quiet_pattern>_quiet<ANYF:mode><X:mode>4_zfa"
+   [(set (match_operand:X      0 "register_operand" "=r")
+	 (unspec:X
+	  [(match_operand:ANYF 1 "register_operand" " f")
+	   (match_operand:ANYF 2 "register_operand" " f")]
+	  QUIET_COMPARISON))]
+  "TARGET_HARD_FLOAT && TARGET_ZFA"
+  "f<quiet_pattern>q.<fmt>\t%0,%1,%2"
+  [(set_attr "type" "fcmp")
+   (set_attr "mode" "<UNITMODE>")
+   (set (attr "length") (const_int 16))])
+
 (define_insn "*seq_zero_<X:mode><GPR:mode>"
   [(set (match_operand:GPR       0 "register_operand" "=r")
 	(eq:GPR (match_operand:X 1 "register_operand" " r")
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq-rv32.c b/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq-rv32.c
new file mode 100644
index 00000000000..26895b76fa4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq-rv32.c
@@ -0,0 +1,19 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv32imafdc_zfa -mabi=ilp32d -O2" } */
+
+extern void abort(void);
+extern float a, b;
+extern double c, d;
+
+void 
+foo()
+{
+  if ((__builtin_isless(a, b) ||  __builtin_islessequal(c, d))
+      && (__builtin_islessequal(a, b)|| __builtin_isless(c, d)))
+    abort();
+}
+
+/* { dg-final { scan-assembler-times "fleq.s" 1 } } */
+/* { dg-final { scan-assembler-times "fltq.s" 1 } } */
+/* { dg-final { scan-assembler-times "fleq.d" 1 } } */
+/* { dg-final { scan-assembler-times "fltq.d" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c b/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c
new file mode 100644
index 00000000000..4ccd6a7dd78
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c
@@ -0,0 +1,19 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imafdc_zfa -mabi=lp64d -O2" } */
+
+extern void abort(void);
+extern float a, b;
+extern double c, d;
+
+void 
+foo()
+{
+  if ((__builtin_isless(a, b) ||  __builtin_islessequal(c, d))
+      && (__builtin_islessequal(a, b)|| __builtin_isless(c, d)))
+    abort();
+}
+
+/* { dg-final { scan-assembler-times "fleq.s" 1 } } */
+/* { dg-final { scan-assembler-times "fltq.s" 1 } } */
+/* { dg-final { scan-assembler-times "fleq.d" 1 } } */
+/* { dg-final { scan-assembler-times "fltq.d" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-rv32.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-rv32.c
new file mode 100644
index 00000000000..c4da04797aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-rv32.c
@@ -0,0 +1,79 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv32imafdc_zfa -mabi=ilp32d -O0" } */
+
+void foo_float32 ()
+{
+  volatile float a;
+  a = -1.0;
+  a = 1.1754944e-38;
+  a = 1.0/(1 << 16);
+  a = 1.0/(1 << 15);
+  a = 1.0/(1 << 8);
+  a = 1.0/(1 << 7);
+  a = 1.0/(1 << 4);
+  a = 1.0/(1 << 3);
+  a = 1.0/(1 << 2);
+  a = 0.3125;
+  a = 0.375;
+  a = 0.4375;
+  a = 0.5;
+  a = 0.625;
+  a = 0.75;
+  a = 0.875;
+  a = 1.0;
+  a = 1.25;
+  a = 1.5;
+  a = 1.75;
+  a = 2.0;
+  a = 2.5;
+  a = 3.0;
+  a = 1.0*(1 << 2);
+  a = 1.0*(1 << 3);
+  a = 1.0*(1 << 4);
+  a = 1.0*(1 << 7);
+  a = 1.0*(1 << 8);
+  a = 1.0*(1 << 15);
+  a = 1.0*(1 << 16);
+  a = __builtin_inff ();
+  a = __builtin_nanf ("");
+}
+
+void foo_double64 ()
+{
+  volatile double a;
+  a = -1.0;
+  a = 2.2250738585072014E-308;
+  a = 1.0/(1 << 16);
+  a = 1.0/(1 << 15);
+  a = 1.0/(1 << 8);
+  a = 1.0/(1 << 7);
+  a = 1.0/(1 << 4);
+  a = 1.0/(1 << 3);
+  a = 1.0/(1 << 2);
+  a = 0.3125;
+  a = 0.375;
+  a = 0.4375;
+  a = 0.5;
+  a = 0.625;
+  a = 0.75;
+  a = 0.875;
+  a = 1.0;
+  a = 1.25;
+  a = 1.5;
+  a = 1.75;
+  a = 2.0;
+  a = 2.5;
+  a = 3.0;
+  a = 1.0*(1 << 2);
+  a = 1.0*(1 << 3);
+  a = 1.0*(1 << 4);
+  a = 1.0*(1 << 7);
+  a = 1.0*(1 << 8);
+  a = 1.0*(1 << 15);
+  a = 1.0*(1 << 16);
+  a = __builtin_inf ();
+  a = __builtin_nan ("");
+}
+
+/* { dg-final { scan-assembler-times "fli.s" 32 } } */
+/* { dg-final { scan-assembler-times "fli.d" 32 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh-rv32.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh-rv32.c
new file mode 100644
index 00000000000..bcffe9d2c82
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh-rv32.c
@@ -0,0 +1,41 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv32imafdc_zfa_zfh -mabi=ilp32d -O0" } */
+
+void foo_float16 ()
+{
+  volatile _Float16 a;
+  a = -1.0;
+  a = 6.104E-5;
+  a = 1.0/(1 << 16);
+  a = 1.0/(1 << 15);
+  a = 1.0/(1 << 8);
+  a = 1.0/(1 << 7);
+  a = 1.0/(1 << 4);
+  a = 1.0/(1 << 3);
+  a = 1.0/(1 << 2);
+  a = 0.3125;
+  a = 0.375;
+  a = 0.4375;
+  a = 0.5;
+  a = 0.625;
+  a = 0.75;
+  a = 0.875;
+  a = 1.0;
+  a = 1.25;
+  a = 1.5;
+  a = 1.75;
+  a = 2.0;
+  a = 2.5;
+  a = 3.0;
+  a = 1.0*(1 << 2);
+  a = 1.0*(1 << 3);
+  a = 1.0*(1 << 4);
+  a = 1.0*(1 << 7);
+  a = 1.0*(1 << 8);
+  a = 1.0*(1 << 15);
+  a = 1.0*(1 << 16);
+  a = __builtin_inff16 ();
+  a = __builtin_nanf16 ("");
+}
+
+/* { dg-final { scan-assembler-times "fli.h" 32 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c
new file mode 100644
index 00000000000..a493ca95f0c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c
@@ -0,0 +1,41 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imafdc_zfa_zfh -mabi=lp64d -O0" } */
+
+void foo_float16 ()
+{
+  volatile _Float16 a;
+  a = -1.0;
+  a = 6.104e-5;
+  a = 1.0/(1 << 16);
+  a = 1.0/(1 << 15);
+  a = 1.0/(1 << 8);
+  a = 1.0/(1 << 7);
+  a = 1.0/(1 << 4);
+  a = 1.0/(1 << 3);
+  a = 1.0/(1 << 2);
+  a = 0.3125;
+  a = 0.375;
+  a = 0.4375;
+  a = 0.5;
+  a = 0.625;
+  a = 0.75;
+  a = 0.875;
+  a = 1.0;
+  a = 1.25;
+  a = 1.5;
+  a = 1.75;
+  a = 2.0;
+  a = 2.5;
+  a = 3.0;
+  a = 1.0*(1 << 2);
+  a = 1.0*(1 << 3);
+  a = 1.0*(1 << 4);
+  a = 1.0*(1 << 7);
+  a = 1.0*(1 << 8);
+  a = 1.0*(1 << 15);
+  a = 1.0*(1 << 16);
+  a = __builtin_inff16 ();
+  a = __builtin_nanf16 ("");
+}
+
+/* { dg-final { scan-assembler-times "fli.h" 32 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli.c b/gcc/testsuite/gcc.target/riscv/zfa-fli.c
new file mode 100644
index 00000000000..babb10f21e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fli.c
@@ -0,0 +1,79 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imafdc_zfa -mabi=lp64d -O0" } */
+
+void foo_float32 ()
+{
+  volatile float a;
+  a = -1.0;
+  a = 1.1754944e-38;
+  a = 1.0/(1 << 16);
+  a = 1.0/(1 << 15);
+  a = 1.0/(1 << 8);
+  a = 1.0/(1 << 7);
+  a = 1.0/(1 << 4);
+  a = 1.0/(1 << 3);
+  a = 1.0/(1 << 2);
+  a = 0.3125;
+  a = 0.375;
+  a = 0.4375;
+  a = 0.5;
+  a = 0.625;
+  a = 0.75;
+  a = 0.875;
+  a = 1.0;
+  a = 1.25;
+  a = 1.5;
+  a = 1.75;
+  a = 2.0;
+  a = 2.5;
+  a = 3.0;
+  a = 1.0*(1 << 2);
+  a = 1.0*(1 << 3);
+  a = 1.0*(1 << 4);
+  a = 1.0*(1 << 7);
+  a = 1.0*(1 << 8);
+  a = 1.0*(1 << 15);
+  a = 1.0*(1 << 16);
+  a = __builtin_inff ();
+  a = __builtin_nanf ("");
+}
+
+void foo_double64 ()
+{
+  volatile double a;
+  a = -1.0;
+  a = 2.2250738585072014e-308;
+  a = 1.0/(1 << 16);
+  a = 1.0/(1 << 15);
+  a = 1.0/(1 << 8);
+  a = 1.0/(1 << 7);
+  a = 1.0/(1 << 4);
+  a = 1.0/(1 << 3);
+  a = 1.0/(1 << 2);
+  a = 0.3125;
+  a = 0.375;
+  a = 0.4375;
+  a = 0.5;
+  a = 0.625;
+  a = 0.75;
+  a = 0.875;
+  a = 1.0;
+  a = 1.25;
+  a = 1.5;
+  a = 1.75;
+  a = 2.0;
+  a = 2.5;
+  a = 3.0;
+  a = 1.0*(1 << 2);
+  a = 1.0*(1 << 3);
+  a = 1.0*(1 << 4);
+  a = 1.0*(1 << 7);
+  a = 1.0*(1 << 8);
+  a = 1.0*(1 << 15);
+  a = 1.0*(1 << 16);
+  a = __builtin_inf ();
+  a = __builtin_nan ("");
+}
+
+/* { dg-final { scan-assembler-times "fli.s" 32 } } */
+/* { dg-final { scan-assembler-times "fli.d" 32 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp-rv32.c b/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp-rv32.c
new file mode 100644
index 00000000000..5a52adce36a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp-rv32.c
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv32g_zfa -mabi=ilp32 -O0" } */
+
+double foo(long long a)
+{
+  return (double)(a + 3);
+}
+
+/* { dg-final { scan-assembler-times "fmvp.d.x" 1 } } */
+/* { dg-final { scan-assembler-times "fmvh.x.d" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fround-rv32.c b/gcc/testsuite/gcc.target/riscv/zfa-fround-rv32.c
new file mode 100644
index 00000000000..b53601d6e1f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fround-rv32.c
@@ -0,0 +1,42 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv32imafdc_zfa -mabi=ilp32d -O2" } */
+
+extern float a;
+extern double b;
+
+void foo (float *x, double *y)
+{
+  {
+    *x = __builtin_roundf (a);
+    *y = __builtin_round (b);
+  }
+  {
+    *x = __builtin_floorf (a);
+    *y = __builtin_floor (b);
+  }
+  {
+    *x = __builtin_ceilf (a);
+    *y = __builtin_ceil (b);
+  }
+  {
+    *x = __builtin_truncf (a);
+    *y = __builtin_trunc (b);
+  }
+  {
+    *x = __builtin_roundevenf (a);
+    *y = __builtin_roundeven (b);
+  }
+  {
+    *x = __builtin_nearbyintf (a);
+    *y = __builtin_nearbyint (b);
+  }
+  {
+    *x = __builtin_rintf (a);
+    *y = __builtin_rint (b);
+  }
+}
+
+/* { dg-final { scan-assembler-times "fround.s" 6 } } */
+/* { dg-final { scan-assembler-times "fround.d" 6 } } */
+/* { dg-final { scan-assembler-times "froundnx.s" 1 } } */
+/* { dg-final { scan-assembler-times "froundnx.d" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fround.c b/gcc/testsuite/gcc.target/riscv/zfa-fround.c
new file mode 100644
index 00000000000..c10de82578e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fround.c
@@ -0,0 +1,42 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imafdc_zfa -mabi=lp64d -O2" } */
+
+extern float a;
+extern double b;
+
+void foo (float *x, double *y)
+{
+  {
+    *x = __builtin_roundf (a);
+    *y = __builtin_round (b);
+  }
+  {
+    *x = __builtin_floorf (a);
+    *y = __builtin_floor (b);
+  }
+  {
+    *x = __builtin_ceilf (a);
+    *y = __builtin_ceil (b);
+  }
+  {
+    *x = __builtin_truncf (a);
+    *y = __builtin_trunc (b);
+  }
+  {
+    *x = __builtin_roundevenf (a);
+    *y = __builtin_roundeven (b);
+  }
+  {
+    *x = __builtin_nearbyintf (a);
+    *y = __builtin_nearbyint (b);
+  }
+  {
+    *x = __builtin_rintf (a);
+    *y = __builtin_rint (b);
+  }
+}
+
+/* { dg-final { scan-assembler-times "fround.s" 6 } } */
+/* { dg-final { scan-assembler-times "fround.d" 6 } } */
+/* { dg-final { scan-assembler-times "froundnx.s" 1 } } */
+/* { dg-final { scan-assembler-times "froundnx.d" 1 } } */