summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/maxwell/control_flow.cpp
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-03-14 03:41:05 -0300
committerGravatar ameerj2021-07-22 21:51:23 -0400
commit71f96fa6366dc6dd306a953bca1b958fb32bc55a (patch)
tree12e13f9502e4b9510446c967a831e5d4bacb729e /src/shader_recompiler/frontend/maxwell/control_flow.cpp
parentspirv: Add SignedZeroInfNanPreserve logic (diff)
downloadyuzu-71f96fa6366dc6dd306a953bca1b958fb32bc55a.tar.gz
yuzu-71f96fa6366dc6dd306a953bca1b958fb32bc55a.tar.xz
yuzu-71f96fa6366dc6dd306a953bca1b958fb32bc55a.zip
shader: Implement CAL inlining function calls
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell/control_flow.cpp')
-rw-r--r--src/shader_recompiler/frontend/maxwell/control_flow.cpp78
1 files changed, 38 insertions, 40 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.cpp b/src/shader_recompiler/frontend/maxwell/control_flow.cpp
index d0dc66330..715c0e92d 100644
--- a/src/shader_recompiler/frontend/maxwell/control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/control_flow.cpp
@@ -31,13 +31,12 @@ struct Compare {
31 return lhs.begin < rhs.begin; 31 return lhs.begin < rhs.begin;
32 } 32 }
33}; 33};
34} // Anonymous namespace
35 34
36static u32 BranchOffset(Location pc, Instruction inst) { 35u32 BranchOffset(Location pc, Instruction inst) {
37 return pc.Offset() + inst.branch.Offset() + 8; 36 return pc.Offset() + inst.branch.Offset() + 8;
38} 37}
39 38
40static void Split(Block* old_block, Block* new_block, Location pc) { 39void Split(Block* old_block, Block* new_block, Location pc) {
41 if (pc <= old_block->begin || pc >= old_block->end) { 40 if (pc <= old_block->begin || pc >= old_block->end) {
42 throw InvalidArgument("Invalid address to split={}", pc); 41 throw InvalidArgument("Invalid address to split={}", pc);
43 } 42 }
@@ -49,21 +48,19 @@ static void Split(Block* old_block, Block* new_block, Location pc) {
49 .cond{old_block->cond}, 48 .cond{old_block->cond},
50 .branch_true{old_block->branch_true}, 49 .branch_true{old_block->branch_true},
51 .branch_false{old_block->branch_false}, 50 .branch_false{old_block->branch_false},
52 .ir{nullptr},
53 }; 51 };
54 *old_block = Block{ 52 *old_block = Block{
55 .begin{old_block->begin}, 53 .begin{old_block->begin},
56 .end{pc}, 54 .end{pc},
57 .end_class{EndClass::Branch}, 55 .end_class{EndClass::Branch},
58 .stack{std::move(old_block->stack)}, 56 .stack{std::move(old_block->stack)},
59 .cond{IR::Condition{true}}, 57 .cond{true},
60 .branch_true{new_block}, 58 .branch_true{new_block},
61 .branch_false{nullptr}, 59 .branch_false{nullptr},
62 .ir{nullptr},
63 }; 60 };
64} 61}
65 62
66static Token OpcodeToken(Opcode opcode) { 63Token OpcodeToken(Opcode opcode) {
67 switch (opcode) { 64 switch (opcode) {
68 case Opcode::PBK: 65 case Opcode::PBK:
69 case Opcode::BRK: 66 case Opcode::BRK:
@@ -89,7 +86,7 @@ static Token OpcodeToken(Opcode opcode) {
89 } 86 }
90} 87}
91 88
92static bool IsAbsoluteJump(Opcode opcode) { 89bool IsAbsoluteJump(Opcode opcode) {
93 switch (opcode) { 90 switch (opcode) {
94 case Opcode::JCAL: 91 case Opcode::JCAL:
95 case Opcode::JMP: 92 case Opcode::JMP:
@@ -100,7 +97,7 @@ static bool IsAbsoluteJump(Opcode opcode) {
100 } 97 }
101} 98}
102 99
103static bool HasFlowTest(Opcode opcode) { 100bool HasFlowTest(Opcode opcode) {
104 switch (opcode) { 101 switch (opcode) {
105 case Opcode::BRA: 102 case Opcode::BRA:
106 case Opcode::BRX: 103 case Opcode::BRX:
@@ -121,13 +118,14 @@ static bool HasFlowTest(Opcode opcode) {
121 } 118 }
122} 119}
123 120
124static std::string NameOf(const Block& block) { 121std::string NameOf(const Block& block) {
125 if (block.begin.IsVirtual()) { 122 if (block.begin.IsVirtual()) {
126 return fmt::format("\"Virtual {}\"", block.begin); 123 return fmt::format("\"Virtual {}\"", block.begin);
127 } else { 124 } else {
128 return fmt::format("\"{}\"", block.begin); 125 return fmt::format("\"{}\"", block.begin);
129 } 126 }
130} 127}
128} // Anonymous namespace
131 129
132void Stack::Push(Token token, Location target) { 130void Stack::Push(Token token, Location target) {
133 entries.push_back({ 131 entries.push_back({
@@ -166,26 +164,24 @@ bool Block::Contains(Location pc) const noexcept {
166 return pc >= begin && pc < end; 164 return pc >= begin && pc < end;
167} 165}
168 166
169Function::Function(Location start_address) 167Function::Function(ObjectPool<Block>& block_pool, Location start_address)
170 : entrypoint{start_address}, labels{{ 168 : entrypoint{start_address}, labels{{
171 .address{start_address}, 169 .address{start_address},
172 .block{nullptr}, 170 .block{block_pool.Create(Block{
171 .begin{start_address},
172 .end{start_address},
173 .end_class{EndClass::Branch},
174 .stack{},
175 .cond{true},
176 .branch_true{nullptr},
177 .branch_false{nullptr},
178 })},
173 .stack{}, 179 .stack{},
174 }} {} 180 }} {}
175 181
176CFG::CFG(Environment& env_, ObjectPool<Block>& block_pool_, Location start_address) 182CFG::CFG(Environment& env_, ObjectPool<Block>& block_pool_, Location start_address)
177 : env{env_}, block_pool{block_pool_} { 183 : env{env_}, block_pool{block_pool_} {
178 functions.emplace_back(start_address); 184 functions.emplace_back(block_pool, start_address);
179 functions.back().labels.back().block = block_pool.Create(Block{
180 .begin{start_address},
181 .end{start_address},
182 .end_class{EndClass::Branch},
183 .stack{},
184 .cond{IR::Condition{true}},
185 .branch_true{nullptr},
186 .branch_false{nullptr},
187 .ir{nullptr},
188 });
189 for (FunctionId function_id = 0; function_id < functions.size(); ++function_id) { 185 for (FunctionId function_id = 0; function_id < functions.size(); ++function_id) {
190 while (!functions[function_id].labels.empty()) { 186 while (!functions[function_id].labels.empty()) {
191 Function& function{functions[function_id]}; 187 Function& function{functions[function_id]};
@@ -308,11 +304,17 @@ CFG::AnalysisState CFG::AnalyzeInst(Block* block, FunctionId function_id, Locati
308 const Location cal_pc{is_absolute ? inst.branch.Absolute() : BranchOffset(pc, inst)}; 304 const Location cal_pc{is_absolute ? inst.branch.Absolute() : BranchOffset(pc, inst)};
309 // Technically CAL pushes into PRET, but that's implicit in the function call for us 305 // Technically CAL pushes into PRET, but that's implicit in the function call for us
310 // Insert the function into the list if it doesn't exist 306 // Insert the function into the list if it doesn't exist
311 if (std::ranges::find(functions, cal_pc, &Function::entrypoint) == functions.end()) { 307 const auto it{std::ranges::find(functions, cal_pc, &Function::entrypoint)};
312 functions.emplace_back(cal_pc); 308 const bool exists{it != functions.end()};
309 const FunctionId call_id{exists ? std::distance(functions.begin(), it) : functions.size()};
310 if (!exists) {
311 functions.emplace_back(block_pool, cal_pc);
313 } 312 }
314 // Handle CAL like a regular instruction 313 block->end_class = EndClass::Call;
315 break; 314 block->function_call = call_id;
315 block->return_block = AddLabel(block, block->stack, pc + 1, function_id);
316 block->end = pc;
317 return AnalysisState::Branch;
316 } 318 }
317 default: 319 default:
318 break; 320 break;
@@ -348,7 +350,6 @@ void CFG::AnalyzeCondInst(Block* block, FunctionId function_id, Location pc,
348 .cond{cond}, 350 .cond{cond},
349 .branch_true{conditional_block}, 351 .branch_true{conditional_block},
350 .branch_false{nullptr}, 352 .branch_false{nullptr},
351 .ir{nullptr},
352 }; 353 };
353 // Save the contents of the visited block in the conditional block 354 // Save the contents of the visited block in the conditional block
354 *conditional_block = std::move(*block); 355 *conditional_block = std::move(*block);
@@ -401,16 +402,6 @@ void CFG::AnalyzeBRX(Block*, Location, Instruction, bool is_absolute) {
401 throw NotImplementedException("{}", is_absolute ? "JMX" : "BRX"); 402 throw NotImplementedException("{}", is_absolute ? "JMX" : "BRX");
402} 403}
403 404
404void CFG::AnalyzeCAL(Location pc, Instruction inst, bool is_absolute) {
405 const Location cal_pc{is_absolute ? inst.branch.Absolute() : BranchOffset(pc, inst)};
406 // Technically CAL pushes into PRET, but that's implicit in the function call for us
407 // Insert the function to the function list if it doesn't exist
408 const auto it{std::ranges::find(functions, cal_pc, &Function::entrypoint)};
409 if (it == functions.end()) {
410 functions.emplace_back(cal_pc);
411 }
412}
413
414CFG::AnalysisState CFG::AnalyzeEXIT(Block* block, FunctionId function_id, Location pc, 405CFG::AnalysisState CFG::AnalyzeEXIT(Block* block, FunctionId function_id, Location pc,
415 Instruction inst) { 406 Instruction inst) {
416 const IR::FlowTest flow_test{inst.branch.flow_test}; 407 const IR::FlowTest flow_test{inst.branch.flow_test};
@@ -455,10 +446,9 @@ Block* CFG::AddLabel(Block* block, Stack stack, Location pc, FunctionId function
455 .end{pc}, 446 .end{pc},
456 .end_class{EndClass::Branch}, 447 .end_class{EndClass::Branch},
457 .stack{stack}, 448 .stack{stack},
458 .cond{IR::Condition{true}}, 449 .cond{true},
459 .branch_true{nullptr}, 450 .branch_true{nullptr},
460 .branch_false{nullptr}, 451 .branch_false{nullptr},
461 .ir{nullptr},
462 })}; 452 })};
463 function.labels.push_back(Label{ 453 function.labels.push_back(Label{
464 .address{pc}, 454 .address{pc},
@@ -495,6 +485,14 @@ std::string CFG::Dot() const {
495 add_branch(block.branch_false, false); 485 add_branch(block.branch_false, false);
496 } 486 }
497 break; 487 break;
488 case EndClass::Call:
489 dot += fmt::format("\t\t{}->N{};\n", name, node_uid);
490 dot += fmt::format("\t\tN{}->{};\n", node_uid, NameOf(*block.return_block));
491 dot += fmt::format("\t\tN{} [label=\"Call {}\"][shape=square][style=stripped];\n",
492 node_uid, block.function_call);
493 dot += '\n';
494 ++node_uid;
495 break;
498 case EndClass::Exit: 496 case EndClass::Exit:
499 dot += fmt::format("\t\t{}->N{};\n", name, node_uid); 497 dot += fmt::format("\t\t{}->N{};\n", name, node_uid);
500 dot += fmt::format("\t\tN{} [label=\"Exit\"][shape=square][style=stripped];\n", 498 dot += fmt::format("\t\tN{} [label=\"Exit\"][shape=square][style=stripped];\n",