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