1 | // Copyright (c) 2016 Google 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_OPT_MODULE_H_ |
16 | #define SOURCE_OPT_MODULE_H_ |
17 | |
18 | #include <functional> |
19 | #include <memory> |
20 | #include <unordered_map> |
21 | #include <utility> |
22 | #include <vector> |
23 | |
24 | #include "source/opt/function.h" |
25 | #include "source/opt/instruction.h" |
26 | #include "source/opt/iterator.h" |
27 | |
28 | namespace spvtools { |
29 | namespace opt { |
30 | |
31 | class IRContext; |
32 | |
33 | // A struct for containing the module header information. |
34 | struct { |
35 | uint32_t ; |
36 | uint32_t ; |
37 | uint32_t ; |
38 | uint32_t ; |
39 | uint32_t ; |
40 | }; |
41 | |
42 | // A SPIR-V module. It contains all the information for a SPIR-V module and |
43 | // serves as the backbone of optimization transformations. |
44 | class Module { |
45 | public: |
46 | using iterator = UptrVectorIterator<Function>; |
47 | using const_iterator = UptrVectorIterator<Function, true>; |
48 | using inst_iterator = InstructionList::iterator; |
49 | using const_inst_iterator = InstructionList::const_iterator; |
50 | |
51 | // Creates an empty module with zero'd header. |
52 | Module() : header_({}), contains_debug_scope_(false) {} |
53 | |
54 | // Sets the header to the given |header|. |
55 | void (const ModuleHeader& ) { header_ = header; } |
56 | |
57 | // Sets the Id bound. The Id bound cannot be set to 0. |
58 | void SetIdBound(uint32_t bound) { |
59 | assert(bound != 0); |
60 | header_.bound = bound; |
61 | } |
62 | |
63 | // Returns the Id bound. |
64 | uint32_t IdBound() { return header_.bound; } |
65 | |
66 | // Returns the current Id bound and increases it to the next available value. |
67 | // If the id bound has already reached its maximum value, then 0 is returned. |
68 | // The maximum value for the id bound is obtained from the context. If there |
69 | // is none, then the minimum that limit can be according to the spir-v |
70 | // specification. |
71 | // TODO(1841): Update the uses to check for a 0 return value. |
72 | uint32_t TakeNextIdBound(); |
73 | |
74 | // Appends a capability instruction to this module. |
75 | inline void AddCapability(std::unique_ptr<Instruction> c); |
76 | |
77 | // Appends an extension instruction to this module. |
78 | inline void AddExtension(std::unique_ptr<Instruction> e); |
79 | |
80 | // Appends an extended instruction set instruction to this module. |
81 | inline void AddExtInstImport(std::unique_ptr<Instruction> e); |
82 | |
83 | // Set the memory model for this module. |
84 | inline void SetMemoryModel(std::unique_ptr<Instruction> m); |
85 | |
86 | // Appends an entry point instruction to this module. |
87 | inline void AddEntryPoint(std::unique_ptr<Instruction> e); |
88 | |
89 | // Appends an execution mode instruction to this module. |
90 | inline void AddExecutionMode(std::unique_ptr<Instruction> e); |
91 | |
92 | // Appends a debug 1 instruction (excluding OpLine & OpNoLine) to this module. |
93 | // "debug 1" instructions are the ones in layout section 7.a), see section |
94 | // 2.4 Logical Layout of a Module from the SPIR-V specification. |
95 | inline void AddDebug1Inst(std::unique_ptr<Instruction> d); |
96 | |
97 | // Appends a debug 2 instruction (excluding OpLine & OpNoLine) to this module. |
98 | // "debug 2" instructions are the ones in layout section 7.b), see section |
99 | // 2.4 Logical Layout of a Module from the SPIR-V specification. |
100 | inline void AddDebug2Inst(std::unique_ptr<Instruction> d); |
101 | |
102 | // Appends a debug 3 instruction (OpModuleProcessed) to this module. |
103 | // This is due to decision by the SPIR Working Group, pending publication. |
104 | inline void AddDebug3Inst(std::unique_ptr<Instruction> d); |
105 | |
106 | // Appends a debug info extension (OpenCL.DebugInfo.100 or DebugInfo) |
107 | // instruction to this module. |
108 | inline void AddExtInstDebugInfo(std::unique_ptr<Instruction> d); |
109 | |
110 | // Appends an annotation instruction to this module. |
111 | inline void AddAnnotationInst(std::unique_ptr<Instruction> a); |
112 | |
113 | // Appends a type-declaration instruction to this module. |
114 | inline void AddType(std::unique_ptr<Instruction> t); |
115 | |
116 | // Appends a constant, global variable, or OpUndef instruction to this module. |
117 | inline void AddGlobalValue(std::unique_ptr<Instruction> v); |
118 | |
119 | // Appends a function to this module. |
120 | inline void AddFunction(std::unique_ptr<Function> f); |
121 | |
122 | // Sets |contains_debug_scope_| as true. |
123 | inline void SetContainsDebugScope(); |
124 | inline bool ContainsDebugScope() { return contains_debug_scope_; } |
125 | |
126 | // Returns a vector of pointers to type-declaration instructions in this |
127 | // module. |
128 | std::vector<Instruction*> GetTypes(); |
129 | std::vector<const Instruction*> GetTypes() const; |
130 | // Returns a vector of pointers to constant-creation instructions in this |
131 | // module. |
132 | std::vector<Instruction*> GetConstants(); |
133 | std::vector<const Instruction*> GetConstants() const; |
134 | |
135 | // Return result id of global value with |opcode|, 0 if not present. |
136 | uint32_t GetGlobalValue(SpvOp opcode) const; |
137 | |
138 | // Add global value with |opcode|, |result_id| and |type_id| |
139 | void AddGlobalValue(SpvOp opcode, uint32_t result_id, uint32_t type_id); |
140 | |
141 | inline uint32_t id_bound() const { return header_.bound; } |
142 | |
143 | inline uint32_t version() const { return header_.version; } |
144 | |
145 | inline void set_version(uint32_t v) { header_.version = v; } |
146 | |
147 | // Iterators for capabilities instructions contained in this module. |
148 | inline inst_iterator capability_begin(); |
149 | inline inst_iterator capability_end(); |
150 | inline IteratorRange<inst_iterator> capabilities(); |
151 | inline IteratorRange<const_inst_iterator> capabilities() const; |
152 | |
153 | // Iterators for ext_inst_imports instructions contained in this module. |
154 | inline inst_iterator ext_inst_import_begin(); |
155 | inline inst_iterator ext_inst_import_end(); |
156 | inline IteratorRange<inst_iterator> ext_inst_imports(); |
157 | inline IteratorRange<const_inst_iterator> ext_inst_imports() const; |
158 | |
159 | // Return the memory model instruction contained inthis module. |
160 | inline Instruction* GetMemoryModel() { return memory_model_.get(); } |
161 | inline const Instruction* GetMemoryModel() const { |
162 | return memory_model_.get(); |
163 | } |
164 | |
165 | // There are several kinds of debug instructions, according to where they can |
166 | // appear in the logical layout of a module: |
167 | // - Section 7a: OpString, OpSourceExtension, OpSource, OpSourceContinued |
168 | // - Section 7b: OpName, OpMemberName |
169 | // - Section 7c: OpModuleProcessed |
170 | // - Mostly anywhere: OpLine and OpNoLine |
171 | // |
172 | |
173 | // Iterators for debug 1 instructions (excluding OpLine & OpNoLine) contained |
174 | // in this module. These are for layout section 7a. |
175 | inline inst_iterator debug1_begin(); |
176 | inline inst_iterator debug1_end(); |
177 | inline IteratorRange<inst_iterator> debugs1(); |
178 | inline IteratorRange<const_inst_iterator> debugs1() const; |
179 | |
180 | // Iterators for debug 2 instructions (excluding OpLine & OpNoLine) contained |
181 | // in this module. These are for layout section 7b. |
182 | inline inst_iterator debug2_begin(); |
183 | inline inst_iterator debug2_end(); |
184 | inline IteratorRange<inst_iterator> debugs2(); |
185 | inline IteratorRange<const_inst_iterator> debugs2() const; |
186 | |
187 | // Iterators for debug 3 instructions (excluding OpLine & OpNoLine) contained |
188 | // in this module. These are for layout section 7c. |
189 | inline inst_iterator debug3_begin(); |
190 | inline inst_iterator debug3_end(); |
191 | inline IteratorRange<inst_iterator> debugs3(); |
192 | inline IteratorRange<const_inst_iterator> debugs3() const; |
193 | |
194 | // Iterators for debug info instructions (excluding OpLine & OpNoLine) |
195 | // contained in this module. These are OpExtInst for OpenCL.DebugInfo.100 |
196 | // or DebugInfo extension placed between section 9 and 10. |
197 | inline inst_iterator ext_inst_debuginfo_begin(); |
198 | inline inst_iterator ext_inst_debuginfo_end(); |
199 | inline IteratorRange<inst_iterator> ext_inst_debuginfo(); |
200 | inline IteratorRange<const_inst_iterator> ext_inst_debuginfo() const; |
201 | |
202 | // Iterators for entry point instructions contained in this module |
203 | inline IteratorRange<inst_iterator> entry_points(); |
204 | inline IteratorRange<const_inst_iterator> entry_points() const; |
205 | |
206 | // Iterators for execution_modes instructions contained in this module. |
207 | inline inst_iterator execution_mode_begin(); |
208 | inline inst_iterator execution_mode_end(); |
209 | inline IteratorRange<inst_iterator> execution_modes(); |
210 | inline IteratorRange<const_inst_iterator> execution_modes() const; |
211 | |
212 | // Iterators for annotation instructions contained in this module. |
213 | inline inst_iterator annotation_begin(); |
214 | inline inst_iterator annotation_end(); |
215 | IteratorRange<inst_iterator> annotations(); |
216 | IteratorRange<const_inst_iterator> annotations() const; |
217 | |
218 | // Iterators for extension instructions contained in this module. |
219 | inline inst_iterator extension_begin(); |
220 | inline inst_iterator extension_end(); |
221 | IteratorRange<inst_iterator> extensions(); |
222 | IteratorRange<const_inst_iterator> extensions() const; |
223 | |
224 | // Iterators for types, constants and global variables instructions. |
225 | inline inst_iterator types_values_begin(); |
226 | inline inst_iterator types_values_end(); |
227 | inline IteratorRange<inst_iterator> types_values(); |
228 | inline IteratorRange<const_inst_iterator> types_values() const; |
229 | |
230 | // Iterators for functions contained in this module. |
231 | iterator begin() { return iterator(&functions_, functions_.begin()); } |
232 | iterator end() { return iterator(&functions_, functions_.end()); } |
233 | const_iterator begin() const { return cbegin(); } |
234 | const_iterator end() const { return cend(); } |
235 | inline const_iterator cbegin() const; |
236 | inline const_iterator cend() const; |
237 | |
238 | // Invokes function |f| on all instructions in this module, and optionally on |
239 | // the debug line instructions that precede them. |
240 | void ForEachInst(const std::function<void(Instruction*)>& f, |
241 | bool run_on_debug_line_insts = false); |
242 | void ForEachInst(const std::function<void(const Instruction*)>& f, |
243 | bool run_on_debug_line_insts = false) const; |
244 | |
245 | // Pushes the binary segments for this instruction into the back of *|binary|. |
246 | // If |skip_nop| is true and this is a OpNop, do nothing. |
247 | void ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const; |
248 | |
249 | // Returns 1 more than the maximum Id value mentioned in the module. |
250 | uint32_t ComputeIdBound() const; |
251 | |
252 | // Returns true if module has capability |cap| |
253 | bool HasExplicitCapability(uint32_t cap); |
254 | |
255 | // Returns id for OpExtInst instruction for extension |extstr|. |
256 | // Returns 0 if not found. |
257 | uint32_t GetExtInstImportId(const char* extstr); |
258 | |
259 | // Sets the associated context for this module |
260 | void SetContext(IRContext* c) { context_ = c; } |
261 | |
262 | // Gets the associated context for this module |
263 | IRContext* context() const { return context_; } |
264 | |
265 | // Sets the trailing debug line info to |dbg_line_info|. |
266 | void SetTrailingDbgLineInfo(std::vector<Instruction>&& dbg_line_info) { |
267 | trailing_dbg_line_info_ = std::move(dbg_line_info); |
268 | } |
269 | |
270 | std::vector<Instruction>& trailing_dbg_line_info() { |
271 | return trailing_dbg_line_info_; |
272 | } |
273 | |
274 | const std::vector<Instruction>& trailing_dbg_line_info() const { |
275 | return trailing_dbg_line_info_; |
276 | } |
277 | |
278 | private: |
279 | ModuleHeader ; // Module header |
280 | |
281 | // The following fields respect the "Logical Layout of a Module" in |
282 | // Section 2.4 of the SPIR-V specification. |
283 | IRContext* context_; |
284 | InstructionList capabilities_; |
285 | InstructionList extensions_; |
286 | InstructionList ext_inst_imports_; |
287 | // A module only has one memory model instruction. |
288 | std::unique_ptr<Instruction> memory_model_; |
289 | InstructionList entry_points_; |
290 | InstructionList execution_modes_; |
291 | InstructionList debugs1_; |
292 | InstructionList debugs2_; |
293 | InstructionList debugs3_; |
294 | InstructionList ext_inst_debuginfo_; |
295 | InstructionList annotations_; |
296 | // Type declarations, constants, and global variable declarations. |
297 | InstructionList types_values_; |
298 | std::vector<std::unique_ptr<Function>> functions_; |
299 | |
300 | // If the module ends with Op*Line instruction, they will not be attached to |
301 | // any instruction. We record them here, so they will not be lost. |
302 | std::vector<Instruction> trailing_dbg_line_info_; |
303 | |
304 | // This module contains DebugScope or DebugNoScope. |
305 | bool contains_debug_scope_; |
306 | }; |
307 | |
308 | // Pretty-prints |module| to |str|. Returns |str|. |
309 | std::ostream& operator<<(std::ostream& str, const Module& module); |
310 | |
311 | inline void Module::AddCapability(std::unique_ptr<Instruction> c) { |
312 | capabilities_.push_back(std::move(c)); |
313 | } |
314 | |
315 | inline void Module::AddExtension(std::unique_ptr<Instruction> e) { |
316 | extensions_.push_back(std::move(e)); |
317 | } |
318 | |
319 | inline void Module::AddExtInstImport(std::unique_ptr<Instruction> e) { |
320 | ext_inst_imports_.push_back(std::move(e)); |
321 | } |
322 | |
323 | inline void Module::SetMemoryModel(std::unique_ptr<Instruction> m) { |
324 | memory_model_ = std::move(m); |
325 | } |
326 | |
327 | inline void Module::AddEntryPoint(std::unique_ptr<Instruction> e) { |
328 | entry_points_.push_back(std::move(e)); |
329 | } |
330 | |
331 | inline void Module::AddExecutionMode(std::unique_ptr<Instruction> e) { |
332 | execution_modes_.push_back(std::move(e)); |
333 | } |
334 | |
335 | inline void Module::AddDebug1Inst(std::unique_ptr<Instruction> d) { |
336 | debugs1_.push_back(std::move(d)); |
337 | } |
338 | |
339 | inline void Module::AddDebug2Inst(std::unique_ptr<Instruction> d) { |
340 | debugs2_.push_back(std::move(d)); |
341 | } |
342 | |
343 | inline void Module::AddDebug3Inst(std::unique_ptr<Instruction> d) { |
344 | debugs3_.push_back(std::move(d)); |
345 | } |
346 | |
347 | inline void Module::AddExtInstDebugInfo(std::unique_ptr<Instruction> d) { |
348 | ext_inst_debuginfo_.push_back(std::move(d)); |
349 | } |
350 | |
351 | inline void Module::AddAnnotationInst(std::unique_ptr<Instruction> a) { |
352 | annotations_.push_back(std::move(a)); |
353 | } |
354 | |
355 | inline void Module::AddType(std::unique_ptr<Instruction> t) { |
356 | types_values_.push_back(std::move(t)); |
357 | } |
358 | |
359 | inline void Module::AddGlobalValue(std::unique_ptr<Instruction> v) { |
360 | types_values_.push_back(std::move(v)); |
361 | } |
362 | |
363 | inline void Module::AddFunction(std::unique_ptr<Function> f) { |
364 | functions_.emplace_back(std::move(f)); |
365 | } |
366 | |
367 | inline void Module::SetContainsDebugScope() { contains_debug_scope_ = true; } |
368 | |
369 | inline Module::inst_iterator Module::capability_begin() { |
370 | return capabilities_.begin(); |
371 | } |
372 | inline Module::inst_iterator Module::capability_end() { |
373 | return capabilities_.end(); |
374 | } |
375 | |
376 | inline IteratorRange<Module::inst_iterator> Module::capabilities() { |
377 | return make_range(capabilities_.begin(), capabilities_.end()); |
378 | } |
379 | |
380 | inline IteratorRange<Module::const_inst_iterator> Module::capabilities() const { |
381 | return make_range(capabilities_.begin(), capabilities_.end()); |
382 | } |
383 | |
384 | inline Module::inst_iterator Module::ext_inst_import_begin() { |
385 | return ext_inst_imports_.begin(); |
386 | } |
387 | inline Module::inst_iterator Module::ext_inst_import_end() { |
388 | return ext_inst_imports_.end(); |
389 | } |
390 | |
391 | inline IteratorRange<Module::inst_iterator> Module::ext_inst_imports() { |
392 | return make_range(ext_inst_imports_.begin(), ext_inst_imports_.end()); |
393 | } |
394 | |
395 | inline IteratorRange<Module::const_inst_iterator> Module::ext_inst_imports() |
396 | const { |
397 | return make_range(ext_inst_imports_.begin(), ext_inst_imports_.end()); |
398 | } |
399 | |
400 | inline Module::inst_iterator Module::debug1_begin() { return debugs1_.begin(); } |
401 | inline Module::inst_iterator Module::debug1_end() { return debugs1_.end(); } |
402 | |
403 | inline IteratorRange<Module::inst_iterator> Module::debugs1() { |
404 | return make_range(debugs1_.begin(), debugs1_.end()); |
405 | } |
406 | |
407 | inline IteratorRange<Module::const_inst_iterator> Module::debugs1() const { |
408 | return make_range(debugs1_.begin(), debugs1_.end()); |
409 | } |
410 | |
411 | inline Module::inst_iterator Module::debug2_begin() { return debugs2_.begin(); } |
412 | inline Module::inst_iterator Module::debug2_end() { return debugs2_.end(); } |
413 | |
414 | inline IteratorRange<Module::inst_iterator> Module::debugs2() { |
415 | return make_range(debugs2_.begin(), debugs2_.end()); |
416 | } |
417 | |
418 | inline IteratorRange<Module::const_inst_iterator> Module::debugs2() const { |
419 | return make_range(debugs2_.begin(), debugs2_.end()); |
420 | } |
421 | |
422 | inline Module::inst_iterator Module::debug3_begin() { return debugs3_.begin(); } |
423 | inline Module::inst_iterator Module::debug3_end() { return debugs3_.end(); } |
424 | |
425 | inline IteratorRange<Module::inst_iterator> Module::debugs3() { |
426 | return make_range(debugs3_.begin(), debugs3_.end()); |
427 | } |
428 | |
429 | inline IteratorRange<Module::const_inst_iterator> Module::debugs3() const { |
430 | return make_range(debugs3_.begin(), debugs3_.end()); |
431 | } |
432 | |
433 | inline Module::inst_iterator Module::ext_inst_debuginfo_begin() { |
434 | return ext_inst_debuginfo_.begin(); |
435 | } |
436 | inline Module::inst_iterator Module::ext_inst_debuginfo_end() { |
437 | return ext_inst_debuginfo_.end(); |
438 | } |
439 | |
440 | inline IteratorRange<Module::inst_iterator> Module::ext_inst_debuginfo() { |
441 | return make_range(ext_inst_debuginfo_.begin(), ext_inst_debuginfo_.end()); |
442 | } |
443 | |
444 | inline IteratorRange<Module::const_inst_iterator> Module::ext_inst_debuginfo() |
445 | const { |
446 | return make_range(ext_inst_debuginfo_.begin(), ext_inst_debuginfo_.end()); |
447 | } |
448 | |
449 | inline IteratorRange<Module::inst_iterator> Module::entry_points() { |
450 | return make_range(entry_points_.begin(), entry_points_.end()); |
451 | } |
452 | |
453 | inline IteratorRange<Module::const_inst_iterator> Module::entry_points() const { |
454 | return make_range(entry_points_.begin(), entry_points_.end()); |
455 | } |
456 | |
457 | inline Module::inst_iterator Module::execution_mode_begin() { |
458 | return execution_modes_.begin(); |
459 | } |
460 | inline Module::inst_iterator Module::execution_mode_end() { |
461 | return execution_modes_.end(); |
462 | } |
463 | |
464 | inline IteratorRange<Module::inst_iterator> Module::execution_modes() { |
465 | return make_range(execution_modes_.begin(), execution_modes_.end()); |
466 | } |
467 | |
468 | inline IteratorRange<Module::const_inst_iterator> Module::execution_modes() |
469 | const { |
470 | return make_range(execution_modes_.begin(), execution_modes_.end()); |
471 | } |
472 | |
473 | inline Module::inst_iterator Module::annotation_begin() { |
474 | return annotations_.begin(); |
475 | } |
476 | inline Module::inst_iterator Module::annotation_end() { |
477 | return annotations_.end(); |
478 | } |
479 | |
480 | inline IteratorRange<Module::inst_iterator> Module::annotations() { |
481 | return make_range(annotations_.begin(), annotations_.end()); |
482 | } |
483 | |
484 | inline IteratorRange<Module::const_inst_iterator> Module::annotations() const { |
485 | return make_range(annotations_.begin(), annotations_.end()); |
486 | } |
487 | |
488 | inline Module::inst_iterator Module::extension_begin() { |
489 | return extensions_.begin(); |
490 | } |
491 | inline Module::inst_iterator Module::extension_end() { |
492 | return extensions_.end(); |
493 | } |
494 | |
495 | inline IteratorRange<Module::inst_iterator> Module::extensions() { |
496 | return make_range(extensions_.begin(), extensions_.end()); |
497 | } |
498 | |
499 | inline IteratorRange<Module::const_inst_iterator> Module::extensions() const { |
500 | return make_range(extensions_.begin(), extensions_.end()); |
501 | } |
502 | |
503 | inline Module::inst_iterator Module::types_values_begin() { |
504 | return types_values_.begin(); |
505 | } |
506 | |
507 | inline Module::inst_iterator Module::types_values_end() { |
508 | return types_values_.end(); |
509 | } |
510 | |
511 | inline IteratorRange<Module::inst_iterator> Module::types_values() { |
512 | return make_range(types_values_.begin(), types_values_.end()); |
513 | } |
514 | |
515 | inline IteratorRange<Module::const_inst_iterator> Module::types_values() const { |
516 | return make_range(types_values_.begin(), types_values_.end()); |
517 | } |
518 | |
519 | inline Module::const_iterator Module::cbegin() const { |
520 | return const_iterator(&functions_, functions_.cbegin()); |
521 | } |
522 | |
523 | inline Module::const_iterator Module::cend() const { |
524 | return const_iterator(&functions_, functions_.cend()); |
525 | } |
526 | |
527 | } // namespace opt |
528 | } // namespace spvtools |
529 | |
530 | #endif // SOURCE_OPT_MODULE_H_ |
531 | |