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