mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
Optimize decoder
This commit is contained in:
@@ -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