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 SOURCE_VAL_VALIDATION_STATE_H_ 16 #define SOURCE_VAL_VALIDATION_STATE_H_ 17 18 #include <algorithm> 19 #include <map> 20 #include <set> 21 #include <string> 22 #include <tuple> 23 #include <unordered_map> 24 #include <unordered_set> 25 #include <vector> 26 27 #include "source/assembly_grammar.h" 28 #include "source/diagnostic.h" 29 #include "source/disassemble.h" 30 #include "source/enum_set.h" 31 #include "source/latest_version_spirv_header.h" 32 #include "source/name_mapper.h" 33 #include "source/spirv_definition.h" 34 #include "source/spirv_validator_options.h" 35 #include "source/val/decoration.h" 36 #include "source/val/function.h" 37 #include "source/val/instruction.h" 38 #include "spirv-tools/libspirv.h" 39 40 namespace spvtools { 41 namespace val { 42 43 /// This enum represents the sections of a SPIRV module. See section 2.4 44 /// of the SPIRV spec for additional details of the order. The enumerant values 45 /// are in the same order as the vector returned by GetModuleOrder 46 enum ModuleLayoutSection { 47 kLayoutCapabilities, /// < Section 2.4 #1 48 kLayoutExtensions, /// < Section 2.4 #2 49 kLayoutExtInstImport, /// < Section 2.4 #3 50 kLayoutMemoryModel, /// < Section 2.4 #4 51 kLayoutSamplerImageAddressMode, /// < Section 2.4 #5 52 kLayoutEntryPoint, /// < Section 2.4 #6 53 kLayoutExecutionMode, /// < Section 2.4 #7 54 kLayoutDebug1, /// < Section 2.4 #8 > 1 55 kLayoutDebug2, /// < Section 2.4 #8 > 2 56 kLayoutDebug3, /// < Section 2.4 #8 > 3 57 kLayoutAnnotations, /// < Section 2.4 #9 58 kLayoutTypes, /// < Section 2.4 #10 59 kLayoutFunctionDeclarations, /// < Section 2.4 #11 60 kLayoutFunctionDefinitions /// < Section 2.4 #12 61 }; 62 63 /// This class manages the state of the SPIR-V validation as it is being parsed. 64 class ValidationState_t { 65 public: 66 // Features that can optionally be turned on by a capability or environment. 67 struct Feature { 68 bool declare_int16_type = false; // Allow OpTypeInt with 16 bit width? 69 bool declare_float16_type = false; // Allow OpTypeFloat with 16 bit width? 70 bool free_fp_rounding_mode = false; // Allow the FPRoundingMode decoration 71 // and its values to be used without 72 // requiring any capability 73 74 // Allow functionalities enabled by VariablePointers or 75 // VariablePointersStorageBuffer capability. 76 bool variable_pointers = false; 77 78 // Permit group oerations Reduce, InclusiveScan, ExclusiveScan 79 bool group_ops_reduce_and_scans = false; 80 81 // Allow OpTypeInt with 8 bit width? 82 bool declare_int8_type = false; 83 84 // Target environment uses relaxed block layout. 85 // This is true for Vulkan 1.1 or later. 86 bool env_relaxed_block_layout = false; 87 88 // Allow an OpTypeInt with 8 bit width to be used in more than just int 89 // conversion opcodes 90 bool use_int8_type = false; 91 92 // SPIR-V 1.4 allows us to select between any two composite values 93 // of the same type. 94 bool select_between_composites = false; 95 96 // SPIR-V 1.4 allows two memory access operands for OpCopyMemory and 97 // OpCopyMemorySized. 98 bool copy_memory_permits_two_memory_accesses = false; 99 100 // SPIR-V 1.4 allows UConvert as a spec constant op in any environment. 101 // The Kernel capability already enables it, separately from this flag. 102 bool uconvert_spec_constant_op = false; 103 104 // SPIR-V 1.4 allows Function and Private variables to be NonWritable 105 bool nonwritable_var_in_function_or_private = false; 106 107 // Whether LocalSizeId execution mode is allowed by the environment. 108 bool env_allow_localsizeid = false; 109 }; 110 111 ValidationState_t(const spv_const_context context, 112 const spv_const_validator_options opt, 113 const uint32_t* words, const size_t num_words, 114 const uint32_t max_warnings); 115 116 /// Returns the context context()117 spv_const_context context() const { return context_; } 118 119 /// Returns the command line options options()120 spv_const_validator_options options() const { return options_; } 121 122 /// Sets the ID of the generator for this module. setGenerator(uint32_t gen)123 void setGenerator(uint32_t gen) { generator_ = gen; } 124 125 /// Returns the ID of the generator for this module. generator()126 uint32_t generator() const { return generator_; } 127 128 /// Sets the SPIR-V version of this module. setVersion(uint32_t ver)129 void setVersion(uint32_t ver) { version_ = ver; } 130 131 /// Gets the SPIR-V version of this module. version()132 uint32_t version() const { return version_; } 133 134 /// Forward declares the id in the module 135 spv_result_t ForwardDeclareId(uint32_t id); 136 137 /// Removes a forward declared ID if it has been defined 138 spv_result_t RemoveIfForwardDeclared(uint32_t id); 139 140 /// Registers an ID as a forward pointer 141 spv_result_t RegisterForwardPointer(uint32_t id); 142 143 /// Returns whether or not an ID is a forward pointer 144 bool IsForwardPointer(uint32_t id) const; 145 146 /// Assigns a name to an ID 147 void AssignNameToId(uint32_t id, std::string name); 148 149 /// Returns a string representation of the ID in the format <id>[Name] where 150 /// the <id> is the numeric valid of the id and the Name is a name assigned by 151 /// the OpName instruction 152 std::string getIdName(uint32_t id) const; 153 154 /// Accessor function for ID bound. 155 uint32_t getIdBound() const; 156 157 /// Mutator function for ID bound. 158 void setIdBound(uint32_t bound); 159 160 /// Returns the number of ID which have been forward referenced but not 161 /// defined 162 size_t unresolved_forward_id_count() const; 163 164 /// Returns a vector of unresolved forward ids. 165 std::vector<uint32_t> UnresolvedForwardIds() const; 166 167 /// Returns true if the id has been defined 168 bool IsDefinedId(uint32_t id) const; 169 170 /// Increments the total number of instructions in the file. increment_total_instructions()171 void increment_total_instructions() { total_instructions_++; } 172 173 /// Increments the total number of functions in the file. increment_total_functions()174 void increment_total_functions() { total_functions_++; } 175 176 /// Allocates internal storage. Note, calling this will invalidate any 177 /// pointers to |ordered_instructions_| or |module_functions_| and, hence, 178 /// should only be called at the beginning of validation. 179 void preallocateStorage(); 180 181 /// Returns the current layout section which is being processed 182 ModuleLayoutSection current_layout_section() const; 183 184 /// Increments the module_layout_order_section_ 185 void ProgressToNextLayoutSectionOrder(); 186 187 /// Determines if the op instruction is in a previous layout section 188 bool IsOpcodeInPreviousLayoutSection(spv::Op op); 189 190 /// Determines if the op instruction is part of the current section 191 bool IsOpcodeInCurrentLayoutSection(spv::Op op); 192 193 DiagnosticStream diag(spv_result_t error_code, const Instruction* inst); 194 195 /// Returns the function states 196 std::vector<Function>& functions(); 197 198 /// Returns the function states 199 Function& current_function(); 200 const Function& current_function() const; 201 202 /// Returns function state with the given id, or nullptr if no such function. 203 const Function* function(uint32_t id) const; 204 Function* function(uint32_t id); 205 206 /// Returns true if the called after a function instruction but before the 207 /// function end instruction 208 bool in_function_body() const; 209 210 /// Returns true if called after a label instruction but before a branch 211 /// instruction 212 bool in_block() const; 213 214 struct EntryPointDescription { 215 std::string name; 216 std::vector<uint32_t> interfaces; 217 }; 218 219 /// Registers |id| as an entry point with |execution_model| and |interfaces|. RegisterEntryPoint(const uint32_t id,spv::ExecutionModel execution_model,EntryPointDescription && desc)220 void RegisterEntryPoint(const uint32_t id, 221 spv::ExecutionModel execution_model, 222 EntryPointDescription&& desc) { 223 entry_points_.push_back(id); 224 entry_point_to_execution_models_[id].insert(execution_model); 225 entry_point_descriptions_[id].emplace_back(desc); 226 } 227 228 /// Returns a list of entry point function ids entry_points()229 const std::vector<uint32_t>& entry_points() const { return entry_points_; } 230 231 /// Returns the set of entry points that root call graphs that contain 232 /// recursion. recursive_entry_points()233 const std::set<uint32_t>& recursive_entry_points() const { 234 return recursive_entry_points_; 235 } 236 237 /// Registers execution mode for the given entry point. RegisterExecutionModeForEntryPoint(uint32_t entry_point,spv::ExecutionMode execution_mode)238 void RegisterExecutionModeForEntryPoint(uint32_t entry_point, 239 spv::ExecutionMode execution_mode) { 240 entry_point_to_execution_modes_[entry_point].insert(execution_mode); 241 } 242 243 /// Registers that the entry point declares its local size RegisterEntryPointLocalSize(uint32_t entry_point,const Instruction * inst)244 void RegisterEntryPointLocalSize(uint32_t entry_point, 245 const Instruction* inst) { 246 entry_point_to_local_size_or_id_[entry_point] = inst; 247 } 248 /// Returns whether the entry point declares its local size EntryPointHasLocalSizeOrId(uint32_t entry_point)249 bool EntryPointHasLocalSizeOrId(uint32_t entry_point) const { 250 return entry_point_to_local_size_or_id_.find(entry_point) != 251 entry_point_to_local_size_or_id_.end(); 252 } 253 /// Returns the id of the local size EntryPointLocalSizeOrId(uint32_t entry_point)254 const Instruction* EntryPointLocalSizeOrId(uint32_t entry_point) const { 255 return entry_point_to_local_size_or_id_.find(entry_point)->second; 256 } 257 258 /// Returns the interface descriptions of a given entry point. entry_point_descriptions(uint32_t entry_point)259 const std::vector<EntryPointDescription>& entry_point_descriptions( 260 uint32_t entry_point) { 261 return entry_point_descriptions_.at(entry_point); 262 } 263 264 /// Returns Execution Models for the given Entry Point. 265 /// Returns nullptr if none found (would trigger assertion). GetExecutionModels(uint32_t entry_point)266 const std::set<spv::ExecutionModel>* GetExecutionModels( 267 uint32_t entry_point) const { 268 const auto it = entry_point_to_execution_models_.find(entry_point); 269 if (it == entry_point_to_execution_models_.end()) { 270 assert(0); 271 return nullptr; 272 } 273 return &it->second; 274 } 275 276 /// Returns Execution Modes for the given Entry Point. 277 /// Returns nullptr if none found. GetExecutionModes(uint32_t entry_point)278 const std::set<spv::ExecutionMode>* GetExecutionModes( 279 uint32_t entry_point) const { 280 const auto it = entry_point_to_execution_modes_.find(entry_point); 281 if (it == entry_point_to_execution_modes_.end()) { 282 return nullptr; 283 } 284 return &it->second; 285 } 286 287 /// Traverses call tree and computes function_to_entry_points_. 288 /// Note: called after fully parsing the binary. 289 void ComputeFunctionToEntryPointMapping(); 290 291 /// Traverse call tree and computes recursive_entry_points_. 292 /// Note: called after fully parsing the binary and calling 293 /// ComputeFunctionToEntryPointMapping. 294 void ComputeRecursiveEntryPoints(); 295 296 /// Returns all the entry points that can call |func|. 297 const std::vector<uint32_t>& FunctionEntryPoints(uint32_t func) const; 298 299 /// Returns all the entry points that statically use |id|. 300 /// 301 /// Note: requires ComputeFunctionToEntryPointMapping to have been called. 302 std::set<uint32_t> EntryPointReferences(uint32_t id) const; 303 304 /// Inserts an <id> to the set of functions that are target of OpFunctionCall. AddFunctionCallTarget(const uint32_t id)305 void AddFunctionCallTarget(const uint32_t id) { 306 function_call_targets_.insert(id); 307 current_function().AddFunctionCallTarget(id); 308 } 309 310 /// Returns whether or not a function<id> is the target of OpFunctionCall. IsFunctionCallTarget(const uint32_t id)311 bool IsFunctionCallTarget(const uint32_t id) { 312 return (function_call_targets_.find(id) != function_call_targets_.end()); 313 } 314 IsFunctionCallDefined(const uint32_t id)315 bool IsFunctionCallDefined(const uint32_t id) { 316 return (id_to_function_.find(id) != id_to_function_.end()); 317 } 318 /// Registers the capability and its dependent capabilities 319 void RegisterCapability(spv::Capability cap); 320 321 /// Registers the extension. 322 void RegisterExtension(Extension ext); 323 324 /// Registers the function in the module. Subsequent instructions will be 325 /// called against this function 326 spv_result_t RegisterFunction(uint32_t id, uint32_t ret_type_id, 327 spv::FunctionControlMask function_control, 328 uint32_t function_type_id); 329 330 /// Register a function end instruction 331 spv_result_t RegisterFunctionEnd(); 332 333 /// Returns true if the capability is enabled in the module. HasCapability(spv::Capability cap)334 bool HasCapability(spv::Capability cap) const { 335 return module_capabilities_.contains(cap); 336 } 337 338 /// Returns a reference to the set of capabilities in the module. 339 /// This is provided for debuggability. module_capabilities()340 const CapabilitySet& module_capabilities() const { 341 return module_capabilities_; 342 } 343 344 /// Returns true if the extension is enabled in the module. HasExtension(Extension ext)345 bool HasExtension(Extension ext) const { 346 return module_extensions_.contains(ext); 347 } 348 349 /// Returns true if any of the capabilities is enabled, or if |capabilities| 350 /// is an empty set. 351 bool HasAnyOfCapabilities(const CapabilitySet& capabilities) const; 352 353 /// Returns true if any of the extensions is enabled, or if |extensions| 354 /// is an empty set. 355 bool HasAnyOfExtensions(const ExtensionSet& extensions) const; 356 357 /// Sets the addressing model of this module (logical/physical). 358 void set_addressing_model(spv::AddressingModel am); 359 360 /// Returns true if the OpMemoryModel was found. has_memory_model_specified()361 bool has_memory_model_specified() const { 362 return addressing_model_ != spv::AddressingModel::Max && 363 memory_model_ != spv::MemoryModel::Max; 364 } 365 366 /// Returns the addressing model of this module, or Logical if uninitialized. 367 spv::AddressingModel addressing_model() const; 368 369 /// Returns the addressing model of this module, or Logical if uninitialized. pointer_size_and_alignment()370 uint32_t pointer_size_and_alignment() const { 371 return pointer_size_and_alignment_; 372 } 373 374 /// Sets the memory model of this module. 375 void set_memory_model(spv::MemoryModel mm); 376 377 /// Returns the memory model of this module, or Simple if uninitialized. 378 spv::MemoryModel memory_model() const; 379 380 /// Sets the bit width for sampler/image type variables. If not set, they are 381 /// considered opaque 382 void set_samplerimage_variable_address_mode(uint32_t bit_width); 383 384 /// Get the addressing mode currently set. If 0, it means addressing mode is 385 /// invalid Sampler/Image type variables must be considered opaque This mode 386 /// is only valid after the instruction has been read 387 uint32_t samplerimage_variable_address_mode() const; 388 389 /// Returns true if the OpSamplerImageAddressingModeNV was found. has_samplerimage_variable_address_mode_specified()390 bool has_samplerimage_variable_address_mode_specified() const { 391 return sampler_image_addressing_mode_ != 0; 392 } 393 grammar()394 const AssemblyGrammar& grammar() const { return grammar_; } 395 396 /// Inserts the instruction into the list of ordered instructions in the file. 397 Instruction* AddOrderedInstruction(const spv_parsed_instruction_t* inst); 398 399 /// Registers the instruction. This will add the instruction to the list of 400 /// definitions and register sampled image consumers. 401 void RegisterInstruction(Instruction* inst); 402 403 /// Registers the debug instruction information. 404 void RegisterDebugInstruction(const Instruction* inst); 405 406 /// Registers the decoration for the given <id> RegisterDecorationForId(uint32_t id,const Decoration & dec)407 void RegisterDecorationForId(uint32_t id, const Decoration& dec) { 408 auto& dec_list = id_decorations_[id]; 409 dec_list.insert(dec); 410 } 411 412 /// Registers the list of decorations for the given <id> 413 template <class InputIt> RegisterDecorationsForId(uint32_t id,InputIt begin,InputIt end)414 void RegisterDecorationsForId(uint32_t id, InputIt begin, InputIt end) { 415 std::set<Decoration>& cur_decs = id_decorations_[id]; 416 cur_decs.insert(begin, end); 417 } 418 419 /// Registers the list of decorations for the given member of the given 420 /// structure. 421 template <class InputIt> RegisterDecorationsForStructMember(uint32_t struct_id,uint32_t member_index,InputIt begin,InputIt end)422 void RegisterDecorationsForStructMember(uint32_t struct_id, 423 uint32_t member_index, InputIt begin, 424 InputIt end) { 425 std::set<Decoration>& cur_decs = id_decorations_[struct_id]; 426 for (InputIt iter = begin; iter != end; ++iter) { 427 Decoration dec = *iter; 428 dec.set_struct_member_index(member_index); 429 cur_decs.insert(dec); 430 } 431 } 432 433 /// Returns all the decorations for the given <id>. If no decorations exist 434 /// for the <id>, it registers an empty set for it in the map and 435 /// returns the empty set. id_decorations(uint32_t id)436 std::set<Decoration>& id_decorations(uint32_t id) { 437 return id_decorations_[id]; 438 } 439 440 /// Returns the range of decorations for the given field of the given <id>. 441 struct FieldDecorationsIter { 442 std::set<Decoration>::const_iterator begin; 443 std::set<Decoration>::const_iterator end; 444 }; id_member_decorations(uint32_t id,uint32_t member_index)445 FieldDecorationsIter id_member_decorations(uint32_t id, 446 uint32_t member_index) { 447 const auto& decorations = id_decorations_[id]; 448 449 // The decorations are sorted by member_index, so this look up will give the 450 // exact range of decorations for this member index. 451 Decoration min_decoration((spv::Decoration)0, {}, member_index); 452 Decoration max_decoration(spv::Decoration::Max, {}, member_index); 453 454 FieldDecorationsIter result; 455 result.begin = decorations.lower_bound(min_decoration); 456 result.end = decorations.upper_bound(max_decoration); 457 458 return result; 459 } 460 461 // Returns const pointer to the internal decoration container. id_decorations()462 const std::map<uint32_t, std::set<Decoration>>& id_decorations() const { 463 return id_decorations_; 464 } 465 466 /// Returns true if the given id <id> has the given decoration <dec>, 467 /// otherwise returns false. HasDecoration(uint32_t id,spv::Decoration dec)468 bool HasDecoration(uint32_t id, spv::Decoration dec) { 469 const auto& decorations = id_decorations_.find(id); 470 if (decorations == id_decorations_.end()) return false; 471 472 return std::any_of( 473 decorations->second.begin(), decorations->second.end(), 474 [dec](const Decoration& d) { return dec == d.dec_type(); }); 475 } 476 477 /// Finds id's def, if it exists. If found, returns the definition otherwise 478 /// nullptr 479 const Instruction* FindDef(uint32_t id) const; 480 481 /// Finds id's def, if it exists. If found, returns the definition otherwise 482 /// nullptr 483 Instruction* FindDef(uint32_t id); 484 485 /// Returns the instructions in the order they appear in the binary ordered_instructions()486 const std::vector<Instruction>& ordered_instructions() const { 487 return ordered_instructions_; 488 } 489 490 /// Returns a map of instructions mapped by their result id all_definitions()491 const std::unordered_map<uint32_t, Instruction*>& all_definitions() const { 492 return all_definitions_; 493 } 494 495 /// Returns a vector containing the instructions that consume the given 496 /// SampledImage id. 497 std::vector<Instruction*> getSampledImageConsumers(uint32_t id) const; 498 499 /// Records cons_id as a consumer of sampled_image_id. 500 void RegisterSampledImageConsumer(uint32_t sampled_image_id, 501 Instruction* consumer); 502 503 // Record a cons_id as a consumer of texture_id 504 // if texture 'texture_id' has a QCOM image processing decoration 505 // and consumer is a load or a sampled image instruction 506 void RegisterQCOMImageProcessingTextureConsumer(uint32_t texture_id, 507 const Instruction* consumer0, 508 const Instruction* consumer1); 509 510 // Record a function's storage class consumer instruction 511 void RegisterStorageClassConsumer(spv::StorageClass storage_class, 512 Instruction* consumer); 513 514 /// Returns the set of Global Variables. global_vars()515 std::unordered_set<uint32_t>& global_vars() { return global_vars_; } 516 517 /// Returns the set of Local Variables. local_vars()518 std::unordered_set<uint32_t>& local_vars() { return local_vars_; } 519 520 /// Returns the number of Global Variables. num_global_vars()521 size_t num_global_vars() { return global_vars_.size(); } 522 523 /// Returns the number of Local Variables. num_local_vars()524 size_t num_local_vars() { return local_vars_.size(); } 525 526 /// Inserts a new <id> to the set of Global Variables. registerGlobalVariable(const uint32_t id)527 void registerGlobalVariable(const uint32_t id) { global_vars_.insert(id); } 528 529 /// Inserts a new <id> to the set of Local Variables. registerLocalVariable(const uint32_t id)530 void registerLocalVariable(const uint32_t id) { local_vars_.insert(id); } 531 532 // Returns true if using relaxed block layout, equivalent to 533 // VK_KHR_relaxed_block_layout. IsRelaxedBlockLayout()534 bool IsRelaxedBlockLayout() const { 535 return features_.env_relaxed_block_layout || options()->relax_block_layout; 536 } 537 538 // Returns true if allowing localsizeid, either because the environment always 539 // allows it, or because it is enabled from the command-line. IsLocalSizeIdAllowed()540 bool IsLocalSizeIdAllowed() const { 541 return features_.env_allow_localsizeid || options()->allow_localsizeid; 542 } 543 544 /// Sets the struct nesting depth for a given struct ID set_struct_nesting_depth(uint32_t id,uint32_t depth)545 void set_struct_nesting_depth(uint32_t id, uint32_t depth) { 546 struct_nesting_depth_[id] = depth; 547 } 548 549 /// Returns the nesting depth of a given structure ID struct_nesting_depth(uint32_t id)550 uint32_t struct_nesting_depth(uint32_t id) { 551 return struct_nesting_depth_[id]; 552 } 553 554 /// Records the has a nested block/bufferblock decorated struct for a given 555 /// struct ID SetHasNestedBlockOrBufferBlockStruct(uint32_t id,bool has)556 void SetHasNestedBlockOrBufferBlockStruct(uint32_t id, bool has) { 557 struct_has_nested_blockorbufferblock_struct_[id] = has; 558 } 559 560 /// For a given struct ID returns true if it has a nested block/bufferblock 561 /// decorated struct GetHasNestedBlockOrBufferBlockStruct(uint32_t id)562 bool GetHasNestedBlockOrBufferBlockStruct(uint32_t id) { 563 return struct_has_nested_blockorbufferblock_struct_[id]; 564 } 565 566 /// Records that the structure type has a member decorated with a built-in. RegisterStructTypeWithBuiltInMember(uint32_t id)567 void RegisterStructTypeWithBuiltInMember(uint32_t id) { 568 builtin_structs_.insert(id); 569 } 570 571 /// Returns true if the struct type with the given Id has a BuiltIn member. IsStructTypeWithBuiltInMember(uint32_t id)572 bool IsStructTypeWithBuiltInMember(uint32_t id) const { 573 return (builtin_structs_.find(id) != builtin_structs_.end()); 574 } 575 576 // Returns the state of optional features. features()577 const Feature& features() const { return features_; } 578 579 /// Adds the instruction data to unique_type_declarations_. 580 /// Returns false if an identical type declaration already exists. 581 bool RegisterUniqueTypeDeclaration(const Instruction* inst); 582 583 // Returns type_id of the scalar component of |id|. 584 // |id| can be either 585 // - scalar, vector or matrix type 586 // - object of either scalar, vector or matrix type 587 uint32_t GetComponentType(uint32_t id) const; 588 589 // Returns 590 // - 1 for scalar types or objects 591 // - vector size for vector types or objects 592 // - num columns for matrix types or objects 593 // Should not be called with any other arguments (will return zero and invoke 594 // assertion). 595 uint32_t GetDimension(uint32_t id) const; 596 597 // Returns bit width of scalar or component. 598 // |id| can be 599 // - scalar, vector or matrix type 600 // - object of either scalar, vector or matrix type 601 // Will invoke assertion and return 0 if |id| is none of the above. 602 uint32_t GetBitWidth(uint32_t id) const; 603 604 // Provides detailed information on matrix type. 605 // Returns false iff |id| is not matrix type. 606 bool GetMatrixTypeInfo(uint32_t id, uint32_t* num_rows, uint32_t* num_cols, 607 uint32_t* column_type, uint32_t* component_type) const; 608 609 // Collects struct member types into |member_types|. 610 // Returns false iff not struct type or has no members. 611 // Deletes prior contents of |member_types|. 612 bool GetStructMemberTypes(uint32_t struct_type_id, 613 std::vector<uint32_t>* member_types) const; 614 615 // Returns true iff |id| is a type corresponding to the name of the function. 616 // Only works for types not for objects. 617 bool IsVoidType(uint32_t id) const; 618 bool IsFloatScalarType(uint32_t id) const; 619 bool IsFloatVectorType(uint32_t id) const; 620 bool IsFloat16Vector2Or4Type(uint32_t id) const; 621 bool IsFloatScalarOrVectorType(uint32_t id) const; 622 bool IsFloatMatrixType(uint32_t id) const; 623 bool IsIntScalarType(uint32_t id) const; 624 bool IsIntArrayType(uint32_t id) const; 625 bool IsIntVectorType(uint32_t id) const; 626 bool IsIntScalarOrVectorType(uint32_t id) const; 627 bool IsUnsignedIntScalarType(uint32_t id) const; 628 bool IsUnsignedIntVectorType(uint32_t id) const; 629 bool IsUnsignedIntScalarOrVectorType(uint32_t id) const; 630 bool IsSignedIntScalarType(uint32_t id) const; 631 bool IsSignedIntVectorType(uint32_t id) const; 632 bool IsBoolScalarType(uint32_t id) const; 633 bool IsBoolVectorType(uint32_t id) const; 634 bool IsBoolScalarOrVectorType(uint32_t id) const; 635 bool IsPointerType(uint32_t id) const; 636 bool IsAccelerationStructureType(uint32_t id) const; 637 bool IsCooperativeMatrixType(uint32_t id) const; 638 bool IsCooperativeMatrixNVType(uint32_t id) const; 639 bool IsCooperativeMatrixKHRType(uint32_t id) const; 640 bool IsCooperativeMatrixAType(uint32_t id) const; 641 bool IsCooperativeMatrixBType(uint32_t id) const; 642 bool IsCooperativeMatrixAccType(uint32_t id) const; 643 bool IsFloatCooperativeMatrixType(uint32_t id) const; 644 bool IsIntCooperativeMatrixType(uint32_t id) const; 645 bool IsUnsignedIntCooperativeMatrixType(uint32_t id) const; 646 bool IsUnsigned64BitHandle(uint32_t id) const; 647 648 // Returns true if |id| is a type id that contains |type| (or integer or 649 // floating point type) of |width| bits. 650 bool ContainsSizedIntOrFloatType(uint32_t id, spv::Op type, 651 uint32_t width) const; 652 // Returns true if |id| is a type id that contains a 8- or 16-bit int or 653 // 16-bit float that is not generally enabled for use. 654 bool ContainsLimitedUseIntOrFloatType(uint32_t id) const; 655 656 // Returns true if |id| is a type that contains a runtime-sized array. 657 // Does not consider a pointers as contains the array. 658 bool ContainsRuntimeArray(uint32_t id) const; 659 660 // Generic type traversal. 661 // Only traverse pointers and functions if |traverse_all_types| is true. 662 // Recursively tests |f| against the type hierarchy headed by |id|. 663 bool ContainsType(uint32_t id, 664 const std::function<bool(const Instruction*)>& f, 665 bool traverse_all_types = true) const; 666 667 // Returns true if |id| is type id that contains an untyped pointer. 668 bool ContainsUntypedPointer(uint32_t id) const; 669 670 // Returns type_id if id has type or zero otherwise. 671 uint32_t GetTypeId(uint32_t id) const; 672 673 // Returns opcode of the instruction which issued the id or OpNop if the 674 // instruction is not registered. 675 spv::Op GetIdOpcode(uint32_t id) const; 676 677 // Returns type_id for given id operand if it has a type or zero otherwise. 678 // |operand_index| is expected to be pointing towards an operand which is an 679 // id. 680 uint32_t GetOperandTypeId(const Instruction* inst, 681 size_t operand_index) const; 682 683 // Provides information on pointer type. Returns false iff not pointer type. 684 bool GetPointerTypeInfo(uint32_t id, uint32_t* data_type, 685 spv::StorageClass* storage_class) const; 686 687 // Is the ID the type of a pointer to a uniform block: Block-decorated struct 688 // in uniform storage class? The result is only valid after internal method 689 // CheckDecorationsOfBuffers has been called. IsPointerToUniformBlock(uint32_t type_id)690 bool IsPointerToUniformBlock(uint32_t type_id) const { 691 return pointer_to_uniform_block_.find(type_id) != 692 pointer_to_uniform_block_.cend(); 693 } 694 // Save the ID of a pointer to uniform block. RegisterPointerToUniformBlock(uint32_t type_id)695 void RegisterPointerToUniformBlock(uint32_t type_id) { 696 pointer_to_uniform_block_.insert(type_id); 697 } 698 // Is the ID the type of a struct used as a uniform block? 699 // The result is only valid after internal method CheckDecorationsOfBuffers 700 // has been called. IsStructForUniformBlock(uint32_t type_id)701 bool IsStructForUniformBlock(uint32_t type_id) const { 702 return struct_for_uniform_block_.find(type_id) != 703 struct_for_uniform_block_.cend(); 704 } 705 // Save the ID of a struct of a uniform block. RegisterStructForUniformBlock(uint32_t type_id)706 void RegisterStructForUniformBlock(uint32_t type_id) { 707 struct_for_uniform_block_.insert(type_id); 708 } 709 // Is the ID the type of a pointer to a storage buffer: BufferBlock-decorated 710 // struct in uniform storage class, or Block-decorated struct in StorageBuffer 711 // storage class? The result is only valid after internal method 712 // CheckDecorationsOfBuffers has been called. IsPointerToStorageBuffer(uint32_t type_id)713 bool IsPointerToStorageBuffer(uint32_t type_id) const { 714 return pointer_to_storage_buffer_.find(type_id) != 715 pointer_to_storage_buffer_.cend(); 716 } 717 // Save the ID of a pointer to a storage buffer. RegisterPointerToStorageBuffer(uint32_t type_id)718 void RegisterPointerToStorageBuffer(uint32_t type_id) { 719 pointer_to_storage_buffer_.insert(type_id); 720 } 721 // Is the ID the type of a struct for storage buffer? 722 // The result is only valid after internal method CheckDecorationsOfBuffers 723 // has been called. IsStructForStorageBuffer(uint32_t type_id)724 bool IsStructForStorageBuffer(uint32_t type_id) const { 725 return struct_for_storage_buffer_.find(type_id) != 726 struct_for_storage_buffer_.cend(); 727 } 728 // Save the ID of a struct of a storage buffer. RegisterStructForStorageBuffer(uint32_t type_id)729 void RegisterStructForStorageBuffer(uint32_t type_id) { 730 struct_for_storage_buffer_.insert(type_id); 731 } 732 733 // Is the ID the type of a pointer to a storage image? That is, the pointee 734 // type is an image type which is known to not use a sampler. IsPointerToStorageImage(uint32_t type_id)735 bool IsPointerToStorageImage(uint32_t type_id) const { 736 return pointer_to_storage_image_.find(type_id) != 737 pointer_to_storage_image_.cend(); 738 } 739 // Save the ID of a pointer to a storage image. RegisterPointerToStorageImage(uint32_t type_id)740 void RegisterPointerToStorageImage(uint32_t type_id) { 741 pointer_to_storage_image_.insert(type_id); 742 } 743 744 // Tries to evaluate a any scalar integer OpConstant as uint64. 745 // OpConstantNull is defined as zero for scalar int (will return true) 746 // OpSpecConstant* return false since their values cannot be relied upon 747 // during validation. 748 bool EvalConstantValUint64(uint32_t id, uint64_t* val) const; 749 // Same as EvalConstantValUint64 but returns a signed int 750 bool EvalConstantValInt64(uint32_t id, int64_t* val) const; 751 752 // Tries to evaluate a 32-bit signed or unsigned scalar integer constant. 753 // Returns tuple <is_int32, is_const_int32, value>. 754 // OpSpecConstant* return |is_const_int32| as false since their values cannot 755 // be relied upon during validation. 756 std::tuple<bool, bool, uint32_t> EvalInt32IfConst(uint32_t id) const; 757 758 // Returns the disassembly string for the given instruction. 759 std::string Disassemble(const Instruction& inst) const; 760 761 // Returns the disassembly string for the given instruction. 762 std::string Disassemble(const uint32_t* words, uint16_t num_words) const; 763 764 // Returns the string name for |decoration|. SpvDecorationString(uint32_t decoration)765 std::string SpvDecorationString(uint32_t decoration) { 766 spv_operand_desc desc = nullptr; 767 if (grammar_.lookupOperand(SPV_OPERAND_TYPE_DECORATION, decoration, 768 &desc) != SPV_SUCCESS) { 769 return std::string("Unknown"); 770 } 771 return std::string(desc->name); 772 } SpvDecorationString(spv::Decoration decoration)773 std::string SpvDecorationString(spv::Decoration decoration) { 774 return SpvDecorationString(uint32_t(decoration)); 775 } 776 777 // Returns whether type result_type_id and type m2 are cooperative matrices 778 // with the same "shape" (matching scope, rows, cols). If any are 779 // specialization constants, we assume they can match because we can't prove 780 // they don't. 781 spv_result_t CooperativeMatrixShapesMatch(const Instruction* inst, 782 uint32_t result_type_id, 783 uint32_t m2, bool is_conversion, 784 bool swap_row_col = false); 785 786 // Returns true if |lhs| and |rhs| logically match and, if the decorations of 787 // |rhs| are a subset of |lhs|. 788 // 789 // 1. Must both be either OpTypeArray or OpTypeStruct 790 // 2. If OpTypeArray, then 791 // * Length must be the same 792 // * Element type must match or logically match 793 // 3. If OpTypeStruct, then 794 // * Both have same number of elements 795 // * Element N for both structs must match or logically match 796 // 797 // If |check_decorations| is false, then the decorations are not checked. 798 bool LogicallyMatch(const Instruction* lhs, const Instruction* rhs, 799 bool check_decorations); 800 801 // Traces |inst| to find a single base pointer. Returns the base pointer. 802 // Will trace through the following instructions: 803 // * OpAccessChain 804 // * OpInBoundsAccessChain 805 // * OpPtrAccessChain 806 // * OpInBoundsPtrAccessChain 807 // * OpCopyObject 808 const Instruction* TracePointer(const Instruction* inst) const; 809 810 // Validates the storage class for the target environment. 811 bool IsValidStorageClass(spv::StorageClass storage_class) const; 812 813 // Takes a Vulkan Valid Usage ID (VUID) as |id| and optional |reference| and 814 // will return a non-empty string only if ID is known and targeting Vulkan. 815 // VUIDs are found in the Vulkan-Docs repo in the form "[[VUID-ref-ref-id]]" 816 // where "id" is always an 5 char long number (with zeros padding) and matches 817 // to |id|. |reference| is used if there is a "common validity" and the VUID 818 // shares the same |id| value. 819 // 820 // More details about Vulkan validation can be found in Vulkan Guide: 821 // https://github.com/KhronosGroup/Vulkan-Guide/blob/master/chapters/validation_overview.md 822 std::string VkErrorID(uint32_t id, const char* reference = nullptr) const; 823 824 // Testing method to allow setting the current layout section. SetCurrentLayoutSectionForTesting(ModuleLayoutSection section)825 void SetCurrentLayoutSectionForTesting(ModuleLayoutSection section) { 826 current_layout_section_ = section; 827 } 828 829 // Check if instruction 'id' is a consumer of a texture decorated 830 // with a QCOM image processing decoration IsQCOMImageProcessingTextureConsumer(uint32_t id)831 bool IsQCOMImageProcessingTextureConsumer(uint32_t id) { 832 return qcom_image_processing_consumers_.find(id) != 833 qcom_image_processing_consumers_.end(); 834 } 835 836 private: 837 ValidationState_t(const ValidationState_t&); 838 839 const spv_const_context context_; 840 841 /// Stores the Validator command line options. Must be a valid options object. 842 const spv_const_validator_options options_; 843 844 /// The SPIR-V binary module we're validating. 845 const uint32_t* words_; 846 const size_t num_words_; 847 848 /// The generator of the SPIR-V. 849 uint32_t generator_ = 0; 850 851 /// The version of the SPIR-V. 852 uint32_t version_ = 0; 853 854 /// The total number of instructions in the binary. 855 size_t total_instructions_ = 0; 856 /// The total number of functions in the binary. 857 size_t total_functions_ = 0; 858 859 /// IDs which have been forward declared but have not been defined 860 std::unordered_set<uint32_t> unresolved_forward_ids_; 861 862 /// IDs that have been declared as forward pointers. 863 std::unordered_set<uint32_t> forward_pointer_ids_; 864 865 /// Stores a vector of instructions that use the result of a given 866 /// OpSampledImage instruction. 867 std::unordered_map<uint32_t, std::vector<Instruction*>> 868 sampled_image_consumers_; 869 870 /// Stores load instructions that load textures used 871 // in QCOM image processing functions 872 std::unordered_set<uint32_t> qcom_image_processing_consumers_; 873 874 /// A map of operand IDs and their names defined by the OpName instruction 875 std::unordered_map<uint32_t, std::string> operand_names_; 876 877 /// The section of the code being processed 878 ModuleLayoutSection current_layout_section_; 879 880 /// A list of functions in the module. 881 /// Pointers to objects in this container are guaranteed to be stable and 882 /// valid until the end of lifetime of the validation state. 883 std::vector<Function> module_functions_; 884 885 /// Capabilities declared in the module 886 CapabilitySet module_capabilities_; 887 888 /// Extensions declared in the module 889 ExtensionSet module_extensions_; 890 891 /// List of all instructions in the order they appear in the binary 892 std::vector<Instruction> ordered_instructions_; 893 894 /// Instructions that can be referenced by Ids 895 std::unordered_map<uint32_t, Instruction*> all_definitions_; 896 897 /// IDs that are entry points, ie, arguments to OpEntryPoint. 898 std::vector<uint32_t> entry_points_; 899 900 /// Maps an entry point id to its descriptions. 901 std::unordered_map<uint32_t, std::vector<EntryPointDescription>> 902 entry_point_descriptions_; 903 904 /// IDs that are entry points, ie, arguments to OpEntryPoint, and root a call 905 /// graph that recurses. 906 std::set<uint32_t> recursive_entry_points_; 907 908 /// Functions IDs that are target of OpFunctionCall. 909 std::unordered_set<uint32_t> function_call_targets_; 910 911 /// ID Bound from the Header 912 uint32_t id_bound_; 913 914 /// Set of Global Variable IDs (Storage Class other than 'Function') 915 std::unordered_set<uint32_t> global_vars_; 916 917 /// Set of Local Variable IDs ('Function' Storage Class) 918 std::unordered_set<uint32_t> local_vars_; 919 920 /// Set of struct types that have members with a BuiltIn decoration. 921 std::unordered_set<uint32_t> builtin_structs_; 922 923 /// Structure Nesting Depth 924 std::unordered_map<uint32_t, uint32_t> struct_nesting_depth_; 925 926 /// Structure has nested blockorbufferblock struct 927 std::unordered_map<uint32_t, bool> 928 struct_has_nested_blockorbufferblock_struct_; 929 930 /// Stores the list of decorations for a given <id> 931 std::map<uint32_t, std::set<Decoration>> id_decorations_; 932 933 /// Stores type declarations which need to be unique (i.e. non-aggregates), 934 /// in the form [opcode, operand words], result_id is not stored. 935 /// Using ordered set to avoid the need for a vector hash function. 936 /// The size of this container is expected not to exceed double-digits. 937 std::set<std::vector<uint32_t>> unique_type_declarations_; 938 939 AssemblyGrammar grammar_; 940 941 spv::AddressingModel addressing_model_; 942 spv::MemoryModel memory_model_; 943 // pointer size derived from addressing model. Assumes all storage classes 944 // have the same pointer size (for physical pointer types). 945 uint32_t pointer_size_and_alignment_; 946 947 /// bit width of sampler/image type variables. Valid values are 32 and 64 948 uint32_t sampler_image_addressing_mode_; 949 950 /// NOTE: See correspoding getter functions 951 bool in_function_; 952 953 /// The state of optional features. These are determined by capabilities 954 /// declared by the module and the environment. 955 Feature features_; 956 957 /// Maps function ids to function stat objects. 958 std::unordered_map<uint32_t, Function*> id_to_function_; 959 960 /// Mapping entry point -> execution models. It is presumed that the same 961 /// function could theoretically be used as 'main' by multiple OpEntryPoint 962 /// instructions. 963 std::unordered_map<uint32_t, std::set<spv::ExecutionModel>> 964 entry_point_to_execution_models_; 965 966 /// Mapping entry point -> execution modes. 967 std::unordered_map<uint32_t, std::set<spv::ExecutionMode>> 968 entry_point_to_execution_modes_; 969 970 // Mapping entry point -> local size execution mode instruction 971 std::unordered_map<uint32_t, const Instruction*> 972 entry_point_to_local_size_or_id_; 973 974 /// Mapping function -> array of entry points inside this 975 /// module which can (indirectly) call the function. 976 std::unordered_map<uint32_t, std::vector<uint32_t>> function_to_entry_points_; 977 const std::vector<uint32_t> empty_ids_; 978 979 // The IDs of types of pointers to Block-decorated structs in Uniform storage 980 // class. This is populated at the start of ValidateDecorations. 981 std::unordered_set<uint32_t> pointer_to_uniform_block_; 982 // The IDs of struct types for uniform blocks. 983 // This is populated at the start of ValidateDecorations. 984 std::unordered_set<uint32_t> struct_for_uniform_block_; 985 // The IDs of types of pointers to BufferBlock-decorated structs in Uniform 986 // storage class, or Block-decorated structs in StorageBuffer storage class. 987 // This is populated at the start of ValidateDecorations. 988 std::unordered_set<uint32_t> pointer_to_storage_buffer_; 989 // The IDs of struct types for storage buffers. 990 // This is populated at the start of ValidateDecorations. 991 std::unordered_set<uint32_t> struct_for_storage_buffer_; 992 // The IDs of types of pointers to storage images. This is populated in the 993 // TypePass. 994 std::unordered_set<uint32_t> pointer_to_storage_image_; 995 996 /// Maps ids to friendly names. 997 std::unique_ptr<spvtools::FriendlyNameMapper> friendly_mapper_; 998 spvtools::NameMapper name_mapper_; 999 1000 /// Variables used to reduce the number of diagnostic messages. 1001 uint32_t num_of_warnings_; 1002 uint32_t max_num_of_warnings_; 1003 }; 1004 1005 } // namespace val 1006 } // namespace spvtools 1007 1008 #endif // SOURCE_VAL_VALIDATION_STATE_H_ 1009