v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
types.cc
Go to the documentation of this file.
1// Copyright 2022 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <optional>
8#include <sstream>
9#include <string_view>
10
11#include "src/base/logging.h"
13#include "src/heap/factory.h"
15
17
18namespace {
19
20std::pair<uint32_t, uint32_t> uint64_to_high_low(uint64_t value) {
21 return {static_cast<uint32_t>(value >> 32), static_cast<uint32_t>(value)};
22}
23
24} // namespace
25
26bool Type::Equals(const Type& other) const {
27 DCHECK(!IsInvalid());
28 DCHECK(!other.IsInvalid());
29
30 if (kind_ != other.kind_) return false;
31 switch (kind_) {
32 case Kind::kInvalid:
34 case Kind::kNone:
35 return true;
36 case Kind::kWord32:
37 return AsWord32().Equals(other.AsWord32());
38 case Kind::kWord64:
39 return AsWord64().Equals(other.AsWord64());
40 case Kind::kFloat32:
41 return AsFloat32().Equals(other.AsFloat32());
42 case Kind::kFloat64:
43 return AsFloat64().Equals(other.AsFloat64());
44 case Kind::kTuple:
45 return AsTuple().Equals(other.AsTuple());
46 case Kind::kAny:
47 return true;
48 }
49}
50
51bool Type::IsSubtypeOf(const Type& other) const {
52 DCHECK(!IsInvalid());
53 DCHECK(!other.IsInvalid());
54
55 if (other.IsAny() || IsNone()) return true;
56 if (kind_ != other.kind_) return false;
57
58 switch (kind_) {
59 case Kind::kInvalid:
60 case Kind::kNone:
62 case Kind::kWord32:
63 return AsWord32().IsSubtypeOf(other.AsWord32());
64 case Kind::kWord64:
65 return AsWord64().IsSubtypeOf(other.AsWord64());
66 case Kind::kFloat32:
67 return AsFloat32().IsSubtypeOf(other.AsFloat32());
68 case Kind::kFloat64:
69 return AsFloat64().IsSubtypeOf(other.AsFloat64());
70 case Kind::kTuple:
71 return AsTuple().IsSubtypeOf(other.AsTuple());
72 case Kind::kAny:
74 }
75}
76
77void Type::PrintTo(std::ostream& stream) const {
78 switch (kind_) {
79 case Kind::kInvalid:
81 case Kind::kNone:
82 stream << "None";
83 break;
84 case Kind::kWord32: {
85 AsWord32().PrintTo(stream);
86 break;
87 }
88 case Kind::kWord64: {
89 AsWord64().PrintTo(stream);
90 break;
91 }
92 case Kind::kFloat32: {
93 AsFloat32().PrintTo(stream);
94 break;
95 }
96 case Kind::kFloat64: {
97 AsFloat64().PrintTo(stream);
98 break;
99 }
100 case Kind::kTuple: {
101 AsTuple().PrintTo(stream);
102 break;
103 }
104 case Kind::kAny: {
105 stream << "Any";
106 break;
107 }
108 }
109}
110
111void Type::Print() const {
112 StdoutStream os;
113 PrintTo(os);
114 os << '\n';
115}
116
117// static
118Type Type::LeastUpperBound(const Type& lhs, const Type& rhs, Zone* zone) {
119 if (lhs.IsAny() || rhs.IsAny()) return Type::Any();
120 if (lhs.IsNone()) return rhs;
121 if (rhs.IsNone()) return lhs;
122
123 // TODO(nicohartmann@): We might use more precise types here but currently
124 // there is not much benefit in that.
125 if (lhs.kind() != rhs.kind()) return Type::Any();
126
127 switch (lhs.kind()) {
130 case Type::Kind::kAny:
131 UNREACHABLE();
133 return Word32Type::LeastUpperBound(lhs.AsWord32(), rhs.AsWord32(), zone);
135 return Word64Type::LeastUpperBound(lhs.AsWord64(), rhs.AsWord64(), zone);
138 zone);
141 zone);
143 return TupleType::LeastUpperBound(lhs.AsTuple(), rhs.AsTuple(), zone);
144 }
145}
146
147std::optional<Type> Type::ParseFromString(const std::string_view& str,
148 Zone* zone) {
149 TypeParser parser(str, zone);
150 return parser.Parse();
151}
152
154 DCHECK_NOT_NULL(factory);
155 switch (kind_) {
156 case Kind::kInvalid:
157 UNREACHABLE();
158 case Kind::kNone:
160 case Kind::kWord32:
161 return AsWord32().AllocateOnHeap(factory);
162 case Kind::kWord64:
163 return AsWord64().AllocateOnHeap(factory);
164 case Kind::kFloat32:
165 return AsFloat32().AllocateOnHeap(factory);
166 case Kind::kFloat64:
167 return AsFloat64().AllocateOnHeap(factory);
168 case Kind::kTuple:
170 case Kind::kAny:
172 }
173}
174
175template <size_t Bits>
177 switch (sub_kind()) {
178 case SubKind::kRange: {
179 if (is_wrapping()) return range_to() >= value || range_from() <= value;
180 return range_from() <= value && value <= range_to();
181 }
182 case SubKind::kSet: {
183 for (int i = 0; i < set_size(); ++i) {
184 if (set_element(i) == value) return true;
185 }
186 return false;
187 }
188 }
189}
190
191template <size_t Bits>
192bool WordType<Bits>::Equals(const WordType<Bits>& other) const {
193 if (sub_kind() != other.sub_kind()) return false;
194 switch (sub_kind()) {
195 case SubKind::kRange:
196 return (range_from() == other.range_from() &&
197 range_to() == other.range_to()) ||
198 (is_any() && other.is_any());
199 case SubKind::kSet: {
200 if (set_size() != other.set_size()) return false;
201 for (int i = 0; i < set_size(); ++i) {
202 if (set_element(i) != other.set_element(i)) return false;
203 }
204 return true;
205 }
206 }
207}
208
209template <size_t Bits>
211 if (other.is_any()) return true;
212 switch (sub_kind()) {
213 case SubKind::kRange: {
214 if (other.is_set()) return false;
215 DCHECK(other.is_range());
216 if (is_wrapping() == other.is_wrapping()) {
217 return range_from() >= other.range_from() &&
218 range_to() <= other.range_to();
219 }
220 return !is_wrapping() && (range_to() <= other.range_to() ||
221 range_from() >= other.range_from());
222 }
223 case SubKind::kSet: {
224 if (other.is_set() && set_size() > other.set_size()) return false;
225 for (int i = 0; i < set_size(); ++i) {
226 if (!other.Contains(set_element(i))) return false;
227 }
228 return true;
229 }
230 }
231}
232
233template <size_t Bits, typename word_t = typename WordType<Bits>::word_t>
235 word_t r_from, word_t r_to,
236 Zone* zone) {
237 const bool lhs_wrapping = l_to < l_from;
238 const bool rhs_wrapping = r_to < r_from;
239 // Case 1: Both ranges non-wrapping
240 // lhs ---|XXX|-- --|XXX|--- -|XXXXXX|- ---|XX|--- -|XX|------
241 // rhs -|XXX|---- ----|XXX|- ---|XX|--- -|XXXXXX|- ------|XX|-
242 // ==> -|XXXXX|-- --|XXXXX|- -|XXXXXX|- -|XXXXXX|- -|XXXXXXX|-
243 if (!lhs_wrapping && !rhs_wrapping) {
244 return WordType<Bits>::Range(std::min(l_from, r_from), std::max(l_to, r_to),
245 zone);
246 }
247 // Case 2: Both ranges wrapping
248 // lhs XXX|----|XXX X|---|XXXXXX XXXXXX|---|X XX|--|XXXXXX
249 // rhs X|---|XXXXXX XXX|----|XXX XX|--|XXXXXX XXXXXX|--|XX
250 // ==> XXX|-|XXXXXX XXX|-|XXXXXX XXXXXXXXXXXX XXXXXXXXXXXX
251 if (lhs_wrapping && rhs_wrapping) {
252 const auto from = std::min(l_from, r_from);
253 const auto to = std::max(l_to, r_to);
254 if (to >= from) return WordType<Bits>::Any();
255 auto result = WordType<Bits>::Range(from, to, zone);
256 DCHECK(result.is_wrapping());
257 return result;
258 }
259
260 if (rhs_wrapping)
261 return LeastUpperBoundFromRanges<Bits>(r_from, r_to, l_from, l_to, zone);
262 DCHECK(lhs_wrapping);
263 DCHECK(!rhs_wrapping);
264 // Case 3 & 4: lhs is wrapping, rhs is not
265 // lhs XXX|----|XXX XXX|----|XXX XXXXX|--|XXX X|-------|XX
266 // rhs -------|XX|- -|XX|------- ----|XXXXX|- ---|XX|-----
267 // ==> XXX|---|XXXX XXXX|---|XXX XXXXXXXXXXXX XXXXXX|--|XX
268 if (r_from <= l_to) {
269 if (r_to <= l_to)
270 return WordType<Bits>::Range(l_from, l_to, zone); // y covered by x
271 if (r_to >= l_from) return WordType<Bits>::Any(); // ex3
272 auto result = WordType<Bits>::Range(l_from, r_to, zone); // ex 1
273 DCHECK(result.is_wrapping());
274 return result;
275 } else if (r_to >= l_from) {
276 if (r_from >= l_from)
277 return WordType<Bits>::Range(l_from, l_to, zone); // y covered by x
278 DCHECK_GT(r_from, l_to); // handled above
279 auto result = WordType<Bits>::Range(r_from, l_to, zone); // ex 2
280 DCHECK(result.is_wrapping());
281 return result;
282 } else {
283 const auto df = r_from - l_to;
284 const auto dt = l_from - r_to;
286 df > dt ? WordType<Bits>::Range(r_from, l_to, zone) // ex 4
287 : WordType<Bits>::Range(l_from, r_to, zone);
288 DCHECK(result.is_wrapping());
289 return result;
290 }
291}
292
293template <size_t Bits>
294// static
296 const WordType<Bits>& rhs,
297 Zone* zone) {
298 if (lhs.is_set()) {
299 if (!rhs.is_set()) {
300 if (lhs.set_size() == 1) {
301 word_t e = lhs.set_element(0);
302 if (rhs.is_wrapping()) {
303 // If {rhs} already contains e, {rhs} is the upper bound.
304 if (e <= rhs.range_to() || rhs.range_from() <= e) return rhs;
305 return (e - rhs.range_to() < rhs.range_from() - e)
306 ? Range(rhs.range_from(), e, zone)
307 : Range(e, rhs.range_to(), zone);
308 }
309 return Range(std::min(e, rhs.range_from()), std::max(e, rhs.range_to()),
310 zone);
311 }
312
313 // TODO(nicohartmann@): A wrapping range may be a better fit in some
314 // cases.
316 lhs.unsigned_min(), lhs.unsigned_max(), rhs.range_from(),
317 rhs.range_to(), zone);
318 }
319
320 // Both sides are sets. We try to construct the combined set.
322 base::vector_append(result_elements, lhs.set_elements());
323 base::vector_append(result_elements, rhs.set_elements());
324 DCHECK(!result_elements.empty());
325 base::sort(result_elements);
326 auto it = std::unique(result_elements.begin(), result_elements.end());
327 result_elements.pop_back(std::distance(it, result_elements.end()));
328 if (result_elements.size() <= kMaxSetSize) {
329 return Set(result_elements, zone);
330 }
331 // We have to construct a range instead.
332 // TODO(nicohartmann@): A wrapping range may be a better fit in some cases.
333 return Range(result_elements.front(), result_elements.back(), zone);
334 } else if (rhs.is_set()) {
335 return LeastUpperBound(rhs, lhs, zone);
336 }
337
338 // Both sides are ranges.
340 lhs.range_from(), lhs.range_to(), rhs.range_from(), rhs.range_to(), zone);
341}
342
343template <size_t Bits>
345 const WordType<Bits>& rhs,
346 ResolutionMode resolution_mode, Zone* zone) {
347 if (lhs.is_any()) return rhs;
348 if (rhs.is_any()) return lhs;
349
350 if (lhs.is_set() || rhs.is_set()) {
351 const auto& x = lhs.is_set() ? lhs : rhs;
352 const auto& y = lhs.is_set() ? rhs : lhs;
354 for (int i = 0; i < x.set_size(); ++i) {
355 const word_t element = x.set_element(i);
356 if (y.Contains(element)) result_elements.push_back(element);
357 }
358 if (result_elements.empty()) return Type::None();
359 DCHECK(detail::is_unique_and_sorted(result_elements));
360 return Set(result_elements, zone);
361 }
362
363 DCHECK(lhs.is_range() && rhs.is_range());
364 const bool lhs_wrapping = lhs.is_wrapping();
365 if (!lhs_wrapping && !rhs.is_wrapping()) {
366 const auto result_from = std::max(lhs.range_from(), rhs.range_from());
367 const auto result_to = std::min(lhs.range_to(), rhs.range_to());
368 return result_to < result_from
369 ? Type::None()
370 : WordType::Range(result_from, result_to, zone);
371 }
372
373 if (lhs_wrapping && rhs.is_wrapping()) {
374 const auto result_from = std::max(lhs.range_from(), rhs.range_from());
375 const auto result_to = std::min(lhs.range_to(), rhs.range_to());
376 auto result = WordType::Range(result_from, result_to, zone);
377 DCHECK(result.is_wrapping());
378 return result;
379 }
380
381 const auto& x = lhs_wrapping ? lhs : rhs;
382 const auto& y = lhs_wrapping ? rhs : lhs;
383 DCHECK(x.is_wrapping());
384 DCHECK(!y.is_wrapping());
385 auto subrange_low = Intersect(y, Range(0, x.range_to(), zone),
386 ResolutionMode::kPreciseOrInvalid, zone);
387 DCHECK(!subrange_low.IsInvalid());
388 auto subrange_high = Intersect(
389 y, Range(x.range_from(), std::numeric_limits<word_t>::max(), zone),
390 ResolutionMode::kPreciseOrInvalid, zone);
391 DCHECK(!subrange_high.IsInvalid());
392
393 if (subrange_low.IsNone()) return subrange_high;
394 if (subrange_high.IsNone()) return subrange_low;
395 auto s_l = subrange_low.template AsWord<Bits>();
396 auto s_h = subrange_high.template AsWord<Bits>();
397
398 switch (resolution_mode) {
399 case ResolutionMode::kPreciseOrInvalid:
400 return Type::Invalid();
401 case ResolutionMode::kOverApproximate:
402 return LeastUpperBound(s_l, s_h, zone);
403 case ResolutionMode::kGreatestLowerBound:
404 return (s_l.unsigned_max() - s_l.unsigned_min() <
405 s_h.unsigned_max() - s_h.unsigned_min())
406 ? s_h
407 : s_l;
408 }
409}
410
411template <size_t Bits>
412void WordType<Bits>::PrintTo(std::ostream& stream) const {
413 stream << (Bits == 32 ? "Word32" : "Word64");
414 switch (sub_kind()) {
415 case SubKind::kRange:
416 stream << "[0x" << std::hex << range_from() << ", 0x" << range_to()
417 << std::dec << "]";
418 break;
419 case SubKind::kSet:
420 stream << "{" << std::hex;
421 for (int i = 0; i < set_size(); ++i) {
422 stream << (i == 0 ? "0x" : ", 0x");
423 stream << set_element(i);
424 }
425 stream << std::dec << "}";
426 break;
427 }
428}
429
430template <size_t Bits>
432 if constexpr (Bits == 32) {
433 if (is_range()) {
434 return factory->NewTurboshaftWord32RangeType(range_from(), range_to(),
436 } else {
437 DCHECK(is_set());
438 auto result = factory->NewTurboshaftWord32SetType(set_size(),
440 for (int i = 0; i < set_size(); ++i) {
441 result->set_elements(i, set_element(i));
442 }
443 return result;
444 }
445 } else {
446 if (is_range()) {
447 const auto [from_high, from_low] = uint64_to_high_low(range_from());
448 const auto [to_high, to_low] = uint64_to_high_low(range_to());
449 return factory->NewTurboshaftWord64RangeType(
450 from_high, from_low, to_high, to_low, AllocationType::kYoung);
451 } else {
452 DCHECK(is_set());
453 auto result = factory->NewTurboshaftWord64SetType(set_size(),
455 for (int i = 0; i < set_size(); ++i) {
456 const auto [high, low] = uint64_to_high_low(set_element(i));
457 result->set_elements_high(i, high);
458 result->set_elements_low(i, low);
459 }
460 return result;
461 }
462 }
463}
464
465template <size_t Bits>
467 if (IsMinusZero(value)) return has_minus_zero();
468 if (std::isnan(value)) return has_nan();
469 switch (sub_kind()) {
470 case SubKind::kOnlySpecialValues:
471 return false;
472 case SubKind::kRange: {
473 return range_min() <= value && value <= range_max();
474 }
475 case SubKind::kSet: {
476 for (int i = 0; i < set_size(); ++i) {
477 if (set_element(i) == value) return true;
478 }
479 return false;
480 }
481 }
482}
483
484template <size_t Bits>
485bool FloatType<Bits>::Equals(const FloatType<Bits>& other) const {
486 if (sub_kind() != other.sub_kind()) return false;
487 if (special_values() != other.special_values()) return false;
488 switch (sub_kind()) {
489 case SubKind::kOnlySpecialValues:
490 return true;
491 case SubKind::kRange: {
492 return range() == other.range();
493 }
494 case SubKind::kSet: {
495 if (set_size() != other.set_size()) {
496 return false;
497 }
498 for (int i = 0; i < set_size(); ++i) {
499 if (set_element(i) != other.set_element(i)) return false;
500 }
501 return true;
502 }
503 }
504}
505
506template <size_t Bits>
508 if (special_values() & ~other.special_values()) return false;
509 switch (sub_kind()) {
510 case SubKind::kOnlySpecialValues:
511 return true;
512 case SubKind::kRange:
513 if (!other.is_range()) {
514 // This relies on the fact that we don't have singleton ranges.
515 DCHECK_NE(range_min(), range_max());
516 return false;
517 }
518 return other.range_min() <= range_min() &&
519 range_max() <= other.range_max();
520 case SubKind::kSet: {
521 switch (other.sub_kind()) {
522 case SubKind::kOnlySpecialValues:
523 return false;
524 case SubKind::kRange:
525 return other.range_min() <= min() && max() <= other.range_max();
526 case SubKind::kSet:
527 for (int i = 0; i < set_size(); ++i) {
528 if (!other.Contains(set_element(i))) return false;
529 }
530 return true;
531 }
532 }
533 }
534}
535
536template <size_t Bits>
537// static
539 const FloatType<Bits>& rhs,
540 Zone* zone) {
541 uint32_t special_values = lhs.special_values() | rhs.special_values();
542 if (lhs.is_any() || rhs.is_any()) {
543 return Any(special_values);
544 }
545
546 const bool lhs_finite = lhs.is_set() || lhs.is_only_special_values();
547 const bool rhs_finite = rhs.is_set() || rhs.is_only_special_values();
548
549 if (lhs_finite && rhs_finite) {
551 if (lhs.is_set()) base::vector_append(result_elements, lhs.set_elements());
552 if (rhs.is_set()) base::vector_append(result_elements, rhs.set_elements());
553 if (result_elements.empty()) {
554 return OnlySpecialValues(special_values);
555 }
556 base::sort(result_elements);
557 auto it = std::unique(result_elements.begin(), result_elements.end());
558 result_elements.pop_back(std::distance(it, result_elements.end()));
559 if (result_elements.size() <= kMaxSetSize) {
560 return Set(result_elements, special_values, zone);
561 }
562 return Range(result_elements.front(), result_elements.back(),
563 special_values, zone);
564 } else if (lhs.is_only_special_values()) {
565 return ReplacedSpecialValues(rhs, special_values).template AsFloat<Bits>();
566 } else if (rhs.is_only_special_values()) {
567 return ReplacedSpecialValues(lhs, special_values).template AsFloat<Bits>();
568 }
569
570 // We need to construct a range.
571 float_t result_min = std::min(lhs.range_or_set_min(), rhs.range_or_set_min());
572 float_t result_max = std::max(lhs.range_or_set_max(), rhs.range_or_set_max());
573 return Range(result_min, result_max, special_values, zone);
574}
575
576template <size_t Bits>
577// static
579 const FloatType<Bits>& rhs, Zone* zone) {
580 const uint32_t special_values = lhs.special_values() & rhs.special_values();
581 if (lhs.is_any()) return ReplacedSpecialValues(rhs, special_values);
582 if (rhs.is_any()) return ReplacedSpecialValues(lhs, special_values);
584 return special_values ? OnlySpecialValues(special_values) : Type::None();
585 }
586
587 if (lhs.is_set() || rhs.is_set()) {
588 const auto& x = lhs.is_set() ? lhs : rhs;
589 const auto& y = lhs.is_set() ? rhs : lhs;
591 for (int i = 0; i < x.set_size(); ++i) {
592 const float_t element = x.set_element(i);
593 if (y.Contains(element)) result_elements.push_back(element);
594 }
595 if (result_elements.empty()) {
596 return special_values ? OnlySpecialValues(special_values) : Type::None();
597 }
598 return Set(result_elements, special_values, zone);
599 }
600
601 DCHECK(lhs.is_range() && rhs.is_range());
602 const float_t result_min = std::max(lhs.min(), rhs.min());
603 const float_t result_max = std::min(lhs.max(), rhs.max());
604 if (result_min < result_max) {
605 return Range(result_min, result_max, special_values, zone);
606 } else if (result_min == result_max) {
607 return Set({result_min}, special_values, zone);
608 }
609 return special_values ? OnlySpecialValues(special_values) : Type::None();
610}
611
612template <size_t Bits>
613void FloatType<Bits>::PrintTo(std::ostream& stream) const {
614 auto PrintSpecials = [this](auto& stream) {
615 if (has_nan()) {
616 stream << "NaN" << (has_minus_zero() ? "|MinusZero" : "");
617 } else {
618 DCHECK(has_minus_zero());
619 stream << "MinusZero";
620 }
621 };
622 stream << (Bits == 32 ? "Float32" : "Float64");
623 switch (sub_kind()) {
624 case SubKind::kOnlySpecialValues:
625 PrintSpecials(stream);
626 break;
627 case SubKind::kRange:
628 stream << "[" << range_min() << ", " << range_max() << "]";
629 if (has_special_values()) {
630 stream << "|";
631 PrintSpecials(stream);
632 }
633 break;
634 case SubKind::kSet:
635 stream << "{";
636 for (int i = 0; i < set_size(); ++i) {
637 if (i != 0) stream << ", ";
638 stream << set_element(i);
639 }
640 if (has_special_values()) {
641 stream << "}|";
642 PrintSpecials(stream);
643 } else {
644 stream << "}";
645 }
646 break;
647 }
648}
649
650template <size_t Bits>
652 float_t min = 0.0f, max = 0.0f;
653 constexpr uint32_t padding = 0;
654 if (is_only_special_values()) {
655 min = std::numeric_limits<float_t>::infinity();
656 max = -std::numeric_limits<float_t>::infinity();
657 return factory->NewTurboshaftFloat64RangeType(
658 special_values(), padding, min, max, AllocationType::kYoung);
659 } else if (is_range()) {
660 std::tie(min, max) = minmax();
661 return factory->NewTurboshaftFloat64RangeType(
662 special_values(), padding, min, max, AllocationType::kYoung);
663 } else {
664 DCHECK(is_set());
665 auto result = factory->NewTurboshaftFloat64SetType(
666 special_values(), set_size(), AllocationType::kYoung);
667 for (int i = 0; i < set_size(); ++i) {
668 result->set_elements(i, set_element(i));
669 }
670 return result;
671 }
672}
673
674bool TupleType::Equals(const TupleType& other) const {
675 if (size() != other.size()) return false;
676 for (int i = 0; i < size(); ++i) {
677 if (!element(i).Equals(other.element(i))) return false;
678 }
679 return true;
680}
681
682bool TupleType::IsSubtypeOf(const TupleType& other) const {
683 if (size() != other.size()) return false;
684 for (int i = 0; i < size(); ++i) {
685 if (!element(i).IsSubtypeOf(other.element(i))) return false;
686 }
687 return true;
688}
689
690// static
692 Zone* zone) {
693 if (lhs.size() != rhs.size()) return Type::Any();
694 Payload p;
695 p.array = zone->AllocateArray<Type>(lhs.size());
696 for (int i = 0; i < lhs.size(); ++i) {
697 p.array[i] = Type::LeastUpperBound(lhs.element(i), rhs.element(i), zone);
698 }
699 return TupleType{static_cast<uint8_t>(lhs.size()), p};
700}
701
702void TupleType::PrintTo(std::ostream& stream) const {
703 stream << "(";
704 for (int i = 0; i < size(); ++i) {
705 if (i != 0) stream << ", ";
706 element(i).PrintTo(stream);
707 }
708 stream << ")";
709}
710
715
716} // namespace v8::internal::compiler::turboshaft
void pop_back(size_t count=1)
size_t size() const
T * AllocateArray(size_t length)
Definition zone.h:127
static Type Intersect(const FloatType &lhs, const FloatType &rhs, Zone *zone)
Definition types.cc:578
bool Equals(const FloatType &other) const
Definition types.cc:485
void PrintTo(std::ostream &stream) const
Definition types.cc:613
bool IsSubtypeOf(const FloatType &other) const
Definition types.cc:507
base::Vector< const float_t > set_elements() const
Definition types.h:676
bool Contains(float_t value) const
Definition types.cc:466
static FloatType LeastUpperBound(const FloatType &lhs, const FloatType &rhs, Zone *zone)
Definition types.cc:538
Handle< TurboshaftType > AllocateOnHeap(Factory *factory) const
Definition types.cc:651
static Type LeastUpperBound(const TupleType &lhs, const TupleType &rhs, Zone *zone)
Definition types.cc:691
bool Equals(const TupleType &other) const
Definition types.cc:674
bool IsSubtypeOf(const TupleType &other) const
Definition types.cc:682
void PrintTo(std::ostream &stream) const
Definition types.cc:702
const Type & element(int index) const
Definition types.h:836
static std::optional< Type > ParseFromString(const std::string_view &str, Zone *zone)
Definition types.cc:147
bool Equals(const Type &other) const
Definition types.cc:26
const TupleType & AsTuple() const
Definition types.h:880
const Word32Type & AsWord32() const
Definition types.h:860
void PrintTo(std::ostream &stream) const
Definition types.cc:77
bool IsSubtypeOf(const Type &other) const
Definition types.cc:51
const Float32Type & AsFloat32() const
Definition types.h:870
Handle< TurboshaftType > AllocateOnHeap(Factory *factory) const
Definition types.cc:153
const Word64Type & AsWord64() const
Definition types.h:865
const Float64Type & AsFloat64() const
Definition types.h:875
static Type LeastUpperBound(const Type &lhs, const Type &rhs, Zone *zone)
Definition types.cc:118
Handle< TurboshaftType > AllocateOnHeap(Factory *factory) const
Definition types.cc:431
void PrintTo(std::ostream &stream) const
Definition types.cc:412
bool Equals(const WordType &other) const
Definition types.cc:192
static WordType LeastUpperBound(const WordType &lhs, const WordType &rhs, Zone *zone)
Definition types.cc:295
bool Contains(word_t value) const
Definition types.cc:176
bool IsSubtypeOf(const WordType &other) const
Definition types.cc:210
word_t set_element(int index) const
Definition types.h:438
base::Vector< const word_t > set_elements() const
Definition types.h:444
static Type Intersect(const WordType &lhs, const WordType &rhs, ResolutionMode resolution_mode, Zone *zone)
Definition types.cc:344
static WordType Range(word_t from, word_t to, Zone *zone)
Definition types.h:342
#define EXPORT_TEMPLATE_DEFINE(export)
ZoneVector< RpoNumber > & result
int x
void vector_append(V &v, const C &container)
void sort(C &container)
bool is_unique_and_sorted(const T &container)
Definition types.h:55
WordType< Bits > LeastUpperBoundFromRanges(word_t l_from, word_t l_to, word_t r_from, word_t r_to, Zone *zone)
Definition types.cc:234
Range(V< T >, V< T >, V< T >) -> Range< T >
std::make_unsigned_t< Tagged_t > word_t
return value
Definition map-inl.h:893
static bool IsMinusZero(double value)
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define V8_EXPORT_PRIVATE
Definition macros.h:460