/src/spirv-tools/source/val/basic_block.h
Line | Count | Source |
1 | | // Copyright (c) 2015-2016 The Khronos Group Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #ifndef SOURCE_VAL_BASIC_BLOCK_H_ |
16 | | #define SOURCE_VAL_BASIC_BLOCK_H_ |
17 | | |
18 | | #include <bitset> |
19 | | #include <cstdint> |
20 | | #include <functional> |
21 | | #include <memory> |
22 | | #include <vector> |
23 | | |
24 | | #include "source/latest_version_spirv_header.h" |
25 | | |
26 | | namespace spvtools { |
27 | | namespace val { |
28 | | |
29 | | enum BlockType : uint32_t { |
30 | | kBlockTypeUndefined, |
31 | | kBlockTypeSelection, |
32 | | kBlockTypeLoop, |
33 | | kBlockTypeMerge, |
34 | | kBlockTypeBreak, |
35 | | kBlockTypeContinue, |
36 | | kBlockTypeReturn, |
37 | | kBlockTypeCOUNT ///< Total number of block types. (must be the last element) |
38 | | }; |
39 | | |
40 | | class Instruction; |
41 | | |
42 | | // This class represents a basic block in a SPIR-V module |
43 | | class BasicBlock { |
44 | | public: |
45 | | /// Constructor for a BasicBlock |
46 | | /// |
47 | | /// @param[in] id The ID of the basic block |
48 | | explicit BasicBlock(uint32_t id); |
49 | | |
50 | | /// Returns the id of the BasicBlock |
51 | 33.1M | uint32_t id() const { return id_; } |
52 | | |
53 | | /// Returns the predecessors of the BasicBlock |
54 | 656k | const std::vector<BasicBlock*>* predecessors() const { |
55 | 656k | return &predecessors_; |
56 | 656k | } |
57 | | |
58 | | /// Returns the predecessors of the BasicBlock |
59 | 375k | std::vector<BasicBlock*>* predecessors() { return &predecessors_; } |
60 | | |
61 | | /// Returns the successors of the BasicBlock |
62 | 885k | const std::vector<BasicBlock*>* successors() const { return &successors_; } |
63 | | |
64 | | /// Returns the successors of the BasicBlock |
65 | 859k | std::vector<BasicBlock*>* successors() { return &successors_; } |
66 | | |
67 | | /// Returns the structural successors of the BasicBlock |
68 | 0 | std::vector<BasicBlock*>* structural_predecessors() { |
69 | 0 | return &structural_predecessors_; |
70 | 0 | } |
71 | | |
72 | | /// Returns the structural predecessors of the BasicBlock |
73 | 5.30M | const std::vector<BasicBlock*>* structural_predecessors() const { |
74 | 5.30M | return &structural_predecessors_; |
75 | 5.30M | } |
76 | | |
77 | | /// Returns the structural successors of the BasicBlock |
78 | 808k | std::vector<BasicBlock*>* structural_successors() { |
79 | 808k | return &structural_successors_; |
80 | 808k | } |
81 | | |
82 | | /// Returns the structural predecessors of the BasicBlock |
83 | 5.27M | const std::vector<BasicBlock*>* structural_successors() const { |
84 | 5.27M | return &structural_successors_; |
85 | 5.27M | } |
86 | | |
87 | | /// Returns true if the block is reachable in the CFG. |
88 | 1.70M | bool reachable() const { return reachable_; } |
89 | | |
90 | | /// Returns true if the block is structurally reachable in the CFG. |
91 | 1.89M | bool structurally_reachable() const { return structurally_reachable_; } |
92 | | |
93 | | /// Returns true if BasicBlock is of the given type |
94 | 2.03M | bool is_type(BlockType type) const { |
95 | 2.03M | if (type == kBlockTypeUndefined) return type_.none(); |
96 | 2.03M | return type_.test(type); |
97 | 2.03M | } |
98 | | |
99 | | /// Sets the reachability of the basic block in the CFG |
100 | 308k | void set_reachable(bool reachability) { reachable_ = reachability; } |
101 | | |
102 | | /// Sets the structural reachability of the basic block in the CFG |
103 | 330k | void set_structurally_reachable(bool reachability) { |
104 | 330k | structurally_reachable_ = reachability; |
105 | 330k | } |
106 | | |
107 | | /// Sets the type of the BasicBlock |
108 | 339k | void set_type(BlockType type) { |
109 | 339k | if (type == kBlockTypeUndefined) |
110 | 0 | type_.reset(); |
111 | 339k | else |
112 | 339k | type_.set(type); |
113 | 339k | } |
114 | | |
115 | | /// Sets the immediate dominator of this basic block |
116 | | /// |
117 | | /// @param[in] dom_block The dominator block |
118 | | void SetImmediateDominator(BasicBlock* dom_block); |
119 | | |
120 | | /// Sets the immediate dominator of this basic block |
121 | | /// |
122 | | /// @param[in] dom_block The dominator block |
123 | | void SetImmediateStructuralDominator(BasicBlock* dom_block); |
124 | | |
125 | | /// Sets the immediate post dominator of this basic block |
126 | | /// |
127 | | /// @param[in] pdom_block The post dominator block |
128 | | void SetImmediateStructuralPostDominator(BasicBlock* pdom_block); |
129 | | |
130 | | /// Returns the immediate dominator of this basic block |
131 | | BasicBlock* immediate_dominator(); |
132 | | |
133 | | /// Returns the immediate dominator of this basic block |
134 | | const BasicBlock* immediate_dominator() const; |
135 | | |
136 | | /// Returns the immediate dominator of this basic block |
137 | | BasicBlock* immediate_structural_dominator(); |
138 | | |
139 | | /// Returns the immediate dominator of this basic block |
140 | | const BasicBlock* immediate_structural_dominator() const; |
141 | | |
142 | | /// Returns the immediate post dominator of this basic block |
143 | | BasicBlock* immediate_structural_post_dominator(); |
144 | | |
145 | | /// Returns the immediate post dominator of this basic block |
146 | | const BasicBlock* immediate_structural_post_dominator() const; |
147 | | |
148 | | /// Returns the label instruction for the block, or nullptr if not set. |
149 | 52.2k | const Instruction* label() const { return label_; } |
150 | | |
151 | | //// Registers the label instruction for the block. |
152 | 392k | void set_label(const Instruction* t) { label_ = t; } |
153 | | |
154 | | /// Registers the terminator instruction for the block. |
155 | 391k | void set_terminator(const Instruction* t) { terminator_ = t; } |
156 | | |
157 | | /// Returns the terminator instruction for the block. |
158 | 625k | const Instruction* terminator() const { return terminator_; } |
159 | | |
160 | | /// Adds @p next BasicBlocks as successors of this BasicBlock |
161 | | void RegisterSuccessors( |
162 | | const std::vector<BasicBlock*>& next = std::vector<BasicBlock*>()); |
163 | | |
164 | | /// Returns true if the id of the BasicBlock matches |
165 | 0 | bool operator==(const BasicBlock& other) const { return other.id_ == id_; } |
166 | | |
167 | | /// Returns true if the id of the BasicBlock matches |
168 | 474k | bool operator==(const uint32_t& other_id) const { return other_id == id_; } |
169 | | |
170 | | /// Returns true if this block dominates the other block. |
171 | | /// Assumes dominators have been computed. |
172 | | bool dominates(const BasicBlock& other) const; |
173 | | |
174 | | /// Returns true if this block structurally dominates the other block. |
175 | | /// Assumes structural dominators have been computed. |
176 | | bool structurally_dominates(const BasicBlock& other) const; |
177 | | |
178 | | /// Returns true if this block structurally postdominates the other block. |
179 | | /// Assumes structural dominators have been computed. |
180 | | bool structurally_postdominates(const BasicBlock& other) const; |
181 | | |
182 | 203k | void RegisterStructuralSuccessor(BasicBlock* block) { |
183 | 203k | block->structural_predecessors_.push_back(this); |
184 | 203k | structural_successors_.push_back(block); |
185 | 203k | } |
186 | | |
187 | | /// @brief A BasicBlock dominator iterator class |
188 | | /// |
189 | | /// This iterator will iterate over the (post)dominators of the block |
190 | | class DominatorIterator { |
191 | | public: |
192 | | using iterator_category = std::forward_iterator_tag; |
193 | | using value_type = BasicBlock*; |
194 | | using pointer = value_type*; |
195 | | using reference = value_type&; |
196 | | using difference_type = std::ptrdiff_t; |
197 | | |
198 | | /// @brief Constructs the end of dominator iterator |
199 | | /// |
200 | | /// This will create an iterator which will represent the element |
201 | | /// before the root node of the dominator tree |
202 | | DominatorIterator(); |
203 | | |
204 | | /// @brief Constructs an iterator for the given block which points to |
205 | | /// @p block |
206 | | /// |
207 | | /// @param block The block which is referenced by the iterator |
208 | | /// @param dominator_func This function will be called to get the immediate |
209 | | /// (post)dominator of the current block |
210 | | DominatorIterator( |
211 | | const BasicBlock* block, |
212 | | std::function<const BasicBlock*(const BasicBlock*)> dominator_func); |
213 | | |
214 | | /// @brief Advances the iterator |
215 | | DominatorIterator& operator++(); |
216 | | |
217 | | /// @brief Returns the current element |
218 | | const BasicBlock*& operator*(); |
219 | | |
220 | | friend bool operator==(const DominatorIterator& lhs, |
221 | | const DominatorIterator& rhs); |
222 | | |
223 | | private: |
224 | | const BasicBlock* current_; |
225 | | std::function<const BasicBlock*(const BasicBlock*)> dom_func_; |
226 | | }; |
227 | | |
228 | | /// Returns a dominator iterator which points to the current block |
229 | | const DominatorIterator dom_begin() const; |
230 | | |
231 | | /// Returns a dominator iterator which points to the current block |
232 | | DominatorIterator dom_begin(); |
233 | | |
234 | | /// Returns a dominator iterator which points to one element past the first |
235 | | /// block |
236 | | const DominatorIterator dom_end() const; |
237 | | |
238 | | /// Returns a dominator iterator which points to one element past the first |
239 | | /// block |
240 | | DominatorIterator dom_end(); |
241 | | |
242 | | /// Returns a dominator iterator which points to the current block |
243 | | const DominatorIterator structural_dom_begin() const; |
244 | | |
245 | | /// Returns a dominator iterator which points to the current block |
246 | | DominatorIterator structural_dom_begin(); |
247 | | |
248 | | /// Returns a dominator iterator which points to one element past the first |
249 | | /// block |
250 | | const DominatorIterator structural_dom_end() const; |
251 | | |
252 | | /// Returns a dominator iterator which points to one element past the first |
253 | | /// block |
254 | | DominatorIterator structural_dom_end(); |
255 | | |
256 | | /// Returns a post dominator iterator which points to the current block |
257 | | const DominatorIterator structural_pdom_begin() const; |
258 | | /// Returns a post dominator iterator which points to the current block |
259 | | DominatorIterator structural_pdom_begin(); |
260 | | |
261 | | /// Returns a post dominator iterator which points to one element past the |
262 | | /// last block |
263 | | const DominatorIterator structural_pdom_end() const; |
264 | | |
265 | | /// Returns a post dominator iterator which points to one element past the |
266 | | /// last block |
267 | | DominatorIterator structural_pdom_end(); |
268 | | |
269 | | private: |
270 | | /// Id of the BasicBlock |
271 | | const uint32_t id_; |
272 | | |
273 | | /// Pointer to the immediate dominator of the BasicBlock |
274 | | BasicBlock* immediate_dominator_; |
275 | | |
276 | | /// Pointer to the immediate structural dominator of the BasicBlock |
277 | | BasicBlock* immediate_structural_dominator_; |
278 | | |
279 | | /// Pointer to the immediate structural post dominator of the BasicBlock |
280 | | BasicBlock* immediate_structural_post_dominator_; |
281 | | |
282 | | /// The set of predecessors of the BasicBlock |
283 | | std::vector<BasicBlock*> predecessors_; |
284 | | |
285 | | /// The set of successors of the BasicBlock |
286 | | std::vector<BasicBlock*> successors_; |
287 | | |
288 | | /// The type of the block |
289 | | std::bitset<kBlockTypeCOUNT> type_; |
290 | | |
291 | | /// True if the block is reachable in the CFG |
292 | | bool reachable_; |
293 | | |
294 | | /// True if the block is structurally reachable in the CFG |
295 | | bool structurally_reachable_; |
296 | | |
297 | | /// label of this block, if any. |
298 | | const Instruction* label_; |
299 | | |
300 | | /// Terminator of this block. |
301 | | const Instruction* terminator_; |
302 | | |
303 | | std::vector<BasicBlock*> structural_predecessors_; |
304 | | std::vector<BasicBlock*> structural_successors_; |
305 | | }; |
306 | | |
307 | | /// @brief Returns true if the iterators point to the same element or if both |
308 | | /// iterators point to the @p dom_end block |
309 | | bool operator==(const BasicBlock::DominatorIterator& lhs, |
310 | | const BasicBlock::DominatorIterator& rhs); |
311 | | |
312 | | /// @brief Returns true if the iterators point to different elements and they |
313 | | /// do not both point to the @p dom_end block |
314 | | bool operator!=(const BasicBlock::DominatorIterator& lhs, |
315 | | const BasicBlock::DominatorIterator& rhs); |
316 | | |
317 | | } // namespace val |
318 | | } // namespace spvtools |
319 | | |
320 | | #endif // SOURCE_VAL_BASIC_BLOCK_H_ |