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