v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
types.h
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
5#ifndef V8_COMPILER_TURBOSHAFT_TYPES_H_
6#define V8_COMPILER_TURBOSHAFT_TYPES_H_
7
8#include <cmath>
9#include <limits>
10#include <optional>
11
14#include "src/base/logging.h"
16#include "src/common/globals.h"
20#include "src/utils/ostreams.h"
22
23#ifdef DEBUG
24#define TURBOSHAFT_TRACE_TYPING(...) \
25 do { \
26 if (V8_UNLIKELY(v8_flags.turboshaft_trace_typing)) { \
27 PrintF(__VA_ARGS__); \
28 } \
29 } while (false)
30
31#define TURBOSHAFT_TRACE_TYPING_WITH_COLOR(colorcode, str, ...) \
32 TURBOSHAFT_TRACE_TYPING( \
33 (v8_flags.log_colour ? ("\033[" colorcode "m" str "\033[m") : str), \
34 __VA_ARGS__)
35#define TURBOSHAFT_TRACE_TYPING_OK(str, ...) \
36 TURBOSHAFT_TRACE_TYPING_WITH_COLOR("32", str, __VA_ARGS__)
37#define TURBOSHAFT_TRACE_TYPING_FAIL(str, ...) \
38 TURBOSHAFT_TRACE_TYPING_WITH_COLOR("31", str, __VA_ARGS__)
39#else
40#define TURBOSHAFT_TRACE_TYPING(...) ((void)0)
41#define TURBOSHAFT_TRACE_TYPING_WITH_COLOR(colorcode, str, ...) ((void)0)
42#define TURBOSHAFT_TRACE_TYPING_OK(str, ...) ((void)0)
43#define TURBOSHAFT_TRACE_TYPING_FAIL(str, ...) ((void)0)
44#endif // DEBUG
45
46namespace v8::internal {
47class Factory;
48}
49
51
52namespace detail {
53
54template <typename T>
55inline bool is_unique_and_sorted(const T& container) {
56 if (std::size(container) <= 1) return true;
57 auto cur = std::begin(container);
58 auto next = cur;
59 for (++next; next != std::end(container); ++cur, ++next) {
60 if (!(*cur < *next)) return false;
61 }
62 return true;
63}
64
65template <typename T>
66inline bool is_minus_zero(T value) {
67 return IsMinusZero(value);
68}
69
70template <typename T>
71inline bool is_float_special_value(T value) {
72 return std::isnan(value) || is_minus_zero(value);
73}
74
75template <size_t Bits>
77template <>
78struct TypeForBits<32> {
79 using uint_type = uint32_t;
80 using float_type = float;
81 static constexpr float_type nan =
82 std::numeric_limits<float_type>::quiet_NaN();
83};
84template <>
85struct TypeForBits<64> {
86 using uint_type = uint64_t;
87 using float_type = double;
88 static constexpr float_type nan =
89 std::numeric_limits<float_type>::quiet_NaN();
90};
91
92// gcc versions < 9 may produce the following compilation error:
93// > '<anonymous>' is used uninitialized in this function
94// if Payload_Empty is initialized without any data, link to a relevant bug:
95// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86465
96// A workaround is to add a dummy value which is zero initialized by default.
97// More information as well as a sample reproducible code can be found at the
98// comment section of this CL crrev.com/c/4057111
99// TODO(nicohartmann@): Remove dummy once all platforms are using gcc >= 9.
101 uint8_t dummy = 0;
102};
103
104template <typename T>
108};
109
110template <typename T>
113};
114
115template <typename T>
118};
119
120} // namespace detail
121
122template <typename T>
124 requires std::is_floating_point<T>::value
125{
126 DCHECK(!std::isnan(v));
127 DCHECK_LT(-std::numeric_limits<T>::infinity(), v);
128 return std::nextafter(v, -std::numeric_limits<T>::infinity());
129}
130
131template <typename T>
133 requires std::is_floating_point<T>::value
134{
135 DCHECK(!std::isnan(v));
136 DCHECK_LT(v, std::numeric_limits<T>::infinity());
137 return std::nextafter(v, std::numeric_limits<T>::infinity());
138}
139
140template <typename T>
142 requires std::is_integral<T>::value
143{
144 DCHECK_LT(std::numeric_limits<T>::min(), v);
145 return v - 1;
146}
147
148template <typename T>
150 requires std::is_integral<T>::value
151{
152 DCHECK_LT(v, std::numeric_limits<T>::max());
153 return v + 1;
154}
155
156template <size_t Bits>
158template <size_t Bits>
160template <size_t Bits>
162
163template <size_t Bits>
164class WordType;
165template <size_t Bits>
166class FloatType;
167class TupleType;
168
173
175 public:
176 enum class Kind : uint8_t {
177 kInvalid,
178 kNone,
179 kWord32,
180 kWord64,
181 kFloat32,
182 kFloat64,
183 kTuple,
184 kAny,
185 };
186
187 // Some operations cannot express the result precisely in a type, e.g. when an
188 // intersection with a wrapping range may produce to disconnect subranges,
189 // which cannot be represented. {ResolutionMode} allows to specify what the
190 // operation should do when the result cannot be represented precisely.
191 enum class ResolutionMode {
192 // Return Type::Invalid().
193 kPreciseOrInvalid,
194 // Return a safe over approximation.
195 kOverApproximate,
196 // Return the greatest lower bound that can be represented.
197 kGreatestLowerBound,
198 };
199
201
202 // Type constructors
203 static inline Type Invalid() { return Type(); }
204 static inline Type None() { return Type(Kind::kNone); }
205 static inline Type Any() { return Type(Kind::kAny); }
206
207 // Checks and casts
208 inline Kind kind() const { return kind_; }
209 inline bool IsInvalid() const { return kind_ == Kind::kInvalid; }
210 inline bool IsNone() const { return kind_ == Kind::kNone; }
211 inline bool IsWord32() const { return kind_ == Kind::kWord32; }
212 inline bool IsWord64() const { return kind_ == Kind::kWord64; }
213 inline bool IsFloat32() const { return kind_ == Kind::kFloat32; }
214 inline bool IsFloat64() const { return kind_ == Kind::kFloat64; }
215 inline bool IsTuple() const { return kind_ == Kind::kTuple; }
216 inline bool IsAny() const { return kind_ == Kind::kAny; }
217 template <size_t B>
218 inline bool IsWord() const {
219 static_assert(B == 32 || B == 64);
220 if constexpr (B == 32)
221 return IsWord32();
222 else
223 return IsWord64();
224 }
225 template <size_t B>
226 inline bool IsFloat() const {
227 static_assert(B == 32 || B == 64);
228 if constexpr (B == 32)
229 return IsFloat32();
230 else
231 return IsFloat64();
232 }
233
234 // Casts
235 inline const Word32Type& AsWord32() const;
236 inline const Word64Type& AsWord64() const;
237 inline const Float32Type& AsFloat32() const;
238 inline const Float64Type& AsFloat64() const;
239 inline const TupleType& AsTuple() const;
240 template <size_t B>
241 inline const auto& AsWord() const {
242 static_assert(B == 32 || B == 64);
243 if constexpr (B == 32)
244 return AsWord32();
245 else
246 return AsWord64();
247 }
248 template <size_t B>
249 inline const auto& AsFloat() const {
250 static_assert(B == 32 || B == 64);
251 if constexpr (B == 32)
252 return AsFloat32();
253 else
254 return AsFloat64();
255 }
256
257 // Comparison
258 bool Equals(const Type& other) const;
259 bool IsSubtypeOf(const Type& other) const;
260
261 // Printing
262 void PrintTo(std::ostream& stream) const;
263 void Print() const;
264 std::string ToString() const {
265 std::stringstream stream;
266 PrintTo(stream);
267 return stream.str();
268 }
269
270 // Other functions
271 static Type LeastUpperBound(const Type& lhs, const Type& rhs, Zone* zone);
272 static std::optional<Type> ParseFromString(const std::string_view& str,
273 Zone* zone);
274 Handle<TurboshaftType> AllocateOnHeap(Factory* factory) const;
275
276 protected:
277 template <typename Payload>
278 Type(Kind kind, uint8_t sub_kind, uint8_t set_size, uint32_t bitfield,
279 uint8_t reserved, const Payload& payload)
280 : kind_(kind),
281 sub_kind_(sub_kind),
282 set_size_(set_size),
283 reserved_(reserved),
284 bitfield_(bitfield) {
285 static_assert(sizeof(Payload) <= sizeof(payload_));
286 memcpy(&payload_[0], &payload, sizeof(Payload));
287 if constexpr (sizeof(Payload) < sizeof(payload_)) {
288 memset(reinterpret_cast<uint8_t*>(&payload_[0]) + sizeof(Payload), 0x00,
289 sizeof(payload_) - sizeof(Payload));
290 }
291 }
292
293 template <typename Payload>
294 const Payload& get_payload() const {
295 static_assert(sizeof(Payload) <= sizeof(payload_));
296 return *reinterpret_cast<const Payload*>(&payload_[0]);
297 }
298
299 union {
300 struct {
302 uint8_t sub_kind_;
303 uint8_t set_size_;
304 uint8_t reserved_;
305 uint32_t bitfield_;
306 };
307 // {header_} can be used for faster hashing or comparison.
308 uint64_t header_;
309 };
310
311 private:
312 // Access through get_payload<>().
313 uint64_t payload_[2]; // Type specific data
314
315 friend struct fast_hash<Type>;
316 explicit Type(Kind kind) : Type(kind, 0, 0, 0, 0, detail::Payload_Empty{}) {
317 DCHECK(kind == Kind::kInvalid || kind == Kind::kNone || kind == Kind::kAny);
318 }
319};
320static_assert(sizeof(Type) == 24);
321
322template <size_t Bits>
323class WordType : public Type {
324 static_assert(Bits == 32 || Bits == 64);
325 friend class Type;
326 static constexpr int kMaxInlineSetSize = 2;
327
328 enum class SubKind : uint8_t {
329 kRange,
330 kSet,
331 };
332
333 public:
334 static constexpr int kMaxSetSize = 8;
337
338 // Constructors
339 static WordType Any() {
340 return Range(0, std::numeric_limits<word_t>::max(), nullptr);
341 }
342 static WordType Range(word_t from, word_t to, Zone* zone) {
343 // Normalize ranges smaller than {kMaxSetSize} to sets.
344 if (to >= from) {
345 // (to - from + 1) <= kMaxSetSize
346 if (to - from <= kMaxSetSize - 1) {
347 // Normalizing non-wrapping ranges to a Set.
349 for (word_t i = from; i < to; ++i) elements.push_back(i);
350 elements.push_back(to);
351 return Set(elements, zone);
352 }
353 } else {
354 // (max - from + 1) + (to + 1) <= kMaxSetSize
355 if ((std::numeric_limits<word_t>::max() - from + to) <= kMaxSetSize - 2) {
356 // Normalizing wrapping ranges to a Set.
358 for (word_t i = from; i < std::numeric_limits<word_t>::max(); ++i) {
359 elements.push_back(i);
360 }
361 elements.push_back(std::numeric_limits<word_t>::max());
362 for (word_t i = 0; i < to; ++i) elements.push_back(i);
363 elements.push_back(to);
364 base::sort(elements);
365 return Set(elements, zone);
366 }
367 }
369 }
370 template <size_t N>
372 Zone* zone) {
373 return Set(base::VectorOf(elements), zone);
374 }
375 static WordType Set(const std::vector<word_t>& elements, Zone* zone) {
376 return Set(base::VectorOf(elements), zone);
377 }
378 static WordType Set(const std::initializer_list<word_t>& elements,
379 Zone* zone) {
380 return Set(base::VectorOf(elements), zone);
381 }
382 static WordType Set(base::Vector<const word_t> elements, Zone* zone) {
384 DCHECK_IMPLIES(elements.size() > kMaxInlineSetSize, zone != nullptr);
385 DCHECK_GT(elements.size(), 0);
386 DCHECK_LE(elements.size(), kMaxSetSize);
387
388 if (elements.size() <= kMaxInlineSetSize) {
389 // Use inline storage.
391 DCHECK_LT(0, elements.size());
392 p.elements[0] = elements[0];
393 if (elements.size() > 1) p.elements[1] = elements[1];
394 return WordType{SubKind::kSet, static_cast<uint8_t>(elements.size()), p};
395 } else {
396 // Allocate storage in the zone.
397#if defined(__GNUC__) && !defined(__clang__)
398 // Work around a spurious GCC-12 warning. The DCHECK above already
399 // checks the right precondition.
400 if (zone == nullptr) return WordType::Any();
401#endif
403 p.array = zone->AllocateArray<word_t>(elements.size());
405 for (size_t i = 0; i < elements.size(); ++i) p.array[i] = elements[i];
406 return WordType{SubKind::kSet, static_cast<uint8_t>(elements.size()), p};
407 }
408 }
409 static WordType Constant(word_t constant) { return Set({constant}, nullptr); }
410
411 // Checks
412 bool is_range() const { return sub_kind() == SubKind::kRange; }
413 bool is_set() const { return sub_kind() == SubKind::kSet; }
414 bool is_any() const { return is_range() && range_to() + 1 == range_from(); }
415 bool is_constant() const {
416 DCHECK_EQ(set_size_ > 0, is_set());
417 return set_size_ == 1;
418 }
419 bool is_wrapping() const { return is_range() && range_from() > range_to(); }
420
421 // Accessors
423 DCHECK(is_range());
424 return get_payload<Payload_Range>().min;
425 }
426 word_t range_to() const {
427 DCHECK(is_range());
428 return get_payload<Payload_Range>().max;
429 }
430 std::pair<word_t, word_t> range() const {
431 DCHECK(is_range());
432 return {range_from(), range_to()};
433 }
434 int set_size() const {
435 DCHECK(is_set());
436 return static_cast<int>(set_size_);
437 }
438 word_t set_element(int index) const {
439 DCHECK(is_set());
440 DCHECK_GE(index, 0);
441 DCHECK_LT(index, set_size());
442 return set_elements()[index];
443 }
454 std::optional<word_t> try_get_constant() const {
455 if (!is_constant()) return std::nullopt;
456 DCHECK(is_set());
457 DCHECK_EQ(set_size(), 1);
458 return set_element(0);
459 }
460 bool is_constant(word_t value) const {
461 if (auto c = try_get_constant()) return *c == value;
462 return false;
463 }
465 switch (sub_kind()) {
466 case SubKind::kRange:
467 return is_wrapping() ? word_t{0} : range_from();
468 case SubKind::kSet:
469 return set_element(0);
470 }
471 }
473 switch (sub_kind()) {
474 case SubKind::kRange:
475 return is_wrapping() ? std::numeric_limits<word_t>::max() : range_to();
476 case SubKind::kSet:
477 DCHECK_GE(set_size(), 1);
478 return set_element(set_size() - 1);
479 }
480 }
481
482 // Misc
483 bool Contains(word_t value) const;
484 bool Equals(const WordType& other) const;
485 bool IsSubtypeOf(const WordType& other) const;
486 static WordType LeastUpperBound(const WordType& lhs, const WordType& rhs,
487 Zone* zone);
488 static Type Intersect(const WordType& lhs, const WordType& rhs,
489 ResolutionMode resolution_mode, Zone* zone);
490 void PrintTo(std::ostream& stream) const;
492
493 private:
494 static constexpr Kind KIND = Bits == 32 ? Kind::kWord32 : Kind::kWord64;
498
499 SubKind sub_kind() const { return static_cast<SubKind>(sub_kind_); }
500 template <typename Payload>
501 WordType(SubKind sub_kind, uint8_t set_size, const Payload& payload)
502 : Type(KIND, static_cast<uint8_t>(sub_kind), set_size, 0, 0, payload) {}
503};
504
507
508template <size_t Bits>
509class FloatType : public Type {
510 static_assert(Bits == 32 || Bits == 64);
511 friend class Type;
512 static constexpr int kMaxInlineSetSize = 2;
513
514 enum class SubKind : uint8_t {
515 kRange,
516 kSet,
517 kOnlySpecialValues,
518 };
519
520 public:
521 static constexpr int kMaxSetSize = 8;
524
525 enum Special : uint32_t {
526 kNoSpecialValues = 0x0,
527 kNaN = 0x1,
529 };
530
531 // Constructors
532 static FloatType OnlySpecialValues(uint32_t special_values) {
533 DCHECK_NE(0, special_values);
534 return FloatType{SubKind::kOnlySpecialValues, 0, special_values,
536 }
537 static FloatType NaN() {
538 return FloatType{SubKind::kOnlySpecialValues, 0, Special::kNaN,
540 }
542 return FloatType{SubKind::kOnlySpecialValues, 0, Special::kMinusZero,
544 }
545 static FloatType Any(uint32_t special_values = Special::kNaN |
546 Special::kMinusZero) {
547 return FloatType::Range(-std::numeric_limits<float_t>::infinity(),
548 std::numeric_limits<float_t>::infinity(),
549 special_values, nullptr);
550 }
551 static FloatType Range(float_t min, float_t max, Zone* zone) {
552 return Range(min, max, Special::kNoSpecialValues, zone);
553 }
554 static FloatType Range(float_t min, float_t max, uint32_t special_values,
555 Zone* zone) {
556 special_values |= IdentifyMinusZero(min);
557 special_values |= IdentifyMinusZero(max);
560 DCHECK_LE(min, max);
561 if (min == max) return Set({min}, special_values, zone);
562 return FloatType{SubKind::kRange, 0, special_values,
563 Payload_Range{min, max}};
564 }
565 template <size_t N>
567 Zone* zone) {
568 return Set(elements, Special::kNoSpecialValues, zone);
569 }
570 template <size_t N>
572 uint32_t special_values, Zone* zone) {
573 return Set(base::VectorOf(elements), special_values, zone);
574 }
575 static FloatType Set(const std::initializer_list<float_t>& elements,
576 uint32_t special_values, Zone* zone) {
577 return Set(base::VectorOf(elements), special_values, zone);
578 }
579 static FloatType Set(const std::vector<float_t>& elements, Zone* zone) {
580 return Set(elements, Special::kNoSpecialValues, zone);
581 }
582 static FloatType Set(const std::vector<float_t>& elements,
583 uint32_t special_values, Zone* zone) {
584 return Set(base::VectorOf(elements), special_values, zone);
585 }
587 uint32_t special_values, Zone* zone) {
589 // NaN should be passed via {special_values} rather than {elements}.
590 DCHECK(base::none_of(elements, [](float_t f) { return std::isnan(f); }));
591 DCHECK_IMPLIES(elements.size() > kMaxInlineSetSize, zone != nullptr);
592 DCHECK_GT(elements.size(), 0);
593 DCHECK_LE(elements.size(), kMaxSetSize);
594
595 if (elements.size() <= kMaxInlineSetSize) {
596 // Use inline storage.
598 DCHECK_LT(0, elements.size());
599 p.elements[0] = elements[0];
600 special_values |= IdentifyMinusZero(p.elements[0]);
601 if (elements.size() > 1) {
602 p.elements[1] = elements[1];
603 special_values |= IdentifyMinusZero(p.elements[1]);
604 }
605 return FloatType{SubKind::kSet, static_cast<uint8_t>(elements.size()),
606 special_values, p};
607 } else {
608 // Allocate storage in the zone.
610 p.array = zone->AllocateArray<float_t>(elements.size());
612 for (size_t i = 0; i < elements.size(); ++i) {
613 p.array[i] = elements[i];
614 special_values |= IdentifyMinusZero(p.array[i]);
615 }
616 return FloatType{SubKind::kSet, static_cast<uint8_t>(elements.size()),
617 special_values, p};
618 }
619 }
620 static FloatType Constant(float_t constant) {
621 return Set({constant}, 0, nullptr);
622 }
623
624 // Checks
626 return sub_kind() == SubKind::kOnlySpecialValues;
627 }
628 bool is_only_nan() const {
629 return is_only_special_values() && (special_values() == Special::kNaN);
630 }
631 bool is_only_minus_zero() const {
632 return is_only_special_values() &&
633 (special_values() == Special::kMinusZero);
634 }
635 bool is_range() const { return sub_kind() == SubKind::kRange; }
636 bool is_set() const { return sub_kind() == SubKind::kSet; }
637 bool is_any() const {
638 return is_range() &&
639 range_min() == -std::numeric_limits<float_t>::infinity() &&
640 range_max() == std::numeric_limits<float_t>::infinity();
641 }
642 bool is_constant() const {
643 DCHECK_EQ(set_size_ > 0, is_set());
644 return set_size_ == 1 && !has_special_values();
645 }
646 uint32_t special_values() const { return bitfield_; }
647 bool has_special_values() const { return special_values() != 0; }
648 bool has_nan() const { return (special_values() & Special::kNaN) != 0; }
649 bool has_minus_zero() const {
650 return (special_values() & Special::kMinusZero) != 0;
651 }
652
653 // Accessors
655 DCHECK(is_range());
656 return get_payload<Payload_Range>().min;
657 }
659 DCHECK(is_range());
660 return get_payload<Payload_Range>().max;
661 }
662 std::pair<float_t, float_t> range() const {
663 DCHECK(is_range());
664 return {range_min(), range_max()};
665 }
666 int set_size() const {
667 DCHECK(is_set());
668 return static_cast<int>(set_size_);
669 }
670 float_t set_element(int index) const {
671 DCHECK(is_set());
672 DCHECK_GE(index, 0);
673 DCHECK_LT(index, set_size());
674 return set_elements()[index];
675 }
677 DCHECK(is_set());
678 if (set_size() <= kMaxInlineSetSize) {
680 get_payload<Payload_InlineSet>().elements, set_size());
681 } else {
683 get_payload<Payload_OutlineSet>().array, set_size());
684 }
685 }
686 float_t min() const {
687 switch (sub_kind()) {
688 case SubKind::kOnlySpecialValues:
689 if (has_minus_zero()) return float_t{-0.0};
690 DCHECK(is_only_nan());
691 return nan_v<Bits>;
692 case SubKind::kRange:
693 if (has_minus_zero()) return std::min(float_t{-0.0}, range_min());
694 return range_min();
695 case SubKind::kSet:
696 if (has_minus_zero()) return std::min(float_t{-0.0}, set_element(0));
697 return set_element(0);
698 }
699 }
700 float_t max() const {
701 switch (sub_kind()) {
702 case SubKind::kOnlySpecialValues:
703 if (has_minus_zero()) return float_t{-0.0};
704 DCHECK(is_only_nan());
705 return nan_v<Bits>;
706 case SubKind::kRange:
707 if (has_minus_zero()) return std::max(float_t{-0.0}, range_max());
708 return range_max();
709 case SubKind::kSet:
710 if (has_minus_zero()) {
711 return std::max(float_t{-0.0}, set_element(set_size() - 1));
712 }
713 return set_element(set_size() - 1);
714 }
715 }
716 std::pair<float_t, float_t> minmax() const { return {min(), max()}; }
717 std::optional<float_t> try_get_constant() const {
718 if (!is_constant()) return std::nullopt;
719 DCHECK(is_set());
720 DCHECK_EQ(set_size(), 1);
721 return set_element(0);
722 }
723 bool is_constant(float_t value) const {
724 if (V8_UNLIKELY(std::isnan(value))) return is_only_nan();
725 if (V8_UNLIKELY(IsMinusZero(value))) return is_only_minus_zero();
726 if (auto c = try_get_constant()) return *c == value;
727 return false;
728 }
729 // Returns the minimium value of a range or set, ignoring any special values
730 // (in contrast to min() above).
732 switch (sub_kind()) {
733 case SubKind::kOnlySpecialValues:
734 UNREACHABLE();
735 case SubKind::kRange:
736 return range_min();
737 case SubKind::kSet:
738 return set_element(0);
739 }
740 }
741 // Returns the maximum value of a range or set, ignoring any special values
742 // (in contrast to max() above).
744 switch (sub_kind()) {
745 case SubKind::kOnlySpecialValues:
746 UNREACHABLE();
747 case SubKind::kRange:
748 return range_max();
749 case SubKind::kSet:
750 return set_element(set_size() - 1);
751 }
752 }
753 std::pair<float_t, float_t> range_or_set_minmax() const {
754 return {range_or_set_min(), range_or_set_max()};
755 }
756
757 // Misc
758 bool Contains(float_t value) const;
759 bool Equals(const FloatType& other) const;
760 bool IsSubtypeOf(const FloatType& other) const;
761 static FloatType LeastUpperBound(const FloatType& lhs, const FloatType& rhs,
762 Zone* zone);
763 static Type Intersect(const FloatType& lhs, const FloatType& rhs, Zone* zone);
764 void PrintTo(std::ostream& stream) const;
765 Handle<TurboshaftType> AllocateOnHeap(Factory* factory) const;
766
767 private:
768 // This helper turns a -0 into a 0 in {value} and returns the
769 // Special::kMinusZero flag in that case. Otherwise the {value} is unchanged
770 // and Special::kNoSpecialValues is returned.
771 static uint32_t IdentifyMinusZero(float_t& value) {
773 value = float_t{0};
774 return Special::kMinusZero;
775 }
776 return Special::kNoSpecialValues;
777 }
779 uint32_t special_values) {
780 if (special_values == 0 && t.is_only_special_values()) {
781 return FloatType::None();
782 }
783 auto result = t;
784 result.bitfield_ = special_values;
785 DCHECK_EQ(result.bitfield_, result.special_values());
786 return result;
787 }
788
789 static constexpr Kind KIND = Bits == 32 ? Kind::kFloat32 : Kind::kFloat64;
790 SubKind sub_kind() const { return static_cast<SubKind>(sub_kind_); }
795
796 template <typename Payload>
797 FloatType(SubKind sub_kind, uint8_t set_size, uint32_t special_values,
798 const Payload& payload)
799 : Type(KIND, static_cast<uint8_t>(sub_kind), set_size, special_values, 0,
800 payload) {
801 DCHECK_EQ(special_values & ~(Special::kNaN | Special::kMinusZero), 0);
802 }
803};
804
807
808class TupleType : public Type {
809 public:
810 static constexpr int kMaxTupleSize = std::numeric_limits<uint8_t>::max();
811
812 // Constructors
813 static TupleType Tuple(const Type& element0, const Type& element1,
814 Zone* zone) {
815 Payload p;
816 p.array = zone->AllocateArray<Type>(2);
818 p.array[0] = element0;
819 p.array[1] = element1;
820 return TupleType{2, p};
821 }
822
823 static TupleType Tuple(base::Vector<Type> elements, Zone* zone) {
824 DCHECK_LE(elements.size(), kMaxTupleSize);
825 Payload p;
826 p.array = zone->AllocateArray<Type>(elements.size());
828 for (size_t i = 0; i < elements.size(); ++i) {
829 p.array[i] = elements[i];
830 }
831 return TupleType{static_cast<uint8_t>(elements.size()), p};
832 }
833
834 // Accessors
835 int size() const { return static_cast<int>(set_size_); }
836 const Type& element(int index) const {
837 DCHECK_LE(0, index);
838 DCHECK_LT(index, size());
839 return get_payload<Payload>().array[index];
840 }
842 return {get_payload<Payload>().array, static_cast<size_t>(size())};
843 }
844
845 // Misc
846 bool Equals(const TupleType& other) const;
847 bool IsSubtypeOf(const TupleType& other) const;
848 static Type LeastUpperBound(const TupleType& lhs, const TupleType& rhs,
849 Zone* zone);
850 void PrintTo(std::ostream& stream) const;
851
852 private:
853 static constexpr Kind KIND = Kind::kTuple;
855
856 TupleType(uint8_t tuple_size, const Payload& payload)
857 : Type(KIND, 0, tuple_size, 0, 0, payload) {}
858};
859
861 DCHECK(IsWord32());
862 return *static_cast<const Word32Type*>(this);
863}
864
866 DCHECK(IsWord64());
867 return *static_cast<const Word64Type*>(this);
868}
869
871 DCHECK(IsFloat32());
872 return *static_cast<const Float32Type*>(this);
873}
874
876 DCHECK(IsFloat64());
877 return *static_cast<const Float64Type*>(this);
878}
879
880const TupleType& Type::AsTuple() const {
881 DCHECK(IsTuple());
882 return *static_cast<const TupleType*>(this);
883}
884
885inline std::ostream& operator<<(std::ostream& stream, Type::Kind kind) {
886 switch (kind) {
888 return stream << "Invalid";
890 return stream << "None";
892 return stream << "Word32";
894 return stream << "Word64";
896 return stream << "Float32";
898 return stream << "Float64";
900 return stream << "Tuple";
901 case Type::Kind::kAny:
902 return stream << "Any";
903 }
904}
905
906inline std::ostream& operator<<(std::ostream& stream, const Type& type) {
907 type.PrintTo(stream);
908 return stream;
909}
910
911inline bool operator==(const Type& lhs, const Type& rhs) {
912 return lhs.Equals(rhs);
913}
914
915inline bool operator!=(const Type& lhs, const Type& rhs) {
916 return !lhs.Equals(rhs);
917}
918
919template <>
921 size_t operator()(const Type& v) const {
922 // TODO(nicohartmann@): Fix fast_hash for outline payload once this is
923 // required.
924 UNREACHABLE();
925 // return fast_hash_combine(v.header_, v.payload_[0], v.payload_[1]);
926 }
927};
928
929} // namespace v8::internal::compiler::turboshaft
930
931#endif // V8_COMPILER_TURBOSHAFT_TYPES_H_
Builtins::Kind kind
Definition builtins.cc:40
constexpr size_t size() const
Definition vector.h:70
T * AllocateArray(size_t length)
Definition zone.h:127
FloatType(SubKind sub_kind, uint8_t set_size, uint32_t special_values, const Payload &payload)
Definition types.h:797
static FloatType Any(uint32_t special_values=Special::kNaN|Special::kMinusZero)
Definition types.h:545
static FloatType Set(base::Vector< const float_t > elements, uint32_t special_values, Zone *zone)
Definition types.h:586
static FloatType Set(const std::vector< float_t > &elements, uint32_t special_values, Zone *zone)
Definition types.h:582
float_t set_element(int index) const
Definition types.h:670
static FloatType Set(const std::initializer_list< float_t > &elements, uint32_t special_values, Zone *zone)
Definition types.h:575
static FloatType Set(const base::SmallVector< float_t, N > &elements, uint32_t special_values, Zone *zone)
Definition types.h:571
static uint32_t IdentifyMinusZero(float_t &value)
Definition types.h:771
static FloatType OnlySpecialValues(uint32_t special_values)
Definition types.h:532
bool is_constant(float_t value) const
Definition types.h:723
std::pair< float_t, float_t > range() const
Definition types.h:662
static FloatType Range(float_t min, float_t max, Zone *zone)
Definition types.h:551
base::Vector< const float_t > set_elements() const
Definition types.h:676
std::pair< float_t, float_t > minmax() const
Definition types.h:716
std::pair< float_t, float_t > range_or_set_minmax() const
Definition types.h:753
static FloatType Range(float_t min, float_t max, uint32_t special_values, Zone *zone)
Definition types.h:554
static FloatType Constant(float_t constant)
Definition types.h:620
static Type ReplacedSpecialValues(const FloatType &t, uint32_t special_values)
Definition types.h:778
static FloatType Set(const base::SmallVector< const float_t, N > &elements, Zone *zone)
Definition types.h:566
static FloatType Set(const std::vector< float_t > &elements, Zone *zone)
Definition types.h:579
std::optional< float_t > try_get_constant() const
Definition types.h:717
static TupleType Tuple(const Type &element0, const Type &element1, Zone *zone)
Definition types.h:813
static TupleType Tuple(base::Vector< Type > elements, Zone *zone)
Definition types.h:823
TupleType(uint8_t tuple_size, const Payload &payload)
Definition types.h:856
base::Vector< Type > elements() const
Definition types.h:841
const Type & element(int index) const
Definition types.h:836
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
const Payload & get_payload() const
Definition types.h:294
const Float32Type & AsFloat32() const
Definition types.h:870
Type(Kind kind, uint8_t sub_kind, uint8_t set_size, uint32_t bitfield, uint8_t reserved, const Payload &payload)
Definition types.h:278
const Word64Type & AsWord64() const
Definition types.h:865
const Float64Type & AsFloat64() const
Definition types.h:875
Handle< TurboshaftType > AllocateOnHeap(Factory *factory) const
Definition types.cc:431
void PrintTo(std::ostream &stream) const
Definition types.cc:412
static WordType Set(const std::vector< word_t > &elements, Zone *zone)
Definition types.h:375
bool Equals(const WordType &other) const
Definition types.cc:192
static WordType Set(base::Vector< const word_t > elements, Zone *zone)
Definition types.h:382
WordType(SubKind sub_kind, uint8_t set_size, const Payload &payload)
Definition types.h:501
static WordType LeastUpperBound(const WordType &lhs, const WordType &rhs, Zone *zone)
Definition types.cc:295
bool is_constant(word_t value) const
Definition types.h:460
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
static WordType Set(const std::initializer_list< word_t > &elements, Zone *zone)
Definition types.h:378
std::optional< word_t > try_get_constant() const
Definition types.h:454
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 Constant(word_t constant)
Definition types.h:409
std::pair< word_t, word_t > range() const
Definition types.h:430
static WordType Range(word_t from, word_t to, Zone *zone)
Definition types.h:342
static WordType Set(const base::SmallVector< word_t, N > &elements, Zone *zone)
Definition types.h:371
const PropertyKind kind_
#define EXPORT_TEMPLATE_DECLARE(export)
ZoneVector< RpoNumber > & result
Point from
Point to
#define KIND(name, Name)
bool none_of(const C &container, const P &predicate)
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
void sort(C &container)
bool is_unique_and_sorted(const T &container)
Definition types.h:55
std::ostream & operator<<(std::ostream &os, PaddingSpace padding)
bool operator==(const ControlState &lhs, const ControlState &rhs)
typename detail::TypeForBits< Bits >::uint_type uint_type
Definition types.h:157
constexpr float_type< Bits > nan_v
Definition types.h:161
Range(V< T >, V< T >, V< T >) -> Range< T >
typename detail::TypeForBits< Bits >::float_type float_type
Definition types.h:159
bool operator!=(const ControlState &lhs, const ControlState &rhs)
constexpr int B
std::make_unsigned_t< Tagged_t > word_t
return value
Definition map-inl.h:893
static bool IsMinusZero(double value)
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define V8_UNLIKELY(condition)
Definition v8config.h:660