Merge pull request #308 from asimplestray/feat/shader-vop3-mad

feat(shader): implement legacy float multiply-add ops
This commit is contained in:
boykopovar 2026-10-02 23:29:05 +03:00 committed by GitHub
commit 7d40a57d18
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 42 additions and 0 deletions

View File

@ -609,6 +609,14 @@ if(BUILD_TESTING)
set_tests_properties(vector_min_max_med16 PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
add_test_executable(vector_mad_legacy_tests ${LIBS_INCLUDE_DIR}/tests/VectorMadLegacy.cpp)
target_link_libraries(vector_mad_legacy_tests PRIVATE shader_recompiler_agc_driver libc)
configure_windows_unwind(vector_mad_legacy_tests)
add_test(NAME vector_mad_legacy COMMAND vector_mad_legacy_tests)
if(WIN32)
set_tests_properties(vector_mad_legacy PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
add_test_executable(scalar_saveexec_tests ${LIBS_INCLUDE_DIR}/tests/ScalarSaveexec.cpp)
target_link_libraries(scalar_saveexec_tests PRIVATE shader_recompiler_agc_driver libc)
configure_windows_unwind(scalar_saveexec_tests)

View File

@ -0,0 +1,26 @@
#include "Translation/TranslationContext.hpp"
#include "RdnaDecoder/RdnaVectorOpDecoder.hpp"
#include <array>
#include <stdexcept>
using namespace ShaderRecompiler;
static void Require(bool value) { if (!value) throw std::runtime_error("vector legacy mad regression"); }
static void Check(std::uint32_t encoding, RdnaOpcode opcode, IrOpcode expected) {
const std::array<std::uint32_t, 2> code{(encoding << 16u) | 1u, 1u | (2u << 9u) | (3u << 18u)};
const RdnaInstruction instruction = DecodeRdnaVop3(0u, code, 0u);
Require(instruction.op == opcode);
Require(instruction.family == RdnaInstructionFamily::VOP3);
Require(IsVectorAluOpcode(instruction.op));
IrProgram program;
auto& block = program.CreateBlock();
program.SetEntryBlock(block);
TranslationContext context(program, block, 256);
context.TranslateInstruction(instruction);
bool found = false;
for (auto* value : block.Instructions()) found = found || value->Opcode() == expected;
Require(found);
}
int main() {
Check(0x140u, RdnaOpcode::VMadLegacyF32, IrOpcode::FPFma32);
Check(0x150u, RdnaOpcode::VMullitF32, IrOpcode::FPMul32);
}

View File

@ -50,6 +50,8 @@ enum class RdnaOpcode : std::uint16_t {
VSubF32,
VMulF32,
VMadF32,
VMadLegacyF32,
VMullitF32,
VFmaF32,
VAddI32,
VSubI32,

View File

@ -156,6 +156,8 @@ bool IsVectorAluOpcode(RdnaOpcode opcode) {
case RdnaOpcode::VSubF32:
case RdnaOpcode::VMulF32:
case RdnaOpcode::VMadF32:
case RdnaOpcode::VMadLegacyF32:
case RdnaOpcode::VMullitF32:
case RdnaOpcode::VFmaF32:
case RdnaOpcode::VAddI32:
case RdnaOpcode::VSubI32:

View File

@ -372,6 +372,7 @@ constexpr VopcOpcodeInfo vopcOpcodes[] = {
};
constexpr VectorOpcodeInfo vop3Opcodes[] = {
{0x140u, RdnaOpcode::VMadLegacyF32},
{0x141u, RdnaOpcode::VMadF32},
{0x142u, RdnaOpcode::VMadI32I24},
{0x143u, RdnaOpcode::VMadU32U24},
@ -385,6 +386,7 @@ constexpr VectorOpcodeInfo vop3Opcodes[] = {
{0x149u, RdnaOpcode::VBfeI32},
{0x14au, RdnaOpcode::VBfiB32},
{0x14eu, RdnaOpcode::VAlignbitB32},
{0x150u, RdnaOpcode::VMullitF32},
{0x151u, RdnaOpcode::VMin3F32},
{0x152u, RdnaOpcode::VMin3I32},
{0x153u, RdnaOpcode::VMin3U32},

View File

@ -724,6 +724,7 @@ bool TranslationContext::emitVector(const RdnaInstruction& inst) {
case RdnaOpcode::VSubrevF32:
return floatBinary(inst, IrOpcode::FPSub32, true);
case RdnaOpcode::VMulF32:
case RdnaOpcode::VMullitF32:
return floatBinary(inst, IrOpcode::FPMul32, false);
case RdnaOpcode::VMinF32:
return floatBinary(inst, IrOpcode::FPMin32, false);
@ -736,6 +737,7 @@ bool TranslationContext::emitVector(const RdnaInstruction& inst) {
case RdnaOpcode::VMadmkF32:
case RdnaOpcode::VMadakF32:
case RdnaOpcode::VMadF32:
case RdnaOpcode::VMadLegacyF32:
case RdnaOpcode::VFmaF32:
return floatTernary(inst, IrOpcode::FPFma32, false, true);
case RdnaOpcode::VMin3F32: