[Lldb-commits] [lldb] 6493fc4 - [LLDB][RISCV] Add RVD instruction support for EmulateInstructionRISCV
via lldb-commits
lldb-commits at lists.llvm.org
Thu Dec 15 08:58:37 PST 2022
Author: Emmmer
Date: 2022-12-16T00:58:26+08:00
New Revision: 6493fc4bccd2a5365f3f3a4f205acb8c1409bd0d
URL: https://github.com/llvm/llvm-project/commit/6493fc4bccd2a5365f3f3a4f205acb8c1409bd0d
DIFF: https://github.com/llvm/llvm-project/commit/6493fc4bccd2a5365f3f3a4f205acb8c1409bd0d.diff
LOG: [LLDB][RISCV] Add RVD instruction support for EmulateInstructionRISCV
RVD extension is a double-precision floating-point instruction-set extension, which adds double-precision floating-point computational instructions compliant with the IEEE 754-2008 arithmetic standard.
This patch:
- Reuse most of the functions in the "F extension" to impl the"D extension"
- corresponding unittests.
Reviewed By: DavidSpickett
Differential Revision: https://reviews.llvm.org/D140032
Added:
Modified:
lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
Removed:
################################################################################
diff --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
index fe29769b4ac6f..cb54097b52f5b 100644
--- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
+++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
@@ -560,9 +560,9 @@ static const InstrPattern PATTERNS[] = {
{"FCVT_W_S", 0xFFF0007F, 0xC0000053, DecodeIType<FCVT_W_S>},
{"FCVT_WU_S", 0xFFF0007F, 0xC0100053, DecodeIType<FCVT_WU_S>},
{"FMV_X_W", 0xFFF0707F, 0xE0000053, DecodeIType<FMV_X_W>},
- {"FEQ_S", 0xFE00707F, 0xA2002053, DecodeRType<FEQ_S>},
- {"FLT_S", 0xFE00707F, 0xA2001053, DecodeRType<FLT_S>},
- {"FLE_S", 0xFE00707F, 0xA2000053, DecodeRType<FLE_S>},
+ {"FEQ_S", 0xFE00707F, 0xA0002053, DecodeRType<FEQ_S>},
+ {"FLT_S", 0xFE00707F, 0xA0001053, DecodeRType<FLT_S>},
+ {"FLE_S", 0xFE00707F, 0xA0000053, DecodeRType<FLE_S>},
{"FCLASS_S", 0xFFF0707F, 0xE0001053, DecodeIType<FCLASS_S>},
{"FCVT_S_W", 0xFFF0007F, 0xD0000053, DecodeIType<FCVT_S_W>},
{"FCVT_S_WU", 0xFFF0007F, 0xD0100053, DecodeIType<FCVT_S_WU>},
@@ -573,6 +573,42 @@ static const InstrPattern PATTERNS[] = {
{"FCVT_LU_S", 0xFFF0007F, 0xC0300053, DecodeIType<FCVT_LU_S>},
{"FCVT_S_L", 0xFFF0007F, 0xD0200053, DecodeIType<FCVT_S_L>},
{"FCVT_S_LU", 0xFFF0007F, 0xD0300053, DecodeIType<FCVT_S_LU>},
+
+ // RV32D (Extension for Double-Precision Floating-Point) //
+ {"FLD", 0x707F, 0x3007, DecodeIType<FLD>},
+ {"FSD", 0x707F, 0x3027, DecodeSType<FSD>},
+ {"FMADD_D", 0x600007F, 0x2000043, DecodeR4Type<FMADD_D>},
+ {"FMSUB_D", 0x600007F, 0x2000047, DecodeR4Type<FMSUB_D>},
+ {"FNMSUB_D", 0x600007F, 0x200004B, DecodeR4Type<FNMSUB_D>},
+ {"FNMADD_D", 0x600007F, 0x200004F, DecodeR4Type<FNMADD_D>},
+ {"FADD_D", 0xFE00007F, 0x2000053, DecodeRType<FADD_D>},
+ {"FSUB_D", 0xFE00007F, 0xA000053, DecodeRType<FSUB_D>},
+ {"FMUL_D", 0xFE00007F, 0x12000053, DecodeRType<FMUL_D>},
+ {"FDIV_D", 0xFE00007F, 0x1A000053, DecodeRType<FDIV_D>},
+ {"FSQRT_D", 0xFFF0007F, 0x5A000053, DecodeIType<FSQRT_D>},
+ {"FSGNJ_D", 0xFE00707F, 0x22000053, DecodeRType<FSGNJ_D>},
+ {"FSGNJN_D", 0xFE00707F, 0x22001053, DecodeRType<FSGNJN_D>},
+ {"FSGNJX_D", 0xFE00707F, 0x22002053, DecodeRType<FSGNJX_D>},
+ {"FMIN_D", 0xFE00707F, 0x2A000053, DecodeRType<FMIN_D>},
+ {"FMAX_D", 0xFE00707F, 0x2A001053, DecodeRType<FMAX_D>},
+ {"FCVT_S_D", 0xFFF0007F, 0x40100053, DecodeIType<FCVT_S_D>},
+ {"FCVT_D_S", 0xFFF0007F, 0x42000053, DecodeIType<FCVT_D_S>},
+ {"FEQ_D", 0xFE00707F, 0xA2002053, DecodeRType<FEQ_D>},
+ {"FLT_D", 0xFE00707F, 0xA2001053, DecodeRType<FLT_D>},
+ {"FLE_D", 0xFE00707F, 0xA2000053, DecodeRType<FLE_D>},
+ {"FCLASS_D", 0xFFF0707F, 0xE2001053, DecodeIType<FCLASS_D>},
+ {"FCVT_W_D", 0xFFF0007F, 0xC2000053, DecodeIType<FCVT_W_D>},
+ {"FCVT_WU_D", 0xFFF0007F, 0xC2100053, DecodeIType<FCVT_WU_D>},
+ {"FCVT_D_W", 0xFFF0007F, 0xD2000053, DecodeIType<FCVT_D_W>},
+ {"FCVT_D_WU", 0xFFF0007F, 0xD2100053, DecodeIType<FCVT_D_WU>},
+
+ // RV64D (Extension for Double-Precision Floating-Point) //
+ {"FCVT_L_D", 0xFFF0007F, 0xC2200053, DecodeIType<FCVT_L_D>},
+ {"FCVT_LU_D", 0xFFF0007F, 0xC2300053, DecodeIType<FCVT_LU_D>},
+ {"FMV_X_D", 0xFFF0707F, 0xE2000053, DecodeIType<FMV_X_D>},
+ {"FCVT_D_L", 0xFFF0007F, 0xD2200053, DecodeIType<FCVT_D_L>},
+ {"FCVT_D_LU", 0xFFF0007F, 0xD2300053, DecodeIType<FCVT_D_LU>},
+ {"FMV_D_X", 0xFFF0707F, 0xF2000053, DecodeIType<FMV_D_X>},
};
Optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) {
@@ -1172,160 +1208,103 @@ class Executor {
m_emu, inst, 8, ZextD,
[](uint64_t a, uint64_t b) { return std::max(a, b); });
}
- bool operator()(FLW inst) {
- return transformOptional(
- inst.rs1.Read(m_emu),
- [&](auto &&rs1) {
- uint64_t addr = rs1 + uint64_t(inst.imm);
- uint64_t bits = m_emu.ReadMem<uint64_t>(addr).value();
- APFloat f(APFloat::IEEEsingle(), APInt(32, bits));
- return inst.rd.WriteAPFloat(m_emu, f);
- })
- .value_or(false);
- }
- bool operator()(FSW inst) {
- return transformOptional(
- zipOpt(inst.rs1.Read(m_emu), inst.rs2.ReadAPFloat(m_emu, false)),
- [&](auto &&tup) {
- auto [rs1, rs2] = tup;
- uint64_t addr = rs1 + uint64_t(inst.imm);
- uint64_t bits = rs2.bitcastToAPInt().getZExtValue();
- return m_emu.WriteMem<uint64_t>(addr, bits);
- })
- .value_or(false);
- }
- bool operator()(FMADD_S inst) {
- return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false),
- inst.rs3.ReadAPFloat(m_emu, false)),
- [&](auto &&tup) {
- auto [rs1, rs2, rs3] = tup;
- auto res = rs1.fusedMultiplyAdd(
- rs2, rs3, m_emu.GetRoundingMode());
- inst.rd.WriteAPFloat(m_emu, rs1);
- return m_emu.SetAccruedExceptions(res);
- })
- .value_or(false);
- }
- bool operator()(FMSUB_S inst) {
- return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false),
- inst.rs3.ReadAPFloat(m_emu, false)),
- [&](auto &&tup) {
- auto [rs1, rs2, rs3] = tup;
- auto res = rs1.fusedMultiplyAdd(
- rs2, -rs3, m_emu.GetRoundingMode());
- inst.rd.WriteAPFloat(m_emu, rs1);
- return m_emu.SetAccruedExceptions(res);
- })
- .value_or(false);
- }
- bool operator()(FNMSUB_S inst) {
- return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false),
- inst.rs3.ReadAPFloat(m_emu, false)),
- [&](auto &&tup) {
- auto [rs1, rs2, rs3] = tup;
- auto res = rs1.fusedMultiplyAdd(
- -rs2, rs3, m_emu.GetRoundingMode());
- inst.rd.WriteAPFloat(m_emu, rs1);
- return m_emu.SetAccruedExceptions(res);
- })
- .value_or(false);
- }
- bool operator()(FNMADD_S inst) {
- return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false),
- inst.rs3.ReadAPFloat(m_emu, false)),
- [&](auto &&tup) {
- auto [rs1, rs2, rs3] = tup;
- auto res = rs1.fusedMultiplyAdd(
- -rs2, -rs3, m_emu.GetRoundingMode());
- inst.rd.WriteAPFloat(m_emu, rs1);
- return m_emu.SetAccruedExceptions(res);
+ template <typename T>
+ bool F_Load(T inst, const fltSemantics &(*semantics)(),
+ unsigned int numBits) {
+ return transformOptional(inst.rs1.Read(m_emu),
+ [&](auto &&rs1) {
+ uint64_t addr = rs1 + uint64_t(inst.imm);
+ uint64_t bits =
+ m_emu.ReadMem<uint64_t>(addr).value();
+ APFloat f(semantics(), APInt(numBits, bits));
+ return inst.rd.WriteAPFloat(m_emu, f);
})
.value_or(false);
}
- bool operator()(FADD_S inst) {
- return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false)),
+ bool operator()(FLW inst) { return F_Load(inst, &APFloat::IEEEsingle, 32); }
+ template <typename T> bool F_Store(T inst, bool isDouble) {
+ return transformOptional(zipOpt(inst.rs1.Read(m_emu),
+ inst.rs2.ReadAPFloat(m_emu, isDouble)),
[&](auto &&tup) {
auto [rs1, rs2] = tup;
- auto res = rs1.add(rs2, m_emu.GetRoundingMode());
- inst.rd.WriteAPFloat(m_emu, rs1);
- return m_emu.SetAccruedExceptions(res);
+ uint64_t addr = rs1 + uint64_t(inst.imm);
+ uint64_t bits =
+ rs2.bitcastToAPInt().getZExtValue();
+ return m_emu.WriteMem<uint64_t>(addr, bits);
})
.value_or(false);
}
- bool operator()(FSUB_S inst) {
- return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false)),
- [&](auto &&tup) {
- auto [rs1, rs2] = tup;
- auto res =
- rs1.subtract(rs2, m_emu.GetRoundingMode());
- inst.rd.WriteAPFloat(m_emu, rs1);
- return m_emu.SetAccruedExceptions(res);
- })
- .value_or(false);
+ bool operator()(FSW inst) { return F_Store(inst, false); }
+ std::tuple<bool, APFloat> FusedMultiplyAdd(APFloat rs1, APFloat rs2,
+ APFloat rs3) {
+ auto opStatus = rs1.fusedMultiplyAdd(rs2, rs3, m_emu.GetRoundingMode());
+ auto res = m_emu.SetAccruedExceptions(opStatus);
+ return {res, rs1};
}
- bool operator()(FMUL_S inst) {
- return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false)),
+ template <typename T>
+ bool FMA(T inst, bool isDouble, float rs2_sign, float rs3_sign) {
+ return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
+ inst.rs2.ReadAPFloat(m_emu, isDouble),
+ inst.rs3.ReadAPFloat(m_emu, isDouble)),
[&](auto &&tup) {
- auto [rs1, rs2] = tup;
- auto res =
- rs1.multiply(rs2, m_emu.GetRoundingMode());
- inst.rd.WriteAPFloat(m_emu, rs1);
- return m_emu.SetAccruedExceptions(res);
+ auto [rs1, rs2, rs3] = tup;
+ rs2.copySign(APFloat(rs2_sign));
+ rs3.copySign(APFloat(rs3_sign));
+ auto [res, f] = FusedMultiplyAdd(rs1, rs2, rs3);
+ return res && inst.rd.WriteAPFloat(m_emu, f);
})
.value_or(false);
}
- bool operator()(FDIV_S inst) {
- return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false)),
+ bool operator()(FMADD_S inst) { return FMA(inst, false, 1.0f, 1.0f); }
+ bool operator()(FMSUB_S inst) { return FMA(inst, false, 1.0f, -1.0f); }
+ bool operator()(FNMSUB_S inst) { return FMA(inst, false, -1.0f, 1.0f); }
+ bool operator()(FNMADD_S inst) { return FMA(inst, false, -1.0f, -1.0f); }
+ template <typename T>
+ bool F_Op(T inst, bool isDouble,
+ APFloat::opStatus (APFloat::*f)(const APFloat &RHS,
+ APFloat::roundingMode RM)) {
+ return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
+ inst.rs2.ReadAPFloat(m_emu, isDouble)),
[&](auto &&tup) {
auto [rs1, rs2] = tup;
auto res =
- rs1.divide(rs2, m_emu.GetRoundingMode());
+ ((&rs1)->*f)(rs2, m_emu.GetRoundingMode());
inst.rd.WriteAPFloat(m_emu, rs1);
return m_emu.SetAccruedExceptions(res);
})
.value_or(false);
}
+ bool operator()(FADD_S inst) { return F_Op(inst, false, &APFloat::add); }
+ bool operator()(FSUB_S inst) { return F_Op(inst, false, &APFloat::subtract); }
+ bool operator()(FMUL_S inst) { return F_Op(inst, false, &APFloat::multiply); }
+ bool operator()(FDIV_S inst) { return F_Op(inst, false, &APFloat::divide); }
bool operator()(FSQRT_S inst) {
// TODO: APFloat doesn't have a sqrt function.
return false;
}
- bool operator()(FSGNJ_S inst) {
- return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false)),
+ template <typename T> bool F_SignInj(T inst, bool isDouble, bool isNegate) {
+ return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
+ inst.rs2.ReadAPFloat(m_emu, isDouble)),
[&](auto &&tup) {
auto [rs1, rs2] = tup;
+ if (isNegate)
+ rs2.changeSign();
rs1.copySign(rs2);
return inst.rd.WriteAPFloat(m_emu, rs1);
})
.value_or(false);
}
- bool operator()(FSGNJN_S inst) {
- return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false)),
- [&](auto &&tup) {
- auto [rs1, rs2] = tup;
- rs1.copySign(-rs2);
- return inst.rd.WriteAPFloat(m_emu, rs1);
- })
- .value_or(false);
- }
- bool operator()(FSGNJX_S inst) {
- return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false)),
+ bool operator()(FSGNJ_S inst) { return F_SignInj(inst, false, false); }
+ bool operator()(FSGNJN_S inst) { return F_SignInj(inst, false, true); }
+ template <typename T> bool F_SignInjXor(T inst, bool isDouble) {
+ return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
+ inst.rs2.ReadAPFloat(m_emu, isDouble)),
[&](auto &&tup) {
auto [rs1, rs2] = tup;
- // spec: the sign bit is the XOR of the
- // sign bits of rs1 and rs2. if rs1 and rs2
- // have the same signs set rs1 to positive
- // else set rs1 to negative
+ // spec: the sign bit is the XOR of the sign bits
+ // of rs1 and rs2. if rs1 and rs2 have the same
+ // signs set rs1 to positive else set rs1 to
+ // negative
if (rs1.isNegative() == rs2.isNegative()) {
rs1.clearSign();
} else {
@@ -1336,10 +1315,13 @@ class Executor {
})
.value_or(false);
}
- bool operator()(FMIN_S inst) {
+ bool operator()(FSGNJX_S inst) { return F_SignInjXor(inst, false); }
+ template <typename T>
+ bool F_MAX_MIN(T inst, bool isDouble,
+ APFloat (*f)(const APFloat &A, const APFloat &B)) {
return transformOptional(
- zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false)),
+ zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
+ inst.rs2.ReadAPFloat(m_emu, isDouble)),
[&](auto &&tup) {
auto [rs1, rs2] = tup;
// If both inputs are NaNs, the result is the canonical NaN.
@@ -1352,102 +1334,83 @@ class Executor {
auto canonicalNaN = APFloat::getQNaN(rs1.getSemantics());
return inst.rd.WriteAPFloat(m_emu, canonicalNaN);
}
- return inst.rd.WriteAPFloat(m_emu, minnum(rs1, rs2));
- })
- .value_or(false);
- }
- bool operator()(FMAX_S inst) {
- return transformOptional(
- zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false)),
- [&](auto &&tup) {
- auto [rs1, rs2] = tup;
- if (rs1.isNaN() || rs2.isNaN())
- m_emu.SetAccruedExceptions(APFloat::opInvalidOp);
- if (rs1.isNaN() && rs2.isNaN()) {
- auto canonicalNaN = APFloat::getQNaN(rs1.getSemantics());
- return inst.rd.WriteAPFloat(m_emu, canonicalNaN);
- }
- return inst.rd.WriteAPFloat(m_emu, maxnum(rs1, rs2));
+ return inst.rd.WriteAPFloat(m_emu, f(rs1, rs2));
})
.value_or(false);
}
+ bool operator()(FMIN_S inst) { return F_MAX_MIN(inst, false, minnum); }
+ bool operator()(FMAX_S inst) { return F_MAX_MIN(inst, false, maxnum); }
bool operator()(FCVT_W_S inst) {
- return transformOptional(inst.rs1.ReadAPFloat(m_emu, false),
- [&](auto &&rs1) {
- int32_t res = rs1.convertToFloat();
- return inst.rd.Write(m_emu, uint64_t(res));
- })
- .value_or(false);
+ return FCVT_i2f<FCVT_W_S, int32_t, float>(inst, false,
+ &APFloat::convertToFloat);
}
bool operator()(FCVT_WU_S inst) {
- return transformOptional(inst.rs1.ReadAPFloat(m_emu, false),
- [&](auto &&rs1) {
- uint32_t res = rs1.convertToFloat();
- return inst.rd.Write(m_emu, uint64_t(res));
- })
- .value_or(false);
- }
- bool operator()(FMV_X_W inst) {
- return transformOptional(inst.rs1.ReadAPFloat(m_emu, false),
- [&](auto &&rs1) {
- if (rs1.isNaN())
- return inst.rd.Write(m_emu, 0x7fc00000);
- auto bits = rs1.bitcastToAPInt();
- return inst.rd.Write(
- m_emu,
- NanBoxing(uint64_t(bits.getSExtValue())));
- })
- .value_or(false);
+ return FCVT_i2f<FCVT_WU_S, uint32_t, float>(inst, false,
+ &APFloat::convertToFloat);
}
- bool operator()(FEQ_S inst) {
+ template <typename T> bool FMV_f2i(T inst, bool isDouble) {
return transformOptional(
- zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false)),
- [&](auto &&tup) {
- auto [rs1, rs2] = tup;
- if (rs1.isNaN() || rs2.isNaN()) {
- if (rs1.isSignaling() || rs2.isSignaling())
- m_emu.SetAccruedExceptions(APFloat::opInvalidOp);
- return inst.rd.Write(m_emu, 0);
+ inst.rs1.ReadAPFloat(m_emu, isDouble),
+ [&](auto &&rs1) {
+ if (rs1.isNaN()) {
+ if (isDouble)
+ return inst.rd.Write(m_emu, 0x7ff8'0000'0000'0000);
+ else
+ return inst.rd.Write(m_emu, 0x7fc0'0000);
}
- return inst.rd.Write(m_emu,
- rs1.compare(rs2) == APFloat::cmpEqual);
+ auto bits = rs1.bitcastToAPInt().getZExtValue();
+ if (isDouble)
+ return inst.rd.Write(m_emu, bits);
+ else
+ return inst.rd.Write(m_emu, uint64_t(bits & 0xffff'ffff));
})
.value_or(false);
}
- bool operator()(FLT_S inst) {
+ bool operator()(FMV_X_W inst) { return FMV_f2i(inst, false); }
+ enum F_CMP {
+ FEQ,
+ FLT,
+ FLE,
+ };
+ template <typename T> bool F_Compare(T inst, bool isDouble, F_CMP cmp) {
return transformOptional(
- zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false)),
+ zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
+ inst.rs2.ReadAPFloat(m_emu, isDouble)),
[&](auto &&tup) {
auto [rs1, rs2] = tup;
if (rs1.isNaN() || rs2.isNaN()) {
- m_emu.SetAccruedExceptions(APFloat::opInvalidOp);
- return inst.rd.Write(m_emu, 0);
+ if (cmp == FEQ) {
+ if (rs1.isSignaling() || rs2.isSignaling()) {
+ auto res =
+ m_emu.SetAccruedExceptions(APFloat::opInvalidOp);
+ return res && inst.rd.Write(m_emu, 0);
+ }
+ }
+ auto res = m_emu.SetAccruedExceptions(APFloat::opInvalidOp);
+ return res && inst.rd.Write(m_emu, 0);
}
- return inst.rd.Write(m_emu,
- rs1.compare(rs2) == APFloat::cmpLessThan);
- })
- .value_or(false);
- }
- bool operator()(FLE_S inst) {
- return transformOptional(
- zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
- inst.rs2.ReadAPFloat(m_emu, false)),
- [&](auto &&tup) {
- auto [rs1, rs2] = tup;
- if (rs1.isNaN() || rs2.isNaN()) {
- m_emu.SetAccruedExceptions(APFloat::opInvalidOp);
- return inst.rd.Write(m_emu, 0);
+ switch (cmp) {
+ case FEQ:
+ return inst.rd.Write(m_emu,
+ rs1.compare(rs2) == APFloat::cmpEqual);
+ case FLT:
+ return inst.rd.Write(m_emu, rs1.compare(rs2) ==
+ APFloat::cmpLessThan);
+ case FLE:
+ return inst.rd.Write(m_emu, rs1.compare(rs2) !=
+ APFloat::cmpGreaterThan);
+ default:
+ llvm_unreachable("Invalid F_CMP");
}
- return inst.rd.Write(m_emu, rs1.compare(rs2) !=
- APFloat::cmpGreaterThan);
})
.value_or(false);
}
- bool operator()(FCLASS_S inst) {
- return transformOptional(inst.rs1.ReadAPFloat(m_emu, false),
+
+ bool operator()(FEQ_S inst) { return F_Compare(inst, false, FEQ); }
+ bool operator()(FLT_S inst) { return F_Compare(inst, false, FLT); }
+ bool operator()(FLE_S inst) { return F_Compare(inst, false, FLE); }
+ template <typename T> bool FCLASS(T inst, bool isDouble) {
+ return transformOptional(inst.rs1.ReadAPFloat(m_emu, isDouble),
[&](auto &&rs1) {
uint64_t result = 0;
if (rs1.isInfinity() && rs1.isNegative())
@@ -1480,63 +1443,134 @@ class Executor {
})
.value_or(false);
}
- bool operator()(FCVT_S_W inst) {
- return transformOptional(inst.rs1.ReadI32(m_emu),
+ bool operator()(FCLASS_S inst) { return FCLASS(inst, false); }
+ template <typename T, typename E>
+ bool FCVT_f2i(T inst, Optional<E> (Rs::*f)(EmulateInstructionRISCV &emu),
+ const fltSemantics &semantics) {
+ return transformOptional(((&inst.rs1)->*f)(m_emu),
[&](auto &&rs1) {
- APFloat apf(APFloat::IEEEsingle(), rs1);
+ APFloat apf(semantics, rs1);
return inst.rd.WriteAPFloat(m_emu, apf);
})
.value_or(false);
}
+ bool operator()(FCVT_S_W inst) {
+ return FCVT_f2i(inst, &Rs::ReadI32, APFloat::IEEEsingle());
+ }
bool operator()(FCVT_S_WU inst) {
- return transformOptional(inst.rs1.ReadU32(m_emu),
- [&](auto &&rs1) {
- APFloat apf(APFloat::IEEEsingle(), rs1);
- return inst.rd.WriteAPFloat(m_emu, apf);
- })
- .value_or(false);
+ return FCVT_f2i(inst, &Rs::ReadU32, APFloat::IEEEsingle());
}
- bool operator()(FMV_W_X inst) {
+ template <typename T, typename E>
+ bool FMV_i2f(T inst, unsigned int numBits, E (APInt::*f)() const) {
return transformOptional(inst.rs1.Read(m_emu),
[&](auto &&rs1) {
- APInt apInt(32, NanUnBoxing(rs1));
- APFloat apf(apInt.bitsToFloat());
+ APInt apInt(numBits, rs1);
+ if (numBits == 32) // a.k.a. float
+ apInt = APInt(numBits, NanUnBoxing(rs1));
+ APFloat apf((&apInt->*f)());
return inst.rd.WriteAPFloat(m_emu, apf);
})
.value_or(false);
}
- bool operator()(FCVT_L_S inst) {
- return transformOptional(inst.rs1.ReadAPFloat(m_emu, false),
+ bool operator()(FMV_W_X inst) {
+ return FMV_i2f(inst, 32, &APInt::bitsToFloat);
+ }
+ template <typename I, typename E, typename T>
+ bool FCVT_i2f(I inst, bool isDouble, T (APFloat::*f)() const) {
+ return transformOptional(inst.rs1.ReadAPFloat(m_emu, isDouble),
[&](auto &&rs1) {
- int64_t res = rs1.convertToFloat();
+ E res = E((&rs1->*f)());
return inst.rd.Write(m_emu, uint64_t(res));
})
.value_or(false);
}
+ bool operator()(FCVT_L_S inst) {
+ return FCVT_i2f<FCVT_L_S, int64_t, float>(inst, false,
+ &APFloat::convertToFloat);
+ }
bool operator()(FCVT_LU_S inst) {
- return transformOptional(inst.rs1.ReadAPFloat(m_emu, false),
- [&](auto &&rs1) {
- uint64_t res = rs1.convertToFloat();
- return inst.rd.Write(m_emu, res);
- })
- .value_or(false);
+ return FCVT_i2f<FCVT_LU_S, uint64_t, float>(inst, false,
+ &APFloat::convertToFloat);
}
bool operator()(FCVT_S_L inst) {
- return transformOptional(inst.rs1.ReadI64(m_emu),
+ return FCVT_f2i(inst, &Rs::ReadI64, APFloat::IEEEsingle());
+ }
+ bool operator()(FCVT_S_LU inst) {
+ return FCVT_f2i(inst, &Rs::Read, APFloat::IEEEsingle());
+ }
+ bool operator()(FLD inst) { return F_Load(inst, &APFloat::IEEEdouble, 64); }
+ bool operator()(FSD inst) { return F_Store(inst, true); }
+ bool operator()(FMADD_D inst) { return FMA(inst, true, 1.0f, 1.0f); }
+ bool operator()(FMSUB_D inst) { return FMA(inst, true, 1.0f, -1.0f); }
+ bool operator()(FNMSUB_D inst) { return FMA(inst, true, -1.0f, 1.0f); }
+ bool operator()(FNMADD_D inst) { return FMA(inst, true, -1.0f, -1.0f); }
+ bool operator()(FADD_D inst) { return F_Op(inst, true, &APFloat::add); }
+ bool operator()(FSUB_D inst) { return F_Op(inst, true, &APFloat::subtract); }
+ bool operator()(FMUL_D inst) { return F_Op(inst, true, &APFloat::multiply); }
+ bool operator()(FDIV_D inst) { return F_Op(inst, true, &APFloat::divide); }
+ bool operator()(FSQRT_D inst) {
+ // TODO: APFloat doesn't have a sqrt function.
+ return false;
+ }
+ bool operator()(FSGNJ_D inst) { return F_SignInj(inst, true, false); }
+ bool operator()(FSGNJN_D inst) { return F_SignInj(inst, true, true); }
+ bool operator()(FSGNJX_D inst) { return F_SignInjXor(inst, true); }
+ bool operator()(FMIN_D inst) { return F_MAX_MIN(inst, true, minnum); }
+ bool operator()(FMAX_D inst) { return F_MAX_MIN(inst, true, maxnum); }
+ bool operator()(FCVT_S_D inst) {
+ return transformOptional(inst.rs1.ReadAPFloat(m_emu, true),
[&](auto &&rs1) {
- APFloat apf(APFloat::IEEEsingle(), rs1);
+ double d = rs1.convertToDouble();
+ APFloat apf((float(d)));
return inst.rd.WriteAPFloat(m_emu, apf);
})
.value_or(false);
}
- bool operator()(FCVT_S_LU inst) {
- return transformOptional(inst.rs1.Read(m_emu),
+ bool operator()(FCVT_D_S inst) {
+ return transformOptional(inst.rs1.ReadAPFloat(m_emu, false),
[&](auto &&rs1) {
- APFloat apf(APFloat::IEEEsingle(), rs1);
+ float f = rs1.convertToFloat();
+ APFloat apf((double(f)));
return inst.rd.WriteAPFloat(m_emu, apf);
})
.value_or(false);
}
+ bool operator()(FEQ_D inst) { return F_Compare(inst, true, FEQ); }
+ bool operator()(FLT_D inst) { return F_Compare(inst, true, FLT); }
+ bool operator()(FLE_D inst) { return F_Compare(inst, true, FLE); }
+ bool operator()(FCLASS_D inst) { return FCLASS(inst, true); }
+ bool operator()(FCVT_W_D inst) {
+ return FCVT_i2f<FCVT_W_D, int32_t, double>(inst, true,
+ &APFloat::convertToDouble);
+ }
+ bool operator()(FCVT_WU_D inst) {
+ return FCVT_i2f<FCVT_WU_D, uint32_t, double>(inst, true,
+ &APFloat::convertToDouble);
+ }
+ bool operator()(FCVT_D_W inst) {
+ return FCVT_f2i(inst, &Rs::ReadI32, APFloat::IEEEdouble());
+ }
+ bool operator()(FCVT_D_WU inst) {
+ return FCVT_f2i(inst, &Rs::ReadU32, APFloat::IEEEdouble());
+ }
+ bool operator()(FCVT_L_D inst) {
+ return FCVT_i2f<FCVT_L_D, int64_t, double>(inst, true,
+ &APFloat::convertToDouble);
+ }
+ bool operator()(FCVT_LU_D inst) {
+ return FCVT_i2f<FCVT_LU_D, uint64_t, double>(inst, true,
+ &APFloat::convertToDouble);
+ }
+ bool operator()(FMV_X_D inst) { return FMV_f2i(inst, true); }
+ bool operator()(FCVT_D_L inst) {
+ return FCVT_f2i(inst, &Rs::ReadI64, APFloat::IEEEdouble());
+ }
+ bool operator()(FCVT_D_LU inst) {
+ return FCVT_f2i(inst, &Rs::Read, APFloat::IEEEdouble());
+ }
+ bool operator()(FMV_D_X inst) {
+ return FMV_i2f(inst, 64, &APInt::bitsToDouble);
+ }
bool operator()(INVALID inst) { return false; }
bool operator()(RESERVED inst) { return false; }
bool operator()(EBREAK inst) { return false; }
diff --git a/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h b/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
index 0a4b0b6c65a6a..8fc51d1d9a717 100644
--- a/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
+++ b/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
@@ -216,6 +216,42 @@ I_TYPE_INST(FCVT_LU_S);
I_TYPE_INST(FCVT_S_L);
I_TYPE_INST(FCVT_S_LU);
+// RV32D inst (Extension for Double-Precision Floating-Point)
+I_TYPE_INST(FLD);
+S_TYPE_INST(FSD);
+R4_TYPE_INST(FMADD_D);
+R4_TYPE_INST(FMSUB_D);
+R4_TYPE_INST(FNMSUB_D);
+R4_TYPE_INST(FNMADD_D);
+R_TYPE_INST(FADD_D);
+R_TYPE_INST(FSUB_D);
+R_TYPE_INST(FMUL_D);
+R_TYPE_INST(FDIV_D);
+I_TYPE_INST(FSQRT_D);
+R_TYPE_INST(FSGNJ_D);
+R_TYPE_INST(FSGNJN_D);
+R_TYPE_INST(FSGNJX_D);
+R_TYPE_INST(FMIN_D);
+R_TYPE_INST(FMAX_D);
+I_TYPE_INST(FCVT_S_D);
+I_TYPE_INST(FCVT_D_S);
+R_TYPE_INST(FEQ_D);
+R_TYPE_INST(FLT_D);
+R_TYPE_INST(FLE_D);
+I_TYPE_INST(FCLASS_D);
+I_TYPE_INST(FCVT_W_D);
+I_TYPE_INST(FCVT_WU_D);
+I_TYPE_INST(FCVT_D_W);
+I_TYPE_INST(FCVT_D_WU);
+
+// RV64D inst (Extension for Double-Precision Floating-Point)
+I_TYPE_INST(FCVT_L_D);
+I_TYPE_INST(FCVT_LU_D);
+I_TYPE_INST(FMV_X_D);
+I_TYPE_INST(FCVT_D_L);
+I_TYPE_INST(FCVT_D_LU);
+I_TYPE_INST(FMV_D_X);
+
/// Invalid and reserved instructions, the `inst` fields are used for debugging.
INVALID_INST(INVALID);
INVALID_INST(RESERVED);
@@ -234,8 +270,12 @@ using RISCVInst = std::variant<
AMOMAXU_D, FLW, FSW, FMADD_S, FMSUB_S, FNMADD_S, FNMSUB_S, FADD_S, FSUB_S,
FMUL_S, FDIV_S, FSQRT_S, FSGNJ_S, FSGNJN_S, FSGNJX_S, FMIN_S, FMAX_S,
FCVT_W_S, FCVT_WU_S, FMV_X_W, FEQ_S, FLT_S, FLE_S, FCLASS_S, FCVT_S_W,
- FCVT_S_WU, FMV_W_X, FCVT_L_S, FCVT_LU_S, FCVT_S_L, FCVT_S_LU, INVALID,
- EBREAK, RESERVED, HINT, NOP>;
+ FCVT_S_WU, FMV_W_X, FCVT_L_S, FCVT_LU_S, FCVT_S_L, FCVT_S_LU, FLD, FSD,
+ FMADD_D, FMSUB_D, FNMSUB_D, FNMADD_D, FADD_D, FSUB_D, FMUL_D, FDIV_D,
+ FSQRT_D, FSGNJ_D, FSGNJN_D, FSGNJX_D, FMIN_D, FMAX_D, FCVT_S_D, FCVT_D_S,
+ FEQ_D, FLT_D, FLE_D, FCLASS_D, FCVT_W_D, FCVT_WU_D, FCVT_D_W, FCVT_D_WU,
+ FCVT_L_D, FCVT_LU_D, FMV_X_D, FCVT_D_L, FCVT_D_LU, FMV_D_X, INVALID, EBREAK,
+ RESERVED, HINT, NOP>;
constexpr uint8_t RV32 = 1;
constexpr uint8_t RV64 = 2;
diff --git a/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp b/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
index 72403bccfd0e9..f00d581275a74 100644
--- a/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
+++ b/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
@@ -487,19 +487,25 @@ TEST_F(RISCVEmulatorTester, TestAMOMAXU) {
TestAtomic<uint64_t>(this, 0xE0F7382F, 0x1, 0x2, 0x1, 0x2);
}
-struct FloatCalInst {
+template <typename T> struct F_D_CalInst {
uint32_t inst;
std::string name;
- float rs1_val;
- float rs2_val;
- float rd_val;
+ T rs1_val;
+ T rs2_val;
+ T rd_val;
};
-static void TestFloatCalInst(RISCVEmulatorTester *tester, DecodeResult inst,
- float rs1_val, float rs2_val, float rd_exp) {
- std::vector<std::string> FloatCMP = {"FEQ_S", "FLT_S", "FLE_S"};
- std::vector<std::string> FloatCal3 = {"FMADD_S", "FMSUB_S", "FNMSUB_S",
- "FNMADD_S"};
+using FloatCalInst = F_D_CalInst<float>;
+using DoubleCalInst = F_D_CalInst<double>;
+
+template <typename T>
+static void TestF_D_CalInst(RISCVEmulatorTester *tester, DecodeResult inst,
+ T rs1_val, T rs2_val, T rd_exp) {
+ std::vector<std::string> CMPs = {"FEQ_S", "FLT_S", "FLE_S",
+ "FEQ_D", "FLT_D", "FLE_D"};
+ std::vector<std::string> FMAs = {"FMADD_S", "FMSUB_S", "FNMSUB_S",
+ "FNMADD_S", "FMADD_D", "FMSUB_D",
+ "FNMSUB_D", "FNMADD_D"};
uint32_t rd = DecodeRD(inst.inst);
uint32_t rs1 = DecodeRS1(inst.inst);
@@ -507,29 +513,42 @@ static void TestFloatCalInst(RISCVEmulatorTester *tester, DecodeResult inst,
APFloat ap_rs1_val(rs1_val);
APFloat ap_rs2_val(rs2_val);
- APFloat ap_rs3_val(0.5f);
+ APFloat ap_rs3_val(0.0f);
+ static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
+ "T should be float or double");
+ if constexpr (std::is_same_v<T, float>)
+ ap_rs3_val = APFloat(0.5f);
+ if constexpr (std::is_same_v<T, double>)
+ ap_rs3_val = APFloat(0.5);
if (rs1)
tester->fpr.fpr[rs1] = ap_rs1_val.bitcastToAPInt().getZExtValue();
if (rs2)
tester->fpr.fpr[rs2] = ap_rs2_val.bitcastToAPInt().getZExtValue();
- for (auto i : FloatCal3) {
+ for (auto i : FMAs) {
if (inst.pattern.name == i) {
uint32_t rs3 = DecodeRS3(inst.inst);
tester->fpr.fpr[rs3] = ap_rs3_val.bitcastToAPInt().getZExtValue();
}
}
ASSERT_TRUE(tester->Execute(inst, false));
- for (auto i : FloatCMP) {
+ for (auto i : CMPs) {
if (inst.pattern.name == i) {
ASSERT_EQ(tester->gpr.gpr[rd], rd_exp);
return;
}
}
- APInt apInt(32, tester->fpr.fpr[rd]);
- APFloat rd_val(apInt.bitsToFloat());
- ASSERT_EQ(rd_val.convertToFloat(), rd_exp);
+ if constexpr (std::is_same_v<T, float>) {
+ APInt apInt(32, tester->fpr.fpr[rd]);
+ APFloat rd_val(apInt.bitsToFloat());
+ ASSERT_EQ(rd_val.convertToFloat(), rd_exp);
+ }
+ if constexpr (std::is_same_v<T, double>) {
+ APInt apInt(64, tester->fpr.fpr[rd]);
+ APFloat rd_val(apInt.bitsToDouble());
+ ASSERT_EQ(rd_val.convertToDouble(), rd_exp);
+ }
}
TEST_F(RISCVEmulatorTester, TestFloatInst) {
@@ -548,14 +567,14 @@ TEST_F(RISCVEmulatorTester, TestFloatInst) {
{0x28219253, "FMAX_S", -0.5f, -0.6f, -0.5f},
{0x28219253, "FMAX_S", 0.5f, 0.6f, 0.6f},
{0x28219253, "FMAX_S", 0.5f, -0.6f, 0.5f},
- {0xA221A253, "FEQ_S", 0.5f, 0.5f, 1},
- {0xA221A253, "FEQ_S", 0.5f, -0.5f, 0},
- {0xA221A253, "FEQ_S", -0.5f, 0.5f, 0},
- {0xA221A253, "FEQ_S", 0.4f, 0.5f, 0},
- {0xA2219253, "FLT_S", 0.4f, 0.5f, 1},
- {0xA2219253, "FLT_S", 0.5f, 0.5f, 0},
- {0xA2218253, "FLE_S", 0.4f, 0.5f, 1},
- {0xA2218253, "FLE_S", 0.5f, 0.5f, 1},
+ {0xA021A253, "FEQ_S", 0.5f, 0.5f, 1},
+ {0xA021A253, "FEQ_S", 0.5f, -0.5f, 0},
+ {0xA021A253, "FEQ_S", -0.5f, 0.5f, 0},
+ {0xA021A253, "FEQ_S", 0.4f, 0.5f, 0},
+ {0xA0219253, "FLT_S", 0.4f, 0.5f, 1},
+ {0xA0219253, "FLT_S", 0.5f, 0.5f, 0},
+ {0xA0218253, "FLE_S", 0.4f, 0.5f, 1},
+ {0xA0218253, "FLE_S", 0.5f, 0.5f, 1},
{0x4021F243, "FMADD_S", 0.5f, 0.5f, 0.75f},
{0x4021F247, "FMSUB_S", 0.5f, 0.5f, -0.25f},
{0x4021F24B, "FNMSUB_S", 0.5f, 0.5f, 0.25f},
@@ -566,60 +585,132 @@ TEST_F(RISCVEmulatorTester, TestFloatInst) {
ASSERT_TRUE(decode.has_value());
std::string name = decode->pattern.name;
ASSERT_EQ(name, i.name);
- TestFloatCalInst(this, decode.value(), i.rs1_val, i.rs2_val, i.rd_val);
+ TestF_D_CalInst(this, decode.value(), i.rs1_val, i.rs2_val, i.rd_val);
}
}
-static void TestFCVT(RISCVEmulatorTester *tester, DecodeResult inst) {
- std::vector<std::string> FloatToInt = {"FCVT_W_S", "FCVT_WU_S"};
- std::vector<std::string> IntToFloat = {"FCVT_S_W", "FCVT_S_WU"};
-
- uint32_t rd = DecodeRD(inst.inst);
- uint32_t rs1 = DecodeRS1(inst.inst);
-
- for (auto i : FloatToInt) {
- if (inst.pattern.name == i) {
- APFloat apf_rs1_val(12.0f);
- tester->fpr.fpr[rs1] = apf_rs1_val.bitcastToAPInt().getZExtValue();
- ASSERT_TRUE(tester->Execute(inst, false));
- ASSERT_EQ(tester->gpr.gpr[rd], uint64_t(12));
- return;
- }
+TEST_F(RISCVEmulatorTester, TestDoubleInst) {
+ std::vector<DoubleCalInst> tests = {
+ {0x221F253, "FADD_D", 0.5, 0.5, 1.0},
+ {0xA21F253, "FSUB_D", 1.0, 0.5, 0.5},
+ {0x1221F253, "FMUL_D", 0.5, 0.5, 0.25},
+ {0x1A21F253, "FDIV_D", 0.1, 0.1, 1.0},
+ {0x22218253, "FSGNJ_D", 0.5, 0.2, 0.5},
+ {0x22219253, "FSGNJN_D", 0.5, -1.0, 0.5},
+ {0x2221A253, "FSGNJX_D", -0.5, -0.5, 0.5},
+ {0x2221A253, "FSGNJX_D", -0.5, 0.5, -0.5},
+ {0x2A218253, "FMIN_D", -0.5, 0.5, -0.5},
+ {0x2A218253, "FMIN_D", -0.5, -0.6, -0.6},
+ {0x2A218253, "FMIN_D", 0.5, 0.6, 0.5},
+ {0x2A219253, "FMAX_D", -0.5, -0.6, -0.5},
+ {0x2A219253, "FMAX_D", 0.5, 0.6, 0.6},
+ {0x2A219253, "FMAX_D", 0.5, -0.6, 0.5},
+ {0xA221A253, "FEQ_D", 0.5, 0.5, 1},
+ {0xA221A253, "FEQ_D", 0.5, -0.5, 0},
+ {0xA221A253, "FEQ_D", -0.5, 0.5, 0},
+ {0xA221A253, "FEQ_D", 0.4, 0.5, 0},
+ {0xA2219253, "FLT_D", 0.4, 0.5, 1},
+ {0xA2219253, "FLT_D", 0.5, 0.5, 0},
+ {0xA2218253, "FLE_D", 0.4, 0.5, 1},
+ {0xA2218253, "FLE_D", 0.5, 0.5, 1},
+ {0x4221F243, "FMADD_D", 0.5, 0.5, 0.75},
+ {0x4221F247, "FMSUB_D", 0.5, 0.5, -0.25},
+ {0x4221F24B, "FNMSUB_D", 0.5, 0.5, 0.25},
+ {0x4221F24F, "FNMADD_D", 0.5, 0.5, -0.75},
+ };
+ for (auto i : tests) {
+ auto decode = this->Decode(i.inst);
+ ASSERT_TRUE(decode.has_value());
+ std::string name = decode->pattern.name;
+ ASSERT_EQ(name, i.name);
+ TestF_D_CalInst(this, decode.value(), i.rs1_val, i.rs2_val, i.rd_val);
}
+}
- for (auto i : IntToFloat) {
- if (inst.pattern.name == i) {
- tester->gpr.gpr[rs1] = 12;
- ASSERT_TRUE(tester->Execute(inst, false));
- APInt apInt(32, tester->fpr.fpr[rd]);
- APFloat rd_val(apInt.bitsToFloat());
- ASSERT_EQ(rd_val.convertToFloat(), 12.0f);
- return;
- }
- }
+template <typename T>
+static void TestInverse(RISCVEmulatorTester *tester, uint32_t f_reg,
+ uint32_t x_reg, DecodeResult f2i, DecodeResult i2f,
+ APFloat apf_val) {
+ uint64_t exp_x;
+ if constexpr (std::is_same_v<T, float>)
+ exp_x = uint64_t(apf_val.convertToFloat());
+ if constexpr (std::is_same_v<T, double>)
+ exp_x = uint64_t(apf_val.convertToDouble());
+ T exp_f = T(exp_x);
+
+ // convert float/double to int.
+ tester->fpr.fpr[f_reg] = apf_val.bitcastToAPInt().getZExtValue();
+ ASSERT_TRUE(tester->Execute(f2i, false));
+ ASSERT_EQ(tester->gpr.gpr[x_reg], exp_x);
+
+ // then convert int to float/double back.
+ ASSERT_TRUE(tester->Execute(i2f, false));
+ ASSERT_EQ(tester->fpr.fpr[f_reg],
+ APFloat(exp_f).bitcastToAPInt().getZExtValue());
}
struct FCVTInst {
- uint32_t inst;
- std::string name;
+ uint32_t f2i;
+ uint32_t i2f;
+ APFloat data;
+ bool isDouble;
};
-TEST_F(RISCVEmulatorTester, TestFCVTInst) {
- std::vector<FCVTInst> tests = {
- {0xC001F253, "FCVT_W_S"}, {0xC011F253, "FCVT_WU_S"},
- {0xD001F253, "FCVT_S_W"}, {0xD011F253, "FCVT_S_WU"},
- {0xC021F253, "FCVT_L_S"}, {0xC031F253, "FCVT_LU_S"},
- {0xD021F253, "FCVT_S_L"}, {0xD031F253, "FCVT_S_LU"},
+TEST_F(RISCVEmulatorTester, TestFCVT) {
+ std::vector<FCVTInst> tests{
+ // FCVT_W_S and FCVT_S_W
+ {0xC000F0D3, 0xD000F0D3, APFloat(12.0f), false},
+ // FCVT_WU_S and FCVT_S_WU
+ {0xC010F0D3, 0xD010F0D3, APFloat(12.0f), false},
+ // FCVT_L_S and FCVT_S_L
+ {0xC020F0D3, 0xD020F0D3, APFloat(12.0f), false},
+ // FCVT_LU_S and FCVT_S_LU
+ {0xC030F0D3, 0xD030F0D3, APFloat(12.0f), false},
+ // FCVT_W_D and FCVT_D_W
+ {0xC200F0D3, 0xD200F0D3, APFloat(12.0), true},
+ // FCVT_WU_D and FCVT_D_WU
+ {0xC210F0D3, 0xD210F0D3, APFloat(12.0), true},
+ // FCVT_L_D and FCVT_D_L
+ {0xC220F0D3, 0xD220F0D3, APFloat(12.0), true},
+ // FCVT_LU_D and FCVT_D_LU
+ {0xC230F0D3, 0xD230F0D3, APFloat(12.0), true},
};
for (auto i : tests) {
- auto decode = this->Decode(i.inst);
- ASSERT_TRUE(decode.has_value());
- std::string name = decode->pattern.name;
- ASSERT_EQ(name, i.name);
- TestFCVT(this, decode.value());
+ auto f2i = this->Decode(i.f2i);
+ auto i2f = this->Decode(i.i2f);
+ ASSERT_TRUE(f2i.has_value());
+ ASSERT_TRUE(i2f.has_value());
+ uint32_t f_reg = DecodeRS1((*f2i).inst);
+ uint32_t x_reg = DecodeRS1((*i2f).inst);
+ if (i.isDouble)
+ TestInverse<double>(this, f_reg, x_reg, *f2i, *i2f, i.data);
+ else
+ TestInverse<float>(this, f_reg, x_reg, *f2i, *i2f, i.data);
}
}
+TEST_F(RISCVEmulatorTester, TestFDInverse) {
+ // FCVT_S_D
+ auto d2f = this->Decode(0x4010F0D3);
+ // FCVT_S_D
+ auto f2d = this->Decode(0x4200F0D3);
+ ASSERT_TRUE(d2f.has_value());
+ ASSERT_TRUE(f2d.has_value());
+ auto data = APFloat(12.0);
+ uint32_t reg = DecodeRS1((*d2f).inst);
+ float exp_f = 12.0f;
+ double exp_d = 12.0;
+
+ // double to float
+ this->fpr.fpr[reg] = data.bitcastToAPInt().getZExtValue();
+ ASSERT_TRUE(this->Execute(*d2f, false));
+ ASSERT_EQ(this->fpr.fpr[reg], APFloat(exp_f).bitcastToAPInt().getZExtValue());
+
+ // float to double
+ ASSERT_TRUE(this->Execute(*f2d, false));
+ ASSERT_EQ(this->fpr.fpr[reg], APFloat(exp_d).bitcastToAPInt().getZExtValue());
+}
+
TEST_F(RISCVEmulatorTester, TestFloatLSInst) {
uint32_t FLWInst = 0x1A207; // imm = 0
uint32_t FSWInst = 0x21A827; // imm = 16
@@ -644,30 +735,82 @@ TEST_F(RISCVEmulatorTester, TestFloatLSInst) {
ASSERT_EQ(*(uint32_t *)(this->memory + 16), bits);
}
+TEST_F(RISCVEmulatorTester, TestDoubleLSInst) {
+ uint32_t FLDInst = 0x1B207; // imm = 0
+ uint32_t FSDInst = 0x21B827; // imm = 16
+
+ APFloat apf(12.0);
+ uint64_t bits = apf.bitcastToAPInt().getZExtValue();
+
+ *(uint64_t *)this->memory = bits;
+ auto decode = this->Decode(FLDInst);
+ ASSERT_TRUE(decode.has_value());
+ std::string name = decode->pattern.name;
+ ASSERT_EQ(name, "FLD");
+ ASSERT_TRUE(this->Execute(decode.value(), false));
+ ASSERT_EQ(this->fpr.fpr[DecodeRD(FLDInst)], bits);
+
+ this->fpr.fpr[DecodeRS2(FSDInst)] = bits;
+ decode = this->Decode(FSDInst);
+ ASSERT_TRUE(decode.has_value());
+ name = decode->pattern.name;
+ ASSERT_EQ(name, "FSD");
+ ASSERT_TRUE(this->Execute(decode.value(), false));
+ ASSERT_EQ(*(uint64_t *)(this->memory + 16), bits);
+}
+
TEST_F(RISCVEmulatorTester, TestFMV_X_WInst) {
auto FMV_X_WInst = 0xE0018253;
APFloat apf(12.0f);
- auto bits = NanBoxing(apf.bitcastToAPInt().getZExtValue());
- this->fpr.fpr[DecodeRS1(FMV_X_WInst)] = bits;
+ auto exp_bits = apf.bitcastToAPInt().getZExtValue();
+ this->fpr.fpr[DecodeRS1(FMV_X_WInst)] = NanBoxing(exp_bits);
auto decode = this->Decode(FMV_X_WInst);
ASSERT_TRUE(decode.has_value());
std::string name = decode->pattern.name;
ASSERT_EQ(name, "FMV_X_W");
ASSERT_TRUE(this->Execute(decode.value(), false));
- ASSERT_EQ(this->gpr.gpr[DecodeRD(FMV_X_WInst)], bits);
+ ASSERT_EQ(this->gpr.gpr[DecodeRD(FMV_X_WInst)], exp_bits);
+}
+
+TEST_F(RISCVEmulatorTester, TestFMV_X_DInst) {
+ auto FMV_X_DInst = 0xE2018253;
+
+ APFloat apf(12.0);
+ auto exp_bits = apf.bitcastToAPInt().getZExtValue();
+ this->fpr.fpr[DecodeRS1(FMV_X_DInst)] = exp_bits;
+ auto decode = this->Decode(FMV_X_DInst);
+ ASSERT_TRUE(decode.has_value());
+ std::string name = decode->pattern.name;
+ ASSERT_EQ(name, "FMV_X_D");
+ ASSERT_TRUE(this->Execute(decode.value(), false));
+ ASSERT_EQ(this->gpr.gpr[DecodeRD(FMV_X_DInst)], exp_bits);
}
TEST_F(RISCVEmulatorTester, TestFMV_W_XInst) {
auto FMV_W_XInst = 0xF0018253;
APFloat apf(12.0f);
- uint64_t bits = NanUnBoxing(apf.bitcastToAPInt().getZExtValue());
- this->gpr.gpr[DecodeRS1(FMV_W_XInst)] = bits;
+ uint64_t exp_bits = NanUnBoxing(apf.bitcastToAPInt().getZExtValue());
+ this->gpr.gpr[DecodeRS1(FMV_W_XInst)] = exp_bits;
auto decode = this->Decode(FMV_W_XInst);
ASSERT_TRUE(decode.has_value());
std::string name = decode->pattern.name;
ASSERT_EQ(name, "FMV_W_X");
ASSERT_TRUE(this->Execute(decode.value(), false));
- ASSERT_EQ(this->fpr.fpr[DecodeRD(FMV_W_XInst)], bits);
+ ASSERT_EQ(this->fpr.fpr[DecodeRD(FMV_W_XInst)], exp_bits);
+}
+
+TEST_F(RISCVEmulatorTester, TestFMV_D_XInst) {
+ auto FMV_D_XInst = 0xF2018253;
+
+ APFloat apf(12.0);
+ uint64_t bits = apf.bitcastToAPInt().getZExtValue();
+ this->gpr.gpr[DecodeRS1(FMV_D_XInst)] = bits;
+ auto decode = this->Decode(FMV_D_XInst);
+ ASSERT_TRUE(decode.has_value());
+ std::string name = decode->pattern.name;
+ ASSERT_EQ(name, "FMV_D_X");
+ ASSERT_TRUE(this->Execute(decode.value(), false));
+ ASSERT_EQ(this->fpr.fpr[DecodeRD(FMV_D_XInst)], bits);
}
More information about the lldb-commits
mailing list