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 Sent At:2023 Apr. 13 (Thu.) 17:22 To:Jin Ma Cc:gcc-patches ; kito.cheng ; kito.cheng ; palmer 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 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 fminm3 and fmaxm3. 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 (fminm3): New. > (fmaxm3): New. > (2): New. > (rint2): New. > (f_quiet4_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 "neg2" > ;; > ;; .................... > > +(define_insn "fminm3" > + [(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.\t%0,%1,%2" > + [(set_attr "type" "fmove") > + (set_attr "mode" "")]) > + > +(define_insn "fmaxm3" > + [(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.\t%0,%1,%2" > + [(set_attr "type" "fmove") > + (set_attr "mode" "")]) > + > (define_insn "fmin3" > [(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 "l2" > [(set_attr "type" "fcvt") > (set_attr "mode" "")]) > > +(define_insn "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.\t%0,%1," > + [(set_attr "type" "fcvt") > + (set_attr "mode" "")]) > + > +(define_insn "rint2" > + [(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.\t%0,%1" > + [(set_attr "type" "fcvt") > + (set_attr "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_quiet4" > rtx op0 = operands[0]; > rtx op1 = operands[1]; > rtx op2 = operands[2]; > - rtx tmp = gen_reg_rtx (SImode); > - rtx cmp = gen_rtx_ (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_quiet4_zfa(op0, op1, op2)); > + else > + { > + rtx tmp = gen_reg_rtx (SImode); > + rtx cmp = gen_rtx_ (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 (mode)) > emit_insn (gen_rtx_UNSPEC_VOLATILE (mode, > gen_rtvec (2, op1, op2), > @@ -2507,6 +2563,18 @@ (define_expand "f_quiet4" > DONE; > }) > > +(define_insn "f_quiet4_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" > + "fq.\t%0,%1,%2" > + [(set_attr "type" "fcmp") > + (set_attr "mode" "") > + (set (attr "length") (const_int 16))]) > + > (define_insn "*seq_zero_" > [(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 >