From c17953978b16f82a3b2049f8b961275020c73dd0 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 27 Jun 2019 00:39:40 -0400 Subject: shader_ir: Initial Decompile Setup --- src/video_core/shader/control_flow.cpp | 58 ++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) (limited to 'src/video_core/shader/control_flow.cpp') diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index ec3a76690..bea7f767c 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp @@ -4,13 +4,14 @@ #include #include +#include #include #include -#include #include #include "common/assert.h" #include "common/common_types.h" +#include "video_core/shader/ast.h" #include "video_core/shader/control_flow.h" #include "video_core/shader/shader_ir.h" @@ -64,7 +65,7 @@ struct CFGRebuildState { std::list inspect_queries{}; std::list queries{}; std::unordered_map registered{}; - std::unordered_set labels{}; + std::set labels{}; std::map ssy_labels{}; std::map pbk_labels{}; std::unordered_map stacks{}; @@ -415,6 +416,54 @@ bool TryQuery(CFGRebuildState& state) { } } // Anonymous namespace +void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch) { + const auto get_expr = ([&](const Condition& cond) -> Expr { + Expr result{}; + if (cond.cc != ConditionCode::T) { + result = MakeExpr(cond.cc); + } + if (cond.predicate != Pred::UnusedIndex) { + Expr extra = MakeExpr(cond.predicate); + if (result) { + return MakeExpr(extra, result); + } + return extra; + } + if (result) { + return result; + } + return MakeExpr(true); + }); + if (branch.address < 0) { + if (branch.kill) { + mm.InsertReturn(get_expr(branch.condition), true); + return; + } + mm.InsertReturn(get_expr(branch.condition), false); + return; + } + mm.InsertGoto(get_expr(branch.condition), branch.address); +} + +void DecompileShader(CFGRebuildState& state) { + ASTManager manager{}; + for (auto label : state.labels) { + manager.DeclareLabel(label); + } + for (auto& block : state.block_info) { + if (state.labels.count(block.start) != 0) { + manager.InsertLabel(block.start); + } + u32 end = block.branch.ignore ? block.end + 1 : block.end; + manager.InsertBlock(block.start, end); + if (!block.branch.ignore) { + InsertBranch(manager, block.branch); + } + } + manager.Decompile(); + LOG_CRITICAL(HW_GPU, "Decompiled Shader:\n{} \n", manager.Print()); +} + std::optional ScanFlow(const ProgramCode& program_code, std::size_t program_size, u32 start_address) { CFGRebuildState state{program_code, program_size, start_address}; @@ -441,7 +490,10 @@ std::optional ScanFlow(const ProgramCode& program_code, // Sort and organize results std::sort(state.block_info.begin(), state.block_info.end(), - [](const BlockInfo& a, const BlockInfo& b) { return a.start < b.start; }); + [](const BlockInfo& a, const BlockInfo& b) -> bool { return a.start < b.start; }); + if (decompiled) { + DecompileShader(state); + } ShaderCharacteristics result_out{}; result_out.decompilable = decompiled; result_out.start = start_address; -- cgit v1.2.3 From 8be6e1c5221066a49b6ad27efbd20a999a7c16b3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 28 Jun 2019 20:54:21 -0400 Subject: shader_ir: Corrections to outward movements and misc stuffs --- src/video_core/shader/control_flow.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/video_core/shader/control_flow.cpp') diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index bea7f767c..7a21d870f 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp @@ -423,7 +423,16 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch) { result = MakeExpr(cond.cc); } if (cond.predicate != Pred::UnusedIndex) { - Expr extra = MakeExpr(cond.predicate); + u32 pred = static_cast(cond.predicate); + bool negate; + if (pred > 7) { + negate = true; + pred -= 8; + } + Expr extra = MakeExpr(pred); + if (negate) { + extra = MakeExpr(extra); + } if (result) { return MakeExpr(extra, result); } @@ -460,8 +469,9 @@ void DecompileShader(CFGRebuildState& state) { InsertBranch(manager, block.branch); } } + //manager.ShowCurrentState("Before Decompiling"); manager.Decompile(); - LOG_CRITICAL(HW_GPU, "Decompiled Shader:\n{} \n", manager.Print()); + //manager.ShowCurrentState("After Decompiling"); } std::optional ScanFlow(const ProgramCode& program_code, -- cgit v1.2.3 From 6fdd501113d5094f9148046c3b17cf2239e99aa5 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 28 Jun 2019 22:59:43 -0400 Subject: shader_ir: Declare Manager and pass it to appropiate programs. --- src/video_core/shader/control_flow.cpp | 65 ++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 31 deletions(-) (limited to 'src/video_core/shader/control_flow.cpp') diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index 7a21d870f..deb3d3ebd 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp @@ -57,8 +57,8 @@ struct BlockInfo { struct CFGRebuildState { explicit CFGRebuildState(const ProgramCode& program_code, const std::size_t program_size, - const u32 start) - : start{start}, program_code{program_code}, program_size{program_size} {} + const u32 start, ASTManager& manager) + : program_code{program_code}, program_size{program_size}, start{start}, manager{manager} {} u32 start{}; std::vector block_info{}; @@ -71,6 +71,7 @@ struct CFGRebuildState { std::unordered_map stacks{}; const ProgramCode& program_code; const std::size_t program_size; + ASTManager& manager; }; enum class BlockCollision : u32 { None, Found, Inside }; @@ -455,29 +456,28 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch) { } void DecompileShader(CFGRebuildState& state) { - ASTManager manager{}; + state.manager.Init(); for (auto label : state.labels) { - manager.DeclareLabel(label); + state.manager.DeclareLabel(label); } for (auto& block : state.block_info) { if (state.labels.count(block.start) != 0) { - manager.InsertLabel(block.start); + state.manager.InsertLabel(block.start); } u32 end = block.branch.ignore ? block.end + 1 : block.end; - manager.InsertBlock(block.start, end); + state.manager.InsertBlock(block.start, end); if (!block.branch.ignore) { - InsertBranch(manager, block.branch); + InsertBranch(state.manager, block.branch); } } - //manager.ShowCurrentState("Before Decompiling"); - manager.Decompile(); - //manager.ShowCurrentState("After Decompiling"); + // state.manager.ShowCurrentState("Before Decompiling"); + state.manager.Decompile(); + // state.manager.ShowCurrentState("After Decompiling"); } -std::optional ScanFlow(const ProgramCode& program_code, - std::size_t program_size, u32 start_address) { - CFGRebuildState state{program_code, program_size, start_address}; - +std::unique_ptr ScanFlow(const ProgramCode& program_code, u32 program_size, + u32 start_address, ASTManager& manager) { + CFGRebuildState state{program_code, program_size, start_address, manager}; // Inspect Code and generate blocks state.labels.clear(); state.labels.emplace(start_address); @@ -503,12 +503,21 @@ std::optional ScanFlow(const ProgramCode& program_code, [](const BlockInfo& a, const BlockInfo& b) -> bool { return a.start < b.start; }); if (decompiled) { DecompileShader(state); + decompiled = state.manager.IsFullyDecompiled(); + if (!decompiled) { + LOG_CRITICAL(HW_GPU, "Failed to remove all the gotos!:"); + state.manager.ShowCurrentState("Of Shader"); + state.manager.Clear(); + } + } + auto result_out = std::make_unique(); + result_out->decompiled = decompiled; + result_out->start = start_address; + if (decompiled) { + result_out->end = state.block_info.back().end + 1; + return std::move(result_out); } - ShaderCharacteristics result_out{}; - result_out.decompilable = decompiled; - result_out.start = start_address; - result_out.end = start_address; - for (const auto& block : state.block_info) { + for (auto& block : state.block_info) { ShaderBlock new_block{}; new_block.start = block.start; new_block.end = block.end; @@ -518,26 +527,20 @@ std::optional ScanFlow(const ProgramCode& program_code, new_block.branch.kills = block.branch.kill; new_block.branch.address = block.branch.address; } - result_out.end = std::max(result_out.end, block.end); - result_out.blocks.push_back(new_block); - } - if (result_out.decompilable) { - result_out.labels = std::move(state.labels); - return {std::move(result_out)}; + result_out->end = std::max(result_out->end, block.end); + result_out->blocks.push_back(new_block); } - - // If it's not decompilable, merge the unlabelled blocks together - auto back = result_out.blocks.begin(); + auto back = result_out->blocks.begin(); auto next = std::next(back); - while (next != result_out.blocks.end()) { + while (next != result_out->blocks.end()) { if (state.labels.count(next->start) == 0 && next->start == back->end + 1) { back->end = next->end; - next = result_out.blocks.erase(next); + next = result_out->blocks.erase(next); continue; } back = next; ++next; } - return {std::move(result_out)}; + return std::move(result_out); } } // namespace VideoCommon::Shader -- cgit v1.2.3 From 38fc995f6cc2c2af29abc976ddb45b72873b2cc4 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 29 Jun 2019 01:44:07 -0400 Subject: gl_shader_decompiler: Implement AST decompiling --- src/video_core/shader/control_flow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/video_core/shader/control_flow.cpp') diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index deb3d3ebd..a29922815 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp @@ -425,7 +425,7 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch) { } if (cond.predicate != Pred::UnusedIndex) { u32 pred = static_cast(cond.predicate); - bool negate; + bool negate = false; if (pred > 7) { negate = true; pred -= 8; -- cgit v1.2.3 From 47e4f6a52c5eb34916e2c1f4c876e6e8624e3840 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 16 Aug 2019 16:25:02 -0400 Subject: Shader_Ir: Refactor Decompilation process and allow multiple decompilation modes. --- src/video_core/shader/control_flow.cpp | 92 ++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 32 deletions(-) (limited to 'src/video_core/shader/control_flow.cpp') diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index a29922815..c4351969b 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp @@ -57,8 +57,8 @@ struct BlockInfo { struct CFGRebuildState { explicit CFGRebuildState(const ProgramCode& program_code, const std::size_t program_size, - const u32 start, ASTManager& manager) - : program_code{program_code}, program_size{program_size}, start{start}, manager{manager} {} + const u32 start) + : program_code{program_code}, program_size{program_size}, start{start} {} u32 start{}; std::vector block_info{}; @@ -71,7 +71,7 @@ struct CFGRebuildState { std::unordered_map stacks{}; const ProgramCode& program_code; const std::size_t program_size; - ASTManager& manager; + ASTManager* manager; }; enum class BlockCollision : u32 { None, Found, Inside }; @@ -456,67 +456,91 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch) { } void DecompileShader(CFGRebuildState& state) { - state.manager.Init(); + state.manager->Init(); for (auto label : state.labels) { - state.manager.DeclareLabel(label); + state.manager->DeclareLabel(label); } for (auto& block : state.block_info) { if (state.labels.count(block.start) != 0) { - state.manager.InsertLabel(block.start); + state.manager->InsertLabel(block.start); } u32 end = block.branch.ignore ? block.end + 1 : block.end; - state.manager.InsertBlock(block.start, end); + state.manager->InsertBlock(block.start, end); if (!block.branch.ignore) { - InsertBranch(state.manager, block.branch); + InsertBranch(*state.manager, block.branch); } } - // state.manager.ShowCurrentState("Before Decompiling"); - state.manager.Decompile(); - // state.manager.ShowCurrentState("After Decompiling"); + state.manager->Decompile(); } std::unique_ptr ScanFlow(const ProgramCode& program_code, u32 program_size, - u32 start_address, ASTManager& manager) { - CFGRebuildState state{program_code, program_size, start_address, manager}; + u32 start_address, + const CompilerSettings& settings) { + auto result_out = std::make_unique(); + if (settings.depth == CompileDepth::BruteForce) { + result_out->settings.depth = CompileDepth::BruteForce; + return std::move(result_out); + } + + CFGRebuildState state{program_code, program_size, start_address}; // Inspect Code and generate blocks state.labels.clear(); state.labels.emplace(start_address); state.inspect_queries.push_back(state.start); while (!state.inspect_queries.empty()) { if (!TryInspectAddress(state)) { - return {}; + result_out->settings.depth = CompileDepth::BruteForce; + return std::move(result_out); } } - // Decompile Stacks - state.queries.push_back(Query{state.start, {}, {}}); - bool decompiled = true; - while (!state.queries.empty()) { - if (!TryQuery(state)) { - decompiled = false; - break; + bool use_flow_stack = true; + + bool decompiled = false; + + if (settings.depth != CompileDepth::FlowStack) { + // Decompile Stacks + state.queries.push_back(Query{state.start, {}, {}}); + decompiled = true; + while (!state.queries.empty()) { + if (!TryQuery(state)) { + decompiled = false; + break; + } } } + use_flow_stack = !decompiled; + // Sort and organize results std::sort(state.block_info.begin(), state.block_info.end(), [](const BlockInfo& a, const BlockInfo& b) -> bool { return a.start < b.start; }); - if (decompiled) { + if (decompiled && settings.depth != CompileDepth::NoFlowStack) { + ASTManager manager{settings.depth != CompileDepth::DecompileBackwards}; + state.manager = &manager; DecompileShader(state); - decompiled = state.manager.IsFullyDecompiled(); + decompiled = state.manager->IsFullyDecompiled(); if (!decompiled) { - LOG_CRITICAL(HW_GPU, "Failed to remove all the gotos!:"); - state.manager.ShowCurrentState("Of Shader"); - state.manager.Clear(); + if (settings.depth == CompileDepth::FullDecompile) { + LOG_CRITICAL(HW_GPU, "Failed to remove all the gotos!:"); + } else { + LOG_CRITICAL(HW_GPU, "Failed to remove all backward gotos!:"); + } + state.manager->ShowCurrentState("Of Shader"); + state.manager->Clear(); + } else { + auto result_out = std::make_unique(); + result_out->start = start_address; + result_out->settings.depth = settings.depth; + result_out->manager = std::move(manager); + result_out->end = state.block_info.back().end + 1; + return std::move(result_out); } } - auto result_out = std::make_unique(); - result_out->decompiled = decompiled; result_out->start = start_address; - if (decompiled) { - result_out->end = state.block_info.back().end + 1; - return std::move(result_out); - } + result_out->settings.depth = + use_flow_stack ? CompileDepth::FlowStack : CompileDepth::NoFlowStack; + result_out->blocks.clear(); for (auto& block : state.block_info) { ShaderBlock new_block{}; new_block.start = block.start; @@ -530,6 +554,10 @@ std::unique_ptr ScanFlow(const ProgramCode& program_code, result_out->end = std::max(result_out->end, block.end); result_out->blocks.push_back(new_block); } + if (!use_flow_stack) { + result_out->labels = std::move(state.labels); + return std::move(result_out); + } auto back = result_out->blocks.begin(); auto next = std::next(back); while (next != result_out->blocks.end()) { -- 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/shader/control_flow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/video_core/shader/control_flow.cpp') 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(); -- cgit v1.2.3 From e6eae4b815bf4bc480d62677fdf9bdbf5d6cba82 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 4 Oct 2019 17:23:16 -0400 Subject: Shader_ir: Address feedback --- src/video_core/shader/control_flow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/video_core/shader/control_flow.cpp') diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index c2fa734e7..3c3a41ba6 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp @@ -58,7 +58,7 @@ struct BlockInfo { struct CFGRebuildState { explicit CFGRebuildState(const ProgramCode& program_code, const std::size_t program_size, const u32 start) - : program_code{program_code}, program_size{program_size}, start{start} {} + : start{start}, program_code{program_code}, program_size{program_size} {} u32 start{}; std::vector block_info{}; -- cgit v1.2.3