diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 5aa1af55..204c89fa 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -240,6 +240,8 @@ Id EmitIAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b); Id EmitIAdd64(EmitContext& ctx, Id a, Id b); Id EmitISub32(EmitContext& ctx, Id a, Id b); Id EmitISub64(EmitContext& ctx, Id a, Id b); +Id EmitSMulExt(EmitContext& ctx, Id a, Id b); +Id EmitUMulExt(EmitContext& ctx, Id a, Id b); Id EmitIMul32(EmitContext& ctx, Id a, Id b); Id EmitSDiv32(EmitContext& ctx, Id a, Id b); Id EmitUDiv32(EmitContext& ctx, Id a, Id b); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp index 74951e16..1d52a3ed 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp @@ -68,6 +68,14 @@ Id EmitISub64(EmitContext& ctx, Id a, Id b) { return ctx.OpISub(ctx.U64, a, b); } +Id EmitSMulExt(EmitContext& ctx, Id a, Id b) { + return ctx.OpSMulExtended(ctx.full_result_i32x2, a, b); +} + +Id EmitUMulExt(EmitContext& ctx, Id a, Id b) { + return ctx.OpUMulExtended(ctx.full_result_u32x2, a, b); +} + Id EmitIMul32(EmitContext& ctx, Id a, Id b) { return ctx.OpIMul(ctx.U32[1], a, b); } diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 39e552c3..1ac25886 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -104,6 +104,9 @@ void EmitContext::DefineArithmeticTypes() { output_f32 = Name(TypePointer(spv::StorageClass::Output, F32[1]), "output_f32"); output_u32 = Name(TypePointer(spv::StorageClass::Output, U32[1]), "output_u32"); + + full_result_i32x2 = Name(TypeStruct(S32[1], S32[1]), "full_result_i32x2"); + full_result_u32x2 = Name(TypeStruct(U32[1], U32[1]), "full_result_u32x2"); } void EmitContext::DefineInterfaces(const IR::Program& program) { diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index c4bc722c..49dd181f 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h @@ -138,6 +138,9 @@ public: VectorIds U32{}; VectorIds U1{}; + Id full_result_i32x2; + Id full_result_u32x2; + Id true_value{}; Id false_value{}; Id u32_one_value{}; diff --git a/src/shader_recompiler/frontend/translate/translate.cpp b/src/shader_recompiler/frontend/translate/translate.cpp index 40b74303..7120a03b 100644 --- a/src/shader_recompiler/frontend/translate/translate.cpp +++ b/src/shader_recompiler/frontend/translate/translate.cpp @@ -584,8 +584,11 @@ void Translate(IR::Block* block, std::span inst_list, Info& info) case Opcode::S_ADD_I32: translator.S_ADD_I32(inst); break; + case Opcode::V_MUL_HI_U32: + translator.V_MUL_HI_U32(false, inst); + break; case Opcode::V_MUL_LO_I32: - translator.V_MUL_LO_I32(inst); + translator.V_MUL_LO_U32(inst); break; case Opcode::V_SAD_U32: translator.V_SAD_U32(inst); diff --git a/src/shader_recompiler/frontend/translate/translate.h b/src/shader_recompiler/frontend/translate/translate.h index fe2a88f1..dcf2e853 100644 --- a/src/shader_recompiler/frontend/translate/translate.h +++ b/src/shader_recompiler/frontend/translate/translate.h @@ -97,7 +97,7 @@ public: void V_SUBREV_I32(const GcnInst& inst); void V_CMP_U32(ConditionOp op, bool is_signed, bool set_exec, const GcnInst& inst); void V_LSHRREV_B32(const GcnInst& inst); - void V_MUL_LO_I32(const GcnInst& inst); + void V_MUL_HI_U32(bool is_signed, const GcnInst& inst); void V_SAD_U32(const GcnInst& inst); void V_BFE_U32(const GcnInst& inst); void V_MAD_I32_I24(const GcnInst& inst); diff --git a/src/shader_recompiler/frontend/translate/vector_alu.cpp b/src/shader_recompiler/frontend/translate/vector_alu.cpp index 7a5bd49e..bb58383d 100644 --- a/src/shader_recompiler/frontend/translate/vector_alu.cpp +++ b/src/shader_recompiler/frontend/translate/vector_alu.cpp @@ -320,10 +320,11 @@ void Translator::V_LSHRREV_B32(const GcnInst& inst) { SetDst(inst.dst[0], ir.ShiftRightLogical(src1, ir.BitwiseAnd(src0, ir.Imm32(0x1F)))); } -void Translator::V_MUL_LO_I32(const GcnInst& inst) { +void Translator::V_MUL_HI_U32(bool is_signed, const GcnInst& inst) { const IR::U32 src0{GetSrc(inst.src[0])}; const IR::U32 src1{GetSrc(inst.src[1])}; - SetDst(inst.dst[0], ir.IMul(src0, src1)); + const IR::U32 hi{ir.CompositeExtract(ir.IMulExt(src0, src1, is_signed), 1)}; + SetDst(inst.dst[0], hi); } void Translator::V_SAD_U32(const GcnInst& inst) { diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index 276269af..d7e1d477 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -880,6 +880,10 @@ U32U64 IREmitter::ISub(const U32U64& a, const U32U64& b) { } } +IR::Value IREmitter::IMulExt(const U32& a, const U32& b, bool is_signed) { + return Inst(is_signed ? Opcode::SMulExt : Opcode::UMulExt, a, b); +} + U32 IREmitter::IMul(const U32& a, const U32& b) { return Inst(Opcode::IMul32, a, b); } diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index 3e951f82..917de458 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -146,6 +146,7 @@ public: [[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b); [[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b); + [[nodiscard]] IR::Value IMulExt(const U32& a, const U32& b, bool is_signed = false); [[nodiscard]] U32 IMul(const U32& a, const U32& b); [[nodiscard]] U32 IDiv(const U32& a, const U32& b, bool is_signed = false); [[nodiscard]] U32U64 INeg(const U32U64& value); diff --git a/src/shader_recompiler/ir/opcodes.inc b/src/shader_recompiler/ir/opcodes.inc index 71933096..18c0ce0b 100644 --- a/src/shader_recompiler/ir/opcodes.inc +++ b/src/shader_recompiler/ir/opcodes.inc @@ -197,6 +197,8 @@ OPCODE(IAdd64, U64, U64, OPCODE(ISub32, U32, U32, U32, ) OPCODE(ISub64, U64, U64, U64, ) OPCODE(IMul32, U32, U32, U32, ) +OPCODE(SMulExt, U32x2, U32, U32, ) +OPCODE(UMulExt, U32x2, U32, U32, ) OPCODE(SDiv32, U32, U32, U32, ) OPCODE(UDiv32, U32, U32, U32, ) OPCODE(INeg32, U32, U32, )