zfh semantic functions: Add conversions between 64bit integers and half precision * fcvt.l.h * fcvt.lu.h * fcvt.h.l * fcvt.h.lu PiperOrigin-RevId: 761730156 Change-Id: I1594e48a32ca99dab3d2ff9ff1d6e66f2a500c38
diff --git a/riscv/riscv_zfh.isa b/riscv/riscv_zfh.isa index 76265d5..66c944d 100644 --- a/riscv/riscv_zfh.isa +++ b/riscv/riscv_zfh.isa
@@ -262,5 +262,21 @@ resources: { next_pc, frs1 : rd[0..]}, semfunc: "&RV64::RiscVZfhFclass", disasm: "fclass.h", "%rd, %frs1"; + fcvt_lh{: frs1, rm : rd, fflags}, + resources: {next_pc, frs1 : rd[0..]}, + semfunc: "&RV64::RiscVZfhCvtLh", + disasm: "fcvt.l.h", "%rd, %frs1"; + fcvt_luh{: frs1, rm : rd, fflags}, + resources: {next_pc, frs1 : rd[0..]}, + semfunc: "&RV64::RiscVZfhCvtLuh", + disasm: "fcvt.lu.h", "%rd, %frs1"; + fcvt_hl{: rs1, rm : frd, fflags}, + resources: {next_pc, frs1 : frd[0..]}, + semfunc: "&RV64::RiscVZfhCvtHl", + disasm: "fcvt.h.l", "%frd, %rs1"; + fcvt_hlu{: rs1, rm : frd, fflags}, + resources: {next_pc, frs1 : frd[0..]}, + semfunc: "&RV64::RiscVZfhCvtHlu", + disasm: "fcvt.h.lu", "%frd, %rs1"; } }
diff --git a/riscv/riscv_zfh_instructions.cc b/riscv/riscv_zfh_instructions.cc index 23af707..e807747 100644 --- a/riscv/riscv_zfh_instructions.cc +++ b/riscv/riscv_zfh_instructions.cc
@@ -705,6 +705,36 @@ }); } +// Converts from half precision to signed 64 bit integer. +void RiscVZfhCvtLh(const Instruction *instruction) { + RiscVConvertFloatWithFflagsOp<typename RV64Register::ValueType, HalfFP, + int64_t>(instruction); +} + +// Converts from half precision to unsigned 64 bit integer. +void RiscVZfhCvtLuh(const Instruction *instruction) { + RiscVConvertFloatWithFflagsOp<typename RV64Register::ValueType, HalfFP, + uint64_t>(instruction); +} + +// Converts from signed 64 bit integer to half precision. +void RiscVZfhCvtHl(const Instruction *instruction) { + RiscVZfhCvtHelper<HalfFP, int64_t>( + instruction, + [](int64_t a, FPRoundingMode rm, uint32_t &fflags) -> HalfFP { + return ConvertToHalfFP(static_cast<float>(a), rm, fflags); + }); +} + +// Convert from unsigned 64 bit integer to half precision. +void RiscVZfhCvtHlu(const Instruction *instruction) { + RiscVZfhCvtHelper<HalfFP, uint64_t>( + instruction, + [](uint64_t a, FPRoundingMode rm, uint32_t &fflags) -> HalfFP { + return ConvertToHalfFP(static_cast<float>(a), rm, fflags); + }); +} + } // namespace RV64 void RiscVZfhFlhChild(const Instruction *instruction) {
diff --git a/riscv/riscv_zfh_instructions.h b/riscv/riscv_zfh_instructions.h index f4e67c8..576d7f2 100644 --- a/riscv/riscv_zfh_instructions.h +++ b/riscv/riscv_zfh_instructions.h
@@ -145,6 +145,38 @@ // rd: Integer Register void RiscVZfhFclass(const Instruction *instruction); +// Source Operands: +// frs1: Float Register +// rm: Literal Operand (rounding mode) +// Destination Operands: +// rd: Integer Register +// fflags: Accrued Exception Flags field in FCSR +void RiscVZfhCvtLh(const Instruction *instruction); + +// Source Operands: +// frs1: Float Register +// rm: Literal Operand (rounding mode) +// Destination Operands: +// rd: Integer Register +// fflags: Accrued Exception Flags field in FCSR +void RiscVZfhCvtLuh(const Instruction *instruction); + +// Source Operands: +// rs1: Integer Register +// rm: Literal Operand (rounding mode) +// Destination Operands: +// frd: Float Register +// fflags: Accrued Exception Flags field in FCSR +void RiscVZfhCvtHl(const Instruction *instruction); + +// Source Operands: +// rs1: Integer Register +// rm: Literal Operand (rounding mode) +// Destination Operands: +// frd: Float Register +// fflags: Accrued Exception Flags field in FCSR +void RiscVZfhCvtHlu(const Instruction *instruction); + } // namespace RV64 // Source Operands: *none*
diff --git a/riscv/test/riscv_zfh_instructions_test.cc b/riscv/test/riscv_zfh_instructions_test.cc index bf8365a..e5e8d73 100644 --- a/riscv/test/riscv_zfh_instructions_test.cc +++ b/riscv/test/riscv_zfh_instructions_test.cc
@@ -84,6 +84,10 @@ using ::mpact::sim::riscv::RVFpRegister; using ::mpact::sim::riscv::ScopedFPRoundingMode; using ::mpact::sim::riscv::ScopedFPStatus; +using ::mpact::sim::riscv::RV64::RiscVZfhCvtHl; +using ::mpact::sim::riscv::RV64::RiscVZfhCvtHlu; +using ::mpact::sim::riscv::RV64::RiscVZfhCvtLh; +using ::mpact::sim::riscv::RV64::RiscVZfhCvtLuh; using ::mpact::sim::riscv::test::FloatingPointToString; using ::mpact::sim::riscv::test::FPCompare; @@ -242,6 +246,7 @@ } // Helper for unary instructions that go between floats and integers. +// TODO(b/419352093): Change the rounding mode datatype to int. template <typename XRegister> template <typename DestRegisterType, typename LhsRegisterType, typename R, typename LHS> @@ -1652,4 +1657,64 @@ ClassHelper(); } +// Test conversion from half precision to signed 64 bit integer. +TEST_F(RV64ZfhInstructionTest, RiscVZfhCvtLh) { + SetSemanticFunction(&RiscVZfhCvtLh); + UnaryOpWithFflagsMixedTestHelper<RV64Register, RVFpRegister, int64_t, HalfFP>( + "fcvt.l.h", instruction_, {"f", "x"}, 32, + [this](HalfFP input, uint32_t rm) -> std::tuple<int64_t, uint32_t> { + uint32_t fflags = 0; + double input_double = + FpConversionsTestHelper(input).ConvertWithFlags<double>(fflags); + int64_t val = + this->RoundToInteger<double, int64_t>(input_double, rm, fflags); + return std::tuple(val, fflags); + }); +} + +// Test conversion from half precision to unsigned 64 bit integer. +TEST_F(RV64ZfhInstructionTest, RiscVZfhCvtLuh) { + SetSemanticFunction(&RiscVZfhCvtLuh); + UnaryOpWithFflagsMixedTestHelper<RV64Register, RVFpRegister, uint64_t, + HalfFP>( + "fcvt.lu.h", instruction_, {"f", "x"}, 32, + [this](HalfFP input, uint32_t rm) -> std::tuple<uint64_t, uint32_t> { + uint32_t fflags = 0; + double input_double = + FpConversionsTestHelper(input).ConvertWithFlags<double>(fflags); + uint64_t val = + this->RoundToInteger<double, uint64_t>(input_double, rm, fflags); + return std::tuple(val, fflags); + }); +} + +// Test conversion from signed 64 bit integer to half precision. +TEST_F(RV64ZfhInstructionTest, RiscVZfhCvtHl) { + SetSemanticFunction(&RiscVZfhCvtHl); + UnaryOpWithFflagsMixedTestHelper<RVFpRegister, RV64Register, HalfFP, int64_t>( + "fcvt.h.l", instruction_, {"x", "f"}, 32, + [](int64_t input_int, uint32_t rm) -> std::tuple<HalfFP, uint32_t> { + uint32_t fflags = 0; + HalfFP result = FpConversionsTestHelper(static_cast<double>(input_int)) + .ConvertWithFlags<HalfFP>( + fflags, static_cast<FPRoundingMode>(rm)); + return std::tuple(result, fflags); + }); +} + +// Test conversion from unsigned 64 bit integer to half precision. +TEST_F(RV64ZfhInstructionTest, RiscVZfhCvtHlu) { + SetSemanticFunction(&RiscVZfhCvtHlu); + UnaryOpWithFflagsMixedTestHelper<RVFpRegister, RV64Register, HalfFP, + uint64_t>( + "fcvt.h.lu", instruction_, {"x", "f"}, 32, + [](uint64_t input_int, uint32_t rm) -> std::tuple<HalfFP, uint32_t> { + uint32_t fflags = 0; + HalfFP result = FpConversionsTestHelper(static_cast<double>(input_int)) + .ConvertWithFlags<HalfFP>( + fflags, static_cast<FPRoundingMode>(rm)); + return std::tuple(result, fflags); + }); +} + } // namespace