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 <cstdint>
20 #include <sstream>
21 #include <string>
22 #include <unordered_set>
23 
24 #include "source/util/make_unique.h"
25 #include "spirv/unified1/spirv.h"
26 
27 namespace spvtools {
28 namespace opt {
29 namespace analysis {
30 
31 using U32VecVec = std::vector<std::vector<uint32_t>>;
32 
33 namespace {
34 
35 // Returns true if the two vector of vectors are identical.
CompareTwoVectors(const U32VecVec a,const U32VecVec b)36 bool CompareTwoVectors(const U32VecVec a, const U32VecVec b) {
37   const auto size = a.size();
38   if (size != b.size()) return false;
39 
40   if (size == 0) return true;
41   if (size == 1) return a.front() == b.front();
42 
43   std::vector<const std::vector<uint32_t>*> a_ptrs, b_ptrs;
44   a_ptrs.reserve(size);
45   a_ptrs.reserve(size);
46   for (uint32_t i = 0; i < size; ++i) {
47     a_ptrs.push_back(&a[i]);
48     b_ptrs.push_back(&b[i]);
49   }
50 
51   const auto cmp = [](const std::vector<uint32_t>* m,
52                       const std::vector<uint32_t>* n) {
53     return m->front() < n->front();
54   };
55 
56   std::sort(a_ptrs.begin(), a_ptrs.end(), cmp);
57   std::sort(b_ptrs.begin(), b_ptrs.end(), cmp);
58 
59   for (uint32_t i = 0; i < size; ++i) {
60     if (*a_ptrs[i] != *b_ptrs[i]) return false;
61   }
62   return true;
63 }
64 
65 }  // anonymous namespace
66 
GetDecorationStr() const67 std::string Type::GetDecorationStr() const {
68   std::ostringstream oss;
69   oss << "[[";
70   for (const auto& decoration : decorations_) {
71     oss << "(";
72     for (size_t i = 0; i < decoration.size(); ++i) {
73       oss << (i > 0 ? ", " : "");
74       oss << decoration.at(i);
75     }
76     oss << ")";
77   }
78   oss << "]]";
79   return oss.str();
80 }
81 
HasSameDecorations(const Type * that) const82 bool Type::HasSameDecorations(const Type* that) const {
83   return CompareTwoVectors(decorations_, that->decorations_);
84 }
85 
IsUniqueType(bool allowVariablePointers) const86 bool Type::IsUniqueType(bool allowVariablePointers) const {
87   switch (kind_) {
88     case kPointer:
89       return !allowVariablePointers;
90     case kStruct:
91     case kArray:
92     case kRuntimeArray:
93       return false;
94     default:
95       return true;
96   }
97 }
98 
Clone() const99 std::unique_ptr<Type> Type::Clone() const {
100   std::unique_ptr<Type> type;
101   switch (kind_) {
102 #define DeclareKindCase(kind)                   \
103   case k##kind:                                 \
104     type = MakeUnique<kind>(*this->As##kind()); \
105     break
106     DeclareKindCase(Void);
107     DeclareKindCase(Bool);
108     DeclareKindCase(Integer);
109     DeclareKindCase(Float);
110     DeclareKindCase(Vector);
111     DeclareKindCase(Matrix);
112     DeclareKindCase(Image);
113     DeclareKindCase(Sampler);
114     DeclareKindCase(SampledImage);
115     DeclareKindCase(Array);
116     DeclareKindCase(RuntimeArray);
117     DeclareKindCase(Struct);
118     DeclareKindCase(Opaque);
119     DeclareKindCase(Pointer);
120     DeclareKindCase(Function);
121     DeclareKindCase(Event);
122     DeclareKindCase(DeviceEvent);
123     DeclareKindCase(ReserveId);
124     DeclareKindCase(Queue);
125     DeclareKindCase(Pipe);
126     DeclareKindCase(ForwardPointer);
127     DeclareKindCase(PipeStorage);
128     DeclareKindCase(NamedBarrier);
129     DeclareKindCase(AccelerationStructureNV);
130     DeclareKindCase(CooperativeMatrixNV);
131 #undef DeclareKindCase
132     default:
133       assert(false && "Unhandled type");
134   }
135   return type;
136 }
137 
RemoveDecorations() const138 std::unique_ptr<Type> Type::RemoveDecorations() const {
139   std::unique_ptr<Type> type(Clone());
140   type->ClearDecorations();
141   return type;
142 }
143 
operator ==(const Type & other) const144 bool Type::operator==(const Type& other) const {
145   if (kind_ != other.kind_) return false;
146 
147   switch (kind_) {
148 #define DeclareKindCase(kind) \
149   case k##kind:               \
150     return As##kind()->IsSame(&other)
151     DeclareKindCase(Void);
152     DeclareKindCase(Bool);
153     DeclareKindCase(Integer);
154     DeclareKindCase(Float);
155     DeclareKindCase(Vector);
156     DeclareKindCase(Matrix);
157     DeclareKindCase(Image);
158     DeclareKindCase(Sampler);
159     DeclareKindCase(SampledImage);
160     DeclareKindCase(Array);
161     DeclareKindCase(RuntimeArray);
162     DeclareKindCase(Struct);
163     DeclareKindCase(Opaque);
164     DeclareKindCase(Pointer);
165     DeclareKindCase(Function);
166     DeclareKindCase(Event);
167     DeclareKindCase(DeviceEvent);
168     DeclareKindCase(ReserveId);
169     DeclareKindCase(Queue);
170     DeclareKindCase(Pipe);
171     DeclareKindCase(ForwardPointer);
172     DeclareKindCase(PipeStorage);
173     DeclareKindCase(NamedBarrier);
174     DeclareKindCase(AccelerationStructureNV);
175     DeclareKindCase(CooperativeMatrixNV);
176 #undef DeclareKindCase
177     default:
178       assert(false && "Unhandled type");
179       return false;
180   }
181 }
182 
GetHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > * seen) const183 void Type::GetHashWords(std::vector<uint32_t>* words,
184                         std::unordered_set<const Type*>* seen) const {
185   if (!seen->insert(this).second) {
186     return;
187   }
188 
189   words->push_back(kind_);
190   for (const auto& d : decorations_) {
191     for (auto w : d) {
192       words->push_back(w);
193     }
194   }
195 
196   switch (kind_) {
197 #define DeclareKindCase(type)                   \
198   case k##type:                                 \
199     As##type()->GetExtraHashWords(words, seen); \
200     break
201     DeclareKindCase(Void);
202     DeclareKindCase(Bool);
203     DeclareKindCase(Integer);
204     DeclareKindCase(Float);
205     DeclareKindCase(Vector);
206     DeclareKindCase(Matrix);
207     DeclareKindCase(Image);
208     DeclareKindCase(Sampler);
209     DeclareKindCase(SampledImage);
210     DeclareKindCase(Array);
211     DeclareKindCase(RuntimeArray);
212     DeclareKindCase(Struct);
213     DeclareKindCase(Opaque);
214     DeclareKindCase(Pointer);
215     DeclareKindCase(Function);
216     DeclareKindCase(Event);
217     DeclareKindCase(DeviceEvent);
218     DeclareKindCase(ReserveId);
219     DeclareKindCase(Queue);
220     DeclareKindCase(Pipe);
221     DeclareKindCase(ForwardPointer);
222     DeclareKindCase(PipeStorage);
223     DeclareKindCase(NamedBarrier);
224     DeclareKindCase(AccelerationStructureNV);
225     DeclareKindCase(CooperativeMatrixNV);
226 #undef DeclareKindCase
227     default:
228       assert(false && "Unhandled type");
229       break;
230   }
231 
232   seen->erase(this);
233 }
234 
HashValue() const235 size_t Type::HashValue() const {
236   std::u32string h;
237   std::vector<uint32_t> words;
238   GetHashWords(&words);
239   for (auto w : words) {
240     h.push_back(w);
241   }
242 
243   return std::hash<std::u32string>()(h);
244 }
245 
IsSameImpl(const Type * that,IsSameCache *) const246 bool Integer::IsSameImpl(const Type* that, IsSameCache*) const {
247   const Integer* it = that->AsInteger();
248   return it && width_ == it->width_ && signed_ == it->signed_ &&
249          HasSameDecorations(that);
250 }
251 
str() const252 std::string Integer::str() const {
253   std::ostringstream oss;
254   oss << (signed_ ? "s" : "u") << "int" << width_;
255   return oss.str();
256 }
257 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > *) const258 void Integer::GetExtraHashWords(std::vector<uint32_t>* words,
259                                 std::unordered_set<const Type*>*) const {
260   words->push_back(width_);
261   words->push_back(signed_);
262 }
263 
IsSameImpl(const Type * that,IsSameCache *) const264 bool Float::IsSameImpl(const Type* that, IsSameCache*) const {
265   const Float* ft = that->AsFloat();
266   return ft && width_ == ft->width_ && HasSameDecorations(that);
267 }
268 
str() const269 std::string Float::str() const {
270   std::ostringstream oss;
271   oss << "float" << width_;
272   return oss.str();
273 }
274 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > *) const275 void Float::GetExtraHashWords(std::vector<uint32_t>* words,
276                               std::unordered_set<const Type*>*) const {
277   words->push_back(width_);
278 }
279 
Vector(const Type * type,uint32_t count)280 Vector::Vector(const Type* type, uint32_t count)
281     : Type(kVector), element_type_(type), count_(count) {
282   assert(type->AsBool() || type->AsInteger() || type->AsFloat());
283 }
284 
IsSameImpl(const Type * that,IsSameCache * seen) const285 bool Vector::IsSameImpl(const Type* that, IsSameCache* seen) const {
286   const Vector* vt = that->AsVector();
287   if (!vt) return false;
288   return count_ == vt->count_ &&
289          element_type_->IsSameImpl(vt->element_type_, seen) &&
290          HasSameDecorations(that);
291 }
292 
str() const293 std::string Vector::str() const {
294   std::ostringstream oss;
295   oss << "<" << element_type_->str() << ", " << count_ << ">";
296   return oss.str();
297 }
298 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > * seen) const299 void Vector::GetExtraHashWords(std::vector<uint32_t>* words,
300                                std::unordered_set<const Type*>* seen) const {
301   element_type_->GetHashWords(words, seen);
302   words->push_back(count_);
303 }
304 
Matrix(const Type * type,uint32_t count)305 Matrix::Matrix(const Type* type, uint32_t count)
306     : Type(kMatrix), element_type_(type), count_(count) {
307   assert(type->AsVector());
308 }
309 
IsSameImpl(const Type * that,IsSameCache * seen) const310 bool Matrix::IsSameImpl(const Type* that, IsSameCache* seen) const {
311   const Matrix* mt = that->AsMatrix();
312   if (!mt) return false;
313   return count_ == mt->count_ &&
314          element_type_->IsSameImpl(mt->element_type_, seen) &&
315          HasSameDecorations(that);
316 }
317 
str() const318 std::string Matrix::str() const {
319   std::ostringstream oss;
320   oss << "<" << element_type_->str() << ", " << count_ << ">";
321   return oss.str();
322 }
323 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > * seen) const324 void Matrix::GetExtraHashWords(std::vector<uint32_t>* words,
325                                std::unordered_set<const Type*>* seen) const {
326   element_type_->GetHashWords(words, seen);
327   words->push_back(count_);
328 }
329 
Image(Type * type,SpvDim dimen,uint32_t d,bool array,bool multisample,uint32_t sampling,SpvImageFormat f,SpvAccessQualifier qualifier)330 Image::Image(Type* type, SpvDim dimen, uint32_t d, bool array, bool multisample,
331              uint32_t sampling, SpvImageFormat f, SpvAccessQualifier qualifier)
332     : Type(kImage),
333       sampled_type_(type),
334       dim_(dimen),
335       depth_(d),
336       arrayed_(array),
337       ms_(multisample),
338       sampled_(sampling),
339       format_(f),
340       access_qualifier_(qualifier) {
341   // TODO(antiagainst): check sampled_type
342 }
343 
IsSameImpl(const Type * that,IsSameCache * seen) const344 bool Image::IsSameImpl(const Type* that, IsSameCache* seen) const {
345   const Image* it = that->AsImage();
346   if (!it) return false;
347   return dim_ == it->dim_ && depth_ == it->depth_ && arrayed_ == it->arrayed_ &&
348          ms_ == it->ms_ && sampled_ == it->sampled_ && format_ == it->format_ &&
349          access_qualifier_ == it->access_qualifier_ &&
350          sampled_type_->IsSameImpl(it->sampled_type_, seen) &&
351          HasSameDecorations(that);
352 }
353 
str() const354 std::string Image::str() const {
355   std::ostringstream oss;
356   oss << "image(" << sampled_type_->str() << ", " << dim_ << ", " << depth_
357       << ", " << arrayed_ << ", " << ms_ << ", " << sampled_ << ", " << format_
358       << ", " << access_qualifier_ << ")";
359   return oss.str();
360 }
361 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > * seen) const362 void Image::GetExtraHashWords(std::vector<uint32_t>* words,
363                               std::unordered_set<const Type*>* seen) const {
364   sampled_type_->GetHashWords(words, seen);
365   words->push_back(dim_);
366   words->push_back(depth_);
367   words->push_back(arrayed_);
368   words->push_back(ms_);
369   words->push_back(sampled_);
370   words->push_back(format_);
371   words->push_back(access_qualifier_);
372 }
373 
IsSameImpl(const Type * that,IsSameCache * seen) const374 bool SampledImage::IsSameImpl(const Type* that, IsSameCache* seen) const {
375   const SampledImage* sit = that->AsSampledImage();
376   if (!sit) return false;
377   return image_type_->IsSameImpl(sit->image_type_, seen) &&
378          HasSameDecorations(that);
379 }
380 
str() const381 std::string SampledImage::str() const {
382   std::ostringstream oss;
383   oss << "sampled_image(" << image_type_->str() << ")";
384   return oss.str();
385 }
386 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > * seen) const387 void SampledImage::GetExtraHashWords(
388     std::vector<uint32_t>* words, std::unordered_set<const Type*>* seen) const {
389   image_type_->GetHashWords(words, seen);
390 }
391 
Array(const Type * type,const Array::LengthInfo & length_info_arg)392 Array::Array(const Type* type, const Array::LengthInfo& length_info_arg)
393     : Type(kArray), element_type_(type), length_info_(length_info_arg) {
394   assert(type != nullptr);
395   assert(!type->AsVoid());
396   // We always have a word to say which case we're in, followed
397   // by at least one more word.
398   assert(length_info_arg.words.size() >= 2);
399 }
400 
IsSameImpl(const Type * that,IsSameCache * seen) const401 bool Array::IsSameImpl(const Type* that, IsSameCache* seen) const {
402   const Array* at = that->AsArray();
403   if (!at) return false;
404   bool is_same = element_type_->IsSameImpl(at->element_type_, seen);
405   is_same = is_same && HasSameDecorations(that);
406   is_same = is_same && (length_info_.words == at->length_info_.words);
407   return is_same;
408 }
409 
str() const410 std::string Array::str() const {
411   std::ostringstream oss;
412   oss << "[" << element_type_->str() << ", id(" << LengthId() << "), words(";
413   const char* spacer = "";
414   for (auto w : length_info_.words) {
415     oss << spacer << w;
416     spacer = ",";
417   }
418   oss << ")]";
419   return oss.str();
420 }
421 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > * seen) const422 void Array::GetExtraHashWords(std::vector<uint32_t>* words,
423                               std::unordered_set<const Type*>* seen) const {
424   element_type_->GetHashWords(words, seen);
425   // This should mirror the logic in IsSameImpl
426   words->insert(words->end(), length_info_.words.begin(),
427                 length_info_.words.end());
428 }
429 
ReplaceElementType(const Type * type)430 void Array::ReplaceElementType(const Type* type) { element_type_ = type; }
431 
RuntimeArray(const Type * type)432 RuntimeArray::RuntimeArray(const Type* type)
433     : Type(kRuntimeArray), element_type_(type) {
434   assert(!type->AsVoid());
435 }
436 
IsSameImpl(const Type * that,IsSameCache * seen) const437 bool RuntimeArray::IsSameImpl(const Type* that, IsSameCache* seen) const {
438   const RuntimeArray* rat = that->AsRuntimeArray();
439   if (!rat) return false;
440   return element_type_->IsSameImpl(rat->element_type_, seen) &&
441          HasSameDecorations(that);
442 }
443 
str() const444 std::string RuntimeArray::str() const {
445   std::ostringstream oss;
446   oss << "[" << element_type_->str() << "]";
447   return oss.str();
448 }
449 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > * seen) const450 void RuntimeArray::GetExtraHashWords(
451     std::vector<uint32_t>* words, std::unordered_set<const Type*>* seen) const {
452   element_type_->GetHashWords(words, seen);
453 }
454 
ReplaceElementType(const Type * type)455 void RuntimeArray::ReplaceElementType(const Type* type) {
456   element_type_ = type;
457 }
458 
Struct(const std::vector<const Type * > & types)459 Struct::Struct(const std::vector<const Type*>& types)
460     : Type(kStruct), element_types_(types) {
461   for (const auto* t : types) {
462     (void)t;
463     assert(!t->AsVoid());
464   }
465 }
466 
AddMemberDecoration(uint32_t index,std::vector<uint32_t> && decoration)467 void Struct::AddMemberDecoration(uint32_t index,
468                                  std::vector<uint32_t>&& decoration) {
469   if (index >= element_types_.size()) {
470     assert(0 && "index out of bound");
471     return;
472   }
473 
474   element_decorations_[index].push_back(std::move(decoration));
475 }
476 
IsSameImpl(const Type * that,IsSameCache * seen) const477 bool Struct::IsSameImpl(const Type* that, IsSameCache* seen) const {
478   const Struct* st = that->AsStruct();
479   if (!st) return false;
480   if (element_types_.size() != st->element_types_.size()) return false;
481   const auto size = element_decorations_.size();
482   if (size != st->element_decorations_.size()) return false;
483   if (!HasSameDecorations(that)) return false;
484 
485   for (size_t i = 0; i < element_types_.size(); ++i) {
486     if (!element_types_[i]->IsSameImpl(st->element_types_[i], seen))
487       return false;
488   }
489   for (const auto& p : element_decorations_) {
490     if (st->element_decorations_.count(p.first) == 0) return false;
491     if (!CompareTwoVectors(p.second, st->element_decorations_.at(p.first)))
492       return false;
493   }
494   return true;
495 }
496 
str() const497 std::string Struct::str() const {
498   std::ostringstream oss;
499   oss << "{";
500   const size_t count = element_types_.size();
501   for (size_t i = 0; i < count; ++i) {
502     oss << element_types_[i]->str();
503     if (i + 1 != count) oss << ", ";
504   }
505   oss << "}";
506   return oss.str();
507 }
508 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > * seen) const509 void Struct::GetExtraHashWords(std::vector<uint32_t>* words,
510                                std::unordered_set<const Type*>* seen) const {
511   for (auto* t : element_types_) {
512     t->GetHashWords(words, seen);
513   }
514   for (const auto& pair : element_decorations_) {
515     words->push_back(pair.first);
516     for (const auto& d : pair.second) {
517       for (auto w : d) {
518         words->push_back(w);
519       }
520     }
521   }
522 }
523 
IsSameImpl(const Type * that,IsSameCache *) const524 bool Opaque::IsSameImpl(const Type* that, IsSameCache*) const {
525   const Opaque* ot = that->AsOpaque();
526   if (!ot) return false;
527   return name_ == ot->name_ && HasSameDecorations(that);
528 }
529 
str() const530 std::string Opaque::str() const {
531   std::ostringstream oss;
532   oss << "opaque('" << name_ << "')";
533   return oss.str();
534 }
535 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > *) const536 void Opaque::GetExtraHashWords(std::vector<uint32_t>* words,
537                                std::unordered_set<const Type*>*) const {
538   for (auto c : name_) {
539     words->push_back(static_cast<char32_t>(c));
540   }
541 }
542 
Pointer(const Type * type,SpvStorageClass sc)543 Pointer::Pointer(const Type* type, SpvStorageClass sc)
544     : Type(kPointer), pointee_type_(type), storage_class_(sc) {}
545 
IsSameImpl(const Type * that,IsSameCache * seen) const546 bool Pointer::IsSameImpl(const Type* that, IsSameCache* seen) const {
547   const Pointer* pt = that->AsPointer();
548   if (!pt) return false;
549   if (storage_class_ != pt->storage_class_) return false;
550   auto p = seen->insert(std::make_pair(this, that->AsPointer()));
551   if (!p.second) {
552     return true;
553   }
554   bool same_pointee = pointee_type_->IsSameImpl(pt->pointee_type_, seen);
555   seen->erase(p.first);
556   if (!same_pointee) {
557     return false;
558   }
559   return HasSameDecorations(that);
560 }
561 
str() const562 std::string Pointer::str() const {
563   std::ostringstream os;
564   os << pointee_type_->str() << " " << static_cast<uint32_t>(storage_class_)
565      << "*";
566   return os.str();
567 }
568 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > * seen) const569 void Pointer::GetExtraHashWords(std::vector<uint32_t>* words,
570                                 std::unordered_set<const Type*>* seen) const {
571   pointee_type_->GetHashWords(words, seen);
572   words->push_back(storage_class_);
573 }
574 
SetPointeeType(const Type * type)575 void Pointer::SetPointeeType(const Type* type) { pointee_type_ = type; }
576 
Function(const Type * ret_type,const std::vector<const Type * > & params)577 Function::Function(const Type* ret_type, const std::vector<const Type*>& params)
578     : Type(kFunction), return_type_(ret_type), param_types_(params) {}
579 
Function(const Type * ret_type,std::vector<const Type * > & params)580 Function::Function(const Type* ret_type, std::vector<const Type*>& params)
581     : Type(kFunction), return_type_(ret_type), param_types_(params) {}
582 
IsSameImpl(const Type * that,IsSameCache * seen) const583 bool Function::IsSameImpl(const Type* that, IsSameCache* seen) const {
584   const Function* ft = that->AsFunction();
585   if (!ft) return false;
586   if (!return_type_->IsSameImpl(ft->return_type_, seen)) return false;
587   if (param_types_.size() != ft->param_types_.size()) return false;
588   for (size_t i = 0; i < param_types_.size(); ++i) {
589     if (!param_types_[i]->IsSameImpl(ft->param_types_[i], seen)) return false;
590   }
591   return HasSameDecorations(that);
592 }
593 
str() const594 std::string Function::str() const {
595   std::ostringstream oss;
596   const size_t count = param_types_.size();
597   oss << "(";
598   for (size_t i = 0; i < count; ++i) {
599     oss << param_types_[i]->str();
600     if (i + 1 != count) oss << ", ";
601   }
602   oss << ") -> " << return_type_->str();
603   return oss.str();
604 }
605 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > * seen) const606 void Function::GetExtraHashWords(std::vector<uint32_t>* words,
607                                  std::unordered_set<const Type*>* seen) const {
608   return_type_->GetHashWords(words, seen);
609   for (const auto* t : param_types_) {
610     t->GetHashWords(words, seen);
611   }
612 }
613 
SetReturnType(const Type * type)614 void Function::SetReturnType(const Type* type) { return_type_ = type; }
615 
IsSameImpl(const Type * that,IsSameCache *) const616 bool Pipe::IsSameImpl(const Type* that, IsSameCache*) const {
617   const Pipe* pt = that->AsPipe();
618   if (!pt) return false;
619   return access_qualifier_ == pt->access_qualifier_ && HasSameDecorations(that);
620 }
621 
str() const622 std::string Pipe::str() const {
623   std::ostringstream oss;
624   oss << "pipe(" << access_qualifier_ << ")";
625   return oss.str();
626 }
627 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > *) const628 void Pipe::GetExtraHashWords(std::vector<uint32_t>* words,
629                              std::unordered_set<const Type*>*) const {
630   words->push_back(access_qualifier_);
631 }
632 
IsSameImpl(const Type * that,IsSameCache *) const633 bool ForwardPointer::IsSameImpl(const Type* that, IsSameCache*) const {
634   const ForwardPointer* fpt = that->AsForwardPointer();
635   if (!fpt) return false;
636   return (pointer_ && fpt->pointer_ ? *pointer_ == *fpt->pointer_
637                                     : target_id_ == fpt->target_id_) &&
638          storage_class_ == fpt->storage_class_ && HasSameDecorations(that);
639 }
640 
str() const641 std::string ForwardPointer::str() const {
642   std::ostringstream oss;
643   oss << "forward_pointer(";
644   if (pointer_ != nullptr) {
645     oss << pointer_->str();
646   } else {
647     oss << target_id_;
648   }
649   oss << ")";
650   return oss.str();
651 }
652 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > * seen) const653 void ForwardPointer::GetExtraHashWords(
654     std::vector<uint32_t>* words, std::unordered_set<const Type*>* seen) const {
655   words->push_back(target_id_);
656   words->push_back(storage_class_);
657   if (pointer_) pointer_->GetHashWords(words, seen);
658 }
659 
CooperativeMatrixNV(const Type * type,const uint32_t scope,const uint32_t rows,const uint32_t columns)660 CooperativeMatrixNV::CooperativeMatrixNV(const Type* type, const uint32_t scope,
661                                          const uint32_t rows,
662                                          const uint32_t columns)
663     : Type(kCooperativeMatrixNV),
664       component_type_(type),
665       scope_id_(scope),
666       rows_id_(rows),
667       columns_id_(columns) {
668   assert(type != nullptr);
669   assert(scope != 0);
670   assert(rows != 0);
671   assert(columns != 0);
672 }
673 
str() const674 std::string CooperativeMatrixNV::str() const {
675   std::ostringstream oss;
676   oss << "<" << component_type_->str() << ", " << scope_id_ << ", " << rows_id_
677       << ", " << columns_id_ << ">";
678   return oss.str();
679 }
680 
GetExtraHashWords(std::vector<uint32_t> * words,std::unordered_set<const Type * > * pSet) const681 void CooperativeMatrixNV::GetExtraHashWords(
682     std::vector<uint32_t>* words, std::unordered_set<const Type*>* pSet) const {
683   component_type_->GetHashWords(words, pSet);
684   words->push_back(scope_id_);
685   words->push_back(rows_id_);
686   words->push_back(columns_id_);
687 }
688 
IsSameImpl(const Type * that,IsSameCache * seen) const689 bool CooperativeMatrixNV::IsSameImpl(const Type* that,
690                                      IsSameCache* seen) const {
691   const CooperativeMatrixNV* mt = that->AsCooperativeMatrixNV();
692   if (!mt) return false;
693   return component_type_->IsSameImpl(mt->component_type_, seen) &&
694          scope_id_ == mt->scope_id_ && rows_id_ == mt->rows_id_ &&
695          columns_id_ == mt->columns_id_ && HasSameDecorations(that);
696 }
697 
698 }  // namespace analysis
699 }  // namespace opt
700 }  // namespace spvtools
701