Thank you very much for your comments. Since a long time has passed and this is 
an initial version, I will update this patch.
------------------------------------------------------------------
From:Christoph Müllner <christoph.muell...@vrull.eu>
Sent At:2023 Apr. 13 (Thu.) 17:22
To:Jin Ma <ji...@linux.alibaba.com>
Cc:gcc-patches <gcc-patches@gcc.gnu.org>; kito.cheng <kito.ch...@sifive.com>; 
kito.cheng <kito.ch...@gmail.com>; palmer <pal...@dabbelt.com>
Subject:Re: [PATCH v6] RISC-V: Add support for experimental zfa extension.
On Fri, Mar 10, 2023 at 1:41 PM Jin Ma via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> This patch adds the 'Zfa' extension for riscv, which is based on:
> https://github.com/riscv/riscv-isa-manual/commit/d74d99e22d5f68832f70982d867614e2149a3bd7
> latest 'Zfa' change on the master branch of the RISC-V ISA Manual as
> of this writing.
>
> The Wiki Page (details):
> https://github.com/a4lg/binutils-gdb/wiki/riscv_zfa
>
> The binutils-gdb for 'Zfa' extension:
> https://sourceware.org/pipermail/binutils/2022-September/122938.html
>
> Implementation of zfa extension on LLVM:
> https://reviews.llvm.org/rGc0947dc44109252fcc0f68a542fc6ef250d4d3a9
>
> There are three points that need to be discussed here.
> 1. 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 in the compiler.
> 2. The FROUND and FROUNDN instructions in this patch use related functions in 
> the math
> library, such as round, floor, ceil, etc. Since there is no interface for 
> half-precision in
> the math library, the instructions FROUN D.H and FROUNDN X.H have not been 
> implemented for
> the time being. Is it necessary to add a built-in interface belonging to 
> riscv such as
> __builtin_roundhf or __builtin_roundf16 to generate half floating point 
> instructions?
> 3. As far as I know, FMINM and FMAXM instructions correspond to C23 library 
> function fminimum
> and fmaximum. Therefore, I have not dealt with such instructions for the time 
> being, but have
> simply implemented the pattern of fminm<hf\sf\df>3 and fmaxm<hf\sf\df>3. Is 
> it necessary to
> add a built-in interface belonging to riscv such as__builtin_fminm to 
> generate half
> floating-point instructions?
I have rebased and tested this patch.
Here are my observations (with fixes below at the actual code):
* There is a compiler warning because of a missing "fallthrough" comment
* There are merge conflicts with a current master
* The constant operand of the fli instruction uses the constant index
in the rs1-field, but not the constant in hex FP literal form
A patch that addresses these issues can also be found here:
 https://github.com/cmuellner/gcc/tree/riscv-zfa
