From ca9901867e91cd0be0cc75094ee8ea2fb2767c47 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 25 Aug 2019 15:32:00 -0400 Subject: vk_shader_compiler: Implement the decompiler in SPIR-V --- .../renderer_vulkan/vk_shader_decompiler.cpp | 298 +++++++++++++++++++-- 1 file changed, 276 insertions(+), 22 deletions(-) (limited to 'src/video_core/renderer_vulkan') diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 77fc58f25..505e49570 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -88,6 +88,9 @@ bool IsPrecise(Operation operand) { } // namespace +class ASTDecompiler; +class ExprDecompiler; + class SPIRVDecompiler : public Sirit::Module { public: explicit SPIRVDecompiler(const VKDevice& device, const ShaderIR& ir, ShaderStage stage) @@ -97,27 +100,7 @@ public: AddExtension("SPV_KHR_variable_pointers"); } - void Decompile() { - AllocateBindings(); - AllocateLabels(); - - DeclareVertex(); - DeclareGeometry(); - DeclareFragment(); - DeclareRegisters(); - DeclarePredicates(); - DeclareLocalMemory(); - DeclareInternalFlags(); - DeclareInputAttributes(); - DeclareOutputAttributes(); - DeclareConstantBuffers(); - DeclareGlobalBuffers(); - DeclareSamplers(); - - execute_function = - Emit(OpFunction(t_void, spv::FunctionControlMask::Inline, TypeFunction(t_void))); - Emit(OpLabel()); - + void DecompileBranchMode() { const u32 first_address = ir.GetBasicBlocks().begin()->first; const Id loop_label = OpLabel("loop"); const Id merge_label = OpLabel("merge"); @@ -174,6 +157,43 @@ public: Emit(continue_label); Emit(OpBranch(loop_label)); Emit(merge_label); + } + + void DecompileAST(); + + void Decompile() { + const bool is_fully_decompiled = ir.IsDecompiled(); + AllocateBindings(); + if (!is_fully_decompiled) { + AllocateLabels(); + } + + DeclareVertex(); + DeclareGeometry(); + DeclareFragment(); + DeclareRegisters(); + DeclarePredicates(); + if (is_fully_decompiled) { + DeclareFlowVariables(); + } + DeclareLocalMemory(); + DeclareInternalFlags(); + DeclareInputAttributes(); + DeclareOutputAttributes(); + DeclareConstantBuffers(); + DeclareGlobalBuffers(); + DeclareSamplers(); + + execute_function = + Emit(OpFunction(t_void, spv::FunctionControlMask::Inline, TypeFunction(t_void))); + Emit(OpLabel()); + + if (is_fully_decompiled) { + DecompileAST(); + } else { + DecompileBranchMode(); + } + Emit(OpReturn()); Emit(OpFunctionEnd()); } @@ -206,6 +226,9 @@ public: } private: + friend class ASTDecompiler; + friend class ExprDecompiler; + static constexpr auto INTERNAL_FLAGS_COUNT = static_cast(InternalFlag::Amount); void AllocateBindings() { @@ -294,6 +317,14 @@ private: } } + void DeclareFlowVariables() { + for (u32 i = 0; i < ir.GetASTNumVariables(); i++) { + const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false); + Name(id, fmt::format("flow_var_{}", static_cast(i))); + flow_variables.emplace(i, AddGlobalVariable(id)); + } + } + void DeclareLocalMemory() { if (const u64 local_memory_size = header.GetLocalMemorySize(); local_memory_size > 0) { const auto element_count = static_cast(Common::AlignUp(local_memory_size, 4) / 4); @@ -1019,7 +1050,7 @@ private: return {}; } - Id Exit(Operation operation) { + Id PreExit() { switch (stage) { case ShaderStage::Vertex: { // TODO(Rodrigo): We should use VK_EXT_depth_range_unrestricted instead, but it doesn't @@ -1067,6 +1098,11 @@ private: } } + return {}; + } + + Id Exit(Operation operation) { + PreExit(); BranchingOp([&]() { Emit(OpReturn()); }); return {}; } @@ -1545,6 +1581,7 @@ private: Id per_vertex{}; std::map registers; std::map predicates; + std::map flow_variables; Id local_memory{}; std::array internal_flags{}; std::map input_attributes; @@ -1580,6 +1617,223 @@ private: std::map labels; }; +class ExprDecompiler { +public: + ExprDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {} + + void operator()(VideoCommon::Shader::ExprAnd& expr) { + const Id type_def = decomp.GetTypeDefinition(Type::Bool); + const Id op1 = Visit(expr.operand1); + const Id op2 = Visit(expr.operand2); + current_id = decomp.Emit(decomp.OpLogicalAnd(type_def, op1, op2)); + } + + void operator()(VideoCommon::Shader::ExprOr& expr) { + const Id type_def = decomp.GetTypeDefinition(Type::Bool); + const Id op1 = Visit(expr.operand1); + const Id op2 = Visit(expr.operand2); + current_id = decomp.Emit(decomp.OpLogicalOr(type_def, op1, op2)); + } + + void operator()(VideoCommon::Shader::ExprNot& expr) { + const Id type_def = decomp.GetTypeDefinition(Type::Bool); + const Id op1 = Visit(expr.operand1); + current_id = decomp.Emit(decomp.OpLogicalNot(type_def, op1)); + } + + void operator()(VideoCommon::Shader::ExprPredicate& expr) { + auto pred = static_cast(expr.predicate); + current_id = decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.predicates.at(pred))); + } + + void operator()(VideoCommon::Shader::ExprCondCode& expr) { + Node cc = decomp.ir.GetConditionCode(expr.cc); + Id target; + + if (const auto pred = std::get_if(&*cc)) { + const auto index = pred->GetIndex(); + switch (index) { + case Tegra::Shader::Pred::NeverExecute: + target = decomp.v_false; + case Tegra::Shader::Pred::UnusedIndex: + target = decomp.v_true; + default: + target = decomp.predicates.at(index); + } + } else if (const auto flag = std::get_if(&*cc)) { + target = decomp.internal_flags.at(static_cast(flag->GetFlag())); + } + current_id = decomp.Emit(decomp.OpLoad(decomp.t_bool, target)); + } + + void operator()(VideoCommon::Shader::ExprVar& expr) { + current_id = decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.flow_variables.at(expr.var_index))); + } + + void operator()(VideoCommon::Shader::ExprBoolean& expr) { + current_id = expr.value ? decomp.v_true : decomp.v_false; + } + + Id GetResult() { + return current_id; + } + + Id Visit(VideoCommon::Shader::Expr& node) { + std::visit(*this, *node); + return current_id; + } + +private: + Id current_id; + SPIRVDecompiler& decomp; +}; + +class ASTDecompiler { +public: + ASTDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {} + + void operator()(VideoCommon::Shader::ASTProgram& ast) { + ASTNode current = ast.nodes.GetFirst(); + while (current) { + Visit(current); + current = current->GetNext(); + } + } + + void operator()(VideoCommon::Shader::ASTIfThen& ast) { + ExprDecompiler expr_parser{decomp}; + const Id condition = expr_parser.Visit(ast.condition); + const Id then_label = decomp.OpLabel(); + const Id endif_label = decomp.OpLabel(); + decomp.Emit(decomp.OpSelectionMerge(endif_label, spv::SelectionControlMask::MaskNone)); + decomp.Emit(decomp.OpBranchConditional(condition, then_label, endif_label)); + decomp.Emit(then_label); + ASTNode current = ast.nodes.GetFirst(); + while (current) { + Visit(current); + current = current->GetNext(); + } + decomp.Emit(endif_label); + } + + void operator()(VideoCommon::Shader::ASTIfElse& ast) { + UNREACHABLE(); + } + + void operator()(VideoCommon::Shader::ASTBlockEncoded& ast) { + UNREACHABLE(); + } + + void operator()(VideoCommon::Shader::ASTBlockDecoded& ast) { + decomp.VisitBasicBlock(ast.nodes); + } + + void operator()(VideoCommon::Shader::ASTVarSet& ast) { + ExprDecompiler expr_parser{decomp}; + const Id condition = expr_parser.Visit(ast.condition); + decomp.Emit(decomp.OpStore(decomp.flow_variables.at(ast.index), condition)); + } + + void operator()(VideoCommon::Shader::ASTLabel& ast) { + // Do nothing + } + + void operator()(VideoCommon::Shader::ASTGoto& ast) { + UNREACHABLE(); + } + + void operator()(VideoCommon::Shader::ASTDoWhile& ast) { + const Id loop_label = decomp.OpLabel(); + const Id endloop_label = decomp.OpLabel(); + const Id loop_start_block = decomp.OpLabel(); + const Id loop_end_block = decomp.OpLabel(); + current_loop_exit = endloop_label; + decomp.Emit(loop_label); + decomp.Emit(decomp.OpLoopMerge(endloop_label, loop_end_block, spv::LoopControlMask::MaskNone)); + decomp.Emit(decomp.OpBranch(loop_start_block)); + decomp.Emit(loop_start_block); + ASTNode current = ast.nodes.GetFirst(); + while (current) { + Visit(current); + current = current->GetNext(); + } + decomp.Emit(decomp.OpBranch(loop_end_block)); + decomp.Emit(loop_end_block); + ExprDecompiler expr_parser{decomp}; + const Id condition = expr_parser.Visit(ast.condition); + decomp.Emit(decomp.OpBranchConditional(condition, loop_label, endloop_label)); + decomp.Emit(endloop_label); + } + + void operator()(VideoCommon::Shader::ASTReturn& ast) { + bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); + if (!is_true) { + ExprDecompiler expr_parser{decomp}; + const Id condition = expr_parser.Visit(ast.condition); + const Id then_label = decomp.OpLabel(); + const Id endif_label = decomp.OpLabel(); + decomp.Emit(decomp.OpSelectionMerge(endif_label, spv::SelectionControlMask::MaskNone)); + decomp.Emit(decomp.OpBranchConditional(condition, then_label, endif_label)); + decomp.Emit(then_label); + if (ast.kills) { + decomp.Emit(decomp.OpKill()); + } else { + decomp.PreExit(); + decomp.Emit(decomp.OpReturn()); + } + decomp.Emit(endif_label); + } else { + decomp.Emit(decomp.OpLabel()); + if (ast.kills) { + decomp.Emit(decomp.OpKill()); + } else { + decomp.PreExit(); + decomp.Emit(decomp.OpReturn()); + } + decomp.Emit(decomp.OpLabel()); + } + } + + void operator()(VideoCommon::Shader::ASTBreak& ast) { + bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); + if (!is_true) { + ExprDecompiler expr_parser{decomp}; + const Id condition = expr_parser.Visit(ast.condition); + const Id then_label = decomp.OpLabel(); + const Id endif_label = decomp.OpLabel(); + decomp.Emit(decomp.OpSelectionMerge(endif_label, spv::SelectionControlMask::MaskNone)); + decomp.Emit(decomp.OpBranchConditional(condition, then_label, endif_label)); + decomp.Emit(then_label); + decomp.Emit(decomp.OpBranch(current_loop_exit)); + decomp.Emit(endif_label); + } else { + decomp.Emit(decomp.OpLabel()); + decomp.Emit(decomp.OpBranch(current_loop_exit)); + decomp.Emit(decomp.OpLabel()); + } + } + + void Visit(VideoCommon::Shader::ASTNode& node) { + std::visit(*this, *node->GetInnerData()); + } + +private: + SPIRVDecompiler& decomp; + Id current_loop_exit; +}; + +void SPIRVDecompiler::DecompileAST() { + u32 num_flow_variables = ir.GetASTNumVariables(); + for (u32 i = 0; i < num_flow_variables; i++) { + const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false); + Name(id, fmt::format("flow_var_{}", i)); + flow_variables.emplace(i, AddGlobalVariable(id)); + } + ASTDecompiler decompiler{*this}; + VideoCommon::Shader::ASTNode program = ir.GetASTProgram(); + decompiler.Visit(program); +} + DecompilerResult Decompile(const VKDevice& device, const VideoCommon::Shader::ShaderIR& ir, Maxwell::ShaderStage stage) { auto decompiler = std::make_unique(device, ir, stage); -- cgit v1.2.3 From 2e9a810423ef36178ac3947f8feeb7b9a5b29bce Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 20 Sep 2019 21:12:06 -0400 Subject: Shader_IR: allow else derivation to be optional. --- src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | 6 ++++-- src/video_core/shader/ast.cpp | 9 ++++++--- src/video_core/shader/ast.h | 3 ++- src/video_core/shader/compiler_settings.h | 3 ++- src/video_core/shader/control_flow.cpp | 3 ++- src/video_core/shader/control_flow.h | 2 +- src/video_core/shader/shader_ir.cpp | 2 +- 7 files changed, 18 insertions(+), 10 deletions(-) (limited to 'src/video_core/renderer_vulkan') diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 505e49570..72fbc69c4 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -1667,7 +1667,8 @@ public: } void operator()(VideoCommon::Shader::ExprVar& expr) { - current_id = decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.flow_variables.at(expr.var_index))); + current_id = + decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.flow_variables.at(expr.var_index))); } void operator()(VideoCommon::Shader::ExprBoolean& expr) { @@ -1749,7 +1750,8 @@ public: const Id loop_end_block = decomp.OpLabel(); current_loop_exit = endloop_label; decomp.Emit(loop_label); - decomp.Emit(decomp.OpLoopMerge(endloop_label, loop_end_block, spv::LoopControlMask::MaskNone)); + decomp.Emit( + decomp.OpLoopMerge(endloop_label, loop_end_block, spv::LoopControlMask::MaskNone)); decomp.Emit(decomp.OpBranch(loop_start_block)); decomp.Emit(loop_start_block); ASTNode current = ast.nodes.GetFirst(); diff --git a/src/video_core/shader/ast.cpp b/src/video_core/shader/ast.cpp index 74b9a8f9a..7e5e916ab 100644 --- a/src/video_core/shader/ast.cpp +++ b/src/video_core/shader/ast.cpp @@ -363,7 +363,8 @@ std::string ASTManager::Print() { return printer.GetResult(); } -ASTManager::ASTManager(bool full_decompile) : full_decompile{full_decompile} {}; +ASTManager::ASTManager(bool full_decompile, bool disable_else_derivation) + : full_decompile{full_decompile}, disable_else_derivation{disable_else_derivation} {}; ASTManager::~ASTManager() { Clear(); @@ -378,7 +379,8 @@ void ASTManager::Init() { ASTManager::ASTManager(ASTManager&& other) : labels_map(std::move(other.labels_map)), labels_count{other.labels_count}, gotos(std::move(other.gotos)), labels(std::move(other.labels)), variables{other.variables}, - program{other.program}, main_node{other.main_node}, false_condition{other.false_condition} { + program{other.program}, main_node{other.main_node}, false_condition{other.false_condition}, + disable_else_derivation{other.disable_else_derivation} { other.main_node.reset(); } @@ -392,6 +394,7 @@ ASTManager& ASTManager::operator=(ASTManager&& other) { program = other.program; main_node = other.main_node; false_condition = other.false_condition; + disable_else_derivation = other.disable_else_derivation; other.main_node.reset(); return *this; @@ -641,7 +644,7 @@ void ASTManager::EncloseIfThen(ASTNode goto_node, ASTNode label) { ASTNode prev = goto_node->GetPrevious(); Expr condition = goto_node->GetGotoCondition(); bool do_else = false; - if (prev->IsIfThen()) { + if (!disable_else_derivation && prev->IsIfThen()) { Expr if_condition = prev->GetIfCondition(); do_else = ExprAreEqual(if_condition, condition); } diff --git a/src/video_core/shader/ast.h b/src/video_core/shader/ast.h index 12db336df..1b73f301f 100644 --- a/src/video_core/shader/ast.h +++ b/src/video_core/shader/ast.h @@ -298,7 +298,7 @@ private: class ASTManager final { public: - ASTManager(bool full_decompile); + ASTManager(bool full_decompile, bool disable_else_derivation); ~ASTManager(); ASTManager(const ASTManager& o) = delete; @@ -378,6 +378,7 @@ private: } bool full_decompile{}; + bool disable_else_derivation{}; std::unordered_map labels_map{}; u32 labels_count{}; std::vector labels{}; diff --git a/src/video_core/shader/compiler_settings.h b/src/video_core/shader/compiler_settings.h index e1fb5bc3a..916018c01 100644 --- a/src/video_core/shader/compiler_settings.h +++ b/src/video_core/shader/compiler_settings.h @@ -19,7 +19,8 @@ enum class CompileDepth : u32 { std::string CompileDepthAsString(CompileDepth cd); struct CompilerSettings { - CompileDepth depth; + CompileDepth depth{CompileDepth::NoFlowStack}; + bool disable_else_derivation{true}; }; } // namespace VideoCommon::Shader diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index c4351969b..c2fa734e7 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp @@ -516,7 +516,8 @@ std::unique_ptr ScanFlow(const ProgramCode& program_code, std::sort(state.block_info.begin(), state.block_info.end(), [](const BlockInfo& a, const BlockInfo& b) -> bool { return a.start < b.start; }); if (decompiled && settings.depth != CompileDepth::NoFlowStack) { - ASTManager manager{settings.depth != CompileDepth::DecompileBackwards}; + ASTManager manager{settings.depth != CompileDepth::DecompileBackwards, + settings.disable_else_derivation}; state.manager = &manager; DecompileShader(state); decompiled = state.manager->IsFullyDecompiled(); diff --git a/src/video_core/shader/control_flow.h b/src/video_core/shader/control_flow.h index 8d0d08422..74e54a5c7 100644 --- a/src/video_core/shader/control_flow.h +++ b/src/video_core/shader/control_flow.h @@ -72,7 +72,7 @@ struct ShaderCharacteristics { std::set labels{}; u32 start{}; u32 end{}; - ASTManager manager{true}; + ASTManager manager{true, true}; CompilerSettings settings{}; }; diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index 04e364634..c1f2b88c8 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp @@ -25,7 +25,7 @@ using Tegra::Shader::Register; ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset, const std::size_t size, CompilerSettings settings) : program_code{program_code}, main_offset{main_offset}, program_size{size}, basic_blocks{}, - program_manager{true}, settings{settings} { + program_manager{true, true}, settings{settings} { Decode(); } -- cgit v1.2.3 From 466cd52ad47b125182baf1544c44e52a741fa58f Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 21 Sep 2019 00:45:13 -0400 Subject: vk_shader_compiler: Correct SPIR-V AST Decompiling --- src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/video_core/renderer_vulkan') diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 72fbc69c4..4527e9261 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -1714,6 +1714,7 @@ public: Visit(current); current = current->GetNext(); } + decomp.Emit(decomp.OpBranch(endif_label)); decomp.Emit(endif_label); } @@ -1749,6 +1750,7 @@ public: const Id loop_start_block = decomp.OpLabel(); const Id loop_end_block = decomp.OpLabel(); current_loop_exit = endloop_label; + decomp.Emit(decomp.OpBranch(loop_label)); decomp.Emit(loop_label); decomp.Emit( decomp.OpLoopMerge(endloop_label, loop_end_block, spv::LoopControlMask::MaskNone)); @@ -1759,8 +1761,6 @@ public: Visit(current); current = current->GetNext(); } - decomp.Emit(decomp.OpBranch(loop_end_block)); - decomp.Emit(loop_end_block); ExprDecompiler expr_parser{decomp}; const Id condition = expr_parser.Visit(ast.condition); decomp.Emit(decomp.OpBranchConditional(condition, loop_label, endloop_label)); @@ -1785,7 +1785,9 @@ public: } decomp.Emit(endif_label); } else { - decomp.Emit(decomp.OpLabel()); + const Id next_block = decomp.OpLabel(); + decomp.Emit(decomp.OpBranch(next_block)); + decomp.Emit(next_block); if (ast.kills) { decomp.Emit(decomp.OpKill()); } else { @@ -1809,7 +1811,9 @@ public: decomp.Emit(decomp.OpBranch(current_loop_exit)); decomp.Emit(endif_label); } else { - decomp.Emit(decomp.OpLabel()); + const Id next_block = decomp.OpLabel(); + decomp.Emit(decomp.OpBranch(next_block)); + decomp.Emit(next_block); decomp.Emit(decomp.OpBranch(current_loop_exit)); decomp.Emit(decomp.OpLabel()); } @@ -1834,6 +1838,9 @@ void SPIRVDecompiler::DecompileAST() { ASTDecompiler decompiler{*this}; VideoCommon::Shader::ASTNode program = ir.GetASTProgram(); decompiler.Visit(program); + const Id next_block = OpLabel(); + Emit(OpBranch(next_block)); + Emit(next_block); } DecompilerResult Decompile(const VKDevice& device, const VideoCommon::Shader::ShaderIR& ir, -- cgit v1.2.3 From 100a4bd98856cf16c1fe16b6c1f1ab2863916c37 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 22 Sep 2019 20:15:09 -0400 Subject: vk_shader_compiler: Don't enclose branches with if(true) to avoid crashing AMD --- .../renderer_vulkan/vk_shader_decompiler.cpp | 49 +++++++++++++++------- 1 file changed, 33 insertions(+), 16 deletions(-) (limited to 'src/video_core/renderer_vulkan') diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 4527e9261..11effe4a1 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -646,7 +646,9 @@ private: Emit(OpBranchConditional(condition, true_label, skip_label)); Emit(true_label); + ++conditional_nest_count; VisitBasicBlock(conditional->GetCode()); + --conditional_nest_count; Emit(OpBranch(skip_label)); Emit(skip_label); @@ -1011,7 +1013,10 @@ private: UNIMPLEMENTED_IF(!target); Emit(OpStore(jmp_to, Constant(t_uint, target->GetValue()))); - BranchingOp([&]() { Emit(OpBranch(continue_label)); }); + Emit(OpBranch(continue_label)); + if (conditional_nest_count == 0) { + Emit(OpLabel()); + } return {}; } @@ -1019,7 +1024,10 @@ private: const Id op_a = VisitOperand(operation, 0); Emit(OpStore(jmp_to, op_a)); - BranchingOp([&]() { Emit(OpBranch(continue_label)); }); + Emit(OpBranch(continue_label)); + if (conditional_nest_count == 0) { + Emit(OpLabel()); + } return {}; } @@ -1046,7 +1054,10 @@ private: Emit(OpStore(flow_stack_top, previous)); Emit(OpStore(jmp_to, target)); - BranchingOp([&]() { Emit(OpBranch(continue_label)); }); + Emit(OpBranch(continue_label)); + if (conditional_nest_count == 0) { + Emit(OpLabel()); + } return {}; } @@ -1103,12 +1114,28 @@ private: Id Exit(Operation operation) { PreExit(); - BranchingOp([&]() { Emit(OpReturn()); }); + if (conditional_nest_count > 0) { + Emit(OpReturn()); + } else { + const Id dummy = OpLabel(); + Emit(OpBranch(dummy)); + Emit(dummy); + Emit(OpReturn()); + Emit(OpLabel()); + } return {}; } Id Discard(Operation operation) { - BranchingOp([&]() { Emit(OpKill()); }); + if (conditional_nest_count > 0) { + Emit(OpKill()); + } else { + const Id dummy = OpLabel(); + Emit(OpBranch(dummy)); + Emit(dummy); + Emit(OpKill()); + Emit(OpLabel()); + } return {}; } @@ -1303,17 +1330,6 @@ private: return {}; } - void BranchingOp(std::function call) { - const Id true_label = OpLabel(); - const Id skip_label = OpLabel(); - Emit(OpSelectionMerge(skip_label, spv::SelectionControlMask::Flatten)); - Emit(OpBranchConditional(v_true, true_label, skip_label, 1, 0)); - Emit(true_label); - call(); - - Emit(skip_label); - } - std::tuple CreateFlowStack() { // TODO(Rodrigo): Figure out the actual depth of the flow stack, for now it seems unlikely // that shaders will use 20 nested SSYs and PBKs. @@ -1519,6 +1535,7 @@ private: const ShaderIR& ir; const ShaderStage stage; const Tegra::Shader::Header header; + u64 conditional_nest_count{}; const Id t_void = Name(TypeVoid(), "void"); -- cgit v1.2.3 From 000ad558dd21a0f1f0be57ddbb59540956314896 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 24 Sep 2019 10:57:45 -0400 Subject: vk_shader_decompiler: Clean code and be const correct. --- src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 2 +- src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'src/video_core/renderer_vulkan') diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 572fae353..bff1067a4 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -19,8 +19,8 @@ #include "video_core/renderer_opengl/gl_device.h" #include "video_core/renderer_opengl/gl_rasterizer.h" #include "video_core/renderer_opengl/gl_shader_decompiler.h" -#include "video_core/shader/node.h" #include "video_core/shader/ast.h" +#include "video_core/shader/node.h" #include "video_core/shader/shader_ir.h" namespace OpenGL::GLShader { diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 11effe4a1..4bc7da198 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -1659,12 +1659,12 @@ public: } void operator()(VideoCommon::Shader::ExprPredicate& expr) { - auto pred = static_cast(expr.predicate); + const auto pred = static_cast(expr.predicate); current_id = decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.predicates.at(pred))); } void operator()(VideoCommon::Shader::ExprCondCode& expr) { - Node cc = decomp.ir.GetConditionCode(expr.cc); + const Node cc = decomp.ir.GetConditionCode(expr.cc); Id target; if (const auto pred = std::get_if(&*cc)) { @@ -1785,8 +1785,7 @@ public: } void operator()(VideoCommon::Shader::ASTReturn& ast) { - bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); - if (!is_true) { + if (!VideoCommon::Shader::ExprIsTrue(ast.condition)) { ExprDecompiler expr_parser{decomp}; const Id condition = expr_parser.Visit(ast.condition); const Id then_label = decomp.OpLabel(); @@ -1816,8 +1815,7 @@ public: } void operator()(VideoCommon::Shader::ASTBreak& ast) { - bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); - if (!is_true) { + if (!VideoCommon::Shader::ExprIsTrue(ast.condition)) { ExprDecompiler expr_parser{decomp}; const Id condition = expr_parser.Visit(ast.condition); const Id then_label = decomp.OpLabel(); @@ -1846,7 +1844,7 @@ private: }; void SPIRVDecompiler::DecompileAST() { - u32 num_flow_variables = ir.GetASTNumVariables(); + const u32 num_flow_variables = ir.GetASTNumVariables(); for (u32 i = 0; i < num_flow_variables; i++) { const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false); Name(id, fmt::format("flow_var_{}", i)); -- cgit v1.2.3 From 507a9c6a402d6ee277e0a8f0cda57d04526c05dd Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 25 Sep 2019 14:34:08 -0400 Subject: vk_shader_decompiler: Correct Branches inside conditionals. --- src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/video_core/renderer_vulkan') diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 4bc7da198..2b55a3727 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -650,7 +650,11 @@ private: VisitBasicBlock(conditional->GetCode()); --conditional_nest_count; - Emit(OpBranch(skip_label)); + if (inside_branch == 0) { + Emit(OpBranch(skip_label)); + } else { + inside_branch--; + } Emit(skip_label); return {}; @@ -1014,6 +1018,7 @@ private: Emit(OpStore(jmp_to, Constant(t_uint, target->GetValue()))); Emit(OpBranch(continue_label)); + inside_branch = conditional_nest_count; if (conditional_nest_count == 0) { Emit(OpLabel()); } @@ -1025,6 +1030,7 @@ private: Emit(OpStore(jmp_to, op_a)); Emit(OpBranch(continue_label)); + inside_branch = conditional_nest_count; if (conditional_nest_count == 0) { Emit(OpLabel()); } @@ -1055,6 +1061,7 @@ private: Emit(OpStore(flow_stack_top, previous)); Emit(OpStore(jmp_to, target)); Emit(OpBranch(continue_label)); + inside_branch = conditional_nest_count; if (conditional_nest_count == 0) { Emit(OpLabel()); } @@ -1114,6 +1121,7 @@ private: Id Exit(Operation operation) { PreExit(); + inside_branch = conditional_nest_count; if (conditional_nest_count > 0) { Emit(OpReturn()); } else { @@ -1127,6 +1135,7 @@ private: } Id Discard(Operation operation) { + inside_branch = conditional_nest_count; if (conditional_nest_count > 0) { Emit(OpKill()); } else { @@ -1536,6 +1545,7 @@ private: const ShaderStage stage; const Tegra::Shader::Header header; u64 conditional_nest_count{}; + u64 inside_branch{}; const Id t_void = Name(TypeVoid(), "void"); -- cgit v1.2.3 From 3c09d9abe6d268ada063fd67c08d09fc0fcad613 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 28 Sep 2019 15:16:19 -0400 Subject: Shader_Ir: Address Feedback and clang format. --- .../renderer_vulkan/vk_shader_decompiler.cpp | 43 ++++++-------- src/video_core/shader/ast.cpp | 14 +++-- src/video_core/shader/ast.h | 65 +++++++++++----------- src/video_core/shader/expr.h | 14 ++--- 4 files changed, 68 insertions(+), 68 deletions(-) (limited to 'src/video_core/renderer_vulkan') diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 2b55a3727..8bcd04221 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -1646,34 +1646,34 @@ private: class ExprDecompiler { public: - ExprDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {} + explicit ExprDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {} - void operator()(VideoCommon::Shader::ExprAnd& expr) { + Id operator()(VideoCommon::Shader::ExprAnd& expr) { const Id type_def = decomp.GetTypeDefinition(Type::Bool); const Id op1 = Visit(expr.operand1); const Id op2 = Visit(expr.operand2); - current_id = decomp.Emit(decomp.OpLogicalAnd(type_def, op1, op2)); + return decomp.Emit(decomp.OpLogicalAnd(type_def, op1, op2)); } - void operator()(VideoCommon::Shader::ExprOr& expr) { + Id operator()(VideoCommon::Shader::ExprOr& expr) { const Id type_def = decomp.GetTypeDefinition(Type::Bool); const Id op1 = Visit(expr.operand1); const Id op2 = Visit(expr.operand2); - current_id = decomp.Emit(decomp.OpLogicalOr(type_def, op1, op2)); + return decomp.Emit(decomp.OpLogicalOr(type_def, op1, op2)); } - void operator()(VideoCommon::Shader::ExprNot& expr) { + Id operator()(VideoCommon::Shader::ExprNot& expr) { const Id type_def = decomp.GetTypeDefinition(Type::Bool); const Id op1 = Visit(expr.operand1); - current_id = decomp.Emit(decomp.OpLogicalNot(type_def, op1)); + return decomp.Emit(decomp.OpLogicalNot(type_def, op1)); } - void operator()(VideoCommon::Shader::ExprPredicate& expr) { + Id operator()(VideoCommon::Shader::ExprPredicate& expr) { const auto pred = static_cast(expr.predicate); - current_id = decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.predicates.at(pred))); + return decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.predicates.at(pred))); } - void operator()(VideoCommon::Shader::ExprCondCode& expr) { + Id operator()(VideoCommon::Shader::ExprCondCode& expr) { const Node cc = decomp.ir.GetConditionCode(expr.cc); Id target; @@ -1690,35 +1690,28 @@ public: } else if (const auto flag = std::get_if(&*cc)) { target = decomp.internal_flags.at(static_cast(flag->GetFlag())); } - current_id = decomp.Emit(decomp.OpLoad(decomp.t_bool, target)); + return decomp.Emit(decomp.OpLoad(decomp.t_bool, target)); } - void operator()(VideoCommon::Shader::ExprVar& expr) { - current_id = - decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.flow_variables.at(expr.var_index))); + Id operator()(VideoCommon::Shader::ExprVar& expr) { + return decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.flow_variables.at(expr.var_index))); } - void operator()(VideoCommon::Shader::ExprBoolean& expr) { - current_id = expr.value ? decomp.v_true : decomp.v_false; - } - - Id GetResult() { - return current_id; + Id operator()(VideoCommon::Shader::ExprBoolean& expr) { + return expr.value ? decomp.v_true : decomp.v_false; } Id Visit(VideoCommon::Shader::Expr& node) { - std::visit(*this, *node); - return current_id; + return std::visit(*this, *node); } private: - Id current_id; SPIRVDecompiler& decomp; }; class ASTDecompiler { public: - ASTDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {} + explicit ASTDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {} void operator()(VideoCommon::Shader::ASTProgram& ast) { ASTNode current = ast.nodes.GetFirst(); @@ -1850,7 +1843,7 @@ public: private: SPIRVDecompiler& decomp; - Id current_loop_exit; + Id current_loop_exit{}; }; void SPIRVDecompiler::DecompileAST() { diff --git a/src/video_core/shader/ast.cpp b/src/video_core/shader/ast.cpp index fc440526f..c4548f0bc 100644 --- a/src/video_core/shader/ast.cpp +++ b/src/video_core/shader/ast.cpp @@ -442,8 +442,11 @@ void ASTManager::Decompile() { auto it = gotos.begin(); while (it != gotos.end()) { const ASTNode goto_node = *it; - const u32 label_index = goto_node->GetGotoLabel(); - const ASTNode label = labels[label_index]; + const auto label_index = goto_node->GetGotoLabel(); + if (!label_index) { + return; + } + const ASTNode label = labels[*label_index]; if (!full_decompile) { // We only decompile backward jumps if (!IsBackwardsJump(goto_node, label)) { @@ -498,8 +501,11 @@ void ASTManager::Decompile() { bool can_remove = true; ASTNode label = *it; for (const ASTNode goto_node : gotos) { - const u32 label_index = goto_node->GetGotoLabel(); - ASTNode glabel = labels[label_index]; + const auto label_index = goto_node->GetGotoLabel(); + if (!label_index) { + return; + } + ASTNode glabel = labels[*label_index]; if (glabel == label) { can_remove = false; break; diff --git a/src/video_core/shader/ast.h b/src/video_core/shader/ast.h index 1b73f301f..8efd4c147 100644 --- a/src/video_core/shader/ast.h +++ b/src/video_core/shader/ast.h @@ -44,7 +44,7 @@ enum class ASTZipperType : u32 { class ASTZipper final { public: - ASTZipper(); + explicit ASTZipper(); void Init(ASTNode first, ASTNode parent); @@ -71,74 +71,74 @@ public: class ASTProgram { public: - ASTProgram() : nodes{} {}; - ASTZipper nodes; + explicit ASTProgram() = default; + ASTZipper nodes{}; }; class ASTIfThen { public: - ASTIfThen(Expr condition) : condition(condition), nodes{} {} + explicit ASTIfThen(Expr condition) : condition(condition) {} Expr condition; - ASTZipper nodes; + ASTZipper nodes{}; }; class ASTIfElse { public: - ASTIfElse() : nodes{} {} - ASTZipper nodes; + explicit ASTIfElse() = default; + ASTZipper nodes{}; }; class ASTBlockEncoded { public: - ASTBlockEncoded(u32 start, u32 end) : start{start}, end{end} {} + explicit ASTBlockEncoded(u32 start, u32 end) : start{start}, end{end} {} u32 start; u32 end; }; class ASTBlockDecoded { public: - ASTBlockDecoded(NodeBlock& new_nodes) : nodes(std::move(new_nodes)) {} + explicit ASTBlockDecoded(NodeBlock& new_nodes) : nodes(std::move(new_nodes)) {} NodeBlock nodes; }; class ASTVarSet { public: - ASTVarSet(u32 index, Expr condition) : index{index}, condition{condition} {} + explicit ASTVarSet(u32 index, Expr condition) : index{index}, condition{condition} {} u32 index; Expr condition; }; class ASTLabel { public: - ASTLabel(u32 index) : index{index} {} + explicit ASTLabel(u32 index) : index{index} {} u32 index; bool unused{}; }; class ASTGoto { public: - ASTGoto(Expr condition, u32 label) : condition{condition}, label{label} {} + explicit ASTGoto(Expr condition, u32 label) : condition{condition}, label{label} {} Expr condition; u32 label; }; class ASTDoWhile { public: - ASTDoWhile(Expr condition) : condition(condition), nodes{} {} + explicit ASTDoWhile(Expr condition) : condition(condition) {} Expr condition; - ASTZipper nodes; + ASTZipper nodes{}; }; class ASTReturn { public: - ASTReturn(Expr condition, bool kills) : condition{condition}, kills{kills} {} + explicit ASTReturn(Expr condition, bool kills) : condition{condition}, kills{kills} {} Expr condition; bool kills; }; class ASTBreak { public: - ASTBreak(Expr condition) : condition{condition} {} + explicit ASTBreak(Expr condition) : condition{condition} {} Expr condition; }; @@ -177,11 +177,11 @@ public: return &data; } - ASTNode GetNext() { + ASTNode GetNext() const { return next; } - ASTNode GetPrevious() { + ASTNode GetPrevious() const { return previous; } @@ -189,12 +189,12 @@ public: return *manager; } - u32 GetGotoLabel() const { + std::optional GetGotoLabel() const { auto inner = std::get_if(&data); if (inner) { - return inner->label; + return {inner->label}; } - return -1; + return {}; } Expr GetGotoCondition() const { @@ -220,12 +220,12 @@ public: return true; } - u32 GetLabelIndex() const { + std::optional GetLabelIndex() const { auto inner = std::get_if(&data); if (inner) { - return inner->index; + return {inner->index}; } - return -1; + return {}; } Expr GetIfCondition() const { @@ -290,7 +290,7 @@ private: friend class ASTZipper; ASTData data; - ASTNode parent; + ASTNode parent{}; ASTNode next{}; ASTNode previous{}; ASTZipper* manager{}; @@ -327,13 +327,18 @@ public: void SanityCheck(); + void Clear(); + bool IsFullyDecompiled() const { if (full_decompile) { return gotos.size() == 0; } else { for (ASTNode goto_node : gotos) { - u32 label_index = goto_node->GetGotoLabel(); - ASTNode glabel = labels[label_index]; + auto label_index = goto_node->GetGotoLabel(); + if (!label_index) { + return false; + } + ASTNode glabel = labels[*label_index]; if (IsBackwardsJump(goto_node, glabel)) { return false; } @@ -346,8 +351,6 @@ public: return main_node; } - void Clear(); - u32 GetVariables() const { return variables; } @@ -372,9 +375,7 @@ private: void MoveOutward(ASTNode goto_node); u32 NewVariable() { - u32 new_var = variables; - variables++; - return new_var; + return variables++; } bool full_decompile{}; diff --git a/src/video_core/shader/expr.h b/src/video_core/shader/expr.h index 60598977a..4c399cef9 100644 --- a/src/video_core/shader/expr.h +++ b/src/video_core/shader/expr.h @@ -28,7 +28,7 @@ using Expr = std::shared_ptr; class ExprAnd final { public: - ExprAnd(Expr a, Expr b) : operand1{a}, operand2{b} {} + explicit ExprAnd(Expr a, Expr b) : operand1{a}, operand2{b} {} bool operator==(const ExprAnd& b) const; @@ -38,7 +38,7 @@ public: class ExprOr final { public: - ExprOr(Expr a, Expr b) : operand1{a}, operand2{b} {} + explicit ExprOr(Expr a, Expr b) : operand1{a}, operand2{b} {} bool operator==(const ExprOr& b) const; @@ -48,7 +48,7 @@ public: class ExprNot final { public: - ExprNot(Expr a) : operand1{a} {} + explicit ExprNot(Expr a) : operand1{a} {} bool operator==(const ExprNot& b) const; @@ -57,7 +57,7 @@ public: class ExprVar final { public: - ExprVar(u32 index) : var_index{index} {} + explicit ExprVar(u32 index) : var_index{index} {} bool operator==(const ExprVar& b) const { return var_index == b.var_index; @@ -68,7 +68,7 @@ public: class ExprPredicate final { public: - ExprPredicate(u32 predicate) : predicate{predicate} {} + explicit ExprPredicate(u32 predicate) : predicate{predicate} {} bool operator==(const ExprPredicate& b) const { return predicate == b.predicate; @@ -79,7 +79,7 @@ public: class ExprCondCode final { public: - ExprCondCode(ConditionCode cc) : cc{cc} {} + explicit ExprCondCode(ConditionCode cc) : cc{cc} {} bool operator==(const ExprCondCode& b) const { return cc == b.cc; @@ -90,7 +90,7 @@ public: class ExprBoolean final { public: - ExprBoolean(bool val) : value{val} {} + explicit ExprBoolean(bool val) : value{val} {} bool operator==(const ExprBoolean& b) const { return value == b.value; -- cgit v1.2.3