control_flow.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <compare>
  6. #include <optional>
  7. #include <span>
  8. #include <string>
  9. #include <vector>
  10. #include <boost/container/small_vector.hpp>
  11. #include <boost/intrusive/set.hpp>
  12. #include "shader_recompiler/environment.h"
  13. #include "shader_recompiler/frontend/ir/condition.h"
  14. #include "shader_recompiler/frontend/maxwell/instruction.h"
  15. #include "shader_recompiler/frontend/maxwell/location.h"
  16. #include "shader_recompiler/frontend/maxwell/opcodes.h"
  17. #include "shader_recompiler/object_pool.h"
  18. namespace Shader::Maxwell::Flow {
  19. using FunctionId = size_t;
  20. enum class EndClass {
  21. Branch,
  22. Call,
  23. Exit,
  24. Return,
  25. Kill,
  26. };
  27. enum class Token {
  28. SSY,
  29. PBK,
  30. PEXIT,
  31. PRET,
  32. PCNT,
  33. PLONGJMP,
  34. };
  35. struct StackEntry {
  36. auto operator<=>(const StackEntry&) const noexcept = default;
  37. Token token;
  38. Location target;
  39. };
  40. class Stack {
  41. public:
  42. void Push(Token token, Location target);
  43. [[nodiscard]] std::pair<Location, Stack> Pop(Token token) const;
  44. [[nodiscard]] std::optional<Location> Peek(Token token) const;
  45. [[nodiscard]] Stack Remove(Token token) const;
  46. private:
  47. boost::container::small_vector<StackEntry, 3> entries;
  48. };
  49. struct Block : boost::intrusive::set_base_hook<
  50. // Normal link is ~2.5% faster compared to safe link
  51. boost::intrusive::link_mode<boost::intrusive::normal_link>> {
  52. [[nodiscard]] bool Contains(Location pc) const noexcept;
  53. bool operator<(const Block& rhs) const noexcept {
  54. return begin < rhs.begin;
  55. }
  56. Location begin;
  57. Location end;
  58. EndClass end_class;
  59. Stack stack;
  60. IR::Condition cond;
  61. union {
  62. Block* branch_true;
  63. FunctionId function_call;
  64. };
  65. union {
  66. Block* branch_false;
  67. Block* return_block;
  68. };
  69. };
  70. struct Label {
  71. Location address;
  72. Block* block;
  73. Stack stack;
  74. };
  75. struct Function {
  76. explicit Function(ObjectPool<Block>& block_pool, Location start_address);
  77. Location entrypoint;
  78. boost::container::small_vector<Label, 16> labels;
  79. boost::intrusive::set<Block> blocks;
  80. };
  81. class CFG {
  82. enum class AnalysisState {
  83. Branch,
  84. Continue,
  85. };
  86. public:
  87. explicit CFG(Environment& env, ObjectPool<Block>& block_pool, Location start_address);
  88. CFG& operator=(const CFG&) = delete;
  89. CFG(const CFG&) = delete;
  90. CFG& operator=(CFG&&) = delete;
  91. CFG(CFG&&) = delete;
  92. [[nodiscard]] std::string Dot() const;
  93. [[nodiscard]] std::span<const Function> Functions() const noexcept {
  94. return std::span(functions.data(), functions.size());
  95. }
  96. [[nodiscard]] std::span<Function> Functions() noexcept {
  97. return std::span(functions.data(), functions.size());
  98. }
  99. private:
  100. void AnalyzeLabel(FunctionId function_id, Label& label);
  101. /// Inspect already visited blocks.
  102. /// Return true when the block has already been visited
  103. bool InspectVisitedBlocks(FunctionId function_id, const Label& label);
  104. AnalysisState AnalyzeInst(Block* block, FunctionId function_id, Location pc);
  105. void AnalyzeCondInst(Block* block, FunctionId function_id, Location pc, EndClass insn_end_class,
  106. IR::Condition cond);
  107. /// Return true when the branch instruction is confirmed to be a branch
  108. bool AnalyzeBranch(Block* block, FunctionId function_id, Location pc, Instruction inst,
  109. Opcode opcode);
  110. void AnalyzeBRA(Block* block, FunctionId function_id, Location pc, Instruction inst,
  111. bool is_absolute);
  112. void AnalyzeBRX(Block* block, Location pc, Instruction inst, bool is_absolute);
  113. AnalysisState AnalyzeEXIT(Block* block, FunctionId function_id, Location pc, Instruction inst);
  114. /// Return the branch target block id
  115. Block* AddLabel(Block* block, Stack stack, Location pc, FunctionId function_id);
  116. Environment& env;
  117. ObjectPool<Block>& block_pool;
  118. boost::container::small_vector<Function, 1> functions;
  119. FunctionId current_function_id{0};
  120. };
  121. } // namespace Shader::Maxwell::Flow