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