1 // Copyright (c) 2015-2016 The Khronos Group 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_VAL_VALIDATIONSTATE_H_ 16 #define LIBSPIRV_VAL_VALIDATIONSTATE_H_ 17 18 #include <deque> 19 #include <set> 20 #include <string> 21 #include <unordered_map> 22 #include <unordered_set> 23 #include <vector> 24 25 #include "assembly_grammar.h" 26 #include "decoration.h" 27 #include "diagnostic.h" 28 #include "enum_set.h" 29 #include "spirv-tools/libspirv.h" 30 #include "spirv/1.2/spirv.h" 31 #include "spirv_definition.h" 32 #include "val/function.h" 33 #include "val/instruction.h" 34 35 namespace libspirv { 36 37 /// This enum represents the sections of a SPIRV module. See section 2.4 38 /// of the SPIRV spec for additional details of the order. The enumerant values 39 /// are in the same order as the vector returned by GetModuleOrder 40 enum ModuleLayoutSection { 41 kLayoutCapabilities, /// < Section 2.4 #1 42 kLayoutExtensions, /// < Section 2.4 #2 43 kLayoutExtInstImport, /// < Section 2.4 #3 44 kLayoutMemoryModel, /// < Section 2.4 #4 45 kLayoutEntryPoint, /// < Section 2.4 #5 46 kLayoutExecutionMode, /// < Section 2.4 #6 47 kLayoutDebug1, /// < Section 2.4 #7 > 1 48 kLayoutDebug2, /// < Section 2.4 #7 > 2 49 kLayoutAnnotations, /// < Section 2.4 #8 50 kLayoutTypes, /// < Section 2.4 #9 51 kLayoutFunctionDeclarations, /// < Section 2.4 #10 52 kLayoutFunctionDefinitions /// < Section 2.4 #11 53 }; 54 55 /// This class manages the state of the SPIR-V validation as it is being parsed. 56 class ValidationState_t { 57 public: 58 // Features that can optionally be turned on by a capability. 59 struct Feature { 60 bool declare_int16_type = false; // Allow OpTypeInt with 16 bit width? 61 bool declare_float16_type = false; // Allow OpTypeFloat with 16 bit width? 62 bool free_fp_rounding_mode = false; // Allow the FPRoundingMode decoration 63 // and its vaules to be used without 64 // requiring any capability 65 66 // Allow functionalities enabled by VariablePointers capability. 67 bool variable_pointers = false; 68 // Allow functionalities enabled by VariablePointersStorageBuffer 69 // capability. 70 bool variable_pointers_storage_buffer = false; 71 }; 72 73 ValidationState_t(const spv_const_context context, 74 const spv_const_validator_options opt); 75 76 /// Returns the context 77 spv_const_context context() const { return context_; } 78 79 /// Returns the command line options 80 spv_const_validator_options options() const { return options_; } 81 82 /// Forward declares the id in the module 83 spv_result_t ForwardDeclareId(uint32_t id); 84 85 /// Removes a forward declared ID if it has been defined 86 spv_result_t RemoveIfForwardDeclared(uint32_t id); 87 88 /// Registers an ID as a forward pointer 89 spv_result_t RegisterForwardPointer(uint32_t id); 90 91 /// Returns whether or not an ID is a forward pointer 92 bool IsForwardPointer(uint32_t id) const; 93 94 /// Assigns a name to an ID 95 void AssignNameToId(uint32_t id, std::string name); 96 97 /// Returns a string representation of the ID in the format <id>[Name] where 98 /// the <id> is the numeric valid of the id and the Name is a name assigned by 99 /// the OpName instruction 100 std::string getIdName(uint32_t id) const; 101 102 /// Accessor function for ID bound. 103 uint32_t getIdBound() const; 104 105 /// Mutator function for ID bound. 106 void setIdBound(uint32_t bound); 107 108 /// Like getIdName but does not display the id if the \p id has a name 109 std::string getIdOrName(uint32_t id) const; 110 111 /// Returns the number of ID which have been forward referenced but not 112 /// defined 113 size_t unresolved_forward_id_count() const; 114 115 /// Returns a vector of unresolved forward ids. 116 std::vector<uint32_t> UnresolvedForwardIds() const; 117 118 /// Returns true if the id has been defined 119 bool IsDefinedId(uint32_t id) const; 120 121 /// Increments the instruction count. Used for diagnostic 122 int increment_instruction_count(); 123 124 /// Returns the current layout section which is being processed 125 ModuleLayoutSection current_layout_section() const; 126 127 /// Increments the module_layout_order_section_ 128 void ProgressToNextLayoutSectionOrder(); 129 130 /// Determines if the op instruction is part of the current section 131 bool IsOpcodeInCurrentLayoutSection(SpvOp op); 132 133 libspirv::DiagnosticStream diag(spv_result_t error_code) const; 134 135 /// Returns the function states 136 std::deque<Function>& functions(); 137 138 /// Returns the function states 139 Function& current_function(); 140 141 /// Returns true if the called after a function instruction but before the 142 /// function end instruction 143 bool in_function_body() const; 144 145 /// Returns true if called after a label instruction but before a branch 146 /// instruction 147 bool in_block() const; 148 149 /// Registers the given <id> as an Entry Point. 150 void RegisterEntryPointId(const uint32_t id) { 151 entry_points_.push_back(id); 152 entry_point_interfaces_.insert(std::make_pair(id, std::vector<uint32_t>())); 153 } 154 155 /// Returns a list of entry point function ids 156 const std::vector<uint32_t>& entry_points() const { return entry_points_; } 157 158 /// Adds a new interface id to the interfaces of the given entry point. 159 void RegisterInterfaceForEntryPoint(uint32_t entry_point, 160 uint32_t interface) { 161 entry_point_interfaces_[entry_point].push_back(interface); 162 } 163 164 /// Returns the interfaces of a given entry point. If the given id is not a 165 /// valid Entry Point id, std::out_of_range exception is thrown. 166 const std::vector<uint32_t>& entry_point_interfaces( 167 uint32_t entry_point) const { 168 return entry_point_interfaces_.at(entry_point); 169 } 170 171 /// Inserts an <id> to the set of functions that are target of OpFunctionCall. 172 void AddFunctionCallTarget(const uint32_t id) { 173 function_call_targets_.insert(id); 174 } 175 176 /// Returns whether or not a function<id> is the target of OpFunctionCall. 177 bool IsFunctionCallTarget(const uint32_t id) { 178 return (function_call_targets_.find(id) != function_call_targets_.end()); 179 } 180 181 /// Registers the capability and its dependent capabilities 182 void RegisterCapability(SpvCapability cap); 183 184 /// Registers the extension. 185 void RegisterExtension(Extension ext); 186 187 /// Registers the function in the module. Subsequent instructions will be 188 /// called against this function 189 spv_result_t RegisterFunction(uint32_t id, uint32_t ret_type_id, 190 SpvFunctionControlMask function_control, 191 uint32_t function_type_id); 192 193 /// Register a function end instruction 194 spv_result_t RegisterFunctionEnd(); 195 196 /// Returns true if the capability is enabled in the module. 197 bool HasCapability(SpvCapability cap) const { 198 return module_capabilities_.Contains(cap); 199 } 200 201 /// Returns true if the extension is enabled in the module. 202 bool HasExtension(Extension ext) const { 203 return module_extensions_.Contains(ext); 204 } 205 206 /// Returns true if any of the capabilities is enabled, or if |capabilities| 207 /// is an empty set. 208 bool HasAnyOfCapabilities(const libspirv::CapabilitySet& capabilities) const; 209 210 /// Returns true if any of the extensions is enabled, or if |extensions| 211 /// is an empty set. 212 bool HasAnyOfExtensions(const libspirv::ExtensionSet& extensions) const; 213 214 /// Sets the addressing model of this module (logical/physical). 215 void set_addressing_model(SpvAddressingModel am); 216 217 /// Returns the addressing model of this module, or Logical if uninitialized. 218 SpvAddressingModel addressing_model() const; 219 220 /// Sets the memory model of this module. 221 void set_memory_model(SpvMemoryModel mm); 222 223 /// Returns the memory model of this module, or Simple if uninitialized. 224 SpvMemoryModel memory_model() const; 225 226 const AssemblyGrammar& grammar() const { return grammar_; } 227 228 /// Registers the instruction 229 void RegisterInstruction(const spv_parsed_instruction_t& inst); 230 231 /// Registers the decoration for the given <id> 232 void RegisterDecorationForId(uint32_t id, const Decoration& dec) { 233 id_decorations_[id].push_back(dec); 234 } 235 236 /// Registers the list of decorations for the given <id> 237 template <class InputIt> 238 void RegisterDecorationsForId(uint32_t id, InputIt begin, InputIt end) { 239 std::vector<Decoration>& cur_decs = id_decorations_[id]; 240 cur_decs.insert(cur_decs.end(), begin, end); 241 } 242 243 /// Registers the list of decorations for the given member of the given 244 /// structure. 245 template <class InputIt> 246 void RegisterDecorationsForStructMember(uint32_t struct_id, 247 uint32_t member_index, InputIt begin, 248 InputIt end) { 249 RegisterDecorationsForId(struct_id, begin, end); 250 for (auto& decoration : id_decorations_[struct_id]) { 251 decoration.set_struct_member_index(member_index); 252 } 253 } 254 255 /// Returns all the decorations for the given <id>. If no decorations exist 256 /// for the <id>, it registers an empty vector for it in the map and 257 /// returns the empty vector. 258 std::vector<Decoration>& id_decorations(uint32_t id) { 259 return id_decorations_[id]; 260 } 261 262 /// Finds id's def, if it exists. If found, returns the definition otherwise 263 /// nullptr 264 const Instruction* FindDef(uint32_t id) const; 265 266 /// Finds id's def, if it exists. If found, returns the definition otherwise 267 /// nullptr 268 Instruction* FindDef(uint32_t id); 269 270 /// Returns a deque of instructions in the order they appear in the binary 271 const std::deque<Instruction>& ordered_instructions() const { 272 return ordered_instructions_; 273 } 274 275 /// Returns a map of instructions mapped by their result id 276 const std::unordered_map<uint32_t, Instruction*>& all_definitions() const { 277 return all_definitions_; 278 } 279 280 /// Returns a vector containing the Ids of instructions that consume the given 281 /// SampledImage id. 282 std::vector<uint32_t> getSampledImageConsumers(uint32_t id) const; 283 284 /// Records cons_id as a consumer of sampled_image_id. 285 void RegisterSampledImageConsumer(uint32_t sampled_image_id, 286 uint32_t cons_id); 287 288 /// Returns the set of Global Variables. 289 std::unordered_set<uint32_t>& global_vars() { return global_vars_; } 290 291 /// Returns the set of Local Variables. 292 std::unordered_set<uint32_t>& local_vars() { return local_vars_; } 293 294 /// Returns the number of Global Variables. 295 size_t num_global_vars() { return global_vars_.size(); } 296 297 /// Returns the number of Local Variables. 298 size_t num_local_vars() { return local_vars_.size(); } 299 300 /// Inserts a new <id> to the set of Global Variables. 301 void registerGlobalVariable(const uint32_t id) { global_vars_.insert(id); } 302 303 /// Inserts a new <id> to the set of Local Variables. 304 void registerLocalVariable(const uint32_t id) { local_vars_.insert(id); } 305 306 /// Sets the struct nesting depth for a given struct ID 307 void set_struct_nesting_depth(uint32_t id, uint32_t depth) { 308 struct_nesting_depth_[id] = depth; 309 } 310 311 /// Returns the nesting depth of a given structure ID 312 uint32_t struct_nesting_depth(uint32_t id) { 313 return struct_nesting_depth_[id]; 314 } 315 316 /// Records that the structure type has a member decorated with a built-in. 317 void RegisterStructTypeWithBuiltInMember(uint32_t id) { 318 builtin_structs_.insert(id); 319 } 320 321 /// Returns true if the struct type with the given Id has a BuiltIn member. 322 bool IsStructTypeWithBuiltInMember(uint32_t id) const { 323 return (builtin_structs_.find(id) != builtin_structs_.end()); 324 } 325 326 // Returns the state of optional features. 327 const Feature& features() const { return features_; } 328 329 /// Adds the instruction data to unique_type_declarations_. 330 /// Returns false if an identical type declaration already exists. 331 bool RegisterUniqueTypeDeclaration(const spv_parsed_instruction_t& inst); 332 333 private: 334 ValidationState_t(const ValidationState_t&); 335 336 const spv_const_context context_; 337 338 /// Stores the Validator command line options. Must be a valid options object. 339 const spv_const_validator_options options_; 340 341 /// Tracks the number of instructions evaluated by the validator 342 int instruction_counter_; 343 344 /// IDs which have been forward declared but have not been defined 345 std::unordered_set<uint32_t> unresolved_forward_ids_; 346 347 /// IDs that have been declared as forward pointers. 348 std::unordered_set<uint32_t> forward_pointer_ids_; 349 350 /// Stores a vector of instructions that use the result of a given 351 /// OpSampledImage instruction. 352 std::unordered_map<uint32_t, std::vector<uint32_t>> sampled_image_consumers_; 353 354 /// A map of operand IDs and their names defined by the OpName instruction 355 std::unordered_map<uint32_t, std::string> operand_names_; 356 357 /// The section of the code being processed 358 ModuleLayoutSection current_layout_section_; 359 360 /// A list of functions in the module 361 std::deque<Function> module_functions_; 362 363 /// Capabilities declared in the module 364 libspirv::CapabilitySet module_capabilities_; 365 366 /// Extensions declared in the module 367 libspirv::ExtensionSet module_extensions_; 368 369 /// List of all instructions in the order they appear in the binary 370 std::deque<Instruction> ordered_instructions_; 371 372 /// Instructions that can be referenced by Ids 373 std::unordered_map<uint32_t, Instruction*> all_definitions_; 374 375 /// IDs that are entry points, ie, arguments to OpEntryPoint. 376 std::vector<uint32_t> entry_points_; 377 378 /// Maps an entry point id to its interfaces. 379 std::unordered_map<uint32_t, std::vector<uint32_t>> entry_point_interfaces_; 380 381 /// Functions IDs that are target of OpFunctionCall. 382 std::unordered_set<uint32_t> function_call_targets_; 383 384 /// ID Bound from the Header 385 uint32_t id_bound_; 386 387 /// Set of Global Variable IDs (Storage Class other than 'Function') 388 std::unordered_set<uint32_t> global_vars_; 389 390 /// Set of Local Variable IDs ('Function' Storage Class) 391 std::unordered_set<uint32_t> local_vars_; 392 393 /// Set of struct types that have members with a BuiltIn decoration. 394 std::unordered_set<uint32_t> builtin_structs_; 395 396 /// Structure Nesting Depth 397 std::unordered_map<uint32_t, uint32_t> struct_nesting_depth_; 398 399 /// Stores the list of decorations for a given <id> 400 std::unordered_map<uint32_t, std::vector<Decoration>> id_decorations_; 401 402 /// Stores type declarations which need to be unique (i.e. non-aggregates), 403 /// in the form [opcode, operand words], result_id is not stored. 404 /// Using ordered set to avoid the need for a vector hash function. 405 /// The size of this container is expected not to exceed double-digits. 406 std::set<std::vector<uint32_t>> unique_type_declarations_; 407 408 AssemblyGrammar grammar_; 409 410 SpvAddressingModel addressing_model_; 411 SpvMemoryModel memory_model_; 412 413 /// NOTE: See correspoding getter functions 414 bool in_function_; 415 416 // The state of optional features. These are determined by capabilities 417 // declared by the module. 418 Feature features_; 419 }; 420 421 } /// namespace libspirv 422 423 #endif /// LIBSPIRV_VAL_VALIDATIONSTATE_H_ 424