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