Merge pull request #1279 from FernandoS27/csetp
shader_decompiler: Implemented (Partialy) Control Codes and CSETP
This commit is contained in:
		| @@ -240,6 +240,41 @@ enum class FlowCondition : u64 { | ||||
|     Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for? | ||||
| }; | ||||
|  | ||||
| enum class ControlCode : u64 { | ||||
|     F = 0, | ||||
|     LT = 1, | ||||
|     EQ = 2, | ||||
|     LE = 3, | ||||
|     GT = 4, | ||||
|     NE = 5, | ||||
|     GE = 6, | ||||
|     Num = 7, | ||||
|     Nan = 8, | ||||
|     LTU = 9, | ||||
|     EQU = 10, | ||||
|     LEU = 11, | ||||
|     GTU = 12, | ||||
|     NEU = 13, | ||||
|     GEU = 14, | ||||
|     // | ||||
|     OFF = 16, | ||||
|     LO = 17, | ||||
|     SFF = 18, | ||||
|     LS = 19, | ||||
|     HI = 20, | ||||
|     SFT = 21, | ||||
|     HS = 22, | ||||
|     OFT = 23, | ||||
|     CSM_TA = 24, | ||||
|     CSM_TR = 25, | ||||
|     CSM_MX = 26, | ||||
|     FCSM_TA = 27, | ||||
|     FCSM_TR = 28, | ||||
|     FCSM_MX = 29, | ||||
|     RLE = 30, | ||||
|     RGT = 31, | ||||
| }; | ||||
|  | ||||
| enum class PredicateResultMode : u64 { | ||||
|     None = 0x0, | ||||
|     NotZero = 0x3, | ||||
| @@ -554,6 +589,15 @@ union Instruction { | ||||
|         BitField<45, 2, PredOperation> op; | ||||
|     } pset; | ||||
|  | ||||
|     union { | ||||
|         BitField<0, 3, u64> pred0; | ||||
|         BitField<3, 3, u64> pred3; | ||||
|         BitField<8, 5, ControlCode> cc; // flag in cc | ||||
|         BitField<39, 3, u64> pred39; | ||||
|         BitField<42, 1, u64> neg_pred39; | ||||
|         BitField<45, 4, PredOperation> op; // op with pred39 | ||||
|     } csetp; | ||||
|  | ||||
|     union { | ||||
|         BitField<39, 3, u64> pred39; | ||||
|         BitField<42, 1, u64> neg_pred; | ||||
| @@ -881,6 +925,7 @@ union Instruction { | ||||
|         BitField<36, 5, u64> index; | ||||
|     } cbuf36; | ||||
|  | ||||
|     BitField<47, 1, u64> generates_cc; | ||||
|     BitField<61, 1, u64> is_b_imm; | ||||
|     BitField<60, 1, u64> is_b_gpr; | ||||
|     BitField<59, 1, u64> is_c_gpr; | ||||
| @@ -1005,6 +1050,7 @@ public: | ||||
|         ISET_IMM, | ||||
|         PSETP, | ||||
|         PSET, | ||||
|         CSETP, | ||||
|         XMAD_IMM, | ||||
|         XMAD_CR, | ||||
|         XMAD_RC, | ||||
| @@ -1241,6 +1287,7 @@ private: | ||||
|             INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"), | ||||
|             INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"), | ||||
|             INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), | ||||
|             INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"), | ||||
|             INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), | ||||
|             INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), | ||||
|             INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"), | ||||
|   | ||||
| @@ -236,6 +236,14 @@ private: | ||||
|     const std::string& suffix; | ||||
| }; | ||||
|  | ||||
| enum class InternalFlag : u64 { | ||||
|     ZeroFlag = 0, | ||||
|     CarryFlag = 1, | ||||
|     OverflowFlag = 2, | ||||
|     NaNFlag = 3, | ||||
|     Amount | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state | ||||
|  * of all registers (e.g. whether they are currently being used as Floats or Integers), and | ||||
| @@ -329,13 +337,19 @@ public: | ||||
|     void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem, | ||||
|                               const std::string& value, u64 dest_num_components, | ||||
|                               u64 value_num_components, bool is_saturated = false, | ||||
|                               u64 dest_elem = 0, Register::Size size = Register::Size::Word) { | ||||
|                               u64 dest_elem = 0, Register::Size size = Register::Size::Word, | ||||
|                               bool sets_cc = false) { | ||||
|         ASSERT_MSG(!is_saturated, "Unimplemented"); | ||||
|  | ||||
|         const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"}; | ||||
|  | ||||
|         SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')', | ||||
|                     dest_num_components, value_num_components, dest_elem); | ||||
|  | ||||
|         if (sets_cc) { | ||||
|             const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; | ||||
|             SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -352,6 +366,26 @@ public: | ||||
|         shader.AddLine(dest + " = " + src + ';'); | ||||
|     } | ||||
|  | ||||
|     std::string GetControlCode(const Tegra::Shader::ControlCode cc) const { | ||||
|         switch (cc) { | ||||
|         case Tegra::Shader::ControlCode::NEU: | ||||
|             return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')'; | ||||
|         default: | ||||
|             LOG_CRITICAL(HW_GPU, "Unimplemented Control Code {}", static_cast<u32>(cc)); | ||||
|             UNREACHABLE(); | ||||
|             return "false"; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     std::string GetInternalFlag(const InternalFlag ii) const { | ||||
|         const u32 code = static_cast<u32>(ii); | ||||
|         return "internalFlag_" + std::to_string(code) + suffix; | ||||
|     } | ||||
|  | ||||
|     void SetInternalFlag(const InternalFlag ii, const std::string& value) const { | ||||
|         shader.AddLine(GetInternalFlag(ii) + " = " + value + ';'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Writes code that does a output attribute assignment to register operation. Output attributes | ||||
|      * are stored as floats, so this may require conversion. | ||||
| @@ -415,6 +449,12 @@ public: | ||||
|         } | ||||
|         declarations.AddNewLine(); | ||||
|  | ||||
|         for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) { | ||||
|             const InternalFlag code = static_cast<InternalFlag>(ii); | ||||
|             declarations.AddLine("bool " + GetInternalFlag(code) + " = false;"); | ||||
|         } | ||||
|         declarations.AddNewLine(); | ||||
|  | ||||
|         for (const auto element : declr_input_attribute) { | ||||
|             // TODO(bunnei): Use proper number of elements for these | ||||
|             u32 idx = | ||||
| @@ -1620,7 +1660,8 @@ private: | ||||
|                 } | ||||
|  | ||||
|                 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, | ||||
|                                           1, instr.alu.saturate_d, 0, instr.conversion.dest_size); | ||||
|                                           1, instr.alu.saturate_d, 0, instr.conversion.dest_size, | ||||
|                                           instr.generates_cc.Value() != 0); | ||||
|                 break; | ||||
|             } | ||||
|             case OpCode::Id::I2F_R: | ||||
| @@ -2277,31 +2318,55 @@ private: | ||||
|             break; | ||||
|         } | ||||
|         case OpCode::Type::PredicateSetPredicate: { | ||||
|             const std::string op_a = | ||||
|                 GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); | ||||
|             const std::string op_b = | ||||
|                 GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0); | ||||
|             switch (opcode->GetId()) { | ||||
|             case OpCode::Id::PSETP: { | ||||
|                 const std::string op_a = | ||||
|                     GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); | ||||
|                 const std::string op_b = | ||||
|                     GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0); | ||||
|  | ||||
|             // We can't use the constant predicate as destination. | ||||
|             ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); | ||||
|                 // We can't use the constant predicate as destination. | ||||
|                 ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); | ||||
|  | ||||
|             const std::string second_pred = | ||||
|                 GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0); | ||||
|                 const std::string second_pred = | ||||
|                     GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0); | ||||
|  | ||||
|             const std::string combiner = GetPredicateCombiner(instr.psetp.op); | ||||
|                 const std::string combiner = GetPredicateCombiner(instr.psetp.op); | ||||
|  | ||||
|             const std::string predicate = | ||||
|                 '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')'; | ||||
|                 const std::string predicate = | ||||
|                     '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')'; | ||||
|  | ||||
|             // Set the primary predicate to the result of Predicate OP SecondPredicate | ||||
|             SetPredicate(instr.psetp.pred3, | ||||
|                          '(' + predicate + ") " + combiner + " (" + second_pred + ')'); | ||||
|                 // Set the primary predicate to the result of Predicate OP SecondPredicate | ||||
|                 SetPredicate(instr.psetp.pred3, | ||||
|                              '(' + predicate + ") " + combiner + " (" + second_pred + ')'); | ||||
|  | ||||
|             if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { | ||||
|                 // Set the secondary predicate to the result of !Predicate OP SecondPredicate, | ||||
|                 // if enabled | ||||
|                 SetPredicate(instr.psetp.pred0, | ||||
|                              "!(" + predicate + ") " + combiner + " (" + second_pred + ')'); | ||||
|                 if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { | ||||
|                     // Set the secondary predicate to the result of !Predicate OP SecondPredicate, | ||||
|                     // if enabled | ||||
|                     SetPredicate(instr.psetp.pred0, | ||||
|                                  "!(" + predicate + ") " + combiner + " (" + second_pred + ')'); | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|             case OpCode::Id::CSETP: { | ||||
|                 const std::string pred = | ||||
|                     GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0); | ||||
|                 const std::string combiner = GetPredicateCombiner(instr.csetp.op); | ||||
|                 const std::string controlCode = regs.GetControlCode(instr.csetp.cc); | ||||
|                 if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) { | ||||
|                     SetPredicate(instr.csetp.pred3, | ||||
|                                  '(' + controlCode + ") " + combiner + " (" + pred + ')'); | ||||
|                 } | ||||
|                 if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { | ||||
|                     SetPredicate(instr.csetp.pred0, | ||||
|                                  "!(" + controlCode + ") " + combiner + " (" + pred + ')'); | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|             default: { | ||||
|                 LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}", opcode->GetName()); | ||||
|                 UNREACHABLE(); | ||||
|             } | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user