From f041276b0407d6a2de12298970d74be6d5beb0ee Mon Sep 17 00:00:00 2001 From: psucien Date: Sat, 13 Jul 2024 14:40:39 +0200 Subject: [PATCH] recompiler: added support for discard on export with masked EXEC --- .../backend/spirv/emit_spirv_instructions.h | 1 + .../backend/spirv/emit_spirv_special.cpp | 11 ++++++++++ .../frontend/control_flow_graph.cpp | 22 ++++++++++++++----- .../frontend/control_flow_graph.h | 1 + .../frontend/structured_control_flow.cpp | 1 + .../frontend/translate/export.cpp | 6 +++++ src/shader_recompiler/ir/basic_block.h | 2 ++ src/shader_recompiler/ir/ir_emitter.cpp | 4 ++++ src/shader_recompiler/ir/ir_emitter.h | 1 + src/shader_recompiler/ir/microinstruction.cpp | 1 + src/shader_recompiler/ir/opcodes.inc | 1 + .../ir/passes/shader_info_collection_pass.cpp | 1 + 12 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 495ada5d..e0b19f4f 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -45,6 +45,7 @@ void EmitSetVccHi(EmitContext& ctx); void EmitPrologue(EmitContext& ctx); void EmitEpilogue(EmitContext& ctx); void EmitDiscard(EmitContext& ctx); +void EmitDiscardCond(EmitContext& ctx, Id condition); void EmitBarrier(EmitContext& ctx); void EmitWorkgroupMemoryBarrier(EmitContext& ctx); void EmitDeviceMemoryBarrier(EmitContext& ctx); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp index 0ef985a9..891e41df 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp @@ -14,6 +14,17 @@ void EmitDiscard(EmitContext& ctx) { ctx.OpDemoteToHelperInvocationEXT(); } +void EmitDiscardCond(EmitContext& ctx, Id condition) { + const Id kill_label{ctx.OpLabel()}; + const Id merge_label{ctx.OpLabel()}; + ctx.OpSelectionMerge(merge_label, spv::SelectionControlMask::MaskNone); + ctx.OpBranchConditional(condition, kill_label, merge_label); + ctx.AddLabel(kill_label); + ctx.OpDemoteToHelperInvocationEXT(); + ctx.OpBranch(merge_label); + ctx.AddLabel(merge_label); +} + void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) { throw NotImplementedException("Geometry streams"); } diff --git a/src/shader_recompiler/frontend/control_flow_graph.cpp b/src/shader_recompiler/frontend/control_flow_graph.cpp index 03af1515..5eadae1b 100644 --- a/src/shader_recompiler/frontend/control_flow_graph.cpp +++ b/src/shader_recompiler/frontend/control_flow_graph.cpp @@ -121,7 +121,7 @@ void CFG::EmitBlocks() { void CFG::LinkBlocks() { const auto get_block = [this](u32 address) { - const auto it = blocks.find(address, Compare{}); + auto it = blocks.find(address, Compare{}); ASSERT_MSG(it != blocks.end() && it->begin == address); return &*it; }; @@ -131,7 +131,10 @@ void CFG::LinkBlocks() { // If the block doesn't end with a branch we simply // need to link with the next block. if (!end_inst.IsTerminateInstruction()) { - block.branch_true = get_block(block.end); + auto* next_block = get_block(block.end); + ++next_block->num_predecessors; + + block.branch_true = next_block; block.end_class = EndClass::Branch; continue; } @@ -141,11 +144,20 @@ void CFG::LinkBlocks() { const u32 branch_pc = block.end - end_inst.length; const u32 target_pc = end_inst.BranchTarget(branch_pc); if (end_inst.IsUnconditionalBranch()) { - block.branch_true = get_block(target_pc); + auto* target_block = get_block(target_pc); + ++target_block->num_predecessors; + + block.branch_true = target_block; block.end_class = EndClass::Branch; } else if (end_inst.IsConditionalBranch()) { - block.branch_true = get_block(target_pc); - block.branch_false = get_block(block.end); + auto* target_block = get_block(target_pc); + ++target_block->num_predecessors; + + auto* end_block = get_block(block.end); + ++end_block->num_predecessors; + + block.branch_true = target_block; + block.branch_false = end_block; block.end_class = EndClass::Branch; } else if (end_inst.opcode == Opcode::S_ENDPGM) { const auto& prev_inst = inst_list[block.end_index - 1]; diff --git a/src/shader_recompiler/frontend/control_flow_graph.h b/src/shader_recompiler/frontend/control_flow_graph.h index d343ca7d..07190087 100644 --- a/src/shader_recompiler/frontend/control_flow_graph.h +++ b/src/shader_recompiler/frontend/control_flow_graph.h @@ -36,6 +36,7 @@ struct Block : Hook { u32 end; u32 begin_index; u32 end_index; + u32 num_predecessors{}; IR::Condition cond{}; GcnInst end_inst{}; EndClass end_class{}; diff --git a/src/shader_recompiler/frontend/structured_control_flow.cpp b/src/shader_recompiler/frontend/structured_control_flow.cpp index 6d78448b..346f00aa 100644 --- a/src/shader_recompiler/frontend/structured_control_flow.cpp +++ b/src/shader_recompiler/frontend/structured_control_flow.cpp @@ -631,6 +631,7 @@ private: case StatementType::Code: { ensure_block(); if (!stmt.block->is_dummy) { + current_block->has_multiple_predecessors = stmt.block->num_predecessors > 1; const u32 start = stmt.block->begin_index; const u32 size = stmt.block->end_index - start + 1; Translate(current_block, stmt.block->begin, inst_list.subspan(start, size), diff --git a/src/shader_recompiler/frontend/translate/export.cpp b/src/shader_recompiler/frontend/translate/export.cpp index 74aac4fb..cc631ff2 100644 --- a/src/shader_recompiler/frontend/translate/export.cpp +++ b/src/shader_recompiler/frontend/translate/export.cpp @@ -1,11 +1,17 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/logging/log.h" #include "shader_recompiler/frontend/translate/translate.h" namespace Shader::Gcn { void Translator::EXP(const GcnInst& inst) { + if (ir.block->has_multiple_predecessors) { + LOG_WARNING(Render_Recompiler, "An ambiguous export appeared in translation"); + ir.Discard(ir.LogicalNot(ir.GetExec())); + } + const auto& exp = inst.control.exp; const IR::Attribute attrib{exp.target}; const std::array vsrc = { diff --git a/src/shader_recompiler/ir/basic_block.h b/src/shader_recompiler/ir/basic_block.h index 5cd36420..5a7036c6 100644 --- a/src/shader_recompiler/ir/basic_block.h +++ b/src/shader_recompiler/ir/basic_block.h @@ -149,6 +149,8 @@ public: std::array ssa_sreg_values; std::array ssa_vreg_values; + bool has_multiple_predecessors{false}; + private: /// Memory pool for instruction list ObjectPool* inst_pool; diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index 44128f23..5dabbb4c 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -115,6 +115,10 @@ void IREmitter::Discard() { Inst(Opcode::Discard); } +void IREmitter::Discard(const U1& cond) { + Inst(Opcode::DiscardCond, cond); +} + void IREmitter::Barrier() { Inst(Opcode::Barrier); } diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index 51ab9d03..5d6fd714 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -42,6 +42,7 @@ public: void Prologue(); void Epilogue(); void Discard(); + void Discard(const U1& cond); void Barrier(); void WorkgroupMemoryBarrier(); diff --git a/src/shader_recompiler/ir/microinstruction.cpp b/src/shader_recompiler/ir/microinstruction.cpp index f823980a..aa03e3d6 100644 --- a/src/shader_recompiler/ir/microinstruction.cpp +++ b/src/shader_recompiler/ir/microinstruction.cpp @@ -49,6 +49,7 @@ bool Inst::MayHaveSideEffects() const noexcept { case Opcode::Prologue: case Opcode::Epilogue: case Opcode::Discard: + case Opcode::DiscardCond: case Opcode::SetAttribute: case Opcode::StoreBufferF32: case Opcode::StoreBufferF32x2: diff --git a/src/shader_recompiler/ir/opcodes.inc b/src/shader_recompiler/ir/opcodes.inc index c22db3e0..94ef1784 100644 --- a/src/shader_recompiler/ir/opcodes.inc +++ b/src/shader_recompiler/ir/opcodes.inc @@ -13,6 +13,7 @@ OPCODE(PhiMove, Void, Opaq OPCODE(Prologue, Void, ) OPCODE(Epilogue, Void, ) OPCODE(Discard, Void, ) +OPCODE(DiscardCond, Void, U1, ) // Constant memory operations OPCODE(ReadConst, U32, U32x2, U32, ) diff --git a/src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp b/src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp index 1cec237f..b51ce94e 100644 --- a/src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp +++ b/src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp @@ -37,6 +37,7 @@ void Visit(Info& info, IR::Inst& inst) { info.uses_group_quad = true; break; case IR::Opcode::Discard: + case IR::Opcode::DiscardCond: info.has_discard = true; break; case IR::Opcode::ImageGather: