diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 55a76da99..ad09dc543 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -309,6 +309,7 @@ Id EmitBitwiseNot32(EmitContext& ctx, Id value); Id EmitFindSMsb32(EmitContext& ctx, Id value); Id EmitFindUMsb32(EmitContext& ctx, Id value); Id EmitFindILsb32(EmitContext& ctx, Id value); +Id EmitFindILsb64(EmitContext& ctx, Id value); Id EmitSMin32(EmitContext& ctx, Id a, Id b); Id EmitUMin32(EmitContext& ctx, Id a, Id b); Id EmitSMax32(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 323cf9b2f..117a8d3a2 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp @@ -221,6 +221,10 @@ Id EmitFindILsb32(EmitContext& ctx, Id value) { return ctx.OpFindILsb(ctx.U32[1], value); } +Id EmitFindILsb64(EmitContext& ctx, Id value) { + return ctx.OpFindILsb(ctx.U64, value); +} + Id EmitSMin32(EmitContext& ctx, Id a, Id b) { return ctx.OpSMin(ctx.U32[1], a, b); } diff --git a/src/shader_recompiler/frontend/translate/scalar_alu.cpp b/src/shader_recompiler/frontend/translate/scalar_alu.cpp index 181cad62e..5c6164d6c 100644 --- a/src/shader_recompiler/frontend/translate/scalar_alu.cpp +++ b/src/shader_recompiler/frontend/translate/scalar_alu.cpp @@ -104,6 +104,8 @@ void Translator::EmitScalarAlu(const GcnInst& inst) { return S_BCNT1_I32_B64(inst); case Opcode::S_FF1_I32_B32: return S_FF1_I32_B32(inst); + case Opcode::S_FF1_I32_B64: + return S_FF1_I32_B64(inst); case Opcode::S_AND_SAVEEXEC_B64: return S_SAVEEXEC_B64(NegateMode::None, false, inst); case Opcode::S_ORN2_SAVEEXEC_B64: @@ -599,6 +601,13 @@ void Translator::S_FF1_I32_B32(const GcnInst& inst) { SetDst(inst.dst[0], result); } +void Translator::S_FF1_I32_B64(const GcnInst& inst) { + const IR::U64 src0{GetSrc64(inst.src[0])}; + const IR::U32 result{ + ir.Select(ir.IEqual(src0, ir.Imm64(u64(0))), ir.Imm64(s64(-1)), ir.FindILsb(src0))}; + SetDst(inst.dst[0], result); +} + void Translator::S_SAVEEXEC_B64(NegateMode negate, bool is_or, const GcnInst& inst) { // This instruction normally operates on 64-bit data (EXEC, VCC, SGPRs) // However here we flatten it to 1-bit EXEC and 1-bit VCC. For the destination diff --git a/src/shader_recompiler/frontend/translate/translate.h b/src/shader_recompiler/frontend/translate/translate.h index 52ea31d66..e8584ec2f 100644 --- a/src/shader_recompiler/frontend/translate/translate.h +++ b/src/shader_recompiler/frontend/translate/translate.h @@ -113,6 +113,7 @@ public: void S_BCNT1_I32_B32(const GcnInst& inst); void S_BCNT1_I32_B64(const GcnInst& inst); void S_FF1_I32_B32(const GcnInst& inst); + void S_FF1_I32_B64(const GcnInst& inst); void S_GETPC_B64(u32 pc, const GcnInst& inst); void S_SAVEEXEC_B64(NegateMode negate, bool is_or, const GcnInst& inst); void S_ABS_I32(const GcnInst& inst); diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index 044f2aa01..9bb3f739c 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -1296,8 +1296,15 @@ U32 IREmitter::FindUMsb(const U32& value) { return Inst(Opcode::FindUMsb32, value); } -U32 IREmitter::FindILsb(const U32& value) { - return Inst(Opcode::FindILsb32, value); +U32 IREmitter::FindILsb(const U32U64& value) { + switch (value.Type()) { + case Type::U32: + return Inst(Opcode::FindILsb32, value); + case Type::U64: + return Inst(Opcode::FindILsb64, value); + default: + ThrowInvalidType(value.Type()); + } } U32 IREmitter::SMin(const U32& a, const U32& b) { diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index 35a60413e..4679a0133 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -234,7 +234,7 @@ public: [[nodiscard]] U32 FindSMsb(const U32& value); [[nodiscard]] U32 FindUMsb(const U32& value); - [[nodiscard]] U32 FindILsb(const U32& value); + [[nodiscard]] U32 FindILsb(const U32U64& value); [[nodiscard]] U32 SMin(const U32& a, const U32& b); [[nodiscard]] U32 UMin(const U32& a, const U32& b); [[nodiscard]] U32 IMin(const U32& a, const U32& b, bool is_signed); diff --git a/src/shader_recompiler/ir/opcodes.inc b/src/shader_recompiler/ir/opcodes.inc index 769b76ef4..e7015853a 100644 --- a/src/shader_recompiler/ir/opcodes.inc +++ b/src/shader_recompiler/ir/opcodes.inc @@ -290,6 +290,7 @@ OPCODE(BitwiseNot32, U32, U32, OPCODE(FindSMsb32, U32, U32, ) OPCODE(FindUMsb32, U32, U32, ) OPCODE(FindILsb32, U32, U32, ) +OPCODE(FindILsb64, U32, U64, ) OPCODE(SMin32, U32, U32, U32, ) OPCODE(UMin32, U32, U32, U32, ) OPCODE(SMax32, U32, U32, U32, )