summaryrefslogtreecommitdiff
path: root/src/video_core/shader/decode.cpp
diff options
context:
space:
mode:
authorGravatar David2019-10-05 21:52:20 +1000
committerGravatar GitHub2019-10-05 21:52:20 +1000
commit3728bbc22a9224ff75fff22487a47bcaaf6ac2be (patch)
tree80809634787307002bf9e07b710a4aa968019f26 /src/video_core/shader/decode.cpp
parentMerge pull request #2917 from FernandoS27/fermi-deduction-2 (diff)
parentShader_ir: Address feedback (diff)
downloadyuzu-3728bbc22a9224ff75fff22487a47bcaaf6ac2be.tar.gz
yuzu-3728bbc22a9224ff75fff22487a47bcaaf6ac2be.tar.xz
yuzu-3728bbc22a9224ff75fff22487a47bcaaf6ac2be.zip
Merge pull request #2888 from FernandoS27/decompiler2
Shader_IR: Implement a full control flow decompiler for the shader IR.
Diffstat (limited to 'src/video_core/shader/decode.cpp')
-rw-r--r--src/video_core/shader/decode.cpp170
1 files changed, 125 insertions, 45 deletions
diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp
index 47a9fd961..2626b1616 100644
--- a/src/video_core/shader/decode.cpp
+++ b/src/video_core/shader/decode.cpp
@@ -35,58 +35,138 @@ constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) {
35 35
36} // namespace 36} // namespace
37 37
38class ASTDecoder {
39public:
40 ASTDecoder(ShaderIR& ir) : ir(ir) {}
41
42 void operator()(ASTProgram& ast) {
43 ASTNode current = ast.nodes.GetFirst();
44 while (current) {
45 Visit(current);
46 current = current->GetNext();
47 }
48 }
49
50 void operator()(ASTIfThen& ast) {
51 ASTNode current = ast.nodes.GetFirst();
52 while (current) {
53 Visit(current);
54 current = current->GetNext();
55 }
56 }
57
58 void operator()(ASTIfElse& ast) {
59 ASTNode current = ast.nodes.GetFirst();
60 while (current) {
61 Visit(current);
62 current = current->GetNext();
63 }
64 }
65
66 void operator()(ASTBlockEncoded& ast) {}
67
68 void operator()(ASTBlockDecoded& ast) {}
69
70 void operator()(ASTVarSet& ast) {}
71
72 void operator()(ASTLabel& ast) {}
73
74 void operator()(ASTGoto& ast) {}
75
76 void operator()(ASTDoWhile& ast) {
77 ASTNode current = ast.nodes.GetFirst();
78 while (current) {
79 Visit(current);
80 current = current->GetNext();
81 }
82 }
83
84 void operator()(ASTReturn& ast) {}
85
86 void operator()(ASTBreak& ast) {}
87
88 void Visit(ASTNode& node) {
89 std::visit(*this, *node->GetInnerData());
90 if (node->IsBlockEncoded()) {
91 auto block = std::get_if<ASTBlockEncoded>(node->GetInnerData());
92 NodeBlock bb = ir.DecodeRange(block->start, block->end);
93 node->TransformBlockEncoded(std::move(bb));
94 }
95 }
96
97private:
98 ShaderIR& ir;
99};
100
38void ShaderIR::Decode() { 101void ShaderIR::Decode() {
39 std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); 102 std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
40 103
41 disable_flow_stack = false; 104 decompiled = false;
42 const auto info = ScanFlow(program_code, program_size, main_offset); 105 auto info = ScanFlow(program_code, program_size, main_offset, settings);
43 if (info) { 106 auto& shader_info = *info;
44 const auto& shader_info = *info; 107 coverage_begin = shader_info.start;
45 coverage_begin = shader_info.start; 108 coverage_end = shader_info.end;
46 coverage_end = shader_info.end; 109 switch (shader_info.settings.depth) {
47 if (shader_info.decompilable) { 110 case CompileDepth::FlowStack: {
48 disable_flow_stack = true;
49 const auto insert_block = [this](NodeBlock& nodes, u32 label) {
50 if (label == static_cast<u32>(exit_branch)) {
51 return;
52 }
53 basic_blocks.insert({label, nodes});
54 };
55 const auto& blocks = shader_info.blocks;
56 NodeBlock current_block;
57 u32 current_label = static_cast<u32>(exit_branch);
58 for (auto& block : blocks) {
59 if (shader_info.labels.count(block.start) != 0) {
60 insert_block(current_block, current_label);
61 current_block.clear();
62 current_label = block.start;
63 }
64 if (!block.ignore_branch) {
65 DecodeRangeInner(current_block, block.start, block.end);
66 InsertControlFlow(current_block, block);
67 } else {
68 DecodeRangeInner(current_block, block.start, block.end + 1);
69 }
70 }
71 insert_block(current_block, current_label);
72 return;
73 }
74 LOG_WARNING(HW_GPU, "Flow Stack Removing Failed! Falling back to old method");
75 // we can't decompile it, fallback to standard method
76 for (const auto& block : shader_info.blocks) { 111 for (const auto& block : shader_info.blocks) {
77 basic_blocks.insert({block.start, DecodeRange(block.start, block.end + 1)}); 112 basic_blocks.insert({block.start, DecodeRange(block.start, block.end + 1)});
78 } 113 }
79 return; 114 break;
80 } 115 }
81 LOG_WARNING(HW_GPU, "Flow Analysis Failed! Falling back to brute force compiling"); 116 case CompileDepth::NoFlowStack: {
82 117 disable_flow_stack = true;
83 // Now we need to deal with an undecompilable shader. We need to brute force 118 const auto insert_block = [this](NodeBlock& nodes, u32 label) {
84 // a shader that captures every position. 119 if (label == static_cast<u32>(exit_branch)) {
85 coverage_begin = main_offset; 120 return;
86 const u32 shader_end = static_cast<u32>(program_size / sizeof(u64)); 121 }
87 coverage_end = shader_end; 122 basic_blocks.insert({label, nodes});
88 for (u32 label = main_offset; label < shader_end; label++) { 123 };
89 basic_blocks.insert({label, DecodeRange(label, label + 1)}); 124 const auto& blocks = shader_info.blocks;
125 NodeBlock current_block;
126 u32 current_label = static_cast<u32>(exit_branch);
127 for (auto& block : blocks) {
128 if (shader_info.labels.count(block.start) != 0) {
129 insert_block(current_block, current_label);
130 current_block.clear();
131 current_label = block.start;
132 }
133 if (!block.ignore_branch) {
134 DecodeRangeInner(current_block, block.start, block.end);
135 InsertControlFlow(current_block, block);
136 } else {
137 DecodeRangeInner(current_block, block.start, block.end + 1);
138 }
139 }
140 insert_block(current_block, current_label);
141 break;
142 }
143 case CompileDepth::DecompileBackwards:
144 case CompileDepth::FullDecompile: {
145 program_manager = std::move(shader_info.manager);
146 disable_flow_stack = true;
147 decompiled = true;
148 ASTDecoder decoder{*this};
149 ASTNode program = GetASTProgram();
150 decoder.Visit(program);
151 break;
152 }
153 default:
154 LOG_CRITICAL(HW_GPU, "Unknown decompilation mode!");
155 [[fallthrough]];
156 case CompileDepth::BruteForce: {
157 coverage_begin = main_offset;
158 const u32 shader_end = static_cast<u32>(program_size / sizeof(u64));
159 coverage_end = shader_end;
160 for (u32 label = main_offset; label < shader_end; label++) {
161 basic_blocks.insert({label, DecodeRange(label, label + 1)});
162 }
163 break;
164 }
165 }
166 if (settings.depth != shader_info.settings.depth) {
167 LOG_WARNING(
168 HW_GPU, "Decompiling to this setting \"{}\" failed, downgrading to this setting \"{}\"",
169 CompileDepthAsString(settings.depth), CompileDepthAsString(shader_info.settings.depth));
90 } 170 }
91} 171}
92 172