diff options
| author | 2021-03-17 00:53:53 -0400 | |
|---|---|---|
| committer | 2021-07-22 21:51:23 -0400 | |
| commit | 3b7fd3ad0fcb0419c455c16127f43d01b6dc7fc9 (patch) | |
| tree | 194884a206ae5c4719fa4ddeeca1c3aa45acec36 /src/shader_recompiler | |
| parent | shader: Reorder phi nodes when redefined as undefined opcodes (diff) | |
| download | yuzu-3b7fd3ad0fcb0419c455c16127f43d01b6dc7fc9.tar.gz yuzu-3b7fd3ad0fcb0419c455c16127f43d01b6dc7fc9.tar.xz yuzu-3b7fd3ad0fcb0419c455c16127f43d01b6dc7fc9.zip | |
shader: Implement CSET and CSETP
Diffstat (limited to 'src/shader_recompiler')
6 files changed, 114 insertions, 15 deletions
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 6d2e804ca..e4e7749c7 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -63,6 +63,7 @@ add_library(shader_recompiler STATIC | |||
| 63 | frontend/maxwell/translate/impl/common_encoding.h | 63 | frontend/maxwell/translate/impl/common_encoding.h |
| 64 | frontend/maxwell/translate/impl/common_funcs.cpp | 64 | frontend/maxwell/translate/impl/common_funcs.cpp |
| 65 | frontend/maxwell/translate/impl/common_funcs.h | 65 | frontend/maxwell/translate/impl/common_funcs.h |
| 66 | frontend/maxwell/translate/impl/condition_code_set.cpp | ||
| 66 | frontend/maxwell/translate/impl/find_leading_one.cpp | 67 | frontend/maxwell/translate/impl/find_leading_one.cpp |
| 67 | frontend/maxwell/translate/impl/floating_point_add.cpp | 68 | frontend/maxwell/translate/impl/floating_point_add.cpp |
| 68 | frontend/maxwell/translate/impl/floating_point_compare.cpp | 69 | 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 ac883da13..09e113773 100644 --- a/src/shader_recompiler/frontend/ir/flow_test.h +++ b/src/shader_recompiler/frontend/ir/flow_test.h | |||
| @@ -5,12 +5,13 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | 7 | #include <string> |
| 8 | |||
| 9 | #include <fmt/format.h> | 8 | #include <fmt/format.h> |
| 10 | 9 | ||
| 10 | #include "common/common_types.h" | ||
| 11 | |||
| 11 | namespace Shader::IR { | 12 | namespace Shader::IR { |
| 12 | 13 | ||
| 13 | enum class FlowTest { | 14 | enum class FlowTest : u64 { |
| 14 | F, | 15 | F, |
| 15 | LT, | 16 | LT, |
| 16 | EQ, | 17 | EQ, |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index d94596ee9..958282160 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) { | |||
| 169 | 169 | ||
| 170 | static U1 GetFlowTest(IREmitter& ir, FlowTest flow_test) { | 170 | static U1 GetFlowTest(IREmitter& ir, FlowTest flow_test) { |
| 171 | switch (flow_test) { | 171 | switch (flow_test) { |
| 172 | case FlowTest::T: | ||
| 173 | return ir.Imm1(true); | ||
| 174 | case FlowTest::F: | 172 | case FlowTest::F: |
| 175 | return ir.Imm1(false); | 173 | return ir.Imm1(false); |
| 174 | case FlowTest::LT: | ||
| 175 | return ir.LogicalXor(ir.LogicalAnd(ir.GetSFlag(), ir.LogicalNot(ir.GetZFlag())), | ||
| 176 | ir.GetOFlag()); | ||
| 176 | case FlowTest::EQ: | 177 | case FlowTest::EQ: |
| 177 | // TODO: Test this | 178 | return ir.LogicalAnd(ir.LogicalNot(ir.GetSFlag()), ir.GetZFlag()); |
| 178 | return ir.GetZFlag(); | 179 | case FlowTest::LE: |
| 180 | return ir.LogicalXor(ir.GetSFlag(), ir.LogicalOr(ir.GetZFlag(), ir.GetOFlag())); | ||
| 181 | case FlowTest::GT: | ||
| 182 | return ir.LogicalAnd(ir.LogicalXor(ir.LogicalNot(ir.GetSFlag()), ir.GetOFlag()), | ||
| 183 | ir.LogicalNot(ir.GetZFlag())); | ||
| 179 | case FlowTest::NE: | 184 | case FlowTest::NE: |
| 180 | // TODO: Test this | ||
| 181 | return ir.LogicalNot(ir.GetZFlag()); | 185 | return ir.LogicalNot(ir.GetZFlag()); |
| 186 | case FlowTest::GE: | ||
| 187 | return ir.LogicalNot(ir.LogicalXor(ir.GetSFlag(), ir.GetOFlag())); | ||
| 188 | case FlowTest::NUM: | ||
| 189 | return ir.LogicalOr(ir.LogicalNot(ir.GetSFlag()), ir.LogicalNot(ir.GetZFlag())); | ||
| 190 | case FlowTest::NaN: | ||
| 191 | return ir.LogicalAnd(ir.GetSFlag(), ir.GetZFlag()); | ||
| 192 | case FlowTest::LTU: | ||
| 193 | return ir.LogicalXor(ir.GetSFlag(), ir.GetOFlag()); | ||
| 194 | case FlowTest::EQU: | ||
| 195 | return ir.GetZFlag(); | ||
| 196 | case FlowTest::LEU: | ||
| 197 | return ir.LogicalOr(ir.LogicalXor(ir.GetSFlag(), ir.GetOFlag()), ir.GetZFlag()); | ||
| 198 | case FlowTest::GTU: | ||
| 199 | return ir.LogicalXor(ir.LogicalNot(ir.GetSFlag()), | ||
| 200 | ir.LogicalOr(ir.GetZFlag(), ir.GetOFlag())); | ||
| 201 | case FlowTest::NEU: | ||
| 202 | return ir.LogicalOr(ir.GetSFlag(), ir.LogicalNot(ir.GetZFlag())); | ||
| 203 | case FlowTest::GEU: | ||
| 204 | return ir.LogicalXor(ir.LogicalOr(ir.LogicalNot(ir.GetSFlag()), ir.GetZFlag()), | ||
| 205 | ir.GetOFlag()); | ||
| 206 | case FlowTest::T: | ||
| 207 | return ir.Imm1(true); | ||
| 208 | case FlowTest::OFF: | ||
| 209 | return ir.LogicalNot(ir.GetOFlag()); | ||
| 210 | case FlowTest::LO: | ||
| 211 | return ir.LogicalNot(ir.GetCFlag()); | ||
| 212 | case FlowTest::SFF: | ||
| 213 | return ir.LogicalNot(ir.GetSFlag()); | ||
| 214 | case FlowTest::LS: | ||
| 215 | return ir.LogicalOr(ir.GetZFlag(), ir.LogicalNot(ir.GetCFlag())); | ||
| 216 | case FlowTest::HI: | ||
| 217 | return ir.LogicalAnd(ir.GetCFlag(), ir.LogicalNot(ir.GetZFlag())); | ||
| 218 | case FlowTest::SFT: | ||
| 219 | return ir.GetSFlag(); | ||
| 220 | case FlowTest::HS: | ||
| 221 | return ir.GetCFlag(); | ||
| 222 | case FlowTest::OFT: | ||
| 223 | return ir.GetOFlag(); | ||
| 224 | case FlowTest::RLE: | ||
| 225 | return ir.LogicalOr(ir.GetSFlag(), ir.GetZFlag()); | ||
| 226 | case FlowTest::RGT: | ||
| 227 | return ir.LogicalAnd(ir.LogicalNot(ir.GetSFlag()), ir.LogicalNot(ir.GetZFlag())); | ||
| 182 | default: | 228 | default: |
| 183 | throw NotImplementedException("Flow test {}", flow_test); | 229 | throw NotImplementedException("Flow test {}", flow_test); |
| 184 | } | 230 | } |
| @@ -190,6 +236,10 @@ U1 IREmitter::Condition(IR::Condition cond) { | |||
| 190 | return LogicalAnd(GetPred(pred, is_negated), GetFlowTest(*this, flow_test)); | 236 | return LogicalAnd(GetPred(pred, is_negated), GetFlowTest(*this, flow_test)); |
| 191 | } | 237 | } |
| 192 | 238 | ||
| 239 | U1 IREmitter::GetFlowTestResult(FlowTest test) { | ||
| 240 | return GetFlowTest(*this, test); | ||
| 241 | } | ||
| 242 | |||
| 193 | F32 IREmitter::GetAttribute(IR::Attribute attribute) { | 243 | F32 IREmitter::GetAttribute(IR::Attribute attribute) { |
| 194 | return Inst<F32>(Opcode::GetAttribute, attribute); | 244 | return Inst<F32>(Opcode::GetAttribute, attribute); |
| 195 | } | 245 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 27ff5a29d..05263fe8b 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -62,6 +62,7 @@ public: | |||
| 62 | void SetOFlag(const U1& value); | 62 | void SetOFlag(const U1& value); |
| 63 | 63 | ||
| 64 | [[nodiscard]] U1 Condition(IR::Condition cond); | 64 | [[nodiscard]] U1 Condition(IR::Condition cond); |
| 65 | [[nodiscard]] U1 GetFlowTestResult(FlowTest test); | ||
| 65 | 66 | ||
| 66 | [[nodiscard]] F32 GetAttribute(IR::Attribute attribute); | 67 | [[nodiscard]] F32 GetAttribute(IR::Attribute attribute); |
| 67 | void SetAttribute(IR::Attribute attribute, const F32& value); | 68 | 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 000000000..ea0c40a54 --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/condition_code_set.cpp | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/bit_field.h" | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h" | ||
| 8 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 9 | |||
| 10 | namespace Shader::Maxwell { | ||
| 11 | |||
| 12 | void TranslatorVisitor::CSET(u64 insn) { | ||
| 13 | union { | ||
| 14 | u64 raw; | ||
| 15 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 16 | BitField<8, 5, IR::FlowTest> cc_test; | ||
| 17 | BitField<39, 3, IR::Pred> bop_pred; | ||
| 18 | BitField<42, 1, u64> neg_bop_pred; | ||
| 19 | BitField<44, 1, u64> bf; | ||
| 20 | BitField<45, 2, BooleanOp> bop; | ||
| 21 | } const cset{insn}; | ||
| 22 | |||
| 23 | const IR::U32 one_mask{ir.Imm32(-1)}; | ||
| 24 | const IR::U32 fp_one{ir.Imm32(0x3f800000)}; | ||
| 25 | const IR::U32 fail_result{ir.Imm32(0)}; | ||
| 26 | const IR::U32 pass_result{cset.bf == 0 ? one_mask : fp_one}; | ||
| 27 | const IR::U1 cc_test_result{ir.GetFlowTestResult(cset.cc_test)}; | ||
| 28 | const IR::U1 bop_pred{ir.GetPred(cset.bop_pred, cset.neg_bop_pred != 0)}; | ||
| 29 | const IR::U1 pred_result{PredicateCombine(ir, cc_test_result, bop_pred, cset.bop)}; | ||
| 30 | const IR::U32 result{ir.Select(pred_result, pass_result, fail_result)}; | ||
| 31 | X(cset.dest_reg, result); | ||
| 32 | } | ||
| 33 | |||
| 34 | void TranslatorVisitor::CSETP(u64 insn) { | ||
| 35 | union { | ||
| 36 | u64 raw; | ||
| 37 | BitField<0, 3, IR::Pred> dest_pred_b; | ||
| 38 | BitField<3, 3, IR::Pred> dest_pred_a; | ||
| 39 | BitField<8, 5, IR::FlowTest> cc_test; | ||
| 40 | BitField<39, 3, IR::Pred> bop_pred; | ||
| 41 | BitField<42, 1, u64> neg_bop_pred; | ||
| 42 | BitField<45, 2, BooleanOp> bop; | ||
| 43 | } const csetp{insn}; | ||
| 44 | |||
| 45 | const BooleanOp bop{csetp.bop}; | ||
| 46 | const IR::U1 bop_pred{ir.GetPred(csetp.bop_pred, csetp.neg_bop_pred != 0)}; | ||
| 47 | const IR::U1 cc_test_result{ir.GetFlowTestResult(csetp.cc_test)}; | ||
| 48 | const IR::U1 result_a{PredicateCombine(ir, cc_test_result, bop_pred, bop)}; | ||
| 49 | const IR::U1 result_b{PredicateCombine(ir, ir.LogicalNot(cc_test_result), bop_pred, bop)}; | ||
| 50 | ir.SetPred(csetp.dest_pred_a, result_a); | ||
| 51 | ir.SetPred(csetp.dest_pred_b, result_b); | ||
| 52 | } | ||
| 53 | |||
| 54 | } // 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 b31928370..0325f14ea 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) { | |||
| 85 | ThrowNotImplemented(Opcode::CS2R); | 85 | ThrowNotImplemented(Opcode::CS2R); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | void TranslatorVisitor::CSET(u64) { | ||
| 89 | ThrowNotImplemented(Opcode::CSET); | ||
| 90 | } | ||
| 91 | |||
| 92 | void TranslatorVisitor::CSETP(u64) { | ||
| 93 | ThrowNotImplemented(Opcode::CSETP); | ||
| 94 | } | ||
| 95 | |||
| 96 | void TranslatorVisitor::DADD_reg(u64) { | 88 | void TranslatorVisitor::DADD_reg(u64) { |
| 97 | ThrowNotImplemented(Opcode::DADD_reg); | 89 | ThrowNotImplemented(Opcode::DADD_reg); |
| 98 | } | 90 | } |