decode.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <array>
  6. #include <bit>
  7. #include <memory>
  8. #include <string_view>
  9. #include "common/common_types.h"
  10. #include "shader_recompiler/exception.h"
  11. #include "shader_recompiler/frontend/maxwell/decode.h"
  12. #include "shader_recompiler/frontend/maxwell/opcodes.h"
  13. namespace Shader::Maxwell {
  14. namespace {
  15. struct MaskValue {
  16. u64 mask;
  17. u64 value;
  18. };
  19. constexpr MaskValue MaskValueFromEncoding(const char* encoding) {
  20. u64 mask{};
  21. u64 value{};
  22. u64 bit{u64(1) << 63};
  23. while (*encoding) {
  24. switch (*encoding) {
  25. case '0':
  26. mask |= bit;
  27. break;
  28. case '1':
  29. mask |= bit;
  30. value |= bit;
  31. break;
  32. case '-':
  33. break;
  34. case ' ':
  35. break;
  36. default:
  37. throw LogicError("Invalid encoding character '{}'", *encoding);
  38. }
  39. ++encoding;
  40. if (*encoding != ' ') {
  41. bit >>= 1;
  42. }
  43. }
  44. return MaskValue{.mask = mask, .value = value};
  45. }
  46. struct InstEncoding {
  47. MaskValue mask_value;
  48. Opcode opcode;
  49. };
  50. constexpr std::array UNORDERED_ENCODINGS{
  51. #define INST(name, cute, encode) \
  52. InstEncoding{ \
  53. .mask_value{MaskValueFromEncoding(encode)}, \
  54. .opcode = Opcode::name, \
  55. },
  56. #include "maxwell.inc"
  57. #undef INST
  58. };
  59. constexpr auto SortedEncodings() {
  60. std::array encodings{UNORDERED_ENCODINGS};
  61. std::ranges::sort(encodings, [](const InstEncoding& lhs, const InstEncoding& rhs) {
  62. return std::popcount(lhs.mask_value.mask) > std::popcount(rhs.mask_value.mask);
  63. });
  64. return encodings;
  65. }
  66. constexpr auto ENCODINGS{SortedEncodings()};
  67. constexpr int WidestLeftBits() {
  68. int bits{64};
  69. for (const InstEncoding& encoding : ENCODINGS) {
  70. bits = std::min(bits, std::countr_zero(encoding.mask_value.mask));
  71. }
  72. return 64 - bits;
  73. }
  74. constexpr int WIDEST_LEFT_BITS{WidestLeftBits()};
  75. constexpr int MASK_SHIFT{64 - WIDEST_LEFT_BITS};
  76. constexpr size_t ToFastLookupIndex(u64 value) {
  77. return static_cast<size_t>(value >> MASK_SHIFT);
  78. }
  79. constexpr size_t FastLookupSize() {
  80. size_t max_width{};
  81. for (const InstEncoding& encoding : ENCODINGS) {
  82. max_width = std::max(max_width, ToFastLookupIndex(encoding.mask_value.mask));
  83. }
  84. return max_width + 1;
  85. }
  86. constexpr size_t FAST_LOOKUP_SIZE{FastLookupSize()};
  87. struct InstInfo {
  88. [[nodiscard]] u64 Mask() const noexcept {
  89. return static_cast<u64>(high_mask) << MASK_SHIFT;
  90. }
  91. [[nodiscard]] u64 Value() const noexcept {
  92. return static_cast<u64>(high_value) << MASK_SHIFT;
  93. }
  94. u16 high_mask;
  95. u16 high_value;
  96. Opcode opcode;
  97. };
  98. constexpr auto MakeFastLookupTableIndex(size_t index) {
  99. std::array<InstInfo, 2> encodings{};
  100. size_t element{};
  101. for (const auto& encoding : ENCODINGS) {
  102. const size_t mask{ToFastLookupIndex(encoding.mask_value.mask)};
  103. const size_t value{ToFastLookupIndex(encoding.mask_value.value)};
  104. if ((index & mask) == value) {
  105. encodings.at(element) = InstInfo{
  106. .high_mask = static_cast<u16>(encoding.mask_value.mask >> MASK_SHIFT),
  107. .high_value = static_cast<u16>(encoding.mask_value.value >> MASK_SHIFT),
  108. .opcode = encoding.opcode,
  109. };
  110. ++element;
  111. }
  112. }
  113. return encodings;
  114. }
  115. /*constexpr*/ auto MakeFastLookupTable() {
  116. auto encodings{std::make_unique<std::array<std::array<InstInfo, 2>, FAST_LOOKUP_SIZE>>()};
  117. for (size_t index = 0; index < FAST_LOOKUP_SIZE; ++index) {
  118. (*encodings)[index] = MakeFastLookupTableIndex(index);
  119. }
  120. return encodings;
  121. }
  122. const auto FAST_LOOKUP_TABLE{MakeFastLookupTable()};
  123. } // Anonymous namespace
  124. Opcode Decode(u64 insn) {
  125. const auto& table{(*FAST_LOOKUP_TABLE)[ToFastLookupIndex(insn)]};
  126. const auto it{std::ranges::find_if(
  127. table, [insn](const InstInfo& info) { return (insn & info.Mask()) == info.Value(); })};
  128. if (it == table.end()) {
  129. throw NotImplementedException("Instruction 0x{:016x} is unknown / unimplemented", insn);
  130. }
  131. return it->opcode;
  132. }
  133. } // namespace Shader::Maxwell