Browse Source

[shader_recompiler] restore FCSM flag tracker for VOTE.vtg

Signed-off-by: lizzie <lizzie@eden-emu.dev>
lizzie/restore-fcsm
lizzie 2 days ago
parent
commit
25c68e678a
  1. 37
      src/shader_recompiler/frontend/ir/ir_emitter.cpp
  2. 10
      src/shader_recompiler/frontend/ir/ir_emitter.h
  3. 8
      src/shader_recompiler/frontend/ir/opcodes.inc
  4. 6
      src/shader_recompiler/frontend/maxwell/translate/impl/vote.cpp
  5. 62
      src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp

37
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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@ -205,6 +205,38 @@ void IREmitter::SetOFlag(const U1& value) {
Inst(Opcode::SetOFlag, value); Inst(Opcode::SetOFlag, value);
} }
U1 IREmitter::GetFCSMFlag() {
return Inst<U1>(Opcode::GetFCSMFlag);
}
U1 IREmitter::GetTAFlag() {
return Inst<U1>(Opcode::GetTAFlag);
}
U1 IREmitter::GetTRFlag() {
return Inst<U1>(Opcode::GetTRFlag);
}
U1 IREmitter::GetMXFlag() {
return Inst<U1>(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) { static U1 GetFlowTest(IREmitter& ir, FlowTest flow_test) {
switch (flow_test) { switch (flow_test) {
case FlowTest::F: case FlowTest::F:
@ -264,8 +296,7 @@ static U1 GetFlowTest(IREmitter& ir, FlowTest flow_test) {
case FlowTest::RGT: case FlowTest::RGT:
return ir.LogicalAnd(ir.LogicalNot(ir.GetSFlag()), ir.LogicalNot(ir.GetZFlag())); return ir.LogicalAnd(ir.LogicalNot(ir.GetSFlag()), ir.LogicalNot(ir.GetZFlag()));
case FlowTest::FCSM_TR: 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_TA:
case FlowTest::CSM_TR: case FlowTest::CSM_TR:
case FlowTest::CSM_MX: case FlowTest::CSM_MX:

10
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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@ -66,11 +66,19 @@ public:
[[nodiscard]] U1 GetSFlag(); [[nodiscard]] U1 GetSFlag();
[[nodiscard]] U1 GetCFlag(); [[nodiscard]] U1 GetCFlag();
[[nodiscard]] U1 GetOFlag(); [[nodiscard]] U1 GetOFlag();
[[nodiscard]] U1 GetFCSMFlag();
[[nodiscard]] U1 GetTAFlag();
[[nodiscard]] U1 GetTRFlag();
[[nodiscard]] U1 GetMXFlag();
void SetZFlag(const U1& value); void SetZFlag(const U1& value);
void SetSFlag(const U1& value); void SetSFlag(const U1& value);
void SetCFlag(const U1& value); void SetCFlag(const U1& value);
void SetOFlag(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 Condition(IR::Condition cond);
[[nodiscard]] U1 GetFlowTestResult(FlowTest test); [[nodiscard]] U1 GetFlowTestResult(FlowTest test);

8
src/shader_recompiler/frontend/ir/opcodes.inc

@ -52,10 +52,18 @@ OPCODE(GetZFlag, U1, Void
OPCODE(GetSFlag, U1, Void, ) OPCODE(GetSFlag, U1, Void, )
OPCODE(GetCFlag, U1, Void, ) OPCODE(GetCFlag, U1, Void, )
OPCODE(GetOFlag, 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(SetZFlag, Void, U1, )
OPCODE(SetSFlag, Void, U1, ) OPCODE(SetSFlag, Void, U1, )
OPCODE(SetCFlag, Void, U1, ) OPCODE(SetCFlag, Void, U1, )
OPCODE(SetOFlag, 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(WorkgroupId, U32x3, )
OPCODE(LocalInvocationId, U32x3, ) OPCODE(LocalInvocationId, U32x3, )
OPCODE(InvocationId, U32, ) OPCODE(InvocationId, U32, )

6
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-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -48,6 +51,9 @@ void TranslatorVisitor::VOTE(u64 insn) {
void TranslatorVisitor::VOTE_vtg(u64) { void TranslatorVisitor::VOTE_vtg(u64) {
LOG_WARNING(Shader, "(STUBBED) called"); LOG_WARNING(Shader, "(STUBBED) called");
auto imm = ir.Imm1(false);
ir.SetFCSMFlag(imm);
ir.SetTRFlag(imm);
} }
} // namespace Shader::Maxwell } // namespace Shader::Maxwell

62
src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp

@ -39,6 +39,10 @@ struct ZeroFlagTag : FlagTag {};
struct SignFlagTag : FlagTag {}; struct SignFlagTag : FlagTag {};
struct CarryFlagTag : FlagTag {}; struct CarryFlagTag : FlagTag {};
struct OverflowFlagTag : FlagTag {}; struct OverflowFlagTag : FlagTag {};
struct FCSMFlagTag : FlagTag {};
struct TAFlagTag : FlagTag {};
struct TRFlagTag : FlagTag {};
struct MXFlagTag : FlagTag {};
struct GotoVariable : FlagTag { struct GotoVariable : FlagTag {
GotoVariable() = default; GotoVariable() = default;
@ -53,7 +57,7 @@ struct IndirectBranchVariable {
auto operator<=>(const IndirectBranchVariable&) const noexcept = default; auto operator<=>(const IndirectBranchVariable&) const noexcept = default;
}; };
using Variant = std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag, OverflowFlagTag, GotoVariable, IndirectBranchVariable>;
using Variant = std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag, OverflowFlagTag, FCSMFlagTag, TAFlagTag, TRFlagTag, MXFlagTag, GotoVariable, IndirectBranchVariable>;
// TODO: majority of these require stable iterators, test with XC beforehand // TODO: majority of these require stable iterators, test with XC beforehand
using ValueMap = std::unordered_map<IR::Block*, IR::Value>; using ValueMap = std::unordered_map<IR::Block*, IR::Value>;
@ -114,6 +118,34 @@ struct DefTable {
overflow_flag.insert_or_assign(block, value); 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<ValueMap, IR::NUM_USER_PREDS> preds; std::array<ValueMap, IR::NUM_USER_PREDS> preds;
// TODO: Requires stable iterators // TODO: Requires stable iterators
std::unordered_map<u32, ValueMap> goto_vars; std::unordered_map<u32, ValueMap> goto_vars;
@ -122,6 +154,10 @@ struct DefTable {
ValueMap sign_flag; ValueMap sign_flag;
ValueMap carry_flag; ValueMap carry_flag;
ValueMap overflow_flag; ValueMap overflow_flag;
ValueMap fcsm_flag;
ValueMap ta_flag;
ValueMap tr_flag;
ValueMap mr_flag;
}; };
IR::Opcode UndefOpcode(IR::Reg) noexcept { IR::Opcode UndefOpcode(IR::Reg) noexcept {
@ -335,6 +371,18 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
case IR::Opcode::SetOFlag: case IR::Opcode::SetOFlag:
pass.WriteVariable(OverflowFlagTag{}, block, inst.Arg(0)); pass.WriteVariable(OverflowFlagTag{}, block, inst.Arg(0));
break; 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: case IR::Opcode::GetRegister:
if (const IR::Reg reg{inst.Arg(0).Reg()}; reg != IR::Reg::RZ) { if (const IR::Reg reg{inst.Arg(0).Reg()}; reg != IR::Reg::RZ) {
inst.ReplaceUsesWith(pass.ReadVariable(reg, block)); inst.ReplaceUsesWith(pass.ReadVariable(reg, block));
@ -363,6 +411,18 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
case IR::Opcode::GetOFlag: case IR::Opcode::GetOFlag:
inst.ReplaceUsesWith(pass.ReadVariable(OverflowFlagTag{}, block)); inst.ReplaceUsesWith(pass.ReadVariable(OverflowFlagTag{}, block));
break; 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: default:
break; break;
} }

Loading…
Cancel
Save