| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef RUNTIME_VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ | 5 #ifndef RUNTIME_VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ |
| 6 #define RUNTIME_VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ | 6 #define RUNTIME_VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ |
| 7 | 7 |
| 8 #include "vm/flow_graph.h" | 8 #include "vm/flow_graph.h" |
| 9 #include "vm/intermediate_language.h" | 9 #include "vm/intermediate_language.h" |
| 10 | 10 |
| 11 namespace dart { | 11 namespace dart { |
| 12 | 12 |
| 13 class RangeBoundary : public ValueObject { | 13 class RangeBoundary : public ValueObject { |
| 14 public: | 14 public: |
| 15 enum Kind { | 15 enum Kind { |
| 16 kUnknown, | 16 kUnknown, |
| 17 kNegativeInfinity, | 17 kNegativeInfinity, |
| 18 kPositiveInfinity, | 18 kPositiveInfinity, |
| 19 kSymbol, | 19 kSymbol, |
| 20 kConstant, | 20 kConstant, |
| 21 }; | 21 }; |
| 22 | 22 |
| 23 enum RangeSize { | 23 enum RangeSize { |
| 24 kRangeBoundarySmi, | 24 kRangeBoundarySmi, |
| 25 kRangeBoundaryInt32, | 25 kRangeBoundaryInt32, |
| 26 kRangeBoundaryInt64, | 26 kRangeBoundaryInt64, |
| 27 }; | 27 }; |
| 28 | 28 |
| 29 RangeBoundary() : kind_(kUnknown), value_(0), offset_(0) { } | 29 RangeBoundary() : kind_(kUnknown), value_(0), offset_(0) {} |
| 30 | 30 |
| 31 RangeBoundary(const RangeBoundary& other) | 31 RangeBoundary(const RangeBoundary& other) |
| 32 : ValueObject(), | 32 : ValueObject(), |
| 33 kind_(other.kind_), | 33 kind_(other.kind_), |
| 34 value_(other.value_), | 34 value_(other.value_), |
| 35 offset_(other.offset_) { } | 35 offset_(other.offset_) {} |
| 36 | 36 |
| 37 explicit RangeBoundary(int64_t val) | 37 explicit RangeBoundary(int64_t val) |
| 38 : kind_(kConstant), value_(val), offset_(0) { } | 38 : kind_(kConstant), value_(val), offset_(0) {} |
| 39 | 39 |
| 40 RangeBoundary& operator=(const RangeBoundary& other) { | 40 RangeBoundary& operator=(const RangeBoundary& other) { |
| 41 kind_ = other.kind_; | 41 kind_ = other.kind_; |
| 42 value_ = other.value_; | 42 value_ = other.value_; |
| 43 offset_ = other.offset_; | 43 offset_ = other.offset_; |
| 44 return *this; | 44 return *this; |
| 45 } | 45 } |
| 46 | 46 |
| 47 static const int64_t kMin = kMinInt64; | 47 static const int64_t kMin = kMinInt64; |
| 48 static const int64_t kMax = kMaxInt64; | 48 static const int64_t kMax = kMaxInt64; |
| 49 | 49 |
| 50 // Construct a RangeBoundary for a constant value. | 50 // Construct a RangeBoundary for a constant value. |
| 51 static RangeBoundary FromConstant(int64_t val) { | 51 static RangeBoundary FromConstant(int64_t val) { return RangeBoundary(val); } |
| 52 return RangeBoundary(val); | |
| 53 } | |
| 54 | 52 |
| 55 // Construct a RangeBoundary for -inf. | 53 // Construct a RangeBoundary for -inf. |
| 56 static RangeBoundary NegativeInfinity() { | 54 static RangeBoundary NegativeInfinity() { |
| 57 return RangeBoundary(kNegativeInfinity, 0, 0); | 55 return RangeBoundary(kNegativeInfinity, 0, 0); |
| 58 } | 56 } |
| 59 | 57 |
| 60 // Construct a RangeBoundary for +inf. | 58 // Construct a RangeBoundary for +inf. |
| 61 static RangeBoundary PositiveInfinity() { | 59 static RangeBoundary PositiveInfinity() { |
| 62 return RangeBoundary(kPositiveInfinity, 0, 0); | 60 return RangeBoundary(kPositiveInfinity, 0, 0); |
| 63 } | 61 } |
| 64 | 62 |
| 65 // Construct a RangeBoundary from a definition and offset. | 63 // Construct a RangeBoundary from a definition and offset. |
| 66 static RangeBoundary FromDefinition(Definition* defn, int64_t offs = 0); | 64 static RangeBoundary FromDefinition(Definition* defn, int64_t offs = 0); |
| 67 | 65 |
| 68 // Construct a RangeBoundary for the constant MinSmi value. | 66 // Construct a RangeBoundary for the constant MinSmi value. |
| 69 static RangeBoundary MinSmi() { | 67 static RangeBoundary MinSmi() { return FromConstant(Smi::kMinValue); } |
| 70 return FromConstant(Smi::kMinValue); | |
| 71 } | |
| 72 | 68 |
| 73 // Construct a RangeBoundary for the constant MaxSmi value. | 69 // Construct a RangeBoundary for the constant MaxSmi value. |
| 74 static RangeBoundary MaxSmi() { | 70 static RangeBoundary MaxSmi() { return FromConstant(Smi::kMaxValue); } |
| 75 return FromConstant(Smi::kMaxValue); | |
| 76 } | |
| 77 | 71 |
| 78 // Construct a RangeBoundary for the constant kMin value. | 72 // Construct a RangeBoundary for the constant kMin value. |
| 79 static RangeBoundary MinConstant() { | 73 static RangeBoundary MinConstant() { return FromConstant(kMin); } |
| 80 return FromConstant(kMin); | |
| 81 } | |
| 82 | 74 |
| 83 // Construct a RangeBoundary for the constant kMax value. | 75 // Construct a RangeBoundary for the constant kMax value. |
| 84 static RangeBoundary MaxConstant() { | 76 static RangeBoundary MaxConstant() { return FromConstant(kMax); } |
| 85 return FromConstant(kMax); | |
| 86 } | |
| 87 | 77 |
| 88 // Construct a RangeBoundary for the constant kMin value. | 78 // Construct a RangeBoundary for the constant kMin value. |
| 89 static RangeBoundary MinConstant(RangeSize size) { | 79 static RangeBoundary MinConstant(RangeSize size) { |
| 90 switch (size) { | 80 switch (size) { |
| 91 case kRangeBoundarySmi: | 81 case kRangeBoundarySmi: |
| 92 return FromConstant(Smi::kMinValue); | 82 return FromConstant(Smi::kMinValue); |
| 93 case kRangeBoundaryInt32: | 83 case kRangeBoundaryInt32: |
| 94 return FromConstant(kMinInt32); | 84 return FromConstant(kMinInt32); |
| 95 case kRangeBoundaryInt64: | 85 case kRangeBoundaryInt64: |
| 96 return FromConstant(kMinInt64); | 86 return FromConstant(kMinInt64); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 bool OverflowedSmi() const { | 139 bool OverflowedSmi() const { |
| 150 return (IsConstant() && !Smi::IsValid(ConstantValue())) || IsInfinity(); | 140 return (IsConstant() && !Smi::IsValid(ConstantValue())) || IsInfinity(); |
| 151 } | 141 } |
| 152 | 142 |
| 153 bool Overflowed(RangeBoundary::RangeSize size) const { | 143 bool Overflowed(RangeBoundary::RangeSize size) const { |
| 154 ASSERT(IsConstantOrInfinity()); | 144 ASSERT(IsConstantOrInfinity()); |
| 155 return !Equals(Clamp(size)); | 145 return !Equals(Clamp(size)); |
| 156 } | 146 } |
| 157 | 147 |
| 158 // Returns true if this outside mint range. | 148 // Returns true if this outside mint range. |
| 159 bool OverflowedMint() const { | 149 bool OverflowedMint() const { return IsInfinity(); } |
| 160 return IsInfinity(); | |
| 161 } | |
| 162 | 150 |
| 163 // -/+ infinity are clamped to MinConstant/MaxConstant of the given type. | 151 // -/+ infinity are clamped to MinConstant/MaxConstant of the given type. |
| 164 RangeBoundary Clamp(RangeSize size) const { | 152 RangeBoundary Clamp(RangeSize size) const { |
| 165 if (IsNegativeInfinity()) { | 153 if (IsNegativeInfinity()) { |
| 166 return RangeBoundary::MinConstant(size); | 154 return RangeBoundary::MinConstant(size); |
| 167 } | 155 } |
| 168 | 156 |
| 169 if (IsPositiveInfinity()) { | 157 if (IsPositiveInfinity()) { |
| 170 return RangeBoundary::MaxConstant(size); | 158 return RangeBoundary::MaxConstant(size); |
| 171 } | 159 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 182 } | 170 } |
| 183 } | 171 } |
| 184 | 172 |
| 185 // If this range is a symbolic range, we do not clamp it. | 173 // If this range is a symbolic range, we do not clamp it. |
| 186 // This could lead to some imprecision later on. | 174 // This could lead to some imprecision later on. |
| 187 return *this; | 175 return *this; |
| 188 } | 176 } |
| 189 | 177 |
| 190 bool IsMinimumOrBelow(RangeSize size) const { | 178 bool IsMinimumOrBelow(RangeSize size) const { |
| 191 return IsNegativeInfinity() || | 179 return IsNegativeInfinity() || |
| 192 (IsConstant() && | 180 (IsConstant() && (ConstantValue() <= |
| 193 (ConstantValue() <= RangeBoundary::MinConstant(size).ConstantValue())); | 181 RangeBoundary::MinConstant(size).ConstantValue())); |
| 194 } | 182 } |
| 195 | 183 |
| 196 bool IsMaximumOrAbove(RangeSize size) const { | 184 bool IsMaximumOrAbove(RangeSize size) const { |
| 197 return IsPositiveInfinity() || | 185 return IsPositiveInfinity() || |
| 198 (IsConstant() && | 186 (IsConstant() && (ConstantValue() >= |
| 199 (ConstantValue() >= RangeBoundary::MaxConstant(size).ConstantValue())); | 187 RangeBoundary::MaxConstant(size).ConstantValue())); |
| 200 } | 188 } |
| 201 | 189 |
| 202 intptr_t kind() const { | 190 intptr_t kind() const { return kind_; } |
| 203 return kind_; | |
| 204 } | |
| 205 | 191 |
| 206 // Kind tests. | 192 // Kind tests. |
| 207 bool IsUnknown() const { return kind_ == kUnknown; } | 193 bool IsUnknown() const { return kind_ == kUnknown; } |
| 208 bool IsConstant() const { return kind_ == kConstant; } | 194 bool IsConstant() const { return kind_ == kConstant; } |
| 209 bool IsSymbol() const { return kind_ == kSymbol; } | 195 bool IsSymbol() const { return kind_ == kSymbol; } |
| 210 bool IsNegativeInfinity() const { return kind_ == kNegativeInfinity; } | 196 bool IsNegativeInfinity() const { return kind_ == kNegativeInfinity; } |
| 211 bool IsPositiveInfinity() const { return kind_ == kPositiveInfinity; } | 197 bool IsPositiveInfinity() const { return kind_ == kPositiveInfinity; } |
| 212 bool IsInfinity() const { | 198 bool IsInfinity() const { |
| 213 return IsNegativeInfinity() || IsPositiveInfinity(); | 199 return IsNegativeInfinity() || IsPositiveInfinity(); |
| 214 } | 200 } |
| 215 bool IsConstantOrInfinity() const { | 201 bool IsConstantOrInfinity() const { return IsConstant() || IsInfinity(); } |
| 216 return IsConstant() || IsInfinity(); | |
| 217 } | |
| 218 | 202 |
| 219 // Returns the value of a kConstant RangeBoundary. | 203 // Returns the value of a kConstant RangeBoundary. |
| 220 int64_t ConstantValue() const; | 204 int64_t ConstantValue() const; |
| 221 | 205 |
| 222 // Returns the Definition associated with a kSymbol RangeBoundary. | 206 // Returns the Definition associated with a kSymbol RangeBoundary. |
| 223 Definition* symbol() const { | 207 Definition* symbol() const { |
| 224 ASSERT(IsSymbol()); | 208 ASSERT(IsSymbol()); |
| 225 return reinterpret_cast<Definition*>(value_); | 209 return reinterpret_cast<Definition*>(value_); |
| 226 } | 210 } |
| 227 | 211 |
| 228 // Offset from symbol. | 212 // Offset from symbol. |
| 229 int64_t offset() const { | 213 int64_t offset() const { return offset_; } |
| 230 return offset_; | |
| 231 } | |
| 232 | 214 |
| 233 // Computes the LowerBound of this. Three cases: | 215 // Computes the LowerBound of this. Three cases: |
| 234 // IsInfinity() -> NegativeInfinity(). | 216 // IsInfinity() -> NegativeInfinity(). |
| 235 // IsConstant() -> value(). | 217 // IsConstant() -> value(). |
| 236 // IsSymbol() -> lower bound computed from definition + offset. | 218 // IsSymbol() -> lower bound computed from definition + offset. |
| 237 RangeBoundary LowerBound() const; | 219 RangeBoundary LowerBound() const; |
| 238 | 220 |
| 239 // Computes the UpperBound of this. Three cases: | 221 // Computes the UpperBound of this. Three cases: |
| 240 // IsInfinity() -> PositiveInfinity(). | 222 // IsInfinity() -> PositiveInfinity(). |
| 241 // IsConstant() -> value(). | 223 // IsConstant() -> value(). |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 bool Equals(const RangeBoundary& other) const; | 266 bool Equals(const RangeBoundary& other) const; |
| 285 | 267 |
| 286 int64_t UpperBound(RangeSize size) const { | 268 int64_t UpperBound(RangeSize size) const { |
| 287 return UpperBound().Clamp(size).ConstantValue(); | 269 return UpperBound().Clamp(size).ConstantValue(); |
| 288 } | 270 } |
| 289 | 271 |
| 290 int64_t LowerBound(RangeSize size) const { | 272 int64_t LowerBound(RangeSize size) const { |
| 291 return LowerBound().Clamp(size).ConstantValue(); | 273 return LowerBound().Clamp(size).ConstantValue(); |
| 292 } | 274 } |
| 293 | 275 |
| 294 int64_t SmiUpperBound() const { | 276 int64_t SmiUpperBound() const { return UpperBound(kRangeBoundarySmi); } |
| 295 return UpperBound(kRangeBoundarySmi); | |
| 296 } | |
| 297 | 277 |
| 298 int64_t SmiLowerBound() const { | 278 int64_t SmiLowerBound() const { return LowerBound(kRangeBoundarySmi); } |
| 299 return LowerBound(kRangeBoundarySmi); | |
| 300 } | |
| 301 | 279 |
| 302 private: | 280 private: |
| 303 RangeBoundary(Kind kind, int64_t value, int64_t offset) | 281 RangeBoundary(Kind kind, int64_t value, int64_t offset) |
| 304 : kind_(kind), value_(value), offset_(offset) { } | 282 : kind_(kind), value_(value), offset_(offset) {} |
| 305 | 283 |
| 306 Kind kind_; | 284 Kind kind_; |
| 307 int64_t value_; | 285 int64_t value_; |
| 308 int64_t offset_; | 286 int64_t offset_; |
| 309 }; | 287 }; |
| 310 | 288 |
| 311 | 289 |
| 312 class Range : public ZoneAllocated { | 290 class Range : public ZoneAllocated { |
| 313 public: | 291 public: |
| 314 Range() : min_(), max_() { } | 292 Range() : min_(), max_() {} |
| 315 Range(RangeBoundary min, RangeBoundary max) : min_(min), max_(max) { | 293 Range(RangeBoundary min, RangeBoundary max) : min_(min), max_(max) { |
| 316 ASSERT(min_.IsUnknown() == max_.IsUnknown()); | 294 ASSERT(min_.IsUnknown() == max_.IsUnknown()); |
| 317 } | 295 } |
| 318 | 296 |
| 319 Range(const Range& other) | 297 Range(const Range& other) |
| 320 : ZoneAllocated(), | 298 : ZoneAllocated(), min_(other.min_), max_(other.max_) {} |
| 321 min_(other.min_), | |
| 322 max_(other.max_) { | |
| 323 } | |
| 324 | 299 |
| 325 Range& operator=(const Range& other) { | 300 Range& operator=(const Range& other) { |
| 326 min_ = other.min_; | 301 min_ = other.min_; |
| 327 max_ = other.max_; | 302 max_ = other.max_; |
| 328 return *this; | 303 return *this; |
| 329 } | 304 } |
| 330 | 305 |
| 331 static bool IsUnknown(const Range* other) { | 306 static bool IsUnknown(const Range* other) { |
| 332 if (other == NULL) { | 307 if (other == NULL) { |
| 333 return true; | 308 return true; |
| 334 } | 309 } |
| 335 return other->min().IsUnknown(); | 310 return other->min().IsUnknown(); |
| 336 } | 311 } |
| 337 | 312 |
| 338 static Range Full(RangeBoundary::RangeSize size) { | 313 static Range Full(RangeBoundary::RangeSize size) { |
| 339 return Range(RangeBoundary::MinConstant(size), | 314 return Range(RangeBoundary::MinConstant(size), |
| 340 RangeBoundary::MaxConstant(size)); | 315 RangeBoundary::MaxConstant(size)); |
| 341 } | 316 } |
| 342 | 317 |
| 343 void PrintTo(BufferFormatter* f) const; | 318 void PrintTo(BufferFormatter* f) const; |
| 344 static const char* ToCString(const Range* range); | 319 static const char* ToCString(const Range* range); |
| 345 | 320 |
| 346 bool Equals(const Range* other) { | 321 bool Equals(const Range* other) { |
| 347 ASSERT(min_.IsUnknown() == max_.IsUnknown()); | 322 ASSERT(min_.IsUnknown() == max_.IsUnknown()); |
| 348 if (other == NULL) { | 323 if (other == NULL) { |
| 349 return min_.IsUnknown(); | 324 return min_.IsUnknown(); |
| 350 } | 325 } |
| 351 return min_.Equals(other->min_) && | 326 return min_.Equals(other->min_) && max_.Equals(other->max_); |
| 352 max_.Equals(other->max_); | |
| 353 } | 327 } |
| 354 | 328 |
| 355 const RangeBoundary& min() const { return min_; } | 329 const RangeBoundary& min() const { return min_; } |
| 356 const RangeBoundary& max() const { return max_; } | 330 const RangeBoundary& max() const { return max_; } |
| 357 void set_min(const RangeBoundary& value) { | 331 void set_min(const RangeBoundary& value) { min_ = value; } |
| 358 min_ = value; | 332 void set_max(const RangeBoundary& value) { max_ = value; } |
| 359 } | |
| 360 void set_max(const RangeBoundary& value) { | |
| 361 max_ = value; | |
| 362 } | |
| 363 | 333 |
| 364 static RangeBoundary ConstantMinSmi(const Range* range) { | 334 static RangeBoundary ConstantMinSmi(const Range* range) { |
| 365 return ConstantMin(range, RangeBoundary::kRangeBoundarySmi); | 335 return ConstantMin(range, RangeBoundary::kRangeBoundarySmi); |
| 366 } | 336 } |
| 367 | 337 |
| 368 static RangeBoundary ConstantMaxSmi(const Range* range) { | 338 static RangeBoundary ConstantMaxSmi(const Range* range) { |
| 369 return ConstantMax(range, RangeBoundary::kRangeBoundarySmi); | 339 return ConstantMax(range, RangeBoundary::kRangeBoundarySmi); |
| 370 } | 340 } |
| 371 | 341 |
| 372 static RangeBoundary ConstantMin(const Range* range) { | 342 static RangeBoundary ConstantMin(const Range* range) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 404 bool OnlyGreaterThanOrEqualTo(int64_t val) const; | 374 bool OnlyGreaterThanOrEqualTo(int64_t val) const; |
| 405 | 375 |
| 406 // Inclusive. | 376 // Inclusive. |
| 407 bool IsWithin(int64_t min_int, int64_t max_int) const; | 377 bool IsWithin(int64_t min_int, int64_t max_int) const; |
| 408 | 378 |
| 409 // Inclusive. | 379 // Inclusive. |
| 410 bool Overlaps(int64_t min_int, int64_t max_int) const; | 380 bool Overlaps(int64_t min_int, int64_t max_int) const; |
| 411 | 381 |
| 412 bool IsUnsatisfiable() const; | 382 bool IsUnsatisfiable() const; |
| 413 | 383 |
| 414 bool IsFinite() const { | 384 bool IsFinite() const { return !min_.IsInfinity() && !max_.IsInfinity(); } |
| 415 return !min_.IsInfinity() && !max_.IsInfinity(); | |
| 416 } | |
| 417 | 385 |
| 418 Range Intersect(const Range* other) const { | 386 Range Intersect(const Range* other) const { |
| 419 return Range(RangeBoundary::IntersectionMin(min(), other->min()), | 387 return Range(RangeBoundary::IntersectionMin(min(), other->min()), |
| 420 RangeBoundary::IntersectionMax(max(), other->max())); | 388 RangeBoundary::IntersectionMax(max(), other->max())); |
| 421 } | 389 } |
| 422 | 390 |
| 423 bool Fits(RangeBoundary::RangeSize size) const { | 391 bool Fits(RangeBoundary::RangeSize size) const { |
| 424 return !min().LowerBound().Overflowed(size) && | 392 return !min().LowerBound().Overflowed(size) && |
| 425 !max().UpperBound().Overflowed(size); | 393 !max().UpperBound().Overflowed(size); |
| 426 } | 394 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 481 const Range* right_range, | 449 const Range* right_range, |
| 482 Definition* left_defn, | 450 Definition* left_defn, |
| 483 Range* result); | 451 Range* result); |
| 484 | 452 |
| 485 private: | 453 private: |
| 486 RangeBoundary min_; | 454 RangeBoundary min_; |
| 487 RangeBoundary max_; | 455 RangeBoundary max_; |
| 488 }; | 456 }; |
| 489 | 457 |
| 490 | 458 |
| 491 class RangeUtils : public AllStatic { | 459 class RangeUtils : public AllStatic { |
| 492 public: | 460 public: |
| 493 static bool Fits(Range* range, RangeBoundary::RangeSize size) { | 461 static bool Fits(Range* range, RangeBoundary::RangeSize size) { |
| 494 return !Range::IsUnknown(range) && range->Fits(size); | 462 return !Range::IsUnknown(range) && range->Fits(size); |
| 495 } | 463 } |
| 496 | 464 |
| 497 static bool IsWithin(Range* range, int64_t min, int64_t max) { | 465 static bool IsWithin(Range* range, int64_t min, int64_t max) { |
| 498 return !Range::IsUnknown(range) && range->IsWithin(min, max); | 466 return !Range::IsUnknown(range) && range->IsWithin(min, max); |
| 499 } | 467 } |
| 500 | 468 |
| 501 static bool IsPositive(Range* range) { | 469 static bool IsPositive(Range* range) { |
| 502 return !Range::IsUnknown(range) && range->IsPositive(); | 470 return !Range::IsUnknown(range) && range->IsPositive(); |
| 503 } | 471 } |
| 504 }; | 472 }; |
| 505 | 473 |
| 506 | 474 |
| 507 // Range analysis for integer values. | 475 // Range analysis for integer values. |
| 508 class RangeAnalysis : public ValueObject { | 476 class RangeAnalysis : public ValueObject { |
| 509 public: | 477 public: |
| 510 explicit RangeAnalysis(FlowGraph* flow_graph) | 478 explicit RangeAnalysis(FlowGraph* flow_graph) |
| 511 : flow_graph_(flow_graph), | 479 : flow_graph_(flow_graph), |
| 512 smi_range_(Range::Full(RangeBoundary::kRangeBoundarySmi)), | 480 smi_range_(Range::Full(RangeBoundary::kRangeBoundarySmi)), |
| 513 int64_range_(Range::Full(RangeBoundary::kRangeBoundaryInt64)) { } | 481 int64_range_(Range::Full(RangeBoundary::kRangeBoundaryInt64)) {} |
| 514 | 482 |
| 515 // Infer ranges for all values and remove overflow checks from binary smi | 483 // Infer ranges for all values and remove overflow checks from binary smi |
| 516 // operations when proven redundant. | 484 // operations when proven redundant. |
| 517 void Analyze(); | 485 void Analyze(); |
| 518 | 486 |
| 519 // Helper that should be used to access ranges of inputs during range | 487 // Helper that should be used to access ranges of inputs during range |
| 520 // inference. | 488 // inference. |
| 521 // Returns meaningful results for uses of non-smi/non-int definitions that | 489 // Returns meaningful results for uses of non-smi/non-int definitions that |
| 522 // have smi/int as a reaching type. | 490 // have smi/int as a reaching type. |
| 523 // For Int typed definitions we use full Int64 range as a safe approximation | 491 // For Int typed definitions we use full Int64 range as a safe approximation |
| 524 // even though they might contain Bigint values because we only support | 492 // even though they might contain Bigint values because we only support |
| 525 // 64-bit operations in the optimized code - which means that Bigint will | 493 // 64-bit operations in the optimized code - which means that Bigint will |
| 526 // cause deoptimization. | 494 // cause deoptimization. |
| 527 const Range* GetSmiRange(Value* value) const; | 495 const Range* GetSmiRange(Value* value) const; |
| 528 const Range* GetIntRange(Value* value) const; | 496 const Range* GetIntRange(Value* value) const; |
| 529 | 497 |
| 530 static bool IsIntegerDefinition(Definition* defn) { | 498 static bool IsIntegerDefinition(Definition* defn) { |
| 531 return defn->Type()->IsInt(); | 499 return defn->Type()->IsInt(); |
| 532 } | 500 } |
| 533 | 501 |
| 534 void AssignRangesRecursively(Definition* defn); | 502 void AssignRangesRecursively(Definition* defn); |
| 535 | 503 |
| 536 private: | 504 private: |
| 537 enum JoinOperator { | 505 enum JoinOperator { NONE, WIDEN, NARROW }; |
| 538 NONE, | |
| 539 WIDEN, | |
| 540 NARROW | |
| 541 }; | |
| 542 static char OpPrefix(JoinOperator op); | 506 static char OpPrefix(JoinOperator op); |
| 543 | 507 |
| 544 // Collect all values that were proven to be smi in smi_values_ array and all | 508 // Collect all values that were proven to be smi in smi_values_ array and all |
| 545 // CheckSmi instructions in smi_check_ array. | 509 // CheckSmi instructions in smi_check_ array. |
| 546 void CollectValues(); | 510 void CollectValues(); |
| 547 | 511 |
| 548 // Iterate over smi values and constrain them at branch successors. | 512 // Iterate over smi values and constrain them at branch successors. |
| 549 // Additionally constraint values after CheckSmi instructions. | 513 // Additionally constraint values after CheckSmi instructions. |
| 550 void InsertConstraints(); | 514 void InsertConstraints(); |
| 551 | 515 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 657 BitVector* selected_uint32_defs_; | 621 BitVector* selected_uint32_defs_; |
| 658 | 622 |
| 659 FlowGraph* flow_graph_; | 623 FlowGraph* flow_graph_; |
| 660 Zone* zone_; | 624 Zone* zone_; |
| 661 }; | 625 }; |
| 662 | 626 |
| 663 | 627 |
| 664 } // namespace dart | 628 } // namespace dart |
| 665 | 629 |
| 666 #endif // RUNTIME_VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ | 630 #endif // RUNTIME_VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ |
| OLD | NEW |