@@ -217,6 +217,8 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
{"zfh", ISA_SPEC_CLASS_NONE, 1, 0},
{"zfhmin", ISA_SPEC_CLASS_NONE, 1, 0},
+ {"zfa", ISA_SPEC_CLASS_NONE, 0, 2},
+
{"zmmul", ISA_SPEC_CLASS_NONE, 1, 0},
{"svinval", ISA_SPEC_CLASS_NONE, 1, 0},
@@ -1260,6 +1262,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},
@@ -118,6 +118,19 @@ (define_constraint "T"
(and (match_operand 0 "move_operand")
(match_test "CONSTANT_P (op)")))
+;; Zfa constraints.
+
+(define_constraint "zfli"
+ "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)")))
+
+(define_register_constraint "zmvf" "(TARGET_ZFA || TARGET_XTHEADFMV) ? FP_REGS : NO_REGS"
+ "A floating-point register for ZFA or XTheadFmv.")
+
+(define_register_constraint "zmvr" "(TARGET_ZFA || TARGET_XTHEADFMV) ? GR_REGS : NO_REGS"
+ "An integer register for ZFA or XTheadFmv.")
+
;; Vector constraints.
(define_register_constraint "vr" "TARGET_VECTOR ? V_REGS : NO_REGS"
@@ -180,11 +193,3 @@ (define_memory_constraint "Wdm"
"Vector duplicate memory operand"
(and (match_code "mem")
(match_code "reg" "0")))
-
-;; Vendor ISA extension constraints.
-
-(define_register_constraint "th_f_fmv" "TARGET_XTHEADFMV ? FP_REGS : NO_REGS"
- "A floating-point register for XTheadFmv.")
-
-(define_register_constraint "th_r_fmv" "TARGET_XTHEADFMV ? GR_REGS : NO_REGS"
- "An integer register for XTheadFmv.")
@@ -294,3 +294,8 @@ (define_int_iterator QUIET_COMPARISON [UNSPEC_FLT_QUIET UNSPEC_FLE_QUIET])
(define_int_attr quiet_pattern [(UNSPEC_FLT_QUIET "lt") (UNSPEC_FLE_QUIET "le")])
(define_int_attr QUIET_PATTERN [(UNSPEC_FLT_QUIET "LT") (UNSPEC_FLE_QUIET "LE")])
+(define_int_iterator ROUND [UNSPEC_ROUND UNSPEC_FLOOR UNSPEC_CEIL UNSPEC_BTRUNC UNSPEC_ROUNDEVEN UNSPEC_NEARBYINT])
+(define_int_attr round_pattern [(UNSPEC_ROUND "round") (UNSPEC_FLOOR "floor") (UNSPEC_CEIL "ceil")
+ (UNSPEC_BTRUNC "btrunc") (UNSPEC_ROUNDEVEN "roundeven") (UNSPEC_NEARBYINT "nearbyint")])
+(define_int_attr round_rm [(UNSPEC_ROUND "rmm") (UNSPEC_FLOOR "rdn") (UNSPEC_CEIL "rup")
+ (UNSPEC_BTRUNC "rtz") (UNSPEC_ROUNDEVEN "rne") (UNSPEC_NEARBYINT "dyn")])
@@ -196,6 +196,9 @@ enum riscv_multilib_select_kind {
#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)
@@ -40,6 +40,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);
@@ -813,6 +813,137 @@ 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/isa-449cd0c */
+
+static unsigned HOST_WIDE_INT fli_value_hf[32] =
+{
+ 0xbcp8, 0x4p8, 0x1p8, 0x2p8, 0x1cp8, 0x20p8, 0x2cp8, 0x30p8,
+ 0x34p8, 0x35p8, 0x36p8, 0x37p8, 0x38p8, 0x39p8, 0x3ap8, 0x3bp8,
+ 0x3cp8, 0x3dp8, 0x3ep8, 0x3fp8, 0x40p8, 0x41p8, 0x42p8, 0x44p8,
+ 0x48p8, 0x4cp8, 0x58p8, 0x5cp8, 0x78p8,
+ /* Only used for filling, ensuring that 29 and 30 of HF are the same. */
+ 0x78p8,
+ 0x7cp8, 0x7ep8
+};
+
+static unsigned HOST_WIDE_INT fli_value_sf[32] =
+{
+ 0xbf8p20, 0x008p20, 0x378p20, 0x380p20, 0x3b8p20, 0x3c0p20, 0x3d8p20, 0x3e0p20,
+ 0x3e8p20, 0x3eap20, 0x3ecp20, 0x3eep20, 0x3f0p20, 0x3f2p20, 0x3f4p20, 0x3f6p20,
+ 0x3f8p20, 0x3fap20, 0x3fcp20, 0x3fep20, 0x400p20, 0x402p20, 0x404p20, 0x408p20,
+ 0x410p20, 0x418p20, 0x430p20, 0x438p20, 0x470p20, 0x478p20, 0x7f8p20, 0x7fcp20
+};
+
+static unsigned HOST_WIDE_INT fli_value_df[32] =
+{
+ 0xbff0p48, 0x10p48, 0x3ef0p48, 0x3f00p48,
+ 0x3f70p48, 0x3f80p48, 0x3fb0p48, 0x3fc0p48,
+ 0x3fd0p48, 0x3fd4p48, 0x3fd8p48, 0x3fdcp48,
+ 0x3fe0p48, 0x3fe4p48, 0x3fe8p48, 0x3fecp48,
+ 0x3ff0p48, 0x3ff4p48, 0x3ff8p48, 0x3ffcp48,
+ 0x4000p48, 0x4004p48, 0x4008p48, 0x4010p48,
+ 0x4020p48, 0x4030p48, 0x4060p48, 0x4070p48,
+ 0x40e0p48, 0x40f0p48, 0x7ff0p48, 0x7ff8p48
+};
+
+/* Display floating-point values at the assembly level, which is consistent
+ with the zfa extension of llvm: */
+
+const char *fli_value_print[32] =
+{
+ "-1.0", "min", "1.52587890625e-05", "3.0517578125e-05", "0.00390625", "0.0078125", "0.0625", "0.125",
+ "0.25", "0.3125", "0.375", "0.4375", "0.5", "0.625", "0.75", "0.875",
+ "1.0", "1.25", "1.5", "1.75", "2.0", "2.5", "3.0", "4.0",
+ "8.0", "16.0", "128.0", "256.0", "32768.0", "65536.0", "inf", "nan"
+};
+
+/* 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. Return -1 if not found. */
+
+int
+riscv_float_const_rtx_index_for_fli (rtx x)
+{
+ unsigned HOST_WIDE_INT *fli_value_array;
+
+ machine_mode mode = GET_MODE (x);
+
+ if (!TARGET_ZFA
+ || !CONST_DOUBLE_P(x)
+ || mode == VOIDmode
+ || (mode == HFmode && !TARGET_ZFH)
+ || (mode == SFmode && !TARGET_HARD_FLOAT)
+ || (mode == DFmode && !TARGET_DOUBLE_FLOAT))
+ return -1;
+
+ if (!SCALAR_FLOAT_MODE_P (mode)
+ || GET_MODE_BITSIZE (mode).to_constant () > HOST_BITS_PER_WIDE_INT
+ /* Only support up to DF mode. */
+ || GET_MODE_BITSIZE (mode).to_constant () > GET_MODE_BITSIZE (DFmode))
+ return -1;
+
+ unsigned HOST_WIDE_INT ival = 0;
+
+ long res[2];
+ real_to_target (res,
+ CONST_DOUBLE_REAL_VALUE (x),
+ REAL_MODE_FORMAT (mode));
+
+ if (mode == DFmode)
+ {
+ int order = BYTES_BIG_ENDIAN ? 1 : 0;
+ ival = zext_hwi (res[order], 32);
+ ival |= (zext_hwi (res[1 - order], 32) << 32);
+
+ /* When the lower 32 bits are not all 0, it is impossible to be in the table. */
+ if (ival & 0xffffffff)
+ return -1;
+ }
+ else
+ ival = zext_hwi (res[0], 32);
+
+ switch (mode)
+ {
+ case E_HFmode:
+ fli_value_array = fli_value_hf;
+ break;
+ case E_SFmode:
+ fli_value_array = fli_value_sf;
+ break;
+ case E_DFmode:
+ fli_value_array = fli_value_df;
+ break;
+ default:
+ return -1;
+ }
+
+ if (fli_value_array[0] == ival)
+ return 0;
+
+ if (fli_value_array[1] == ival)
+ return 1;
+
+ /* Perform a binary search to find target index. */
+ unsigned l, r, m;
+
+ l = 2;
+ r = 31;
+
+ while (l <= r)
+ {
+ m = (l + r) / 2;
+ if (fli_value_array[m] == ival)
+ return m;
+ else if (fli_value_array[m] < ival)
+ l = m+1;
+ else
+ r = m-1;
+ }
+
+ return -1;
+}
+
/* Implement TARGET_LEGITIMATE_CONSTANT_P. */
static bool
@@ -840,6 +971,9 @@ riscv_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
if (GET_CODE (x) == HIGH)
return true;
+ if (satisfies_constraint_zfli (x))
+ return true;
+
split_const (x, &base, &offset);
if (riscv_symbolic_constant_p (base, &type))
{
@@ -1266,6 +1400,10 @@ riscv_const_insns (rtx x)
}
case CONST_DOUBLE:
+ /* See if we can use FMV directly. */
+ if (satisfies_constraint_zfli (x))
+ return 1;
+
/* We can use x0 to load floating-point zero. */
return x == CONST0_RTX (GET_MODE (x)) ? 1 : 0;
case CONST_VECTOR:
@@ -1824,6 +1962,12 @@ riscv_legitimize_const_move (machine_mode mode, rtx dest, rtx src)
return;
}
+ if (satisfies_constraint_zfli (src))
+ {
+ 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))
{
@@ -2847,6 +2991,10 @@ riscv_split_64bit_move_p (rtx dest, rtx src)
if (TARGET_64BIT)
return false;
+ /* There is no need to split if the FLI instruction in the `Zfa` extension can be used. */
+ if (satisfies_constraint_zfli (src))
+ return false;
+
/* Allow FPR <-> FPR and FPR <-> MEM moves, and permit the special case
of zeroing an FPR with FCVT.D.W. */
if (TARGET_DOUBLE_FLOAT
@@ -2866,22 +3014,36 @@ riscv_split_64bit_move_p (rtx dest, rtx src)
void
riscv_split_doubleword_move (rtx dest, rtx src)
{
- /* XTheadFmv has instructions for accessing the upper bits of a double. */
- if (!TARGET_64BIT && TARGET_XTHEADFMV)
+ /* ZFA or XTheadFmv has instructions for accessing the upper bits of a double. */
+ if (!TARGET_64BIT && (TARGET_ZFA || TARGET_XTHEADFMV))
{
if (FP_REG_RTX_P (dest))
{
rtx low_src = riscv_subword (src, false);
rtx high_src = riscv_subword (src, true);
- emit_insn (gen_th_fmv_hw_w_x (dest, high_src, low_src));
+
+ if (TARGET_ZFA)
+ emit_insn (gen_movdfsisi3_rv32 (dest, high_src, low_src));
+ else
+ emit_insn (gen_th_fmv_hw_w_x (dest, high_src, low_src));
return;
}
if (FP_REG_RTX_P (src))
{
rtx low_dest = riscv_subword (dest, false);
rtx high_dest = riscv_subword (dest, true);
- emit_insn (gen_th_fmv_x_w (low_dest, src));
- emit_insn (gen_th_fmv_x_hw (high_dest, src));
+
+ if (TARGET_ZFA)
+ {
+ emit_insn (gen_movsidf2_low_rv32 (low_dest, src));
+ emit_insn (gen_movsidf2_high_rv32 (high_dest, src));
+ return;
+ }
+ else
+ {
+ emit_insn (gen_th_fmv_x_w (low_dest, src));
+ emit_insn (gen_th_fmv_x_hw (high_dest, src));
+ }
return;
}
}
@@ -3045,6 +3207,17 @@ riscv_output_move (rtx dest, rtx src)
case 8:
return "fld\t%0,%1";
}
+
+ if (src_code == CONST_DOUBLE && satisfies_constraint_zfli (src))
+ 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)
{
@@ -4671,6 +4844,24 @@ riscv_print_operand (FILE *file, rtx op, int letter)
output_address (mode, XEXP (op, 0));
break;
+ case CONST_DOUBLE:
+ {
+ if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
+ {
+ fputs (reg_names[GP_REG_FIRST], file);
+ break;
+ }
+
+ int fli_index = riscv_float_const_rtx_index_for_fli (op);
+ if (fli_index == -1 || fli_index > 31)
+ {
+ output_operand_lossage ("invalid use of '%%%c'", letter);
+ break;
+ }
+ asm_fprintf (file, "%s", fli_value_print[fli_index]);
+ break;
+ }
+
default:
if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
fputs (reg_names[GP_REG_FIRST], file);
@@ -6033,7 +6224,8 @@ riscv_secondary_memory_needed (machine_mode mode, reg_class_t class1,
return (!riscv_v_ext_mode_p (mode)
&& GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD
&& (class1 == FP_REGS) != (class2 == FP_REGS)
- && !TARGET_XTHEADFMV);
+ && !TARGET_XTHEADFMV
+ && !TARGET_ZFA);
}
/* Implement TARGET_REGISTER_MOVE_COST. */
@@ -55,10 +55,19 @@ (define_c_enum "unspec" [
UNSPEC_FLT_QUIET
UNSPEC_FLE_QUIET
UNSPEC_COPYSIGN
+ UNSPEC_RINT
+ UNSPEC_ROUND
+ UNSPEC_FLOOR
+ UNSPEC_CEIL
+ UNSPEC_BTRUNC
+ UNSPEC_ROUNDEVEN
+ UNSPEC_NEARBYINT
UNSPEC_LRINT
UNSPEC_LROUND
UNSPEC_FMIN
UNSPEC_FMAX
+ UNSPEC_FMINM
+ UNSPEC_FMAXM
;; Stack tie
UNSPEC_TIE
@@ -1290,6 +1299,26 @@ (define_insn "neg<mode>2"
;;
;; ....................
+(define_insn "fminm<mode>3"
+ [(set (match_operand:ANYF 0 "register_operand" "=f")
+ (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f"))
+ (use (match_operand:ANYF 2 "register_operand" " f"))]
+ UNSPEC_FMINM))]
+ "TARGET_HARD_FLOAT && TARGET_ZFA"
+ "fminm.<fmt>\t%0,%1,%2"
+ [(set_attr "type" "fmove")
+ (set_attr "mode" "<UNITMODE>")])
+
+(define_insn "fmaxm<mode>3"
+ [(set (match_operand:ANYF 0 "register_operand" "=f")
+ (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f"))
+ (use (match_operand:ANYF 2 "register_operand" " f"))]
+ UNSPEC_FMAXM))]
+ "TARGET_HARD_FLOAT && TARGET_ZFA"
+ "fmaxm.<fmt>\t%0,%1,%2"
+ [(set_attr "type" "fmove")
+ (set_attr "mode" "<UNITMODE>")])
+
(define_insn "fmin<mode>3"
[(set (match_operand:ANYF 0 "register_operand" "=f")
(unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f"))
@@ -1566,13 +1595,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,zfli,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"
@@ -1638,6 +1667,26 @@ (define_insn "l<rint_pattern><ANYF:mode><GPR:mode>2"
[(set_attr "type" "fcvt")
(set_attr "mode" "<ANYF:MODE>")])
+(define_insn "<round_pattern><ANYF:mode>2"
+ [(set (match_operand:ANYF 0 "register_operand" "=f")
+ (unspec:ANYF
+ [(match_operand:ANYF 1 "register_operand" " f")]
+ ROUND))]
+ "TARGET_HARD_FLOAT && TARGET_ZFA"
+ "fround.<ANYF:fmt>\t%0,%1,<round_rm>"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "<ANYF:MODE>")])
+
+(define_insn "rint<ANYF:mode>2"
+ [(set (match_operand:ANYF 0 "register_operand" "=f")
+ (unspec:ANYF
+ [(match_operand:ANYF 1 "register_operand" " f")]
+ UNSPEC_RINT))]
+ "TARGET_HARD_FLOAT && TARGET_ZFA"
+ "froundnx.<ANYF:fmt>\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "<ANYF:MODE>")])
+
;;
;; ....................
;;
@@ -1897,13 +1946,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,zfli,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"
@@ -1931,23 +1980,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,*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,*zmvf,*zmvr, *r,*r,*m")
+ (match_operand:DF 1 "move_operand" " f,zfli,G,m,f,G,*zmvr,*zmvf,*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_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,zfli,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"
@@ -1960,6 +2009,39 @@ (define_insn "*movdf_softfloat"
[(set_attr "move_type" "move,load,store")
(set_attr "mode" "DF")])
+(define_insn "movsidf2_low_rv32"
+ [(set (match_operand:SI 0 "register_operand" "= r")
+ (truncate:SI
+ (match_operand:DF 1 "register_operand" "zmvf")))]
+ "TARGET_HARD_FLOAT && !TARGET_64BIT && TARGET_ZFA"
+ "fmv.x.w\t%0,%1"
+ [(set_attr "move_type" "fmove")
+ (set_attr "mode" "DF")])
+
+
+(define_insn "movsidf2_high_rv32"
+ [(set (match_operand:SI 0 "register_operand" "= r")
+ (truncate:SI
+ (lshiftrt:DF
+ (match_operand:DF 1 "register_operand" "zmvf")
+ (const_int 32))))]
+ "TARGET_HARD_FLOAT && !TARGET_64BIT && TARGET_ZFA"
+ "fmvh.x.d\t%0,%1"
+ [(set_attr "move_type" "fmove")
+ (set_attr "mode" "DF")])
+
+(define_insn "movdfsisi3_rv32"
+ [(set (match_operand:DF 0 "register_operand" "= f")
+ (plus:DF
+ (match_operand:SI 2 "register_operand" "zmvr")
+ (ashift:SI
+ (match_operand:SI 1 "register_operand" "zmvr")
+ (const_int 32))))]
+ "TARGET_HARD_FLOAT && !TARGET_64BIT && TARGET_ZFA"
+ "fmvp.d.x\t%0,%2,%1"
+ [(set_attr "move_type" "fmove")
+ (set_attr "mode" "DF")])
+
(define_split
[(set (match_operand:MOVE64 0 "nonimmediate_operand")
(match_operand:MOVE64 1 "move_operand"))]
@@ -2552,16 +2634,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),
@@ -2569,6 +2658,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")
new file mode 100644
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32imafdc_zfa -mabi=ilp32d -O2" } */
+
+extern void abort(void);
+extern float a, b;
+extern double c, d;
+
+void
+foo()
+{
+ if ((__builtin_isless(a, b) || __builtin_islessequal(c, d))
+ && (__builtin_islessequal(a, b)|| __builtin_isless(c, d)))
+ abort();
+}
+
+/* { dg-final { scan-assembler-times "fleq.s" 1 } } */
+/* { dg-final { scan-assembler-times "fltq.s" 1 } } */
+/* { dg-final { scan-assembler-times "fleq.d" 1 } } */
+/* { dg-final { scan-assembler-times "fltq.d" 1 } } */
new file mode 100644
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imafdc_zfa -mabi=lp64d -O2" } */
+
+extern void abort(void);
+extern float a, b;
+extern double c, d;
+
+void
+foo()
+{
+ if ((__builtin_isless(a, b) || __builtin_islessequal(c, d))
+ && (__builtin_islessequal(a, b)|| __builtin_isless(c, d)))
+ abort();
+}
+
+/* { dg-final { scan-assembler-times "fleq.s" 1 } } */
+/* { dg-final { scan-assembler-times "fltq.s" 1 } } */
+/* { dg-final { scan-assembler-times "fleq.d" 1 } } */
+/* { dg-final { scan-assembler-times "fltq.d" 1 } } */
new file mode 100644
@@ -0,0 +1,79 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32imafdc_zfa -mabi=ilp32d -O0" } */
+
+void foo_float32 ()
+{
+ volatile float a;
+ a = -1.0;
+ a = 1.1754944e-38;
+ a = 1.0/(1 << 16);
+ a = 1.0/(1 << 15);
+ a = 1.0/(1 << 8);
+ a = 1.0/(1 << 7);
+ a = 1.0/(1 << 4);
+ a = 1.0/(1 << 3);
+ a = 1.0/(1 << 2);
+ a = 0.3125;
+ a = 0.375;
+ a = 0.4375;
+ a = 0.5;
+ a = 0.625;
+ a = 0.75;
+ a = 0.875;
+ a = 1.0;
+ a = 1.25;
+ a = 1.5;
+ a = 1.75;
+ a = 2.0;
+ a = 2.5;
+ a = 3.0;
+ a = 1.0*(1 << 2);
+ a = 1.0*(1 << 3);
+ a = 1.0*(1 << 4);
+ a = 1.0*(1 << 7);
+ a = 1.0*(1 << 8);
+ a = 1.0*(1 << 15);
+ a = 1.0*(1 << 16);
+ a = __builtin_inff ();
+ a = __builtin_nanf ("");
+}
+
+void foo_double64 ()
+{
+ volatile double a;
+ a = -1.0;
+ a = 2.2250738585072014E-308;
+ a = 1.0/(1 << 16);
+ a = 1.0/(1 << 15);
+ a = 1.0/(1 << 8);
+ a = 1.0/(1 << 7);
+ a = 1.0/(1 << 4);
+ a = 1.0/(1 << 3);
+ a = 1.0/(1 << 2);
+ a = 0.3125;
+ a = 0.375;
+ a = 0.4375;
+ a = 0.5;
+ a = 0.625;
+ a = 0.75;
+ a = 0.875;
+ a = 1.0;
+ a = 1.25;
+ a = 1.5;
+ a = 1.75;
+ a = 2.0;
+ a = 2.5;
+ a = 3.0;
+ a = 1.0*(1 << 2);
+ a = 1.0*(1 << 3);
+ a = 1.0*(1 << 4);
+ a = 1.0*(1 << 7);
+ a = 1.0*(1 << 8);
+ a = 1.0*(1 << 15);
+ a = 1.0*(1 << 16);
+ a = __builtin_inf ();
+ a = __builtin_nan ("");
+}
+
+/* { dg-final { scan-assembler-times "fli.s" 32 } } */
+/* { dg-final { scan-assembler-times "fli.d" 32 } } */
new file mode 100644
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32imafdc_zfa_zfh -mabi=ilp32d -O0" } */
+
+void foo_float16 ()
+{
+ volatile _Float16 a;
+ a = -1.0;
+ a = 6.104E-5;
+ a = 1.0/(1 << 16);
+ a = 1.0/(1 << 15);
+ a = 1.0/(1 << 8);
+ a = 1.0/(1 << 7);
+ a = 1.0/(1 << 4);
+ a = 1.0/(1 << 3);
+ a = 1.0/(1 << 2);
+ a = 0.3125;
+ a = 0.375;
+ a = 0.4375;
+ a = 0.5;
+ a = 0.625;
+ a = 0.75;
+ a = 0.875;
+ a = 1.0;
+ a = 1.25;
+ a = 1.5;
+ a = 1.75;
+ a = 2.0;
+ a = 2.5;
+ a = 3.0;
+ a = 1.0*(1 << 2);
+ a = 1.0*(1 << 3);
+ a = 1.0*(1 << 4);
+ a = 1.0*(1 << 7);
+ a = 1.0*(1 << 8);
+ a = 1.0*(1 << 15);
+ a = 1.0*(1 << 16);
+ a = __builtin_inff16 ();
+ a = __builtin_nanf16 ("");
+}
+
+/* { dg-final { scan-assembler-times "fli.h" 32 } } */
new file mode 100644
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imafdc_zfa_zfh -mabi=lp64d -O0" } */
+
+void foo_float16 ()
+{
+ volatile _Float16 a;
+ a = -1.0;
+ a = 6.104e-5;
+ a = 1.0/(1 << 16);
+ a = 1.0/(1 << 15);
+ a = 1.0/(1 << 8);
+ a = 1.0/(1 << 7);
+ a = 1.0/(1 << 4);
+ a = 1.0/(1 << 3);
+ a = 1.0/(1 << 2);
+ a = 0.3125;
+ a = 0.375;
+ a = 0.4375;
+ a = 0.5;
+ a = 0.625;
+ a = 0.75;
+ a = 0.875;
+ a = 1.0;
+ a = 1.25;
+ a = 1.5;
+ a = 1.75;
+ a = 2.0;
+ a = 2.5;
+ a = 3.0;
+ a = 1.0*(1 << 2);
+ a = 1.0*(1 << 3);
+ a = 1.0*(1 << 4);
+ a = 1.0*(1 << 7);
+ a = 1.0*(1 << 8);
+ a = 1.0*(1 << 15);
+ a = 1.0*(1 << 16);
+ a = __builtin_inff16 ();
+ a = __builtin_nanf16 ("");
+}
+
+/* { dg-final { scan-assembler-times "fli.h" 32 } } */
new file mode 100644
@@ -0,0 +1,79 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imafdc_zfa -mabi=lp64d -O0" } */
+
+void foo_float32 ()
+{
+ volatile float a;
+ a = -1.0;
+ a = 1.1754944e-38;
+ a = 1.0/(1 << 16);
+ a = 1.0/(1 << 15);
+ a = 1.0/(1 << 8);
+ a = 1.0/(1 << 7);
+ a = 1.0/(1 << 4);
+ a = 1.0/(1 << 3);
+ a = 1.0/(1 << 2);
+ a = 0.3125;
+ a = 0.375;
+ a = 0.4375;
+ a = 0.5;
+ a = 0.625;
+ a = 0.75;
+ a = 0.875;
+ a = 1.0;
+ a = 1.25;
+ a = 1.5;
+ a = 1.75;
+ a = 2.0;
+ a = 2.5;
+ a = 3.0;
+ a = 1.0*(1 << 2);
+ a = 1.0*(1 << 3);
+ a = 1.0*(1 << 4);
+ a = 1.0*(1 << 7);
+ a = 1.0*(1 << 8);
+ a = 1.0*(1 << 15);
+ a = 1.0*(1 << 16);
+ a = __builtin_inff ();
+ a = __builtin_nanf ("");
+}
+
+void foo_double64 ()
+{
+ volatile double a;
+ a = -1.0;
+ a = 2.2250738585072014e-308;
+ a = 1.0/(1 << 16);
+ a = 1.0/(1 << 15);
+ a = 1.0/(1 << 8);
+ a = 1.0/(1 << 7);
+ a = 1.0/(1 << 4);
+ a = 1.0/(1 << 3);
+ a = 1.0/(1 << 2);
+ a = 0.3125;
+ a = 0.375;
+ a = 0.4375;
+ a = 0.5;
+ a = 0.625;
+ a = 0.75;
+ a = 0.875;
+ a = 1.0;
+ a = 1.25;
+ a = 1.5;
+ a = 1.75;
+ a = 2.0;
+ a = 2.5;
+ a = 3.0;
+ a = 1.0*(1 << 2);
+ a = 1.0*(1 << 3);
+ a = 1.0*(1 << 4);
+ a = 1.0*(1 << 7);
+ a = 1.0*(1 << 8);
+ a = 1.0*(1 << 15);
+ a = 1.0*(1 << 16);
+ a = __builtin_inf ();
+ a = __builtin_nan ("");
+}
+
+/* { dg-final { scan-assembler-times "fli.s" 32 } } */
+/* { dg-final { scan-assembler-times "fli.d" 32 } } */
new file mode 100644
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32g_zfa -mabi=ilp32 -O0" } */
+
+double foo(long long a)
+{
+ return (double)(a + 3);
+}
+
+/* { dg-final { scan-assembler-times "fmvp.d.x" 1 } } */
+/* { dg-final { scan-assembler-times "fmvh.x.d" 1 } } */
new file mode 100644
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32imafdc_zfa -mabi=ilp32d -O2" } */
+
+extern float a;
+extern double b;
+
+void foo (float *x, double *y)
+{
+ {
+ *x = __builtin_roundf (a);
+ *y = __builtin_round (b);
+ }
+ {
+ *x = __builtin_floorf (a);
+ *y = __builtin_floor (b);
+ }
+ {
+ *x = __builtin_ceilf (a);
+ *y = __builtin_ceil (b);
+ }
+ {
+ *x = __builtin_truncf (a);
+ *y = __builtin_trunc (b);
+ }
+ {
+ *x = __builtin_roundevenf (a);
+ *y = __builtin_roundeven (b);
+ }
+ {
+ *x = __builtin_nearbyintf (a);
+ *y = __builtin_nearbyint (b);
+ }
+ {
+ *x = __builtin_rintf (a);
+ *y = __builtin_rint (b);
+ }
+}
+
+/* { dg-final { scan-assembler-times "fround.s" 6 } } */
+/* { dg-final { scan-assembler-times "fround.d" 6 } } */
+/* { dg-final { scan-assembler-times "froundnx.s" 1 } } */
+/* { dg-final { scan-assembler-times "froundnx.d" 1 } } */
new file mode 100644
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imafdc_zfa -mabi=lp64d -O2" } */
+
+extern float a;
+extern double b;
+
+void foo (float *x, double *y)
+{
+ {
+ *x = __builtin_roundf (a);
+ *y = __builtin_round (b);
+ }
+ {
+ *x = __builtin_floorf (a);
+ *y = __builtin_floor (b);
+ }
+ {
+ *x = __builtin_ceilf (a);
+ *y = __builtin_ceil (b);
+ }
+ {
+ *x = __builtin_truncf (a);
+ *y = __builtin_trunc (b);
+ }
+ {
+ *x = __builtin_roundevenf (a);
+ *y = __builtin_roundeven (b);
+ }
+ {
+ *x = __builtin_nearbyintf (a);
+ *y = __builtin_nearbyint (b);
+ }
+ {
+ *x = __builtin_rintf (a);
+ *y = __builtin_rint (b);
+ }
+}
+
+/* { dg-final { scan-assembler-times "fround.s" 6 } } */
+/* { dg-final { scan-assembler-times "fround.d" 6 } } */
+/* { dg-final { scan-assembler-times "froundnx.s" 1 } } */
+/* { dg-final { scan-assembler-times "froundnx.d" 1 } } */