• 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 #include "source/opt/types.h"
16 
17 #include <algorithm>
18 #include <cassert>
19 #include <climits>
20 #include <cstdint>
21 #include <sstream>
22 #include <string>
23 #include <unordered_set>
24 
25 #include "source/util/hash_combine.h"
26 #include "source/util/make_unique.h"
27 #include "spirv/unified1/spirv.h"
28 
29 namespace spvtools {
30 namespace opt {
31 namespace analysis {
32 
33 using spvtools::utils::hash_combine;
34 using U32VecVec = std::vector<std::vector<uint32_t>>;
35 
36 namespace {
37 
38 // Returns true if the two vector of vectors are identical.
CompareTwoVectors(const U32VecVec a,const U32VecVec b)39 bool CompareTwoVectors(const U32VecVec a, const U32VecVec b) {
40   const auto size = a.size();
41   if (size != b.size()) return false;
42 
43   if (size == 0) return true;
44   if (size == 1) return a.front() == b.front();
45 
46   std::vector<const std::vector<uint32_t>*> a_ptrs, b_ptrs;
47   a_ptrs.reserve(size);
48   a_ptrs.reserve(size);
49   for (uint32_t i = 0; i < size; ++i) {
50     a_ptrs.push_back(&a[i]);
51     b_ptrs.push_back(&b[i]);
52   }
53 
54   const auto cmp = [](const std::vector<uint32_t>* m,
55                       const std::vector<uint32_t>* n) {
56     return m->front() < n->front();
57   };
58 
59   std::sort(a_ptrs.begin(), a_ptrs.end(), cmp);
60   std::sort(b_ptrs.begin(), b_ptrs.end(), cmp);
61 
62   for (uint32_t i = 0; i < size; ++i) {
63     if (*a_ptrs[i] != *b_ptrs[i]) return false;
64   }
65   return true;
66 }
67 
68 }  // anonymous namespace
69 
GetDecorationStr() const70 std::string Type::GetDecorationStr() const {
71   std::ostringstream oss;
72   oss << "[[";
73   for (const auto& decoration : decorations_) {
74     oss << "(";
75     for (size_t i = 0; i < decoration.size(); ++i) {
76       oss << (i > 0 ? ", " : "");
77       oss << decoration.at(i);
78     }
79     oss << ")";
80   }
81   oss << "]]";
82   return oss.str();
83 }
84 
HasSameDecorations(const Type * that) const85 bool Type::HasSameDecorations(const Type* that) const {
86   return CompareTwoVectors(decorations_, that->decorations_);
87 }
88 
IsUniqueType(bool allowVariablePointers) const89 bool Type::IsUniqueType(bool allowVariablePointers) const {
90   switch (kind_) {
91     case kPointer:
92       return !allowVariablePointers;
93     case kStruct:
94     case kArray:
95     case kRuntimeArray:
96       return false;
97     default:
98       return true;
99   }
100 }
101 
Clone() const102 std::unique_ptr<Type> Type::Clone() const {
103   std::unique_ptr<Type> type;
104   switch (kind_) {
105 #define DeclareKindCase(kind)                   \
106   case k##kind:                                 \
107     type = MakeUnique<kind>(*this->As##kind()); \
108     break
109     DeclareKindCase(Void);
110     DeclareKindCase(Bool);
111     DeclareKindCase(Integer);
112     DeclareKindCase(Float);
113     DeclareKindCase(Vector);
114     DeclareKindCase(Matrix);
115     DeclareKindCase(Image);
116     DeclareKindCase(Sampler);
117     DeclareKindCase(SampledImage);
118     DeclareKindCase(Array);
119     DeclareKindCase(RuntimeArray);
120     DeclareKindCase(Struct);
121     DeclareKindCase(Opaque);
122     DeclareKindCase(Pointer);
123     DeclareKindCase(Function);
124     DeclareKindCase(Event);
125     DeclareKindCase(DeviceEvent);
126     DeclareKindCase(ReserveId);
127     DeclareKindCase(Queue);
128     DeclareKindCase(Pipe);
129     DeclareKindCase(ForwardPointer);
130     DeclareKindCase(PipeStorage);
131     DeclareKindCase(NamedBarrier);
132     DeclareKindCase(AccelerationStructureNV);
133     DeclareKindCase(CooperativeMatrixNV);
134     DeclareKindCase(RayQueryKHR);
135 #undef DeclareKindCase
136     default:
137       assert(false && "Unhandled type");
138   }
139   return type;
140 }
141 
RemoveDecorations() const142 std::unique_ptr<Type> Type::RemoveDecorations() const {
143   std::unique_ptr<Type> type(Clone());
144   type->ClearDecorations();
145   return type;
146 }
147 
operator ==(const Type & other) const148 bool Type::operator==(const Type& other) const {
149   if (kind_ != other.kind_) return false;
150 
151   switch (kind_) {
152 #define DeclareKindCase(kind) \
153   case k##kind:               \
154     return As##kind()->IsSame(&other)
155     DeclareKindCase(Void);
156     DeclareKindCase(Bool);
157     DeclareKindCase(Integer);
158     DeclareKindCase(Float);
159     DeclareKindCase(Vector);
160     DeclareKindCase(Matrix);
161     DeclareKindCase(Image);
162     DeclareKindCase(Sampler);
163     DeclareKindCase(SampledImage);
164     DeclareKindCase(Array);
165     DeclareKindCase(RuntimeArray);
166     DeclareKindCase(Struct);
167     DeclareKindCase(Opaque);
168     DeclareKindCase(Pointer);
169     DeclareKindCase(Function);
170     DeclareKindCase(Event);
171     DeclareKindCase(DeviceEvent);
172     DeclareKindCase(ReserveId);
173     DeclareKindCase(Queue);
174     DeclareKindCase(Pipe);
175     DeclareKindCase(ForwardPointer);
176     DeclareKindCase(PipeStorage);
177     DeclareKindCase(NamedBarrier);
178     DeclareKindCase(AccelerationStructureNV);
179     DeclareKindCase(CooperativeMatrixNV);
180     DeclareKindCase(RayQueryKHR);
181 #undef DeclareKindCase
182     default:
183       assert(false && "Unhandled type");
184       return false;
185   }
186 }
187 
ComputeHashValue(size_t hash,SeenTypes * seen) const188 size_t Type::ComputeHashValue(size_t hash, SeenTypes* seen) const {
189   // Linear search through a dense, cache coherent vector is faster than O(log
190   // n) search in a complex data structure (eg std::set) for the generally small
191   // number of nodes.  It also skips the overhead of an new/delete per Type
192   // (when inserting/removing from a set).
193   if (std::find(seen->begin(), seen->end(), this) != seen->end()) {
194     return hash;
195   }
196 
197   seen->push_back(this);
198 
199   hash = hash_combine(hash, uint32_t(kind_));
200   for (const auto& d : decorations_) {
201     hash = hash_combine(hash, d);
202   }
203 
204   switch (kind_) {
205 #define DeclareKindCase(type)                             \
206   case k##type:                                           \
207     hash = As##type()->ComputeExtraStateHash(hash, seen); \
208     break
209     DeclareKindCase(Void);
210     DeclareKindCase(Bool);
211     DeclareKindCase(Integer);
212     DeclareKindCase(Float);
213     DeclareKindCase(Vector);
214     DeclareKindCase(Matrix);
215     DeclareKindCase(Image);
216     DeclareKindCase(Sampler);
217     DeclareKindCase(SampledImage);
218     DeclareKindCase(Array);
219     DeclareKindCase(RuntimeArray);
220     DeclareKindCase(Struct);
221     DeclareKindCase(Opaque);
222     DeclareKindCase(Pointer);
223     DeclareKindCase(Function);
224     DeclareKindCase(Event);
225     DeclareKindCase(DeviceEvent);
226     DeclareKindCase(ReserveId);
227     DeclareKindCase(Queue);
228     DeclareKindCase(Pipe);
229     DeclareKindCase(ForwardPointer);
230     DeclareKindCase(PipeStorage);
231     DeclareKindCase(NamedBarrier);
232     DeclareKindCase(AccelerationStructureNV);
233     DeclareKindCase(CooperativeMatrixNV);
234     DeclareKindCase(RayQueryKHR);
235 #undef DeclareKindCase
236     default:
237       assert(false && "Unhandled type");
238       break;
239   }
240 
241   seen->pop_back();
242   return hash;
243 }
244 
HashValue() const245 size_t Type::HashValue() const {
246   SeenTypes seen;
247   return ComputeHashValue(0, &seen);
248 }
249 
NumberOfComponents() const250 uint64_t Type::NumberOfComponents() const {
251   switch (kind()) {
252     case kVector:
253       return AsVector()->element_count();
254     case kMatrix:
255       return AsMatrix()->element_count();
256     case kArray: {
257       Array::LengthInfo length_info = AsArray()->length_info();
258       if (length_info.words[0] != Array::LengthInfo::kConstant) {
259         return UINT64_MAX;
260       }
261       assert(length_info.words.size() <= 3 &&
262              "The size of the array could not fit size_t.");
263       uint64_t length = 0;
264       length |= length_info.words[1];
265       if (length_info.words.size() > 2) {
266         length |= static_cast<uint64_t>(length_info.words[2]) << 32;
267       }
268       return length;
269     }
270     case kRuntimeArray:
271       return UINT64_MAX;
272     case kStruct:
273       return AsStruct()->element_types().size();
274     default:
275       return 0;
276   }
277 }
278 
IsSameImpl(const Type * that,IsSameCache *) const279 bool Integer::IsSameImpl(const Type* that, IsSameCache*) const {
280   const Integer* it = that->AsInteger();
281   return it && width_ == it->width_ && signed_ == it->signed_ &&
282          HasSameDecorations(that);
283 }
284 
str() const285 std::string Integer::str() const {
286   std::ostringstream oss;
287   oss << (signed_ ? "s" : "u") << "int" << width_;
288   return oss.str();
289 }
290 
ComputeExtraStateHash(size_t hash,SeenTypes *) const291 size_t Integer::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
292   return hash_combine(hash, width_, signed_);
293 }
294 
IsSameImpl(const Type * that,IsSameCache *) const295 bool Float::IsSameImpl(const Type* that, IsSameCache*) const {
296   const Float* ft = that->AsFloat();
297   return ft && width_ == ft->width_ && HasSameDecorations(that);
298 }
299 
str() const300 std::string Float::str() const {
301   std::ostringstream oss;
302   oss << "float" << width_;
303   return oss.str();
304 }
305 
ComputeExtraStateHash(size_t hash,SeenTypes *) const306 size_t Float::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
307   return hash_combine(hash, width_);
308 }
309 
Vector(const Type * type,uint32_t count)310 Vector::Vector(const Type* type, uint32_t count)
311     : Type(kVector), element_type_(type), count_(count) {
312   assert(type->AsBool() || type->AsInteger() || type->AsFloat());
313 }
314 
IsSameImpl(const Type * that,IsSameCache * seen) const315 bool Vector::IsSameImpl(const Type* that, IsSameCache* seen) const {
316   const Vector* vt = that->AsVector();
317   if (!vt) return false;
318   return count_ == vt->count_ &&
319          element_type_->IsSameImpl(vt->element_type_, seen) &&
320          HasSameDecorations(that);
321 }
322 
str() const323 std::string Vector::str() const {
324   std::ostringstream oss;
325   oss << "<" << element_type_->str() << ", " << count_ << ">";
326   return oss.str();
327 }
328 
ComputeExtraStateHash(size_t hash,SeenTypes * seen) const329 size_t Vector::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
330   // prefer form that doesn't require push/pop from stack: add state and
331   // make tail call.
332   hash = hash_combine(hash, count_);
333   return element_type_->ComputeHashValue(hash, seen);
334 }
335 
Matrix(const Type * type,uint32_t count)336 Matrix::Matrix(const Type* type, uint32_t count)
337     : Type(kMatrix), element_type_(type), count_(count) {
338   assert(type->AsVector());
339 }
340 
IsSameImpl(const Type * that,IsSameCache * seen) const341 bool Matrix::IsSameImpl(const Type* that, IsSameCache* seen) const {
342   const Matrix* mt = that->AsMatrix();
343   if (!mt) return false;
344   return count_ == mt->count_ &&
345          element_type_->IsSameImpl(mt->element_type_, seen) &&
346          HasSameDecorations(that);
347 }
348 
str() const349 std::string Matrix::str() const {
350   std::ostringstream oss;
351   oss << "<" << element_type_->str() << ", " << count_ << ">";
352   return oss.str();
353 }
354 
ComputeExtraStateHash(size_t hash,SeenTypes * seen) const355 size_t Matrix::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
356   hash = hash_combine(hash, count_);
357   return element_type_->ComputeHashValue(hash, seen);
358 }
359 
Image(Type * type,SpvDim dimen,uint32_t d,bool array,bool multisample,uint32_t sampling,SpvImageFormat f,SpvAccessQualifier qualifier)360 Image::Image(Type* type, SpvDim dimen, uint32_t d, bool array, bool multisample,
361              uint32_t sampling, SpvImageFormat f, SpvAccessQualifier qualifier)
362     : Type(kImage),
363       sampled_type_(type),
364       dim_(dimen),
365       depth_(d),
366       arrayed_(array),
367       ms_(multisample),
368       sampled_(sampling),
369       format_(f),
370       access_qualifier_(qualifier) {
371   // TODO(antiagainst): check sampled_type
372 }
373 
IsSameImpl(const Type * that,IsSameCache * seen) const374 bool Image::IsSameImpl(const Type* that, IsSameCache* seen) const {
375   const Image* it = that->AsImage();
376   if (!it) return false;
377   return dim_ == it->dim_ && depth_ == it->depth_ && arrayed_ == it->arrayed_ &&
378          ms_ == it->ms_ && sampled_ == it->sampled_ && format_ == it->format_ &&
379          access_qualifier_ == it->access_qualifier_ &&
380          sampled_type_->IsSameImpl(it->sampled_type_, seen) &&
381          HasSameDecorations(that);
382 }
383 
str() const384 std::string Image::str() const {
385   std::ostringstream oss;
386   oss << "image(" << sampled_type_->str() << ", " << dim_ << ", " << depth_
387       << ", " << arrayed_ << ", " << ms_ << ", " << sampled_ << ", " << format_
388       << ", " << access_qualifier_ << ")";
389   return oss.str();
390 }
391 
ComputeExtraStateHash(size_t hash,SeenTypes * seen) const392 size_t Image::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
393   hash = hash_combine(hash, uint32_t(dim_), depth_, arrayed_, ms_, sampled_,
394                       uint32_t(format_), uint32_t(access_qualifier_));
395   return sampled_type_->ComputeHashValue(hash, seen);
396 }
397 
IsSameImpl(const Type * that,IsSameCache * seen) const398 bool SampledImage::IsSameImpl(const Type* that, IsSameCache* seen) const {
399   const SampledImage* sit = that->AsSampledImage();
400   if (!sit) return false;
401   return image_type_->IsSameImpl(sit->image_type_, seen) &&
402          HasSameDecorations(that);
403 }
404 
str() const405 std::string SampledImage::str() const {
406   std::ostringstream oss;
407   oss << "sampled_image(" << image_type_->str() << ")";
408   return oss.str();
409 }
410 
ComputeExtraStateHash(size_t hash,SeenTypes * seen) const411 size_t SampledImage::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
412   return image_type_->ComputeHashValue(hash, seen);
413 }
414 
Array(const Type * type,const Array::LengthInfo & length_info_arg)415 Array::Array(const Type* type, const Array::LengthInfo& length_info_arg)
416     : Type(kArray), element_type_(type), length_info_(length_info_arg) {
417   assert(type != nullptr);
418   assert(!type->AsVoid());
419   // We always have a word to say which case we're in, followed
420   // by at least one more word.
421   assert(length_info_arg.words.size() >= 2);
422 }
423 
IsSameImpl(const Type * that,IsSameCache * seen) const424 bool Array::IsSameImpl(const Type* that, IsSameCache* seen) const {
425   const Array* at = that->AsArray();
426   if (!at) return false;
427   bool is_same = element_type_->IsSameImpl(at->element_type_, seen);
428   is_same = is_same && HasSameDecorations(that);
429   is_same = is_same && (length_info_.words == at->length_info_.words);
430   return is_same;
431 }
432 
str() const433 std::string Array::str() const {
434   std::ostringstream oss;
435   oss << "[" << element_type_->str() << ", id(" << LengthId() << "), words(";
436   const char* spacer = "";
437   for (auto w : length_info_.words) {
438     oss << spacer << w;
439     spacer = ",";
440   }
441   oss << ")]";
442   return oss.str();
443 }
444 
ComputeExtraStateHash(size_t hash,SeenTypes * seen) const445 size_t Array::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
446   hash = hash_combine(hash, length_info_.words);
447   return element_type_->ComputeHashValue(hash, seen);
448 }
449 
ReplaceElementType(const Type * type)450 void Array::ReplaceElementType(const Type* type) { element_type_ = type; }
451 
GetConstantLengthInfo(uint32_t const_id,uint32_t length) const452 Array::LengthInfo Array::GetConstantLengthInfo(uint32_t const_id,
453                                                uint32_t length) const {
454   std::vector<uint32_t> extra_words{LengthInfo::Case::kConstant, length};
455   return {const_id, extra_words};
456 }
457 
RuntimeArray(const Type * type)458 RuntimeArray::RuntimeArray(const Type* type)
459     : Type(kRuntimeArray), element_type_(type) {
460   assert(!type->AsVoid());
461 }
462 
IsSameImpl(const Type * that,IsSameCache * seen) const463 bool RuntimeArray::IsSameImpl(const Type* that, IsSameCache* seen) const {
464   const RuntimeArray* rat = that->AsRuntimeArray();
465   if (!rat) return false;
466   return element_type_->IsSameImpl(rat->element_type_, seen) &&
467          HasSameDecorations(that);
468 }
469 
str() const470 std::string RuntimeArray::str() const {
471   std::ostringstream oss;
472   oss << "[" << element_type_->str() << "]";
473   return oss.str();
474 }
475 
ComputeExtraStateHash(size_t hash,SeenTypes * seen) const476 size_t RuntimeArray::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
477   return element_type_->ComputeHashValue(hash, seen);
478 }
479 
ReplaceElementType(const Type * type)480 void RuntimeArray::ReplaceElementType(const Type* type) {
481   element_type_ = type;
482 }
483 
Struct(const std::vector<const Type * > & types)484 Struct::Struct(const std::vector<const Type*>& types)
485     : Type(kStruct), element_types_(types) {
486   for (const auto* t : types) {
487     (void)t;
488     assert(!t->AsVoid());
489   }
490 }
491 
AddMemberDecoration(uint32_t index,std::vector<uint32_t> && decoration)492 void Struct::AddMemberDecoration(uint32_t index,
493                                  std::vector<uint32_t>&& decoration) {
494   if (index >= element_types_.size()) {
495     assert(0 && "index out of bound");
496     return;
497   }
498 
499   element_decorations_[index].push_back(std::move(decoration));
500 }
501 
IsSameImpl(const Type * that,IsSameCache * seen) const502 bool Struct::IsSameImpl(const Type* that, IsSameCache* seen) const {
503   const Struct* st = that->AsStruct();
504   if (!st) return false;
505   if (element_types_.size() != st->element_types_.size()) return false;
506   const auto size = element_decorations_.size();
507   if (size != st->element_decorations_.size()) return false;
508   if (!HasSameDecorations(that)) return false;
509 
510   for (size_t i = 0; i < element_types_.size(); ++i) {
511     if (!element_types_[i]->IsSameImpl(st->element_types_[i], seen))
512       return false;
513   }
514   for (const auto& p : element_decorations_) {
515     if (st->element_decorations_.count(p.first) == 0) return false;
516     if (!CompareTwoVectors(p.second, st->element_decorations_.at(p.first)))
517       return false;
518   }
519   return true;
520 }
521 
str() const522 std::string Struct::str() const {
523   std::ostringstream oss;
524   oss << "{";
525   const size_t count = element_types_.size();
526   for (size_t i = 0; i < count; ++i) {
527     oss << element_types_[i]->str();
528     if (i + 1 != count) oss << ", ";
529   }
530   oss << "}";
531   return oss.str();
532 }
533 
ComputeExtraStateHash(size_t hash,SeenTypes * seen) const534 size_t Struct::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
535   for (auto* t : element_types_) {
536     hash = t->ComputeHashValue(hash, seen);
537   }
538   for (const auto& pair : element_decorations_) {
539     hash = hash_combine(hash, pair.first, pair.second);
540   }
541   return hash;
542 }
543 
IsSameImpl(const Type * that,IsSameCache *) const544 bool Opaque::IsSameImpl(const Type* that, IsSameCache*) const {
545   const Opaque* ot = that->AsOpaque();
546   if (!ot) return false;
547   return name_ == ot->name_ && HasSameDecorations(that);
548 }
549 
str() const550 std::string Opaque::str() const {
551   std::ostringstream oss;
552   oss << "opaque('" << name_ << "')";
553   return oss.str();
554 }
555 
ComputeExtraStateHash(size_t hash,SeenTypes *) const556 size_t Opaque::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
557   return hash_combine(hash, name_);
558 }
559 
Pointer(const Type * type,SpvStorageClass sc)560 Pointer::Pointer(const Type* type, SpvStorageClass sc)
561     : Type(kPointer), pointee_type_(type), storage_class_(sc) {}
562 
IsSameImpl(const Type * that,IsSameCache * seen) const563 bool Pointer::IsSameImpl(const Type* that, IsSameCache* seen) const {
564   const Pointer* pt = that->AsPointer();
565   if (!pt) return false;
566   if (storage_class_ != pt->storage_class_) return false;
567   auto p = seen->insert(std::make_pair(this, that->AsPointer()));
568   if (!p.second) {
569     return true;
570   }
571   bool same_pointee = pointee_type_->IsSameImpl(pt->pointee_type_, seen);
572   seen->erase(p.first);
573   if (!same_pointee) {
574     return false;
575   }
576   return HasSameDecorations(that);
577 }
578 
str() const579 std::string Pointer::str() const {
580   std::ostringstream os;
581   os << pointee_type_->str() << " " << static_cast<uint32_t>(storage_class_)
582      << "*";
583   return os.str();
584 }
585 
ComputeExtraStateHash(size_t hash,SeenTypes * seen) const586 size_t Pointer::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
587   hash = hash_combine(hash, uint32_t(storage_class_));
588   return pointee_type_->ComputeHashValue(hash, seen);
589 }
590 
SetPointeeType(const Type * type)591 void Pointer::SetPointeeType(const Type* type) { pointee_type_ = type; }
592 
Function(const Type * ret_type,const std::vector<const Type * > & params)593 Function::Function(const Type* ret_type, const std::vector<const Type*>& params)
594     : Type(kFunction), return_type_(ret_type), param_types_(params) {}
595 
Function(const Type * ret_type,std::vector<const Type * > & params)596 Function::Function(const Type* ret_type, std::vector<const Type*>& params)
597     : Type(kFunction), return_type_(ret_type), param_types_(params) {}
598 
IsSameImpl(const Type * that,IsSameCache * seen) const599 bool Function::IsSameImpl(const Type* that, IsSameCache* seen) const {
600   const Function* ft = that->AsFunction();
601   if (!ft) return false;
602   if (!return_type_->IsSameImpl(ft->return_type_, seen)) return false;
603   if (param_types_.size() != ft->param_types_.size()) return false;
604   for (size_t i = 0; i < param_types_.size(); ++i) {
605     if (!param_types_[i]->IsSameImpl(ft->param_types_[i], seen)) return false;
606   }
607   return HasSameDecorations(that);
608 }
609 
str() const610 std::string Function::str() const {
611   std::ostringstream oss;
612   const size_t count = param_types_.size();
613   oss << "(";
614   for (size_t i = 0; i < count; ++i) {
615     oss << param_types_[i]->str();
616     if (i + 1 != count) oss << ", ";
617   }
618   oss << ") -> " << return_type_->str();
619   return oss.str();
620 }
621 
ComputeExtraStateHash(size_t hash,SeenTypes * seen) const622 size_t Function::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
623   for (const auto* t : param_types_) {
624     hash = t->ComputeHashValue(hash, seen);
625   }
626   return return_type_->ComputeHashValue(hash, seen);
627 }
628 
SetReturnType(const Type * type)629 void Function::SetReturnType(const Type* type) { return_type_ = type; }
630 
IsSameImpl(const Type * that,IsSameCache *) const631 bool Pipe::IsSameImpl(const Type* that, IsSameCache*) const {
632   const Pipe* pt = that->AsPipe();
633   if (!pt) return false;
634   return access_qualifier_ == pt->access_qualifier_ && HasSameDecorations(that);
635 }
636 
str() const637 std::string Pipe::str() const {
638   std::ostringstream oss;
639   oss << "pipe(" << access_qualifier_ << ")";
640   return oss.str();
641 }
642 
ComputeExtraStateHash(size_t hash,SeenTypes *) const643 size_t Pipe::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
644   return hash_combine(hash, uint32_t(access_qualifier_));
645 }
646 
IsSameImpl(const Type * that,IsSameCache *) const647 bool ForwardPointer::IsSameImpl(const Type* that, IsSameCache*) const {
648   const ForwardPointer* fpt = that->AsForwardPointer();
649   if (!fpt) return false;
650   return (pointer_ && fpt->pointer_ ? *pointer_ == *fpt->pointer_
651                                     : target_id_ == fpt->target_id_) &&
652          storage_class_ == fpt->storage_class_ && HasSameDecorations(that);
653 }
654 
str() const655 std::string ForwardPointer::str() const {
656   std::ostringstream oss;
657   oss << "forward_pointer(";
658   if (pointer_ != nullptr) {
659     oss << pointer_->str();
660   } else {
661     oss << target_id_;
662   }
663   oss << ")";
664   return oss.str();
665 }
666 
ComputeExtraStateHash(size_t hash,SeenTypes * seen) const667 size_t ForwardPointer::ComputeExtraStateHash(size_t hash,
668                                              SeenTypes* seen) const {
669   hash = hash_combine(hash, target_id_, uint32_t(storage_class_));
670   if (pointer_) hash = pointer_->ComputeHashValue(hash, seen);
671   return hash;
672 }
673 
CooperativeMatrixNV(const Type * type,const uint32_t scope,const uint32_t rows,const uint32_t columns)674 CooperativeMatrixNV::CooperativeMatrixNV(const Type* type, const uint32_t scope,
675                                          const uint32_t rows,
676                                          const uint32_t columns)
677     : Type(kCooperativeMatrixNV),
678       component_type_(type),
679       scope_id_(scope),
680       rows_id_(rows),
681       columns_id_(columns) {
682   assert(type != nullptr);
683   assert(scope != 0);
684   assert(rows != 0);
685   assert(columns != 0);
686 }
687 
str() const688 std::string CooperativeMatrixNV::str() const {
689   std::ostringstream oss;
690   oss << "<" << component_type_->str() << ", " << scope_id_ << ", " << rows_id_
691       << ", " << columns_id_ << ">";
692   return oss.str();
693 }
694 
ComputeExtraStateHash(size_t hash,SeenTypes * seen) const695 size_t CooperativeMatrixNV::ComputeExtraStateHash(size_t hash,
696                                                   SeenTypes* seen) const {
697   hash = hash_combine(hash, scope_id_, rows_id_, columns_id_);
698   return component_type_->ComputeHashValue(hash, seen);
699 }
700 
IsSameImpl(const Type * that,IsSameCache * seen) const701 bool CooperativeMatrixNV::IsSameImpl(const Type* that,
702                                      IsSameCache* seen) const {
703   const CooperativeMatrixNV* mt = that->AsCooperativeMatrixNV();
704   if (!mt) return false;
705   return component_type_->IsSameImpl(mt->component_type_, seen) &&
706          scope_id_ == mt->scope_id_ && rows_id_ == mt->rows_id_ &&
707          columns_id_ == mt->columns_id_ && HasSameDecorations(that);
708 }
709 
710 }  // namespace analysis
711 }  // namespace opt
712 }  // namespace spvtools
713