Message ID | 77a18666-f71d-48e2-a502-a879b3eb6ccf.jinma@linux.alibaba.com |
---|---|
State | New |
Headers | show |
Series | [v2,RISCV] Add 'Zfa' extension according to riscv-isa-manual | expand |
From e4ce8e825c145d74e6b9827f972629548e39f118 Mon Sep 17 00:00:00 2001
From: Jin Ma <jinma@linux.alibaba.com>
Date: Wed, 11 Jan 2023 19:13:27 +0800
Subject: [PATCH] [RISCV] Add 'Zfa' extension according to riscv-isa-manual
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 )
gcc/ChangeLog:
* common/config/riscv/riscv-common.cc:
* config/riscv/constraints.md (Zf):
* config/riscv/predicates.md:
* config/riscv/riscv-builtins.cc (RISCV_FTYPE_NAME2):
(AVAIL):
(RISCV_ATYPE_SF):
(RISCV_ATYPE_DF):
(RISCV_FTYPE_ATYPES2):
* config/riscv/riscv-ftypes.def (2):
* config/riscv/riscv-opts.h (MASK_ZFA):
(TARGET_ZFA):
* config/riscv/riscv-protos.h (riscv_float_const_rtx_index_for_fli):
* config/riscv/riscv.cc (riscv_float_const_rtx_index_for_fli):
(riscv_cannot_force_const_mem):
(riscv_const_insns):
(riscv_legitimize_const_move):
(riscv_split_64bit_move_p):
(riscv_output_move):
(riscv_memmodel_needs_release_fence):
(riscv_print_operand):
(riscv_secondary_memory_needed):
* config/riscv/riscv.h (GP_REG_RTX_P):
* config/riscv/riscv.md (riscv_fminm<mode>3):
(riscv_fmaxm<mode>3):
(fix_truncdfsi2_zfa):
(round<ANYF:mode>2):
(rint<ANYF:mode>2):
(f<quiet_pattern>_quiet<ANYF:mode><X:mode>4_zfa):
* config/riscv/riscv.opt:
gcc/testsuite/ChangeLog:
* gcc.target/riscv/zfa-fcvtmod.c: New test.
* gcc.target/riscv/zfa-fleq-fltq.c: New test.
* gcc.target/riscv/zfa-fli-zfh.c: New test.
* gcc.target/riscv/zfa-fli.c: New test.
* gcc.target/riscv/zfa-fminm-fmaxm.c: New test.
* gcc.target/riscv/zfa-fmovh-fmovp.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/predicates.md | 4 +
gcc/config/riscv/riscv-builtins.cc | 11 ++
gcc/config/riscv/riscv-ftypes.def | 2 +
gcc/config/riscv/riscv-opts.h | 3 +
gcc/config/riscv/riscv-protos.h | 1 +
gcc/config/riscv/riscv.cc | 105 +++++++++++++++-
gcc/config/riscv/riscv.h | 1 +
gcc/config/riscv/riscv.md | 114 ++++++++++++++----
gcc/config/riscv/riscv.opt | 4 +
gcc/testsuite/gcc.target/riscv/zfa-fcvtmod.c | 12 ++
.../gcc.target/riscv/zfa-fleq-fltq.c | 20 +++
gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c | 42 +++++++
gcc/testsuite/gcc.target/riscv/zfa-fli.c | 80 ++++++++++++
.../gcc.target/riscv/zfa-fminm-fmaxm.c | 25 ++++
.../gcc.target/riscv/zfa-fmovh-fmovp.c | 11 ++
gcc/testsuite/gcc.target/riscv/zfa-fround.c | 25 ++++
18 files changed, 448 insertions(+), 23 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fcvtmod.c
create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.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-fminm-fmaxm.c
create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.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 0a89fdaffe2..cccec12975c 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, 1, 0},
+
{"zmmul", ISA_SPEC_CLASS_NONE, 1, 0},
{"svinval", ISA_SPEC_CLASS_NONE, 1, 0},
@@ -1242,6 +1244,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 51cffb2bcb6..2fd407b1d9c 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -110,6 +110,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/predicates.md b/gcc/config/riscv/predicates.md
index 5a5a49bf7c0..0e8cf3b3708 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-builtins.cc b/gcc/config/riscv/riscv-builtins.cc
index 24ae22c99cd..a99b1e50d96 100644
--- a/gcc/config/riscv/riscv-builtins.cc
+++ b/gcc/config/riscv/riscv-builtins.cc
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see
/* Macros to create an enumeration identifier for a function prototype. */
#define RISCV_FTYPE_NAME0(A) RISCV_##A##_FTYPE
#define RISCV_FTYPE_NAME1(A, B) RISCV_##A##_FTYPE_##B
+#define RISCV_FTYPE_NAME2(A, B, C) RISCV_##A##_FTYPE_##B##_##C
/* Classifies the prototype of a built-in function. */
enum riscv_function_type {
@@ -98,6 +99,7 @@ AVAIL (zero32, TARGET_ZICBOZ && !TARGET_64BIT)
AVAIL (zero64, TARGET_ZICBOZ && TARGET_64BIT)
AVAIL (prefetchi32, TARGET_ZICBOP && !TARGET_64BIT)
AVAIL (prefetchi64, TARGET_ZICBOP && TARGET_64BIT)
+AVAIL (zfa, TARGET_ZFA)
AVAIL (always, (!0))
/* Construct a riscv_builtin_description from the given arguments.
@@ -135,6 +137,8 @@ AVAIL (always, (!0))
#define RISCV_ATYPE_SI intSI_type_node
#define RISCV_ATYPE_DI intDI_type_node
#define RISCV_ATYPE_VOID_PTR ptr_type_node
+#define RISCV_ATYPE_SF float_type_node
+#define RISCV_ATYPE_DF double_type_node
/* RISCV_FTYPE_ATYPESN takes N RISCV_FTYPES-like type codes and lists
their associated RISCV_ATYPEs. */
@@ -142,6 +146,8 @@ AVAIL (always, (!0))
RISCV_ATYPE_##A
#define RISCV_FTYPE_ATYPES1(A, B) \
RISCV_ATYPE_##A, RISCV_ATYPE_##B
+#define RISCV_FTYPE_ATYPES2(A, B, C) \
+ RISCV_ATYPE_##A, RISCV_ATYPE_##B, RISCV_ATYPE_##C
static const struct riscv_builtin_description riscv_builtins[] = {
#include "riscv-cmo.def"
@@ -149,6 +155,11 @@ static const struct riscv_builtin_description riscv_builtins[] = {
DIRECT_BUILTIN (frflags, RISCV_USI_FTYPE, hard_float),
DIRECT_NO_TARGET_BUILTIN (fsflags, RISCV_VOID_FTYPE_USI, hard_float),
DIRECT_NO_TARGET_BUILTIN (pause, RISCV_VOID_FTYPE, always),
+
+ RISCV_BUILTIN (fminmsf3, "fminmf", RISCV_BUILTIN_DIRECT, RISCV_SF_FTYPE_SF_SF, zfa),
+ RISCV_BUILTIN (fminmdf3, "fminm", RISCV_BUILTIN_DIRECT, RISCV_DF_FTYPE_DF_DF, zfa),
+ RISCV_BUILTIN (fmaxmsf3, "fmaxmf", RISCV_BUILTIN_DIRECT, RISCV_SF_FTYPE_SF_SF, zfa),
+ RISCV_BUILTIN (fmaxmdf3, "fmaxm", RISCV_BUILTIN_DIRECT, RISCV_DF_FTYPE_DF_DF, zfa),
};
/* Index I is the function declaration for riscv_builtins[I], or null if the
diff --git a/gcc/config/riscv/riscv-ftypes.def b/gcc/config/riscv/riscv-ftypes.def
index bf2d30782d9..dd3e6f39ff0 100644
--- a/gcc/config/riscv/riscv-ftypes.def
+++ b/gcc/config/riscv/riscv-ftypes.def
@@ -32,3 +32,5 @@ DEF_RISCV_FTYPE (1, (VOID, USI))
DEF_RISCV_FTYPE (1, (VOID, VOID_PTR))
DEF_RISCV_FTYPE (1, (SI, SI))
DEF_RISCV_FTYPE (1, (DI, DI))
+DEF_RISCV_FTYPE (2, (SF, SF, SF))
+DEF_RISCV_FTYPE (2, (DF, DF, DF))
diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index 25fd85b09b1..3ab6d5766c4 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 64ee56b8a7c..d99ec3e9002 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 9a53999a39d..1b269b76dd6 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -799,6 +799,53 @@ static int riscv_symbol_insns (enum riscv_symbol_type type)
}
}
+static unsigned HOST_WIDE_INT fli_value[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
+};
+
+/* 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_ZFHMIN)
+ || (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))
+ {
+ unsigned HOST_WIDE_INT ival = 0;
+ REAL_VALUE_TYPE d;
+
+ d = real_value_truncate (float_mode_for_size (32).require (), *CONST_DOUBLE_REAL_VALUE (x));
+ REAL_VALUE_TO_TARGET_SINGLE (d, ival);
+
+ for (int i = 0; i < 32; i++)
+ {
+ if (ival == fli_value[i])
+ return i;
+ }
+
+ /* The minimum positive normal value (6.104E-5) for half-precision. */
+ if (mode == HFmode && ival == 0x38800000)
+ return 1;
+ }
+ return -1;
+}
+
/* Implement TARGET_LEGITIMATE_CONSTANT_P. */
static bool
@@ -826,6 +873,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))
{
@@ -1179,6 +1229,8 @@ riscv_const_insns (rtx x)
}
case CONST_DOUBLE:
+ if (riscv_float_const_rtx_index_for_fli (x) != -1)
+ return 4;
case CONST_VECTOR:
/* We can use x0 to load floating-point zero. */
return x == CONST0_RTX (GET_MODE (x)) ? 1 : 0;
@@ -1715,6 +1767,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))
{
@@ -2732,6 +2790,9 @@ riscv_split_64bit_move_p (rtx dest, rtx src)
&& ((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;
@@ -2795,6 +2856,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";
}
@@ -2854,6 +2917,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";
@@ -2906,6 +2971,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)
{
@@ -4209,6 +4282,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. */
@@ -4350,6 +4424,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)
{
@@ -4366,6 +4443,31 @@ 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;
+ }
+
+ if (riscv_float_const_rtx_index_for_fli (op) == -1)
+ output_operand_lossage ("invalid use of '%%%c'", letter);
+
+ if (riscv_fli_value_by_int)
+ {
+ asm_fprintf (file, "%d", riscv_float_const_rtx_index_for_fli (op));
+ break;
+ }
+
+ const unsigned int buf_size = 32;
+ char float_buf[buf_size] = {'\0'};
+ real_to_decimal_for_mode (float_buf, CONST_DOUBLE_REAL_VALUE (op),
+ buf_size, buf_size, 1, GET_MODE(op));
+ asm_fprintf (file, "%s", float_buf);
+ break;
+ }
+
default:
if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
fputs (reg_names[GP_REG_FIRST], file);
@@ -5676,7 +5778,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);
}
/* Implement TARGET_REGISTER_MOVE_COST. */
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 0ab739bd6eb..8918f350ec0 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 a10cee2a0dc..d90ea8d35e7 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -59,6 +59,8 @@ (define_c_enum "unspec" [
UNSPEC_LROUND
UNSPEC_FMIN
UNSPEC_FMAX
+ UNSPEC_FMINM
+ UNSPEC_FMAXM
;; Stack tie
UNSPEC_TIE
@@ -1220,6 +1222,26 @@ (define_insn "neg<mode>2"
;;
;; ....................
+(define_insn "riscv_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 && !HONOR_SNANS (<MODE>mode)"
+ "fminm.<fmt>\t%0,%1,%2"
+ [(set_attr "type" "fmove")
+ (set_attr "mode" "<UNITMODE>")])
+
+(define_insn "riscv_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 && !HONOR_SNANS (<MODE>mode)"
+ "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"))
@@ -1494,13 +1516,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"
@@ -1520,6 +1542,15 @@ (define_insn "*movhf_softfloat"
;;
;; ....................
+(define_insn "fix_truncdfsi2_zfa"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (fix:SI
+ (match_operand:DF 1 "register_operand" " f")))]
+ "TARGET_ZFA && (TARGET_HARD_FLOAT || TARGET_ZFINX)"
+ "fcvtmod.w.d\t%0,%1,rtz"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "DF")])
+
(define_insn "fix_trunc<ANYF:mode><GPR:mode>2"
[(set (match_operand:GPR 0 "register_operand" "=r")
(fix:GPR
@@ -1566,6 +1597,26 @@ (define_insn "l<rint_pattern><ANYF:mode><GPR:mode>2"
[(set_attr "type" "fcvt")
(set_attr "mode" "<ANYF:MODE>")])
+(define_insn "round<ANYF:mode>2"
+ [(set (match_operand:ANYF 0 "register_operand" "=f")
+ (unspec:ANYF
+ [(match_operand:ANYF 1 "register_operand" " f")]
+ UNSPEC_LROUND))]
+ "TARGET_HARD_FLOAT && TARGET_ZFA"
+ "fround.<ANYF:fmt>\t%0,%1"
+ [(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_LRINT))]
+ "TARGET_HARD_FLOAT && TARGET_ZFA"
+ "froundnx.<ANYF:fmt>\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "<ANYF:MODE>")])
+
;;
;; ....................
;;
@@ -1823,13 +1874,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"
@@ -1856,23 +1907,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"))]
"!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")
(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"
@@ -2479,16 +2530,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),
@@ -2496,6 +2554,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/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 7c3ca48d1cc..14427624392 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -162,6 +162,10 @@ malign-data=
Target RejectNegative Joined Var(riscv_align_data_type) Enum(riscv_align_data) Init(riscv_align_data_type_xlen)
Use the given data alignment.
+mfli_value_by_int
+Target Var(riscv_fli_value_by_int) Init(1) Undocumented
+The fli instruction in the zfa extension uses integers to represent floating-point values.
+
Enum
Name(riscv_align_data) Type(enum riscv_align_data)
Known data alignment choices (for use with the -malign-data= option):
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fcvtmod.c b/gcc/testsuite/gcc.target/riscv/zfa-fcvtmod.c
new file mode 100644
index 00000000000..65455516a77
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fcvtmod.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */
+/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */
+
+extern double a;
+
+void foo(int *x, double a)
+{
+ *x = a;
+}
+
+/* { dg-final { scan-assembler-times "fcvtmod.w.d" 1 } } */
\ No newline at end of file
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..b57b0810e96
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */
+/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */
+
+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-zfh.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c
new file mode 100644
index 00000000000..26b43f61774
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */
+/* { dg-options "-march=rv64g_zfa_zfh -mabi=lp64d" } */
+
+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_inff ();
+ a = __builtin_nanf ("");
+}
+
+/* { dg-final { scan-assembler-times "fli.h" 31 } } */
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..e3390c697ce
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fli.c
@@ -0,0 +1,80 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */
+/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */
+
+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 = 1.1754943508222875E-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_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-fminm-fmaxm.c b/gcc/testsuite/gcc.target/riscv/zfa-fminm-fmaxm.c
new file mode 100644
index 00000000000..386725a9030
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fminm-fmaxm.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */
+/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */
+
+extern float a, b;
+extern double c, d;
+
+void
+foo(float *x, double *y)
+{
+ {
+ *x = __builtin_riscv_fminmf(a, b);
+ *y = __builtin_riscv_fminm(c, d);
+ }
+
+ {
+ *x = __builtin_riscv_fmaxmf(a, b);
+ *y = __builtin_riscv_fmaxm(c, d);
+ }
+}
+
+/* { dg-final { scan-assembler-times "fminm.s" 1 } } */
+/* { dg-final { scan-assembler-times "fminm.d" 1 } } */
+/* { dg-final { scan-assembler-times "fmaxm.s" 1 } } */
+/* { dg-final { scan-assembler-times "fmaxm.d" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c b/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c
new file mode 100644
index 00000000000..9005e75d868
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv32* -O0" } } */
+/* { dg-options "-march=rv32g_zfa -mabi=ilp32" } */
+
+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.c b/gcc/testsuite/gcc.target/riscv/zfa-fround.c
new file mode 100644
index 00000000000..e84a0bd1998
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fround.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */
+/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */
+
+#include <math.h>
+
+extern float a;
+extern double b;
+
+void foo (float *x, double *y)
+{
+ {
+ *x = roundf (a);
+ *y = round (b);
+ }
+ {
+ *x = rintf (a);
+ *y = rint (b);
+ }
+}
+
+/* { dg-final { scan-assembler-times "fround.s" 1 } } */
+/* { dg-final { scan-assembler-times "fround.d" 1 } } */
+/* { dg-final { scan-assembler-times "froundnx.s" 1 } } */
+/* { dg-final { scan-assembler-times "froundnx.d" 1 } } */
--
2.17.1
From 4ee11f99d23d39d55bdadd86699ac35a60c79705 Mon Sep 17 00:00:00 2001
From: Jin Ma <jinma@linux.alibaba.com>
Date: Thu, 12 Jan 2023 12:51:37 +0800
Subject: [PATCH v2] [RISCV] Add 'Zfa' extension according to riscv-isa-manual
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 )
gcc/ChangeLog:
* common/config/riscv/riscv-common.cc:
* config/riscv/constraints.md (Zf):
* config/riscv/predicates.md:
* config/riscv/riscv-builtins.cc (RISCV_FTYPE_NAME2):
(AVAIL):
(RISCV_ATYPE_SF):
(RISCV_ATYPE_DF):
(RISCV_FTYPE_ATYPES2):
* config/riscv/riscv-ftypes.def (2):
* config/riscv/riscv-opts.h (MASK_ZFA):
(TARGET_ZFA):
* config/riscv/riscv-protos.h (riscv_float_const_rtx_index_for_fli):
* config/riscv/riscv.cc (riscv_float_const_rtx_index_for_fli):
(riscv_cannot_force_const_mem):
(riscv_const_insns):
(riscv_legitimize_const_move):
(riscv_split_64bit_move_p):
(riscv_output_move):
(riscv_memmodel_needs_release_fence):
(riscv_print_operand):
(riscv_secondary_memory_needed):
* config/riscv/riscv.h (GP_REG_RTX_P):
* config/riscv/riscv.md (riscv_fminm<mode>3):
(riscv_fmaxm<mode>3):
(fix_truncdfsi2_zfa):
(round<ANYF:mode>2):
(rint<ANYF:mode>2):
(f<quiet_pattern>_quiet<ANYF:mode><X:mode>4_zfa):
* config/riscv/riscv.opt:
gcc/testsuite/ChangeLog:
* gcc.target/riscv/zfa-fcvtmod.c: New test.
* gcc.target/riscv/zfa-fleq-fltq.c: New test.
* gcc.target/riscv/zfa-fli-zfh.c: New test.
* gcc.target/riscv/zfa-fli.c: New test.
* gcc.target/riscv/zfa-fminm-fmaxm.c: New test.
* gcc.target/riscv/zfa-fmovh-fmovp.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/predicates.md | 4 +
gcc/config/riscv/riscv-builtins.cc | 11 ++
gcc/config/riscv/riscv-ftypes.def | 2 +
gcc/config/riscv/riscv-opts.h | 3 +
gcc/config/riscv/riscv-protos.h | 1 +
gcc/config/riscv/riscv.cc | 109 ++++++++++++++++-
gcc/config/riscv/riscv.h | 1 +
gcc/config/riscv/riscv.md | 114 ++++++++++++++----
gcc/config/riscv/riscv.opt | 4 +
gcc/testsuite/gcc.target/riscv/zfa-fcvtmod.c | 12 ++
.../gcc.target/riscv/zfa-fleq-fltq.c | 20 +++
gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c | 42 +++++++
gcc/testsuite/gcc.target/riscv/zfa-fli.c | 80 ++++++++++++
.../gcc.target/riscv/zfa-fminm-fmaxm.c | 25 ++++
.../gcc.target/riscv/zfa-fmovh-fmovp.c | 11 ++
gcc/testsuite/gcc.target/riscv/zfa-fround.c | 25 ++++
18 files changed, 452 insertions(+), 23 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fcvtmod.c
create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.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-fminm-fmaxm.c
create mode 100644 gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.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 0a89fdaffe2..cccec12975c 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, 1, 0},
+
{"zmmul", ISA_SPEC_CLASS_NONE, 1, 0},
{"svinval", ISA_SPEC_CLASS_NONE, 1, 0},
@@ -1242,6 +1244,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 51cffb2bcb6..2fd407b1d9c 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -110,6 +110,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/predicates.md b/gcc/config/riscv/predicates.md
index 5a5a49bf7c0..0e8cf3b3708 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-builtins.cc b/gcc/config/riscv/riscv-builtins.cc
index 24ae22c99cd..a99b1e50d96 100644
--- a/gcc/config/riscv/riscv-builtins.cc
+++ b/gcc/config/riscv/riscv-builtins.cc
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see
/* Macros to create an enumeration identifier for a function prototype. */
#define RISCV_FTYPE_NAME0(A) RISCV_##A##_FTYPE
#define RISCV_FTYPE_NAME1(A, B) RISCV_##A##_FTYPE_##B
+#define RISCV_FTYPE_NAME2(A, B, C) RISCV_##A##_FTYPE_##B##_##C
/* Classifies the prototype of a built-in function. */
enum riscv_function_type {
@@ -98,6 +99,7 @@ AVAIL (zero32, TARGET_ZICBOZ && !TARGET_64BIT)
AVAIL (zero64, TARGET_ZICBOZ && TARGET_64BIT)
AVAIL (prefetchi32, TARGET_ZICBOP && !TARGET_64BIT)
AVAIL (prefetchi64, TARGET_ZICBOP && TARGET_64BIT)
+AVAIL (zfa, TARGET_ZFA)
AVAIL (always, (!0))
/* Construct a riscv_builtin_description from the given arguments.
@@ -135,6 +137,8 @@ AVAIL (always, (!0))
#define RISCV_ATYPE_SI intSI_type_node
#define RISCV_ATYPE_DI intDI_type_node
#define RISCV_ATYPE_VOID_PTR ptr_type_node
+#define RISCV_ATYPE_SF float_type_node
+#define RISCV_ATYPE_DF double_type_node
/* RISCV_FTYPE_ATYPESN takes N RISCV_FTYPES-like type codes and lists
their associated RISCV_ATYPEs. */
@@ -142,6 +146,8 @@ AVAIL (always, (!0))
RISCV_ATYPE_##A
#define RISCV_FTYPE_ATYPES1(A, B) \
RISCV_ATYPE_##A, RISCV_ATYPE_##B
+#define RISCV_FTYPE_ATYPES2(A, B, C) \
+ RISCV_ATYPE_##A, RISCV_ATYPE_##B, RISCV_ATYPE_##C
static const struct riscv_builtin_description riscv_builtins[] = {
#include "riscv-cmo.def"
@@ -149,6 +155,11 @@ static const struct riscv_builtin_description riscv_builtins[] = {
DIRECT_BUILTIN (frflags, RISCV_USI_FTYPE, hard_float),
DIRECT_NO_TARGET_BUILTIN (fsflags, RISCV_VOID_FTYPE_USI, hard_float),
DIRECT_NO_TARGET_BUILTIN (pause, RISCV_VOID_FTYPE, always),
+
+ RISCV_BUILTIN (fminmsf3, "fminmf", RISCV_BUILTIN_DIRECT, RISCV_SF_FTYPE_SF_SF, zfa),
+ RISCV_BUILTIN (fminmdf3, "fminm", RISCV_BUILTIN_DIRECT, RISCV_DF_FTYPE_DF_DF, zfa),
+ RISCV_BUILTIN (fmaxmsf3, "fmaxmf", RISCV_BUILTIN_DIRECT, RISCV_SF_FTYPE_SF_SF, zfa),
+ RISCV_BUILTIN (fmaxmdf3, "fmaxm", RISCV_BUILTIN_DIRECT, RISCV_DF_FTYPE_DF_DF, zfa),
};
/* Index I is the function declaration for riscv_builtins[I], or null if the
diff --git a/gcc/config/riscv/riscv-ftypes.def b/gcc/config/riscv/riscv-ftypes.def
index bf2d30782d9..dd3e6f39ff0 100644
--- a/gcc/config/riscv/riscv-ftypes.def
+++ b/gcc/config/riscv/riscv-ftypes.def
@@ -32,3 +32,5 @@ DEF_RISCV_FTYPE (1, (VOID, USI))
DEF_RISCV_FTYPE (1, (VOID, VOID_PTR))
DEF_RISCV_FTYPE (1, (SI, SI))
DEF_RISCV_FTYPE (1, (DI, DI))
+DEF_RISCV_FTYPE (2, (SF, SF, SF))
+DEF_RISCV_FTYPE (2, (DF, DF, DF))
diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index 25fd85b09b1..3ab6d5766c4 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 64ee56b8a7c..d99ec3e9002 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 9a53999a39d..77777e8a77f 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -799,6 +799,57 @@ 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 */
+
+static unsigned HOST_WIDE_INT fli_value[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
+};
+
+/* 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_ZFHMIN)
+ || (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))
+ {
+ unsigned HOST_WIDE_INT ival = 0;
+ REAL_VALUE_TYPE d;
+
+ d = real_value_truncate (float_mode_for_size (32).require (), *CONST_DOUBLE_REAL_VALUE (x));
+ REAL_VALUE_TO_TARGET_SINGLE (d, ival);
+
+ for (int i = 0; i < 32; i++)
+ {
+ if (ival == fli_value[i])
+ return i;
+ }
+
+ /* The minimum positive normal value (6.104E-5) for half-precision. */
+ if (mode == HFmode && ival == 0x38800000)
+ return 1;
+ }
+ return -1;
+}
+
/* Implement TARGET_LEGITIMATE_CONSTANT_P. */
static bool
@@ -826,6 +877,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))
{
@@ -1179,6 +1233,8 @@ riscv_const_insns (rtx x)
}
case CONST_DOUBLE:
+ if (riscv_float_const_rtx_index_for_fli (x) != -1)
+ return 4;
case CONST_VECTOR:
/* We can use x0 to load floating-point zero. */
return x == CONST0_RTX (GET_MODE (x)) ? 1 : 0;
@@ -1715,6 +1771,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))
{
@@ -2732,6 +2794,9 @@ riscv_split_64bit_move_p (rtx dest, rtx src)
&& ((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;
@@ -2795,6 +2860,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";
}
@@ -2854,6 +2921,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";
@@ -2906,6 +2975,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)
{
@@ -4209,6 +4286,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. */
@@ -4350,6 +4428,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)
{
@@ -4366,6 +4447,31 @@ 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;
+ }
+
+ if (riscv_float_const_rtx_index_for_fli (op) == -1)
+ output_operand_lossage ("invalid use of '%%%c'", letter);
+
+ if (riscv_fli_value_by_int)
+ {
+ asm_fprintf (file, "%d", riscv_float_const_rtx_index_for_fli (op));
+ break;
+ }
+
+ const unsigned int buf_size = 32;
+ char float_buf[buf_size] = {'\0'};
+ real_to_decimal_for_mode (float_buf, CONST_DOUBLE_REAL_VALUE (op),
+ buf_size, buf_size, 1, GET_MODE(op));
+ asm_fprintf (file, "%s", float_buf);
+ break;
+ }
+
default:
if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
fputs (reg_names[GP_REG_FIRST], file);
@@ -5676,7 +5782,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);
}
/* Implement TARGET_REGISTER_MOVE_COST. */
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 0ab739bd6eb..8918f350ec0 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 a10cee2a0dc..d90ea8d35e7 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -59,6 +59,8 @@ (define_c_enum "unspec" [
UNSPEC_LROUND
UNSPEC_FMIN
UNSPEC_FMAX
+ UNSPEC_FMINM
+ UNSPEC_FMAXM
;; Stack tie
UNSPEC_TIE
@@ -1220,6 +1222,26 @@ (define_insn "neg<mode>2"
;;
;; ....................
+(define_insn "riscv_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 && !HONOR_SNANS (<MODE>mode)"
+ "fminm.<fmt>\t%0,%1,%2"
+ [(set_attr "type" "fmove")
+ (set_attr "mode" "<UNITMODE>")])
+
+(define_insn "riscv_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 && !HONOR_SNANS (<MODE>mode)"
+ "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"))
@@ -1494,13 +1516,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"
@@ -1520,6 +1542,15 @@ (define_insn "*movhf_softfloat"
;;
;; ....................
+(define_insn "fix_truncdfsi2_zfa"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (fix:SI
+ (match_operand:DF 1 "register_operand" " f")))]
+ "TARGET_ZFA && (TARGET_HARD_FLOAT || TARGET_ZFINX)"
+ "fcvtmod.w.d\t%0,%1,rtz"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "DF")])
+
(define_insn "fix_trunc<ANYF:mode><GPR:mode>2"
[(set (match_operand:GPR 0 "register_operand" "=r")
(fix:GPR
@@ -1566,6 +1597,26 @@ (define_insn "l<rint_pattern><ANYF:mode><GPR:mode>2"
[(set_attr "type" "fcvt")
(set_attr "mode" "<ANYF:MODE>")])
+(define_insn "round<ANYF:mode>2"
+ [(set (match_operand:ANYF 0 "register_operand" "=f")
+ (unspec:ANYF
+ [(match_operand:ANYF 1 "register_operand" " f")]
+ UNSPEC_LROUND))]
+ "TARGET_HARD_FLOAT && TARGET_ZFA"
+ "fround.<ANYF:fmt>\t%0,%1"
+ [(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_LRINT))]
+ "TARGET_HARD_FLOAT && TARGET_ZFA"
+ "froundnx.<ANYF:fmt>\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "<ANYF:MODE>")])
+
;;
;; ....................
;;
@@ -1823,13 +1874,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"
@@ -1856,23 +1907,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"))]
"!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")
(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"
@@ -2479,16 +2530,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),
@@ -2496,6 +2554,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/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 7c3ca48d1cc..14427624392 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -162,6 +162,10 @@ malign-data=
Target RejectNegative Joined Var(riscv_align_data_type) Enum(riscv_align_data) Init(riscv_align_data_type_xlen)
Use the given data alignment.
+mfli_value_by_int
+Target Var(riscv_fli_value_by_int) Init(1) Undocumented
+The fli instruction in the zfa extension uses integers to represent floating-point values.
+
Enum
Name(riscv_align_data) Type(enum riscv_align_data)
Known data alignment choices (for use with the -malign-data= option):
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fcvtmod.c b/gcc/testsuite/gcc.target/riscv/zfa-fcvtmod.c
new file mode 100644
index 00000000000..65455516a77
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fcvtmod.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */
+/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */
+
+extern double a;
+
+void foo(int *x, double a)
+{
+ *x = a;
+}
+
+/* { dg-final { scan-assembler-times "fcvtmod.w.d" 1 } } */
\ No newline at end of file
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..b57b0810e96
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */
+/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */
+
+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-zfh.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c
new file mode 100644
index 00000000000..26b43f61774
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */
+/* { dg-options "-march=rv64g_zfa_zfh -mabi=lp64d" } */
+
+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_inff ();
+ a = __builtin_nanf ("");
+}
+
+/* { dg-final { scan-assembler-times "fli.h" 31 } } */
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..e3390c697ce
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fli.c
@@ -0,0 +1,80 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */
+/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */
+
+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 = 1.1754943508222875E-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_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-fminm-fmaxm.c b/gcc/testsuite/gcc.target/riscv/zfa-fminm-fmaxm.c
new file mode 100644
index 00000000000..386725a9030
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fminm-fmaxm.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */
+/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */
+
+extern float a, b;
+extern double c, d;
+
+void
+foo(float *x, double *y)
+{
+ {
+ *x = __builtin_riscv_fminmf(a, b);
+ *y = __builtin_riscv_fminm(c, d);
+ }
+
+ {
+ *x = __builtin_riscv_fmaxmf(a, b);
+ *y = __builtin_riscv_fmaxm(c, d);
+ }
+}
+
+/* { dg-final { scan-assembler-times "fminm.s" 1 } } */
+/* { dg-final { scan-assembler-times "fminm.d" 1 } } */
+/* { dg-final { scan-assembler-times "fmaxm.s" 1 } } */
+/* { dg-final { scan-assembler-times "fmaxm.d" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c b/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c
new file mode 100644
index 00000000000..9005e75d868
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv32* -O0" } } */
+/* { dg-options "-march=rv32g_zfa -mabi=ilp32" } */
+
+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.c b/gcc/testsuite/gcc.target/riscv/zfa-fround.c
new file mode 100644
index 00000000000..e84a0bd1998
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zfa-fround.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */
+/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */
+
+#include <math.h>
+
+extern float a;
+extern double b;
+
+void foo (float *x, double *y)
+{
+ {
+ *x = roundf (a);
+ *y = round (b);
+ }
+ {
+ *x = rintf (a);
+ *y = rint (b);
+ }
+}
+
+/* { dg-final { scan-assembler-times "fround.s" 1 } } */
+/* { dg-final { scan-assembler-times "fround.d" 1 } } */
+/* { dg-final { scan-assembler-times "froundnx.s" 1 } } */
+/* { dg-final { scan-assembler-times "froundnx.d" 1 } } */
--
2.17.1
I am very sorry. There seems to be some unknown problems in my email, which caused a problem with the format of the patch. I will deal with it as soon as possible. I am very sorry for the trouble.
diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc index 0a89fdaffe2..cccec12975c 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, 1, 0}, + {"zmmul", ISA_SPEC_CLASS_NONE, 1, 0}, {"svinval", ISA_SPEC_CLASS_NONE, 1, 0}, @@ -1242,6 +1244,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 51cffb2bcb6..2fd407b1d9c 100644 --- a/gcc/config/riscv/constraints.md +++ b/gcc/config/riscv/constraints.md @@ -110,6 +110,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/predicates.md b/gcc/config/riscv/predicates.md index 5a5a49bf7c0..0e8cf3b3708 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-builtins.cc b/gcc/config/riscv/riscv-builtins.cc index 24ae22c99cd..a99b1e50d96 100644 --- a/gcc/config/riscv/riscv-builtins.cc +++ b/gcc/config/riscv/riscv-builtins.cc @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see /* Macros to create an enumeration identifier for a function prototype. */ #define RISCV_FTYPE_NAME0(A) RISCV_##A##_FTYPE #define RISCV_FTYPE_NAME1(A, B) RISCV_##A##_FTYPE_##B +#define RISCV_FTYPE_NAME2(A, B, C) RISCV_##A##_FTYPE_##B##_##C /* Classifies the prototype of a built-in function. */ enum riscv_function_type { @@ -98,6 +99,7 @@ AVAIL (zero32, TARGET_ZICBOZ && !TARGET_64BIT) AVAIL (zero64, TARGET_ZICBOZ && TARGET_64BIT) AVAIL (prefetchi32, TARGET_ZICBOP && !TARGET_64BIT) AVAIL (prefetchi64, TARGET_ZICBOP && TARGET_64BIT) +AVAIL (zfa, TARGET_ZFA) AVAIL (always, (!0)) /* Construct a riscv_builtin_description from the given arguments. @@ -135,6 +137,8 @@ AVAIL (always, (!0)) #define RISCV_ATYPE_SI intSI_type_node #define RISCV_ATYPE_DI intDI_type_node #define RISCV_ATYPE_VOID_PTR ptr_type_node +#define RISCV_ATYPE_SF float_type_node +#define RISCV_ATYPE_DF double_type_node /* RISCV_FTYPE_ATYPESN takes N RISCV_FTYPES-like type codes and lists their associated RISCV_ATYPEs. */ @@ -142,6 +146,8 @@ AVAIL (always, (!0)) RISCV_ATYPE_##A #define RISCV_FTYPE_ATYPES1(A, B) \ RISCV_ATYPE_##A, RISCV_ATYPE_##B +#define RISCV_FTYPE_ATYPES2(A, B, C) \ + RISCV_ATYPE_##A, RISCV_ATYPE_##B, RISCV_ATYPE_##C static const struct riscv_builtin_description riscv_builtins[] = { #include "riscv-cmo.def" @@ -149,6 +155,11 @@ static const struct riscv_builtin_description riscv_builtins[] = { DIRECT_BUILTIN (frflags, RISCV_USI_FTYPE, hard_float), DIRECT_NO_TARGET_BUILTIN (fsflags, RISCV_VOID_FTYPE_USI, hard_float), DIRECT_NO_TARGET_BUILTIN (pause, RISCV_VOID_FTYPE, always), + + RISCV_BUILTIN (fminmsf3, "fminmf", RISCV_BUILTIN_DIRECT, RISCV_SF_FTYPE_SF_SF, zfa), + RISCV_BUILTIN (fminmdf3, "fminm", RISCV_BUILTIN_DIRECT, RISCV_DF_FTYPE_DF_DF, zfa), + RISCV_BUILTIN (fmaxmsf3, "fmaxmf", RISCV_BUILTIN_DIRECT, RISCV_SF_FTYPE_SF_SF, zfa), + RISCV_BUILTIN (fmaxmdf3, "fmaxm", RISCV_BUILTIN_DIRECT, RISCV_DF_FTYPE_DF_DF, zfa), }; /* Index I is the function declaration for riscv_builtins[I], or null if the diff --git a/gcc/config/riscv/riscv-ftypes.def b/gcc/config/riscv/riscv-ftypes.def index bf2d30782d9..dd3e6f39ff0 100644 --- a/gcc/config/riscv/riscv-ftypes.def +++ b/gcc/config/riscv/riscv-ftypes.def @@ -32,3 +32,5 @@ DEF_RISCV_FTYPE (1, (VOID, USI)) DEF_RISCV_FTYPE (1, (VOID, VOID_PTR)) DEF_RISCV_FTYPE (1, (SI, SI)) DEF_RISCV_FTYPE (1, (DI, DI)) +DEF_RISCV_FTYPE (2, (SF, SF, SF)) +DEF_RISCV_FTYPE (2, (DF, DF, DF)) diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h index 25fd85b09b1..3ab6d5766c4 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 64ee56b8a7c..d99ec3e9002 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 9a53999a39d..1b269b76dd6 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -799,6 +799,53 @@ static int riscv_symbol_insns (enum riscv_symbol_type type) } } +static unsigned HOST_WIDE_INT fli_value[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 +}; + +/* 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_ZFHMIN) + || (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)) + { + unsigned HOST_WIDE_INT ival = 0; + REAL_VALUE_TYPE d; + + d = real_value_truncate (float_mode_for_size (32).require (), *CONST_DOUBLE_REAL_VALUE (x)); + REAL_VALUE_TO_TARGET_SINGLE (d, ival); + + for (int i = 0; i < 32; i++) + { + if (ival == fli_value[i]) + return i; + } + + /* The minimum positive normal value (6.104E-5) for half-precision. */ + if (mode == HFmode && ival == 0x38800000) + return 1; + } + return -1; +} + /* Implement TARGET_LEGITIMATE_CONSTANT_P. */ static bool @@ -826,6 +873,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)) { @@ -1179,6 +1229,8 @@ riscv_const_insns (rtx x) } case CONST_DOUBLE: + if (riscv_float_const_rtx_index_for_fli (x) != -1) + return 4; case CONST_VECTOR: /* We can use x0 to load floating-point zero. */ return x == CONST0_RTX (GET_MODE (x)) ? 1 : 0; @@ -1715,6 +1767,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)) { @@ -2732,6 +2790,9 @@ riscv_split_64bit_move_p (rtx dest, rtx src) && ((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; @@ -2795,6 +2856,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"; } @@ -2854,6 +2917,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"; @@ -2906,6 +2971,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) { @@ -4209,6 +4282,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. */ @@ -4350,6 +4424,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) { @@ -4366,6 +4443,31 @@ 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; + } + + if (riscv_float_const_rtx_index_for_fli (op) == -1) + output_operand_lossage ("invalid use of '%%%c'", letter); + + if (riscv_fli_value_by_int) + { + asm_fprintf (file, "%d", riscv_float_const_rtx_index_for_fli (op)); + break; + } + + const unsigned int buf_size = 32; + char float_buf[buf_size] = {'\0'}; + real_to_decimal_for_mode (float_buf, CONST_DOUBLE_REAL_VALUE (op), + buf_size, buf_size, 1, GET_MODE(op)); + asm_fprintf (file, "%s", float_buf); + break; + } + default: if (letter == 'z' && op == CONST0_RTX (GET_MODE (op))) fputs (reg_names[GP_REG_FIRST], file); @@ -5676,7 +5778,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); } /* Implement TARGET_REGISTER_MOVE_COST. */ diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 0ab739bd6eb..8918f350ec0 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 a10cee2a0dc..d90ea8d35e7 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -59,6 +59,8 @@ (define_c_enum "unspec" [ UNSPEC_LROUND UNSPEC_FMIN UNSPEC_FMAX + UNSPEC_FMINM + UNSPEC_FMAXM ;; Stack tie UNSPEC_TIE @@ -1220,6 +1222,26 @@ (define_insn "neg<mode>2" ;; ;; .................... +(define_insn "riscv_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 && !HONOR_SNANS (<MODE>mode)" + "fminm.<fmt>\t%0,%1,%2" + [(set_attr "type" "fmove") + (set_attr "mode" "<UNITMODE>")]) + +(define_insn "riscv_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 && !HONOR_SNANS (<MODE>mode)" + "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")) @@ -1494,13 +1516,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" @@ -1520,6 +1542,15 @@ (define_insn "*movhf_softfloat" ;; ;; .................... +(define_insn "fix_truncdfsi2_zfa" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI + (match_operand:DF 1 "register_operand" " f")))] + "TARGET_ZFA && (TARGET_HARD_FLOAT || TARGET_ZFINX)" + "fcvtmod.w.d\t%0,%1,rtz" + [(set_attr "type" "fcvt") + (set_attr "mode" "DF")]) + (define_insn "fix_trunc<ANYF:mode><GPR:mode>2" [(set (match_operand:GPR 0 "register_operand" "=r") (fix:GPR @@ -1566,6 +1597,26 @@ (define_insn "l<rint_pattern><ANYF:mode><GPR:mode>2" [(set_attr "type" "fcvt") (set_attr "mode" "<ANYF:MODE>")]) +(define_insn "round<ANYF:mode>2" + [(set (match_operand:ANYF 0 "register_operand" "=f") + (unspec:ANYF + [(match_operand:ANYF 1 "register_operand" " f")] + UNSPEC_LROUND))] + "TARGET_HARD_FLOAT && TARGET_ZFA" + "fround.<ANYF:fmt>\t%0,%1" + [(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_LRINT))] + "TARGET_HARD_FLOAT && TARGET_ZFA" + "froundnx.<ANYF:fmt>\t%0,%1" + [(set_attr "type" "fcvt") + (set_attr "mode" "<ANYF:MODE>")]) + ;; ;; .................... ;; @@ -1823,13 +1874,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" @@ -1856,23 +1907,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"))] "!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") (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" @@ -2479,16 +2530,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), @@ -2496,6 +2554,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/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt index 7c3ca48d1cc..14427624392 100644 --- a/gcc/config/riscv/riscv.opt +++ b/gcc/config/riscv/riscv.opt @@ -162,6 +162,10 @@ malign-data= Target RejectNegative Joined Var(riscv_align_data_type) Enum(riscv_align_data) Init(riscv_align_data_type_xlen) Use the given data alignment. +mfli_value_by_int +Target Var(riscv_fli_value_by_int) Init(1) Undocumented +The fli instruction in the zfa extension uses integers to represent floating-point values. + Enum Name(riscv_align_data) Type(enum riscv_align_data) Known data alignment choices (for use with the -malign-data= option): diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fcvtmod.c b/gcc/testsuite/gcc.target/riscv/zfa-fcvtmod.c new file mode 100644 index 00000000000..65455516a77 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fcvtmod.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */ +/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */ + +extern double a; + +void foo(int *x, double a) +{ + *x = a; +} + +/* { dg-final { scan-assembler-times "fcvtmod.w.d" 1 } } */ \ No newline at end of file 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..b57b0810e96 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */ +/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */ + +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-zfh.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c new file mode 100644 index 00000000000..26b43f61774 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */ +/* { dg-options "-march=rv64g_zfa_zfh -mabi=lp64d" } */ + +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_inff (); + a = __builtin_nanf (""); +} + +/* { dg-final { scan-assembler-times "fli.h" 31 } } */ 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..e3390c697ce --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fli.c @@ -0,0 +1,80 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */ +/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */ + +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 = 1.1754943508222875E-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_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-fminm-fmaxm.c b/gcc/testsuite/gcc.target/riscv/zfa-fminm-fmaxm.c new file mode 100644 index 00000000000..386725a9030 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fminm-fmaxm.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */ +/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */ + +extern float a, b; +extern double c, d; + +void +foo(float *x, double *y) +{ + { + *x = __builtin_riscv_fminmf(a, b); + *y = __builtin_riscv_fminm(c, d); + } + + { + *x = __builtin_riscv_fmaxmf(a, b); + *y = __builtin_riscv_fmaxm(c, d); + } +} + +/* { dg-final { scan-assembler-times "fminm.s" 1 } } */ +/* { dg-final { scan-assembler-times "fminm.d" 1 } } */ +/* { dg-final { scan-assembler-times "fmaxm.s" 1 } } */ +/* { dg-final { scan-assembler-times "fmaxm.d" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c b/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c new file mode 100644 index 00000000000..9005e75d868 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv32* -O0" } } */ +/* { dg-options "-march=rv32g_zfa -mabi=ilp32" } */ + +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.c b/gcc/testsuite/gcc.target/riscv/zfa-fround.c new file mode 100644 index 00000000000..e84a0bd1998 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fround.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "*" } { "-march=rv64* -O2" } } */ +/* { dg-options "-march=rv64g_zfa -mabi=lp64d" } */ + +#include <math.h> + +extern float a; +extern double b; + +void foo (float *x, double *y) +{ + { + *x = roundf (a); + *y = round (b); + } + { + *x = rintf (a); + *y = rint (b); + } +} + +/* { dg-final { scan-assembler-times "fround.s" 1 } } */ +/* { dg-final { scan-assembler-times "fround.d" 1 } } */ +/* { dg-final { scan-assembler-times "froundnx.s" 1 } } */ +/* { dg-final { scan-assembler-times "froundnx.d" 1 } } */