Index: src/hydrogen-instructions.cc |
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc |
index 8e418e4c76cc1edb6709124657e3d5af4c597927..f69fbc9b938cc5466d859771eb707ee1b1762c54 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<uint32_t>( |
+ 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<int32_t>(-limit) : 0; |
+ return new(zone) Range(min, static_cast<int32_t>(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<int32_t>(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); |
} |