Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(869)

Unified Diff: src/compiler/typer.cc

Issue 986073003: [TurboFan] Calculate precise ranges for bitwise-or with positive input ranges. Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Split the bitwise-or type derivation into a separate function. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/typer.h ('k') | test/unittests/compiler/typer-unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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());
}
« no previous file with comments | « src/compiler/typer.h ('k') | test/unittests/compiler/typer-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698