diff --git a/src/shader_recompiler/frontend/translate/scalar_alu.cpp b/src/shader_recompiler/frontend/translate/scalar_alu.cpp index 1e627d95..de8b9da8 100644 --- a/src/shader_recompiler/frontend/translate/scalar_alu.cpp +++ b/src/shader_recompiler/frontend/translate/scalar_alu.cpp @@ -132,6 +132,16 @@ void Translator::EmitSOPC(const GcnInst& inst) { return S_CMP(ConditionOp::LT, false, inst); case Opcode::S_CMP_LE_U32: return S_CMP(ConditionOp::LE, false, inst); + + case Opcode::S_BITCMP0_B32: + return S_BITCMP(false, 32, inst); + case Opcode::S_BITCMP1_B32: + return S_BITCMP(true, 32, inst); + case Opcode::S_BITCMP0_B64: + return S_BITCMP(false, 64, inst); + case Opcode::S_BITCMP1_B64: + return S_BITCMP(true, 64, inst); + default: LogMissingOpcode(inst); } @@ -615,4 +625,33 @@ void Translator::S_CMP(ConditionOp cond, bool is_signed, const GcnInst& inst) { ir.SetScc(result); } +void Translator::S_BITCMP(bool compare_mode, u32 bits, const GcnInst& inst) { + const IR::U1 result = [&] { + const IR::U32 src0 = GetSrc(inst.src[0]); + const IR::U32 src1 = GetSrc(inst.src[1]); + + IR::U32 mask; + switch (bits) { + case 32: + mask = ir.Imm32(0x1f); + break; + case 64: + mask = ir.Imm32(0x3f); + break; + default: + UNREACHABLE(); + } + + const IR::U32 bitpos{ir.BitwiseAnd(src1, mask)}; + const IR::U32 bittest{ir.BitwiseAnd(ir.ShiftRightLogical(src0, bitpos), ir.Imm32(1))}; + + if (!compare_mode) { + return ir.IEqual(bittest, ir.Imm32(0)); + } else { + return ir.IEqual(bittest, ir.Imm32(1)); + } + }(); + ir.SetScc(result); +} + } // namespace Shader::Gcn diff --git a/src/shader_recompiler/frontend/translate/translate.cpp b/src/shader_recompiler/frontend/translate/translate.cpp index ccce31a2..005c4a7f 100644 --- a/src/shader_recompiler/frontend/translate/translate.cpp +++ b/src/shader_recompiler/frontend/translate/translate.cpp @@ -174,6 +174,13 @@ T Translator::GetSrc(const InstOperand& operand) { value = ir.GetM0(); } break; + case OperandField::Scc: + if constexpr (is_float) { + UNREACHABLE(); + } else { + value = ir.BitCast(ir.GetScc()); + } + break; default: UNREACHABLE(); } diff --git a/src/shader_recompiler/frontend/translate/translate.h b/src/shader_recompiler/frontend/translate/translate.h index 79bc33f0..9fb441f3 100644 --- a/src/shader_recompiler/frontend/translate/translate.h +++ b/src/shader_recompiler/frontend/translate/translate.h @@ -114,6 +114,7 @@ public: // SOPC void S_CMP(ConditionOp cond, bool is_signed, const GcnInst& inst); + void S_BITCMP(bool compare_mode, u32 bits, const GcnInst& inst); // SOPP void S_BARRIER(); diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index cfd044f9..73b33432 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -59,6 +59,11 @@ F64 IREmitter::Imm64(f64 value) const { return F64{Value{value}}; } +template <> +IR::U32 IREmitter::BitCast(const IR::U1& value) { + return IR::U32{Select(value, Imm32(1), Imm32(0))}; +} + template <> IR::U32 IREmitter::BitCast(const IR::F32& value) { return Inst(Opcode::BitCastU32F32, value);