diff --git a/src/dynarmic/frontend/A32/decoder/arm.h b/src/dynarmic/frontend/A32/decoder/arm.h index 5b4a7b34..16ae52e1 100644 --- a/src/dynarmic/frontend/A32/decoder/arm.h +++ b/src/dynarmic/frontend/A32/decoder/arm.h @@ -23,9 +23,18 @@ namespace Dynarmic::A32 { template using ArmMatcher = Decoder::Matcher; +template +using ArmDecodeTable = std::array>, 0x1000>; + +namespace detail { +inline size_t ToFastLookupIndexArm(u32 instruction) { + return ((instruction >> 4) & 0x00F) | ((instruction >> 16) & 0xFF0); +} +} // namespace detail + template -std::vector> GetArmDecodeTable() { - std::vector> table = { +ArmDecodeTable GetArmDecodeTable() { + std::vector> list = { #define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)), #include "./arm.inc" @@ -34,10 +43,20 @@ std::vector> GetArmDecodeTable() { }; // If a matcher has more bits in its mask it is more specific, so it should come first. - std::stable_sort(table.begin(), table.end(), [](const auto& matcher1, const auto& matcher2) { + std::stable_sort(list.begin(), list.end(), [](const auto& matcher1, const auto& matcher2) { return mcl::bit::count_ones(matcher1.GetMask()) > mcl::bit::count_ones(matcher2.GetMask()); }); + ArmDecodeTable table{}; + for (size_t i = 0; i < table.size(); ++i) { + for (auto matcher : list) { + const auto expect = detail::ToFastLookupIndexArm(matcher.GetExpected()); + const auto mask = detail::ToFastLookupIndexArm(matcher.GetMask()); + if ((i & mask) == expect) { + table[i].push_back(matcher); + } + } + } return table; } @@ -47,8 +66,9 @@ std::optional>> DecodeArm(u32 instruc const auto matches_instruction = [instruction](const auto& matcher) { return matcher.Matches(instruction); }; - auto iter = std::find_if(table.begin(), table.end(), matches_instruction); - return iter != table.end() ? std::optional>>(*iter) : std::nullopt; + const auto& subtable = table[detail::ToFastLookupIndexArm(instruction)]; + auto iter = std::find_if(subtable.begin(), subtable.end(), matches_instruction); + return iter != subtable.end() ? std::optional>>(*iter) : std::nullopt; } } // namespace Dynarmic::A32