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