Additionally I observe the following failing test cases with this patch applied:
 === gcc: Unexpected fails for rv64gc lp64d medlow ===
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -O0 (internal compiler
error: Segmentation fault)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -O0 (test for excess errors)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -O1 (internal compiler
error: Segmentation fault)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -O1 (test for excess errors)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -O2 (internal compiler
error: Segmentation fault)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -O2 (test for excess errors)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -O2 -flto
-fno-use-linker-plugin -flto-partition=none (internal compiler error:
Segmentation fault)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -O2 -flto
-fno-use-linker-plugin -flto-partition=none (test for excess errors)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -O2 -flto
-fuse-linker-plugin -fno-fat-lto-objects (internal compiler error:
Segmentation fault)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -O2 -flto
-fuse-linker-plugin -fno-fat-lto-objects (test for excess errors)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -O3 -g (internal
compiler error: Segmentation fault)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -O3 -g (test for excess errors)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -Os (internal compiler
error: Segmentation fault)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -Os (test for excess errors)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -Og -g (internal
compiler error: Segmentation fault)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -Og -g (test for excess errors)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -Oz (internal compiler
error: Segmentation fault)
FAIL: gcc.target/riscv/zero-scratch-regs-3.c -Oz (test for excess errors)
I have not analysed these ICEs so far.
>
> gcc/ChangeLog:
>
> * common/config/riscv/riscv-common.cc: Add zfa extension.
> * config/riscv/constraints.md (Zf): Constrain the floating point number that 
> the FLI instruction can load.
> * config/riscv/iterators.md (round_pattern): New.
> * config/riscv/predicates.md: Predicate the floating point number that the 
> FLI instruction can load.
> * config/riscv/riscv-opts.h (MASK_ZFA): New.
> (TARGET_ZFA): New.
> * config/riscv/riscv-protos.h (riscv_float_const_rtx_index_for_fli): Get the 
> index of the
> floating-point number that the FLI instruction can load.
> * config/riscv/riscv.cc (find_index_in_array): New.
> (riscv_float_const_rtx_index_for_fli): New.
> (riscv_cannot_force_const_mem): Likewise.
> (riscv_const_insns): Likewise.
> (riscv_legitimize_const_move): Likewise.
> (riscv_split_64bit_move_p): Exclude floating point numbers that can be loaded 
> by FLI instructions.
> (riscv_output_move): Likewise.
> (riscv_memmodel_needs_release_fence): Likewise.
> (riscv_print_operand): Likewise.
> (riscv_secondary_memory_needed): Likewise.
> * config/riscv/riscv.h (GP_REG_RTX_P): New.
> * config/riscv/riscv.md (fminm<mode>3): New.
> (fmaxm<mode>3): New.
> (<round_pattern><ANYF:mode>2): New.
> (rint<ANYF:mode>2): New.
> (f<quiet_pattern>_quiet<ANYF:mode><X:mode>4_zfa): New.
>
> 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 | 7 +
> gcc/config/riscv/iterators.md | 5 +
> gcc/config/riscv/predicates.md | 4 +
> gcc/config/riscv/riscv-opts.h | 3 +
> gcc/config/riscv/riscv-protos.h | 1 +
> gcc/config/riscv/riscv.cc | 168 +++++++++++++++++-
> gcc/config/riscv/riscv.h | 1 +
> gcc/config/riscv/riscv.md | 112 +++++++++---
> .../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 +++++
> 18 files changed, 654 insertions(+), 23 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
>
> diff --git a/gcc/common/config/riscv/riscv-common.cc 
> b/gcc/common/config/riscv/riscv-common.cc
> index ebc1ed7d7e4..8fec3bc71c9 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, 1},
> +
> {"zmmul", ISA_SPEC_CLASS_NONE, 1, 0},
>
> {"svinval", ISA_SPEC_CLASS_NONE, 1, 0},
> @@ -1243,6 +1245,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 fdfcf2380f8..2ba0160934a 100644
> --- a/gcc/config/riscv/constraints.md
> +++ b/gcc/config/riscv/constraints.md
> @@ -118,6 +118,13 @@ (define_constraint "T"
> (and (match_operand 0 "move_operand")
> (match_test "CONSTANT_P (op)")))
>
> +;; Zfa constraints.
> +
> +(define_constraint "Zf"
> + "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)")))
> +
> ;; Vector constraints.
>
> (define_register_constraint "vr" "TARGET_VECTOR ? V_REGS : NO_REGS"
> diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md
> index 5b70ab20758..ef9b1aa9ed3 100644
> --- a/gcc/config/riscv/iterators.md
> +++ b/gcc/config/riscv/iterators.md
> @@ -284,3 +284,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")])
> \ No newline at end of file
> diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
> index 0d9d7701c7e..b16b8d438e3 100644
> --- a/gcc/config/riscv/predicates.md
> +++ b/gcc/config/riscv/predicates.md
> @@ -149,6 +149,10 @@ (define_predicate "move_operand"
> case CONST_POLY_INT:
> return known_eq (rtx_to_poly_int64 (op), BYTES_PER_RISCV_VECTOR);
>
> + case CONST_DOUBLE:
> + return const_0_operand (op, mode)
> + || (riscv_float_const_rtx_index_for_fli (op) != -1);
> +
> case CONST:
> case SYMBOL_REF:
> case LABEL_REF:
> diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
> index ff398c0a2ae..3ae729eec30 100644
> --- a/gcc/config/riscv/riscv-opts.h
> +++ b/gcc/config/riscv/riscv-opts.h
> @@ -172,6 +172,9 @@ enum stack_protector_guard {
> #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 f35aaf35b48..0f5dcba8294 100644
> --- a/gcc/config/riscv/riscv-protos.h
> +++ b/gcc/config/riscv/riscv-protos.h
> @@ -38,6 +38,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 c91fa3101aa..c81a2bf44f5 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -799,6 +799,108 @@ 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/draft-20221217-cb3b9d1 
> */
> +
> +unsigned HOST_WIDE_INT fli_value_hf[32] =
> +{
> + 0xbc00, 0x400, 0x100, 0x200, 0x1c00, 0x2000, 0x2c00, 0x3000,
> + 0x3400, 0x3500, 0x3600, 0x3700, 0x3800, 0x3900, 0x3a00, 0x3b00,
> + 0x3c00, 0x3d00, 0x3e00, 0x3f00, 0x4000, 0x4100, 0x4200, 0x4400,
> + 0x4800, 0x4c00, 0x5800, 0x5c00, 0x7800,
> + /* Only used for filling, ensuring that 29 and 30 of HF are the same. */
> + 0x7800,
> + 0x7c00, 0x7e00,
> +};
> +
> +unsigned HOST_WIDE_INT fli_value_sf[32] =
> +{
> + 0xbf800000, 0x00800000, 0x37800000, 0x38000000, 0x3b800000, 0x3c000000, 
> 0x3d800000, 0x3e000000,
> + 0x3e800000, 0x3ea00000, 0x3ec00000, 0x3ee00000, 0x3f000000, 0x3f200000, 
> 0x3f400000, 0x3f600000,
> + 0x3f800000, 0x3fa00000, 0x3fc00000, 0x3fe00000, 0x40000000, 0x40200000, 
> 0x40400000, 0x40800000,
> + 0x41000000, 0x41800000, 0x43000000, 0x43800000, 0x47000000, 0x47800000, 
> 0x7f800000, 0x7fc00000
> +};
> +
> +unsigned HOST_WIDE_INT fli_value_df[32] =
> +{
> + 0xbff0000000000000, 0x10000000000000, 0x3ef0000000000000, 
> 0x3f00000000000000,
> + 0x3f70000000000000, 0x3f80000000000000, 0x3fb0000000000000, 
> 0x3fc0000000000000,
> + 0x3fd0000000000000, 0x3fd4000000000000, 0x3fd8000000000000, 
> 0x3fdc000000000000,
> + 0x3fe0000000000000, 0x3fe4000000000000, 0x3fe8000000000000, 
> 0x3fec000000000000,
> + 0x3ff0000000000000, 0x3ff4000000000000, 0x3ff8000000000000, 
> 0x3ffc000000000000,
> + 0x4000000000000000, 0x4004000000000000, 0x4008000000000000, 
> 0x4010000000000000,
> + 0x4020000000000000, 0x4030000000000000, 0x4060000000000000, 
> 0x4070000000000000,
> + 0x40e0000000000000, 0x40f0000000000000, 0x7ff0000000000000, 
> 0x7ff8000000000000,
> +};
> +
> +/* Find the index of TARGET in ARRAY, and return -1 if not found. */
> +
> +static int
> +find_index_in_array (unsigned HOST_WIDE_INT target, unsigned HOST_WIDE_INT 
> *array, int len)
> +{
> + if (array == NULL)
> + return -1;
> +
> + for (int i = 0; i < len; i++)
> + {
> + if (target == array[i])
> + return i;
> + }
> + return -1;
> +}
> +
> +/* 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. -1 otherwise. 
> */
> +
> +int
> +riscv_float_const_rtx_index_for_fli (rtx x)
> +{
> + machine_mode mode = GET_MODE (x);
> +
> + if (!TARGET_ZFA || mode == VOIDmode
> + || !CONST_DOUBLE_P(x)
> + || (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);
> + }
> + else
> + ival = zext_hwi (res[0], 32);
> +
> + switch (mode)
> + {
> + case SFmode:
> + return find_index_in_array (ival, fli_value_sf, 32);
> + case DFmode:
> + return find_index_in_array (ival, fli_value_df, 32);
> + case HFmode:
> + return find_index_in_array (ival, fli_value_hf, 32);
> + default:
> + break;
> + }
> + return -1;
> +}
> +
> /* Implement TARGET_LEGITIMATE_CONSTANT_P. */
>
> static bool
> @@ -826,6 +928,9 @@ riscv_cannot_force_const_mem (machine_mode mode 
> ATTRIBUTE_UNUSED, rtx x)
> if (GET_CODE (x) == HIGH)
> return true;
>
> + if (riscv_float_const_rtx_index_for_fli (x) != -1)
> + return true;
> +
> split_const (x, &base, &offset);
> if (riscv_symbolic_constant_p (base, &type))
> {
> @@ -1191,6 +1296,8 @@ riscv_const_insns (rtx x)
> }
>
> case CONST_DOUBLE:
> + if (riscv_float_const_rtx_index_for_fli (x) != -1)
> + return 4;
Here a "/* Fall through. */" is missing to avoid a compiler warning.
> case CONST_VECTOR:
> /* We can use x0 to load floating-point zero. */
> return x == CONST0_RTX (GET_MODE (x)) ? 1 : 0;
> @@ -1727,6 +1834,12 @@ riscv_legitimize_const_move (machine_mode mode, rtx 
> dest, rtx src)
> return;
> }
>
> + if (riscv_float_const_rtx_index_for_fli (src) != -1)
> + {
> + 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, FALSE))
> {
> @@ -2739,12 +2852,19 @@ 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 (TARGET_ZFA && (riscv_float_const_rtx_index_for_fli (src) != -1))
> + 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
> && ((FP_REG_RTX_P (src) && FP_REG_RTX_P (dest))
> || (FP_REG_RTX_P (dest) && MEM_P (src))
> || (FP_REG_RTX_P (src) && MEM_P (dest))
> + || (TARGET_ZFA
> + && ((FP_REG_RTX_P (dest) && GP_REG_RTX_P (src))
> + || (FP_REG_RTX_P (src) && GP_REG_RTX_P (dest))))
> || (FP_REG_RTX_P (dest) && src == CONST0_RTX (GET_MODE (src)))))
> return false;
>
> @@ -2808,6 +2928,8 @@ riscv_output_move (rtx dest, rtx src)
> case 4:
> return "fmv.x.s\t%0,%1";
> case 8:
> + if (!TARGET_64BIT && TARGET_ZFA)
> + return "fmv.x.w\t%0,%1\n\tfmvh.x.d\t%N0,%1";
> return "fmv.x.d\t%0,%1";
> }
>
> @@ -2867,6 +2989,8 @@ riscv_output_move (rtx dest, rtx src)
> case 8:
> if (TARGET_64BIT)
> return "fmv.d.x\t%0,%z1";
> + else if (TARGET_ZFA && src != CONST0_RTX (mode))
> + return "fmvp.d.x\t%0,%1,%N1";
> /* in RV32, we can emulate fmv.d.x %0, x0 using fcvt.d.w */
> gcc_assert (src == CONST0_RTX (mode));
> return "fcvt.d.w\t%0,x0";
> @@ -2919,6 +3043,14 @@ riscv_output_move (rtx dest, rtx src)
> case 8:
> return "fld\t%0,%1";
> }
> +
> + if (src_code == CONST_DOUBLE && (riscv_float_const_rtx_index_for_fli (src) 
> != -1))
> + 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)
> {
> @@ -4222,6 +4354,7 @@ riscv_memmodel_needs_release_fence (enum memmodel model)
> 'S' Print shift-index of single-bit mask OP.
> 'T' Print shift-index of inverted single-bit mask OP.
> '~' Print w if TARGET_64BIT is true; otherwise not print anything.
> + 'N' Print next register.
>
> Note please keep this list and the list in riscv.md in sync. */
>
> @@ -4406,6 +4539,9 @@ riscv_print_operand (FILE *file, rtx op, int letter)
> output_addr_const (file, newop);
> break;
> }
> + case 'N':
> + fputs (reg_names[REGNO (op) + 1], file);
> + break;
> default:
> switch (code)
> {
> @@ -4422,6 +4558,35 @@ 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;
> + }
> +
> + switch (fli_index)
> + {
> + case 1:
> + asm_fprintf (file, "%s", "min");break;
> + case 30:
> + asm_fprintf (file, "%s", "inf");break;
> + case 31:
> + asm_fprintf (file, "%s", "nan");break;
> + default:
> + asm_fprintf (file, "%d", fli_index);break;
This prints the constant-index, but not the constant itself.
We discussed this on the Binutils patch and agreed that we will use
hex floating-point literals.
Something like this should work:
 default:
 {
 char s[60];
 real_to_hexadecimal (s, CONST_DOUBLE_REAL_VALUE (op),
 sizeof (s), 0, 1);
 asm_fprintf (file, "%s", s);
 break;
 }
So, since we know the value is a valid constant, we can just print it.
> + }
> + break;
> + }
> +
> default:
> if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
> fputs (reg_names[GP_REG_FIRST], file);
> @@ -5734,7 +5899,8 @@ riscv_secondary_memory_needed (machine_mode mode, 
> reg_class_t class1,
> {
> return (!riscv_v_ext_vector_mode_p (mode)
> && GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD
> - && (class1 == FP_REGS) != (class2 == FP_REGS));
> + && (class1 == FP_REGS) != (class2 == FP_REGS)
> + && !TARGET_ZFA);
Does not apply on master anymore.
New code:
 && !TARGET_XTHEADFMV && !TARGET_ZFA);
