Index: src/compiler/typer.cc |
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc |
index dafd3c95a128f317d0033d1d0b6aeb2e0441f0a2..740701b5cebee4192eed8663b1d33622b3b975a0 100644 |
--- a/src/compiler/typer.cc |
+++ b/src/compiler/typer.cc |
@@ -900,36 +900,165 @@ Type* Typer::Visitor::JSGreaterThanOrEqualTyper( |
// JS bitwise operators. |
-Type* Typer::Visitor::JSBitwiseOrTyper(Type* lhs, Type* rhs, Typer* t) { |
- lhs = NumberToInt32(ToNumber(lhs, t), t); |
- rhs = NumberToInt32(ToNumber(rhs, t), t); |
- double lmin = lhs->Min(); |
- 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(); |
+// Calculate the result minimum. The algorithm considers one bit at a time, from |
+// the most significant to least significant, refining a copy of the input |
+// ranges and terminating when the ranges are equal. |
+static uint32_t BitwiseOrLow(uint32_t lmin, uint32_t lmax, |
+ uint32_t rmin, uint32_t rmax) { |
+ uint32_t bit = 0x80000000, mask = 0x7fffffff; |
+ |
+ // Loop, terminating when the ranges are equal, moving down one bit on each |
+ // iteration. |
+ for (; lmin != lmax || rmin != rmax; bit >>= 1, mask >>= 1) { |
+ // Mask off the current bit from each range limit. |
+ uint32_t lminb = lmin & bit; |
+ uint32_t lmaxb = lmax & bit; |
+ uint32_t rminb = rmin & bit; |
+ uint32_t rmaxb = rmax & bit; |
+ // At this point the higher bits of each range are equal so comparing the |
+ // current bit between the upper and lower limit can determine if the bit |
+ // changes over the range. If the two input bits are both static across |
+ // their ranges then this bit result is known and is the logical OR of each. |
+ if (lminb != lmaxb || rminb != rmaxb) { |
+ if (lminb == lmaxb) { |
+ // The lhs bit is static over its range. The rhs bit changes across it's |
+ // range. |
+ if (lminb) { |
+ // The lhs bit is one forcing the result bit to be one. The rhs bit is |
+ // not significant to this bit in the result due to the OR |
+ // operation. The rhs minimum of the remaining bits is zero which |
+ // occurs when this current bit ticks over to one - which must be |
+ // within range because the bit changes. When the lower rhs bits are |
+ // zero they do not affect the lower lhs bits and the result is known. |
+ rmin &= ~mask; |
+ break; |
+ } else { |
+ // The lhs bit is zero so the result bit equals the rhs bit. The result |
+ // minimum occurs when the bit is zero so the rhs range can be culled |
+ // to highest input that does not give a one in this bit position. This |
+ // is achieved by clearing the bit and setting all the lower bits. |
+ rmax = (rmax & ~bit) | mask; |
+ } |
+ } else if (rminb == rmaxb) { |
+ // The rhs bit is static over its range. The lhs bit changes across it's |
+ // range. Cull the lhs range as above. |
+ if (rminb) { |
+ lmin &= ~mask; |
+ break; |
+ } else { |
+ lmax = (lmax & ~bit) | mask; |
+ } |
+ } else { |
+ // Both input bits change across their ranges. The result minimum will |
+ // occur then the result bit is zero which demands that both input ranges |
+ // be zero in this bit and they are culled as above. |
+ lmax = (lmax & ~bit) | mask; |
+ rmax = (rmax & ~bit) | mask; |
+ } |
+ } |
+ } |
+ return lmin | rmin; |
+} |
+ |
+ |
+// Calculate the result maximum. The algorithm is parallel to the above, but the |
+// logic is somewhat reversed because it is calculating the maximum rather than |
+// the minimum, and it is possible to exit early if both input bits change |
+// across their range. |
+static uint32_t BitwiseOrHigh(uint32_t lmin, uint32_t lmax, |
+ uint32_t rmin, uint32_t rmax) { |
+ uint32_t bit = 0x80000000, mask = 0x7fffffff; |
+ |
+ for (; lmin != lmax || rmin != rmax; bit >>= 1, mask >>= 1) { |
+ uint32_t lminb = lmin & bit; |
+ uint32_t lmaxb = lmax & bit; |
+ uint32_t rminb = rmin & bit; |
+ uint32_t rmaxb = rmax & bit; |
+ if (lminb != lmaxb || rminb != rmaxb) { |
+ if (lminb == lmaxb) { |
+ if (lminb) { |
+ rmax |= mask; |
+ break; |
+ } else { |
+ rmin = (rmin & ~mask) | bit; |
+ } |
+ } else if (rminb == rmaxb) { |
+ if (rminb) { |
+ lmax |= mask; |
+ break; |
+ } else { |
+ lmin = (lmin & ~mask) | bit; |
+ } |
+ } else { |
+ // Both input bits change across their ranges. If this bit changes then |
+ // all the lower bits also change across both input ranges, and since |
+ // the result is one if either is one then the maximum occurs when all |
+ // lower bits are one. The lhsUpperBit is already set at this point, so |
+ // this bit does not need setting here too, just the lower bits. |
+ lmax |= mask; |
+ break; |
+ } |
+ } |
+ } |
+ return lmax | rmax; |
+} |
+ |
- // Or-ing with 0 is essentially a conversion to int32. |
- if (rmin == 0 && rmax == 0) { |
- min = lmin; |
- max = lmax; |
+IntType JSBitwiseOrIntType(IntType lhs, IntType rhs) { |
+ // Or-ing with 0 is essentially a conversion to int32, and or-ing |
+ // with -1 returns -1. |
+ if (rhs.min == rhs.max) { |
+ if (rhs.min == 0) { |
+ return IntType(lhs.min, lhs.max); |
+ } |
+ if (rhs.min == -1) { |
+ return IntType(rhs.min, rhs.max); |
+ } |
} |
- if (lmin == 0 && lmax == 0) { |
- min = rmin; |
- max = rmax; |
+ if (lhs.min == lhs.max) { |
+ if (lhs.min == 0) { |
+ return IntType(rhs.min, rhs.max); |
+ } |
+ if (lhs.min == -1) { |
+ return IntType(lhs.min, lhs.max); |
+ } |
} |
- if (lmax < 0 || rmax < 0) { |
- // Or-ing two values of which at least one is negative results in a negative |
- // value. |
- max = std::min(max, -1.0); |
+ // Divide the calculation into sub-ranges that do not change sign. |
+ uint32_t lminp = uint32_t(std::max(lhs.min, 0)); |
+ uint32_t lmaxn = uint32_t(std::min(lhs.max, -1)); |
+ uint32_t rminp = uint32_t(std::max(rhs.min, 0)); |
+ uint32_t rmaxn = uint32_t(std::min(rhs.max, -1)); |
+ int32_t min = kMaxInt, max = kMinInt; |
+ |
+ if (lhs.max >= 0 && rhs.max >= 0) { |
+ min = std::min(min, int32_t(BitwiseOrLow(lminp, lhs.max, rminp, rhs.max))); |
+ max = std::max(max, int32_t(BitwiseOrHigh(lminp, lhs.max, rminp, rhs.max))); |
} |
- return Type::Range(min, max, t->zone()); |
- // TODO(neis): Be precise for singleton inputs, here and elsewhere. |
+ if (lhs.max >= 0 && rhs.min < 0) { |
+ min = std::min(min, int32_t(BitwiseOrLow(lminp, lhs.max, rhs.min, rmaxn))); |
+ max = std::max(max, int32_t(BitwiseOrHigh(lminp, lhs.max, rhs.min, rmaxn))); |
+ } |
+ if (lhs.min < 0 && rhs.max >= 0) { |
+ min = std::min(min, int32_t(BitwiseOrLow(lhs.min, lmaxn, rminp, rhs.max))); |
+ max = std::max(max, int32_t(BitwiseOrHigh(lhs.min, lmaxn, rminp, rhs.max))); |
+ } |
+ if (lhs.min < 0 && rhs.min < 0) { |
+ min = std::min(min, int32_t(BitwiseOrLow(lhs.min, lmaxn, rhs.min, rmaxn))); |
+ max = std::max(max, int32_t(BitwiseOrHigh(lhs.min, lmaxn, rhs.min, rmaxn))); |
+ } |
+ DCHECK(max >= min); |
+ |
+ return IntType(min, max); |
+} |
+ |
+ |
+Type* Typer::Visitor::JSBitwiseOrTyper(Type* lhs, Type* rhs, Typer* t) { |
+ lhs = NumberToInt32(ToNumber(lhs, t), t); |
+ rhs = NumberToInt32(ToNumber(rhs, t), t); |
+ IntType type = JSBitwiseOrIntType(IntType(lhs->Min(), lhs->Max()), |
+ IntType(rhs->Min(), rhs->Max())); |
+ return Type::Range(type.min, type.max, t->zone()); |
} |