diff --git a/src/shader_recompiler/frontend/translate/scalar_alu.cpp b/src/shader_recompiler/frontend/translate/scalar_alu.cpp index 7914726f..da74f901 100644 --- a/src/shader_recompiler/frontend/translate/scalar_alu.cpp +++ b/src/shader_recompiler/frontend/translate/scalar_alu.cpp @@ -6,98 +6,150 @@ namespace Shader::Gcn { void Translator::EmitScalarAlu(const GcnInst& inst) { + switch (inst.encoding) { + case InstEncoding::SOPC: { + EmitSOPC(inst); + break; + } + case InstEncoding::SOPK: { + EmitSOPK(inst); + break; + } + default: + switch (inst.opcode) { + case Opcode::S_MOV_B32: + return S_MOV(inst); + case Opcode::S_MUL_I32: + return S_MUL_I32(inst); + case Opcode::S_AND_SAVEEXEC_B64: + return S_AND_SAVEEXEC_B64(inst); + case Opcode::S_MOV_B64: + return S_MOV_B64(inst); + case Opcode::S_OR_B64: + return S_OR_B64(NegateMode::None, false, inst); + case Opcode::S_NOR_B64: + return S_OR_B64(NegateMode::Result, false, inst); + case Opcode::S_XOR_B64: + return S_OR_B64(NegateMode::None, true, inst); + case Opcode::S_ORN2_B64: + return S_OR_B64(NegateMode::Src1, false, inst); + case Opcode::S_AND_B64: + return S_AND_B64(NegateMode::None, inst); + case Opcode::S_NAND_B64: + return S_AND_B64(NegateMode::Result, inst); + case Opcode::S_ANDN2_B64: + return S_AND_B64(NegateMode::Src1, inst); + case Opcode::S_NOT_B64: + return S_NOT_B64(inst); + case Opcode::S_ADD_I32: + return S_ADD_I32(inst); + case Opcode::S_AND_B32: + return S_AND_B32(inst); + case Opcode::S_ASHR_I32: + return S_ASHR_I32(inst); + case Opcode::S_OR_B32: + return S_OR_B32(inst); + case Opcode::S_LSHL_B32: + return S_LSHL_B32(inst); + case Opcode::S_LSHR_B32: + return S_LSHR_B32(inst); + case Opcode::S_CSELECT_B32: + return S_CSELECT_B32(inst); + case Opcode::S_CSELECT_B64: + return S_CSELECT_B64(inst); + case Opcode::S_BFE_U32: + return S_BFE_U32(inst); + case Opcode::S_BFM_B32: + return S_BFM_B32(inst); + case Opcode::S_BREV_B32: + return S_BREV_B32(inst); + case Opcode::S_ADD_U32: + return S_ADD_U32(inst); + case Opcode::S_ADDC_U32: + return S_ADDC_U32(inst); + case Opcode::S_SUB_U32: + case Opcode::S_SUB_I32: + return S_SUB_U32(inst); + case Opcode::S_MIN_U32: + return S_MIN_U32(inst); + case Opcode::S_MAX_U32: + return S_MAX_U32(inst); + case Opcode::S_WQM_B64: + break; + default: + LogMissingOpcode(inst); + } + break; + } +} + +void Translator::EmitSOPC(const GcnInst& inst) { switch (inst.opcode) { - case Opcode::S_MOVK_I32: - return S_MOVK(inst); - case Opcode::S_MOV_B32: - return S_MOV(inst); - case Opcode::S_MUL_I32: - return S_MUL_I32(inst); - case Opcode::S_AND_SAVEEXEC_B64: - return S_AND_SAVEEXEC_B64(inst); - case Opcode::S_MOV_B64: - return S_MOV_B64(inst); - case Opcode::S_CMP_LT_U32: - return S_CMP(ConditionOp::LT, false, inst); - case Opcode::S_CMP_LE_U32: - return S_CMP(ConditionOp::LE, false, inst); - case Opcode::S_CMP_LG_U32: - return S_CMP(ConditionOp::LG, false, inst); - case Opcode::S_CMP_LT_I32: - return S_CMP(ConditionOp::LT, true, inst); + case Opcode::S_CMP_EQ_I32: + return S_CMP(ConditionOp::EQ, true, inst); case Opcode::S_CMP_LG_I32: return S_CMP(ConditionOp::LG, true, inst); case Opcode::S_CMP_GT_I32: return S_CMP(ConditionOp::GT, true, inst); - case Opcode::S_CMP_LE_I32: - return S_CMP(ConditionOp::LE, true, inst); case Opcode::S_CMP_GE_I32: return S_CMP(ConditionOp::GE, true, inst); - case Opcode::S_CMP_EQ_I32: - return S_CMP(ConditionOp::EQ, true, inst); + case Opcode::S_CMP_LT_I32: + return S_CMP(ConditionOp::LT, true, inst); + case Opcode::S_CMP_LE_I32: + return S_CMP(ConditionOp::LE, true, inst); + case Opcode::S_CMP_EQ_U32: return S_CMP(ConditionOp::EQ, false, inst); - case Opcode::S_CMP_GE_U32: - return S_CMP(ConditionOp::GE, false, inst); + case Opcode::S_CMP_LG_U32: + return S_CMP(ConditionOp::LG, false, inst); case Opcode::S_CMP_GT_U32: return S_CMP(ConditionOp::GT, false, inst); - case Opcode::S_OR_B64: - return S_OR_B64(NegateMode::None, false, inst); - case Opcode::S_NOR_B64: - return S_OR_B64(NegateMode::Result, false, inst); - case Opcode::S_XOR_B64: - return S_OR_B64(NegateMode::None, true, inst); - case Opcode::S_ORN2_B64: - return S_OR_B64(NegateMode::Src1, false, inst); - case Opcode::S_AND_B64: - return S_AND_B64(NegateMode::None, inst); - case Opcode::S_NAND_B64: - return S_AND_B64(NegateMode::Result, inst); - case Opcode::S_ANDN2_B64: - return S_AND_B64(NegateMode::Src1, inst); - case Opcode::S_NOT_B64: - return S_NOT_B64(inst); - case Opcode::S_ADD_I32: - return S_ADD_I32(inst); - case Opcode::S_AND_B32: - return S_AND_B32(inst); - case Opcode::S_ASHR_I32: - return S_ASHR_I32(inst); - case Opcode::S_OR_B32: - return S_OR_B32(inst); - case Opcode::S_LSHL_B32: - return S_LSHL_B32(inst); - case Opcode::S_LSHR_B32: - return S_LSHR_B32(inst); - case Opcode::S_CSELECT_B32: - return S_CSELECT_B32(inst); - case Opcode::S_CSELECT_B64: - return S_CSELECT_B64(inst); - case Opcode::S_BFE_U32: - return S_BFE_U32(inst); - case Opcode::S_BFM_B32: - return S_BFM_B32(inst); - case Opcode::S_BREV_B32: - return S_BREV_B32(inst); - case Opcode::S_ADD_U32: - return S_ADD_U32(inst); - case Opcode::S_ADDC_U32: - return S_ADDC_U32(inst); + case Opcode::S_CMP_GE_U32: + return S_CMP(ConditionOp::GE, false, inst); + case Opcode::S_CMP_LT_U32: + return S_CMP(ConditionOp::LT, false, inst); + case Opcode::S_CMP_LE_U32: + return S_CMP(ConditionOp::LE, false, inst); + default: + LogMissingOpcode(inst); + } +} + +void Translator::EmitSOPK(const GcnInst& inst) { + switch (inst.opcode) { + case Opcode::S_MOVK_I32: + return S_MOVK(inst); + + case Opcode::S_CMPK_EQ_I32: + return S_CMPK(ConditionOp::EQ, true, inst); + case Opcode::S_CMPK_LG_I32: + return S_CMPK(ConditionOp::LG, true, inst); + case Opcode::S_CMPK_GT_I32: + return S_CMPK(ConditionOp::GT, true, inst); + case Opcode::S_CMPK_GE_I32: + return S_CMPK(ConditionOp::GE, true, inst); + case Opcode::S_CMPK_LT_I32: + return S_CMPK(ConditionOp::LT, true, inst); + case Opcode::S_CMPK_LE_I32: + return S_CMPK(ConditionOp::LE, true, inst); + + case Opcode::S_CMPK_EQ_U32: + return S_CMPK(ConditionOp::EQ, false, inst); + case Opcode::S_CMPK_LG_U32: + return S_CMPK(ConditionOp::LG, false, inst); + case Opcode::S_CMPK_GT_U32: + return S_CMPK(ConditionOp::GT, false, inst); + case Opcode::S_CMPK_GE_U32: + return S_CMPK(ConditionOp::GE, false, inst); + case Opcode::S_CMPK_LT_U32: + return S_CMPK(ConditionOp::LT, false, inst); + case Opcode::S_CMPK_LE_U32: + return S_CMPK(ConditionOp::LE, false, inst); + case Opcode::S_ADDK_I32: return S_ADDK_I32(inst); case Opcode::S_MULK_I32: return S_MULK_I32(inst); - case Opcode::S_SUB_U32: - case Opcode::S_SUB_I32: - return S_SUB_U32(inst); - case Opcode::S_MIN_U32: - return S_MIN_U32(inst); - case Opcode::S_MAX_U32: - return S_MAX_U32(inst); - case Opcode::S_WQM_B64: - break; - case Opcode::S_CMPK_EQ_U32: - return S_CMPK_EQ_U32(inst); default: LogMissingOpcode(inst); } @@ -154,6 +206,31 @@ void Translator::S_CMP(ConditionOp cond, bool is_signed, const GcnInst& inst) { ir.SetScc(result); } +void Translator::S_CMPK(ConditionOp cond, bool is_signed, const GcnInst& inst) { + const s32 simm16 = inst.control.sopk.simm; + const IR::U32 lhs = GetSrc(inst.dst[0]); + const IR::U32 rhs = ir.Imm32(simm16); + const IR::U1 result = [&] { + switch (cond) { + case ConditionOp::EQ: + return ir.IEqual(lhs, rhs); + case ConditionOp::LG: + return ir.INotEqual(lhs, rhs); + case ConditionOp::GT: + return ir.IGreaterThan(lhs, rhs, is_signed); + case ConditionOp::GE: + return ir.IGreaterThanEqual(lhs, rhs, is_signed); + case ConditionOp::LT: + return ir.ILessThan(lhs, rhs, is_signed); + case ConditionOp::LE: + return ir.ILessThanEqual(lhs, rhs, is_signed); + default: + UNREACHABLE(); + } + }(); + ir.SetScc(result); +} + void Translator::S_AND_SAVEEXEC_B64(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 @@ -470,11 +547,4 @@ void Translator::S_MIN_U32(const GcnInst& inst) { ir.SetScc(ir.IEqual(result, src0)); } -void Translator::S_CMPK_EQ_U32(const GcnInst& inst) { - const s32 simm16 = inst.control.sopk.simm; - const IR::U32 src0{GetSrc(inst.dst[0])}; - const IR::U32 src1{ir.Imm32(simm16)}; - ir.SetScc(ir.IEqual(src0, src1)); -} - } // namespace Shader::Gcn diff --git a/src/shader_recompiler/frontend/translate/translate.h b/src/shader_recompiler/frontend/translate/translate.h index cde9e58e..8cbf7357 100644 --- a/src/shader_recompiler/frontend/translate/translate.h +++ b/src/shader_recompiler/frontend/translate/translate.h @@ -69,6 +69,10 @@ public: void EmitScalarAlu(const GcnInst& inst); void EmitVectorAlu(const GcnInst& inst); + // Instruction encodings + void EmitSOPC(const GcnInst& inst); + void EmitSOPK(const GcnInst& inst); + // Scalar ALU void S_MOVK(const GcnInst& inst); void S_MOV(const GcnInst& inst); @@ -98,7 +102,7 @@ public: void S_ADDK_I32(const GcnInst& inst); void S_MAX_U32(const GcnInst& inst); void S_MIN_U32(const GcnInst& inst); - void S_CMPK_EQ_U32(const GcnInst& inst); + void S_CMPK(ConditionOp cond, bool is_signed, const GcnInst& inst); // Scalar Memory void S_LOAD_DWORD(int num_dwords, const GcnInst& inst);