UNSPEC_ROUNDEVEN
UNSPEC_NEARBYINT
UNSPEC_LRINT
- UNSPEC_LROUND
UNSPEC_FMIN
UNSPEC_FMAX
UNSPEC_FMINM
;;
;; ....................
-(define_insn "fix_trunc<ANYF:mode><GPR:mode>2"
- [(set (match_operand:GPR 0 "register_operand" "=r")
- (fix:GPR
+(define_expand "<fix_uns>_trunc<ANYF:mode>si2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (fix_ops:SI
(match_operand:ANYF 1 "register_operand" " f")))]
"TARGET_HARD_FLOAT || TARGET_ZFINX"
- "fcvt.<GPR:ifmt>.<ANYF:fmt> %0,%1,rtz"
+{
+ if (TARGET_64BIT)
+ {
+ rtx t = gen_reg_rtx (DImode);
+ emit_insn (gen_<fix_uns>_trunc<ANYF:mode>si2_sext (t, operands[1]));
+ t = gen_lowpart (SImode, t);
+ SUBREG_PROMOTED_VAR_P (t) = 1;
+ SUBREG_PROMOTED_SET (t, SRP_SIGNED);
+ emit_move_insn (operands[0], t);
+ DONE;
+ }
+})
+
+(define_insn "*<fix_uns>_trunc<ANYF:mode>si2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (fix_ops:SI
+ (match_operand:ANYF 1 "register_operand" " f")))]
+ "TARGET_HARD_FLOAT || TARGET_ZFINX"
+ "fcvt.w<u>.<ANYF:fmt> %0,%1,rtz"
+ [(set_attr "type" "fcvt_f2i")
+ (set_attr "mode" "<ANYF:MODE>")])
+
+(define_insn "<fix_uns>_trunc<ANYF:mode>si2_sext"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (fix_ops:SI
+ (match_operand:ANYF 1 "register_operand" " f"))))]
+ "TARGET_64BIT && (TARGET_HARD_FLOAT || TARGET_ZFINX)"
+ "fcvt.w<u>.<ANYF:fmt> %0,%1,rtz"
[(set_attr "type" "fcvt_f2i")
(set_attr "mode" "<ANYF:MODE>")])
-(define_insn "fixuns_trunc<ANYF:mode><GPR:mode>2"
- [(set (match_operand:GPR 0 "register_operand" "=r")
- (unsigned_fix:GPR
+(define_insn "<fix_uns>_trunc<ANYF:mode>di2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (fix_ops:DI
(match_operand:ANYF 1 "register_operand" " f")))]
- "TARGET_HARD_FLOAT || TARGET_ZFINX"
- "fcvt.<GPR:ifmt>u.<ANYF:fmt> %0,%1,rtz"
+ "TARGET_64BIT && (TARGET_HARD_FLOAT || TARGET_ZFINX)"
+ "fcvt.l<u>.<ANYF:fmt> %0,%1,rtz"
[(set_attr "type" "fcvt_f2i")
(set_attr "mode" "<ANYF:MODE>")])
[(set_attr "type" "fcvt_i2f")
(set_attr "mode" "<ANYF:MODE>")])
-(define_insn "l<rint_pattern><ANYF:mode><GPR:mode>2"
- [(set (match_operand:GPR 0 "register_operand" "=r")
- (unspec:GPR
+(define_expand "lrint<ANYF:mode>si2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI
[(match_operand:ANYF 1 "register_operand" " f")]
- RINT))]
+ UNSPEC_LRINT))]
"TARGET_HARD_FLOAT || TARGET_ZFINX"
- "fcvt.<GPR:ifmt>.<ANYF:fmt> %0,%1,<rint_rm>"
+{
+ if (TARGET_64BIT)
+ {
+ rtx t = gen_reg_rtx (DImode);
+ emit_insn (gen_lrint<ANYF:mode>si2_sext (t, operands[1]));
+ t = gen_lowpart (SImode, t);
+ SUBREG_PROMOTED_VAR_P (t) = 1;
+ SUBREG_PROMOTED_SET (t, SRP_SIGNED);
+ emit_move_insn (operands[0], t);
+ DONE;
+ }
+})
+
+(define_insn "*lrint<ANYF:mode>si2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI
+ [(match_operand:ANYF 1 "register_operand" " f")]
+ UNSPEC_LRINT))]
+ "TARGET_HARD_FLOAT || TARGET_ZFINX"
+ "fcvt.w.<ANYF:fmt> %0,%1,dyn"
[(set_attr "type" "fcvt_f2i")
(set_attr "mode" "<ANYF:MODE>")])
-(define_insn "<round_pattern><ANYF:mode>2"
+(define_insn "lrint<ANYF:mode>si2_sext"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (unspec:SI
+ [(match_operand:ANYF 1 "register_operand" " f")]
+ UNSPEC_LRINT)))]
+ "TARGET_64BIT && (TARGET_HARD_FLOAT || TARGET_ZFINX)"
+ "fcvt.w.<ANYF:fmt> %0,%1,dyn"
+ [(set_attr "type" "fcvt_f2i")
+ (set_attr "mode" "<ANYF:MODE>")])
+
+(define_insn "lrint<ANYF:mode>di2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI
+ [(match_operand:ANYF 1 "register_operand" " f")]
+ UNSPEC_LRINT))]
+ "TARGET_64BIT && (TARGET_HARD_FLOAT || TARGET_ZFINX)"
+ "fcvt.l.<ANYF:fmt> %0,%1,dyn"
+ [(set_attr "type" "fcvt_f2i")
+ (set_attr "mode" "<ANYF:MODE>")])
+
+(define_expand "l<round_pattern><ANYF:mode>si2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI
+ [(match_operand:ANYF 1 "register_operand" " f")]
+ ROUND))]
+ "TARGET_HARD_FLOAT || TARGET_ZFINX"
+{
+ if (TARGET_64BIT)
+ {
+ rtx t = gen_reg_rtx (DImode);
+ emit_insn (gen_l<round_pattern><ANYF:mode>si2_sext (t, operands[1]));
+ t = gen_lowpart (SImode, t);
+ SUBREG_PROMOTED_VAR_P (t) = 1;
+ SUBREG_PROMOTED_SET (t, SRP_SIGNED);
+ emit_move_insn (operands[0], t);
+ DONE;
+ }
+})
+
+(define_insn "*l<round_pattern><ANYF:mode>si2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI
+ [(match_operand:ANYF 1 "register_operand" " f")]
+ ROUND))]
+ "TARGET_HARD_FLOAT || TARGET_ZFINX"
+ "fcvt.w.<ANYF:fmt> %0,%1,<round_rm>"
+ [(set_attr "type" "fcvt_f2i")
+ (set_attr "mode" "<ANYF:MODE>")])
+
+(define_insn "l<round_pattern><ANYF:mode>si2_sext"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (unspec:SI
+ [(match_operand:ANYF 1 "register_operand" " f")]
+ ROUND)))]
+ "TARGET_64BIT && (TARGET_HARD_FLOAT || TARGET_ZFINX)"
+ "fcvt.w.<ANYF:fmt> %0,%1,<round_rm>"
+ [(set_attr "type" "fcvt_f2i")
+ (set_attr "mode" "<ANYF:MODE>")])
+
+(define_insn "l<round_pattern><ANYF:mode>di2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI
+ [(match_operand:ANYF 1 "register_operand" " f")]
+ ROUND))]
+ "TARGET_64BIT && (TARGET_HARD_FLOAT || TARGET_ZFINX)"
+ "fcvt.l.<ANYF:fmt> %0,%1,<round_rm>"
+ [(set_attr "type" "fcvt_f2i")
+ (set_attr "mode" "<ANYF:MODE>")])
+
+(define_expand "<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
+ || flag_fp_int_builtin_inexact || !flag_trapping_math)"
+{
+ if (TARGET_ZFA)
+ emit_insn (gen_<round_pattern><ANYF:mode>_zfa2 (operands[0],
+ operands[1]));
+ else
+ {
+ rtx reg;
+ rtx label = gen_label_rtx ();
+ rtx end_label = gen_label_rtx ();
+ rtx abs_reg = gen_reg_rtx (<ANYF:MODE>mode);
+ rtx coeff_reg = gen_reg_rtx (<ANYF:MODE>mode);
+ rtx tmp_reg = gen_reg_rtx (<ANYF:MODE>mode);
+
+ riscv_emit_move (tmp_reg, operands[1]);
+ riscv_emit_move (coeff_reg,
+ riscv_vector::get_fp_rounding_coefficient (<ANYF:MODE>mode));
+ emit_insn (gen_abs<ANYF:mode>2 (abs_reg, operands[1]));
+
+ riscv_expand_conditional_branch (label, LT, abs_reg, coeff_reg);
+
+ emit_jump_insn (gen_jump (end_label));
+ emit_barrier ();
+
+ emit_label (label);
+ switch (<ANYF:MODE>mode)
+ {
+ case SFmode:
+ reg = gen_reg_rtx (SImode);
+ emit_insn (gen_l<round_pattern>sfsi2 (reg, operands[1]));
+ emit_insn (gen_floatsisf2 (abs_reg, reg));
+ break;
+ case DFmode:
+ if (TARGET_64BIT)
+ {
+ reg = gen_reg_rtx (DImode);
+ emit_insn (gen_l<round_pattern>dfdi2 (reg, operands[1]));
+ emit_insn (gen_floatdidf2 (abs_reg, reg));
+ }
+ else
+ {
+ reg = gen_reg_rtx (SImode);
+ emit_insn (gen_l<round_pattern>dfsi2 (reg, operands[1]));
+ emit_insn (gen_floatsidf2 (abs_reg, reg));
+ }
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ emit_insn (gen_copysign<ANYF:mode>3 (tmp_reg, abs_reg, operands[1]));
+
+ emit_label (end_label);
+ riscv_emit_move (operands[0], tmp_reg);
+ }
+
+ DONE;
+})
+
+(define_insn "<round_pattern><ANYF:mode>_zfa2"
[(set (match_operand:ANYF 0 "register_operand" "=f")
(unspec:ANYF
[(match_operand:ANYF 1 "register_operand" " f")]
--- /dev/null
+#include <math.h>
+
+extern void abort (void);
+extern void exit (int);
+
+#define NEQ(a, b) (fabs((a) - (b)) > 0.000001)
+
+#define DECL_FUNC(TYPE1, TYPE2, ROUND) \
+ __attribute__ ((noinline, noclone)) TYPE2 \
+ convert_##TYPE1##_to_##TYPE2##_##ROUND (TYPE1 N) \
+ { \
+ return ROUND (N); \
+ }
+
+#define DECL_ALL_ROUNDS_FOR(ROUND_FUNC) \
+ DECL_FUNC(float, float, ROUND_FUNC) \
+ DECL_FUNC(double, double, ROUND_FUNC) \
+ DECL_FUNC(double, int, ROUND_FUNC) \
+ DECL_FUNC(double, long, ROUND_FUNC) \
+ DECL_FUNC(float, int, ROUND_FUNC) \
+ DECL_FUNC(float, long, ROUND_FUNC)
+
+
+DECL_ALL_ROUNDS_FOR(round)
+DECL_ALL_ROUNDS_FOR(ceil)
+DECL_ALL_ROUNDS_FOR(floor)
+DECL_ALL_ROUNDS_FOR(trunc)
+DECL_ALL_ROUNDS_FOR(nearbyint)
+
+#define TEST_ROUND(TYPE1, TYPE2, N, N_R, ROUND) \
+ if (NEQ (convert_##TYPE1##_to_##TYPE2##_##ROUND (N), N_R)) \
+ abort ();
+
+
+int main () {
+
+ /* Round */
+ TEST_ROUND(double, double, -4.8, -5.0, round);
+ TEST_ROUND(double, double, -4.2, -4.0, round);
+ TEST_ROUND(double, double, 4.8, 5.0, round);
+ TEST_ROUND(double, double, 4.2, 4.0, round);
+
+ TEST_ROUND(double, int, -4.8, -5, round);
+ TEST_ROUND(double, int, -4.2, -4, round);
+ TEST_ROUND(double, int, 4.8, 5, round);
+ TEST_ROUND(double, int, 4.2, 4, round);
+
+ TEST_ROUND(double, long, -4.8, -5, round);
+ TEST_ROUND(double, long, -4.2, -4, round);
+ TEST_ROUND(double, long, 4.8, 5, round);
+ TEST_ROUND(double, long, 4.2, 4, round);
+
+ TEST_ROUND(float, long, -4.8, -5, round);
+ TEST_ROUND(float, long, -4.2, -4, round);
+ TEST_ROUND(float, long, 4.8, 5, round);
+ TEST_ROUND(float, long, 4.2, 4, round);
+
+ /* Ceil */
+ TEST_ROUND(double, double, -4.8, -4.0, ceil);
+ TEST_ROUND(double, double, -4.2, -4.0, ceil);
+ TEST_ROUND(double, double, 4.8, 5.0, ceil);
+ TEST_ROUND(double, double, 4.2, 5.0, ceil);
+
+ TEST_ROUND(double, int, -4.8, -4, ceil);
+ TEST_ROUND(double, int, -4.2, -4, ceil);
+ TEST_ROUND(double, int, 4.8, 5, ceil);
+ TEST_ROUND(double, int, 4.2, 5, ceil);
+
+ TEST_ROUND(double, long, -4.8, -4, ceil);
+ TEST_ROUND(double, long, -4.2, -4, ceil);
+ TEST_ROUND(double, long, 4.8, 5, ceil);
+ TEST_ROUND(double, long, 4.2, 5, ceil);
+
+ TEST_ROUND(float, long, -4.8, -4, ceil);
+ TEST_ROUND(float, long, -4.2, -4, ceil);
+ TEST_ROUND(float, long, 4.8, 5, ceil);
+ TEST_ROUND(float, long, 4.2, 5, ceil);
+
+ /* Floor */
+ TEST_ROUND(double, double, -4.8, -5.0, floor);
+ TEST_ROUND(double, double, -4.2, -5.0, floor);
+ TEST_ROUND(double, double, 4.8, 4.0, floor);
+ TEST_ROUND(double, double, 4.2, 4.0, floor);
+
+ TEST_ROUND(double, int, -4.8, -5, floor);
+ TEST_ROUND(double, int, -4.2, -5, floor);
+ TEST_ROUND(double, int, 4.8, 4, floor);
+ TEST_ROUND(double, int, 4.2, 4, floor);
+
+ TEST_ROUND(double, long, -4.8, -5, floor);
+ TEST_ROUND(double, long, -4.2, -5, floor);
+ TEST_ROUND(double, long, 4.8, 4, floor);
+ TEST_ROUND(double, long, 4.2, 4, floor);
+
+ TEST_ROUND(float, long, -4.8, -5, floor);
+ TEST_ROUND(float, long, -4.2, -5, floor);
+ TEST_ROUND(float, long, 4.8, 4, floor);
+ TEST_ROUND(float, long, 4.2, 4, floor);
+
+ /* Trunc */
+ TEST_ROUND(double, double, -4.8, -4.0, trunc);
+ TEST_ROUND(double, double, -4.2, -4.0, trunc);
+ TEST_ROUND(double, double, 4.8, 4.0, trunc);
+ TEST_ROUND(double, double, 4.2, 4.0, trunc);
+
+ TEST_ROUND(double, int, -4.8, -4, trunc);
+ TEST_ROUND(double, int, -4.2, -4, trunc);
+ TEST_ROUND(double, int, 4.8, 4, trunc);
+ TEST_ROUND(double, int, 4.2, 4, trunc);
+
+ TEST_ROUND(double, long, -4.8, -4, trunc);
+ TEST_ROUND(double, long, -4.2, -4, trunc);
+ TEST_ROUND(double, long, 4.8, 4, trunc);
+ TEST_ROUND(double, long, 4.2, 4, trunc);
+
+ TEST_ROUND(float, long, -4.8, -4, trunc);
+ TEST_ROUND(float, long, -4.2, -4, trunc);
+ TEST_ROUND(float, long, 4.8, 4, trunc);
+ TEST_ROUND(float, long, 4.2, 4, trunc);
+
+ /* Nearbyint */
+ TEST_ROUND(double, double, -4.8, -5.0, nearbyint);
+ TEST_ROUND(double, double, -4.2, -4.0, nearbyint);
+ TEST_ROUND(double, double, 4.8, 5.0, nearbyint);
+ TEST_ROUND(double, double, 4.2, 4.0, nearbyint);
+
+ TEST_ROUND(double, int, -4.8, -5, nearbyint);
+ TEST_ROUND(double, int, -4.2, -4, nearbyint);
+ TEST_ROUND(double, int, 4.8, 5, nearbyint);
+ TEST_ROUND(double, int, 4.2, 4, nearbyint);
+
+ TEST_ROUND(double, long, -4.8, -5, nearbyint);
+ TEST_ROUND(double, long, -4.2, -4, nearbyint);
+ TEST_ROUND(double, long, 4.8, 5, nearbyint);
+ TEST_ROUND(double, long, 4.2, 4, nearbyint);
+
+ TEST_ROUND(float, long, -4.8, -5, nearbyint);
+ TEST_ROUND(float, long, -4.2, -4, nearbyint);
+ TEST_ROUND(float, long, 4.8, 5, nearbyint);
+ TEST_ROUND(float, long, 4.2, 4, nearbyint);
+
+ exit(0);
+}
+