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. 49 Module() : header_({}) {} 50 51 // Sets the header to the given |header|. 52 void SetHeader(const ModuleHeader& header) { header_ = header; } 53 // Sets the Id bound. 54 void SetIdBound(uint32_t bound) { header_.bound = bound; } 55 // Returns the Id bound. 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 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). 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. 126 iterator begin() { return iterator(&functions_, functions_.begin()); } 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 171 inline void Module::AddCapability(std::unique_ptr<Instruction> c) { 172 capabilities_.emplace_back(std::move(c)); 173 } 174 175 inline void Module::AddExtension(std::unique_ptr<Instruction> e) { 176 extensions_.emplace_back(std::move(e)); 177 } 178 179 inline void Module::AddExtInstImport(std::unique_ptr<Instruction> e) { 180 ext_inst_imports_.emplace_back(std::move(e)); 181 } 182 183 inline void Module::SetMemoryModel(std::unique_ptr<Instruction> m) { 184 memory_model_ = std::move(m); 185 } 186 187 inline void Module::AddEntryPoint(std::unique_ptr<Instruction> e) { 188 entry_points_.emplace_back(std::move(e)); 189 } 190 191 inline void Module::AddExecutionMode(std::unique_ptr<Instruction> e) { 192 execution_modes_.emplace_back(std::move(e)); 193 } 194 195 inline void Module::AddDebugInst(std::unique_ptr<Instruction> d) { 196 debugs_.emplace_back(std::move(d)); 197 } 198 199 inline void Module::AddAnnotationInst(std::unique_ptr<Instruction> a) { 200 annotations_.emplace_back(std::move(a)); 201 } 202 203 inline void Module::AddType(std::unique_ptr<Instruction> t) { 204 types_values_.emplace_back(std::move(t)); 205 } 206 207 inline void Module::AddGlobalValue(std::unique_ptr<Instruction> v) { 208 types_values_.emplace_back(std::move(v)); 209 } 210 211 inline void Module::AddFunction(std::unique_ptr<Function> f) { 212 functions_.emplace_back(std::move(f)); 213 } 214 215 inline Module::inst_iterator Module::debug_begin() { 216 return inst_iterator(&debugs_, debugs_.begin()); 217 } 218 inline Module::inst_iterator Module::debug_end() { 219 return inst_iterator(&debugs_, debugs_.end()); 220 } 221 222 inline IteratorRange<Module::inst_iterator> Module::debugs() { 223 return make_range(debugs_); 224 } 225 226 inline IteratorRange<Module::const_inst_iterator> Module::debugs() const { 227 return make_const_range(debugs_); 228 } 229 230 inline IteratorRange<Module::inst_iterator> Module::entry_points() { 231 return make_range(entry_points_); 232 } 233 234 inline IteratorRange<Module::const_inst_iterator> Module::entry_points() const { 235 return make_const_range(entry_points_); 236 } 237 238 inline IteratorRange<Module::inst_iterator> Module::annotations() { 239 return make_range(annotations_); 240 } 241 242 inline IteratorRange<Module::const_inst_iterator> Module::annotations() const { 243 return make_const_range(annotations_); 244 } 245 246 inline IteratorRange<Module::inst_iterator> Module::extensions() { 247 return make_range(extensions_); 248 } 249 250 inline IteratorRange<Module::const_inst_iterator> Module::extensions() const { 251 return make_const_range(extensions_); 252 } 253 254 inline Module::inst_iterator Module::types_values_begin() { 255 return inst_iterator(&types_values_, types_values_.begin()); 256 } 257 258 inline Module::inst_iterator Module::types_values_end() { 259 return inst_iterator(&types_values_, types_values_.end()); 260 } 261 262 inline IteratorRange<Module::inst_iterator> Module::types_values() { 263 return make_range(types_values_); 264 } 265 266 inline IteratorRange<Module::const_inst_iterator> Module::types_values() const { 267 return make_const_range(types_values_); 268 } 269 270 inline Module::const_iterator Module::cbegin() const { 271 return const_iterator(&functions_, functions_.cbegin()); 272 } 273 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