Merge pull request #3799 from ReinUsesLisp/iadd-cc
shader: Implement P2R CC, IADD Rd.CC and IADD.X
This commit is contained in:
		
							
								
								
									
										2
									
								
								externals/sirit
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								externals/sirit
									
									
									
									
										vendored
									
									
								
							 Submodule externals/sirit updated: a712959f1e...414fc4dbd2
									
								
							| @@ -813,6 +813,10 @@ union Instruction { | |||||||
|         BitField<49, 1, u64> negate_a; |         BitField<49, 1, u64> negate_a; | ||||||
|     } alu_integer; |     } alu_integer; | ||||||
|  |  | ||||||
|  |     union { | ||||||
|  |         BitField<43, 1, u64> x; | ||||||
|  |     } iadd; | ||||||
|  |  | ||||||
|     union { |     union { | ||||||
|         BitField<39, 1, u64> ftz; |         BitField<39, 1, u64> ftz; | ||||||
|         BitField<32, 1, u64> saturate; |         BitField<32, 1, u64> saturate; | ||||||
|   | |||||||
| @@ -1870,6 +1870,14 @@ private: | |||||||
|         return GenerateBinaryInfix(operation, ">=", Type::Bool, type, type); |         return GenerateBinaryInfix(operation, ">=", Type::Bool, type, type); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     Expression LogicalAddCarry(Operation operation) { | ||||||
|  |         const std::string carry = code.GenerateTemporary(); | ||||||
|  |         code.AddLine("uint {};", carry); | ||||||
|  |         code.AddLine("uaddCarry({}, {}, {});", VisitOperand(operation, 0).AsUint(), | ||||||
|  |                      VisitOperand(operation, 1).AsUint(), carry); | ||||||
|  |         return {fmt::format("({} != 0)", carry), Type::Bool}; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     Expression LogicalFIsNan(Operation operation) { |     Expression LogicalFIsNan(Operation operation) { | ||||||
|         return GenerateUnary(operation, "isnan", Type::Bool, Type::Float); |         return GenerateUnary(operation, "isnan", Type::Bool, Type::Float); | ||||||
|     } |     } | ||||||
| @@ -2441,6 +2449,8 @@ private: | |||||||
|         &GLSLDecompiler::LogicalNotEqual<Type::Uint>, |         &GLSLDecompiler::LogicalNotEqual<Type::Uint>, | ||||||
|         &GLSLDecompiler::LogicalGreaterEqual<Type::Uint>, |         &GLSLDecompiler::LogicalGreaterEqual<Type::Uint>, | ||||||
|  |  | ||||||
|  |         &GLSLDecompiler::LogicalAddCarry, | ||||||
|  |  | ||||||
|         &GLSLDecompiler::Logical2HLessThan<false>, |         &GLSLDecompiler::Logical2HLessThan<false>, | ||||||
|         &GLSLDecompiler::Logical2HEqual<false>, |         &GLSLDecompiler::Logical2HEqual<false>, | ||||||
|         &GLSLDecompiler::Logical2HLessEqual<false>, |         &GLSLDecompiler::Logical2HLessEqual<false>, | ||||||
|   | |||||||
| @@ -1584,6 +1584,15 @@ private: | |||||||
|         return {OpCompositeConstruct(t_half, low, high), Type::HalfFloat}; |         return {OpCompositeConstruct(t_half, low, high), Type::HalfFloat}; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     Expression LogicalAddCarry(Operation operation) { | ||||||
|  |         const Id op_a = AsUint(Visit(operation[0])); | ||||||
|  |         const Id op_b = AsUint(Visit(operation[1])); | ||||||
|  |  | ||||||
|  |         const Id result = OpIAddCarry(TypeStruct({t_uint, t_uint}), op_a, op_b); | ||||||
|  |         const Id carry = OpCompositeExtract(t_uint, result, 1); | ||||||
|  |         return {OpINotEqual(t_bool, carry, Constant(t_uint, 0)), Type::Bool}; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     Expression LogicalAssign(Operation operation) { |     Expression LogicalAssign(Operation operation) { | ||||||
|         const Node& dest = operation[0]; |         const Node& dest = operation[0]; | ||||||
|         const Node& src = operation[1]; |         const Node& src = operation[1]; | ||||||
| @@ -2518,6 +2527,8 @@ private: | |||||||
|         &SPIRVDecompiler::Binary<&Module::OpINotEqual, Type::Bool, Type::Uint>, |         &SPIRVDecompiler::Binary<&Module::OpINotEqual, Type::Bool, Type::Uint>, | ||||||
|         &SPIRVDecompiler::Binary<&Module::OpUGreaterThanEqual, Type::Bool, Type::Uint>, |         &SPIRVDecompiler::Binary<&Module::OpUGreaterThanEqual, Type::Bool, Type::Uint>, | ||||||
|  |  | ||||||
|  |         &SPIRVDecompiler::LogicalAddCarry, | ||||||
|  |  | ||||||
|         &SPIRVDecompiler::Binary<&Module::OpFOrdLessThan, Type::Bool2, Type::HalfFloat>, |         &SPIRVDecompiler::Binary<&Module::OpFOrdLessThan, Type::Bool2, Type::HalfFloat>, | ||||||
|         &SPIRVDecompiler::Binary<&Module::OpFOrdEqual, Type::Bool2, Type::HalfFloat>, |         &SPIRVDecompiler::Binary<&Module::OpFOrdEqual, Type::Bool2, Type::HalfFloat>, | ||||||
|         &SPIRVDecompiler::Binary<&Module::OpFOrdLessThanEqual, Type::Bool2, Type::HalfFloat>, |         &SPIRVDecompiler::Binary<&Module::OpFOrdLessThanEqual, Type::Bool2, Type::HalfFloat>, | ||||||
|   | |||||||
| @@ -35,15 +35,38 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) { | |||||||
|     case OpCode::Id::IADD_C: |     case OpCode::Id::IADD_C: | ||||||
|     case OpCode::Id::IADD_R: |     case OpCode::Id::IADD_R: | ||||||
|     case OpCode::Id::IADD_IMM: { |     case OpCode::Id::IADD_IMM: { | ||||||
|         UNIMPLEMENTED_IF_MSG(instr.alu.saturate_d, "IADD saturation not implemented"); |         UNIMPLEMENTED_IF_MSG(instr.alu.saturate_d, "IADD.SAT"); | ||||||
|  |         UNIMPLEMENTED_IF_MSG(instr.iadd.x && instr.generates_cc, "IADD.X Rd.CC"); | ||||||
|  |  | ||||||
|         op_a = GetOperandAbsNegInteger(op_a, false, instr.alu_integer.negate_a, true); |         op_a = GetOperandAbsNegInteger(op_a, false, instr.alu_integer.negate_a, true); | ||||||
|         op_b = GetOperandAbsNegInteger(op_b, false, instr.alu_integer.negate_b, true); |         op_b = GetOperandAbsNegInteger(op_b, false, instr.alu_integer.negate_b, true); | ||||||
|  |  | ||||||
|         const Node value = Operation(OperationCode::IAdd, PRECISE, op_a, op_b); |         Node value = Operation(OperationCode::UAdd, op_a, op_b); | ||||||
|  |  | ||||||
|         SetInternalFlagsFromInteger(bb, value, instr.generates_cc); |         if (instr.iadd.x) { | ||||||
|         SetRegister(bb, instr.gpr0, value); |             Node carry = GetInternalFlag(InternalFlag::Carry); | ||||||
|  |             Node x = Operation(OperationCode::Select, std::move(carry), Immediate(1), Immediate(0)); | ||||||
|  |             value = Operation(OperationCode::UAdd, std::move(value), std::move(x)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (instr.generates_cc) { | ||||||
|  |             const Node i0 = Immediate(0); | ||||||
|  |  | ||||||
|  |             Node zero = Operation(OperationCode::LogicalIEqual, value, i0); | ||||||
|  |             Node sign = Operation(OperationCode::LogicalILessThan, value, i0); | ||||||
|  |             Node carry = Operation(OperationCode::LogicalAddCarry, op_a, op_b); | ||||||
|  |  | ||||||
|  |             Node pos_a = Operation(OperationCode::LogicalIGreaterThan, op_a, i0); | ||||||
|  |             Node pos_b = Operation(OperationCode::LogicalIGreaterThan, op_b, i0); | ||||||
|  |             Node pos = Operation(OperationCode::LogicalAnd, std::move(pos_a), std::move(pos_b)); | ||||||
|  |             Node overflow = Operation(OperationCode::LogicalAnd, pos, sign); | ||||||
|  |  | ||||||
|  |             SetInternalFlag(bb, InternalFlag::Zero, std::move(zero)); | ||||||
|  |             SetInternalFlag(bb, InternalFlag::Sign, std::move(sign)); | ||||||
|  |             SetInternalFlag(bb, InternalFlag::Carry, std::move(carry)); | ||||||
|  |             SetInternalFlag(bb, InternalFlag::Overflow, std::move(overflow)); | ||||||
|  |         } | ||||||
|  |         SetRegister(bb, instr.gpr0, std::move(value)); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case OpCode::Id::IADD3_C: |     case OpCode::Id::IADD3_C: | ||||||
|   | |||||||
| @@ -2,6 +2,8 @@ | |||||||
| // Licensed under GPLv2 or any later version | // Licensed under GPLv2 or any later version | ||||||
| // Refer to the license.txt file included. | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include <utility> | ||||||
|  |  | ||||||
| #include "common/assert.h" | #include "common/assert.h" | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "video_core/engines/shader_bytecode.h" | #include "video_core/engines/shader_bytecode.h" | ||||||
| @@ -10,20 +12,20 @@ | |||||||
|  |  | ||||||
| namespace VideoCommon::Shader { | namespace VideoCommon::Shader { | ||||||
|  |  | ||||||
|  | using std::move; | ||||||
| using Tegra::Shader::Instruction; | using Tegra::Shader::Instruction; | ||||||
| using Tegra::Shader::OpCode; | using Tegra::Shader::OpCode; | ||||||
|  |  | ||||||
| namespace { | namespace { | ||||||
| constexpr u64 NUM_PROGRAMMABLE_PREDICATES = 7; | constexpr u64 NUM_CONDITION_CODES = 4; | ||||||
| } | constexpr u64 NUM_PREDICATES = 7; | ||||||
|  | } // namespace | ||||||
|  |  | ||||||
| u32 ShaderIR::DecodeRegisterSetPredicate(NodeBlock& bb, u32 pc) { | u32 ShaderIR::DecodeRegisterSetPredicate(NodeBlock& bb, u32 pc) { | ||||||
|     const Instruction instr = {program_code[pc]}; |     const Instruction instr = {program_code[pc]}; | ||||||
|     const auto opcode = OpCode::Decode(instr); |     const auto opcode = OpCode::Decode(instr); | ||||||
|  |  | ||||||
|     UNIMPLEMENTED_IF(instr.p2r_r2p.mode != Tegra::Shader::R2pMode::Pr); |     Node apply_mask = [this, opcode, instr] { | ||||||
|  |  | ||||||
|     const Node apply_mask = [&] { |  | ||||||
|         switch (opcode->get().GetId()) { |         switch (opcode->get().GetId()) { | ||||||
|         case OpCode::Id::R2P_IMM: |         case OpCode::Id::R2P_IMM: | ||||||
|         case OpCode::Id::P2R_IMM: |         case OpCode::Id::P2R_IMM: | ||||||
| @@ -34,39 +36,43 @@ u32 ShaderIR::DecodeRegisterSetPredicate(NodeBlock& bb, u32 pc) { | |||||||
|         } |         } | ||||||
|     }(); |     }(); | ||||||
|  |  | ||||||
|     const auto offset = static_cast<u32>(instr.p2r_r2p.byte) * 8; |     const u32 offset = static_cast<u32>(instr.p2r_r2p.byte) * 8; | ||||||
|  |  | ||||||
|  |     const bool cc = instr.p2r_r2p.mode == Tegra::Shader::R2pMode::Cc; | ||||||
|  |     const u64 num_entries = cc ? NUM_CONDITION_CODES : NUM_PREDICATES; | ||||||
|  |     const auto get_entry = [this, cc](u64 entry) { | ||||||
|  |         return cc ? GetInternalFlag(static_cast<InternalFlag>(entry)) : GetPredicate(entry); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     switch (opcode->get().GetId()) { |     switch (opcode->get().GetId()) { | ||||||
|     case OpCode::Id::R2P_IMM: { |     case OpCode::Id::R2P_IMM: { | ||||||
|         const Node mask = GetRegister(instr.gpr8); |         Node mask = GetRegister(instr.gpr8); | ||||||
|  |  | ||||||
|         for (u64 pred = 0; pred < NUM_PROGRAMMABLE_PREDICATES; ++pred) { |         for (u64 entry = 0; entry < num_entries; ++entry) { | ||||||
|             const auto shift = static_cast<u32>(pred); |             const u32 shift = static_cast<u32>(entry); | ||||||
|  |  | ||||||
|             const Node apply_compare = BitfieldExtract(apply_mask, shift, 1); |             Node apply = BitfieldExtract(apply_mask, shift, 1); | ||||||
|             const Node condition = |             Node condition = Operation(OperationCode::LogicalUNotEqual, apply, Immediate(0)); | ||||||
|                 Operation(OperationCode::LogicalUNotEqual, apply_compare, Immediate(0)); |  | ||||||
|  |  | ||||||
|             const Node value_compare = BitfieldExtract(mask, offset + shift, 1); |             Node compare = BitfieldExtract(mask, offset + shift, 1); | ||||||
|             const Node value = |             Node value = Operation(OperationCode::LogicalUNotEqual, move(compare), Immediate(0)); | ||||||
|                 Operation(OperationCode::LogicalUNotEqual, value_compare, Immediate(0)); |  | ||||||
|  |  | ||||||
|             const Node code = Operation(OperationCode::LogicalAssign, GetPredicate(pred), value); |             Node code = Operation(OperationCode::LogicalAssign, get_entry(entry), move(value)); | ||||||
|             bb.push_back(Conditional(condition, {code})); |             bb.push_back(Conditional(condition, {move(code)})); | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case OpCode::Id::P2R_IMM: { |     case OpCode::Id::P2R_IMM: { | ||||||
|         Node value = Immediate(0); |         Node value = Immediate(0); | ||||||
|         for (u64 pred = 0; pred < NUM_PROGRAMMABLE_PREDICATES; ++pred) { |         for (u64 entry = 0; entry < num_entries; ++entry) { | ||||||
|             Node bit = Operation(OperationCode::Select, GetPredicate(pred), Immediate(1U << pred), |             Node bit = Operation(OperationCode::Select, get_entry(entry), Immediate(1U << entry), | ||||||
|                                  Immediate(0)); |                                  Immediate(0)); | ||||||
|             value = Operation(OperationCode::UBitwiseOr, std::move(value), std::move(bit)); |             value = Operation(OperationCode::UBitwiseOr, move(value), move(bit)); | ||||||
|         } |         } | ||||||
|         value = Operation(OperationCode::UBitwiseAnd, std::move(value), apply_mask); |         value = Operation(OperationCode::UBitwiseAnd, move(value), apply_mask); | ||||||
|         value = BitfieldInsert(GetRegister(instr.gpr8), std::move(value), offset, 8); |         value = BitfieldInsert(GetRegister(instr.gpr8), move(value), offset, 8); | ||||||
|  |  | ||||||
|         SetRegister(bb, instr.gpr0, std::move(value)); |         SetRegister(bb, instr.gpr0, move(value)); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     default: |     default: | ||||||
|   | |||||||
| @@ -132,6 +132,8 @@ enum class OperationCode { | |||||||
|     LogicalUNotEqual,     /// (uint a, uint b) -> bool |     LogicalUNotEqual,     /// (uint a, uint b) -> bool | ||||||
|     LogicalUGreaterEqual, /// (uint a, uint b) -> bool |     LogicalUGreaterEqual, /// (uint a, uint b) -> bool | ||||||
|  |  | ||||||
|  |     LogicalAddCarry, /// (uint a, uint b) -> bool | ||||||
|  |  | ||||||
|     Logical2HLessThan,            /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 |     Logical2HLessThan,            /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | ||||||
|     Logical2HEqual,               /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 |     Logical2HEqual,               /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | ||||||
|     Logical2HLessEqual,           /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 |     Logical2HLessEqual,           /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user