summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/maxwell/control_flow.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell/control_flow.h')
-rw-r--r--src/shader_recompiler/frontend/maxwell/control_flow.h77
1 files changed, 30 insertions, 47 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.h b/src/shader_recompiler/frontend/maxwell/control_flow.h
index 49b369282..8179787b8 100644
--- a/src/shader_recompiler/frontend/maxwell/control_flow.h
+++ b/src/shader_recompiler/frontend/maxwell/control_flow.h
@@ -11,25 +11,27 @@
11#include <vector> 11#include <vector>
12 12
13#include <boost/container/small_vector.hpp> 13#include <boost/container/small_vector.hpp>
14#include <boost/intrusive/set.hpp>
14 15
15#include "shader_recompiler/environment.h" 16#include "shader_recompiler/environment.h"
16#include "shader_recompiler/frontend/ir/condition.h" 17#include "shader_recompiler/frontend/ir/condition.h"
17#include "shader_recompiler/frontend/maxwell/instruction.h" 18#include "shader_recompiler/frontend/maxwell/instruction.h"
18#include "shader_recompiler/frontend/maxwell/location.h" 19#include "shader_recompiler/frontend/maxwell/location.h"
19#include "shader_recompiler/frontend/maxwell/opcodes.h" 20#include "shader_recompiler/frontend/maxwell/opcodes.h"
21#include "shader_recompiler/object_pool.h"
22
23namespace Shader::IR {
24class Block;
25}
20 26
21namespace Shader::Maxwell::Flow { 27namespace Shader::Maxwell::Flow {
22 28
23using BlockId = u32;
24using FunctionId = size_t; 29using FunctionId = size_t;
25 30
26constexpr BlockId UNREACHABLE_BLOCK_ID{static_cast<u32>(-1)};
27
28enum class EndClass { 31enum class EndClass {
29 Branch, 32 Branch,
30 Exit, 33 Exit,
31 Return, 34 Return,
32 Unreachable,
33}; 35};
34 36
35enum class Token { 37enum class Token {
@@ -59,58 +61,37 @@ private:
59 boost::container::small_vector<StackEntry, 3> entries; 61 boost::container::small_vector<StackEntry, 3> entries;
60}; 62};
61 63
62struct Block { 64struct Block : boost::intrusive::set_base_hook<
65 // Normal link is ~2.5% faster compared to safe link
66 boost::intrusive::link_mode<boost::intrusive::normal_link>> {
63 [[nodiscard]] bool Contains(Location pc) const noexcept; 67 [[nodiscard]] bool Contains(Location pc) const noexcept;
64 68
69 bool operator<(const Block& rhs) const noexcept {
70 return begin < rhs.begin;
71 }
72
65 Location begin; 73 Location begin;
66 Location end; 74 Location end;
67 EndClass end_class; 75 EndClass end_class;
68 BlockId id;
69 Stack stack; 76 Stack stack;
70 IR::Condition cond; 77 IR::Condition cond;
71 BlockId branch_true; 78 Block* branch_true;
72 BlockId branch_false; 79 Block* branch_false;
73 boost::container::small_vector<BlockId, 4> imm_predecessors; 80 IR::Block* ir;
74 boost::container::small_vector<BlockId, 8> dominance_frontiers;
75 union {
76 bool post_order_visited{false};
77 Block* imm_dominator;
78 };
79}; 81};
80 82
81struct Label { 83struct Label {
82 Location address; 84 Location address;
83 BlockId block_id; 85 Block* block;
84 Stack stack; 86 Stack stack;
85}; 87};
86 88
87struct Function { 89struct Function {
88 Function(Location start_address); 90 Function(Location start_address);
89 91
90 void BuildBlocksMap();
91
92 void BuildImmediatePredecessors();
93
94 void BuildPostOrder();
95
96 void BuildImmediateDominators();
97
98 void BuildDominanceFrontier();
99
100 [[nodiscard]] size_t NumBlocks() const noexcept {
101 return static_cast<size_t>(current_block_id) + 1;
102 }
103
104 Location entrypoint; 92 Location entrypoint;
105 BlockId current_block_id{0};
106 boost::container::small_vector<Label, 16> labels; 93 boost::container::small_vector<Label, 16> labels;
107 boost::container::small_vector<u32, 0x130> blocks; 94 boost::intrusive::set<Block> blocks;
108 boost::container::small_vector<Block, 0x130> blocks_data;
109 // Translates from BlockId to block index
110 boost::container::small_vector<Block*, 0x130> blocks_map;
111
112 boost::container::small_vector<u32, 0x130> post_order_blocks;
113 boost::container::small_vector<BlockId, 0x130> post_order_map;
114}; 95};
115 96
116class CFG { 97class CFG {
@@ -120,7 +101,7 @@ class CFG {
120 }; 101 };
121 102
122public: 103public:
123 explicit CFG(Environment& env, Location start_address); 104 explicit CFG(Environment& env, ObjectPool<Block>& block_pool, Location start_address);
124 105
125 CFG& operator=(const CFG&) = delete; 106 CFG& operator=(const CFG&) = delete;
126 CFG(const CFG&) = delete; 107 CFG(const CFG&) = delete;
@@ -133,35 +114,37 @@ public:
133 [[nodiscard]] std::span<const Function> Functions() const noexcept { 114 [[nodiscard]] std::span<const Function> Functions() const noexcept {
134 return std::span(functions.data(), functions.size()); 115 return std::span(functions.data(), functions.size());
135 } 116 }
117 [[nodiscard]] std::span<Function> Functions() noexcept {
118 return std::span(functions.data(), functions.size());
119 }
136 120
137private: 121private:
138 void VisitFunctions(Location start_address);
139
140 void AnalyzeLabel(FunctionId function_id, Label& label); 122 void AnalyzeLabel(FunctionId function_id, Label& label);
141 123
142 /// Inspect already visited blocks. 124 /// Inspect already visited blocks.
143 /// Return true when the block has already been visited 125 /// Return true when the block has already been visited
144 bool InspectVisitedBlocks(FunctionId function_id, const Label& label); 126 bool InspectVisitedBlocks(FunctionId function_id, const Label& label);
145 127
146 AnalysisState AnalyzeInst(Block& block, FunctionId function_id, Location pc); 128 AnalysisState AnalyzeInst(Block* block, FunctionId function_id, Location pc);
147 129
148 void AnalyzeCondInst(Block& block, FunctionId function_id, Location pc, EndClass insn_end_class, 130 void AnalyzeCondInst(Block* block, FunctionId function_id, Location pc, EndClass insn_end_class,
149 IR::Condition cond); 131 IR::Condition cond);
150 132
151 /// Return true when the branch instruction is confirmed to be a branch 133 /// Return true when the branch instruction is confirmed to be a branch
152 bool AnalyzeBranch(Block& block, FunctionId function_id, Location pc, Instruction inst, 134 bool AnalyzeBranch(Block* block, FunctionId function_id, Location pc, Instruction inst,
153 Opcode opcode); 135 Opcode opcode);
154 136
155 void AnalyzeBRA(Block& block, FunctionId function_id, Location pc, Instruction inst, 137 void AnalyzeBRA(Block* block, FunctionId function_id, Location pc, Instruction inst,
156 bool is_absolute); 138 bool is_absolute);
157 void AnalyzeBRX(Block& block, Location pc, Instruction inst, bool is_absolute); 139 void AnalyzeBRX(Block* block, Location pc, Instruction inst, bool is_absolute);
158 void AnalyzeCAL(Location pc, Instruction inst, bool is_absolute); 140 void AnalyzeCAL(Location pc, Instruction inst, bool is_absolute);
159 AnalysisState AnalyzeEXIT(Block& block, FunctionId function_id, Location pc, Instruction inst); 141 AnalysisState AnalyzeEXIT(Block* block, FunctionId function_id, Location pc, Instruction inst);
160 142
161 /// Return the branch target block id 143 /// Return the branch target block id
162 BlockId AddLabel(const Block& block, Stack stack, Location pc, FunctionId function_id); 144 Block* AddLabel(Block* block, Stack stack, Location pc, FunctionId function_id);
163 145
164 Environment& env; 146 Environment& env;
147 ObjectPool<Block>& block_pool;
165 boost::container::small_vector<Function, 1> functions; 148 boost::container::small_vector<Function, 1> functions;
166 FunctionId current_function_id{0}; 149 FunctionId current_function_id{0};
167}; 150};