From 54c839959fd0b0de2923a048c7bc3a23bddd9599 Mon Sep 17 00:00:00 2001 From: goncalompontes Date: Sat, 10 Oct 2026 21:07:55 +0100 Subject: [PATCH 1/3] feat(shader): decode GFX10 VOP3-encoded interpolation v_interp_p1_f32_e64, v_interp_p2_f32_e64 and v_interp_mov_f32_e64 (VOP3Interp opcodes 0x200, 0x201 and 0x202) reach the decoder as VOP3 and were refused as unimplemented VOP3 opcodes. Decode them into the existing VInterpP1F32, VInterpP2F32 and VInterpMovF32 opcodes with the VOP3Interp operand layout, so the interpolation translation already used by the VINTRP encodings handles them. Encodings and operand layout follow LLVM's gfx10 MC tests for VOP3Interp_Real_gfx10 (D69348). The interpolation parameter is the low six bits of src0, the channel bits 6:7, the coordinate (or the interpolation parameter of the mov form) is src1, and clamp and omod reach the destination. op_sel, the packed-half selector, a third source and abs/neg on operands that do not exist throw. --- core/libs/prx/libSceAgcDriver/CMakeLists.txt | 13 +++ .../tests/Vop3InterpDecode.cpp | 100 ++++++++++++++++++ .../RdnaDecoder/src/RdnaVectorOpDecoder.cpp | 44 ++++++++ 3 files changed, 157 insertions(+) create mode 100644 core/libs/prx/libSceAgcDriver/tests/Vop3InterpDecode.cpp diff --git a/core/libs/prx/libSceAgcDriver/CMakeLists.txt b/core/libs/prx/libSceAgcDriver/CMakeLists.txt index d24c90ab0..a8a566cab 100644 --- a/core/libs/prx/libSceAgcDriver/CMakeLists.txt +++ b/core/libs/prx/libSceAgcDriver/CMakeLists.txt @@ -470,6 +470,19 @@ if(BUILD_TESTING) endif() endif() +add_test_executable(agc_vop3_interp_decode_tests EXCLUDE_FROM_ALL tests/Vop3InterpDecode.cpp) +target_link_libraries(agc_vop3_interp_decode_tests PRIVATE shader_recompiler_agc_driver libc) +set_target_properties(agc_vop3_interp_decode_tests PROPERTIES CXX_EXTENSIONS OFF) +configure_windows_unwind(agc_vop3_interp_decode_tests) +if(BUILD_TESTING) + set_target_properties(agc_vop3_interp_decode_tests PROPERTIES EXCLUDE_FROM_ALL OFF) + add_test(NAME agc_vop3_interp_decode COMMAND agc_vop3_interp_decode_tests) + if(WIN32) + set_tests_properties(agc_vop3_interp_decode PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() +endif() + add_test_executable(agc_pass_hazards_tests EXCLUDE_FROM_ALL tests/PassHazards.cpp Graphics/src/PassHazards.cpp) target_include_directories(agc_pass_hazards_tests PRIVATE ${LIBS_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/3rdparty/Vulkan-Headers/include) target_link_libraries(agc_pass_hazards_tests PRIVATE libc) diff --git a/core/libs/prx/libSceAgcDriver/tests/Vop3InterpDecode.cpp b/core/libs/prx/libSceAgcDriver/tests/Vop3InterpDecode.cpp new file mode 100644 index 000000000..a8c267b53 --- /dev/null +++ b/core/libs/prx/libSceAgcDriver/tests/Vop3InterpDecode.cpp @@ -0,0 +1,100 @@ +#include "RdnaDecoder/RdnaInstructionDecoder.hpp" +#include +#include +#include +#include +#include + +using namespace ShaderRecompiler; + +namespace { + +struct Accepted { + std::vector words; + RdnaOpcode op; + const char* name; + RdnaOperandKind source0Kind; + std::uint32_t source0Value; + std::uint32_t attribute; + std::uint32_t channel; + bool absolute; + bool negate; + bool clamp; + std::uint32_t omod; +}; + +struct Refused { + std::vector words; + const char* reason; + const char* name; +}; + +} + +int main() { + constexpr std::uint32_t Destination = 5; + const std::vector accepted{ + {{0xd6000005u, 0x00020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr0.x", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, false, false, 0u}, + {{0xd6010005u, 0x00020440u}, RdnaOpcode::VInterpP2F32, "v_interp_p2_f32_e64 v5, v2, attr0.y", RdnaOperandKind::VectorRegister, 2u, 0u, 1u, false, false, false, 0u}, + {{0xd6020005u, 0x00000200u}, RdnaOpcode::VInterpMovF32, "v_interp_mov_f32_e64 v5, p20, attr0.x", RdnaOperandKind::IntegerInlineConstant, 1u, 0u, 0u, false, false, false, 0u}, + {{0xd6000005u, 0x0002041fu}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr31.x", RdnaOperandKind::VectorRegister, 2u, 31u, 0u, false, false, false, 0u}, + {{0xd6000005u, 0x00020420u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr32.x", RdnaOperandKind::VectorRegister, 2u, 32u, 0u, false, false, false, 0u}, + {{0xd6000005u, 0x0003fe00u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v255, attr0.x", RdnaOperandKind::VectorRegister, 255u, 0u, 0u, false, false, false, 0u}, + {{0xd6000205u, 0x00020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, |v2|, attr0.x", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, true, false, false, 0u}, + {{0xd6000005u, 0x40020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, -v2, attr0.x", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, true, false, 0u}, + {{0xd6008005u, 0x00020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr0.x clamp", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, false, true, 0u}, + {{0xd6000005u, 0x08020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr0.x mul:2", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, false, false, 1u}, + }; + const std::vector refused{ + {{0xd6000005u, 0x00000400u}, "not a vector register", "v_interp_p1_f32_e64 with a non-VGPR coordinate"}, + {{0xd6020005u, 0x00000600u}, "not an interpolation parameter", "v_interp_mov_f32_e64 with a reserved parameter"}, + {{0xd6000805u, 0x00020400u}, "modifiers are not implemented", "v_interp_p1_f32_e64 with op_sel"}, + {{0xd6000005u, 0x00020500u}, "modifiers are not implemented", "v_interp_p1_f32_e64 with the packed-half selector"}, + {{0xd6000005u, 0x00060400u}, "modifiers are not implemented", "v_interp_p1_f32_e64 with a third source"}, + {{0xd6000105u, 0x00020400u}, "modifiers are not implemented", "v_interp_p1_f32_e64 with an absolute source 0"}, + {{0xd6020005u, 0x20000000u}, "modifiers are not implemented", "v_interp_mov_f32_e64 with a negated parameter"}, + }; + 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()) { + std::fprintf(stderr, "%s decoded no instruction\n", test.name); + ++failures; + continue; + } + const auto& instruction = decoded.instructions[0]; + const auto source0Value = test.source0Kind == RdnaOperandKind::VectorRegister ? instruction.source0.reg : instruction.source0.value; + if (instruction.op != test.op || instruction.wordCount != test.words.size() || instruction.family != RdnaInstructionFamily::VOP3 || + instruction.destination.kind != RdnaOperandKind::VectorRegister || instruction.destination.reg != Destination || + instruction.destination.clamp != test.clamp || instruction.destination.omod != test.omod || instruction.sourceCount != 3u || + instruction.source0.kind != test.source0Kind || source0Value != test.source0Value || + instruction.source0.absolute != test.absolute || instruction.source0.negate != test.negate || + instruction.source1.kind != RdnaOperandKind::IntegerInlineConstant || instruction.source1.value != test.attribute || + instruction.source2.kind != RdnaOperandKind::IntegerInlineConstant || instruction.source2.value != test.channel) { + std::fprintf(stderr, "%s decoded to the wrong opcode or operands\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(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; +} diff --git a/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp b/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp index 521e629c2..00b7078af 100644 --- a/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp +++ b/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp @@ -529,6 +529,9 @@ constexpr VectorOpcodeInfo vop3Opcodes[] = { {0x311u, RdnaOpcode::VPackB32F16}, {0x314u, RdnaOpcode::VLshlrevB16}, {0x319u, RdnaOpcode::VSubrevI32}, + {0x200u, RdnaOpcode::VInterpP1F32}, + {0x201u, RdnaOpcode::VInterpP2F32}, + {0x202u, RdnaOpcode::VInterpMovF32}, {0x342u, RdnaOpcode::VInterpP1llF16}, {0x343u, RdnaOpcode::VInterpP1lvF16}, {0x344u, RdnaOpcode::VPermB32}, @@ -2114,6 +2117,43 @@ void decodeVop3F16Interpolation(RdnaInstruction& instruction, std::uint32_t vdst } } +bool isVop3F32InterpolationOpcode(RdnaOpcode opcode) { + return opcode == RdnaOpcode::VInterpP1F32 || opcode == RdnaOpcode::VInterpP2F32 || opcode == RdnaOpcode::VInterpMovF32; +} + +void decodeVop3F32Interpolation(RdnaInstruction& instruction, std::uint32_t vdst, std::uint32_t src0, std::uint32_t src1, std::uint32_t src2, std::uint32_t abs, std::uint32_t opSel, std::uint32_t clamp, std::uint32_t omod, std::uint32_t neg) { + const bool moves = instruction.op == RdnaOpcode::VInterpMovF32; + if ((abs & 0x5u) != 0u || (neg & 0x5u) != 0u || opSel != 0u || src2 != 0u || (src0 >> 8u) != 0u || (moves && (abs | neg) != 0u)) { + throw std::invalid_argument("VOP3 interpolation modifiers are not implemented"); + } + if (moves) { + if (src1 >= 3u) { + throw std::invalid_argument("VOP3 interpolation source is not an interpolation parameter"); + } + } else if (src1 < 256u) { + throw std::invalid_argument("VOP3 interpolation source is not a vector register"); + } + instruction.destination = DecodeRdnaVectorGpr(vdst); + instruction.destination.clamp = clamp != 0u; + instruction.destination.omod = omod; + if (moves) { + instruction.source0.kind = RdnaOperandKind::IntegerInlineConstant; + instruction.source0.value = src1; + instruction.source0.signedVal = static_cast(src1); + } else { + instruction.source0 = DecodeRdnaVectorGpr(src1 - 256u); + instruction.source0.absolute = (abs & 0x2u) != 0u; + instruction.source0.negate = (neg & 0x2u) != 0u; + } + instruction.source1.kind = RdnaOperandKind::IntegerInlineConstant; + instruction.source1.value = src0 & 0x3fu; + instruction.source1.signedVal = static_cast(instruction.source1.value); + instruction.source2.kind = RdnaOperandKind::IntegerInlineConstant; + instruction.source2.value = (src0 >> 6u) & 0x3u; + instruction.source2.signedVal = static_cast(instruction.source2.value); + instruction.sourceCount = 3; +} + void applyNativeVop3SourceModifiers(RdnaInstruction& instruction, std::uint32_t abs, std::uint32_t neg) { RdnaOperand* sources[] = {&instruction.source0, &instruction.source1, &instruction.source2}; for (std::uint32_t i = 0; i < instruction.sourceCount && i < 3u; ++i) { @@ -2278,6 +2318,10 @@ RdnaInstruction DecodeRdnaVop3(std::uint32_t programCounter, std::span Date: Sun, 11 Oct 2026 16:03:46 +0100 Subject: [PATCH 2/3] fix(shader): accept the inline constant third source of VOP3 interpolation The assembler encodes the unused third source of the VOP3-encoded interpolation forms as the inline constant 0 (src2 = 0x80, bit 25 of the second word), which the decoder refused. Accept that encoding and refuse any other third source. The decode test now uses the assembler words for every accepted form and keeps the refusals one field away from a valid word. --- .../tests/Vop3InterpDecode.cpp | 34 +++++++++---------- .../RdnaDecoder/src/RdnaVectorOpDecoder.cpp | 6 +++- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/core/libs/prx/libSceAgcDriver/tests/Vop3InterpDecode.cpp b/core/libs/prx/libSceAgcDriver/tests/Vop3InterpDecode.cpp index a8c267b53..b3a4aca23 100644 --- a/core/libs/prx/libSceAgcDriver/tests/Vop3InterpDecode.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/Vop3InterpDecode.cpp @@ -34,25 +34,25 @@ struct Refused { int main() { constexpr std::uint32_t Destination = 5; const std::vector accepted{ - {{0xd6000005u, 0x00020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr0.x", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, false, false, 0u}, - {{0xd6010005u, 0x00020440u}, RdnaOpcode::VInterpP2F32, "v_interp_p2_f32_e64 v5, v2, attr0.y", RdnaOperandKind::VectorRegister, 2u, 0u, 1u, false, false, false, 0u}, - {{0xd6020005u, 0x00000200u}, RdnaOpcode::VInterpMovF32, "v_interp_mov_f32_e64 v5, p20, attr0.x", RdnaOperandKind::IntegerInlineConstant, 1u, 0u, 0u, false, false, false, 0u}, - {{0xd6000005u, 0x0002041fu}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr31.x", RdnaOperandKind::VectorRegister, 2u, 31u, 0u, false, false, false, 0u}, - {{0xd6000005u, 0x00020420u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr32.x", RdnaOperandKind::VectorRegister, 2u, 32u, 0u, false, false, false, 0u}, - {{0xd6000005u, 0x0003fe00u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v255, attr0.x", RdnaOperandKind::VectorRegister, 255u, 0u, 0u, false, false, false, 0u}, - {{0xd6000205u, 0x00020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, |v2|, attr0.x", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, true, false, false, 0u}, - {{0xd6000005u, 0x40020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, -v2, attr0.x", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, true, false, 0u}, - {{0xd6008005u, 0x00020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr0.x clamp", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, false, true, 0u}, - {{0xd6000005u, 0x08020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr0.x mul:2", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, false, false, 1u}, + {{0xd6000005u, 0x02020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr0.x", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, false, false, 0u}, + {{0xd6010005u, 0x02020440u}, RdnaOpcode::VInterpP2F32, "v_interp_p2_f32_e64 v5, v2, attr0.y", RdnaOperandKind::VectorRegister, 2u, 0u, 1u, false, false, false, 0u}, + {{0xd6020005u, 0x02000200u}, RdnaOpcode::VInterpMovF32, "v_interp_mov_f32_e64 v5, p20, attr0.x", RdnaOperandKind::IntegerInlineConstant, 1u, 0u, 0u, false, false, false, 0u}, + {{0xd6000005u, 0x0202041fu}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr31.x", RdnaOperandKind::VectorRegister, 2u, 31u, 0u, false, false, false, 0u}, + {{0xd6000005u, 0x02020420u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr32.x", RdnaOperandKind::VectorRegister, 2u, 32u, 0u, false, false, false, 0u}, + {{0xd6000005u, 0x0203fe00u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v255, attr0.x", RdnaOperandKind::VectorRegister, 255u, 0u, 0u, false, false, false, 0u}, + {{0xd6000205u, 0x02020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, |v2|, attr0.x", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, true, false, false, 0u}, + {{0xd6000005u, 0x42020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, -v2, attr0.x", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, true, false, 0u}, + {{0xd6008005u, 0x02020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr0.x clamp", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, false, true, 0u}, + {{0xd6000005u, 0x0a020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr0.x mul:2", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, false, false, 1u}, }; const std::vector refused{ - {{0xd6000005u, 0x00000400u}, "not a vector register", "v_interp_p1_f32_e64 with a non-VGPR coordinate"}, - {{0xd6020005u, 0x00000600u}, "not an interpolation parameter", "v_interp_mov_f32_e64 with a reserved parameter"}, - {{0xd6000805u, 0x00020400u}, "modifiers are not implemented", "v_interp_p1_f32_e64 with op_sel"}, - {{0xd6000005u, 0x00020500u}, "modifiers are not implemented", "v_interp_p1_f32_e64 with the packed-half selector"}, - {{0xd6000005u, 0x00060400u}, "modifiers are not implemented", "v_interp_p1_f32_e64 with a third source"}, - {{0xd6000105u, 0x00020400u}, "modifiers are not implemented", "v_interp_p1_f32_e64 with an absolute source 0"}, - {{0xd6020005u, 0x20000000u}, "modifiers are not implemented", "v_interp_mov_f32_e64 with a negated parameter"}, + {{0xd6000005u, 0x02000400u}, "not a vector register", "v_interp_p1_f32_e64 with a non-VGPR coordinate"}, + {{0xd6020005u, 0x02000600u}, "not an interpolation parameter", "v_interp_mov_f32_e64 with a reserved parameter"}, + {{0xd6000005u, 0x02060400u}, "third source is not the inline constant 0", "v_interp_p1_f32_e64 with a third source other than the inline constant 0"}, + {{0xd6000805u, 0x02020400u}, "modifiers are not implemented", "v_interp_p1_f32_e64 with op_sel"}, + {{0xd6000005u, 0x02020500u}, "modifiers are not implemented", "v_interp_p1_f32_e64 with the packed-half selector"}, + {{0xd6000105u, 0x02020400u}, "modifiers are not implemented", "v_interp_p1_f32_e64 with an absolute source 0"}, + {{0xd6020005u, 0x22000200u}, "modifiers are not implemented", "v_interp_mov_f32_e64 with a negated parameter"}, }; int failures = 0; for (const auto& test : accepted) { diff --git a/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp b/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp index 00b7078af..5856ec94e 100644 --- a/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp +++ b/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp @@ -2123,7 +2123,11 @@ bool isVop3F32InterpolationOpcode(RdnaOpcode opcode) { void decodeVop3F32Interpolation(RdnaInstruction& instruction, std::uint32_t vdst, std::uint32_t src0, std::uint32_t src1, std::uint32_t src2, std::uint32_t abs, std::uint32_t opSel, std::uint32_t clamp, std::uint32_t omod, std::uint32_t neg) { const bool moves = instruction.op == RdnaOpcode::VInterpMovF32; - if ((abs & 0x5u) != 0u || (neg & 0x5u) != 0u || opSel != 0u || src2 != 0u || (src0 >> 8u) != 0u || (moves && (abs | neg) != 0u)) { + const RdnaOperand thirdSource = DecodeRdnaScalarSource(src2, instruction.programCounter); + if (thirdSource.kind != RdnaOperandKind::IntegerInlineConstant || thirdSource.value != 0u) { + throw std::invalid_argument("VOP3 interpolation third source is not the inline constant 0"); + } + if ((abs & 0x5u) != 0u || (neg & 0x5u) != 0u || opSel != 0u || (src0 >> 8u) != 0u || (moves && (abs | neg) != 0u)) { throw std::invalid_argument("VOP3 interpolation modifiers are not implemented"); } if (moves) { From fa726efe9490b7b0d0b374cf941b03d1d43fb18e Mon Sep 17 00:00:00 2001 From: goncalompontes Date: Sun, 11 Oct 2026 18:57:55 +0100 Subject: [PATCH 3/3] test(shader): cover the VOP3 interpolation result and source modifiers Extend the decode test to mul:4, div:2, -|v2|, -|v2| div:2, a p2 coordinate with neg and a non-zero attribute channel, a clamped p2, and the mov form with clamp and mul:2. All 18 accepted words are the assembler output (llvm-mc -mcpu=gfx1010). --- core/libs/prx/libSceAgcDriver/tests/Vop3InterpDecode.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/libs/prx/libSceAgcDriver/tests/Vop3InterpDecode.cpp b/core/libs/prx/libSceAgcDriver/tests/Vop3InterpDecode.cpp index b3a4aca23..f362f67d6 100644 --- a/core/libs/prx/libSceAgcDriver/tests/Vop3InterpDecode.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/Vop3InterpDecode.cpp @@ -44,6 +44,14 @@ int main() { {{0xd6000005u, 0x42020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, -v2, attr0.x", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, true, false, 0u}, {{0xd6008005u, 0x02020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr0.x clamp", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, false, true, 0u}, {{0xd6000005u, 0x0a020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr0.x mul:2", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, false, false, 1u}, + {{0xd6000005u, 0x12020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr0.x mul:4", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, false, false, 2u}, + {{0xd6000005u, 0x1a020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, v2, attr0.x div:2", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, false, false, false, 3u}, + {{0xd6000205u, 0x42020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, -|v2|, attr0.x", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, true, true, false, 0u}, + {{0xd6000205u, 0x5a020400u}, RdnaOpcode::VInterpP1F32, "v_interp_p1_f32_e64 v5, -|v2|, attr0.x div:2", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, true, true, false, 3u}, + {{0xd6010005u, 0x42020481u}, RdnaOpcode::VInterpP2F32, "v_interp_p2_f32_e64 v5, -v2, attr1.z", RdnaOperandKind::VectorRegister, 2u, 1u, 2u, false, true, false, 0u}, + {{0xd6018205u, 0x02020400u}, RdnaOpcode::VInterpP2F32, "v_interp_p2_f32_e64 v5, |v2|, attr0.x clamp", RdnaOperandKind::VectorRegister, 2u, 0u, 0u, true, false, true, 0u}, + {{0xd6028005u, 0x02000000u}, RdnaOpcode::VInterpMovF32, "v_interp_mov_f32_e64 v5, p10, attr0.x clamp", RdnaOperandKind::IntegerInlineConstant, 0u, 0u, 0u, false, false, true, 0u}, + {{0xd6020005u, 0x0a000000u}, RdnaOpcode::VInterpMovF32, "v_interp_mov_f32_e64 v5, p10, attr0.x mul:2", RdnaOperandKind::IntegerInlineConstant, 0u, 0u, 0u, false, false, false, 1u}, }; const std::vector refused{ {{0xd6000005u, 0x02000400u}, "not a vector register", "v_interp_p1_f32_e64 with a non-VGPR coordinate"},