summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2019-06-28 22:59:43 -0400
committerGravatar FernandoS272019-10-04 18:52:49 -0400
commit6fdd501113d5094f9148046c3b17cf2239e99aa5 (patch)
tree5a328292210ac4f07696bad5ea237277a7cb9113 /src
parentshader_ir: Corrections to outward movements and misc stuffs (diff)
downloadyuzu-6fdd501113d5094f9148046c3b17cf2239e99aa5.tar.gz
yuzu-6fdd501113d5094f9148046c3b17cf2239e99aa5.tar.xz
yuzu-6fdd501113d5094f9148046c3b17cf2239e99aa5.zip
shader_ir: Declare Manager and pass it to appropiate programs.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/shader/ast.cpp139
-rw-r--r--src/video_core/shader/ast.h74
-rw-r--r--src/video_core/shader/control_flow.cpp65
-rw-r--r--src/video_core/shader/control_flow.h8
-rw-r--r--src/video_core/shader/decode.cpp28
-rw-r--r--src/video_core/shader/shader_ir.cpp2
-rw-r--r--src/video_core/shader/shader_ir.h2
7 files changed, 214 insertions, 104 deletions
diff --git a/src/video_core/shader/ast.cpp b/src/video_core/shader/ast.cpp
index d521a7b52..0bf289f98 100644
--- a/src/video_core/shader/ast.cpp
+++ b/src/video_core/shader/ast.cpp
@@ -363,6 +363,71 @@ std::string ASTManager::Print() {
363 return printer.GetResult(); 363 return printer.GetResult();
364} 364}
365 365
366ASTManager::ASTManager() = default;
367
368ASTManager::~ASTManager() {
369 Clear();
370}
371
372void ASTManager::Init() {
373 main_node = ASTBase::Make<ASTProgram>(ASTNode{});
374 program = std::get_if<ASTProgram>(main_node->GetInnerData());
375 true_condition = MakeExpr<ExprBoolean>(true);
376}
377
378ASTManager::ASTManager(ASTManager&& other)
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},
381 program{other.program}, main_node{other.main_node}, true_condition{other.true_condition} {
382 other.main_node.reset();
383}
384
385ASTManager& ASTManager::operator=(ASTManager&& other) {
386 labels_map = std::move(other.labels_map);
387 labels_count = other.labels_count;
388 gotos = std::move(other.gotos);
389 labels = std::move(other.labels);
390 variables = other.variables;
391 program = other.program;
392 main_node = other.main_node;
393 true_condition = other.true_condition;
394
395 other.main_node.reset();
396 return *this;
397}
398
399void ASTManager::DeclareLabel(u32 address) {
400 const auto pair = labels_map.emplace(address, labels_count);
401 if (pair.second) {
402 labels_count++;
403 labels.resize(labels_count);
404 }
405}
406
407void ASTManager::InsertLabel(u32 address) {
408 u32 index = labels_map[address];
409 ASTNode label = ASTBase::Make<ASTLabel>(main_node, index);
410 labels[index] = label;
411 program->nodes.PushBack(label);
412}
413
414void ASTManager::InsertGoto(Expr condition, u32 address) {
415 u32 index = labels_map[address];
416 ASTNode goto_node = ASTBase::Make<ASTGoto>(main_node, condition, index);
417 gotos.push_back(goto_node);
418 program->nodes.PushBack(goto_node);
419}
420
421void ASTManager::InsertBlock(u32 start_address, u32 end_address) {
422 ASTNode block = ASTBase::Make<ASTBlockEncoded>(main_node, start_address, end_address);
423 program->nodes.PushBack(block);
424}
425
426void ASTManager::InsertReturn(Expr condition, bool kills) {
427 ASTNode node = ASTBase::Make<ASTReturn>(main_node, condition, kills);
428 program->nodes.PushBack(node);
429}
430
366void ASTManager::Decompile() { 431void ASTManager::Decompile() {
367 auto it = gotos.begin(); 432 auto it = gotos.begin();
368 while (it != gotos.end()) { 433 while (it != gotos.end()) {
@@ -460,7 +525,6 @@ void ASTManager::SanityCheck() {
460 525
461void ASTManager::EncloseDoWhile(ASTNode goto_node, ASTNode label) { 526void ASTManager::EncloseDoWhile(ASTNode goto_node, ASTNode label) {
462 // ShowCurrentState("Before DoWhile Enclose"); 527 // ShowCurrentState("Before DoWhile Enclose");
463 enclose_count++;
464 ASTZipper& zipper = goto_node->GetManager(); 528 ASTZipper& zipper = goto_node->GetManager();
465 ASTNode loop_start = label->GetNext(); 529 ASTNode loop_start = label->GetNext();
466 if (loop_start == goto_node) { 530 if (loop_start == goto_node) {
@@ -481,7 +545,6 @@ void ASTManager::EncloseDoWhile(ASTNode goto_node, ASTNode label) {
481 545
482void ASTManager::EncloseIfThen(ASTNode goto_node, ASTNode label) { 546void ASTManager::EncloseIfThen(ASTNode goto_node, ASTNode label) {
483 // ShowCurrentState("Before IfThen Enclose"); 547 // ShowCurrentState("Before IfThen Enclose");
484 enclose_count++;
485 ASTZipper& zipper = goto_node->GetManager(); 548 ASTZipper& zipper = goto_node->GetManager();
486 ASTNode if_end = label->GetPrevious(); 549 ASTNode if_end = label->GetPrevious();
487 if (if_end == goto_node) { 550 if (if_end == goto_node) {
@@ -514,7 +577,6 @@ void ASTManager::EncloseIfThen(ASTNode goto_node, ASTNode label) {
514 577
515void ASTManager::MoveOutward(ASTNode goto_node) { 578void ASTManager::MoveOutward(ASTNode goto_node) {
516 // ShowCurrentState("Before MoveOutward"); 579 // ShowCurrentState("Before MoveOutward");
517 outward_count++;
518 ASTZipper& zipper = goto_node->GetManager(); 580 ASTZipper& zipper = goto_node->GetManager();
519 ASTNode parent = goto_node->GetParent(); 581 ASTNode parent = goto_node->GetParent();
520 ASTZipper& zipper2 = parent->GetManager(); 582 ASTZipper& zipper2 = parent->GetManager();
@@ -582,4 +644,75 @@ void ASTManager::MoveOutward(ASTNode goto_node) {
582 // ShowCurrentState("After MoveOutward"); 644 // ShowCurrentState("After MoveOutward");
583} 645}
584 646
647class ASTClearer {
648public:
649 ASTClearer() = default;
650
651 void operator()(ASTProgram& ast) {
652 ASTNode current = ast.nodes.GetFirst();
653 while (current) {
654 Visit(current);
655 current = current->GetNext();
656 }
657 }
658
659 void operator()(ASTIfThen& ast) {
660 ASTNode current = ast.nodes.GetFirst();
661 while (current) {
662 Visit(current);
663 current = current->GetNext();
664 }
665 }
666
667 void operator()(ASTIfElse& ast) {
668 ASTNode current = ast.nodes.GetFirst();
669 while (current) {
670 Visit(current);
671 current = current->GetNext();
672 }
673 }
674
675 void operator()(ASTBlockEncoded& ast) {}
676
677 void operator()(ASTBlockDecoded& ast) {
678 ast.nodes.clear();
679 }
680
681 void operator()(ASTVarSet& ast) {}
682
683 void operator()(ASTLabel& ast) {}
684
685 void operator()(ASTGoto& ast) {}
686
687 void operator()(ASTDoWhile& ast) {
688 ASTNode current = ast.nodes.GetFirst();
689 while (current) {
690 Visit(current);
691 current = current->GetNext();
692 }
693 }
694
695 void operator()(ASTReturn& ast) {}
696
697 void operator()(ASTBreak& ast) {}
698
699 void Visit(ASTNode& node) {
700 std::visit(*this, *node->GetInnerData());
701 node->Clear();
702 }
703};
704
705void ASTManager::Clear() {
706 if (!main_node) {
707 return;
708 }
709 ASTClearer clearer{};
710 clearer.Visit(main_node);
711 main_node.reset();
712 program = nullptr;
713 labels_map.clear();
714 labels.clear();
715 gotos.clear();
716}
717
585} // namespace VideoCommon::Shader 718} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/ast.h b/src/video_core/shader/ast.h
index 4276f66a9..958989bcd 100644
--- a/src/video_core/shader/ast.h
+++ b/src/video_core/shader/ast.h
@@ -30,8 +30,8 @@ class ASTDoWhile;
30class ASTReturn; 30class ASTReturn;
31class ASTBreak; 31class ASTBreak;
32 32
33using ASTData = std::variant<ASTProgram, ASTIfThen, ASTIfElse, ASTBlockEncoded, ASTBlockDecoded, ASTVarSet, ASTGoto, 33using ASTData = std::variant<ASTProgram, ASTIfThen, ASTIfElse, ASTBlockEncoded, ASTBlockDecoded,
34 ASTLabel, ASTDoWhile, ASTReturn, ASTBreak>; 34 ASTVarSet, ASTGoto, ASTLabel, ASTDoWhile, ASTReturn, ASTBreak>;
35 35
36using ASTNode = std::shared_ptr<ASTBase>; 36using ASTNode = std::shared_ptr<ASTBase>;
37 37
@@ -261,6 +261,13 @@ public:
261 return nullptr; 261 return nullptr;
262 } 262 }
263 263
264 void Clear() {
265 next.reset();
266 previous.reset();
267 parent.reset();
268 manager = nullptr;
269 }
270
264private: 271private:
265 friend class ASTZipper; 272 friend class ASTZipper;
266 273
@@ -273,43 +280,26 @@ private:
273 280
274class ASTManager final { 281class ASTManager final {
275public: 282public:
276 explicit ASTManager() { 283 ASTManager();
277 main_node = ASTBase::Make<ASTProgram>(ASTNode{}); 284 ~ASTManager();
278 program = std::get_if<ASTProgram>(main_node->GetInnerData());
279 true_condition = MakeExpr<ExprBoolean>(true);
280 }
281 285
282 void DeclareLabel(u32 address) { 286 ASTManager(const ASTManager& o) = delete;
283 const auto pair = labels_map.emplace(address, labels_count); 287 ASTManager& operator=(const ASTManager& other) = delete;
284 if (pair.second) {
285 labels_count++;
286 labels.resize(labels_count);
287 }
288 }
289 288
290 void InsertLabel(u32 address) { 289 ASTManager(ASTManager&& other);
291 u32 index = labels_map[address]; 290 ASTManager& operator=(ASTManager&& other);
292 ASTNode label = ASTBase::Make<ASTLabel>(main_node, index);
293 labels[index] = label;
294 program->nodes.PushBack(label);
295 }
296 291
297 void InsertGoto(Expr condition, u32 address) { 292 void Init();
298 u32 index = labels_map[address];
299 ASTNode goto_node = ASTBase::Make<ASTGoto>(main_node, condition, index);
300 gotos.push_back(goto_node);
301 program->nodes.PushBack(goto_node);
302 }
303 293
304 void InsertBlock(u32 start_address, u32 end_address) { 294 void DeclareLabel(u32 address);
305 ASTNode block = ASTBase::Make<ASTBlockEncoded>(main_node, start_address, end_address);
306 program->nodes.PushBack(block);
307 }
308 295
309 void InsertReturn(Expr condition, bool kills) { 296 void InsertLabel(u32 address);
310 ASTNode node = ASTBase::Make<ASTReturn>(main_node, condition, kills); 297
311 program->nodes.PushBack(node); 298 void InsertGoto(Expr condition, u32 address);
312 } 299
300 void InsertBlock(u32 start_address, u32 end_address);
301
302 void InsertReturn(Expr condition, bool kills);
313 303
314 std::string Print(); 304 std::string Print();
315 305
@@ -323,6 +313,12 @@ public:
323 return gotos.size() == 0; 313 return gotos.size() == 0;
324 } 314 }
325 315
316 ASTNode GetProgram() {
317 return main_node;
318 }
319
320 void Clear();
321
326private: 322private:
327 bool IndirectlyRelated(ASTNode first, ASTNode second); 323 bool IndirectlyRelated(ASTNode first, ASTNode second);
328 324
@@ -332,7 +328,7 @@ private:
332 328
333 void EncloseIfThen(ASTNode goto_node, ASTNode label); 329 void EncloseIfThen(ASTNode goto_node, ASTNode label);
334 330
335 void MoveOutward(ASTNode goto_node) ; 331 void MoveOutward(ASTNode goto_node);
336 332
337 u32 NewVariable() { 333 u32 NewVariable() {
338 u32 new_var = variables; 334 u32 new_var = variables;
@@ -345,11 +341,9 @@ private:
345 std::vector<ASTNode> labels{}; 341 std::vector<ASTNode> labels{};
346 std::list<ASTNode> gotos{}; 342 std::list<ASTNode> gotos{};
347 u32 variables{}; 343 u32 variables{};
348 ASTProgram* program; 344 ASTProgram* program{};
349 ASTNode main_node; 345 ASTNode main_node{};
350 Expr true_condition; 346 Expr true_condition{};
351 u32 outward_count{};
352 u32 enclose_count{};
353}; 347};
354 348
355} // namespace VideoCommon::Shader 349} // namespace VideoCommon::Shader
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 {
57 57
58struct CFGRebuildState { 58struct CFGRebuildState {
59 explicit CFGRebuildState(const ProgramCode& program_code, const std::size_t program_size, 59 explicit CFGRebuildState(const ProgramCode& program_code, const std::size_t program_size,
60 const u32 start) 60 const u32 start, ASTManager& manager)
61 : start{start}, program_code{program_code}, program_size{program_size} {} 61 : program_code{program_code}, program_size{program_size}, start{start}, manager{manager} {}
62 62
63 u32 start{}; 63 u32 start{};
64 std::vector<BlockInfo> block_info{}; 64 std::vector<BlockInfo> block_info{};
@@ -71,6 +71,7 @@ struct CFGRebuildState {
71 std::unordered_map<u32, BlockStack> stacks{}; 71 std::unordered_map<u32, BlockStack> stacks{};
72 const ProgramCode& program_code; 72 const ProgramCode& program_code;
73 const std::size_t program_size; 73 const std::size_t program_size;
74 ASTManager& manager;
74}; 75};
75 76
76enum class BlockCollision : u32 { None, Found, Inside }; 77enum class BlockCollision : u32 { None, Found, Inside };
@@ -455,29 +456,28 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch) {
455} 456}
456 457
457void DecompileShader(CFGRebuildState& state) { 458void DecompileShader(CFGRebuildState& state) {
458 ASTManager manager{}; 459 state.manager.Init();
459 for (auto label : state.labels) { 460 for (auto label : state.labels) {
460 manager.DeclareLabel(label); 461 state.manager.DeclareLabel(label);
461 } 462 }
462 for (auto& block : state.block_info) { 463 for (auto& block : state.block_info) {
463 if (state.labels.count(block.start) != 0) { 464 if (state.labels.count(block.start) != 0) {
464 manager.InsertLabel(block.start); 465 state.manager.InsertLabel(block.start);
465 } 466 }
466 u32 end = block.branch.ignore ? block.end + 1 : block.end; 467 u32 end = block.branch.ignore ? block.end + 1 : block.end;
467 manager.InsertBlock(block.start, end); 468 state.manager.InsertBlock(block.start, end);
468 if (!block.branch.ignore) { 469 if (!block.branch.ignore) {
469 InsertBranch(manager, block.branch); 470 InsertBranch(state.manager, block.branch);
470 } 471 }
471 } 472 }
472 //manager.ShowCurrentState("Before Decompiling"); 473 // state.manager.ShowCurrentState("Before Decompiling");
473 manager.Decompile(); 474 state.manager.Decompile();
474 //manager.ShowCurrentState("After Decompiling"); 475 // state.manager.ShowCurrentState("After Decompiling");
475} 476}
476 477
477std::optional<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, 478std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 program_size,
478 std::size_t program_size, u32 start_address) { 479 u32 start_address, ASTManager& manager) {
479 CFGRebuildState state{program_code, program_size, start_address}; 480 CFGRebuildState state{program_code, program_size, start_address, manager};
480
481 // Inspect Code and generate blocks 481 // Inspect Code and generate blocks
482 state.labels.clear(); 482 state.labels.clear();
483 state.labels.emplace(start_address); 483 state.labels.emplace(start_address);
@@ -503,12 +503,21 @@ std::optional<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
503 [](const BlockInfo& a, const BlockInfo& b) -> bool { return a.start < b.start; }); 503 [](const BlockInfo& a, const BlockInfo& b) -> bool { return a.start < b.start; });
504 if (decompiled) { 504 if (decompiled) {
505 DecompileShader(state); 505 DecompileShader(state);
506 decompiled = state.manager.IsFullyDecompiled();
507 if (!decompiled) {
508 LOG_CRITICAL(HW_GPU, "Failed to remove all the gotos!:");
509 state.manager.ShowCurrentState("Of Shader");
510 state.manager.Clear();
511 }
512 }
513 auto result_out = std::make_unique<ShaderCharacteristics>();
514 result_out->decompiled = decompiled;
515 result_out->start = start_address;
516 if (decompiled) {
517 result_out->end = state.block_info.back().end + 1;
518 return std::move(result_out);
506 } 519 }
507 ShaderCharacteristics result_out{}; 520 for (auto& block : state.block_info) {
508 result_out.decompilable = decompiled;
509 result_out.start = start_address;
510 result_out.end = start_address;
511 for (const auto& block : state.block_info) {
512 ShaderBlock new_block{}; 521 ShaderBlock new_block{};
513 new_block.start = block.start; 522 new_block.start = block.start;
514 new_block.end = block.end; 523 new_block.end = block.end;
@@ -518,26 +527,20 @@ std::optional<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
518 new_block.branch.kills = block.branch.kill; 527 new_block.branch.kills = block.branch.kill;
519 new_block.branch.address = block.branch.address; 528 new_block.branch.address = block.branch.address;
520 } 529 }
521 result_out.end = std::max(result_out.end, block.end); 530 result_out->end = std::max(result_out->end, block.end);
522 result_out.blocks.push_back(new_block); 531 result_out->blocks.push_back(new_block);
523 }
524 if (result_out.decompilable) {
525 result_out.labels = std::move(state.labels);
526 return {std::move(result_out)};
527 } 532 }
528 533 auto back = result_out->blocks.begin();
529 // If it's not decompilable, merge the unlabelled blocks together
530 auto back = result_out.blocks.begin();
531 auto next = std::next(back); 534 auto next = std::next(back);
532 while (next != result_out.blocks.end()) { 535 while (next != result_out->blocks.end()) {
533 if (state.labels.count(next->start) == 0 && next->start == back->end + 1) { 536 if (state.labels.count(next->start) == 0 && next->start == back->end + 1) {
534 back->end = next->end; 537 back->end = next->end;
535 next = result_out.blocks.erase(next); 538 next = result_out->blocks.erase(next);
536 continue; 539 continue;
537 } 540 }
538 back = next; 541 back = next;
539 ++next; 542 ++next;
540 } 543 }
541 return {std::move(result_out)}; 544 return std::move(result_out);
542} 545}
543} // namespace VideoCommon::Shader 546} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/control_flow.h b/src/video_core/shader/control_flow.h
index efd037f1a..2805d975c 100644
--- a/src/video_core/shader/control_flow.h
+++ b/src/video_core/shader/control_flow.h
@@ -10,6 +10,7 @@
10 10
11#include "video_core/engines/shader_bytecode.h" 11#include "video_core/engines/shader_bytecode.h"
12#include "video_core/shader/shader_ir.h" 12#include "video_core/shader/shader_ir.h"
13#include "video_core/shader/ast.h"
13 14
14namespace VideoCommon::Shader { 15namespace VideoCommon::Shader {
15 16
@@ -67,13 +68,12 @@ struct ShaderBlock {
67 68
68struct ShaderCharacteristics { 69struct ShaderCharacteristics {
69 std::list<ShaderBlock> blocks{}; 70 std::list<ShaderBlock> blocks{};
70 bool decompilable{}; 71 bool decompiled{};
71 u32 start{}; 72 u32 start{};
72 u32 end{}; 73 u32 end{};
73 std::set<u32> labels{};
74}; 74};
75 75
76std::optional<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, 76std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 program_size,
77 std::size_t program_size, u32 start_address); 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 47a9fd961..381e87415 100644
--- a/src/video_core/shader/decode.cpp
+++ b/src/video_core/shader/decode.cpp
@@ -39,36 +39,14 @@ void ShaderIR::Decode() {
39 std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); 39 std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
40 40
41 disable_flow_stack = false; 41 disable_flow_stack = false;
42 const auto info = ScanFlow(program_code, program_size, main_offset); 42 const auto info =
43 ScanFlow(program_code, program_size, main_offset, program_manager);
43 if (info) { 44 if (info) {
44 const auto& shader_info = *info; 45 const auto& shader_info = *info;
45 coverage_begin = shader_info.start; 46 coverage_begin = shader_info.start;
46 coverage_end = shader_info.end; 47 coverage_end = shader_info.end;
47 if (shader_info.decompilable) { 48 if (shader_info.decompiled) {
48 disable_flow_stack = true; 49 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; 50 return;
73 } 51 }
74 LOG_WARNING(HW_GPU, "Flow Stack Removing Failed! Falling back to old method"); 52 LOG_WARNING(HW_GPU, "Flow Stack Removing Failed! Falling back to old method");
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp
index 2c357f310..c79f80e04 100644
--- a/src/video_core/shader/shader_ir.cpp
+++ b/src/video_core/shader/shader_ir.cpp
@@ -23,7 +23,7 @@ using Tegra::Shader::PredOperation;
23using Tegra::Shader::Register; 23using Tegra::Shader::Register;
24 24
25ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset, const std::size_t size) 25ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset, const std::size_t size)
26 : program_code{program_code}, main_offset{main_offset}, program_size{size} { 26 : program_code{program_code}, main_offset{main_offset}, program_size{size}, program_manager{} {
27 Decode(); 27 Decode();
28} 28}
29 29
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index 6f666ee30..a91cd7d67 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -16,6 +16,7 @@
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" 18#include "video_core/shader/node.h"
19#include "video_core/shader/ast.h"
19 20
20namespace VideoCommon::Shader { 21namespace VideoCommon::Shader {
21 22
@@ -364,6 +365,7 @@ private:
364 365
365 std::map<u32, NodeBlock> basic_blocks; 366 std::map<u32, NodeBlock> basic_blocks;
366 NodeBlock global_code; 367 NodeBlock global_code;
368 ASTManager program_manager;
367 369
368 std::set<u32> used_registers; 370 std::set<u32> used_registers;
369 std::set<Tegra::Shader::Pred> used_predicates; 371 std::set<Tegra::Shader::Pred> used_predicates;