From 255197e64363f9286ed145cafdeb129c85c16621 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sat, 25 Apr 2020 21:56:11 -0300 Subject: shader/arithmetic_integer: Implement CC for IADD --- .../shader/decode/arithmetic_integer.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'src/video_core/shader/decode/arithmetic_integer.cpp') diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp index 9af8c606d..99b4b6342 100644 --- a/src/video_core/shader/decode/arithmetic_integer.cpp +++ b/src/video_core/shader/decode/arithmetic_integer.cpp @@ -40,10 +40,26 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) { op_a = GetOperandAbsNegInteger(op_a, false, instr.alu_integer.negate_a, 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::IAdd, op_a, op_b); - SetInternalFlagsFromInteger(bb, value, instr.generates_cc); - SetRegister(bb, instr.gpr0, value); + 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; } case OpCode::Id::IADD3_C: -- cgit v1.2.3 From c788f9c0bd9cb0b0cb66f7424a65032cca3731cc Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sat, 25 Apr 2020 22:41:20 -0300 Subject: shader/arithmetic_integer: Implement IADD.X IADD.X takes the carry flag and adds it to the result. This is generally used to emulate 64-bit operations with 32-bit registers. --- src/video_core/shader/decode/arithmetic_integer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/video_core/shader/decode/arithmetic_integer.cpp') diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp index 99b4b6342..2a3311cb8 100644 --- a/src/video_core/shader/decode/arithmetic_integer.cpp +++ b/src/video_core/shader/decode/arithmetic_integer.cpp @@ -42,6 +42,12 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) { Node value = Operation(OperationCode::IAdd, op_a, op_b); + if (instr.iadd.x) { + Node carry = GetInternalFlag(InternalFlag::Carry); + Node x = Operation(OperationCode::Select, std::move(carry), Immediate(1), Immediate(0)); + value = Operation(OperationCode::IAdd, std::move(value), std::move(x)); + } + if (instr.generates_cc) { const Node i0 = Immediate(0); -- cgit v1.2.3 From 2a96bea6a7efd9efaaa8d1d72f1eb8ca27cb81f8 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sat, 25 Apr 2020 22:42:33 -0300 Subject: shader/arithmetic_integer: Change IAdd to UAdd to avoid signed overflow Signed integer addition overflow might be undefined behavior. It's free to change operations to UAdd and use unsigned integers to avoid potential bugs. --- src/video_core/shader/decode/arithmetic_integer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/video_core/shader/decode/arithmetic_integer.cpp') diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp index 2a3311cb8..addd7f533 100644 --- a/src/video_core/shader/decode/arithmetic_integer.cpp +++ b/src/video_core/shader/decode/arithmetic_integer.cpp @@ -40,12 +40,12 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) { op_a = GetOperandAbsNegInteger(op_a, false, instr.alu_integer.negate_a, true); op_b = GetOperandAbsNegInteger(op_b, false, instr.alu_integer.negate_b, true); - Node value = Operation(OperationCode::IAdd, op_a, op_b); + Node value = Operation(OperationCode::UAdd, op_a, op_b); if (instr.iadd.x) { Node carry = GetInternalFlag(InternalFlag::Carry); Node x = Operation(OperationCode::Select, std::move(carry), Immediate(1), Immediate(0)); - value = Operation(OperationCode::IAdd, std::move(value), std::move(x)); + value = Operation(OperationCode::UAdd, std::move(value), std::move(x)); } if (instr.generates_cc) { -- cgit v1.2.3 From e895a4e2d7ebf29fbafda7d950301cd7d03efdbb Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sat, 25 Apr 2020 22:53:54 -0300 Subject: shader/arithmetic_integer: Fix edge case and mark IADD.X Rd.CC as unimplemented IADD.X Rd.CC requires some extra logic that is not currently implemented. Abort when this is hit. --- src/video_core/shader/decode/arithmetic_integer.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/video_core/shader/decode/arithmetic_integer.cpp') diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp index addd7f533..ced5c3dc1 100644 --- a/src/video_core/shader/decode/arithmetic_integer.cpp +++ b/src/video_core/shader/decode/arithmetic_integer.cpp @@ -35,7 +35,8 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) { case OpCode::Id::IADD_C: case OpCode::Id::IADD_R: 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_b = GetOperandAbsNegInteger(op_b, false, instr.alu_integer.negate_b, true); @@ -49,6 +50,10 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) { } if (instr.generates_cc) { + // Avoid changing result's carry flag + SetTemporary(bb, 0, std::move(value)); + value = GetTemporary(0); + const Node i0 = Immediate(0); Node zero = Operation(OperationCode::LogicalIEqual, value, i0); -- cgit v1.2.3 From 871aadbe36b7480f7dc318e2a8bebb064a1fbaaf Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Tue, 28 Apr 2020 17:14:53 -0300 Subject: shader/arithmetic_integer: Fix tracking issue in temporary This temporary is not needed as we mark Rd.CC + IADD.X as unimplemented. It caused issues when tracking global buffers. --- src/video_core/shader/decode/arithmetic_integer.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/video_core/shader/decode/arithmetic_integer.cpp') diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp index ced5c3dc1..a041519b7 100644 --- a/src/video_core/shader/decode/arithmetic_integer.cpp +++ b/src/video_core/shader/decode/arithmetic_integer.cpp @@ -50,10 +50,6 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) { } if (instr.generates_cc) { - // Avoid changing result's carry flag - SetTemporary(bb, 0, std::move(value)); - value = GetTemporary(0); - const Node i0 = Immediate(0); Node zero = Operation(OperationCode::LogicalIEqual, value, i0); -- cgit v1.2.3