Coverage Report

Created: 2026-06-08 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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*) const
Unexecuted 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_