diff --git a/src/shader_recompiler/frontend/translate/scalar_alu.cpp b/src/shader_recompiler/frontend/translate/scalar_alu.cpp index 8931e8dde..5ac8a5d8d 100644 --- a/src/shader_recompiler/frontend/translate/scalar_alu.cpp +++ b/src/shader_recompiler/frontend/translate/scalar_alu.cpp @@ -311,33 +311,10 @@ void Translator::S_CSELECT_B32(const GcnInst& inst) { } void Translator::S_CSELECT_B64(const GcnInst& inst) { - const auto get_src = [&](const InstOperand& operand) { - switch (operand.field) { - case OperandField::VccLo: - return ir.GetVcc(); - case OperandField::ExecLo: - return ir.GetExec(); - case OperandField::ScalarGPR: - return ir.GetThreadBitScalarReg(IR::ScalarReg(operand.code)); - case OperandField::ConstZero: - return ir.Imm1(false); - default: - UNREACHABLE(); - } - }; - const IR::U1 src0{get_src(inst.src[0])}; - const IR::U1 src1{get_src(inst.src[1])}; + const IR::U1 src0{GetSrc1(inst.src[0])}; + const IR::U1 src1{GetSrc1(inst.src[1])}; const IR::U1 result{ir.Select(ir.GetScc(), src0, src1)}; - switch (inst.dst[0].field) { - case OperandField::VccLo: - ir.SetVcc(result); - break; - case OperandField::ScalarGPR: - ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[0].code), result); - break; - default: - UNREACHABLE(); - } + SetDst1(inst.dst[0], result); } void Translator::S_AND_B32(NegateMode negate, const GcnInst& inst) { @@ -355,30 +332,8 @@ void Translator::S_AND_B32(NegateMode negate, const GcnInst& inst) { } void Translator::S_AND_B64(NegateMode negate, const GcnInst& inst) { - const auto get_src = [&](const InstOperand& operand) { - switch (operand.field) { - case OperandField::VccLo: - return ir.GetVcc(); - case OperandField::ExecLo: - return ir.GetExec(); - case OperandField::ScalarGPR: - return ir.GetThreadBitScalarReg(IR::ScalarReg(operand.code)); - case OperandField::ConstZero: - return ir.Imm1(false); - case OperandField::SignedConstIntNeg: - ASSERT_MSG(-s32(operand.code) + SignedConstIntNegMin - 1 == -1, - "SignedConstIntNeg must be -1"); - return ir.Imm1(true); - case OperandField::LiteralConst: - ASSERT_MSG(operand.code == 0 || operand.code == std::numeric_limits::max(), - "Unsupported literal {:#x}", operand.code); - return ir.Imm1(operand.code & 1); - default: - UNREACHABLE(); - } - }; - const IR::U1 src0{get_src(inst.src[0])}; - IR::U1 src1{get_src(inst.src[1])}; + const IR::U1 src0{GetSrc1(inst.src[0])}; + IR::U1 src1{GetSrc1(inst.src[1])}; if (negate == NegateMode::Src1) { src1 = ir.LogicalNot(src1); } @@ -387,19 +342,7 @@ void Translator::S_AND_B64(NegateMode negate, const GcnInst& inst) { result = ir.LogicalNot(result); } ir.SetScc(result); - switch (inst.dst[0].field) { - case OperandField::VccLo: - ir.SetVcc(result); - break; - case OperandField::ScalarGPR: - ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[0].code), result); - break; - case OperandField::ExecLo: - ir.SetExec(result); - break; - default: - UNREACHABLE(); - } + SetDst1(inst.dst[0], result); } void Translator::S_OR_B32(const GcnInst& inst) { @@ -411,21 +354,8 @@ void Translator::S_OR_B32(const GcnInst& inst) { } void Translator::S_OR_B64(NegateMode negate, bool is_xor, const GcnInst& inst) { - const auto get_src = [&](const InstOperand& operand) { - switch (operand.field) { - case OperandField::ExecLo: - return ir.GetExec(); - case OperandField::VccLo: - return ir.GetVcc(); - case OperandField::ScalarGPR: - return ir.GetThreadBitScalarReg(IR::ScalarReg(operand.code)); - default: - UNREACHABLE(); - } - }; - - const IR::U1 src0{get_src(inst.src[0])}; - IR::U1 src1{get_src(inst.src[1])}; + const IR::U1 src0{GetSrc1(inst.src[0])}; + IR::U1 src1{GetSrc1(inst.src[1])}; if (negate == NegateMode::Src1) { src1 = ir.LogicalNot(src1); } @@ -434,16 +364,7 @@ void Translator::S_OR_B64(NegateMode negate, bool is_xor, const GcnInst& inst) { result = ir.LogicalNot(result); } ir.SetScc(result); - switch (inst.dst[0].field) { - case OperandField::VccLo: - ir.SetVcc(result); - break; - case OperandField::ScalarGPR: - ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[0].code), result); - break; - default: - UNREACHABLE(); - } + SetDst1(inst.dst[0], result); } void Translator::S_XOR_B32(const GcnInst& inst) { @@ -604,66 +525,14 @@ void Translator::S_MOV_B64(const GcnInst& inst) { ir.SetScalarReg(IR::ScalarReg(inst.dst[0].code + 1), ir.GetScalarReg(IR::ScalarReg(inst.src[0].code + 1))); } - const IR::U1 src = [&] { - switch (inst.src[0].field) { - case OperandField::VccLo: - return ir.GetVcc(); - case OperandField::ExecLo: - return ir.GetExec(); - case OperandField::ScalarGPR: - return ir.GetThreadBitScalarReg(IR::ScalarReg(inst.src[0].code)); - case OperandField::ConstZero: - return ir.Imm1(false); - default: - UNREACHABLE(); - } - }(); - switch (inst.dst[0].field) { - case OperandField::ScalarGPR: - ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[0].code), src); - break; - case OperandField::ExecLo: - ir.SetExec(src); - break; - case OperandField::VccLo: - ir.SetVcc(src); - break; - default: - UNREACHABLE(); - } + SetDst1(inst.dst[0], GetSrc1(inst.src[0])); } void Translator::S_NOT_B64(const GcnInst& inst) { - const auto get_src = [&](const InstOperand& operand) { - switch (operand.field) { - case OperandField::VccLo: - return ir.GetVcc(); - case OperandField::ExecLo: - return ir.GetExec(); - case OperandField::ScalarGPR: - return ir.GetThreadBitScalarReg(IR::ScalarReg(operand.code)); - case OperandField::ConstZero: - return ir.Imm1(false); - default: - UNREACHABLE(); - } - }; - const IR::U1 src0{get_src(inst.src[0])}; + const IR::U1 src0{GetSrc1(inst.src[0])}; const IR::U1 result = ir.LogicalNot(src0); ir.SetScc(result); - switch (inst.dst[0].field) { - case OperandField::VccLo: - ir.SetVcc(result); - break; - case OperandField::ScalarGPR: - ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[0].code), result); - break; - case OperandField::ExecLo: - ir.SetExec(result); - break; - default: - UNREACHABLE(); - } + SetDst1(inst.dst[0], result); } void Translator::S_BREV_B32(const GcnInst& inst) { @@ -689,21 +558,7 @@ void Translator::S_FF1_I32_B32(const GcnInst& inst) { } void Translator::S_FF1_I32_B64(const GcnInst& inst) { - const auto src = [&] { - switch (inst.src[0].field) { - case OperandField::ScalarGPR: - return ir.GetThreadBitScalarReg(IR::ScalarReg(inst.src[0].code)); - case OperandField::VccLo: - return ir.GetVcc(); - case OperandField::ExecLo: - return ir.GetExec(); - default: - UNREACHABLE_MSG("unhandled operand type {}", magic_enum::enum_name(inst.src[0].field)); - } - }(); - const IR::U32 result{ir.BallotFindLsb(ir.Ballot(src))}; - - SetDst(inst.dst[0], result); + SetDst(inst.dst[0], ir.BallotFindLsb(ir.Ballot(GetSrc1(inst.src[0])))); } void Translator::S_FLBIT_I32_B32(const GcnInst& inst) { @@ -740,29 +595,8 @@ void Translator::S_SAVEEXEC_B64(NegateMode negate, bool is_or, const GcnInst& in // However here we flatten it to 1-bit EXEC and 1-bit VCC. For the destination // SGPR we have a special IR opcode for SPGRs that act as thread masks. IR::U1 exec{ir.GetExec()}; - const IR::U1 src = [&] { - switch (inst.src[0].field) { - case OperandField::VccLo: - return ir.GetVcc(); - case OperandField::ScalarGPR: - return ir.GetThreadBitScalarReg(IR::ScalarReg(inst.src[0].code)); - case OperandField::ExecLo: - return ir.GetExec(); - default: - UNREACHABLE(); - } - }(); - - switch (inst.dst[0].field) { - case OperandField::ScalarGPR: - ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[0].code), exec); - break; - case OperandField::VccLo: - ir.SetVcc(exec); - break; - default: - UNREACHABLE(); - } + const IR::U1 src{GetSrc1(inst.src[0])}; + SetDst1(inst.dst[0], exec); // Update EXEC. if (negate == NegateMode::Src1) { diff --git a/src/shader_recompiler/frontend/translate/translate.cpp b/src/shader_recompiler/frontend/translate/translate.cpp index de3822296..3a97bcef7 100644 --- a/src/shader_recompiler/frontend/translate/translate.cpp +++ b/src/shader_recompiler/frontend/translate/translate.cpp @@ -255,6 +255,29 @@ IR::VectorReg Translator::GetScratchVgpr(u32 offset) { return it->second; }; +IR::U1 Translator::GetSrc1(const InstOperand& operand) { + switch (operand.field) { + case OperandField::VccLo: + return ir.GetVcc(); + case OperandField::ExecLo: + return ir.GetExec(); + case OperandField::ScalarGPR: + return ir.GetThreadBitScalarReg(IR::ScalarReg(operand.code)); + case OperandField::ConstZero: + return ir.Imm1(false); + case OperandField::SignedConstIntNeg: + ASSERT_MSG(-s32(operand.code) + SignedConstIntNegMin - 1 == -1, + "SignedConstIntNeg must be -1"); + return ir.Imm1(true); + case OperandField::LiteralConst: + ASSERT_MSG(operand.code == 0 || operand.code == std::numeric_limits::max(), + "Unsupported literal {:#x}", operand.code); + return ir.Imm1(operand.code & 1); + default: + UNREACHABLE_MSG("Unknown field {}", u32(operand.field)); + } +} + template T Translator::GetSrc(const InstOperand& operand) { constexpr bool is_float = std::is_same_v; @@ -477,6 +500,22 @@ T Translator::GetSrc64(const InstOperand& operand) { template IR::U64 Translator::GetSrc64(const InstOperand&); template IR::F64 Translator::GetSrc64(const InstOperand&); +void Translator::SetDst1(const InstOperand& operand, const IR::U1& value) { + switch (operand.field) { + case OperandField::VccLo: + ir.SetVcc(value); + break; + case OperandField::ScalarGPR: + ir.SetThreadBitScalarReg(IR::ScalarReg(operand.code), value); + break; + case OperandField::ExecLo: + ir.SetExec(value); + break; + default: + UNREACHABLE_MSG("Unknown field {}", u32(operand.field)); + } +} + void Translator::SetDst(const InstOperand& operand, const IR::U32F32& value) { IR::U32F32 result = value; if (value.Type() == IR::Type::F32) { diff --git a/src/shader_recompiler/frontend/translate/translate.h b/src/shader_recompiler/frontend/translate/translate.h index 5ee75e336..c4180d843 100644 --- a/src/shader_recompiler/frontend/translate/translate.h +++ b/src/shader_recompiler/frontend/translate/translate.h @@ -307,10 +307,12 @@ public: void IMAGE_GET_LOD(const GcnInst& inst); private: + IR::U1 GetSrc1(const InstOperand& operand); template [[nodiscard]] T GetSrc(const InstOperand& operand); template [[nodiscard]] T GetSrc64(const InstOperand& operand); + void SetDst1(const InstOperand& operand, const IR::U1& value); void SetDst(const InstOperand& operand, const IR::U32F32& value); void SetDst64(const InstOperand& operand, const IR::U64F64& value_raw); diff --git a/src/shader_recompiler/frontend/translate/vector_alu.cpp b/src/shader_recompiler/frontend/translate/vector_alu.cpp index 23236b702..4c35dc435 100644 --- a/src/shader_recompiler/frontend/translate/vector_alu.cpp +++ b/src/shader_recompiler/frontend/translate/vector_alu.cpp @@ -1056,17 +1056,7 @@ void Translator::V_CMP_F32(ConditionOp op, bool set_exec, const GcnInst& inst) { if (set_exec) { ir.SetExec(result); } - - switch (inst.dst[1].field) { - case OperandField::VccLo: - ir.SetVcc(result); - break; - case OperandField::ScalarGPR: - ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[1].code), result); - break; - default: - UNREACHABLE(); - } + SetDst1(inst.dst[1], result); } void Translator::V_CMP_F64(ConditionOp op, bool set_exec, const GcnInst& inst) { @@ -1097,17 +1087,7 @@ void Translator::V_CMP_F64(ConditionOp op, bool set_exec, const GcnInst& inst) { if (set_exec) { ir.SetExec(result); } - - switch (inst.dst[1].field) { - case OperandField::VccLo: - ir.SetVcc(result); - break; - case OperandField::ScalarGPR: - ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[1].code), result); - break; - default: - UNREACHABLE(); - } + SetDst1(inst.dst[1], result); } void Translator::V_CMP_U32(ConditionOp op, bool is_signed, bool set_exec, const GcnInst& inst) { @@ -1138,14 +1118,7 @@ void Translator::V_CMP_U32(ConditionOp op, bool is_signed, bool set_exec, const if (set_exec) { ir.SetExec(result); } - switch (inst.dst[1].field) { - case OperandField::VccLo: - return ir.SetVcc(result); - case OperandField::ScalarGPR: - return ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[0].code), result); - default: - UNREACHABLE(); - } + SetDst1(inst.dst[1], result); } void Translator::V_CMP_U64(ConditionOp op, bool is_signed, bool set_exec, const GcnInst& inst) { @@ -1187,15 +1160,7 @@ void Translator::V_CMP_U64(ConditionOp op, bool is_signed, bool set_exec, const if (set_exec) { UNREACHABLE_MSG("Exec setting for V_CMP_U64 is not supported"); } - - switch (inst.dst[1].field) { - case OperandField::VccLo: - return ir.SetVcc(result); - case OperandField::ScalarGPR: - return ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[1].code), result); - default: - UNREACHABLE(); - } + SetDst1(inst.dst[1], result); } void Translator::V_CMP_CLASS_F32(const GcnInst& inst) { @@ -1217,15 +1182,7 @@ void Translator::V_CMP_CLASS_F32(const GcnInst& inst) { // We don't know the type yet, delay its resolution. value = ir.FPCmpClass32(src0, src1); } - - switch (inst.dst[1].field) { - case OperandField::VccLo: - return ir.SetVcc(value); - case OperandField::ScalarGPR: - return ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[1].code), value); - default: - UNREACHABLE(); - } + SetDst1(inst.dst[1], value); } // VOP3a @@ -1527,13 +1484,7 @@ void Translator::V_MAD_U64_U32(const GcnInst& inst) { IR::U32 Translator::GetCarryIn(const GcnInst& inst) { IR::U1 carry; if (inst.src_count == 3) { // VOP3 - if (inst.src[2].field == OperandField::VccLo) { - carry = ir.GetVcc(); - } else if (inst.src[2].field == OperandField::ScalarGPR) { - carry = ir.GetThreadBitScalarReg(IR::ScalarReg(inst.src[2].code)); - } else { - UNREACHABLE(); - } + carry = GetSrc1(inst.src[2]); } else { // VOP2 carry = ir.GetVcc(); } @@ -1543,13 +1494,7 @@ IR::U32 Translator::GetCarryIn(const GcnInst& inst) { void Translator::SetCarryOut(const GcnInst& inst, const IR::U1& carry) { if (inst.dst_count == 2) { // VOP3 - if (inst.dst[1].field == OperandField::VccLo) { - ir.SetVcc(carry); - } else if (inst.dst[1].field == OperandField::ScalarGPR) { - ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[1].code), carry); - } else { - UNREACHABLE(); - } + SetDst1(inst.dst[1], carry); } else { // VOP2 ir.SetVcc(carry); }