michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_RangeAnalysis_h michael@0: #define jit_RangeAnalysis_h michael@0: michael@0: #include "mozilla/FloatingPoint.h" michael@0: #include "mozilla/MathAlgorithms.h" michael@0: michael@0: #include "jit/IonAnalysis.h" michael@0: #include "jit/MIR.h" michael@0: michael@0: // windows.h defines those, which messes with the definitions below. michael@0: #undef min michael@0: #undef max michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: class MBasicBlock; michael@0: class MIRGraph; michael@0: michael@0: // An upper bound computed on the number of backedges a loop will take. michael@0: // This count only includes backedges taken while running Ion code: for OSR michael@0: // loops, this will exclude iterations that executed in the interpreter or in michael@0: // baseline compiled code. michael@0: struct LoopIterationBound : public TempObject michael@0: { michael@0: // Loop for which this bound applies. michael@0: MBasicBlock *header; michael@0: michael@0: // Test from which this bound was derived. Code in the loop body which this michael@0: // test dominates (will include the backedge) will execute at most 'bound' michael@0: // times. Other code in the loop will execute at most '1 + Max(bound, 0)' michael@0: // times. michael@0: MTest *test; michael@0: michael@0: // Symbolic bound computed for the number of backedge executions. michael@0: LinearSum sum; michael@0: michael@0: LoopIterationBound(MBasicBlock *header, MTest *test, LinearSum sum) michael@0: : header(header), test(test), sum(sum) michael@0: { michael@0: } michael@0: }; michael@0: michael@0: // A symbolic upper or lower bound computed for a term. michael@0: struct SymbolicBound : public TempObject michael@0: { michael@0: private: michael@0: SymbolicBound(LoopIterationBound *loop, LinearSum sum) michael@0: : loop(loop), sum(sum) michael@0: { michael@0: } michael@0: michael@0: public: michael@0: // Any loop iteration bound from which this was derived. michael@0: // michael@0: // If non-nullptr, then 'sum' is only valid within the loop body, at michael@0: // points dominated by the loop bound's test (see LoopIterationBound). michael@0: // michael@0: // If nullptr, then 'sum' is always valid. michael@0: LoopIterationBound *loop; michael@0: michael@0: static SymbolicBound *New(TempAllocator &alloc, LoopIterationBound *loop, LinearSum sum) { michael@0: return new(alloc) SymbolicBound(loop, sum); michael@0: } michael@0: michael@0: // Computed symbolic bound, see above. michael@0: LinearSum sum; michael@0: michael@0: void print(Sprinter &sp) const; michael@0: void dump() const; michael@0: }; michael@0: michael@0: class RangeAnalysis michael@0: { michael@0: protected: michael@0: bool blockDominates(MBasicBlock *b, MBasicBlock *b2); michael@0: void replaceDominatedUsesWith(MDefinition *orig, MDefinition *dom, michael@0: MBasicBlock *block); michael@0: michael@0: protected: michael@0: MIRGenerator *mir; michael@0: MIRGraph &graph_; michael@0: michael@0: TempAllocator &alloc() const; michael@0: michael@0: public: michael@0: MOZ_CONSTEXPR RangeAnalysis(MIRGenerator *mir, MIRGraph &graph) : michael@0: mir(mir), graph_(graph) {} michael@0: bool addBetaNodes(); michael@0: bool analyze(); michael@0: bool addRangeAssertions(); michael@0: bool removeBetaNodes(); michael@0: bool prepareForUCE(bool *shouldRemoveDeadCode); michael@0: bool truncate(); michael@0: michael@0: private: michael@0: bool analyzeLoop(MBasicBlock *header); michael@0: LoopIterationBound *analyzeLoopIterationCount(MBasicBlock *header, michael@0: MTest *test, BranchDirection direction); michael@0: void analyzeLoopPhi(MBasicBlock *header, LoopIterationBound *loopBound, MPhi *phi); michael@0: bool tryHoistBoundsCheck(MBasicBlock *header, MBoundsCheck *ins); michael@0: bool markBlocksInLoopBody(MBasicBlock *header, MBasicBlock *current); michael@0: }; michael@0: michael@0: class Range : public TempObject { michael@0: public: michael@0: // Int32 are signed. INT32_MAX is pow(2,31)-1 and INT32_MIN is -pow(2,31), michael@0: // so the greatest exponent we need is 31. michael@0: static const uint16_t MaxInt32Exponent = 31; michael@0: michael@0: // UInt32 are unsigned. UINT32_MAX is pow(2,32)-1, so it's the greatest michael@0: // value that has an exponent of 31. michael@0: static const uint16_t MaxUInt32Exponent = 31; michael@0: michael@0: // Maximal exponenent under which we have no precission loss on double michael@0: // operations. Double has 52 bits of mantissa, so 2^52+1 cannot be michael@0: // represented without loss. michael@0: static const uint16_t MaxTruncatableExponent = mozilla::FloatingPoint::ExponentShift; michael@0: michael@0: // Maximum exponent for finite values. michael@0: static const uint16_t MaxFiniteExponent = mozilla::FloatingPoint::ExponentBias; michael@0: michael@0: // An special exponent value representing all non-NaN values. This michael@0: // includes finite values and the infinities. michael@0: static const uint16_t IncludesInfinity = MaxFiniteExponent + 1; michael@0: michael@0: // An special exponent value representing all possible double-precision michael@0: // values. This includes finite values, the infinities, and NaNs. michael@0: static const uint16_t IncludesInfinityAndNaN = UINT16_MAX; michael@0: michael@0: // This range class uses int32_t ranges, but has several interfaces which michael@0: // use int64_t, which either holds an int32_t value, or one of the following michael@0: // special values which mean a value which is beyond the int32 range, michael@0: // potentially including infinity or NaN. These special values are michael@0: // guaranteed to compare greater, and less than, respectively, any int32_t michael@0: // value. michael@0: static const int64_t NoInt32UpperBound = int64_t(JSVAL_INT_MAX) + 1; michael@0: static const int64_t NoInt32LowerBound = int64_t(JSVAL_INT_MIN) - 1; michael@0: michael@0: private: michael@0: // Absolute ranges. michael@0: // michael@0: // We represent ranges where the endpoints can be in the set: michael@0: // {-infty} U [INT_MIN, INT_MAX] U {infty}. A bound of +/- michael@0: // infty means that the value may have overflowed in that michael@0: // direction. When computing the range of an integer michael@0: // instruction, the ranges of the operands can be clamped to michael@0: // [INT_MIN, INT_MAX], since if they had overflowed they would michael@0: // no longer be integers. This is important for optimizations michael@0: // and somewhat subtle. michael@0: // michael@0: // N.B.: All of the operations that compute new ranges based michael@0: // on existing ranges will ignore the hasInt32*Bound_ flags of the michael@0: // input ranges; that is, they implicitly clamp the ranges of michael@0: // the inputs to [INT_MIN, INT_MAX]. Therefore, while our range might michael@0: // be unbounded (and could overflow), when using this information to michael@0: // propagate through other ranges, we disregard this fact; if that code michael@0: // executes, then the overflow did not occur, so we may safely assume michael@0: // that the range is [INT_MIN, INT_MAX] instead. michael@0: // michael@0: // To facilitate this trick, we maintain the invariants that: michael@0: // 1) hasInt32LowerBound_ == false implies lower_ == JSVAL_INT_MIN michael@0: // 2) hasInt32UpperBound_ == false implies upper_ == JSVAL_INT_MAX michael@0: // michael@0: // As a second and less precise range analysis, we represent the maximal michael@0: // exponent taken by a value. The exponent is calculated by taking the michael@0: // absolute value and looking at the position of the highest bit. All michael@0: // exponent computation have to be over-estimations of the actual result. On michael@0: // the Int32 this over approximation is rectified. michael@0: michael@0: int32_t lower_; michael@0: bool hasInt32LowerBound_; michael@0: michael@0: int32_t upper_; michael@0: bool hasInt32UpperBound_; michael@0: michael@0: bool canHaveFractionalPart_; michael@0: uint16_t max_exponent_; michael@0: michael@0: // Any symbolic lower or upper bound computed for this term. michael@0: const SymbolicBound *symbolicLower_; michael@0: const SymbolicBound *symbolicUpper_; michael@0: michael@0: // This function simply makes several JS_ASSERTs to verify the internal michael@0: // consistency of this range. michael@0: void assertInvariants() const { michael@0: // Basic sanity :). michael@0: JS_ASSERT(lower_ <= upper_); michael@0: michael@0: // When hasInt32LowerBound_ or hasInt32UpperBound_ are false, we set michael@0: // lower_ and upper_ to these specific values as it simplifies the michael@0: // implementation in some places. michael@0: JS_ASSERT_IF(!hasInt32LowerBound_, lower_ == JSVAL_INT_MIN); michael@0: JS_ASSERT_IF(!hasInt32UpperBound_, upper_ == JSVAL_INT_MAX); michael@0: michael@0: // max_exponent_ must be one of three possible things. michael@0: JS_ASSERT(max_exponent_ <= MaxFiniteExponent || michael@0: max_exponent_ == IncludesInfinity || michael@0: max_exponent_ == IncludesInfinityAndNaN); michael@0: michael@0: // Forbid the max_exponent_ field from implying better bounds for michael@0: // lower_/upper_ fields. We have to add 1 to the max_exponent_ when michael@0: // canHaveFractionalPart_ is true in order to accomodate fractional michael@0: // offsets. For example, 2147483647.9 is greater than INT32_MAX, so a michael@0: // range containing that value will have hasInt32UpperBound_ set to michael@0: // false, however that value also has exponent 30, which is strictly michael@0: // less than MaxInt32Exponent. For another example, 1.9 has an exponent michael@0: // of 0 but requires upper_ to be at least 2, which has exponent 1. michael@0: JS_ASSERT_IF(!hasInt32LowerBound_ || !hasInt32UpperBound_, michael@0: max_exponent_ + canHaveFractionalPart_ >= MaxInt32Exponent); michael@0: JS_ASSERT(max_exponent_ + canHaveFractionalPart_ >= michael@0: mozilla::FloorLog2(mozilla::Abs(upper_))); michael@0: JS_ASSERT(max_exponent_ + canHaveFractionalPart_ >= michael@0: mozilla::FloorLog2(mozilla::Abs(lower_))); michael@0: michael@0: // The following are essentially static assertions, but FloorLog2 isn't michael@0: // trivially suitable for constexpr :(. michael@0: JS_ASSERT(mozilla::FloorLog2(JSVAL_INT_MIN) == MaxInt32Exponent); michael@0: JS_ASSERT(mozilla::FloorLog2(JSVAL_INT_MAX) == 30); michael@0: JS_ASSERT(mozilla::FloorLog2(UINT32_MAX) == MaxUInt32Exponent); michael@0: JS_ASSERT(mozilla::FloorLog2(0) == 0); michael@0: } michael@0: michael@0: // Set the lower_ and hasInt32LowerBound_ values. michael@0: void setLowerInit(int64_t x) { michael@0: if (x > JSVAL_INT_MAX) { michael@0: lower_ = JSVAL_INT_MAX; michael@0: hasInt32LowerBound_ = true; michael@0: } else if (x < JSVAL_INT_MIN) { michael@0: lower_ = JSVAL_INT_MIN; michael@0: hasInt32LowerBound_ = false; michael@0: } else { michael@0: lower_ = int32_t(x); michael@0: hasInt32LowerBound_ = true; michael@0: } michael@0: } michael@0: // Set the upper_ and hasInt32UpperBound_ values. michael@0: void setUpperInit(int64_t x) { michael@0: if (x > JSVAL_INT_MAX) { michael@0: upper_ = JSVAL_INT_MAX; michael@0: hasInt32UpperBound_ = false; michael@0: } else if (x < JSVAL_INT_MIN) { michael@0: upper_ = JSVAL_INT_MIN; michael@0: hasInt32UpperBound_ = true; michael@0: } else { michael@0: upper_ = int32_t(x); michael@0: hasInt32UpperBound_ = true; michael@0: } michael@0: } michael@0: michael@0: // Compute the least exponent value that would be compatible with the michael@0: // values of lower() and upper(). michael@0: // michael@0: // Note: michael@0: // exponent of JSVAL_INT_MIN == 31 michael@0: // exponent of JSVAL_INT_MAX == 30 michael@0: uint16_t exponentImpliedByInt32Bounds() const { michael@0: // The number of bits needed to encode |max| is the power of 2 plus one. michael@0: uint32_t max = Max(mozilla::Abs(lower()), mozilla::Abs(upper())); michael@0: uint16_t result = mozilla::FloorLog2(max); michael@0: JS_ASSERT(result == (max == 0 ? 0 : mozilla::ExponentComponent(double(max)))); michael@0: return result; michael@0: } michael@0: michael@0: // When converting a range which contains fractional values to a range michael@0: // containing only integers, the old max_exponent_ value may imply a better michael@0: // lower and/or upper bound than was previously available, because they no michael@0: // longer need to be conservative about fractional offsets and the ends of michael@0: // the range. michael@0: // michael@0: // Given an exponent value and pointers to the lower and upper bound values, michael@0: // this function refines the lower and upper bound values to the tighest michael@0: // bound for integer values implied by the exponent. michael@0: static void refineInt32BoundsByExponent(uint16_t e, int32_t *l, int32_t *h) { michael@0: if (e < MaxInt32Exponent) { michael@0: // pow(2, max_exponent_+1)-1 to compute a maximum absolute value. michael@0: int32_t limit = (uint32_t(1) << (e + 1)) - 1; michael@0: *h = Min(*h, limit); michael@0: *l = Max(*l, -limit); michael@0: } michael@0: } michael@0: michael@0: // If the value of any of the fields implies a stronger possible value for michael@0: // any other field, update that field to the stronger value. The range must michael@0: // be completely valid before and it is guaranteed to be kept valid. michael@0: void optimize() { michael@0: assertInvariants(); michael@0: michael@0: if (hasInt32Bounds()) { michael@0: // Examine lower() and upper(), and if they imply a better exponent michael@0: // bound than max_exponent_, set that value as the new michael@0: // max_exponent_. michael@0: uint16_t newExponent = exponentImpliedByInt32Bounds(); michael@0: if (newExponent < max_exponent_) { michael@0: max_exponent_ = newExponent; michael@0: assertInvariants(); michael@0: } michael@0: michael@0: // If we have a completely precise range, the value is an integer, michael@0: // since we can only represent integers. michael@0: if (canHaveFractionalPart_ && lower_ == upper_) { michael@0: canHaveFractionalPart_ = false; michael@0: assertInvariants(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Set the range fields to the given raw values. michael@0: void rawInitialize(int32_t l, bool lb, int32_t h, bool hb, bool f, uint16_t e) { michael@0: lower_ = l; michael@0: hasInt32LowerBound_ = lb; michael@0: upper_ = h; michael@0: hasInt32UpperBound_ = hb; michael@0: canHaveFractionalPart_ = f; michael@0: max_exponent_ = e; michael@0: optimize(); michael@0: } michael@0: michael@0: // Construct a range from the given raw values. michael@0: Range(int32_t l, bool lb, int32_t h, bool hb, bool f, uint16_t e) michael@0: : symbolicLower_(nullptr), michael@0: symbolicUpper_(nullptr) michael@0: { michael@0: rawInitialize(l, lb, h, hb, f, e); michael@0: } michael@0: michael@0: public: michael@0: Range() michael@0: : symbolicLower_(nullptr), michael@0: symbolicUpper_(nullptr) michael@0: { michael@0: setUnknown(); michael@0: } michael@0: michael@0: Range(int64_t l, int64_t h, bool f = false, uint16_t e = MaxInt32Exponent) michael@0: : symbolicLower_(nullptr), michael@0: symbolicUpper_(nullptr) michael@0: { michael@0: set(l, h, f, e); michael@0: } michael@0: michael@0: Range(const Range &other) michael@0: : lower_(other.lower_), michael@0: hasInt32LowerBound_(other.hasInt32LowerBound_), michael@0: upper_(other.upper_), michael@0: hasInt32UpperBound_(other.hasInt32UpperBound_), michael@0: canHaveFractionalPart_(other.canHaveFractionalPart_), michael@0: max_exponent_(other.max_exponent_), michael@0: symbolicLower_(nullptr), michael@0: symbolicUpper_(nullptr) michael@0: { michael@0: assertInvariants(); michael@0: } michael@0: michael@0: // Construct a range from the given MDefinition. This differs from the michael@0: // MDefinition's range() method in that it describes the range of values michael@0: // *after* any bailout checks. michael@0: Range(const MDefinition *def); michael@0: michael@0: static Range *NewInt32Range(TempAllocator &alloc, int32_t l, int32_t h) { michael@0: return new(alloc) Range(l, h, false, MaxInt32Exponent); michael@0: } michael@0: michael@0: static Range *NewUInt32Range(TempAllocator &alloc, uint32_t l, uint32_t h) { michael@0: // For now, just pass them to the constructor as int64_t values. michael@0: // They'll become unbounded if they're not in the int32_t range. michael@0: return new(alloc) Range(l, h, false, MaxUInt32Exponent); michael@0: } michael@0: michael@0: static Range *NewDoubleRange(TempAllocator &alloc, double l, double h) { michael@0: if (mozilla::IsNaN(l) && mozilla::IsNaN(h)) michael@0: return nullptr; michael@0: michael@0: Range *r = new(alloc) Range(); michael@0: r->setDouble(l, h); michael@0: return r; michael@0: } michael@0: michael@0: void print(Sprinter &sp) const; michael@0: void dump(FILE *fp) const; michael@0: void dump() const; michael@0: bool update(const Range *other); michael@0: michael@0: // Unlike the other operations, unionWith is an in-place michael@0: // modification. This is to avoid a bunch of useless extra michael@0: // copying when chaining together unions when handling Phi michael@0: // nodes. michael@0: void unionWith(const Range *other); michael@0: static Range *intersect(TempAllocator &alloc, const Range *lhs, const Range *rhs, michael@0: bool *emptyRange); michael@0: static Range *add(TempAllocator &alloc, const Range *lhs, const Range *rhs); michael@0: static Range *sub(TempAllocator &alloc, const Range *lhs, const Range *rhs); michael@0: static Range *mul(TempAllocator &alloc, const Range *lhs, const Range *rhs); michael@0: static Range *and_(TempAllocator &alloc, const Range *lhs, const Range *rhs); michael@0: static Range *or_(TempAllocator &alloc, const Range *lhs, const Range *rhs); michael@0: static Range *xor_(TempAllocator &alloc, const Range *lhs, const Range *rhs); michael@0: static Range *not_(TempAllocator &alloc, const Range *op); michael@0: static Range *lsh(TempAllocator &alloc, const Range *lhs, int32_t c); michael@0: static Range *rsh(TempAllocator &alloc, const Range *lhs, int32_t c); michael@0: static Range *ursh(TempAllocator &alloc, const Range *lhs, int32_t c); michael@0: static Range *lsh(TempAllocator &alloc, const Range *lhs, const Range *rhs); michael@0: static Range *rsh(TempAllocator &alloc, const Range *lhs, const Range *rhs); michael@0: static Range *ursh(TempAllocator &alloc, const Range *lhs, const Range *rhs); michael@0: static Range *abs(TempAllocator &alloc, const Range *op); michael@0: static Range *min(TempAllocator &alloc, const Range *lhs, const Range *rhs); michael@0: static Range *max(TempAllocator &alloc, const Range *lhs, const Range *rhs); michael@0: michael@0: static bool negativeZeroMul(const Range *lhs, const Range *rhs); michael@0: michael@0: bool isUnknownInt32() const { michael@0: return isInt32() && lower() == INT32_MIN && upper() == INT32_MAX; michael@0: } michael@0: michael@0: bool isUnknown() const { michael@0: return !hasInt32LowerBound_ && michael@0: !hasInt32UpperBound_ && michael@0: canHaveFractionalPart_ && michael@0: max_exponent_ == IncludesInfinityAndNaN; michael@0: } michael@0: michael@0: bool hasInt32LowerBound() const { michael@0: return hasInt32LowerBound_; michael@0: } michael@0: bool hasInt32UpperBound() const { michael@0: return hasInt32UpperBound_; michael@0: } michael@0: michael@0: // Test whether the value is known to be within [INT32_MIN,INT32_MAX]. michael@0: // Note that this does not necessarily mean the value is an integer. michael@0: bool hasInt32Bounds() const { michael@0: return hasInt32LowerBound() && hasInt32UpperBound(); michael@0: } michael@0: michael@0: // Test whether the value is known to be representable as an int32. michael@0: bool isInt32() const { michael@0: return hasInt32Bounds() && !canHaveFractionalPart(); michael@0: } michael@0: michael@0: // Test whether the given value is known to be either 0 or 1. michael@0: bool isBoolean() const { michael@0: return lower() >= 0 && upper() <= 1 && !canHaveFractionalPart(); michael@0: } michael@0: michael@0: bool canHaveRoundingErrors() const { michael@0: return canHaveFractionalPart() || max_exponent_ >= MaxTruncatableExponent; michael@0: } michael@0: michael@0: // Test whether the range contains zero. michael@0: bool canBeZero() const { michael@0: return lower_ <= 0 && upper_ >= 0; michael@0: } michael@0: michael@0: // Test whether the range contains NaN values. michael@0: bool canBeNaN() const { michael@0: return max_exponent_ == IncludesInfinityAndNaN; michael@0: } michael@0: michael@0: // Test whether the range contains infinities or NaN values. michael@0: bool canBeInfiniteOrNaN() const { michael@0: return max_exponent_ >= IncludesInfinity; michael@0: } michael@0: michael@0: bool canHaveFractionalPart() const { michael@0: return canHaveFractionalPart_; michael@0: } michael@0: michael@0: uint16_t exponent() const { michael@0: JS_ASSERT(!canBeInfiniteOrNaN()); michael@0: return max_exponent_; michael@0: } michael@0: michael@0: uint16_t numBits() const { michael@0: return exponent() + 1; // 2^0 -> 1 michael@0: } michael@0: michael@0: // Return the lower bound. Asserts that the value has an int32 bound. michael@0: int32_t lower() const { michael@0: JS_ASSERT(hasInt32LowerBound()); michael@0: return lower_; michael@0: } michael@0: michael@0: // Return the upper bound. Asserts that the value has an int32 bound. michael@0: int32_t upper() const { michael@0: JS_ASSERT(hasInt32UpperBound()); michael@0: return upper_; michael@0: } michael@0: michael@0: // Test whether all values in this range can are finite and negative. michael@0: bool isFiniteNegative() const { michael@0: return upper_ < 0 && !canBeInfiniteOrNaN(); michael@0: } michael@0: michael@0: // Test whether all values in this range can are finite and non-negative. michael@0: bool isFiniteNonNegative() const { michael@0: return lower_ >= 0 && !canBeInfiniteOrNaN(); michael@0: } michael@0: michael@0: // Test whether a value in this range can possibly be a finite michael@0: // negative value. michael@0: bool canBeFiniteNegative() const { michael@0: return lower_ < 0; michael@0: } michael@0: michael@0: // Test whether a value in this range can possibly be a finite michael@0: // non-negative value. michael@0: bool canBeFiniteNonNegative() const { michael@0: return upper_ >= 0; michael@0: } michael@0: michael@0: // Set this range to have a lower bound not less than x. michael@0: void refineLower(int32_t x) { michael@0: assertInvariants(); michael@0: hasInt32LowerBound_ = true; michael@0: lower_ = Max(lower_, x); michael@0: optimize(); michael@0: } michael@0: michael@0: // Set this range to have an upper bound not greater than x. michael@0: void refineUpper(int32_t x) { michael@0: assertInvariants(); michael@0: hasInt32UpperBound_ = true; michael@0: upper_ = Min(upper_, x); michael@0: optimize(); michael@0: } michael@0: michael@0: void setInt32(int32_t l, int32_t h) { michael@0: hasInt32LowerBound_ = true; michael@0: hasInt32UpperBound_ = true; michael@0: lower_ = l; michael@0: upper_ = h; michael@0: canHaveFractionalPart_ = false; michael@0: max_exponent_ = exponentImpliedByInt32Bounds(); michael@0: assertInvariants(); michael@0: } michael@0: michael@0: void setDouble(double l, double h); michael@0: michael@0: void setUnknown() { michael@0: set(NoInt32LowerBound, NoInt32UpperBound, true, IncludesInfinityAndNaN); michael@0: JS_ASSERT(isUnknown()); michael@0: } michael@0: michael@0: void set(int64_t l, int64_t h, bool f, uint16_t e) { michael@0: max_exponent_ = e; michael@0: canHaveFractionalPart_ = f; michael@0: setLowerInit(l); michael@0: setUpperInit(h); michael@0: optimize(); michael@0: } michael@0: michael@0: // Make the lower end of this range at least INT32_MIN, and make michael@0: // the upper end of this range at most INT32_MAX. michael@0: void clampToInt32(); michael@0: michael@0: // If this range exceeds int32_t range, at either or both ends, change michael@0: // it to int32_t range. Otherwise do nothing. michael@0: void wrapAroundToInt32(); michael@0: michael@0: // If this range exceeds [0, 32) range, at either or both ends, change michael@0: // it to the [0, 32) range. Otherwise do nothing. michael@0: void wrapAroundToShiftCount(); michael@0: michael@0: // If this range exceeds [0, 1] range, at either or both ends, change michael@0: // it to the [0, 1] range. Otherwise do nothing. michael@0: void wrapAroundToBoolean(); michael@0: michael@0: const SymbolicBound *symbolicLower() const { michael@0: return symbolicLower_; michael@0: } michael@0: const SymbolicBound *symbolicUpper() const { michael@0: return symbolicUpper_; michael@0: } michael@0: michael@0: void setSymbolicLower(SymbolicBound *bound) { michael@0: symbolicLower_ = bound; michael@0: } michael@0: void setSymbolicUpper(SymbolicBound *bound) { michael@0: symbolicUpper_ = bound; michael@0: } michael@0: }; michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif /* jit_RangeAnalysis_h */