From 6d292e3eac44478ae36d766e1e8f745ede38410b Mon Sep 17 00:00:00 2001 From: MerryMage Date: Mon, 3 May 2021 13:00:40 +0100 Subject: [PATCH] decoder: Ensure more compiler-time computation Replace with consteval when C++20 hits --- src/frontend/A32/decoder/arm.h | 2 +- src/frontend/A32/decoder/asimd.h | 2 +- src/frontend/A32/decoder/thumb16.h | 2 +- src/frontend/A32/decoder/thumb32.h | 2 +- src/frontend/A32/decoder/vfp.h | 2 +- src/frontend/A64/decoder/a64.h | 18 ++++++++-------- src/frontend/decoder/decoder_detail.h | 31 +++++++++++++++++---------- 7 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/frontend/A32/decoder/arm.h b/src/frontend/A32/decoder/arm.h index 184ae30a..442fe67d 100644 --- a/src/frontend/A32/decoder/arm.h +++ b/src/frontend/A32/decoder/arm.h @@ -26,7 +26,7 @@ template std::vector> GetArmDecodeTable() { std::vector> table = { -#define INST(fn, name, bitstring) Decoder::detail::detail>::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" #undef INST diff --git a/src/frontend/A32/decoder/asimd.h b/src/frontend/A32/decoder/asimd.h index 5316430a..07fb0f71 100644 --- a/src/frontend/A32/decoder/asimd.h +++ b/src/frontend/A32/decoder/asimd.h @@ -25,7 +25,7 @@ template std::vector> GetASIMDDecodeTable() { std::vector> table = { -#define INST(fn, name, bitstring) Decoder::detail::detail>::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" #undef INST diff --git a/src/frontend/A32/decoder/thumb16.h b/src/frontend/A32/decoder/thumb16.h index d2dfb863..b1ce7446 100644 --- a/src/frontend/A32/decoder/thumb16.h +++ b/src/frontend/A32/decoder/thumb16.h @@ -23,7 +23,7 @@ template std::optional>> DecodeThumb16(u16 instruction) { static const std::vector> table = { -#define INST(fn, name, bitstring) Decoder::detail::detail>::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" #undef INST diff --git a/src/frontend/A32/decoder/thumb32.h b/src/frontend/A32/decoder/thumb32.h index a0dd4333..dc370a31 100644 --- a/src/frontend/A32/decoder/thumb32.h +++ b/src/frontend/A32/decoder/thumb32.h @@ -22,7 +22,7 @@ template std::optional>> DecodeThumb32(u32 instruction) { static const std::vector> table = { -#define INST(fn, name, bitstring) Decoder::detail::detail>::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" #undef INST diff --git a/src/frontend/A32/decoder/vfp.h b/src/frontend/A32/decoder/vfp.h index 2b78c66e..1abfc67a 100644 --- a/src/frontend/A32/decoder/vfp.h +++ b/src/frontend/A32/decoder/vfp.h @@ -30,7 +30,7 @@ std::optional>> DecodeVFP(u32 instruc } tables = []{ Table list = { -#define INST(fn, name, bitstring) Decoder::detail::detail>::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" #undef INST diff --git a/src/frontend/A64/decoder/a64.h b/src/frontend/A64/decoder/a64.h index 0379c32c..d3dc0cf6 100644 --- a/src/frontend/A64/decoder/a64.h +++ b/src/frontend/A64/decoder/a64.h @@ -31,10 +31,10 @@ inline size_t ToFastLookupIndex(u32 instruction) { } } // namespace detail -template -DecodeTable GetDecodeTable() { - std::vector> list = { -#define INST(fn, name, bitstring) Decoder::detail::detail>::GetMatcher(&Visitor::fn, name, bitstring), +template +DecodeTable GetDecodeTable() { + std::vector> list = { +#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)), #include "a64.inc" #undef INST }; @@ -55,7 +55,7 @@ DecodeTable GetDecodeTable() { return comes_first.count(matcher.GetName()) > 0; }); - DecodeTable table{}; + DecodeTable table{}; for (size_t i = 0; i < table.size(); ++i) { for (auto matcher : list) { const auto expect = detail::ToFastLookupIndex(matcher.GetExpected()); @@ -68,15 +68,15 @@ DecodeTable GetDecodeTable() { return table; } -template -std::optional>> Decode(u32 instruction) { - static const auto table = GetDecodeTable(); +template +std::optional>> Decode(u32 instruction) { + static const auto table = GetDecodeTable(); const auto matches_instruction = [instruction](const auto& matcher) { return matcher.Matches(instruction); }; const auto& subtable = table[detail::ToFastLookupIndex(instruction)]; auto iter = std::find_if(subtable.begin(), subtable.end(), matches_instruction); - return iter != subtable.end() ? std::optional>>(*iter) : std::nullopt; + return iter != subtable.end() ? std::optional>>(*iter) : std::nullopt; } } // namespace Dynarmic::A64 diff --git a/src/frontend/decoder/decoder_detail.h b/src/frontend/decoder/decoder_detail.h index 4f41929e..124b1f57 100644 --- a/src/frontend/decoder/decoder_detail.h +++ b/src/frontend/decoder/decoder_detail.h @@ -17,6 +17,15 @@ namespace Dynarmic::Decoder { namespace detail { +template +inline constexpr std::array StringToArray(const char (&str)[N + 1]) { + std::array result; + for (size_t i = 0; i < N; i++) { + result[i] = str[i]; + } + return result; +} + /** * Helper functions for the decoders. * @@ -24,7 +33,6 @@ namespace detail { */ template struct detail { -private: using opcode_type = typename MatcherT::opcode_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 '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 bitstring) { const auto one = static_cast(1); opcode_type mask = 0, expect = 0; 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. */ template - static auto GetArgInfo(const char* const bitstring) { + static constexpr auto GetArgInfo(std::array bitstring) { std::array masks = {}; std::array shifts = {}; size_t arg_index = 0; @@ -85,11 +93,12 @@ private: if constexpr (N > 0) { 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(1) << bit_position; shifts[arg_index] = bit_position; } else { - ASSERT_FALSE(); + throw std::out_of_range("Unexpected field"); } } } @@ -148,23 +157,23 @@ private: #pragma warning(pop) #endif -public: /** * Creates a matcher that can match and parse instructions based on bitstring. * See also: GetMaskAndExpect and GetArgInfo for format of bitstring. */ - template - static auto GetMatcher(FnT fn, const char* const name, const char* const bitstring) { - constexpr size_t args_count = mp::parameter_count_v; + template> + static auto GetMatcher(FnT fn, const char* const name, std::tuple mask_and_expect, std::tuple, std::array> masks_and_shifts) { using Iota = std::make_index_sequence; - const auto [mask, expect] = GetMaskAndExpect(bitstring); - const auto [arg_masks, arg_shifts] = GetArgInfo(bitstring); + const auto [mask, expect] = mask_and_expect; + const auto [arg_masks, arg_shifts] = masks_and_shifts; const auto proxy_fn = VisitorCaller::Make(Iota(), fn, arg_masks, arg_shifts); return MatcherT(name, mask, expect, proxy_fn); } }; +#define DYNARMIC_DECODER_GET_MATCHER(MatcherT, fn, name, bitstring) Decoder::detail::detail>::GetMatcher(&V::fn, name, Decoder::detail::detail>::GetMaskAndExpect(bitstring), Decoder::detail::detail>::template GetArgInfo>(bitstring)) + } // namespace detail } // namespace Dynarmic::Decoder