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