/src/spirv-tools/source/val/validation_state.h
Line | Count | Source |
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/table2.h" |
36 | | #include "source/val/decoration.h" |
37 | | #include "source/val/function.h" |
38 | | #include "source/val/instruction.h" |
39 | | #include "spirv-tools/libspirv.h" |
40 | | |
41 | | namespace spvtools { |
42 | | namespace val { |
43 | | |
44 | | /// This enum represents the sections of a SPIRV module. See section 2.4 |
45 | | /// of the SPIRV spec for additional details of the order. The enumerant values |
46 | | /// are in the same order as the vector returned by GetModuleOrder |
47 | | enum ModuleLayoutSection { |
48 | | kLayoutCapabilities, /// < Section 2.4 #1 |
49 | | kLayoutExtensions, /// < Section 2.4 #2 |
50 | | kLayoutExtInstImport, /// < Section 2.4 #3 |
51 | | kLayoutMemoryModel, /// < Section 2.4 #4 |
52 | | kLayoutSamplerImageAddressMode, /// < Section 2.4 #5 |
53 | | /// (SPV_NV_bindless_texture) |
54 | | kLayoutEntryPoint, /// < Section 2.4 #6 |
55 | | kLayoutExecutionMode, /// < Section 2.4 #7 |
56 | | kLayoutDebug1, /// < Section 2.4 #8 > 1 |
57 | | kLayoutDebug2, /// < Section 2.4 #8 > 2 |
58 | | kLayoutDebug3, /// < Section 2.4 #8 > 3 |
59 | | kLayoutAnnotations, /// < Section 2.4 #9 |
60 | | kLayoutTypes, /// < Section 2.4 #10 |
61 | | kLayoutFunctionDeclarations, /// < Section 2.4 #11 |
62 | | kLayoutFunctionDefinitions, /// < Section 2.4 #12 |
63 | | kLayoutGraphDefinitions /// < Section 2.4 #13 (SPV_ARM_graph) |
64 | | }; |
65 | | |
66 | | /// This enum represents the regions of a graph definition. The relative |
67 | | /// ordering of the values is significant. |
68 | | enum GraphDefinitionRegion { |
69 | | kGraphDefinitionOutside, |
70 | | kGraphDefinitionBegin, |
71 | | kGraphDefinitionInputs, |
72 | | kGraphDefinitionBody, |
73 | | kGraphDefinitionOutputs, |
74 | | }; |
75 | | |
76 | | /// This class manages the state of the SPIR-V validation as it is being parsed. |
77 | | class ValidationState_t { |
78 | | public: |
79 | | // Features that can optionally be turned on by a capability or environment. |
80 | | struct Feature { |
81 | | bool declare_int16_type = false; // Allow OpTypeInt with 16 bit width? |
82 | | bool declare_float16_type = false; // Allow OpTypeFloat with 16 bit width? |
83 | | bool declare_float8_type = false; // Allow OpTypeFloat with 8 bit width? |
84 | | bool free_fp_rounding_mode = false; // Allow the FPRoundingMode decoration |
85 | | // and its values to be used without |
86 | | // requiring any capability |
87 | | |
88 | | // Allow functionalities enabled by VariablePointers or |
89 | | // VariablePointersStorageBuffer capability. |
90 | | bool variable_pointers = false; |
91 | | |
92 | | // Permit group oerations Reduce, InclusiveScan, ExclusiveScan |
93 | | bool group_ops_reduce_and_scans = false; |
94 | | |
95 | | // Allow OpTypeInt with 8 bit width? |
96 | | bool declare_int8_type = false; |
97 | | |
98 | | // Target environment uses relaxed block layout. |
99 | | // This is true for Vulkan 1.1 or later. |
100 | | bool env_relaxed_block_layout = false; |
101 | | |
102 | | // Allow an OpTypeInt with 8 bit width to be used in more than just int |
103 | | // conversion opcodes |
104 | | bool use_int8_type = 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 | | // Whether LocalSizeId execution mode is allowed by the environment. |
122 | | bool env_allow_localsizeid = false; |
123 | | }; |
124 | | |
125 | | ValidationState_t(const spv_const_context context, |
126 | | const spv_const_validator_options opt, |
127 | | const uint32_t* words, const size_t num_words, |
128 | | const uint32_t max_warnings); |
129 | | |
130 | | /// Returns the context |
131 | 19.3M | spv_const_context context() const { return context_; } |
132 | | |
133 | | /// Returns the command line options |
134 | 1.46M | spv_const_validator_options options() const { return options_; } |
135 | | |
136 | | /// Sets the ID of the generator for this module. |
137 | 56.3k | void setGenerator(uint32_t gen) { generator_ = gen; } |
138 | | |
139 | | /// Returns the ID of the generator for this module. |
140 | 0 | uint32_t generator() const { return generator_; } |
141 | | |
142 | | /// Sets the SPIR-V version of this module. |
143 | 56.3k | void setVersion(uint32_t ver) { version_ = ver; } |
144 | | |
145 | | /// Gets the SPIR-V version of this module. |
146 | 16.7M | uint32_t version() const { return version_; } |
147 | | |
148 | | /// Forward declares the id in the module |
149 | | spv_result_t ForwardDeclareId(uint32_t id); |
150 | | |
151 | | /// Removes a forward declared ID if it has been defined |
152 | | spv_result_t RemoveIfForwardDeclared(uint32_t id); |
153 | | |
154 | | /// Registers an ID as a forward pointer |
155 | | spv_result_t RegisterForwardPointer(uint32_t id); |
156 | | |
157 | | /// Returns whether or not an ID is a forward pointer |
158 | | bool IsForwardPointer(uint32_t id) const; |
159 | | |
160 | | /// Assigns a name to an ID |
161 | | void AssignNameToId(uint32_t id, std::string name); |
162 | | |
163 | | /// Returns a string representation of the ID in the format <id>[Name] where |
164 | | /// the <id> is the numeric valid of the id and the Name is a name assigned by |
165 | | /// the OpName instruction |
166 | | std::string getIdName(uint32_t id) const; |
167 | | |
168 | | /// Accessor function for ID bound. |
169 | | uint32_t getIdBound() const; |
170 | | |
171 | | /// Mutator function for ID bound. |
172 | | void setIdBound(uint32_t bound); |
173 | | |
174 | | /// Returns the number of ID which have been forward referenced but not |
175 | | /// defined |
176 | | size_t unresolved_forward_id_count() const; |
177 | | |
178 | | /// Returns a vector of unresolved forward ids. |
179 | | std::vector<uint32_t> UnresolvedForwardIds() const; |
180 | | |
181 | | /// Returns true if the id has been defined |
182 | | bool IsDefinedId(uint32_t id) const; |
183 | | |
184 | | /// Increments the total number of instructions in the file. |
185 | 15.6M | void increment_total_instructions() { total_instructions_++; } |
186 | | |
187 | | /// Increments the total number of functions in the file. |
188 | 54.7k | void increment_total_functions() { total_functions_++; } |
189 | | |
190 | | /// Allocates internal storage. Note, calling this will invalidate any |
191 | | /// pointers to |ordered_instructions_| or |module_functions_| and, hence, |
192 | | /// should only be called at the beginning of validation. |
193 | | void preallocateStorage(); |
194 | | |
195 | | /// Returns the current layout section which is being processed |
196 | | ModuleLayoutSection current_layout_section() const; |
197 | | |
198 | | /// Increments the module_layout_order_section_ |
199 | | void ProgressToNextLayoutSectionOrder(); |
200 | | |
201 | | /// Determines if the op instruction is in a previous layout section |
202 | | bool IsOpcodeInPreviousLayoutSection(spv::Op op); |
203 | | |
204 | | /// Determines if the op instruction is part of the current section |
205 | | bool IsOpcodeInCurrentLayoutSection(spv::Op op); |
206 | | |
207 | | DiagnosticStream diag(spv_result_t error_code, const Instruction* inst); |
208 | | |
209 | | /// Returns the function states |
210 | | std::vector<Function>& functions(); |
211 | | |
212 | | /// Returns the function states |
213 | | Function& current_function(); |
214 | | const Function& current_function() const; |
215 | | |
216 | | /// Returns function state with the given id, or nullptr if no such function. |
217 | | const Function* function(uint32_t id) const; |
218 | | Function* function(uint32_t id); |
219 | | |
220 | | /// Returns true if the called after a function instruction but before the |
221 | | /// function end instruction |
222 | | bool in_function_body() const; |
223 | | |
224 | | /// Returns true if called after a label instruction but before a branch |
225 | | /// instruction |
226 | | bool in_block() const; |
227 | | |
228 | | /// Returns the region of a graph definition we are in. |
229 | | GraphDefinitionRegion graph_definition_region() const; |
230 | | |
231 | | struct EntryPointDescription { |
232 | | std::string name; |
233 | | std::vector<uint32_t> interfaces; |
234 | | }; |
235 | | |
236 | | /// Registers |id| as an entry point with |execution_model| and |interfaces|. |
237 | | void RegisterEntryPoint(const uint32_t id, |
238 | | spv::ExecutionModel execution_model, |
239 | 30.3k | EntryPointDescription&& desc) { |
240 | 30.3k | entry_points_.push_back(id); |
241 | 30.3k | entry_point_to_execution_models_[id].insert(execution_model); |
242 | 30.3k | entry_point_descriptions_[id].emplace_back(desc); |
243 | 30.3k | } |
244 | | |
245 | | /// Returns a list of entry point function ids |
246 | 262k | const std::vector<uint32_t>& entry_points() const { return entry_points_; } |
247 | | |
248 | | /// Returns the set of entry points that root call graphs that contain |
249 | | /// recursion. |
250 | 0 | const std::set<uint32_t>& recursive_entry_points() const { |
251 | 0 | return recursive_entry_points_; |
252 | 0 | } |
253 | | |
254 | | /// Registers execution mode for the given entry point. |
255 | | void RegisterExecutionModeForEntryPoint(uint32_t entry_point, |
256 | 45.7k | spv::ExecutionMode execution_mode) { |
257 | 45.7k | entry_point_to_execution_modes_[entry_point].insert(execution_mode); |
258 | 45.7k | } |
259 | | |
260 | | /// Registers that the entry point declares its local size |
261 | | void RegisterEntryPointLocalSize(uint32_t entry_point, |
262 | 1.98k | const Instruction* inst) { |
263 | 1.98k | entry_point_to_local_size_or_id_[entry_point] = inst; |
264 | 1.98k | } |
265 | | |
266 | | /// Registers that the entry point maximum number of primitives |
267 | | /// mesh shader will ever emit |
268 | | void RegisterEntryPointOutputPrimitivesEXT(uint32_t entry_point, |
269 | 0 | const Instruction* inst) { |
270 | 0 | entry_point_to_output_primitives_[entry_point] = inst; |
271 | 0 | } |
272 | | |
273 | | /// Returns the maximum number of primitives mesh shader can emit |
274 | 0 | uint32_t GetOutputPrimitivesEXT(uint32_t entry_point) const { |
275 | 0 | auto entry = entry_point_to_output_primitives_.find(entry_point); |
276 | 0 | if (entry != entry_point_to_output_primitives_.end()) { |
277 | 0 | auto inst = entry->second; |
278 | 0 | return inst->GetOperandAs<uint32_t>(2); |
279 | 0 | } |
280 | 0 | return 0; |
281 | 0 | } |
282 | | |
283 | | /// Registers that the entry point maximum number of vertices |
284 | | /// mesh shader will ever emit |
285 | | void RegisterEntryPointOutputVertices(uint32_t entry_point, |
286 | 1.89k | const Instruction* inst) { |
287 | 1.89k | entry_point_to_output_vertices_[entry_point] = inst; |
288 | 1.89k | } |
289 | | |
290 | | /// Returns the maximum number of primitives mesh shader can emit |
291 | 0 | uint32_t GetOutputVertices(uint32_t entry_point) const { |
292 | 0 | auto entry = entry_point_to_output_vertices_.find(entry_point); |
293 | 0 | if (entry != entry_point_to_output_vertices_.end()) { |
294 | 0 | auto inst = entry->second; |
295 | 0 | return inst->GetOperandAs<uint32_t>(2); |
296 | 0 | } |
297 | 0 | return 0; |
298 | 0 | } |
299 | | |
300 | | /// Returns whether the entry point declares its local size |
301 | 24.1k | bool EntryPointHasLocalSizeOrId(uint32_t entry_point) const { |
302 | 24.1k | return entry_point_to_local_size_or_id_.find(entry_point) != |
303 | 24.1k | entry_point_to_local_size_or_id_.end(); |
304 | 24.1k | } |
305 | | /// Returns the id of the local size |
306 | 544 | const Instruction* EntryPointLocalSizeOrId(uint32_t entry_point) const { |
307 | 544 | return entry_point_to_local_size_or_id_.find(entry_point)->second; |
308 | 544 | } |
309 | | |
310 | | /// Returns the interface descriptions of a given entry point. |
311 | | const std::vector<EntryPointDescription>& entry_point_descriptions( |
312 | 36.1k | uint32_t entry_point) { |
313 | 36.1k | return entry_point_descriptions_.at(entry_point); |
314 | 36.1k | } |
315 | | |
316 | | /// Returns Execution Models for the given Entry Point. |
317 | | /// Returns nullptr if none found (would trigger assertion). |
318 | | const std::set<spv::ExecutionModel>* GetExecutionModels( |
319 | 66.2k | uint32_t entry_point) const { |
320 | 66.2k | const auto it = entry_point_to_execution_models_.find(entry_point); |
321 | 66.2k | if (it == entry_point_to_execution_models_.end()) { |
322 | 0 | assert(0); |
323 | 0 | return nullptr; |
324 | 0 | } |
325 | 66.2k | return &it->second; |
326 | 66.2k | } |
327 | | |
328 | | /// Returns Execution Modes for the given Entry Point. |
329 | | /// Returns nullptr if none found. |
330 | | const std::set<spv::ExecutionMode>* GetExecutionModes( |
331 | 69.1k | uint32_t entry_point) const { |
332 | 69.1k | const auto it = entry_point_to_execution_modes_.find(entry_point); |
333 | 69.1k | if (it == entry_point_to_execution_modes_.end()) { |
334 | 10.5k | return nullptr; |
335 | 10.5k | } |
336 | 58.5k | return &it->second; |
337 | 69.1k | } |
338 | | |
339 | | /// Traverses call tree and computes function_to_entry_points_. |
340 | | /// Note: called after fully parsing the binary. |
341 | | void ComputeFunctionToEntryPointMapping(); |
342 | | |
343 | | /// Traverse call tree and computes recursive_entry_points_. |
344 | | /// Note: called after fully parsing the binary and calling |
345 | | /// ComputeFunctionToEntryPointMapping. |
346 | | void ComputeRecursiveEntryPoints(); |
347 | | |
348 | | /// Registers |id| as a graph entry point. |
349 | 34 | void RegisterGraphEntryPoint(const uint32_t id) { |
350 | 34 | graph_entry_points_.push_back(id); |
351 | 34 | } |
352 | | |
353 | | /// Returns a list of graph entry point graph ids |
354 | 26.6k | const std::vector<uint32_t>& graph_entry_points() const { |
355 | 26.6k | return graph_entry_points_; |
356 | 26.6k | } |
357 | | |
358 | | /// Returns all the entry points that can call |func|. |
359 | | const std::vector<uint32_t>& FunctionEntryPoints(uint32_t func) const; |
360 | | |
361 | | /// Returns all the entry points that statically use |id|. |
362 | | /// |
363 | | /// Note: requires ComputeFunctionToEntryPointMapping to have been called. |
364 | | std::set<uint32_t> EntryPointReferences(uint32_t id) const; |
365 | | |
366 | | /// Inserts an <id> to the set of functions that are target of OpFunctionCall. |
367 | 36.2k | void AddFunctionCallTarget(const uint32_t id) { |
368 | 36.2k | function_call_targets_.insert(id); |
369 | 36.2k | current_function().AddFunctionCallTarget(id); |
370 | 36.2k | } |
371 | | |
372 | | /// Returns whether or not a function<id> is the target of OpFunctionCall. |
373 | 21.0k | bool IsFunctionCallTarget(const uint32_t id) { |
374 | 21.0k | return (function_call_targets_.find(id) != function_call_targets_.end()); |
375 | 21.0k | } |
376 | | |
377 | 0 | bool IsFunctionCallDefined(const uint32_t id) { |
378 | 0 | return (id_to_function_.find(id) != id_to_function_.end()); |
379 | 0 | } |
380 | | /// Registers the capability and its dependent capabilities |
381 | | void RegisterCapability(spv::Capability cap); |
382 | | |
383 | | /// Registers the extension. |
384 | | void RegisterExtension(Extension ext); |
385 | | |
386 | | /// Registers the function in the module. Subsequent instructions will be |
387 | | /// called against this function |
388 | | spv_result_t RegisterFunction(uint32_t id, uint32_t ret_type_id, |
389 | | spv::FunctionControlMask function_control, |
390 | | uint32_t function_type_id); |
391 | | |
392 | | /// Register a function end instruction |
393 | | spv_result_t RegisterFunctionEnd(); |
394 | | |
395 | | /// Sets the region of a graph definition we're in. |
396 | | void SetGraphDefinitionRegion(GraphDefinitionRegion region); |
397 | | |
398 | | /// Returns true if the capability is enabled in the module. |
399 | 37.9M | bool HasCapability(spv::Capability cap) const { |
400 | 37.9M | return module_capabilities_.contains(cap); |
401 | 37.9M | } |
402 | | |
403 | | /// Returns a reference to the set of capabilities in the module. |
404 | | /// This is provided for debuggability. |
405 | 0 | const CapabilitySet& module_capabilities() const { |
406 | 0 | return module_capabilities_; |
407 | 0 | } |
408 | | |
409 | | /// Returns true if the extension is enabled in the module. |
410 | 343k | bool HasExtension(Extension ext) const { |
411 | 343k | return module_extensions_.contains(ext); |
412 | 343k | } |
413 | | |
414 | | /// Returns true if any of the capabilities is enabled, or if |capabilities| |
415 | | /// is an empty set. |
416 | | bool HasAnyOfCapabilities(const CapabilitySet& capabilities) const; |
417 | | |
418 | | /// Returns true if any of the extensions is enabled, or if |extensions| |
419 | | /// is an empty set. |
420 | | bool HasAnyOfExtensions(const ExtensionSet& extensions) const; |
421 | | |
422 | | /// Sets the addressing model of this module (logical/physical). |
423 | | void set_addressing_model(spv::AddressingModel am); |
424 | | |
425 | | /// Returns true if the OpMemoryModel was found. |
426 | 88.3k | bool has_memory_model_specified() const { |
427 | 88.3k | return addressing_model_ != spv::AddressingModel::Max && |
428 | 42.3k | memory_model_ != spv::MemoryModel::Max; |
429 | 88.3k | } |
430 | | |
431 | | /// Returns the addressing model of this module, or Logical if uninitialized. |
432 | | spv::AddressingModel addressing_model() const; |
433 | | |
434 | | /// Returns the addressing model of this module, or Logical if uninitialized. |
435 | 0 | uint32_t pointer_size_and_alignment() const { |
436 | 0 | return pointer_size_and_alignment_; |
437 | 0 | } |
438 | | |
439 | | /// Sets the memory model of this module. |
440 | | void set_memory_model(spv::MemoryModel mm); |
441 | | |
442 | | /// Returns the memory model of this module, or Simple if uninitialized. |
443 | | spv::MemoryModel memory_model() const; |
444 | | |
445 | | /// Sets the bit width for sampler/image type variables. If not set, they are |
446 | | /// considered opaque |
447 | | void set_samplerimage_variable_address_mode(uint32_t bit_width); |
448 | | |
449 | | /// Get the addressing mode currently set. If 0, it means addressing mode is |
450 | | /// invalid Sampler/Image type variables must be considered opaque This mode |
451 | | /// is only valid after the instruction has been read |
452 | | uint32_t samplerimage_variable_address_mode() const; |
453 | | |
454 | | /// Returns true if the OpSamplerImageAddressingModeNV was found. |
455 | 0 | bool has_samplerimage_variable_address_mode_specified() const { |
456 | 0 | return sampler_image_addressing_mode_ != 0; |
457 | 0 | } |
458 | | |
459 | 16.6M | const AssemblyGrammar& grammar() const { return grammar_; } |
460 | | |
461 | | /// Inserts the instruction into the list of ordered instructions in the file. |
462 | | Instruction* AddOrderedInstruction(const spv_parsed_instruction_t* inst); |
463 | | |
464 | | /// Registers the instruction. This will add the instruction to the list of |
465 | | /// definitions and register sampled image consumers. |
466 | | void RegisterInstruction(Instruction* inst); |
467 | | |
468 | | /// Registers the debug instruction information. |
469 | | void RegisterDebugInstruction(const Instruction* inst); |
470 | | |
471 | | /// Registers the decoration for the given <id> |
472 | 613k | void RegisterDecorationForId(uint32_t id, const Decoration& dec) { |
473 | 613k | auto& dec_list = id_decorations_[id]; |
474 | 613k | dec_list.insert(dec); |
475 | 613k | } |
476 | | |
477 | | /// Registers the list of decorations for the given <id> |
478 | | template <class InputIt> |
479 | 17.5k | void RegisterDecorationsForId(uint32_t id, InputIt begin, InputIt end) { |
480 | 17.5k | std::set<Decoration>& cur_decs = id_decorations_[id]; |
481 | 17.5k | cur_decs.insert(begin, end); |
482 | 17.5k | } |
483 | | |
484 | | /// Registers the list of decorations for the given member of the given |
485 | | /// structure. |
486 | | template <class InputIt> |
487 | | void RegisterDecorationsForStructMember(uint32_t struct_id, |
488 | | uint32_t member_index, InputIt begin, |
489 | 7.37k | InputIt end) { |
490 | 7.37k | std::set<Decoration>& cur_decs = id_decorations_[struct_id]; |
491 | 762k | for (InputIt iter = begin; iter != end; ++iter) { |
492 | 755k | Decoration dec = *iter; |
493 | 755k | dec.set_struct_member_index(member_index); |
494 | 755k | cur_decs.insert(dec); |
495 | 755k | } |
496 | 7.37k | } |
497 | | |
498 | | /// Returns all the decorations for the given <id>. If no decorations exist |
499 | | /// for the <id>, it registers an empty set for it in the map and |
500 | | /// returns the empty set. |
501 | 10.8M | std::set<Decoration>& id_decorations(uint32_t id) { |
502 | 10.8M | return id_decorations_[id]; |
503 | 10.8M | } |
504 | | |
505 | | /// Returns the range of decorations for the given field of the given <id>. |
506 | | struct FieldDecorationsIter { |
507 | | std::set<Decoration>::const_iterator begin; |
508 | | std::set<Decoration>::const_iterator end; |
509 | | }; |
510 | | FieldDecorationsIter id_member_decorations(uint32_t id, |
511 | 11.2k | uint32_t member_index) { |
512 | 11.2k | const auto& decorations = id_decorations_[id]; |
513 | | |
514 | | // The decorations are sorted by member_index, so this look up will give the |
515 | | // exact range of decorations for this member index. |
516 | 11.2k | Decoration min_decoration((spv::Decoration)0, {}, member_index); |
517 | 11.2k | Decoration max_decoration(spv::Decoration::Max, {}, member_index); |
518 | | |
519 | 11.2k | FieldDecorationsIter result; |
520 | 11.2k | result.begin = decorations.lower_bound(min_decoration); |
521 | 11.2k | result.end = decorations.upper_bound(max_decoration); |
522 | | |
523 | 11.2k | return result; |
524 | 11.2k | } |
525 | | |
526 | | // Returns const pointer to the internal decoration container. |
527 | 46.6k | const std::map<uint32_t, std::set<Decoration>>& id_decorations() const { |
528 | 46.6k | return id_decorations_; |
529 | 46.6k | } |
530 | | |
531 | | /// Returns true if the given id <id> has the given decoration <dec>, |
532 | | /// otherwise returns false. |
533 | 1.01M | bool HasDecoration(uint32_t id, spv::Decoration dec) { |
534 | 1.01M | const auto& decorations = id_decorations_.find(id); |
535 | 1.01M | if (decorations == id_decorations_.end()) return false; |
536 | | |
537 | 173k | return std::any_of( |
538 | 173k | decorations->second.begin(), decorations->second.end(), |
539 | 2.33M | [dec](const Decoration& d) { return dec == d.dec_type(); }); |
540 | 1.01M | } |
541 | | |
542 | | /// Returns true if the given id <id> has the given built-in decoration <bt>, |
543 | | /// otherwise returns false. |
544 | 0 | bool IsBuiltin(spv::Id id, spv::BuiltIn bt) { |
545 | 0 | for (auto& dec : id_decorations(id)) { |
546 | 0 | if (dec.dec_type() == spv::Decoration::BuiltIn) { |
547 | 0 | if (dec.builtin() == bt) return true; |
548 | 0 | break; |
549 | 0 | } |
550 | 0 | } |
551 | 0 | return false; |
552 | 0 | } |
553 | | |
554 | 0 | bool ContainsBuiltin(spv::Id id, spv::BuiltIn bt) { |
555 | 0 | const auto isHeapType = [&](const Instruction* inst) { |
556 | 0 | if (HasCapability(spv::Capability::DescriptorHeapEXT) && |
557 | 0 | IsBuiltin(inst->id(), bt)) { |
558 | 0 | return true; |
559 | 0 | } |
560 | 0 | return false; |
561 | 0 | }; |
562 | 0 | return ContainsType(uint32_t(id), isHeapType); |
563 | 0 | } |
564 | | |
565 | | /// Finds id's def, if it exists. If found, returns the definition otherwise |
566 | | /// nullptr |
567 | | const Instruction* FindDef(uint32_t id) const; |
568 | | |
569 | | /// Finds id's def, if it exists. If found, returns the definition otherwise |
570 | | /// nullptr |
571 | | Instruction* FindDef(uint32_t id); |
572 | | |
573 | | /// Returns the instructions in the order they appear in the binary |
574 | 60.8M | const std::vector<Instruction>& ordered_instructions() const { |
575 | 60.8M | return ordered_instructions_; |
576 | 60.8M | } |
577 | | |
578 | | /// Returns a map of instructions mapped by their result id |
579 | 0 | const std::unordered_map<uint32_t, Instruction*>& all_definitions() const { |
580 | 0 | return all_definitions_; |
581 | 0 | } |
582 | | |
583 | | /// Returns a vector containing the instructions that consume the given |
584 | | /// SampledImage id. |
585 | | std::vector<Instruction*> getSampledImageConsumers(uint32_t id) const; |
586 | | |
587 | | /// Records cons_id as a consumer of sampled_image_id. |
588 | | void RegisterSampledImageConsumer(uint32_t sampled_image_id, |
589 | | Instruction* consumer); |
590 | | |
591 | | // Record a cons_id as a consumer of texture_id |
592 | | // if texture 'texture_id' has a QCOM image processing decoration |
593 | | // and consumer is a load or a sampled image instruction |
594 | | void RegisterQCOMImageProcessingTextureConsumer(uint32_t texture_id, |
595 | | const Instruction* consumer0, |
596 | | const Instruction* consumer1); |
597 | | |
598 | | // Record a function's storage class consumer instruction |
599 | | void RegisterStorageClassConsumer(spv::StorageClass storage_class, |
600 | | Instruction* consumer); |
601 | | |
602 | | /// Returns the set of Global Variables. |
603 | 25.0k | std::unordered_set<uint32_t>& global_vars() { return global_vars_; } |
604 | | |
605 | | /// Returns the set of Local Variables. |
606 | 0 | std::unordered_set<uint32_t>& local_vars() { return local_vars_; } |
607 | | |
608 | | /// Returns the number of Global Variables. |
609 | 58.5k | size_t num_global_vars() { return global_vars_.size(); } |
610 | | |
611 | | /// Returns the number of Local Variables. |
612 | 151k | size_t num_local_vars() { return local_vars_.size(); } |
613 | | |
614 | | /// Inserts a new <id> to the set of Global Variables. |
615 | 58.5k | void registerGlobalVariable(const uint32_t id) { global_vars_.insert(id); } |
616 | | |
617 | | /// Inserts a new <id> to the set of Local Variables. |
618 | 151k | void registerLocalVariable(const uint32_t id) { local_vars_.insert(id); } |
619 | | |
620 | | // Returns true if using relaxed block layout, equivalent to |
621 | | // VK_KHR_relaxed_block_layout. |
622 | 0 | bool IsRelaxedBlockLayout() const { |
623 | 0 | return features_.env_relaxed_block_layout || options()->relax_block_layout; |
624 | 0 | } |
625 | | |
626 | | // Returns true if allowing localsizeid, either because the environment always |
627 | | // allows it, or because it is enabled from the command-line. |
628 | 0 | bool IsLocalSizeIdAllowed() const { |
629 | 0 | return features_.env_allow_localsizeid || options()->allow_localsizeid; |
630 | 0 | } |
631 | | |
632 | | /// Sets the struct nesting depth for a given struct ID |
633 | 31.7k | void set_struct_nesting_depth(uint32_t id, uint32_t depth) { |
634 | 31.7k | struct_nesting_depth_[id] = depth; |
635 | 31.7k | } |
636 | | |
637 | | /// Returns the nesting depth of a given structure ID |
638 | 2.44k | uint32_t struct_nesting_depth(uint32_t id) { |
639 | 2.44k | return struct_nesting_depth_[id]; |
640 | 2.44k | } |
641 | | |
642 | | /// Records the has a nested block/bufferblock decorated struct for a given |
643 | | /// struct ID |
644 | 29.0k | void SetHasNestedBlockOrBufferBlockStruct(uint32_t id, bool has) { |
645 | 29.0k | struct_has_nested_blockorbufferblock_struct_[id] = has; |
646 | 29.0k | } |
647 | | |
648 | | /// For a given struct ID returns true if it has a nested block/bufferblock |
649 | | /// decorated struct |
650 | 29.0k | bool GetHasNestedBlockOrBufferBlockStruct(uint32_t id) { |
651 | 29.0k | return struct_has_nested_blockorbufferblock_struct_[id]; |
652 | 29.0k | } |
653 | | |
654 | | /// Records that the structure type has a member decorated with a built-in. |
655 | 123 | void RegisterStructTypeWithBuiltInMember(uint32_t id) { |
656 | 123 | builtin_structs_.insert(id); |
657 | 123 | } |
658 | | |
659 | | /// Returns true if the struct type with the given Id has a BuiltIn member. |
660 | 2.36k | bool IsStructTypeWithBuiltInMember(uint32_t id) const { |
661 | 2.36k | return (builtin_structs_.find(id) != builtin_structs_.end()); |
662 | 2.36k | } |
663 | | |
664 | | // Returns the state of optional features. |
665 | 1.13M | const Feature& features() const { return features_; } |
666 | | |
667 | | /// Adds the instruction data to unique_type_declarations_. |
668 | | /// Returns false if an identical type declaration already exists. |
669 | | bool RegisterUniqueTypeDeclaration(const Instruction* inst); |
670 | | |
671 | | // Returns type_id of the scalar component of |id|. |
672 | | // |id| can be either |
673 | | // - scalar, vector or matrix type |
674 | | // - object of either scalar, vector or matrix type |
675 | | uint32_t GetComponentType(uint32_t id) const; |
676 | | |
677 | | // Returns |
678 | | // - 1 for scalar types or objects |
679 | | // - vector size for vector types or objects |
680 | | // - num columns for matrix types or objects |
681 | | // Should not be called with any other arguments (will return zero and invoke |
682 | | // assertion). |
683 | | uint32_t GetDimension(uint32_t id) const; |
684 | | |
685 | | // Returns bit width of scalar or component. |
686 | | // |id| can be |
687 | | // - scalar, vector or matrix type |
688 | | // - object of either scalar, vector or matrix type |
689 | | // Will invoke assertion and return 0 if |id| is none of the above. |
690 | | uint32_t GetBitWidth(uint32_t id) const; |
691 | | |
692 | | // Provides detailed information on matrix type. |
693 | | // Returns false iff |id| is not matrix type. |
694 | | bool GetMatrixTypeInfo(uint32_t id, uint32_t* num_rows, uint32_t* num_cols, |
695 | | uint32_t* column_type, uint32_t* component_type) const; |
696 | | |
697 | | // Collects struct member types into |member_types|. |
698 | | // Returns false iff not struct type or has no members. |
699 | | // Deletes prior contents of |member_types|. |
700 | | bool GetStructMemberTypes(uint32_t struct_type_id, |
701 | | std::vector<uint32_t>* member_types) const; |
702 | | |
703 | | // Returns true if |id| is a type corresponding to the name of the function. |
704 | | // Only works for types not for objects. |
705 | | bool IsVoidType(uint32_t id) const; |
706 | | bool IsScalarType(uint32_t id) const; |
707 | | bool IsVectorType(uint32_t id) const; |
708 | | bool IsBfloat16ScalarType(uint32_t id) const; |
709 | | bool IsBfloat16VectorType(uint32_t id) const; |
710 | | bool IsBfloat16CoopMatType(uint32_t id) const; |
711 | | bool IsBfloat16Type(uint32_t id) const; |
712 | | bool IsFP8ScalarType(uint32_t id) const; |
713 | | bool IsFP8VectorType(uint32_t id) const; |
714 | | bool IsFP8CoopMatType(uint32_t id) const; |
715 | | bool IsFP8Type(uint32_t id) const; |
716 | | bool IsFloatScalarType(uint32_t id, uint32_t width = 0) const; |
717 | | bool IsFloatArrayType(uint32_t id) const; |
718 | | bool IsFloatVectorType(uint32_t id) const; |
719 | | bool IsFloat16Vector2Or4Type(uint32_t id) const; |
720 | | bool IsFloatScalarOrVectorType(uint32_t id) const; |
721 | | bool IsFloatMatrixType(uint32_t id) const; |
722 | | bool IsIntScalarType(uint32_t id, uint32_t width = 0) const; |
723 | | bool IsIntScalarTypeWithSignedness(uint32_t id, uint32_t signedness) const; |
724 | | bool IsIntVectorType(uint32_t id) const; |
725 | | bool IsIntScalarOrVectorType(uint32_t id) const; |
726 | | bool IsUnsignedIntScalarType(uint32_t id) const; |
727 | | bool IsUnsignedIntVectorType(uint32_t id) const; |
728 | | bool IsUnsignedIntScalarOrVectorType(uint32_t id) const; |
729 | | bool IsSignedIntScalarType(uint32_t id) const; |
730 | | bool IsSignedIntVectorType(uint32_t id) const; |
731 | | bool IsBoolScalarType(uint32_t id) const; |
732 | | bool IsBoolVectorType(uint32_t id) const; |
733 | | bool IsBoolScalarOrVectorType(uint32_t id) const; |
734 | | bool IsPointerType(uint32_t id) const; |
735 | | bool IsAccelerationStructureType(uint32_t id) const; |
736 | | bool IsCooperativeMatrixType(uint32_t id) const; |
737 | | bool IsCooperativeMatrixNVType(uint32_t id) const; |
738 | | bool IsCooperativeMatrixKHRType(uint32_t id) const; |
739 | | bool IsCooperativeMatrixAType(uint32_t id) const; |
740 | | bool IsCooperativeMatrixBType(uint32_t id) const; |
741 | | bool IsCooperativeMatrixAccType(uint32_t id) const; |
742 | | bool IsFloatCooperativeMatrixType(uint32_t id) const; |
743 | | bool IsIntCooperativeMatrixType(uint32_t id) const; |
744 | | bool IsUnsignedIntCooperativeMatrixType(uint32_t id) const; |
745 | | bool IsUnsigned64BitHandle(uint32_t id) const; |
746 | | bool IsCooperativeVectorNVType(uint32_t id) const; |
747 | | bool IsFloatCooperativeVectorNVType(uint32_t id) const; |
748 | | bool IsIntCooperativeVectorNVType(uint32_t id) const; |
749 | | bool IsUnsignedIntCooperativeVectorNVType(uint32_t id) const; |
750 | | bool IsTensorType(uint32_t id) const; |
751 | | bool IsDescriptorType(spv::Op opcode) const; |
752 | | bool IsDescriptorType(uint32_t id) const; |
753 | | // When |length| is not 0, return true only if the array length is equal to |
754 | | // |length| and the array length is not defined by a specialization constant. |
755 | | bool IsArrayType(uint32_t id, uint64_t length = 0) const; |
756 | | bool IsIntArrayType(uint32_t id, uint64_t length = 0) const; |
757 | | template <unsigned int N> |
758 | 0 | bool IsIntNOrFP32OrFP16(unsigned int type_id) { |
759 | 0 | return this->ContainsType( |
760 | 0 | type_id, |
761 | 0 | [](const Instruction* inst) { |
762 | 0 | if (inst->opcode() == spv::Op::OpTypeInt) { |
763 | 0 | return inst->GetOperandAs<uint32_t>(1) == N; |
764 | 0 | } else if (inst->opcode() == spv::Op::OpTypeFloat) { |
765 | 0 | if (inst->operands().size() > 2) { |
766 | | // Not IEEE |
767 | 0 | return false; |
768 | 0 | } |
769 | 0 | auto width = inst->GetOperandAs<uint32_t>(1); |
770 | 0 | return width == 32 || width == 16; |
771 | 0 | } |
772 | 0 | return false; |
773 | 0 | }, Unexecuted instantiation: spvtools::val::ValidationState_t::IsIntNOrFP32OrFP16<8u>(unsigned int)::{lambda(spvtools::val::Instruction const*)#1}::operator()(spvtools::val::Instruction const*) constUnexecuted instantiation: spvtools::val::ValidationState_t::IsIntNOrFP32OrFP16<32u>(unsigned int)::{lambda(spvtools::val::Instruction const*)#1}::operator()(spvtools::val::Instruction const*) const |
774 | 0 | /* traverse_all_types = */ false); |
775 | 0 | } Unexecuted instantiation: bool spvtools::val::ValidationState_t::IsIntNOrFP32OrFP16<8u>(unsigned int) Unexecuted instantiation: bool spvtools::val::ValidationState_t::IsIntNOrFP32OrFP16<32u>(unsigned int) |
776 | | |
777 | | // Will walk the type to find the largest scalar value size. |
778 | | // Returns value is in bytes. |
779 | | // This is designed to pass in the %type from a PSB pointer |
780 | | // %ptr = OpTypePointer PhysicalStorageBuffer %type |
781 | | uint32_t GetLargestScalarType(uint32_t id) const; |
782 | | bool IsDescriptorHeapBaseVariable(const Instruction* inst); |
783 | | const Instruction* FindUntypedBaseVariable(const Instruction* inst); |
784 | | |
785 | | // Returns true if |id| is a type id that contains |type| (or integer or |
786 | | // floating point type) of |width| bits. |
787 | | bool ContainsSizedIntOrFloatType(uint32_t id, spv::Op type, |
788 | | uint32_t width) const; |
789 | | // Returns true if |id| is a type id that contains a 8- or 16-bit int or |
790 | | // 16-bit float that is not generally enabled for use. |
791 | | bool ContainsLimitedUseIntOrFloatType(uint32_t id) const; |
792 | | |
793 | | // Returns true if |id| is a type that contains a runtime-sized array. |
794 | | // Does not consider a pointers as contains the array. |
795 | | bool ContainsRuntimeArray(uint32_t id) const; |
796 | | |
797 | | // Generic type traversal. |
798 | | // Only traverse pointers and functions if |traverse_all_types| is true. |
799 | | // Recursively tests |f| against the type hierarchy headed by |id|. |
800 | | bool ContainsType(uint32_t id, |
801 | | const std::function<bool(const Instruction*)>& f, |
802 | | bool traverse_all_types = true) const; |
803 | | |
804 | | // Returns true if |id| is type id that contains an untyped pointer. |
805 | | bool ContainsUntypedPointer(uint32_t id) const; |
806 | | |
807 | | // Returns type_id if id has type or zero otherwise. |
808 | | uint32_t GetTypeId(uint32_t id) const; |
809 | | |
810 | | // Returns opcode of the instruction which issued the id or OpNop if the |
811 | | // instruction is not registered. |
812 | | spv::Op GetIdOpcode(uint32_t id) const; |
813 | | |
814 | | // Returns type_id for given id operand if it has a type or zero otherwise. |
815 | | // |operand_index| is expected to be pointing towards an operand which is an |
816 | | // id. |
817 | | uint32_t GetOperandTypeId(const Instruction* inst, |
818 | | size_t operand_index) const; |
819 | | |
820 | | // Provides information on pointer type. Returns false iff not pointer type. |
821 | | bool GetPointerTypeInfo(uint32_t id, uint32_t* data_type, |
822 | | spv::StorageClass* storage_class) const; |
823 | | |
824 | | // Returns the value assocated with id via 'value' if id is an OpConstant |
825 | | template <typename T> |
826 | 0 | bool GetConstantValueAs(unsigned int id, T& value) { |
827 | 0 | const auto inst = FindDef(id); |
828 | 0 | uint64_t ui64_val = 0u; |
829 | 0 | bool status = (inst && spvOpcodeIsConstant(inst->opcode()) && |
830 | 0 | EvalConstantValUint64(id, &ui64_val)); |
831 | 0 | if (status == true) value = static_cast<T>(ui64_val); |
832 | 0 | return status; |
833 | 0 | } |
834 | | |
835 | | // Is the ID the type of a pointer to a uniform block: Block-decorated struct |
836 | | // in uniform storage class? The result is only valid after internal method |
837 | | // CheckDecorationsOfBuffers has been called. |
838 | 57 | bool IsPointerToUniformBlock(uint32_t type_id) const { |
839 | 57 | return pointer_to_uniform_block_.find(type_id) != |
840 | 57 | pointer_to_uniform_block_.cend(); |
841 | 57 | } |
842 | | // Save the ID of a pointer to uniform block. |
843 | 3.41k | void RegisterPointerToUniformBlock(uint32_t type_id) { |
844 | 3.41k | pointer_to_uniform_block_.insert(type_id); |
845 | 3.41k | } |
846 | | // Is the ID the type of a struct used as a uniform block? |
847 | | // The result is only valid after internal method CheckDecorationsOfBuffers |
848 | | // has been called. |
849 | 0 | bool IsStructForUniformBlock(uint32_t type_id) const { |
850 | 0 | return struct_for_uniform_block_.find(type_id) != |
851 | 0 | struct_for_uniform_block_.cend(); |
852 | 0 | } |
853 | | // Save the ID of a struct of a uniform block. |
854 | 3.41k | void RegisterStructForUniformBlock(uint32_t type_id) { |
855 | 3.41k | struct_for_uniform_block_.insert(type_id); |
856 | 3.41k | } |
857 | | // Is the ID the type of a pointer to a storage buffer: BufferBlock-decorated |
858 | | // struct in uniform storage class, or Block-decorated struct in StorageBuffer |
859 | | // storage class? The result is only valid after internal method |
860 | | // CheckDecorationsOfBuffers has been called. |
861 | 47 | bool IsPointerToStorageBuffer(uint32_t type_id) const { |
862 | 47 | return pointer_to_storage_buffer_.find(type_id) != |
863 | 47 | pointer_to_storage_buffer_.cend(); |
864 | 47 | } |
865 | | // Save the ID of a pointer to a storage buffer. |
866 | 470 | void RegisterPointerToStorageBuffer(uint32_t type_id) { |
867 | 470 | pointer_to_storage_buffer_.insert(type_id); |
868 | 470 | } |
869 | | // Is the ID the type of a struct for storage buffer? |
870 | | // The result is only valid after internal method CheckDecorationsOfBuffers |
871 | | // has been called. |
872 | 0 | bool IsStructForStorageBuffer(uint32_t type_id) const { |
873 | 0 | return struct_for_storage_buffer_.find(type_id) != |
874 | 0 | struct_for_storage_buffer_.cend(); |
875 | 0 | } |
876 | | // Save the ID of a struct of a storage buffer. |
877 | 470 | void RegisterStructForStorageBuffer(uint32_t type_id) { |
878 | 470 | struct_for_storage_buffer_.insert(type_id); |
879 | 470 | } |
880 | | |
881 | | // Is the ID the type of a pointer to a storage image? That is, the pointee |
882 | | // type is an image type which is known to not use a sampler. |
883 | 42 | bool IsPointerToStorageImage(uint32_t type_id) const { |
884 | 42 | return pointer_to_storage_image_.find(type_id) != |
885 | 42 | pointer_to_storage_image_.cend(); |
886 | 42 | } |
887 | | // Save the ID of a pointer to a storage image. |
888 | 106 | void RegisterPointerToStorageImage(uint32_t type_id) { |
889 | 106 | pointer_to_storage_image_.insert(type_id); |
890 | 106 | } |
891 | | |
892 | | // Is the ID the type of a pointer to a tensor? That is, the pointee |
893 | | // type is a tensor type. |
894 | 42 | bool IsPointerToTensor(uint32_t type_id) const { |
895 | 42 | return pointer_to_tensor_.find(type_id) != pointer_to_tensor_.cend(); |
896 | 42 | } |
897 | | // Save the ID of a pointer to a tensor. |
898 | 0 | void RegisterPointerToTensor(uint32_t type_id) { |
899 | 0 | pointer_to_tensor_.insert(type_id); |
900 | 0 | } |
901 | | |
902 | | // Tries to evaluate a any scalar integer OpConstant as uint64. |
903 | | // OpConstantNull is defined as zero for scalar int (will return true) |
904 | | // OpSpecConstant* return false since their values cannot be relied upon |
905 | | // during validation. |
906 | | bool EvalConstantValUint64(uint32_t id, uint64_t* val) const; |
907 | | // Same as EvalConstantValUint64 but returns a signed int |
908 | | bool EvalConstantValInt64(uint32_t id, int64_t* val) const; |
909 | | |
910 | | // Tries to evaluate a 32-bit signed or unsigned scalar integer constant. |
911 | | // Returns tuple <is_int32, is_const_int32, value>. |
912 | | // OpSpecConstant* return |is_const_int32| as false since their values cannot |
913 | | // be relied upon during validation. |
914 | | std::tuple<bool, bool, uint32_t> EvalInt32IfConst(uint32_t id) const; |
915 | | |
916 | | // Returns the disassembly string for the given instruction. |
917 | | std::string Disassemble(const Instruction& inst) const; |
918 | | |
919 | | // Returns the disassembly string for the given instruction. |
920 | | std::string Disassemble(const uint32_t* words, uint16_t num_words) const; |
921 | | |
922 | | // Returns the string name for |decoration|. |
923 | 1.07k | std::string SpvDecorationString(uint32_t decoration) { |
924 | 1.07k | const spvtools::OperandDesc* desc = nullptr; |
925 | 1.07k | if (spvtools::LookupOperand(SPV_OPERAND_TYPE_DECORATION, decoration, |
926 | 1.07k | &desc) != SPV_SUCCESS) { |
927 | 0 | return std::string("Unknown"); |
928 | 0 | } |
929 | 1.07k | return std::string(desc->name().data()); |
930 | 1.07k | } |
931 | 1.07k | std::string SpvDecorationString(spv::Decoration decoration) { |
932 | 1.07k | return SpvDecorationString(uint32_t(decoration)); |
933 | 1.07k | } |
934 | | |
935 | | bool CheckForceOpacityMicromap2StateKHRCapabilityRequirement( |
936 | 0 | const Instruction* inst, uint32_t flag_operand) { |
937 | 0 | bool retval = true; |
938 | 0 | uint64_t flag_val = 0; |
939 | 0 | if (EvalConstantValUint64(inst->GetOperandAs<uint32_t>(flag_operand), |
940 | 0 | &flag_val)) { |
941 | 0 | if ((flag_val & static_cast<uint64_t>( |
942 | 0 | spv::RayFlagsMask::ForceOpacityMicromap2StateKHR)) != |
943 | 0 | 0) { |
944 | 0 | assert(HasCapability(spv::Capability::RayQueryKHR) || |
945 | 0 | HasCapability(spv::Capability::RayTracingKHR)); |
946 | 0 | retval = HasCapability(spv::Capability::RayTracingOpacityMicromapKHR); |
947 | 0 | } |
948 | 0 | } |
949 | 0 | return retval; |
950 | 0 | } |
951 | | |
952 | | // Returns whether type result_type_id and type m2 are cooperative matrices |
953 | | // with the same "shape" (matching scope, rows, cols). If any are |
954 | | // specialization constants, we assume they can match because we can't prove |
955 | | // they don't. |
956 | | spv_result_t CooperativeMatrixShapesMatch(const Instruction* inst, |
957 | | uint32_t result_type_id, |
958 | | uint32_t m2, bool is_conversion, |
959 | | bool swap_row_col = false); |
960 | | |
961 | | spv_result_t CooperativeVectorDimensionsMatch(const Instruction* inst, |
962 | | uint32_t v1, uint32_t v2); |
963 | | |
964 | | // Returns true if |lhs| and |rhs| logically match and, if the decorations of |
965 | | // |rhs| are a subset of |lhs|. |
966 | | // |
967 | | // 1. Must both be either OpTypeArray or OpTypeStruct |
968 | | // 2. If OpTypeArray, then |
969 | | // * Length must be the same |
970 | | // * Element type must match or logically match |
971 | | // 3. If OpTypeStruct, then |
972 | | // * Both have same number of elements |
973 | | // * Element N for both structs must match or logically match |
974 | | // |
975 | | // If |check_decorations| is false, then the decorations are not checked. |
976 | | bool LogicallyMatch(const Instruction* lhs, const Instruction* rhs, |
977 | | bool check_decorations); |
978 | | |
979 | | // Traces |inst| to find a single base pointer. Returns the base pointer. |
980 | | // Will trace through the following instructions: |
981 | | // * OpAccessChain |
982 | | // * OpInBoundsAccessChain |
983 | | // * OpPtrAccessChain |
984 | | // * OpInBoundsPtrAccessChain |
985 | | // * OpCopyObject |
986 | | const Instruction* TracePointer(const Instruction* inst) const; |
987 | | |
988 | | // Validates the storage class for the target environment. |
989 | | bool IsValidStorageClass(spv::StorageClass storage_class) const; |
990 | | |
991 | | // Helps formulate a mesesage to user that setting one of the validator |
992 | | // options might make their SPIR-V actually valid The |hint| option is because |
993 | | // some checks are intertwined with each other, so hard to give confirmation |
994 | | std::string MissingFeature(const std::string& feature, |
995 | | const std::string& cmdline, bool hint) const; |
996 | | |
997 | | // Takes a Vulkan Valid Usage ID (VUID) as |id| and optional |reference| and |
998 | | // will return a non-empty string only if ID is known and targeting Vulkan. |
999 | | // VUIDs are found in the Vulkan-Docs repo in the form "[[VUID-ref-ref-id]]" |
1000 | | // where "id" is always an 5 char long number (with zeros padding) and matches |
1001 | | // to |id|. |reference| is used if there is a "common validity" and the VUID |
1002 | | // shares the same |id| value. |
1003 | | // |
1004 | | // More details about Vulkan validation can be found in Vulkan Guide: |
1005 | | // https://github.com/KhronosGroup/Vulkan-Guide/blob/master/chapters/validation_overview.md |
1006 | | std::string VkErrorID(uint32_t id, const char* reference = nullptr) const; |
1007 | | |
1008 | | // Testing method to allow setting the current layout section. |
1009 | 0 | void SetCurrentLayoutSectionForTesting(ModuleLayoutSection section) { |
1010 | 0 | current_layout_section_ = section; |
1011 | 0 | } |
1012 | | |
1013 | | // Check if instruction 'id' is a consumer of a texture decorated |
1014 | | // with a QCOM image processing decoration |
1015 | 4.02k | bool IsQCOMImageProcessingTextureConsumer(uint32_t id) { |
1016 | 4.02k | return qcom_image_processing_consumers_.find(id) != |
1017 | 4.02k | qcom_image_processing_consumers_.end(); |
1018 | 4.02k | } |
1019 | | |
1020 | | // Get the list of line lengths for a given result ID of a DebugSource |
1021 | | // instruction Will create a new vector if DebugSource is not found |
1022 | | std::vector<uint32_t>& GetDebugSourceLineLength(uint32_t id); |
1023 | | |
1024 | 0 | void RegisterShaderDebugInfo(uint32_t id) { shader_debug_info_set_id = id; } |
1025 | 26.2k | uint32_t ShaderDebugInfoSet() const { return shader_debug_info_set_id; } |
1026 | | std::string InspectShaderDebugInfo(const Instruction& inst); |
1027 | | |
1028 | | private: |
1029 | | ValidationState_t(const ValidationState_t&); |
1030 | | |
1031 | | const spv_const_context context_; |
1032 | | |
1033 | | /// Stores the Validator command line options. Must be a valid options object. |
1034 | | const spv_const_validator_options options_; |
1035 | | |
1036 | | /// The SPIR-V binary module we're validating. |
1037 | | const uint32_t* words_; |
1038 | | const size_t num_words_; |
1039 | | |
1040 | | /// The generator of the SPIR-V. |
1041 | | uint32_t generator_ = 0; |
1042 | | |
1043 | | /// The version of the SPIR-V. |
1044 | | uint32_t version_ = 0; |
1045 | | |
1046 | | /// The total number of instructions in the binary. |
1047 | | size_t total_instructions_ = 0; |
1048 | | /// The total number of functions in the binary. |
1049 | | size_t total_functions_ = 0; |
1050 | | |
1051 | | /// IDs which have been forward declared but have not been defined |
1052 | | std::unordered_set<uint32_t> unresolved_forward_ids_; |
1053 | | |
1054 | | /// IDs that have been declared as forward pointers. |
1055 | | std::unordered_set<uint32_t> forward_pointer_ids_; |
1056 | | |
1057 | | /// Stores a vector of instructions that use the result of a given |
1058 | | /// OpSampledImage instruction. |
1059 | | std::unordered_map<uint32_t, std::vector<Instruction*>> |
1060 | | sampled_image_consumers_; |
1061 | | |
1062 | | /// Stores load instructions that load textures used |
1063 | | // in QCOM image processing functions |
1064 | | std::unordered_set<uint32_t> qcom_image_processing_consumers_; |
1065 | | |
1066 | | /// A map of operand IDs and their names defined by the OpName instruction |
1067 | | std::unordered_map<uint32_t, std::string> operand_names_; |
1068 | | |
1069 | | /// The section of the code being processed |
1070 | | ModuleLayoutSection current_layout_section_; |
1071 | | |
1072 | | /// A list of functions in the module. |
1073 | | /// Pointers to objects in this container are guaranteed to be stable and |
1074 | | /// valid until the end of lifetime of the validation state. |
1075 | | std::vector<Function> module_functions_; |
1076 | | |
1077 | | /// Capabilities declared in the module |
1078 | | CapabilitySet module_capabilities_; |
1079 | | |
1080 | | /// Extensions declared in the module |
1081 | | ExtensionSet module_extensions_; |
1082 | | |
1083 | | /// List of all instructions in the order they appear in the binary |
1084 | | std::vector<Instruction> ordered_instructions_; |
1085 | | |
1086 | | /// Instructions that can be referenced by Ids |
1087 | | std::unordered_map<uint32_t, Instruction*> all_definitions_; |
1088 | | |
1089 | | /// IDs that are entry points, ie, arguments to OpEntryPoint. |
1090 | | std::vector<uint32_t> entry_points_; |
1091 | | |
1092 | | /// Maps an entry point id to its descriptions. |
1093 | | std::unordered_map<uint32_t, std::vector<EntryPointDescription>> |
1094 | | entry_point_descriptions_; |
1095 | | |
1096 | | /// IDs that are entry points, ie, arguments to OpEntryPoint, and root a call |
1097 | | /// graph that recurses. |
1098 | | std::set<uint32_t> recursive_entry_points_; |
1099 | | |
1100 | | /// IDs that are graph entry points, ie, arguments to OpGraphEntryPointARM. |
1101 | | std::vector<uint32_t> graph_entry_points_; |
1102 | | |
1103 | | /// Functions IDs that are target of OpFunctionCall. |
1104 | | std::unordered_set<uint32_t> function_call_targets_; |
1105 | | |
1106 | | /// ID Bound from the Header |
1107 | | uint32_t id_bound_; |
1108 | | |
1109 | | /// Set of Global Variable IDs (Storage Class other than 'Function') |
1110 | | std::unordered_set<uint32_t> global_vars_; |
1111 | | |
1112 | | /// Set of Local Variable IDs ('Function' Storage Class) |
1113 | | std::unordered_set<uint32_t> local_vars_; |
1114 | | |
1115 | | /// Set of struct types that have members with a BuiltIn decoration. |
1116 | | std::unordered_set<uint32_t> builtin_structs_; |
1117 | | |
1118 | | /// Structure Nesting Depth |
1119 | | std::unordered_map<uint32_t, uint32_t> struct_nesting_depth_; |
1120 | | |
1121 | | /// Structure has nested blockorbufferblock struct |
1122 | | std::unordered_map<uint32_t, bool> |
1123 | | struct_has_nested_blockorbufferblock_struct_; |
1124 | | |
1125 | | /// Stores the list of decorations for a given <id> |
1126 | | std::map<uint32_t, std::set<Decoration>> id_decorations_; |
1127 | | |
1128 | | /// Stores type declarations which need to be unique (i.e. non-aggregates), |
1129 | | /// in the form [opcode, operand words], result_id is not stored. |
1130 | | /// Using ordered set to avoid the need for a vector hash function. |
1131 | | /// The size of this container is expected not to exceed double-digits. |
1132 | | std::set<std::vector<uint32_t>> unique_type_declarations_; |
1133 | | |
1134 | | AssemblyGrammar grammar_; |
1135 | | |
1136 | | spv::AddressingModel addressing_model_; |
1137 | | spv::MemoryModel memory_model_; |
1138 | | // pointer size derived from addressing model. Assumes all storage classes |
1139 | | // have the same pointer size (for physical pointer types). |
1140 | | uint32_t pointer_size_and_alignment_; |
1141 | | |
1142 | | /// bit width of sampler/image type variables. Valid values are 32 and 64 |
1143 | | uint32_t sampler_image_addressing_mode_; |
1144 | | |
1145 | | /// NOTE: See corresponding getter functions |
1146 | | bool in_function_; |
1147 | | |
1148 | | /// Where in a graph definition we are |
1149 | | /// NOTE: See corresponding getter/setter functions |
1150 | | GraphDefinitionRegion graph_definition_region_; |
1151 | | |
1152 | | /// The state of optional features. These are determined by capabilities |
1153 | | /// declared by the module and the environment. |
1154 | | Feature features_; |
1155 | | |
1156 | | /// Maps function ids to function stat objects. |
1157 | | std::unordered_map<uint32_t, Function*> id_to_function_; |
1158 | | |
1159 | | /// Mapping entry point -> execution models. It is presumed that the same |
1160 | | /// function could theoretically be used as 'main' by multiple OpEntryPoint |
1161 | | /// instructions. |
1162 | | std::unordered_map<uint32_t, std::set<spv::ExecutionModel>> |
1163 | | entry_point_to_execution_models_; |
1164 | | |
1165 | | /// Mapping entry point -> execution modes. |
1166 | | std::unordered_map<uint32_t, std::set<spv::ExecutionMode>> |
1167 | | entry_point_to_execution_modes_; |
1168 | | |
1169 | | // Mapping entry point -> local size execution mode instruction |
1170 | | std::unordered_map<uint32_t, const Instruction*> |
1171 | | entry_point_to_local_size_or_id_; |
1172 | | |
1173 | | // Mapping entry point -> OutputPrimitivesEXT execution mode instruction |
1174 | | std::unordered_map<uint32_t, const Instruction*> |
1175 | | entry_point_to_output_primitives_; |
1176 | | |
1177 | | // Mapping entry point -> OutputVertices execution mode instruction |
1178 | | std::unordered_map<uint32_t, const Instruction*> |
1179 | | entry_point_to_output_vertices_; |
1180 | | |
1181 | | /// Mapping function -> array of entry points inside this |
1182 | | /// module which can (indirectly) call the function. |
1183 | | std::unordered_map<uint32_t, std::vector<uint32_t>> function_to_entry_points_; |
1184 | | const std::vector<uint32_t> empty_ids_; |
1185 | | |
1186 | | // The IDs of types of pointers to Block-decorated structs in Uniform storage |
1187 | | // class. This is populated at the start of ValidateDecorations. |
1188 | | std::unordered_set<uint32_t> pointer_to_uniform_block_; |
1189 | | // The IDs of struct types for uniform blocks. |
1190 | | // This is populated at the start of ValidateDecorations. |
1191 | | std::unordered_set<uint32_t> struct_for_uniform_block_; |
1192 | | // The IDs of types of pointers to BufferBlock-decorated structs in Uniform |
1193 | | // storage class, or Block-decorated structs in StorageBuffer storage class. |
1194 | | // This is populated at the start of ValidateDecorations. |
1195 | | std::unordered_set<uint32_t> pointer_to_storage_buffer_; |
1196 | | // The IDs of struct types for storage buffers. |
1197 | | // This is populated at the start of ValidateDecorations. |
1198 | | std::unordered_set<uint32_t> struct_for_storage_buffer_; |
1199 | | // The IDs of types of pointers to storage images. This is populated in the |
1200 | | // TypePass. |
1201 | | std::unordered_set<uint32_t> pointer_to_storage_image_; |
1202 | | // The IDs of types of pointers to tensors. This is populated in the |
1203 | | // TypePass. |
1204 | | std::unordered_set<uint32_t> pointer_to_tensor_; |
1205 | | |
1206 | | /// Maps an id of DebugSource to a vector that contains the length of each |
1207 | | /// line side of it. (Also will have the DebugSourceContinued source included) |
1208 | | std::unordered_map<uint32_t, std::vector<uint32_t>> debug_source_line_length_; |
1209 | | |
1210 | | // Quick check if we have seen NonSemantic.Shader.DebugInfo.* |
1211 | | // to know to try and print out a source line on an error message |
1212 | | uint32_t shader_debug_info_set_id = 0; |
1213 | | |
1214 | | /// Maps ids to friendly names. |
1215 | | std::unique_ptr<spvtools::FriendlyNameMapper> friendly_mapper_; |
1216 | | spvtools::NameMapper name_mapper_; |
1217 | | |
1218 | | /// Variables used to reduce the number of diagnostic messages. |
1219 | | uint32_t num_of_warnings_; |
1220 | | uint32_t max_num_of_warnings_; |
1221 | | |
1222 | | struct DebugSourceInfo { |
1223 | | uint32_t line_start; |
1224 | | uint32_t line_end; |
1225 | | uint32_t column_start; |
1226 | | uint32_t column_end; |
1227 | | }; |
1228 | | DebugSourceInfo GetDebugSourceInfo(const Instruction& inst); |
1229 | | void InspectDebugLine(std::ostringstream& ss, const Instruction& inst); |
1230 | | void InspectDebugGlobalVariable(std::ostringstream& ss, |
1231 | | const Instruction& inst); |
1232 | | void InspectDebugLocalVariable(std::ostringstream& ss, const Function& func, |
1233 | | const Instruction& inst); |
1234 | | void InspectFunctionCall(std::ostringstream& ss, |
1235 | | const Instruction& function_call_inst); |
1236 | | void InspectLineAndFunctionDefinition(std::ostringstream& ss, |
1237 | | const Function& func, |
1238 | | const Instruction& inst); |
1239 | | void InspectEntryPoint(std::ostringstream& ss, const Instruction& inst); |
1240 | | void InspectDebugFunctionDefinition(std::ostringstream& ss, |
1241 | | const Instruction& function_inst); |
1242 | | void PrintShaderDebugInfoSource(std::ostringstream& ss, |
1243 | | const Instruction& debug_source, |
1244 | | const DebugSourceInfo& source_info); |
1245 | | }; |
1246 | | |
1247 | | } // namespace val |
1248 | | } // namespace spvtools |
1249 | | |
1250 | | #endif // SOURCE_VAL_VALIDATION_STATE_H_ |