From 0a2f4814acde4a417cdd8558fee30bbfcd3fc6f9 Mon Sep 17 00:00:00 2001 From: nmzik Date: Wed, 5 Aug 2026 01:40:08 +0200 Subject: [PATCH] refactor(shader): centralize opcode metadata and lookup paths --- .../recompiler/decompiler/OpcodeTable.h | 45 +++ .../recompiler/decompiler/ScalarAluOps.cpp | 31 +- .../recompiler/decompiler/ShaderDecoder.cpp | 33 +- .../recompiler/decompiler/VectorAluOps.cpp | 277 +++++++------ .../recompiler/emitter/SpirvEmitter.cpp | 2 +- .../recompiler/emitter/spirvEmitterAluOps.cpp | 3 +- .../emitter/spirvEmitterAnalysis.cpp | 96 +---- .../emitter/spirvEmitterControlFlow.cpp | 4 +- .../recompiler/emitter/spirvEmitterInternal.h | 6 +- .../shader/recompiler/ir/ShaderIR.cpp | 28 +- src/graphics/shader/recompiler/ir/ShaderIR.h | 373 ++---------------- .../shader/recompiler/ir/ShaderIRInternal.h | 13 +- .../shader/recompiler/ir/ShaderIRLog.cpp | 341 +--------------- .../shader/recompiler/ir/ShaderIROpcodes.cpp | 13 +- .../shader/recompiler/ir/ShaderIROpcodes.inc | 340 ++++++++++++++++ tests/shaderCfgTests.cpp | 48 +++ 16 files changed, 689 insertions(+), 964 deletions(-) create mode 100644 src/graphics/shader/recompiler/decompiler/OpcodeTable.h create mode 100644 src/graphics/shader/recompiler/ir/ShaderIROpcodes.inc diff --git a/src/graphics/shader/recompiler/decompiler/OpcodeTable.h b/src/graphics/shader/recompiler/decompiler/OpcodeTable.h new file mode 100644 index 0000000..5177cc9 --- /dev/null +++ b/src/graphics/shader/recompiler/decompiler/OpcodeTable.h @@ -0,0 +1,45 @@ +#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_DECOMPILER_OPCODETABLE_H_ +#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_DECOMPILER_OPCODETABLE_H_ + +#include "graphics/shader/recompiler/decompiler/ShaderDecoder.h" + +#include + +namespace Libs::Graphics::ShaderRecompiler::Decoder::Detail { + +struct OpcodeMap { + uint32_t encoding = 0; + Opcode decoded = Opcode::Unknown; +}; + +template +constexpr const Entry* FindOpcode(const Entry (&table)[N], uint32_t encoding) { + for (const auto& entry: table) { + if (entry.encoding == encoding) { + return &entry; + } + } + return nullptr; +} + +template +constexpr Opcode LookupOpcode(const Entry (&table)[N], uint32_t encoding) { + const auto* entry = FindOpcode(table, encoding); + return entry != nullptr ? entry->decoded : Opcode::Unsupported; +} + +template +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_ diff --git a/src/graphics/shader/recompiler/decompiler/ScalarAluOps.cpp b/src/graphics/shader/recompiler/decompiler/ScalarAluOps.cpp index cf5ad78..50de42a 100644 --- a/src/graphics/shader/recompiler/decompiler/ScalarAluOps.cpp +++ b/src/graphics/shader/recompiler/decompiler/ScalarAluOps.cpp @@ -1,14 +1,11 @@ #include "graphics/shader/recompiler/decompiler/ScalarAluOps.h" -#include +#include "graphics/shader/recompiler/decompiler/OpcodeTable.h" namespace Libs::Graphics::ShaderRecompiler::Decoder { namespace { -struct OpcodeMap { - uint32_t opcode = 0; - Opcode ir = Opcode::Unknown; -}; +using Detail::OpcodeMap; constexpr OpcodeMap SOP2_OPS[] = { {0x00u, Opcode::SAddU32}, {0x01u, Opcode::SSubU32}, {0x02u, Opcode::SAddI32}, @@ -79,15 +76,11 @@ constexpr OpcodeMap SOPP_OPS[] = { {0x0au, Opcode::SBarrier}, {0x0cu, Opcode::SWaitcnt}, {0x0eu, Opcode::SSleep}, {0x10u, Opcode::SSendmsg}, {0x16u, Opcode::STtraceData}, {0x20u, Opcode::SInstPrefetch}, }; - -Opcode Lookup(const OpcodeMap* ops, uint32_t count, uint32_t opcode) { - for (uint32_t i = 0; i < count; i++) { - if (ops[i].opcode == opcode) { - return ops[i].ir; - } - } - return Opcode::Unsupported; -} +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)); bool DecodeBinarySources(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, uint32_t ssrc0, uint32_t ssrc1, std::string* error) { @@ -112,7 +105,7 @@ bool DecodeSop1(uint32_t pc, std::span code, uint32_t word_index inst.word = word; inst.family = Family::SOP1; inst.opcode_id = opcode; - inst.opcode = Lookup(SOP1_OPS, static_cast(std::size(SOP1_OPS)), opcode); + inst.opcode = Detail::LookupOpcode(SOP1_OPS, opcode); SetRawWords(inst, code, word_index, 1); if (inst.opcode == Opcode::Unsupported) { @@ -154,7 +147,7 @@ bool DecodeSop2(uint32_t pc, std::span code, uint32_t word_index inst.word = word; inst.family = Family::SOP2; inst.opcode_id = opcode; - inst.opcode = Lookup(SOP2_OPS, static_cast(std::size(SOP2_OPS)), opcode); + inst.opcode = Detail::LookupOpcode(SOP2_OPS, opcode); SetRawWords(inst, code, word_index, 1); if (inst.opcode == Opcode::Unsupported) { @@ -181,7 +174,7 @@ bool DecodeSopk(uint32_t pc, std::span code, uint32_t word_index inst.word = word; inst.family = Family::SOPK; inst.opcode_id = opcode; - inst.opcode = Lookup(SOPK_OPS, static_cast(std::size(SOPK_OPS)), opcode); + inst.opcode = Detail::LookupOpcode(SOPK_OPS, opcode); inst.src0.kind = OperandKind::IntegerInlineConstant; inst.src0.signed_val = imm; inst.src0.value = static_cast(imm); @@ -238,7 +231,7 @@ bool DecodeSopc(uint32_t pc, std::span code, uint32_t word_index inst.word = word; inst.family = Family::SOPC; inst.opcode_id = opcode; - inst.opcode = Lookup(SOPC_OPS, static_cast(std::size(SOPC_OPS)), opcode); + inst.opcode = Detail::LookupOpcode(SOPC_OPS, opcode); inst.dst.kind = OperandKind::Scc; SetRawWords(inst, code, word_index, 1); @@ -262,7 +255,7 @@ bool DecodeSopp(uint32_t pc, std::span code, uint32_t word_index inst.word = word; inst.family = Family::SOPP; inst.opcode_id = opcode; - inst.opcode = Lookup(SOPP_OPS, static_cast(std::size(SOPP_OPS)), opcode); + inst.opcode = Detail::LookupOpcode(SOPP_OPS, opcode); inst.src0.kind = OperandKind::LiteralConstant; inst.src0.value = simm; inst.src0.signed_val = static_cast(simm); diff --git a/src/graphics/shader/recompiler/decompiler/ShaderDecoder.cpp b/src/graphics/shader/recompiler/decompiler/ShaderDecoder.cpp index 4230abf..fcbb3e2 100644 --- a/src/graphics/shader/recompiler/decompiler/ShaderDecoder.cpp +++ b/src/graphics/shader/recompiler/decompiler/ShaderDecoder.cpp @@ -77,6 +77,16 @@ std::string FormatBinary(const Instruction& inst) { return text; } +std::string FormatSources(const Instruction& inst) { + std::string text = fmt::format("0x{:08x}: {}", inst.pc, OpcodeToString(inst.opcode)); + const Operand* sources[] = {&inst.src0, &inst.src1, &inst.src2, &inst.src3}; + for (uint32_t i = 0; i < inst.src_count && i < 4u; i++) { + text += i == 0 ? " " : ", "; + text += OperandToString(*sources[i]); + } + return text; +} + std::string FormatMemory(const Instruction& inst) { std::string text = fmt::format("0x{:08x}: {} {}", inst.pc, OpcodeToString(inst.opcode).c_str(), OperandToString(inst.dst).c_str()); @@ -985,6 +995,9 @@ std::string InstructionToString(const Instruction& inst) { inst.pc, FamilyToString(inst.family).c_str(), inst.opcode_id, RawWordsToString(inst).c_str(), inst.unsupported_reason.c_str()); } + if (inst.family == Family::SOPC) { + return WithUnsupportedReason(inst, FormatSources(inst)); + } switch (inst.opcode) { case Opcode::SMovB32: @@ -1173,26 +1186,6 @@ std::string InstructionToString(const Instruction& inst) { case Opcode::DsWriteB128: case Opcode::DsWriteAddtidB32: case Opcode::DsReadAddtidB32: return WithUnsupportedReason(inst, FormatMemory(inst)); - case Opcode::SCmpEqU32: - case Opcode::SCmpEqI32: - case Opcode::SCmpLgU32: - case Opcode::SCmpLgI32: - case Opcode::SCmpGtU32: - case Opcode::SCmpGtI32: - case Opcode::SCmpGeU32: - case Opcode::SCmpGeI32: - case Opcode::SCmpLtU32: - case Opcode::SCmpLtI32: - case Opcode::SCmpLeU32: - case Opcode::SCmpLeI32: - case Opcode::SBitcmp0B32: - case Opcode::SBitcmp1B32: - case Opcode::SCmpEqU64: - case Opcode::SCmpLgU64: - return WithUnsupportedReason(inst, fmt::format("0x{:08x}: {} {}, {}", inst.pc, - OpcodeToString(inst.opcode).c_str(), - OperandToString(inst.src0).c_str(), - OperandToString(inst.src1).c_str())); default: return WithUnsupportedReason(inst, FormatBinary(inst)); } } diff --git a/src/graphics/shader/recompiler/decompiler/VectorAluOps.cpp b/src/graphics/shader/recompiler/decompiler/VectorAluOps.cpp index 6fd1dbf..6ca9db9 100644 --- a/src/graphics/shader/recompiler/decompiler/VectorAluOps.cpp +++ b/src/graphics/shader/recompiler/decompiler/VectorAluOps.cpp @@ -1,43 +1,91 @@ #include "graphics/shader/recompiler/decompiler/VectorAluOps.h" +#include "graphics/shader/recompiler/decompiler/OpcodeTable.h" + #include -#include namespace Libs::Graphics::ShaderRecompiler::Decoder { namespace { -struct OpcodeMap { - uint32_t opcode = 0; - Opcode ir = Opcode::Unknown; +using Detail::OpcodeMap; + +// These profiles describe the selectors that the current lowering implements. They are not +// architectural SDWA legality classes. +enum class Vop2SdwaProfile { + None, + Cndmask, + Float32, + Float16, + IntegerFullDestination, + IntegerPartialDestination, + ReverseLogicalRight, + ReverseLogicalLeft, + Bitwise, + Count, }; -constexpr OpcodeMap VOP2_OPS[] = { - {0x01u, Opcode::VCndmaskB32}, {0x02u, Opcode::VDot2cF32F16}, - {0x03u, Opcode::VAddF32}, {0x04u, Opcode::VSubF32}, - {0x05u, Opcode::VSubrevF32}, {0x08u, Opcode::VMulF32}, - {0x09u, Opcode::VMulI32I24}, {0x0bu, Opcode::VMulU32U24}, - {0x0fu, Opcode::VMinF32}, {0x10u, Opcode::VMaxF32}, - {0x11u, Opcode::VMinI32}, {0x12u, Opcode::VMaxI32}, - {0x13u, Opcode::VMinU32}, {0x14u, Opcode::VMaxU32}, - {0x15u, Opcode::VLshrB32}, {0x16u, Opcode::VLshrrevB32}, - {0x17u, Opcode::VAshrI32}, {0x18u, Opcode::VAshrrevI32}, - {0x19u, Opcode::VLshlB32}, {0x1au, Opcode::VLshlrevB32}, - {0x1bu, Opcode::VAndB32}, {0x1cu, Opcode::VOrB32}, - {0x1du, Opcode::VXorB32}, {0x1eu, Opcode::VXnorB32}, - {0x1fu, Opcode::VMacF32}, {0x20u, Opcode::VMadmkF32}, - {0x21u, Opcode::VMadakF32}, {0x22u, Opcode::VBcntU32B32}, - {0x23u, Opcode::VMbcntLoU32B32}, {0x24u, Opcode::VMbcntHiU32B32}, - {0x25u, Opcode::VAddNcU32}, {0x28u, Opcode::VAddcU32}, - {0x26u, Opcode::VSubNcU32}, {0x27u, Opcode::VSubrevNcU32}, - {0x2bu, Opcode::VMacF32}, {0x2cu, Opcode::VMadmkF32}, - {0x2du, Opcode::VMadakF32}, {0x2fu, Opcode::VCvtPkrtzF16F32}, - {0x32u, Opcode::VAddF16}, {0x33u, Opcode::VSubF16}, - {0x34u, Opcode::VSubrevF16}, {0x35u, Opcode::VMulF16}, - {0x36u, Opcode::VFmacF16}, {0x37u, Opcode::VFmamkF16}, - {0x38u, Opcode::VFmaakF16}, {0x39u, Opcode::VMaxF16}, - {0x3au, Opcode::VMinF16}, {0x3cu, Opcode::VPkFmacF16}, +struct Vop2OpcodeInfo { + uint32_t encoding = 0; + Opcode decoded = Opcode::Unknown; + Vop2SdwaProfile sdwa_profile = Vop2SdwaProfile::None; }; +constexpr Vop2OpcodeInfo VOP2_OPS[] = { + {0x01u, Opcode::VCndmaskB32, Vop2SdwaProfile::Cndmask}, + {0x02u, Opcode::VDot2cF32F16}, + {0x03u, Opcode::VAddF32, Vop2SdwaProfile::Float32}, + {0x04u, Opcode::VSubF32, Vop2SdwaProfile::Float32}, + {0x05u, Opcode::VSubrevF32}, + {0x08u, Opcode::VMulF32, Vop2SdwaProfile::Float32}, + {0x09u, Opcode::VMulI32I24, Vop2SdwaProfile::IntegerFullDestination}, + {0x0bu, Opcode::VMulU32U24, Vop2SdwaProfile::IntegerFullDestination}, + {0x0fu, Opcode::VMinF32}, + {0x10u, Opcode::VMaxF32}, + {0x11u, Opcode::VMinI32}, + {0x12u, Opcode::VMaxI32}, + {0x13u, Opcode::VMinU32, Vop2SdwaProfile::IntegerPartialDestination}, + {0x14u, Opcode::VMaxU32, Vop2SdwaProfile::IntegerFullDestination}, + {0x15u, Opcode::VLshrB32}, + {0x16u, Opcode::VLshrrevB32, Vop2SdwaProfile::ReverseLogicalRight}, + {0x17u, Opcode::VAshrI32}, + {0x18u, Opcode::VAshrrevI32}, + {0x19u, Opcode::VLshlB32}, + {0x1au, Opcode::VLshlrevB32, Vop2SdwaProfile::ReverseLogicalLeft}, + {0x1bu, Opcode::VAndB32, Vop2SdwaProfile::Bitwise}, + {0x1cu, Opcode::VOrB32, Vop2SdwaProfile::Bitwise}, + {0x1du, Opcode::VXorB32, Vop2SdwaProfile::Bitwise}, + {0x1eu, Opcode::VXnorB32, Vop2SdwaProfile::Bitwise}, + {0x1fu, Opcode::VMacF32}, + {0x20u, Opcode::VMadmkF32}, + {0x21u, Opcode::VMadakF32}, + {0x22u, Opcode::VBcntU32B32}, + {0x23u, Opcode::VMbcntLoU32B32}, + {0x24u, Opcode::VMbcntHiU32B32}, + {0x25u, Opcode::VAddNcU32, Vop2SdwaProfile::IntegerFullDestination}, + {0x28u, Opcode::VAddcU32}, + {0x26u, Opcode::VSubNcU32, Vop2SdwaProfile::IntegerPartialDestination}, + {0x27u, Opcode::VSubrevNcU32, Vop2SdwaProfile::IntegerFullDestination}, + {0x2bu, Opcode::VMacF32}, + {0x2cu, Opcode::VMadmkF32}, + {0x2du, Opcode::VMadakF32}, + {0x2fu, Opcode::VCvtPkrtzF16F32}, + {0x32u, Opcode::VAddF16, Vop2SdwaProfile::Float16}, + {0x33u, Opcode::VSubF16, Vop2SdwaProfile::Float16}, + {0x34u, Opcode::VSubrevF16, Vop2SdwaProfile::Float16}, + {0x35u, Opcode::VMulF16, Vop2SdwaProfile::Float16}, + {0x36u, Opcode::VFmacF16}, + {0x37u, Opcode::VFmamkF16}, + {0x38u, Opcode::VFmaakF16}, + {0x39u, Opcode::VMaxF16, Vop2SdwaProfile::Float16}, + {0x3au, Opcode::VMinF16, Vop2SdwaProfile::Float16}, + {0x3cu, Opcode::VPkFmacF16}, +}; +static_assert(Detail::HasUniqueEncodings(VOP2_OPS)); + +constexpr Opcode LookupVop2Opcode(uint32_t encoding) { + return Detail::LookupOpcode(VOP2_OPS, encoding); +} + constexpr OpcodeMap VOP1_OPS[] = { {0x00u, Opcode::VNop}, {0x01u, Opcode::VMovB32}, @@ -135,37 +183,58 @@ constexpr OpcodeMap VOP3_ENCODED_VOP1_OPS[] = { {0x5eu, Opcode::VRndneF16}, }; -constexpr OpcodeMap VOPC_OPS[] = { - {0x00u, Opcode::VCmpFF32}, {0x01u, Opcode::VCmpLtF32}, {0x02u, Opcode::VCmpEqF32}, - {0x03u, Opcode::VCmpLeF32}, {0x04u, Opcode::VCmpGtF32}, {0x05u, Opcode::VCmpLgF32}, - {0x06u, Opcode::VCmpGeF32}, {0x07u, Opcode::VCmpOF32}, {0x08u, Opcode::VCmpUF32}, - {0x09u, Opcode::VCmpNgeF32}, {0x0au, Opcode::VCmpNlgF32}, {0x0bu, Opcode::VCmpNgtF32}, - {0x0cu, Opcode::VCmpNleF32}, {0x0du, Opcode::VCmpNeqF32}, {0x0eu, Opcode::VCmpNltF32}, - {0x0fu, Opcode::VCmpTruF32}, {0x11u, Opcode::VCmpxLtF32}, {0x12u, Opcode::VCmpxEqF32}, - {0x13u, Opcode::VCmpxLeF32}, {0x14u, Opcode::VCmpxGtF32}, {0x15u, Opcode::VCmpxLgF32}, - {0x16u, Opcode::VCmpxGeF32}, {0x19u, Opcode::VCmpxNgeF32}, {0x1au, Opcode::VCmpxNlgF32}, - {0x1bu, Opcode::VCmpxNgtF32}, {0x1cu, Opcode::VCmpxNleF32}, {0x1du, Opcode::VCmpxNeqF32}, - {0x1eu, Opcode::VCmpxNltF32}, {0x80u, Opcode::VCmpFI32}, {0x81u, Opcode::VCmpLtI32}, - {0x82u, Opcode::VCmpEqI32}, {0x83u, Opcode::VCmpLeI32}, {0x84u, Opcode::VCmpGtI32}, - {0x85u, Opcode::VCmpNeI32}, {0x86u, Opcode::VCmpGeI32}, {0x87u, Opcode::VCmpTI32}, - {0x88u, Opcode::VCmpClassF32}, {0x89u, Opcode::VCmpLtI16}, {0x8au, Opcode::VCmpEqI16}, - {0x8bu, Opcode::VCmpLeI16}, {0x8cu, Opcode::VCmpGtI16}, {0x8du, Opcode::VCmpNeI16}, - {0x8eu, Opcode::VCmpGeI16}, {0x91u, Opcode::VCmpxLtI32}, {0x92u, Opcode::VCmpxEqI32}, - {0x93u, Opcode::VCmpxLeI32}, {0x94u, Opcode::VCmpxGtI32}, {0x95u, Opcode::VCmpxNeI32}, - {0x96u, Opcode::VCmpxGeI32}, {0xa9u, Opcode::VCmpLtU16}, {0xaau, Opcode::VCmpEqU16}, - {0xabu, Opcode::VCmpLeU16}, {0xacu, Opcode::VCmpGtU16}, {0xadu, Opcode::VCmpNeU16}, - {0xaeu, Opcode::VCmpGeU16}, {0xc0u, Opcode::VCmpFU32}, {0xc1u, Opcode::VCmpLtU32}, - {0xc2u, Opcode::VCmpEqU32}, {0xc3u, Opcode::VCmpLeU32}, {0xc4u, Opcode::VCmpGtU32}, - {0xc5u, Opcode::VCmpNeU32}, {0xc6u, Opcode::VCmpGeU32}, {0xc7u, Opcode::VCmpTU32}, - {0xa2u, Opcode::VCmpEqI64}, {0xd1u, Opcode::VCmpxLtU32}, {0xd2u, Opcode::VCmpxEqU32}, - {0xd3u, Opcode::VCmpxLeU32}, {0xd4u, Opcode::VCmpxGtU32}, {0xd5u, Opcode::VCmpxNeU32}, - {0xd6u, Opcode::VCmpxGeU32}, {0xe5u, Opcode::VCmpNeU64}, {0xc9u, Opcode::VCmpLtF16}, - {0xcau, Opcode::VCmpEqF16}, {0xcbu, Opcode::VCmpLeF16}, {0xccu, Opcode::VCmpGtF16}, - {0xcdu, Opcode::VCmpLgF16}, {0xceu, Opcode::VCmpGeF16}, {0xedu, Opcode::VCmpNeqF16}, - {0xd9u, Opcode::VCmpxLtF16}, {0xdau, Opcode::VCmpxEqF16}, {0xdbu, Opcode::VCmpxLeF16}, - {0xdcu, Opcode::VCmpxGtF16}, {0xdeu, Opcode::VCmpxGeF16}, {0xfdu, Opcode::VCmpxNeqF16}, +struct VopcOpcodeInfo { + uint32_t encoding = 0; + Opcode decoded = Opcode::Unknown; + bool supports_dpp = true; +}; + +constexpr VopcOpcodeInfo VOPC_OPS[] = { + {0x00u, Opcode::VCmpFF32}, {0x01u, Opcode::VCmpLtF32}, + {0x02u, Opcode::VCmpEqF32}, {0x03u, Opcode::VCmpLeF32}, + {0x04u, Opcode::VCmpGtF32}, {0x05u, Opcode::VCmpLgF32}, + {0x06u, Opcode::VCmpGeF32}, {0x07u, Opcode::VCmpOF32}, + {0x08u, Opcode::VCmpUF32}, {0x09u, Opcode::VCmpNgeF32}, + {0x0au, Opcode::VCmpNlgF32}, {0x0bu, Opcode::VCmpNgtF32}, + {0x0cu, Opcode::VCmpNleF32}, {0x0du, Opcode::VCmpNeqF32}, + {0x0eu, Opcode::VCmpNltF32}, {0x0fu, Opcode::VCmpTruF32}, + {0x11u, Opcode::VCmpxLtF32}, {0x12u, Opcode::VCmpxEqF32}, + {0x13u, Opcode::VCmpxLeF32}, {0x14u, Opcode::VCmpxGtF32}, + {0x15u, Opcode::VCmpxLgF32}, {0x16u, Opcode::VCmpxGeF32}, + {0x19u, Opcode::VCmpxNgeF32}, {0x1au, Opcode::VCmpxNlgF32}, + {0x1bu, Opcode::VCmpxNgtF32}, {0x1cu, Opcode::VCmpxNleF32}, + {0x1du, Opcode::VCmpxNeqF32}, {0x1eu, Opcode::VCmpxNltF32}, + {0x80u, Opcode::VCmpFI32}, {0x81u, Opcode::VCmpLtI32}, + {0x82u, Opcode::VCmpEqI32}, {0x83u, Opcode::VCmpLeI32}, + {0x84u, Opcode::VCmpGtI32}, {0x85u, Opcode::VCmpNeI32}, + {0x86u, Opcode::VCmpGeI32}, {0x87u, Opcode::VCmpTI32}, + {0x88u, Opcode::VCmpClassF32}, {0x89u, Opcode::VCmpLtI16}, + {0x8au, Opcode::VCmpEqI16}, {0x8bu, Opcode::VCmpLeI16}, + {0x8cu, Opcode::VCmpGtI16}, {0x8du, Opcode::VCmpNeI16}, + {0x8eu, Opcode::VCmpGeI16}, {0x91u, Opcode::VCmpxLtI32}, + {0x92u, Opcode::VCmpxEqI32}, {0x93u, Opcode::VCmpxLeI32}, + {0x94u, Opcode::VCmpxGtI32}, {0x95u, Opcode::VCmpxNeI32}, + {0x96u, Opcode::VCmpxGeI32}, {0xa9u, Opcode::VCmpLtU16}, + {0xaau, Opcode::VCmpEqU16}, {0xabu, Opcode::VCmpLeU16}, + {0xacu, Opcode::VCmpGtU16}, {0xadu, Opcode::VCmpNeU16}, + {0xaeu, Opcode::VCmpGeU16}, {0xc0u, Opcode::VCmpFU32}, + {0xc1u, Opcode::VCmpLtU32}, {0xc2u, Opcode::VCmpEqU32}, + {0xc3u, Opcode::VCmpLeU32}, {0xc4u, Opcode::VCmpGtU32}, + {0xc5u, Opcode::VCmpNeU32}, {0xc6u, Opcode::VCmpGeU32}, + {0xc7u, Opcode::VCmpTU32}, {0xa2u, Opcode::VCmpEqI64, false}, + {0xd1u, Opcode::VCmpxLtU32}, {0xd2u, Opcode::VCmpxEqU32}, + {0xd3u, Opcode::VCmpxLeU32}, {0xd4u, Opcode::VCmpxGtU32}, + {0xd5u, Opcode::VCmpxNeU32}, {0xd6u, Opcode::VCmpxGeU32}, + {0xe5u, Opcode::VCmpNeU64, false}, {0xc9u, Opcode::VCmpLtF16}, + {0xcau, Opcode::VCmpEqF16}, {0xcbu, Opcode::VCmpLeF16}, + {0xccu, Opcode::VCmpGtF16}, {0xcdu, Opcode::VCmpLgF16}, + {0xceu, Opcode::VCmpGeF16}, {0xedu, Opcode::VCmpNeqF16}, + {0xd9u, Opcode::VCmpxLtF16}, {0xdau, Opcode::VCmpxEqF16}, + {0xdbu, Opcode::VCmpxLeF16}, {0xdcu, Opcode::VCmpxGtF16}, + {0xdeu, Opcode::VCmpxGeF16}, {0xfdu, Opcode::VCmpxNeqF16}, {0xfeu, Opcode::VCmpxNltF16}, }; +static_assert(Detail::HasUniqueEncodings(VOPC_OPS)); constexpr OpcodeMap VOP3_OPS[] = { {0x141u, Opcode::VMadF32}, {0x142u, Opcode::VMadI32I24}, @@ -215,16 +284,6 @@ constexpr OpcodeMap VOP3P_OPS[] = { {0x22u, Opcode::VMadMixhiF16}, }; -Opcode Lookup(const OpcodeMap* ops, uint32_t count, uint32_t opcode) { - for (uint32_t i = 0; i < count; i++) { - const auto& op = ops[i]; - if (op.opcode == opcode) { - return op.ir; - } - } - return Opcode::Unsupported; -} - bool IsVop2LiteralMadOpcode(uint32_t opcode) { return opcode == 0x20u || opcode == 0x21u || opcode == 0x2cu || opcode == 0x2du; } @@ -235,24 +294,23 @@ bool IsUnsupportedVop3EncodedVop2Alias(uint32_t opcode) { } Opcode LookupVop3Opcode(uint32_t opcode) { - const auto direct = Lookup(VOP3_OPS, static_cast(std::size(VOP3_OPS)), opcode); + const auto direct = Detail::LookupOpcode(VOP3_OPS, opcode); if (direct != Opcode::Unsupported) { return direct; } if (opcode <= 0xffu) { - return Lookup(VOPC_OPS, static_cast(std::size(VOPC_OPS)), opcode); + return Detail::LookupOpcode(VOPC_OPS, opcode); } if (opcode >= 0x100u && opcode <= 0x13fu) { if (IsUnsupportedVop3EncodedVop2Alias(opcode - 0x100u)) { return Opcode::Unsupported; } - return Lookup(VOP2_OPS, static_cast(std::size(VOP2_OPS)), opcode - 0x100u); + return LookupVop2Opcode(opcode - 0x100u); } if (opcode >= 0x180u && opcode <= 0x1ffu) { - return Lookup(VOP3_ENCODED_VOP1_OPS, - static_cast(std::size(VOP3_ENCODED_VOP1_OPS)), opcode - 0x180u); + return Detail::LookupOpcode(VOP3_ENCODED_VOP1_OPS, opcode - 0x180u); } - return Lookup(VOP3_OPS, static_cast(std::size(VOP3_OPS)), opcode); + return Detail::LookupOpcode(VOP3_OPS, opcode); } bool IsVop3EncodedVopc(uint32_t opcode) { @@ -792,7 +850,6 @@ Vop2SdwaFields DecodeVop2SdwaFields(uint32_t modifier) { } struct Vop2SdwaRule { - Opcode opcode = Opcode::Unknown; uint32_t dst_selectors = SdwaSelFull(); uint32_t src0_selectors = SdwaSelFull(); uint32_t src1_selectors = SdwaSelFull(); @@ -805,46 +862,27 @@ constexpr uint32_t SdwaSelAll() { } constexpr Vop2SdwaRule VOP2_SDWA_RULES[] = { - {Opcode::VCndmaskB32, SdwaSelWords() | SdwaSelFull(), SdwaSelWords() | SdwaSelFull(), - SdwaSelWords() | SdwaSelFull(), true, false}, - {Opcode::VAddF32, SdwaSelFull(), SdwaSelFull(), SdwaSelFull(), false, true}, - {Opcode::VSubF32, SdwaSelFull(), SdwaSelFull(), SdwaSelFull(), false, true}, - {Opcode::VMulF32, SdwaSelFull(), SdwaSelFull(), SdwaSelFull(), false, true}, - {Opcode::VAddF16, SdwaSelWords() | SdwaSelFull(), SdwaSelWords() | SdwaSelFull(), - SdwaSelWords() | SdwaSelFull(), true, true}, - {Opcode::VSubF16, SdwaSelWords() | SdwaSelFull(), SdwaSelWords() | SdwaSelFull(), - SdwaSelWords() | SdwaSelFull(), true, true}, - {Opcode::VSubrevF16, SdwaSelWords() | SdwaSelFull(), SdwaSelWords() | SdwaSelFull(), - SdwaSelWords() | SdwaSelFull(), true, true}, - {Opcode::VMulF16, SdwaSelWords() | SdwaSelFull(), SdwaSelWords() | SdwaSelFull(), - SdwaSelWords() | SdwaSelFull(), true, true}, - {Opcode::VMaxF16, SdwaSelWords() | SdwaSelFull(), SdwaSelWords() | SdwaSelFull(), - SdwaSelWords() | SdwaSelFull(), true, true}, - {Opcode::VMinF16, SdwaSelWords() | SdwaSelFull(), SdwaSelWords() | SdwaSelFull(), - SdwaSelWords() | SdwaSelFull(), true, true}, - {Opcode::VMulI32I24, SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), false, false}, - {Opcode::VMulU32U24, SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), false, false}, - {Opcode::VMinU32, SdwaSelAll(), SdwaSelAll(), SdwaSelAll(), true, false}, - {Opcode::VMaxU32, SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), false, false}, - {Opcode::VLshrrevB32, SdwaSelFull(), SdwaSelFull(), SdwaSelWords() | SdwaSelFull(), false, - false}, - {Opcode::VLshlrevB32, SdwaSelFull(), SdwaSelFull(), SdwaSelAll(), false, false}, - {Opcode::VAndB32, SdwaSelWords() | SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), true, false}, - {Opcode::VOrB32, SdwaSelWords() | SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), true, false}, - {Opcode::VXorB32, SdwaSelWords() | SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), true, false}, - {Opcode::VXnorB32, SdwaSelWords() | SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), true, false}, - {Opcode::VAddNcU32, SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), false, false}, - {Opcode::VSubNcU32, SdwaSelAll(), SdwaSelAll(), SdwaSelAll(), true, false}, - {Opcode::VSubrevNcU32, SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), false, false}, + {}, + {SdwaSelWords() | SdwaSelFull(), SdwaSelWords() | SdwaSelFull(), SdwaSelWords() | SdwaSelFull(), + true, false}, + {SdwaSelFull(), SdwaSelFull(), SdwaSelFull(), false, true}, + {SdwaSelWords() | SdwaSelFull(), SdwaSelWords() | SdwaSelFull(), SdwaSelWords() | SdwaSelFull(), + true, true}, + {SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), false, false}, + {SdwaSelAll(), SdwaSelAll(), SdwaSelAll(), true, false}, + {SdwaSelFull(), SdwaSelFull(), SdwaSelWords() | SdwaSelFull(), false, false}, + {SdwaSelFull(), SdwaSelFull(), SdwaSelAll(), false, false}, + {SdwaSelWords() | SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), true, false}, }; +static_assert(sizeof(VOP2_SDWA_RULES) / sizeof(VOP2_SDWA_RULES[0]) == + static_cast(Vop2SdwaProfile::Count)); -const Vop2SdwaRule* FindVop2SdwaRule(Opcode opcode) { - for (const auto& rule: VOP2_SDWA_RULES) { - if (rule.opcode == opcode) { - return &rule; - } +const Vop2SdwaRule* FindVop2SdwaRule(uint32_t encoding) { + const auto* info = Detail::FindOpcode(VOP2_OPS, encoding); + if (info == nullptr || info->sdwa_profile == Vop2SdwaProfile::None) { + return nullptr; } - return nullptr; + return &VOP2_SDWA_RULES[static_cast(info->sdwa_profile)]; } bool IsVop2SdwaDestinationSupported(const Vop2SdwaRule& rule, const Vop2SdwaFields& fields) { @@ -882,7 +920,7 @@ bool ValidateVop2Sdwa(Instruction& inst, uint32_t opcode, const Vop2SdwaFields& return true; } - const auto* rule = FindVop2SdwaRule(inst.opcode); + const auto* rule = FindVop2SdwaRule(opcode); if (rule == nullptr) { SetUnsupported(inst, Family::VOP2, opcode, "VOP2 SDWA modifier is not supported for opcode"); @@ -1136,6 +1174,11 @@ bool DecodeVopcDpp(uint32_t pc, std::span code, uint32_t word_in SetUnsupported(inst, Family::VOPC, opcode, "VOPC opcode is not implemented"); return true; } + const auto* info = Detail::FindOpcode(VOPC_OPS, opcode); + if (info == nullptr || !info->supports_dpp) { + 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)) { return false; @@ -1428,7 +1471,7 @@ bool DecodeVop2(uint32_t pc, std::span code, uint32_t word_index inst.word = word; inst.family = Family::VOP2; inst.opcode_id = opcode; - inst.opcode = Lookup(VOP2_OPS, static_cast(std::size(VOP2_OPS)), opcode); + inst.opcode = LookupVop2Opcode(opcode); SetRawWords(inst, code, word_index, 1); switch (opcode) { @@ -1469,7 +1512,7 @@ bool DecodeVop1(uint32_t pc, std::span code, uint32_t word_index inst.word = word; inst.family = Family::VOP1; inst.opcode_id = opcode; - inst.opcode = Lookup(VOP1_OPS, static_cast(std::size(VOP1_OPS)), opcode); + inst.opcode = Detail::LookupOpcode(VOP1_OPS, opcode); SetRawWords(inst, code, word_index, 1); if (inst.opcode == Opcode::Unsupported) { @@ -1510,7 +1553,7 @@ bool DecodeVopc(uint32_t pc, std::span code, uint32_t word_index inst.word = word; inst.family = Family::VOPC; inst.opcode_id = opcode; - inst.opcode = Lookup(VOPC_OPS, static_cast(std::size(VOPC_OPS)), opcode); + inst.opcode = Detail::LookupOpcode(VOPC_OPS, opcode); inst.dst.kind = IsVopcCompareExec(inst.opcode) ? OperandKind::ExecLo : OperandKind::VccLo; SetRawWords(inst, code, word_index, 1); @@ -1724,7 +1767,7 @@ bool DecodeVop3p(uint32_t pc, std::span code, uint32_t word_inde inst.word = word0; inst.family = Family::VOP3P; inst.opcode_id = opcode; - inst.opcode = Lookup(VOP3P_OPS, static_cast(std::size(VOP3P_OPS)), opcode); + inst.opcode = Detail::LookupOpcode(VOP3P_OPS, opcode); SetRawWords(inst, code, word_index, 2); if (inst.opcode == Opcode::Unsupported) { diff --git a/src/graphics/shader/recompiler/emitter/SpirvEmitter.cpp b/src/graphics/shader/recompiler/emitter/SpirvEmitter.cpp index d338310..7323755 100644 --- a/src/graphics/shader/recompiler/emitter/SpirvEmitter.cpp +++ b/src/graphics/shader/recompiler/emitter/SpirvEmitter.cpp @@ -389,7 +389,7 @@ bool ProgramRequiresExactSubgroupSize(const IR::Program& program) { if (Emitter::InstructionHasDppSource(inst)) { return true; } - if (Emitter::IsCompareOpcode(inst.op) && !Emitter::IsSccOperand(inst.dst)) { + if (IR::IsCompareOpcode(inst.op) && !Emitter::IsSccOperand(inst.dst)) { return true; } if ((IsExecDestination(inst.dst) || IsExecDestination(inst.dst2)) && diff --git a/src/graphics/shader/recompiler/emitter/spirvEmitterAluOps.cpp b/src/graphics/shader/recompiler/emitter/spirvEmitterAluOps.cpp index 33d7a83..4ecf53c 100644 --- a/src/graphics/shader/recompiler/emitter/spirvEmitterAluOps.cpp +++ b/src/graphics/shader/recompiler/emitter/spirvEmitterAluOps.cpp @@ -1486,7 +1486,8 @@ void EmitBitCompareB32(EmitterState& state, const IR::Instruction& inst, bool bi EmitStoreU32(state, inst.dst, ret); } -void EmitCompareU64(EmitterState& state, const IR::Instruction& inst, bool equal) { +void EmitCompareU64(EmitterState& state, const IR::Instruction& inst) { + const bool equal = inst.op == IR::Opcode::CompareEqU64; const auto lhs_low = EmitSequentialValueLoad(state, inst.src[0], 0); const auto lhs_high = EmitSequentialValueLoad(state, inst.src[0], 1); const auto rhs_low = EmitSequentialValueLoad(state, inst.src[1], 0); diff --git a/src/graphics/shader/recompiler/emitter/spirvEmitterAnalysis.cpp b/src/graphics/shader/recompiler/emitter/spirvEmitterAnalysis.cpp index 4515242..48611a2 100644 --- a/src/graphics/shader/recompiler/emitter/spirvEmitterAnalysis.cpp +++ b/src/graphics/shader/recompiler/emitter/spirvEmitterAnalysis.cpp @@ -75,8 +75,6 @@ bool IsSccOperand(const IR::Operand& operand) { return operand.kind == IR::OperandKind::Register && operand.reg.file == IR::RegisterFile::Scc; } -bool IsCompareOpcode(IR::Opcode op); - void CollectMaskStateRegisters(std::vector& registers) { CollectRegister(registers, {IR::RegisterFile::Exec, 0}); CollectRegister(registers, {IR::RegisterFile::Exec, 1}); @@ -189,11 +187,11 @@ void CollectRegisters(const IR::Program& program, std::vector& if (inst.op == IR::Opcode::BitCountU64 || inst.op == IR::Opcode::FindMsbFromHighU64) { CollectSequentialRegisters(registers, inst.src[0], 2); } - if (inst.op == IR::Opcode::CompareEqU64 || inst.op == IR::Opcode::CompareNeU64) { + if (IR::IsCompare64Opcode(inst.op)) { CollectSequentialRegisters(registers, inst.src[0], 2); CollectSequentialRegisters(registers, inst.src[1], 2); } - if (IsCompareOpcode(inst.op) && inst.dst.kind == IR::OperandKind::Register && + if (IR::IsCompareOpcode(inst.op) && inst.dst.kind == IR::OperandKind::Register && inst.dst.reg.file != IR::RegisterFile::Scc) { CollectSequentialRegisters(registers, inst.dst, 2); } @@ -384,94 +382,6 @@ bool ProgramNeedsSubgroupShuffle(const IR::Program& program) { return false; } -bool IsCompareOpcode(IR::Opcode op) { - switch (op) { - case IR::Opcode::CompareFalse: - case IR::Opcode::CompareTrue: - case IR::Opcode::CompareEqU32: - case IR::Opcode::CompareNeU32: - case IR::Opcode::CompareGtU32: - case IR::Opcode::CompareGeU32: - case IR::Opcode::CompareLtU32: - case IR::Opcode::CompareLeU32: - case IR::Opcode::CompareEqU64: - case IR::Opcode::CompareNeU64: - case IR::Opcode::CompareMaskEqU32: - case IR::Opcode::CompareMaskNeU32: - case IR::Opcode::CompareMaskGtU32: - case IR::Opcode::CompareMaskGeU32: - case IR::Opcode::CompareMaskLtU32: - case IR::Opcode::CompareMaskLeU32: - case IR::Opcode::CompareEqI32: - case IR::Opcode::CompareNeI32: - case IR::Opcode::CompareGtI32: - case IR::Opcode::CompareGeI32: - case IR::Opcode::CompareLtI32: - case IR::Opcode::CompareLeI32: - case IR::Opcode::CompareEqI16: - case IR::Opcode::CompareNeI16: - case IR::Opcode::CompareGtI16: - case IR::Opcode::CompareGeI16: - case IR::Opcode::CompareLtI16: - case IR::Opcode::CompareLeI16: - case IR::Opcode::CompareMaskEqI32: - case IR::Opcode::CompareMaskNeI32: - case IR::Opcode::CompareMaskGtI32: - case IR::Opcode::CompareMaskGeI32: - case IR::Opcode::CompareMaskLtI32: - case IR::Opcode::CompareMaskLeI32: - case IR::Opcode::CompareEqU16: - case IR::Opcode::CompareNeU16: - case IR::Opcode::CompareGtU16: - case IR::Opcode::CompareGeU16: - case IR::Opcode::CompareLtU16: - case IR::Opcode::CompareLeU16: - case IR::Opcode::CompareEqF32: - case IR::Opcode::CompareNeF32: - case IR::Opcode::CompareGtF32: - case IR::Opcode::CompareGeF32: - case IR::Opcode::CompareLtF32: - case IR::Opcode::CompareLeF32: - case IR::Opcode::CompareOrderedF32: - case IR::Opcode::CompareUnorderedF32: - case IR::Opcode::CompareUnordEqF32: - case IR::Opcode::CompareUnordNeF32: - case IR::Opcode::CompareUnordGtF32: - case IR::Opcode::CompareUnordGeF32: - case IR::Opcode::CompareUnordLtF32: - case IR::Opcode::CompareUnordLeF32: - case IR::Opcode::CompareClassF32: - case IR::Opcode::CompareEqF16: - case IR::Opcode::CompareNeF16: - case IR::Opcode::CompareGtF16: - case IR::Opcode::CompareGeF16: - case IR::Opcode::CompareLtF16: - case IR::Opcode::CompareLeF16: - case IR::Opcode::CompareUnordNeF16: - case IR::Opcode::CompareMaskEqF16: - case IR::Opcode::CompareMaskNeF16: - case IR::Opcode::CompareMaskGtF16: - case IR::Opcode::CompareMaskGeF16: - case IR::Opcode::CompareMaskLtF16: - case IR::Opcode::CompareMaskLeF16: - case IR::Opcode::CompareMaskUnordNeF16: - case IR::Opcode::CompareMaskUnordGeF16: - case IR::Opcode::CompareMaskEqF32: - case IR::Opcode::CompareMaskNeF32: - case IR::Opcode::CompareMaskGtF32: - case IR::Opcode::CompareMaskGeF32: - case IR::Opcode::CompareMaskLtF32: - case IR::Opcode::CompareMaskLeF32: - case IR::Opcode::CompareMaskUnordEqF32: - case IR::Opcode::CompareMaskUnordNeF32: - case IR::Opcode::CompareMaskUnordGtF32: - case IR::Opcode::CompareMaskUnordGeF32: - case IR::Opcode::CompareMaskUnordLtF32: - case IR::Opcode::CompareMaskUnordLeF32: return true; - default: return false; - } -} - bool ProgramNeedsSubgroupLocalInvocationId(const IR::Program& program) { for (const auto& block: program.blocks) { for (const auto& inst: block.instructions) { @@ -482,7 +392,7 @@ bool ProgramNeedsSubgroupLocalInvocationId(const IR::Program& program) { InstructionHasDppSource(inst)) { return true; } - if (IsCompareOpcode(inst.op)) { + if (IR::IsCompareOpcode(inst.op)) { return true; } if (inst.dst.kind == IR::OperandKind::Register && diff --git a/src/graphics/shader/recompiler/emitter/spirvEmitterControlFlow.cpp b/src/graphics/shader/recompiler/emitter/spirvEmitterControlFlow.cpp index 1bb66f0..aaf6def 100644 --- a/src/graphics/shader/recompiler/emitter/spirvEmitterControlFlow.cpp +++ b/src/graphics/shader/recompiler/emitter/spirvEmitterControlFlow.cpp @@ -516,8 +516,8 @@ void EmitInstruction(EmitterState& state, const IR::Instruction& inst) { case IR::Opcode::CompareGeU32: EmitCompareU32(state, inst, OpUGreaterThanEqual); break; case IR::Opcode::CompareLtU32: EmitCompareU32(state, inst, OpULessThan); break; case IR::Opcode::CompareLeU32: EmitCompareU32(state, inst, OpULessThanEqual); break; - case IR::Opcode::CompareEqU64: EmitCompareU64(state, inst, true); break; - case IR::Opcode::CompareNeU64: EmitCompareU64(state, inst, false); break; + case IR::Opcode::CompareEqU64: + case IR::Opcode::CompareNeU64: EmitCompareU64(state, inst); break; case IR::Opcode::CompareMaskEqU32: EmitCompareMaskU32(state, inst, OpIEqual); break; case IR::Opcode::CompareMaskNeU32: EmitCompareMaskU32(state, inst, OpINotEqual); break; case IR::Opcode::CompareMaskGtU32: EmitCompareMaskU32(state, inst, OpUGreaterThan); break; diff --git a/src/graphics/shader/recompiler/emitter/spirvEmitterInternal.h b/src/graphics/shader/recompiler/emitter/spirvEmitterInternal.h index 702d37d..0158dfe 100644 --- a/src/graphics/shader/recompiler/emitter/spirvEmitterInternal.h +++ b/src/graphics/shader/recompiler/emitter/spirvEmitterInternal.h @@ -611,8 +611,6 @@ bool IsMaskRegisterFile(IR::RegisterFile file); bool IsSccOperand(const IR::Operand& operand); -bool IsCompareOpcode(IR::Opcode op); - void CollectMaskStateRegisters(std::vector& registers); void CollectSequentialRegisters(std::vector& registers, const IR::Operand& base, @@ -651,8 +649,6 @@ bool ProgramNeedsSubgroupBallot(const IR::Program& program); bool ProgramNeedsSubgroupShuffle(const IR::Program& program); -bool IsCompareOpcode(IR::Opcode op); - bool ProgramNeedsSubgroupLocalInvocationId(const IR::Program& program); uint32_t PointerForRegister(const EmitterState& state, IR::Register reg); @@ -1345,7 +1341,7 @@ void EmitCompareI16(EmitterState& state, const IR::Instruction& inst, uint32_t o void EmitBitCompareB32(EmitterState& state, const IR::Instruction& inst, bool bit_set); -void EmitCompareU64(EmitterState& state, const IR::Instruction& inst, bool equal); +void EmitCompareU64(EmitterState& state, const IR::Instruction& inst); void EmitCompareConstant(EmitterState& state, const IR::Instruction& inst, bool value); diff --git a/src/graphics/shader/recompiler/ir/ShaderIR.cpp b/src/graphics/shader/recompiler/ir/ShaderIR.cpp index ac01d4f..cfcd0ee 100644 --- a/src/graphics/shader/recompiler/ir/ShaderIR.cpp +++ b/src/graphics/shader/recompiler/ir/ShaderIR.cpp @@ -490,13 +490,26 @@ bool IsScalarMinMaxOpcode(Decoder::Opcode opcode) { } } +bool ResolveIrOpcode(Decoder::Opcode decoded, Opcode& lowered, std::string* error) { + const auto opcode = LookupIrOpcode(decoded); + if (!opcode.has_value()) { + if (error != nullptr) { + *error = fmt::format("decoded opcode has no IR lowering: {}", + Decoder::OpcodeToString(decoded)); + } + return false; + } + lowered = *opcode; + return true; +} + bool LowerScalarMinMaxWithScc(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction result; result.pc = decoded.pc; - result.op = LookupIrOpcode(decoded.opcode); result.src_count = 2; - if (!LowerRegisterOperand(decoded.dst, result.dst, error) || + if (!ResolveIrOpcode(decoded.opcode, result.op, error) || + !LowerRegisterOperand(decoded.dst, result.dst, error) || !LowerSourceOperand(decoded.src0, result.src[0], error) || !LowerSourceOperand(decoded.src1, result.src[1], error)) { return false; @@ -1116,23 +1129,16 @@ bool LowerDecodedInstruction(const Decoder::Instruction& inst, BasicBlock& block if (VectorByteConvertIndex(inst.opcode) <= 3u) { return LowerVectorByteConvert(inst, block, error); } - if (!IsImplemented(inst.opcode)) { - if (error != nullptr) { - *error = fmt::format("decoded opcode has no IR lowering yet: {}", - Decoder::InstructionToString(inst).c_str()); - } - return false; - } return LowerImplemented(inst, block, error); } bool LowerImplemented(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; - inst.op = LookupIrOpcode(decoded.opcode); inst.src_count = decoded.src_count; - if (!LowerRegisterOperand(decoded.dst, inst.dst, error)) { + if (!ResolveIrOpcode(decoded.opcode, inst.op, error) || + !LowerRegisterOperand(decoded.dst, inst.dst, error)) { return false; } ApplyDppDestinationMask(decoded, inst.dst); diff --git a/src/graphics/shader/recompiler/ir/ShaderIR.h b/src/graphics/shader/recompiler/ir/ShaderIR.h index 89ed757..8f66ad8 100644 --- a/src/graphics/shader/recompiler/ir/ShaderIR.h +++ b/src/graphics/shader/recompiler/ir/ShaderIR.h @@ -8,351 +8,48 @@ #include "graphics/shader/shader.h" #include +#include #include namespace Libs::Graphics::ShaderRecompiler::IR { enum class Opcode { - ControlNop, - Waitcnt, - Barrier, - Sendmsg, - TtraceData, - InstPrefetch, - MoveU32, - MoveF32Bits, - MoveRelDestU32, - MoveRelSourceU32, - MoveU64, - WqmB64, - SaveexecB32, - SaveexecB64, - ReadFirstLaneU32, - ReadLaneU32, - WriteLaneU32, - Permlane16B32, - Permlanex16B32, - AbsI32, - IAddU32, - IAddCarryU32, - ISubBorrowU32, - ScalarAddCarryU32, - ScalarSubBorrowU32, - ScalarSubBorrowCarryU32, - ScalarSignedAddOverflowI32, - ScalarSignedSubOverflowI32, - ScalarShiftLeftAddCarryU32, - ISubU32, - IMulU32, - UMulHighU32, - SMulHighI32, - IMadI24U32, - UMadU24U32, - UMadU64U32, - SadU32, - IAdd3U32, - IMulI24U32, - UMulU24U32, - IMinI32, - IMaxI32, - IMin3I32, - IMax3I32, - IMed3I32, - UMinU32, - UMaxU32, - UMin3U32, - UMax3U32, - UMed3U32, - BitwiseAndU32, - BitwiseAndU64, - BitwiseAndNotU32, - BitwiseAndNotU64, - BitwiseOrU32, - BitwiseOrU64, - BitwiseOrNotU32, - BitwiseOrNotU64, - BitwiseAndOrU32, - BitwiseOr3U32, - BitwiseXorU32, - BitwiseXorU64, - BitwiseXor3U32, - BitwiseNandU32, - BitwiseNandU64, - BitwiseNorU32, - BitwiseNorU64, - BitwiseXnorU32, - BitwiseXnorU64, - BitwiseNotU32, - BitwiseNotU64, - BitClearU32, - BitSetU32, - BitReverseU32, - BitCountU32, - BitCountU64, - BitReplicateB64B32, - BitCountAddU32, - MaskedBitCountLowU32, - MaskedBitCountHighU32, - FindLsbU32, - FindMsbFromHighU32, - FindMsbFromHighU64, - BitFieldMaskU32, - BitFieldMaskU64, - BitFieldExtractU32, - BitFieldExtractU64, - BitFieldExtract3U32, - BitFieldExtract3I32, - BitFieldInsertSelectU32, - BitCompare0B32, - BitCompare1B32, - AlignBitU32, - ShiftLeftAddU32, - AddShiftLeftU32, - XorAddU32, - ShiftLeftOrU32, - ShiftLeftLogicalU32, - ShiftLeftLogicalU64, - ShiftLeftLogicalU16, - ShiftRightLogicalU32, - ShiftRightLogicalU64, - ShiftRightLogicalU16, - ShiftRightArithmeticI32, - ShiftRightArithmeticI16, - SelectU32, - SelectMaskU32, - SelectF32Bits, - SelectMaskF32Bits, - SelectU64, - PackLowLowU16, - PackLowHighU16, - PackHighHighU16, - CompareFalse, - CompareTrue, - CompareEqU32, - CompareNeU32, - CompareGtU32, - CompareGeU32, - CompareLtU32, - CompareLeU32, - CompareEqU64, - CompareNeU64, - CompareMaskEqU32, - CompareMaskNeU32, - CompareMaskGtU32, - CompareMaskGeU32, - CompareMaskLtU32, - CompareMaskLeU32, - CompareEqI32, - CompareNeI32, - CompareGtI32, - CompareGeI32, - CompareLtI32, - CompareLeI32, - CompareEqI16, - CompareNeI16, - CompareGtI16, - CompareGeI16, - CompareLtI16, - CompareLeI16, - CompareMaskEqI32, - CompareMaskNeI32, - CompareMaskGtI32, - CompareMaskGeI32, - CompareMaskLtI32, - CompareMaskLeI32, - CompareEqU16, - CompareNeU16, - CompareGtU16, - CompareGeU16, - CompareLtU16, - CompareLeU16, - CompareEqF32, - CompareNeF32, - CompareGtF32, - CompareGeF32, - CompareLtF32, - CompareLeF32, - CompareOrderedF32, - CompareUnorderedF32, - CompareUnordEqF32, - CompareUnordNeF32, - CompareUnordGtF32, - CompareUnordGeF32, - CompareUnordLtF32, - CompareUnordLeF32, - CompareClassF32, - CompareEqF16, - CompareNeF16, - CompareGtF16, - CompareGeF16, - CompareLtF16, - CompareLeF16, - CompareUnordNeF16, - CompareMaskEqF16, - CompareMaskNeF16, - CompareMaskGtF16, - CompareMaskGeF16, - CompareMaskLtF16, - CompareMaskLeF16, - CompareMaskUnordNeF16, - CompareMaskUnordGeF16, - CompareMaskEqF32, - CompareMaskNeF32, - CompareMaskGtF32, - CompareMaskGeF32, - CompareMaskLtF32, - CompareMaskLeF32, - CompareMaskUnordEqF32, - CompareMaskUnordNeF32, - CompareMaskUnordGtF32, - CompareMaskUnordGeF32, - CompareMaskUnordLtF32, - CompareMaskUnordLeF32, - ConvertByteU32ToF32, - ConvertU32ToF32, - ConvertI32ToF32, - ConvertF32ToU32, - ConvertF32ToI32, - ConvertF32ToF16, - ConvertF16ToF32, - ConvertU16ToF16, - ConvertF16ToU16, - ConvertI16ToF16, - ConvertF16ToI16, - ConvertRoundPlusInfF32ToI32, - ConvertFloorF32ToI32, - ConvertI4ToOffsetF32, - LdexpF32, - PackF32ToF16Rtz, - PackSnorm2x16F32, - PackUnorm2x16F32, - PackU16U32, - PackU8F32, - PackB32F16, - PackedMadI16, - PackedMulLoU16, - PackedAddI16, - PackedSubI16, - PackedLshlrevB16, - PackedLshrrevB16, - PackedAshrrevI16, - PackedMaxI16, - PackedMinI16, - PackedMadU16, - PackedAddU16, - PackedSubU16, - PackedMaxU16, - PackedMinU16, - PackedAddF16, - PackedMulF16, - PackedMinF16, - PackedMaxF16, - PackedFmaF16, - AddF16, - SubF16, - MulF16, - MinF16, - MaxF16, - FmaF16, - MadMixF16, - IAddU16, - ISubI16, - IMinI16, - IMaxI16, - UMinU16, - UMaxU16, - RcpF32, - FractF32, - TruncF32, - CeilF32, - RoundEvenF32, - FloorF32, - Exp2F32, - Log2F32, - InverseSqrtF32, - SqrtF32, - RcpF16, - SqrtF16, - InverseSqrtF16, - Log2F16, - Exp2F16, - FloorF16, - CeilF16, - TruncF16, - RoundEvenF16, - SinF32, - CosF32, - CubeIdF32, - CubeScF32, - CubeTcF32, - CubeMaF32, - FAddF32, - FSubF32, - FMulF32, - FMinF32, - FMaxF32, - FMadF32, - Dot2AccF32F16, - FMin3F32, - FMax3F32, - FMed3F32, - Min3F16, - Max3F16, - Med3F16, - LoadSrtDword, - SLoadDword, - SBufferLoadDword, - BufferLoadUbyte, - BufferLoadSbyte, - BufferLoadUshort, - BufferLoadSshort, - BufferLoadDword, - BufferStoreByte, - BufferStoreShort, - BufferStoreDword, - AtomicSwapU32, - AtomicAddU32, - AtomicSubU32, - AtomicSMinI32, - AtomicUMinU32, - AtomicSMaxI32, - AtomicUMaxU32, - AtomicAndU32, - AtomicOrU32, - AtomicXorU32, - FlatLoadUbyte, - FlatLoadSbyte, - FlatLoadUshort, - FlatLoadSshort, - FlatLoadDword, - FlatStoreByte, - FlatStoreShort, - FlatStoreDword, - DsReadUbyte, - DsReadSbyte, - DsReadUshort, - DsReadSshort, - DsReadB32, - DsWriteByte, - DsWriteShort, - DsWriteB32, - DsMinF32, - DsMaxF32, - DsSwizzleB32, - DsConsume, - DsAppend, - DsWriteAddtidB32, - DsReadAddtidB32, - ImageGetResinfo, - ImageGetLod, - ImageLoad, - ImageStore, - ImageSample, - ImageGather4, - LoadInputF32, - Export, +#define IR_OPCODE(name, category) name, +#include "graphics/shader/recompiler/ir/ShaderIROpcodes.inc" +#undef IR_OPCODE + Count, }; +enum class OpcodeClass { General, Compare, Compare64 }; + +struct OpcodeInfo { + std::string_view name; + OpcodeClass opcode_class = OpcodeClass::General; +}; + +inline constexpr OpcodeInfo OPCODE_INFO[] = { +#define IR_OPCODE(name, category) {#name, OpcodeClass::category}, +#include "graphics/shader/recompiler/ir/ShaderIROpcodes.inc" +#undef IR_OPCODE +}; +static_assert(sizeof(OPCODE_INFO) / sizeof(OPCODE_INFO[0]) == static_cast(Opcode::Count)); + +constexpr const OpcodeInfo& GetOpcodeInfo(Opcode opcode) { + return OPCODE_INFO[static_cast(opcode)]; +} + +constexpr std::string_view OpcodeName(Opcode opcode) { + return GetOpcodeInfo(opcode).name; +} + +constexpr bool IsCompareOpcode(Opcode opcode) { + return GetOpcodeInfo(opcode).opcode_class != OpcodeClass::General; +} + +constexpr bool IsCompare64Opcode(Opcode opcode) { + return GetOpcodeInfo(opcode).opcode_class == OpcodeClass::Compare64; +} + enum class RegisterFile { Scalar, Vector, Vcc, Exec, Scc, M0 }; struct Register { diff --git a/src/graphics/shader/recompiler/ir/ShaderIRInternal.h b/src/graphics/shader/recompiler/ir/ShaderIRInternal.h index 8095a10..f94b58e 100644 --- a/src/graphics/shader/recompiler/ir/ShaderIRInternal.h +++ b/src/graphics/shader/recompiler/ir/ShaderIRInternal.h @@ -3,16 +3,17 @@ #include "graphics/shader/recompiler/ir/ShaderIR.h" +#include + namespace Libs::Graphics::ShaderRecompiler::IR { void SetError(std::string* error, const char* message); -Opcode LookupIrOpcode(Decoder::Opcode opcode); -bool IsImplemented(Decoder::Opcode opcode); -bool IsReversedBinary(Decoder::Opcode opcode); -bool IsVectorCarryOutOpcode(Decoder::Opcode opcode); -bool ScalarResultWritesSccNonZero(Decoder::Opcode opcode); -bool ScalarResultIs64Bit(Decoder::Opcode opcode); +std::optional LookupIrOpcode(Decoder::Opcode opcode); +bool IsReversedBinary(Decoder::Opcode opcode); +bool IsVectorCarryOutOpcode(Decoder::Opcode opcode); +bool ScalarResultWritesSccNonZero(Decoder::Opcode opcode); +bool ScalarResultIs64Bit(Decoder::Opcode opcode); Operand MakeSccOperand(); Operand MakeImmediateU32(uint32_t value); diff --git a/src/graphics/shader/recompiler/ir/ShaderIRLog.cpp b/src/graphics/shader/recompiler/ir/ShaderIRLog.cpp index 303e7f9..cda8993 100644 --- a/src/graphics/shader/recompiler/ir/ShaderIRLog.cpp +++ b/src/graphics/shader/recompiler/ir/ShaderIRLog.cpp @@ -157,346 +157,7 @@ std::string InstructionToString(const Instruction& inst) { text += ExportInfoToString(inst.export_info); return text; } - switch (inst.op) { - case Opcode::ControlNop: text += "ControlNop"; break; - case Opcode::Waitcnt: text += "Waitcnt"; break; - case Opcode::Barrier: text += "Barrier"; break; - case Opcode::Sendmsg: text += "Sendmsg"; break; - case Opcode::TtraceData: text += "TtraceData"; break; - case Opcode::InstPrefetch: text += "InstPrefetch"; break; - case Opcode::MoveU32: text += "MoveU32"; break; - case Opcode::MoveF32Bits: text += "MoveF32Bits"; break; - case Opcode::MoveRelDestU32: text += "MoveRelDestU32"; break; - case Opcode::MoveRelSourceU32: text += "MoveRelSourceU32"; break; - case Opcode::MoveU64: text += "MoveU64"; break; - case Opcode::WqmB64: text += "WqmB64"; break; - case Opcode::SaveexecB32: text += "SaveexecB32"; break; - case Opcode::SaveexecB64: text += "SaveexecB64"; break; - case Opcode::ReadFirstLaneU32: text += "ReadFirstLaneU32"; break; - case Opcode::ReadLaneU32: text += "ReadLaneU32"; break; - case Opcode::WriteLaneU32: text += "WriteLaneU32"; break; - case Opcode::Permlane16B32: text += "Permlane16B32"; break; - case Opcode::Permlanex16B32: text += "Permlanex16B32"; break; - case Opcode::AbsI32: text += "AbsI32"; break; - case Opcode::IAddU32: text += "IAddU32"; break; - case Opcode::IAddCarryU32: text += "IAddCarryU32"; break; - case Opcode::ISubBorrowU32: text += "ISubBorrowU32"; break; - case Opcode::ScalarAddCarryU32: text += "ScalarAddCarryU32"; break; - case Opcode::ScalarSubBorrowU32: text += "ScalarSubBorrowU32"; break; - case Opcode::ScalarSubBorrowCarryU32: text += "ScalarSubBorrowCarryU32"; break; - case Opcode::ScalarSignedAddOverflowI32: text += "ScalarSignedAddOverflowI32"; break; - case Opcode::ScalarSignedSubOverflowI32: text += "ScalarSignedSubOverflowI32"; break; - case Opcode::ScalarShiftLeftAddCarryU32: text += "ScalarShiftLeftAddCarryU32"; break; - case Opcode::ISubU32: text += "ISubU32"; break; - case Opcode::IMulU32: text += "IMulU32"; break; - case Opcode::UMulHighU32: text += "UMulHighU32"; break; - case Opcode::SMulHighI32: text += "SMulHighI32"; break; - case Opcode::IMadI24U32: text += "IMadI24U32"; break; - case Opcode::UMadU24U32: text += "UMadU24U32"; break; - case Opcode::UMadU64U32: text += "UMadU64U32"; break; - case Opcode::SadU32: text += "SadU32"; break; - case Opcode::IAdd3U32: text += "IAdd3U32"; break; - case Opcode::IMulI24U32: text += "IMulI24U32"; break; - case Opcode::UMulU24U32: text += "UMulU24U32"; break; - case Opcode::IMinI32: text += "IMinI32"; break; - case Opcode::IMaxI32: text += "IMaxI32"; break; - case Opcode::IMin3I32: text += "IMin3I32"; break; - case Opcode::IMax3I32: text += "IMax3I32"; break; - case Opcode::IMed3I32: text += "IMed3I32"; break; - case Opcode::UMinU32: text += "UMinU32"; break; - case Opcode::UMaxU32: text += "UMaxU32"; break; - case Opcode::UMin3U32: text += "UMin3U32"; break; - case Opcode::UMax3U32: text += "UMax3U32"; break; - case Opcode::UMed3U32: text += "UMed3U32"; break; - case Opcode::BitwiseAndU32: text += "BitwiseAndU32"; break; - case Opcode::BitwiseAndU64: text += "BitwiseAndU64"; break; - case Opcode::BitwiseAndNotU32: text += "BitwiseAndNotU32"; break; - case Opcode::BitwiseAndNotU64: text += "BitwiseAndNotU64"; break; - case Opcode::BitwiseOrU32: text += "BitwiseOrU32"; break; - case Opcode::BitwiseOrU64: text += "BitwiseOrU64"; break; - case Opcode::BitwiseOrNotU32: text += "BitwiseOrNotU32"; break; - case Opcode::BitwiseOrNotU64: text += "BitwiseOrNotU64"; break; - case Opcode::BitwiseAndOrU32: text += "BitwiseAndOrU32"; break; - case Opcode::BitwiseOr3U32: text += "BitwiseOr3U32"; break; - case Opcode::BitwiseXorU32: text += "BitwiseXorU32"; break; - case Opcode::BitwiseXorU64: text += "BitwiseXorU64"; break; - case Opcode::BitwiseXor3U32: text += "BitwiseXor3U32"; break; - case Opcode::BitwiseNandU32: text += "BitwiseNandU32"; break; - case Opcode::BitwiseNandU64: text += "BitwiseNandU64"; break; - case Opcode::BitwiseNorU32: text += "BitwiseNorU32"; break; - case Opcode::BitwiseNorU64: text += "BitwiseNorU64"; break; - case Opcode::BitwiseXnorU32: text += "BitwiseXnorU32"; break; - case Opcode::BitwiseXnorU64: text += "BitwiseXnorU64"; break; - case Opcode::BitwiseNotU32: text += "BitwiseNotU32"; break; - case Opcode::BitwiseNotU64: text += "BitwiseNotU64"; break; - case Opcode::BitClearU32: text += "BitClearU32"; break; - case Opcode::BitSetU32: text += "BitSetU32"; break; - case Opcode::BitReverseU32: text += "BitReverseU32"; break; - case Opcode::BitCountU32: text += "BitCountU32"; break; - case Opcode::BitCountU64: text += "BitCountU64"; break; - case Opcode::BitReplicateB64B32: text += "BitReplicateB64B32"; break; - case Opcode::BitCountAddU32: text += "BitCountAddU32"; break; - case Opcode::MaskedBitCountLowU32: text += "MaskedBitCountLowU32"; break; - case Opcode::MaskedBitCountHighU32: text += "MaskedBitCountHighU32"; break; - case Opcode::FindLsbU32: text += "FindLsbU32"; break; - case Opcode::FindMsbFromHighU32: text += "FindMsbFromHighU32"; break; - case Opcode::FindMsbFromHighU64: text += "FindMsbFromHighU64"; break; - case Opcode::BitFieldMaskU32: text += "BitFieldMaskU32"; break; - case Opcode::BitFieldMaskU64: text += "BitFieldMaskU64"; break; - case Opcode::BitFieldExtractU32: text += "BitFieldExtractU32"; break; - case Opcode::BitFieldExtractU64: text += "BitFieldExtractU64"; break; - case Opcode::BitFieldExtract3U32: text += "BitFieldExtract3U32"; break; - case Opcode::BitFieldExtract3I32: text += "BitFieldExtract3I32"; break; - case Opcode::BitFieldInsertSelectU32: text += "BitFieldInsertSelectU32"; break; - case Opcode::BitCompare0B32: text += "BitCompare0B32"; break; - case Opcode::BitCompare1B32: text += "BitCompare1B32"; break; - case Opcode::AlignBitU32: text += "AlignBitU32"; break; - case Opcode::ShiftLeftAddU32: text += "ShiftLeftAddU32"; break; - case Opcode::AddShiftLeftU32: text += "AddShiftLeftU32"; break; - case Opcode::XorAddU32: text += "XorAddU32"; break; - case Opcode::ShiftLeftOrU32: text += "ShiftLeftOrU32"; break; - case Opcode::ShiftLeftLogicalU32: text += "ShiftLeftLogicalU32"; break; - case Opcode::ShiftLeftLogicalU64: text += "ShiftLeftLogicalU64"; break; - case Opcode::ShiftLeftLogicalU16: text += "ShiftLeftLogicalU16"; break; - case Opcode::ShiftRightLogicalU32: text += "ShiftRightLogicalU32"; break; - case Opcode::ShiftRightLogicalU64: text += "ShiftRightLogicalU64"; break; - case Opcode::ShiftRightLogicalU16: text += "ShiftRightLogicalU16"; break; - case Opcode::ShiftRightArithmeticI32: text += "ShiftRightArithmeticI32"; break; - case Opcode::ShiftRightArithmeticI16: text += "ShiftRightArithmeticI16"; break; - case Opcode::SelectU32: text += "SelectU32"; break; - case Opcode::SelectMaskU32: text += "SelectMaskU32"; break; - case Opcode::SelectF32Bits: text += "SelectF32Bits"; break; - case Opcode::SelectMaskF32Bits: text += "SelectMaskF32Bits"; break; - case Opcode::SelectU64: text += "SelectU64"; break; - case Opcode::PackLowLowU16: text += "PackLowLowU16"; break; - case Opcode::PackLowHighU16: text += "PackLowHighU16"; break; - case Opcode::PackHighHighU16: text += "PackHighHighU16"; break; - case Opcode::CompareFalse: text += "CompareFalse"; break; - case Opcode::CompareTrue: text += "CompareTrue"; break; - case Opcode::CompareEqU32: text += "CompareEqU32"; break; - case Opcode::CompareNeU32: text += "CompareNeU32"; break; - case Opcode::CompareGtU32: text += "CompareGtU32"; break; - case Opcode::CompareGeU32: text += "CompareGeU32"; break; - case Opcode::CompareLtU32: text += "CompareLtU32"; break; - case Opcode::CompareLeU32: text += "CompareLeU32"; break; - case Opcode::CompareEqU64: text += "CompareEqU64"; break; - case Opcode::CompareNeU64: text += "CompareNeU64"; break; - case Opcode::CompareMaskEqU32: text += "CompareMaskEqU32"; break; - case Opcode::CompareMaskNeU32: text += "CompareMaskNeU32"; break; - case Opcode::CompareMaskGtU32: text += "CompareMaskGtU32"; break; - case Opcode::CompareMaskGeU32: text += "CompareMaskGeU32"; break; - case Opcode::CompareMaskLtU32: text += "CompareMaskLtU32"; break; - case Opcode::CompareMaskLeU32: text += "CompareMaskLeU32"; break; - case Opcode::CompareEqI32: text += "CompareEqI32"; break; - case Opcode::CompareNeI32: text += "CompareNeI32"; break; - case Opcode::CompareGtI32: text += "CompareGtI32"; break; - case Opcode::CompareGeI32: text += "CompareGeI32"; break; - case Opcode::CompareLtI32: text += "CompareLtI32"; break; - case Opcode::CompareLeI32: text += "CompareLeI32"; break; - case Opcode::CompareEqI16: text += "CompareEqI16"; break; - case Opcode::CompareNeI16: text += "CompareNeI16"; break; - case Opcode::CompareGtI16: text += "CompareGtI16"; break; - case Opcode::CompareGeI16: text += "CompareGeI16"; break; - case Opcode::CompareLtI16: text += "CompareLtI16"; break; - case Opcode::CompareLeI16: text += "CompareLeI16"; break; - case Opcode::CompareMaskEqI32: text += "CompareMaskEqI32"; break; - case Opcode::CompareMaskNeI32: text += "CompareMaskNeI32"; break; - case Opcode::CompareMaskGtI32: text += "CompareMaskGtI32"; break; - case Opcode::CompareMaskGeI32: text += "CompareMaskGeI32"; break; - case Opcode::CompareMaskLtI32: text += "CompareMaskLtI32"; break; - case Opcode::CompareMaskLeI32: text += "CompareMaskLeI32"; break; - case Opcode::CompareEqU16: text += "CompareEqU16"; break; - case Opcode::CompareNeU16: text += "CompareNeU16"; break; - case Opcode::CompareGtU16: text += "CompareGtU16"; break; - case Opcode::CompareGeU16: text += "CompareGeU16"; break; - case Opcode::CompareLtU16: text += "CompareLtU16"; break; - case Opcode::CompareLeU16: text += "CompareLeU16"; break; - case Opcode::CompareEqF32: text += "CompareEqF32"; break; - case Opcode::CompareNeF32: text += "CompareNeF32"; break; - case Opcode::CompareGtF32: text += "CompareGtF32"; break; - case Opcode::CompareGeF32: text += "CompareGeF32"; break; - case Opcode::CompareLtF32: text += "CompareLtF32"; break; - case Opcode::CompareLeF32: text += "CompareLeF32"; break; - case Opcode::CompareOrderedF32: text += "CompareOrderedF32"; break; - case Opcode::CompareUnorderedF32: text += "CompareUnorderedF32"; break; - case Opcode::CompareUnordEqF32: text += "CompareUnordEqF32"; break; - case Opcode::CompareUnordNeF32: text += "CompareUnordNeF32"; break; - case Opcode::CompareUnordGtF32: text += "CompareUnordGtF32"; break; - case Opcode::CompareUnordGeF32: text += "CompareUnordGeF32"; break; - case Opcode::CompareUnordLtF32: text += "CompareUnordLtF32"; break; - case Opcode::CompareUnordLeF32: text += "CompareUnordLeF32"; break; - case Opcode::CompareClassF32: text += "CompareClassF32"; break; - case Opcode::CompareEqF16: text += "CompareEqF16"; break; - case Opcode::CompareNeF16: text += "CompareNeF16"; break; - case Opcode::CompareGtF16: text += "CompareGtF16"; break; - case Opcode::CompareGeF16: text += "CompareGeF16"; break; - case Opcode::CompareLtF16: text += "CompareLtF16"; break; - case Opcode::CompareLeF16: text += "CompareLeF16"; break; - case Opcode::CompareUnordNeF16: text += "CompareUnordNeF16"; break; - case Opcode::CompareMaskEqF16: text += "CompareMaskEqF16"; break; - case Opcode::CompareMaskNeF16: text += "CompareMaskNeF16"; break; - case Opcode::CompareMaskGtF16: text += "CompareMaskGtF16"; break; - case Opcode::CompareMaskGeF16: text += "CompareMaskGeF16"; break; - case Opcode::CompareMaskLtF16: text += "CompareMaskLtF16"; break; - case Opcode::CompareMaskLeF16: text += "CompareMaskLeF16"; break; - case Opcode::CompareMaskUnordNeF16: text += "CompareMaskUnordNeF16"; break; - case Opcode::CompareMaskUnordGeF16: text += "CompareMaskUnordGeF16"; break; - case Opcode::CompareMaskEqF32: text += "CompareMaskEqF32"; break; - case Opcode::CompareMaskNeF32: text += "CompareMaskNeF32"; break; - case Opcode::CompareMaskGtF32: text += "CompareMaskGtF32"; break; - case Opcode::CompareMaskGeF32: text += "CompareMaskGeF32"; break; - case Opcode::CompareMaskLtF32: text += "CompareMaskLtF32"; break; - case Opcode::CompareMaskLeF32: text += "CompareMaskLeF32"; break; - case Opcode::CompareMaskUnordEqF32: text += "CompareMaskUnordEqF32"; break; - case Opcode::CompareMaskUnordNeF32: text += "CompareMaskUnordNeF32"; break; - case Opcode::CompareMaskUnordGtF32: text += "CompareMaskUnordGtF32"; break; - case Opcode::CompareMaskUnordGeF32: text += "CompareMaskUnordGeF32"; break; - case Opcode::CompareMaskUnordLtF32: text += "CompareMaskUnordLtF32"; break; - case Opcode::CompareMaskUnordLeF32: text += "CompareMaskUnordLeF32"; break; - case Opcode::ConvertByteU32ToF32: text += "ConvertByteU32ToF32"; break; - case Opcode::ConvertU32ToF32: text += "ConvertU32ToF32"; break; - case Opcode::ConvertI32ToF32: text += "ConvertI32ToF32"; break; - case Opcode::ConvertF32ToU32: text += "ConvertF32ToU32"; break; - case Opcode::ConvertF32ToI32: text += "ConvertF32ToI32"; break; - case Opcode::ConvertF32ToF16: text += "ConvertF32ToF16"; break; - case Opcode::ConvertF16ToF32: text += "ConvertF16ToF32"; break; - case Opcode::ConvertU16ToF16: text += "ConvertU16ToF16"; break; - case Opcode::ConvertF16ToU16: text += "ConvertF16ToU16"; break; - case Opcode::ConvertI16ToF16: text += "ConvertI16ToF16"; break; - case Opcode::ConvertF16ToI16: text += "ConvertF16ToI16"; break; - case Opcode::ConvertRoundPlusInfF32ToI32: text += "ConvertRoundPlusInfF32ToI32"; break; - case Opcode::ConvertFloorF32ToI32: text += "ConvertFloorF32ToI32"; break; - case Opcode::ConvertI4ToOffsetF32: text += "ConvertI4ToOffsetF32"; break; - case Opcode::LdexpF32: text += "LdexpF32"; break; - case Opcode::PackF32ToF16Rtz: text += "PackF32ToF16Rtz"; break; - case Opcode::PackSnorm2x16F32: text += "PackSnorm2x16F32"; break; - case Opcode::PackUnorm2x16F32: text += "PackUnorm2x16F32"; break; - case Opcode::PackU16U32: text += "PackU16U32"; break; - case Opcode::PackU8F32: text += "PackU8F32"; break; - case Opcode::PackB32F16: text += "PackB32F16"; break; - case Opcode::PackedMadI16: text += "PackedMadI16"; break; - case Opcode::PackedMulLoU16: text += "PackedMulLoU16"; break; - case Opcode::PackedAddI16: text += "PackedAddI16"; break; - case Opcode::PackedSubI16: text += "PackedSubI16"; break; - case Opcode::PackedLshlrevB16: text += "PackedLshlrevB16"; break; - case Opcode::PackedLshrrevB16: text += "PackedLshrrevB16"; break; - case Opcode::PackedAshrrevI16: text += "PackedAshrrevI16"; break; - case Opcode::PackedMaxI16: text += "PackedMaxI16"; break; - case Opcode::PackedMinI16: text += "PackedMinI16"; break; - case Opcode::PackedMadU16: text += "PackedMadU16"; break; - case Opcode::PackedAddU16: text += "PackedAddU16"; break; - case Opcode::PackedSubU16: text += "PackedSubU16"; break; - case Opcode::PackedMaxU16: text += "PackedMaxU16"; break; - case Opcode::PackedMinU16: text += "PackedMinU16"; break; - case Opcode::PackedAddF16: text += "PackedAddF16"; break; - case Opcode::PackedMulF16: text += "PackedMulF16"; break; - case Opcode::PackedMinF16: text += "PackedMinF16"; break; - case Opcode::PackedMaxF16: text += "PackedMaxF16"; break; - case Opcode::PackedFmaF16: text += "PackedFmaF16"; break; - case Opcode::AddF16: text += "AddF16"; break; - case Opcode::SubF16: text += "SubF16"; break; - case Opcode::MulF16: text += "MulF16"; break; - case Opcode::MinF16: text += "MinF16"; break; - case Opcode::MaxF16: text += "MaxF16"; break; - case Opcode::FmaF16: text += "FmaF16"; break; - case Opcode::MadMixF16: text += "MadMixF16"; break; - case Opcode::IAddU16: text += "IAddU16"; break; - case Opcode::ISubI16: text += "ISubI16"; break; - case Opcode::IMinI16: text += "IMinI16"; break; - case Opcode::IMaxI16: text += "IMaxI16"; break; - case Opcode::UMinU16: text += "UMinU16"; break; - case Opcode::UMaxU16: text += "UMaxU16"; break; - case Opcode::RcpF32: text += "RcpF32"; break; - case Opcode::FractF32: text += "FractF32"; break; - case Opcode::TruncF32: text += "TruncF32"; break; - case Opcode::CeilF32: text += "CeilF32"; break; - case Opcode::RoundEvenF32: text += "RoundEvenF32"; break; - case Opcode::FloorF32: text += "FloorF32"; break; - case Opcode::Exp2F32: text += "Exp2F32"; break; - case Opcode::Log2F32: text += "Log2F32"; break; - case Opcode::InverseSqrtF32: text += "InverseSqrtF32"; break; - case Opcode::SqrtF32: text += "SqrtF32"; break; - case Opcode::RcpF16: text += "RcpF16"; break; - case Opcode::SqrtF16: text += "SqrtF16"; break; - case Opcode::InverseSqrtF16: text += "InverseSqrtF16"; break; - case Opcode::Log2F16: text += "Log2F16"; break; - case Opcode::Exp2F16: text += "Exp2F16"; break; - case Opcode::FloorF16: text += "FloorF16"; break; - case Opcode::CeilF16: text += "CeilF16"; break; - case Opcode::TruncF16: text += "TruncF16"; break; - case Opcode::RoundEvenF16: text += "RoundEvenF16"; break; - case Opcode::SinF32: text += "SinF32"; break; - case Opcode::CosF32: text += "CosF32"; break; - case Opcode::CubeIdF32: text += "CubeIdF32"; break; - case Opcode::CubeScF32: text += "CubeScF32"; break; - case Opcode::CubeTcF32: text += "CubeTcF32"; break; - case Opcode::CubeMaF32: text += "CubeMaF32"; break; - case Opcode::FAddF32: text += "FAddF32"; break; - case Opcode::FSubF32: text += "FSubF32"; break; - case Opcode::FMulF32: text += "FMulF32"; break; - case Opcode::FMinF32: text += "FMinF32"; break; - case Opcode::FMaxF32: text += "FMaxF32"; break; - case Opcode::FMadF32: text += "FMadF32"; break; - case Opcode::Dot2AccF32F16: text += "Dot2AccF32F16"; break; - case Opcode::FMin3F32: text += "FMin3F32"; break; - case Opcode::FMax3F32: text += "FMax3F32"; break; - case Opcode::FMed3F32: text += "FMed3F32"; break; - case Opcode::Min3F16: text += "Min3F16"; break; - case Opcode::Max3F16: text += "Max3F16"; break; - case Opcode::Med3F16: text += "Med3F16"; break; - case Opcode::LoadSrtDword: text += "LoadSrtDword"; break; - case Opcode::SLoadDword: text += "SLoadDword"; break; - case Opcode::SBufferLoadDword: text += "SBufferLoadDword"; break; - case Opcode::BufferLoadUbyte: text += "BufferLoadUbyte"; break; - case Opcode::BufferLoadSbyte: text += "BufferLoadSbyte"; break; - case Opcode::BufferLoadUshort: text += "BufferLoadUshort"; break; - case Opcode::BufferLoadSshort: text += "BufferLoadSshort"; break; - case Opcode::BufferLoadDword: text += "BufferLoadDword"; break; - case Opcode::BufferStoreByte: text += "BufferStoreByte"; break; - case Opcode::BufferStoreShort: text += "BufferStoreShort"; break; - case Opcode::BufferStoreDword: text += "BufferStoreDword"; break; - case Opcode::AtomicSwapU32: text += "AtomicSwapU32"; break; - case Opcode::AtomicAddU32: text += "AtomicAddU32"; break; - case Opcode::AtomicSubU32: text += "AtomicSubU32"; break; - case Opcode::AtomicSMinI32: text += "AtomicSMinI32"; break; - case Opcode::AtomicUMinU32: text += "AtomicUMinU32"; break; - case Opcode::AtomicSMaxI32: text += "AtomicSMaxI32"; break; - case Opcode::AtomicUMaxU32: text += "AtomicUMaxU32"; break; - case Opcode::AtomicAndU32: text += "AtomicAndU32"; break; - case Opcode::AtomicOrU32: text += "AtomicOrU32"; break; - case Opcode::AtomicXorU32: text += "AtomicXorU32"; break; - case Opcode::FlatLoadUbyte: text += "FlatLoadUbyte"; break; - case Opcode::FlatLoadSbyte: text += "FlatLoadSbyte"; break; - case Opcode::FlatLoadUshort: text += "FlatLoadUshort"; break; - case Opcode::FlatLoadSshort: text += "FlatLoadSshort"; break; - case Opcode::FlatLoadDword: text += "FlatLoadDword"; break; - case Opcode::FlatStoreByte: text += "FlatStoreByte"; break; - case Opcode::FlatStoreShort: text += "FlatStoreShort"; break; - case Opcode::FlatStoreDword: text += "FlatStoreDword"; break; - case Opcode::DsReadUbyte: text += "DsReadUbyte"; break; - case Opcode::DsReadSbyte: text += "DsReadSbyte"; break; - case Opcode::DsReadUshort: text += "DsReadUshort"; break; - case Opcode::DsReadSshort: text += "DsReadSshort"; break; - case Opcode::DsReadB32: text += "DsReadB32"; break; - case Opcode::DsWriteByte: text += "DsWriteByte"; break; - case Opcode::DsWriteShort: text += "DsWriteShort"; break; - case Opcode::DsWriteB32: text += "DsWriteB32"; break; - case Opcode::DsMinF32: text += "DsMinF32"; break; - case Opcode::DsMaxF32: text += "DsMaxF32"; break; - case Opcode::DsSwizzleB32: text += "DsSwizzleB32"; break; - case Opcode::DsConsume: text += "DsConsume"; break; - case Opcode::DsAppend: text += "DsAppend"; break; - case Opcode::DsWriteAddtidB32: text += "DsWriteAddtidB32"; break; - case Opcode::DsReadAddtidB32: text += "DsReadAddtidB32"; break; - case Opcode::ImageGetResinfo: text += "ImageGetResinfo"; break; - case Opcode::ImageGetLod: text += "ImageGetLod"; break; - case Opcode::ImageLoad: text += "ImageLoad"; break; - case Opcode::ImageStore: text += "ImageStore"; break; - case Opcode::ImageSample: text += "ImageSample"; break; - case Opcode::ImageGather4: text += "ImageGather4"; break; - case Opcode::LoadInputF32: text += "LoadInputF32"; break; - case Opcode::Export: text += "Export"; break; - } + text += OpcodeName(inst.op); text += " "; text += OperandToString(inst.dst); if (inst.dst2.kind != OperandKind::Null) { diff --git a/src/graphics/shader/recompiler/ir/ShaderIROpcodes.cpp b/src/graphics/shader/recompiler/ir/ShaderIROpcodes.cpp index 61190c5..192a455 100644 --- a/src/graphics/shader/recompiler/ir/ShaderIROpcodes.cpp +++ b/src/graphics/shader/recompiler/ir/ShaderIROpcodes.cpp @@ -434,22 +434,13 @@ void SetError(std::string* error, const char* message) { } } -Opcode LookupIrOpcode(Decoder::Opcode opcode) { +std::optional LookupIrOpcode(Decoder::Opcode opcode) { for (const auto& op: LOWER_OPS) { if (op.decoded == opcode) { return op.ir; } } - return Opcode::MoveU32; -} - -bool IsImplemented(Decoder::Opcode opcode) { - for (const auto& op: LOWER_OPS) { - if (op.decoded == opcode) { - return true; - } - } - return false; + return std::nullopt; } bool IsReversedBinary(Decoder::Opcode opcode) { diff --git a/src/graphics/shader/recompiler/ir/ShaderIROpcodes.inc b/src/graphics/shader/recompiler/ir/ShaderIROpcodes.inc new file mode 100644 index 0000000..0b5b0eb --- /dev/null +++ b/src/graphics/shader/recompiler/ir/ShaderIROpcodes.inc @@ -0,0 +1,340 @@ +// Central IR opcode catalog. Keep semantic categories here so enum identity, logging, +// and generic analysis cannot drift apart. +IR_OPCODE(ControlNop, General) +IR_OPCODE(Waitcnt, General) +IR_OPCODE(Barrier, General) +IR_OPCODE(Sendmsg, General) +IR_OPCODE(TtraceData, General) +IR_OPCODE(InstPrefetch, General) +IR_OPCODE(MoveU32, General) +IR_OPCODE(MoveF32Bits, General) +IR_OPCODE(MoveRelDestU32, General) +IR_OPCODE(MoveRelSourceU32, General) +IR_OPCODE(MoveU64, General) +IR_OPCODE(WqmB64, General) +IR_OPCODE(SaveexecB32, General) +IR_OPCODE(SaveexecB64, General) +IR_OPCODE(ReadFirstLaneU32, General) +IR_OPCODE(ReadLaneU32, General) +IR_OPCODE(WriteLaneU32, General) +IR_OPCODE(Permlane16B32, General) +IR_OPCODE(Permlanex16B32, General) +IR_OPCODE(AbsI32, General) +IR_OPCODE(IAddU32, General) +IR_OPCODE(IAddCarryU32, General) +IR_OPCODE(ISubBorrowU32, General) +IR_OPCODE(ScalarAddCarryU32, General) +IR_OPCODE(ScalarSubBorrowU32, General) +IR_OPCODE(ScalarSubBorrowCarryU32, General) +IR_OPCODE(ScalarSignedAddOverflowI32, General) +IR_OPCODE(ScalarSignedSubOverflowI32, General) +IR_OPCODE(ScalarShiftLeftAddCarryU32, General) +IR_OPCODE(ISubU32, General) +IR_OPCODE(IMulU32, General) +IR_OPCODE(UMulHighU32, General) +IR_OPCODE(SMulHighI32, General) +IR_OPCODE(IMadI24U32, General) +IR_OPCODE(UMadU24U32, General) +IR_OPCODE(UMadU64U32, General) +IR_OPCODE(SadU32, General) +IR_OPCODE(IAdd3U32, General) +IR_OPCODE(IMulI24U32, General) +IR_OPCODE(UMulU24U32, General) +IR_OPCODE(IMinI32, General) +IR_OPCODE(IMaxI32, General) +IR_OPCODE(IMin3I32, General) +IR_OPCODE(IMax3I32, General) +IR_OPCODE(IMed3I32, General) +IR_OPCODE(UMinU32, General) +IR_OPCODE(UMaxU32, General) +IR_OPCODE(UMin3U32, General) +IR_OPCODE(UMax3U32, General) +IR_OPCODE(UMed3U32, General) +IR_OPCODE(BitwiseAndU32, General) +IR_OPCODE(BitwiseAndU64, General) +IR_OPCODE(BitwiseAndNotU32, General) +IR_OPCODE(BitwiseAndNotU64, General) +IR_OPCODE(BitwiseOrU32, General) +IR_OPCODE(BitwiseOrU64, General) +IR_OPCODE(BitwiseOrNotU32, General) +IR_OPCODE(BitwiseOrNotU64, General) +IR_OPCODE(BitwiseAndOrU32, General) +IR_OPCODE(BitwiseOr3U32, General) +IR_OPCODE(BitwiseXorU32, General) +IR_OPCODE(BitwiseXorU64, General) +IR_OPCODE(BitwiseXor3U32, General) +IR_OPCODE(BitwiseNandU32, General) +IR_OPCODE(BitwiseNandU64, General) +IR_OPCODE(BitwiseNorU32, General) +IR_OPCODE(BitwiseNorU64, General) +IR_OPCODE(BitwiseXnorU32, General) +IR_OPCODE(BitwiseXnorU64, General) +IR_OPCODE(BitwiseNotU32, General) +IR_OPCODE(BitwiseNotU64, General) +IR_OPCODE(BitClearU32, General) +IR_OPCODE(BitSetU32, General) +IR_OPCODE(BitReverseU32, General) +IR_OPCODE(BitCountU32, General) +IR_OPCODE(BitCountU64, General) +IR_OPCODE(BitReplicateB64B32, General) +IR_OPCODE(BitCountAddU32, General) +IR_OPCODE(MaskedBitCountLowU32, General) +IR_OPCODE(MaskedBitCountHighU32, General) +IR_OPCODE(FindLsbU32, General) +IR_OPCODE(FindMsbFromHighU32, General) +IR_OPCODE(FindMsbFromHighU64, General) +IR_OPCODE(BitFieldMaskU32, General) +IR_OPCODE(BitFieldMaskU64, General) +IR_OPCODE(BitFieldExtractU32, General) +IR_OPCODE(BitFieldExtractU64, General) +IR_OPCODE(BitFieldExtract3U32, General) +IR_OPCODE(BitFieldExtract3I32, General) +IR_OPCODE(BitFieldInsertSelectU32, General) +IR_OPCODE(BitCompare0B32, General) +IR_OPCODE(BitCompare1B32, General) +IR_OPCODE(AlignBitU32, General) +IR_OPCODE(ShiftLeftAddU32, General) +IR_OPCODE(AddShiftLeftU32, General) +IR_OPCODE(XorAddU32, General) +IR_OPCODE(ShiftLeftOrU32, General) +IR_OPCODE(ShiftLeftLogicalU32, General) +IR_OPCODE(ShiftLeftLogicalU64, General) +IR_OPCODE(ShiftLeftLogicalU16, General) +IR_OPCODE(ShiftRightLogicalU32, General) +IR_OPCODE(ShiftRightLogicalU64, General) +IR_OPCODE(ShiftRightLogicalU16, General) +IR_OPCODE(ShiftRightArithmeticI32, General) +IR_OPCODE(ShiftRightArithmeticI16, General) +IR_OPCODE(SelectU32, General) +IR_OPCODE(SelectMaskU32, General) +IR_OPCODE(SelectF32Bits, General) +IR_OPCODE(SelectMaskF32Bits, General) +IR_OPCODE(SelectU64, General) +IR_OPCODE(PackLowLowU16, General) +IR_OPCODE(PackLowHighU16, General) +IR_OPCODE(PackHighHighU16, General) +IR_OPCODE(CompareFalse, Compare) +IR_OPCODE(CompareTrue, Compare) +IR_OPCODE(CompareEqU32, Compare) +IR_OPCODE(CompareNeU32, Compare) +IR_OPCODE(CompareGtU32, Compare) +IR_OPCODE(CompareGeU32, Compare) +IR_OPCODE(CompareLtU32, Compare) +IR_OPCODE(CompareLeU32, Compare) +IR_OPCODE(CompareEqU64, Compare64) +IR_OPCODE(CompareNeU64, Compare64) +IR_OPCODE(CompareMaskEqU32, Compare) +IR_OPCODE(CompareMaskNeU32, Compare) +IR_OPCODE(CompareMaskGtU32, Compare) +IR_OPCODE(CompareMaskGeU32, Compare) +IR_OPCODE(CompareMaskLtU32, Compare) +IR_OPCODE(CompareMaskLeU32, Compare) +IR_OPCODE(CompareEqI32, Compare) +IR_OPCODE(CompareNeI32, Compare) +IR_OPCODE(CompareGtI32, Compare) +IR_OPCODE(CompareGeI32, Compare) +IR_OPCODE(CompareLtI32, Compare) +IR_OPCODE(CompareLeI32, Compare) +IR_OPCODE(CompareEqI16, Compare) +IR_OPCODE(CompareNeI16, Compare) +IR_OPCODE(CompareGtI16, Compare) +IR_OPCODE(CompareGeI16, Compare) +IR_OPCODE(CompareLtI16, Compare) +IR_OPCODE(CompareLeI16, Compare) +IR_OPCODE(CompareMaskEqI32, Compare) +IR_OPCODE(CompareMaskNeI32, Compare) +IR_OPCODE(CompareMaskGtI32, Compare) +IR_OPCODE(CompareMaskGeI32, Compare) +IR_OPCODE(CompareMaskLtI32, Compare) +IR_OPCODE(CompareMaskLeI32, Compare) +IR_OPCODE(CompareEqU16, Compare) +IR_OPCODE(CompareNeU16, Compare) +IR_OPCODE(CompareGtU16, Compare) +IR_OPCODE(CompareGeU16, Compare) +IR_OPCODE(CompareLtU16, Compare) +IR_OPCODE(CompareLeU16, Compare) +IR_OPCODE(CompareEqF32, Compare) +IR_OPCODE(CompareNeF32, Compare) +IR_OPCODE(CompareGtF32, Compare) +IR_OPCODE(CompareGeF32, Compare) +IR_OPCODE(CompareLtF32, Compare) +IR_OPCODE(CompareLeF32, Compare) +IR_OPCODE(CompareOrderedF32, Compare) +IR_OPCODE(CompareUnorderedF32, Compare) +IR_OPCODE(CompareUnordEqF32, Compare) +IR_OPCODE(CompareUnordNeF32, Compare) +IR_OPCODE(CompareUnordGtF32, Compare) +IR_OPCODE(CompareUnordGeF32, Compare) +IR_OPCODE(CompareUnordLtF32, Compare) +IR_OPCODE(CompareUnordLeF32, Compare) +IR_OPCODE(CompareClassF32, Compare) +IR_OPCODE(CompareEqF16, Compare) +IR_OPCODE(CompareNeF16, Compare) +IR_OPCODE(CompareGtF16, Compare) +IR_OPCODE(CompareGeF16, Compare) +IR_OPCODE(CompareLtF16, Compare) +IR_OPCODE(CompareLeF16, Compare) +IR_OPCODE(CompareUnordNeF16, Compare) +IR_OPCODE(CompareMaskEqF16, Compare) +IR_OPCODE(CompareMaskNeF16, Compare) +IR_OPCODE(CompareMaskGtF16, Compare) +IR_OPCODE(CompareMaskGeF16, Compare) +IR_OPCODE(CompareMaskLtF16, Compare) +IR_OPCODE(CompareMaskLeF16, Compare) +IR_OPCODE(CompareMaskUnordNeF16, Compare) +IR_OPCODE(CompareMaskUnordGeF16, Compare) +IR_OPCODE(CompareMaskEqF32, Compare) +IR_OPCODE(CompareMaskNeF32, Compare) +IR_OPCODE(CompareMaskGtF32, Compare) +IR_OPCODE(CompareMaskGeF32, Compare) +IR_OPCODE(CompareMaskLtF32, Compare) +IR_OPCODE(CompareMaskLeF32, Compare) +IR_OPCODE(CompareMaskUnordEqF32, Compare) +IR_OPCODE(CompareMaskUnordNeF32, Compare) +IR_OPCODE(CompareMaskUnordGtF32, Compare) +IR_OPCODE(CompareMaskUnordGeF32, Compare) +IR_OPCODE(CompareMaskUnordLtF32, Compare) +IR_OPCODE(CompareMaskUnordLeF32, Compare) +IR_OPCODE(ConvertByteU32ToF32, General) +IR_OPCODE(ConvertU32ToF32, General) +IR_OPCODE(ConvertI32ToF32, General) +IR_OPCODE(ConvertF32ToU32, General) +IR_OPCODE(ConvertF32ToI32, General) +IR_OPCODE(ConvertF32ToF16, General) +IR_OPCODE(ConvertF16ToF32, General) +IR_OPCODE(ConvertU16ToF16, General) +IR_OPCODE(ConvertF16ToU16, General) +IR_OPCODE(ConvertI16ToF16, General) +IR_OPCODE(ConvertF16ToI16, General) +IR_OPCODE(ConvertRoundPlusInfF32ToI32, General) +IR_OPCODE(ConvertFloorF32ToI32, General) +IR_OPCODE(ConvertI4ToOffsetF32, General) +IR_OPCODE(LdexpF32, General) +IR_OPCODE(PackF32ToF16Rtz, General) +IR_OPCODE(PackSnorm2x16F32, General) +IR_OPCODE(PackUnorm2x16F32, General) +IR_OPCODE(PackU16U32, General) +IR_OPCODE(PackU8F32, General) +IR_OPCODE(PackB32F16, General) +IR_OPCODE(PackedMadI16, General) +IR_OPCODE(PackedMulLoU16, General) +IR_OPCODE(PackedAddI16, General) +IR_OPCODE(PackedSubI16, General) +IR_OPCODE(PackedLshlrevB16, General) +IR_OPCODE(PackedLshrrevB16, General) +IR_OPCODE(PackedAshrrevI16, General) +IR_OPCODE(PackedMaxI16, General) +IR_OPCODE(PackedMinI16, General) +IR_OPCODE(PackedMadU16, General) +IR_OPCODE(PackedAddU16, General) +IR_OPCODE(PackedSubU16, General) +IR_OPCODE(PackedMaxU16, General) +IR_OPCODE(PackedMinU16, General) +IR_OPCODE(PackedAddF16, General) +IR_OPCODE(PackedMulF16, General) +IR_OPCODE(PackedMinF16, General) +IR_OPCODE(PackedMaxF16, General) +IR_OPCODE(PackedFmaF16, General) +IR_OPCODE(AddF16, General) +IR_OPCODE(SubF16, General) +IR_OPCODE(MulF16, General) +IR_OPCODE(MinF16, General) +IR_OPCODE(MaxF16, General) +IR_OPCODE(FmaF16, General) +IR_OPCODE(MadMixF16, General) +IR_OPCODE(IAddU16, General) +IR_OPCODE(ISubI16, General) +IR_OPCODE(IMinI16, General) +IR_OPCODE(IMaxI16, General) +IR_OPCODE(UMinU16, General) +IR_OPCODE(UMaxU16, General) +IR_OPCODE(RcpF32, General) +IR_OPCODE(FractF32, General) +IR_OPCODE(TruncF32, General) +IR_OPCODE(CeilF32, General) +IR_OPCODE(RoundEvenF32, General) +IR_OPCODE(FloorF32, General) +IR_OPCODE(Exp2F32, General) +IR_OPCODE(Log2F32, General) +IR_OPCODE(InverseSqrtF32, General) +IR_OPCODE(SqrtF32, General) +IR_OPCODE(RcpF16, General) +IR_OPCODE(SqrtF16, General) +IR_OPCODE(InverseSqrtF16, General) +IR_OPCODE(Log2F16, General) +IR_OPCODE(Exp2F16, General) +IR_OPCODE(FloorF16, General) +IR_OPCODE(CeilF16, General) +IR_OPCODE(TruncF16, General) +IR_OPCODE(RoundEvenF16, General) +IR_OPCODE(SinF32, General) +IR_OPCODE(CosF32, General) +IR_OPCODE(CubeIdF32, General) +IR_OPCODE(CubeScF32, General) +IR_OPCODE(CubeTcF32, General) +IR_OPCODE(CubeMaF32, General) +IR_OPCODE(FAddF32, General) +IR_OPCODE(FSubF32, General) +IR_OPCODE(FMulF32, General) +IR_OPCODE(FMinF32, General) +IR_OPCODE(FMaxF32, General) +IR_OPCODE(FMadF32, General) +IR_OPCODE(Dot2AccF32F16, General) +IR_OPCODE(FMin3F32, General) +IR_OPCODE(FMax3F32, General) +IR_OPCODE(FMed3F32, General) +IR_OPCODE(Min3F16, General) +IR_OPCODE(Max3F16, General) +IR_OPCODE(Med3F16, General) +IR_OPCODE(LoadSrtDword, General) +IR_OPCODE(SLoadDword, General) +IR_OPCODE(SBufferLoadDword, General) +IR_OPCODE(BufferLoadUbyte, General) +IR_OPCODE(BufferLoadSbyte, General) +IR_OPCODE(BufferLoadUshort, General) +IR_OPCODE(BufferLoadSshort, General) +IR_OPCODE(BufferLoadDword, General) +IR_OPCODE(BufferStoreByte, General) +IR_OPCODE(BufferStoreShort, General) +IR_OPCODE(BufferStoreDword, General) +IR_OPCODE(AtomicSwapU32, General) +IR_OPCODE(AtomicAddU32, General) +IR_OPCODE(AtomicSubU32, General) +IR_OPCODE(AtomicSMinI32, General) +IR_OPCODE(AtomicUMinU32, General) +IR_OPCODE(AtomicSMaxI32, General) +IR_OPCODE(AtomicUMaxU32, General) +IR_OPCODE(AtomicAndU32, General) +IR_OPCODE(AtomicOrU32, General) +IR_OPCODE(AtomicXorU32, General) +IR_OPCODE(FlatLoadUbyte, General) +IR_OPCODE(FlatLoadSbyte, General) +IR_OPCODE(FlatLoadUshort, General) +IR_OPCODE(FlatLoadSshort, General) +IR_OPCODE(FlatLoadDword, General) +IR_OPCODE(FlatStoreByte, General) +IR_OPCODE(FlatStoreShort, General) +IR_OPCODE(FlatStoreDword, General) +IR_OPCODE(DsReadUbyte, General) +IR_OPCODE(DsReadSbyte, General) +IR_OPCODE(DsReadUshort, General) +IR_OPCODE(DsReadSshort, General) +IR_OPCODE(DsReadB32, General) +IR_OPCODE(DsWriteByte, General) +IR_OPCODE(DsWriteShort, General) +IR_OPCODE(DsWriteB32, General) +IR_OPCODE(DsMinF32, General) +IR_OPCODE(DsMaxF32, General) +IR_OPCODE(DsSwizzleB32, General) +IR_OPCODE(DsConsume, General) +IR_OPCODE(DsAppend, General) +IR_OPCODE(DsWriteAddtidB32, General) +IR_OPCODE(DsReadAddtidB32, General) +IR_OPCODE(ImageGetResinfo, General) +IR_OPCODE(ImageGetLod, General) +IR_OPCODE(ImageLoad, General) +IR_OPCODE(ImageStore, General) +IR_OPCODE(ImageSample, General) +IR_OPCODE(ImageGather4, General) +IR_OPCODE(LoadInputF32, General) +IR_OPCODE(Export, General) diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index 328ed10..036288f 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -2915,6 +2915,52 @@ void CheckNewDecoderUnsupported(const uint32_t* shader, uint32_t words, const ch "unsupported lowering error was not explicit"); } +void TestNewShaderRecompilerRejectsDppOn64BitCompares() { + const uint32_t opcodes[] = {0xa2u, 0xe5u}; // v_cmp_eq_i64, v_cmp_ne_u64 + for (const auto opcode: opcodes) { + const uint32_t shader[] = { + EncodeVopc(opcode, 250u, 0u), // DPP escape in SRC0 + EncodeVop2Dpp(0u), + 0xbf810000u, + }; + + ShaderRecompiler::Decoder::Program program; + std::string error; + Check(ShaderRecompiler::Decoder::DecodeProgram(shader, program, &error), error.c_str()); + Check(program.instructions.size() == 2u, + "64-bit VOPC DPP decode did not consume its modifier word"); + const auto& compare = program.instructions.front(); + Check(compare.opcode == ShaderRecompiler::Decoder::Opcode::Unsupported, + "64-bit VOPC illegally accepted a DPP modifier"); + Check(Common::ContainsStr(compare.unsupported_reason, + "VOPC DPP modifier is not supported for opcode"), + "64-bit VOPC DPP rejection reason was not explicit"); + } +} + +void TestNewShaderRecompilerIrLookupMissFailsExplicitly() { + ShaderRecompiler::Decoder::Program decoded; + ShaderRecompiler::Decoder::Instruction missing; + missing.pc = 0u; + missing.family = ShaderRecompiler::Decoder::Family::VOP1; + missing.opcode = ShaderRecompiler::Decoder::Opcode::Unknown; + decoded.instructions.push_back(missing); + + ShaderRecompiler::CFG::Graph cfg; + ShaderRecompiler::CFG::BasicBlock block; + block.inst_end = 1u; + cfg.blocks.push_back(block); + cfg.entry_block = 0u; + + ShaderRecompiler::IR::Program ir; + std::string error; + Check(!ShaderRecompiler::IR::LowerProgram(decoded, cfg, ShaderType::Compute, 64u, ir, &error), + "missing decoder-to-IR mapping unexpectedly lowered as an instruction"); + Check(Common::ContainsStr(error, "no IR lowering"), + "missing decoder-to-IR mapping did not report an explicit error"); + Check(ir.blocks.empty(), "missing decoder-to-IR mapping emitted a fallback IR block"); +} + void TestNewShaderRecompilerMemoryFamilyLowering() { const uint32_t shader[] = { EncodeSmem0(0x00, 0, 4), @@ -7437,6 +7483,8 @@ int main() { TestNewShaderRecompilerScalarVectorAlu(); TestNewShaderRecompilerVop3LaneReadDestinationEncoding(); TestNewShaderRecompilerMoreAluFamilies(); + TestNewShaderRecompilerRejectsDppOn64BitCompares(); + TestNewShaderRecompilerIrLookupMissFailsExplicitly(); TestNewShaderRecompilerExpandedAluBatch(); TestNewShaderRecompilerVop3pPackedF16(); TestNewShaderRecompilerStagedShaderOps();