Browse Source

[shader_recompiler] simplify decoder table logic and let compiler do tables for us

Signed-off-by: lizzie <lizzie@eden-emu.dev>
pull/2915/head
lizzie 3 months ago
parent
commit
0f1abe3a2e
No known key found for this signature in database GPG Key ID: 287378CADCAB13
  1. 129
      src/shader_recompiler/frontend/maxwell/decode.cpp
  2. 4
      src/shader_recompiler/frontend/maxwell/maxwell.inc
  3. 1
      src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
  4. 4
      src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp

129
src/shader_recompiler/frontend/maxwell/decode.cpp

@ -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

4
src/shader_recompiler/frontend/maxwell/maxwell.inc

@ -24,6 +24,7 @@ INST(BRX, "BRX", "1110 0010 0101 ----")
INST(CAL, "CAL", "1110 0010 0110 ----")
INST(CCTL, "CCTL", "1110 1111 011- ----")
INST(CCTLL, "CCTLL", "1110 1111 100- ----")
INST(CCTLT, "CCTLT", "1110 1011 1111 0--0")
INST(CONT, "CONT", "1110 0011 0101 ----")
INST(CS2R, "CS2R", "0101 0000 1100 1---")
INST(CSET, "CSET", "0101 0000 1001 1---")
@ -280,6 +281,3 @@ INST(XMAD_reg, "XMAD (reg)", "0101 1011 00-- ----")
INST(XMAD_rc, "XMAD (rc)", "0101 0001 0--- ----")
INST(XMAD_cr, "XMAD (cr)", "0100 111- ---- ----")
INST(XMAD_imm, "XMAD (imm)", "0011 011- 00-- ----")
// Removed due to its weird formatting making fast tables larger
// INST(CCTLT, "CCTLT", "1110 1011 1111 0--0")

1
src/shader_recompiler/frontend/maxwell/translate/impl/impl.h

@ -86,6 +86,7 @@ public:
void CAL();
void CCTL(u64 insn);
void CCTLL(u64 insn);
void CCTLT(u64 insn);
void CONT(u64 insn);
void CS2R(u64 insn);
void CSET(u64 insn);

4
src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp

@ -48,6 +48,10 @@ void TranslatorVisitor::CCTLL(u64) {
ThrowNotImplemented(Opcode::CCTLL);
}
void TranslatorVisitor::CCTLT(u64) {
ThrowNotImplemented(Opcode::CCTLT);
}
void TranslatorVisitor::CONT(u64) {
ThrowNotImplemented(Opcode::CONT);
}

Loading…
Cancel
Save