diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index e19b2f2cff5..dbdf76c0599 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -1829,6 +1829,49 @@ void C2_MacroAssembler::float16_to_float(FloatRegister dst, Register src, Regist bind(stub->continuation()); } +static void float_to_float16_slow_path(C2_MacroAssembler& masm, C2GeneralStub& stub) { +#define __ masm. + Register dst = stub.data<0>(); + FloatRegister src = stub.data<1>(); + Register tmp = stub.data<2>(); + __ bind(stub.entry()); + + __ fmv_x_w(dst, src); + + // preserve the payloads of non-canonical NaNs. + __ srai(dst, dst, 13); + // preserve the sign bit. + __ srai(tmp, dst, 13); + __ slli(tmp, tmp, 10); + __ mv(t0, 0x3ff); + __ orr(tmp, tmp, t0); + + // get the result by merging sign bit and payloads of preserved non-canonical NaNs. + __ andr(dst, dst, tmp); + + __ j(stub.continuation()); +#undef __ +} + +// j.l.Float.floatToFloat16 +void C2_MacroAssembler::float_to_float16(Register dst, FloatRegister src, FloatRegister ftmp, Register xtmp) { + auto stub = C2CodeStub::make(dst, src, xtmp, 130, float_to_float16_slow_path); + + // in riscv, NaN needs a special process as fcvt does not work in that case. + + // check whether it's a NaN. + // replace fclass with feq as performance optimization. + feq_s(t0, src, src); + // jump to stub processing NaN cases. + beqz(t0, stub->entry()); + + // non-NaN cases, just use built-in instructions. + fcvt_h_s(ftmp, src); + fmv_x_h(dst, ftmp); + + bind(stub->continuation()); +} + void C2_MacroAssembler::signum_fp_v(VectorRegister dst, VectorRegister one, BasicType bt, int vlen) { vsetvli_helper(bt, vlen); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index 7309c59110a..cf8d28a3362 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -173,6 +173,7 @@ void signum_fp(FloatRegister dst, FloatRegister one, bool is_double); void float16_to_float(FloatRegister dst, Register src, Register tmp); + void float_to_float16(Register dst, FloatRegister src, FloatRegister ftmp, Register xtmp); void signum_fp_v(VectorRegister dst, VectorRegister one, BasicType bt, int vlen); diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 550e7947cc5..458e381b3b0 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1934,6 +1934,7 @@ bool Matcher::match_rule_supported(int opcode) { return UseFMA; case Op_ConvHF2F: + case Op_ConvF2HF: return UseZfh; } @@ -8292,6 +8293,18 @@ instruct convHF2F_reg_reg(fRegF dst, iRegINoSp src, iRegINoSp tmp) %{ ins_pipe(pipe_slow); %} +instruct convF2HF_reg_reg(iRegINoSp dst, fRegF src, fRegF ftmp, iRegINoSp xtmp) %{ + match(Set dst (ConvF2HF src)); + effect(TEMP_DEF dst, TEMP ftmp, TEMP xtmp); + format %{ "fcvt.h.s $ftmp, $src\t# convert single precision to half\n\t" + "fmv.x.h $dst, $ftmp\t# move result from $ftmp to $dst" + %} + ins_encode %{ + __ float_to_float16($dst$$Register, $src$$FloatRegister, $ftmp$$FloatRegister, $xtmp$$Register); + %} + ins_pipe(pipe_slow); +%} + // float <-> int instruct convF2I_reg_reg(iRegINoSp dst, fRegF src) %{