summaryrefslogtreecommitdiffstats
path: root/src/video_core/shader/control_flow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/shader/control_flow.cpp')
-rw-r--r--src/video_core/shader/control_flow.cpp58
1 files changed, 55 insertions, 3 deletions
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 <list>
#include <map>
+#include <set>
#include <stack>
#include <unordered_map>
-#include <unordered_set>
#include <vector>
#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<u32> inspect_queries{};
std::list<Query> queries{};
std::unordered_map<u32, u32> registered{};
- std::unordered_set<u32> labels{};
+ std::set<u32> labels{};
std::map<u32, u32> ssy_labels{};
std::map<u32, u32> pbk_labels{};
std::unordered_map<u32, BlockStack> 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<ExprCondCode>(cond.cc);
+ }
+ if (cond.predicate != Pred::UnusedIndex) {
+ Expr extra = MakeExpr<ExprPredicate>(cond.predicate);
+ if (result) {
+ return MakeExpr<ExprAnd>(extra, result);
+ }
+ return extra;
+ }
+ if (result) {
+ return result;
+ }
+ return MakeExpr<ExprBoolean>(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<ShaderCharacteristics> 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<ShaderCharacteristics> 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;