summaryrefslogtreecommitdiffstats
path: root/src/video_core/shader
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/shader')
-rw-r--r--src/video_core/shader/decode/arithmetic_integer.cpp60
-rw-r--r--src/video_core/shader/shader_ir.h2
2 files changed, 62 insertions, 0 deletions
diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp
index dbdcebbb4..145bbcfc8 100644
--- a/src/video_core/shader/decode/arithmetic_integer.cpp
+++ b/src/video_core/shader/decode/arithmetic_integer.cpp
@@ -11,6 +11,7 @@ namespace VideoCommon::Shader {
using Tegra::Shader::Instruction;
using Tegra::Shader::OpCode;
+using Tegra::Shader::Register;
u32 ShaderIR::DecodeArithmeticInteger(BasicBlock& bb, u32 pc) {
const Instruction instr = {program_code[pc]};
@@ -79,6 +80,24 @@ u32 ShaderIR::DecodeArithmeticInteger(BasicBlock& bb, u32 pc) {
instr.alu.lop.pred_result_mode, instr.alu.lop.pred48);
break;
}
+ case OpCode::Id::LOP3_C:
+ case OpCode::Id::LOP3_R:
+ case OpCode::Id::LOP3_IMM: {
+ UNIMPLEMENTED_IF_MSG(instr.generates_cc,
+ "Condition codes generation in LOP3 is not implemented");
+
+ const Node op_c = GetRegister(instr.gpr39);
+ const Node lut = [&]() {
+ if (opcode->get().GetId() == OpCode::Id::LOP3_R) {
+ return Immediate(instr.alu.lop3.GetImmLut28());
+ } else {
+ return Immediate(instr.alu.lop3.GetImmLut48());
+ }
+ }();
+
+ WriteLop3Instruction(bb, instr.gpr0, op_a, op_b, op_c, lut);
+ break;
+ }
case OpCode::Id::IMNMX_C:
case OpCode::Id::IMNMX_R:
case OpCode::Id::IMNMX_IMM: {
@@ -102,4 +121,45 @@ u32 ShaderIR::DecodeArithmeticInteger(BasicBlock& bb, u32 pc) {
return pc;
}
+void ShaderIR::WriteLop3Instruction(BasicBlock& bb, Register dest, Node op_a, Node op_b, Node op_c,
+ Node imm_lut) {
+ constexpr u32 lop_iterations = 32;
+ const Node one = Immediate(1);
+ const Node two = Immediate(2);
+
+ Node value{};
+ for (u32 i = 0; i < lop_iterations; ++i) {
+ const Node shift_amount = Immediate(i);
+
+ const Node a = Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, op_c, shift_amount);
+ const Node pack_0 = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, a, one);
+
+ const Node b = Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, op_b, shift_amount);
+ const Node c = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, b, one);
+ const Node pack_1 = Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, c, one);
+
+ const Node d = Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, op_a, shift_amount);
+ const Node e = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, d, one);
+ const Node pack_2 = Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, e, two);
+
+ const Node pack_01 = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, pack_0, pack_1);
+ const Node pack_012 = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, pack_01, pack_2);
+
+ const Node shifted_bit =
+ Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, imm_lut, pack_012);
+ const Node bit = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, shifted_bit, one);
+
+ const Node right =
+ Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, bit, shift_amount);
+
+ if (i > 0) {
+ value = Operation(OperationCode::IBitwiseOr, NO_PRECISE, value, right);
+ } else {
+ value = right;
+ }
+ }
+
+ SetRegister(bb, dest, value);
+}
+
} // namespace VideoCommon::Shader \ No newline at end of file
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index b67fd6531..b91ef246f 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -701,6 +701,8 @@ private:
Tegra::Shader::LogicOperation logic_op, Node op_a, Node op_b,
Tegra::Shader::PredicateResultMode predicate_mode,
Tegra::Shader::Pred predicate);
+ void WriteLop3Instruction(BasicBlock& bb, Tegra::Shader::Register dest, Node op_a, Node op_b,
+ Node op_c, Node imm_lut);
template <typename... T>
inline Node Operation(OperationCode code, const T*... operands) {