> }
>
> /* Implement TARGET_REGISTER_MOVE_COST. */
> diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
> index 15b9317a8ce..f6ab9c75317 100644
> --- a/gcc/config/riscv/riscv.h
> +++ b/gcc/config/riscv/riscv.h
> @@ -377,6 +377,7 @@ ASM_MISA_SPEC
> #define SIBCALL_REG_P(REGNO) \
> TEST_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], REGNO)
>
> +#define GP_REG_RTX_P(X) (REG_P (X) && GP_REG_P (REGNO (X)))
> #define FP_REG_RTX_P(X) (REG_P (X) && FP_REG_P (REGNO (X)))
>
> /* Use s0 as the frame pointer if it is so requested. */
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index 371d6838c0b..4fa2896b8e8 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -59,6 +59,15 @@ (define_c_enum "unspec" [
> UNSPEC_LROUND
> UNSPEC_FMIN
> UNSPEC_FMAX
> + UNSPEC_RINT
> + UNSPEC_ROUND
> + UNSPEC_FLOOR
> + UNSPEC_CEIL
> + UNSPEC_BTRUNC
> + UNSPEC_ROUNDEVEN
> + UNSPEC_NEARBYINT
> + UNSPEC_FMINM
> + UNSPEC_FMAXM
>
> ;; Stack tie
> UNSPEC_TIE
> @@ -1227,6 +1236,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"))
> @@ -1503,13 +1532,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,Zf,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"
> @@ -1575,6 +1604,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>")])
> +
> ;;
> ;; ....................
> ;;
> @@ -1834,13 +1883,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,Zf,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"
> @@ -1867,23 +1916,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, *r,*r,*m")
> - (match_operand:DF 1 "move_operand" " f,G,m,f,G,*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,Zf,G,m,f,G,*r,*f,*r*G,*m,*r"))]
Does not apply on master anymore, needs:
 [(set (match_operand:DF 0 "nonimmediate_operand"
"=f,f,f,f,m,m,*f,*r,*th_f_fmv,*th_r_fmv, *r,*r,*m")
 (match_operand:DF 1 "move_operand" "
f,Zf,G,m,f,G,*r,*f,*th_r_fmv,*th_f_fmv,*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,move,load,store")
> + [(set_attr "move_type" 
> "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
Does not apply on master anymore, needs:
 [(set_attr "move_type"
"fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,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,Zf,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"
> @@ -2490,16 +2539,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),
> @@ -2507,6 +2563,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..13aa7b5f846
> --- /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..b6d41cf460f
> --- /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 } } */
> --
> 2.17.1
>

Reply via email to