summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp')
-rw-r--r--src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp57
1 files changed, 57 insertions, 0 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
index 9d4688390..a6e55f61e 100644
--- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
@@ -17,6 +17,7 @@
17#include "shader_recompiler/environment.h" 17#include "shader_recompiler/environment.h"
18#include "shader_recompiler/frontend/ir/basic_block.h" 18#include "shader_recompiler/frontend/ir/basic_block.h"
19#include "shader_recompiler/frontend/ir/ir_emitter.h" 19#include "shader_recompiler/frontend/ir/ir_emitter.h"
20#include "shader_recompiler/frontend/maxwell/decode.h"
20#include "shader_recompiler/frontend/maxwell/structured_control_flow.h" 21#include "shader_recompiler/frontend/maxwell/structured_control_flow.h"
21#include "shader_recompiler/frontend/maxwell/translate/translate.h" 22#include "shader_recompiler/frontend/maxwell/translate/translate.h"
22#include "shader_recompiler/object_pool.h" 23#include "shader_recompiler/object_pool.h"
@@ -46,12 +47,15 @@ enum class StatementType {
46 Break, 47 Break,
47 Return, 48 Return,
48 Kill, 49 Kill,
50 Unreachable,
49 Function, 51 Function,
50 Identity, 52 Identity,
51 Not, 53 Not,
52 Or, 54 Or,
53 SetVariable, 55 SetVariable,
56 SetIndirectBranchVariable,
54 Variable, 57 Variable,
58 IndirectBranchCond,
55}; 59};
56 60
57bool HasChildren(StatementType type) { 61bool HasChildren(StatementType type) {
@@ -72,12 +76,15 @@ struct Loop {};
72struct Break {}; 76struct Break {};
73struct Return {}; 77struct Return {};
74struct Kill {}; 78struct Kill {};
79struct Unreachable {};
75struct FunctionTag {}; 80struct FunctionTag {};
76struct Identity {}; 81struct Identity {};
77struct Not {}; 82struct Not {};
78struct Or {}; 83struct Or {};
79struct SetVariable {}; 84struct SetVariable {};
85struct SetIndirectBranchVariable {};
80struct Variable {}; 86struct Variable {};
87struct IndirectBranchCond {};
81 88
82#ifdef _MSC_VER 89#ifdef _MSC_VER
83#pragma warning(push) 90#pragma warning(push)
@@ -96,6 +103,7 @@ struct Statement : ListBaseHook {
96 : cond{cond_}, up{up_}, type{StatementType::Break} {} 103 : cond{cond_}, up{up_}, type{StatementType::Break} {}
97 Statement(Return) : type{StatementType::Return} {} 104 Statement(Return) : type{StatementType::Return} {}
98 Statement(Kill) : type{StatementType::Kill} {} 105 Statement(Kill) : type{StatementType::Kill} {}
106 Statement(Unreachable) : type{StatementType::Unreachable} {}
99 Statement(FunctionTag) : children{}, type{StatementType::Function} {} 107 Statement(FunctionTag) : children{}, type{StatementType::Function} {}
100 Statement(Identity, IR::Condition cond_) : guest_cond{cond_}, type{StatementType::Identity} {} 108 Statement(Identity, IR::Condition cond_) : guest_cond{cond_}, type{StatementType::Identity} {}
101 Statement(Not, Statement* op_) : op{op_}, type{StatementType::Not} {} 109 Statement(Not, Statement* op_) : op{op_}, type{StatementType::Not} {}
@@ -103,7 +111,12 @@ struct Statement : ListBaseHook {
103 : op_a{op_a_}, op_b{op_b_}, type{StatementType::Or} {} 111 : op_a{op_a_}, op_b{op_b_}, type{StatementType::Or} {}
104 Statement(SetVariable, u32 id_, Statement* op_, Statement* up_) 112 Statement(SetVariable, u32 id_, Statement* op_, Statement* up_)
105 : op{op_}, id{id_}, up{up_}, type{StatementType::SetVariable} {} 113 : op{op_}, id{id_}, up{up_}, type{StatementType::SetVariable} {}
114 Statement(SetIndirectBranchVariable, IR::Reg branch_reg_, s32 branch_offset_)
115 : branch_offset{branch_offset_},
116 branch_reg{branch_reg_}, type{StatementType::SetIndirectBranchVariable} {}
106 Statement(Variable, u32 id_) : id{id_}, type{StatementType::Variable} {} 117 Statement(Variable, u32 id_) : id{id_}, type{StatementType::Variable} {}
118 Statement(IndirectBranchCond, u32 location_)
119 : location{location_}, type{StatementType::IndirectBranchCond} {}
107 120
108 ~Statement() { 121 ~Statement() {
109 if (HasChildren(type)) { 122 if (HasChildren(type)) {
@@ -118,11 +131,14 @@ struct Statement : ListBaseHook {
118 IR::Condition guest_cond; 131 IR::Condition guest_cond;
119 Statement* op; 132 Statement* op;
120 Statement* op_a; 133 Statement* op_a;
134 u32 location;
135 s32 branch_offset;
121 }; 136 };
122 union { 137 union {
123 Statement* cond; 138 Statement* cond;
124 Statement* op_b; 139 Statement* op_b;
125 u32 id; 140 u32 id;
141 IR::Reg branch_reg;
126 }; 142 };
127 Statement* up{}; 143 Statement* up{};
128 StatementType type; 144 StatementType type;
@@ -141,6 +157,8 @@ std::string DumpExpr(const Statement* stmt) {
141 return fmt::format("{} || {}", DumpExpr(stmt->op_a), DumpExpr(stmt->op_b)); 157 return fmt::format("{} || {}", DumpExpr(stmt->op_a), DumpExpr(stmt->op_b));
142 case StatementType::Variable: 158 case StatementType::Variable:
143 return fmt::format("goto_L{}", stmt->id); 159 return fmt::format("goto_L{}", stmt->id);
160 case StatementType::IndirectBranchCond:
161 return fmt::format("(indirect_branch == {:x})", stmt->location);
144 default: 162 default:
145 return "<invalid type>"; 163 return "<invalid type>";
146 } 164 }
@@ -182,14 +200,22 @@ std::string DumpTree(const Tree& tree, u32 indentation = 0) {
182 case StatementType::Kill: 200 case StatementType::Kill:
183 ret += fmt::format("{} kill;\n", indent); 201 ret += fmt::format("{} kill;\n", indent);
184 break; 202 break;
203 case StatementType::Unreachable:
204 ret += fmt::format("{} unreachable;\n", indent);
205 break;
185 case StatementType::SetVariable: 206 case StatementType::SetVariable:
186 ret += fmt::format("{} goto_L{} = {};\n", indent, stmt->id, DumpExpr(stmt->op)); 207 ret += fmt::format("{} goto_L{} = {};\n", indent, stmt->id, DumpExpr(stmt->op));
187 break; 208 break;
209 case StatementType::SetIndirectBranchVariable:
210 ret += fmt::format("{} indirect_branch = {} + {};\n", indent, stmt->branch_reg,
211 stmt->branch_offset);
212 break;
188 case StatementType::Function: 213 case StatementType::Function:
189 case StatementType::Identity: 214 case StatementType::Identity:
190 case StatementType::Not: 215 case StatementType::Not:
191 case StatementType::Or: 216 case StatementType::Or:
192 case StatementType::Variable: 217 case StatementType::Variable:
218 case StatementType::IndirectBranchCond:
193 throw LogicError("Statement can't be printed"); 219 throw LogicError("Statement can't be printed");
194 } 220 }
195 } 221 }
@@ -417,6 +443,17 @@ private:
417 } 443 }
418 break; 444 break;
419 } 445 }
446 case Flow::EndClass::IndirectBranch:
447 root.insert(ip, *pool.Create(SetIndirectBranchVariable{}, block.branch_reg,
448 block.branch_offset));
449 for (Flow::Block* const branch : block.indirect_branches) {
450 const Node indirect_label{local_labels.at(branch)};
451 Statement* cond{pool.Create(IndirectBranchCond{}, branch->begin.Offset())};
452 Statement* goto_stmt{pool.Create(Goto{}, cond, indirect_label, &root_stmt)};
453 gotos.push_back(root.insert(ip, *goto_stmt));
454 }
455 root.insert(ip, *pool.Create(Unreachable{}));
456 break;
420 case Flow::EndClass::Call: { 457 case Flow::EndClass::Call: {
421 Flow::Function& call{cfg.Functions()[block.function_call]}; 458 Flow::Function& call{cfg.Functions()[block.function_call]};
422 const Node call_return_label{local_labels.at(block.return_block)}; 459 const Node call_return_label{local_labels.at(block.return_block)};
@@ -623,6 +660,8 @@ IR::Block* TryFindForwardBlock(const Statement& stmt) {
623 return ir.LogicalOr(VisitExpr(ir, *stmt.op_a), VisitExpr(ir, *stmt.op_b)); 660 return ir.LogicalOr(VisitExpr(ir, *stmt.op_a), VisitExpr(ir, *stmt.op_b));
624 case StatementType::Variable: 661 case StatementType::Variable:
625 return ir.GetGotoVariable(stmt.id); 662 return ir.GetGotoVariable(stmt.id);
663 case StatementType::IndirectBranchCond:
664 return ir.IEqual(ir.GetIndirectBranchVariable(), ir.Imm32(stmt.location));
626 default: 665 default:
627 throw NotImplementedException("Statement type {}", stmt.type); 666 throw NotImplementedException("Statement type {}", stmt.type);
628 } 667 }
@@ -670,6 +709,15 @@ private:
670 ir.SetGotoVariable(stmt.id, VisitExpr(ir, *stmt.op)); 709 ir.SetGotoVariable(stmt.id, VisitExpr(ir, *stmt.op));
671 break; 710 break;
672 } 711 }
712 case StatementType::SetIndirectBranchVariable: {
713 if (!current_block) {
714 current_block = MergeBlock(parent, stmt);
715 }
716 IR::IREmitter ir{*current_block};
717 IR::U32 address{ir.IAdd(ir.GetReg(stmt.branch_reg), ir.Imm32(stmt.branch_offset))};
718 ir.SetIndirectBranchVariable(address);
719 break;
720 }
673 case StatementType::If: { 721 case StatementType::If: {
674 if (!current_block) { 722 if (!current_block) {
675 current_block = block_pool.Create(inst_pool); 723 current_block = block_pool.Create(inst_pool);
@@ -756,6 +804,15 @@ private:
756 current_block = demote_block; 804 current_block = demote_block;
757 break; 805 break;
758 } 806 }
807 case StatementType::Unreachable: {
808 if (!current_block) {
809 current_block = block_pool.Create(inst_pool);
810 block_list.push_back(current_block);
811 }
812 IR::IREmitter{*current_block}.Unreachable();
813 current_block = nullptr;
814 break;
815 }
759 default: 816 default:
760 throw NotImplementedException("Statement type {}", stmt.type); 817 throw NotImplementedException("Statement type {}", stmt.type);
761 } 818 }