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 ModuleHeader {
35 uint32_t magic_number;
36 uint32_t version;
37 uint32_t generator;
38 uint32_t bound;
39 uint32_t reserved;
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.
Module()52 Module() : header_({}), contains_debug_info_(false) {}
53
54 // Sets the header to the given |header|.
SetHeader(const ModuleHeader & header)55 void SetHeader(const ModuleHeader& header) { header_ = header; }
56
57 // Sets the Id bound. The Id bound cannot be set to 0.
SetIdBound(uint32_t bound)58 void SetIdBound(uint32_t bound) {
59 assert(bound != 0);
60 header_.bound = bound;
61 }
62
63 // Returns the Id bound.
IdBound()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_info_| as true.
123 inline void SetContainsDebugInfo();
ContainsDebugInfo()124 inline bool ContainsDebugInfo() { return contains_debug_info_; }
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
id_bound()141 inline uint32_t id_bound() const { return header_.bound; }
142
version()143 inline uint32_t version() const { return header_.version; }
144
set_version(uint32_t v)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.
GetMemoryModel()160 inline Instruction* GetMemoryModel() { return memory_model_.get(); }
GetMemoryModel()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.
begin()231 iterator begin() { return iterator(&functions_, functions_.begin()); }
end()232 iterator end() { return iterator(&functions_, functions_.end()); }
begin()233 const_iterator begin() const { return cbegin(); }
end()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
SetContext(IRContext * c)260 void SetContext(IRContext* c) { context_ = c; }
261
262 // Gets the associated context for this module
context()263 IRContext* context() const { return context_; }
264
265 // Sets the trailing debug line info to |dbg_line_info|.
SetTrailingDbgLineInfo(std::vector<Instruction> && dbg_line_info)266 void SetTrailingDbgLineInfo(std::vector<Instruction>&& dbg_line_info) {
267 trailing_dbg_line_info_ = std::move(dbg_line_info);
268 }
269
trailing_dbg_line_info()270 std::vector<Instruction>& trailing_dbg_line_info() {
271 return trailing_dbg_line_info_;
272 }
273
trailing_dbg_line_info()274 const std::vector<Instruction>& trailing_dbg_line_info() const {
275 return trailing_dbg_line_info_;
276 }
277
278 private:
279 ModuleHeader header_; // 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/DebugNoScope or OpLine/OpNoLine.
305 bool contains_debug_info_;
306 };
307
308 // Pretty-prints |module| to |str|. Returns |str|.
309 std::ostream& operator<<(std::ostream& str, const Module& module);
310
AddCapability(std::unique_ptr<Instruction> c)311 inline void Module::AddCapability(std::unique_ptr<Instruction> c) {
312 capabilities_.push_back(std::move(c));
313 }
314
AddExtension(std::unique_ptr<Instruction> e)315 inline void Module::AddExtension(std::unique_ptr<Instruction> e) {
316 extensions_.push_back(std::move(e));
317 }
318
AddExtInstImport(std::unique_ptr<Instruction> e)319 inline void Module::AddExtInstImport(std::unique_ptr<Instruction> e) {
320 ext_inst_imports_.push_back(std::move(e));
321 }
322
SetMemoryModel(std::unique_ptr<Instruction> m)323 inline void Module::SetMemoryModel(std::unique_ptr<Instruction> m) {
324 memory_model_ = std::move(m);
325 }
326
AddEntryPoint(std::unique_ptr<Instruction> e)327 inline void Module::AddEntryPoint(std::unique_ptr<Instruction> e) {
328 entry_points_.push_back(std::move(e));
329 }
330
AddExecutionMode(std::unique_ptr<Instruction> e)331 inline void Module::AddExecutionMode(std::unique_ptr<Instruction> e) {
332 execution_modes_.push_back(std::move(e));
333 }
334
AddDebug1Inst(std::unique_ptr<Instruction> d)335 inline void Module::AddDebug1Inst(std::unique_ptr<Instruction> d) {
336 debugs1_.push_back(std::move(d));
337 }
338
AddDebug2Inst(std::unique_ptr<Instruction> d)339 inline void Module::AddDebug2Inst(std::unique_ptr<Instruction> d) {
340 debugs2_.push_back(std::move(d));
341 }
342
AddDebug3Inst(std::unique_ptr<Instruction> d)343 inline void Module::AddDebug3Inst(std::unique_ptr<Instruction> d) {
344 debugs3_.push_back(std::move(d));
345 }
346
AddExtInstDebugInfo(std::unique_ptr<Instruction> d)347 inline void Module::AddExtInstDebugInfo(std::unique_ptr<Instruction> d) {
348 ext_inst_debuginfo_.push_back(std::move(d));
349 }
350
AddAnnotationInst(std::unique_ptr<Instruction> a)351 inline void Module::AddAnnotationInst(std::unique_ptr<Instruction> a) {
352 annotations_.push_back(std::move(a));
353 }
354
AddType(std::unique_ptr<Instruction> t)355 inline void Module::AddType(std::unique_ptr<Instruction> t) {
356 types_values_.push_back(std::move(t));
357 }
358
AddGlobalValue(std::unique_ptr<Instruction> v)359 inline void Module::AddGlobalValue(std::unique_ptr<Instruction> v) {
360 types_values_.push_back(std::move(v));
361 }
362
AddFunction(std::unique_ptr<Function> f)363 inline void Module::AddFunction(std::unique_ptr<Function> f) {
364 functions_.emplace_back(std::move(f));
365 }
366
SetContainsDebugInfo()367 inline void Module::SetContainsDebugInfo() { contains_debug_info_ = true; }
368
capability_begin()369 inline Module::inst_iterator Module::capability_begin() {
370 return capabilities_.begin();
371 }
capability_end()372 inline Module::inst_iterator Module::capability_end() {
373 return capabilities_.end();
374 }
375
capabilities()376 inline IteratorRange<Module::inst_iterator> Module::capabilities() {
377 return make_range(capabilities_.begin(), capabilities_.end());
378 }
379
capabilities()380 inline IteratorRange<Module::const_inst_iterator> Module::capabilities() const {
381 return make_range(capabilities_.begin(), capabilities_.end());
382 }
383
ext_inst_import_begin()384 inline Module::inst_iterator Module::ext_inst_import_begin() {
385 return ext_inst_imports_.begin();
386 }
ext_inst_import_end()387 inline Module::inst_iterator Module::ext_inst_import_end() {
388 return ext_inst_imports_.end();
389 }
390
ext_inst_imports()391 inline IteratorRange<Module::inst_iterator> Module::ext_inst_imports() {
392 return make_range(ext_inst_imports_.begin(), ext_inst_imports_.end());
393 }
394
ext_inst_imports()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
debug1_begin()400 inline Module::inst_iterator Module::debug1_begin() { return debugs1_.begin(); }
debug1_end()401 inline Module::inst_iterator Module::debug1_end() { return debugs1_.end(); }
402
debugs1()403 inline IteratorRange<Module::inst_iterator> Module::debugs1() {
404 return make_range(debugs1_.begin(), debugs1_.end());
405 }
406
debugs1()407 inline IteratorRange<Module::const_inst_iterator> Module::debugs1() const {
408 return make_range(debugs1_.begin(), debugs1_.end());
409 }
410
debug2_begin()411 inline Module::inst_iterator Module::debug2_begin() { return debugs2_.begin(); }
debug2_end()412 inline Module::inst_iterator Module::debug2_end() { return debugs2_.end(); }
413
debugs2()414 inline IteratorRange<Module::inst_iterator> Module::debugs2() {
415 return make_range(debugs2_.begin(), debugs2_.end());
416 }
417
debugs2()418 inline IteratorRange<Module::const_inst_iterator> Module::debugs2() const {
419 return make_range(debugs2_.begin(), debugs2_.end());
420 }
421
debug3_begin()422 inline Module::inst_iterator Module::debug3_begin() { return debugs3_.begin(); }
debug3_end()423 inline Module::inst_iterator Module::debug3_end() { return debugs3_.end(); }
424
debugs3()425 inline IteratorRange<Module::inst_iterator> Module::debugs3() {
426 return make_range(debugs3_.begin(), debugs3_.end());
427 }
428
debugs3()429 inline IteratorRange<Module::const_inst_iterator> Module::debugs3() const {
430 return make_range(debugs3_.begin(), debugs3_.end());
431 }
432
ext_inst_debuginfo_begin()433 inline Module::inst_iterator Module::ext_inst_debuginfo_begin() {
434 return ext_inst_debuginfo_.begin();
435 }
ext_inst_debuginfo_end()436 inline Module::inst_iterator Module::ext_inst_debuginfo_end() {
437 return ext_inst_debuginfo_.end();
438 }
439
ext_inst_debuginfo()440 inline IteratorRange<Module::inst_iterator> Module::ext_inst_debuginfo() {
441 return make_range(ext_inst_debuginfo_.begin(), ext_inst_debuginfo_.end());
442 }
443
ext_inst_debuginfo()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
entry_points()449 inline IteratorRange<Module::inst_iterator> Module::entry_points() {
450 return make_range(entry_points_.begin(), entry_points_.end());
451 }
452
entry_points()453 inline IteratorRange<Module::const_inst_iterator> Module::entry_points() const {
454 return make_range(entry_points_.begin(), entry_points_.end());
455 }
456
execution_mode_begin()457 inline Module::inst_iterator Module::execution_mode_begin() {
458 return execution_modes_.begin();
459 }
execution_mode_end()460 inline Module::inst_iterator Module::execution_mode_end() {
461 return execution_modes_.end();
462 }
463
execution_modes()464 inline IteratorRange<Module::inst_iterator> Module::execution_modes() {
465 return make_range(execution_modes_.begin(), execution_modes_.end());
466 }
467
execution_modes()468 inline IteratorRange<Module::const_inst_iterator> Module::execution_modes()
469 const {
470 return make_range(execution_modes_.begin(), execution_modes_.end());
471 }
472
annotation_begin()473 inline Module::inst_iterator Module::annotation_begin() {
474 return annotations_.begin();
475 }
annotation_end()476 inline Module::inst_iterator Module::annotation_end() {
477 return annotations_.end();
478 }
479
annotations()480 inline IteratorRange<Module::inst_iterator> Module::annotations() {
481 return make_range(annotations_.begin(), annotations_.end());
482 }
483
annotations()484 inline IteratorRange<Module::const_inst_iterator> Module::annotations() const {
485 return make_range(annotations_.begin(), annotations_.end());
486 }
487
extension_begin()488 inline Module::inst_iterator Module::extension_begin() {
489 return extensions_.begin();
490 }
extension_end()491 inline Module::inst_iterator Module::extension_end() {
492 return extensions_.end();
493 }
494
extensions()495 inline IteratorRange<Module::inst_iterator> Module::extensions() {
496 return make_range(extensions_.begin(), extensions_.end());
497 }
498
extensions()499 inline IteratorRange<Module::const_inst_iterator> Module::extensions() const {
500 return make_range(extensions_.begin(), extensions_.end());
501 }
502
types_values_begin()503 inline Module::inst_iterator Module::types_values_begin() {
504 return types_values_.begin();
505 }
506
types_values_end()507 inline Module::inst_iterator Module::types_values_end() {
508 return types_values_.end();
509 }
510
types_values()511 inline IteratorRange<Module::inst_iterator> Module::types_values() {
512 return make_range(types_values_.begin(), types_values_.end());
513 }
514
types_values()515 inline IteratorRange<Module::const_inst_iterator> Module::types_values() const {
516 return make_range(types_values_.begin(), types_values_.end());
517 }
518
cbegin()519 inline Module::const_iterator Module::cbegin() const {
520 return const_iterator(&functions_, functions_.cbegin());
521 }
522
cend()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