diff options
| author | 2019-10-05 21:52:20 +1000 | |
|---|---|---|
| committer | 2019-10-05 21:52:20 +1000 | |
| commit | 3728bbc22a9224ff75fff22487a47bcaaf6ac2be (patch) | |
| tree | 80809634787307002bf9e07b710a4aa968019f26 /src/video_core/shader/decode.cpp | |
| parent | Merge pull request #2917 from FernandoS27/fermi-deduction-2 (diff) | |
| parent | Shader_ir: Address feedback (diff) | |
| download | yuzu-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.cpp | 170 |
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 | ||
| 38 | class ASTDecoder { | ||
| 39 | public: | ||
| 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 | |||
| 97 | private: | ||
| 98 | ShaderIR& ir; | ||
| 99 | }; | ||
| 100 | |||
| 38 | void ShaderIR::Decode() { | 101 | void 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 | ||