• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 Google 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 // This file provides a class hierarchy for representing SPIR-V types.
16 
17 #ifndef SOURCE_OPT_TYPES_H_
18 #define SOURCE_OPT_TYPES_H_
19 
20 #include <map>
21 #include <memory>
22 #include <set>
23 #include <string>
24 #include <unordered_map>
25 #include <unordered_set>
26 #include <utility>
27 #include <vector>
28 
29 #include "source/latest_version_spirv_header.h"
30 #include "source/opt/instruction.h"
31 #include "source/util/small_vector.h"
32 #include "spirv-tools/libspirv.h"
33 
34 namespace spvtools {
35 namespace opt {
36 namespace analysis {
37 
38 class Void;
39 class Bool;
40 class Integer;
41 class Float;
42 class Vector;
43 class Matrix;
44 class Image;
45 class Sampler;
46 class SampledImage;
47 class Array;
48 class RuntimeArray;
49 class Struct;
50 class Opaque;
51 class Pointer;
52 class Function;
53 class Event;
54 class DeviceEvent;
55 class ReserveId;
56 class Queue;
57 class Pipe;
58 class ForwardPointer;
59 class PipeStorage;
60 class NamedBarrier;
61 class AccelerationStructureNV;
62 class CooperativeMatrixNV;
63 class CooperativeMatrixKHR;
64 class RayQueryKHR;
65 class HitObjectNV;
66 
67 // Abstract class for a SPIR-V type. It has a bunch of As<sublcass>() methods,
68 // which is used as a way to probe the actual <subclass>.
69 class Type {
70  public:
71   typedef std::set<std::pair<const Pointer*, const Pointer*>> IsSameCache;
72 
73   using SeenTypes = spvtools::utils::SmallVector<const Type*, 8>;
74 
75   // Available subtypes.
76   //
77   // When adding a new derived class of Type, please add an entry to the enum.
78   enum Kind {
79     kVoid,
80     kBool,
81     kInteger,
82     kFloat,
83     kVector,
84     kMatrix,
85     kImage,
86     kSampler,
87     kSampledImage,
88     kArray,
89     kRuntimeArray,
90     kStruct,
91     kOpaque,
92     kPointer,
93     kFunction,
94     kEvent,
95     kDeviceEvent,
96     kReserveId,
97     kQueue,
98     kPipe,
99     kForwardPointer,
100     kPipeStorage,
101     kNamedBarrier,
102     kAccelerationStructureNV,
103     kCooperativeMatrixNV,
104     kCooperativeMatrixKHR,
105     kRayQueryKHR,
106     kHitObjectNV,
107     kLast
108   };
109 
Type(Kind k)110   Type(Kind k) : kind_(k) {}
111 
112   virtual ~Type() = default;
113 
114   // Attaches a decoration directly on this type.
AddDecoration(std::vector<uint32_t> && d)115   void AddDecoration(std::vector<uint32_t>&& d) {
116     decorations_.push_back(std::move(d));
117   }
118   // Returns the decorations on this type as a string.
119   std::string GetDecorationStr() const;
120   // Returns true if this type has exactly the same decorations as |that| type.
121   bool HasSameDecorations(const Type* that) const;
122   // Returns true if this type is exactly the same as |that| type, including
123   // decorations.
IsSame(const Type * that)124   bool IsSame(const Type* that) const {
125     IsSameCache seen;
126     return IsSameImpl(that, &seen);
127   }
128 
129   // Returns true if this type is exactly the same as |that| type, including
130   // decorations.  |seen| is the set of |Pointer*| pair that are currently being
131   // compared in a parent call to |IsSameImpl|.
132   virtual bool IsSameImpl(const Type* that, IsSameCache* seen) const = 0;
133 
134   // Returns a human-readable string to represent this type.
135   virtual std::string str() const = 0;
136 
kind()137   Kind kind() const { return kind_; }
decorations()138   const std::vector<std::vector<uint32_t>>& decorations() const {
139     return decorations_;
140   }
141 
142   // Returns true if there is no decoration on this type. For struct types,
143   // returns true only when there is no decoration for both the struct type
144   // and the struct members.
decoration_empty()145   virtual bool decoration_empty() const { return decorations_.empty(); }
146 
147   // Creates a clone of |this|.
148   std::unique_ptr<Type> Clone() const;
149 
150   // Returns a clone of |this| minus any decorations.
151   std::unique_ptr<Type> RemoveDecorations() const;
152 
153   // Returns true if this cannot hash to the same value as another type in the
154   // module. For example, structs are not unique types because the module could
155   // have two types
156   //
157   //  %1 = OpTypeStruct %int
158   //  %2 = OpTypeStruct %int
159   //
160   // The only way to distinguish these types is the result id. The type manager
161   // will hash them to the same value.
162   bool IsUniqueType() const;
163 
164   bool operator==(const Type& other) const;
165 
166   // Returns the hash value of this type.
167   size_t HashValue() const;
168 
169   size_t ComputeHashValue(size_t hash, SeenTypes* seen) const;
170 
171   // Returns the number of components in a composite type.  Returns 0 for a
172   // non-composite type.
173   uint64_t NumberOfComponents() const;
174 
175 // A bunch of methods for casting this type to a given type. Returns this if the
176 // cast can be done, nullptr otherwise.
177 // clang-format off
178 #define DeclareCastMethod(target)                  \
179   virtual target* As##target() { return nullptr; } \
180   virtual const target* As##target() const { return nullptr; }
181   DeclareCastMethod(Void)
182   DeclareCastMethod(Bool)
183   DeclareCastMethod(Integer)
184   DeclareCastMethod(Float)
185   DeclareCastMethod(Vector)
186   DeclareCastMethod(Matrix)
187   DeclareCastMethod(Image)
188   DeclareCastMethod(Sampler)
189   DeclareCastMethod(SampledImage)
190   DeclareCastMethod(Array)
191   DeclareCastMethod(RuntimeArray)
192   DeclareCastMethod(Struct)
193   DeclareCastMethod(Opaque)
194   DeclareCastMethod(Pointer)
195   DeclareCastMethod(Function)
196   DeclareCastMethod(Event)
197   DeclareCastMethod(DeviceEvent)
198   DeclareCastMethod(ReserveId)
199   DeclareCastMethod(Queue)
200   DeclareCastMethod(Pipe)
201   DeclareCastMethod(ForwardPointer)
202   DeclareCastMethod(PipeStorage)
203   DeclareCastMethod(NamedBarrier)
204   DeclareCastMethod(AccelerationStructureNV)
205   DeclareCastMethod(CooperativeMatrixNV)
206   DeclareCastMethod(CooperativeMatrixKHR)
207   DeclareCastMethod(RayQueryKHR)
208   DeclareCastMethod(HitObjectNV)
209 #undef DeclareCastMethod
210 
211 protected:
212   // Add any type-specific state to |hash| and returns new hash.
213   virtual size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const = 0;
214 
215  protected:
216   // Decorations attached to this type. Each decoration is encoded as a vector
217   // of uint32_t numbers. The first uint32_t number is the decoration value,
218   // and the rest are the parameters to the decoration (if exists).
219   std::vector<std::vector<uint32_t>> decorations_;
220 
221  private:
222   // Removes decorations on this type. For struct types, also removes element
223   // decorations.
ClearDecorations()224   virtual void ClearDecorations() { decorations_.clear(); }
225 
226   Kind kind_;
227 };
228 // clang-format on
229 
230 class Integer : public Type {
231  public:
Integer(uint32_t w,bool is_signed)232   Integer(uint32_t w, bool is_signed)
233       : Type(kInteger), width_(w), signed_(is_signed) {}
234   Integer(const Integer&) = default;
235 
236   std::string str() const override;
237 
AsInteger()238   Integer* AsInteger() override { return this; }
AsInteger()239   const Integer* AsInteger() const override { return this; }
width()240   uint32_t width() const { return width_; }
IsSigned()241   bool IsSigned() const { return signed_; }
242 
243   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
244 
245  private:
246   bool IsSameImpl(const Type* that, IsSameCache*) const override;
247 
248   uint32_t width_;  // bit width
249   bool signed_;     // true if this integer is signed
250 };
251 
252 class Float : public Type {
253  public:
Float(uint32_t w)254   Float(uint32_t w) : Type(kFloat), width_(w) {}
255   Float(const Float&) = default;
256 
257   std::string str() const override;
258 
AsFloat()259   Float* AsFloat() override { return this; }
AsFloat()260   const Float* AsFloat() const override { return this; }
width()261   uint32_t width() const { return width_; }
262 
263   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
264 
265  private:
266   bool IsSameImpl(const Type* that, IsSameCache*) const override;
267 
268   uint32_t width_;  // bit width
269 };
270 
271 class Vector : public Type {
272  public:
273   Vector(const Type* element_type, uint32_t count);
274   Vector(const Vector&) = default;
275 
276   std::string str() const override;
element_type()277   const Type* element_type() const { return element_type_; }
element_count()278   uint32_t element_count() const { return count_; }
279 
AsVector()280   Vector* AsVector() override { return this; }
AsVector()281   const Vector* AsVector() const override { return this; }
282 
283   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
284 
285  private:
286   bool IsSameImpl(const Type* that, IsSameCache*) const override;
287 
288   const Type* element_type_;
289   uint32_t count_;
290 };
291 
292 class Matrix : public Type {
293  public:
294   Matrix(const Type* element_type, uint32_t count);
295   Matrix(const Matrix&) = default;
296 
297   std::string str() const override;
element_type()298   const Type* element_type() const { return element_type_; }
element_count()299   uint32_t element_count() const { return count_; }
300 
AsMatrix()301   Matrix* AsMatrix() override { return this; }
AsMatrix()302   const Matrix* AsMatrix() const override { return this; }
303 
304   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
305 
306  private:
307   bool IsSameImpl(const Type* that, IsSameCache*) const override;
308 
309   const Type* element_type_;
310   uint32_t count_;
311 };
312 
313 class Image : public Type {
314  public:
315   Image(Type* type, spv::Dim dimen, uint32_t d, bool array, bool multisample,
316         uint32_t sampling, spv::ImageFormat f,
317         spv::AccessQualifier qualifier = spv::AccessQualifier::ReadOnly);
318   Image(const Image&) = default;
319 
320   std::string str() const override;
321 
AsImage()322   Image* AsImage() override { return this; }
AsImage()323   const Image* AsImage() const override { return this; }
324 
sampled_type()325   const Type* sampled_type() const { return sampled_type_; }
dim()326   spv::Dim dim() const { return dim_; }
depth()327   uint32_t depth() const { return depth_; }
is_arrayed()328   bool is_arrayed() const { return arrayed_; }
is_multisampled()329   bool is_multisampled() const { return ms_; }
sampled()330   uint32_t sampled() const { return sampled_; }
format()331   spv::ImageFormat format() const { return format_; }
access_qualifier()332   spv::AccessQualifier access_qualifier() const { return access_qualifier_; }
333 
334   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
335 
336  private:
337   bool IsSameImpl(const Type* that, IsSameCache*) const override;
338 
339   Type* sampled_type_;
340   spv::Dim dim_;
341   uint32_t depth_;
342   bool arrayed_;
343   bool ms_;
344   uint32_t sampled_;
345   spv::ImageFormat format_;
346   spv::AccessQualifier access_qualifier_;
347 };
348 
349 class SampledImage : public Type {
350  public:
SampledImage(Type * image)351   SampledImage(Type* image) : Type(kSampledImage), image_type_(image) {}
352   SampledImage(const SampledImage&) = default;
353 
354   std::string str() const override;
355 
AsSampledImage()356   SampledImage* AsSampledImage() override { return this; }
AsSampledImage()357   const SampledImage* AsSampledImage() const override { return this; }
358 
image_type()359   const Type* image_type() const { return image_type_; }
360 
361   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
362 
363  private:
364   bool IsSameImpl(const Type* that, IsSameCache*) const override;
365   Type* image_type_;
366 };
367 
368 class Array : public Type {
369  public:
370   // Data about the length operand, that helps us distinguish between one
371   // array length and another.
372   struct LengthInfo {
373     // The result id of the instruction defining the length.
374     const uint32_t id;
375     enum Case : uint32_t {
376       kConstant = 0,
377       kConstantWithSpecId = 1,
378       kDefiningId = 2
379     };
380     // Extra words used to distinshish one array length and another.
381     //  - if OpConstant, then it's 0, then the words in the literal constant
382     //    value.
383     //  - if OpSpecConstant, then it's 1, then the SpecID decoration if there
384     //    is one, followed by the words in the literal constant value.
385     //    The spec might not be overridden, in which case we'll end up using
386     //    the literal value.
387     //  - Otherwise, it's an OpSpecConsant, and this 2, then the ID (again).
388     const std::vector<uint32_t> words;
389   };
390 
391   // Constructs an array type with given element and length.  If the length
392   // is an OpSpecConstant, then |spec_id| should be its SpecId decoration.
393   Array(const Type* element_type, const LengthInfo& length_info_arg);
394   Array(const Array&) = default;
395 
396   std::string str() const override;
element_type()397   const Type* element_type() const { return element_type_; }
LengthId()398   uint32_t LengthId() const { return length_info_.id; }
length_info()399   const LengthInfo& length_info() const { return length_info_; }
400 
AsArray()401   Array* AsArray() override { return this; }
AsArray()402   const Array* AsArray() const override { return this; }
403 
404   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
405 
406   void ReplaceElementType(const Type* element_type);
407   LengthInfo GetConstantLengthInfo(uint32_t const_id, uint32_t length) const;
408 
409  private:
410   bool IsSameImpl(const Type* that, IsSameCache*) const override;
411 
412   const Type* element_type_;
413   const LengthInfo length_info_;
414 };
415 
416 class RuntimeArray : public Type {
417  public:
418   RuntimeArray(const Type* element_type);
419   RuntimeArray(const RuntimeArray&) = default;
420 
421   std::string str() const override;
element_type()422   const Type* element_type() const { return element_type_; }
423 
AsRuntimeArray()424   RuntimeArray* AsRuntimeArray() override { return this; }
AsRuntimeArray()425   const RuntimeArray* AsRuntimeArray() const override { return this; }
426 
427   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
428 
429   void ReplaceElementType(const Type* element_type);
430 
431  private:
432   bool IsSameImpl(const Type* that, IsSameCache*) const override;
433 
434   const Type* element_type_;
435 };
436 
437 class Struct : public Type {
438  public:
439   Struct(const std::vector<const Type*>& element_types);
440   Struct(const Struct&) = default;
441 
442   // Adds a decoration to the member at the given index.  The first word is the
443   // decoration enum, and the remaining words, if any, are its operands.
444   void AddMemberDecoration(uint32_t index, std::vector<uint32_t>&& decoration);
445 
446   std::string str() const override;
element_types()447   const std::vector<const Type*>& element_types() const {
448     return element_types_;
449   }
element_types()450   std::vector<const Type*>& element_types() { return element_types_; }
decoration_empty()451   bool decoration_empty() const override {
452     return decorations_.empty() && element_decorations_.empty();
453   }
454 
455   const std::map<uint32_t, std::vector<std::vector<uint32_t>>>&
element_decorations()456   element_decorations() const {
457     return element_decorations_;
458   }
459 
AsStruct()460   Struct* AsStruct() override { return this; }
AsStruct()461   const Struct* AsStruct() const override { return this; }
462 
463   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
464 
465  private:
466   bool IsSameImpl(const Type* that, IsSameCache*) const override;
467 
ClearDecorations()468   void ClearDecorations() override {
469     decorations_.clear();
470     element_decorations_.clear();
471   }
472 
473   std::vector<const Type*> element_types_;
474   // We can attach decorations to struct members and that should not affect the
475   // underlying element type. So we need an extra data structure here to keep
476   // track of element type decorations.  They must be stored in an ordered map
477   // because |GetExtraHashWords| will traverse the structure.  It must have a
478   // fixed order in order to hash to the same value every time.
479   std::map<uint32_t, std::vector<std::vector<uint32_t>>> element_decorations_;
480 };
481 
482 class Opaque : public Type {
483  public:
Opaque(std::string n)484   Opaque(std::string n) : Type(kOpaque), name_(std::move(n)) {}
485   Opaque(const Opaque&) = default;
486 
487   std::string str() const override;
488 
AsOpaque()489   Opaque* AsOpaque() override { return this; }
AsOpaque()490   const Opaque* AsOpaque() const override { return this; }
491 
name()492   const std::string& name() const { return name_; }
493 
494   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
495 
496  private:
497   bool IsSameImpl(const Type* that, IsSameCache*) const override;
498 
499   std::string name_;
500 };
501 
502 class Pointer : public Type {
503  public:
504   Pointer(const Type* pointee, spv::StorageClass sc);
505   Pointer(const Pointer&) = default;
506 
507   std::string str() const override;
pointee_type()508   const Type* pointee_type() const { return pointee_type_; }
storage_class()509   spv::StorageClass storage_class() const { return storage_class_; }
510 
AsPointer()511   Pointer* AsPointer() override { return this; }
AsPointer()512   const Pointer* AsPointer() const override { return this; }
513 
514   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
515 
516   void SetPointeeType(const Type* type);
517 
518  private:
519   bool IsSameImpl(const Type* that, IsSameCache*) const override;
520 
521   const Type* pointee_type_;
522   spv::StorageClass storage_class_;
523 };
524 
525 class Function : public Type {
526  public:
527   Function(const Type* ret_type, const std::vector<const Type*>& params);
528   Function(const Type* ret_type, std::vector<const Type*>& params);
529   Function(const Function&) = default;
530 
531   std::string str() const override;
532 
AsFunction()533   Function* AsFunction() override { return this; }
AsFunction()534   const Function* AsFunction() const override { return this; }
535 
return_type()536   const Type* return_type() const { return return_type_; }
param_types()537   const std::vector<const Type*>& param_types() const { return param_types_; }
param_types()538   std::vector<const Type*>& param_types() { return param_types_; }
539 
540   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
541 
542   void SetReturnType(const Type* type);
543 
544  private:
545   bool IsSameImpl(const Type* that, IsSameCache*) const override;
546 
547   const Type* return_type_;
548   std::vector<const Type*> param_types_;
549 };
550 
551 class Pipe : public Type {
552  public:
Pipe(spv::AccessQualifier qualifier)553   Pipe(spv::AccessQualifier qualifier)
554       : Type(kPipe), access_qualifier_(qualifier) {}
555   Pipe(const Pipe&) = default;
556 
557   std::string str() const override;
558 
AsPipe()559   Pipe* AsPipe() override { return this; }
AsPipe()560   const Pipe* AsPipe() const override { return this; }
561 
access_qualifier()562   spv::AccessQualifier access_qualifier() const { return access_qualifier_; }
563 
564   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
565 
566  private:
567   bool IsSameImpl(const Type* that, IsSameCache*) const override;
568 
569   spv::AccessQualifier access_qualifier_;
570 };
571 
572 class ForwardPointer : public Type {
573  public:
ForwardPointer(uint32_t id,spv::StorageClass sc)574   ForwardPointer(uint32_t id, spv::StorageClass sc)
575       : Type(kForwardPointer),
576         target_id_(id),
577         storage_class_(sc),
578         pointer_(nullptr) {}
579   ForwardPointer(const ForwardPointer&) = default;
580 
target_id()581   uint32_t target_id() const { return target_id_; }
SetTargetPointer(const Pointer * pointer)582   void SetTargetPointer(const Pointer* pointer) { pointer_ = pointer; }
storage_class()583   spv::StorageClass storage_class() const { return storage_class_; }
target_pointer()584   const Pointer* target_pointer() const { return pointer_; }
585 
586   std::string str() const override;
587 
AsForwardPointer()588   ForwardPointer* AsForwardPointer() override { return this; }
AsForwardPointer()589   const ForwardPointer* AsForwardPointer() const override { return this; }
590 
591   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
592 
593  private:
594   bool IsSameImpl(const Type* that, IsSameCache*) const override;
595 
596   uint32_t target_id_;
597   spv::StorageClass storage_class_;
598   const Pointer* pointer_;
599 };
600 
601 class CooperativeMatrixNV : public Type {
602  public:
603   CooperativeMatrixNV(const Type* type, const uint32_t scope,
604                       const uint32_t rows, const uint32_t columns);
605   CooperativeMatrixNV(const CooperativeMatrixNV&) = default;
606 
607   std::string str() const override;
608 
AsCooperativeMatrixNV()609   CooperativeMatrixNV* AsCooperativeMatrixNV() override { return this; }
AsCooperativeMatrixNV()610   const CooperativeMatrixNV* AsCooperativeMatrixNV() const override {
611     return this;
612   }
613 
614   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
615 
component_type()616   const Type* component_type() const { return component_type_; }
scope_id()617   uint32_t scope_id() const { return scope_id_; }
rows_id()618   uint32_t rows_id() const { return rows_id_; }
columns_id()619   uint32_t columns_id() const { return columns_id_; }
620 
621  private:
622   bool IsSameImpl(const Type* that, IsSameCache*) const override;
623 
624   const Type* component_type_;
625   const uint32_t scope_id_;
626   const uint32_t rows_id_;
627   const uint32_t columns_id_;
628 };
629 
630 class CooperativeMatrixKHR : public Type {
631  public:
632   CooperativeMatrixKHR(const Type* type, const uint32_t scope,
633                        const uint32_t rows, const uint32_t columns,
634                        const uint32_t use);
635   CooperativeMatrixKHR(const CooperativeMatrixKHR&) = default;
636 
637   std::string str() const override;
638 
AsCooperativeMatrixKHR()639   CooperativeMatrixKHR* AsCooperativeMatrixKHR() override { return this; }
AsCooperativeMatrixKHR()640   const CooperativeMatrixKHR* AsCooperativeMatrixKHR() const override {
641     return this;
642   }
643 
644   size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
645 
component_type()646   const Type* component_type() const { return component_type_; }
scope_id()647   uint32_t scope_id() const { return scope_id_; }
rows_id()648   uint32_t rows_id() const { return rows_id_; }
columns_id()649   uint32_t columns_id() const { return columns_id_; }
use_id()650   uint32_t use_id() const { return use_id_; }
651 
652  private:
653   bool IsSameImpl(const Type* that, IsSameCache*) const override;
654 
655   const Type* component_type_;
656   const uint32_t scope_id_;
657   const uint32_t rows_id_;
658   const uint32_t columns_id_;
659   const uint32_t use_id_;
660 };
661 
662 #define DefineParameterlessType(type, name)                                \
663   class type : public Type {                                               \
664    public:                                                                 \
665     type() : Type(k##type) {}                                              \
666     type(const type&) = default;                                           \
667                                                                            \
668     std::string str() const override { return #name; }                     \
669                                                                            \
670     type* As##type() override { return this; }                             \
671     const type* As##type() const override { return this; }                 \
672                                                                            \
673     size_t ComputeExtraStateHash(size_t hash, SeenTypes*) const override { \
674       return hash;                                                         \
675     }                                                                      \
676                                                                            \
677    private:                                                                \
678     bool IsSameImpl(const Type* that, IsSameCache*) const override {       \
679       return that->As##type() && HasSameDecorations(that);                 \
680     }                                                                      \
681   }
682 DefineParameterlessType(Void, void);
683 DefineParameterlessType(Bool, bool);
684 DefineParameterlessType(Sampler, sampler);
685 DefineParameterlessType(Event, event);
686 DefineParameterlessType(DeviceEvent, device_event);
687 DefineParameterlessType(ReserveId, reserve_id);
688 DefineParameterlessType(Queue, queue);
689 DefineParameterlessType(PipeStorage, pipe_storage);
690 DefineParameterlessType(NamedBarrier, named_barrier);
691 DefineParameterlessType(AccelerationStructureNV, accelerationStructureNV);
692 DefineParameterlessType(RayQueryKHR, rayQueryKHR);
693 DefineParameterlessType(HitObjectNV, hitObjectNV);
694 #undef DefineParameterlessType
695 
696 }  // namespace analysis
697 }  // namespace opt
698 }  // namespace spvtools
699 
700 #endif  // SOURCE_OPT_TYPES_H_
701