diff --git a/src/shader_recompiler/frontend/decode.cpp b/src/shader_recompiler/frontend/decode.cpp index 806ccce6e..4f71e1caf 100644 --- a/src/shader_recompiler/frontend/decode.cpp +++ b/src/shader_recompiler/frontend/decode.cpp @@ -133,6 +133,7 @@ GcnInst GcnDecodeContext::decodeInstruction(GcnCodeSlice& code) { if (encodingLen == sizeof(u32)) { decodeLiteralConstant(encoding, code); decodeSubDwordAddressing(encoding, code); + decodeDataParallelPrimitive(encoding, code); } repairOperandType(); @@ -505,6 +506,41 @@ void GcnDecodeContext::decodeSubDwordAddressing(InstEncoding encoding, GcnCodeSl } } +void GcnDecodeContext::decodeDataParallelPrimitive(InstEncoding encoding, GcnCodeSlice& code) { + // Find if the instruction contains DPP + if (m_instruction.src[0].field == OperandField::Dpp) { + m_instruction.src[0].code = code.readu32(); + m_instruction.length += sizeof(u32); + + Dpp dpp = *reinterpret_cast(&m_instruction.src[0].code); + + m_instruction.src[0].field = OperandField::VectorGPR; + m_instruction.src[0].code = dpp.src0; + + if (dpp.src0_abs) { + m_instruction.src[0].input_modifier.abs = true; + } + if (dpp.src0_neg) { + m_instruction.src[0].input_modifier.neg = true; + } + if (dpp.src1_abs) { + m_instruction.src[1].input_modifier.abs = true; + } + if (dpp.src1_neg) { + m_instruction.src[1].input_modifier.neg = true; + } + + auto op = dpp.GetOperation(); + LOG_ERROR( + Render_Recompiler, + "unhandled DPP operation: {} ({:#x}), value {}, bc {}, row_mask {:#b}, bank_mask {:#b}", + magic_enum::enum_name(op.op), u32(op.op), op.value, bool(dpp.bc), u8(dpp.row_mask), + u8(dpp.bank_mask)); + + m_instruction.src[0].dpp = op; + } +} + void GcnDecodeContext::decodeInstructionSOP1(u32 hexInstruction) { u32 ssrc0 = bit::extract(hexInstruction, 7, 0); u32 op = bit::extract(hexInstruction, 15, 8); diff --git a/src/shader_recompiler/frontend/decode.h b/src/shader_recompiler/frontend/decode.h index dfcf851bf..ee973dd18 100644 --- a/src/shader_recompiler/frontend/decode.h +++ b/src/shader_recompiler/frontend/decode.h @@ -71,6 +71,7 @@ private: void decodeInstruction64(InstEncoding encoding, GcnCodeSlice& code); void decodeLiteralConstant(InstEncoding encoding, GcnCodeSlice& code); void decodeSubDwordAddressing(InstEncoding encoding, GcnCodeSlice& code); + void decodeDataParallelPrimitive(InstEncoding encoding, GcnCodeSlice& code); // 32 bits encodings void decodeInstructionSOP1(uint32_t hexInstruction); diff --git a/src/shader_recompiler/frontend/instruction.h b/src/shader_recompiler/frontend/instruction.h index cb02445dc..8bb4f275f 100644 --- a/src/shader_recompiler/frontend/instruction.h +++ b/src/shader_recompiler/frontend/instruction.h @@ -60,6 +60,23 @@ enum class SdwaDstUnused : u32 { Invalid = 3, }; +enum class DppCtrl : u16 { + DppQuadPerm = 0, + DppRowShl = 0x101, + DppRowShr = 0x111, + DppRowRor = 0x121, + DppRowMirror = 0x140, + DppRowHalfMirror = 0x141, +}; + +struct DppOperation { + DppCtrl op; + u16 value; + bool bc; + u8 row_mask; + u8 bank_mask; +}; + struct InstOperand { OperandField field = OperandField::Undefined; ScalarType type = ScalarType::Undefined; @@ -69,6 +86,7 @@ struct InstOperand { OperandSelection op_sel = {}; SdwaDstUnused sdwa_dst = SdwaDstUnused::Invalid; SdwaSelector sdwa_sel = SdwaSelector::Invalid; + std::optional dpp = {}; u32 code = 0xFFFFFFFF; }; @@ -286,6 +304,39 @@ union Sdwa { SdwaVop12 vop12; }; +struct Dpp { + u32 src0 : 8; + u32 dpp_ctrl : 9; + u32 : 1; + u32 fi : 1; + u32 bc : 1; + u32 src0_neg : 1; + u32 src0_abs : 1; + u32 src1_neg : 1; + u32 src1_abs : 1; + u32 bank_mask : 4; + u32 row_mask : 4; + + DppOperation GetOperation() const { + if (dpp_ctrl >= u32(DppCtrl::DppQuadPerm) && dpp_ctrl < 0x100) { + return {DppCtrl::DppQuadPerm, u16(dpp_ctrl & 0xFF), bool(bc), u8(row_mask), + u8(bank_mask)}; + } else if (dpp_ctrl >= u32(DppCtrl::DppRowShl) && dpp_ctrl < 0x110) { + return {DppCtrl::DppRowShl, u16(dpp_ctrl & 0xF), bool(bc), u8(row_mask), u8(bank_mask)}; + } else if (dpp_ctrl >= u32(DppCtrl::DppRowShr) && dpp_ctrl < 0x120) { + return {DppCtrl::DppRowShr, u16(dpp_ctrl & 0xF), bool(bc), u8(row_mask), u8(bank_mask)}; + } else if (dpp_ctrl >= u32(DppCtrl::DppRowRor) && dpp_ctrl < 0x130) { + return {DppCtrl::DppRowRor, u16(dpp_ctrl & 0xF), bool(bc), u8(row_mask), u8(bank_mask)}; + } else if (dpp_ctrl == u32(DppCtrl::DppRowMirror)) { + return {DppCtrl::DppRowMirror, 0, bool(bc), u8(row_mask), u8(bank_mask)}; + } else if (dpp_ctrl == u32(DppCtrl::DppRowHalfMirror)) { + return {DppCtrl::DppRowHalfMirror, 0, bool(bc), u8(row_mask), u8(bank_mask)}; + } else { + UNREACHABLE_MSG("malformed dpp_ctrl"); + } + } +}; + struct GcnInst { Opcode opcode; InstEncoding encoding;