From 25c68e678a2364433bd0a8b26dd3111a0e387c66 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 6 Mar 2026 06:01:43 +0000 Subject: [PATCH] [shader_recompiler] restore FCSM flag tracker for VOTE.vtg Signed-off-by: lizzie --- .../frontend/ir/ir_emitter.cpp | 37 ++++++++++- .../frontend/ir/ir_emitter.h | 10 ++- src/shader_recompiler/frontend/ir/opcodes.inc | 8 +++ .../frontend/maxwell/translate/impl/vote.cpp | 6 ++ .../ir_opt/ssa_rewrite_pass.cpp | 62 ++++++++++++++++++- 5 files changed, 118 insertions(+), 5 deletions(-) diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index 171161ffd1..9228ab3aa3 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project @@ -205,6 +205,38 @@ void IREmitter::SetOFlag(const U1& value) { Inst(Opcode::SetOFlag, value); } +U1 IREmitter::GetFCSMFlag() { + return Inst(Opcode::GetFCSMFlag); +} + +U1 IREmitter::GetTAFlag() { + return Inst(Opcode::GetTAFlag); +} + +U1 IREmitter::GetTRFlag() { + return Inst(Opcode::GetTRFlag); +} + +U1 IREmitter::GetMXFlag() { + return Inst(Opcode::GetMXFlag); +} + +void IREmitter::SetFCSMFlag(const U1& value) { + Inst(Opcode::SetFCSMFlag, value); +} + +void IREmitter::SetTAFlag(const U1& value) { + Inst(Opcode::SetTAFlag, value); +} + +void IREmitter::SetTRFlag(const U1& value) { + Inst(Opcode::SetTRFlag, value); +} + +void IREmitter::SetMXFlag(const U1& value) { + Inst(Opcode::SetMXFlag, value); +} + static U1 GetFlowTest(IREmitter& ir, FlowTest flow_test) { switch (flow_test) { case FlowTest::F: @@ -264,8 +296,7 @@ static U1 GetFlowTest(IREmitter& ir, FlowTest flow_test) { case FlowTest::RGT: return ir.LogicalAnd(ir.LogicalNot(ir.GetSFlag()), ir.LogicalNot(ir.GetZFlag())); case FlowTest::FCSM_TR: - LOG_WARNING(Shader, "(STUBBED) FCSM_TR"); - return ir.Imm1(false); + return ir.LogicalAnd(ir.GetFCSMFlag(), ir.GetTRFlag()); case FlowTest::CSM_TA: case FlowTest::CSM_TR: case FlowTest::CSM_MX: diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 725eac3951..f09d7e9faa 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project @@ -66,11 +66,19 @@ public: [[nodiscard]] U1 GetSFlag(); [[nodiscard]] U1 GetCFlag(); [[nodiscard]] U1 GetOFlag(); + [[nodiscard]] U1 GetFCSMFlag(); + [[nodiscard]] U1 GetTAFlag(); + [[nodiscard]] U1 GetTRFlag(); + [[nodiscard]] U1 GetMXFlag(); void SetZFlag(const U1& value); void SetSFlag(const U1& value); void SetCFlag(const U1& value); void SetOFlag(const U1& value); + void SetFCSMFlag(const U1& value); + void SetTAFlag(const U1& value); + void SetTRFlag(const U1& value); + void SetMXFlag(const U1& value); [[nodiscard]] U1 Condition(IR::Condition cond); [[nodiscard]] U1 GetFlowTestResult(FlowTest test); diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 960009d89e..53811eaecf 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc @@ -52,10 +52,18 @@ OPCODE(GetZFlag, U1, Void OPCODE(GetSFlag, U1, Void, ) OPCODE(GetCFlag, U1, Void, ) OPCODE(GetOFlag, U1, Void, ) +OPCODE(GetFCSMFlag, U1, Void, ) +OPCODE(GetTAFlag, U1, Void, ) +OPCODE(GetTRFlag, U1, Void, ) +OPCODE(GetMXFlag, U1, Void, ) OPCODE(SetZFlag, Void, U1, ) OPCODE(SetSFlag, Void, U1, ) OPCODE(SetCFlag, Void, U1, ) OPCODE(SetOFlag, Void, U1, ) +OPCODE(SetFCSMFlag, Void, U1, ) +OPCODE(SetTAFlag, Void, U1, ) +OPCODE(SetTRFlag, Void, U1, ) +OPCODE(SetMXFlag, Void, U1, ) OPCODE(WorkgroupId, U32x3, ) OPCODE(LocalInvocationId, U32x3, ) OPCODE(InvocationId, U32, ) diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/vote.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/vote.cpp index 70e490e808..ca6257c97b 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/vote.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/vote.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -48,6 +51,9 @@ void TranslatorVisitor::VOTE(u64 insn) { void TranslatorVisitor::VOTE_vtg(u64) { LOG_WARNING(Shader, "(STUBBED) called"); + auto imm = ir.Imm1(false); + ir.SetFCSMFlag(imm); + ir.SetTRFlag(imm); } } // namespace Shader::Maxwell diff --git a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp index 2bde38a661..1e30506577 100644 --- a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp +++ b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp @@ -39,6 +39,10 @@ struct ZeroFlagTag : FlagTag {}; struct SignFlagTag : FlagTag {}; struct CarryFlagTag : FlagTag {}; struct OverflowFlagTag : FlagTag {}; +struct FCSMFlagTag : FlagTag {}; +struct TAFlagTag : FlagTag {}; +struct TRFlagTag : FlagTag {}; +struct MXFlagTag : FlagTag {}; struct GotoVariable : FlagTag { GotoVariable() = default; @@ -53,7 +57,7 @@ struct IndirectBranchVariable { auto operator<=>(const IndirectBranchVariable&) const noexcept = default; }; -using Variant = std::variant; +using Variant = std::variant; // TODO: majority of these require stable iterators, test with XC beforehand using ValueMap = std::unordered_map; @@ -114,6 +118,34 @@ struct DefTable { overflow_flag.insert_or_assign(block, value); } + const IR::Value& Def(IR::Block* block, FCSMFlagTag) { + return fcsm_flag[block]; + } + void SetDef(IR::Block* block, FCSMFlagTag, const IR::Value& value) { + fcsm_flag.insert_or_assign(block, value); + } + + const IR::Value& Def(IR::Block* block, TAFlagTag) { + return ta_flag[block]; + } + void SetDef(IR::Block* block, TAFlagTag, const IR::Value& value) { + ta_flag.insert_or_assign(block, value); + } + + const IR::Value& Def(IR::Block* block, TRFlagTag) { + return tr_flag[block]; + } + void SetDef(IR::Block* block, TRFlagTag, const IR::Value& value) { + tr_flag.insert_or_assign(block, value); + } + + const IR::Value& Def(IR::Block* block, MXFlagTag) { + return mr_flag[block]; + } + void SetDef(IR::Block* block, MXFlagTag, const IR::Value& value) { + mr_flag.insert_or_assign(block, value); + } + std::array preds; // TODO: Requires stable iterators std::unordered_map goto_vars; @@ -122,6 +154,10 @@ struct DefTable { ValueMap sign_flag; ValueMap carry_flag; ValueMap overflow_flag; + ValueMap fcsm_flag; + ValueMap ta_flag; + ValueMap tr_flag; + ValueMap mr_flag; }; IR::Opcode UndefOpcode(IR::Reg) noexcept { @@ -335,6 +371,18 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) { case IR::Opcode::SetOFlag: pass.WriteVariable(OverflowFlagTag{}, block, inst.Arg(0)); break; + case IR::Opcode::SetFCSMFlag: + pass.WriteVariable(FCSMFlagTag{}, block, inst.Arg(0)); + break; + case IR::Opcode::SetTAFlag: + pass.WriteVariable(TAFlagTag{}, block, inst.Arg(0)); + break; + case IR::Opcode::SetTRFlag: + pass.WriteVariable(TRFlagTag{}, block, inst.Arg(0)); + break; + case IR::Opcode::SetMXFlag: + pass.WriteVariable(MXFlagTag{}, block, inst.Arg(0)); + break; case IR::Opcode::GetRegister: if (const IR::Reg reg{inst.Arg(0).Reg()}; reg != IR::Reg::RZ) { inst.ReplaceUsesWith(pass.ReadVariable(reg, block)); @@ -363,6 +411,18 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) { case IR::Opcode::GetOFlag: inst.ReplaceUsesWith(pass.ReadVariable(OverflowFlagTag{}, block)); break; + case IR::Opcode::GetFCSMFlag: + inst.ReplaceUsesWith(pass.ReadVariable(FCSMFlagTag{}, block)); + break; + case IR::Opcode::GetTAFlag: + inst.ReplaceUsesWith(pass.ReadVariable(TAFlagTag{}, block)); + break; + case IR::Opcode::GetTRFlag: + inst.ReplaceUsesWith(pass.ReadVariable(TRFlagTag{}, block)); + break; + case IR::Opcode::GetMXFlag: + inst.ReplaceUsesWith(pass.ReadVariable(MXFlagTag{}, block)); + break; default: break; }