From 1b7e0e487e7683620058340c7ae4424034c96137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Franch?= Date: Fri, 2 Oct 2026 08:04:11 +0200 Subject: [PATCH] feat(shader): implement v_movrelsd_b32, v_movrelsd_2_b32, v_swap_b32 and v_swaprel_b32 v_movrelsd moves VGPR[src + M0] to VGPR[dst + M0]. The _2 form and v_swaprel take the source offset from M0[9:0] and the destination offset from M0[25:16]; v_swaprel and v_swap exchange the two registers. They reuse the select-over-registers lowering of v_movrels/v_movreld, now shared as readRelativeVector/writeRelativeVector. Co-Authored-By: Claude --- .../tests/execution/RelativeIndexing.cpp | 140 ++++++++++++++++++ .../include/RdnaDecoder/RdnaOpcode.hpp | 4 + .../recompiler/RdnaDecoder/src/RdnaOpcode.cpp | 4 + .../RdnaDecoder/src/RdnaVectorOpDecoder.cpp | 6 + .../Translation/TranslationContext.hpp | 4 + .../src/ControlFlowInstructions.cpp | 60 ++++++-- .../Translation/src/EmbeddedVertexFetch.cpp | 5 +- .../Translation/src/VectorInstructions.cpp | 12 ++ 8 files changed, 220 insertions(+), 15 deletions(-) create mode 100644 core/libs/prx/libSceAgcDriver/tests/execution/RelativeIndexing.cpp diff --git a/core/libs/prx/libSceAgcDriver/tests/execution/RelativeIndexing.cpp b/core/libs/prx/libSceAgcDriver/tests/execution/RelativeIndexing.cpp new file mode 100644 index 000000000..0c2d2e688 --- /dev/null +++ b/core/libs/prx/libSceAgcDriver/tests/execution/RelativeIndexing.cpp @@ -0,0 +1,140 @@ +#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp" +#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp" +#include "Recompiler.hpp" +#include "VulkanTestDevice.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +using AgcDriver::Graphics::Require; +using ShaderRecompiler::ShaderStage; + +constexpr std::uint32_t Threads = 32; +constexpr std::uint32_t Inputs = 4; +constexpr std::uint32_t Results = 16; +alignas(256) std::array Input{}; +alignas(256) std::array Output{}; + +alignas(256) constexpr std::array Code{ + 0x34020084, 0x34060086, 0xe0301000, 0x80000401, 0x7e140280, 0x7e160280, 0x7e180280, 0x7e1a0280, + 0x7e1c0280, 0x7e1e0280, 0x7e200280, 0x7e220280, 0x7e240280, 0x7e260280, 0x7e280280, 0xbf8c3f70, + 0x7e3c0304, 0xd525001f, 0x00010304, 0xd5250020, 0x00010504, 0xd5250021, 0x00010704, 0xd5250022, + 0x00010904, 0xd5250023, 0x00010b04, 0xd5250024, 0x00010d04, 0xd5250025, 0x00010f04, 0xbefc0382, + 0x7e3e891e, 0x7e140321, 0xbefc03ff, 0xfc03fc02, 0x7e3e911e, 0x7e160322, 0x7e18031f, 0x4a4008a0, + 0x4a4208b0, 0xbefc03ff, 0x00010003, 0x7e3ed11e, 0x7e1a0320, 0x7e1c0321, 0x7e1e031e, 0x7e48cb25, + 0x7e200324, 0x7e220325, 0xbefc03ff, 0x00020002, 0x7e44d122, 0x7e240324, 0x7e260323, 0xd5c40023, + 0x0000011f, 0x7e280323, 0xe0701000, 0x80010a03, 0xe0701004, 0x80010b03, 0xe0701008, 0x80010c03, + 0xe070100c, 0x80010d03, 0xe0701010, 0x80010e03, 0xe0701014, 0x80010f03, 0xe0701018, 0x80011003, + 0xe070101c, 0x80011103, 0xe0701020, 0x80011203, 0xe0701024, 0x80011303, 0xe0701028, 0x80011403, + 0xbf810000, +}; + +constexpr std::uint32_t Expected[32][11] = { + {0x00001002u, 0x00001002u, 0x00001001u, 0x00001030u, 0x00001020u, 0x00001000u, 0x00001007u, 0x00001006u, 0x00001007u, 0x00001005u, 0x00001005u}, + {0x00002002u, 0x00002002u, 0x00002001u, 0x00002030u, 0x00002020u, 0x00002000u, 0x00002007u, 0x00002006u, 0x00002007u, 0x00002005u, 0x00002005u}, + {0x00003002u, 0x00003002u, 0x00003001u, 0x00003030u, 0x00003020u, 0x00003000u, 0x00003007u, 0x00003006u, 0x00003007u, 0x00003005u, 0x00003005u}, + {0x00004002u, 0x00004002u, 0x00004001u, 0x00004030u, 0x00004020u, 0x00004000u, 0x00004007u, 0x00004006u, 0x00004007u, 0x00004005u, 0x00004005u}, + {0x00005002u, 0x00005002u, 0x00005001u, 0x00005030u, 0x00005020u, 0x00005000u, 0x00005007u, 0x00005006u, 0x00005007u, 0x00005005u, 0x00005005u}, + {0x00006002u, 0x00006002u, 0x00006001u, 0x00006030u, 0x00006020u, 0x00006000u, 0x00006007u, 0x00006006u, 0x00006007u, 0x00006005u, 0x00006005u}, + {0x00007002u, 0x00007002u, 0x00007001u, 0x00007030u, 0x00007020u, 0x00007000u, 0x00007007u, 0x00007006u, 0x00007007u, 0x00007005u, 0x00007005u}, + {0x00008002u, 0x00008002u, 0x00008001u, 0x00008030u, 0x00008020u, 0x00008000u, 0x00008007u, 0x00008006u, 0x00008007u, 0x00008005u, 0x00008005u}, + {0x00009002u, 0x00009002u, 0x00009001u, 0x00009030u, 0x00009020u, 0x00009000u, 0x00009007u, 0x00009006u, 0x00009007u, 0x00009005u, 0x00009005u}, + {0x0000a002u, 0x0000a002u, 0x0000a001u, 0x0000a030u, 0x0000a020u, 0x0000a000u, 0x0000a007u, 0x0000a006u, 0x0000a007u, 0x0000a005u, 0x0000a005u}, + {0x0000b002u, 0x0000b002u, 0x0000b001u, 0x0000b030u, 0x0000b020u, 0x0000b000u, 0x0000b007u, 0x0000b006u, 0x0000b007u, 0x0000b005u, 0x0000b005u}, + {0x0000c002u, 0x0000c002u, 0x0000c001u, 0x0000c030u, 0x0000c020u, 0x0000c000u, 0x0000c007u, 0x0000c006u, 0x0000c007u, 0x0000c005u, 0x0000c005u}, + {0x0000d002u, 0x0000d002u, 0x0000d001u, 0x0000d030u, 0x0000d020u, 0x0000d000u, 0x0000d007u, 0x0000d006u, 0x0000d007u, 0x0000d005u, 0x0000d005u}, + {0x0000e002u, 0x0000e002u, 0x0000e001u, 0x0000e030u, 0x0000e020u, 0x0000e000u, 0x0000e007u, 0x0000e006u, 0x0000e007u, 0x0000e005u, 0x0000e005u}, + {0x0000f002u, 0x0000f002u, 0x0000f001u, 0x0000f030u, 0x0000f020u, 0x0000f000u, 0x0000f007u, 0x0000f006u, 0x0000f007u, 0x0000f005u, 0x0000f005u}, + {0x00010002u, 0x00010002u, 0x00010001u, 0x00010030u, 0x00010020u, 0x00010000u, 0x00010007u, 0x00010006u, 0x00010007u, 0x00010005u, 0x00010005u}, + {0x00011002u, 0x00011002u, 0x00011001u, 0x00011030u, 0x00011020u, 0x00011000u, 0x00011007u, 0x00011006u, 0x00011007u, 0x00011005u, 0x00011005u}, + {0x00012002u, 0x00012002u, 0x00012001u, 0x00012030u, 0x00012020u, 0x00012000u, 0x00012007u, 0x00012006u, 0x00012007u, 0x00012005u, 0x00012005u}, + {0x00013002u, 0x00013002u, 0x00013001u, 0x00013030u, 0x00013020u, 0x00013000u, 0x00013007u, 0x00013006u, 0x00013007u, 0x00013005u, 0x00013005u}, + {0x00014002u, 0x00014002u, 0x00014001u, 0x00014030u, 0x00014020u, 0x00014000u, 0x00014007u, 0x00014006u, 0x00014007u, 0x00014005u, 0x00014005u}, + {0x00015002u, 0x00015002u, 0x00015001u, 0x00015030u, 0x00015020u, 0x00015000u, 0x00015007u, 0x00015006u, 0x00015007u, 0x00015005u, 0x00015005u}, + {0x00016002u, 0x00016002u, 0x00016001u, 0x00016030u, 0x00016020u, 0x00016000u, 0x00016007u, 0x00016006u, 0x00016007u, 0x00016005u, 0x00016005u}, + {0x00017002u, 0x00017002u, 0x00017001u, 0x00017030u, 0x00017020u, 0x00017000u, 0x00017007u, 0x00017006u, 0x00017007u, 0x00017005u, 0x00017005u}, + {0x00018002u, 0x00018002u, 0x00018001u, 0x00018030u, 0x00018020u, 0x00018000u, 0x00018007u, 0x00018006u, 0x00018007u, 0x00018005u, 0x00018005u}, + {0x00019002u, 0x00019002u, 0x00019001u, 0x00019030u, 0x00019020u, 0x00019000u, 0x00019007u, 0x00019006u, 0x00019007u, 0x00019005u, 0x00019005u}, + {0x0001a002u, 0x0001a002u, 0x0001a001u, 0x0001a030u, 0x0001a020u, 0x0001a000u, 0x0001a007u, 0x0001a006u, 0x0001a007u, 0x0001a005u, 0x0001a005u}, + {0x0001b002u, 0x0001b002u, 0x0001b001u, 0x0001b030u, 0x0001b020u, 0x0001b000u, 0x0001b007u, 0x0001b006u, 0x0001b007u, 0x0001b005u, 0x0001b005u}, + {0x0001c002u, 0x0001c002u, 0x0001c001u, 0x0001c030u, 0x0001c020u, 0x0001c000u, 0x0001c007u, 0x0001c006u, 0x0001c007u, 0x0001c005u, 0x0001c005u}, + {0x0001d002u, 0x0001d002u, 0x0001d001u, 0x0001d030u, 0x0001d020u, 0x0001d000u, 0x0001d007u, 0x0001d006u, 0x0001d007u, 0x0001d005u, 0x0001d005u}, + {0x0001e002u, 0x0001e002u, 0x0001e001u, 0x0001e030u, 0x0001e020u, 0x0001e000u, 0x0001e007u, 0x0001e006u, 0x0001e007u, 0x0001e005u, 0x0001e005u}, + {0x0001f002u, 0x0001f002u, 0x0001f001u, 0x0001f030u, 0x0001f020u, 0x0001f000u, 0x0001f007u, 0x0001f006u, 0x0001f007u, 0x0001f005u, 0x0001f005u}, + {0x00020002u, 0x00020002u, 0x00020001u, 0x00020030u, 0x00020020u, 0x00020000u, 0x00020007u, 0x00020006u, 0x00020007u, 0x00020005u, 0x00020005u}, +}; +constexpr const char* Names[11] = {"movrelsd", "swapped_2", "sd2_untouched", "swaprel_dst", "swaprel_src", "swaprel_other", "swap_dst", "swap_src", "swaprel_same", "swaprel_same_other", "movrelsd_e64_out_of_range"}; + +void Fill(std::uint32_t tid, std::uint32_t* words) { + words[0] = 0x1000u * (tid + 1u); +} + +std::array BufferDescriptor(const void* data, std::uint32_t bytes) { + const auto address = reinterpret_cast(data); + return {static_cast(address), static_cast((address >> 32u) & 0xffffu), bytes, 0x01016facu}; +} + +std::string Hex(std::uint32_t value) { + char text[16]; + std::snprintf(text, sizeof(text), "0x%08x", value); + return text; +} + +void Expect(std::uint32_t tid, std::uint32_t actual, std::uint32_t expected, const char* name) { + Require(actual == expected, std::string("relative indexing: lane ") + std::to_string(tid) + " " + name + " is " + Hex(actual) + ", expected " + Hex(expected)); +} + +void Run(AgcDriver::VulkanDevice& device) { + for (std::uint32_t tid = 0; tid < Threads; ++tid) Fill(tid, &Input[tid * Inputs]); + Output.fill(0xdeadbeefu); + std::vector userData(8, 0u); + const auto input = BufferDescriptor(Input.data(), static_cast(Input.size() * 4u)); + const auto output = BufferDescriptor(Output.data(), static_cast(Output.size() * 4u)); + std::copy(input.begin(), input.end(), userData.begin()); + std::copy(output.begin(), output.end(), userData.begin() + 4); + const std::span code(Code); + const std::array memory{{{reinterpret_cast(code.data()), std::as_bytes(code)}}}; + const ShaderRecompiler::ShaderComputeStageInfo compute{{Threads, 1, 1}, 0u, {false, false, false}, false, 1}; + ShaderRecompiler::RecompileRequest request{ + {ShaderStage::Compute, reinterpret_cast(code.data()), code, 0, {}}, + {32, 0, userData, compute, std::nullopt, std::nullopt, memory}, + device.Target(), + {0, 0, 0, 128} + }; + request.useCache = false; + const auto result = ShaderRecompiler::Recompile(request); + device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast(code.data())); + device.WaitIdle(); +} + +void Check() { + for (std::uint32_t tid = 0; tid < Threads; ++tid) { + const std::uint32_t* in = &Input[tid * Inputs]; + const std::uint32_t* out = &Output[tid * Results]; + for (std::uint32_t index = 0; index < 11; ++index) Expect(tid, out[index], Expected[tid][index], Names[index]); + } +} + +} + +int main() { + try { + const auto device = OpenVulkanTestDevice(); + if (!device) return VulkanTestSkipped; + Run(*device); + Check(); + std::puts("relative indexing tests passed"); + return 0; + } catch (const std::exception& error) { + std::cerr << error.what() << '\n'; + return 1; + } +} diff --git a/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp b/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp index e622c4f72..0dced0ba9 100644 --- a/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp +++ b/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp @@ -264,6 +264,10 @@ enum class RdnaOpcode : std::uint16_t { VPipeflush, VClrexcp, VMovrelsB32, + VMovrelsdB32, + VMovrelsd2B32, + VSwapB32, + VSwaprelB32, VPermlane16B32, VPermlanex16B32, VCubeidF32, diff --git a/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp b/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp index c40d5bc97..b0dbb7640 100644 --- a/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp +++ b/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp @@ -212,6 +212,10 @@ bool IsVectorAluOpcode(RdnaOpcode opcode) { case RdnaOpcode::VPipeflush: case RdnaOpcode::VClrexcp: case RdnaOpcode::VMovrelsB32: + case RdnaOpcode::VMovrelsdB32: + case RdnaOpcode::VMovrelsd2B32: + case RdnaOpcode::VSwapB32: + case RdnaOpcode::VSwaprelB32: case RdnaOpcode::VPermlane16B32: case RdnaOpcode::VPermlanex16B32: case RdnaOpcode::VCubeidF32: diff --git a/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp b/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp index b2e403665..30f6e14c3 100644 --- a/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp +++ b/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp @@ -144,6 +144,8 @@ constexpr VectorOpcodeInfo vop1Opcodes[] = { {0x41u, RdnaOpcode::VClrexcp}, {0x42u, RdnaOpcode::VMovreldB32}, {0x43u, RdnaOpcode::VMovrelsB32}, + {0x44u, RdnaOpcode::VMovrelsdB32}, + {0x48u, RdnaOpcode::VMovrelsd2B32}, {0x50u, RdnaOpcode::VCvtF16U16}, {0x51u, RdnaOpcode::VCvtF16I16}, {0x52u, RdnaOpcode::VCvtU16F16}, @@ -165,6 +167,8 @@ constexpr VectorOpcodeInfo vop1Opcodes[] = { {0x62u, RdnaOpcode::VSatPkU8I16}, {0x63u, RdnaOpcode::VCvtNormI16F16}, {0x64u, RdnaOpcode::VCvtNormU16F16}, + {0x65u, RdnaOpcode::VSwapB32}, + {0x68u, RdnaOpcode::VSwaprelB32}, }; constexpr VectorOpcodeInfo vop3EncodedVop1Opcodes[] = { @@ -208,6 +212,8 @@ constexpr VectorOpcodeInfo vop3EncodedVop1Opcodes[] = { {0x41u, RdnaOpcode::VClrexcp}, {0x42u, RdnaOpcode::VMovreldB32}, {0x43u, RdnaOpcode::VMovrelsB32}, + {0x44u, RdnaOpcode::VMovrelsdB32}, + {0x48u, RdnaOpcode::VMovrelsd2B32}, {0x50u, RdnaOpcode::VCvtF16U16}, {0x51u, RdnaOpcode::VCvtF16I16}, {0x52u, RdnaOpcode::VCvtU16F16}, diff --git a/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp b/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp index 876ab3162..066f04a41 100644 --- a/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp +++ b/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp @@ -243,6 +243,10 @@ private: void sWqm(const RdnaInstruction& inst, bool wide); void vMovrelsB32(const RdnaInstruction& inst); void vMovreldB32(const RdnaInstruction& inst); + void vMovrelsdB32(const RdnaInstruction& inst, bool split, bool swap); + void vSwapB32(const RdnaInstruction& inst); + IrU32 readRelativeVector(const RdnaOperand& base, IrValue& offset, const char* name); + void writeRelativeVector(const RdnaOperand& base, IrValue& offset, IrU32 value, const char* name); void vReadfirstlaneB32(const RdnaInstruction& inst); void vReadlaneB32(const RdnaInstruction& inst); void vWritelaneB32(const RdnaInstruction& inst); diff --git a/core/shader/recompiler/Translation/src/ControlFlowInstructions.cpp b/core/shader/recompiler/Translation/src/ControlFlowInstructions.cpp index b867014ef..588b9717b 100644 --- a/core/shader/recompiler/Translation/src/ControlFlowInstructions.cpp +++ b/core/shader/recompiler/Translation/src/ControlFlowInstructions.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace ShaderRecompiler { @@ -248,27 +249,23 @@ void TranslationContext::sWqm(const RdnaInstruction& inst, bool wide) { // M0 holds a uniform register offset. Vector registers are SSA values with fixed indices, so an indexed // access becomes a select over every register the program references at or past the base. -void TranslationContext::vMovrelsB32(const RdnaInstruction& inst) { - const RdnaOperand& source = sourceAt(inst, 0u); - if (source.kind != RdnaOperandKind::VectorRegister) { - throw std::runtime_error("v_movrels_b32 source is not a vector register"); +IrU32 TranslationContext::readRelativeVector(const RdnaOperand& base, IrValue& offset, const char* name) { + if (base.kind != RdnaOperandKind::VectorRegister) { + throw std::runtime_error(std::string(name) + " source is not a vector register"); } - IrValue& offset = ir.GetM0(); - IrU32 result(ir.GetVectorReg(static_cast(source.reg))); - for (std::uint32_t reg = source.reg + 1u; reg < currentVectorLimit; ++reg) { - IrValue& hit = ir.IEqual(offset, ir.Constant(reg - source.reg)); + IrU32 result(ir.GetVectorReg(static_cast(base.reg))); + for (std::uint32_t reg = base.reg + 1u; reg < currentVectorLimit; ++reg) { + IrValue& hit = ir.IEqual(offset, ir.Constant(reg - base.reg)); result = IrU32(ir.Select(hit, ir.GetVectorReg(static_cast(reg)), result.Value())); } - writeRawU32(inst.destination, result); + return result; } -void TranslationContext::vMovreldB32(const RdnaInstruction& inst) { - const RdnaOperand destination = plainOperand(inst.destination); +void TranslationContext::writeRelativeVector(const RdnaOperand& base, IrValue& offset, IrU32 value, const char* name) { + const RdnaOperand destination = plainOperand(base); if (destination.kind != RdnaOperandKind::VectorRegister) { - throw std::runtime_error("v_movreld_b32 destination is not a vector register"); + throw std::runtime_error(std::string(name) + " destination is not a vector register"); } - const IrU32 value = readU32(sourceAt(inst, 0u)); - IrValue& offset = ir.GetM0(); for (std::uint32_t reg = destination.reg; reg < currentVectorLimit; ++reg) { RdnaOperand target = destination; target.reg = reg; @@ -277,6 +274,41 @@ void TranslationContext::vMovreldB32(const RdnaInstruction& inst) { } } +void TranslationContext::vMovrelsB32(const RdnaInstruction& inst) { + writeRawU32(inst.destination, readRelativeVector(sourceAt(inst, 0u), ir.GetM0(), "v_movrels_b32")); +} + +void TranslationContext::vMovreldB32(const RdnaInstruction& inst) { + const IrU32 value = readU32(sourceAt(inst, 0u)); + writeRelativeVector(inst.destination, ir.GetM0(), value, "v_movreld_b32"); +} + +void TranslationContext::vMovrelsdB32(const RdnaInstruction& inst, bool split, bool swap) { + const char* name = swap ? "v_swaprel_b32" : split ? "v_movrelsd_2_b32" : "v_movrelsd_b32"; + IrValue& m0 = ir.GetM0(); + IrValue& sourceOffset = split ? ir.BitwiseAnd(m0, ir.Constant(0x3ffu)) : m0; + IrValue& destinationOffset = split ? ir.BitwiseAnd(ir.ShiftRightLogical(m0, ir.Constant(16u)), ir.Constant(0x3ffu)) : m0; + const IrU32 value = readRelativeVector(sourceAt(inst, 0u), sourceOffset, name); + if (!swap) { + writeRelativeVector(inst.destination, destinationOffset, value, name); + return; + } + const IrU32 previous = readRelativeVector(plainOperand(inst.destination), destinationOffset, name); + writeRelativeVector(inst.destination, destinationOffset, value, name); + writeRelativeVector(sourceAt(inst, 0u), sourceOffset, previous, name); +} + +void TranslationContext::vSwapB32(const RdnaInstruction& inst) { + const RdnaOperand& source = sourceAt(inst, 0u); + if (source.kind != RdnaOperandKind::VectorRegister) { + throw std::runtime_error("v_swap_b32 source is not a vector register"); + } + const IrU32 value = readU32(source); + const IrU32 previous = readU32(plainOperand(inst.destination)); + writeRawU32(inst.destination, value); + writeRawU32(plainOperand(source), previous); +} + void TranslationContext::vReadfirstlaneB32(const RdnaInstruction& inst) { const IrU32 value = readU32(sourceAt(inst, 0u)); const IrU32 result(ir.Emit(IrOpcode::ReadFirstLane, IrType::U32, {&value.Value(), &ir.GetExec()})); diff --git a/core/shader/recompiler/Translation/src/EmbeddedVertexFetch.cpp b/core/shader/recompiler/Translation/src/EmbeddedVertexFetch.cpp index da66abcb0..2a3574458 100644 --- a/core/shader/recompiler/Translation/src/EmbeddedVertexFetch.cpp +++ b/core/shader/recompiler/Translation/src/EmbeddedVertexFetch.cpp @@ -407,8 +407,11 @@ EmbeddedFetchPlan EmbeddedVertexFetchAnalyzer::Analyze(const RdnaProgram& progra } break; } - if (inst.op == RdnaOpcode::VMovreldB32) { + if (inst.op == RdnaOpcode::VMovreldB32 || inst.op == RdnaOpcode::VMovrelsdB32 || inst.op == RdnaOpcode::VMovrelsd2B32 || inst.op == RdnaOpcode::VSwaprelB32) { vectorLanes.clear(); + } else if (inst.op == RdnaOpcode::VSwapB32) { + clearVectorLanes(vectorLanes, inst.destination.reg); + clearVectorLanes(vectorLanes, inst.source0.reg); } else if (inst.op != RdnaOpcode::VWritelaneB32 && isVectorOperand(inst.destination)) { for (std::uint32_t i = 0u; i < embeddedFetchDstSize(inst) && inst.destination.reg + i < vgprIsIndex.size(); i++) { clearVectorLanes(vectorLanes, inst.destination.reg + i); diff --git a/core/shader/recompiler/Translation/src/VectorInstructions.cpp b/core/shader/recompiler/Translation/src/VectorInstructions.cpp index 10d4cecb8..a13bcb3a0 100644 --- a/core/shader/recompiler/Translation/src/VectorInstructions.cpp +++ b/core/shader/recompiler/Translation/src/VectorInstructions.cpp @@ -53,6 +53,18 @@ bool TranslationContext::emitVector(const RdnaInstruction& inst) { case RdnaOpcode::VMovreldB32: vMovreldB32(inst); return true; + case RdnaOpcode::VMovrelsdB32: + vMovrelsdB32(inst, false, false); + return true; + case RdnaOpcode::VMovrelsd2B32: + vMovrelsdB32(inst, true, false); + return true; + case RdnaOpcode::VSwaprelB32: + vMovrelsdB32(inst, true, true); + return true; + case RdnaOpcode::VSwapB32: + vSwapB32(inst); + return true; case RdnaOpcode::VReadfirstlaneB32: vReadfirstlaneB32(inst); return true;