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