shader: Implement CSET and CSETP
This commit is contained in:
		| @@ -63,6 +63,7 @@ add_library(shader_recompiler STATIC | |||||||
|     frontend/maxwell/translate/impl/common_encoding.h |     frontend/maxwell/translate/impl/common_encoding.h | ||||||
|     frontend/maxwell/translate/impl/common_funcs.cpp |     frontend/maxwell/translate/impl/common_funcs.cpp | ||||||
|     frontend/maxwell/translate/impl/common_funcs.h |     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/find_leading_one.cpp | ||||||
|     frontend/maxwell/translate/impl/floating_point_add.cpp |     frontend/maxwell/translate/impl/floating_point_add.cpp | ||||||
|     frontend/maxwell/translate/impl/floating_point_compare.cpp |     frontend/maxwell/translate/impl/floating_point_compare.cpp | ||||||
|   | |||||||
| @@ -5,12 +5,13 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <string> | #include <string> | ||||||
|  |  | ||||||
| #include <fmt/format.h> | #include <fmt/format.h> | ||||||
|  |  | ||||||
|  | #include "common/common_types.h" | ||||||
|  |  | ||||||
| namespace Shader::IR { | namespace Shader::IR { | ||||||
|  |  | ||||||
| enum class FlowTest { | enum class FlowTest : u64 { | ||||||
|     F, |     F, | ||||||
|     LT, |     LT, | ||||||
|     EQ, |     EQ, | ||||||
|   | |||||||
| @@ -169,16 +169,62 @@ void IREmitter::SetOFlag(const U1& value) { | |||||||
|  |  | ||||||
| static U1 GetFlowTest(IREmitter& ir, FlowTest flow_test) { | static U1 GetFlowTest(IREmitter& ir, FlowTest flow_test) { | ||||||
|     switch (flow_test) { |     switch (flow_test) { | ||||||
|     case FlowTest::T: |  | ||||||
|         return ir.Imm1(true); |  | ||||||
|     case FlowTest::F: |     case FlowTest::F: | ||||||
|         return ir.Imm1(false); |         return ir.Imm1(false); | ||||||
|  |     case FlowTest::LT: | ||||||
|  |         return ir.LogicalXor(ir.LogicalAnd(ir.GetSFlag(), ir.LogicalNot(ir.GetZFlag())), | ||||||
|  |                              ir.GetOFlag()); | ||||||
|     case FlowTest::EQ: |     case FlowTest::EQ: | ||||||
|         // TODO: Test this |         return ir.LogicalAnd(ir.LogicalNot(ir.GetSFlag()), ir.GetZFlag()); | ||||||
|         return 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: |     case FlowTest::NE: | ||||||
|         // TODO: Test this |  | ||||||
|         return ir.LogicalNot(ir.GetZFlag()); |         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: |     default: | ||||||
|         throw NotImplementedException("Flow test {}", flow_test); |         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)); |     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) { | F32 IREmitter::GetAttribute(IR::Attribute attribute) { | ||||||
|     return Inst<F32>(Opcode::GetAttribute, attribute); |     return Inst<F32>(Opcode::GetAttribute, attribute); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ public: | |||||||
|     void SetOFlag(const U1& value); |     void SetOFlag(const U1& value); | ||||||
|  |  | ||||||
|     [[nodiscard]] U1 Condition(IR::Condition cond); |     [[nodiscard]] U1 Condition(IR::Condition cond); | ||||||
|  |     [[nodiscard]] U1 GetFlowTestResult(FlowTest test); | ||||||
|  |  | ||||||
|     [[nodiscard]] F32 GetAttribute(IR::Attribute attribute); |     [[nodiscard]] F32 GetAttribute(IR::Attribute attribute); | ||||||
|     void SetAttribute(IR::Attribute attribute, const F32& value); |     void SetAttribute(IR::Attribute attribute, const F32& value); | ||||||
|   | |||||||
| @@ -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 | ||||||
| @@ -85,14 +85,6 @@ void TranslatorVisitor::CS2R(u64) { | |||||||
|     ThrowNotImplemented(Opcode::CS2R); |     ThrowNotImplemented(Opcode::CS2R); | ||||||
| } | } | ||||||
|  |  | ||||||
| void TranslatorVisitor::CSET(u64) { |  | ||||||
|     ThrowNotImplemented(Opcode::CSET); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void TranslatorVisitor::CSETP(u64) { |  | ||||||
|     ThrowNotImplemented(Opcode::CSETP); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void TranslatorVisitor::DADD_reg(u64) { | void TranslatorVisitor::DADD_reg(u64) { | ||||||
|     ThrowNotImplemented(Opcode::DADD_reg); |     ThrowNotImplemented(Opcode::DADD_reg); | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user