diff --git a/core/libs/tests/VectorFusedMultiplyAdd.cpp b/core/libs/tests/VectorFusedMultiplyAdd.cpp index e8713719a..3315e155a 100644 --- a/core/libs/tests/VectorFusedMultiplyAdd.cpp +++ b/core/libs/tests/VectorFusedMultiplyAdd.cpp @@ -70,6 +70,26 @@ void Check(const std::string& name, std::uint32_t encoding, std::uint32_t wordCo } } +void CheckMix(const std::string& name, const std::array& words) { + const RdnaInstruction instruction = DecodeRdnaVectorOp(std::span(words), 0u); + Require(instruction.family == RdnaInstructionFamily::VOP3P, name + " is not decoded as VOP3P"); + Require(instruction.op == RdnaOpcode::VFmaF32, name + " decodes to another opcode"); + + IrProgram program; + auto& block = program.CreateBlock(); + program.SetEntryBlock(block); + TranslationContext context(program, block, 256); + context.SetFloatMode(ShaderFloatMode{0xf0u, false, false, false}); + context.TranslateInstruction(instruction); + + std::uint32_t fused = 0u; + for (const auto* value : block.Instructions()) { + Require(value->Opcode() != IrOpcode::FPMad32, name + " rounds the product separately"); + if (value->Opcode() == IrOpcode::FPFma32) ++fused; + } + Require(fused == 1u, name + " emits " + std::to_string(fused) + " fused multiply-adds"); +} + } int main() { @@ -83,6 +103,8 @@ int main() { Check("v_fmac_f32", 0x2bu, 1u, RdnaOpcode::VMacF32, IrOpcode::FPFma32, accumulate); Check("v_fmamk_f32", 0x2cu, 2u, RdnaOpcode::VMadmkF32, IrOpcode::FPFma32, multiplyLiteral); Check("v_fmaak_f32", 0x2du, 2u, RdnaOpcode::VMadakF32, IrOpcode::FPFma32, addLiteral); + CheckMix("v_fma_mix_f32", {0xcc200005u, 0x04220f06u}); + CheckMix("v_fma_mix_f32 op_sel_hi:[1,0,1]", {0xcc204005u, 0x0c220f06u}); return 0; } catch (const std::exception& error) { std::cerr << error.what() << '\n'; diff --git a/core/shader/recompiler/Translation/src/VectorInstructions.cpp b/core/shader/recompiler/Translation/src/VectorInstructions.cpp index e4376863d..9b5fd4580 100644 --- a/core/shader/recompiler/Translation/src/VectorInstructions.cpp +++ b/core/shader/recompiler/Translation/src/VectorInstructions.cpp @@ -14,6 +14,9 @@ bool roundsProductSeparately(const RdnaInstruction& inst) { if (inst.op == RdnaOpcode::VMadF32) { return true; } + if (inst.family == RdnaInstructionFamily::VOP3P) { + return false; + } const std::uint32_t vop2 = inst.family == RdnaInstructionFamily::VOP3 ? inst.opcodeId - 0x100u : inst.opcodeId; return vop2 == 0x1fu || vop2 == 0x20u || vop2 == 0x21u; }