v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
operation-typer.cc
Go to the documentation of this file.
1// Copyright 2016 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
11#include "src/objects/oddball.h"
12
13namespace v8 {
14namespace internal {
15namespace compiler {
16
18 : zone_(zone), cache_(TypeCache::Get()) {
21 Type truncating_to_zero = Type::MinusZeroOrNaN();
22 DCHECK(!truncating_to_zero.Maybe(Type::Integral32()));
23
25 Type::Constant(broker, broker->empty_string(), zone);
30 signed32ish_ = Type::Union(Type::Signed32(), truncating_to_zero, zone);
31 unsigned32ish_ = Type::Union(Type::Unsigned32(), truncating_to_zero, zone);
32
34 Type::Undetectable(),
37 zone);
40 Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone), zone);
41}
42
44 return Type::Union(left, right, zone());
45}
46
47Type OperationTyper::WeakenRange(Type previous_range, Type current_range) {
48 static const double kWeakenMinLimits[] = {0.0,
49 -1073741824.0,
50 -2147483648.0,
51 -4294967296.0,
52 -8589934592.0,
53 -17179869184.0,
54 -34359738368.0,
55 -68719476736.0,
56 -137438953472.0,
57 -274877906944.0,
58 -549755813888.0,
59 -1099511627776.0,
60 -2199023255552.0,
61 -4398046511104.0,
62 -8796093022208.0,
63 -17592186044416.0,
64 -35184372088832.0,
65 -70368744177664.0,
66 -140737488355328.0,
67 -281474976710656.0,
68 -562949953421312.0};
69 static const double kWeakenMaxLimits[] = {0.0,
70 1073741823.0,
71 2147483647.0,
72 4294967295.0,
73 8589934591.0,
74 17179869183.0,
75 34359738367.0,
76 68719476735.0,
77 137438953471.0,
78 274877906943.0,
79 549755813887.0,
80 1099511627775.0,
81 2199023255551.0,
82 4398046511103.0,
83 8796093022207.0,
84 17592186044415.0,
85 35184372088831.0,
86 70368744177663.0,
87 140737488355327.0,
88 281474976710655.0,
89 562949953421311.0};
90 static_assert(arraysize(kWeakenMinLimits) == arraysize(kWeakenMaxLimits));
91
92 double current_min = current_range.Min();
93 double new_min = current_min;
94 // Find the closest lower entry in the list of allowed
95 // minima (or negative infinity if there is no such entry).
96 if (current_min != previous_range.Min()) {
97 new_min = -V8_INFINITY;
98 for (double const min : kWeakenMinLimits) {
99 if (min <= current_min) {
100 new_min = min;
101 break;
102 }
103 }
104 }
105
106 double current_max = current_range.Max();
107 double new_max = current_max;
108 // Find the closest greater entry in the list of allowed
109 // maxima (or infinity if there is no such entry).
110 if (current_max != previous_range.Max()) {
111 new_max = V8_INFINITY;
112 for (double const max : kWeakenMaxLimits) {
113 if (max >= current_max) {
114 new_max = max;
115 break;
116 }
117 }
118 }
119
120 return Type::Range(new_min, new_max, zone());
121}
122
124 if (type.IsRange()) return type; // Shortcut.
125 if (!type.Is(cache_->kInteger)) {
126 return type; // Give up on non-integer types.
127 }
128 return Type::Range(type.Min(), type.Max(), zone());
129}
130
131namespace {
132
133// Returns the array's least element, ignoring NaN.
134// There must be at least one non-NaN element.
135// Any -0 is converted to 0.
136double array_min(double a[], size_t n) {
137 DCHECK_NE(0, n);
138 double x = +V8_INFINITY;
139 for (size_t i = 0; i < n; ++i) {
140 if (!std::isnan(a[i])) {
141 x = std::min(a[i], x);
142 }
143 }
144 DCHECK(!std::isnan(x));
145 return x == 0 ? 0 : x; // -0 -> 0
146}
147
148// Returns the array's greatest element, ignoring NaN.
149// There must be at least one non-NaN element.
150// Any -0 is converted to 0.
151double array_max(double a[], size_t n) {
152 DCHECK_NE(0, n);
153 double x = -V8_INFINITY;
154 for (size_t i = 0; i < n; ++i) {
155 if (!std::isnan(a[i])) {
156 x = std::max(a[i], x);
157 }
158 }
159 DCHECK(!std::isnan(x));
160 return x == 0 ? 0 : x; // -0 -> 0
161}
162
163} // namespace
164
165Type OperationTyper::AddRanger(double lhs_min, double lhs_max, double rhs_min,
166 double rhs_max) {
167 double results[4];
168 results[0] = lhs_min + rhs_min;
169 results[1] = lhs_min + rhs_max;
170 results[2] = lhs_max + rhs_min;
171 results[3] = lhs_max + rhs_max;
172 // Since none of the inputs can be -0, the result cannot be -0 either.
173 // However, it can be nan (the sum of two infinities of opposite sign).
174 // On the other hand, if none of the "results" above is nan, then the
175 // actual result cannot be nan either.
176 int nans = 0;
177 for (int i = 0; i < 4; ++i) {
178 if (std::isnan(results[i])) ++nans;
179 }
180 if (nans == 4) return Type::NaN();
181 Type type = Type::Range(array_min(results, 4), array_max(results, 4), zone());
182 if (nans > 0) type = Type::Union(type, Type::NaN(), zone());
183 // Examples:
184 // [-inf, -inf] + [+inf, +inf] = NaN
185 // [-inf, -inf] + [n, +inf] = [-inf, -inf] \/ NaN
186 // [-inf, +inf] + [n, +inf] = [-inf, +inf] \/ NaN
187 // [-inf, m] + [n, +inf] = [-inf, +inf] \/ NaN
188 return type;
189}
190
191Type OperationTyper::SubtractRanger(double lhs_min, double lhs_max,
192 double rhs_min, double rhs_max) {
193 double results[4];
194 results[0] = lhs_min - rhs_min;
195 results[1] = lhs_min - rhs_max;
196 results[2] = lhs_max - rhs_min;
197 results[3] = lhs_max - rhs_max;
198 // Since none of the inputs can be -0, the result cannot be -0.
199 // However, it can be nan (the subtraction of two infinities of same sign).
200 // On the other hand, if none of the "results" above is nan, then the actual
201 // result cannot be nan either.
202 int nans = 0;
203 for (int i = 0; i < 4; ++i) {
204 if (std::isnan(results[i])) ++nans;
205 }
206 if (nans == 4) return Type::NaN(); // [inf..inf] - [inf..inf] (all same sign)
207 Type type = Type::Range(array_min(results, 4), array_max(results, 4), zone());
208 return nans == 0 ? type : Type::Union(type, Type::NaN(), zone());
209 // Examples:
210 // [-inf, +inf] - [-inf, +inf] = [-inf, +inf] \/ NaN
211 // [-inf, -inf] - [-inf, -inf] = NaN
212 // [-inf, -inf] - [n, +inf] = [-inf, -inf] \/ NaN
213 // [m, +inf] - [-inf, n] = [-inf, +inf] \/ NaN
214}
215
216Type OperationTyper::MultiplyRanger(double lhs_min, double lhs_max,
217 double rhs_min, double rhs_max) {
218 double results[4];
219 results[0] = lhs_min * rhs_min;
220 results[1] = lhs_min * rhs_max;
221 results[2] = lhs_max * rhs_min;
222 results[3] = lhs_max * rhs_max;
223 // If the result may be nan, we give up on calculating a precise type,
224 // because the discontinuity makes it too complicated. Note that even if
225 // none of the "results" above is nan, the actual result may still be, so we
226 // have to do a different check:
227 for (int i = 0; i < 4; ++i) {
228 if (std::isnan(results[i])) {
230 }
231 }
232 double min = array_min(results, 4);
233 double max = array_max(results, 4);
234 Type type = Type::Range(min, max, zone());
235 if (min <= 0.0 && 0.0 <= max && (lhs_min < 0.0 || rhs_min < 0.0)) {
236 type = Type::Union(type, Type::MinusZero(), zone());
237 }
238 // 0 * V8_INFINITY is NaN, regardless of sign
239 if (((lhs_min == -V8_INFINITY || lhs_max == V8_INFINITY) &&
240 (rhs_min <= 0.0 && 0.0 <= rhs_max)) ||
241 ((rhs_min == -V8_INFINITY || rhs_max == V8_INFINITY) &&
242 (lhs_min <= 0.0 && 0.0 <= lhs_max))) {
243 type = Type::Union(type, Type::NaN(), zone());
244 }
245 return type;
246}
247
248Type OperationTyper::ConvertReceiver(Type type) {
249 if (type.Is(Type::Receiver())) return type;
250 bool const maybe_primitive = type.Maybe(Type::Primitive());
251 type = Type::Intersect(type, Type::Receiver(), zone());
252 if (maybe_primitive) {
253 // ConvertReceiver maps null and undefined to the JSGlobalProxy of the
254 // target function, and all other primitives are wrapped into a
255 // JSPrimitiveWrapper.
256 type = Type::Union(type, Type::StringWrapperOrOtherObject(), zone());
257 }
258 return type;
259}
260
262 if (type.Is(Type::Number())) return type;
263
264 // If {type} includes any receivers, we cannot tell what kind of
265 // Number their callbacks might produce. Similarly in the case
266 // where {type} includes String, it's not possible at this point
267 // to tell which exact numbers are going to be produced.
268 if (type.Maybe(Type::StringOrReceiver())) return Type::Number();
269
270 // Both Symbol and BigInt primitives will cause exceptions
271 // to be thrown from ToNumber conversions, so they don't
272 // contribute to the resulting type anyways.
273 type = Type::Intersect(type, Type::PlainPrimitive(), zone());
274
275 // This leaves us with Number\/Oddball, so deal with the individual
276 // Oddball primitives below.
277 DCHECK(type.Is(Type::NumberOrOddball()));
278 if (type.Maybe(Type::Null())) {
279 // ToNumber(null) => +0
280 type = Type::Union(type, cache_->kSingletonZero, zone());
281 }
282 if (type.Maybe(Type::Undefined())) {
283 // ToNumber(undefined) => NaN
284 type = Type::Union(type, Type::NaN(), zone());
285 }
286 if (type.Maybe(singleton_false_)) {
287 // ToNumber(false) => +0
288 type = Type::Union(type, cache_->kSingletonZero, zone());
289 }
290 if (type.Maybe(singleton_true_)) {
291 // ToNumber(true) => +1
292 type = Type::Union(type, cache_->kSingletonOne, zone());
293 }
294 return Type::Intersect(type, Type::Number(), zone());
295}
296
298 // If the {type} includes any receivers, then the callbacks
299 // might actually produce BigInt primitive values here.
300 bool maybe_bigint =
301 type.Maybe(Type::BigInt()) || type.Maybe(Type::Receiver());
302 type = ToNumber(Type::Intersect(type, Type::NonBigInt(), zone()));
303
304 // Any BigInt is rounded to an integer Number in the range [-inf, inf].
305 return maybe_bigint ? Type::Union(type, cache_->kInteger, zone()) : type;
306}
307
309 if (type.Is(Type::BigInt())) {
310 return type;
311 }
312
313 return Type::BigInt();
314}
315
317 if (type.Is(Type::Unsigned32OrMinusZero())) {
318 return Type::UnsignedBigInt63();
319 } else if (type.Is(Type::Signed32OrMinusZero())) {
320 return Type::SignedBigInt64();
321 }
322
323 bool maybe_number =
324 type.Maybe(Type::Number()) || type.Maybe(Type::Receiver());
325 type = ToBigInt(Type::Intersect(type, Type::NonNumber(), zone()));
326 return maybe_number ? Type::Union(type, Type::BigInt(), zone()) : type;
327}
328
330 // If the {type} includes any receivers, then the callbacks
331 // might actually produce BigInt primitive values here.
332 if (type.Maybe(Type::Receiver())) {
333 type = Type::Union(type, Type::BigInt(), zone());
334 }
335 return Type::Union(ToNumber(Type::Intersect(type, Type::NonBigInt(), zone())),
336 Type::Intersect(type, Type::BigInt(), zone()), zone());
337}
338
339Type OperationTyper::NumberAbs(Type type) {
340 DCHECK(type.Is(Type::Number()));
341 if (type.IsNone()) return type;
342
343 bool const maybe_nan = type.Maybe(Type::NaN());
344 bool const maybe_minuszero = type.Maybe(Type::MinusZero());
345
346 type = Type::Intersect(type, Type::PlainNumber(), zone());
347 if (!type.IsNone()) {
348 double const max = type.Max();
349 double const min = type.Min();
350 if (min < 0) {
351 if (type.Is(cache_->kInteger)) {
352 type =
353 Type::Range(0.0, std::max(std::fabs(min), std::fabs(max)), zone());
354 } else {
355 type = Type::PlainNumber();
356 }
357 }
358 }
359
360 if (maybe_minuszero) {
361 type = Type::Union(type, cache_->kSingletonZero, zone());
362 }
363 if (maybe_nan) {
364 type = Type::Union(type, Type::NaN(), zone());
365 }
366 return type;
367}
368
369Type OperationTyper::NumberAcos(Type type) {
370 DCHECK(type.Is(Type::Number()));
371 return Type::Number();
372}
373
374Type OperationTyper::NumberAcosh(Type type) {
375 DCHECK(type.Is(Type::Number()));
376 return Type::Number();
377}
378
379Type OperationTyper::NumberAsin(Type type) {
380 DCHECK(type.Is(Type::Number()));
381 return Type::Number();
382}
383
384Type OperationTyper::NumberAsinh(Type type) {
385 DCHECK(type.Is(Type::Number()));
386 return Type::Number();
387}
388
389Type OperationTyper::NumberAtan(Type type) {
390 DCHECK(type.Is(Type::Number()));
391 return Type::Number();
392}
393
394Type OperationTyper::NumberAtanh(Type type) {
395 DCHECK(type.Is(Type::Number()));
396 return Type::Number();
397}
398
399Type OperationTyper::NumberCbrt(Type type) {
400 DCHECK(type.Is(Type::Number()));
401 return Type::Number();
402}
403
404Type OperationTyper::NumberCeil(Type type) {
405 DCHECK(type.Is(Type::Number()));
406 if (type.Is(cache_->kIntegerOrMinusZeroOrNaN)) return type;
407 type = Type::Intersect(type, Type::NaN(), zone());
408 type = Type::Union(type, cache_->kIntegerOrMinusZero, zone());
409 return type;
410}
411
412Type OperationTyper::NumberClz32(Type type) {
413 DCHECK(type.Is(Type::Number()));
414 return cache_->kZeroToThirtyTwo;
415}
416
417Type OperationTyper::NumberCos(Type type) {
418 DCHECK(type.Is(Type::Number()));
419 return Type::Number();
420}
421
422Type OperationTyper::NumberCosh(Type type) {
423 DCHECK(type.Is(Type::Number()));
424 return Type::Number();
425}
426
427Type OperationTyper::NumberExp(Type type) {
428 DCHECK(type.Is(Type::Number()));
429 return Type::Union(Type::PlainNumber(), Type::NaN(), zone());
430}
431
432Type OperationTyper::NumberExpm1(Type type) {
433 DCHECK(type.Is(Type::Number()));
434 return Type::Number();
435}
436
437Type OperationTyper::NumberFloor(Type type) {
438 DCHECK(type.Is(Type::Number()));
439 if (type.Is(cache_->kIntegerOrMinusZeroOrNaN)) return type;
440 type = Type::Intersect(type, Type::MinusZeroOrNaN(), zone());
441 type = Type::Union(type, cache_->kInteger, zone());
442 return type;
443}
444
445Type OperationTyper::NumberFround(Type type) {
446 DCHECK(type.Is(Type::Number()));
447 return Type::Number();
448}
449
450Type OperationTyper::NumberLog(Type type) {
451 DCHECK(type.Is(Type::Number()));
452 return Type::Number();
453}
454
455Type OperationTyper::NumberLog1p(Type type) {
456 DCHECK(type.Is(Type::Number()));
457 return Type::Number();
458}
459
460Type OperationTyper::NumberLog2(Type type) {
461 DCHECK(type.Is(Type::Number()));
462 return Type::Number();
463}
464
465Type OperationTyper::NumberLog10(Type type) {
466 DCHECK(type.Is(Type::Number()));
467 return Type::Number();
468}
469
470Type OperationTyper::NumberRound(Type type) {
471 DCHECK(type.Is(Type::Number()));
472 if (type.Is(cache_->kIntegerOrMinusZeroOrNaN)) return type;
473 type = Type::Intersect(type, Type::NaN(), zone());
474 type = Type::Union(type, cache_->kIntegerOrMinusZero, zone());
475 return type;
476}
477
478Type OperationTyper::NumberSign(Type type) {
479 DCHECK(type.Is(Type::Number()));
480 if (type.Is(cache_->kZeroish)) return type;
481 bool maybe_minuszero = type.Maybe(Type::MinusZero());
482 bool maybe_nan = type.Maybe(Type::NaN());
483 type = Type::Intersect(type, Type::PlainNumber(), zone());
484 if (type.IsNone()) {
485 // Do nothing.
486 } else if (type.Max() < 0.0) {
488 } else if (type.Max() <= 0.0) {
489 type = cache_->kMinusOneOrZero;
490 } else if (type.Min() > 0.0) {
491 type = cache_->kSingletonOne;
492 } else if (type.Min() >= 0.0) {
493 type = cache_->kZeroOrOne;
494 } else {
495 type = Type::Range(-1.0, 1.0, zone());
496 }
497 if (maybe_minuszero) type = Type::Union(type, Type::MinusZero(), zone());
498 if (maybe_nan) type = Type::Union(type, Type::NaN(), zone());
499 DCHECK(!type.IsNone());
500 return type;
501}
502
503Type OperationTyper::NumberSin(Type type) {
504 DCHECK(type.Is(Type::Number()));
505 return Type::Number();
506}
507
508Type OperationTyper::NumberSinh(Type type) {
509 DCHECK(type.Is(Type::Number()));
510 return Type::Number();
511}
512
513Type OperationTyper::NumberSqrt(Type type) {
514 DCHECK(type.Is(Type::Number()));
515 return Type::Number();
516}
517
518Type OperationTyper::NumberTan(Type type) {
519 DCHECK(type.Is(Type::Number()));
520 return Type::Number();
521}
522
523Type OperationTyper::NumberTanh(Type type) {
524 DCHECK(type.Is(Type::Number()));
525 return Type::Number();
526}
527
528Type OperationTyper::NumberTrunc(Type type) {
529 DCHECK(type.Is(Type::Number()));
530 if (type.Is(cache_->kIntegerOrMinusZeroOrNaN)) return type;
531 type = Type::Intersect(type, Type::NaN(), zone());
532 type = Type::Union(type, cache_->kIntegerOrMinusZero, zone());
533 return type;
534}
535
536Type OperationTyper::NumberToBoolean(Type type) {
537 DCHECK(type.Is(Type::Number()));
538 if (type.IsNone()) return type;
539 if (type.Is(cache_->kZeroish)) return singleton_false_;
540 if (type.Is(Type::PlainNumber()) && (type.Max() < 0 || 0 < type.Min())) {
541 return singleton_true_; // Ruled out nan, -0 and +0.
542 }
543 return Type::Boolean();
544}
545
546Type OperationTyper::NumberToInt32(Type type) {
547 DCHECK(type.Is(Type::Number()));
548
549 if (type.Is(Type::Signed32())) return type;
550 if (type.Is(cache_->kZeroish)) return cache_->kSingletonZero;
551 if (type.Is(signed32ish_)) {
553 Type::Signed32(), zone());
554 }
555 return Type::Signed32();
556}
557
558Type OperationTyper::NumberToString(Type type) {
559 DCHECK(type.Is(Type::Number()));
560 if (type.IsNone()) return type;
561 if (type.Is(Type::NaN())) return singleton_NaN_string_;
562 if (type.Is(cache_->kZeroOrMinusZero)) return singleton_zero_string_;
563 return Type::String();
564}
565
566Type OperationTyper::NumberToUint32(Type type) {
567 DCHECK(type.Is(Type::Number()));
568
569 if (type.Is(Type::Unsigned32())) return type;
570 if (type.Is(cache_->kZeroish)) return cache_->kSingletonZero;
571 if (type.Is(unsigned32ish_)) {
573 Type::Unsigned32(), zone());
574 }
575 return Type::Unsigned32();
576}
577
578Type OperationTyper::NumberToUint8Clamped(Type type) {
579 DCHECK(type.Is(Type::Number()));
580
581 if (type.Is(cache_->kUint8)) return type;
582 return cache_->kUint8;
583}
584
585Type OperationTyper::Integral32OrMinusZeroToBigInt(Type type) {
586 DCHECK(type.Is(Type::Number()));
587
588 if (type.Is(Type::Unsigned32OrMinusZero())) {
589 return Type::UnsignedBigInt63();
590 }
591 if (type.Is(Type::Signed32OrMinusZero())) {
592 return Type::SignedBigInt64();
593 }
594 return Type::BigInt();
595}
596
597Type OperationTyper::NumberSilenceNaN(Type type) {
598 DCHECK(type.Is(Type::Number()));
599 // TODO(jarin): This is a terrible hack; we definitely need a dedicated type
600 // for the hole (tagged and/or double). Otherwise if the input is the hole
601 // NaN constant, we'd just eliminate this node in JSTypedLowering.
602 if (type.Maybe(Type::NaN())) return Type::Number();
603 return type;
604}
605
606Type OperationTyper::SpeculativeBigIntAsIntN(Type) {
607 return Type::SignedBigInt64();
608}
609
610Type OperationTyper::SpeculativeBigIntAsUintN(Type) {
611 return Type::UnsignedBigInt64();
612}
613
614Type OperationTyper::CheckBigInt(Type type) { return Type::BigInt(); }
615
616Type OperationTyper::CheckedBigIntToBigInt64(Type type) {
617 return Type::SignedBigInt64();
618}
619
620Type OperationTyper::NumberAdd(Type lhs, Type rhs) {
621 DCHECK(lhs.Is(Type::Number()));
622 DCHECK(rhs.Is(Type::Number()));
623
624 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
625
626 // Addition can return NaN if either input can be NaN or we try to compute
627 // the sum of two infinities of opposite sign.
628 bool maybe_nan = lhs.Maybe(Type::NaN()) || rhs.Maybe(Type::NaN());
629
630 // Addition can yield minus zero only if both inputs can be minus zero.
631 bool maybe_minuszero = true;
632 if (lhs.Maybe(Type::MinusZero())) {
633 lhs = Type::Union(lhs, cache_->kSingletonZero, zone());
634 } else {
635 maybe_minuszero = false;
636 }
637 if (rhs.Maybe(Type::MinusZero())) {
638 rhs = Type::Union(rhs, cache_->kSingletonZero, zone());
639 } else {
640 maybe_minuszero = false;
641 }
642
643 // We can give more precise types for integers.
644 Type type = Type::None();
645 lhs = Type::Intersect(lhs, Type::PlainNumber(), zone());
646 rhs = Type::Intersect(rhs, Type::PlainNumber(), zone());
647 if (!lhs.IsNone() && !rhs.IsNone()) {
648 if (lhs.Is(cache_->kInteger) && rhs.Is(cache_->kInteger)) {
649 type = AddRanger(lhs.Min(), lhs.Max(), rhs.Min(), rhs.Max());
650 } else {
651 if ((lhs.Maybe(minus_infinity_) && rhs.Maybe(infinity_)) ||
652 (rhs.Maybe(minus_infinity_) && lhs.Maybe(infinity_))) {
653 maybe_nan = true;
654 }
655 type = Type::PlainNumber();
656 }
657 }
658
659 // Take into account the -0 and NaN information computed earlier.
660 if (maybe_minuszero) type = Type::Union(type, Type::MinusZero(), zone());
661 if (maybe_nan) type = Type::Union(type, Type::NaN(), zone());
662 return type;
663}
664
665Type OperationTyper::NumberSubtract(Type lhs, Type rhs) {
666 DCHECK(lhs.Is(Type::Number()));
667 DCHECK(rhs.Is(Type::Number()));
668
669 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
670
671 // Subtraction can return NaN if either input can be NaN or we try to
672 // compute the sum of two infinities of opposite sign.
673 bool maybe_nan = lhs.Maybe(Type::NaN()) || rhs.Maybe(Type::NaN());
674
675 // Subtraction can yield minus zero if {lhs} can be minus zero and {rhs}
676 // can be zero.
677 bool maybe_minuszero = false;
678 if (lhs.Maybe(Type::MinusZero())) {
679 lhs = Type::Union(lhs, cache_->kSingletonZero, zone());
680 maybe_minuszero = rhs.Maybe(cache_->kSingletonZero);
681 }
682 if (rhs.Maybe(Type::MinusZero())) {
683 rhs = Type::Union(rhs, cache_->kSingletonZero, zone());
684 }
685
686 // We can give more precise types for integers.
687 Type type = Type::None();
688 lhs = Type::Intersect(lhs, Type::PlainNumber(), zone());
689 rhs = Type::Intersect(rhs, Type::PlainNumber(), zone());
690 if (!lhs.IsNone() && !rhs.IsNone()) {
691 if (lhs.Is(cache_->kInteger) && rhs.Is(cache_->kInteger)) {
692 type = SubtractRanger(lhs.Min(), lhs.Max(), rhs.Min(), rhs.Max());
693 } else {
694 if ((lhs.Maybe(infinity_) && rhs.Maybe(infinity_)) ||
695 (rhs.Maybe(minus_infinity_) && lhs.Maybe(minus_infinity_))) {
696 maybe_nan = true;
697 }
698 type = Type::PlainNumber();
699 }
700 }
701
702 // Take into account the -0 and NaN information computed earlier.
703 if (maybe_minuszero) type = Type::Union(type, Type::MinusZero(), zone());
704 if (maybe_nan) type = Type::Union(type, Type::NaN(), zone());
705 return type;
706}
707
708Type OperationTyper::SpeculativeAdditiveSafeIntegerAdd(Type lhs, Type rhs) {
709 Type result = SpeculativeNumberAdd(lhs, rhs);
710 if (lhs.Is(cache_->kAdditiveSafeInteger) ||
711 rhs.Is(cache_->kAdditiveSafeInteger)) {
713 }
714 return result;
715}
716
717Type OperationTyper::SpeculativeAdditiveSafeIntegerSubtract(Type lhs,
718 Type rhs) {
719 Type result = SpeculativeNumberSubtract(lhs, rhs);
720 if (lhs.Is(cache_->kAdditiveSafeInteger) ||
721 rhs.Is(cache_->kAdditiveSafeInteger)) {
723 }
724 return result;
725}
726
727Type OperationTyper::SpeculativeSmallIntegerAdd(Type lhs, Type rhs) {
728 Type result = SpeculativeNumberAdd(lhs, rhs);
729 // If we have a Smi or Int32 feedback, the representation selection will
730 // either truncate or it will check the inputs (i.e., deopt if not int32).
731 // In either case the result will be in the safe integer range, so we
732 // can bake in the type here. This needs to be in sync with
733 // SimplifiedLowering::VisitSpeculativeAdditiveOp.
735}
736
737Type OperationTyper::SpeculativeSmallIntegerSubtract(Type lhs, Type rhs) {
738 Type result = SpeculativeNumberSubtract(lhs, rhs);
739 // If we have a Smi or Int32 feedback, the representation selection will
740 // either truncate or it will check the inputs (i.e., deopt if not int32).
741 // In either case the result will be in the safe integer range, so we
742 // can bake in the type here. This needs to be in sync with
743 // SimplifiedLowering::VisitSpeculativeAdditiveOp.
745}
746
747Type OperationTyper::NumberMultiply(Type lhs, Type rhs) {
748 DCHECK(lhs.Is(Type::Number()));
749 DCHECK(rhs.Is(Type::Number()));
750
751 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
752 if (lhs.Is(Type::NaN()) || rhs.Is(Type::NaN())) return Type::NaN();
753
754 // Multiplication propagates NaN:
755 // NaN * x = NaN (regardless of sign of x)
756 // 0 * Infinity = NaN (regardless of signs)
757 bool maybe_nan = lhs.Maybe(Type::NaN()) || rhs.Maybe(Type::NaN()) ||
758 (lhs.Maybe(cache_->kZeroish) &&
759 (rhs.Min() == -V8_INFINITY || rhs.Max() == V8_INFINITY)) ||
760 (rhs.Maybe(cache_->kZeroish) &&
761 (lhs.Min() == -V8_INFINITY || lhs.Max() == V8_INFINITY));
762 lhs = Type::Intersect(lhs, Type::OrderedNumber(), zone());
763 DCHECK(!lhs.IsNone());
764 rhs = Type::Intersect(rhs, Type::OrderedNumber(), zone());
765 DCHECK(!rhs.IsNone());
766
767 // Try to rule out -0.
768 bool maybe_minuszero = lhs.Maybe(Type::MinusZero()) ||
769 rhs.Maybe(Type::MinusZero()) ||
770 (lhs.Maybe(cache_->kZeroish) && rhs.Min() < 0.0) ||
771 (rhs.Maybe(cache_->kZeroish) && lhs.Min() < 0.0);
772 if (lhs.Maybe(Type::MinusZero())) {
773 lhs = Type::Union(lhs, cache_->kSingletonZero, zone());
774 lhs = Type::Intersect(lhs, Type::PlainNumber(), zone());
775 }
776 if (rhs.Maybe(Type::MinusZero())) {
777 rhs = Type::Union(rhs, cache_->kSingletonZero, zone());
778 rhs = Type::Intersect(rhs, Type::PlainNumber(), zone());
779 }
780
781 // Compute the effective type, utilizing range information if possible.
782 Type type = (lhs.Is(cache_->kInteger) && rhs.Is(cache_->kInteger))
783 ? MultiplyRanger(lhs.Min(), lhs.Max(), rhs.Min(), rhs.Max())
784 : Type::OrderedNumber();
785
786 // Take into account the -0 and NaN information computed earlier.
787 if (maybe_minuszero) type = Type::Union(type, Type::MinusZero(), zone());
788 if (maybe_nan) type = Type::Union(type, Type::NaN(), zone());
789 return type;
790}
791
792Type OperationTyper::NumberDivide(Type lhs, Type rhs) {
793 DCHECK(lhs.Is(Type::Number()));
794 DCHECK(rhs.Is(Type::Number()));
795
796 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
797 if (lhs.Is(Type::NaN()) || rhs.Is(Type::NaN())) return Type::NaN();
798
799 // Division is tricky, so all we do is try ruling out -0 and NaN.
800 bool maybe_nan = lhs.Maybe(Type::NaN()) || rhs.Maybe(cache_->kZeroish) ||
801 ((lhs.Min() == -V8_INFINITY || lhs.Max() == +V8_INFINITY) &&
802 (rhs.Min() == -V8_INFINITY || rhs.Max() == +V8_INFINITY));
803 lhs = Type::Intersect(lhs, Type::OrderedNumber(), zone());
804 DCHECK(!lhs.IsNone());
805 rhs = Type::Intersect(rhs, Type::OrderedNumber(), zone());
806 DCHECK(!rhs.IsNone());
807
808 // Try to rule out -0.
809 bool maybe_minuszero =
810 !lhs.Is(cache_->kInteger) ||
811 (lhs.Maybe(cache_->kZeroish) && rhs.Min() < 0.0) ||
812 (rhs.Min() == -V8_INFINITY || rhs.Max() == +V8_INFINITY);
813
814 // Take into account the -0 and NaN information computed earlier.
815 Type type = Type::PlainNumber();
816 if (maybe_minuszero) type = Type::Union(type, Type::MinusZero(), zone());
817 if (maybe_nan) type = Type::Union(type, Type::NaN(), zone());
818 return type;
819}
820
821Type OperationTyper::NumberModulus(Type lhs, Type rhs) {
822 DCHECK(lhs.Is(Type::Number()));
823 DCHECK(rhs.Is(Type::Number()));
824
825 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
826
827 // Modulus can yield NaN if either {lhs} or {rhs} are NaN, or
828 // {lhs} is not finite, or the {rhs} is a zero value.
829 bool maybe_nan = lhs.Maybe(Type::NaN()) || rhs.Maybe(cache_->kZeroish) ||
830 lhs.Min() == -V8_INFINITY || lhs.Max() == +V8_INFINITY;
831
832 // Deal with -0 inputs, only the signbit of {lhs} matters for the result.
833 bool maybe_minuszero = false;
834 if (lhs.Maybe(Type::MinusZero())) {
835 maybe_minuszero = true;
836 lhs = Type::Union(lhs, cache_->kSingletonZero, zone());
837 }
838 if (rhs.Maybe(Type::MinusZero())) {
839 rhs = Type::Union(rhs, cache_->kSingletonZero, zone());
840 }
841
842 // Rule out NaN and -0, and check what we can do with the remaining type info.
843 Type type = Type::None();
844 lhs = Type::Intersect(lhs, Type::PlainNumber(), zone());
845 rhs = Type::Intersect(rhs, Type::PlainNumber(), zone());
846
847 // We can only derive a meaningful type if both {lhs} and {rhs} are inhabited,
848 // and the {rhs} is not 0, otherwise the result is NaN independent of {lhs}.
849 if (!lhs.IsNone() && !rhs.Is(cache_->kSingletonZero)) {
850 // Determine the bounds of {lhs} and {rhs}.
851 double const lmin = lhs.Min();
852 double const lmax = lhs.Max();
853 double const rmin = rhs.Min();
854 double const rmax = rhs.Max();
855
856 // The sign of the result is the sign of the {lhs}.
857 if (lmin < 0.0) maybe_minuszero = true;
858
859 // For integer inputs {lhs} and {rhs} we can infer a precise type.
860 if (lhs.Is(cache_->kInteger) && rhs.Is(cache_->kInteger)) {
861 double labs = std::max(std::abs(lmin), std::abs(lmax));
862 double rabs = std::max(std::abs(rmin), std::abs(rmax)) - 1;
863 double abs = std::min(labs, rabs);
864 double min = 0.0, max = 0.0;
865 if (lmin >= 0.0) {
866 // {lhs} positive.
867 min = 0.0;
868 max = abs;
869 } else if (lmax <= 0.0) {
870 // {lhs} negative.
871 min = 0.0 - abs;
872 max = 0.0;
873 } else {
874 // {lhs} positive or negative.
875 min = 0.0 - abs;
876 max = abs;
877 }
878 type = Type::Range(min, max, zone());
879 } else {
880 type = Type::PlainNumber();
881 }
882 }
883
884 // Take into account the -0 and NaN information computed earlier.
885 if (maybe_minuszero) type = Type::Union(type, Type::MinusZero(), zone());
886 if (maybe_nan) type = Type::Union(type, Type::NaN(), zone());
887 return type;
888}
889
890Type OperationTyper::NumberBitwiseOr(Type lhs, Type rhs) {
891 DCHECK(lhs.Is(Type::Number()));
892 DCHECK(rhs.Is(Type::Number()));
893
894 lhs = NumberToInt32(lhs);
895 rhs = NumberToInt32(rhs);
896
897 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
898
899 double lmin = lhs.Min();
900 double rmin = rhs.Min();
901 double lmax = lhs.Max();
902 double rmax = rhs.Max();
903 // Or-ing any two values results in a value no smaller than their minimum.
904 // Even no smaller than their maximum if both values are non-negative.
905 double min =
906 lmin >= 0 && rmin >= 0 ? std::max(lmin, rmin) : std::min(lmin, rmin);
907 double max = kMaxInt;
908
909 // Or-ing with 0 is essentially a conversion to int32.
910 if (rmin == 0 && rmax == 0) {
911 min = lmin;
912 max = lmax;
913 }
914 if (lmin == 0 && lmax == 0) {
915 min = rmin;
916 max = rmax;
917 }
918
919 if (lmax < 0 || rmax < 0) {
920 // Or-ing two values of which at least one is negative results in a negative
921 // value.
922 max = std::min(max, -1.0);
923 }
924 return Type::Range(min, max, zone());
925}
926
927Type OperationTyper::NumberBitwiseAnd(Type lhs, Type rhs) {
928 DCHECK(lhs.Is(Type::Number()));
929 DCHECK(rhs.Is(Type::Number()));
930
931 lhs = NumberToInt32(lhs);
932 rhs = NumberToInt32(rhs);
933
934 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
935
936 double lmin = lhs.Min();
937 double rmin = rhs.Min();
938 double lmax = lhs.Max();
939 double rmax = rhs.Max();
940 double min = kMinInt;
941 // And-ing any two values results in a value no larger than their maximum.
942 // Even no larger than their minimum if both values are non-negative.
943 double max =
944 lmin >= 0 && rmin >= 0 ? std::min(lmax, rmax) : std::max(lmax, rmax);
945 // And-ing with a non-negative value x causes the result to be between
946 // zero and x.
947 if (lmin >= 0) {
948 min = 0;
949 max = std::min(max, lmax);
950 }
951 if (rmin >= 0) {
952 min = 0;
953 max = std::min(max, rmax);
954 }
955 return Type::Range(min, max, zone());
956}
957
958Type OperationTyper::NumberBitwiseXor(Type lhs, Type rhs) {
959 DCHECK(lhs.Is(Type::Number()));
960 DCHECK(rhs.Is(Type::Number()));
961
962 lhs = NumberToInt32(lhs);
963 rhs = NumberToInt32(rhs);
964
965 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
966
967 double lmin = lhs.Min();
968 double rmin = rhs.Min();
969 double lmax = lhs.Max();
970 double rmax = rhs.Max();
971 if ((lmin >= 0 && rmin >= 0) || (lmax < 0 && rmax < 0)) {
972 // Xor-ing negative or non-negative values results in a non-negative value.
973 return Type::Unsigned31();
974 }
975 if ((lmax < 0 && rmin >= 0) || (lmin >= 0 && rmax < 0)) {
976 // Xor-ing a negative and a non-negative value results in a negative value.
977 // TODO(jarin) Use a range here.
978 return Type::Negative32();
979 }
980 return Type::Signed32();
981}
982
983Type OperationTyper::NumberShiftLeft(Type lhs, Type rhs) {
984 DCHECK(lhs.Is(Type::Number()));
985 DCHECK(rhs.Is(Type::Number()));
986
987 lhs = NumberToInt32(lhs);
988 rhs = NumberToUint32(rhs);
989
990 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
991
992 int32_t min_lhs = lhs.Min();
993 int32_t max_lhs = lhs.Max();
994 uint32_t min_rhs = rhs.Min();
995 uint32_t max_rhs = rhs.Max();
996 if (max_rhs > 31) {
997 // rhs can be larger than the bitmask
998 max_rhs = 31;
999 min_rhs = 0;
1000 }
1001
1002 if (max_lhs > (kMaxInt >> max_rhs) || min_lhs < (kMinInt >> max_rhs)) {
1003 // overflow possible
1004 return Type::Signed32();
1005 }
1006
1007 double min =
1008 std::min(static_cast<int32_t>(static_cast<uint32_t>(min_lhs) << min_rhs),
1009 static_cast<int32_t>(static_cast<uint32_t>(min_lhs) << max_rhs));
1010 double max =
1011 std::max(static_cast<int32_t>(static_cast<uint32_t>(max_lhs) << min_rhs),
1012 static_cast<int32_t>(static_cast<uint32_t>(max_lhs) << max_rhs));
1013
1014 if (max == kMaxInt && min == kMinInt) return Type::Signed32();
1015 return Type::Range(min, max, zone());
1016}
1017
1018Type OperationTyper::NumberShiftRight(Type lhs, Type rhs) {
1019 DCHECK(lhs.Is(Type::Number()));
1020 DCHECK(rhs.Is(Type::Number()));
1021
1022 lhs = NumberToInt32(lhs);
1023 rhs = NumberToUint32(rhs);
1024
1025 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
1026
1027 int32_t min_lhs = lhs.Min();
1028 int32_t max_lhs = lhs.Max();
1029 uint32_t min_rhs = rhs.Min();
1030 uint32_t max_rhs = rhs.Max();
1031 if (max_rhs > 31) {
1032 // rhs can be larger than the bitmask
1033 max_rhs = 31;
1034 min_rhs = 0;
1035 }
1036 double min = std::min(min_lhs >> min_rhs, min_lhs >> max_rhs);
1037 double max = std::max(max_lhs >> min_rhs, max_lhs >> max_rhs);
1038
1039 if (max == kMaxInt && min == kMinInt) return Type::Signed32();
1040 return Type::Range(min, max, zone());
1041}
1042
1043Type OperationTyper::NumberShiftRightLogical(Type lhs, Type rhs) {
1044 DCHECK(lhs.Is(Type::Number()));
1045 DCHECK(rhs.Is(Type::Number()));
1046
1047 lhs = NumberToUint32(lhs);
1048 rhs = NumberToUint32(rhs);
1049
1050 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
1051
1052 uint32_t min_lhs = lhs.Min();
1053 uint32_t max_lhs = lhs.Max();
1054 uint32_t min_rhs = rhs.Min();
1055 uint32_t max_rhs = rhs.Max();
1056 if (max_rhs > 31) {
1057 // rhs can be larger than the bitmask
1058 max_rhs = 31;
1059 min_rhs = 0;
1060 }
1061
1062 double min = min_lhs >> max_rhs;
1063 double max = max_lhs >> min_rhs;
1064 DCHECK_LE(0, min);
1065 DCHECK_LE(max, kMaxUInt32);
1066
1067 if (min == 0 && max == kMaxInt) return Type::Unsigned31();
1068 if (min == 0 && max == kMaxUInt32) return Type::Unsigned32();
1069 return Type::Range(min, max, zone());
1070}
1071
1072Type OperationTyper::NumberAtan2(Type lhs, Type rhs) {
1073 DCHECK(lhs.Is(Type::Number()));
1074 DCHECK(rhs.Is(Type::Number()));
1075 return Type::Number();
1076}
1077
1078Type OperationTyper::NumberImul(Type lhs, Type rhs) {
1079 DCHECK(lhs.Is(Type::Number()));
1080 DCHECK(rhs.Is(Type::Number()));
1081 // TODO(turbofan): We should be able to do better here.
1082 return Type::Signed32();
1083}
1084
1085Type OperationTyper::NumberMax(Type lhs, Type rhs) {
1086 DCHECK(lhs.Is(Type::Number()));
1087 DCHECK(rhs.Is(Type::Number()));
1088
1089 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
1090 if (lhs.Is(Type::NaN()) || rhs.Is(Type::NaN())) return Type::NaN();
1091
1092 Type type = Type::None();
1093 if (lhs.Maybe(Type::NaN()) || rhs.Maybe(Type::NaN())) {
1094 type = Type::Union(type, Type::NaN(), zone());
1095 }
1096 if (lhs.Maybe(Type::MinusZero()) || rhs.Maybe(Type::MinusZero())) {
1097 type = Type::Union(type, Type::MinusZero(), zone());
1098 // In order to ensure monotonicity of the computation below, we additionally
1099 // pretend +0 is present (for simplicity on both sides).
1100 lhs = Type::Union(lhs, cache_->kSingletonZero, zone());
1101 rhs = Type::Union(rhs, cache_->kSingletonZero, zone());
1102 }
1103 if (!lhs.Is(cache_->kIntegerOrMinusZeroOrNaN) ||
1104 !rhs.Is(cache_->kIntegerOrMinusZeroOrNaN)) {
1105 return Type::Union(type, Type::Union(lhs, rhs, zone()), zone());
1106 }
1107
1108 lhs = Type::Intersect(lhs, cache_->kInteger, zone());
1109 rhs = Type::Intersect(rhs, cache_->kInteger, zone());
1110 DCHECK(!lhs.IsNone());
1111 DCHECK(!rhs.IsNone());
1112
1113 double min = std::max(lhs.Min(), rhs.Min());
1114 double max = std::max(lhs.Max(), rhs.Max());
1115 type = Type::Union(type, Type::Range(min, max, zone()), zone());
1116
1117 return type;
1118}
1119
1120Type OperationTyper::NumberMin(Type lhs, Type rhs) {
1121 DCHECK(lhs.Is(Type::Number()));
1122 DCHECK(rhs.Is(Type::Number()));
1123
1124 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
1125 if (lhs.Is(Type::NaN()) || rhs.Is(Type::NaN())) return Type::NaN();
1126
1127 Type type = Type::None();
1128 if (lhs.Maybe(Type::NaN()) || rhs.Maybe(Type::NaN())) {
1129 type = Type::Union(type, Type::NaN(), zone());
1130 }
1131 if (lhs.Maybe(Type::MinusZero()) || rhs.Maybe(Type::MinusZero())) {
1132 type = Type::Union(type, Type::MinusZero(), zone());
1133 // In order to ensure monotonicity of the computation below, we additionally
1134 // pretend +0 is present (for simplicity on both sides).
1135 lhs = Type::Union(lhs, cache_->kSingletonZero, zone());
1136 rhs = Type::Union(rhs, cache_->kSingletonZero, zone());
1137 }
1138 if (!lhs.Is(cache_->kIntegerOrMinusZeroOrNaN) ||
1139 !rhs.Is(cache_->kIntegerOrMinusZeroOrNaN)) {
1140 return Type::Union(type, Type::Union(lhs, rhs, zone()), zone());
1141 }
1142
1143 lhs = Type::Intersect(lhs, cache_->kInteger, zone());
1144 rhs = Type::Intersect(rhs, cache_->kInteger, zone());
1145 DCHECK(!lhs.IsNone());
1146 DCHECK(!rhs.IsNone());
1147
1148 double min = std::min(lhs.Min(), rhs.Min());
1149 double max = std::min(lhs.Max(), rhs.Max());
1150 type = Type::Union(type, Type::Range(min, max, zone()), zone());
1151
1152 return type;
1153}
1154
1155Type OperationTyper::NumberPow(Type lhs, Type rhs) {
1156 DCHECK(lhs.Is(Type::Number()));
1157 DCHECK(rhs.Is(Type::Number()));
1158 // TODO(turbofan): We should be able to do better here.
1159 return Type::Number();
1160}
1161
1162#define SPECULATIVE_NUMBER_BINOP(Name) \
1163 Type OperationTyper::Speculative##Name(Type lhs, Type rhs) { \
1164 lhs = SpeculativeToNumber(lhs); \
1165 rhs = SpeculativeToNumber(rhs); \
1166 return Name(lhs, rhs); \
1167 }
1168SPECULATIVE_NUMBER_BINOP(NumberAdd)
1169SPECULATIVE_NUMBER_BINOP(NumberSubtract)
1170SPECULATIVE_NUMBER_BINOP(NumberMultiply)
1171SPECULATIVE_NUMBER_BINOP(NumberPow)
1172SPECULATIVE_NUMBER_BINOP(NumberDivide)
1173SPECULATIVE_NUMBER_BINOP(NumberModulus)
1174SPECULATIVE_NUMBER_BINOP(NumberBitwiseOr)
1175SPECULATIVE_NUMBER_BINOP(NumberBitwiseAnd)
1176SPECULATIVE_NUMBER_BINOP(NumberBitwiseXor)
1177SPECULATIVE_NUMBER_BINOP(NumberShiftLeft)
1178SPECULATIVE_NUMBER_BINOP(NumberShiftRight)
1179SPECULATIVE_NUMBER_BINOP(NumberShiftRightLogical)
1180#undef SPECULATIVE_NUMBER_BINOP
1181
1182#define MACHINE_BINOP(Name) \
1183 Type OperationTyper::Name(Type, Type) { return Type::Machine(); }
1185#undef MACHINE_BINOP
1186
1188 return Type::Machine();
1189}
1190
1191#define BIGINT_BINOP(Name) \
1192 Type OperationTyper::Name(Type lhs, Type rhs) { \
1193 DCHECK(lhs.Is(Type::BigInt())); \
1194 DCHECK(rhs.Is(Type::BigInt())); \
1195 if (lhs.IsNone() || rhs.IsNone()) return Type::None(); \
1196 return Type::BigInt(); \
1197 }
1199#undef BIGINT_BINOP
1200
1201Type OperationTyper::BigIntNegate(Type type) {
1202 DCHECK(type.Is(Type::BigInt()));
1203
1204 if (type.IsNone()) return type;
1205 return Type::BigInt();
1206}
1207
1208#define SPECULATIVE_BIGINT_BINOP(Name) \
1209 Type OperationTyper::Name(Type lhs, Type rhs) { \
1210 if (lhs.IsNone() || rhs.IsNone()) return Type::None(); \
1211 return Type::BigInt(); \
1212 }
1214#undef SPECULATIVE_BIGINT_BINOP
1215
1216Type OperationTyper::SpeculativeBigIntNegate(Type type) {
1217 if (type.IsNone()) return type;
1218 return Type::BigInt();
1219}
1220
1221Type OperationTyper::SpeculativeToBigInt(Type type) {
1222 return ToBigInt(Type::Intersect(type, Type::BigInt(), zone()));
1223}
1224
1225Type OperationTyper::SpeculativeToNumber(Type type) {
1226 return ToNumber(Type::Intersect(type, Type::NumberOrOddball(), zone()));
1227}
1228
1230 if (type.Is(Type::Primitive())) {
1231 return type;
1232 }
1233 return Type::Primitive();
1234}
1235
1237 DCHECK(type.Is(Type::Boolean()));
1238 CHECK(!type.IsNone());
1239 if (type.Is(singleton_false())) return singleton_true();
1240 if (type.Is(singleton_true())) return singleton_false();
1241 return type;
1242}
1243
1245 ComparisonOutcome outcome) {
1247 if ((outcome & kComparisonUndefined) != 0) result |= kComparisonUndefined;
1248 if ((outcome & kComparisonTrue) != 0) result |= kComparisonFalse;
1249 if ((outcome & kComparisonFalse) != 0) result |= kComparisonTrue;
1250 return result;
1251}
1252
1254 if ((outcome & kComparisonFalse) != 0 ||
1255 (outcome & kComparisonUndefined) != 0) {
1256 return (outcome & kComparisonTrue) != 0 ? Type::Boolean()
1257 : singleton_false();
1258 }
1259 // Type should be non empty, so we know it should be true.
1260 DCHECK_NE(0, outcome & kComparisonTrue);
1261 return singleton_true();
1262}
1263
1264namespace {
1265
1266Type JSType(Type type) {
1267 if (type.Is(Type::Boolean())) return Type::Boolean();
1268 if (type.Is(Type::String())) return Type::String();
1269 if (type.Is(Type::Number())) return Type::Number();
1270 if (type.Is(Type::BigInt())) return Type::BigInt();
1271 if (type.Is(Type::Undefined())) return Type::Undefined();
1272 if (type.Is(Type::Null())) return Type::Null();
1273 if (type.Is(Type::Symbol())) return Type::Symbol();
1274 if (type.Is(Type::Receiver())) return Type::Receiver(); // JS "Object"
1275 return Type::Any();
1276}
1277
1278} // namespace
1279
1281 if (lhs.IsNone() || rhs.IsNone()) return Type::None();
1282 if (!JSType(lhs).Maybe(JSType(rhs))) return singleton_false();
1283 if (lhs.Is(Type::NaN())) {
1284 if (rhs.Is(Type::NaN())) return singleton_true();
1285 if (!rhs.Maybe(Type::NaN())) return singleton_false();
1286 } else if (rhs.Is(Type::NaN())) {
1287 if (!lhs.Maybe(Type::NaN())) return singleton_false();
1288 }
1289 if (lhs.Is(Type::MinusZero())) {
1290 if (rhs.Is(Type::MinusZero())) return singleton_true();
1291 if (!rhs.Maybe(Type::MinusZero())) return singleton_false();
1292 } else if (rhs.Is(Type::MinusZero())) {
1293 if (!lhs.Maybe(Type::MinusZero())) return singleton_false();
1294 }
1295 if (lhs.Is(Type::OrderedNumber()) && rhs.Is(Type::OrderedNumber()) &&
1296 (lhs.Max() < rhs.Min() || lhs.Min() > rhs.Max())) {
1297 return singleton_false();
1298 }
1299 return Type::Boolean();
1300}
1301
1303 // SameValue and SamevalueNumbersOnly only differ in treatment of
1304 // strings and biginits. Since the SameValue typer does not do anything
1305 // special about strings or bigints, we can just use it here.
1306 return SameValue(lhs, rhs);
1307}
1308
1310 CHECK(!lhs.IsNone());
1311 CHECK(!rhs.IsNone());
1312 if (!JSType(lhs).Maybe(JSType(rhs))) return singleton_false();
1313 if (lhs.Is(Type::NaN()) || rhs.Is(Type::NaN())) return singleton_false();
1314 if (lhs.Is(Type::Number()) && rhs.Is(Type::Number()) &&
1315 (lhs.Max() < rhs.Min() || lhs.Min() > rhs.Max())) {
1316 return singleton_false();
1317 }
1318 if (lhs.IsSingleton() && rhs.Is(lhs)) {
1319 // Types are equal and are inhabited only by a single semantic value,
1320 // which is not nan due to the earlier check.
1321 DCHECK(lhs.Is(rhs));
1322 return singleton_true();
1323 }
1324 if ((lhs.Is(Type::Unique()) || rhs.Is(Type::Unique())) && !lhs.Maybe(rhs)) {
1325 // One of the inputs has a canonical representation but types don't overlap.
1326 return singleton_false();
1327 }
1328 return Type::Boolean();
1329}
1330
1332 DCHECK(length.Is(cache_->kPositiveSafeInteger));
1333 if (length.Is(cache_->kSingletonZero)) return Type::None();
1334 Type const upper_bound = Type::Range(0.0, length.Max() - 1, zone());
1335 if (index.Maybe(Type::String())) return upper_bound;
1336 if (index.Maybe(Type::MinusZero())) {
1337 index = Type::Union(index, cache_->kSingletonZero, zone());
1338 }
1339 return Type::Intersect(index, upper_bound, zone());
1340}
1341
1343 if (type.Maybe(Type::Hole())) {
1344 // Turn a "hole" into undefined.
1345 type = Type::Intersect(type, Type::Number(), zone());
1346 type = Type::Union(type, Type::Undefined(), zone());
1347 }
1348 return type;
1349}
1350
1352 return Type::Intersect(type, Type::Number(), zone());
1353}
1354
1356 return Type::Intersect(type, Type::Signed32(), zone());
1357}
1358
1360 return Type::Intersect(input, TypeGuardTypeOf(sigma_op), zone());
1361}
1362
1364 if (input.Maybe(Type::Hole())) {
1365 // Turn a "hole" into undefined.
1366 Type type = Type::Intersect(input, Type::NonInternal(), zone());
1367 return Type::Union(type, Type::Undefined(), zone());
1368 }
1369 return input;
1370}
1371
1373 if (type.Is(Type::Boolean())) return type;
1374 if (type.Is(falsish_)) return singleton_false_;
1375 if (type.Is(truish_)) return singleton_true_;
1376 if (type.Is(Type::Number())) {
1377 return NumberToBoolean(type);
1378 }
1379 return Type::Boolean();
1380}
1381
1382} // namespace compiler
1383} // namespace internal
1384} // namespace v8
OperationTyper(JSHeapBroker *broker, Zone *zone)
Type TypeTypeGuard(const Operator *sigma_op, Type input)
Type AddRanger(double lhs_min, double lhs_max, double rhs_min, double rhs_max)
Type Merge(Type left, Type right)
ComparisonOutcome Invert(ComparisonOutcome)
Type WeakenRange(Type current_range, Type previous_range)
Type SubtractRanger(double lhs_min, double lhs_max, double rhs_min, double rhs_max)
Type SameValueNumbersOnly(Type lhs, Type rhs)
Type MultiplyRanger(double lhs_min, double lhs_max, double rhs_min, double rhs_max)
Type CheckBounds(Type index, Type length)
static Type Union(Type type1, Type type2, Zone *zone)
bool Maybe(Type that) const
static Type Constant(JSHeapBroker *broker, Handle< i::Object > value, Zone *zone)
static Type Intersect(Type type1, Type type2, Zone *zone)
bool Is(Type that) const
static Type Range(double min, double max, Zone *zone)
Zone * zone_
#define V8_INFINITY
Definition globals.h:23
JSHeapBroker * broker
ZoneVector< RpoNumber > & result
int x
int n
Definition mul-fft.cc:296
STL namespace.
int int32_t
Definition unicode.cc:40
V8_INLINE const Operation & Get(const Graph &graph, OpIndex index)
Definition graph.h:1231
T array_min(const std::array< T, N > &a)
Definition typer.h:22
T array_max(const std::array< T, N > &a)
Definition typer.h:38
Type TypeGuardTypeOf(Operator const *op)
constexpr int kMinInt
Definition globals.h:375
uint32_t NumberToUint32(Tagged< Object > number)
int32_t NumberToInt32(Tagged< Object > number)
constexpr int kMaxInt
Definition globals.h:374
constexpr uint32_t kMaxUInt32
Definition globals.h:387
#define SIMPLIFIED_BIGINT_BINOP_LIST(V)
Definition opcodes.h:367
#define SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(V)
Definition opcodes.h:561
#define SPECULATIVE_BIGINT_BINOP(Name)
#define SPECULATIVE_NUMBER_BINOP(Name)
#define MACHINE_BINOP(Name)
#define BIGINT_BINOP(Name)
#define TYPER_SUPPORTED_MACHINE_BINOP_LIST(V)
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define arraysize(array)
Definition macros.h:67
wasm::ValueType type