decoder: Ensure more compiler-time computation
Replace with consteval when C++20 hits
This commit is contained in:
parent
795b9bea9a
commit
6d292e3eac
7 changed files with 34 additions and 25 deletions
|
@ -26,7 +26,7 @@ template <typename V>
|
||||||
std::vector<ArmMatcher<V>> GetArmDecodeTable() {
|
std::vector<ArmMatcher<V>> GetArmDecodeTable() {
|
||||||
std::vector<ArmMatcher<V>> table = {
|
std::vector<ArmMatcher<V>> table = {
|
||||||
|
|
||||||
#define INST(fn, name, bitstring) Decoder::detail::detail<ArmMatcher<V>>::GetMatcher(&V::fn, name, bitstring),
|
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
|
||||||
#include "arm.inc"
|
#include "arm.inc"
|
||||||
#undef INST
|
#undef INST
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ template <typename V>
|
||||||
std::vector<ASIMDMatcher<V>> GetASIMDDecodeTable() {
|
std::vector<ASIMDMatcher<V>> GetASIMDDecodeTable() {
|
||||||
std::vector<ASIMDMatcher<V>> table = {
|
std::vector<ASIMDMatcher<V>> table = {
|
||||||
|
|
||||||
#define INST(fn, name, bitstring) Decoder::detail::detail<ASIMDMatcher<V>>::GetMatcher(&V::fn, name, bitstring),
|
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(ASIMDMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
|
||||||
#include "asimd.inc"
|
#include "asimd.inc"
|
||||||
#undef INST
|
#undef INST
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ template<typename V>
|
||||||
std::optional<std::reference_wrapper<const Thumb16Matcher<V>>> DecodeThumb16(u16 instruction) {
|
std::optional<std::reference_wrapper<const Thumb16Matcher<V>>> DecodeThumb16(u16 instruction) {
|
||||||
static const std::vector<Thumb16Matcher<V>> table = {
|
static const std::vector<Thumb16Matcher<V>> table = {
|
||||||
|
|
||||||
#define INST(fn, name, bitstring) Decoder::detail::detail<Thumb16Matcher<V>>::GetMatcher(&V::fn, name, bitstring),
|
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Thumb16Matcher, fn, name, Decoder::detail::StringToArray<16>(bitstring)),
|
||||||
#include "thumb16.inc"
|
#include "thumb16.inc"
|
||||||
#undef INST
|
#undef INST
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ template<typename V>
|
||||||
std::optional<std::reference_wrapper<const Thumb32Matcher<V>>> DecodeThumb32(u32 instruction) {
|
std::optional<std::reference_wrapper<const Thumb32Matcher<V>>> DecodeThumb32(u32 instruction) {
|
||||||
static const std::vector<Thumb32Matcher<V>> table = {
|
static const std::vector<Thumb32Matcher<V>> table = {
|
||||||
|
|
||||||
#define INST(fn, name, bitstring) Decoder::detail::detail<Thumb32Matcher<V>>::GetMatcher(&V::fn, name, bitstring),
|
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Thumb32Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
|
||||||
#include "thumb32.inc"
|
#include "thumb32.inc"
|
||||||
#undef INST
|
#undef INST
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ std::optional<std::reference_wrapper<const VFPMatcher<V>>> DecodeVFP(u32 instruc
|
||||||
} tables = []{
|
} tables = []{
|
||||||
Table list = {
|
Table list = {
|
||||||
|
|
||||||
#define INST(fn, name, bitstring) Decoder::detail::detail<VFPMatcher<V>>::GetMatcher(&V::fn, name, bitstring),
|
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(VFPMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
|
||||||
#include "vfp.inc"
|
#include "vfp.inc"
|
||||||
#undef INST
|
#undef INST
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,10 @@ inline size_t ToFastLookupIndex(u32 instruction) {
|
||||||
}
|
}
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <typename Visitor>
|
template <typename V>
|
||||||
DecodeTable<Visitor> GetDecodeTable() {
|
DecodeTable<V> GetDecodeTable() {
|
||||||
std::vector<Matcher<Visitor>> list = {
|
std::vector<Matcher<V>> list = {
|
||||||
#define INST(fn, name, bitstring) Decoder::detail::detail<Matcher<Visitor>>::GetMatcher(&Visitor::fn, name, bitstring),
|
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
|
||||||
#include "a64.inc"
|
#include "a64.inc"
|
||||||
#undef INST
|
#undef INST
|
||||||
};
|
};
|
||||||
|
@ -55,7 +55,7 @@ DecodeTable<Visitor> GetDecodeTable() {
|
||||||
return comes_first.count(matcher.GetName()) > 0;
|
return comes_first.count(matcher.GetName()) > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
DecodeTable<Visitor> table{};
|
DecodeTable<V> table{};
|
||||||
for (size_t i = 0; i < table.size(); ++i) {
|
for (size_t i = 0; i < table.size(); ++i) {
|
||||||
for (auto matcher : list) {
|
for (auto matcher : list) {
|
||||||
const auto expect = detail::ToFastLookupIndex(matcher.GetExpected());
|
const auto expect = detail::ToFastLookupIndex(matcher.GetExpected());
|
||||||
|
@ -68,15 +68,15 @@ DecodeTable<Visitor> GetDecodeTable() {
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Visitor>
|
template<typename V>
|
||||||
std::optional<std::reference_wrapper<const Matcher<Visitor>>> Decode(u32 instruction) {
|
std::optional<std::reference_wrapper<const Matcher<V>>> Decode(u32 instruction) {
|
||||||
static const auto table = GetDecodeTable<Visitor>();
|
static const auto table = GetDecodeTable<V>();
|
||||||
|
|
||||||
const auto matches_instruction = [instruction](const auto& matcher) { return matcher.Matches(instruction); };
|
const auto matches_instruction = [instruction](const auto& matcher) { return matcher.Matches(instruction); };
|
||||||
|
|
||||||
const auto& subtable = table[detail::ToFastLookupIndex(instruction)];
|
const auto& subtable = table[detail::ToFastLookupIndex(instruction)];
|
||||||
auto iter = std::find_if(subtable.begin(), subtable.end(), matches_instruction);
|
auto iter = std::find_if(subtable.begin(), subtable.end(), matches_instruction);
|
||||||
return iter != subtable.end() ? std::optional<std::reference_wrapper<const Matcher<Visitor>>>(*iter) : std::nullopt;
|
return iter != subtable.end() ? std::optional<std::reference_wrapper<const Matcher<V>>>(*iter) : std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::A64
|
} // namespace Dynarmic::A64
|
||||||
|
|
|
@ -17,6 +17,15 @@
|
||||||
namespace Dynarmic::Decoder {
|
namespace Dynarmic::Decoder {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
inline constexpr std::array<char, N> StringToArray(const char (&str)[N + 1]) {
|
||||||
|
std::array<char, N> result;
|
||||||
|
for (size_t i = 0; i < N; i++) {
|
||||||
|
result[i] = str[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper functions for the decoders.
|
* Helper functions for the decoders.
|
||||||
*
|
*
|
||||||
|
@ -24,7 +33,6 @@ namespace detail {
|
||||||
*/
|
*/
|
||||||
template<class MatcherT>
|
template<class MatcherT>
|
||||||
struct detail {
|
struct detail {
|
||||||
private:
|
|
||||||
using opcode_type = typename MatcherT::opcode_type;
|
using opcode_type = typename MatcherT::opcode_type;
|
||||||
using visitor_type = typename MatcherT::visitor_type;
|
using visitor_type = typename MatcherT::visitor_type;
|
||||||
|
|
||||||
|
@ -35,7 +43,7 @@ private:
|
||||||
* A '0' in a bitstring indicates that a zero must be present at that bit position.
|
* A '0' in a bitstring indicates that a zero must be present at that bit position.
|
||||||
* A '1' in a bitstring indicates that a one must be present at that bit position.
|
* A '1' in a bitstring indicates that a one must be present at that bit position.
|
||||||
*/
|
*/
|
||||||
static constexpr auto GetMaskAndExpect(const char* const bitstring) {
|
static constexpr auto GetMaskAndExpect(std::array<char, opcode_bitsize> bitstring) {
|
||||||
const auto one = static_cast<opcode_type>(1);
|
const auto one = static_cast<opcode_type>(1);
|
||||||
opcode_type mask = 0, expect = 0;
|
opcode_type mask = 0, expect = 0;
|
||||||
for (size_t i = 0; i < opcode_bitsize; i++) {
|
for (size_t i = 0; i < opcode_bitsize; i++) {
|
||||||
|
@ -62,7 +70,7 @@ private:
|
||||||
* An argument is specified by a continuous string of the same character.
|
* An argument is specified by a continuous string of the same character.
|
||||||
*/
|
*/
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
static auto GetArgInfo(const char* const bitstring) {
|
static constexpr auto GetArgInfo(std::array<char, opcode_bitsize> bitstring) {
|
||||||
std::array<opcode_type, N> masks = {};
|
std::array<opcode_type, N> masks = {};
|
||||||
std::array<size_t, N> shifts = {};
|
std::array<size_t, N> shifts = {};
|
||||||
size_t arg_index = 0;
|
size_t arg_index = 0;
|
||||||
|
@ -85,11 +93,12 @@ private:
|
||||||
if constexpr (N > 0) {
|
if constexpr (N > 0) {
|
||||||
const size_t bit_position = opcode_bitsize - i - 1;
|
const size_t bit_position = opcode_bitsize - i - 1;
|
||||||
|
|
||||||
ASSERT(arg_index < N);
|
if (arg_index >= N) throw std::out_of_range("Unexpected field");
|
||||||
|
|
||||||
masks[arg_index] |= static_cast<opcode_type>(1) << bit_position;
|
masks[arg_index] |= static_cast<opcode_type>(1) << bit_position;
|
||||||
shifts[arg_index] = bit_position;
|
shifts[arg_index] = bit_position;
|
||||||
} else {
|
} else {
|
||||||
ASSERT_FALSE();
|
throw std::out_of_range("Unexpected field");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,23 +157,23 @@ private:
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
/**
|
||||||
* Creates a matcher that can match and parse instructions based on bitstring.
|
* Creates a matcher that can match and parse instructions based on bitstring.
|
||||||
* See also: GetMaskAndExpect and GetArgInfo for format of bitstring.
|
* See also: GetMaskAndExpect and GetArgInfo for format of bitstring.
|
||||||
*/
|
*/
|
||||||
template<typename FnT>
|
template<typename FnT, size_t args_count = mp::parameter_count_v<FnT>>
|
||||||
static auto GetMatcher(FnT fn, const char* const name, const char* const bitstring) {
|
static auto GetMatcher(FnT fn, const char* const name, std::tuple<opcode_type, opcode_type> mask_and_expect, std::tuple<std::array<opcode_type, args_count>, std::array<size_t, args_count>> masks_and_shifts) {
|
||||||
constexpr size_t args_count = mp::parameter_count_v<FnT>;
|
|
||||||
using Iota = std::make_index_sequence<args_count>;
|
using Iota = std::make_index_sequence<args_count>;
|
||||||
|
|
||||||
const auto [mask, expect] = GetMaskAndExpect(bitstring);
|
const auto [mask, expect] = mask_and_expect;
|
||||||
const auto [arg_masks, arg_shifts] = GetArgInfo<args_count>(bitstring);
|
const auto [arg_masks, arg_shifts] = masks_and_shifts;
|
||||||
const auto proxy_fn = VisitorCaller<FnT>::Make(Iota(), fn, arg_masks, arg_shifts);
|
const auto proxy_fn = VisitorCaller<FnT>::Make(Iota(), fn, arg_masks, arg_shifts);
|
||||||
|
|
||||||
return MatcherT(name, mask, expect, proxy_fn);
|
return MatcherT(name, mask, expect, proxy_fn);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define DYNARMIC_DECODER_GET_MATCHER(MatcherT, fn, name, bitstring) Decoder::detail::detail<MatcherT<V>>::GetMatcher(&V::fn, name, Decoder::detail::detail<MatcherT<V>>::GetMaskAndExpect(bitstring), Decoder::detail::detail<MatcherT<V>>::template GetArgInfo<mp::parameter_count_v<decltype(&V::fn)>>(bitstring))
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace Dynarmic::Decoder
|
} // namespace Dynarmic::Decoder
|
||||||
|
|
Loading…
Reference in a new issue