From 5a97411f857b0bc9e70b417efa76a5fd5f887fe0 Mon Sep 17 00:00:00 2001 From: Ilya Gavrilin Date: Fri, 20 Oct 2023 14:31:41 +0000 Subject: [PATCH] 8317971: RISC-V: implement copySignF/D and signumF/D intrinsics Reviewed-by: fyang, vkempik --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 32 +++++++++++++ .../cpu/riscv/c2_MacroAssembler_riscv.hpp | 3 ++ src/hotspot/cpu/riscv/riscv.ad | 46 +++++++++++++++++++ src/hotspot/cpu/riscv/vm_version_riscv.cpp | 8 ++++ .../openjdk/bench/java/lang/MathBench.java | 2 +- 5 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index ac20e12946c..d4a86de58f3 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -1653,6 +1653,38 @@ void C2_MacroAssembler::round_double_mode(FloatRegister dst, FloatRegister src, bind(done); } +// According to Java SE specification, for floating-point signum operations, if +// on input we have NaN or +/-0.0 value we should return it, +// otherwise return +/- 1.0 using sign of input. +// one - gives us a floating-point 1.0 (got from matching rule) +// bool is_double - specifies single or double precision operations will be used. +void C2_MacroAssembler::signum_fp(FloatRegister dst, FloatRegister src, FloatRegister one, bool is_double) { + Register tmp1 = t0; + + Label done; + + is_double ? fclass_d(tmp1, src) + : fclass_s(tmp1, src); + + is_double ? fmv_d(dst, src) + : fmv_s(dst, src); + + //bitmask 0b1100011000 specifies this bits: + // 3 - src is -0 + // 4 - src is +0 + // 8 - src is signaling NaN + // 9 - src is a quiet NaN + andi(tmp1, tmp1, 0b1100011000); + + bnez(tmp1, done); + + // use floating-point 1.0 with a sign of input + is_double ? fsgnj_d(dst, one, src) + : fsgnj_s(dst, one, 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; diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index 7dd22389aa4..e46c62d5c9e 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -157,6 +157,9 @@ void round_double_mode(FloatRegister dst, FloatRegister src, int round_mode, Register tmp1, Register tmp2, Register tmp3); + void signum_fp(FloatRegister dst, FloatRegister src, FloatRegister one, + bool is_double); + // intrinsic methods implemented by rvv instructions void string_equals_v(Register r1, Register r2, Register result, Register cnt1, diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index caf39498cf9..553c189891a 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -7506,6 +7506,52 @@ instruct roundD_reg(fRegD dst, fRegD src, immI rmode, iRegLNoSp tmp1, iRegLNoSp ins_pipe(pipe_class_default); %} +// Copysign and signum intrinsics + +instruct copySignD_reg(fRegD dst, fRegD src1, fRegD src2, immD zero) %{ + match(Set dst (CopySignD src1 (Binary src2 zero))); + format %{ "CopySignD $dst $src1 $src2" %} + ins_encode %{ + FloatRegister dst = as_FloatRegister($dst$$reg), + src1 = as_FloatRegister($src1$$reg), + src2 = as_FloatRegister($src2$$reg); + __ fsgnj_d(dst, src1, src2); + %} + ins_pipe(fp_dop_reg_reg_d); +%} + +instruct copySignF_reg(fRegF dst, fRegF src1, fRegF src2) %{ + match(Set dst (CopySignF src1 src2)); + format %{ "CopySignF $dst $src1 $src2" %} + ins_encode %{ + FloatRegister dst = as_FloatRegister($dst$$reg), + src1 = as_FloatRegister($src1$$reg), + src2 = as_FloatRegister($src2$$reg); + __ fsgnj_s(dst, src1, src2); + %} + ins_pipe(fp_dop_reg_reg_s); +%} + +instruct signumD_reg(fRegD dst, fRegD src, immD zero, fRegD one) %{ + match(Set dst (SignumD src (Binary zero one))); + format %{ "signumD $dst, $src" %} + ins_encode %{ + __ signum_fp(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), + as_FloatRegister($one$$reg), true /* is_double */); + %} + ins_pipe(pipe_class_default); +%} + +instruct signumF_reg(fRegF dst, fRegF src, immF zero, fRegF one) %{ + match(Set dst (SignumF src (Binary zero one))); + format %{ "signumF $dst, $src" %} + ins_encode %{ + __ signum_fp(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), + as_FloatRegister($one$$reg), false /* is_double */); + %} + ins_pipe(pipe_class_default); +%} + // Arithmetic Instructions End // ============================================================================ diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 9a88be33d90..6cec56832a2 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -191,6 +191,14 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseMD5Intrinsics, true); } + if (FLAG_IS_DEFAULT(UseCopySignIntrinsic)) { + FLAG_SET_DEFAULT(UseCopySignIntrinsic, true); + } + + if (FLAG_IS_DEFAULT(UseSignumIntrinsic)) { + FLAG_SET_DEFAULT(UseSignumIntrinsic, true); + } + if (UseRVV) { if (!ext_V.enabled()) { warning("RVV is not supported on this CPU"); diff --git a/test/micro/org/openjdk/bench/java/lang/MathBench.java b/test/micro/org/openjdk/bench/java/lang/MathBench.java index 6cd1353907e..c7dde019154 100644 --- a/test/micro/org/openjdk/bench/java/lang/MathBench.java +++ b/test/micro/org/openjdk/bench/java/lang/MathBench.java @@ -471,7 +471,7 @@ public class MathBench { } @Benchmark - public double sigNumDouble() { + public double signumDouble() { return Math.signum(double4Dot1); }