diff options
| author | 2021-03-27 22:30:24 +0100 | |
|---|---|---|
| committer | 2021-07-22 21:51:25 -0400 | |
| commit | 34aba9627a8fad20b3b173180e2f3d679dd32293 (patch) | |
| tree | a4f2faec67a793e8b44493532a683908dcefb4d8 /src/shader_recompiler/frontend/maxwell/control_flow.cpp | |
| parent | shader: Fix alignment checks on RZ (diff) | |
| download | yuzu-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.cpp | 58 |
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 | ||
| 19 | namespace Shader::Maxwell::Flow { | 20 | namespace 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 | ||
| 410 | void CFG::AnalyzeBRX(Block*, Location, Instruction, bool is_absolute) { | 408 | CFG::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 | ||
| 414 | CFG::AnalysisState CFG::AnalyzeEXIT(Block* block, FunctionId function_id, Location pc, | 450 | CFG::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)); |