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
28namespace spvtools {
29namespace opt {
30
31class IRContext;
32
33// A struct for containing the module header information.
34struct 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.
44class 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 SetHeader(const ModuleHeader& header) { 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 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 or DebugNoScope.
305 bool contains_debug_scope_;
306};
307
308// Pretty-prints |module| to |str|. Returns |str|.
309std::ostream& operator<<(std::ostream& str, const Module& module);
310
311inline void Module::AddCapability(std::unique_ptr<Instruction> c) {
312 capabilities_.push_back(std::move(c));
313}
314
315inline void Module::AddExtension(std::unique_ptr<Instruction> e) {
316 extensions_.push_back(std::move(e));
317}
318
319inline void Module::AddExtInstImport(std::unique_ptr<Instruction> e) {
320 ext_inst_imports_.push_back(std::move(e));
321}
322
323inline void Module::SetMemoryModel(std::unique_ptr<Instruction> m) {
324 memory_model_ = std::move(m);
325}
326
327inline void Module::AddEntryPoint(std::unique_ptr<Instruction> e) {
328 entry_points_.push_back(std::move(e));
329}
330
331inline void Module::AddExecutionMode(std::unique_ptr<Instruction> e) {
332 execution_modes_.push_back(std::move(e));
333}
334
335inline void Module::AddDebug1Inst(std::unique_ptr<Instruction> d) {
336 debugs1_.push_back(std::move(d));
337}
338
339inline void Module::AddDebug2Inst(std::unique_ptr<Instruction> d) {
340 debugs2_.push_back(std::move(d));
341}
342
343inline void Module::AddDebug3Inst(std::unique_ptr<Instruction> d) {
344 debugs3_.push_back(std::move(d));
345}
346
347inline void Module::AddExtInstDebugInfo(std::unique_ptr<Instruction> d) {
348 ext_inst_debuginfo_.push_back(std::move(d));
349}
350
351inline void Module::AddAnnotationInst(std::unique_ptr<Instruction> a) {
352 annotations_.push_back(std::move(a));
353}
354
355inline void Module::AddType(std::unique_ptr<Instruction> t) {
356 types_values_.push_back(std::move(t));
357}
358
359inline void Module::AddGlobalValue(std::unique_ptr<Instruction> v) {
360 types_values_.push_back(std::move(v));
361}
362
363inline void Module::AddFunction(std::unique_ptr<Function> f) {
364 functions_.emplace_back(std::move(f));
365}
366
367inline void Module::SetContainsDebugScope() { contains_debug_scope_ = true; }
368
369inline Module::inst_iterator Module::capability_begin() {
370 return capabilities_.begin();
371}
372inline Module::inst_iterator Module::capability_end() {
373 return capabilities_.end();
374}
375
376inline IteratorRange<Module::inst_iterator> Module::capabilities() {
377 return make_range(capabilities_.begin(), capabilities_.end());
378}
379
380inline IteratorRange<Module::const_inst_iterator> Module::capabilities() const {
381 return make_range(capabilities_.begin(), capabilities_.end());
382}
383
384inline Module::inst_iterator Module::ext_inst_import_begin() {
385 return ext_inst_imports_.begin();
386}
387inline Module::inst_iterator Module::ext_inst_import_end() {
388 return ext_inst_imports_.end();
389}
390
391inline IteratorRange<Module::inst_iterator> Module::ext_inst_imports() {
392 return make_range(ext_inst_imports_.begin(), ext_inst_imports_.end());
393}
394
395inline 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
400inline Module::inst_iterator Module::debug1_begin() { return debugs1_.begin(); }
401inline Module::inst_iterator Module::debug1_end() { return debugs1_.end(); }
402
403inline IteratorRange<Module::inst_iterator> Module::debugs1() {
404 return make_range(debugs1_.begin(), debugs1_.end());
405}
406
407inline IteratorRange<Module::const_inst_iterator> Module::debugs1() const {
408 return make_range(debugs1_.begin(), debugs1_.end());
409}
410
411inline Module::inst_iterator Module::debug2_begin() { return debugs2_.begin(); }
412inline Module::inst_iterator Module::debug2_end() { return debugs2_.end(); }
413
414inline IteratorRange<Module::inst_iterator> Module::debugs2() {
415 return make_range(debugs2_.begin(), debugs2_.end());
416}
417
418inline IteratorRange<Module::const_inst_iterator> Module::debugs2() const {
419 return make_range(debugs2_.begin(), debugs2_.end());
420}
421
422inline Module::inst_iterator Module::debug3_begin() { return debugs3_.begin(); }
423inline Module::inst_iterator Module::debug3_end() { return debugs3_.end(); }
424
425inline IteratorRange<Module::inst_iterator> Module::debugs3() {
426 return make_range(debugs3_.begin(), debugs3_.end());
427}
428
429inline IteratorRange<Module::const_inst_iterator> Module::debugs3() const {
430 return make_range(debugs3_.begin(), debugs3_.end());
431}
432
433inline Module::inst_iterator Module::ext_inst_debuginfo_begin() {
434 return ext_inst_debuginfo_.begin();
435}
436inline Module::inst_iterator Module::ext_inst_debuginfo_end() {
437 return ext_inst_debuginfo_.end();
438}
439
440inline IteratorRange<Module::inst_iterator> Module::ext_inst_debuginfo() {
441 return make_range(ext_inst_debuginfo_.begin(), ext_inst_debuginfo_.end());
442}
443
444inline 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
449inline IteratorRange<Module::inst_iterator> Module::entry_points() {
450 return make_range(entry_points_.begin(), entry_points_.end());
451}
452
453inline IteratorRange<Module::const_inst_iterator> Module::entry_points() const {
454 return make_range(entry_points_.begin(), entry_points_.end());
455}
456
457inline Module::inst_iterator Module::execution_mode_begin() {
458 return execution_modes_.begin();
459}
460inline Module::inst_iterator Module::execution_mode_end() {
461 return execution_modes_.end();
462}
463
464inline IteratorRange<Module::inst_iterator> Module::execution_modes() {
465 return make_range(execution_modes_.begin(), execution_modes_.end());
466}
467
468inline IteratorRange<Module::const_inst_iterator> Module::execution_modes()
469 const {
470 return make_range(execution_modes_.begin(), execution_modes_.end());
471}
472
473inline Module::inst_iterator Module::annotation_begin() {
474 return annotations_.begin();
475}
476inline Module::inst_iterator Module::annotation_end() {
477 return annotations_.end();
478}
479
480inline IteratorRange<Module::inst_iterator> Module::annotations() {
481 return make_range(annotations_.begin(), annotations_.end());
482}
483
484inline IteratorRange<Module::const_inst_iterator> Module::annotations() const {
485 return make_range(annotations_.begin(), annotations_.end());
486}
487
488inline Module::inst_iterator Module::extension_begin() {
489 return extensions_.begin();
490}
491inline Module::inst_iterator Module::extension_end() {
492 return extensions_.end();
493}
494
495inline IteratorRange<Module::inst_iterator> Module::extensions() {
496 return make_range(extensions_.begin(), extensions_.end());
497}
498
499inline IteratorRange<Module::const_inst_iterator> Module::extensions() const {
500 return make_range(extensions_.begin(), extensions_.end());
501}
502
503inline Module::inst_iterator Module::types_values_begin() {
504 return types_values_.begin();
505}
506
507inline Module::inst_iterator Module::types_values_end() {
508 return types_values_.end();
509}
510
511inline IteratorRange<Module::inst_iterator> Module::types_values() {
512 return make_range(types_values_.begin(), types_values_.end());
513}
514
515inline IteratorRange<Module::const_inst_iterator> Module::types_values() const {
516 return make_range(types_values_.begin(), types_values_.end());
517}
518
519inline Module::const_iterator Module::cbegin() const {
520 return const_iterator(&functions_, functions_.cbegin());
521}
522
523inline 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