[v2,2/2] RISC-V: Support zfh and zfhmin extension
Commit Message
Zfh and Zfhmin are extensions for IEEE half precision, both are ratified
in Jan. 2022[1]:
- Zfh has full set of operation like F or D for single or double precision.
- Zfhmin has only provide minimal support for half precision operation,
like conversion, load, store and move instructions.
[1] https://github.com/riscv/riscv-isa-manual/commit/b35a54079e0da11740ce5b1e6db999d1d5172768
gcc/ChangeLog:
* common/config/riscv/riscv-common.cc (riscv_implied_info): Add
zfh and zfhmin.
(riscv_ext_version_table): Ditto.
(riscv_ext_flag_table): Ditto.
* config/riscv/riscv-opts.h (MASK_ZFHMIN): New.
(MASK_ZFH): Ditto.
(TARGET_ZFHMIN): Ditto.
(TARGET_ZFH): Ditto.
* config/riscv/riscv.cc (riscv_output_move): Handle HFmode move
for zfh and zfhmin.
(riscv_emit_float_compare): Handle HFmode.
* config/riscv/riscv.md (ANYF): Add HF.
(SOFTF): Add HF.
(load): Ditto.
(store): Ditto.
(truncsfhf2): New.
(truncdfhf2): Ditto.
(extendhfsf2): Ditto.
(extendhfdf2): Ditto.
(*movhf_hardfloat): Ditto.
(*movhf_softfloat): Make sure not ZFHMIN.
* config/riscv/riscv.opt (riscv_zf_subext): New.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/_Float16-zfh-1.c: New.
* gcc.target/riscv/_Float16-zfh-2.c: Ditto.
* gcc.target/riscv/_Float16-zfh-3.c: Ditto.
* gcc.target/riscv/_Float16-zfhmin-1.c: Ditto.
* gcc.target/riscv/_Float16-zfhmin-2.c: Ditto.
* gcc.target/riscv/_Float16-zfhmin-3.c: Ditto.
* gcc.target/riscv/arch-16.c: Ditto.
* gcc.target/riscv/arch-17.c: Ditto.
* gcc.target/riscv/predef-21.c: Ditto.
* gcc.target/riscv/predef-22.c: Ditto.
---
gcc/common/config/riscv/riscv-common.cc | 8 +++
gcc/config/riscv/riscv-opts.h | 6 ++
gcc/config/riscv/riscv.cc | 33 ++++++++++-
gcc/config/riscv/riscv.md | 59 +++++++++++++++++--
gcc/config/riscv/riscv.opt | 3 +
.../gcc.target/riscv/_Float16-zfh-1.c | 8 +++
.../gcc.target/riscv/_Float16-zfh-2.c | 8 +++
.../gcc.target/riscv/_Float16-zfh-3.c | 8 +++
.../gcc.target/riscv/_Float16-zfhmin-1.c | 9 +++
.../gcc.target/riscv/_Float16-zfhmin-2.c | 9 +++
.../gcc.target/riscv/_Float16-zfhmin-3.c | 9 +++
gcc/testsuite/gcc.target/riscv/arch-16.c | 5 ++
gcc/testsuite/gcc.target/riscv/arch-17.c | 5 ++
gcc/testsuite/gcc.target/riscv/predef-21.c | 59 +++++++++++++++++++
gcc/testsuite/gcc.target/riscv/predef-22.c | 59 +++++++++++++++++++
15 files changed, 279 insertions(+), 9 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zfh-1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zfh-2.c
create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zfh-3.c
create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-2.c
create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-3.c
create mode 100644 gcc/testsuite/gcc.target/riscv/arch-16.c
create mode 100644 gcc/testsuite/gcc.target/riscv/arch-17.c
create mode 100644 gcc/testsuite/gcc.target/riscv/predef-21.c
create mode 100644 gcc/testsuite/gcc.target/riscv/predef-22.c
Comments
LGTM.
juzhe.zhong@rivai.ai
From: Kito Cheng
Date: 2022-08-10 23:44
To: gcc-patches; kito.cheng; jim.wilson.gcc; palmer; andrew; juzhe.zhong; joseph
CC: Kito Cheng
Subject: [PATCH v2 2/2] RISC-V: Support zfh and zfhmin extension
Zfh and Zfhmin are extensions for IEEE half precision, both are ratified
in Jan. 2022[1]:
- Zfh has full set of operation like F or D for single or double precision.
- Zfhmin has only provide minimal support for half precision operation,
like conversion, load, store and move instructions.
[1] https://github.com/riscv/riscv-isa-manual/commit/b35a54079e0da11740ce5b1e6db999d1d5172768
gcc/ChangeLog:
* common/config/riscv/riscv-common.cc (riscv_implied_info): Add
zfh and zfhmin.
(riscv_ext_version_table): Ditto.
(riscv_ext_flag_table): Ditto.
* config/riscv/riscv-opts.h (MASK_ZFHMIN): New.
(MASK_ZFH): Ditto.
(TARGET_ZFHMIN): Ditto.
(TARGET_ZFH): Ditto.
* config/riscv/riscv.cc (riscv_output_move): Handle HFmode move
for zfh and zfhmin.
(riscv_emit_float_compare): Handle HFmode.
* config/riscv/riscv.md (ANYF): Add HF.
(SOFTF): Add HF.
(load): Ditto.
(store): Ditto.
(truncsfhf2): New.
(truncdfhf2): Ditto.
(extendhfsf2): Ditto.
(extendhfdf2): Ditto.
(*movhf_hardfloat): Ditto.
(*movhf_softfloat): Make sure not ZFHMIN.
* config/riscv/riscv.opt (riscv_zf_subext): New.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/_Float16-zfh-1.c: New.
* gcc.target/riscv/_Float16-zfh-2.c: Ditto.
* gcc.target/riscv/_Float16-zfh-3.c: Ditto.
* gcc.target/riscv/_Float16-zfhmin-1.c: Ditto.
* gcc.target/riscv/_Float16-zfhmin-2.c: Ditto.
* gcc.target/riscv/_Float16-zfhmin-3.c: Ditto.
* gcc.target/riscv/arch-16.c: Ditto.
* gcc.target/riscv/arch-17.c: Ditto.
* gcc.target/riscv/predef-21.c: Ditto.
* gcc.target/riscv/predef-22.c: Ditto.
---
gcc/common/config/riscv/riscv-common.cc | 8 +++
gcc/config/riscv/riscv-opts.h | 6 ++
gcc/config/riscv/riscv.cc | 33 ++++++++++-
gcc/config/riscv/riscv.md | 59 +++++++++++++++++--
gcc/config/riscv/riscv.opt | 3 +
.../gcc.target/riscv/_Float16-zfh-1.c | 8 +++
.../gcc.target/riscv/_Float16-zfh-2.c | 8 +++
.../gcc.target/riscv/_Float16-zfh-3.c | 8 +++
.../gcc.target/riscv/_Float16-zfhmin-1.c | 9 +++
.../gcc.target/riscv/_Float16-zfhmin-2.c | 9 +++
.../gcc.target/riscv/_Float16-zfhmin-3.c | 9 +++
gcc/testsuite/gcc.target/riscv/arch-16.c | 5 ++
gcc/testsuite/gcc.target/riscv/arch-17.c | 5 ++
gcc/testsuite/gcc.target/riscv/predef-21.c | 59 +++++++++++++++++++
gcc/testsuite/gcc.target/riscv/predef-22.c | 59 +++++++++++++++++++
15 files changed, 279 insertions(+), 9 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zfh-1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zfh-2.c
create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zfh-3.c
create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-2.c
create mode 100644 gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-3.c
create mode 100644 gcc/testsuite/gcc.target/riscv/arch-16.c
create mode 100644 gcc/testsuite/gcc.target/riscv/arch-17.c
create mode 100644 gcc/testsuite/gcc.target/riscv/predef-21.c
create mode 100644 gcc/testsuite/gcc.target/riscv/predef-22.c
diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index 0e5be2ce105..4ee1b3198c5 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -96,6 +96,9 @@ static const riscv_implied_info_t riscv_implied_info[] =
{"zvl32768b", "zvl16384b"},
{"zvl65536b", "zvl32768b"},
+ {"zfh", "zfhmin"},
+ {"zfhmin", "f"},
+
{NULL, NULL}
};
@@ -193,6 +196,9 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
{"zvl32768b", ISA_SPEC_CLASS_NONE, 1, 0},
{"zvl65536b", ISA_SPEC_CLASS_NONE, 1, 0},
+ {"zfh", ISA_SPEC_CLASS_NONE, 1, 0},
+ {"zfhmin", ISA_SPEC_CLASS_NONE, 1, 0},
+
/* Terminate the list. */
{NULL, ISA_SPEC_CLASS_NONE, 0, 0}
};
@@ -1148,6 +1154,8 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
{"zvl32768b", &gcc_options::x_riscv_zvl_flags, MASK_ZVL32768B},
{"zvl65536b", &gcc_options::x_riscv_zvl_flags, MASK_ZVL65536B},
+ {"zfhmin", &gcc_options::x_riscv_zf_subext, MASK_ZFHMIN},
+ {"zfh", &gcc_options::x_riscv_zf_subext, MASK_ZFH},
{NULL, NULL, 0}
};
diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index 1e153b3a6e7..85e869e62e3 100644
--- a/gcc/config/riscv/riscv-opts.h
+++ b/gcc/config/riscv/riscv-opts.h
@@ -153,6 +153,12 @@ enum stack_protector_guard {
#define TARGET_ZICBOM ((riscv_zicmo_subext & MASK_ZICBOM) != 0)
#define TARGET_ZICBOP ((riscv_zicmo_subext & MASK_ZICBOP) != 0)
+#define MASK_ZFHMIN (1 << 0)
+#define MASK_ZFH (1 << 1)
+
+#define TARGET_ZFHMIN ((riscv_zf_subext & MASK_ZFHMIN) != 0)
+#define TARGET_ZFH ((riscv_zf_subext & MASK_ZFH) != 0)
+
/* Bit of riscv_zvl_flags will set contintuly, N-1 bit will set if N-bit is
set, e.g. MASK_ZVL64B has set then MASK_ZVL32B is set, so we can use
popcount to caclulate the minimal VLEN. */
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 47e6110767c..9d70974c893 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2313,6 +2313,8 @@ riscv_output_move (rtx dest, rtx src)
switch (width)
{
case 2:
+ if (TARGET_ZFHMIN)
+ return "fmv.x.h\t%0,%1";
/* Using fmv.x.s + sign-extend to emulate fmv.x.h. */
return "fmv.x.s\t%0,%1;slli\t%0,%0,16;srai\t%0,%0,16";
case 4:
@@ -2367,6 +2369,8 @@ riscv_output_move (rtx dest, rtx src)
switch (width)
{
case 2:
+ if (TARGET_ZFHMIN)
+ return "fmv.h.x\t%0,%z1";
/* High 16 bits should be all-1, otherwise HW will treated
as a n-bit canonical NaN, but isn't matter for softfloat. */
return "fmv.s.x\t%0,%1";
@@ -2395,6 +2399,8 @@ riscv_output_move (rtx dest, rtx src)
switch (width)
{
case 2:
+ if (TARGET_ZFH)
+ return "fmv.h\t%0,%1";
return "fmv.s\t%0,%1";
case 4:
return "fmv.s\t%0,%1";
@@ -2403,12 +2409,28 @@ riscv_output_move (rtx dest, rtx src)
}
if (dest_code == MEM)
- return dbl_p ? "fsd\t%1,%0" : "fsw\t%1,%0";
+ switch (width)
+ {
+ case 2:
+ return "fsh\t%1,%0";
+ case 4:
+ return "fsw\t%1,%0";
+ case 8:
+ return "fsd\t%1,%0";
+ }
}
if (dest_code == REG && FP_REG_P (REGNO (dest)))
{
if (src_code == MEM)
- return dbl_p ? "fld\t%0,%1" : "flw\t%0,%1";
+ switch (width)
+ {
+ case 2:
+ return "flh\t%0,%1";
+ case 4:
+ return "flw\t%0,%1";
+ case 8:
+ return "fld\t%0,%1";
+ }
}
gcc_unreachable ();
}
@@ -2685,6 +2707,10 @@ riscv_emit_float_compare (enum rtx_code *code, rtx *op0, rtx *op1)
emit_insn (gen_f##CMP##_quietdfdi4 (*op0, cmp_op0, cmp_op1)); \
else if (GET_MODE (cmp_op0) == DFmode) \
emit_insn (gen_f##CMP##_quietdfsi4 (*op0, cmp_op0, cmp_op1)); \
+ else if (GET_MODE (cmp_op0) == HFmode && TARGET_64BIT) \
+ emit_insn (gen_f##CMP##_quiethfdi4 (*op0, cmp_op0, cmp_op1)); \
+ else if (GET_MODE (cmp_op0) == HFmode) \
+ emit_insn (gen_f##CMP##_quiethfsi4 (*op0, cmp_op0, cmp_op1)); \
else \
gcc_unreachable (); \
*op1 = const0_rtx; \
@@ -5722,7 +5748,8 @@ riscv_excess_precision (enum excess_precision_type type)
{
case EXCESS_PRECISION_TYPE_FAST:
case EXCESS_PRECISION_TYPE_STANDARD:
- return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT;
+ return (TARGET_ZFH ? FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16
+ : FLT_EVAL_METHOD_PROMOTE_TO_FLOAT);
case EXCESS_PRECISION_TYPE_IMPLICIT:
return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16;
default:
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 7af5c90e0f3..493f00cdb80 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -307,17 +307,18 @@ (define_mode_iterator ANYI [QI HI SI (DI "TARGET_64BIT")])
;; Iterator for hardware-supported floating-point modes.
(define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT")
- (DF "TARGET_DOUBLE_FLOAT")])
+ (DF "TARGET_DOUBLE_FLOAT")
+ (HF "TARGET_ZFH")])
;; Iterator for floating-point modes that can be loaded into X registers.
-(define_mode_iterator SOFTF [SF (DF "TARGET_64BIT")])
+(define_mode_iterator SOFTF [SF (DF "TARGET_64BIT") (HF "TARGET_ZFHMIN")])
;; This attribute gives the length suffix for a sign- or zero-extension
;; instruction.
(define_mode_attr size [(QI "b") (HI "h")])
;; Mode attributes for loads.
-(define_mode_attr load [(QI "lb") (HI "lh") (SI "lw") (DI "ld") (SF "flw") (DF "fld")])
+(define_mode_attr load [(QI "lb") (HI "lh") (SI "lw") (DI "ld") (HF "flh") (SF "flw") (DF "fld")])
;; Instruction names for integer loads that aren't explicitly sign or zero
;; extended. See riscv_output_move and LOAD_EXTEND_OP.
@@ -327,7 +328,7 @@ (define_mode_attr default_load [(QI "lbu") (HI "lhu") (SI "lw") (DI "ld")])
(define_mode_attr softload [(HF "lh") (SF "lw") (DF "ld")])
;; Instruction names for stores.
-(define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd") (SF "fsw") (DF "fsd")])
+(define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd") (HF "fsh") (SF "fsw") (DF "fsd")])
;; Instruction names for FP stores from integer registers.
(define_mode_attr softstore [(HF "sh") (SF "sw") (DF "sd")])
@@ -1324,6 +1325,24 @@ (define_insn "truncdfsf2"
[(set_attr "type" "fcvt")
(set_attr "mode" "SF")])
+(define_insn "truncsfhf2"
+ [(set (match_operand:HF 0 "register_operand" "=f")
+ (float_truncate:HF
+ (match_operand:SF 1 "register_operand" " f")))]
+ "TARGET_ZFHMIN"
+ "fcvt.h.s\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "HF")])
+
+(define_insn "truncdfhf2"
+ [(set (match_operand:HF 0 "register_operand" "=f")
+ (float_truncate:HF
+ (match_operand:DF 1 "register_operand" " f")))]
+ "TARGET_ZFHMIN && TARGET_DOUBLE_FLOAT"
+ "fcvt.h.d\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "HF")])
+
;;
;; ....................
;;
@@ -1441,6 +1460,15 @@ (define_insn_and_split "*extend<SHORT:mode><SUPERQI:mode>2"
[(set_attr "move_type" "shift_shift,load")
(set_attr "mode" "SI")])
+(define_insn "extendhfsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float_extend:SF
+ (match_operand:HF 1 "register_operand" " f")))]
+ "TARGET_ZFHMIN"
+ "fcvt.s.h\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "SF")])
+
(define_insn "extendsfdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(float_extend:DF
@@ -1450,6 +1478,15 @@ (define_insn "extendsfdf2"
[(set_attr "type" "fcvt")
(set_attr "mode" "DF")])
+(define_insn "extendhfdf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (float_extend:DF
+ (match_operand:HF 1 "register_operand" " f")))]
+ "TARGET_ZFHMIN && TARGET_DOUBLE_FLOAT"
+ "fcvt.d.h\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "DF")])
+
;; 16-bit floating point moves
(define_expand "movhf"
[(set (match_operand:HF 0 "")
@@ -1460,12 +1497,22 @@ (define_expand "movhf"
DONE;
})
+(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"))]
+ "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 "mode" "HF")])
(define_insn "*movhf_softfloat"
[(set (match_operand:HF 0 "nonimmediate_operand" "=f, r,r,m,*f,*r")
(match_operand:HF 1 "move_operand" " f,Gr,m,r,*r,*f"))]
- "(register_operand (operands[0], HFmode)
- || reg_or_0_operand (operands[1], HFmode))"
+ "!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,move,load,store,mtc,mfc")
(set_attr "mode" "HF")])
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 9e9fe6d8ccd..fbca91b956c 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -212,6 +212,9 @@ int riscv_zvl_flags
TargetVariable
int riscv_zicmo_subext
+TargetVariable
+int riscv_zf_subext
+
Enum
Name(isa_spec_class) Type(enum riscv_isa_spec_class)
Supported ISA specs (for use with the -misa-spec= option):
diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zfh-1.c b/gcc/testsuite/gcc.target/riscv/_Float16-zfh-1.c
new file mode 100644
index 00000000000..98908dccbb3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/_Float16-zfh-1.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64if_zfh -mabi=lp64f -O" } */
+
+_Float16 foo1 (_Float16 a, _Float16 b)
+{
+ /* { dg-final { scan-assembler-times "fmv.h" 1 } } */
+ return b;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zfh-2.c b/gcc/testsuite/gcc.target/riscv/_Float16-zfh-2.c
new file mode 100644
index 00000000000..58bfa6b4198
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/_Float16-zfh-2.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64if_zfh -mabi=lp64f -O" } */
+
+_Float16 foo1 (_Float16 a, _Float16 b)
+{
+ /* { dg-final { scan-assembler-times "fadd.h" 1 } } */
+ return a + b;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zfh-3.c b/gcc/testsuite/gcc.target/riscv/_Float16-zfh-3.c
new file mode 100644
index 00000000000..128b4e53f27
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/_Float16-zfh-3.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64if_zfh -mabi=lp64f -O" } */
+
+int foo1 (_Float16 a, _Float16 b)
+{
+ /* { dg-final { scan-assembler-times "fgt.h" 1 } } */
+ return a > b;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-1.c b/gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-1.c
new file mode 100644
index 00000000000..631a049f52f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-1.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64if_zfhmin -mabi=lp64f -O" } */
+
+_Float16 foo1 (_Float16 a, _Float16 b)
+{
+ /* { dg-final { scan-assembler-not "fmv.h" } } */
+ /* { dg-final { scan-assembler-times "fmv.s" 1 } } */
+ return b;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-2.c b/gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-2.c
new file mode 100644
index 00000000000..06c85eb797d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-2.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64if_zfhmin -mabi=lp64f -O" } */
+
+_Float16 foo1 (_Float16 a, _Float16 b)
+{
+ /* { dg-final { scan-assembler-not "fadd.h" } } */
+ /* { dg-final { scan-assembler-times "fadd.s" 1 } } */
+ return a + b;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-3.c b/gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-3.c
new file mode 100644
index 00000000000..28960d60245
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-3.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64if_zfhmin -mabi=lp64f -O" } */
+
+int foo1 (_Float16 a, _Float16 b)
+{
+ /* { dg-final { scan-assembler-not "fgt.h" } } */
+ /* { dg-final { scan-assembler-times "fgt.s" 1 } } */
+ return a > b;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/arch-16.c b/gcc/testsuite/gcc.target/riscv/arch-16.c
new file mode 100644
index 00000000000..14b40ae9a5a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/arch-16.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv32gcv_zfh -mabi=ilp32 -mcmodel=medlow" } */
+int foo()
+{
+}
diff --git a/gcc/testsuite/gcc.target/riscv/arch-17.c b/gcc/testsuite/gcc.target/riscv/arch-17.c
new file mode 100644
index 00000000000..3d3275e44a5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/arch-17.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv32gcv_zfhmin -mabi=ilp32 -mcmodel=medlow" } */
+int foo()
+{
+}
diff --git a/gcc/testsuite/gcc.target/riscv/predef-21.c b/gcc/testsuite/gcc.target/riscv/predef-21.c
new file mode 100644
index 00000000000..a171b3b83af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/predef-21.c
@@ -0,0 +1,59 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64i_zfh -mabi=lp64f -mcmodel=medlow -misa-spec=20191213" } */
+
+int main () {
+
+#ifndef __riscv_arch_test
+#error "__riscv_arch_test"
+#endif
+
+#if __riscv_xlen != 64
+#error "__riscv_xlen"
+#endif
+
+#if !defined(__riscv_i)
+#error "__riscv_i"
+#endif
+
+#if defined(__riscv_c)
+#error "__riscv_c"
+#endif
+
+#if defined(__riscv_e)
+#error "__riscv_e"
+#endif
+
+#if defined(__riscv_a)
+#error "__riscv_a"
+#endif
+
+#if defined(__riscv_m)
+#error "__riscv_m"
+#endif
+
+#if !defined(__riscv_f)
+#error "__riscv_f"
+#endif
+
+#if defined(__riscv_d)
+#error "__riscv_d"
+#endif
+
+#if defined(__riscv_v)
+#error "__riscv_v"
+#endif
+
+#if !defined(__riscv_zfh)
+#error "__riscv_zfh"
+#endif
+
+#if !defined(__riscv_zfhmin)
+#error "__riscv_zfhmin"
+#endif
+
+#if !defined(__riscv_zicsr)
+#error "__riscv_zicsr"
+#endif
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/predef-22.c b/gcc/testsuite/gcc.target/riscv/predef-22.c
new file mode 100644
index 00000000000..ad1896573ce
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/predef-22.c
@@ -0,0 +1,59 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64i_zfhmin -mabi=lp64f -mcmodel=medlow -misa-spec=20191213" } */
+
+int main () {
+
+#ifndef __riscv_arch_test
+#error "__riscv_arch_test"
+#endif
+
+#if __riscv_xlen != 64
+#error "__riscv_xlen"
+#endif
+
+#if !defined(__riscv_i)
+#error "__riscv_i"
+#endif
+
+#if defined(__riscv_c)
+#error "__riscv_c"
+#endif
+
+#if defined(__riscv_e)
+#error "__riscv_e"
+#endif
+
+#if defined(__riscv_a)
+#error "__riscv_a"
+#endif
+
+#if defined(__riscv_m)
+#error "__riscv_m"
+#endif
+
+#if !defined(__riscv_f)
+#error "__riscv_f"
+#endif
+
+#if defined(__riscv_d)
+#error "__riscv_d"
+#endif
+
+#if defined(__riscv_v)
+#error "__riscv_v"
+#endif
+
+#if defined(__riscv_zfh)
+#error "__riscv_zfh"
+#endif
+
+#if !defined(__riscv_zfhmin)
+#error "__riscv_zfhmin"
+#endif
+
+#if !defined(__riscv_zicsr)
+#error "__riscv_zicsr"
+#endif
+
+ return 0;
+}
--
2.37.1
@@ -96,6 +96,9 @@ static const riscv_implied_info_t riscv_implied_info[] =
{"zvl32768b", "zvl16384b"},
{"zvl65536b", "zvl32768b"},
+ {"zfh", "zfhmin"},
+ {"zfhmin", "f"},
+
{NULL, NULL}
};
@@ -193,6 +196,9 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
{"zvl32768b", ISA_SPEC_CLASS_NONE, 1, 0},
{"zvl65536b", ISA_SPEC_CLASS_NONE, 1, 0},
+ {"zfh", ISA_SPEC_CLASS_NONE, 1, 0},
+ {"zfhmin", ISA_SPEC_CLASS_NONE, 1, 0},
+
/* Terminate the list. */
{NULL, ISA_SPEC_CLASS_NONE, 0, 0}
};
@@ -1148,6 +1154,8 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
{"zvl32768b", &gcc_options::x_riscv_zvl_flags, MASK_ZVL32768B},
{"zvl65536b", &gcc_options::x_riscv_zvl_flags, MASK_ZVL65536B},
+ {"zfhmin", &gcc_options::x_riscv_zf_subext, MASK_ZFHMIN},
+ {"zfh", &gcc_options::x_riscv_zf_subext, MASK_ZFH},
{NULL, NULL, 0}
};
@@ -153,6 +153,12 @@ enum stack_protector_guard {
#define TARGET_ZICBOM ((riscv_zicmo_subext & MASK_ZICBOM) != 0)
#define TARGET_ZICBOP ((riscv_zicmo_subext & MASK_ZICBOP) != 0)
+#define MASK_ZFHMIN (1 << 0)
+#define MASK_ZFH (1 << 1)
+
+#define TARGET_ZFHMIN ((riscv_zf_subext & MASK_ZFHMIN) != 0)
+#define TARGET_ZFH ((riscv_zf_subext & MASK_ZFH) != 0)
+
/* Bit of riscv_zvl_flags will set contintuly, N-1 bit will set if N-bit is
set, e.g. MASK_ZVL64B has set then MASK_ZVL32B is set, so we can use
popcount to caclulate the minimal VLEN. */
@@ -2313,6 +2313,8 @@ riscv_output_move (rtx dest, rtx src)
switch (width)
{
case 2:
+ if (TARGET_ZFHMIN)
+ return "fmv.x.h\t%0,%1";
/* Using fmv.x.s + sign-extend to emulate fmv.x.h. */
return "fmv.x.s\t%0,%1;slli\t%0,%0,16;srai\t%0,%0,16";
case 4:
@@ -2367,6 +2369,8 @@ riscv_output_move (rtx dest, rtx src)
switch (width)
{
case 2:
+ if (TARGET_ZFHMIN)
+ return "fmv.h.x\t%0,%z1";
/* High 16 bits should be all-1, otherwise HW will treated
as a n-bit canonical NaN, but isn't matter for softfloat. */
return "fmv.s.x\t%0,%1";
@@ -2395,6 +2399,8 @@ riscv_output_move (rtx dest, rtx src)
switch (width)
{
case 2:
+ if (TARGET_ZFH)
+ return "fmv.h\t%0,%1";
return "fmv.s\t%0,%1";
case 4:
return "fmv.s\t%0,%1";
@@ -2403,12 +2409,28 @@ riscv_output_move (rtx dest, rtx src)
}
if (dest_code == MEM)
- return dbl_p ? "fsd\t%1,%0" : "fsw\t%1,%0";
+ switch (width)
+ {
+ case 2:
+ return "fsh\t%1,%0";
+ case 4:
+ return "fsw\t%1,%0";
+ case 8:
+ return "fsd\t%1,%0";
+ }
}
if (dest_code == REG && FP_REG_P (REGNO (dest)))
{
if (src_code == MEM)
- return dbl_p ? "fld\t%0,%1" : "flw\t%0,%1";
+ switch (width)
+ {
+ case 2:
+ return "flh\t%0,%1";
+ case 4:
+ return "flw\t%0,%1";
+ case 8:
+ return "fld\t%0,%1";
+ }
}
gcc_unreachable ();
}
@@ -2685,6 +2707,10 @@ riscv_emit_float_compare (enum rtx_code *code, rtx *op0, rtx *op1)
emit_insn (gen_f##CMP##_quietdfdi4 (*op0, cmp_op0, cmp_op1)); \
else if (GET_MODE (cmp_op0) == DFmode) \
emit_insn (gen_f##CMP##_quietdfsi4 (*op0, cmp_op0, cmp_op1)); \
+ else if (GET_MODE (cmp_op0) == HFmode && TARGET_64BIT) \
+ emit_insn (gen_f##CMP##_quiethfdi4 (*op0, cmp_op0, cmp_op1)); \
+ else if (GET_MODE (cmp_op0) == HFmode) \
+ emit_insn (gen_f##CMP##_quiethfsi4 (*op0, cmp_op0, cmp_op1)); \
else \
gcc_unreachable (); \
*op1 = const0_rtx; \
@@ -5722,7 +5748,8 @@ riscv_excess_precision (enum excess_precision_type type)
{
case EXCESS_PRECISION_TYPE_FAST:
case EXCESS_PRECISION_TYPE_STANDARD:
- return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT;
+ return (TARGET_ZFH ? FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16
+ : FLT_EVAL_METHOD_PROMOTE_TO_FLOAT);
case EXCESS_PRECISION_TYPE_IMPLICIT:
return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16;
default:
@@ -307,17 +307,18 @@ (define_mode_iterator ANYI [QI HI SI (DI "TARGET_64BIT")])
;; Iterator for hardware-supported floating-point modes.
(define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT")
- (DF "TARGET_DOUBLE_FLOAT")])
+ (DF "TARGET_DOUBLE_FLOAT")
+ (HF "TARGET_ZFH")])
;; Iterator for floating-point modes that can be loaded into X registers.
-(define_mode_iterator SOFTF [SF (DF "TARGET_64BIT")])
+(define_mode_iterator SOFTF [SF (DF "TARGET_64BIT") (HF "TARGET_ZFHMIN")])
;; This attribute gives the length suffix for a sign- or zero-extension
;; instruction.
(define_mode_attr size [(QI "b") (HI "h")])
;; Mode attributes for loads.
-(define_mode_attr load [(QI "lb") (HI "lh") (SI "lw") (DI "ld") (SF "flw") (DF "fld")])
+(define_mode_attr load [(QI "lb") (HI "lh") (SI "lw") (DI "ld") (HF "flh") (SF "flw") (DF "fld")])
;; Instruction names for integer loads that aren't explicitly sign or zero
;; extended. See riscv_output_move and LOAD_EXTEND_OP.
@@ -327,7 +328,7 @@ (define_mode_attr default_load [(QI "lbu") (HI "lhu") (SI "lw") (DI "ld")])
(define_mode_attr softload [(HF "lh") (SF "lw") (DF "ld")])
;; Instruction names for stores.
-(define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd") (SF "fsw") (DF "fsd")])
+(define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd") (HF "fsh") (SF "fsw") (DF "fsd")])
;; Instruction names for FP stores from integer registers.
(define_mode_attr softstore [(HF "sh") (SF "sw") (DF "sd")])
@@ -1324,6 +1325,24 @@ (define_insn "truncdfsf2"
[(set_attr "type" "fcvt")
(set_attr "mode" "SF")])
+(define_insn "truncsfhf2"
+ [(set (match_operand:HF 0 "register_operand" "=f")
+ (float_truncate:HF
+ (match_operand:SF 1 "register_operand" " f")))]
+ "TARGET_ZFHMIN"
+ "fcvt.h.s\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "HF")])
+
+(define_insn "truncdfhf2"
+ [(set (match_operand:HF 0 "register_operand" "=f")
+ (float_truncate:HF
+ (match_operand:DF 1 "register_operand" " f")))]
+ "TARGET_ZFHMIN && TARGET_DOUBLE_FLOAT"
+ "fcvt.h.d\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "HF")])
+
;;
;; ....................
;;
@@ -1441,6 +1460,15 @@ (define_insn_and_split "*extend<SHORT:mode><SUPERQI:mode>2"
[(set_attr "move_type" "shift_shift,load")
(set_attr "mode" "SI")])
+(define_insn "extendhfsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float_extend:SF
+ (match_operand:HF 1 "register_operand" " f")))]
+ "TARGET_ZFHMIN"
+ "fcvt.s.h\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "SF")])
+
(define_insn "extendsfdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(float_extend:DF
@@ -1450,6 +1478,15 @@ (define_insn "extendsfdf2"
[(set_attr "type" "fcvt")
(set_attr "mode" "DF")])
+(define_insn "extendhfdf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (float_extend:DF
+ (match_operand:HF 1 "register_operand" " f")))]
+ "TARGET_ZFHMIN && TARGET_DOUBLE_FLOAT"
+ "fcvt.d.h\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "DF")])
+
;; 16-bit floating point moves
(define_expand "movhf"
[(set (match_operand:HF 0 "")
@@ -1460,12 +1497,22 @@ (define_expand "movhf"
DONE;
})
+(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"))]
+ "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 "mode" "HF")])
(define_insn "*movhf_softfloat"
[(set (match_operand:HF 0 "nonimmediate_operand" "=f, r,r,m,*f,*r")
(match_operand:HF 1 "move_operand" " f,Gr,m,r,*r,*f"))]
- "(register_operand (operands[0], HFmode)
- || reg_or_0_operand (operands[1], HFmode))"
+ "!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,move,load,store,mtc,mfc")
(set_attr "mode" "HF")])
@@ -212,6 +212,9 @@ int riscv_zvl_flags
TargetVariable
int riscv_zicmo_subext
+TargetVariable
+int riscv_zf_subext
+
Enum
Name(isa_spec_class) Type(enum riscv_isa_spec_class)
Supported ISA specs (for use with the -misa-spec= option):
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64if_zfh -mabi=lp64f -O" } */
+
+_Float16 foo1 (_Float16 a, _Float16 b)
+{
+ /* { dg-final { scan-assembler-times "fmv.h" 1 } } */
+ return b;
+}
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64if_zfh -mabi=lp64f -O" } */
+
+_Float16 foo1 (_Float16 a, _Float16 b)
+{
+ /* { dg-final { scan-assembler-times "fadd.h" 1 } } */
+ return a + b;
+}
new file mode 100644
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64if_zfh -mabi=lp64f -O" } */
+
+int foo1 (_Float16 a, _Float16 b)
+{
+ /* { dg-final { scan-assembler-times "fgt.h" 1 } } */
+ return a > b;
+}
new file mode 100644
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64if_zfhmin -mabi=lp64f -O" } */
+
+_Float16 foo1 (_Float16 a, _Float16 b)
+{
+ /* { dg-final { scan-assembler-not "fmv.h" } } */
+ /* { dg-final { scan-assembler-times "fmv.s" 1 } } */
+ return b;
+}
new file mode 100644
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64if_zfhmin -mabi=lp64f -O" } */
+
+_Float16 foo1 (_Float16 a, _Float16 b)
+{
+ /* { dg-final { scan-assembler-not "fadd.h" } } */
+ /* { dg-final { scan-assembler-times "fadd.s" 1 } } */
+ return a + b;
+}
new file mode 100644
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64if_zfhmin -mabi=lp64f -O" } */
+
+int foo1 (_Float16 a, _Float16 b)
+{
+ /* { dg-final { scan-assembler-not "fgt.h" } } */
+ /* { dg-final { scan-assembler-times "fgt.s" 1 } } */
+ return a > b;
+}
new file mode 100644
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv32gcv_zfh -mabi=ilp32 -mcmodel=medlow" } */
+int foo()
+{
+}
new file mode 100644
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv32gcv_zfhmin -mabi=ilp32 -mcmodel=medlow" } */
+int foo()
+{
+}
new file mode 100644
@@ -0,0 +1,59 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64i_zfh -mabi=lp64f -mcmodel=medlow -misa-spec=20191213" } */
+
+int main () {
+
+#ifndef __riscv_arch_test
+#error "__riscv_arch_test"
+#endif
+
+#if __riscv_xlen != 64
+#error "__riscv_xlen"
+#endif
+
+#if !defined(__riscv_i)
+#error "__riscv_i"
+#endif
+
+#if defined(__riscv_c)
+#error "__riscv_c"
+#endif
+
+#if defined(__riscv_e)
+#error "__riscv_e"
+#endif
+
+#if defined(__riscv_a)
+#error "__riscv_a"
+#endif
+
+#if defined(__riscv_m)
+#error "__riscv_m"
+#endif
+
+#if !defined(__riscv_f)
+#error "__riscv_f"
+#endif
+
+#if defined(__riscv_d)
+#error "__riscv_d"
+#endif
+
+#if defined(__riscv_v)
+#error "__riscv_v"
+#endif
+
+#if !defined(__riscv_zfh)
+#error "__riscv_zfh"
+#endif
+
+#if !defined(__riscv_zfhmin)
+#error "__riscv_zfhmin"
+#endif
+
+#if !defined(__riscv_zicsr)
+#error "__riscv_zicsr"
+#endif
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,59 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64i_zfhmin -mabi=lp64f -mcmodel=medlow -misa-spec=20191213" } */
+
+int main () {
+
+#ifndef __riscv_arch_test
+#error "__riscv_arch_test"
+#endif
+
+#if __riscv_xlen != 64
+#error "__riscv_xlen"
+#endif
+
+#if !defined(__riscv_i)
+#error "__riscv_i"
+#endif
+
+#if defined(__riscv_c)
+#error "__riscv_c"
+#endif
+
+#if defined(__riscv_e)
+#error "__riscv_e"
+#endif
+
+#if defined(__riscv_a)
+#error "__riscv_a"
+#endif
+
+#if defined(__riscv_m)
+#error "__riscv_m"
+#endif
+
+#if !defined(__riscv_f)
+#error "__riscv_f"
+#endif
+
+#if defined(__riscv_d)
+#error "__riscv_d"
+#endif
+
+#if defined(__riscv_v)
+#error "__riscv_v"
+#endif
+
+#if defined(__riscv_zfh)
+#error "__riscv_zfh"
+#endif
+
+#if !defined(__riscv_zfhmin)
+#error "__riscv_zfhmin"
+#endif
+
+#if !defined(__riscv_zicsr)
+#error "__riscv_zicsr"
+#endif
+
+ return 0;
+}