js/src/jit/RangeAnalysis.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef jit_RangeAnalysis_h
michael@0 8 #define jit_RangeAnalysis_h
michael@0 9
michael@0 10 #include "mozilla/FloatingPoint.h"
michael@0 11 #include "mozilla/MathAlgorithms.h"
michael@0 12
michael@0 13 #include "jit/IonAnalysis.h"
michael@0 14 #include "jit/MIR.h"
michael@0 15
michael@0 16 // windows.h defines those, which messes with the definitions below.
michael@0 17 #undef min
michael@0 18 #undef max
michael@0 19
michael@0 20 namespace js {
michael@0 21 namespace jit {
michael@0 22
michael@0 23 class MBasicBlock;
michael@0 24 class MIRGraph;
michael@0 25
michael@0 26 // An upper bound computed on the number of backedges a loop will take.
michael@0 27 // This count only includes backedges taken while running Ion code: for OSR
michael@0 28 // loops, this will exclude iterations that executed in the interpreter or in
michael@0 29 // baseline compiled code.
michael@0 30 struct LoopIterationBound : public TempObject
michael@0 31 {
michael@0 32 // Loop for which this bound applies.
michael@0 33 MBasicBlock *header;
michael@0 34
michael@0 35 // Test from which this bound was derived. Code in the loop body which this
michael@0 36 // test dominates (will include the backedge) will execute at most 'bound'
michael@0 37 // times. Other code in the loop will execute at most '1 + Max(bound, 0)'
michael@0 38 // times.
michael@0 39 MTest *test;
michael@0 40
michael@0 41 // Symbolic bound computed for the number of backedge executions.
michael@0 42 LinearSum sum;
michael@0 43
michael@0 44 LoopIterationBound(MBasicBlock *header, MTest *test, LinearSum sum)
michael@0 45 : header(header), test(test), sum(sum)
michael@0 46 {
michael@0 47 }
michael@0 48 };
michael@0 49
michael@0 50 // A symbolic upper or lower bound computed for a term.
michael@0 51 struct SymbolicBound : public TempObject
michael@0 52 {
michael@0 53 private:
michael@0 54 SymbolicBound(LoopIterationBound *loop, LinearSum sum)
michael@0 55 : loop(loop), sum(sum)
michael@0 56 {
michael@0 57 }
michael@0 58
michael@0 59 public:
michael@0 60 // Any loop iteration bound from which this was derived.
michael@0 61 //
michael@0 62 // If non-nullptr, then 'sum' is only valid within the loop body, at
michael@0 63 // points dominated by the loop bound's test (see LoopIterationBound).
michael@0 64 //
michael@0 65 // If nullptr, then 'sum' is always valid.
michael@0 66 LoopIterationBound *loop;
michael@0 67
michael@0 68 static SymbolicBound *New(TempAllocator &alloc, LoopIterationBound *loop, LinearSum sum) {
michael@0 69 return new(alloc) SymbolicBound(loop, sum);
michael@0 70 }
michael@0 71
michael@0 72 // Computed symbolic bound, see above.
michael@0 73 LinearSum sum;
michael@0 74
michael@0 75 void print(Sprinter &sp) const;
michael@0 76 void dump() const;
michael@0 77 };
michael@0 78
michael@0 79 class RangeAnalysis
michael@0 80 {
michael@0 81 protected:
michael@0 82 bool blockDominates(MBasicBlock *b, MBasicBlock *b2);
michael@0 83 void replaceDominatedUsesWith(MDefinition *orig, MDefinition *dom,
michael@0 84 MBasicBlock *block);
michael@0 85
michael@0 86 protected:
michael@0 87 MIRGenerator *mir;
michael@0 88 MIRGraph &graph_;
michael@0 89
michael@0 90 TempAllocator &alloc() const;
michael@0 91
michael@0 92 public:
michael@0 93 MOZ_CONSTEXPR RangeAnalysis(MIRGenerator *mir, MIRGraph &graph) :
michael@0 94 mir(mir), graph_(graph) {}
michael@0 95 bool addBetaNodes();
michael@0 96 bool analyze();
michael@0 97 bool addRangeAssertions();
michael@0 98 bool removeBetaNodes();
michael@0 99 bool prepareForUCE(bool *shouldRemoveDeadCode);
michael@0 100 bool truncate();
michael@0 101
michael@0 102 private:
michael@0 103 bool analyzeLoop(MBasicBlock *header);
michael@0 104 LoopIterationBound *analyzeLoopIterationCount(MBasicBlock *header,
michael@0 105 MTest *test, BranchDirection direction);
michael@0 106 void analyzeLoopPhi(MBasicBlock *header, LoopIterationBound *loopBound, MPhi *phi);
michael@0 107 bool tryHoistBoundsCheck(MBasicBlock *header, MBoundsCheck *ins);
michael@0 108 bool markBlocksInLoopBody(MBasicBlock *header, MBasicBlock *current);
michael@0 109 };
michael@0 110
michael@0 111 class Range : public TempObject {
michael@0 112 public:
michael@0 113 // Int32 are signed. INT32_MAX is pow(2,31)-1 and INT32_MIN is -pow(2,31),
michael@0 114 // so the greatest exponent we need is 31.
michael@0 115 static const uint16_t MaxInt32Exponent = 31;
michael@0 116
michael@0 117 // UInt32 are unsigned. UINT32_MAX is pow(2,32)-1, so it's the greatest
michael@0 118 // value that has an exponent of 31.
michael@0 119 static const uint16_t MaxUInt32Exponent = 31;
michael@0 120
michael@0 121 // Maximal exponenent under which we have no precission loss on double
michael@0 122 // operations. Double has 52 bits of mantissa, so 2^52+1 cannot be
michael@0 123 // represented without loss.
michael@0 124 static const uint16_t MaxTruncatableExponent = mozilla::FloatingPoint<double>::ExponentShift;
michael@0 125
michael@0 126 // Maximum exponent for finite values.
michael@0 127 static const uint16_t MaxFiniteExponent = mozilla::FloatingPoint<double>::ExponentBias;
michael@0 128
michael@0 129 // An special exponent value representing all non-NaN values. This
michael@0 130 // includes finite values and the infinities.
michael@0 131 static const uint16_t IncludesInfinity = MaxFiniteExponent + 1;
michael@0 132
michael@0 133 // An special exponent value representing all possible double-precision
michael@0 134 // values. This includes finite values, the infinities, and NaNs.
michael@0 135 static const uint16_t IncludesInfinityAndNaN = UINT16_MAX;
michael@0 136
michael@0 137 // This range class uses int32_t ranges, but has several interfaces which
michael@0 138 // use int64_t, which either holds an int32_t value, or one of the following
michael@0 139 // special values which mean a value which is beyond the int32 range,
michael@0 140 // potentially including infinity or NaN. These special values are
michael@0 141 // guaranteed to compare greater, and less than, respectively, any int32_t
michael@0 142 // value.
michael@0 143 static const int64_t NoInt32UpperBound = int64_t(JSVAL_INT_MAX) + 1;
michael@0 144 static const int64_t NoInt32LowerBound = int64_t(JSVAL_INT_MIN) - 1;
michael@0 145
michael@0 146 private:
michael@0 147 // Absolute ranges.
michael@0 148 //
michael@0 149 // We represent ranges where the endpoints can be in the set:
michael@0 150 // {-infty} U [INT_MIN, INT_MAX] U {infty}. A bound of +/-
michael@0 151 // infty means that the value may have overflowed in that
michael@0 152 // direction. When computing the range of an integer
michael@0 153 // instruction, the ranges of the operands can be clamped to
michael@0 154 // [INT_MIN, INT_MAX], since if they had overflowed they would
michael@0 155 // no longer be integers. This is important for optimizations
michael@0 156 // and somewhat subtle.
michael@0 157 //
michael@0 158 // N.B.: All of the operations that compute new ranges based
michael@0 159 // on existing ranges will ignore the hasInt32*Bound_ flags of the
michael@0 160 // input ranges; that is, they implicitly clamp the ranges of
michael@0 161 // the inputs to [INT_MIN, INT_MAX]. Therefore, while our range might
michael@0 162 // be unbounded (and could overflow), when using this information to
michael@0 163 // propagate through other ranges, we disregard this fact; if that code
michael@0 164 // executes, then the overflow did not occur, so we may safely assume
michael@0 165 // that the range is [INT_MIN, INT_MAX] instead.
michael@0 166 //
michael@0 167 // To facilitate this trick, we maintain the invariants that:
michael@0 168 // 1) hasInt32LowerBound_ == false implies lower_ == JSVAL_INT_MIN
michael@0 169 // 2) hasInt32UpperBound_ == false implies upper_ == JSVAL_INT_MAX
michael@0 170 //
michael@0 171 // As a second and less precise range analysis, we represent the maximal
michael@0 172 // exponent taken by a value. The exponent is calculated by taking the
michael@0 173 // absolute value and looking at the position of the highest bit. All
michael@0 174 // exponent computation have to be over-estimations of the actual result. On
michael@0 175 // the Int32 this over approximation is rectified.
michael@0 176
michael@0 177 int32_t lower_;
michael@0 178 bool hasInt32LowerBound_;
michael@0 179
michael@0 180 int32_t upper_;
michael@0 181 bool hasInt32UpperBound_;
michael@0 182
michael@0 183 bool canHaveFractionalPart_;
michael@0 184 uint16_t max_exponent_;
michael@0 185
michael@0 186 // Any symbolic lower or upper bound computed for this term.
michael@0 187 const SymbolicBound *symbolicLower_;
michael@0 188 const SymbolicBound *symbolicUpper_;
michael@0 189
michael@0 190 // This function simply makes several JS_ASSERTs to verify the internal
michael@0 191 // consistency of this range.
michael@0 192 void assertInvariants() const {
michael@0 193 // Basic sanity :).
michael@0 194 JS_ASSERT(lower_ <= upper_);
michael@0 195
michael@0 196 // When hasInt32LowerBound_ or hasInt32UpperBound_ are false, we set
michael@0 197 // lower_ and upper_ to these specific values as it simplifies the
michael@0 198 // implementation in some places.
michael@0 199 JS_ASSERT_IF(!hasInt32LowerBound_, lower_ == JSVAL_INT_MIN);
michael@0 200 JS_ASSERT_IF(!hasInt32UpperBound_, upper_ == JSVAL_INT_MAX);
michael@0 201
michael@0 202 // max_exponent_ must be one of three possible things.
michael@0 203 JS_ASSERT(max_exponent_ <= MaxFiniteExponent ||
michael@0 204 max_exponent_ == IncludesInfinity ||
michael@0 205 max_exponent_ == IncludesInfinityAndNaN);
michael@0 206
michael@0 207 // Forbid the max_exponent_ field from implying better bounds for
michael@0 208 // lower_/upper_ fields. We have to add 1 to the max_exponent_ when
michael@0 209 // canHaveFractionalPart_ is true in order to accomodate fractional
michael@0 210 // offsets. For example, 2147483647.9 is greater than INT32_MAX, so a
michael@0 211 // range containing that value will have hasInt32UpperBound_ set to
michael@0 212 // false, however that value also has exponent 30, which is strictly
michael@0 213 // less than MaxInt32Exponent. For another example, 1.9 has an exponent
michael@0 214 // of 0 but requires upper_ to be at least 2, which has exponent 1.
michael@0 215 JS_ASSERT_IF(!hasInt32LowerBound_ || !hasInt32UpperBound_,
michael@0 216 max_exponent_ + canHaveFractionalPart_ >= MaxInt32Exponent);
michael@0 217 JS_ASSERT(max_exponent_ + canHaveFractionalPart_ >=
michael@0 218 mozilla::FloorLog2(mozilla::Abs(upper_)));
michael@0 219 JS_ASSERT(max_exponent_ + canHaveFractionalPart_ >=
michael@0 220 mozilla::FloorLog2(mozilla::Abs(lower_)));
michael@0 221
michael@0 222 // The following are essentially static assertions, but FloorLog2 isn't
michael@0 223 // trivially suitable for constexpr :(.
michael@0 224 JS_ASSERT(mozilla::FloorLog2(JSVAL_INT_MIN) == MaxInt32Exponent);
michael@0 225 JS_ASSERT(mozilla::FloorLog2(JSVAL_INT_MAX) == 30);
michael@0 226 JS_ASSERT(mozilla::FloorLog2(UINT32_MAX) == MaxUInt32Exponent);
michael@0 227 JS_ASSERT(mozilla::FloorLog2(0) == 0);
michael@0 228 }
michael@0 229
michael@0 230 // Set the lower_ and hasInt32LowerBound_ values.
michael@0 231 void setLowerInit(int64_t x) {
michael@0 232 if (x > JSVAL_INT_MAX) {
michael@0 233 lower_ = JSVAL_INT_MAX;
michael@0 234 hasInt32LowerBound_ = true;
michael@0 235 } else if (x < JSVAL_INT_MIN) {
michael@0 236 lower_ = JSVAL_INT_MIN;
michael@0 237 hasInt32LowerBound_ = false;
michael@0 238 } else {
michael@0 239 lower_ = int32_t(x);
michael@0 240 hasInt32LowerBound_ = true;
michael@0 241 }
michael@0 242 }
michael@0 243 // Set the upper_ and hasInt32UpperBound_ values.
michael@0 244 void setUpperInit(int64_t x) {
michael@0 245 if (x > JSVAL_INT_MAX) {
michael@0 246 upper_ = JSVAL_INT_MAX;
michael@0 247 hasInt32UpperBound_ = false;
michael@0 248 } else if (x < JSVAL_INT_MIN) {
michael@0 249 upper_ = JSVAL_INT_MIN;
michael@0 250 hasInt32UpperBound_ = true;
michael@0 251 } else {
michael@0 252 upper_ = int32_t(x);
michael@0 253 hasInt32UpperBound_ = true;
michael@0 254 }
michael@0 255 }
michael@0 256
michael@0 257 // Compute the least exponent value that would be compatible with the
michael@0 258 // values of lower() and upper().
michael@0 259 //
michael@0 260 // Note:
michael@0 261 // exponent of JSVAL_INT_MIN == 31
michael@0 262 // exponent of JSVAL_INT_MAX == 30
michael@0 263 uint16_t exponentImpliedByInt32Bounds() const {
michael@0 264 // The number of bits needed to encode |max| is the power of 2 plus one.
michael@0 265 uint32_t max = Max(mozilla::Abs(lower()), mozilla::Abs(upper()));
michael@0 266 uint16_t result = mozilla::FloorLog2(max);
michael@0 267 JS_ASSERT(result == (max == 0 ? 0 : mozilla::ExponentComponent(double(max))));
michael@0 268 return result;
michael@0 269 }
michael@0 270
michael@0 271 // When converting a range which contains fractional values to a range
michael@0 272 // containing only integers, the old max_exponent_ value may imply a better
michael@0 273 // lower and/or upper bound than was previously available, because they no
michael@0 274 // longer need to be conservative about fractional offsets and the ends of
michael@0 275 // the range.
michael@0 276 //
michael@0 277 // Given an exponent value and pointers to the lower and upper bound values,
michael@0 278 // this function refines the lower and upper bound values to the tighest
michael@0 279 // bound for integer values implied by the exponent.
michael@0 280 static void refineInt32BoundsByExponent(uint16_t e, int32_t *l, int32_t *h) {
michael@0 281 if (e < MaxInt32Exponent) {
michael@0 282 // pow(2, max_exponent_+1)-1 to compute a maximum absolute value.
michael@0 283 int32_t limit = (uint32_t(1) << (e + 1)) - 1;
michael@0 284 *h = Min(*h, limit);
michael@0 285 *l = Max(*l, -limit);
michael@0 286 }
michael@0 287 }
michael@0 288
michael@0 289 // If the value of any of the fields implies a stronger possible value for
michael@0 290 // any other field, update that field to the stronger value. The range must
michael@0 291 // be completely valid before and it is guaranteed to be kept valid.
michael@0 292 void optimize() {
michael@0 293 assertInvariants();
michael@0 294
michael@0 295 if (hasInt32Bounds()) {
michael@0 296 // Examine lower() and upper(), and if they imply a better exponent
michael@0 297 // bound than max_exponent_, set that value as the new
michael@0 298 // max_exponent_.
michael@0 299 uint16_t newExponent = exponentImpliedByInt32Bounds();
michael@0 300 if (newExponent < max_exponent_) {
michael@0 301 max_exponent_ = newExponent;
michael@0 302 assertInvariants();
michael@0 303 }
michael@0 304
michael@0 305 // If we have a completely precise range, the value is an integer,
michael@0 306 // since we can only represent integers.
michael@0 307 if (canHaveFractionalPart_ && lower_ == upper_) {
michael@0 308 canHaveFractionalPart_ = false;
michael@0 309 assertInvariants();
michael@0 310 }
michael@0 311 }
michael@0 312 }
michael@0 313
michael@0 314 // Set the range fields to the given raw values.
michael@0 315 void rawInitialize(int32_t l, bool lb, int32_t h, bool hb, bool f, uint16_t e) {
michael@0 316 lower_ = l;
michael@0 317 hasInt32LowerBound_ = lb;
michael@0 318 upper_ = h;
michael@0 319 hasInt32UpperBound_ = hb;
michael@0 320 canHaveFractionalPart_ = f;
michael@0 321 max_exponent_ = e;
michael@0 322 optimize();
michael@0 323 }
michael@0 324
michael@0 325 // Construct a range from the given raw values.
michael@0 326 Range(int32_t l, bool lb, int32_t h, bool hb, bool f, uint16_t e)
michael@0 327 : symbolicLower_(nullptr),
michael@0 328 symbolicUpper_(nullptr)
michael@0 329 {
michael@0 330 rawInitialize(l, lb, h, hb, f, e);
michael@0 331 }
michael@0 332
michael@0 333 public:
michael@0 334 Range()
michael@0 335 : symbolicLower_(nullptr),
michael@0 336 symbolicUpper_(nullptr)
michael@0 337 {
michael@0 338 setUnknown();
michael@0 339 }
michael@0 340
michael@0 341 Range(int64_t l, int64_t h, bool f = false, uint16_t e = MaxInt32Exponent)
michael@0 342 : symbolicLower_(nullptr),
michael@0 343 symbolicUpper_(nullptr)
michael@0 344 {
michael@0 345 set(l, h, f, e);
michael@0 346 }
michael@0 347
michael@0 348 Range(const Range &other)
michael@0 349 : lower_(other.lower_),
michael@0 350 hasInt32LowerBound_(other.hasInt32LowerBound_),
michael@0 351 upper_(other.upper_),
michael@0 352 hasInt32UpperBound_(other.hasInt32UpperBound_),
michael@0 353 canHaveFractionalPart_(other.canHaveFractionalPart_),
michael@0 354 max_exponent_(other.max_exponent_),
michael@0 355 symbolicLower_(nullptr),
michael@0 356 symbolicUpper_(nullptr)
michael@0 357 {
michael@0 358 assertInvariants();
michael@0 359 }
michael@0 360
michael@0 361 // Construct a range from the given MDefinition. This differs from the
michael@0 362 // MDefinition's range() method in that it describes the range of values
michael@0 363 // *after* any bailout checks.
michael@0 364 Range(const MDefinition *def);
michael@0 365
michael@0 366 static Range *NewInt32Range(TempAllocator &alloc, int32_t l, int32_t h) {
michael@0 367 return new(alloc) Range(l, h, false, MaxInt32Exponent);
michael@0 368 }
michael@0 369
michael@0 370 static Range *NewUInt32Range(TempAllocator &alloc, uint32_t l, uint32_t h) {
michael@0 371 // For now, just pass them to the constructor as int64_t values.
michael@0 372 // They'll become unbounded if they're not in the int32_t range.
michael@0 373 return new(alloc) Range(l, h, false, MaxUInt32Exponent);
michael@0 374 }
michael@0 375
michael@0 376 static Range *NewDoubleRange(TempAllocator &alloc, double l, double h) {
michael@0 377 if (mozilla::IsNaN(l) && mozilla::IsNaN(h))
michael@0 378 return nullptr;
michael@0 379
michael@0 380 Range *r = new(alloc) Range();
michael@0 381 r->setDouble(l, h);
michael@0 382 return r;
michael@0 383 }
michael@0 384
michael@0 385 void print(Sprinter &sp) const;
michael@0 386 void dump(FILE *fp) const;
michael@0 387 void dump() const;
michael@0 388 bool update(const Range *other);
michael@0 389
michael@0 390 // Unlike the other operations, unionWith is an in-place
michael@0 391 // modification. This is to avoid a bunch of useless extra
michael@0 392 // copying when chaining together unions when handling Phi
michael@0 393 // nodes.
michael@0 394 void unionWith(const Range *other);
michael@0 395 static Range *intersect(TempAllocator &alloc, const Range *lhs, const Range *rhs,
michael@0 396 bool *emptyRange);
michael@0 397 static Range *add(TempAllocator &alloc, const Range *lhs, const Range *rhs);
michael@0 398 static Range *sub(TempAllocator &alloc, const Range *lhs, const Range *rhs);
michael@0 399 static Range *mul(TempAllocator &alloc, const Range *lhs, const Range *rhs);
michael@0 400 static Range *and_(TempAllocator &alloc, const Range *lhs, const Range *rhs);
michael@0 401 static Range *or_(TempAllocator &alloc, const Range *lhs, const Range *rhs);
michael@0 402 static Range *xor_(TempAllocator &alloc, const Range *lhs, const Range *rhs);
michael@0 403 static Range *not_(TempAllocator &alloc, const Range *op);
michael@0 404 static Range *lsh(TempAllocator &alloc, const Range *lhs, int32_t c);
michael@0 405 static Range *rsh(TempAllocator &alloc, const Range *lhs, int32_t c);
michael@0 406 static Range *ursh(TempAllocator &alloc, const Range *lhs, int32_t c);
michael@0 407 static Range *lsh(TempAllocator &alloc, const Range *lhs, const Range *rhs);
michael@0 408 static Range *rsh(TempAllocator &alloc, const Range *lhs, const Range *rhs);
michael@0 409 static Range *ursh(TempAllocator &alloc, const Range *lhs, const Range *rhs);
michael@0 410 static Range *abs(TempAllocator &alloc, const Range *op);
michael@0 411 static Range *min(TempAllocator &alloc, const Range *lhs, const Range *rhs);
michael@0 412 static Range *max(TempAllocator &alloc, const Range *lhs, const Range *rhs);
michael@0 413
michael@0 414 static bool negativeZeroMul(const Range *lhs, const Range *rhs);
michael@0 415
michael@0 416 bool isUnknownInt32() const {
michael@0 417 return isInt32() && lower() == INT32_MIN && upper() == INT32_MAX;
michael@0 418 }
michael@0 419
michael@0 420 bool isUnknown() const {
michael@0 421 return !hasInt32LowerBound_ &&
michael@0 422 !hasInt32UpperBound_ &&
michael@0 423 canHaveFractionalPart_ &&
michael@0 424 max_exponent_ == IncludesInfinityAndNaN;
michael@0 425 }
michael@0 426
michael@0 427 bool hasInt32LowerBound() const {
michael@0 428 return hasInt32LowerBound_;
michael@0 429 }
michael@0 430 bool hasInt32UpperBound() const {
michael@0 431 return hasInt32UpperBound_;
michael@0 432 }
michael@0 433
michael@0 434 // Test whether the value is known to be within [INT32_MIN,INT32_MAX].
michael@0 435 // Note that this does not necessarily mean the value is an integer.
michael@0 436 bool hasInt32Bounds() const {
michael@0 437 return hasInt32LowerBound() && hasInt32UpperBound();
michael@0 438 }
michael@0 439
michael@0 440 // Test whether the value is known to be representable as an int32.
michael@0 441 bool isInt32() const {
michael@0 442 return hasInt32Bounds() && !canHaveFractionalPart();
michael@0 443 }
michael@0 444
michael@0 445 // Test whether the given value is known to be either 0 or 1.
michael@0 446 bool isBoolean() const {
michael@0 447 return lower() >= 0 && upper() <= 1 && !canHaveFractionalPart();
michael@0 448 }
michael@0 449
michael@0 450 bool canHaveRoundingErrors() const {
michael@0 451 return canHaveFractionalPart() || max_exponent_ >= MaxTruncatableExponent;
michael@0 452 }
michael@0 453
michael@0 454 // Test whether the range contains zero.
michael@0 455 bool canBeZero() const {
michael@0 456 return lower_ <= 0 && upper_ >= 0;
michael@0 457 }
michael@0 458
michael@0 459 // Test whether the range contains NaN values.
michael@0 460 bool canBeNaN() const {
michael@0 461 return max_exponent_ == IncludesInfinityAndNaN;
michael@0 462 }
michael@0 463
michael@0 464 // Test whether the range contains infinities or NaN values.
michael@0 465 bool canBeInfiniteOrNaN() const {
michael@0 466 return max_exponent_ >= IncludesInfinity;
michael@0 467 }
michael@0 468
michael@0 469 bool canHaveFractionalPart() const {
michael@0 470 return canHaveFractionalPart_;
michael@0 471 }
michael@0 472
michael@0 473 uint16_t exponent() const {
michael@0 474 JS_ASSERT(!canBeInfiniteOrNaN());
michael@0 475 return max_exponent_;
michael@0 476 }
michael@0 477
michael@0 478 uint16_t numBits() const {
michael@0 479 return exponent() + 1; // 2^0 -> 1
michael@0 480 }
michael@0 481
michael@0 482 // Return the lower bound. Asserts that the value has an int32 bound.
michael@0 483 int32_t lower() const {
michael@0 484 JS_ASSERT(hasInt32LowerBound());
michael@0 485 return lower_;
michael@0 486 }
michael@0 487
michael@0 488 // Return the upper bound. Asserts that the value has an int32 bound.
michael@0 489 int32_t upper() const {
michael@0 490 JS_ASSERT(hasInt32UpperBound());
michael@0 491 return upper_;
michael@0 492 }
michael@0 493
michael@0 494 // Test whether all values in this range can are finite and negative.
michael@0 495 bool isFiniteNegative() const {
michael@0 496 return upper_ < 0 && !canBeInfiniteOrNaN();
michael@0 497 }
michael@0 498
michael@0 499 // Test whether all values in this range can are finite and non-negative.
michael@0 500 bool isFiniteNonNegative() const {
michael@0 501 return lower_ >= 0 && !canBeInfiniteOrNaN();
michael@0 502 }
michael@0 503
michael@0 504 // Test whether a value in this range can possibly be a finite
michael@0 505 // negative value.
michael@0 506 bool canBeFiniteNegative() const {
michael@0 507 return lower_ < 0;
michael@0 508 }
michael@0 509
michael@0 510 // Test whether a value in this range can possibly be a finite
michael@0 511 // non-negative value.
michael@0 512 bool canBeFiniteNonNegative() const {
michael@0 513 return upper_ >= 0;
michael@0 514 }
michael@0 515
michael@0 516 // Set this range to have a lower bound not less than x.
michael@0 517 void refineLower(int32_t x) {
michael@0 518 assertInvariants();
michael@0 519 hasInt32LowerBound_ = true;
michael@0 520 lower_ = Max(lower_, x);
michael@0 521 optimize();
michael@0 522 }
michael@0 523
michael@0 524 // Set this range to have an upper bound not greater than x.
michael@0 525 void refineUpper(int32_t x) {
michael@0 526 assertInvariants();
michael@0 527 hasInt32UpperBound_ = true;
michael@0 528 upper_ = Min(upper_, x);
michael@0 529 optimize();
michael@0 530 }
michael@0 531
michael@0 532 void setInt32(int32_t l, int32_t h) {
michael@0 533 hasInt32LowerBound_ = true;
michael@0 534 hasInt32UpperBound_ = true;
michael@0 535 lower_ = l;
michael@0 536 upper_ = h;
michael@0 537 canHaveFractionalPart_ = false;
michael@0 538 max_exponent_ = exponentImpliedByInt32Bounds();
michael@0 539 assertInvariants();
michael@0 540 }
michael@0 541
michael@0 542 void setDouble(double l, double h);
michael@0 543
michael@0 544 void setUnknown() {
michael@0 545 set(NoInt32LowerBound, NoInt32UpperBound, true, IncludesInfinityAndNaN);
michael@0 546 JS_ASSERT(isUnknown());
michael@0 547 }
michael@0 548
michael@0 549 void set(int64_t l, int64_t h, bool f, uint16_t e) {
michael@0 550 max_exponent_ = e;
michael@0 551 canHaveFractionalPart_ = f;
michael@0 552 setLowerInit(l);
michael@0 553 setUpperInit(h);
michael@0 554 optimize();
michael@0 555 }
michael@0 556
michael@0 557 // Make the lower end of this range at least INT32_MIN, and make
michael@0 558 // the upper end of this range at most INT32_MAX.
michael@0 559 void clampToInt32();
michael@0 560
michael@0 561 // If this range exceeds int32_t range, at either or both ends, change
michael@0 562 // it to int32_t range. Otherwise do nothing.
michael@0 563 void wrapAroundToInt32();
michael@0 564
michael@0 565 // If this range exceeds [0, 32) range, at either or both ends, change
michael@0 566 // it to the [0, 32) range. Otherwise do nothing.
michael@0 567 void wrapAroundToShiftCount();
michael@0 568
michael@0 569 // If this range exceeds [0, 1] range, at either or both ends, change
michael@0 570 // it to the [0, 1] range. Otherwise do nothing.
michael@0 571 void wrapAroundToBoolean();
michael@0 572
michael@0 573 const SymbolicBound *symbolicLower() const {
michael@0 574 return symbolicLower_;
michael@0 575 }
michael@0 576 const SymbolicBound *symbolicUpper() const {
michael@0 577 return symbolicUpper_;
michael@0 578 }
michael@0 579
michael@0 580 void setSymbolicLower(SymbolicBound *bound) {
michael@0 581 symbolicLower_ = bound;
michael@0 582 }
michael@0 583 void setSymbolicUpper(SymbolicBound *bound) {
michael@0 584 symbolicUpper_ = bound;
michael@0 585 }
michael@0 586 };
michael@0 587
michael@0 588 } // namespace jit
michael@0 589 } // namespace js
michael@0 590
michael@0 591 #endif /* jit_RangeAnalysis_h */

mercurial