summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/maxwell/control_flow.cpp
diff options
context:
space:
mode:
authorGravatar FernandoS272021-03-27 22:30:24 +0100
committerGravatar ameerj2021-07-22 21:51:25 -0400
commit34aba9627a8fad20b3b173180e2f3d679dd32293 (patch)
treea4f2faec67a793e8b44493532a683908dcefb4d8 /src/shader_recompiler/frontend/maxwell/control_flow.cpp
parentshader: Fix alignment checks on RZ (diff)
downloadyuzu-34aba9627a8fad20b3b173180e2f3d679dd32293.tar.gz
yuzu-34aba9627a8fad20b3b173180e2f3d679dd32293.tar.xz
yuzu-34aba9627a8fad20b3b173180e2f3d679dd32293.zip
shader: Implement BRX
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell/control_flow.cpp')
-rw-r--r--src/shader_recompiler/frontend/maxwell/control_flow.cpp58
1 files changed, 49 insertions, 9 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.cpp b/src/shader_recompiler/frontend/maxwell/control_flow.cpp
index 4f6707fae..1e9b8e426 100644
--- a/src/shader_recompiler/frontend/maxwell/control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/control_flow.cpp
@@ -14,6 +14,7 @@
14#include "shader_recompiler/exception.h" 14#include "shader_recompiler/exception.h"
15#include "shader_recompiler/frontend/maxwell/control_flow.h" 15#include "shader_recompiler/frontend/maxwell/control_flow.h"
16#include "shader_recompiler/frontend/maxwell/decode.h" 16#include "shader_recompiler/frontend/maxwell/decode.h"
17#include "shader_recompiler/frontend/maxwell/indirect_branch_table_track.h"
17#include "shader_recompiler/frontend/maxwell/location.h" 18#include "shader_recompiler/frontend/maxwell/location.h"
18 19
19namespace Shader::Maxwell::Flow { 20namespace Shader::Maxwell::Flow {
@@ -252,9 +253,7 @@ CFG::AnalysisState CFG::AnalyzeInst(Block* block, FunctionId function_id, Locati
252 const Opcode opcode{Decode(inst.raw)}; 253 const Opcode opcode{Decode(inst.raw)};
253 switch (opcode) { 254 switch (opcode) {
254 case Opcode::BRA: 255 case Opcode::BRA:
255 case Opcode::BRX:
256 case Opcode::JMP: 256 case Opcode::JMP:
257 case Opcode::JMX:
258 case Opcode::RET: 257 case Opcode::RET:
259 if (!AnalyzeBranch(block, function_id, pc, inst, opcode)) { 258 if (!AnalyzeBranch(block, function_id, pc, inst, opcode)) {
260 return AnalysisState::Continue; 259 return AnalysisState::Continue;
@@ -264,10 +263,6 @@ CFG::AnalysisState CFG::AnalyzeInst(Block* block, FunctionId function_id, Locati
264 case Opcode::JMP: 263 case Opcode::JMP:
265 AnalyzeBRA(block, function_id, pc, inst, IsAbsoluteJump(opcode)); 264 AnalyzeBRA(block, function_id, pc, inst, IsAbsoluteJump(opcode));
266 break; 265 break;
267 case Opcode::BRX:
268 case Opcode::JMX:
269 AnalyzeBRX(block, pc, inst, IsAbsoluteJump(opcode));
270 break;
271 case Opcode::RET: 266 case Opcode::RET:
272 block->end_class = EndClass::Return; 267 block->end_class = EndClass::Return;
273 break; 268 break;
@@ -302,6 +297,9 @@ CFG::AnalysisState CFG::AnalyzeInst(Block* block, FunctionId function_id, Locati
302 case Opcode::SSY: 297 case Opcode::SSY:
303 block->stack.Push(OpcodeToken(opcode), BranchOffset(pc, inst)); 298 block->stack.Push(OpcodeToken(opcode), BranchOffset(pc, inst));
304 return AnalysisState::Continue; 299 return AnalysisState::Continue;
300 case Opcode::BRX:
301 case Opcode::JMX:
302 return AnalyzeBRX(block, pc, inst, IsAbsoluteJump(opcode), function_id);
305 case Opcode::EXIT: 303 case Opcode::EXIT:
306 return AnalyzeEXIT(block, function_id, pc, inst); 304 return AnalyzeEXIT(block, function_id, pc, inst);
307 case Opcode::PRET: 305 case Opcode::PRET:
@@ -407,8 +405,46 @@ void CFG::AnalyzeBRA(Block* block, FunctionId function_id, Location pc, Instruct
407 block->branch_true = AddLabel(block, block->stack, bra_pc, function_id); 405 block->branch_true = AddLabel(block, block->stack, bra_pc, function_id);
408} 406}
409 407
410void CFG::AnalyzeBRX(Block*, Location, Instruction, bool is_absolute) { 408CFG::AnalysisState CFG::AnalyzeBRX(Block* block, Location pc, Instruction inst, bool is_absolute,
411 throw NotImplementedException("{}", is_absolute ? "JMX" : "BRX"); 409 FunctionId function_id) {
410 const std::optional brx_table{TrackIndirectBranchTable(env, pc, block->begin)};
411 if (!brx_table) {
412 TrackIndirectBranchTable(env, pc, block->begin);
413 throw NotImplementedException("Failed to track indirect branch");
414 }
415 const IR::FlowTest flow_test{inst.branch.flow_test};
416 const Predicate pred{inst.Pred()};
417 if (flow_test != IR::FlowTest::T || pred != Predicate{true}) {
418 throw NotImplementedException("Conditional indirect branch");
419 }
420 std::vector<u32> targets;
421 targets.reserve(brx_table->num_entries);
422 for (u32 i = 0; i < brx_table->num_entries; ++i) {
423 u32 target{env.ReadCbufValue(brx_table->cbuf_index, brx_table->cbuf_offset + i * 4)};
424 if (!is_absolute) {
425 target += pc.Offset();
426 }
427 target += brx_table->branch_offset;
428 target += 8;
429 targets.push_back(target);
430 }
431 std::ranges::sort(targets);
432 targets.erase(std::unique(targets.begin(), targets.end()), targets.end());
433
434 block->indirect_branches.reserve(targets.size());
435 for (const u32 target : targets) {
436 Block* const branch{AddLabel(block, block->stack, target, function_id)};
437 block->indirect_branches.push_back(branch);
438 }
439 block->cond = IR::Condition{true};
440 block->end = pc + 1;
441 block->end_class = EndClass::IndirectBranch;
442 block->branch_reg = brx_table->branch_reg;
443 block->branch_offset = brx_table->branch_offset + 8;
444 if (!is_absolute) {
445 block->branch_offset += pc.Offset();
446 }
447 return AnalysisState::Branch;
412} 448}
413 449
414CFG::AnalysisState CFG::AnalyzeEXIT(Block* block, FunctionId function_id, Location pc, 450CFG::AnalysisState CFG::AnalyzeEXIT(Block* block, FunctionId function_id, Location pc,
@@ -449,7 +485,6 @@ Block* CFG::AddLabel(Block* block, Stack stack, Location pc, FunctionId function
449 // Block already exists and it has been visited 485 // Block already exists and it has been visited
450 return &*it; 486 return &*it;
451 } 487 }
452 // TODO: FIX DANGLING BLOCKS
453 Block* const new_block{block_pool.Create(Block{ 488 Block* const new_block{block_pool.Create(Block{
454 .begin{pc}, 489 .begin{pc},
455 .end{pc}, 490 .end{pc},
@@ -494,6 +529,11 @@ std::string CFG::Dot() const {
494 add_branch(block.branch_false, false); 529 add_branch(block.branch_false, false);
495 } 530 }
496 break; 531 break;
532 case EndClass::IndirectBranch:
533 for (Block* const branch : block.indirect_branches) {
534 add_branch(branch, false);
535 }
536 break;
497 case EndClass::Call: 537 case EndClass::Call:
498 dot += fmt::format("\t\t{}->N{};\n", name, node_uid); 538 dot += fmt::format("\t\t{}->N{};\n", name, node_uid);
499 dot += fmt::format("\t\tN{}->{};\n", node_uid, NameOf(*block.return_block)); 539 dot += fmt::format("\t\tN{}->{};\n", node_uid, NameOf(*block.return_block));