Procházet zdrojové kódy

shader: Implement CSET and CSETP

ameerj před 5 roky
rodič
revize
3b7fd3ad0f

+ 1 - 0
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

+ 3 - 2
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,

+ 55 - 5
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);
 }

+ 1 - 0
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);

+ 54 - 0
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

+ 0 - 8
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);
 }