mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-08-18 22:42:23 +00:00
Optimize decoder
This commit is contained in:
@@ -1,18 +1,9 @@
|
||||
#include "graphics/shader/recompiler/frontend/decode/ExportOps.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
|
||||
bool DecodeExp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated EXP instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DecodeExp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst) {
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t target = (word0 >> 4u) & 0x3fu;
|
||||
@@ -31,12 +22,10 @@ bool DecodeExp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
inst.exp.vm = ((word0 >> 12u) & 1u) != 0;
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
|
||||
if (!DecodeVectorGpr(word1 & 0xffu, inst.src0, error) ||
|
||||
!DecodeVectorGpr((word1 >> 8u) & 0xffu, inst.src1, error) ||
|
||||
!DecodeVectorGpr((word1 >> 16u) & 0xffu, inst.src2, error) ||
|
||||
!DecodeVectorGpr((word1 >> 24u) & 0xffu, inst.src3, error)) {
|
||||
return false;
|
||||
}
|
||||
DecodeVectorGpr(word1 & 0xffu, inst.src0);
|
||||
DecodeVectorGpr((word1 >> 8u) & 0xffu, inst.src1);
|
||||
DecodeVectorGpr((word1 >> 16u) & 0xffu, inst.src2);
|
||||
DecodeVectorGpr((word1 >> 24u) & 0xffu, inst.src3);
|
||||
|
||||
if (target == 0x14u && inst.exp.done && en == 0x1u) {
|
||||
inst.src_count = 1u;
|
||||
@@ -46,8 +35,6 @@ bool DecodeExp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
if (en == 0u) {
|
||||
inst.src_count = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
|
||||
bool DecodeExp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
void DecodeExp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
#include "graphics/shader/recompiler/frontend/decode/ImageOps.h"
|
||||
|
||||
#include "graphics/shader/recompiler/frontend/decode/OpcodeTable.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fmt/format.h>
|
||||
#include <iterator>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
namespace {
|
||||
|
||||
struct MimgSampleInfo {
|
||||
uint32_t opcode = 0;
|
||||
uint32_t encoding = 0;
|
||||
const char* name = nullptr;
|
||||
uint32_t flags = 0;
|
||||
uint32_t address_components = 3;
|
||||
};
|
||||
|
||||
struct MimgGatherInfo {
|
||||
uint32_t opcode = 0;
|
||||
uint32_t encoding = 0;
|
||||
const char* name = nullptr;
|
||||
Opcode decoded = Opcode::Unsupported;
|
||||
uint32_t flags = 0;
|
||||
@@ -23,9 +23,9 @@ struct MimgGatherInfo {
|
||||
};
|
||||
|
||||
struct MimgAtomicInfo {
|
||||
uint32_t opcode = 0;
|
||||
const char* name = nullptr;
|
||||
Opcode decoded = Opcode::Unsupported;
|
||||
uint32_t encoding = 0;
|
||||
const char* name = nullptr;
|
||||
Opcode decoded = Opcode::Unsupported;
|
||||
};
|
||||
|
||||
constexpr ImageDimension DecodeImageDimension(uint32_t dim) {
|
||||
@@ -88,7 +88,7 @@ constexpr MimgSampleInfo SampleInfo(uint32_t opcode, const char* name, uint32_t
|
||||
return {opcode, name, flags, ImageSampleAddressComponents(flags, ImageDimension::Dim2D)};
|
||||
}
|
||||
|
||||
constexpr MimgSampleInfo MIMG_SAMPLE_OPS[] = {
|
||||
constexpr MimgSampleInfo MIMG_SAMPLE_OPCODE_LIST[] = {
|
||||
SampleInfo(0x20u, "image_sample", 0),
|
||||
SampleInfo(0x21u, "image_sample_cl", ImageSampleFlagLodClamp),
|
||||
SampleInfo(0x22u, "image_sample_d", ImageSampleFlagDerivative),
|
||||
@@ -177,7 +177,7 @@ constexpr MimgSampleInfo MIMG_SAMPLE_OPS[] = {
|
||||
ImageSampleFlagOffset),
|
||||
};
|
||||
|
||||
constexpr MimgGatherInfo MIMG_GATHER_OPS[] = {
|
||||
constexpr MimgGatherInfo MIMG_GATHER_OPCODE_LIST[] = {
|
||||
{0x47u, "image_gather4_lz", Opcode::ImageGather4Lz, ImageSampleFlagLevelZero, 2u},
|
||||
{0x48u, "image_gather4_c", Opcode::ImageGather4C, ImageSampleFlagCompare, 3u},
|
||||
{0x4fu, "image_gather4_c_lz", Opcode::ImageGather4CLz,
|
||||
@@ -191,7 +191,7 @@ constexpr MimgGatherInfo MIMG_GATHER_OPS[] = {
|
||||
{0x61u, "image_gather4h", Opcode::ImageGather4H, ImageSampleFlagGatherHorizontal, 2u},
|
||||
};
|
||||
|
||||
constexpr MimgAtomicInfo MIMG_ATOMIC_OPS[] = {
|
||||
constexpr MimgAtomicInfo MIMG_ATOMIC_OPCODE_LIST[] = {
|
||||
{0x11u, "image_atomic_add", Opcode::ImageAtomicAdd},
|
||||
{0x15u, "image_atomic_umin", Opcode::ImageAtomicUMin},
|
||||
{0x17u, "image_atomic_umax", Opcode::ImageAtomicUMax},
|
||||
@@ -200,31 +200,20 @@ constexpr MimgAtomicInfo MIMG_ATOMIC_OPS[] = {
|
||||
{0x1au, "image_atomic_xor", Opcode::ImageAtomicXor},
|
||||
};
|
||||
|
||||
constexpr auto MIMG_SAMPLE_OPS = Detail::MakeOpcodeTable<0x100>(MIMG_SAMPLE_OPCODE_LIST);
|
||||
constexpr auto MIMG_GATHER_OPS = Detail::MakeOpcodeTable<0x100>(MIMG_GATHER_OPCODE_LIST);
|
||||
constexpr auto MIMG_ATOMIC_OPS = Detail::MakeOpcodeTable<0x100>(MIMG_ATOMIC_OPCODE_LIST);
|
||||
|
||||
const MimgSampleInfo* LookupSample(uint32_t opcode) {
|
||||
for (const auto& info: MIMG_SAMPLE_OPS) {
|
||||
if (info.opcode == opcode) {
|
||||
return &info;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return Detail::FindOpcode(MIMG_SAMPLE_OPS, opcode);
|
||||
}
|
||||
|
||||
const MimgGatherInfo* LookupGather(uint32_t opcode) {
|
||||
for (const auto& info: MIMG_GATHER_OPS) {
|
||||
if (info.opcode == opcode) {
|
||||
return &info;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return Detail::FindOpcode(MIMG_GATHER_OPS, opcode);
|
||||
}
|
||||
|
||||
const MimgAtomicInfo* LookupAtomic(uint32_t opcode) {
|
||||
for (const auto& info: MIMG_ATOMIC_OPS) {
|
||||
if (info.opcode == opcode) {
|
||||
return &info;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return Detail::FindOpcode(MIMG_ATOMIC_OPS, opcode);
|
||||
}
|
||||
|
||||
Opcode DecodeMimgOpcode(uint32_t opcode, const MimgSampleInfo* sample, const MimgGatherInfo* gather,
|
||||
@@ -297,27 +286,14 @@ bool IsSingleDmaskBit(uint32_t dmask) {
|
||||
|
||||
} // namespace
|
||||
|
||||
bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated MIMG instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst) {
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t opcode = ((word0 >> 18u) & 0x7fu) | ((word0 & 1u) << 7u);
|
||||
const uint32_t nsa_dwords = (word0 >> 1u) & 0x3u;
|
||||
const auto dimension = DecodeImageDimension((word0 >> 3u) & 0x7u);
|
||||
const uint32_t word_count = 2u + nsa_dwords;
|
||||
if (word_index + word_count > code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated MIMG NSA instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t vdata = (word1 >> 8u) & 0xffu;
|
||||
const uint32_t vaddr = word1 & 0xffu;
|
||||
@@ -344,7 +320,7 @@ bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
}
|
||||
inst.image_dimension = dimension;
|
||||
inst.image_nsa_dwords = nsa_dwords;
|
||||
for (uint32_t i = 0; i < nsa_dwords * 4u && i < MaxImageNsaAddressComponents; i++) {
|
||||
for (uint32_t i = 0; i < nsa_dwords * 4u; i++) {
|
||||
inst.image_nsa_addr[i] = (code[word_index + 2u + i / 4u] >> ((i % 4u) * 8u)) & 0xffu;
|
||||
}
|
||||
inst.image_address_components =
|
||||
@@ -359,12 +335,11 @@ bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
"MIMG image gather requires exactly one dmask bit");
|
||||
}
|
||||
|
||||
DecodeVectorGpr(vdata, inst.dst, nullptr);
|
||||
DecodeVectorGpr(vaddr, inst.src0, nullptr);
|
||||
DecodeVectorGpr(vdata, inst.dst);
|
||||
DecodeVectorGpr(vaddr, inst.src0);
|
||||
DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr);
|
||||
DecodeScalarSource(ssamp * 4u, pc, inst.src2, nullptr);
|
||||
inst.src_count = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* MimgSampleOpcodeName(uint32_t opcode) {
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
|
||||
bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
void DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst);
|
||||
|
||||
const char* MimgSampleOpcodeName(uint32_t opcode);
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#include "graphics/shader/recompiler/frontend/decode/MemoryOps.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <iterator>
|
||||
#include "graphics/shader/recompiler/frontend/decode/OpcodeTable.h"
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
namespace {
|
||||
|
||||
struct MemoryOpcodeInfo {
|
||||
uint32_t opcode = 0;
|
||||
uint32_t encoding = 0;
|
||||
Opcode decoded = Opcode::Unsupported;
|
||||
uint32_t data_dwords = 1;
|
||||
uint32_t data_bits = 32;
|
||||
@@ -16,7 +15,7 @@ struct MemoryOpcodeInfo {
|
||||
bool formatted = false;
|
||||
};
|
||||
|
||||
constexpr MemoryOpcodeInfo SMEM_OPS[] = {
|
||||
constexpr MemoryOpcodeInfo SMEM_OPCODE_LIST[] = {
|
||||
{0x00u, Opcode::SLoadDword, 1, 32}, {0x01u, Opcode::SLoadDwordx2, 2, 32},
|
||||
{0x02u, Opcode::SLoadDwordx4, 4, 32}, {0x03u, Opcode::SLoadDwordx8, 8, 32},
|
||||
{0x04u, Opcode::SLoadDwordx16, 16, 32}, {0x08u, Opcode::SBufferLoadDword, 1, 32},
|
||||
@@ -24,7 +23,7 @@ constexpr MemoryOpcodeInfo SMEM_OPS[] = {
|
||||
{0x0bu, Opcode::SBufferLoadDwordx8, 8, 32}, {0x0cu, Opcode::SBufferLoadDwordx16, 16, 32},
|
||||
};
|
||||
|
||||
constexpr MemoryOpcodeInfo MUBUF_OPS[] = {
|
||||
constexpr MemoryOpcodeInfo MUBUF_OPCODE_LIST[] = {
|
||||
{0x00u, Opcode::BufferLoadFormatX, 1, 32, false, false, true},
|
||||
{0x01u, Opcode::BufferLoadFormatXy, 2, 32, false, false, true},
|
||||
{0x02u, Opcode::BufferLoadFormatXyz, 3, 32, false, false, true},
|
||||
@@ -61,7 +60,7 @@ constexpr MemoryOpcodeInfo MUBUF_OPS[] = {
|
||||
{0x40u, Opcode::BufferAtomicFMax, 1, 32},
|
||||
};
|
||||
|
||||
constexpr MemoryOpcodeInfo MTBUF_OPS[] = {
|
||||
constexpr MemoryOpcodeInfo MTBUF_OPCODE_LIST[] = {
|
||||
{0x00u, Opcode::TBufferLoadFormatX, 1, 32, false, true, true},
|
||||
{0x01u, Opcode::TBufferLoadFormatXy, 2, 32, false, true, true},
|
||||
{0x02u, Opcode::TBufferLoadFormatXyz, 3, 32, false, true, true},
|
||||
@@ -72,7 +71,7 @@ constexpr MemoryOpcodeInfo MTBUF_OPS[] = {
|
||||
{0x07u, Opcode::TBufferStoreFormatXyzw, 4, 32, false, true, true},
|
||||
};
|
||||
|
||||
constexpr MemoryOpcodeInfo FLAT_OPS[] = {
|
||||
constexpr MemoryOpcodeInfo FLAT_OPCODE_LIST[] = {
|
||||
{0x08u, Opcode::FlatLoadUbyte, 1, 8}, {0x09u, Opcode::FlatLoadSbyte, 1, 8, true},
|
||||
{0x0au, Opcode::FlatLoadUshort, 1, 16}, {0x0bu, Opcode::FlatLoadSshort, 1, 16, true},
|
||||
{0x0cu, Opcode::FlatLoadDword, 1, 32}, {0x0du, Opcode::FlatLoadDwordx2, 2, 32},
|
||||
@@ -82,7 +81,7 @@ constexpr MemoryOpcodeInfo FLAT_OPS[] = {
|
||||
{0x1eu, Opcode::FlatStoreDwordx4, 4, 32}, {0x1fu, Opcode::FlatStoreDwordx3, 3, 32},
|
||||
};
|
||||
|
||||
constexpr MemoryOpcodeInfo DS_OPS[] = {
|
||||
constexpr MemoryOpcodeInfo DS_OPCODE_LIST[] = {
|
||||
{0x00u, Opcode::DsAddU32, 1, 32}, {0x01u, Opcode::DsSubU32, 1, 32},
|
||||
{0x05u, Opcode::DsMinI32, 1, 32}, {0x06u, Opcode::DsMaxI32, 1, 32},
|
||||
{0x07u, Opcode::DsMinU32, 1, 32}, {0x08u, Opcode::DsMaxU32, 1, 32},
|
||||
@@ -109,15 +108,11 @@ constexpr MemoryOpcodeInfo DS_OPS[] = {
|
||||
{0xfeu, Opcode::DsReadB96, 3, 32}, {0xffu, Opcode::DsReadB128, 4, 32},
|
||||
};
|
||||
|
||||
const MemoryOpcodeInfo* LookupMemoryOpcode(const MemoryOpcodeInfo* ops, uint32_t count,
|
||||
uint32_t opcode) {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (ops[i].opcode == opcode) {
|
||||
return &ops[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
constexpr auto SMEM_OPS = Detail::MakeOpcodeTable<0x100>(SMEM_OPCODE_LIST);
|
||||
constexpr auto MUBUF_OPS = Detail::MakeOpcodeTable<0x100>(MUBUF_OPCODE_LIST);
|
||||
constexpr auto MTBUF_OPS = Detail::MakeOpcodeTable<0x10>(MTBUF_OPCODE_LIST);
|
||||
constexpr auto FLAT_OPS = Detail::MakeOpcodeTable<0x80>(FLAT_OPCODE_LIST);
|
||||
constexpr auto DS_OPS = Detail::MakeOpcodeTable<0x100>(DS_OPCODE_LIST);
|
||||
|
||||
uint32_t SignExtendU32(uint32_t value, uint32_t bits) {
|
||||
if (bits == 0u || bits >= 32u) {
|
||||
@@ -217,15 +212,8 @@ bool IsFlatStoreOpcode(Opcode opcode) {
|
||||
|
||||
} // namespace
|
||||
|
||||
bool DecodeSmem(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated SMEM instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DecodeSmem(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst) {
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t opcode = (word0 >> 18u) & 0xffu;
|
||||
@@ -233,15 +221,14 @@ bool DecodeSmem(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
const uint32_t sbase = word0 & 0x3fu;
|
||||
const uint32_t soffset = (word1 >> 25u) & 0x7fu;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word0;
|
||||
inst.word_count = 2;
|
||||
inst.offset = SignExtendU32(word1 & 0x1fffffu, 21u);
|
||||
inst.glc = ((word0 >> 16u) & 1u) != 0;
|
||||
inst.family = Family::SMEM;
|
||||
inst.opcode_id = opcode;
|
||||
const auto* info =
|
||||
LookupMemoryOpcode(SMEM_OPS, static_cast<uint32_t>(std::size(SMEM_OPS)), opcode);
|
||||
inst.pc = pc;
|
||||
inst.word = word0;
|
||||
inst.word_count = 2;
|
||||
inst.offset = SignExtendU32(word1 & 0x1fffffu, 21u);
|
||||
inst.glc = ((word0 >> 16u) & 1u) != 0;
|
||||
inst.family = Family::SMEM;
|
||||
inst.opcode_id = opcode;
|
||||
const auto* info = Detail::FindOpcode(SMEM_OPS, opcode);
|
||||
ApplyMemoryInfo(inst, info);
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
@@ -254,18 +241,10 @@ bool DecodeSmem(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
DecodeScalarSource(sbase * 2u, pc, inst.src0, nullptr);
|
||||
DecodeScalarSource(soffset, pc, inst.src1, nullptr);
|
||||
inst.src_count = 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated MUBUF instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst) {
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t opcode = ((word0 >> 18u) & 0x7fu) | (((word0 >> 25u) & 1u) << 7u);
|
||||
@@ -274,41 +253,32 @@ bool DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_inde
|
||||
const uint32_t srsrc = (word1 >> 16u) & 0x1fu;
|
||||
const uint32_t soffset = (word1 >> 24u) & 0xffu;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word0;
|
||||
inst.word_count = 2;
|
||||
inst.offset = word0 & 0xfffu;
|
||||
inst.idxen = ((word0 >> 13u) & 1u) != 0;
|
||||
inst.offen = ((word0 >> 12u) & 1u) != 0;
|
||||
inst.glc = ((word0 >> 14u) & 1u) != 0;
|
||||
inst.slc = ((word1 >> 22u) & 1u) != 0;
|
||||
inst.family = Family::MUBUF;
|
||||
inst.opcode_id = opcode;
|
||||
const auto* info =
|
||||
LookupMemoryOpcode(MUBUF_OPS, static_cast<uint32_t>(std::size(MUBUF_OPS)), opcode);
|
||||
inst.pc = pc;
|
||||
inst.word = word0;
|
||||
inst.word_count = 2;
|
||||
inst.offset = word0 & 0xfffu;
|
||||
inst.idxen = ((word0 >> 13u) & 1u) != 0;
|
||||
inst.offen = ((word0 >> 12u) & 1u) != 0;
|
||||
inst.glc = ((word0 >> 14u) & 1u) != 0;
|
||||
inst.slc = ((word1 >> 22u) & 1u) != 0;
|
||||
inst.family = Family::MUBUF;
|
||||
inst.opcode_id = opcode;
|
||||
const auto* info = Detail::FindOpcode(MUBUF_OPS, opcode);
|
||||
ApplyMemoryInfo(inst, info);
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
MarkMemoryUnsupported(inst, Family::MUBUF, opcode, "MUBUF opcode is not implemented");
|
||||
}
|
||||
|
||||
DecodeVectorGpr(vdata, inst.dst, nullptr);
|
||||
DecodeVectorGpr(vaddr, inst.src0, nullptr);
|
||||
DecodeVectorGpr(vdata, inst.dst);
|
||||
DecodeVectorGpr(vaddr, inst.src0);
|
||||
DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr);
|
||||
DecodeScalarSource(soffset, pc, inst.src2, nullptr);
|
||||
inst.src_count = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeMtbuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated MTBUF instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DecodeMtbuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst) {
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t opcode = ((word0 >> 16u) & 0x7u) | (((word1 >> 21u) & 1u) << 3u);
|
||||
@@ -331,31 +301,22 @@ bool DecodeMtbuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_inde
|
||||
inst.opcode_id = opcode;
|
||||
inst.data_format = dfmt;
|
||||
inst.number_format = nfmt;
|
||||
const auto* info =
|
||||
LookupMemoryOpcode(MTBUF_OPS, static_cast<uint32_t>(std::size(MTBUF_OPS)), opcode);
|
||||
const auto* info = Detail::FindOpcode(MTBUF_OPS, opcode);
|
||||
ApplyMemoryInfo(inst, info);
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
MarkMemoryUnsupported(inst, Family::MTBUF, opcode, "MTBUF opcode is not implemented");
|
||||
}
|
||||
|
||||
DecodeVectorGpr(vdata, inst.dst, nullptr);
|
||||
DecodeVectorGpr(vaddr, inst.src0, nullptr);
|
||||
DecodeVectorGpr(vdata, inst.dst);
|
||||
DecodeVectorGpr(vaddr, inst.src0);
|
||||
DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr);
|
||||
DecodeScalarSource(soffset, pc, inst.src2, nullptr);
|
||||
inst.src_count = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated FLAT instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst) {
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t offset = word0 & 0xfffu;
|
||||
@@ -377,42 +338,32 @@ bool DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
inst.family = Family::FLAT;
|
||||
inst.opcode_id = opcode;
|
||||
inst.memory_segment = seg;
|
||||
const auto* info =
|
||||
LookupMemoryOpcode(FLAT_OPS, static_cast<uint32_t>(std::size(FLAT_OPS)), opcode);
|
||||
const auto* info = Detail::FindOpcode(FLAT_OPS, opcode);
|
||||
ApplyMemoryInfo(inst, info);
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
|
||||
if (dlc != 0 || lds != 0 || inst.glc || inst.slc || seg == 3u) {
|
||||
SetUnsupported(inst, Family::FLAT, opcode, "FLAT modifiers or segment are not implemented");
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
MarkMemoryUnsupported(inst, Family::FLAT, opcode, "FLAT opcode is not implemented");
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
DecodeVectorGpr(IsFlatStoreOpcode(inst.opcode) ? data : vdst, inst.dst, nullptr);
|
||||
DecodeVectorGpr(addr, inst.src0, nullptr);
|
||||
DecodeVectorGpr(IsFlatStoreOpcode(inst.opcode) ? data : vdst, inst.dst);
|
||||
DecodeVectorGpr(addr, inst.src0);
|
||||
inst.src_count = 1;
|
||||
if (seg == 0u || saddr == 0x7du || saddr == 0x7fu) {
|
||||
DecodeVectorGpr(addr + 1u, inst.src1, nullptr);
|
||||
DecodeVectorGpr(addr + 1u, inst.src1);
|
||||
inst.src_count = 2;
|
||||
} else {
|
||||
DecodeScalarSource(saddr, pc, inst.src1, nullptr);
|
||||
inst.src_count = 2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeDs(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated DS instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DecodeDs(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst) {
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t opcode = (word0 >> 18u) & 0xffu;
|
||||
@@ -430,7 +381,7 @@ bool DecodeDs(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
inst.gds = ((word0 >> 17u) & 1u) != 0u;
|
||||
inst.family = Family::DS;
|
||||
inst.opcode_id = opcode;
|
||||
const auto* info = LookupMemoryOpcode(DS_OPS, static_cast<uint32_t>(std::size(DS_OPS)), opcode);
|
||||
const auto* info = Detail::FindOpcode(DS_OPS, opcode);
|
||||
ApplyMemoryInfo(inst, info);
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
@@ -466,12 +417,11 @@ bool DecodeDs(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
inst.secondary_offset = offset1 * 512u;
|
||||
}
|
||||
|
||||
DecodeVectorGpr(vdst, inst.dst, nullptr);
|
||||
DecodeVectorGpr(addr, inst.src0, nullptr);
|
||||
DecodeVectorGpr(data0, inst.src1, nullptr);
|
||||
DecodeVectorGpr(data1, inst.src2, nullptr);
|
||||
DecodeVectorGpr(vdst, inst.dst);
|
||||
DecodeVectorGpr(addr, inst.src0);
|
||||
DecodeVectorGpr(data0, inst.src1);
|
||||
DecodeVectorGpr(data1, inst.src2);
|
||||
inst.src_count = DsSourceCount(inst.opcode);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
@@ -5,16 +5,15 @@
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
|
||||
bool DecodeSmem(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error);
|
||||
bool DecodeMtbuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error);
|
||||
bool DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeDs(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
void DecodeSmem(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst);
|
||||
void DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst);
|
||||
void DecodeMtbuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst);
|
||||
void DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst);
|
||||
void DecodeDs(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
#include "graphics/shader/recompiler/frontend/decode/ShaderDecoder.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder::Detail {
|
||||
|
||||
@@ -12,34 +14,43 @@ struct OpcodeMap {
|
||||
Opcode decoded = Opcode::Unknown;
|
||||
};
|
||||
|
||||
template <typename Entry, size_t N>
|
||||
constexpr const Entry* FindOpcode(const Entry (&table)[N], uint32_t encoding) {
|
||||
for (const auto& entry: table) {
|
||||
if (entry.encoding == encoding) {
|
||||
return &entry;
|
||||
template <typename Entry, size_t EncodingCount, size_t EntryCount>
|
||||
struct OpcodeTable {
|
||||
std::array<Entry, EntryCount> entries = {};
|
||||
std::array<uint16_t, EncodingCount> indices = {};
|
||||
};
|
||||
|
||||
template <size_t EncodingCount, typename Entry, size_t EntryCount>
|
||||
consteval auto MakeOpcodeTable(const Entry (&entries)[EntryCount]) {
|
||||
static_assert(EntryCount < UINT16_MAX);
|
||||
OpcodeTable<Entry, EncodingCount, EntryCount> table;
|
||||
for (size_t i = 0; i < EntryCount; i++) {
|
||||
const auto encoding = entries[i].encoding;
|
||||
if (encoding >= EncodingCount || table.indices[encoding] != 0) {
|
||||
throw "invalid opcode table";
|
||||
}
|
||||
table.entries[i] = entries[i];
|
||||
table.indices[encoding] = static_cast<uint16_t>(i + 1);
|
||||
}
|
||||
return nullptr;
|
||||
return table;
|
||||
}
|
||||
|
||||
template <typename Entry, size_t N>
|
||||
constexpr Opcode LookupOpcode(const Entry (&table)[N], uint32_t encoding) {
|
||||
template <typename Entry, size_t EncodingCount, size_t EntryCount>
|
||||
constexpr const Entry* FindOpcode(const OpcodeTable<Entry, EncodingCount, EntryCount>& table,
|
||||
uint32_t encoding) {
|
||||
if (table.indices[encoding] == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return &table.entries[table.indices[encoding] - 1];
|
||||
}
|
||||
|
||||
template <typename Entry, size_t EncodingCount, size_t EntryCount>
|
||||
constexpr Opcode LookupOpcode(const OpcodeTable<Entry, EncodingCount, EntryCount>& table,
|
||||
uint32_t encoding) {
|
||||
const auto* entry = FindOpcode(table, encoding);
|
||||
return entry != nullptr ? entry->decoded : Opcode::Unsupported;
|
||||
}
|
||||
|
||||
template <typename Entry, size_t N>
|
||||
constexpr bool HasUniqueEncodings(const Entry (&table)[N]) {
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
for (size_t j = i + 1; j < N; j++) {
|
||||
if (table[i].encoding == table[j].encoding) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder::Detail
|
||||
|
||||
#endif // EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_DECOMPILER_OPCODETABLE_H_
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace {
|
||||
|
||||
using Detail::OpcodeMap;
|
||||
|
||||
constexpr OpcodeMap SOP2_OPS[] = {
|
||||
constexpr OpcodeMap SOP2_OPCODE_LIST[] = {
|
||||
{0x00u, Opcode::SAddU32}, {0x01u, Opcode::SSubU32}, {0x02u, Opcode::SAddI32},
|
||||
{0x03u, Opcode::SSubI32}, {0x04u, Opcode::SAddcU32}, {0x05u, Opcode::SSubbU32},
|
||||
{0x06u, Opcode::SMinI32}, {0x07u, Opcode::SMinU32}, {0x08u, Opcode::SMaxI32},
|
||||
@@ -26,7 +26,7 @@ constexpr OpcodeMap SOP2_OPS[] = {
|
||||
{0x35u, Opcode::SMulHiU32},
|
||||
};
|
||||
|
||||
constexpr OpcodeMap SOP1_OPS[] = {
|
||||
constexpr OpcodeMap SOP1_OPCODE_LIST[] = {
|
||||
{0x03u, Opcode::SMovB32}, {0x04u, Opcode::SMovB64},
|
||||
{0x07u, Opcode::SNotB32}, {0x08u, Opcode::SNotB64},
|
||||
{0x0au, Opcode::SWqmB64}, {0x0bu, Opcode::SBrevB32},
|
||||
@@ -40,7 +40,7 @@ constexpr OpcodeMap SOP1_OPS[] = {
|
||||
{0x3cu, Opcode::SAndSaveexecB32}, {0x44u, Opcode::SAndn1SaveexecB32},
|
||||
};
|
||||
|
||||
constexpr OpcodeMap SOPC_OPS[] = {
|
||||
constexpr OpcodeMap SOPC_OPCODE_LIST[] = {
|
||||
{0x00u, Opcode::SCmpEqI32}, {0x01u, Opcode::SCmpLgI32}, {0x02u, Opcode::SCmpGtI32},
|
||||
{0x03u, Opcode::SCmpGeI32}, {0x04u, Opcode::SCmpLtI32}, {0x05u, Opcode::SCmpLeI32},
|
||||
{0x06u, Opcode::SCmpEqU32}, {0x07u, Opcode::SCmpLgU32}, {0x08u, Opcode::SCmpGtU32},
|
||||
@@ -49,7 +49,7 @@ constexpr OpcodeMap SOPC_OPS[] = {
|
||||
{0x13u, Opcode::SCmpLgU64},
|
||||
};
|
||||
|
||||
constexpr OpcodeMap SOPK_OPS[] = {
|
||||
constexpr OpcodeMap SOPK_OPCODE_LIST[] = {
|
||||
{0x00u, Opcode::SMovkI32}, {0x03u, Opcode::SCmpEqI32}, {0x04u, Opcode::SCmpLgI32},
|
||||
{0x05u, Opcode::SCmpGtI32}, {0x06u, Opcode::SCmpGeI32}, {0x07u, Opcode::SCmpLtI32},
|
||||
{0x08u, Opcode::SCmpLeI32}, {0x09u, Opcode::SCmpEqU32}, {0x0au, Opcode::SCmpLgU32},
|
||||
@@ -59,7 +59,7 @@ constexpr OpcodeMap SOPK_OPS[] = {
|
||||
{0x19u, Opcode::SWaitcnt}, {0x1au, Opcode::SWaitcnt},
|
||||
};
|
||||
|
||||
constexpr OpcodeMap SOPP_OPS[] = {
|
||||
constexpr OpcodeMap SOPP_OPCODE_LIST[] = {
|
||||
{0x00u, Opcode::SNop}, {0x01u, Opcode::SEndpgm}, {0x02u, Opcode::SBranch},
|
||||
{0x04u, Opcode::SCbranchScc0}, {0x05u, Opcode::SCbranchScc1}, {0x06u, Opcode::SCbranchVccz},
|
||||
{0x07u, Opcode::SCbranchVccnz}, {0x08u, Opcode::SCbranchExecz}, {0x09u, Opcode::SCbranchExecnz},
|
||||
@@ -67,11 +67,12 @@ constexpr OpcodeMap SOPP_OPS[] = {
|
||||
{0x10u, Opcode::SSendmsg}, {0x12u, Opcode::STrap}, {0x16u, Opcode::STtraceData},
|
||||
{0x20u, Opcode::SInstPrefetch},
|
||||
};
|
||||
static_assert(Detail::HasUniqueEncodings(SOP1_OPS));
|
||||
static_assert(Detail::HasUniqueEncodings(SOP2_OPS));
|
||||
static_assert(Detail::HasUniqueEncodings(SOPK_OPS));
|
||||
static_assert(Detail::HasUniqueEncodings(SOPC_OPS));
|
||||
static_assert(Detail::HasUniqueEncodings(SOPP_OPS));
|
||||
|
||||
constexpr auto SOP1_OPS = Detail::MakeOpcodeTable<0x100>(SOP1_OPCODE_LIST);
|
||||
constexpr auto SOP2_OPS = Detail::MakeOpcodeTable<0x80>(SOP2_OPCODE_LIST);
|
||||
constexpr auto SOPK_OPS = Detail::MakeOpcodeTable<0x20>(SOPK_OPCODE_LIST);
|
||||
constexpr auto SOPC_OPS = Detail::MakeOpcodeTable<0x80>(SOPC_OPCODE_LIST);
|
||||
constexpr auto SOPP_OPS = Detail::MakeOpcodeTable<0x80>(SOPP_OPCODE_LIST);
|
||||
|
||||
bool DecodeBinarySources(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, uint32_t ssrc0, uint32_t ssrc1, std::string* error) {
|
||||
@@ -80,7 +81,8 @@ bool DecodeBinarySources(uint32_t pc, std::span<const uint32_t> code, uint32_t w
|
||||
return false;
|
||||
}
|
||||
inst.src_count = 2;
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -114,7 +116,8 @@ bool DecodeSop1(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
if (!DecodeScalarSource(ssrc0, pc, inst.src0, error)) {
|
||||
return false;
|
||||
}
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -123,7 +126,8 @@ bool DecodeSop1(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
return false;
|
||||
}
|
||||
inst.src_count = 1;
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeSop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
@@ -159,8 +163,6 @@ bool DecodeSopk(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
const uint32_t sdst = (word >> 16u) & 0x7fu;
|
||||
const auto imm = static_cast<int16_t>(word & 0xffffu);
|
||||
|
||||
(void)error;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word;
|
||||
inst.family = Family::SOPK;
|
||||
@@ -234,14 +236,12 @@ bool DecodeSopc(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
return DecodeBinarySources(pc, code, word_index, inst, ssrc0, ssrc1, error);
|
||||
}
|
||||
|
||||
bool DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
void DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst) {
|
||||
const uint32_t word = code[word_index];
|
||||
const uint32_t opcode = (word >> 16u) & 0x7fu;
|
||||
const uint32_t simm = word & 0xffffu;
|
||||
|
||||
(void)error;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word;
|
||||
inst.family = Family::SOPP;
|
||||
@@ -265,7 +265,6 @@ bool DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
SetUnsupported(inst, Family::SOPP, opcode, "SOPP control-flow opcode is not implemented");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
@@ -13,8 +13,8 @@ bool DecodeSopk(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
std::string* error);
|
||||
bool DecodeSopc(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
void DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <fmt/format.h>
|
||||
#include <set>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
namespace {
|
||||
@@ -111,7 +110,7 @@ std::string WithUnsupportedReason(const Instruction& inst, const std::string& te
|
||||
}
|
||||
return text + fmt::format(" ; family={} opcode=0x{:02x} raw=[{}] reason={}",
|
||||
FamilyToString(inst.family).c_str(), inst.opcode_id,
|
||||
RawWordsToString(inst).c_str(), inst.unsupported_reason.c_str());
|
||||
RawWordsToString(inst).c_str(), inst.unsupported_reason);
|
||||
}
|
||||
|
||||
void AppendFlag(std::string* text, bool* first, uint32_t flags, uint32_t flag, const char* name) {
|
||||
@@ -238,7 +237,8 @@ bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand& operand, std::strin
|
||||
return true;
|
||||
}
|
||||
if (code >= 256u && code <= 511u) {
|
||||
return DecodeVectorGpr(code - 256u, operand, error);
|
||||
DecodeVectorGpr(code - 256u, operand);
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
@@ -292,27 +292,15 @@ bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand& operand, std::
|
||||
}
|
||||
}
|
||||
|
||||
bool DecodeVectorGpr(uint32_t reg, Operand& operand, std::string* error) {
|
||||
if (reg > 255u) {
|
||||
SetError(error, "VGPR index is out of range");
|
||||
return false;
|
||||
}
|
||||
void DecodeVectorGpr(uint32_t reg, Operand& operand) {
|
||||
operand = {};
|
||||
operand.kind = OperandKind::Vgpr;
|
||||
operand.reg = reg;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadLiteralOperands(std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
void ReadLiteralOperands(std::span<const uint32_t> code, uint32_t word_index, Instruction& inst) {
|
||||
if (!HasLiteral(inst)) {
|
||||
return true;
|
||||
}
|
||||
if (word_index + inst.word_count >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("missing literal constant at pc 0x{:08x}", inst.pc);
|
||||
}
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto literal = code[word_index + inst.word_count];
|
||||
@@ -322,13 +310,12 @@ bool ReadLiteralOperands(std::span<const uint32_t> code, uint32_t word_index, In
|
||||
ApplyLiteral(inst.src3, literal);
|
||||
inst.word_count++;
|
||||
SetRawWords(inst, code, word_index, inst.word_count);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetRawWords(Instruction& inst, std::span<const uint32_t> code, uint32_t word_index,
|
||||
uint32_t word_count) {
|
||||
inst.word_count = word_count;
|
||||
inst.raw_count = std::min<uint32_t>(word_count, MaxInstructionRawWords);
|
||||
inst.raw_count = word_count;
|
||||
for (uint32_t i = 0; i < inst.raw_count; i++) {
|
||||
inst.raw[i] = code[word_index + i];
|
||||
}
|
||||
@@ -341,69 +328,96 @@ void SetUnsupported(Instruction& inst, Family family, uint32_t opcode_id, const
|
||||
inst.unsupported_reason = reason;
|
||||
}
|
||||
|
||||
bool DecodeProgram(std::span<const uint32_t> code, Program& program, std::string* error) {
|
||||
if (code.empty() || code.size() > UINT32_MAX / sizeof(uint32_t)) {
|
||||
SetError(error, "invalid shader decoder input");
|
||||
return false;
|
||||
Family GetInstructionFamily(uint32_t word) {
|
||||
if ((word & 0x80000000u) == 0u) {
|
||||
switch ((word >> 25u) & 0x3fu) {
|
||||
case 0x3eu: return Family::VOPC;
|
||||
case 0x3fu: return Family::VOP1;
|
||||
default: return Family::VOP2;
|
||||
}
|
||||
}
|
||||
if ((word & 0xc0000000u) == 0x80000000u) {
|
||||
const auto opcode = (word >> 23u) & 0x7fu;
|
||||
switch (opcode) {
|
||||
case 0x7du: return Family::SOP1;
|
||||
case 0x7eu: return Family::SOPC;
|
||||
case 0x7fu: return Family::SOPP;
|
||||
default: return opcode >= 0x60u ? Family::SOPK : Family::SOP2;
|
||||
}
|
||||
}
|
||||
|
||||
switch (word >> 26u) {
|
||||
case 0x32u: return Family::VINTRP;
|
||||
case 0x33u: return Family::VOP3P;
|
||||
case 0x35u: return Family::VOP3;
|
||||
case 0x36u: return Family::DS;
|
||||
case 0x37u: return Family::FLAT;
|
||||
case 0x38u: return Family::MUBUF;
|
||||
case 0x3au: return Family::MTBUF;
|
||||
case 0x3cu: return Family::MIMG;
|
||||
case 0x3du: return Family::SMEM;
|
||||
case 0x3eu: return Family::EXP;
|
||||
default: return Family::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
bool DecodeInstruction(std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
const uint32_t pc = word_index * sizeof(uint32_t);
|
||||
switch (GetInstructionFamily(code[word_index])) {
|
||||
case Family::SOP1: return DecodeSop1(pc, code, word_index, inst, error);
|
||||
case Family::SOP2: return DecodeSop2(pc, code, word_index, inst, error);
|
||||
case Family::SOPK: return DecodeSopk(pc, code, word_index, inst, error);
|
||||
case Family::SOPC: return DecodeSopc(pc, code, word_index, inst, error);
|
||||
case Family::SOPP: DecodeSopp(pc, code, word_index, inst); return true;
|
||||
case Family::VOP1: return DecodeVop1(pc, code, word_index, inst, error);
|
||||
case Family::VOP2: return DecodeVop2(pc, code, word_index, inst, error);
|
||||
case Family::VOP3: return DecodeVop3(pc, code, word_index, inst, error);
|
||||
case Family::VOP3P: return DecodeVop3p(pc, code, word_index, inst, error);
|
||||
case Family::VOPC: return DecodeVopc(pc, code, word_index, inst, error);
|
||||
case Family::VINTRP: DecodeVintrp(pc, code, word_index, inst); return true;
|
||||
case Family::SMEM: DecodeSmem(pc, code, word_index, inst); return true;
|
||||
case Family::MUBUF: DecodeMubuf(pc, code, word_index, inst); return true;
|
||||
case Family::MTBUF: DecodeMtbuf(pc, code, word_index, inst); return true;
|
||||
case Family::FLAT: DecodeFlat(pc, code, word_index, inst); return true;
|
||||
case Family::DS: DecodeDs(pc, code, word_index, inst); return true;
|
||||
case Family::MIMG: DecodeMimg(pc, code, word_index, inst); return true;
|
||||
case Family::EXP: DecodeExp(pc, code, word_index, inst); return true;
|
||||
default:
|
||||
if (error != nullptr) {
|
||||
*error =
|
||||
fmt::format("unknown RDNA2 instruction family at pc 0x{:08x}, raw=0x{:08x}", pc,
|
||||
code[word_index]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DecodeProgram(std::span<const uint32_t> code, Program& program, std::string* error) {
|
||||
program.instructions.clear();
|
||||
program.instructions.reserve(code.size());
|
||||
program.code = code;
|
||||
|
||||
std::set<uint32_t> branch_targets;
|
||||
std::vector<bool> branch_targets;
|
||||
for (uint32_t word_index = 0; word_index < code.size();) {
|
||||
const uint32_t pc = word_index * 4u;
|
||||
const uint32_t word = code[word_index];
|
||||
|
||||
Instruction inst;
|
||||
bool ok = false;
|
||||
if ((word & 0x80000000u) == 0u) {
|
||||
ok = DecodeVop2(pc, code, word_index, inst, error);
|
||||
} else if ((word & 0xc0000000u) == 0x80000000u) {
|
||||
const auto opcode = (word >> 23u) & 0x7fu;
|
||||
switch (opcode) {
|
||||
case 0x7du: ok = DecodeSop1(pc, code, word_index, inst, error); break;
|
||||
case 0x7eu: ok = DecodeSopc(pc, code, word_index, inst, error); break;
|
||||
case 0x7fu: ok = DecodeSopp(pc, code, word_index, inst, error); break;
|
||||
default:
|
||||
ok = opcode >= 0x60u ? DecodeSopk(pc, code, word_index, inst, error)
|
||||
: DecodeSop2(pc, code, word_index, inst, error);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (word >> 26u) {
|
||||
case 0x32u: ok = DecodeVintrp(pc, code, word_index, inst, error); break;
|
||||
case 0x33u: ok = DecodeVop3p(pc, code, word_index, inst, error); break;
|
||||
case 0x35u: ok = DecodeVop3(pc, code, word_index, inst, error); break;
|
||||
case 0x36u: ok = DecodeDs(pc, code, word_index, inst, error); break;
|
||||
case 0x37u: ok = DecodeFlat(pc, code, word_index, inst, error); break;
|
||||
case 0x38u: ok = DecodeMubuf(pc, code, word_index, inst, error); break;
|
||||
case 0x3au: ok = DecodeMtbuf(pc, code, word_index, inst, error); break;
|
||||
case 0x3cu: ok = DecodeMimg(pc, code, word_index, inst, error); break;
|
||||
case 0x3du: ok = DecodeSmem(pc, code, word_index, inst, error); break;
|
||||
case 0x3eu: ok = DecodeExp(pc, code, word_index, inst, error); break;
|
||||
default:
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format(
|
||||
"unknown RDNA2 instruction family at pc 0x{:08x}, raw=0x{:08x}", pc,
|
||||
word);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
program.instructions.emplace_back();
|
||||
if (!DecodeInstruction(code, word_index, program.instructions.back(), error)) {
|
||||
program.instructions.pop_back();
|
||||
return false;
|
||||
}
|
||||
|
||||
program.instructions.push_back(inst);
|
||||
const auto& inst = program.instructions.back();
|
||||
word_index += inst.word_count;
|
||||
|
||||
if (IsControlFlowBranch(inst.opcode)) {
|
||||
branch_targets.insert(inst.branch_target);
|
||||
const auto target_index = inst.branch_target / sizeof(uint32_t);
|
||||
if (branch_targets.empty()) {
|
||||
branch_targets.resize(code.size());
|
||||
}
|
||||
branch_targets[target_index] = true;
|
||||
}
|
||||
if (inst.opcode == Opcode::SEndpgm &&
|
||||
(word_index >= code.size() || !branch_targets.contains(word_index * 4u))) {
|
||||
(word_index >= code.size() || branch_targets.empty() || !branch_targets[word_index])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1001,7 +1015,7 @@ std::string InstructionToString(const Instruction& inst) {
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
return fmt::format("0x{:08x}: unsupported family={} opcode=0x{:02x} raw=[{}] reason={}",
|
||||
inst.pc, FamilyToString(inst.family).c_str(), inst.opcode_id,
|
||||
RawWordsToString(inst).c_str(), inst.unsupported_reason.c_str());
|
||||
RawWordsToString(inst).c_str(), inst.unsupported_reason);
|
||||
}
|
||||
if (inst.family == Family::SOPC) {
|
||||
return WithUnsupportedReason(inst, FormatSources(inst));
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
@@ -664,7 +665,7 @@ struct Instruction {
|
||||
bool compr = false;
|
||||
bool vm = false;
|
||||
} exp;
|
||||
std::string unsupported_reason;
|
||||
std::string_view unsupported_reason;
|
||||
};
|
||||
|
||||
struct Program {
|
||||
@@ -672,13 +673,17 @@ struct Program {
|
||||
std::vector<Instruction> instructions;
|
||||
};
|
||||
|
||||
// Code spans are trusted to contain complete instructions, valid branch targets, and 32-bit PCs.
|
||||
Family GetInstructionFamily(uint32_t word);
|
||||
// The output object must be freshly initialized.
|
||||
bool DecodeInstruction(std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeProgram(std::span<const uint32_t> code, Program& program, std::string* error);
|
||||
|
||||
bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand& operand, std::string* error);
|
||||
bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand& operand, std::string* error);
|
||||
bool DecodeVectorGpr(uint32_t reg, Operand& operand, std::string* error);
|
||||
bool ReadLiteralOperands(std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
void DecodeVectorGpr(uint32_t reg, Operand& operand);
|
||||
void ReadLiteralOperands(std::span<const uint32_t> code, uint32_t word_index, Instruction& inst);
|
||||
void SetRawWords(Instruction& inst, std::span<const uint32_t> code, uint32_t word_index,
|
||||
uint32_t word_count);
|
||||
void SetUnsupported(Instruction& inst, Family family, uint32_t opcode_id, const char* reason);
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include "graphics/shader/recompiler/frontend/decode/OpcodeTable.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
namespace {
|
||||
|
||||
@@ -30,7 +28,7 @@ struct Vop2OpcodeInfo {
|
||||
Vop2SdwaProfile sdwa_profile = Vop2SdwaProfile::None;
|
||||
};
|
||||
|
||||
constexpr Vop2OpcodeInfo VOP2_OPS[] = {
|
||||
constexpr Vop2OpcodeInfo VOP2_OPCODE_LIST[] = {
|
||||
{0x01u, Opcode::VCndmaskB32, Vop2SdwaProfile::Cndmask},
|
||||
{0x02u, Opcode::VDot2cF32F16},
|
||||
{0x03u, Opcode::VAddF32, Vop2SdwaProfile::Float32},
|
||||
@@ -81,13 +79,14 @@ constexpr Vop2OpcodeInfo VOP2_OPS[] = {
|
||||
{0x3au, Opcode::VMinF16, Vop2SdwaProfile::Float16},
|
||||
{0x3cu, Opcode::VPkFmacF16},
|
||||
};
|
||||
static_assert(Detail::HasUniqueEncodings(VOP2_OPS));
|
||||
|
||||
constexpr auto VOP2_OPS = Detail::MakeOpcodeTable<0x40>(VOP2_OPCODE_LIST);
|
||||
|
||||
constexpr Opcode LookupVop2Opcode(uint32_t encoding) {
|
||||
return Detail::LookupOpcode(VOP2_OPS, encoding);
|
||||
}
|
||||
|
||||
constexpr OpcodeMap VOP1_OPS[] = {
|
||||
constexpr OpcodeMap VOP1_OPCODE_LIST[] = {
|
||||
{0x00u, Opcode::VNop},
|
||||
{0x01u, Opcode::VMovB32},
|
||||
{0x02u, Opcode::VReadfirstlaneB32},
|
||||
@@ -138,7 +137,9 @@ constexpr OpcodeMap VOP1_OPS[] = {
|
||||
{0x5eu, Opcode::VRndneF16},
|
||||
};
|
||||
|
||||
constexpr OpcodeMap VOP3_ENCODED_VOP1_OPS[] = {
|
||||
constexpr auto VOP1_OPS = Detail::MakeOpcodeTable<0x100>(VOP1_OPCODE_LIST);
|
||||
|
||||
constexpr OpcodeMap VOP3_ENCODED_VOP1_OPCODE_LIST[] = {
|
||||
{0x00u, Opcode::VNop},
|
||||
{0x01u, Opcode::VMovB32},
|
||||
{0x02u, Opcode::VReadfirstlaneB32},
|
||||
@@ -184,13 +185,15 @@ constexpr OpcodeMap VOP3_ENCODED_VOP1_OPS[] = {
|
||||
{0x5eu, Opcode::VRndneF16},
|
||||
};
|
||||
|
||||
constexpr auto VOP3_ENCODED_VOP1_OPS = Detail::MakeOpcodeTable<0x80>(VOP3_ENCODED_VOP1_OPCODE_LIST);
|
||||
|
||||
struct VopcOpcodeInfo {
|
||||
uint32_t encoding = 0;
|
||||
Opcode decoded = Opcode::Unknown;
|
||||
bool supports_dpp = true;
|
||||
};
|
||||
|
||||
constexpr VopcOpcodeInfo VOPC_OPS[] = {
|
||||
constexpr VopcOpcodeInfo VOPC_OPCODE_LIST[] = {
|
||||
{0x00u, Opcode::VCmpFF32}, {0x01u, Opcode::VCmpLtF32},
|
||||
{0x02u, Opcode::VCmpEqF32}, {0x03u, Opcode::VCmpLeF32},
|
||||
{0x04u, Opcode::VCmpGtF32}, {0x05u, Opcode::VCmpLgF32},
|
||||
@@ -235,9 +238,10 @@ constexpr VopcOpcodeInfo VOPC_OPS[] = {
|
||||
{0xdcu, Opcode::VCmpxGtF16}, {0xdeu, Opcode::VCmpxGeF16},
|
||||
{0xfdu, Opcode::VCmpxNeqF16}, {0xfeu, Opcode::VCmpxNltF16},
|
||||
};
|
||||
static_assert(Detail::HasUniqueEncodings(VOPC_OPS));
|
||||
|
||||
constexpr OpcodeMap VOP3_OPS[] = {
|
||||
constexpr auto VOPC_OPS = Detail::MakeOpcodeTable<0x100>(VOPC_OPCODE_LIST);
|
||||
|
||||
constexpr OpcodeMap VOP3_OPCODE_LIST[] = {
|
||||
{0x141u, Opcode::VMadF32}, {0x142u, Opcode::VMadI32I24},
|
||||
{0x143u, Opcode::VMadU32U24}, {0x176u, Opcode::VMadU64U32},
|
||||
{0x144u, Opcode::VCubeidF32}, {0x145u, Opcode::VCubescF32},
|
||||
@@ -275,7 +279,9 @@ constexpr OpcodeMap VOP3_OPS[] = {
|
||||
{0x14fu, Opcode::VAlignbyteB32},
|
||||
};
|
||||
|
||||
constexpr OpcodeMap VOP3P_OPS[] = {
|
||||
constexpr auto VOP3_OPS = Detail::MakeOpcodeTable<0x400>(VOP3_OPCODE_LIST);
|
||||
|
||||
constexpr OpcodeMap VOP3P_OPCODE_LIST[] = {
|
||||
{0x00u, Opcode::VPkMadI16}, {0x01u, Opcode::VPkMulLoU16}, {0x02u, Opcode::VPkAddI16},
|
||||
{0x03u, Opcode::VPkSubI16}, {0x04u, Opcode::VPkLshlrevB16}, {0x05u, Opcode::VPkLshrrevB16},
|
||||
{0x06u, Opcode::VPkAshrrevI16}, {0x07u, Opcode::VPkMaxI16}, {0x08u, Opcode::VPkMinI16},
|
||||
@@ -286,6 +292,8 @@ constexpr OpcodeMap VOP3P_OPS[] = {
|
||||
{0x22u, Opcode::VMadMixhiF16},
|
||||
};
|
||||
|
||||
constexpr auto VOP3P_OPS = Detail::MakeOpcodeTable<0x80>(VOP3P_OPCODE_LIST);
|
||||
|
||||
bool IsVop2LiteralMadOpcode(uint32_t opcode) {
|
||||
return opcode == 0x20u || opcode == 0x21u || opcode == 0x2cu || opcode == 0x2du;
|
||||
}
|
||||
@@ -312,7 +320,7 @@ Opcode LookupVop3Opcode(uint32_t opcode) {
|
||||
if (opcode >= 0x180u && opcode <= 0x1ffu) {
|
||||
return Detail::LookupOpcode(VOP3_ENCODED_VOP1_OPS, opcode - 0x180u);
|
||||
}
|
||||
return Detail::LookupOpcode(VOP3_OPS, opcode);
|
||||
return Opcode::Unsupported;
|
||||
}
|
||||
|
||||
bool IsVop3EncodedVopc(uint32_t opcode) {
|
||||
@@ -573,13 +581,6 @@ bool ValidateVop1Sdwa(Instruction& inst, uint32_t opcode, uint32_t modifier) {
|
||||
|
||||
bool DecodeVop1Sdwa(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
uint32_t opcode, uint32_t vdst, Instruction& inst, std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated VOP1 SDWA instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto modifier = code[word_index + 1u];
|
||||
const auto src0 = modifier & 0xffu;
|
||||
const auto dst_sel = (modifier >> 8u) & 0x7u;
|
||||
@@ -598,9 +599,14 @@ bool DecodeVop1Sdwa(uint32_t pc, std::span<const uint32_t> code, uint32_t word_i
|
||||
}
|
||||
|
||||
const bool scalar_dst = UsesScalarDestination(inst.opcode);
|
||||
if (!(scalar_dst ? DecodeScalarDestination(vdst, pc, inst.dst, error)
|
||||
: DecodeVectorGpr(vdst, inst.dst, error)) ||
|
||||
!DecodeScalarSource(src0 + (s0 == 0u ? 256u : 0u), pc, inst.src0, error)) {
|
||||
if (scalar_dst) {
|
||||
if (!DecodeScalarDestination(vdst, pc, inst.dst, error)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
DecodeVectorGpr(vdst, inst.dst);
|
||||
}
|
||||
if (!DecodeScalarSource(src0 + (s0 == 0u ? 256u : 0u), pc, inst.src0, error)) {
|
||||
return false;
|
||||
}
|
||||
inst.dst.sdwa_sel = dst_sel;
|
||||
@@ -612,7 +618,8 @@ bool DecodeVop1Sdwa(uint32_t pc, std::span<const uint32_t> code, uint32_t word_i
|
||||
inst.src0.negate = src0_neg != 0u;
|
||||
inst.src0.absolute = src0_abs != 0u;
|
||||
inst.src_count = 1;
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ApplyDppModifier(Operand& operand, uint32_t modifier) {
|
||||
@@ -628,21 +635,19 @@ void ApplyDppModifier(Operand& operand, uint32_t modifier) {
|
||||
|
||||
bool DecodeVop1Dpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
uint32_t opcode, uint32_t vdst, Instruction& inst, std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated VOP1 DPP instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto modifier = code[word_index + 1u];
|
||||
const auto src0 = modifier & 0xffu;
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
|
||||
const bool scalar_dst = UsesScalarDestination(inst.opcode);
|
||||
if (!(scalar_dst ? DecodeScalarDestination(vdst, pc, inst.dst, error)
|
||||
: DecodeVectorGpr(vdst, inst.dst, error)) ||
|
||||
!DecodeScalarSource(src0 + 256u, pc, inst.src0, error)) {
|
||||
if (scalar_dst) {
|
||||
if (!DecodeScalarDestination(vdst, pc, inst.dst, error)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
DecodeVectorGpr(vdst, inst.dst);
|
||||
}
|
||||
if (!DecodeScalarSource(src0 + 256u, pc, inst.src0, error)) {
|
||||
return false;
|
||||
}
|
||||
ApplyDppModifier(inst.src0, modifier);
|
||||
@@ -653,7 +658,8 @@ bool DecodeVop1Dpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_in
|
||||
"VOP1 DPP integer source modifiers are not supported");
|
||||
return true;
|
||||
}
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
using Vop1ModifierDecodeFn = bool (*)(uint32_t pc, std::span<const uint32_t> code,
|
||||
@@ -976,19 +982,13 @@ bool FinalizeVop2Instruction(uint32_t pc, std::span<const uint32_t> code, uint32
|
||||
break;
|
||||
default: inst.src_count = 2; break;
|
||||
}
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeVop2Sdwa(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
uint32_t opcode, uint32_t vdst, uint32_t vsrc1, Instruction& inst,
|
||||
std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated VOP2 SDWA instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto modifier = code[word_index + 1u];
|
||||
const auto fields = DecodeVop2SdwaFields(modifier);
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
@@ -996,8 +996,8 @@ bool DecodeVop2Sdwa(uint32_t pc, std::span<const uint32_t> code, uint32_t word_i
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!DecodeVectorGpr(vdst, inst.dst, error) ||
|
||||
!DecodeScalarSource(fields.src0 + (fields.s0 == 0u ? 256u : 0u), pc, inst.src0, error) ||
|
||||
DecodeVectorGpr(vdst, inst.dst);
|
||||
if (!DecodeScalarSource(fields.src0 + (fields.s0 == 0u ? 256u : 0u), pc, inst.src0, error) ||
|
||||
!DecodeScalarSource(vsrc1 + (fields.s1 == 0u ? 256u : 0u), pc, inst.src1, error)) {
|
||||
return false;
|
||||
}
|
||||
@@ -1019,20 +1019,13 @@ bool DecodeVop2Sdwa(uint32_t pc, std::span<const uint32_t> code, uint32_t word_i
|
||||
bool DecodeVop2Dpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
uint32_t opcode, uint32_t vdst, uint32_t vsrc1, Instruction& inst,
|
||||
std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated VOP2 DPP instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto modifier = code[word_index + 1u];
|
||||
const auto src0 = modifier & 0xffu;
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
|
||||
if (!DecodeVectorGpr(vdst, inst.dst, error) ||
|
||||
!DecodeScalarSource(src0 + 256u, pc, inst.src0, error) ||
|
||||
!DecodeVectorGpr(vsrc1, inst.src1, error)) {
|
||||
DecodeVectorGpr(vdst, inst.dst);
|
||||
DecodeVectorGpr(vsrc1, inst.src1);
|
||||
if (!DecodeScalarSource(src0 + 256u, pc, inst.src0, error)) {
|
||||
return false;
|
||||
}
|
||||
ApplyDefaultVop2F16Destination(inst);
|
||||
@@ -1120,13 +1113,6 @@ bool SupportsVopcSdwa(Opcode opcode) {
|
||||
|
||||
bool DecodeVopcSdwa(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
uint32_t opcode, uint32_t vsrc1, Instruction& inst, std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated VOPC SDWA instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto modifier = code[word_index + 1u];
|
||||
const auto fields = DecodeVopcSdwaFields(modifier);
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
@@ -1160,18 +1146,12 @@ bool DecodeVopcSdwa(uint32_t pc, std::span<const uint32_t> code, uint32_t word_i
|
||||
inst.src1.negate = fields.src1_neg != 0u;
|
||||
inst.src1.absolute = fields.src1_abs != 0u;
|
||||
inst.src_count = 2;
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeVopcDpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
uint32_t opcode, uint32_t vsrc1, Instruction& inst, std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated VOPC DPP instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto modifier = code[word_index + 1u];
|
||||
const auto src0 = modifier & 0xffu;
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
@@ -1184,8 +1164,8 @@ bool DecodeVopcDpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_in
|
||||
SetUnsupported(inst, Family::VOPC, opcode, "VOPC DPP modifier is not supported for opcode");
|
||||
return true;
|
||||
}
|
||||
if (!DecodeScalarSource(src0 + 256u, pc, inst.src0, error) ||
|
||||
!DecodeVectorGpr(vsrc1, inst.src1, error)) {
|
||||
DecodeVectorGpr(vsrc1, inst.src1);
|
||||
if (!DecodeScalarSource(src0 + 256u, pc, inst.src0, error)) {
|
||||
return false;
|
||||
}
|
||||
inst.dst.kind = IsVopcCompareExec(inst.opcode) ? OperandKind::ExecLo : OperandKind::VccLo;
|
||||
@@ -1193,7 +1173,8 @@ bool DecodeVopcDpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_in
|
||||
inst.src1.negate = ((modifier >> 22u) & 0x1u) != 0u;
|
||||
inst.src1.absolute = ((modifier >> 23u) & 0x1u) != 0u;
|
||||
inst.src_count = 2;
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t NativeVop3SourceCount(Opcode opcode) {
|
||||
@@ -1480,11 +1461,6 @@ bool DecodeVop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
inst.opcode = LookupVop2Opcode(opcode);
|
||||
SetRawWords(inst, code, word_index, 1);
|
||||
|
||||
switch (opcode) {
|
||||
case 0x3eu: return DecodeVopc(pc, code, word_index, inst, error);
|
||||
case 0x3fu: return DecodeVop1(pc, code, word_index, inst, error);
|
||||
default: break;
|
||||
}
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
SetUnsupported(inst, Family::VOP2, opcode, "VOP2 opcode is not implemented");
|
||||
return true;
|
||||
@@ -1498,9 +1474,9 @@ bool DecodeVop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!DecodeVectorGpr(vdst, inst.dst, error) ||
|
||||
!DecodeScalarSource(src0, pc, inst.src0, error) ||
|
||||
!DecodeVectorGpr(vsrc1, inst.src1, error)) {
|
||||
DecodeVectorGpr(vdst, inst.dst);
|
||||
DecodeVectorGpr(vsrc1, inst.src1);
|
||||
if (!DecodeScalarSource(src0, pc, inst.src0, error)) {
|
||||
return false;
|
||||
}
|
||||
ApplyDefaultVop2F16Destination(inst);
|
||||
@@ -1539,13 +1515,19 @@ bool DecodeVop1(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
return true;
|
||||
}
|
||||
const bool scalar_dst = UsesScalarDestination(inst.opcode);
|
||||
if (!(scalar_dst ? DecodeScalarDestination(vdst, pc, inst.dst, error)
|
||||
: DecodeVectorGpr(vdst, inst.dst, error)) ||
|
||||
!DecodeScalarSource(src0, pc, inst.src0, error)) {
|
||||
if (scalar_dst) {
|
||||
if (!DecodeScalarDestination(vdst, pc, inst.dst, error)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
DecodeVectorGpr(vdst, inst.dst);
|
||||
}
|
||||
if (!DecodeScalarSource(src0, pc, inst.src0, error)) {
|
||||
return false;
|
||||
}
|
||||
inst.src_count = 1;
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeVopc(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
@@ -1572,23 +1554,17 @@ bool DecodeVopc(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
SetUnsupported(inst, Family::VOPC, opcode, "VOPC opcode is not implemented");
|
||||
return true;
|
||||
}
|
||||
if (!DecodeScalarSource(src0, pc, inst.src0, error) ||
|
||||
!DecodeVectorGpr(vsrc1, inst.src1, error)) {
|
||||
DecodeVectorGpr(vsrc1, inst.src1);
|
||||
if (!DecodeScalarSource(src0, pc, inst.src0, error)) {
|
||||
return false;
|
||||
}
|
||||
inst.src_count = 2;
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeVop3(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated VOP3 instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t opcode = (word0 >> 16u) & 0x3ffu;
|
||||
@@ -1655,7 +1631,7 @@ bool DecodeVop3(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
// VOP3A uses VDST for VOPC and the scalar-destination lane-read opcodes.
|
||||
dst_ok = DecodeScalarDestination(vdst, pc, inst.dst, error);
|
||||
} else {
|
||||
dst_ok = DecodeVectorGpr(vdst, inst.dst, error);
|
||||
DecodeVectorGpr(vdst, inst.dst);
|
||||
}
|
||||
if (!dst_ok || !DecodeScalarSource(src0, pc, inst.src0, error)) {
|
||||
return false;
|
||||
@@ -1674,14 +1650,16 @@ bool DecodeVop3(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
if (native_source_modifiers) {
|
||||
ApplyNativeVop3SourceModifiers(inst, abs, neg);
|
||||
}
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
if (IsVop3EncodedVop1(opcode)) {
|
||||
inst.src_count = 1;
|
||||
if (native_source_modifiers) {
|
||||
ApplyNativeVop3SourceModifiers(inst, abs, neg);
|
||||
}
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
if (carry_in_out) {
|
||||
if (!DecodeScalarDestination(sdst, pc, inst.dst2, error) ||
|
||||
@@ -1690,7 +1668,8 @@ bool DecodeVop3(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
return false;
|
||||
}
|
||||
inst.src_count = 3;
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
if (vop3b_carry_out) {
|
||||
if (!DecodeScalarDestination(sdst, pc, inst.dst2, error) ||
|
||||
@@ -1698,7 +1677,8 @@ bool DecodeVop3(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
return false;
|
||||
}
|
||||
inst.src_count = 2;
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
if (vop3b_mad_u64) {
|
||||
if (!DecodeScalarDestination(sdst, pc, inst.dst2, error) ||
|
||||
@@ -1707,7 +1687,8 @@ bool DecodeVop3(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
return false;
|
||||
}
|
||||
inst.src_count = 3;
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
if (IsVop3EncodedVop2(opcode)) {
|
||||
if (!DecodeScalarSource(src1, pc, inst.src1, error)) {
|
||||
@@ -1724,7 +1705,8 @@ bool DecodeVop3(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
if (native_source_modifiers) {
|
||||
ApplyNativeVop3SourceModifiers(inst, abs, neg);
|
||||
}
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
if (!DecodeScalarSource(src1, pc, inst.src1, error)) {
|
||||
return false;
|
||||
@@ -1744,31 +1726,26 @@ bool DecodeVop3(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
} else if (native_source_modifiers) {
|
||||
ApplyNativeVop3SourceModifiers(inst, abs, neg);
|
||||
}
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeVop3p(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated VOP3P instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t opcode = (word0 >> 16u) & 0x7fu;
|
||||
const uint32_t vdst = word0 & 0xffu;
|
||||
const uint32_t neg_hi = (word0 >> 8u) & 0x7u;
|
||||
const uint32_t op_sel = (word0 >> 11u) & 0x7u;
|
||||
const uint32_t op_sel_hi_2 = (word0 >> 14u) & 0x1u;
|
||||
const uint32_t op_sel_hi_0 = (word0 >> 14u) & 0x1u;
|
||||
const uint32_t clamp = (word0 >> 15u) & 0x1u;
|
||||
const uint32_t src0 = word1 & 0x1ffu;
|
||||
const uint32_t src1 = (word1 >> 9u) & 0x1ffu;
|
||||
const uint32_t src2 = (word1 >> 18u) & 0x1ffu;
|
||||
const uint32_t op_sel_hi = ((word1 >> 27u) & 0x3u) | (op_sel_hi_2 << 2u);
|
||||
const uint32_t neg = (word1 >> 29u) & 0x7u;
|
||||
const uint32_t op_sel_hi =
|
||||
op_sel_hi_0 | (((word1 >> 28u) & 0x1u) << 1u) | (((word1 >> 27u) & 0x1u) << 2u);
|
||||
const uint32_t neg = (word1 >> 29u) & 0x7u;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word0;
|
||||
@@ -1782,8 +1759,8 @@ bool DecodeVop3p(uint32_t pc, std::span<const uint32_t> code, uint32_t word_inde
|
||||
return true;
|
||||
}
|
||||
inst.src_count = Vop3pSourceCount(inst.opcode);
|
||||
if (!DecodeVectorGpr(vdst, inst.dst, error) ||
|
||||
!DecodeScalarSource(src0, pc, inst.src0, error) ||
|
||||
DecodeVectorGpr(vdst, inst.dst);
|
||||
if (!DecodeScalarSource(src0, pc, inst.src0, error) ||
|
||||
!DecodeScalarSource(src1, pc, inst.src1, error)) {
|
||||
return false;
|
||||
}
|
||||
@@ -1810,18 +1787,12 @@ bool DecodeVop3p(uint32_t pc, std::span<const uint32_t> code, uint32_t word_inde
|
||||
} else if (inst.opcode == Opcode::VFmaF32) {
|
||||
ApplyVop3pMixAbsModifiers(inst);
|
||||
}
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
ReadLiteralOperands(code, word_index, inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeVintrp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error) {
|
||||
if (word_index >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated VINTRP instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DecodeVintrp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst) {
|
||||
const uint32_t word = code[word_index];
|
||||
const uint32_t opcode = (word >> 16u) & 0x3u;
|
||||
const uint32_t vdst = (word >> 18u) & 0xffu;
|
||||
@@ -1838,18 +1809,16 @@ bool DecodeVintrp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_ind
|
||||
SetRawWords(inst, code, word_index, 1);
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
SetUnsupported(inst, Family::VINTRP, opcode, "VINTRP opcode is not implemented");
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DecodeVectorGpr(vdst, inst.dst, error)) {
|
||||
return false;
|
||||
}
|
||||
DecodeVectorGpr(vdst, inst.dst);
|
||||
if (inst.opcode == Opcode::VInterpMovF32) {
|
||||
inst.src0.kind = OperandKind::IntegerInlineConstant;
|
||||
inst.src0.value = vsrc & 0x3u;
|
||||
inst.src0.signed_val = static_cast<int32_t>(inst.src0.value);
|
||||
} else if (!DecodeVectorGpr(vsrc, inst.src0, error)) {
|
||||
return false;
|
||||
} else {
|
||||
DecodeVectorGpr(vsrc, inst.src0);
|
||||
}
|
||||
inst.src1.kind = OperandKind::IntegerInlineConstant;
|
||||
inst.src1.value = attr;
|
||||
@@ -1858,7 +1827,6 @@ bool DecodeVintrp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_ind
|
||||
inst.src2.value = chan;
|
||||
inst.src2.signed_val = static_cast<int32_t>(chan);
|
||||
inst.src_count = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
@@ -15,8 +15,8 @@ bool DecodeVop3(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
std::string* error);
|
||||
bool DecodeVop3p(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error);
|
||||
bool DecodeVintrp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error);
|
||||
void DecodeVintrp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
|
||||
@@ -505,14 +505,15 @@ constexpr u32 EncodeVop3pWord0(u32 opcode, u32 dst, u32 op_sel_hi = 0,
|
||||
u32 op_sel = 0, u32 neg_hi = 0,
|
||||
bool clamp = false) {
|
||||
return (0x33u << 26u) | ((opcode & 0x7fu) << 16u) | ((neg_hi & 0x7u) << 8u) |
|
||||
((op_sel & 0x7u) << 11u) | ((op_sel_hi & 0x4u) << 12u) |
|
||||
((op_sel & 0x7u) << 11u) | ((op_sel_hi & 0x1u) << 14u) |
|
||||
(clamp ? (1u << 15u) : 0u) | (dst & 0xffu);
|
||||
}
|
||||
|
||||
constexpr u32 EncodeVop3pWord1(u32 src0, u32 src1, u32 src2 = 0,
|
||||
u32 op_sel_hi = 0, u32 neg = 0) {
|
||||
return (src0 & 0x1ffu) | ((src1 & 0x1ffu) << 9u) | ((src2 & 0x1ffu) << 18u) |
|
||||
((op_sel_hi & 0x3u) << 27u) | ((neg & 0x7u) << 29u);
|
||||
(((op_sel_hi >> 2u) & 0x1u) << 27u) |
|
||||
(((op_sel_hi >> 1u) & 0x1u) << 28u) | ((neg & 0x7u) << 29u);
|
||||
}
|
||||
|
||||
constexpr u32 EncodeVopc(u32 opcode, u32 src0, u32 src1) {
|
||||
@@ -11118,14 +11119,15 @@ TestCase ScalarBitfieldPack() {
|
||||
return {"ScalarBitfieldPack",
|
||||
code,
|
||||
{},
|
||||
{0xf0000000u, 8, 9, 1, 0, 0, 0x0000000fu, 0, 0x00000f00u, 0x0000000fu,
|
||||
0xddddbbbbu, 0xccccbbbbu, 0xccccaaaau, 1, 1, 40, 5, 0xffffffffu, 0,
|
||||
1},
|
||||
{0xf0000000u, 8, 9, 1, 0,
|
||||
0, 0x0000000fu, 0, 0x00000f00u, 0x0000000fu,
|
||||
0xddddbbbbu, 0xccccbbbbu, 0xccccaaaau, 1, 1,
|
||||
40, 5, 0xffffffffu, 0, 1},
|
||||
{O::SMovB32, O::SBrevB32, O::SBcnt1I32B32, O::SBcnt1I32B64,
|
||||
O::SFf1I32B64, O::SBitreplicateB64B32, O::SBfmB32, O::SBfeU32,
|
||||
O::SPackLlB32B16,
|
||||
O::SPackLhB32B16, O::SPackHhB32B16, O::SBitcmp0B32, O::SBitcmp1B32,
|
||||
O::SCselectB32, O::VMovB32, O::BufferStoreDword, O::SEndpgm}};
|
||||
O::SPackLlB32B16, O::SPackLhB32B16, O::SPackHhB32B16, O::SBitcmp0B32,
|
||||
O::SBitcmp1B32, O::SCselectB32, O::VMovB32, O::BufferStoreDword,
|
||||
O::SEndpgm}};
|
||||
}
|
||||
|
||||
TestCase ScalarBrevB32PreservesScc() {
|
||||
|
||||
+120
-43
@@ -11,20 +11,20 @@
|
||||
#include "graphics/host_gpu/renderer/pipeline/shaderSubgroup.h"
|
||||
#include "graphics/shader/recompiler/ExecMask.h"
|
||||
#include "graphics/shader/recompiler/ShaderRecompiler.h"
|
||||
#include "graphics/shader/recompiler/backend/spirv/SpirvEmitter.h"
|
||||
#include "graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h"
|
||||
#include "graphics/shader/recompiler/frontend/cfg/ShaderCFG.h"
|
||||
#include "graphics/shader/recompiler/frontend/decode/ShaderDecoder.h"
|
||||
#include "graphics/shader/recompiler/frontend/translate/Translate.h"
|
||||
#include "graphics/shader/recompiler/backend/spirv/SpirvEmitter.h"
|
||||
#include "graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h"
|
||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||
#include "graphics/shader/recompiler/ir/ValueProgram.h"
|
||||
#include "graphics/shader/recompiler/ir/passes/ConstantPropagation.h"
|
||||
#include "graphics/shader/recompiler/ir/passes/DeadCodeElimination.h"
|
||||
#include "graphics/shader/recompiler/ir/passes/ReadLaneElimination.h"
|
||||
#include "graphics/shader/recompiler/ir/passes/ResourceTracking.h"
|
||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||
#include "graphics/shader/recompiler/ir/passes/ShaderInfoCollection.h"
|
||||
#include "graphics/shader/recompiler/ir/passes/SrtWalker.h"
|
||||
#include "graphics/shader/recompiler/ir/passes/SsaRewrite.h"
|
||||
#include "graphics/shader/recompiler/ir/ValueProgram.h"
|
||||
#include "graphics/shader/shader.h"
|
||||
#include "libs/agc.h"
|
||||
#include "spirv-tools/libspirv.hpp"
|
||||
@@ -163,8 +163,7 @@ uint32_t SpirvInstructionOpcodeCount(const std::vector<uint32_t> &binary,
|
||||
}
|
||||
|
||||
bool SpirvSourceHasInstructionOperand(const std::string &source,
|
||||
const char *opcode,
|
||||
const char *operand) {
|
||||
const char *opcode, const char *operand) {
|
||||
std::istringstream lines(source);
|
||||
std::string line;
|
||||
while (std::getline(lines, line)) {
|
||||
@@ -835,13 +834,14 @@ constexpr uint32_t EncodeVop3pWord0(uint32_t opcode, uint32_t dst,
|
||||
uint32_t neg_hi = 0, bool clamp = false) {
|
||||
return (0x33u << 26u) | ((opcode & 0x7fu) << 16u) | (dst & 0xffu) |
|
||||
((neg_hi & 0x7u) << 8u) | ((op_sel & 0x7u) << 11u) |
|
||||
(((op_sel_hi >> 2u) & 0x1u) << 14u) | (clamp ? (1u << 15u) : 0u);
|
||||
((op_sel_hi & 0x1u) << 14u) | (clamp ? (1u << 15u) : 0u);
|
||||
}
|
||||
|
||||
constexpr uint32_t EncodeVop3pWord1(uint32_t src0, uint32_t src1, uint32_t src2,
|
||||
uint32_t op_sel_hi = 0, uint32_t neg = 0) {
|
||||
return (src0 & 0x1ffu) | ((src1 & 0x1ffu) << 9u) | ((src2 & 0x1ffu) << 18u) |
|
||||
((op_sel_hi & 0x3u) << 27u) | ((neg & 0x7u) << 29u);
|
||||
(((op_sel_hi >> 2u) & 0x1u) << 27u) |
|
||||
(((op_sel_hi >> 1u) & 0x1u) << 28u) | ((neg & 0x7u) << 29u);
|
||||
}
|
||||
|
||||
constexpr uint32_t EncodeSmem0(uint32_t opcode, uint32_t dst, uint32_t sbase) {
|
||||
@@ -3315,6 +3315,81 @@ void CheckNewDecoderUnsupported(const uint32_t *shader, uint32_t words,
|
||||
"unsupported lowering error was not explicit");
|
||||
}
|
||||
|
||||
void TestNewShaderDecoderArchitecture() {
|
||||
using namespace ShaderRecompiler::Decoder;
|
||||
|
||||
Check(GetInstructionFamily(EncodeVop1(0x01, 2, 3)) == Family::VOP1,
|
||||
"decoder did not classify compact VOP1 directly");
|
||||
Check(GetInstructionFamily(EncodeVopc(0x02, 2, 3)) == Family::VOPC,
|
||||
"decoder did not classify compact VOPC directly");
|
||||
Check(GetInstructionFamily(EncodeDs0(0x36)) == Family::DS,
|
||||
"decoder did not classify DS directly");
|
||||
|
||||
const uint32_t offset_code[] = {0u, EncodeVop1(0x01, 2, 3)};
|
||||
Instruction direct;
|
||||
std::string error;
|
||||
Check(DecodeInstruction(offset_code, 1u, direct, &error), error.c_str());
|
||||
Check(direct.pc == 4u && direct.family == Family::VOP1 &&
|
||||
direct.opcode == Opcode::VMovB32 && direct.dst.reg == 2u &&
|
||||
direct.src0.reg == 3u,
|
||||
"single-instruction decoder failed at a nonzero offset");
|
||||
|
||||
const uint32_t program_code[] = {EncodeVop1(0x01, 2, 3), EncodeSopp(0x01, 0)};
|
||||
Instruction program_direct;
|
||||
Check(DecodeInstruction(program_code, 0u, program_direct, &error),
|
||||
error.c_str());
|
||||
Program program;
|
||||
Check(DecodeProgram(program_code, program, &error), error.c_str());
|
||||
Check(program.instructions.size() == 2u &&
|
||||
program.instructions.front().family == program_direct.family &&
|
||||
program.instructions.front().opcode == program_direct.opcode &&
|
||||
program.instructions.front().word_count ==
|
||||
program_direct.word_count,
|
||||
"program decoder diverged from the single-instruction decoder");
|
||||
|
||||
const uint32_t literal_code[] = {EncodeVop1(0x01, 2, 255u), 0x12345678u};
|
||||
Instruction literal;
|
||||
Check(DecodeInstruction(literal_code, 0u, literal, &error), error.c_str());
|
||||
Check(literal.word_count == 2u && literal.src0.value == 0x12345678u,
|
||||
"single-instruction decoder lost a compact literal extension");
|
||||
|
||||
const uint32_t mimg_nsa[] = {EncodeMimg0(0x20, 0xf) | (3u << 1u),
|
||||
EncodeMimg1(4, 0, 1, 8), 0x03020100u,
|
||||
0x07060504u, 0x0b0a0908u};
|
||||
Instruction image;
|
||||
Check(DecodeInstruction(mimg_nsa, 0u, image, &error), error.c_str());
|
||||
Check(image.family == Family::MIMG && image.word_count == 5u &&
|
||||
image.image_nsa_dwords == 3u,
|
||||
"single-instruction decoder lost the MIMG NSA length");
|
||||
|
||||
const uint32_t ds_code[] = {EncodeDs0(0x36) | (1u << 17u),
|
||||
EncodeDs1(2, 0, 1)};
|
||||
Instruction ds;
|
||||
Check(DecodeInstruction(ds_code, 0u, ds, &error), error.c_str());
|
||||
Check(ds.opcode == Opcode::DsReadB32 && ds.gds,
|
||||
"DS decoder lost the GFX10 opcode or GDS fields");
|
||||
|
||||
const uint32_t boot_ds[] = {0xd8d4c480u, 0x45000045u};
|
||||
Instruction boot;
|
||||
Check(DecodeInstruction(boot_ds, 0u, boot, &error), error.c_str());
|
||||
Check(boot.opcode == Opcode::DsSwizzleB32 && boot.offset == 0xc480u,
|
||||
"DS decoder rejected a captured boot-shader instruction");
|
||||
|
||||
for (uint32_t source = 0; source < 3u; source++) {
|
||||
const uint32_t op_sel_hi = 1u << source;
|
||||
const uint32_t packed[] = {
|
||||
EncodeVop3pWord0(0x0e, 0, 0, op_sel_hi),
|
||||
EncodeVop3pWord1(256, 257, 258, op_sel_hi),
|
||||
};
|
||||
Instruction packed_inst;
|
||||
Check(DecodeInstruction(packed, 0u, packed_inst, &error), error.c_str());
|
||||
Check(packed_inst.src0.op_sel_hi == (source == 0u) &&
|
||||
packed_inst.src1.op_sel_hi == (source == 1u) &&
|
||||
packed_inst.src2.op_sel_hi == (source == 2u),
|
||||
"VOP3P OPSEL_HI source bit mapping is incorrect");
|
||||
}
|
||||
}
|
||||
|
||||
void TestNewShaderRecompilerRejectsDppOn64BitCompares() {
|
||||
const uint32_t opcodes[] = {0xa2u, 0xe4u, 0xe5u}; // eq_i64, gt_u64, ne_u64
|
||||
for (const auto opcode : opcodes) {
|
||||
@@ -6053,14 +6128,17 @@ void TestNewShaderRecompilerCfgLoopHeaderDynamicScalarBufferLoadStructured() {
|
||||
|
||||
void TestNewShaderRecompilerCfgLoopHeaderBufferLoadDispatcher() {
|
||||
const uint32_t shader[] = {
|
||||
EncodeSMovB32(0, 128), // preheader: s0 = 0
|
||||
EncodeMubuf0(0x0c), EncodeMubuf1(0, 0, 1), // loop:
|
||||
// buffer_load_dword
|
||||
// v0
|
||||
EncodeSMovB32(0, 128), // preheader: s0 = 0
|
||||
EncodeMubuf0(0x0c),
|
||||
EncodeMubuf1(0, 0, 1), // loop:
|
||||
// buffer_load_dword
|
||||
// v0
|
||||
EncodeSop2(0x00, 0, 0, 129), // s_add_u32 s0, s0, 1
|
||||
EncodeSopc(0x0a, 0, 130), // s_cmp_lt_u32 s0, 2
|
||||
EncodeSopp(0x05, 0xfffbu), // s_cbranch_scc1 loop
|
||||
EncodeMubuf0(0x1c, 0, false), EncodeMubuf1(0, 12, 0), 0xbf810000u,
|
||||
EncodeMubuf0(0x1c, 0, false),
|
||||
EncodeMubuf1(0, 12, 0),
|
||||
0xbf810000u,
|
||||
};
|
||||
|
||||
ShaderRecompiler::CompileOptions options;
|
||||
@@ -6458,16 +6536,16 @@ void TestNewShaderRecompilerCfgLoopEarlyContinuesNoSelection() {
|
||||
|
||||
void TestNewShaderRecompilerCfgLoopGatewaySelection() {
|
||||
const uint32_t shader[] = {
|
||||
EncodeSopc(0x0a, 0, 130), // loop: s_cmp_lt_u32 s0, 2
|
||||
EncodeSopp(0x04, 8), // loop exit -> end
|
||||
EncodeSopc(0x06, 1, 1), // skip-body condition
|
||||
EncodeSopp(0x05, 3), // skip body -> loop-control gateway
|
||||
EncodeSopc(0x06, 2, 2), // body early-break condition
|
||||
EncodeSopp(0x05, 4), // early break -> end
|
||||
EncodeSMovB32(3, 129), // body work
|
||||
EncodeSopc(0x0a, 0, 130), // loop-control gateway
|
||||
EncodeSopp(0x04, 1), // exit -> end, else latch
|
||||
EncodeSopp(0x02, 0xfff6u), // latch -> loop header
|
||||
EncodeSopc(0x0a, 0, 130), // loop: s_cmp_lt_u32 s0, 2
|
||||
EncodeSopp(0x04, 8), // loop exit -> end
|
||||
EncodeSopc(0x06, 1, 1), // skip-body condition
|
||||
EncodeSopp(0x05, 3), // skip body -> loop-control gateway
|
||||
EncodeSopc(0x06, 2, 2), // body early-break condition
|
||||
EncodeSopp(0x05, 4), // early break -> end
|
||||
EncodeSMovB32(3, 129), // body work
|
||||
EncodeSopc(0x0a, 0, 130), // loop-control gateway
|
||||
EncodeSopp(0x04, 1), // exit -> end, else latch
|
||||
EncodeSopp(0x02, 0xfff6u), // latch -> loop header
|
||||
0xbf810000u,
|
||||
};
|
||||
|
||||
@@ -7017,9 +7095,12 @@ void TestNewShaderRecompilerCompareMaskIsFullWaveBallot() {
|
||||
|
||||
void TestNewShaderRecompilerBufferLoadsGuardedByExec() {
|
||||
const uint32_t shader[] = {
|
||||
EncodeMubuf0(0x0c), EncodeMubuf1(0, 0, 1), // buffer_load_dword
|
||||
// v0
|
||||
EncodeMubuf0(0x1c, 0, false), EncodeMubuf1(0, 12, 0), EncodeSopp(0x01),
|
||||
EncodeMubuf0(0x0c),
|
||||
EncodeMubuf1(0, 0, 1), // buffer_load_dword
|
||||
// v0
|
||||
EncodeMubuf0(0x1c, 0, false),
|
||||
EncodeMubuf1(0, 12, 0),
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
|
||||
ShaderRecompiler::CompileOptions options;
|
||||
@@ -7430,9 +7511,7 @@ void TestNewShaderRecompilerPerInvocationU64Complement() {
|
||||
EncodeSop2(0x0f, 2, 126, 106), // s_and_b64 s[2:3], exec, vcc
|
||||
EncodeSop1(0x08, 4, 2), // s_not_b64 s[4:5], s[2:3]
|
||||
EncodeSop2(0x0f, 126, 126, 4), // s_and_b64 exec, exec, s[4:5]
|
||||
EncodeExp0(0x0c, 0xf),
|
||||
EncodeExp1(0, 1, 2, 3),
|
||||
EncodeSopp(0x01),
|
||||
EncodeExp0(0x0c, 0xf), EncodeExp1(0, 1, 2, 3), EncodeSopp(0x01),
|
||||
};
|
||||
|
||||
ShaderRecompiler::CompileOptions options;
|
||||
@@ -7542,7 +7621,7 @@ void TestNewShaderRecompilerExpPixelOutputs() {
|
||||
const auto compressed_ba_source =
|
||||
DisassembleSpirvBinary(compressed_ba_result.spirv);
|
||||
Check(CountSourceOccurrences(compressed_ba_source, "OpCompositeExtract") ==
|
||||
1u &&
|
||||
1u &&
|
||||
CountSourceOccurrences(compressed_ba_source,
|
||||
"OpBitFieldUExtract") == 2u,
|
||||
"compressed UINT16 BA-only export did not read and unpack VSRC1");
|
||||
@@ -7796,7 +7875,7 @@ void TestNewShaderRecompilerEarlyZDisabledWhenPixelKillEnabled() {
|
||||
Check(!Common::ContainsStr(ordinary_source, "pixel_valid_mask_active"),
|
||||
"ordinary pixel shader allocated pixel-valid state");
|
||||
Check(SpirvContainsExecutionMode(ordinary_result.spirv,
|
||||
ExecutionModeEarlyFragmentTests),
|
||||
ExecutionModeEarlyFragmentTests),
|
||||
"ordinary early-Z pixel shader lost EarlyFragmentTests");
|
||||
CheckSpirvBinaryValidates(ordinary_result.spirv);
|
||||
}
|
||||
@@ -8294,9 +8373,9 @@ void TestSrtWalkerRealSmemLowering() {
|
||||
|
||||
void TestSrtWalkerVccBaseLowering() {
|
||||
const uint32_t shader[] = {
|
||||
EncodeSMovB32(106, 27), EncodeSMovB32(107, 28),
|
||||
EncodeSMovB32(106, 27), EncodeSMovB32(107, 28),
|
||||
EncodeSmem0(0x02, 0, 53), 125u << 25u,
|
||||
EncodeMubuf0(0x1c), EncodeMubuf1(0, 0, 1),
|
||||
EncodeMubuf0(0x1c), EncodeMubuf1(0, 0, 1),
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
std::string error;
|
||||
@@ -8307,8 +8386,8 @@ void TestSrtWalkerVccBaseLowering() {
|
||||
Check(ir.values->srt_reads.size() == 4,
|
||||
"VCC-based SMEM lowering did not build four SRT reads");
|
||||
|
||||
const std::array<uint32_t, 4> table = {0x11111111u, 0x22222222u,
|
||||
0x33333333u, 0x44444444u};
|
||||
const std::array<uint32_t, 4> table = {0x11111111u, 0x22222222u, 0x33333333u,
|
||||
0x44444444u};
|
||||
std::array<uint32_t, 32> user_data{};
|
||||
const auto address = reinterpret_cast<uint64_t>(table.data());
|
||||
user_data[27] = static_cast<uint32_t>(address);
|
||||
@@ -8461,9 +8540,8 @@ void TestScalarMemoryLoadCrossesIntoVcc() {
|
||||
"wide SMEM destination crossing into VCC lost its descriptor source");
|
||||
for (uint32_t dword = 0; dword < 4; dword++) {
|
||||
const auto *value = source->dwords[dword].ResolveInstruction();
|
||||
Check(value != nullptr &&
|
||||
value->GetOpcode() ==
|
||||
ShaderRecompiler::IR::ValueOpcode::ReadConst,
|
||||
Check(value != nullptr && value->GetOpcode() ==
|
||||
ShaderRecompiler::IR::ValueOpcode::ReadConst,
|
||||
"wide SMEM descriptor lost a dword crossing into VCC");
|
||||
}
|
||||
}
|
||||
@@ -8698,11 +8776,9 @@ void TestNewShaderRecompilerPixelPipelineEntry() {
|
||||
CheckSpirvBinaryValidates(spirv);
|
||||
|
||||
const uint32_t vcc_load_shader[] = {
|
||||
EncodeSMovB32(106, 27), EncodeSMovB32(107, 28),
|
||||
EncodeSmem0(0x02, 44, 53), (0x7du << 25u) | 160u,
|
||||
EncodeMubuf0(0x0c), EncodeMubuf1(0, 11, 1),
|
||||
EncodeExp0(0x00, 0x1), EncodeExp1(0, 0, 0, 0),
|
||||
EncodeSopp(0x01),
|
||||
EncodeSMovB32(106, 27), EncodeSMovB32(107, 28), EncodeSmem0(0x02, 44, 53),
|
||||
(0x7du << 25u) | 160u, EncodeMubuf0(0x0c), EncodeMubuf1(0, 11, 1),
|
||||
EncodeExp0(0x00, 0x1), EncodeExp1(0, 0, 0, 0), EncodeSopp(0x01),
|
||||
};
|
||||
std::array<uint32_t, 44> table{};
|
||||
std::array<uint32_t, 1> buffer{};
|
||||
@@ -8899,6 +8975,7 @@ int main() {
|
||||
// Opcode semantics and optimized direct SPIR-V are exercised by
|
||||
// ShaderRecompilerComputeTests. The pre-SSA register-IR shape checks above
|
||||
// remain as historical decoder fixtures only.
|
||||
TestNewShaderDecoderArchitecture();
|
||||
TestNewShaderRecompilerRejectsDppOn64BitCompares();
|
||||
TestNewShaderRecompilerIrLookupMissFailsExplicitly();
|
||||
TestPsInputCountRegisterDecode();
|
||||
|
||||
Reference in New Issue
Block a user