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