| 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 VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ | 5 #ifndef VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ |
| 6 #define VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ | 6 #define 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 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 // Construct a RangeBoundary for the constant kMin value. | 77 // Construct a RangeBoundary for the constant kMin value. |
| 78 static RangeBoundary MinConstant() { | 78 static RangeBoundary MinConstant() { |
| 79 return FromConstant(kMin); | 79 return FromConstant(kMin); |
| 80 } | 80 } |
| 81 | 81 |
| 82 // Construct a RangeBoundary for the constant kMax value. | 82 // Construct a RangeBoundary for the constant kMax value. |
| 83 static RangeBoundary MaxConstant() { | 83 static RangeBoundary MaxConstant() { |
| 84 return FromConstant(kMax); | 84 return FromConstant(kMax); |
| 85 } | 85 } |
| 86 | 86 |
| 87 // Given two boundaries a and b, select one of them as c so that | 87 // Calculate the minimum of a and b within the given range. |
| 88 // | 88 static RangeBoundary Min(RangeBoundary a, RangeBoundary b, RangeSize size); |
| 89 // inf {[a, ...) ^ [b, ...)} >= inf {c} | 89 static RangeBoundary Max(RangeBoundary a, RangeBoundary b, RangeSize size); |
| 90 // | |
| 91 static RangeBoundary IntersectionMin(RangeBoundary a, RangeBoundary b); | |
| 92 | |
| 93 // Given two boundaries a and b, select one of them as c so that | |
| 94 // | |
| 95 // sup {(..., a] ^ (..., b]} <= sup {c} | |
| 96 // | |
| 97 static RangeBoundary IntersectionMax(RangeBoundary a, RangeBoundary b); | |
| 98 | |
| 99 // Given two boundaries a and b compute boundary c such that | |
| 100 // | |
| 101 // inf {[a, ...) U [b, ...)} >= inf {c} | |
| 102 // | |
| 103 // Try to select c such that it is as close to inf {[a, ...) U [b, ...)} | |
| 104 // as possible. | |
| 105 static RangeBoundary JoinMin(RangeBoundary a, RangeBoundary b); | |
| 106 | |
| 107 // Given two boundaries a and b compute boundary c such that | |
| 108 // | |
| 109 // sup {(..., a] U (..., b]} <= sup {c} | |
| 110 // | |
| 111 // Try to select c such that it is as close to sup {(..., a] U (..., b]} | |
| 112 // as possible. | |
| 113 static RangeBoundary JoinMax(RangeBoundary a, RangeBoundary b); | |
| 114 | 90 |
| 115 // Returns true when this is a constant that is outside of Smi range. | 91 // Returns true when this is a constant that is outside of Smi range. |
| 116 bool OverflowedSmi() const { | 92 bool OverflowedSmi() const { |
| 117 return (IsConstant() && !Smi::IsValid(ConstantValue())) || IsInfinity(); | 93 return (IsConstant() && !Smi::IsValid(ConstantValue())) || IsInfinity(); |
| 118 } | 94 } |
| 119 | 95 |
| 120 // Returns true if this outside mint range. | 96 // Returns true if this outside mint range. |
| 121 bool OverflowedMint() const { | 97 bool OverflowedMint() const { |
| 122 return IsInfinity(); | 98 return IsInfinity(); |
| 123 } | 99 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 136 } | 112 } |
| 137 if (ConstantValue() >= Smi::kMaxValue) { | 113 if (ConstantValue() >= Smi::kMaxValue) { |
| 138 return MaxSmi(); | 114 return MaxSmi(); |
| 139 } | 115 } |
| 140 } | 116 } |
| 141 // If this range is a symbolic range, we do not clamp it. | 117 // If this range is a symbolic range, we do not clamp it. |
| 142 // This could lead to some imprecision later on. | 118 // This could lead to some imprecision later on. |
| 143 return *this; | 119 return *this; |
| 144 } | 120 } |
| 145 | 121 |
| 122 |
| 146 bool IsSmiMinimumOrBelow() const { | 123 bool IsSmiMinimumOrBelow() const { |
| 147 return IsNegativeInfinity() || | 124 return IsNegativeInfinity() || |
| 148 (IsConstant() && (ConstantValue() <= Smi::kMinValue)); | 125 (IsConstant() && (ConstantValue() <= Smi::kMinValue)); |
| 149 } | 126 } |
| 150 | 127 |
| 151 bool IsSmiMaximumOrAbove() const { | 128 bool IsSmiMaximumOrAbove() const { |
| 152 return IsPositiveInfinity() || | 129 return IsPositiveInfinity() || |
| 153 (IsConstant() && (ConstantValue() >= Smi::kMaxValue)); | 130 (IsConstant() && (ConstantValue() >= Smi::kMaxValue)); |
| 154 } | 131 } |
| 155 | 132 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 | 215 |
| 239 // Attempts to calculate a - b when: | 216 // Attempts to calculate a - b when: |
| 240 // a is a symbol and b is a constant | 217 // a is a symbol and b is a constant |
| 241 // returns true if it succeeds, output is in result. | 218 // returns true if it succeeds, output is in result. |
| 242 static bool SymbolicSub(const RangeBoundary& a, | 219 static bool SymbolicSub(const RangeBoundary& a, |
| 243 const RangeBoundary& b, | 220 const RangeBoundary& b, |
| 244 RangeBoundary* result); | 221 RangeBoundary* result); |
| 245 | 222 |
| 246 bool Equals(const RangeBoundary& other) const; | 223 bool Equals(const RangeBoundary& other) const; |
| 247 | 224 |
| 248 int64_t SmiUpperBound() const { | |
| 249 return UpperBound().Clamp(kRangeBoundarySmi).ConstantValue(); | |
| 250 } | |
| 251 | |
| 252 int64_t SmiLowerBound() const { | |
| 253 return LowerBound().Clamp(kRangeBoundarySmi).ConstantValue(); | |
| 254 } | |
| 255 | |
| 256 private: | 225 private: |
| 257 RangeBoundary(Kind kind, int64_t value, int64_t offset) | 226 RangeBoundary(Kind kind, int64_t value, int64_t offset) |
| 258 : kind_(kind), value_(value), offset_(offset) { } | 227 : kind_(kind), value_(value), offset_(offset) { } |
| 259 | 228 |
| 260 Kind kind_; | 229 Kind kind_; |
| 261 int64_t value_; | 230 int64_t value_; |
| 262 int64_t offset_; | 231 int64_t offset_; |
| 263 }; | 232 }; |
| 264 | 233 |
| 265 | 234 |
| 266 class Range : public ZoneAllocated { | 235 class Range : public ZoneAllocated { |
| 267 public: | 236 public: |
| 268 Range() : min_(), max_() { } | 237 Range(RangeBoundary min, RangeBoundary max) : min_(min), max_(max) { } |
| 269 Range(RangeBoundary min, RangeBoundary max) : min_(min), max_(max) { | 238 |
| 270 ASSERT(min_.IsUnknown() == max_.IsUnknown()); | 239 static Range* Unknown() { |
| 240 return new Range(RangeBoundary::MinConstant(), |
| 241 RangeBoundary::MaxConstant()); |
| 271 } | 242 } |
| 272 | 243 |
| 273 Range(const Range& other) | 244 static Range* UnknownSmi() { |
| 274 : ZoneAllocated(), | 245 return new Range(RangeBoundary::MinSmi(), |
| 275 min_(other.min_), | 246 RangeBoundary::MaxSmi()); |
| 276 max_(other.max_) { | |
| 277 } | |
| 278 | |
| 279 Range& operator=(const Range& other) { | |
| 280 min_ = other.min_; | |
| 281 max_ = other.max_; | |
| 282 return *this; | |
| 283 } | |
| 284 | |
| 285 static bool IsUnknown(const Range* other) { | |
| 286 if (other == NULL) { | |
| 287 return true; | |
| 288 } | |
| 289 return other->min().IsUnknown(); | |
| 290 } | |
| 291 | |
| 292 static Range Full(RangeBoundary::RangeSize size) { | |
| 293 if (size == RangeBoundary::kRangeBoundarySmi) { | |
| 294 return Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); | |
| 295 } else { | |
| 296 ASSERT(size == RangeBoundary::kRangeBoundaryInt64); | |
| 297 return Range(RangeBoundary::MinConstant(), RangeBoundary::MaxConstant()); | |
| 298 } | |
| 299 } | 247 } |
| 300 | 248 |
| 301 void PrintTo(BufferFormatter* f) const; | 249 void PrintTo(BufferFormatter* f) const; |
| 302 static const char* ToCString(const Range* range); | 250 static const char* ToCString(const Range* range); |
| 303 | 251 |
| 304 bool Equals(const Range* other) { | |
| 305 ASSERT(min_.IsUnknown() == max_.IsUnknown()); | |
| 306 if (other == NULL) { | |
| 307 return min_.IsUnknown(); | |
| 308 } | |
| 309 return min_.Equals(other->min_) && | |
| 310 max_.Equals(other->max_); | |
| 311 } | |
| 312 | |
| 313 const RangeBoundary& min() const { return min_; } | 252 const RangeBoundary& min() const { return min_; } |
| 314 const RangeBoundary& max() const { return max_; } | 253 const RangeBoundary& max() const { return max_; } |
| 315 void set_min(const RangeBoundary& value) { | |
| 316 min_ = value; | |
| 317 } | |
| 318 void set_max(const RangeBoundary& value) { | |
| 319 max_ = value; | |
| 320 } | |
| 321 | 254 |
| 322 static RangeBoundary ConstantMinSmi(const Range* range) { | 255 static RangeBoundary ConstantMinSmi(const Range* range) { |
| 323 if (range == NULL) { | 256 if (range == NULL) { |
| 324 return RangeBoundary::MinSmi(); | 257 return RangeBoundary::MinSmi(); |
| 325 } | 258 } |
| 326 return range->min().LowerBound().Clamp(RangeBoundary::kRangeBoundarySmi); | 259 return range->min().LowerBound().Clamp(RangeBoundary::kRangeBoundarySmi); |
| 327 } | 260 } |
| 328 | 261 |
| 329 static RangeBoundary ConstantMaxSmi(const Range* range) { | 262 static RangeBoundary ConstantMaxSmi(const Range* range) { |
| 330 if (range == NULL) { | 263 if (range == NULL) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 361 | 294 |
| 362 // Inclusive. | 295 // Inclusive. |
| 363 bool Overlaps(int64_t min_int, int64_t max_int) const; | 296 bool Overlaps(int64_t min_int, int64_t max_int) const; |
| 364 | 297 |
| 365 bool IsUnsatisfiable() const; | 298 bool IsUnsatisfiable() const; |
| 366 | 299 |
| 367 bool IsFinite() const { | 300 bool IsFinite() const { |
| 368 return !min_.IsInfinity() && !max_.IsInfinity(); | 301 return !min_.IsInfinity() && !max_.IsInfinity(); |
| 369 } | 302 } |
| 370 | 303 |
| 371 Range Intersect(const Range* other) const { | |
| 372 return Range(RangeBoundary::IntersectionMin(min(), other->min()), | |
| 373 RangeBoundary::IntersectionMax(max(), other->max())); | |
| 374 } | |
| 375 | |
| 376 // Clamp this to be within size. | 304 // Clamp this to be within size. |
| 377 void Clamp(RangeBoundary::RangeSize size); | 305 void Clamp(RangeBoundary::RangeSize size); |
| 378 | 306 |
| 379 static void Add(const Range* left_range, | 307 static void Add(const Range* left_range, |
| 380 const Range* right_range, | 308 const Range* right_range, |
| 381 RangeBoundary* min, | 309 RangeBoundary* min, |
| 382 RangeBoundary* max, | 310 RangeBoundary* max, |
| 383 Definition* left_defn); | 311 Definition* left_defn); |
| 384 | 312 |
| 385 static void Sub(const Range* left_range, | 313 static void Sub(const Range* left_range, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 410 | 338 |
| 411 // Both the a and b ranges are >= 0. | 339 // Both the a and b ranges are >= 0. |
| 412 static bool OnlyPositiveOrZero(const Range& a, const Range& b); | 340 static bool OnlyPositiveOrZero(const Range& a, const Range& b); |
| 413 | 341 |
| 414 // Both the a and b ranges are <= 0. | 342 // Both the a and b ranges are <= 0. |
| 415 static bool OnlyNegativeOrZero(const Range& a, const Range& b); | 343 static bool OnlyNegativeOrZero(const Range& a, const Range& b); |
| 416 | 344 |
| 417 // Return the maximum absolute value included in range. | 345 // Return the maximum absolute value included in range. |
| 418 static int64_t ConstantAbsMax(const Range* range); | 346 static int64_t ConstantAbsMax(const Range* range); |
| 419 | 347 |
| 420 static void BinaryOp(const Token::Kind op, | 348 static Range* BinaryOp(const Token::Kind op, |
| 421 const Range* left_range, | 349 const Range* left_range, |
| 422 const Range* right_range, | 350 const Range* right_range, |
| 423 Definition* left_defn, | 351 Definition* left_defn); |
| 424 Range* result); | |
| 425 | 352 |
| 426 private: | 353 private: |
| 427 RangeBoundary min_; | 354 RangeBoundary min_; |
| 428 RangeBoundary max_; | 355 RangeBoundary max_; |
| 429 }; | 356 }; |
| 430 | 357 |
| 431 | 358 |
| 432 // Range analysis for integer values. | 359 // Range analysis for integer values. |
| 433 class RangeAnalysis : public ValueObject { | 360 class RangeAnalysis : public ValueObject { |
| 434 public: | 361 public: |
| 435 explicit RangeAnalysis(FlowGraph* flow_graph) | 362 explicit RangeAnalysis(FlowGraph* flow_graph) |
| 436 : flow_graph_(flow_graph) { } | 363 : flow_graph_(flow_graph), |
| 364 marked_defns_(NULL) { } |
| 437 | 365 |
| 438 // Infer ranges for all values and remove overflow checks from binary smi | 366 // Infer ranges for all values and remove overflow checks from binary smi |
| 439 // operations when proven redundant. | 367 // operations when proven redundant. |
| 440 void Analyze(); | 368 void Analyze(); |
| 441 | 369 |
| 442 private: | 370 private: |
| 443 enum JoinOperator { | |
| 444 NONE, | |
| 445 WIDEN, | |
| 446 NARROW | |
| 447 }; | |
| 448 static char OpPrefix(JoinOperator op); | |
| 449 | |
| 450 // Collect all values that were proven to be smi in smi_values_ array and all | 371 // Collect all values that were proven to be smi in smi_values_ array and all |
| 451 // CheckSmi instructions in smi_check_ array. | 372 // CheckSmi instructions in smi_check_ array. |
| 452 void CollectValues(); | 373 void CollectValues(); |
| 453 | 374 |
| 454 // Iterate over smi values and constrain them at branch successors. | 375 // Iterate over smi values and constrain them at branch successors. |
| 455 // Additionally constraint values after CheckSmi instructions. | 376 // Additionally constraint values after CheckSmi instructions. |
| 456 void InsertConstraints(); | 377 void InsertConstraints(); |
| 457 | 378 |
| 458 // Iterate over uses of the given definition and discover branches that | 379 // Iterate over uses of the given definition and discover branches that |
| 459 // constrain it. Insert appropriate Constraint instructions at true | 380 // constrain it. Insert appropriate Constraint instructions at true |
| (...skipping 12 matching lines...) Expand all Loading... |
| 472 CheckArrayBoundInstr* check, | 393 CheckArrayBoundInstr* check, |
| 473 intptr_t use_index); | 394 intptr_t use_index); |
| 474 | 395 |
| 475 // Replace uses of the definition def that are dominated by instruction dom | 396 // Replace uses of the definition def that are dominated by instruction dom |
| 476 // with uses of other definition. | 397 // with uses of other definition. |
| 477 void RenameDominatedUses(Definition* def, | 398 void RenameDominatedUses(Definition* def, |
| 478 Instruction* dom, | 399 Instruction* dom, |
| 479 Definition* other); | 400 Definition* other); |
| 480 | 401 |
| 481 | 402 |
| 482 // Infer ranges for integer (smi or mint) definitions. | 403 // Walk the dominator tree and infer ranges for smi values. |
| 483 void InferRanges(); | 404 void InferRanges(); |
| 405 void InferRangesRecursive(BlockEntryInstr* block); |
| 484 | 406 |
| 485 // Collect integer definition in the reverse postorder. | 407 enum Direction { |
| 486 void CollectDefinitions(BlockEntryInstr* block, BitVector* set); | 408 kUnknown, |
| 409 kPositive, |
| 410 kNegative, |
| 411 kBoth |
| 412 }; |
| 487 | 413 |
| 488 // Recompute ranges of all definitions until they stop changing. | 414 Range* InferInductionVariableRange(JoinEntryInstr* loop_header, |
| 489 // Apply the given JoinOperator when computing Phi ranges. | 415 PhiInstr* var); |
| 490 void Iterate(JoinOperator op, intptr_t max_iterations); | |
| 491 bool InferRange(JoinOperator op, Definition* defn, intptr_t iteration); | |
| 492 | 416 |
| 493 // Based on computed ranges find and eliminate redundant CheckArrayBound | 417 void ResetWorklist(); |
| 494 // instructions. | 418 void MarkDefinition(Definition* defn); |
| 495 void EliminateRedundantBoundsChecks(); | |
| 496 | 419 |
| 497 // Find unsatisfiable constraints and mark corresponding blocks unreachable. | 420 static Direction ToDirection(Value* val); |
| 498 void MarkUnreachableBlocks(); | 421 |
| 422 static Direction Invert(Direction direction) { |
| 423 return (direction == kPositive) ? kNegative : kPositive; |
| 424 } |
| 425 |
| 426 static void UpdateDirection(Direction* direction, |
| 427 Direction new_direction) { |
| 428 if (*direction != new_direction) { |
| 429 if (*direction != kUnknown) new_direction = kBoth; |
| 430 *direction = new_direction; |
| 431 } |
| 432 } |
| 499 | 433 |
| 500 // Remove artificial Constraint instructions and replace them with actual | 434 // Remove artificial Constraint instructions and replace them with actual |
| 501 // unconstrained definitions. | 435 // unconstrained definitions. |
| 502 void RemoveConstraints(); | 436 void RemoveConstraints(); |
| 503 | 437 |
| 504 Range* ConstraintSmiRange(Token::Kind op, Definition* boundary); | 438 Range* ConstraintRange(Token::Kind op, Definition* boundary); |
| 505 | 439 |
| 506 Isolate* isolate() const { return flow_graph_->isolate(); } | 440 Isolate* isolate() const { return flow_graph_->isolate(); } |
| 507 | 441 |
| 508 FlowGraph* flow_graph_; | 442 FlowGraph* flow_graph_; |
| 509 | 443 |
| 510 // Value that are known to be smi or mint. | 444 // Value that are known to be smi or mint. |
| 511 GrowableArray<Definition*> values_; | 445 GrowableArray<Definition*> values_; |
| 512 | |
| 513 // All CheckSmi instructions. | 446 // All CheckSmi instructions. |
| 514 GrowableArray<CheckSmiInstr*> smi_checks_; | 447 GrowableArray<CheckSmiInstr*> smi_checks_; |
| 515 | 448 |
| 516 // All CheckArrayBound instructions. | |
| 517 GrowableArray<CheckArrayBoundInstr*> bounds_checks_; | |
| 518 | |
| 519 // All Constraints inserted during InsertConstraints phase. They are treated | 449 // All Constraints inserted during InsertConstraints phase. They are treated |
| 520 // as smi values. | 450 // as smi values. |
| 521 GrowableArray<ConstraintInstr*> constraints_; | 451 GrowableArray<ConstraintInstr*> constraints_; |
| 522 | 452 |
| 523 // List of integer (smi or mint) definitions including constraints sorted | 453 // Bitvector for a quick filtering of known smi or mint values. |
| 524 // in the reverse postorder. | 454 BitVector* definitions_; |
| 525 GrowableArray<Definition*> definitions_; | 455 |
| 456 // Worklist for induction variables analysis. |
| 457 GrowableArray<Definition*> worklist_; |
| 458 BitVector* marked_defns_; |
| 526 | 459 |
| 527 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis); | 460 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis); |
| 528 }; | 461 }; |
| 529 | 462 |
| 530 | 463 |
| 531 // Replaces Mint IL instructions with Uint32 IL instructions | 464 // Replaces Mint IL instructions with Uint32 IL instructions |
| 532 // when possible. Uses output of RangeAnalysis. | 465 // when possible. Uses output of RangeAnalysis. |
| 533 class IntegerInstructionSelector : public ValueObject { | 466 class IntegerInstructionSelector : public ValueObject { |
| 534 public: | 467 public: |
| 535 explicit IntegerInstructionSelector(FlowGraph* flow_graph); | 468 explicit IntegerInstructionSelector(FlowGraph* flow_graph); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 553 BitVector* selected_uint32_defs_; | 486 BitVector* selected_uint32_defs_; |
| 554 | 487 |
| 555 FlowGraph* flow_graph_; | 488 FlowGraph* flow_graph_; |
| 556 Isolate* isolate_; | 489 Isolate* isolate_; |
| 557 }; | 490 }; |
| 558 | 491 |
| 559 | 492 |
| 560 } // namespace dart | 493 } // namespace dart |
| 561 | 494 |
| 562 #endif // VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ | 495 #endif // VM_FLOW_GRAPH_RANGE_ANALYSIS_H_ |
| OLD | NEW |