Merge pull request #766 from Kikoarl/feat/s-scratch-load

feat(shader): implement S_SCRATCH_LOAD_DWORD, S_SCRATCH_LOAD_DWORDX2 and S_SCRATCH_LOAD_DWORDX4
This commit is contained in:
Dean 2026-10-06 12:52:17 +13:00 committed by GitHub
commit cb33f858c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 64 additions and 0 deletions

View File

@ -764,6 +764,14 @@ if(BUILD_TESTING)
set_tests_properties(scalar_bitcount64 PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
add_test_executable(scalar_scratch_load_tests ${LIBS_INCLUDE_DIR}/tests/ScalarScratchLoad.cpp)
target_link_libraries(scalar_scratch_load_tests PRIVATE shader_recompiler_agc_driver libc)
configure_windows_unwind(scalar_scratch_load_tests)
add_test(NAME scalar_scratch_load COMMAND scalar_scratch_load_tests)
if(WIN32)
set_tests_properties(scalar_scratch_load PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
add_test_executable(image_sample_gather_tests ${LIBS_INCLUDE_DIR}/tests/ImageSampleGather.cpp)
target_link_libraries(image_sample_gather_tests PRIVATE shader_recompiler_agc_driver libc)
configure_windows_unwind(image_sample_gather_tests)

View File

@ -0,0 +1,38 @@
#include "Translation/TranslationContext.hpp"
#include "RdnaDecoder/RdnaMemoryOpDecoder.hpp"
#include <array>
#include <stdexcept>
using namespace ShaderRecompiler;
static void Require(bool value) { if (!value) throw std::runtime_error("scalar scratch load regression"); }
static void Check(std::uint32_t opcode, RdnaOpcode expected, std::uint32_t dwords) {
const std::array<std::uint32_t, 2> code{
(0x3du << 26u) | (opcode << 18u) | (2u << 6u) | 1u,
(125u << 25u) | 0x10u
};
const RdnaInstruction instruction = DecodeRdnaSmem(0u, code, 0u);
Require(instruction.op == expected);
Require(instruction.family == RdnaInstructionFamily::SMEM);
Require(instruction.dataDwordCount == dwords);
Require(instruction.destination.kind == RdnaOperandKind::ScalarRegister);
Require(instruction.destination.reg == 2u);
Require(instruction.source0.kind == RdnaOperandKind::ScalarRegister);
Require(instruction.source0.reg == 2u);
Require(instruction.memoryOffset == 0x10);
IrProgram program;
auto& block = program.CreateBlock();
program.SetEntryBlock(block);
TranslationContext context(program, block, 256);
bool threw = false;
try {
context.TranslateInstruction(instruction);
} catch (const std::runtime_error&) {
threw = true;
}
Require(threw);
}
int main() {
Check(0x05u, RdnaOpcode::SScratchLoadDword, 1u);
Check(0x06u, RdnaOpcode::SScratchLoadDwordx2, 2u);
Check(0x07u, RdnaOpcode::SScratchLoadDwordx4, 4u);
}

View File

@ -697,6 +697,9 @@ enum class RdnaOpcode : std::uint16_t {
SBufferLoadDwordx4,
SBufferLoadDwordx8,
SBufferLoadDwordx16,
SScratchLoadDword,
SScratchLoadDwordx2,
SScratchLoadDwordx4,
SGetWaveidInWorkgroup,
BufferStoreFormatXy,
BufferStoreFormatXyz,

View File

@ -59,6 +59,9 @@ constexpr MemoryOpcodeInfo smemOpcodes[] = {
{0x02u, RdnaOpcode::SLoadDwordx4, 4, 32, false, false, false},
{0x03u, RdnaOpcode::SLoadDwordx8, 8, 32, false, false, false},
{0x04u, RdnaOpcode::SLoadDwordx16, 16, 32, false, false, false},
{0x05u, RdnaOpcode::SScratchLoadDword, 1, 32, false, false, false},
{0x06u, RdnaOpcode::SScratchLoadDwordx2, 2, 32, false, false, false},
{0x07u, RdnaOpcode::SScratchLoadDwordx4, 4, 32, false, false, false},
{0x08u, RdnaOpcode::SBufferLoadDword, 1, 32, false, false, false},
{0x09u, RdnaOpcode::SBufferLoadDwordx2, 2, 32, false, false, false},
{0x0au, RdnaOpcode::SBufferLoadDwordx4, 4, 32, false, false, false},

View File

@ -646,6 +646,9 @@ bool IsScalarMemoryOpcode(RdnaOpcode opcode) {
case RdnaOpcode::SBufferLoadDwordx4:
case RdnaOpcode::SBufferLoadDwordx8:
case RdnaOpcode::SBufferLoadDwordx16:
case RdnaOpcode::SScratchLoadDword:
case RdnaOpcode::SScratchLoadDwordx2:
case RdnaOpcode::SScratchLoadDwordx4:
return true;
default:
return false;

View File

@ -86,6 +86,7 @@ private:
IrU32 widenSubdword(IrValue* value, std::uint32_t bits, bool sign);
IrValue* narrowSubdword(IrU32 value, std::uint32_t bits);
bool sLoad(const RdnaInstruction& inst, bool raw);
bool sScratchLoad(const RdnaInstruction& inst);
bool bufferLoad(const RdnaInstruction& inst);
bool bufferLoadFormatD16(const RdnaInstruction& inst);
bool bufferStoreFormatD16(const RdnaInstruction& inst);

View File

@ -40,6 +40,10 @@ bool TranslationContext::emitMemory(const RdnaInstruction& inst) {
case RdnaOpcode::SBufferLoadDwordx8:
case RdnaOpcode::SBufferLoadDwordx16:
return sLoad(inst, false);
case RdnaOpcode::SScratchLoadDword:
case RdnaOpcode::SScratchLoadDwordx2:
case RdnaOpcode::SScratchLoadDwordx4:
return sScratchLoad(inst);
case RdnaOpcode::SGetWaveidInWorkgroup: {
if (program.Resources().stage != IrShaderStage::Compute) {
throw std::runtime_error("s_get_waveid_in_workgroup is supported only in compute shaders, at pc " + std::to_string(inst.programCounter));

View File

@ -52,6 +52,10 @@ bool TranslationContext::sLoad(const RdnaInstruction& inst, bool raw) {
return true;
}
bool TranslationContext::sScratchLoad(const RdnaInstruction& /*inst*/) {
throw std::runtime_error("s_scratch_load not yet implemented: wave-uniform or swizzled scratch layout required");
}
void TranslationContext::TranslateCodeTableLoad(const RdnaInstruction& instruction, const ControlFlowGraph::CodeTableLoad& table) {
if (table.values.empty()) throw std::runtime_error("empty shader code table");
const IrU32 index = readRawU32(instruction.source1);