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