@@ -98,6 +98,13 @@
(and (match_code "const_double")
(match_test "op == CONST0_RTX (mode)")))
+;; Floating-point constant that can be generated by a FLI instruction
+;; in the 'Zfa' standard extension.
+(define_constraint "H"
+ "@internal"
+ (and (match_code "const_double")
+ (match_test "riscv_get_float_fli_const (op).valid")))
+
(define_memory_constraint "A"
"An address that is held in a general-purpose register."
(and (match_code "mem")
@@ -80,6 +80,39 @@ struct riscv_address_info {
enum riscv_symbol_type symbol_type;
};
+/* Classifies a floating point constant possibly retrieved by
+ the FLI instructions.
+
+ RISCV_FLOAT_CONST_MIN
+ The minimum positive normal value for given mode.
+
+ RISCV_FLOAT_CONST_INF
+ Positive infinity.
+
+ RISCV_FLOAT_CONST_NAN
+ Canonical NaN (positive, quiet and zero payload NaN).
+
+ RISCV_FLOAT_CONST_FINITE
+ A finite number. */
+enum riscv_float_fli_const_type {
+ RISCV_FLOAT_CONST_MIN,
+ RISCV_FLOAT_CONST_INF,
+ RISCV_FLOAT_CONST_NAN,
+ RISCV_FLOAT_CONST_FINITE,
+};
+
+/* Information about a floating point constant possibly retrieved by
+ the FLI instructions. */
+struct riscv_float_fli_const {
+ bool valid: 1;
+ bool sign: 1;
+ enum riscv_float_fli_const_type type: 2;
+ /* Highest 2 bits of IEEE754 mantissa on RISCV_FLOAT_CONST_FINITE. */
+ unsigned int mantissa_below_point: 2;
+ /* IEEE754 normal exponent - 16 on RISCV_FLOAT_CONST_FINITE. */
+ unsigned int biased_exponent: 6;
+};
+
/* 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 *);
@@ -125,6 +158,7 @@ extern rtx riscv_gen_gpr_save_insn (struct riscv_frame_info *);
extern bool riscv_gpr_save_operation_p (rtx);
extern void riscv_reinit (void);
extern poly_uint64 riscv_regmode_natural_size (machine_mode);
+extern struct riscv_float_fli_const riscv_get_float_fli_const (rtx);
extern bool riscv_v_ext_vector_mode_p (machine_mode);
extern bool riscv_v_ext_tuple_mode_p (machine_mode);
extern bool riscv_v_ext_vls_mode_p (machine_mode);
@@ -812,6 +812,185 @@ riscv_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
return riscv_const_insns (x) > 0;
}
+/* Check and generate information corresponding a floating point constant
+ that can be generated from a FLI instruction. */
+
+struct riscv_float_fli_const
+riscv_get_float_fli_const (rtx x)
+{
+ struct riscv_float_fli_const result = {
+ false, false, RISCV_FLOAT_CONST_FINITE, 0, 0
+ };
+ REAL_VALUE_TYPE r, m;
+
+ if (!TARGET_HARD_FLOAT || !TARGET_ZFA)
+ return result;
+ switch (GET_MODE (x))
+ {
+ case HFmode:
+ /* Not only 'Zfhmin', either 'Zfh' or 'Zvfh' is required. */
+ if (!TARGET_ZFH && !TARGET_ZVFH)
+ return result;
+ break;
+ case SFmode: break;
+ case DFmode: break;
+ default: return result;
+ }
+
+ if (!CONST_DOUBLE_P (x))
+ return result;
+
+ r = *CONST_DOUBLE_REAL_VALUE (x);
+
+ if (REAL_VALUE_ISNAN (r))
+ {
+ long reprs[2] = { 0 };
+ /* Compare with canonical NaN. */
+ switch (GET_MODE (x))
+ {
+ case HFmode:
+ reprs[0] = real_to_target (NULL, &r,
+ float_mode_for_size (16).require ());
+ /* 0x7e00: Canonical NaN for binary16. */
+ if (reprs[0] != 0x7e00)
+ return result;
+ break;
+ case SFmode:
+ reprs[0] = real_to_target (NULL, &r,
+ float_mode_for_size (32).require ());
+ /* 0x7fc00000: Canonical NaN for binary32. */
+ if (reprs[0] != 0x7fc00000)
+ return result;
+ break;
+ case DFmode:
+ real_to_target (reprs, &r, float_mode_for_size (64).require ());
+ if (FLOAT_WORDS_BIG_ENDIAN)
+ std::swap (reprs[0], reprs[1]);
+ /* 0x7ff80000_00000000: Canonical NaN for binary64. */
+ if (reprs[0] != 0 || reprs[1] != 0x7ff80000)
+ return result;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ result.type = RISCV_FLOAT_CONST_NAN;
+ result.valid = true;
+ return result;
+ }
+ else if (REAL_VALUE_ISINF (r))
+ {
+ if (REAL_VALUE_NEGATIVE (r))
+ return result;
+ result.type = RISCV_FLOAT_CONST_INF;
+ result.valid = true;
+ return result;
+ }
+
+ bool sign = REAL_VALUE_NEGATIVE (r);
+ result.sign = sign;
+
+ r = real_value_abs (&r);
+ /* GCC internally does not use IEEE754-like encoding (where normalized
+ significands are in the range [1, 2). GCC uses [0.5, 1) (see real.cc).
+ So, this exponent_p1 variable equals IEEE754 unbiased exponent + 1. */
+ int exponent_p1 = REAL_EXP (&r);
+
+ /* For the mantissa, we expand into two HOST_WIDE_INTS, apart from the
+ highest (sign) bit, with a fixed binary point at bit point_pos.
+ m1 holds the low part of the mantissa, m2 the high part.
+ WARNING: If we ever have a representation using more than 2 * H_W_I - 1
+ bits for the mantissa, this can fail (low bits will be lost). */
+ bool fail = false;
+ real_ldexp (&m, &r, (2 * HOST_BITS_PER_WIDE_INT - 1) - exponent_p1);
+ wide_int w = real_to_integer (&m, &fail, HOST_BITS_PER_WIDE_INT * 2);
+ if (fail)
+ return result;
+
+ /* If the low part of the mantissa has bits set we cannot represent
+ the value. */
+ if (w.ulow () != 0)
+ return result;
+ /* We have rejected the lower HOST_WIDE_INT, so update our
+ understanding of how many bits lie in the mantissa and
+ look only at the high HOST_WIDE_INT. */
+ unsigned HOST_WIDE_INT mantissa = w.elt (1);
+
+ /* We cannot represent the value 0.0. */
+ if (mantissa == 0)
+ return result;
+
+ /* We can only represent values with a mantissa of the form 1.xx. */
+ unsigned HOST_WIDE_INT mask
+ = ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 4)) - 1;
+ if ((mantissa & mask) != 0)
+ return result;
+ mantissa >>= HOST_BITS_PER_WIDE_INT - 4;
+ /* Now the lowest 3-bits of mantissa should form (1.xx)b. */
+ gcc_assert (mantissa & (1u << 2));
+ /* Mask out the highest bit. */
+ mantissa &= ~(1u << 2);
+
+ if (mantissa == 0)
+ {
+ /* We cannot represent any values but -1.0. */
+ if (exponent_p1 != 1 && sign)
+ return result;
+ switch (exponent_p1)
+ {
+ case -15: /* 1.0 * 2^(-16) */
+ case -14: /* 1.0 * 2^(-15) */
+ case -7: /* 1.0 * 2^(- 8) */
+ case -6: /* 1.0 * 2^(- 7) */
+ case 8: /* 1.0 * 2^(+ 7) */
+ case 9: /* 1.0 * 2^(+ 8) */
+ case 16: /* 1.0 * 2^(+15) */
+ case 17: /* 1.0 * 2^(+16) */
+ break;
+ default:
+ if (exponent_p1 >= -3 && exponent_p1 <= 5)
+ /* 1.0 * 2^[-4,4] */
+ break;
+ switch (GET_MODE (x))
+ {
+ case HFmode: /* IEEE 754 binary16. */
+ /* Minimum positive normal == 1.0 * 2^(-14) */
+ if (exponent_p1 != -13) return result;
+ break;
+ case SFmode: /* IEEE 754 binary32. */
+ /* Minimum positive normal == 1.0 * 2^(-126) */
+ if (exponent_p1 != -125) return result;
+ break;
+ case DFmode: /* IEEE 754 binary64. */
+ /* Minimum positive normal == 1.0 * 2^(-1022) */
+ if (exponent_p1 != -1021) return result;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ result.type = RISCV_FLOAT_CONST_MIN;
+ result.valid = true;
+ return result;
+ }
+ }
+ else
+ {
+ if (sign)
+ return result;
+ if (exponent_p1 < -1 || exponent_p1 > 2)
+ return result;
+ /* The value is (+1.xx)b * 2^[-2,1].
+ But we cannot represent (+1.11)b * 2^1 (that is 3.5). */
+ if (exponent_p1 == 2 && mantissa == 3)
+ return result;
+ }
+
+ result.valid = true;
+ result.mantissa_below_point = mantissa;
+ result.biased_exponent = exponent_p1 + 15;
+
+ return result;
+}
+
/* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
static bool
@@ -1322,8 +1501,12 @@ riscv_const_insns (rtx x)
}
case CONST_DOUBLE:
- /* We can use x0 to load floating-point zero. */
- return x == CONST0_RTX (GET_MODE (x)) ? 1 : 0;
+ /* We can use x0 to load floating-point zero.
+ We also have FLI instructions when the Zfa extension is enabled. */
+ return x == CONST0_RTX (GET_MODE (x)) ? 1
+ : riscv_get_float_fli_const (x).valid ? 1
+ : 0;
+
case CONST_VECTOR:
{
/* TODO: This is not accurate, we will need to
@@ -1362,17 +1545,14 @@ riscv_const_insns (rtx x)
constant incurs a literal-pool access. Allow this in
order to increase vectorization possibilities. */
int n = riscv_const_insns (elt);
- if (CONST_DOUBLE_P (elt))
- return 1 + 4; /* vfmv.v.f + memory access. */
+ /* We need as many insns as it takes to load the constant
+ into a GPR and one vmv.v.x. */
+ if (n != 0)
+ return 1 + n;
+ else if (CONST_DOUBLE_P (elt))
+ return 1 + 4; /* vfmv.v.f + memory access. */
else
- {
- /* We need as many insns as it takes to load the constant
- into a GPR and one vmv.v.x. */
- if (n != 0)
- return 1 + n;
- else
- return 1 + 4; /*vmv.v.x + memory access. */
- }
+ return 1 + 4; /* vmv.v.x + memory access. */
}
}
@@ -3196,6 +3376,22 @@ riscv_output_move (rtx dest, rtx src)
gcc_assert (known_eq (rtx_to_poly_int64 (src), BYTES_PER_RISCV_VECTOR));
return "csrr\t%0,vlenb";
}
+ if (dest_code == REG && src_code == CONST_DOUBLE)
+ {
+ struct riscv_float_fli_const flt = riscv_get_float_fli_const (src);
+ if (flt.valid)
+ {
+ 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";
+ }
+ }
+ }
gcc_unreachable ();
}
@@ -5117,6 +5313,36 @@ riscv_print_operand (FILE *file, rtx op, int letter)
output_address (mode, XEXP (op, 0));
break;
+ case CONST_DOUBLE:
+ {
+ struct riscv_float_fli_const flt = riscv_get_float_fli_const (op);
+ if (flt.valid)
+ {
+ switch (flt.type)
+ {
+ case RISCV_FLOAT_CONST_MIN:
+ fputs ("min", file);
+ break;
+ case RISCV_FLOAT_CONST_INF:
+ fputs ("inf", file);
+ break;
+ case RISCV_FLOAT_CONST_NAN:
+ fputs ("nan", file);
+ break;
+ default:
+ /* Use simpler (and bit-perfect) printer. */
+ if (flt.sign)
+ fputc ('-', file);
+ fprintf (file, "0x1.%cp%+d",
+ "048c"[flt.mantissa_below_point],
+ (int) flt.biased_exponent - 16);
+ break;
+ }
+ break;
+ }
+ }
+ /* Fall through. */
+
default:
if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
fputs (reg_names[GP_REG_FIRST], file);
@@ -1744,13 +1744,13 @@
})
(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,G,H,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,mtc,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
(set_attr "mode" "HF")])
(define_insn "*movhf_softfloat"
@@ -2075,13 +2075,13 @@
})
(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,G,H,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,mtc,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
(set_attr "mode" "SF")])
(define_insn "*movsf_softfloat"
@@ -2109,23 +2109,23 @@
;; In RV32, we lack fmv.x.d and fmv.d.x. Go through memory instead.
;; (However, we can still use fcvt.d.w to zero a floating-point register.)
(define_insn "*movdf_hardfloat_rv32"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*th_f_fmv,*th_r_fmv, *r,*r,*m")
- (match_operand:DF 1 "move_operand" " f,G,m,f,G,*th_r_fmv,*th_f_fmv,*r*G,*m,*r"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,f,m,m, *th_f_fmv,*th_r_fmv, *r, *r,*m")
+ (match_operand:DF 1 "move_operand" " f,G,H,m,f,G,*th_r_fmv,*th_f_fmv,*r*G,*m,*r"))]
"!TARGET_64BIT && TARGET_DOUBLE_FLOAT
&& (register_operand (operands[0], DFmode)
|| reg_or_0_operand (operands[1], DFmode))"
{ return riscv_output_move (operands[0], operands[1]); }
- [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+ [(set_attr "move_type" "fmove,mtc,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,G,H,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,mtc,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
(set_attr "mode" "DF")])
(define_insn "*movdf_softfloat"
new file mode 100644
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imfd_zfa -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32imfd_zfa -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os" "-Og" "-Oz"} } */
+
+#ifndef __riscv_zfa
+#error Feature macro not defined
+#endif
+
+double
+foo_positive_d (double a)
+{
+ /* Use 3 FLI FP constants. */
+ return (2.5 * a - 1.0) / 0.875;
+}
+
+float
+foo_positive_s (float a)
+{
+ return ((float) 2.5 * a - (float) 1.0) / (float) 0.875;
+}
+
+/* { dg-final { scan-assembler-times "fli\\.s\t" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.d\t" 3 } } */
new file mode 100644
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imfd_zfa -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32imfd_zfa -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Os" "-Og" "-Oz"} } */
+
+#ifndef __riscv_zfa
+#error Feature macro not defined
+#endif
+
+double
+foo_negative_d (double a)
+{
+ /* Use 3 "non-FLI" FP constants. */
+ return (3.5 * a - 5.0) / 0.1875;
+}
+
+float
+foo_negative_s (float a)
+{
+ return ((float) 3.5 * a - (float) 5.0) / (float) 0.1875;
+}
+
+/* { dg-final { scan-assembler-not "fli\\.s\t" } } */
+/* { dg-final { scan-assembler-not "fli\\.d\t" } } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imfd_zfa -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32imfd_zfa -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os" "-Og" "-Oz"} } */
+
+double
+foo_positive_s (float a)
+{
+ /* Use 3 FLI FP constants (but type conversion occur in the middle). */
+ return (2.5f * a - 1.0) / 0.875;
+}
+
+/* { dg-final { scan-assembler-times "fli\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.d\t" 2 } } */
new file mode 100644
@@ -0,0 +1,111 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imfd_zfa_zfh -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32imfd_zfa_zfh -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */
+
+#define TYPE_h _Float16
+#define TYPE_s float
+#define TYPE_d double
+
+#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT
+
+#define DECL_FUNC(TYPE_SHORT, N, VALUE) \
+ DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void) \
+ { \
+ return VALUE; \
+ }
+
+#define DECL_FINITE_FUNCS(TYPE_SHORT) \
+ DECL_FUNC (TYPE_SHORT, 00, -1) \
+ DECL_FUNC (TYPE_SHORT, 02, 0.0000152587890625) \
+ DECL_FUNC (TYPE_SHORT, 03, 0.000030517578125) \
+ DECL_FUNC (TYPE_SHORT, 04, 0.00390625) \
+ DECL_FUNC (TYPE_SHORT, 05, 0.0078125) \
+ DECL_FUNC (TYPE_SHORT, 06, 0.0625) \
+ DECL_FUNC (TYPE_SHORT, 07, 0.125) \
+ DECL_FUNC (TYPE_SHORT, 08, 0.25) \
+ DECL_FUNC (TYPE_SHORT, 09, 0.3125) \
+ DECL_FUNC (TYPE_SHORT, 10, 0.375) \
+ DECL_FUNC (TYPE_SHORT, 11, 0.4375) \
+ DECL_FUNC (TYPE_SHORT, 12, 0.5) \
+ DECL_FUNC (TYPE_SHORT, 13, 0.625) \
+ DECL_FUNC (TYPE_SHORT, 14, 0.75) \
+ DECL_FUNC (TYPE_SHORT, 15, 0.875) \
+ DECL_FUNC (TYPE_SHORT, 16, 1) \
+ DECL_FUNC (TYPE_SHORT, 17, 1.25) \
+ DECL_FUNC (TYPE_SHORT, 18, 1.5) \
+ DECL_FUNC (TYPE_SHORT, 19, 1.75) \
+ DECL_FUNC (TYPE_SHORT, 20, 2) \
+ DECL_FUNC (TYPE_SHORT, 21, 2.5) \
+ DECL_FUNC (TYPE_SHORT, 22, 3) \
+ DECL_FUNC (TYPE_SHORT, 23, 4) \
+ DECL_FUNC (TYPE_SHORT, 24, 8) \
+ DECL_FUNC (TYPE_SHORT, 25, 16) \
+ DECL_FUNC (TYPE_SHORT, 26, 128) \
+ DECL_FUNC (TYPE_SHORT, 27, 256) \
+ DECL_FUNC (TYPE_SHORT, 28, 32768) \
+ DECL_FUNC (TYPE_SHORT, 29, 65536)
+
+/* Finite numbers (except 2^16 in _Float16, making an inf). */
+DECL_FINITE_FUNCS (h)
+DECL_FINITE_FUNCS (s)
+DECL_FINITE_FUNCS (d)
+
+/* min. */
+DECL_FUNC (h, 01, __FLT16_MIN__)
+DECL_FUNC (s, 01, __FLT_MIN__)
+DECL_FUNC (d, 01, __DBL_MIN__)
+
+/* inf. */
+DECL_FUNC (h, 30, __builtin_inff16 ())
+DECL_FUNC (s, 30, __builtin_inff ())
+DECL_FUNC (d, 30, __builtin_inf ())
+
+/* nan. */
+DECL_FUNC (h, 31, __builtin_nanf16 (""))
+DECL_FUNC (s, 31, __builtin_nanf (""))
+DECL_FUNC (d, 31, __builtin_nan (""))
+
+
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,-0x1\\.0p\\+0\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p-16\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p-15\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p-8\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p-7\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p-4\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p-3\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p-2\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.4p-2\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.8p-2\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.cp-2\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p-1\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.4p-1\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.8p-1\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.cp-1\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p\\+0\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.4p\\+0\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.8p\\+0\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.cp\\+0\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p\\+1\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.4p\\+1\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.8p\\+1\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p\\+2\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p\\+3\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p\\+4\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p\\+7\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p\\+8\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,0x1\\.0p\\+15\n" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.\[sd]\tfa0,0x1\\.0p\\+16\n" 2 } } */
+
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,min\n" 3 } } */
+
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,inf\n" 2 } } */
+/* { dg-final { scan-assembler-times "fli\\.s\tfa0,inf\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.d\tfa0,inf\n" 1 } } */
+
+/* { dg-final { scan-assembler-times "fli\\.\[hsd]\tfa0,nan\n" 3 } } */
+
+
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0," 32 } } */
+/* { dg-final { scan-assembler-times "fli\\.s\tfa0," 32 } } */
+/* { dg-final { scan-assembler-times "fli\\.d\tfa0," 32 } } */
new file mode 100644
@@ -0,0 +1,98 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imf_zfa_zvfh -mabi=lp64f" { target { rv64 } } } */
+/* { dg-options "-march=rv32imf_zfa_zvfh -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */
+
+/* Even if 'Zfh' is disabled, "fli.h" is usable when
+ both 'Zfa' and 'Zvfh' are available. */
+#ifdef __riscv_zfh
+#error Invalid feature macro defined
+#endif
+
+#define TYPE_h _Float16
+
+#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT
+
+#define DECL_FUNC(TYPE_SHORT, N, VALUE) \
+ DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void) \
+ { \
+ return VALUE; \
+ }
+
+#define DECL_FINITE_FUNCS(TYPE_SHORT) \
+ DECL_FUNC (TYPE_SHORT, 00, -1) \
+ DECL_FUNC (TYPE_SHORT, 02, 0.0000152587890625) \
+ DECL_FUNC (TYPE_SHORT, 03, 0.000030517578125) \
+ DECL_FUNC (TYPE_SHORT, 04, 0.00390625) \
+ DECL_FUNC (TYPE_SHORT, 05, 0.0078125) \
+ DECL_FUNC (TYPE_SHORT, 06, 0.0625) \
+ DECL_FUNC (TYPE_SHORT, 07, 0.125) \
+ DECL_FUNC (TYPE_SHORT, 08, 0.25) \
+ DECL_FUNC (TYPE_SHORT, 09, 0.3125) \
+ DECL_FUNC (TYPE_SHORT, 10, 0.375) \
+ DECL_FUNC (TYPE_SHORT, 11, 0.4375) \
+ DECL_FUNC (TYPE_SHORT, 12, 0.5) \
+ DECL_FUNC (TYPE_SHORT, 13, 0.625) \
+ DECL_FUNC (TYPE_SHORT, 14, 0.75) \
+ DECL_FUNC (TYPE_SHORT, 15, 0.875) \
+ DECL_FUNC (TYPE_SHORT, 16, 1) \
+ DECL_FUNC (TYPE_SHORT, 17, 1.25) \
+ DECL_FUNC (TYPE_SHORT, 18, 1.5) \
+ DECL_FUNC (TYPE_SHORT, 19, 1.75) \
+ DECL_FUNC (TYPE_SHORT, 20, 2) \
+ DECL_FUNC (TYPE_SHORT, 21, 2.5) \
+ DECL_FUNC (TYPE_SHORT, 22, 3) \
+ DECL_FUNC (TYPE_SHORT, 23, 4) \
+ DECL_FUNC (TYPE_SHORT, 24, 8) \
+ DECL_FUNC (TYPE_SHORT, 25, 16) \
+ DECL_FUNC (TYPE_SHORT, 26, 128) \
+ DECL_FUNC (TYPE_SHORT, 27, 256) \
+ DECL_FUNC (TYPE_SHORT, 28, 32768) \
+ DECL_FUNC (TYPE_SHORT, 29, 65536)
+
+/* Finite numbers (except 2^16 in _Float16, making an inf). */
+DECL_FINITE_FUNCS (h)
+
+/* min. */
+DECL_FUNC (h, 01, __FLT16_MIN__)
+
+/* inf. */
+DECL_FUNC (h, 30, __builtin_inff16 ())
+
+
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,-0x1\\.0p\\+0\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p-16\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p-15\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p-8\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p-7\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p-4\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p-3\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p-2\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.4p-2\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.8p-2\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.cp-2\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p-1\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.4p-1\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.8p-1\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.cp-1\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p\\+0\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.4p\\+0\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.8p\\+0\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.cp\\+0\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p\\+1\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.4p\\+1\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.8p\\+1\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p\\+2\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p\\+3\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p\\+4\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p\\+7\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p\\+8\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,0x1\\.0p\\+15\n" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,inf\n" 2 } } */
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,min\n" 1 } } */
+
+
+/* nan. */
+DECL_FUNC (h, 31, __builtin_nanf16 (""))
+
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,nan\n" 1 } } */
new file mode 100644
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imf_zfa_zfhmin -mabi=lp64f" { target { rv64 } } } */
+/* { dg-options "-march=rv32imf_zfa_zfhmin -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */
+
+/* "fli.h" is unavailable even if both 'Zfa' and 'Zfhmin' is enabled. */
+
+#define TYPE_h _Float16
+
+#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT
+
+#define DECL_FUNC(TYPE_SHORT, N, VALUE) \
+ DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void) \
+ { \
+ return VALUE; \
+ }
+
+#define DECL_FINITE_FUNCS(TYPE_SHORT) \
+ DECL_FUNC (TYPE_SHORT, 00, -1) \
+ DECL_FUNC (TYPE_SHORT, 02, 0.0000152587890625) \
+ DECL_FUNC (TYPE_SHORT, 03, 0.000030517578125) \
+ DECL_FUNC (TYPE_SHORT, 04, 0.00390625) \
+ DECL_FUNC (TYPE_SHORT, 05, 0.0078125) \
+ DECL_FUNC (TYPE_SHORT, 06, 0.0625) \
+ DECL_FUNC (TYPE_SHORT, 07, 0.125) \
+ DECL_FUNC (TYPE_SHORT, 08, 0.25) \
+ DECL_FUNC (TYPE_SHORT, 09, 0.3125) \
+ DECL_FUNC (TYPE_SHORT, 10, 0.375) \
+ DECL_FUNC (TYPE_SHORT, 11, 0.4375) \
+ DECL_FUNC (TYPE_SHORT, 12, 0.5) \
+ DECL_FUNC (TYPE_SHORT, 13, 0.625) \
+ DECL_FUNC (TYPE_SHORT, 14, 0.75) \
+ DECL_FUNC (TYPE_SHORT, 15, 0.875) \
+ DECL_FUNC (TYPE_SHORT, 16, 1) \
+ DECL_FUNC (TYPE_SHORT, 17, 1.25) \
+ DECL_FUNC (TYPE_SHORT, 18, 1.5) \
+ DECL_FUNC (TYPE_SHORT, 19, 1.75) \
+ DECL_FUNC (TYPE_SHORT, 20, 2) \
+ DECL_FUNC (TYPE_SHORT, 21, 2.5) \
+ DECL_FUNC (TYPE_SHORT, 22, 3) \
+ DECL_FUNC (TYPE_SHORT, 23, 4) \
+ DECL_FUNC (TYPE_SHORT, 24, 8) \
+ DECL_FUNC (TYPE_SHORT, 25, 16) \
+ DECL_FUNC (TYPE_SHORT, 26, 128) \
+ DECL_FUNC (TYPE_SHORT, 27, 256) \
+ DECL_FUNC (TYPE_SHORT, 28, 32768) \
+ DECL_FUNC (TYPE_SHORT, 29, 65536)
+
+/* Finite numbers (except 2^16 in _Float16, making an inf). */
+DECL_FINITE_FUNCS (h)
+
+/* min. */
+DECL_FUNC (h, 01, __FLT16_MIN__)
+
+/* inf. */
+DECL_FUNC (h, 30, __builtin_inff16 ())
+
+/* nan. */
+DECL_FUNC (h, 31, __builtin_nanf16 (""))
+
+/* { dg-final { scan-assembler-not "fli\\.h\t" } } */
new file mode 100644
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imfd_zfa_zfh -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32imfd_zfa_zfh -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */
+
+/* Canonical NaN is, positive, quiet NaN with zero payload. */
+
+#define TYPE_h _Float16
+#define TYPE_s float
+#define TYPE_d double
+
+#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT
+
+#define DECL_FUNC(TYPE_SHORT, N, VALUE) \
+ DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void) \
+ { \
+ return VALUE; \
+ }
+
+/* Canonical NaN. */
+DECL_FUNC (h, 1, __builtin_nanf16 (""))
+DECL_FUNC (s, 1, __builtin_nanf (""))
+DECL_FUNC (d, 1, __builtin_nan (""))
+DECL_FUNC (h, 2, __builtin_nanf16 ("0"))
+DECL_FUNC (s, 2, __builtin_nanf ("0"))
+DECL_FUNC (d, 2, __builtin_nan ("0"))
+
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,nan\n" 2 } } */
+/* { dg-final { scan-assembler-times "fli\\.s\tfa0,nan\n" 2 } } */
+/* { dg-final { scan-assembler-times "fli\\.d\tfa0,nan\n" 2 } } */
new file mode 100644
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imfd_zfa_zfh -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32imfd_zfa_zfh -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */
+
+/* Canonical NaN is, positive, quiet NaN with zero payload. */
+
+#define TYPE_h _Float16
+#define TYPE_s float
+#define TYPE_d double
+
+#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT
+
+#define DECL_FUNC(TYPE_SHORT, N, VALUE) \
+ DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void) \
+ { \
+ return VALUE; \
+ }
+
+/* Non-canonical NaN. */
+DECL_FUNC (h, 1, __builtin_nansf16 (""))
+DECL_FUNC (s, 1, __builtin_nansf (""))
+DECL_FUNC (d, 1, __builtin_nans (""))
+DECL_FUNC (h, 2, __builtin_nansf16 ("0"))
+DECL_FUNC (s, 2, __builtin_nansf ("0"))
+DECL_FUNC (d, 2, __builtin_nans ("0"))
+DECL_FUNC (h, 3, __builtin_nanf16 ("1"))
+DECL_FUNC (s, 3, __builtin_nanf ("1"))
+DECL_FUNC (d, 3, __builtin_nan ("1"))
+DECL_FUNC (h, 4, __builtin_nansf16 ("1"))
+DECL_FUNC (s, 4, __builtin_nansf ("1"))
+DECL_FUNC (d, 4, __builtin_nans ("1"))
+
+/* Canonical NaN, negated (making it non-canonical). */
+DECL_FUNC (h, 5, -__builtin_nanf16 (""))
+DECL_FUNC (s, 5, -__builtin_nanf (""))
+DECL_FUNC (d, 5, -__builtin_nan (""))
+
+/* { dg-final { scan-assembler-not "fli\\.\[hsd]\tfa0,nan\n" } } */