From 2e398be5a01fd346bdcaf77b3f3b196e6e79b7f4 Mon Sep 17 00:00:00 2001 From: SamG-Coder <13449963+SamG-Coder@users.noreply.github.com> Date: Mon, 28 Sep 2026 18:21:34 +1000 Subject: [PATCH 1/2] fix(shader): support scalar conditional move and zero-bit operations --- .../include/RdnaDecoder/RdnaOpcode.hpp | 3 +++ .../recompiler/RdnaDecoder/src/RdnaOpcode.cpp | 3 +++ .../RdnaDecoder/src/RdnaScalarOpDecoder.cpp | 3 +++ .../Translation/src/ScalarInstructions.cpp | 19 +++++++++++++++++++ 4 files changed, 28 insertions(+) diff --git a/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp b/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp index a45f532c6..a56f770d4 100644 --- a/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp +++ b/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp @@ -114,14 +114,17 @@ enum class RdnaOpcode : std::uint16_t { ExpParam, Unknown, Unsupported, + SCmovB32, SCmovB64, SAbsI32, SAbsdiffI32, SBrevB32, SSextI32I8, SSextI32I16, + SBcnt0I32B32, SBcnt1I32B32, SBcnt1I32B64, + SFf0I32B32, SFf1I32B32, SFf1I32B64, SFlbitI32B32, diff --git a/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp b/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp index b5daa8d16..697cfa774 100644 --- a/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp +++ b/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp @@ -36,14 +36,17 @@ bool IsScalarAluOpcode(RdnaOpcode opcode) { case RdnaOpcode::SCmpLtI32: case RdnaOpcode::SCmpGtI32: case RdnaOpcode::SCmpEqU32: + case RdnaOpcode::SCmovB32: case RdnaOpcode::SCmovB64: case RdnaOpcode::SAbsI32: case RdnaOpcode::SAbsdiffI32: case RdnaOpcode::SBrevB32: case RdnaOpcode::SSextI32I8: case RdnaOpcode::SSextI32I16: + case RdnaOpcode::SBcnt0I32B32: case RdnaOpcode::SBcnt1I32B32: case RdnaOpcode::SBcnt1I32B64: + case RdnaOpcode::SFf0I32B32: case RdnaOpcode::SFf1I32B32: case RdnaOpcode::SFf1I32B64: case RdnaOpcode::SFlbitI32B32: diff --git a/core/shader/recompiler/RdnaDecoder/src/RdnaScalarOpDecoder.cpp b/core/shader/recompiler/RdnaDecoder/src/RdnaScalarOpDecoder.cpp index 5403a21bd..1f7d14b14 100644 --- a/core/shader/recompiler/RdnaDecoder/src/RdnaScalarOpDecoder.cpp +++ b/core/shader/recompiler/RdnaDecoder/src/RdnaScalarOpDecoder.cpp @@ -11,14 +11,17 @@ RdnaOpcode decodeSop1Opcode(std::uint32_t opcode) { switch (opcode) { case 0x03u: return RdnaOpcode::SMovB32; case 0x04u: return RdnaOpcode::SMovB64; + case 0x05u: return RdnaOpcode::SCmovB32; case 0x06u: return RdnaOpcode::SCmovB64; case 0x07u: return RdnaOpcode::SNotB32; case 0x08u: return RdnaOpcode::SNotB64; case 0x09u: return RdnaOpcode::SWqmB32; case 0x0au: return RdnaOpcode::SWqmB64; case 0x0bu: return RdnaOpcode::SBrevB32; + case 0x0du: return RdnaOpcode::SBcnt0I32B32; case 0x0fu: return RdnaOpcode::SBcnt1I32B32; case 0x10u: return RdnaOpcode::SBcnt1I32B64; + case 0x11u: return RdnaOpcode::SFf0I32B32; case 0x13u: return RdnaOpcode::SFf1I32B32; case 0x14u: return RdnaOpcode::SFf1I32B64; case 0x15u: return RdnaOpcode::SFlbitI32B32; diff --git a/core/shader/recompiler/Translation/src/ScalarInstructions.cpp b/core/shader/recompiler/Translation/src/ScalarInstructions.cpp index 26a53968e..34c1e0096 100644 --- a/core/shader/recompiler/Translation/src/ScalarInstructions.cpp +++ b/core/shader/recompiler/Translation/src/ScalarInstructions.cpp @@ -40,6 +40,13 @@ bool TranslationContext::emitScalar(const RdnaInstruction& inst) { case RdnaOpcode::SCselectB64: scalarSelect64(inst, sourceAt(inst, 1u)); return true; + case RdnaOpcode::SCmovB32: { + const IrU32 source = readU32(sourceAt(inst, 0u)); + const IrU32 previous = readU32(inst.destination); + const IrU32 result(ir.Select(ir.GetScc(), source.Value(), previous.Value())); + writeRawU32(inst.destination, result); + return true; + } case RdnaOpcode::SCmovB64: scalarSelect64(inst, inst.destination); return true; @@ -195,6 +202,18 @@ bool TranslationContext::emitScalar(const RdnaInstruction& inst) { writeOperand(inst.destination, &result); return true; } + case RdnaOpcode::SBcnt0I32B32: + case RdnaOpcode::SFf0I32B32: { + const IrU32 source = readU32(sourceAt(inst, 0u)); + auto& inverted = ir.BitwiseNot(source.Value()); + const bool count = inst.op == RdnaOpcode::SBcnt0I32B32; + auto& result = ir.Emit(count ? IrOpcode::BitCount32 : IrOpcode::FindILsb32, IrType::U32, {&inverted}); + writeOperand(inst.destination, &result); + if (count) { + ir.SetScc(ir.INotEqual(result, ir.Constant(0u))); + } + return true; + } case RdnaOpcode::SBcnt1I32B32: return simpleInteger(inst, IrOpcode::BitCount32, IrType::U32, false, false, true); case RdnaOpcode::SBcnt1I32B64: From 198b43c9858e50f4b6c07b63bb008491cb3e5ca8 Mon Sep 17 00:00:00 2001 From: SamG-Coder <13449963+SamG-Coder@users.noreply.github.com> Date: Mon, 28 Sep 2026 18:37:51 +1000 Subject: [PATCH 2/2] fix(shader): support additional 64-bit saveexec operations --- .../RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp | 3 +++ core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp | 3 +++ .../recompiler/RdnaDecoder/src/RdnaScalarOpDecoder.cpp | 6 ++++++ .../Translation/src/ControlFlowInstructions.cpp | 1 + .../recompiler/Translation/src/ScalarInstructions.cpp | 9 +++++++++ 5 files changed, 22 insertions(+) diff --git a/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp b/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp index a56f770d4..76b6972ac 100644 --- a/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp +++ b/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp @@ -138,6 +138,9 @@ enum class RdnaOpcode : std::uint16_t { SOrn2SaveexecB32, SAndn1SaveexecB32, SAndSaveexecB64, + SOrSaveexecB64, + SXorSaveexecB64, + SAndn2SaveexecB64, SOrn2SaveexecB64, SAndn1SaveexecB64, SNotB32, diff --git a/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp b/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp index 697cfa774..f77f40a5e 100644 --- a/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp +++ b/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp @@ -57,6 +57,9 @@ bool IsScalarAluOpcode(RdnaOpcode opcode) { case RdnaOpcode::SOrn2SaveexecB32: case RdnaOpcode::SAndn1SaveexecB32: case RdnaOpcode::SAndSaveexecB64: + case RdnaOpcode::SOrSaveexecB64: + case RdnaOpcode::SXorSaveexecB64: + case RdnaOpcode::SAndn2SaveexecB64: case RdnaOpcode::SOrn2SaveexecB64: case RdnaOpcode::SAndn1SaveexecB64: case RdnaOpcode::SNotB32: diff --git a/core/shader/recompiler/RdnaDecoder/src/RdnaScalarOpDecoder.cpp b/core/shader/recompiler/RdnaDecoder/src/RdnaScalarOpDecoder.cpp index 1f7d14b14..b93ed8afb 100644 --- a/core/shader/recompiler/RdnaDecoder/src/RdnaScalarOpDecoder.cpp +++ b/core/shader/recompiler/RdnaDecoder/src/RdnaScalarOpDecoder.cpp @@ -35,6 +35,9 @@ RdnaOpcode decodeSop1Opcode(std::uint32_t opcode) { case 0x1fu: return RdnaOpcode::SGetpcB64; case 0x20u: return RdnaOpcode::SSetpcB64; case 0x24u: return RdnaOpcode::SAndSaveexecB64; + case 0x25u: return RdnaOpcode::SOrSaveexecB64; + case 0x26u: return RdnaOpcode::SXorSaveexecB64; + case 0x27u: return RdnaOpcode::SAndn2SaveexecB64; case 0x28u: return RdnaOpcode::SOrn2SaveexecB64; case 0x2du: return RdnaOpcode::SQuadmaskB64; case 0x34u: return RdnaOpcode::SAbsI32; @@ -199,6 +202,9 @@ std::uint32_t scalarDestinationDwordCount(RdnaOpcode opcode) { case RdnaOpcode::SBitset1B64: case RdnaOpcode::SGetpcB64: case RdnaOpcode::SAndSaveexecB64: + case RdnaOpcode::SOrSaveexecB64: + case RdnaOpcode::SXorSaveexecB64: + case RdnaOpcode::SAndn2SaveexecB64: case RdnaOpcode::SOrn2SaveexecB64: case RdnaOpcode::SQuadmaskB64: case RdnaOpcode::SAndn1SaveexecB64: diff --git a/core/shader/recompiler/Translation/src/ControlFlowInstructions.cpp b/core/shader/recompiler/Translation/src/ControlFlowInstructions.cpp index bcf67a573..16f9423d6 100644 --- a/core/shader/recompiler/Translation/src/ControlFlowInstructions.cpp +++ b/core/shader/recompiler/Translation/src/ControlFlowInstructions.cpp @@ -28,6 +28,7 @@ void TranslationContext::sSaveexec(const RdnaInstruction& inst, IrOpcode operati // Callers name the lane-wise operation; the exec mask words themselves combine bitwise. if (operation == IrOpcode::LogicalAnd) operation = IrOpcode::BitwiseAnd32; else if (operation == IrOpcode::LogicalOr) operation = IrOpcode::BitwiseOr32; + else if (operation == IrOpcode::LogicalXor) operation = IrOpcode::BitwiseXor32; const bool writeFirst = SaveexecWritesDestinationFirst(); if (write64) { const std::array oldExec{IrU32(ir.GetExecLo()), IrU32(ir.GetExecHi())}; diff --git a/core/shader/recompiler/Translation/src/ScalarInstructions.cpp b/core/shader/recompiler/Translation/src/ScalarInstructions.cpp index 34c1e0096..3515a3132 100644 --- a/core/shader/recompiler/Translation/src/ScalarInstructions.cpp +++ b/core/shader/recompiler/Translation/src/ScalarInstructions.cpp @@ -68,6 +68,15 @@ bool TranslationContext::emitScalar(const RdnaInstruction& inst) { case RdnaOpcode::SAndSaveexecB64: sSaveexec(inst, IrOpcode::LogicalAnd, false, false, true); return true; + case RdnaOpcode::SOrSaveexecB64: + sSaveexec(inst, IrOpcode::LogicalOr, false, false, true); + return true; + case RdnaOpcode::SXorSaveexecB64: + sSaveexec(inst, IrOpcode::LogicalXor, false, false, true); + return true; + case RdnaOpcode::SAndn2SaveexecB64: + sSaveexec(inst, IrOpcode::LogicalAnd, true, false, true); + return true; case RdnaOpcode::SAndn1SaveexecB64: sSaveexec(inst, IrOpcode::LogicalAnd, false, true, true); return true;