From: verwaest@chromium.org Date: Fri, 14 Jun 2013 17:25:03 +0000 (+0000) Subject: Revert "Improved range analysis for bitwise operations." X-Git-Tag: upstream/4.7.83~13813 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=328aeb14fbeba317e7a49b8c63c93ea60aa462ae;p=platform%2Fupstream%2Fv8.git Revert "Improved range analysis for bitwise operations." This reverts commit r15170 R=jkummerow@chromium.org Review URL: https://chromiumcodereview.appspot.com/17093005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15173 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index 8e418e4..f69fbc9 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -289,8 +289,16 @@ static int32_t MulWithoutOverflow(int32_t a, int32_t b, bool* overflow) { } -void Range::ToBitRange(BitRange* bits) const { - BitRange::SetFromRange(bits, lower_, upper_); +int32_t Range::Mask() const { + if (lower_ == upper_) return lower_; + if (lower_ >= 0) { + int32_t res = 1; + while (res < upper_) { + res = (res << 1) | 1; + } + return res; + } + return 0xffffffff; } @@ -2374,38 +2382,50 @@ void HMathMinMax::InferRepresentation(HInferRepresentation* h_infer) { Range* HBitwise::InferRange(Zone* zone) { - if (representation().IsInteger32()) { - BitRange left_bits, right_bits; - - if (left()->HasRange()) { - left()->range()->ToBitRange(&left_bits); + if (op() == Token::BIT_XOR) { + if (left()->HasRange() && right()->HasRange()) { + // The maximum value has the high bit, and all bits below, set: + // (1 << high) - 1. + // If the range can be negative, the minimum int is a negative number with + // the high bit, and all bits below, unset: + // -(1 << high). + // If it cannot be negative, conservatively choose 0 as minimum int. + int64_t left_upper = left()->range()->upper(); + int64_t left_lower = left()->range()->lower(); + int64_t right_upper = right()->range()->upper(); + int64_t right_lower = right()->range()->lower(); + + if (left_upper < 0) left_upper = ~left_upper; + if (left_lower < 0) left_lower = ~left_lower; + if (right_upper < 0) right_upper = ~right_upper; + if (right_lower < 0) right_lower = ~right_lower; + + int high = MostSignificantBit( + static_cast( + left_upper | left_lower | right_upper | right_lower)); + + int64_t limit = 1; + limit <<= high; + int32_t min = (left()->range()->CanBeNegative() || + right()->range()->CanBeNegative()) + ? static_cast(-limit) : 0; + return new(zone) Range(min, static_cast(limit - 1)); } - - if (right()->HasRange()) { - right()->range()->ToBitRange(&right_bits); - } - - BitRange result; - switch (op()) { - case Token::BIT_AND: - result = BitRange::And(left_bits, right_bits); - break; - case Token::BIT_OR: - result = BitRange::Or(left_bits, right_bits); - break; - case Token::BIT_XOR: - result = BitRange::Xor(left_bits, right_bits); - break; - default: - UNREACHABLE(); - } - - int32_t lower = kMaxInt, upper = kMinInt; // 'empty' range. - result.ExtendRange(&lower, &upper); - return new(zone) Range(lower, upper); - } else { return HValue::InferRange(zone); } + const int32_t kDefaultMask = static_cast(0xffffffff); + int32_t left_mask = (left()->range() != NULL) + ? left()->range()->Mask() + : kDefaultMask; + int32_t right_mask = (right()->range() != NULL) + ? right()->range()->Mask() + : kDefaultMask; + int32_t result_mask = (op() == Token::BIT_AND) + ? left_mask & right_mask + : left_mask | right_mask; + return (result_mask >= 0) + ? new(zone) Range(0, result_mask) + : HValue::InferRange(zone); } diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index d92770a..7554fd8 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -43,7 +43,6 @@ namespace v8 { namespace internal { // Forward declarations. -class BitRange; class HBasicBlock; class HEnvironment; class HInferRepresentation; @@ -260,7 +259,7 @@ class Range: public ZoneObject { result->set_can_be_minus_zero(CanBeMinusZero()); return result; } - void ToBitRange(BitRange* bits) const; + int32_t Mask() const; void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; } bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; } bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; } @@ -307,60 +306,6 @@ class Range: public ZoneObject { }; -class BitRange { - public: - BitRange() : known_(0), bits_(0) { } - BitRange(int32_t known, int32_t bits) - : known_(known), bits_(bits & known) { } - - static void SetFromRange(BitRange* bits, int32_t lower, int32_t upper) { - // Find a mask for the most significant bits that are the same for all - // values in the range. - int32_t same = ~(lower ^ upper); - // Flood zeros to any bits lower than the most significant zero. - same &= (same >> 1); - same &= (same >> 2); - same &= (same >> 4); - same &= (same >> 8); - same &= (same >> 16); - - bits->known_ = same; - bits->bits_ = lower & same; - } - - void ExtendRange(int32_t* lower, int32_t* upper) const { - int32_t limit1 = (~known_ & 0x80000000) | bits_; - int32_t limit2 = (~known_ & 0x7fffffff) | bits_; - *lower = Min(*lower, Min(limit1, limit2)); - *upper = Max(*upper, Max(limit1, limit2)); - } - - static BitRange And(BitRange a, BitRange b) { - int32_t known = a.known_ & b.known_; - // Zeros in either operand become known. - known |= (a.known_ & ~a.bits_); - known |= (b.known_ & ~b.bits_); - return BitRange(known, a.bits_ & b.bits_); - } - - static BitRange Or(BitRange a, BitRange b) { - int32_t known = a.known_ & b.known_; - // Ones in either operand become known. - known |= (a.known_ & a.bits_); - known |= (b.known_ & b.bits_); - return BitRange(known, a.bits_ | b.bits_); - } - - static BitRange Xor(BitRange a, BitRange b) { - return BitRange(a.known_ & b.known_, a.bits_ ^ b.bits_); - } - - private: - int32_t known_; // A mask of known bits. - int32_t bits_; // Values of known bits, zero elsewhere. -}; - - class UniqueValueId { public: UniqueValueId() : raw_address_(NULL) { } diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index b8e0516..0811093 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -52,7 +52,6 @@ 'test-ast.cc', 'test-bignum.cc', 'test-bignum-dtoa.cc', - 'test-bitrange.cc', 'test-circular-queue.cc', 'test-compare-nil-ic-stub.cc', 'test-compiler.cc', diff --git a/test/cctest/test-bitrange.cc b/test/cctest/test-bitrange.cc deleted file mode 100644 index 44e751d..0000000 --- a/test/cctest/test-bitrange.cc +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2013 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include - -#include "v8.h" - -#include "hydrogen-instructions.h" -#include "cctest.h" - -using namespace v8::internal; - -static int32_t GetLo(const BitRange& range) { - int32_t lo = kMaxInt, hi = kMinInt; - range.ExtendRange(&lo, &hi); - return lo; -} - - -static int32_t GetHi(const BitRange& range) { - int32_t lo = kMaxInt, hi = kMinInt; - range.ExtendRange(&lo, &hi); - return hi; -} - - -static void CheckOp(int32_t a_lo, int32_t a_hi, - int32_t b_lo, int32_t b_hi, - BitRange op(BitRange, BitRange), - int32_t expected_lo, int32_t expected_hi) { - BitRange a_range; - BitRange b_range; - BitRange::SetFromRange(&a_range, a_lo, a_hi); - BitRange::SetFromRange(&b_range, b_lo, b_hi); - BitRange result = op(a_range, b_range); - CHECK_EQ(expected_lo, GetLo(result)); - CHECK_EQ(expected_hi, GetHi(result)); -} - - -TEST(BitRangeConstants) { - // Converting a constant to BitRange and back is lossless. - for (int32_t i = -100; i <= 100; i++) { - BitRange r; - BitRange::SetFromRange(&r, i, i); - int32_t lo = kMaxInt, hi = kMinInt; - r.ExtendRange(&lo, &hi); - CHECK_EQ(i, lo); - CHECK_EQ(i, hi); - } -} - - -TEST(BitRangeConstantOps) { - for (int32_t a = -16; a <= 15; a++) { - for (int32_t b = -16; b <= 15; b++) { - CheckOp(a, a, b, b, &BitRange::And, a & b, a & b); - CheckOp(a, a, b, b, &BitRange::Or, a | b, a | b); - CheckOp(a, a, b, b, &BitRange::Xor, a ^ b, a ^ b); - } - } -} - - -static void CheckConvert(int32_t lo, int32_t hi, - int32_t expected_lo, int32_t expected_hi) { - BitRange range; - BitRange::SetFromRange(&range, lo, hi); - CHECK_EQ(expected_lo, GetLo(range)); - CHECK_EQ(expected_hi, GetHi(range)); -} - - -TEST(BitRangeConversion) { - // [0, 4] --> 000xxx - CheckConvert(0, 4, 0, 7); - CheckConvert(0, 5, 0, 7); - CheckConvert(0, 6, 0, 7); - CheckConvert(0, 7, 0, 7); - - CheckConvert(1, 4, 0, 7); - CheckConvert(1, 5, 0, 7); - CheckConvert(1, 6, 0, 7); - CheckConvert(1, 7, 0, 7); -} - - -TEST(BitRangeConservativeApproximation) { - // Exhaustive test of 5-bit integers. - // The BitRange operation must always include all real possible values. - const int32_t kMin = -16; - const int32_t kMax = 15; - - int count = 0; - int and_precise_count = 0; - int or_precise_count = 0; - int xor_precise_count = 0; - - for (int32_t a_lo = kMin; a_lo <= kMax; a_lo++) { - for (int32_t a_hi = a_lo; a_hi <= kMax; a_hi++) { - for (int32_t b_lo = kMin; b_lo <= kMax; b_lo++) { - for (int32_t b_hi = a_lo; b_hi <= kMax; b_hi++) { - // Compute precise ranges. - int32_t and_lo = kMaxInt, and_hi = kMinInt; - int32_t or_lo = kMaxInt, or_hi = kMinInt; - int32_t xor_lo = kMaxInt, xor_hi = kMinInt; - - for (int32_t a = a_lo; a <= a_hi; a++) { - for (int32_t b = b_lo; b <= b_hi; b++) { - int32_t a_and_b = a & b; - and_lo = Min(and_lo, a_and_b); - and_hi = Max(and_hi, a_and_b); - int32_t a_or_b = a | b; - or_lo = Min(or_lo, a_or_b); - or_hi = Max(or_hi, a_or_b); - int32_t a_xor_b = a ^ b; - xor_lo = Min(xor_lo, a_xor_b); - xor_hi = Max(xor_hi, a_xor_b); - } - } - - BitRange a_range; - BitRange::SetFromRange(&a_range, a_lo, a_hi); - BitRange b_range; - BitRange::SetFromRange(&b_range, b_lo, b_hi); - - ++count; - // Precise range must always be included in approximate result. - BitRange and_range = BitRange::And(a_range, b_range); - CHECK(GetLo(and_range) <= and_lo); - CHECK(GetHi(and_range) >= and_hi); - if (GetLo(and_range) == and_lo && GetHi(and_range) == and_hi) { - ++and_precise_count; - } - - BitRange or_range = BitRange::Or(a_range, b_range); - CHECK(GetLo(or_range) <= or_lo); - CHECK(GetHi(or_range) >= or_hi); - if (GetLo(or_range) == or_lo && GetHi(or_range) == or_hi) { - ++or_precise_count; - } - - BitRange xor_range = BitRange::Xor(a_range, b_range); - CHECK(GetLo(xor_range) <= xor_lo); - CHECK(GetHi(xor_range) >= xor_hi); - if (GetLo(xor_range) == xor_lo && GetHi(xor_range) == xor_hi) { - ++xor_precise_count; - } - } - } - } - } - - CHECK_EQ(366080, count); - CHECK_EQ(35668, and_precise_count); - CHECK_EQ(35668, or_precise_count); - CHECK_EQ(37480, xor_precise_count); -} - - -TEST(BitRangeMultiRange) { - // Multiple ranges can be unioned with multiple calls to ExtendRange. - // - // HBitWise::InferRange is a 1x1 decomposition. Each input range is - // 'decomposed' into 1 BitRange. It is possible to do a more precise - // decompostion into several BitRanges. 2 BitRanges might be the sweet-spot - // since it prevents change-of-sign polluting the result. - // - // E.g. [-2,3] = {xxxxxxxx} as one BitRange, but is {1111111x, 000000xx} as - // two. - // - // [-2,3] ^ [-1,5] = {xxxxxxxx} ^ {xxxxxxxx} = xxxxxxxx - // - // With a 2x2 decomposition, there are 4 intermediate results. - // - // [-2,3] ^ [-1,5] = {1111111x, 000000xx} ^ {11111111, 00000xxx} - // result11 = 1111111x ^ 11111111 = 0000000x - // result12 = 1111111x ^ 00000xxx = 11111xxx - // result21 = 000000xx ^ 11111111 = 111111xx - // result22 = 000000xx ^ 00000xxx = 00000xxx - // - // These can be accumulated into a range as follows: - // - // result11.ExtendRange(&lower, &upper); // 0, 1 - // result12.ExtendRange(&lower, &upper); // -8, 1 - // result21.ExtendRange(&lower, &upper); // -8, 1 - // result22.ExtendRange(&lower, &upper); // -8, 7 - // = [-8,7] - - { - BitRange r1(~0x000C, 0x0022); // 0010xx10 - BitRange r2(~0x0003, 0x0004); // 0000x1xx - int32_t lo = kMaxInt, hi = kMinInt; - r1.ExtendRange(&lo, &hi); - CHECK_EQ(0x22, lo); - CHECK_EQ(0x2E, hi); - - r2.ExtendRange(&lo, &hi); - CHECK_EQ(0x04, lo); - CHECK_EQ(0x2E, hi); - } - - { - BitRange r1(~0, -1); // 11111111 - BitRange r2(~1, 0); // 0000000x - int32_t lo = kMaxInt, hi = kMinInt; - r1.ExtendRange(&lo, &hi); - CHECK_EQ(-1, lo); - CHECK_EQ(-1, hi); - - r2.ExtendRange(&lo, &hi); - CHECK_EQ(-1, lo); - CHECK_EQ(1, hi); - } -} - - -TEST(BitRangeOps) { - // xxxx & 000x => 000x - CheckOp(kMinInt, kMaxInt, 0, 1, &BitRange::And, 0, 1); - - CheckOp(3, 7, 0, 0, &BitRange::Or, 0, 7); - CheckOp(4, 5, 0, 0, &BitRange::Or, 4, 5); - CheckOp(3, 7, 4, 4, &BitRange::Or, 4, 7); - CheckOp(0, 99, 4, 4, &BitRange::Or, 4, 127); - - // 01xx ^ 0100 -> 00xx - CheckOp(4, 7, 4, 4, &BitRange::Xor, 0, 3); - // 00xx ^ 0100 -> 01xx - CheckOp(0, 3, 4, 4, &BitRange::Xor, 4, 7); -}