fix(shader): stop decoding gfx6/7-only VOP2 opcodes on RDNA

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
krishnaraya 2026-10-09 12:30:40 -04:00
parent d70b899894
commit 2ea1f6fb71
8 changed files with 107 additions and 30 deletions

View File

@ -344,6 +344,18 @@ add_test_executable(agc_vop1_control_decode_tests EXCLUDE_FROM_ALL tests/Vop1Con
target_link_libraries(agc_vop1_control_decode_tests PRIVATE shader_recompiler_agc_driver libc)
set_target_properties(agc_vop1_control_decode_tests PROPERTIES CXX_EXTENSIONS OFF)
configure_windows_unwind(agc_vop1_control_decode_tests)
add_test_executable(agc_vop2_encoding_decode_tests EXCLUDE_FROM_ALL tests/Vop2EncodingDecode.cpp)
target_link_libraries(agc_vop2_encoding_decode_tests PRIVATE shader_recompiler_agc_driver libc)
set_target_properties(agc_vop2_encoding_decode_tests PROPERTIES CXX_EXTENSIONS OFF)
configure_windows_unwind(agc_vop2_encoding_decode_tests)
if(BUILD_TESTING)
set_target_properties(agc_vop2_encoding_decode_tests PROPERTIES EXCLUDE_FROM_ALL OFF)
add_test(NAME agc_vop2_encoding_decode COMMAND agc_vop2_encoding_decode_tests)
if(WIN32)
set_tests_properties(agc_vop2_encoding_decode PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
endif()
add_test_executable(agc_dcc_key_sharing_tests EXCLUDE_FROM_ALL tests/DccKeySharing.cpp)
target_include_directories(agc_dcc_key_sharing_tests PRIVATE ${LIBS_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/core/shader/recompiler ${CMAKE_SOURCE_DIR}/3rdparty/Vulkan-Headers/include)

View File

@ -0,0 +1,82 @@
#include "RdnaDecoder/RdnaInstructionDecoder.hpp"
#include <cstdio>
#include <exception>
#include <string>
#include <vector>
using namespace ShaderRecompiler;
namespace {
struct Accepted {
std::vector<std::uint32_t> words;
RdnaOpcode op;
const char* name;
};
struct Refused {
std::vector<std::uint32_t> words;
const char* reason;
const char* name;
};
}
int main() {
const std::vector<Accepted> accepted{
{{0x2c040300u}, RdnaOpcode::VLshrrevB32, "v_lshrrev_b32"},
{{0x6e040300u, 0x00003c00u}, RdnaOpcode::VFmamkF16, "v_fmamk_f16"},
{{0x78040300u}, RdnaOpcode::VPkFmacF16, "v_pk_fmac_f16"},
{{0xd5160002u, 0x00020300u}, RdnaOpcode::VLshrrevB32, "VOP3 v_lshrrev_b32"},
{{0xd7640002u, 0x00020300u}, RdnaOpcode::VBcntU32B32, "VOP3 v_bcnt_u32_b32"},
{{0xd7650002u, 0x00020300u}, RdnaOpcode::VMbcntLoU32B32, "VOP3 v_mbcnt_lo_u32_b32"},
{{0xd7660002u, 0x00020300u}, RdnaOpcode::VMbcntHiU32B32, "VOP3 v_mbcnt_hi_u32_b32"},
};
const std::vector<Refused> refused{
{{0x2a040300u}, "VOP2 opcode is not implemented", "VOP2 opcode 0x15"},
{{0x2e040300u}, "VOP2 opcode is not implemented", "VOP2 opcode 0x17"},
{{0x32040300u}, "VOP2 opcode is not implemented", "VOP2 opcode 0x19"},
{{0x44040300u}, "VOP2 opcode is not implemented", "VOP2 opcode 0x22"},
{{0x46040300u}, "VOP2 opcode is not implemented", "VOP2 opcode 0x23"},
{{0x48040300u}, "VOP2 opcode is not implemented", "VOP2 opcode 0x24"},
{{0xd5150002u, 0x00020300u}, "VOP3 opcode is not implemented", "VOP3 opcode 0x115"},
{{0xd5170002u, 0x00020300u}, "VOP3 opcode is not implemented", "VOP3 opcode 0x117"},
{{0xd5190002u, 0x00020300u}, "VOP3 opcode is not implemented", "VOP3 opcode 0x119"},
{{0xd5220002u, 0x00020300u}, "VOP3 opcode is not implemented", "VOP3 opcode 0x122"},
{{0xd5230002u, 0x00020300u}, "VOP3 opcode is not implemented", "VOP3 opcode 0x123"},
{{0xd5240002u, 0x00020300u}, "VOP3 opcode is not implemented", "VOP3 opcode 0x124"},
{{0xd5370002u, 0x00020300u}, "VOP3 opcode is not implemented", "VOP3 opcode 0x137"},
{{0xd5380002u, 0x00020300u}, "VOP3 opcode is not implemented", "VOP3 opcode 0x138"},
{{0xd53c0002u, 0x00020300u}, "VOP3 opcode is not implemented", "VOP3 opcode 0x13c"},
};
int failures = 0;
for (const auto& test : accepted) {
auto code = test.words;
code.push_back(0xbf810000u);
try {
const auto decoded = RdnaInstructionDecoder{}.Decode(code);
if (decoded.instructions.empty() || decoded.instructions[0].op != test.op || decoded.instructions[0].wordCount != test.words.size()) {
std::fprintf(stderr, "%s decodes to the wrong opcode or length\n", test.name);
++failures;
}
} catch (const std::exception& error) {
std::fprintf(stderr, "%s was refused: %s\n", test.name, error.what());
++failures;
}
}
for (const auto& test : refused) {
auto code = test.words;
code.push_back(0xbf810000u);
std::string refusal;
try {
static_cast<void>(RdnaInstructionDecoder{}.Decode(code));
} catch (const std::exception& error) {
refusal = error.what();
}
if (refusal.find(test.reason) == std::string::npos) {
std::fprintf(stderr, "%s was not refused\n", test.name);
++failures;
}
}
return failures == 0 ? 0 : 1;
}

View File

@ -28,12 +28,12 @@ constexpr std::uint32_t SharedExhausted = 1000u;
alignas(256) std::array<std::uint32_t, MaxThreads * Inputs> Input{};
alignas(256) std::array<std::uint32_t, MaxThreads * Results + SharedWords> Output{};
alignas(256) constexpr std::array<std::uint32_t, 35> Code{
alignas(256) constexpr std::array<std::uint32_t, 37> Code{
0x34020084, 0x34040085, 0xe0301000, 0x80000401, 0xe0301004, 0x80000501, 0xe0301008, 0x80000601,
0xbf8c3f70, 0x7e140280, 0x461414c1, 0x481414c1, 0x7e0e0304, 0xe0d05000, 0x80010702, 0x7e100304,
0xbefe03ff, 0x55555555, 0xe0d05004, 0x80010802, 0xbefe03c1, 0x7e120305, 0xe0d04800, 0x80010900,
0x7e160306, 0xe0d04804, 0x80010b00, 0xbf8c3f70, 0xe0701008, 0x80010702, 0xe070100c, 0x80010802,
0xe0701010, 0x80010a02, 0xbf810000,
0xbf8c3f70, 0x7e140280, 0xd765000a, 0x000214c1, 0xd766000a, 0x000214c1, 0x7e0e0304, 0xe0d05000,
0x80010702, 0x7e100304, 0xbefe03ff, 0x55555555, 0xe0d05004, 0x80010802, 0xbefe03c1, 0x7e120305,
0xe0d04800, 0x80010900, 0x7e160306, 0xe0d04804, 0x80010b00, 0xbf8c3f70, 0xe0701008, 0x80010702,
0xe070100c, 0x80010802, 0xe0701010, 0x80010a02, 0xbf810000,
};
alignas(256) constexpr std::array<std::uint32_t, 3> NoReturnCode{

View File

@ -28,12 +28,13 @@ constexpr std::uint32_t MaskedExecLo = 0x55555555u;
alignas(256) std::array<std::uint32_t, TableDwords> Table{};
alignas(256) std::array<std::uint32_t, MaxThreads * Results> Output{};
alignas(256) constexpr std::array<std::uint32_t, 39> AddtidCode{
alignas(256) constexpr std::array<std::uint32_t, 41> AddtidCode{
0x34020085, 0x34040082, 0xbe880300, 0x8709ff01, 0x0000ffff, 0x800aff08, 0x00000200, 0x820b8009,
0x7e080280, 0x460808c1, 0x480808c1, 0x7e0a02ff, 0xabcdabcd, 0x7e0c02ff, 0xabcdabcd, 0x7e0e02ff,
0xabcdabcd, 0xe0301000, 0x80000802, 0xdc588040, 0x05080000, 0xdc588fe4, 0x060a0000, 0xbefe03ff,
0x55555555, 0xdc588000, 0x07080000, 0xbefe03c1, 0xe0701000, 0x80010401, 0xe0701004, 0x80010501,
0xe0701008, 0x80010601, 0xe070100c, 0x80010701, 0xe0701010, 0x80010801, 0xbf810000,
0x7e080280, 0xd7650004, 0x000208c1, 0xd7660004, 0x000208c1, 0x7e0a02ff, 0xabcdabcd, 0x7e0c02ff,
0xabcdabcd, 0x7e0e02ff, 0xabcdabcd, 0xe0301000, 0x80000802, 0xdc588040, 0x05080000, 0xdc588fe4,
0x060a0000, 0xbefe03ff, 0x55555555, 0xdc588000, 0x07080000, 0xbefe03c1, 0xe0701000, 0x80010401,
0xe0701004, 0x80010501, 0xe0701008, 0x80010601, 0xe070100c, 0x80010701, 0xe0701010, 0x80010801,
0xbf810000,
};
struct Workgroup {

View File

@ -70,9 +70,6 @@ enum class RdnaOpcode : std::uint16_t {
VAndB32,
VOrB32,
VXorB32,
VLshlB32,
VLshrB32,
VAshrI32,
VCmpEqF32,
VCmpLtF32,
VCmpGtF32,

View File

@ -183,9 +183,6 @@ bool IsVectorAluOpcode(RdnaOpcode opcode) {
case RdnaOpcode::VAndB32:
case RdnaOpcode::VOrB32:
case RdnaOpcode::VXorB32:
case RdnaOpcode::VLshlB32:
case RdnaOpcode::VLshrB32:
case RdnaOpcode::VAshrI32:
case RdnaOpcode::VCmpEqF32:
case RdnaOpcode::VCmpLtF32:
case RdnaOpcode::VCmpGtF32:

View File

@ -58,11 +58,8 @@ constexpr Vop2OpcodeInfo vop2Opcodes[] = {
{0x12u, RdnaOpcode::VMaxI32, Vop2SdwaProfile::Integer},
{0x13u, RdnaOpcode::VMinU32, Vop2SdwaProfile::Integer},
{0x14u, RdnaOpcode::VMaxU32, Vop2SdwaProfile::Integer},
{0x15u, RdnaOpcode::VLshrB32},
{0x16u, RdnaOpcode::VLshrrevB32, Vop2SdwaProfile::Integer},
{0x17u, RdnaOpcode::VAshrI32},
{0x18u, RdnaOpcode::VAshrrevI32, Vop2SdwaProfile::Integer},
{0x19u, RdnaOpcode::VLshlB32},
{0x1au, RdnaOpcode::VLshlrevB32, Vop2SdwaProfile::Integer},
{0x1bu, RdnaOpcode::VAndB32, Vop2SdwaProfile::Integer},
{0x1cu, RdnaOpcode::VOrB32, Vop2SdwaProfile::Integer},
@ -71,9 +68,6 @@ constexpr Vop2OpcodeInfo vop2Opcodes[] = {
{0x1fu, RdnaOpcode::VMacF32},
{0x20u, RdnaOpcode::VMadmkF32},
{0x21u, RdnaOpcode::VMadakF32},
{0x22u, RdnaOpcode::VBcntU32B32},
{0x23u, RdnaOpcode::VMbcntLoU32B32},
{0x24u, RdnaOpcode::VMbcntHiU32B32},
{0x25u, RdnaOpcode::VAddNcU32, Vop2SdwaProfile::Integer},
{0x28u, RdnaOpcode::VAddcU32, Vop2SdwaProfile::Integer},
{0x29u, RdnaOpcode::VSubCoCiU32, Vop2SdwaProfile::Integer},
@ -630,11 +624,11 @@ RdnaOpcode lookupVectorOpcode(const TEntry (&table)[Size], std::uint32_t encodin
}
bool isVop2LiteralMadOpcode(std::uint32_t opcode) {
return opcode == 0x20u || opcode == 0x21u || opcode == 0x2cu || opcode == 0x2du;
return opcode == 0x20u || opcode == 0x21u || opcode == 0x2cu || opcode == 0x2du || opcode == 0x37u || opcode == 0x38u;
}
bool isUnsupportedVop3EncodedVop2Alias(std::uint32_t opcode) {
return isVop2LiteralMadOpcode(opcode) || opcode == 0x02u || opcode == 0x0du;
return isVop2LiteralMadOpcode(opcode) || opcode == 0x02u || opcode == 0x0du || opcode == 0x3cu;
}
bool isVop3EncodedVopc(std::uint32_t opcode) {

View File

@ -1113,16 +1113,10 @@ bool TranslationContext::emitVector(const RdnaInstruction& inst) {
return simpleInteger(inst, IrOpcode::BitReverse32, IrType::U32, false, false, false);
case RdnaOpcode::VFfblB32:
return simpleInteger(inst, IrOpcode::FindILsb32, IrType::U32, false, false, false);
case RdnaOpcode::VLshlB32:
return simpleInteger(inst, IrOpcode::ShiftLeftLogical32, IrType::U32, false, true, false);
case RdnaOpcode::VLshlrevB32:
return simpleInteger(inst, IrOpcode::ShiftLeftLogical32, IrType::U32, true, true, false);
case RdnaOpcode::VLshrB32:
return simpleInteger(inst, IrOpcode::ShiftRightLogical32, IrType::U32, false, true, false);
case RdnaOpcode::VLshrrevB32:
return simpleInteger(inst, IrOpcode::ShiftRightLogical32, IrType::U32, true, true, false);
case RdnaOpcode::VAshrI32:
return simpleInteger(inst, IrOpcode::ShiftRightArithmetic32, IrType::U32, false, true, false);
case RdnaOpcode::VAshrrevI32:
return simpleInteger(inst, IrOpcode::ShiftRightArithmetic32, IrType::U32, true, true, false);
case RdnaOpcode::VLshlrevB64: