Index: src/compiler/typer.cc |
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc |
index c638535727f1c9593c001fb90e9333d2481dd1fa..00692d9581c7cb59efea7ff3b594258d62f07dfc 100644 |
--- a/src/compiler/typer.cc |
+++ b/src/compiler/typer.cc |
@@ -874,22 +874,96 @@ Type* Typer::Visitor::JSBitwiseOrTyper(Type* lhs, Type* rhs, Typer* t) { |
double rmin = rhs->Min(); |
double lmax = lhs->Max(); |
double rmax = rhs->Max(); |
- // Or-ing any two values results in a value no smaller than their minimum. |
- // Even no smaller than their maximum if both values are non-negative. |
- double min = |
- lmin >= 0 && rmin >= 0 ? std::max(lmin, rmin) : std::min(lmin, rmin); |
- double max = Type::Signed32()->Max(); |
titzer
2015/03/10 07:47:13
Please add unit tests for the typer and mjsunit te
|
- // Or-ing with 0 is essentially a conversion to int32. |
- if (rmin == 0 && rmax == 0) { |
- min = lmin; |
- max = lmax; |
+ // Or-ing with 0 is essentially a conversion to int32, and or-ing |
+ // with -1 returns -1. |
+ if (rmin == rmax) { |
+ if (rmin == 0) { |
+ return Type::Range(lmin, lmax, t->zone()); |
+ } |
+ if (rmin == -1) { |
+ return Type::Range(rmin, rmax, t->zone()); |
+ } |
+ } |
+ if (lmin == lmax) { |
+ if (lmin == 0) { |
+ return Type::Range(rmin, rmax, t->zone()); |
+ } |
+ if (lmin == -1) { |
+ return Type::Range(lmin, lmax, t->zone()); |
+ } |
} |
- if (lmin == 0 && lmax == 0) { |
- min = rmin; |
- max = rmax; |
+ |
+ if (lmin >= 0 && rmin >= 0) { |
+ // Precise calculation of the result range for positive ranges. |
+ double min, max; |
+ int32_t lmin2, lmax2, rmin2, rmax2, bit, mask; |
+ |
+ // Calculate the result minimum. |
+ lmin2 = lmin, lmax2 = lmax, rmin2 = rmin, rmax2 = rmax; |
+ bit = 0x40000000, mask = 0x3fffffff; |
+ for (; lmin2 != lmax2 || rmin2 != rmax2; bit >>= 1, mask >>= 1) { |
+ int32_t lminb = lmin2 & bit; |
+ int32_t lmaxb = lmax2 & bit; |
+ int32_t rminb = rmin2 & bit; |
+ int32_t rmaxb = rmax2 & bit; |
+ if (lminb != lmaxb || rminb != rmaxb) { |
+ if (lminb == lmaxb) { |
+ if (lminb) { |
+ rmin2 = (rmin2 & ~mask) | bit; |
+ } else { |
+ rmax2 = (rmax2 & ~bit) | mask; |
+ } |
+ } else if (rminb == rmaxb) { |
+ if (rminb) { |
+ lmin2 = (lmin2 & ~mask) | bit; |
+ } else { |
+ lmax2 = (lmax2 & ~bit) | mask; |
+ } |
+ } else { |
+ lmax2 = (lmax2 & ~bit) | mask; |
+ rmax2 = (rmax2 & ~bit) | mask; |
+ } |
+ } |
+ } |
+ min = lmin2 | rmin2; |
+ |
+ // Calculate the result maximum. |
+ lmin2 = lmin, lmax2 = lmax, rmin2 = rmin, rmax2 = rmax; |
+ bit = 0x40000000, mask = 0x3fffffff; |
+ for (; lmin2 != lmax2 || rmin2 != rmax2; bit >>= 1, mask >>= 1) { |
+ int32_t lminb = lmin2 & bit; |
+ int32_t lmaxb = lmax2 & bit; |
+ int32_t rminb = rmin2 & bit; |
+ int32_t rmaxb = rmax2 & bit; |
+ if (lminb != lmaxb || rminb != rmaxb) { |
+ if (lminb == lmaxb) { |
+ if (lminb) { |
+ rmax2 = (rmax2 & ~bit) | mask; |
+ } else { |
+ rmin2 = (rmin2 & ~mask) | bit; |
+ } |
+ } else if (rminb == rmaxb) { |
+ if (rminb) { |
+ lmax2 = (lmax2 & ~bit) | mask; |
+ } else { |
+ lmin2 = (lmin2 & ~mask) | bit; |
+ } |
+ } else { |
+ lmax2 = lmax2 | mask; |
+ break; |
+ } |
+ } |
+ } |
+ max = lmax2 | rmax2; |
+ |
+ return Type::Range(min, max, t->zone()); |
} |
+ // Or-ing any two values results in a value no smaller than their minimum. |
+ double min = std::min(lmin, rmin); |
+ double max = Type::Signed32()->Max(); |
+ |
if (lmax < 0 || rmax < 0) { |
// Or-ing two values of which at least one is negative results in a negative |
// value. |