8312569: RISC-V: Missing intrinsics for Math.ceil, floor, rint

Reviewed-by: luhenry, fjiang, fyang
This commit is contained in:
Ilya Gavrilin 2023-09-07 15:26:55 +00:00 committed by Vladimir Kempik
parent 2fd870a74f
commit 8557205a82
4 changed files with 83 additions and 2 deletions

View File

@ -2791,7 +2791,7 @@ public:
if (shamt != 0) { \
_slli(Rd, Rs1, shamt); \
} else { \
if (Rd != Rs1) { \
if (Rd != Rs1) { \
addi(Rd, Rs1, 0); \
} \
} \
@ -2812,7 +2812,7 @@ public:
if (shamt != 0) { \
NORMAL_NAME(Rd, Rs1, shamt); \
} else { \
if (Rd != Rs1) { \
if (Rd != Rs1) { \
addi(Rd, Rs1, 0); \
} \
} \

View File

@ -1372,6 +1372,70 @@ void C2_MacroAssembler::minmax_fp(FloatRegister dst, FloatRegister src1, FloatRe
bind(Done);
}
// According to Java SE specification, for floating-point round operations, if
// the input is NaN, +/-infinity, or +/-0, the same input is returned as the
// rounded result; this differs from behavior of RISC-V fcvt instructions (which
// round out-of-range values to the nearest max or min value), therefore special
// handling is needed by NaN, +/-Infinity, +/-0.
void C2_MacroAssembler::round_double_mode(FloatRegister dst, FloatRegister src, int round_mode,
Register tmp1, Register tmp2, Register tmp3) {
assert_different_registers(dst, src);
assert_different_registers(tmp1, tmp2, tmp3);
// Set rounding mode for conversions
// Here we use similar modes to double->long and long->double conversions
// Different mode for long->double conversion matter only if long value was not representable as double,
// we got long value as a result of double->long conversion so, it is definitely representable
RoundingMode rm;
switch (round_mode) {
case RoundDoubleModeNode::rmode_ceil:
rm = RoundingMode::rup;
break;
case RoundDoubleModeNode::rmode_floor:
rm = RoundingMode::rdn;
break;
case RoundDoubleModeNode::rmode_rint:
rm = RoundingMode::rne;
break;
default:
ShouldNotReachHere();
}
// tmp1 - is a register to store double converted to long int
// tmp2 - is a register to create constant for comparison
// tmp3 - is a register where we store modified result of double->long conversion
Label done, bad_val;
// Conversion from double to long
fcvt_l_d(tmp1, src, rm);
// Generate constant (tmp2)
// tmp2 = 100...0000
addi(tmp2, zr, 1);
slli(tmp2, tmp2, 63);
// Prepare converted long (tmp1)
// as a result when conversion overflow we got:
// tmp1 = 011...1111 or 100...0000
// Convert it to: tmp3 = 100...0000
addi(tmp3, tmp1, 1);
andi(tmp3, tmp3, -2);
beq(tmp3, tmp2, bad_val);
// Conversion from long to double
fcvt_d_l(dst, tmp1, rm);
// Add sign of input value to result for +/- 0 cases
fsgnj_d(dst, dst, src);
j(done);
// If got conversion overflow return src
bind(bad_val);
fmv_d(dst, src);
bind(done);
}
void C2_MacroAssembler::element_compare(Register a1, Register a2, Register result, Register cnt, Register tmp1, Register tmp2,
VectorRegister vr1, VectorRegister vr2, VectorRegister vrs, bool islatin, Label &DONE) {
Label loop;

View File

@ -149,6 +149,9 @@
FloatRegister src1, FloatRegister src2,
bool is_double, bool is_min);
void round_double_mode(FloatRegister dst, FloatRegister src, int round_mode,
Register tmp1, Register tmp2, Register tmp3);
// intrinsic methods implemented by rvv instructions
void string_equals_v(Register r1, Register r2,
Register result, Register cnt1,

View File

@ -7709,6 +7709,20 @@ instruct sqrtD_reg(fRegD dst, fRegD src) %{
ins_pipe(fp_sqrt_d);
%}
// Round Instruction
instruct roundD_reg(fRegD dst, fRegD src, immI rmode, iRegLNoSp tmp1, iRegLNoSp tmp2, iRegLNoSp tmp3) %{
match(Set dst (RoundDoubleMode src rmode));
ins_cost(2 * XFER_COST + BRANCH_COST);
effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, TEMP tmp3);
format %{ "RoundDoubleMode $src, $rmode" %}
ins_encode %{
__ round_double_mode(as_FloatRegister($dst$$reg),
as_FloatRegister($src$$reg), $rmode$$constant, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register);
%}
ins_pipe(pipe_class_default);
%}
// Arithmetic Instructions End
// ============================================================================