• 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 LIBSPIRV_OPT_MODULE_H_
16 #define LIBSPIRV_OPT_MODULE_H_
17 
18 #include <functional>
19 #include <memory>
20 #include <utility>
21 #include <vector>
22 
23 #include "function.h"
24 #include "instruction.h"
25 #include "iterator.h"
26 
27 namespace spvtools {
28 namespace ir {
29 
30 // A struct for containing the module header information.
31 struct ModuleHeader {
32   uint32_t magic_number;
33   uint32_t version;
34   uint32_t generator;
35   uint32_t bound;
36   uint32_t reserved;
37 };
38 
39 // A SPIR-V module. It contains all the information for a SPIR-V module and
40 // serves as the backbone of optimization transformations.
41 class Module {
42  public:
43   using iterator = UptrVectorIterator<Function>;
44   using const_iterator = UptrVectorIterator<Function, true>;
45   using inst_iterator = UptrVectorIterator<Instruction>;
46   using const_inst_iterator = UptrVectorIterator<Instruction, true>;
47 
48   // Creates an empty module with zero'd header.
Module()49   Module() : header_({}) {}
50 
51   // Sets the header to the given |header|.
SetHeader(const ModuleHeader & header)52   void SetHeader(const ModuleHeader& header) { header_ = header; }
53   // Sets the Id bound.
SetIdBound(uint32_t bound)54   void SetIdBound(uint32_t bound) { header_.bound = bound; }
55   // Returns the Id bound.
IdBound()56   uint32_t IdBound() { return header_.bound; }
57   // Appends a capability instruction to this module.
58   inline void AddCapability(std::unique_ptr<Instruction> c);
59   // Appends an extension instruction to this module.
60   inline void AddExtension(std::unique_ptr<Instruction> e);
61   // Appends an extended instruction set instruction to this module.
62   inline void AddExtInstImport(std::unique_ptr<Instruction> e);
63   // Set the memory model for this module.
64   inline void SetMemoryModel(std::unique_ptr<Instruction> m);
65   // Appends an entry point instruction to this module.
66   inline void AddEntryPoint(std::unique_ptr<Instruction> e);
67   // Appends an execution mode instruction to this module.
68   inline void AddExecutionMode(std::unique_ptr<Instruction> e);
69   // Appends a debug instruction (excluding OpLine & OpNoLine) to this module.
70   inline void AddDebugInst(std::unique_ptr<Instruction> d);
71   // Appends an annotation instruction to this module.
72   inline void AddAnnotationInst(std::unique_ptr<Instruction> a);
73   // Appends a type-declaration instruction to this module.
74   inline void AddType(std::unique_ptr<Instruction> t);
75   // Appends a constant, global variable, or OpUndef instruction to this module.
76   inline void AddGlobalValue(std::unique_ptr<Instruction> v);
77   // Appends a function to this module.
78   inline void AddFunction(std::unique_ptr<Function> f);
79 
80   // Returns a vector of pointers to type-declaration instructions in this
81   // module.
82   std::vector<Instruction*> GetTypes();
83   std::vector<const Instruction*> GetTypes() const;
84   // Returns a vector of pointers to constant-creation instructions in this
85   // module.
86   std::vector<Instruction*> GetConstants();
87   std::vector<const Instruction*> GetConstants() const;
88 
89   // Return result id of global value with |opcode|, 0 if not present.
90   uint32_t GetGlobalValue(SpvOp opcode) const;
91 
92   // Add global value with |opcode|, |result_id| and |type_id|
93   void AddGlobalValue(SpvOp opcode, uint32_t result_id, uint32_t type_id);
94 
id_bound()95   inline uint32_t id_bound() const { return header_.bound; }
96 
97   // Iterators for debug instructions (excluding OpLine & OpNoLine) contained in
98   // this module.
99   inline inst_iterator debug_begin();
100   inline inst_iterator debug_end();
101   inline IteratorRange<inst_iterator> debugs();
102   inline IteratorRange<const_inst_iterator> debugs() const;
103 
104   // Iterators for entry point instructions contained in this module
105   inline IteratorRange<inst_iterator> entry_points();
106   inline IteratorRange<const_inst_iterator> entry_points() const;
107 
108   // Clears all debug instructions (excluding OpLine & OpNoLine).
debug_clear()109   void debug_clear() { debugs_.clear(); }
110 
111   // Iterators for annotation instructions contained in this module.
112   IteratorRange<inst_iterator> annotations();
113   IteratorRange<const_inst_iterator> annotations() const;
114 
115   // Iterators for extension instructions contained in this module.
116   IteratorRange<inst_iterator> extensions();
117   IteratorRange<const_inst_iterator> extensions() const;
118 
119   // Iterators for types, constants and global variables instructions.
120   inline inst_iterator types_values_begin();
121   inline inst_iterator types_values_end();
122   inline IteratorRange<inst_iterator> types_values();
123   inline IteratorRange<const_inst_iterator> types_values() const;
124 
125   // Iterators for functions contained in this module.
begin()126   iterator begin() { return iterator(&functions_, functions_.begin()); }
end()127   iterator end() { return iterator(&functions_, functions_.end()); }
128   inline const_iterator cbegin() const;
129   inline const_iterator cend() const;
130 
131   // Invokes function |f| on all instructions in this module, and optionally on
132   // the debug line instructions that precede them.
133   void ForEachInst(const std::function<void(Instruction*)>& f,
134                    bool run_on_debug_line_insts = false);
135   void ForEachInst(const std::function<void(const Instruction*)>& f,
136                    bool run_on_debug_line_insts = false) const;
137 
138   // Pushes the binary segments for this instruction into the back of *|binary|.
139   // If |skip_nop| is true and this is a OpNop, do nothing.
140   void ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const;
141 
142   // Returns 1 more than the maximum Id value mentioned in the module.
143   uint32_t ComputeIdBound() const;
144 
145   // Returns true if module has capability |cap|
146   bool HasCapability(uint32_t cap);
147 
148   // Returns id for OpExtInst instruction for extension |extstr|.
149   // Returns 0 if not found.
150   uint32_t GetExtInstImportId(const char* extstr);
151 
152  private:
153   ModuleHeader header_;  // Module header
154 
155   // The following fields respect the "Logical Layout of a Module" in
156   // Section 2.4 of the SPIR-V specification.
157   std::vector<std::unique_ptr<Instruction>> capabilities_;
158   std::vector<std::unique_ptr<Instruction>> extensions_;
159   std::vector<std::unique_ptr<Instruction>> ext_inst_imports_;
160   // A module only has one memory model instruction.
161   std::unique_ptr<Instruction> memory_model_;
162   std::vector<std::unique_ptr<Instruction>> entry_points_;
163   std::vector<std::unique_ptr<Instruction>> execution_modes_;
164   std::vector<std::unique_ptr<Instruction>> debugs_;
165   std::vector<std::unique_ptr<Instruction>> annotations_;
166   // Type declarations, constants, and global variable declarations.
167   std::vector<std::unique_ptr<Instruction>> types_values_;
168   std::vector<std::unique_ptr<Function>> functions_;
169 };
170 
AddCapability(std::unique_ptr<Instruction> c)171 inline void Module::AddCapability(std::unique_ptr<Instruction> c) {
172   capabilities_.emplace_back(std::move(c));
173 }
174 
AddExtension(std::unique_ptr<Instruction> e)175 inline void Module::AddExtension(std::unique_ptr<Instruction> e) {
176   extensions_.emplace_back(std::move(e));
177 }
178 
AddExtInstImport(std::unique_ptr<Instruction> e)179 inline void Module::AddExtInstImport(std::unique_ptr<Instruction> e) {
180   ext_inst_imports_.emplace_back(std::move(e));
181 }
182 
SetMemoryModel(std::unique_ptr<Instruction> m)183 inline void Module::SetMemoryModel(std::unique_ptr<Instruction> m) {
184   memory_model_ = std::move(m);
185 }
186 
AddEntryPoint(std::unique_ptr<Instruction> e)187 inline void Module::AddEntryPoint(std::unique_ptr<Instruction> e) {
188   entry_points_.emplace_back(std::move(e));
189 }
190 
AddExecutionMode(std::unique_ptr<Instruction> e)191 inline void Module::AddExecutionMode(std::unique_ptr<Instruction> e) {
192   execution_modes_.emplace_back(std::move(e));
193 }
194 
AddDebugInst(std::unique_ptr<Instruction> d)195 inline void Module::AddDebugInst(std::unique_ptr<Instruction> d) {
196   debugs_.emplace_back(std::move(d));
197 }
198 
AddAnnotationInst(std::unique_ptr<Instruction> a)199 inline void Module::AddAnnotationInst(std::unique_ptr<Instruction> a) {
200   annotations_.emplace_back(std::move(a));
201 }
202 
AddType(std::unique_ptr<Instruction> t)203 inline void Module::AddType(std::unique_ptr<Instruction> t) {
204   types_values_.emplace_back(std::move(t));
205 }
206 
AddGlobalValue(std::unique_ptr<Instruction> v)207 inline void Module::AddGlobalValue(std::unique_ptr<Instruction> v) {
208   types_values_.emplace_back(std::move(v));
209 }
210 
AddFunction(std::unique_ptr<Function> f)211 inline void Module::AddFunction(std::unique_ptr<Function> f) {
212   functions_.emplace_back(std::move(f));
213 }
214 
debug_begin()215 inline Module::inst_iterator Module::debug_begin() {
216   return inst_iterator(&debugs_, debugs_.begin());
217 }
debug_end()218 inline Module::inst_iterator Module::debug_end() {
219   return inst_iterator(&debugs_, debugs_.end());
220 }
221 
debugs()222 inline IteratorRange<Module::inst_iterator> Module::debugs() {
223   return make_range(debugs_);
224 }
225 
debugs()226 inline IteratorRange<Module::const_inst_iterator> Module::debugs() const {
227   return make_const_range(debugs_);
228 }
229 
entry_points()230 inline IteratorRange<Module::inst_iterator> Module::entry_points() {
231   return make_range(entry_points_);
232 }
233 
entry_points()234 inline IteratorRange<Module::const_inst_iterator> Module::entry_points() const {
235   return make_const_range(entry_points_);
236 }
237 
annotations()238 inline IteratorRange<Module::inst_iterator> Module::annotations() {
239   return make_range(annotations_);
240 }
241 
annotations()242 inline IteratorRange<Module::const_inst_iterator> Module::annotations() const {
243   return make_const_range(annotations_);
244 }
245 
extensions()246 inline IteratorRange<Module::inst_iterator> Module::extensions() {
247   return make_range(extensions_);
248 }
249 
extensions()250 inline IteratorRange<Module::const_inst_iterator> Module::extensions() const {
251   return make_const_range(extensions_);
252 }
253 
types_values_begin()254 inline Module::inst_iterator Module::types_values_begin() {
255   return inst_iterator(&types_values_, types_values_.begin());
256 }
257 
types_values_end()258 inline Module::inst_iterator Module::types_values_end() {
259   return inst_iterator(&types_values_, types_values_.end());
260 }
261 
types_values()262 inline IteratorRange<Module::inst_iterator> Module::types_values() {
263   return make_range(types_values_);
264 }
265 
types_values()266 inline IteratorRange<Module::const_inst_iterator> Module::types_values() const {
267   return make_const_range(types_values_);
268 }
269 
cbegin()270 inline Module::const_iterator Module::cbegin() const {
271   return const_iterator(&functions_, functions_.cbegin());
272 }
273 
cend()274 inline Module::const_iterator Module::cend() const {
275   return const_iterator(&functions_, functions_.cend());
276 }
277 
278 }  // namespace ir
279 }  // namespace spvtools
280 
281 #endif  // LIBSPIRV_OPT_MODULE_H_
282