|
|
|
@ -7,142 +7,45 @@ |
|
|
|
#include <array>
|
|
|
|
#include <bit>
|
|
|
|
#include <memory>
|
|
|
|
#include <ranges>
|
|
|
|
#include <string_view>
|
|
|
|
|
|
|
|
#include "common/common_types.h"
|
|
|
|
#include <ranges>
|
|
|
|
#include "shader_recompiler/exception.h"
|
|
|
|
#include "shader_recompiler/frontend/maxwell/decode.h"
|
|
|
|
#include "shader_recompiler/frontend/maxwell/opcodes.h"
|
|
|
|
|
|
|
|
namespace Shader::Maxwell { |
|
|
|
namespace { |
|
|
|
struct MaskValue { |
|
|
|
u64 mask; |
|
|
|
u64 value; |
|
|
|
}; |
|
|
|
|
|
|
|
constexpr MaskValue MaskValueFromEncoding(const char* encoding) { |
|
|
|
u64 mask{}; |
|
|
|
u64 value{}; |
|
|
|
u64 bit{u64(1) << 63}; |
|
|
|
while (*encoding) { |
|
|
|
switch (*encoding) { |
|
|
|
consteval std::pair<u64, u64> MaskValueFromEncoding(const char data[20]) noexcept { |
|
|
|
u64 mask = 0, value = 0, bit = u64(1) << 63; |
|
|
|
for (int i = 0; i < 20; ++i) |
|
|
|
switch (data[i]) { |
|
|
|
case '0': |
|
|
|
mask |= bit; |
|
|
|
bit >>= 1; |
|
|
|
break; |
|
|
|
case '1': |
|
|
|
mask |= bit; |
|
|
|
value |= bit; |
|
|
|
bit >>= 1; |
|
|
|
break; |
|
|
|
case '-': |
|
|
|
break; |
|
|
|
case ' ': |
|
|
|
bit >>= 1; |
|
|
|
break; |
|
|
|
default: |
|
|
|
throw LogicError("Invalid encoding character '{}'", *encoding); |
|
|
|
} |
|
|
|
++encoding; |
|
|
|
if (*encoding != ' ') { |
|
|
|
bit >>= 1; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
return MaskValue{.mask = mask, .value = value}; |
|
|
|
return { mask, value }; |
|
|
|
} |
|
|
|
|
|
|
|
struct InstEncoding { |
|
|
|
MaskValue mask_value; |
|
|
|
Opcode opcode; |
|
|
|
}; |
|
|
|
constexpr auto SortedEncodings() { |
|
|
|
std::array<InstEncoding, 279> encodings{ |
|
|
|
#define INST(name, cute, encode) \
|
|
|
|
InstEncoding{ \ |
|
|
|
.mask_value{MaskValueFromEncoding(encode)}, \ |
|
|
|
.opcode = Opcode::name, \ |
|
|
|
}, |
|
|
|
Opcode Decode(u64 insn) { |
|
|
|
#define INST(name, cute, encode) \
|
|
|
|
if (auto const p = MaskValueFromEncoding(encode); (insn & p.first) == p.second) \ |
|
|
|
return Opcode::name; |
|
|
|
#include "maxwell.inc"
|
|
|
|
#undef INST
|
|
|
|
}; |
|
|
|
std::ranges::sort(encodings, [](const InstEncoding& lhs, const InstEncoding& rhs) { |
|
|
|
return std::popcount(lhs.mask_value.mask) > std::popcount(rhs.mask_value.mask); |
|
|
|
}); |
|
|
|
return encodings; |
|
|
|
} |
|
|
|
constexpr auto ENCODINGS{SortedEncodings()}; |
|
|
|
|
|
|
|
constexpr int WidestLeftBits() { |
|
|
|
int bits{64}; |
|
|
|
for (const InstEncoding& encoding : ENCODINGS) { |
|
|
|
bits = (std::min)(bits, std::countr_zero(encoding.mask_value.mask)); |
|
|
|
} |
|
|
|
return 64 - bits; |
|
|
|
} |
|
|
|
constexpr int WIDEST_LEFT_BITS{WidestLeftBits()}; |
|
|
|
constexpr int MASK_SHIFT{64 - WIDEST_LEFT_BITS}; |
|
|
|
|
|
|
|
constexpr size_t ToFastLookupIndex(u64 value) { |
|
|
|
return static_cast<size_t>(value >> MASK_SHIFT); |
|
|
|
} |
|
|
|
|
|
|
|
constexpr size_t FastLookupSize() { |
|
|
|
size_t max_width{}; |
|
|
|
for (const InstEncoding& encoding : ENCODINGS) { |
|
|
|
max_width = (std::max)(max_width, ToFastLookupIndex(encoding.mask_value.mask)); |
|
|
|
} |
|
|
|
return max_width + 1; |
|
|
|
} |
|
|
|
constexpr size_t FAST_LOOKUP_SIZE{FastLookupSize()}; |
|
|
|
|
|
|
|
struct InstInfo { |
|
|
|
[[nodiscard]] u64 Mask() const noexcept { |
|
|
|
return static_cast<u64>(high_mask) << MASK_SHIFT; |
|
|
|
} |
|
|
|
|
|
|
|
[[nodiscard]] u64 Value() const noexcept { |
|
|
|
return static_cast<u64>(high_value) << MASK_SHIFT; |
|
|
|
} |
|
|
|
|
|
|
|
u16 high_mask; |
|
|
|
u16 high_value; |
|
|
|
Opcode opcode; |
|
|
|
}; |
|
|
|
|
|
|
|
constexpr auto MakeFastLookupTableIndex(size_t index) { |
|
|
|
std::array<InstInfo, 2> encodings{}; |
|
|
|
size_t element{}; |
|
|
|
for (const auto& encoding : ENCODINGS) { |
|
|
|
const size_t mask{ToFastLookupIndex(encoding.mask_value.mask)}; |
|
|
|
const size_t value{ToFastLookupIndex(encoding.mask_value.value)}; |
|
|
|
if ((index & mask) == value) { |
|
|
|
encodings.at(element) = InstInfo{ |
|
|
|
.high_mask = static_cast<u16>(encoding.mask_value.mask >> MASK_SHIFT), |
|
|
|
.high_value = static_cast<u16>(encoding.mask_value.value >> MASK_SHIFT), |
|
|
|
.opcode = encoding.opcode, |
|
|
|
}; |
|
|
|
++element; |
|
|
|
} |
|
|
|
} |
|
|
|
return encodings; |
|
|
|
} |
|
|
|
|
|
|
|
/*constexpr*/ auto MakeFastLookupTable() { |
|
|
|
auto encodings{std::make_unique<std::array<std::array<InstInfo, 2>, FAST_LOOKUP_SIZE>>()}; |
|
|
|
for (size_t index = 0; index < FAST_LOOKUP_SIZE; ++index) { |
|
|
|
(*encodings)[index] = MakeFastLookupTableIndex(index); |
|
|
|
} |
|
|
|
return encodings; |
|
|
|
} |
|
|
|
const auto FAST_LOOKUP_TABLE{MakeFastLookupTable()}; |
|
|
|
} // Anonymous namespace
|
|
|
|
|
|
|
|
Opcode Decode(u64 insn) { |
|
|
|
const auto& table{(*FAST_LOOKUP_TABLE)[ToFastLookupIndex(insn)]}; |
|
|
|
const auto it{std::ranges::find_if( |
|
|
|
table, [insn](const InstInfo& info) { return (insn & info.Mask()) == info.Value(); })}; |
|
|
|
if (it == table.end()) { |
|
|
|
throw NotImplementedException("Instruction 0x{:016x} is unknown / unimplemented", insn); |
|
|
|
} |
|
|
|
return it->opcode; |
|
|
|
throw NotImplementedException("Invalid insn 0x{:016x}", insn); |
|
|
|
} |
|
|
|
|
|
|
|
} // namespace Shader::Maxwell
|