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