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
40namespace spvtools {
41namespace 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
46enum 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.
63class 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