diff options
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell/control_flow.cpp')
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/control_flow.cpp | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.cpp b/src/shader_recompiler/frontend/maxwell/control_flow.cpp index 715c0e92d..4f6707fae 100644 --- a/src/shader_recompiler/frontend/maxwell/control_flow.cpp +++ b/src/shader_recompiler/frontend/maxwell/control_flow.cpp | |||
| @@ -104,6 +104,7 @@ bool HasFlowTest(Opcode opcode) { | |||
| 104 | case Opcode::EXIT: | 104 | case Opcode::EXIT: |
| 105 | case Opcode::JMP: | 105 | case Opcode::JMP: |
| 106 | case Opcode::JMX: | 106 | case Opcode::JMX: |
| 107 | case Opcode::KIL: | ||
| 107 | case Opcode::BRK: | 108 | case Opcode::BRK: |
| 108 | case Opcode::CONT: | 109 | case Opcode::CONT: |
| 109 | case Opcode::LONGJMP: | 110 | case Opcode::LONGJMP: |
| @@ -287,6 +288,13 @@ CFG::AnalysisState CFG::AnalyzeInst(Block* block, FunctionId function_id, Locati | |||
| 287 | block->end = pc; | 288 | block->end = pc; |
| 288 | return AnalysisState::Branch; | 289 | return AnalysisState::Branch; |
| 289 | } | 290 | } |
| 291 | case Opcode::KIL: { | ||
| 292 | const Predicate pred{inst.Pred()}; | ||
| 293 | const auto ir_pred{static_cast<IR::Pred>(pred.index)}; | ||
| 294 | const IR::Condition cond{inst.branch.flow_test, ir_pred, pred.negated}; | ||
| 295 | AnalyzeCondInst(block, function_id, pc, EndClass::Kill, cond); | ||
| 296 | return AnalysisState::Branch; | ||
| 297 | } | ||
| 290 | case Opcode::PBK: | 298 | case Opcode::PBK: |
| 291 | case Opcode::PCNT: | 299 | case Opcode::PCNT: |
| 292 | case Opcode::PEXIT: | 300 | case Opcode::PEXIT: |
| @@ -324,13 +332,12 @@ CFG::AnalysisState CFG::AnalyzeInst(Block* block, FunctionId function_id, Locati | |||
| 324 | return AnalysisState::Continue; | 332 | return AnalysisState::Continue; |
| 325 | } | 333 | } |
| 326 | const IR::Condition cond{static_cast<IR::Pred>(pred.index), pred.negated}; | 334 | const IR::Condition cond{static_cast<IR::Pred>(pred.index), pred.negated}; |
| 327 | AnalyzeCondInst(block, function_id, pc, EndClass::Branch, cond, true); | 335 | AnalyzeCondInst(block, function_id, pc, EndClass::Branch, cond); |
| 328 | return AnalysisState::Branch; | 336 | return AnalysisState::Branch; |
| 329 | } | 337 | } |
| 330 | 338 | ||
| 331 | void CFG::AnalyzeCondInst(Block* block, FunctionId function_id, Location pc, | 339 | void CFG::AnalyzeCondInst(Block* block, FunctionId function_id, Location pc, |
| 332 | EndClass insn_end_class, IR::Condition cond, | 340 | EndClass insn_end_class, IR::Condition cond) { |
| 333 | bool visit_conditional_inst) { | ||
| 334 | if (block->begin != pc) { | 341 | if (block->begin != pc) { |
| 335 | // If the block doesn't start in the conditional instruction | 342 | // If the block doesn't start in the conditional instruction |
| 336 | // mark it as a label to visit it later | 343 | // mark it as a label to visit it later |
| @@ -356,14 +363,16 @@ void CFG::AnalyzeCondInst(Block* block, FunctionId function_id, Location pc, | |||
| 356 | // Impersonate the visited block with a virtual block | 363 | // Impersonate the visited block with a virtual block |
| 357 | *block = std::move(virtual_block); | 364 | *block = std::move(virtual_block); |
| 358 | // Set the end properties of the conditional instruction | 365 | // Set the end properties of the conditional instruction |
| 359 | conditional_block->end = visit_conditional_inst ? (pc + 1) : pc; | 366 | conditional_block->end = pc + 1; |
| 360 | conditional_block->end_class = insn_end_class; | 367 | conditional_block->end_class = insn_end_class; |
| 361 | // Add a label to the instruction after the conditional instruction | 368 | // Add a label to the instruction after the conditional instruction |
| 362 | Block* const endif_block{AddLabel(conditional_block, block->stack, pc + 1, function_id)}; | 369 | Block* const endif_block{AddLabel(conditional_block, block->stack, pc + 1, function_id)}; |
| 363 | // Branch to the next instruction from the virtual block | 370 | // Branch to the next instruction from the virtual block |
| 364 | block->branch_false = endif_block; | 371 | block->branch_false = endif_block; |
| 365 | // And branch to it from the conditional instruction if it is a branch | 372 | // And branch to it from the conditional instruction if it is a branch or a kill instruction |
| 366 | if (insn_end_class == EndClass::Branch) { | 373 | // Kill instructions are considered a branch because they demote to a helper invocation and |
| 374 | // execution may continue. | ||
| 375 | if (insn_end_class == EndClass::Branch || insn_end_class == EndClass::Kill) { | ||
| 367 | conditional_block->cond = IR::Condition{true}; | 376 | conditional_block->cond = IR::Condition{true}; |
| 368 | conditional_block->branch_true = endif_block; | 377 | conditional_block->branch_true = endif_block; |
| 369 | conditional_block->branch_false = nullptr; | 378 | conditional_block->branch_false = nullptr; |
| @@ -415,7 +424,7 @@ CFG::AnalysisState CFG::AnalyzeEXIT(Block* block, FunctionId function_id, Locati | |||
| 415 | throw NotImplementedException("Conditional EXIT with PEXIT token"); | 424 | throw NotImplementedException("Conditional EXIT with PEXIT token"); |
| 416 | } | 425 | } |
| 417 | const IR::Condition cond{flow_test, static_cast<IR::Pred>(pred.index), pred.negated}; | 426 | const IR::Condition cond{flow_test, static_cast<IR::Pred>(pred.index), pred.negated}; |
| 418 | AnalyzeCondInst(block, function_id, pc, EndClass::Exit, cond, false); | 427 | AnalyzeCondInst(block, function_id, pc, EndClass::Exit, cond); |
| 419 | return AnalysisState::Branch; | 428 | return AnalysisState::Branch; |
| 420 | } | 429 | } |
| 421 | if (const std::optional<Location> exit_pc{block->stack.Peek(Token::PEXIT)}) { | 430 | if (const std::optional<Location> exit_pc{block->stack.Peek(Token::PEXIT)}) { |
| @@ -425,7 +434,7 @@ CFG::AnalysisState CFG::AnalyzeEXIT(Block* block, FunctionId function_id, Locati | |||
| 425 | block->branch_false = nullptr; | 434 | block->branch_false = nullptr; |
| 426 | return AnalysisState::Branch; | 435 | return AnalysisState::Branch; |
| 427 | } | 436 | } |
| 428 | block->end = pc; | 437 | block->end = pc + 1; |
| 429 | block->end_class = EndClass::Exit; | 438 | block->end_class = EndClass::Exit; |
| 430 | return AnalysisState::Branch; | 439 | return AnalysisState::Branch; |
| 431 | } | 440 | } |
| @@ -505,6 +514,12 @@ std::string CFG::Dot() const { | |||
| 505 | node_uid); | 514 | node_uid); |
| 506 | ++node_uid; | 515 | ++node_uid; |
| 507 | break; | 516 | break; |
| 517 | case EndClass::Kill: | ||
| 518 | dot += fmt::format("\t\t{}->N{};\n", name, node_uid); | ||
| 519 | dot += fmt::format("\t\tN{} [label=\"Kill\"][shape=square][style=stripped];\n", | ||
| 520 | node_uid); | ||
| 521 | ++node_uid; | ||
| 522 | break; | ||
| 508 | } | 523 | } |
| 509 | } | 524 | } |
| 510 | if (function.entrypoint == 8) { | 525 | if (function.entrypoint == 8) { |