From 3b7fd3ad0fcb0419c455c16127f43d01b6dc7fc9 Mon Sep 17 00:00:00 2001
From: ameerj <52414509+ameerj@users.noreply.github.com>
Date: Wed, 17 Mar 2021 00:53:53 -0400
Subject: shader: Implement CSET and CSETP

---
 src/shader_recompiler/CMakeLists.txt               |  1 +
 src/shader_recompiler/frontend/ir/flow_test.h      |  5 +-
 src/shader_recompiler/frontend/ir/ir_emitter.cpp   | 60 ++++++++++++++++++++--
 src/shader_recompiler/frontend/ir/ir_emitter.h     |  1 +
 .../maxwell/translate/impl/condition_code_set.cpp  | 54 +++++++++++++++++++
 .../maxwell/translate/impl/not_implemented.cpp     |  8 ---
 6 files changed, 114 insertions(+), 15 deletions(-)
 create mode 100644 src/shader_recompiler/frontend/maxwell/translate/impl/condition_code_set.cpp

(limited to 'src')

diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt
index 6d2e804caa..e4e7749c79 100644
--- a/src/shader_recompiler/CMakeLists.txt
+++ b/src/shader_recompiler/CMakeLists.txt
@@ -63,6 +63,7 @@ add_library(shader_recompiler STATIC
     frontend/maxwell/translate/impl/common_encoding.h
     frontend/maxwell/translate/impl/common_funcs.cpp
     frontend/maxwell/translate/impl/common_funcs.h
+    frontend/maxwell/translate/impl/condition_code_set.cpp
     frontend/maxwell/translate/impl/find_leading_one.cpp
     frontend/maxwell/translate/impl/floating_point_add.cpp
     frontend/maxwell/translate/impl/floating_point_compare.cpp
diff --git a/src/shader_recompiler/frontend/ir/flow_test.h b/src/shader_recompiler/frontend/ir/flow_test.h
index ac883da136..09e113773d 100644
--- a/src/shader_recompiler/frontend/ir/flow_test.h
+++ b/src/shader_recompiler/frontend/ir/flow_test.h
@@ -5,12 +5,13 @@
 #pragma once
 
 #include <string>
-
 #include <fmt/format.h>
 
+#include "common/common_types.h"
+
 namespace Shader::IR {
 
-enum class FlowTest {
+enum class FlowTest : u64 {
     F,
     LT,
     EQ,
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index d94596ee91..958282160d 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -169,16 +169,62 @@ void IREmitter::SetOFlag(const U1& value) {
 
 static U1 GetFlowTest(IREmitter& ir, FlowTest flow_test) {
     switch (flow_test) {
-    case FlowTest::T:
-        return ir.Imm1(true);
     case FlowTest::F:
         return ir.Imm1(false);
+    case FlowTest::LT:
+        return ir.LogicalXor(ir.LogicalAnd(ir.GetSFlag(), ir.LogicalNot(ir.GetZFlag())),
+                             ir.GetOFlag());
     case FlowTest::EQ:
-        // TODO: Test this
-        return ir.GetZFlag();
+        return ir.LogicalAnd(ir.LogicalNot(ir.GetSFlag()), ir.GetZFlag());
+    case FlowTest::LE:
+        return ir.LogicalXor(ir.GetSFlag(), ir.LogicalOr(ir.GetZFlag(), ir.GetOFlag()));
+    case FlowTest::GT:
+        return ir.LogicalAnd(ir.LogicalXor(ir.LogicalNot(ir.GetSFlag()), ir.GetOFlag()),
+                             ir.LogicalNot(ir.GetZFlag()));
     case FlowTest::NE:
-        // TODO: Test this
         return ir.LogicalNot(ir.GetZFlag());
+    case FlowTest::GE:
+        return ir.LogicalNot(ir.LogicalXor(ir.GetSFlag(), ir.GetOFlag()));
+    case FlowTest::NUM:
+        return ir.LogicalOr(ir.LogicalNot(ir.GetSFlag()), ir.LogicalNot(ir.GetZFlag()));
+    case FlowTest::NaN:
+        return ir.LogicalAnd(ir.GetSFlag(), ir.GetZFlag());
+    case FlowTest::LTU:
+        return ir.LogicalXor(ir.GetSFlag(), ir.GetOFlag());
+    case FlowTest::EQU:
+        return ir.GetZFlag();
+    case FlowTest::LEU:
+        return ir.LogicalOr(ir.LogicalXor(ir.GetSFlag(), ir.GetOFlag()), ir.GetZFlag());
+    case FlowTest::GTU:
+        return ir.LogicalXor(ir.LogicalNot(ir.GetSFlag()),
+                             ir.LogicalOr(ir.GetZFlag(), ir.GetOFlag()));
+    case FlowTest::NEU:
+        return ir.LogicalOr(ir.GetSFlag(), ir.LogicalNot(ir.GetZFlag()));
+    case FlowTest::GEU:
+        return ir.LogicalXor(ir.LogicalOr(ir.LogicalNot(ir.GetSFlag()), ir.GetZFlag()),
+                             ir.GetOFlag());
+    case FlowTest::T:
+        return ir.Imm1(true);
+    case FlowTest::OFF:
+        return ir.LogicalNot(ir.GetOFlag());
+    case FlowTest::LO:
+        return ir.LogicalNot(ir.GetCFlag());
+    case FlowTest::SFF:
+        return ir.LogicalNot(ir.GetSFlag());
+    case FlowTest::LS:
+        return ir.LogicalOr(ir.GetZFlag(), ir.LogicalNot(ir.GetCFlag()));
+    case FlowTest::HI:
+        return ir.LogicalAnd(ir.GetCFlag(), ir.LogicalNot(ir.GetZFlag()));
+    case FlowTest::SFT:
+        return ir.GetSFlag();
+    case FlowTest::HS:
+        return ir.GetCFlag();
+    case FlowTest::OFT:
+        return ir.GetOFlag();
+    case FlowTest::RLE:
+        return ir.LogicalOr(ir.GetSFlag(), ir.GetZFlag());
+    case FlowTest::RGT:
+        return ir.LogicalAnd(ir.LogicalNot(ir.GetSFlag()), ir.LogicalNot(ir.GetZFlag()));
     default:
         throw NotImplementedException("Flow test {}", flow_test);
     }
@@ -190,6 +236,10 @@ U1 IREmitter::Condition(IR::Condition cond) {
     return LogicalAnd(GetPred(pred, is_negated), GetFlowTest(*this, flow_test));
 }
 
+U1 IREmitter::GetFlowTestResult(FlowTest test) {
+    return GetFlowTest(*this, test);
+}
+
 F32 IREmitter::GetAttribute(IR::Attribute attribute) {
     return Inst<F32>(Opcode::GetAttribute, attribute);
 }
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index 27ff5a29d6..05263fe8b4 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -62,6 +62,7 @@ public:
     void SetOFlag(const U1& value);
 
     [[nodiscard]] U1 Condition(IR::Condition cond);
+    [[nodiscard]] U1 GetFlowTestResult(FlowTest test);
 
     [[nodiscard]] F32 GetAttribute(IR::Attribute attribute);
     void SetAttribute(IR::Attribute attribute, const F32& value);
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/condition_code_set.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/condition_code_set.cpp
new file mode 100644
index 0000000000..ea0c40a546
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/condition_code_set.cpp
@@ -0,0 +1,54 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+
+void TranslatorVisitor::CSET(u64 insn) {
+    union {
+        u64 raw;
+        BitField<0, 8, IR::Reg> dest_reg;
+        BitField<8, 5, IR::FlowTest> cc_test;
+        BitField<39, 3, IR::Pred> bop_pred;
+        BitField<42, 1, u64> neg_bop_pred;
+        BitField<44, 1, u64> bf;
+        BitField<45, 2, BooleanOp> bop;
+    } const cset{insn};
+
+    const IR::U32 one_mask{ir.Imm32(-1)};
+    const IR::U32 fp_one{ir.Imm32(0x3f800000)};
+    const IR::U32 fail_result{ir.Imm32(0)};
+    const IR::U32 pass_result{cset.bf == 0 ? one_mask : fp_one};
+    const IR::U1 cc_test_result{ir.GetFlowTestResult(cset.cc_test)};
+    const IR::U1 bop_pred{ir.GetPred(cset.bop_pred, cset.neg_bop_pred != 0)};
+    const IR::U1 pred_result{PredicateCombine(ir, cc_test_result, bop_pred, cset.bop)};
+    const IR::U32 result{ir.Select(pred_result, pass_result, fail_result)};
+    X(cset.dest_reg, result);
+}
+
+void TranslatorVisitor::CSETP(u64 insn) {
+    union {
+        u64 raw;
+        BitField<0, 3, IR::Pred> dest_pred_b;
+        BitField<3, 3, IR::Pred> dest_pred_a;
+        BitField<8, 5, IR::FlowTest> cc_test;
+        BitField<39, 3, IR::Pred> bop_pred;
+        BitField<42, 1, u64> neg_bop_pred;
+        BitField<45, 2, BooleanOp> bop;
+    } const csetp{insn};
+
+    const BooleanOp bop{csetp.bop};
+    const IR::U1 bop_pred{ir.GetPred(csetp.bop_pred, csetp.neg_bop_pred != 0)};
+    const IR::U1 cc_test_result{ir.GetFlowTestResult(csetp.cc_test)};
+    const IR::U1 result_a{PredicateCombine(ir, cc_test_result, bop_pred, bop)};
+    const IR::U1 result_b{PredicateCombine(ir, ir.LogicalNot(cc_test_result), bop_pred, bop)};
+    ir.SetPred(csetp.dest_pred_a, result_a);
+    ir.SetPred(csetp.dest_pred_b, result_b);
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
index b319283701..0325f14eaf 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
@@ -85,14 +85,6 @@ void TranslatorVisitor::CS2R(u64) {
     ThrowNotImplemented(Opcode::CS2R);
 }
 
-void TranslatorVisitor::CSET(u64) {
-    ThrowNotImplemented(Opcode::CSET);
-}
-
-void TranslatorVisitor::CSETP(u64) {
-    ThrowNotImplemented(Opcode::CSETP);
-}
-
 void TranslatorVisitor::DADD_reg(u64) {
     ThrowNotImplemented(Opcode::DADD_reg);
 }
-- 
cgit v1.2.3-70-g09d2