summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2019-06-29 01:44:07 -0400
committerGravatar FernandoS272019-10-04 18:52:50 -0400
commit38fc995f6cc2c2af29abc976ddb45b72873b2cc4 (patch)
treea73839d510c79a5e296e54a6768868f788abd45d /src
parentshader_ir: Declare Manager and pass it to appropiate programs. (diff)
downloadyuzu-38fc995f6cc2c2af29abc976ddb45b72873b2cc4.tar.gz
yuzu-38fc995f6cc2c2af29abc976ddb45b72873b2cc4.tar.xz
yuzu-38fc995f6cc2c2af29abc976ddb45b72873b2cc4.zip
gl_shader_decompiler: Implement AST decompiling
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp271
-rw-r--r--src/video_core/shader/ast.cpp10
-rw-r--r--src/video_core/shader/ast.h18
-rw-r--r--src/video_core/shader/control_flow.cpp2
-rw-r--r--src/video_core/shader/control_flow.h2
-rw-r--r--src/video_core/shader/decode.cpp70
-rw-r--r--src/video_core/shader/decode/other.cpp8
-rw-r--r--src/video_core/shader/expr.cpp7
-rw-r--r--src/video_core/shader/expr.h2
-rw-r--r--src/video_core/shader/shader_ir.cpp6
-rw-r--r--src/video_core/shader/shader_ir.h25
11 files changed, 358 insertions, 63 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 8fa9e6534..2955c6abf 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -20,6 +20,7 @@
20#include "video_core/renderer_opengl/gl_rasterizer.h" 20#include "video_core/renderer_opengl/gl_rasterizer.h"
21#include "video_core/renderer_opengl/gl_shader_decompiler.h" 21#include "video_core/renderer_opengl/gl_shader_decompiler.h"
22#include "video_core/shader/node.h" 22#include "video_core/shader/node.h"
23#include "video_core/shader/ast.h"
23#include "video_core/shader/shader_ir.h" 24#include "video_core/shader/shader_ir.h"
24 25
25namespace OpenGL::GLShader { 26namespace OpenGL::GLShader {
@@ -334,43 +335,26 @@ constexpr bool IsVertexShader(ProgramType stage) {
334 return stage == ProgramType::VertexA || stage == ProgramType::VertexB; 335 return stage == ProgramType::VertexA || stage == ProgramType::VertexB;
335} 336}
336 337
338class ASTDecompiler;
339class ExprDecompiler;
340
337class GLSLDecompiler final { 341class GLSLDecompiler final {
338public: 342public:
339 explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, ProgramType stage, 343 explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, ProgramType stage,
340 std::string suffix) 344 std::string suffix)
341 : device{device}, ir{ir}, stage{stage}, suffix{suffix}, header{ir.GetHeader()} {} 345 : device{device}, ir{ir}, stage{stage}, suffix{suffix}, header{ir.GetHeader()} {}
342 346
343 void Decompile() { 347 void DecompileBranchMode() {
344 DeclareVertex();
345 DeclareGeometry();
346 DeclareRegisters();
347 DeclarePredicates();
348 DeclareLocalMemory();
349 DeclareSharedMemory();
350 DeclareInternalFlags();
351 DeclareInputAttributes();
352 DeclareOutputAttributes();
353 DeclareConstantBuffers();
354 DeclareGlobalMemory();
355 DeclareSamplers();
356 DeclarePhysicalAttributeReader();
357 DeclareImages();
358
359 code.AddLine("void execute_{}() {{", suffix);
360 ++code.scope;
361
362 // VM's program counter 348 // VM's program counter
363 const auto first_address = ir.GetBasicBlocks().begin()->first; 349 const auto first_address = ir.GetBasicBlocks().begin()->first;
364 code.AddLine("uint jmp_to = {}U;", first_address); 350 code.AddLine("uint jmp_to = {}U;", first_address);
365 351
366 // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems 352 // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems
367 // unlikely that shaders will use 20 nested SSYs and PBKs. 353 // unlikely that shaders will use 20 nested SSYs and PBKs.
368 if (!ir.IsFlowStackDisabled()) { 354 constexpr u32 FLOW_STACK_SIZE = 20;
369 constexpr u32 FLOW_STACK_SIZE = 20; 355 for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) {
370 for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) { 356 code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE);
371 code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE); 357 code.AddLine("uint {} = 0u;", FlowStackTopName(stack));
372 code.AddLine("uint {} = 0U;", FlowStackTopName(stack));
373 }
374 } 358 }
375 359
376 code.AddLine("while (true) {{"); 360 code.AddLine("while (true) {{");
@@ -392,10 +376,37 @@ public:
392 code.AddLine("default: return;"); 376 code.AddLine("default: return;");
393 code.AddLine("}}"); 377 code.AddLine("}}");
394 378
395 for (std::size_t i = 0; i < 2; ++i) { 379 --code.scope;
396 --code.scope; 380 code.AddLine("}}");
397 code.AddLine("}}"); 381 }
382
383 void DecompileAST();
384
385 void Decompile() {
386 DeclareVertex();
387 DeclareGeometry();
388 DeclareRegisters();
389 DeclarePredicates();
390 DeclareLocalMemory();
391 DeclareInternalFlags();
392 DeclareInputAttributes();
393 DeclareOutputAttributes();
394 DeclareConstantBuffers();
395 DeclareGlobalMemory();
396 DeclareSamplers();
397 DeclarePhysicalAttributeReader();
398
399 code.AddLine("void execute_{}() {{", suffix);
400 ++code.scope;
401
402 if (ir.IsDecompiled()) {
403 DecompileAST();
404 } else {
405 DecompileBranchMode();
398 } 406 }
407
408 --code.scope;
409 code.AddLine("}}");
399 } 410 }
400 411
401 std::string GetResult() { 412 std::string GetResult() {
@@ -424,6 +435,9 @@ public:
424 } 435 }
425 436
426private: 437private:
438 friend class ASTDecompiler;
439 friend class ExprDecompiler;
440
427 void DeclareVertex() { 441 void DeclareVertex() {
428 if (!IsVertexShader(stage)) 442 if (!IsVertexShader(stage))
429 return; 443 return;
@@ -1821,7 +1835,7 @@ private:
1821 return {}; 1835 return {};
1822 } 1836 }
1823 1837
1824 Expression Exit(Operation operation) { 1838 Expression WriteExit() {
1825 if (stage != ProgramType::Fragment) { 1839 if (stage != ProgramType::Fragment) {
1826 code.AddLine("return;"); 1840 code.AddLine("return;");
1827 return {}; 1841 return {};
@@ -1861,6 +1875,10 @@ private:
1861 return {}; 1875 return {};
1862 } 1876 }
1863 1877
1878 Expression Exit(Operation operation) {
1879 return WriteExit();
1880 }
1881
1864 Expression Discard(Operation operation) { 1882 Expression Discard(Operation operation) {
1865 // Enclose "discard" in a conditional, so that GLSL compilation does not complain 1883 // Enclose "discard" in a conditional, so that GLSL compilation does not complain
1866 // about unexecuted instructions that may follow this. 1884 // about unexecuted instructions that may follow this.
@@ -2253,6 +2271,201 @@ private:
2253 ShaderWriter code; 2271 ShaderWriter code;
2254}; 2272};
2255 2273
2274const std::string flow_var = "flow_var_";
2275
2276class ExprDecompiler {
2277public:
2278 ExprDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {}
2279
2280 void operator()(VideoCommon::Shader::ExprAnd& expr) {
2281 inner += "( ";
2282 std::visit(*this, *expr.operand1);
2283 inner += " && ";
2284 std::visit(*this, *expr.operand2);
2285 inner += ')';
2286 }
2287
2288 void operator()(VideoCommon::Shader::ExprOr& expr) {
2289 inner += "( ";
2290 std::visit(*this, *expr.operand1);
2291 inner += " || ";
2292 std::visit(*this, *expr.operand2);
2293 inner += ')';
2294 }
2295
2296 void operator()(VideoCommon::Shader::ExprNot& expr) {
2297 inner += '!';
2298 std::visit(*this, *expr.operand1);
2299 }
2300
2301 void operator()(VideoCommon::Shader::ExprPredicate& expr) {
2302 auto pred = static_cast<Tegra::Shader::Pred>(expr.predicate);
2303 inner += decomp.GetPredicate(pred);
2304 }
2305
2306 void operator()(VideoCommon::Shader::ExprCondCode& expr) {
2307 Node cc = decomp.ir.GetConditionCode(expr.cc);
2308 std::string target;
2309
2310 if (const auto pred = std::get_if<PredicateNode>(&*cc)) {
2311 const auto index = pred->GetIndex();
2312 switch (index) {
2313 case Tegra::Shader::Pred::NeverExecute:
2314 target = "false";
2315 case Tegra::Shader::Pred::UnusedIndex:
2316 target = "true";
2317 default:
2318 target = decomp.GetPredicate(index);
2319 }
2320 } else if (const auto flag = std::get_if<InternalFlagNode>(&*cc)) {
2321 target = decomp.GetInternalFlag(flag->GetFlag());
2322 }
2323 inner += target;
2324 }
2325
2326 void operator()(VideoCommon::Shader::ExprVar& expr) {
2327 inner += flow_var + std::to_string(expr.var_index);
2328 }
2329
2330 void operator()(VideoCommon::Shader::ExprBoolean& expr) {
2331 inner += expr.value ? "true" : "false";
2332 }
2333
2334 std::string& GetResult() {
2335 return inner;
2336 }
2337
2338private:
2339 std::string inner{};
2340 GLSLDecompiler& decomp;
2341};
2342
2343class ASTDecompiler {
2344public:
2345 ASTDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {}
2346
2347 void operator()(VideoCommon::Shader::ASTProgram& ast) {
2348 ASTNode current = ast.nodes.GetFirst();
2349 while (current) {
2350 Visit(current);
2351 current = current->GetNext();
2352 }
2353 }
2354
2355 void operator()(VideoCommon::Shader::ASTIfThen& ast) {
2356 ExprDecompiler expr_parser{decomp};
2357 std::visit(expr_parser, *ast.condition);
2358 decomp.code.AddLine("if ({}) {{", expr_parser.GetResult());
2359 decomp.code.scope++;
2360 ASTNode current = ast.nodes.GetFirst();
2361 while (current) {
2362 Visit(current);
2363 current = current->GetNext();
2364 }
2365 decomp.code.scope--;
2366 decomp.code.AddLine("}}");
2367 }
2368
2369 void operator()(VideoCommon::Shader::ASTIfElse& ast) {
2370 decomp.code.AddLine("else {{");
2371 decomp.code.scope++;
2372 ASTNode current = ast.nodes.GetFirst();
2373 while (current) {
2374 Visit(current);
2375 current = current->GetNext();
2376 }
2377 decomp.code.scope--;
2378 decomp.code.AddLine("}}");
2379 }
2380
2381 void operator()(VideoCommon::Shader::ASTBlockEncoded& ast) {
2382 UNREACHABLE();
2383 }
2384
2385 void operator()(VideoCommon::Shader::ASTBlockDecoded& ast) {
2386 decomp.VisitBlock(ast.nodes);
2387 }
2388
2389 void operator()(VideoCommon::Shader::ASTVarSet& ast) {
2390 ExprDecompiler expr_parser{decomp};
2391 std::visit(expr_parser, *ast.condition);
2392 decomp.code.AddLine("{}{} = {};", flow_var, ast.index, expr_parser.GetResult());
2393 }
2394
2395 void operator()(VideoCommon::Shader::ASTLabel& ast) {
2396 decomp.code.AddLine("// Label_{}:", ast.index);
2397 }
2398
2399 void operator()(VideoCommon::Shader::ASTGoto& ast) {
2400 UNREACHABLE();
2401 }
2402
2403 void operator()(VideoCommon::Shader::ASTDoWhile& ast) {
2404 ExprDecompiler expr_parser{decomp};
2405 std::visit(expr_parser, *ast.condition);
2406 decomp.code.AddLine("do {{");
2407 decomp.code.scope++;
2408 ASTNode current = ast.nodes.GetFirst();
2409 while (current) {
2410 Visit(current);
2411 current = current->GetNext();
2412 }
2413 decomp.code.scope--;
2414 decomp.code.AddLine("}} while({});", expr_parser.GetResult());
2415 }
2416
2417 void operator()(VideoCommon::Shader::ASTReturn& ast) {
2418 bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition);
2419 if (!is_true) {
2420 ExprDecompiler expr_parser{decomp};
2421 std::visit(expr_parser, *ast.condition);
2422 decomp.code.AddLine("if ({}) {{", expr_parser.GetResult());
2423 decomp.code.scope++;
2424 }
2425 if (ast.kills) {
2426 decomp.code.AddLine("discard;");
2427 } else {
2428 decomp.WriteExit();
2429 }
2430 if (!is_true) {
2431 decomp.code.scope--;
2432 decomp.code.AddLine("}}");
2433 }
2434 }
2435
2436 void operator()(VideoCommon::Shader::ASTBreak& ast) {
2437 bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition);
2438 if (!is_true) {
2439 ExprDecompiler expr_parser{decomp};
2440 std::visit(expr_parser, *ast.condition);
2441 decomp.code.AddLine("if ({}) {{", expr_parser.GetResult());
2442 decomp.code.scope++;
2443 }
2444 decomp.code.AddLine("break;");
2445 if (!is_true) {
2446 decomp.code.scope--;
2447 decomp.code.AddLine("}}");
2448 }
2449 }
2450
2451 void Visit(VideoCommon::Shader::ASTNode& node) {
2452 std::visit(*this, *node->GetInnerData());
2453 }
2454
2455private:
2456 GLSLDecompiler& decomp;
2457};
2458
2459void GLSLDecompiler::DecompileAST() {
2460 u32 num_flow_variables = ir.GetASTNumVariables();
2461 for (u32 i = 0; i < num_flow_variables; i++) {
2462 code.AddLine("bool {}{} = false;", flow_var, i);
2463 }
2464 ASTDecompiler decompiler{*this};
2465 VideoCommon::Shader::ASTNode program = ir.GetASTProgram();
2466 decompiler.Visit(program);
2467}
2468
2256} // Anonymous namespace 2469} // Anonymous namespace
2257 2470
2258std::string GetCommonDeclarations() { 2471std::string GetCommonDeclarations() {
diff --git a/src/video_core/shader/ast.cpp b/src/video_core/shader/ast.cpp
index 0bf289f98..68a96cc79 100644
--- a/src/video_core/shader/ast.cpp
+++ b/src/video_core/shader/ast.cpp
@@ -372,13 +372,13 @@ ASTManager::~ASTManager() {
372void ASTManager::Init() { 372void ASTManager::Init() {
373 main_node = ASTBase::Make<ASTProgram>(ASTNode{}); 373 main_node = ASTBase::Make<ASTProgram>(ASTNode{});
374 program = std::get_if<ASTProgram>(main_node->GetInnerData()); 374 program = std::get_if<ASTProgram>(main_node->GetInnerData());
375 true_condition = MakeExpr<ExprBoolean>(true); 375 false_condition = MakeExpr<ExprBoolean>(false);
376} 376}
377 377
378ASTManager::ASTManager(ASTManager&& other) 378ASTManager::ASTManager(ASTManager&& other)
379 : labels_map(std::move(other.labels_map)), labels_count{other.labels_count}, 379 : labels_map(std::move(other.labels_map)), labels_count{other.labels_count},
380 gotos(std::move(other.gotos)), labels(std::move(other.labels)), variables{other.variables}, 380 gotos(std::move(other.gotos)), labels(std::move(other.labels)), variables{other.variables},
381 program{other.program}, main_node{other.main_node}, true_condition{other.true_condition} { 381 program{other.program}, main_node{other.main_node}, false_condition{other.false_condition} {
382 other.main_node.reset(); 382 other.main_node.reset();
383} 383}
384 384
@@ -390,7 +390,7 @@ ASTManager& ASTManager::operator=(ASTManager&& other) {
390 variables = other.variables; 390 variables = other.variables;
391 program = other.program; 391 program = other.program;
392 main_node = other.main_node; 392 main_node = other.main_node;
393 true_condition = other.true_condition; 393 false_condition = other.false_condition;
394 394
395 other.main_node.reset(); 395 other.main_node.reset();
396 return *this; 396 return *this;
@@ -594,7 +594,7 @@ void ASTManager::MoveOutward(ASTNode goto_node) {
594 u32 var_index = NewVariable(); 594 u32 var_index = NewVariable();
595 Expr var_condition = MakeExpr<ExprVar>(var_index); 595 Expr var_condition = MakeExpr<ExprVar>(var_index);
596 ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition); 596 ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition);
597 ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, true_condition); 597 ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, false_condition);
598 zipper2.InsertBefore(var_node_init, parent); 598 zipper2.InsertBefore(var_node_init, parent);
599 zipper.InsertAfter(var_node, prev); 599 zipper.InsertAfter(var_node, prev);
600 goto_node->SetGotoCondition(var_condition); 600 goto_node->SetGotoCondition(var_condition);
@@ -605,7 +605,7 @@ void ASTManager::MoveOutward(ASTNode goto_node) {
605 u32 var_index = NewVariable(); 605 u32 var_index = NewVariable();
606 Expr var_condition = MakeExpr<ExprVar>(var_index); 606 Expr var_condition = MakeExpr<ExprVar>(var_index);
607 ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition); 607 ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition);
608 ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, true_condition); 608 ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, false_condition);
609 if (is_if) { 609 if (is_if) {
610 zipper2.InsertBefore(var_node_init, parent); 610 zipper2.InsertBefore(var_node_init, parent);
611 } else { 611 } else {
diff --git a/src/video_core/shader/ast.h b/src/video_core/shader/ast.h
index 958989bcd..06ab20cc5 100644
--- a/src/video_core/shader/ast.h
+++ b/src/video_core/shader/ast.h
@@ -141,8 +141,6 @@ public:
141 Expr condition; 141 Expr condition;
142}; 142};
143 143
144using TransformCallback = std::function<NodeBlock(u32 start, u32 end)>;
145
146class ASTBase { 144class ASTBase {
147public: 145public:
148 explicit ASTBase(ASTNode parent, ASTData data) : parent{parent}, data{data} {} 146 explicit ASTBase(ASTNode parent, ASTData data) : parent{parent}, data{data} {}
@@ -233,11 +231,7 @@ public:
233 return std::holds_alternative<ASTBlockEncoded>(data); 231 return std::holds_alternative<ASTBlockEncoded>(data);
234 } 232 }
235 233
236 void TransformBlockEncoded(TransformCallback& callback) { 234 void TransformBlockEncoded(NodeBlock& nodes) {
237 auto block = std::get_if<ASTBlockEncoded>(&data);
238 const u32 start = block->start;
239 const u32 end = block->end;
240 NodeBlock nodes = callback(start, end);
241 data = ASTBlockDecoded(nodes); 235 data = ASTBlockDecoded(nodes);
242 } 236 }
243 237
@@ -309,16 +303,20 @@ public:
309 303
310 void SanityCheck(); 304 void SanityCheck();
311 305
312 bool IsFullyDecompiled() { 306 bool IsFullyDecompiled() const {
313 return gotos.size() == 0; 307 return gotos.size() == 0;
314 } 308 }
315 309
316 ASTNode GetProgram() { 310 ASTNode GetProgram() const {
317 return main_node; 311 return main_node;
318 } 312 }
319 313
320 void Clear(); 314 void Clear();
321 315
316 u32 GetVariables() const {
317 return variables;
318 }
319
322private: 320private:
323 bool IndirectlyRelated(ASTNode first, ASTNode second); 321 bool IndirectlyRelated(ASTNode first, ASTNode second);
324 322
@@ -343,7 +341,7 @@ private:
343 u32 variables{}; 341 u32 variables{};
344 ASTProgram* program{}; 342 ASTProgram* program{};
345 ASTNode main_node{}; 343 ASTNode main_node{};
346 Expr true_condition{}; 344 Expr false_condition{};
347}; 345};
348 346
349} // namespace VideoCommon::Shader 347} // namespace VideoCommon::Shader
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) {
425 } 425 }
426 if (cond.predicate != Pred::UnusedIndex) { 426 if (cond.predicate != Pred::UnusedIndex) {
427 u32 pred = static_cast<u32>(cond.predicate); 427 u32 pred = static_cast<u32>(cond.predicate);
428 bool negate; 428 bool negate = false;
429 if (pred > 7) { 429 if (pred > 7) {
430 negate = true; 430 negate = true;
431 pred -= 8; 431 pred -= 8;
diff --git a/src/video_core/shader/control_flow.h b/src/video_core/shader/control_flow.h
index 2805d975c..347a35dcf 100644
--- a/src/video_core/shader/control_flow.h
+++ b/src/video_core/shader/control_flow.h
@@ -74,6 +74,6 @@ struct ShaderCharacteristics {
74}; 74};
75 75
76std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 program_size, 76std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 program_size,
77 u32 start_address, ASTManager& manager); 77 u32 start_address, ASTManager& manager);
78 78
79} // namespace VideoCommon::Shader 79} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp
index 381e87415..e7e0903f6 100644
--- a/src/video_core/shader/decode.cpp
+++ b/src/video_core/shader/decode.cpp
@@ -35,10 +35,73 @@ 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(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 = 105 const auto info =
43 ScanFlow(program_code, program_size, main_offset, program_manager); 106 ScanFlow(program_code, program_size, main_offset, program_manager);
44 if (info) { 107 if (info) {
@@ -46,7 +109,10 @@ void ShaderIR::Decode() {
46 coverage_begin = shader_info.start; 109 coverage_begin = shader_info.start;
47 coverage_end = shader_info.end; 110 coverage_end = shader_info.end;
48 if (shader_info.decompiled) { 111 if (shader_info.decompiled) {
49 disable_flow_stack = true; 112 decompiled = true;
113 ASTDecoder decoder{*this};
114 ASTNode program = GetASTProgram();
115 decoder.Visit(program);
50 return; 116 return;
51 } 117 }
52 LOG_WARNING(HW_GPU, "Flow Stack Removing Failed! Falling back to old method"); 118 LOG_WARNING(HW_GPU, "Flow Stack Removing Failed! Falling back to old method");
diff --git a/src/video_core/shader/decode/other.cpp b/src/video_core/shader/decode/other.cpp
index d46e0f823..6f678003c 100644
--- a/src/video_core/shader/decode/other.cpp
+++ b/src/video_core/shader/decode/other.cpp
@@ -157,7 +157,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
157 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0, 157 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
158 "Constant buffer flow is not supported"); 158 "Constant buffer flow is not supported");
159 159
160 if (disable_flow_stack) { 160 if (decompiled) {
161 break; 161 break;
162 } 162 }
163 163
@@ -171,7 +171,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
171 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0, 171 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
172 "Constant buffer PBK is not supported"); 172 "Constant buffer PBK is not supported");
173 173
174 if (disable_flow_stack) { 174 if (decompiled) {
175 break; 175 break;
176 } 176 }
177 177
@@ -186,7 +186,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
186 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "SYNC condition code used: {}", 186 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "SYNC condition code used: {}",
187 static_cast<u32>(cc)); 187 static_cast<u32>(cc));
188 188
189 if (disable_flow_stack) { 189 if (decompiled) {
190 break; 190 break;
191 } 191 }
192 192
@@ -198,7 +198,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
198 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code; 198 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
199 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "BRK condition code used: {}", 199 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "BRK condition code used: {}",
200 static_cast<u32>(cc)); 200 static_cast<u32>(cc));
201 if (disable_flow_stack) { 201 if (decompiled) {
202 break; 202 break;
203 } 203 }
204 204
diff --git a/src/video_core/shader/expr.cpp b/src/video_core/shader/expr.cpp
index ebce6339b..ca633ffb1 100644
--- a/src/video_core/shader/expr.cpp
+++ b/src/video_core/shader/expr.cpp
@@ -72,4 +72,11 @@ bool ExprAreOpposite(Expr first, Expr second) {
72 return false; 72 return false;
73} 73}
74 74
75bool ExprIsTrue(Expr first) {
76 if (ExprIsBoolean(first)) {
77 return ExprBooleanGet(first);
78 }
79 return false;
80}
81
75} // namespace VideoCommon::Shader 82} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/expr.h b/src/video_core/shader/expr.h
index f012f6fcf..b954cffb0 100644
--- a/src/video_core/shader/expr.h
+++ b/src/video_core/shader/expr.h
@@ -115,4 +115,6 @@ Expr MakeExprAnd(Expr first, Expr second);
115 115
116Expr MakeExprOr(Expr first, Expr second); 116Expr MakeExprOr(Expr first, Expr second);
117 117
118bool ExprIsTrue(Expr first);
119
118} // namespace VideoCommon::Shader 120} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp
index c79f80e04..004b1e16f 100644
--- a/src/video_core/shader/shader_ir.cpp
+++ b/src/video_core/shader/shader_ir.cpp
@@ -137,7 +137,7 @@ Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buff
137 return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer)); 137 return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer));
138} 138}
139 139
140Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) { 140Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) const {
141 const Node node = MakeNode<InternalFlagNode>(flag); 141 const Node node = MakeNode<InternalFlagNode>(flag);
142 if (negated) { 142 if (negated) {
143 return Operation(OperationCode::LogicalNegate, node); 143 return Operation(OperationCode::LogicalNegate, node);
@@ -367,13 +367,13 @@ OperationCode ShaderIR::GetPredicateCombiner(PredOperation operation) {
367 return op->second; 367 return op->second;
368} 368}
369 369
370Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) { 370Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) const {
371 switch (cc) { 371 switch (cc) {
372 case Tegra::Shader::ConditionCode::NEU: 372 case Tegra::Shader::ConditionCode::NEU:
373 return GetInternalFlag(InternalFlag::Zero, true); 373 return GetInternalFlag(InternalFlag::Zero, true);
374 default: 374 default:
375 UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc)); 375 UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc));
376 return GetPredicate(static_cast<u64>(Pred::NeverExecute)); 376 return MakeNode<PredicateNode>(Pred::NeverExecute, false);
377 } 377 }
378} 378}
379 379
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index a91cd7d67..48c7b722e 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -15,8 +15,8 @@
15#include "video_core/engines/maxwell_3d.h" 15#include "video_core/engines/maxwell_3d.h"
16#include "video_core/engines/shader_bytecode.h" 16#include "video_core/engines/shader_bytecode.h"
17#include "video_core/engines/shader_header.h" 17#include "video_core/engines/shader_header.h"
18#include "video_core/shader/node.h"
19#include "video_core/shader/ast.h" 18#include "video_core/shader/ast.h"
19#include "video_core/shader/node.h"
20 20
21namespace VideoCommon::Shader { 21namespace VideoCommon::Shader {
22 22
@@ -141,15 +141,27 @@ public:
141 return header; 141 return header;
142 } 142 }
143 143
144 bool IsFlowStackDisabled() const { 144 bool IsDecompiled() const {
145 return disable_flow_stack; 145 return decompiled;
146 }
147
148 ASTNode GetASTProgram() const {
149 return program_manager.GetProgram();
150 }
151
152 u32 GetASTNumVariables() const {
153 return program_manager.GetVariables();
146 } 154 }
147 155
148 u32 ConvertAddressToNvidiaSpace(const u32 address) const { 156 u32 ConvertAddressToNvidiaSpace(const u32 address) const {
149 return (address - main_offset) * sizeof(Tegra::Shader::Instruction); 157 return (address - main_offset) * sizeof(Tegra::Shader::Instruction);
150 } 158 }
151 159
160 /// Returns a condition code evaluated from internal flags
161 Node GetConditionCode(Tegra::Shader::ConditionCode cc) const;
162
152private: 163private:
164 friend class ASTDecoder;
153 void Decode(); 165 void Decode();
154 166
155 NodeBlock DecodeRange(u32 begin, u32 end); 167 NodeBlock DecodeRange(u32 begin, u32 end);
@@ -214,7 +226,7 @@ private:
214 /// Generates a node representing an output attribute. Keeps track of used attributes. 226 /// Generates a node representing an output attribute. Keeps track of used attributes.
215 Node GetOutputAttribute(Tegra::Shader::Attribute::Index index, u64 element, Node buffer); 227 Node GetOutputAttribute(Tegra::Shader::Attribute::Index index, u64 element, Node buffer);
216 /// Generates a node representing an internal flag 228 /// Generates a node representing an internal flag
217 Node GetInternalFlag(InternalFlag flag, bool negated = false); 229 Node GetInternalFlag(InternalFlag flag, bool negated = false) const;
218 /// Generates a node representing a local memory address 230 /// Generates a node representing a local memory address
219 Node GetLocalMemory(Node address); 231 Node GetLocalMemory(Node address);
220 /// Generates a node representing a shared memory address 232 /// Generates a node representing a shared memory address
@@ -272,9 +284,6 @@ private:
272 /// Returns a predicate combiner operation 284 /// Returns a predicate combiner operation
273 OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation); 285 OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation);
274 286
275 /// Returns a condition code evaluated from internal flags
276 Node GetConditionCode(Tegra::Shader::ConditionCode cc);
277
278 /// Accesses a texture sampler 287 /// Accesses a texture sampler
279 const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler, 288 const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler,
280 Tegra::Shader::TextureType type, bool is_array, bool is_shadow); 289 Tegra::Shader::TextureType type, bool is_array, bool is_shadow);
@@ -358,7 +367,7 @@ private:
358 const ProgramCode& program_code; 367 const ProgramCode& program_code;
359 const u32 main_offset; 368 const u32 main_offset;
360 const std::size_t program_size; 369 const std::size_t program_size;
361 bool disable_flow_stack{}; 370 bool decompiled{};
362 371
363 u32 coverage_begin{}; 372 u32 coverage_begin{};
364 u32 coverage_end{}; 373 u32 coverage_end{};